text: /**************************************************************
   * 
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   * 
   *************************************************************/
  
  
  
  #include "precompiled_sd.hxx"
  
  #include "controller/SlsPageSelector.hxx"
  
  #include "SlideSorter.hxx"
  #include "SlideSorterViewShell.hxx"
  #include "controller/SlideSorterController.hxx"
  #include "controller/SlsSelectionManager.hxx"
  #include "controller/SlsAnimator.hxx"
  #include "controller/SlsCurrentSlideManager.hxx"
  #include "controller/SlsVisibleAreaManager.hxx"
  #include "model/SlsPageDescriptor.hxx"
  #include "model/SlsPageEnumerationProvider.hxx"
  #include "model/SlideSorterModel.hxx"
  #include "view/SlideSorterView.hxx"
  
  #include "sdpage.hxx"
  #include "ViewShell.hxx"
  #include "DrawViewShell.hxx"
  #include "ViewShellBase.hxx"
  #include <com/sun/star/drawing/XDrawView.hpp>
  #include <com/sun/star/beans/XPropertySet.hpp>
  #include <boost/bind.hpp>
  
  
  using namespace ::com::sun::star;
  using namespace ::com::sun::star::uno;
  using namespace ::sd::slidesorter::model;
  using namespace ::sd::slidesorter::view;
  
  
  namespace sd { namespace slidesorter { namespace controller {
  
  PageSelector::PageSelector (SlideSorter& rSlideSorter)
      : mrModel(rSlideSorter.GetModel()),
        mrSlideSorter(rSlideSorter),
        mrController(mrSlideSorter.GetController()),
        mnSelectedPageCount(0),
        mnBroadcastDisableLevel(0),
        mbSelectionChangeBroadcastPending(false),
        mpMostRecentlySelectedPage(),
        mpSelectionAnchor(),
        mpCurrentPage(),
        mnUpdateLockCount(0),
        mbIsUpdateCurrentPagePending(true)
  {
      CountSelectedPages ();
  }
  
  
  
  
  void PageSelector::SelectAllPages (void)
  {
      VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter);
      PageSelector::UpdateLock aLock (*this);
  
      int nPageCount = mrModel.GetPageCount();
      for (int nPageIndex=0; nPageIndex<nPageCount; nPageIndex++)
          SelectPage(nPageIndex);
  }
  
  
  
  
  void PageSelector::DeselectAllPages (void)
  {
      VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter);
      PageSelector::UpdateLock aLock (*this);
  
      int nPageCount = mrModel.GetPageCount();
      for (int nPageIndex=0; nPageIndex<nPageCount; nPageIndex++)
          DeselectPage(nPageIndex);
  
      DBG_ASSERT (mnSelectedPageCount==0, 
          "PageSelector::DeselectAllPages: the selected pages counter is not 0");
      mnSelectedPageCount = 0;
      mpSelectionAnchor.reset();
  }
  
  
  
  
  void PageSelector::GetCoreSelection (void)
  {
      PageSelector::UpdateLock aLock (*this);
  
      bool bSelectionHasChanged (true);
      mnSelectedPageCount = 0;
      model::PageEnumeration aAllPages (
          model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
      while (aAllPages.HasMoreElements())
      {
          model::SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
          if (pDescriptor->GetCoreSelection())
          {
              mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(pDescriptor);
              mrSlideSorter.GetView().RequestRepaint(pDescriptor);
              bSelectionHasChanged = true;
          }
  
          if (pDescriptor->HasState(PageDescriptor::ST_Selected))
              mnSelectedPageCount++;
      }
  
      if (bSelectionHasChanged)
      {
          if (mnBroadcastDisableLevel > 0)
              mbSelectionChangeBroadcastPending = true;
          else
              mrController.GetSelectionManager()->SelectionHasChanged();
      }
  }
  
  
  
  
  void PageSelector::SetCoreSelection (void)
  {
      model::PageEnumeration aAllPages (
          model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
      while (aAllPages.HasMoreElements())
      {
          model::SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
          pDescriptor->SetCoreSelection();
      }
  }
  
  
  
  
  void PageSelector::SelectPage (int nPageIndex)
  {
      SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
      if (pDescriptor.get() != NULL)
          SelectPage(pDescriptor);
  }
  
  
  
  
  void PageSelector::SelectPage (const SdPage* pPage)
  {
      const sal_Int32 nPageIndex (mrModel.GetIndex(pPage));
      SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
      if (pDescriptor.get()!=NULL && pDescriptor->GetPage()==pPage)
          SelectPage(pDescriptor);
  }
  
  
  
  
  void PageSelector::SelectPage (const SharedPageDescriptor& rpDescriptor)
  {
      if (rpDescriptor.get()!=NULL
          && mrSlideSorter.GetView().SetState(rpDescriptor, PageDescriptor::ST_Selected, true))
      {
          ++mnSelectedPageCount;
          mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor,true);
          mrSlideSorter.GetView().RequestRepaint(rpDescriptor);
  
          mpMostRecentlySelectedPage = rpDescriptor;
          if( !bool(mpSelectionAnchor) )
              mpSelectionAnchor = rpDescriptor;
  
          if (mnBroadcastDisableLevel > 0)
              mbSelectionChangeBroadcastPending = true;
          else
              mrController.GetSelectionManager()->SelectionHasChanged();
          UpdateCurrentPage();
  
          CheckConsistency();
      }
  }
  
  
  
  
  void PageSelector::DeselectPage (
      int nPageIndex,
      const bool bUpdateCurrentPage)
  {
      model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
      if (pDescriptor.get() != NULL)
          DeselectPage(pDescriptor, bUpdateCurrentPage);
  }
  
  
  
  
  void PageSelector::DeselectPage (
      const SdPage* pPage,
      const bool bUpdateCurrentPage)
  {
      const sal_Int32 nPageIndex (mrModel.GetIndex(pPage));
      SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
      if (pDescriptor.get()!=NULL && pDescriptor->GetPage()==pPage)
          DeselectPage(pDescriptor, bUpdateCurrentPage);
  }
  
  
  
  
  void PageSelector::DeselectPage (
      const SharedPageDescriptor& rpDescriptor,
      const bool bUpdateCurrentPage)
  {
      if (rpDescriptor.get()!=NULL
          && mrSlideSorter.GetView().SetState(rpDescriptor, PageDescriptor::ST_Selected, false))
      {
          --mnSelectedPageCount;
          mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor);
          mrSlideSorter.GetView().RequestRepaint(rpDescriptor);
          if (mpMostRecentlySelectedPage == rpDescriptor)
              mpMostRecentlySelectedPage.reset();
          if (mnBroadcastDisableLevel > 0)
              mbSelectionChangeBroadcastPending = true;
          else
              mrController.GetSelectionManager()->SelectionHasChanged();
          if (bUpdateCurrentPage)
              UpdateCurrentPage();
  
          CheckConsistency();
      }
  }
  
  
  
  
  void PageSelector::CheckConsistency (void) const
  {
      int nSelectionCount (0);
      for (int nPageIndex=0,nPageCount=mrModel.GetPageCount(); nPageIndex<nPageCount; nPageIndex++)
      {
          SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
          assert(pDescriptor);
          if (pDescriptor->HasState(PageDescriptor::ST_Selected))
              ++nSelectionCount;
      }
      if (nSelectionCount!=mnSelectedPageCount)
      {
          // #120020# The former call to assert(..) internally calls 
          // SlideSorterModel::GetPageDescriptor which will crash in this situation
          // (only in non-pro code). All what is wanted there is to assert it (the
          // error is already detected), so do this directly.
          OSL_ENSURE(false, "PageSelector: Consistency error (!)");
      }
  }
  
  
  
  
  bool PageSelector::IsPageSelected (int nPageIndex)
  {
      SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
      if (pDescriptor.get() != NULL)
          return pDescriptor->HasState(PageDescriptor::ST_Selected);
      else
          return false;
  }
  
  
  
  
  int PageSelector::GetPageCount (void) const
  {
      return mrModel.GetPageCount();
  }
  
  
  
  
  int PageSelector::GetSelectedPageCount (void) const
  {
      return mnSelectedPageCount;
  }
  
  
  
  
  SharedPageDescriptor PageSelector::GetSelectionAnchor (void) const
  {
      return mpSelectionAnchor;
  }
  
  
  
  
  void PageSelector::CountSelectedPages (void)
  {
      mnSelectedPageCount = 0;
      model::PageEnumeration aSelectedPages (
          model::PageEnumerationProvider::CreateSelectedPagesEnumeration(mrModel));
      while (aSelectedPages.HasMoreElements())
      {
          mnSelectedPageCount++;
          aSelectedPages.GetNextElement();
      }
  }
  
  
  
  
  void PageSelector::EnableBroadcasting (void)
  {
      if (mnBroadcastDisableLevel > 0)
          mnBroadcastDisableLevel --;
      if (mnBroadcastDisableLevel==0 && mbSelectionChangeBroadcastPending)
      {
          mrController.GetSelectionManager()->SelectionHasChanged();
          mbSelectionChangeBroadcastPending = false;
      }
  }
  
  
  
  
  void PageSelector::DisableBroadcasting (void)
  {
      mnBroadcastDisableLevel ++;
  }
  
  
  
  
  ::boost::shared_ptr<PageSelector::PageSelection> PageSelector::GetPageSelection (void) const
  {
      ::boost::shared_ptr<PageSelection> pSelection (new PageSelection());
      pSelection->reserve(GetSelectedPageCount());
  
      int nPageCount = GetPageCount();
      for (int nIndex=0; nIndex<nPageCount; nIndex++)
      {
          SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex));
          if (pDescriptor.get()!=NULL && pDescriptor->HasState(PageDescriptor::ST_Selected))
              pSelection->push_back(pDescriptor->GetPage());
      }
  
      return pSelection;
  }
  
  
  
  
  void PageSelector::SetPageSelection (
      const ::boost::shared_ptr<PageSelection>& rpSelection,
      const bool bUpdateCurrentPage)
  {
      PageSelection::const_iterator iPage;
      for (iPage=rpSelection->begin(); iPage!=rpSelection->end(); ++iPage)
          SelectPage(*iPage);
      if (bUpdateCurrentPage)
          UpdateCurrentPage();
  }
  
  
  
  
  void PageSelector::UpdateCurrentPage (const bool bUpdateOnlyWhenPending)
  {
      if (mnUpdateLockCount > 0)
      {
          mbIsUpdateCurrentPagePending = true;
          return;
      }
  
      if ( ! mbIsUpdateCurrentPagePending && bUpdateOnlyWhenPending)
          return;
  
      mbIsUpdateCurrentPagePending = false;
      
      // Make the first selected page the current page.
      SharedPageDescriptor pCurrentPageDescriptor;
      const sal_Int32 nPageCount (GetPageCount());
      for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex)
      {
          SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex));
          if ( ! pDescriptor)
              continue;
          if (pDescriptor->HasState(PageDescriptor::ST_Selected))
          {
              pCurrentPageDescriptor = pDescriptor;
              break;
          }
      }
      if ( ! pCurrentPageDescriptor && nPageCount>0)
      {
          // No page is selected.  Make the first slide the current page.
          pCurrentPageDescriptor = mrModel.GetPageDescriptor(0);
      }
  
      if (pCurrentPageDescriptor)
      {
          // Switching the current slide normally sets also the
          // selection to just the new current slide.  To prevent that,
          // we store (and at the end of this scope restore) the current
          // selection.
          ::boost::shared_ptr<PageSelection> pSelection (GetPageSelection());
                  
          mrController.GetCurrentSlideManager()->SwitchCurrentSlide(pCurrentPageDescriptor);
                  
          // Restore the selection and prevent a recursive call to
          // UpdateCurrentPage().
          SetPageSelection(pSelection, false);
      }
  }
  
  
  
  
  //===== PageSelector::UpdateLock ==============================================
  
  PageSelector::UpdateLock::UpdateLock (SlideSorter& rSlideSorter)
      : mpSelector(&rSlideSorter.GetController().GetPageSelector())
  {
      ++mpSelector->mnUpdateLockCount;
  }
  
  
  
  
  PageSelector::UpdateLock::UpdateLock (PageSelector& rSelector)
      : mpSelector(&rSelector)
  {
      ++mpSelector->mnUpdateLockCount;
  }
  
  
  
  
  PageSelector::UpdateLock::~UpdateLock (void)
  {
      Release();
  }
  
  void PageSelector::UpdateLock::Release (void)
  {
      if (mpSelector != NULL)
      {
          --mpSelector->mnUpdateLockCount;
          OSL_ASSERT(mpSelector->mnUpdateLockCount >= 0);
          if (mpSelector->mnUpdateLockCount == 0)
              mpSelector->UpdateCurrentPage(true);
  
          mpSelector = NULL;
      }
  }
  
  
  
  
  //===== PageSelector::BroadcastLock ==============================================
  
  PageSelector::BroadcastLock::BroadcastLock (SlideSorter& rSlideSorter)
      : mrSelector(rSlideSorter.GetController().GetPageSelector())
  {
      mrSelector.DisableBroadcasting();
  }
  
  
  
  
  PageSelector::BroadcastLock::BroadcastLock (PageSelector& rSelector)
      : mrSelector(rSelector)
  {
      mrSelector.DisableBroadcasting();
  }
  
  
  
  
  PageSelector::BroadcastLock::~BroadcastLock (void)
  {
      mrSelector.EnableBroadcasting();
  }
  
  } } } // end of namespace ::sd::slidesorter::controller
  