diff options
Diffstat (limited to 'sd/source')
129 files changed, 16890 insertions, 6394 deletions
diff --git a/sd/source/core/drawdoc2.cxx b/sd/source/core/drawdoc2.cxx index 74a1bde5f5f8..6ccf0d2f73cb 100755 --- a/sd/source/core/drawdoc2.cxx +++ b/sd/source/core/drawdoc2.cxx @@ -1354,7 +1354,8 @@ USHORT SdDrawDocument::CreatePage ( AutoLayout eStandardLayout, AutoLayout eNotesLayout, BOOL bIsPageBack, - BOOL bIsPageObj) + BOOL bIsPageObj, + const sal_Int32 nInsertPosition) { SdPage* pPreviousStandardPage; SdPage* pPreviousNotesPage; @@ -1422,16 +1423,17 @@ USHORT SdDrawDocument::CreatePage ( pNotesPage->setHeaderFooterSettings( pPreviousNotesPage->getHeaderFooterSettings() ); return InsertPageSet ( - pActualPage, ePageKind, + pActualPage, + ePageKind, sStandardPageName, sNotesPageName, eStandardLayout, eNotesLayout, bIsPageBack, bIsPageObj, - pStandardPage, - pNotesPage); + pNotesPage, + nInsertPosition); } @@ -1473,7 +1475,8 @@ USHORT SdDrawDocument::DuplicatePage ( AutoLayout eStandardLayout, AutoLayout eNotesLayout, BOOL bIsPageBack, - BOOL bIsPageObj) + BOOL bIsPageObj, + const sal_Int32 nInsertPosition) { SdPage* pPreviousStandardPage; SdPage* pPreviousNotesPage; @@ -1500,16 +1503,17 @@ USHORT SdDrawDocument::DuplicatePage ( pNotesPage = (SdPage*) pPreviousNotesPage->Clone(); return InsertPageSet ( - pActualPage, ePageKind, + pActualPage, + ePageKind, sStandardPageName, sNotesPageName, eStandardLayout, eNotesLayout, bIsPageBack, bIsPageObj, - pStandardPage, - pNotesPage); + pNotesPage, + nInsertPosition); } @@ -1524,9 +1528,9 @@ USHORT SdDrawDocument::InsertPageSet ( AutoLayout eNotesLayout, BOOL bIsPageBack, BOOL bIsPageObj, - SdPage* pStandardPage, - SdPage* pNotesPage) + SdPage* pNotesPage, + sal_Int32 nInsertPosition) { SdPage* pPreviousStandardPage; SdPage* pPreviousNotesPage; @@ -1556,13 +1560,16 @@ USHORT SdDrawDocument::InsertPageSet ( eNotesLayout = pPreviousNotesPage->GetAutoLayout(); } + OSL_ASSERT(nNotesPageNum==nStandardPageNum+1); + if (nInsertPosition < 0) + nInsertPosition = nStandardPageNum; // Set up and insert the standard page. SetupNewPage ( pPreviousStandardPage, pStandardPage, aStandardPageName, - nStandardPageNum, + nInsertPosition, bIsPageBack, bIsPageObj); @@ -1572,7 +1579,7 @@ USHORT SdDrawDocument::InsertPageSet ( pPreviousNotesPage, pNotesPage, aNotesPageName, - nNotesPageNum, + nInsertPosition+1, bIsPageBack, bIsPageObj); diff --git a/sd/source/core/drawdoc3.cxx b/sd/source/core/drawdoc3.cxx index 103a197d5a1f..025700a790fc 100644..100755 --- a/sd/source/core/drawdoc3.cxx +++ b/sd/source/core/drawdoc3.cxx @@ -57,6 +57,7 @@ #include <sot/formats.hxx> #include <set> +#include <boost/bind.hpp> #include "glob.hrc" #include "drawdoc.hxx" @@ -410,6 +411,20 @@ void InsertBookmarkAsPage_FindDuplicateLayouts::operator()( SdDrawDocument& rDoc delete pLayout; } +/** Just add one page to the container given to the constructor. +*/ +class InsertBookmarkAsPage_AddBookmarkedPages + : public SdDrawDocument::InsertBookmarkAsPage_PageFunctorBase +{ +public: + InsertBookmarkAsPage_AddBookmarkedPages(::std::vector<SdPage*>& rContainer) + : mrContainer(rContainer) {} + ~InsertBookmarkAsPage_AddBookmarkedPages(void) {} + void operator() (SdDrawDocument&, SdPage* pPage) { mrContainer.push_back(pPage); } +private: + ::std::vector<SdPage*>& mrContainer; +}; + BOOL SdDrawDocument::InsertBookmarkAsPage( List* pBookmarkList, @@ -668,23 +683,24 @@ BOOL SdDrawDocument::InsertBookmarkAsPage( USHORT nActualInsertPos = nInsertPos; + // Collect the bookmarked pages. + ::std::vector<SdPage*> aBookmarkedPages (pBookmarkList->Count(), NULL); for (USHORT nPos = 0; nPos < pBookmarkList->Count(); nPos++) { - /************************************************************** - * Namen der Bookmark-Seiten aus Liste holen - **************************************************************/ String aPgName(*(String*) pBookmarkList->GetObject(nPos)); BOOL bIsMasterPage; USHORT nBMPage = pBookmarkDoc->GetPageByName( aPgName, bIsMasterPage ); if (nBMPage != SDRPAGE_NOTFOUND) { - pBMPage = (SdPage*) pBookmarkDoc->GetPage(nBMPage); - } - else - { - pBMPage = NULL; + aBookmarkedPages[nPos] = dynamic_cast<SdPage*>(pBookmarkDoc->GetPage(nBMPage)); } + } + + for (USHORT nPos = 0; nPos < pBookmarkList->Count(); nPos++) + { + pBMPage = aBookmarkedPages[nPos]; + USHORT nBMPage = pBMPage!=NULL ? pBMPage->GetPageNum() : SDRPAGE_NOTFOUND; if (pBMPage && pBMPage->GetPageKind()==PK_STANDARD && !pBMPage->IsMasterPage()) { @@ -696,6 +712,8 @@ BOOL SdDrawDocument::InsertBookmarkAsPage( // #95991# delay renaming *after* pages are copied (might destroy source otherwise) // #67905# don't change name if source and dest model are the same! // #96029# avoid renaming if replacing the same page + String aPgName(*(String*) pBookmarkList->GetObject(nPos)); + BOOL bIsMasterPage; USHORT nPageSameName = GetPageByName(aPgName, bIsMasterPage); if( pBookmarkDoc != this && nPageSameName != SDRPAGE_NOTFOUND && @@ -705,7 +723,7 @@ BOOL SdDrawDocument::InsertBookmarkAsPage( bMustRename = sal_True; } - SdPage* pBookmarkPage = dynamic_cast< SdPage* >( pBookmarkDoc->GetPage(nBMPage) ); + SdPage* pBookmarkPage = pBMPage; if (bReplace ) { ReplacePageInCustomShows( dynamic_cast< SdPage* >( GetPage( nActualInsertPos ) ), pBookmarkPage ); diff --git a/sd/source/ui/accessibility/AccessibleSlideSorterObject.cxx b/sd/source/ui/accessibility/AccessibleSlideSorterObject.cxx index ae1f6f633edc..510f0233667c 100755 --- a/sd/source/ui/accessibility/AccessibleSlideSorterObject.cxx +++ b/sd/source/ui/accessibility/AccessibleSlideSorterObject.cxx @@ -37,6 +37,8 @@ #include "model/SlideSorterModel.hxx" #include "model/SlsPageDescriptor.hxx" #include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsPageObjectLayouter.hxx" #include <com/sun/star/accessibility/AccessibleRole.hpp> #include <com/sun/star/accessibility/AccessibleStateType.hpp> #include <comphelper/accessibleeventnotifier.hxx> @@ -385,10 +387,11 @@ awt::Rectangle SAL_CALL AccessibleSlideSorterObject::getBounds (void) const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); - Rectangle aBBox (mrSlideSorter.GetView().GetPageBoundingBox ( - mnPageNumber, - ::sd::slidesorter::view::SlideSorterView::CS_SCREEN, - ::sd::slidesorter::view::SlideSorterView::BBT_INFO)); + Rectangle aBBox ( + mrSlideSorter.GetView().GetLayouter().GetPageObjectLayouter()->GetBoundingBox( + mrSlideSorter.GetModel().GetPageDescriptor(mnPageNumber), + ::sd::slidesorter::view::PageObjectLayouter::PageObject, + ::sd::slidesorter::view::PageObjectLayouter::WindowCoordinateSystem)); if (mxParent.is()) { diff --git a/sd/source/ui/accessibility/AccessibleSlideSorterView.cxx b/sd/source/ui/accessibility/AccessibleSlideSorterView.cxx index 6f3508d731a8..91c09b55697d 100755..100644 --- a/sd/source/ui/accessibility/AccessibleSlideSorterView.cxx +++ b/sd/source/ui/accessibility/AccessibleSlideSorterView.cxx @@ -62,6 +62,14 @@ using namespace ::com::sun::star::accessibility; namespace accessibility { +/** Inner implementation class of the AccessibleSlideSorterView. + + Note that some event broadcasting is done asynchronously because + otherwise it could lead to deadlocks on (at least) some Solaris + machines. Probably (but unverified) this can happen on all GTK based + systems. The asynchronous broadcasting is just a workaround for a + poorly understood problem. +*/ class AccessibleSlideSorterView::Implementation : public SfxListener { @@ -72,7 +80,7 @@ public: ::Window* pWindow); ~Implementation (void); - void UpdateChildren (void); + void RequestUpdateChildren (void); void Clear (void); sal_Int32 GetVisibleChildCount (void) const; AccessibleSlideSorterObject* GetAccessibleChild (sal_Int32 nIndex); @@ -83,8 +91,9 @@ public: void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint); DECL_LINK(WindowEventListener, VclWindowEvent*); DECL_LINK(SelectionChangeListener, void*); + DECL_LINK(BroadcastSelectionChange, void*); DECL_LINK(FocusChangeListener, void*); - DECL_LINK(VisibilityChangeListener, void*); + DECL_LINK(UpdateChildrenCallback, void*); private: AccessibleSlideSorterView& mrAccessibleSlideSorter; @@ -97,6 +106,10 @@ private: ::Window* mpWindow; sal_Int32 mnFocusedIndex; bool mbModelChangeLocked; + ULONG mnUpdateChildrenUserEventId; + ULONG mnSelectionChangeUserEventId; + + void UpdateChildren (void); }; @@ -115,7 +128,6 @@ AccessibleSlideSorterView::AccessibleSlideSorterView( mnClientId(0), mpContentWindow(pContentWindow) { - OSL_TRACE("creating AccessibleSlideSorterView"); } @@ -771,6 +783,9 @@ sal_Bool AccessibleSlideSorterView::IsDisposed (void) return (rBHelper.bDisposed || rBHelper.bInDispose); } + + + //===== AccessibleSlideSorterView::Implementation ============================= AccessibleSlideSorterView::Implementation::Implementation ( @@ -785,7 +800,9 @@ AccessibleSlideSorterView::Implementation::Implementation ( mbListeningToDocument(false), mpWindow(pWindow), mnFocusedIndex(-1), - mbModelChangeLocked(false) + mbModelChangeLocked(false), + mnUpdateChildrenUserEventId(0), + mnSelectionChangeUserEventId(0) { ConnectListeners(); UpdateChildren(); @@ -796,6 +813,10 @@ AccessibleSlideSorterView::Implementation::Implementation ( AccessibleSlideSorterView::Implementation::~Implementation (void) { + if (mnUpdateChildrenUserEventId != 0) + Application::RemoveUserEvent(mnUpdateChildrenUserEventId); + if (mnSelectionChangeUserEventId != 0) + Application::RemoveUserEvent(mnSelectionChangeUserEventId); ReleaseListeners(); Clear(); } @@ -803,6 +824,17 @@ AccessibleSlideSorterView::Implementation::~Implementation (void) +void AccessibleSlideSorterView::Implementation::RequestUpdateChildren (void) +{ + if (mnUpdateChildrenUserEventId == 0) + mnUpdateChildrenUserEventId = Application::PostUserEvent( + LINK(this, AccessibleSlideSorterView::Implementation, + UpdateChildrenCallback)); +} + + + + void AccessibleSlideSorterView::Implementation::UpdateChildren (void) { if (mbModelChangeLocked) @@ -812,10 +844,9 @@ void AccessibleSlideSorterView::Implementation::UpdateChildren (void) return; } - ::sd::slidesorter::view::SlideSorterView::PageRange aRange ( - mrSlideSorter.GetView().GetVisiblePageRange()); - mnFirstVisibleChild = aRange.first; - mnLastVisibleChild = aRange.second; + const Pair aRange (mrSlideSorter.GetView().GetVisiblePageRange()); + mnFirstVisibleChild = aRange.A(); + mnLastVisibleChild = aRange.B(); // Release all children. Clear(); @@ -854,7 +885,7 @@ void AccessibleSlideSorterView::Implementation::Clear (void) sal_Int32 AccessibleSlideSorterView::Implementation::GetVisibleChildCount (void) const { - if (mnFirstVisibleChild <= mnLastVisibleChild) + if (mnFirstVisibleChild<=mnLastVisibleChild && mnFirstVisibleChild>=0) return mnLastVisibleChild - mnFirstVisibleChild + 1; else return 0; @@ -929,7 +960,7 @@ void AccessibleSlideSorterView::Implementation::ConnectListeners (void) mrSlideSorter.GetController().GetFocusManager().AddFocusChangeListener( LINK(this,AccessibleSlideSorterView::Implementation,FocusChangeListener)); mrSlideSorter.GetView().AddVisibilityChangeListener( - LINK(this,AccessibleSlideSorterView::Implementation,VisibilityChangeListener)); + LINK(this,AccessibleSlideSorterView::Implementation,UpdateChildrenCallback)); } @@ -942,7 +973,7 @@ void AccessibleSlideSorterView::Implementation::ReleaseListeners (void) mrSlideSorter.GetController().GetSelectionManager()->RemoveSelectionChangeListener( LINK(this,AccessibleSlideSorterView::Implementation,SelectionChangeListener)); mrSlideSorter.GetView().RemoveVisibilityChangeListener( - LINK(this,AccessibleSlideSorterView::Implementation,VisibilityChangeListener)); + LINK(this,AccessibleSlideSorterView::Implementation,UpdateChildrenCallback)); if (mpWindow != NULL) mpWindow->RemoveEventListener( @@ -970,7 +1001,7 @@ void AccessibleSlideSorterView::Implementation::Notify ( switch (rSdrHint.GetKind()) { case HINT_PAGEORDERCHG: - UpdateChildren(); + RequestUpdateChildren(); break; default: break; @@ -987,7 +1018,7 @@ void AccessibleSlideSorterView::Implementation::Notify ( case sd::ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END: mbModelChangeLocked = false; - UpdateChildren(); + RequestUpdateChildren(); break; default: break; @@ -1004,7 +1035,7 @@ IMPL_LINK(AccessibleSlideSorterView::Implementation, WindowEventListener, VclWin { case VCLEVENT_WINDOW_MOVE: case VCLEVENT_WINDOW_RESIZE: - UpdateChildren(); + RequestUpdateChildren(); break; case VCLEVENT_WINDOW_GETFOCUS: @@ -1025,6 +1056,18 @@ IMPL_LINK(AccessibleSlideSorterView::Implementation, WindowEventListener, VclWin IMPL_LINK(AccessibleSlideSorterView::Implementation, SelectionChangeListener, void*, EMPTYARG ) { + if (mnSelectionChangeUserEventId == 0) + mnSelectionChangeUserEventId = Application::PostUserEvent( + LINK(this, AccessibleSlideSorterView::Implementation, BroadcastSelectionChange)); + return 1; +} + + + + +IMPL_LINK(AccessibleSlideSorterView::Implementation, BroadcastSelectionChange, void*, EMPTYARG ) +{ + mnSelectionChangeUserEventId = 0; mrAccessibleSlideSorter.FireAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), @@ -1068,8 +1111,9 @@ IMPL_LINK(AccessibleSlideSorterView::Implementation, FocusChangeListener, void*, -IMPL_LINK(AccessibleSlideSorterView::Implementation, VisibilityChangeListener, void*, EMPTYARG ) +IMPL_LINK(AccessibleSlideSorterView::Implementation, UpdateChildrenCallback, void*, EMPTYARG ) { + mnUpdateChildrenUserEventId = 0; UpdateChildren(); return 1; diff --git a/sd/source/ui/dlg/PaneDockingWindow.cxx b/sd/source/ui/dlg/PaneDockingWindow.cxx index c1dedd5d8293..bcf58c38c0b1 100755..100644 --- a/sd/source/ui/dlg/PaneDockingWindow.cxx +++ b/sd/source/ui/dlg/PaneDockingWindow.cxx @@ -31,12 +31,16 @@ #include "PaneDockingWindow.hxx" #include "Window.hxx" #include "ViewShellBase.hxx" +#include "framework/FrameworkHelper.hxx" #include "sdresid.hxx" #include "res_bmp.hrc" #include <sfx2/dispatch.hxx> #include <vcl/toolbox.hxx> #include <vcl/taskpanelist.hxx> -#include "framework/FrameworkHelper.hxx" +#include <vcl/splitwin.hxx> +#include <vcl/svapp.hxx> +#include <tools/wintypes.hxx> +#include <boost/bind.hpp> using namespace ::com::sun::star; using namespace ::com::sun::star::uno; @@ -61,6 +65,11 @@ void PaneDockingWindow::StateChanged( StateChangedType nType ) { switch (nType) { + case STATE_CHANGE_INITSHOW: + Resize(); + GetContentWindow().SetStyle(GetContentWindow().GetStyle() | WB_DIALOGCONTROL); + break; + case STATE_CHANGE_VISIBLE: // The visibility of the docking window has changed. Tell the // ConfigurationController so that it can activate or deactivate @@ -78,4 +87,61 @@ void PaneDockingWindow::StateChanged( StateChangedType nType ) SfxDockingWindow::StateChanged (nType); } +void PaneDockingWindow::MouseButtonDown (const MouseEvent& rEvent) +{ + if (rEvent.GetButtons() == MOUSE_LEFT) + { + // For some strange reason we have to set the WB_DIALOGCONTROL at + // the content window in order to have it pass focus to its content + // window. Without setting this flag here that works only on views + // that have not been taken from the cash and relocated to this pane + // docking window. + GetContentWindow().SetStyle(GetContentWindow().GetStyle() | WB_DIALOGCONTROL); + GetContentWindow().GrabFocus(); + } + SfxDockingWindow::MouseButtonDown(rEvent); +} + + + + + + + + +void PaneDockingWindow::SetValidSizeRange (const Range aValidSizeRange) +{ + SplitWindow* pSplitWindow = dynamic_cast<SplitWindow*>(GetParent()); + if (pSplitWindow != NULL) + { + const USHORT nId (pSplitWindow->GetItemId(static_cast< ::Window*>(this))); + const USHORT nSetId (pSplitWindow->GetSet(nId)); + // Because the PaneDockingWindow paints its own decoration, we have + // to compensate the valid size range for that. + const SvBorder aBorder (GetDecorationBorder()); + sal_Int32 nCompensation (pSplitWindow->IsHorizontal() + ? mnTitleBarHeight + aBorder.Top() + aBorder.Bottom() + : aBorder.Left() + aBorder.Right()); + pSplitWindow->SetItemSizeRange( + nSetId, + Range( + aValidSizeRange.Min() + nCompensation, + aValidSizeRange.Max() + nCompensation)); + } +} + + + + +PaneDockingWindow::Orientation PaneDockingWindow::GetOrientation (void) const +{ + SplitWindow* pSplitWindow = dynamic_cast<SplitWindow*>(GetParent()); + if (pSplitWindow == NULL) + return UnknownOrientation; + else if (pSplitWindow->IsHorizontal()) + return HorizontalOrientation; + else + return VerticalOrientation; +} + } // end of namespace ::sd diff --git a/sd/source/ui/dlg/PaneDockingWindow.src b/sd/source/ui/dlg/PaneDockingWindow.src index 23b0d19ac79b..7754283332cd 100755 --- a/sd/source/ui/dlg/PaneDockingWindow.src +++ b/sd/source/ui/dlg/PaneDockingWindow.src @@ -29,7 +29,6 @@ DockingWindow FLT_LEFT_PANE_IMPRESS_DOCKING_WINDOW { - // HelpID = SID_EFFECT_WIN ; Border = TRUE ; Hide = TRUE ; SVLook = TRUE ; @@ -45,7 +44,6 @@ DockingWindow FLT_LEFT_PANE_IMPRESS_DOCKING_WINDOW DockingWindow FLT_LEFT_PANE_DRAW_DOCKING_WINDOW { - // HelpID = SID_EFFECT_WIN ; Border = TRUE ; Hide = TRUE ; SVLook = TRUE ; @@ -61,7 +59,6 @@ DockingWindow FLT_LEFT_PANE_DRAW_DOCKING_WINDOW DockingWindow FLT_TOOL_PANEL_DOCKING_WINDOW { - // HelpID = SID_EFFECT_WIN ; Border = TRUE ; Hide = TRUE ; SVLook = TRUE ; diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx index 5e70c313f251..bf3571cbd8f4 100644..100755 --- a/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx +++ b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx @@ -197,9 +197,10 @@ void ChangeRequestQueueProcessor::ProcessOneEvent (void) // its state. if (mpConfigurationUpdater.get() != NULL) { +#ifdef VERBOSE ConfigurationTracer::TraceConfiguration ( mxConfiguration, "updating to configuration"); - +#endif mpConfigurationUpdater->RequestUpdate(mxConfiguration); } } diff --git a/sd/source/ui/framework/factories/BasicViewFactory.cxx b/sd/source/ui/framework/factories/BasicViewFactory.cxx index 1320df5c827b..2dd7689f2b39 100755 --- a/sd/source/ui/framework/factories/BasicViewFactory.cxx +++ b/sd/source/ui/framework/factories/BasicViewFactory.cxx @@ -227,7 +227,7 @@ Reference<XResource> SAL_CALL BasicViewFactory::createResource ( // When the requested view is not in the cache then create a new view. if (pDescriptor.get() == NULL) { - pDescriptor = CreateView(rxViewId, *pFrame, *pWindow, xPane, pFrameView); + pDescriptor = CreateView(rxViewId, *pFrame, *pWindow, xPane, pFrameView, bIsCenterPane); } if (pDescriptor.get() != NULL) @@ -351,7 +351,8 @@ void SAL_CALL BasicViewFactory::initialize (const Sequence<Any>& aArguments) SfxViewFrame& rFrame, ::Window& rWindow, const Reference<XPane>& rxPane, - FrameView* pFrameView) + FrameView* pFrameView, + const bool bIsCenterPane) { ::boost::shared_ptr<ViewDescriptor> pDescriptor (new ViewDescriptor()); @@ -359,13 +360,12 @@ void SAL_CALL BasicViewFactory::initialize (const Sequence<Any>& aArguments) rxViewId, rFrame, rWindow, - pFrameView); + pFrameView, + bIsCenterPane); pDescriptor->mxViewId = rxViewId; if (pDescriptor->mpViewShell.get() != NULL) { - const bool bIsCenterPane ( - rxViewId->isBoundToURL(FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)); pDescriptor->mpViewShell->Init(bIsCenterPane); mpBase->GetViewShellManager()->ActivateViewShell(pDescriptor->mpViewShell.get()); @@ -386,7 +386,8 @@ void SAL_CALL BasicViewFactory::initialize (const Sequence<Any>& aArguments) const Reference<XResourceId>& rxViewId, SfxViewFrame& rFrame, ::Window& rWindow, - FrameView* pFrameView) + FrameView* pFrameView, + const bool bIsCenterPane) { ::boost::shared_ptr<ViewShell> pViewShell; const OUString& rsViewURL (rxViewId->getResourceURL()); @@ -462,7 +463,8 @@ void SAL_CALL BasicViewFactory::initialize (const Sequence<Any>& aArguments) &rFrame, *mpBase, &rWindow, - pFrameView); + pFrameView, + bIsCenterPane); } return pViewShell; diff --git a/sd/source/ui/framework/factories/BasicViewFactory.hxx b/sd/source/ui/framework/factories/BasicViewFactory.hxx index e5bb43551a24..0cdb45ffc7c1 100755 --- a/sd/source/ui/framework/factories/BasicViewFactory.hxx +++ b/sd/source/ui/framework/factories/BasicViewFactory.hxx @@ -128,13 +128,15 @@ private: SfxViewFrame& rFrame, ::Window& rWindow, const css::uno::Reference<css::drawing::framework::XPane>& rxPane, - FrameView* pFrameView); + FrameView* pFrameView, + const bool bIsCenterView); ::boost::shared_ptr<ViewShell> CreateViewShell ( const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewId, SfxViewFrame& rFrame, ::Window& rWindow, - FrameView* pFrameView); + FrameView* pFrameView, + const bool bIsCenterView); void ActivateCenterView ( const ::boost::shared_ptr<ViewDescriptor>& rpDescriptor); diff --git a/sd/source/ui/framework/tools/FrameworkHelper.cxx b/sd/source/ui/framework/tools/FrameworkHelper.cxx index 078f86a88d86..8c325ff202af 100755 --- a/sd/source/ui/framework/tools/FrameworkHelper.cxx +++ b/sd/source/ui/framework/tools/FrameworkHelper.cxx @@ -565,12 +565,27 @@ Reference<XResourceId> FrameworkHelper::RequestView ( void FrameworkHelper::RequestTaskPanel ( - const OUString& rsTaskPanelURL) + const OUString& rsTaskPanelURL, + const bool bEnsureTaskPaneIsVisible) { try { if (mxConfigurationController.is()) { + // Check the existence of the task pane. + if ( ! bEnsureTaskPaneIsVisible) + { + Reference<XConfiguration> xConfiguration ( + mxConfigurationController->getCurrentConfiguration()); + if (xConfiguration.is()) + if ( ! xConfiguration->hasResource( + CreateResourceId(msTaskPaneURL, msRightPaneURL))) + { + // Task pane does is not active. Do not force it. + return; + } + } + // Create the resource id from URLs for the pane, the task pane // view, and the task panel. mxConfigurationController->requestResourceActivation( diff --git a/sd/source/ui/inc/DrawViewShell.hxx b/sd/source/ui/inc/DrawViewShell.hxx index 4abb1a22946d..1110c3ee130c 100755 --- a/sd/source/ui/inc/DrawViewShell.hxx +++ b/sd/source/ui/inc/DrawViewShell.hxx @@ -443,7 +443,8 @@ private: virtual SdPage* CreateOrDuplicatePage ( SfxRequest& rRequest, PageKind ePageKind, - SdPage* pPage); + SdPage* pPage, + const sal_Int32 nInsertPosition = -1); ::com::sun::star::uno::Reference< ::com::sun::star::scanner::XScannerManager > mxScannerManager; ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener > mxScannerListener; diff --git a/sd/source/ui/inc/PaneDockingWindow.hxx b/sd/source/ui/inc/PaneDockingWindow.hxx index 1874df10dd53..960f09ff796d 100755..100644 --- a/sd/source/ui/inc/PaneDockingWindow.hxx +++ b/sd/source/ui/inc/PaneDockingWindow.hxx @@ -35,6 +35,7 @@ #include <boost/shared_ptr.hpp> class ToolBox; +class SplitWindow; namespace sd { @@ -65,6 +66,24 @@ public: virtual ~PaneDockingWindow (void); virtual void StateChanged( StateChangedType nType ); + virtual void MouseButtonDown (const MouseEvent& rEvent); + /** When docked the given range is passed to the parent SplitWindow. + */ + void SetValidSizeRange (const Range aValidSizeRange); + + enum Orientation { HorizontalOrientation, VerticalOrientation, UnknownOrientation }; + /** When the PaneDockingWindow is docked and managed by a split window + it can derive its orientation from the orientation of the split + window and return either HorizontalOrientation or + VerticalOrientation. + Otherwise UnknownOrientation is returned. + */ + Orientation GetOrientation (void) const; + + /** The current height of the title bar. + */ + sal_Int32 mnTitleBarHeight; + }; } // end of namespace ::sd diff --git a/sd/source/ui/inc/PreviewRenderer.hxx b/sd/source/ui/inc/PreviewRenderer.hxx index fc9b657f7796..b157d686b044 100644..100755 --- a/sd/source/ui/inc/PreviewRenderer.hxx +++ b/sd/source/ui/inc/PreviewRenderer.hxx @@ -80,12 +80,16 @@ public: ignored and the preview is rendered in normal mode. When <TRUE/> and high contrast mode is active then the preview is rendered in high contrast mode. + @param bDisplayPresentationObjects + When <FALSE/> then the PresObj place holders are not displayed + in the returned preview. */ Image RenderPage ( const SdPage* pPage, const sal_Int32 nWidth, const String& sSubstitutionText, - const bool bObeyHighContrastMode = true); + const bool bObeyHighContrastMode = true, + const bool bDisplayPresentationObjects = true); /** Render a page with the given pixel size. @param pPage @@ -101,12 +105,16 @@ public: ignored and the preview is rendered in normal mode. When <TRUE/> and high contrast mode is active then the preview is rendered in high contrast mode. + @param bDisplayPresentationObjects + When <FALSE/> then the PresObj place holders are not displayed + in the returned preview. */ Image RenderPage ( const SdPage* pPage, const Size aPreviewPixelSize, const String& sSubstitutionText, - const bool bObeyHighContrastMode = true); + const bool bObeyHighContrastMode = true, + const bool bDisplayPresentationObjects = true); /** Render an image that contains the given substitution text instead of a slide preview. @@ -143,7 +151,9 @@ private: const Size& rPixelSize, const bool bObeyHighContrastMode); void Cleanup (void); - void PaintPage (const SdPage* pPage); + void PaintPage ( + const SdPage* pPage, + const bool bDisplayPresentationObjects); void PaintSubstitutionText (const String& rSubstitutionText); void PaintFrame (void); diff --git a/sd/source/ui/inc/SlideSorter.hxx b/sd/source/ui/inc/SlideSorter.hxx index f52bbb48ab6a..257695e0fc91 100644..100755 --- a/sd/source/ui/inc/SlideSorter.hxx +++ b/sd/source/ui/inc/SlideSorter.hxx @@ -29,12 +29,15 @@ #define SD_SLIDESORTER_SLIDE_SORTER_HXX #include "fupoor.hxx" +#include "Window.hxx" #include <com/sun/star/frame/XController.hpp> #include <cppuhelper/weakref.hxx> #include <sfx2/viewfrm.hxx> #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> #include <boost/scoped_ptr.hpp> +#include <boost/current_function.hpp> + class ScrollBar; class ScrollBarBox; @@ -53,17 +56,21 @@ class SlideSorterModel; namespace sd { namespace slidesorter { namespace view { class SlideSorterView; +class Theme; } } } namespace sd { namespace slidesorter { namespace controller { class Listener; class SlideSorterController; class SlotManager; +class Properties; } } } -namespace sd { namespace slidesorter { +typedef ::boost::shared_ptr<sd::Window> SharedSdWindow; + +namespace sd { namespace slidesorter { /** Show previews for all the slides in a document and allow the user to insert or delete slides and modify the order of the slides. @@ -140,12 +147,7 @@ public: /** Return the content window. This is a sibling and is geometrically enclosed by the scroll bars. */ - ::boost::shared_ptr<sd::Window> GetContentWindow (void) const; - - /** Return the active window as it is returned by a view shell. - Typically the content window. - */ - ::sd::Window* GetActiveWindow (void) const; + SharedSdWindow GetContentWindow (void) const; model::SlideSorterModel& GetModel (void) const; @@ -189,6 +191,15 @@ public: */ void SetCurrentFunction (const FunctionReference& rpFunction); + /** Return a collection of properties that are used througout the slide + sorter. + */ + ::boost::shared_ptr<controller::Properties> GetProperties (void) const; + + /** Return the active theme wich gives access to colors and fonts. + */ + ::boost::shared_ptr<view::Theme> GetTheme (void) const; + protected: /** This virtual method makes it possible to create a specialization of the slide sorter view shell that works with its own implementation @@ -225,7 +236,8 @@ private: ::com::sun::star::uno::WeakReference<com::sun::star::frame::XController> mxControllerWeak; ViewShell* mpViewShell; ViewShellBase* mpViewShellBase; - ::boost::shared_ptr<sd::Window> mpContentWindow; + SharedSdWindow mpContentWindow; + bool mbOwnesContentWindow; ::boost::shared_ptr<ScrollBar> mpHorizontalScrollBar; ::boost::shared_ptr<ScrollBar> mpVerticalScrollBar; ::boost::shared_ptr<ScrollBarBox> mpScrollBarBox; @@ -234,6 +246,11 @@ private: */ bool mbLayoutPending; + /** Some slide sorter wide properties that are used in different + classes. + */ + ::boost::shared_ptr<controller::Properties> mpProperties; + ::boost::shared_ptr<view::Theme> mpTheme; SlideSorter ( ViewShell& rViewShell, diff --git a/sd/source/ui/inc/SlideSorterViewShell.hxx b/sd/source/ui/inc/SlideSorterViewShell.hxx index 4e6033d67ad1..2b03cd636d0f 100755 --- a/sd/source/ui/inc/SlideSorterViewShell.hxx +++ b/sd/source/ui/inc/SlideSorterViewShell.hxx @@ -57,7 +57,8 @@ public: SfxViewFrame* pFrame, ViewShellBase& rViewShellBase, ::Window* pParentWindow, - FrameView* pFrameView); + FrameView* pFrameView, + const bool bIsCenterPane); virtual ~SlideSorterViewShell (void); @@ -106,9 +107,6 @@ public: virtual void SetZoom (long int nZoom); virtual void SetZoomRect (const Rectangle& rZoomRect); - /// forward VCLs PrePaint window event to DrawingLayer - virtual void PrePaint(); - /** This is a callback method used by the active window to delegate its Paint() call to. This view shell itself delegates it to the view. */ @@ -120,6 +118,8 @@ public: */ virtual void ArrangeGUIElements (void); + virtual void Activate (BOOL IsMDIActivate); + //===== Drag and Drop ===================================================== virtual void StartDrag ( @@ -196,6 +196,7 @@ protected: private: ::boost::shared_ptr<SlideSorter> mpSlideSorter; + bool mbIsArrangeGUIElementsPending; SlideSorterViewShell ( SfxViewFrame* pFrame, diff --git a/sd/source/ui/inc/ViewShell.hxx b/sd/source/ui/inc/ViewShell.hxx index ffefb9de7359..e6e6b401cb57 100755 --- a/sd/source/ui/inc/ViewShell.hxx +++ b/sd/source/ui/inc/ViewShell.hxx @@ -209,7 +209,7 @@ public: virtual BOOL RequestHelp( const HelpEvent& rEvt, ::sd::Window* pWin ); virtual long Notify( NotifyEvent& rNEvt, ::sd::Window* pWin ); - BOOL HandleScrollCommand(const CommandEvent& rCEvt, ::sd::Window* pWin); + virtual bool HandleScrollCommand(const CommandEvent& rCEvt, ::sd::Window* pWin); virtual void Draw(OutputDevice &rDev, const Region &rReg); @@ -441,6 +441,30 @@ public: void AdaptDefaultsForChart( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject > & xEmbObj ); + /** Depending on the given request create a new page or duplicate an + existing one. A new page is created behind the given slide. + @param rRequest + The request as passed to an Execute() method. Its arguments are + evaluated. Its slot id determines whether to create or + duplicate a slide. + @param pPage + This page is either duplicated or becomes the predecessor of the + new slide. If NULL a duplication request is ignored. A new + slide is inserted as first slide. + @param nInsertPosition + When -1 (the default) then insert after pPage. Otherwise insert + before the given index (of a standard page). + @return + The new slide is returned. If for some reason a new page can + not be created then NULL is returned. + */ + virtual SdPage* CreateOrDuplicatePage ( + SfxRequest& rRequest, + PageKind ePageKind, + SdPage* pPage, + const sal_Int32 nInsertPosition = -1); + + class Implementation; protected: @@ -539,25 +563,6 @@ protected: virtual void SetZoomFactor( const Fraction &rZoomX, const Fraction &rZoomY ); - /** Depending on the given request create a new page or duplicate an - existing one. A new page is created behind the given slide. - @param rRequest - The request as passed to an Execute() method. Its arguments are - evaluated. Its slot id determines whether to create or - duplicate a slide. - @param pPage - This page is either duplicated or becomes the predecessor of the - new slide. If NULL a duplication request is ignored. A new - slide is inserted as first slide. - @return - The new slide is returned. If for some reason a new page can - not be created then NULL is returned. - */ - virtual SdPage* CreateOrDuplicatePage ( - SfxRequest& rRequest, - PageKind ePageKind, - SdPage* pPage); - private: ::Window* mpParentWindow; /** This window updater is used to keep all relevant windows up to date diff --git a/sd/source/ui/inc/framework/FrameworkHelper.hxx b/sd/source/ui/inc/framework/FrameworkHelper.hxx index 58c663449bbc..6ecdeaf31e7e 100755 --- a/sd/source/ui/inc/framework/FrameworkHelper.hxx +++ b/sd/source/ui/inc/framework/FrameworkHelper.hxx @@ -223,9 +223,18 @@ public: /** Request the activation of the specified task panel in the standard task pane. + @param rsTaskPanelURL + The panel that is to be activated. + @param bEnsureTaskPaneIsVisible + When this is <TRUE/> then the task pane is activated when not + yet active. + When this flag is <FALSE/> then the requested panel + is activated only when the task pane is already active. When it + is not active then this call is silently ignored. */ void RequestTaskPanel ( - const ::rtl::OUString& rsTaskPanelURL); + const ::rtl::OUString& rsTaskPanelURL, + const bool bEnsureTaskPaneIsVisible = true); /** Process a slot call that requests a view shell change. */ diff --git a/sd/source/ui/presenter/PresenterPreviewCache.cxx b/sd/source/ui/presenter/PresenterPreviewCache.cxx index 3f50c6f7a1b7..aa55bc9e07ed 100644..100755 --- a/sd/source/ui/presenter/PresenterPreviewCache.cxx +++ b/sd/source/ui/presenter/PresenterPreviewCache.cxx @@ -64,7 +64,8 @@ public: // CacheContext virtual void NotifyPreviewCreation ( - CacheKey aKey, const ::boost::shared_ptr<BitmapEx>& rPreview); + CacheKey aKey, + const Bitmap& rPreview); virtual bool IsIdle (void); virtual bool IsVisible (CacheKey aKey); virtual const SdrPage* GetPage (CacheKey aKey); @@ -122,7 +123,7 @@ PresenterPreviewCache::PresenterPreviewCache (const Reference<XComponentContext> : PresenterPreviewCacheInterfaceBase(m_aMutex), maPreviewSize(Size(200,200)), mpCacheContext(new PresenterCacheContext()), - mpCache(new PageCache(maPreviewSize, mpCacheContext)) + mpCache(new PageCache(maPreviewSize, false, mpCacheContext)) { (void)rxContext; } @@ -187,7 +188,7 @@ void SAL_CALL PresenterPreviewCache::setPreviewSize ( OSL_ASSERT(mpCache.get()!=NULL); maPreviewSize = Size(rSize.Width, rSize.Height); - mpCache->ChangeSize(maPreviewSize); + mpCache->ChangeSize(maPreviewSize, false); } @@ -209,7 +210,7 @@ Reference<rendering::XBitmap> SAL_CALL PresenterPreviewCache::getSlidePreview ( if (pPage == NULL) throw RuntimeException(); - const BitmapEx aPreview (mpCache->GetPreviewBitmap(pPage, maPreviewSize)); + const BitmapEx aPreview (mpCache->GetPreviewBitmap(pPage,true)); if (aPreview.IsEmpty()) return NULL; else @@ -368,7 +369,7 @@ void PresenterPreviewCache::PresenterCacheContext::RemovePreviewCreationNotifyLi void PresenterPreviewCache::PresenterCacheContext::NotifyPreviewCreation ( CacheKey aKey, - const ::boost::shared_ptr<BitmapEx>& rPreview) + const Bitmap& rPreview) { (void)rPreview; diff --git a/sd/source/ui/slideshow/slideshow.cxx b/sd/source/ui/slideshow/slideshow.cxx index 187d0d5ea715..70777d8a06db 100755 --- a/sd/source/ui/slideshow/slideshow.cxx +++ b/sd/source/ui/slideshow/slideshow.cxx @@ -59,6 +59,7 @@ #include "FactoryIds.hxx" #include "ViewShell.hxx" #include "SlideShowRestarter.hxx" +#include "DrawController.hxx" #include <boost/bind.hpp> using ::com::sun::star::presentation::XSlideShowController; @@ -769,6 +770,16 @@ void SAL_CALL SlideShow::end() throw(RuntimeException) DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>( pViewShell ); if( pDrawViewShell ) pDrawViewShell->SwitchPage( (USHORT)xController->getRestoreSlide() ); + else + { + Reference<XDrawView> xDrawView ( + Reference<XWeak>(&mpCurrentViewShellBase->GetDrawController()), UNO_QUERY); + if (xDrawView.is()) + xDrawView->setCurrentPage( + Reference<XDrawPage>( + mpDoc->GetSdPage(xController->getRestoreSlide(), PK_STANDARD)->getUnoPage(), + UNO_QUERY)); + } } } } @@ -1171,9 +1182,9 @@ void SlideShow::StartFullscreenPresentation( ) // fullscreen. const sal_Int32 nDisplay (GetDisplay()); WorkWindow* pWorkWindow = new FullScreenWorkWindow(this, mpCurrentViewShellBase); + pWorkWindow->SetBackground(Wallpaper(COL_BLACK)); pWorkWindow->StartPresentationMode( TRUE, mpDoc->getPresentationSettings().mbAlwaysOnTop ? PRESENTATION_HIDEALLAPPS : 0, nDisplay); // pWorkWindow->ShowFullScreenMode(FALSE, nDisplay); - pWorkWindow->SetBackground(Wallpaper(COL_BLACK)); if (pWorkWindow->IsVisible()) { diff --git a/sd/source/ui/slideshow/slideshowimpl.cxx b/sd/source/ui/slideshow/slideshowimpl.cxx index 5afcb65ab90c..ee89da143910 100755 --- a/sd/source/ui/slideshow/slideshowimpl.cxx +++ b/sd/source/ui/slideshow/slideshowimpl.cxx @@ -1230,9 +1230,11 @@ void SlideshowImpl::onFirstPaint() { if( mpShowWindow ) { + /* mpShowWindow->SetBackground( Wallpaper( Color( COL_BLACK ) ) ); mpShowWindow->Erase(); mpShowWindow->SetBackground(); + */ } ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx index 1bbecbef3d66..ddb50ea878e0 100755..100644 --- a/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx @@ -33,7 +33,6 @@ #include "SlsBitmapCompressor.hxx" #include "SlsCacheConfiguration.hxx" -#include "taskpane/SlideSorterCacheDisplay.hxx" #include "sdpage.hxx" #include "drawdoc.hxx" @@ -55,8 +54,7 @@ namespace sd { namespace slidesorter { namespace cache { class BitmapCache::CacheEntry { public: - CacheEntry(const ::boost::shared_ptr<BitmapEx>& rpBitmap, - sal_Int32 nLastAccessTime, bool bIsPrecious); + CacheEntry(const Bitmap& rBitmap, sal_Int32 nLastAccessTime, bool bIsPrecious); CacheEntry(sal_Int32 nLastAccessTime, bool bIsPrecious); ~CacheEntry (void) {}; inline void Recycle (const CacheEntry& rEntry); @@ -68,18 +66,26 @@ public: void SetUpToDate (bool bIsUpToDate) { mbIsUpToDate = bIsUpToDate; } sal_Int32 GetAccessTime (void) const { return mnLastAccessTime; } void SetAccessTime (sal_Int32 nAccessTime) { mnLastAccessTime = nAccessTime; } - ::boost::shared_ptr<BitmapEx> GetPreview (void) const { return mpPreview; } - inline void SetPreview (const ::boost::shared_ptr<BitmapEx>& rpPreview); + + Bitmap GetPreview (void) const { return maPreview; } + inline void SetPreview (const Bitmap& rPreview); bool HasPreview (void) const; + + Bitmap GetMarkedPreview (void) const { return maMarkedPreview; } + inline void SetMarkedPreview (const Bitmap& rMarkePreview); + bool HasMarkedPreview (void) const; + bool HasReplacement (void) const { return (mpReplacement.get() != NULL); } inline bool HasLosslessReplacement (void) const; - void Clear (void) { mpPreview.reset(); mpReplacement.reset(); mpCompressor.reset(); } + void Clear (void) { maPreview.SetEmpty(); maMarkedPreview.SetEmpty(); + mpReplacement.reset(); mpCompressor.reset(); } void Invalidate (void) { mpReplacement.reset(); mpCompressor.reset(); mbIsUpToDate = false; } bool IsPrecious (void) const { return mbIsPrecious; } void SetPrecious (bool bIsPrecious) { mbIsPrecious = bIsPrecious; } private: - ::boost::shared_ptr<BitmapEx> mpPreview; + Bitmap maPreview; + Bitmap maMarkedPreview; ::boost::shared_ptr<BitmapReplacement> mpReplacement; ::boost::shared_ptr<BitmapCompressor> mpCompressor; Size maBitmapSize; @@ -221,7 +227,7 @@ bool BitmapCache::BitmapIsUpToDate (const CacheKey& rKey) -::boost::shared_ptr<BitmapEx> BitmapCache::GetBitmap (const CacheKey& rKey) +Bitmap BitmapCache::GetBitmap (const CacheKey& rKey) { ::osl::MutexGuard aGuard (maMutex); @@ -230,10 +236,9 @@ bool BitmapCache::BitmapIsUpToDate (const CacheKey& rKey) { // Create an empty bitmap for the given key that acts as placeholder // until we are given the real one. Mark it as not being up to date. - SetBitmap (rKey, ::boost::shared_ptr<BitmapEx>(new BitmapEx()), false); + SetBitmap(rKey, Bitmap(), false); iEntry = mpBitmapContainer->find(rKey); iEntry->second.SetUpToDate(false); - SSCD_SET_UPTODATE(iEntry->first,false); } else { @@ -253,7 +258,39 @@ bool BitmapCache::BitmapIsUpToDate (const CacheKey& rKey) -void BitmapCache::InvalidateBitmap (const CacheKey& rKey) +Bitmap BitmapCache::GetMarkedBitmap (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end()) + { + iEntry->second.SetAccessTime(mnCurrentAccessTime++); + return iEntry->second.GetMarkedPreview(); + } + else + return Bitmap(); +} + + + + +void BitmapCache::ReleaseBitmap (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator aIterator (mpBitmapContainer->find(rKey)); + if (aIterator != mpBitmapContainer->end()) + { + UpdateCacheSize(aIterator->second, REMOVE); + mpBitmapContainer->erase(aIterator); + } +} + + + + +bool BitmapCache::InvalidateBitmap (const CacheKey& rKey) { ::osl::MutexGuard aGuard (maMutex); @@ -261,7 +298,6 @@ void BitmapCache::InvalidateBitmap (const CacheKey& rKey) if (iEntry != mpBitmapContainer->end()) { iEntry->second.SetUpToDate(false); - SSCD_SET_UPTODATE(iEntry->first,false); // When there is a preview then we release the replacement. The // preview itself is kept until a new one is created. @@ -269,10 +305,12 @@ void BitmapCache::InvalidateBitmap (const CacheKey& rKey) { UpdateCacheSize(iEntry->second, REMOVE); iEntry->second.Invalidate(); - SSCD_SET_UPTODATE(iEntry->first,false); UpdateCacheSize(iEntry->second, ADD); } + return true; } + else + return false; } @@ -286,7 +324,6 @@ void BitmapCache::InvalidateCache (void) for (iEntry=mpBitmapContainer->begin(); iEntry!=mpBitmapContainer->end(); ++iEntry) { iEntry->second.Invalidate(); - SSCD_SET_UPTODATE(iEntry->first,false); } ReCalculateTotalCacheSize(); } @@ -296,7 +333,7 @@ void BitmapCache::InvalidateCache (void) void BitmapCache::SetBitmap ( const CacheKey& rKey, - const ::boost::shared_ptr<BitmapEx>& rpPreview, + const Bitmap& rPreview, bool bIsPrecious) { ::osl::MutexGuard aGuard (maMutex); @@ -305,16 +342,15 @@ void BitmapCache::SetBitmap ( if (iEntry != mpBitmapContainer->end()) { UpdateCacheSize(iEntry->second, REMOVE); - iEntry->second.SetPreview(rpPreview); + iEntry->second.SetPreview(rPreview); iEntry->second.SetUpToDate(true); - SSCD_SET_UPTODATE(iEntry->first,true); iEntry->second.SetAccessTime(mnCurrentAccessTime++); } else { iEntry = mpBitmapContainer->insert(CacheBitmapContainer::value_type ( rKey, - CacheEntry (rpPreview, mnCurrentAccessTime++, bIsPrecious)) + CacheEntry(rPreview, mnCurrentAccessTime++, bIsPrecious)) ).first; } @@ -325,6 +361,25 @@ void BitmapCache::SetBitmap ( +void BitmapCache::SetMarkedBitmap ( + const CacheKey& rKey, + const Bitmap& rPreview) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.SetMarkedPreview(rPreview); + iEntry->second.SetAccessTime(mnCurrentAccessTime++); + UpdateCacheSize(iEntry->second, ADD); + } +} + + + + void BitmapCache::SetPrecious (const CacheKey& rKey, bool bIsPrecious) { ::osl::MutexGuard aGuard (maMutex); @@ -343,9 +398,7 @@ void BitmapCache::SetPrecious (const CacheKey& rKey, bool bIsPrecious) { iEntry = mpBitmapContainer->insert(CacheBitmapContainer::value_type ( rKey, - CacheEntry ( - ::boost::shared_ptr<BitmapEx>(), - mnCurrentAccessTime++, bIsPrecious)) + CacheEntry(Bitmap(), mnCurrentAccessTime++, bIsPrecious)) ).first; UpdateCacheSize(iEntry->second, ADD); } @@ -503,7 +556,8 @@ void BitmapCache::UpdateCacheSize (const CacheEntry& rEntry, CacheOperation eOpe BitmapCache::CacheEntry::CacheEntry( sal_Int32 nLastAccessTime, bool bIsPrecious) - : mpPreview(), + : maPreview(), + maMarkedPreview(), mbIsUpToDate(true), mnLastAccessTime(nLastAccessTime), mbIsPrecious(bIsPrecious) @@ -514,10 +568,11 @@ BitmapCache::CacheEntry::CacheEntry( BitmapCache::CacheEntry::CacheEntry( - const ::boost::shared_ptr<BitmapEx>& rpPreview, + const Bitmap& rPreview, sal_Int32 nLastAccessTime, bool bIsPrecious) - : mpPreview(rpPreview), + : maPreview(rPreview), + maMarkedPreview(), mbIsUpToDate(true), mnLastAccessTime(nLastAccessTime), mbIsPrecious(bIsPrecious) @@ -532,7 +587,8 @@ inline void BitmapCache::CacheEntry::Recycle (const CacheEntry& rEntry) if ((rEntry.HasPreview() || rEntry.HasLosslessReplacement()) && ! (HasPreview() || HasLosslessReplacement())) { - mpPreview = rEntry.mpPreview; + maPreview = rEntry.maPreview; + maMarkedPreview = rEntry.maMarkedPreview; mpReplacement = rEntry.mpReplacement; mpCompressor = rEntry.mpCompressor; mnLastAccessTime = rEntry.mnLastAccessTime; @@ -546,8 +602,8 @@ inline void BitmapCache::CacheEntry::Recycle (const CacheEntry& rEntry) inline sal_Int32 BitmapCache::CacheEntry::GetMemorySize (void) const { sal_Int32 nSize (0); - if (mpPreview.get() != NULL) - nSize += mpPreview->GetSizeBytes(); + nSize += maPreview.GetSizeBytes(); + nSize += maMarkedPreview.GetSizeBytes(); if (mpReplacement.get() != NULL) nSize += mpReplacement->GetMemorySize(); return nSize; @@ -558,14 +614,14 @@ inline sal_Int32 BitmapCache::CacheEntry::GetMemorySize (void) const void BitmapCache::CacheEntry::Compress (const ::boost::shared_ptr<BitmapCompressor>& rpCompressor) { - if (mpPreview.get() != NULL) + if ( ! maPreview.IsEmpty()) { if (mpReplacement.get() == NULL) { - mpReplacement = rpCompressor->Compress(mpPreview); + mpReplacement = rpCompressor->Compress(maPreview); #ifdef VERBOSE - sal_uInt32 nOldSize (mpPreview->GetSizeBytes()); + sal_uInt32 nOldSize (maPreview.GetSizeBytes()); sal_uInt32 nNewSize (mpReplacement.get()!=NULL ? mpReplacement->GetMemorySize() : 0); if (nOldSize == 0) nOldSize = 1; @@ -580,7 +636,8 @@ void BitmapCache::CacheEntry::Compress (const ::boost::shared_ptr<BitmapCompress mpCompressor = rpCompressor; } - mpPreview.reset(); + maPreview.SetEmpty(); + maMarkedPreview.SetEmpty(); } } @@ -589,9 +646,10 @@ void BitmapCache::CacheEntry::Compress (const ::boost::shared_ptr<BitmapCompress inline void BitmapCache::CacheEntry::Decompress (void) { - if (mpReplacement.get()!=NULL && mpCompressor.get()!=NULL && mpPreview.get()==NULL) + if (mpReplacement.get()!=NULL && mpCompressor.get()!=NULL && maPreview.IsEmpty()) { - mpPreview = mpCompressor->Decompress(*mpReplacement); + maPreview = mpCompressor->Decompress(*mpReplacement); + maMarkedPreview.SetEmpty(); if ( ! mpCompressor->IsLossless()) mbIsUpToDate = false; } @@ -599,9 +657,10 @@ inline void BitmapCache::CacheEntry::Decompress (void) -inline void BitmapCache::CacheEntry::SetPreview (const ::boost::shared_ptr<BitmapEx>& rpPreview) +inline void BitmapCache::CacheEntry::SetPreview (const Bitmap& rPreview) { - mpPreview = rpPreview; + maPreview = rPreview; + maMarkedPreview.SetEmpty(); mpReplacement.reset(); mpCompressor.reset(); } @@ -611,10 +670,23 @@ inline void BitmapCache::CacheEntry::SetPreview (const ::boost::shared_ptr<Bitma bool BitmapCache::CacheEntry::HasPreview (void) const { - if (mpPreview.get() != NULL) - return mpPreview->GetSizePixel().Width()>0 && mpPreview->GetSizePixel().Height()>0; - else - return false; + return ! maPreview.IsEmpty(); +} + + + + +inline void BitmapCache::CacheEntry::SetMarkedPreview (const Bitmap& rMarkedPreview) +{ + maMarkedPreview = rMarkedPreview; +} + + + + +bool BitmapCache::CacheEntry::HasMarkedPreview (void) const +{ + return ! maMarkedPreview.IsEmpty(); } diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx index 2c33e042342f..734c630d31ce 100755..100644 --- a/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx @@ -32,8 +32,8 @@ class SdrPage; #include <vcl/bitmapex.hxx> #include <osl/mutex.hxx> -#include <memory> #include <boost/shared_ptr.hpp> +#include <boost/scoped_ptr.hpp> #include <hash_map> namespace sd { namespace slidesorter { namespace cache { @@ -44,10 +44,14 @@ class BitmapCompressor; /** This low level cache is the actual bitmap container. It supports a precious flag for every preview bitmap and keeps track of total sizes - for all previews with as well as those without the flag. The precious - flag is used by compaction algorithms to determine which previews may be - compressed or even discarded and which have to remain in their original - form. The precious flag is usually set for the visible previews. + for all previews with/without this flag. The precious flag is used by + compaction algorithms to determine which previews may be compressed or + even discarded and which have to remain in their original form. The + precious flag is usually set for the visible previews. + + Additionally to the actual preview there is an optional marked preview. + This is used for slides excluded from the slide show which have a preview + that shows a mark (some sort of bitmap overlay) to that effect. */ class BitmapCache { @@ -102,11 +106,25 @@ public: /** Return the preview bitmap for the given contact object. */ - ::boost::shared_ptr<BitmapEx> GetBitmap (const CacheKey& rKey); + Bitmap GetBitmap (const CacheKey& rKey); - /** Mark the specified preview bitmap as not being up-to-date anymore. + /** Return the marked preview bitmap for the given contact object. */ - void InvalidateBitmap (const CacheKey& rKey); + Bitmap GetMarkedBitmap (const CacheKey& rKey); + + /** Release the reference to the preview bitmap that is associated with + the given key. + */ + void ReleaseBitmap (const CacheKey& rKey); + + /** Mark the specified preview bitmap as not being up-to-date + anymore. + @return + When the key references a page in the cache then + return <TRUE/>. When the key is not known then <FALSE/> + is returned. + */ + bool InvalidateBitmap (const CacheKey& rKey); /** Mark all preview bitmaps as not being up-to-date anymore. */ @@ -116,9 +134,15 @@ public: */ void SetBitmap ( const CacheKey& rKey, - const ::boost::shared_ptr<BitmapEx>& rpPreview, + const Bitmap& rPreview, bool bIsPrecious); + /** Add or replace a marked bitmap for the given key. + */ + void SetMarkedBitmap ( + const CacheKey& rKey, + const Bitmap& rPreview); + /** Mark the specified preview bitmap as precious, i.e. that it must not be compressed or otherwise removed from the cache. */ @@ -161,7 +185,7 @@ public: private: mutable ::osl::Mutex maMutex; - ::std::auto_ptr<CacheBitmapContainer> mpBitmapContainer; + ::boost::scoped_ptr<CacheBitmapContainer> mpBitmapContainer; /** Total size of bytes that are occupied by bitmaps in the cache for whom the slides are currently not inside the visible area. diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx index 86fc72885414..e0f950442bb5 100644..100755 --- a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx @@ -47,37 +47,24 @@ class NoBitmapCompression::DummyReplacement : public BitmapReplacement { public: - ::boost::shared_ptr<BitmapEx> mpPreview; + Bitmap maPreview; Size maOriginalSize; - DummyReplacement (const ::boost::shared_ptr<BitmapEx>& rpPreview) : mpPreview(rpPreview) - { - } - - virtual ~DummyReplacement(); - - virtual sal_Int32 GetMemorySize (void) const; + DummyReplacement (const Bitmap& rPreview) : maPreview(rPreview) { } + virtual ~DummyReplacement(void) {} + virtual sal_Int32 GetMemorySize (void) const { return maPreview.GetSizeBytes(); } }; -NoBitmapCompression::DummyReplacement::~DummyReplacement() -{ -} -sal_Int32 NoBitmapCompression::DummyReplacement::GetMemorySize (void) const -{ - return mpPreview->GetSizeBytes(); -} -::boost::shared_ptr<BitmapReplacement> NoBitmapCompression::Compress ( - const ::boost::shared_ptr<BitmapEx>& rpBitmap) const +::boost::shared_ptr<BitmapReplacement> NoBitmapCompression::Compress (const Bitmap& rBitmap) const { - return ::boost::shared_ptr<BitmapReplacement>(new DummyReplacement(rpBitmap)); + return ::boost::shared_ptr<BitmapReplacement>(new DummyReplacement(rBitmap)); } -::boost::shared_ptr<BitmapEx> NoBitmapCompression::Decompress ( - const BitmapReplacement& rBitmapData) const +Bitmap NoBitmapCompression::Decompress (const BitmapReplacement& rBitmapData) const { - return dynamic_cast<const DummyReplacement&>(rBitmapData).mpPreview; + return dynamic_cast<const DummyReplacement&>(rBitmapData).maPreview; } @@ -93,8 +80,7 @@ bool NoBitmapCompression::IsLossless (void) const //===== CompressionByDeletion ================================================= -::boost::shared_ptr<BitmapReplacement> CompressionByDeletion::Compress ( - const ::boost::shared_ptr<BitmapEx>& ) const +::boost::shared_ptr<BitmapReplacement> CompressionByDeletion::Compress (const Bitmap& ) const { return ::boost::shared_ptr<BitmapReplacement>(); } @@ -102,12 +88,11 @@ bool NoBitmapCompression::IsLossless (void) const -::boost::shared_ptr<BitmapEx> CompressionByDeletion::Decompress ( - const BitmapReplacement& ) const +Bitmap CompressionByDeletion::Decompress (const BitmapReplacement& ) const { // Return a NULL pointer. This will eventually lead to a request for // the creation of a new one. - return ::boost::shared_ptr<BitmapEx>(); + return Bitmap(); } @@ -128,11 +113,10 @@ bool CompressionByDeletion::IsLossless (void) const class ResolutionReduction::ResolutionReducedReplacement : public BitmapReplacement { public: - ::boost::shared_ptr<BitmapEx> mpPreview; + Bitmap maPreview; Size maOriginalSize; virtual ~ResolutionReducedReplacement(); - virtual sal_Int32 GetMemorySize (void) const; }; @@ -142,23 +126,20 @@ ResolutionReduction::ResolutionReducedReplacement::~ResolutionReducedReplacement sal_Int32 ResolutionReduction::ResolutionReducedReplacement::GetMemorySize (void) const { - if (mpPreview.get() != NULL) - return mpPreview->GetSizeBytes(); - else - return 0; + return maPreview.GetSizeBytes(); } ::boost::shared_ptr<BitmapReplacement> ResolutionReduction::Compress ( - const ::boost::shared_ptr<BitmapEx>& rpBitmap) const + const Bitmap& rBitmap) const { ResolutionReducedReplacement* pResult = new ResolutionReducedReplacement(); - pResult->mpPreview.reset(new BitmapEx(*rpBitmap)); - Size aSize (rpBitmap->GetSizePixel()); + pResult->maPreview = rBitmap; + Size aSize (rBitmap.GetSizePixel()); pResult->maOriginalSize = aSize; if (aSize.Width()>0 && aSize.Width()<mnWidth) { int nHeight = aSize.Height() * mnWidth / aSize.Width() ; - pResult->mpPreview->Scale(Size(mnWidth,nHeight)); + pResult->maPreview.Scale(Size(mnWidth,nHeight)); } return ::boost::shared_ptr<BitmapReplacement>(pResult); @@ -167,22 +148,21 @@ sal_Int32 ResolutionReduction::ResolutionReducedReplacement::GetMemorySize (void -::boost::shared_ptr<BitmapEx> ResolutionReduction::Decompress ( - const BitmapReplacement& rBitmapData) const +Bitmap ResolutionReduction::Decompress (const BitmapReplacement& rBitmapData) const { - ::boost::shared_ptr<BitmapEx> pResult; + Bitmap aResult; const ResolutionReducedReplacement* pData ( dynamic_cast<const ResolutionReducedReplacement*>(&rBitmapData)); - if (pData->mpPreview.get() != NULL) + if ( ! pData->maPreview.IsEmpty()) { - pResult.reset(new BitmapEx(*pData->mpPreview)); + aResult = pData->maPreview; if (pData->maOriginalSize.Width() > mnWidth) - pResult->Scale(pData->maOriginalSize); + aResult.Scale(pData->maOriginalSize); } - return pResult; + return aResult; } @@ -223,15 +203,14 @@ public: -::boost::shared_ptr<BitmapReplacement> PngCompression::Compress ( - const ::boost::shared_ptr<BitmapEx>& rpBitmap) const +::boost::shared_ptr<BitmapReplacement> PngCompression::Compress (const Bitmap& rBitmap) const { - ::vcl::PNGWriter aWriter (*rpBitmap); + ::vcl::PNGWriter aWriter (rBitmap); SvMemoryStream aStream (32768, 32768); aWriter.Write(aStream); PngReplacement* pResult = new PngReplacement(); - pResult->maImageSize = rpBitmap->GetSizePixel(); + pResult->maImageSize = rBitmap.GetSizePixel(); pResult->mnDataSize = aStream.Tell(); pResult->mpData = new char[pResult->mnDataSize]; memcpy(pResult->mpData, aStream.GetData(), pResult->mnDataSize); @@ -242,21 +221,19 @@ public: -::boost::shared_ptr<BitmapEx> PngCompression::Decompress ( +Bitmap PngCompression::Decompress ( const BitmapReplacement& rBitmapData) const { - BitmapEx* pResult = NULL; + Bitmap aResult; const PngReplacement* pData (dynamic_cast<const PngReplacement*>(&rBitmapData)); if (pData != NULL) { SvMemoryStream aStream (pData->mpData, pData->mnDataSize, STREAM_READ); ::vcl::PNGReader aReader (aStream); - pResult = new BitmapEx(aReader.Read()); + aResult = aReader.Read().GetBitmap(); } -// sal_Int32 nRatio ((100L * (ULONG)pResult->GetSizeBytes()) / (ULONG)pData->mnDataSize); - - return ::boost::shared_ptr<BitmapEx>(pResult); + return aResult; } diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx index cd564ddddcfd..35184449bfe2 100644..100755 --- a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx @@ -32,7 +32,8 @@ #include <tools/gen.hxx> #include <boost/shared_ptr.hpp> -class BitmapEx; + +class Bitmap; namespace sd { namespace slidesorter { namespace cache { @@ -48,8 +49,7 @@ public: /** Compress the given bitmap into a replacement format that is specific to the compressor class. */ - virtual ::boost::shared_ptr<BitmapReplacement> Compress ( - const ::boost::shared_ptr<BitmapEx>& rpBitmap) const = 0; + virtual ::boost::shared_ptr<BitmapReplacement> Compress (const Bitmap& rBitmap) const = 0; /** Decompress the given replacement data into a preview bitmap. Depending on the compression technique the returned bitmap may @@ -58,7 +58,7 @@ public: task of the caller to create a new preview bitmap if the returned one is not as desired. */ - virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData)const=0; + virtual Bitmap Decompress (const BitmapReplacement& rBitmapData)const=0; /** Return whether the compression and decompression is lossless. This value is used by the caller of Decompress() to decide whether to use @@ -91,9 +91,8 @@ class NoBitmapCompression { class DummyReplacement; public: - virtual ::boost::shared_ptr<BitmapReplacement> Compress ( - const ::boost::shared_ptr<BitmapEx>& rpBitmap) const; - virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData) const; + virtual ::boost::shared_ptr<BitmapReplacement> Compress (const Bitmap& rpBitmap) const; + virtual Bitmap Decompress (const BitmapReplacement& rBitmapData) const; virtual bool IsLossless (void) const; }; @@ -109,9 +108,8 @@ class CompressionByDeletion : public BitmapCompressor { public: - virtual ::boost::shared_ptr<BitmapReplacement> Compress ( - const ::boost::shared_ptr<BitmapEx>& rpBitmap) const; - virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData) const; + virtual ::boost::shared_ptr<BitmapReplacement> Compress (const Bitmap& rBitmap) const; + virtual Bitmap Decompress (const BitmapReplacement& rBitmapData) const; virtual bool IsLossless (void) const; }; @@ -129,11 +127,10 @@ class ResolutionReduction class ResolutionReducedReplacement; static const sal_Int32 mnWidth = 100; public: - virtual ::boost::shared_ptr<BitmapReplacement> Compress ( - const ::boost::shared_ptr<BitmapEx>& rpBitmap) const; + virtual ::boost::shared_ptr<BitmapReplacement> Compress (const Bitmap& rpBitmap) const; /** Scale the replacement bitmap up to the original size. */ - virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData) const; + virtual Bitmap Decompress (const BitmapReplacement& rBitmapData) const; virtual bool IsLossless (void) const; }; @@ -148,9 +145,8 @@ class PngCompression { class PngReplacement; public: - virtual ::boost::shared_ptr<BitmapReplacement> Compress ( - const ::boost::shared_ptr<BitmapEx>& rpBitmap) const; - virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData) const; + virtual ::boost::shared_ptr<BitmapReplacement> Compress (const Bitmap& rBitmap) const; + virtual Bitmap Decompress (const BitmapReplacement& rBitmapData) const; virtual bool IsLossless (void) const; }; diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx index 5ad30ef43c1f..8abba77faf4f 100644..100755 --- a/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx +++ b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx @@ -24,8 +24,6 @@ * for a copy of the LGPLv3 License. * ************************************************************************/ -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_sd.hxx" #include "precompiled_sd.hxx" @@ -33,12 +31,19 @@ #include "PreviewRenderer.hxx" #include "view/SlideSorterView.hxx" -#include "view/SlsPageObjectViewObjectContact.hxx" #include "sdpage.hxx" #include "Window.hxx" +#include <drawdoc.hxx> +#include "DrawDocShell.hxx" #include <svx/svdtypes.hxx> #include <svx/svdpage.hxx> #include <vcl/bitmapex.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/pngwrite.hxx> + +const static sal_Int32 gnSuperSampleFactor (2); +const static bool gbAllowSuperSampling (false); + namespace sd { namespace slidesorter { namespace view { class SlideSorterView; @@ -48,7 +53,7 @@ class PageObjectViewObjectContact; namespace sd { namespace slidesorter { namespace cache { BitmapFactory::BitmapFactory (void) - : maRenderer(NULL,false) + : maRenderer(NULL, false) { } @@ -62,16 +67,30 @@ BitmapFactory::~BitmapFactory (void) -::boost::shared_ptr<BitmapEx> BitmapFactory::CreateBitmap ( +Bitmap BitmapFactory::CreateBitmap ( const SdPage& rPage, - const Size& rPixelSize) + const Size& rPixelSize, + const bool bDoSuperSampling) { - Image aPreview (maRenderer.RenderPage ( + Size aSize (rPixelSize); + if (bDoSuperSampling && gbAllowSuperSampling) + { + aSize.Width() *= gnSuperSampleFactor; + aSize.Height() *= gnSuperSampleFactor; + } + + Bitmap aPreview (maRenderer.RenderPage ( &rPage, - rPixelSize, - String())); - - return ::boost::shared_ptr<BitmapEx>(new BitmapEx(aPreview.GetBitmapEx())); + aSize, + String(), + true, + false).GetBitmapEx().GetBitmap()); + if (bDoSuperSampling && gbAllowSuperSampling) + { + aPreview.Scale(rPixelSize, BMP_SCALE_INTERPOLATE); + } + + return aPreview; } diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx index 87cd1f268f80..7e6aca940ec6 100644..100755 --- a/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx +++ b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx @@ -31,7 +31,6 @@ #include "PreviewRenderer.hxx" #include <boost/shared_ptr.hpp> -class BitmapEx; class SdPage; class Size; @@ -50,9 +49,10 @@ public: BitmapFactory (void); ~BitmapFactory (void); - ::boost::shared_ptr<BitmapEx> CreateBitmap ( + Bitmap CreateBitmap ( const SdPage& rPage, - const Size& rPixelSize); + const Size& rPixelSize, + const bool bDoSuperSampling); private: PreviewRenderer maRenderer; diff --git a/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx index 780a429df29e..f7fb30a4c6ec 100755..100644 --- a/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx +++ b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx @@ -24,8 +24,6 @@ * for a copy of the LGPLv3 License. * ************************************************************************/ -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_sd.hxx" #include "precompiled_sd.hxx" @@ -37,20 +35,27 @@ #include "cache/SlsPageCacheManager.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageDescriptor.hxx" -#include "view/SlsPageObjectViewObjectContact.hxx" #include "controller/SlideSorterController.hxx" + namespace sd { namespace slidesorter { namespace cache { GenericPageCache::GenericPageCache ( const Size& rPreviewSize, + const bool bDoSuperSampling, const SharedCacheContext& rpCacheContext) : mpBitmapCache(), maRequestQueue(rpCacheContext), mpQueueProcessor(), mpCacheContext(rpCacheContext), - maPreviewSize(rPreviewSize) + maPreviewSize(rPreviewSize), + mbDoSuperSampling(bDoSuperSampling) { + // A large size may indicate an error of the caller. After all we + // are creating previews. + DBG_ASSERT (maPreviewSize.Width()<1000 && maPreviewSize.Height()<1000, + "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width. " + "This may indicate an error."); } @@ -58,14 +63,12 @@ GenericPageCache::GenericPageCache ( GenericPageCache::~GenericPageCache (void) { - OSL_TRACE("terminating queue processor %p", mpQueueProcessor.get()); if (mpQueueProcessor.get() != NULL) mpQueueProcessor->Stop(); maRequestQueue.Clear(); if (mpQueueProcessor.get() != NULL) mpQueueProcessor->Terminate(); mpQueueProcessor.reset(); - OSL_TRACE("queue processor stopped and terminated"); if (mpBitmapCache.get() != NULL) PageCacheManager::Instance()->ReleaseCache(mpBitmapCache); @@ -87,62 +90,69 @@ void GenericPageCache::ProvideCacheAndProcessor (void) maRequestQueue, mpBitmapCache, maPreviewSize, + mbDoSuperSampling, mpCacheContext)); } -void GenericPageCache::ChangePreviewSize (const Size& rPreviewSize) +void GenericPageCache::ChangePreviewSize ( + const Size& rPreviewSize, + const bool bDoSuperSampling) { - if (rPreviewSize != maPreviewSize) + if (rPreviewSize!=maPreviewSize || bDoSuperSampling!=mbDoSuperSampling) { + // A large size may indicate an error of the caller. After all we + // are creating previews. + DBG_ASSERT (maPreviewSize.Width()<1000 && maPreviewSize.Height()<1000, + "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width. " + "This may indicate an error."); + if (mpBitmapCache.get() != NULL) { mpBitmapCache = PageCacheManager::Instance()->ChangeSize( mpBitmapCache, maPreviewSize, rPreviewSize); if (mpQueueProcessor.get() != NULL) { - mpQueueProcessor->SetPreviewSize(rPreviewSize); + mpQueueProcessor->SetPreviewSize(rPreviewSize, bDoSuperSampling); mpQueueProcessor->SetBitmapCache(mpBitmapCache); } } maPreviewSize = rPreviewSize; + mbDoSuperSampling = bDoSuperSampling; } } -BitmapEx GenericPageCache::GetPreviewBitmap ( - CacheKey aKey, - const Size& rSize) +Bitmap GenericPageCache::GetPreviewBitmap ( + const CacheKey aKey, + const bool bResize) { OSL_ASSERT(aKey != NULL); - BitmapEx aPreview; + Bitmap aPreview; bool bMayBeUpToDate = true; ProvideCacheAndProcessor(); const SdrPage* pPage = mpCacheContext->GetPage(aKey); if (mpBitmapCache->HasBitmap(pPage)) { - ::boost::shared_ptr<BitmapEx> pPreview(mpBitmapCache->GetBitmap(pPage)); - OSL_ASSERT(pPreview.get() != NULL); - aPreview = *pPreview; - Size aBitmapSize (aPreview.GetSizePixel()); - if (aBitmapSize != rSize) + aPreview = mpBitmapCache->GetBitmap(pPage); + const Size aBitmapSize (aPreview.GetSizePixel()); + if (aBitmapSize != maPreviewSize) { - // The bitmap has the wrong size. - DBG_ASSERT (rSize.Width() < 1000, - "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width. " - "This may indicate an error."); - // Scale the bitmap to the desired size when that is possible, // i.e. the bitmap is not empty. - if (aBitmapSize.Width()>0 && aBitmapSize.Height()>0) - aPreview.Scale (rSize, BMP_SCALE_FAST); + if (bResize && aBitmapSize.Width()>0 && aBitmapSize.Height()>0) + { + aPreview.Scale(maPreviewSize, BMP_SCALE_FAST); + } + bMayBeUpToDate = false; } - bMayBeUpToDate = true; + else + bMayBeUpToDate = true; } else bMayBeUpToDate = false; @@ -150,7 +160,7 @@ BitmapEx GenericPageCache::GetPreviewBitmap ( // Request the creation of a correctly sized preview bitmap. We do this // even when the size of the bitmap in the cache is correct because its // content may be not up-to-date anymore. - RequestPreviewBitmap(aKey, rSize, bMayBeUpToDate); + RequestPreviewBitmap(aKey, bMayBeUpToDate); return aPreview; } @@ -158,10 +168,49 @@ BitmapEx GenericPageCache::GetPreviewBitmap ( +Bitmap GenericPageCache::GetMarkedPreviewBitmap ( + const CacheKey aKey, + const bool bResize) +{ + OSL_ASSERT(aKey != NULL); + + ProvideCacheAndProcessor(); + const SdrPage* pPage = mpCacheContext->GetPage(aKey); + Bitmap aMarkedPreview (mpBitmapCache->GetMarkedBitmap(pPage)); + const Size aBitmapSize (aMarkedPreview.GetSizePixel()); + if (bResize && aBitmapSize != maPreviewSize) + { + // Scale the bitmap to the desired size when that is possible, + // i.e. the bitmap is not empty. + if (aBitmapSize.Width()>0 && aBitmapSize.Height()>0) + { + aMarkedPreview.Scale(maPreviewSize, BMP_SCALE_FAST); + } + } + + return aMarkedPreview; +} + + + + +void GenericPageCache::SetMarkedPreviewBitmap ( + const CacheKey aKey, + const Bitmap& rMarkedBitmap) +{ + OSL_ASSERT(aKey != NULL); + + ProvideCacheAndProcessor(); + const SdrPage* pPage = mpCacheContext->GetPage(aKey); + mpBitmapCache->SetMarkedBitmap(pPage, rMarkedBitmap); +} + + + + void GenericPageCache::RequestPreviewBitmap ( - CacheKey aKey, - const Size& rSize, - bool bMayBeUpToDate) + const CacheKey aKey, + const bool bMayBeUpToDate) { OSL_ASSERT(aKey != NULL); @@ -175,8 +224,8 @@ void GenericPageCache::RequestPreviewBitmap ( bIsUpToDate = mpBitmapCache->BitmapIsUpToDate (pPage); if (bIsUpToDate) { - ::boost::shared_ptr<BitmapEx> pPreview (mpBitmapCache->GetBitmap(pPage)); - if (pPreview.get()==NULL || pPreview->GetSizePixel()!=rSize) + const Bitmap aPreview (mpBitmapCache->GetBitmap(pPage)); + if (aPreview.IsEmpty() || aPreview.GetSizePixel()!=maPreviewSize) bIsUpToDate = false; } @@ -199,7 +248,25 @@ void GenericPageCache::RequestPreviewBitmap ( -void GenericPageCache::ReleasePreviewBitmap (CacheKey aKey) +bool GenericPageCache::InvalidatePreviewBitmap (const CacheKey aKey) +{ + // Invalidate the page in all caches that reference it, not just this one. + ::boost::shared_ptr<cache::PageCacheManager> pCacheManager ( + cache::PageCacheManager::Instance()); + if (pCacheManager) + return pCacheManager->InvalidatePreviewBitmap( + mpCacheContext->GetModel(), + aKey); + else if (mpBitmapCache.get() != NULL) + return mpBitmapCache->InvalidateBitmap(mpCacheContext->GetPage(aKey)); + else + return false; +} + + + + +void GenericPageCache::ReleasePreviewBitmap (const CacheKey aKey) { if (mpBitmapCache.get() != NULL) { @@ -233,9 +300,9 @@ void GenericPageCache::ReleasePreviewBitmap (CacheKey aKey) -void GenericPageCache::InvalidateCache (bool bUpdateCache) +void GenericPageCache::InvalidateCache (const bool bUpdateCache) { - if (mpBitmapCache.get() != NULL) + if (mpBitmapCache) { // When the cache is being invalidated then it makes no sense to // continue creating preview bitmaps. However, this may be @@ -255,7 +322,9 @@ void GenericPageCache::InvalidateCache (bool bUpdateCache) -void GenericPageCache::SetPreciousFlag (CacheKey aKey, bool bIsPrecious) +void GenericPageCache::SetPreciousFlag ( + const CacheKey aKey, + const bool bIsPrecious) { ProvideCacheAndProcessor(); diff --git a/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx index 89fc657004e8..96636576f79a 100755..100644 --- a/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx +++ b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx @@ -30,8 +30,6 @@ #include "SlideSorter.hxx" #include "SlsRequestQueue.hxx" -#include "SlsQueueProcessor.hxx" -#include <boost/function.hpp> #include <boost/scoped_ptr.hpp> namespace sd { namespace slidesorter { namespace cache { @@ -44,12 +42,18 @@ class QueueProcessor; class GenericPageCache { public: - /** The page chache is created with references both to the SlideSorter. - This allows access to both view and model and the cache can so fill - itself with requests for all or just the visible pages. + /** The page chache is created with a reference to the SlideSorter and + thus has access to both view and model. This allows the cache to + fill itself with requests for all pages or just the visible ones. + @param rPreviewSize + The size of the previews is expected in pixel values. + @param bDoSuperSampling + When <TRUE/> the previews are rendered larger and then scaled + down to the requested size to improve image quality. */ GenericPageCache ( const Size& rPreviewSize, + const bool bDoSuperSampling, const SharedCacheContext& rpCacheContext); ~GenericPageCache (void); @@ -58,10 +62,12 @@ public: resize of the slide sorter window or a change of the number of columns. */ - void ChangePreviewSize (const Size& rPreviewSize); + void ChangePreviewSize ( + const Size& rPreviewSize, + const bool bDoSuperSampling); /** Request a preview bitmap for the specified page object in the - specified size. The returned bitmap may be preview of the preview, + specified size. The returned bitmap may be a preview of the preview, i.e. either a scaled (up or down) version of a previous preview (of the wrong size) or an empty bitmap. In this case a request for the generation of a new preview is created and inserted into the request @@ -70,53 +76,67 @@ public: receives the correctly sized preview bitmap. @param rRequestData This data is used to determine the preview. - @param rSize - The size of the requested preview bitmap. + @param bResize + When <TRUE/> then when the available bitmap has not the + requested size, it is scaled before it is returned. When + <FALSE/> then the bitmap is returned in the wrong size and it is + the task of the caller to scale it. @return Returns a bitmap that is either empty, contains a scaled (up or down) version or is the requested bitmap. */ - BitmapEx GetPreviewBitmap ( - CacheKey aKey, - const Size& rSize); + Bitmap GetPreviewBitmap ( + const CacheKey aKey, + const bool bResize); + Bitmap GetMarkedPreviewBitmap ( + const CacheKey aKey, + const bool bResize); + void SetMarkedPreviewBitmap ( + const CacheKey aKey, + const Bitmap& rMarkedBitmap); /** When the requested preview bitmap does not yet exist or is not up-to-date then the rendering of one is scheduled. Otherwise this method does nothing. @param rRequestData This data is used to determine the preview. - @param rSize - The size of the requested preview bitmap in pixel coordinates. @param bMayBeUpToDate This flag helps the method to determine whether an existing preview that matches the request is up to date. If the caller - know that it is not then by passing <FALSE/> he tells us that we + knows that it is not then by passing <FALSE/> he tells us that we do not have to check the up-to-date flag a second time. If - unsure pass <TRUE/>. + unsure use <TRUE/>. */ void RequestPreviewBitmap ( - CacheKey aKey, - const Size& rSize, - bool bMayBeUpToDate = true); + const CacheKey aKey, + const bool bMayBeUpToDate = true); + + /** Tell the cache to replace the bitmap associated with the given + request data with a new one that reflects recent changes in the + content of the page object. + @return + When the key is kown then return <TRUE/>. + */ + bool InvalidatePreviewBitmap (const CacheKey aKey); /** Call this method when a view-object-contact object is being deleted and does not need (a) its current bitmap in the cache and (b) a requested a new bitmap. */ - void ReleasePreviewBitmap (CacheKey aKey); + void ReleasePreviewBitmap (const CacheKey aKey); /** Call this method when all preview bitmaps have to be generated anew. This is the case when the size of the page objects on the screen has changed or when the model has changed. */ - void InvalidateCache (bool bUpdateCache); + void InvalidateCache (const bool bUpdateCache); /** With the precious flag you can control whether a bitmap can be removed from the cache or reduced in size to make room for other bitmaps or is so precious that it will not be touched. A typical use is to set the precious flag for the visible pages. */ - void SetPreciousFlag (CacheKey aKey, bool bIsPrecious); + void SetPreciousFlag (const CacheKey aKey, const bool bIsPrecious); void Pause (void); void Resume (void); @@ -134,6 +154,8 @@ private: */ Size maPreviewSize; + bool mbDoSuperSampling; + /** Both bitmap cache and queue processor are created on demand by this method. */ diff --git a/sd/source/ui/slidesorter/cache/SlsPageCache.cxx b/sd/source/ui/slidesorter/cache/SlsPageCache.cxx index 714e1f008329..e51630ec79ac 100755..100644 --- a/sd/source/ui/slidesorter/cache/SlsPageCache.cxx +++ b/sd/source/ui/slidesorter/cache/SlsPageCache.cxx @@ -44,10 +44,12 @@ namespace sd { namespace slidesorter { namespace cache { PageCache::PageCache ( const Size& rPreviewSize, + const bool bDoSuperSampling, const SharedCacheContext& rpCacheContext) : mpImplementation( new GenericPageCache( rPreviewSize, + bDoSuperSampling, rpCacheContext)) { } @@ -62,26 +64,66 @@ PageCache::~PageCache (void) -void PageCache::ChangeSize(const Size& rPreviewSize) +void PageCache::ChangeSize ( + const Size& rPreviewSize, + const bool bDoSuperSampling) +{ + mpImplementation->ChangePreviewSize(rPreviewSize, bDoSuperSampling); +} + + + + +Bitmap PageCache::GetPreviewBitmap ( + const CacheKey aKey, + const bool bResize) +{ + return mpImplementation->GetPreviewBitmap(aKey, bResize); +} + + + + +Bitmap PageCache::GetMarkedPreviewBitmap ( + const CacheKey aKey, + const bool bResize) +{ + return mpImplementation->GetMarkedPreviewBitmap(aKey, bResize); +} + + + + +void PageCache::SetMarkedPreviewBitmap ( + const CacheKey aKey, + const Bitmap& rMarkedBitmap) +{ + mpImplementation->SetMarkedPreviewBitmap(aKey, rMarkedBitmap); +} + + + + +void PageCache::RequestPreviewBitmap (const CacheKey aKey) { - mpImplementation->ChangePreviewSize(rPreviewSize); + return mpImplementation->RequestPreviewBitmap(aKey); } -BitmapEx PageCache::GetPreviewBitmap ( - CacheKey aKey, - const Size& rSize) +void PageCache::InvalidatePreviewBitmap ( + const CacheKey aKey, + const bool bRequestPreview) { - return mpImplementation->GetPreviewBitmap(aKey, rSize); + if (mpImplementation->InvalidatePreviewBitmap(aKey) && bRequestPreview) + RequestPreviewBitmap(aKey); } -void PageCache::ReleasePreviewBitmap ( - CacheKey aKey) +void PageCache::ReleasePreviewBitmap (const CacheKey aKey) { mpImplementation->ReleasePreviewBitmap(aKey); } @@ -89,7 +131,7 @@ void PageCache::ReleasePreviewBitmap ( -void PageCache::InvalidateCache (bool bUpdateCache) +void PageCache::InvalidateCache (const bool bUpdateCache) { mpImplementation->InvalidateCache(bUpdateCache); } @@ -98,8 +140,8 @@ void PageCache::InvalidateCache (bool bUpdateCache) void PageCache::SetPreciousFlag ( - CacheKey aKey, - bool bIsPrecious) + const CacheKey aKey, + const bool bIsPrecious) { mpImplementation->SetPreciousFlag(aKey, bIsPrecious); } diff --git a/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx b/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx index 3c8a15892e7c..e3083ecb4aaf 100644..100755 --- a/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx +++ b/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx @@ -325,7 +325,6 @@ void PageCacheManager::ReleaseCache (const ::boost::shared_ptr<Cache>& rpCache) mpPageCaches->begin(), mpPageCaches->end(), PageCacheContainer::CompareWithCache(rpCache))); - OSL_ASSERT(iCacheToChange != mpPageCaches->end()); if (iCacheToChange != mpPageCaches->end()) { OSL_ASSERT(iCacheToChange->second == rpCache); @@ -342,6 +341,10 @@ void PageCacheManager::ReleaseCache (const ::boost::shared_ptr<Cache>& rpCache) pResult = rpCache; } + else + { + OSL_ASSERT(iCacheToChange != mpPageCaches->end()); + } } return pResult; @@ -350,10 +353,12 @@ void PageCacheManager::ReleaseCache (const ::boost::shared_ptr<Cache>& rpCache) -void PageCacheManager::InvalidatePreviewBitmap ( +bool PageCacheManager::InvalidatePreviewBitmap ( DocumentKey pDocument, const SdrPage* pKey) { + bool bHasChanged (false); + if (pDocument!=NULL) { // Iterate over all caches that are currently in use and invalidate @@ -361,7 +366,7 @@ void PageCacheManager::InvalidatePreviewBitmap ( PageCacheContainer::iterator iCache; for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end(); ++iCache) if (iCache->first.mpDocument == pDocument) - iCache->second->InvalidateBitmap(pKey); + bHasChanged |= iCache->second->InvalidateBitmap(pKey); // Invalidate the previews in the recently used caches belonging to // the given document. @@ -370,9 +375,37 @@ void PageCacheManager::InvalidatePreviewBitmap ( { RecentlyUsedQueue::const_iterator iCache2; for (iCache2=iQueue->second.begin(); iCache2!=iQueue->second.end(); ++iCache2) - iCache2->mpCache->InvalidateBitmap(pKey); + bHasChanged |= iCache2->mpCache->InvalidateBitmap(pKey); } } + + return bHasChanged; +} + + + + +void PageCacheManager::InvalidateAllPreviewBitmaps (DocumentKey pDocument) +{ + if (pDocument == NULL) + return; + + // Iterate over all caches that are currently in use and invalidate the + // previews in those that belong to the document. + PageCacheContainer::iterator iCache; + for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end(); ++iCache) + if (iCache->first.mpDocument == pDocument) + iCache->second->InvalidateCache(); + + // Invalidate the previews in the recently used caches belonging to the + // given document. + RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument)); + if (iQueue != mpRecentlyUsedPageCaches->end()) + { + RecentlyUsedQueue::const_iterator iCache2; + for (iCache2=iQueue->second.begin(); iCache2!=iQueue->second.end(); ++iCache2) + iCache2->mpCache->InvalidateCache(); + } } @@ -394,6 +427,16 @@ void PageCacheManager::InvalidateAllCaches (void) +void PageCacheManager::ReleasePreviewBitmap (const SdrPage* pPage) +{ + PageCacheContainer::iterator iCache; + for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end(); ++iCache) + iCache->second->ReleaseBitmap(pPage); +} + + + + ::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::GetRecentlyUsedCache ( DocumentKey pDocument, const Size& rPreviewSize) diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx index bec9c7fa369d..86d20d6c8924 100755 --- a/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx +++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx @@ -40,6 +40,7 @@ QueueProcessor::QueueProcessor ( RequestQueue& rQueue, const ::boost::shared_ptr<BitmapCache>& rpCache, const Size& rPreviewSize, + const bool bDoSuperSampling, const SharedCacheContext& rpCacheContext) : maMutex(), maTimer(), @@ -47,6 +48,7 @@ QueueProcessor::QueueProcessor ( mnTimeBetweenLowPriorityRequests (100/*ms*/), mnTimeBetweenRequestsWhenNotIdle (1000/*ms*/), maPreviewSize(rPreviewSize), + mbDoSuperSampling(bDoSuperSampling), mpCacheContext(rpCacheContext), mrQueue(rQueue), mpCache(rpCache), @@ -136,9 +138,12 @@ void QueueProcessor::Terminate (void) -void QueueProcessor::SetPreviewSize (const Size& rPreviewSize) +void QueueProcessor::SetPreviewSize ( + const Size& rPreviewSize, + const bool bDoSuperSampling) { maPreviewSize = rPreviewSize; + mbDoSuperSampling = bDoSuperSampling; } @@ -207,15 +212,12 @@ void QueueProcessor::ProcessOneRequest ( const SdPage* pSdPage = dynamic_cast<const SdPage*>(mpCacheContext->GetPage(aKey)); if (pSdPage != NULL) { - const ::boost::shared_ptr<BitmapEx> pPreview ( - maBitmapFactory.CreateBitmap(*pSdPage, maPreviewSize)); - mpCache->SetBitmap ( - pSdPage, - pPreview, - ePriorityClass!=NOT_VISIBLE); + const Bitmap aPreview ( + maBitmapFactory.CreateBitmap(*pSdPage, maPreviewSize, mbDoSuperSampling)); + mpCache->SetBitmap (pSdPage, aPreview, ePriorityClass!=NOT_VISIBLE); // Initiate a repaint of the new preview. - mpCacheContext->NotifyPreviewCreation(aKey, pPreview); + mpCacheContext->NotifyPreviewCreation(aKey, aPreview); } } } diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx index e42ad092d0e2..f84b774c4280 100644..100755 --- a/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx +++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx @@ -31,9 +31,7 @@ #include "cache/SlsPageCache.hxx" #include "SlsRequestPriorityClass.hxx" #include "SlsBitmapFactory.hxx" -#include "view/SlsPageObject.hxx" #include "view/SlideSorterView.hxx" -#include "view/SlsPageObjectViewObjectContact.hxx" #include "tools/IdleDetection.hxx" #include "SlsBitmapCache.hxx" #include "sdpage.hxx" @@ -71,6 +69,7 @@ public: RequestQueue& rQueue, const ::boost::shared_ptr<BitmapCache>& rpCache, const Size& rPreviewSize, + const bool bDoSuperSampling, const SharedCacheContext& rpCacheContext); virtual ~QueueProcessor(); @@ -90,7 +89,9 @@ public: void Terminate (void); - void SetPreviewSize (const Size& rSize); + void SetPreviewSize ( + const Size& rSize, + const bool bDoSuperSampling); /** As we can not really terminate the rendering of a preview bitmap for a request in midair this method acts more like a semaphor. It @@ -118,6 +119,7 @@ private: sal_uInt32 mnTimeBetweenLowPriorityRequests; sal_uInt32 mnTimeBetweenRequestsWhenNotIdle; Size maPreviewSize; + bool mbDoSuperSampling; SharedCacheContext mpCacheContext; RequestQueue& mrQueue; ::boost::shared_ptr<BitmapCache> mpCache; diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx index 08ca63284ea6..e813a5ac5f2b 100644..100755 --- a/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx +++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx @@ -128,7 +128,6 @@ template <class Queue, class Request, class Cache, class Factory> mrQueue (rQueue), mrCache (rCache) { - OSL_TRACE("QueueProcessorThread::constructor %p", this); create(); } @@ -139,7 +138,6 @@ template <class Queue, class Request, class Cache, class Factory> QueueProcessorThread<Queue, Request, Cache, Factory> ::~QueueProcessorThread (void) { - OSL_TRACE("QueueProcessorThread::destructor %p", this); } @@ -148,16 +146,12 @@ template <class Queue, class Request, class Cache, class Factory> template <class Queue, class Request, class Cache, class Factory> void SAL_CALL QueueProcessorThread<Queue, Request, Cache, Factory>::run (void) { - OSL_TRACE("QueueProcessorThread::run(): running thread %p", this); while ( ! mbIsTerminated) { - OSL_TRACE("QueueProcessorThread::run(): still running thread %p: %d", this, mbIsTerminated?1:0); if (mrQueue.IsEmpty()) { // Sleep while the queue is empty. - OSL_TRACE("QueueProcessorThread::run(): suspending thread %p", this); suspend(); - OSL_TRACE("QueueProcessorThread::run(): running again thread %p", this); } else if (GetpApp()->AnyInput()) @@ -168,19 +162,15 @@ void SAL_CALL QueueProcessorThread<Queue, Request, Cache, Factory>::run (void) TimeValue aTimeToWait; aTimeToWait.Seconds = 0; aTimeToWait.Nanosec = 50*1000*1000; - OSL_TRACE("QueueProcessorThread::run(): input pending: waiting %d nanoseconds", - aTimeToWait.Nanosec); wait (aTimeToWait); } else { - OSL_TRACE ("QueueProcessorThread::run(): Processing Query"); ProcessQueueEntry(); yield (); } } - OSL_TRACE("QueueProcessorThread::run(): exiting run %p", this); } @@ -196,7 +186,6 @@ void QueueProcessorThread<Queue, Request, Cache, Factory> do { - OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry(): testing for mbIsTerminated %p", this); { ::osl::MutexGuard aGuard (maMutex); if (mbIsTerminated) @@ -204,7 +193,6 @@ void QueueProcessorThread<Queue, Request, Cache, Factory> if (mrQueue.IsEmpty()) break; } - OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry():acquiring mutex for bitmap creation %p", this); ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); ::osl::MutexGuard aGuard (maMutex); if (mbIsTerminated) @@ -213,18 +201,12 @@ void QueueProcessorThread<Queue, Request, Cache, Factory> if (mrQueue.IsEmpty()) break; - OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry(): have mutexes %p", this); - // Get the requeuest with the highest priority from the queue. nPriorityClass = mrQueue.GetFrontPriorityClass(); pRequest = &mrQueue.GetFront(); mrQueue.PopFront(); bRequestIsValid = true; - - OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry():using request %p for creating bitmap", pRequest); - OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry():processing request for page %d with priority class ", - pRequest->GetPage()->GetPageNum(), nPriorityClass); try { // Create a new preview bitmap and store it in the cache. @@ -260,7 +242,6 @@ void QueueProcessorThread< Queue, RequestData, BitmapCache, BitmapFactory >::Start (void) { - OSL_TRACE ("QueueProcessorThread::Start %p", this); resume (); } @@ -275,7 +256,6 @@ void QueueProcessorThread< Queue, RequestData, BitmapCache, BitmapFactory >::Stop (void) { - OSL_TRACE ("QueueProcessorThread::Stop %p", this); suspend(); } @@ -290,7 +270,6 @@ void QueueProcessorThread< Queue, RequestData, BitmapCache, BitmapFactory >::RemoveRequest (RequestData& rRequest) { - OSL_TRACE ("QueueProcessorThread::RemoveRequest %p", this); // Do nothing else then wait for the mutex to be released. ::osl::MutexGuard aGuard (mrQueue.GetMutex()); } @@ -307,11 +286,9 @@ void QueueProcessorThread< >::Terminate (void) { // ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); - OSL_TRACE("QueueProcessorThread::Terminate(): terminating thread %p", this); ::osl::Thread::terminate (); { ::osl::MutexGuard aGuard (maMutex); - OSL_TRACE("QueueProcessorThread::Terminate(): starting to join %p, %d", this, mbIsTerminated?1:0); mbIsTerminated = true; } Start(); @@ -332,29 +309,6 @@ void SAL_CALL QueueProcessorThread< { ::osl::MutexGuard aGuard (maMutex); mbCanBeJoined = true; - /* - OSL_TRACE("QueueProcessorThread::Terminate():join %p, %d", this, mbIsTerminated?1:0); - while (true) - { - { - ::osl::MutexGuard aGuard (maMutex); - if (mbCanBeJoined) - break; - } - Start(); - TimeValue aTimeToWait; - aTimeToWait.Seconds = 0; - aTimeToWait.Nanosec = 50*1000*1000; - OSL_TRACE("QueueProcessorThread::Terminate(): waiting for join"); - wait (aTimeToWait); - } - if (mbCanBeJoined) - join(); - else - OSL_TRACE("Can not join"); - OSL_TRACE("QueueProcessorThread::Terminate():terminated thread %p :%d", - this, mbIsTerminated?1:0); - */ } diff --git a/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx b/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx index 8030558759f3..166b04661d99 100644..100755 --- a/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx +++ b/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx @@ -24,8 +24,6 @@ * for a copy of the LGPLv3 License. * ************************************************************************/ -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_sd.hxx" #include "precompiled_sd.hxx" diff --git a/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx b/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx index ccd590131343..11721e09ecb3 100644..100755 --- a/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx +++ b/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx @@ -24,8 +24,6 @@ * for a copy of the LGPLv3 License. * ************************************************************************/ -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_sd.hxx" #include "precompiled_sd.hxx" diff --git a/sd/source/ui/slidesorter/controller/SlideSorterController.cxx b/sd/source/ui/slidesorter/controller/SlideSorterController.cxx index 69c2a02ddc24..8018c71e2b88 100755..100644 --- a/sd/source/ui/slidesorter/controller/SlideSorterController.cxx +++ b/sd/source/ui/slidesorter/controller/SlideSorterController.cxx @@ -39,17 +39,22 @@ #include "SlsSelectionCommand.hxx" #include "controller/SlsAnimator.hxx" #include "controller/SlsClipboard.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" #include "controller/SlsScrollBarManager.hxx" -#include "controller/SlsPageObjectFactory.hxx" #include "controller/SlsSelectionManager.hxx" #include "controller/SlsSlotManager.hxx" +#include "controller/SlsTransferable.hxx" +#include "controller/SlsVisibleAreaManager.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "model/SlsPageDescriptor.hxx" #include "view/SlideSorterView.hxx" #include "view/SlsLayouter.hxx" -#include "view/SlsViewOverlay.hxx" #include "view/SlsFontProvider.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsPageObjectPainter.hxx" +#include "view/SlsTheme.hxx" +#include "view/SlsToolTip.hxx" #include "cache/SlsPageCache.hxx" #include "cache/SlsPageCacheManager.hxx" @@ -91,12 +96,12 @@ #include <com/sun/star/drawing/XDrawPages.hpp> #include <com/sun/star/accessibility/AccessibleEventId.hpp> - using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::sd::slidesorter::model; using namespace ::sd::slidesorter::view; using namespace ::sd::slidesorter::controller; +using namespace ::basegfx; namespace sd { namespace slidesorter { namespace controller { @@ -112,9 +117,12 @@ SlideSorterController::SlideSorterController (SlideSorter& rSlideSorter) mpScrollBarManager(), mpCurrentSlideManager(), mpSelectionManager(), + mpInsertionIndicatorHandler(new InsertionIndicatorHandler(rSlideSorter)), mpAnimator(new Animator(rSlideSorter)), + mpVisibleAreaManager(new VisibleAreaManager(rSlideSorter)), mpListener(), mnModelChangeLockCount(0), + mbIsForcedRearrangePending(false), mbPreModelChangeDone(false), mbPostModelChangePending(false), maSelectionBeforeSwitch(), @@ -122,12 +130,11 @@ SlideSorterController::SlideSorterController (SlideSorter& rSlideSorter) mpEditModeChangeMasterPage(NULL), maTotalWindowArea(), mnPaintEntranceCount(0), - mbIsContextMenuOpen(false), - mpProperties(new Properties()) + mbIsContextMenuOpen(false) { - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - OSL_ASSERT(pWindow!=NULL); - if (pWindow != NULL) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + OSL_ASSERT(pWindow); + if (pWindow) { // The whole background is painted by the view and controls. ::Window* pParentWindow = pWindow->GetParent(); @@ -136,22 +143,10 @@ SlideSorterController::SlideSorterController (SlideSorter& rSlideSorter) // Connect the view with the window that has been created by our base // class. - pWindow->SetBackground (Wallpaper()); - mrView.AddWindowToPaintView(pWindow); - mrView.SetActualWin(pWindow); - pWindow->SetCenterAllowed (false); - pWindow->SetViewSize (mrView.GetModelArea().GetSize()); - pWindow->EnableRTL(FALSE); - - // Reinitialize colors in Properties with window specific values. - mpProperties->SetBackgroundColor( - pWindow->GetSettings().GetStyleSettings().GetWindowColor()); - mpProperties->SetTextColor( - pWindow->GetSettings().GetStyleSettings().GetWindowTextColor()); - mpProperties->SetSelectionColor( - pWindow->GetSettings().GetStyleSettings().GetMenuHighlightColor()); - mpProperties->SetHighlightColor( - pWindow->GetSettings().GetStyleSettings().GetMenuHighlightColor()); + pWindow->SetBackground(Wallpaper()); + pWindow->SetCenterAllowed(false); + pWindow->SetMapMode(MapMode(MAP_PIXEL)); + pWindow->SetViewSize(mrView.GetModelArea().GetSize()); } } @@ -160,8 +155,6 @@ SlideSorterController::SlideSorterController (SlideSorter& rSlideSorter) void SlideSorterController::Init (void) { - mrView.HandleModelChange(); - mpCurrentSlideManager.reset(new CurrentSlideManager(mrSlideSorter)); mpPageSelector.reset(new PageSelector(mrSlideSorter)); mpFocusManager.reset(new FocusManager(mrSlideSorter)); @@ -181,7 +174,7 @@ void SlideSorterController::Init (void) mpListener = new Listener(mrSlideSorter); - mpPageSelector->UpdateAllPages(); + mpPageSelector->GetCoreSelection(); GetSelectionManager()->SelectionHasChanged(); } @@ -210,17 +203,48 @@ SlideSorterController::~SlideSorterController (void) +void SlideSorterController::Dispose (void) +{ + mpInsertionIndicatorHandler->End(Animator::AM_Immediate); + mpSelectionManager.reset(); + mpAnimator->Dispose(); +} + + + + model::SharedPageDescriptor SlideSorterController::GetPageAt ( - const Point& aPixelPosition) + const Point& aWindowPosition) { - sal_Int32 nHitPageIndex (mrView.GetPageIndexAtPoint(aPixelPosition)); + sal_Int32 nHitPageIndex (mrView.GetPageIndexAtPoint(aWindowPosition)); model::SharedPageDescriptor pDescriptorAtPoint; if (nHitPageIndex >= 0) + { pDescriptorAtPoint = mrModel.GetPageDescriptor(nHitPageIndex); + // Depending on a property we may have to check that the mouse is no + // just over the page object but over the preview area. + if (pDescriptorAtPoint + && mrSlideSorter.GetProperties()->IsOnlyPreviewTriggersMouseOver() + && ! pDescriptorAtPoint->HasState(PageDescriptor::ST_Selected)) + { + // Make sure that the mouse is over the preview area. + if ( ! mrView.GetLayouter().GetPageObjectLayouter()->GetBoundingBox( + pDescriptorAtPoint, + view::PageObjectLayouter::Preview, + view::PageObjectLayouter::WindowCoordinateSystem).IsInside(aWindowPosition)) + { + pDescriptorAtPoint.reset(); + } + } + } + return pDescriptorAtPoint; } + + + PageSelector& SlideSorterController::GetPageSelector (void) { OSL_ASSERT(mpPageSelector.get()!=NULL); @@ -284,10 +308,11 @@ ScrollBarManager& SlideSorterController::GetScrollBarManager (void) -void SlideSorterController::PrePaint() +::boost::shared_ptr<InsertionIndicatorHandler> + SlideSorterController::GetInsertionIndicatorHandler (void) const { - // forward VCLs PrePaint window event to DrawingLayer - mrView.PrePaint(); + OSL_ASSERT(mpInsertionIndicatorHandler.get()!=NULL); + return mpInsertionIndicatorHandler; } @@ -297,16 +322,12 @@ void SlideSorterController::Paint ( const Rectangle& rBBox, ::Window* pWindow) { - // if (mnPaintEntranceCount == 0) + if (mnPaintEntranceCount == 0) { ++mnPaintEntranceCount; try { - if (GetSelectionManager()->IsMakeSelectionVisiblePending()) - GetSelectionManager()->MakeSelectionVisible(); - - mrView.SetApplicationDocumentColor(GetProperties()->GetBackgroundColor()); mrView.CompleteRedraw(pWindow, Region(rBBox), 0); } catch (const Exception&) @@ -394,50 +415,64 @@ bool SlideSorterController::Command ( else nPopupId = RID_SLIDE_SORTER_MASTER_NOSEL_POPUP; } - + ::boost::scoped_ptr<InsertionIndicatorHandler::ForceShowContext> pContext; if (pPage == NULL) { // When there is no selection, then we show the insertion // indicator so that the user knows where a page insertion // would take place. - mrView.GetOverlay().GetInsertionIndicatorOverlay().SetPosition( - pWindow->PixelToLogic(rEvent.GetMousePosPixel())); - mrView.GetOverlay().GetInsertionIndicatorOverlay().setVisible(true); + mpInsertionIndicatorHandler->Start(false); + mpInsertionIndicatorHandler->UpdateIndicatorIcon( + dynamic_cast<Transferable*>(SD_MOD()->pTransferClip)); + mpInsertionIndicatorHandler->UpdatePosition( + pWindow->PixelToLogic(rEvent.GetMousePosPixel()), + InsertionIndicatorHandler::MoveMode); + pContext.reset(new InsertionIndicatorHandler::ForceShowContext( + mpInsertionIndicatorHandler)); } pWindow->ReleaseMouse(); + + Point aMenuLocation (0,0); if (rEvent.IsMouseEvent()) { - mbIsContextMenuOpen = true; - if (pViewShell != NULL) - { - SfxDispatcher* pDispatcher = pViewShell->GetDispatcher(); - if (pDispatcher != NULL) - pDispatcher->ExecutePopup(SdResId(nPopupId)); - } + // We have to explicitly specify the location of the menu + // when the slide sorter is placed in an undocked child + // menu. But when it is docked it does not hurt, so we + // specify the location always. + aMenuLocation = rEvent.GetMousePosPixel(); } else { // The event is not a mouse event. Use the center of the // focused page as top left position of the context menu. - if (pPage != NULL) + model::SharedPageDescriptor pDescriptor ( + GetFocusManager().GetFocusedPageDescriptor()); + if (pDescriptor.get() != NULL) { - model::SharedPageDescriptor pDescriptor ( - GetFocusManager().GetFocusedPageDescriptor()); - if (pDescriptor.get() != NULL) - { - Rectangle aBBox (mrView.GetPageBoundingBox ( + Rectangle aBBox ( + mrView.GetLayouter().GetPageObjectLayouter()->GetBoundingBox ( pDescriptor, - view::SlideSorterView::CS_SCREEN, - view::SlideSorterView::BBT_SHAPE)); - Point aPosition (aBBox.Center()); - mbIsContextMenuOpen = true; - if (pViewShell != NULL) - pViewShell->GetViewFrame()->GetDispatcher()->ExecutePopup( - SdResId(nPopupId), - pWindow, - &aPosition); - } + PageObjectLayouter::PageObject, + PageObjectLayouter::ModelCoordinateSystem)); + aMenuLocation = aBBox.Center(); + } + } + + mbIsContextMenuOpen = true; + if (pViewShell != NULL) + { + SfxDispatcher* pDispatcher = pViewShell->GetDispatcher(); + if (pDispatcher != NULL) + { + pDispatcher->ExecutePopup( + SdResId(nPopupId), + pWindow, + &aMenuLocation); + mrSlideSorter.GetView().UpdatePageUnderMouse(false); + ::rtl::Reference<SelectionFunction> pFunction(GetCurrentSelectionFunction()); + if (pFunction.is()) + pFunction->ResetMouseAnchor(); } } mbIsContextMenuOpen = false; @@ -447,19 +482,44 @@ bool SlideSorterController::Command ( // it is hidden, so that a pending slide insertion slot call // finds the right place to insert a new slide. GetSelectionManager()->SetInsertionPosition( - mrView.GetOverlay().GetInsertionIndicatorOverlay().GetInsertionPageIndex()); - mrView.GetOverlay().GetInsertionIndicatorOverlay().setVisible(false); + GetInsertionIndicatorHandler()->GetInsertionPageIndex()); } + pContext.reset(); bEventHasBeenHandled = true; } break; case COMMAND_WHEEL: { - // We ignore zooming with control+mouse wheel. const CommandWheelData* pData = rEvent.GetWheelData(); - if (pData!=NULL && pData->IsMod1()) - bEventHasBeenHandled = true; + if (pData == NULL) + return false; + if (pData->IsMod1()) + { + // We do not support zooming with control+mouse wheel. + return false; + } + // Determine whether to scroll horizontally or vertically. This + // depends on the orientation of the scroll bar and the + // IsHoriz() flag of the event. + if ((mrSlideSorter.GetView().GetOrientation()==view::Layouter::HORIZONTAL) + == pData->IsHorz()) + { + GetScrollBarManager().Scroll( + ScrollBarManager::Orientation_Vertical, + ScrollBarManager::Unit_Slide, + -pData->GetNotchDelta()); + } + else + { + GetScrollBarManager().Scroll( + ScrollBarManager::Orientation_Horizontal, + ScrollBarManager::Unit_Slide, + -pData->GetNotchDelta()); + } + mrSlideSorter.GetView().UpdatePageUnderMouse(rEvent.GetMousePosPixel(), false); + + bEventHasBeenHandled = true; } break; } @@ -482,7 +542,9 @@ void SlideSorterController::UnlockModelChange (void) { mnModelChangeLockCount -= 1; if (mnModelChangeLockCount==0 && mbPostModelChangePending) + { PostModelChange(); + } } @@ -499,11 +561,9 @@ void SlideSorterController::PreModelChange (void) mrSlideSorter.GetViewShell()->Broadcast( ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START)); - mpPageSelector->PrepareModelChange(); GetCurrentSlideManager()->PrepareModelChange(); - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow != NULL) + if (mrSlideSorter.GetContentWindow()) mrView.PreModelChange(); mbPostModelChangePending = true; @@ -517,8 +577,8 @@ void SlideSorterController::PostModelChange (void) mbPostModelChangePending = false; mrModel.Resync(); - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow != NULL) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) { GetCurrentSlideManager()->HandleModelChange(); @@ -530,11 +590,9 @@ void SlideSorterController::PostModelChange (void) // The visibility of the scroll bars may have to be changed. Then // the size of the view has to change, too. Let Rearrange() handle // that. - Rearrange(); + Rearrange(mbIsForcedRearrangePending); } - mpPageSelector->HandleModelChange (); - if (mrSlideSorter.GetViewShell() != NULL) mrSlideSorter.GetViewShell()->Broadcast( ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END)); @@ -564,23 +622,36 @@ IMPL_LINK(SlideSorterController, WindowEventHandler, VclWindowEvent*, pEvent) if (pEvent != NULL) { ::Window* pWindow = pEvent->GetWindow(); - ::sd::Window* pActiveWindow = mrSlideSorter.GetActiveWindow(); + SharedSdWindow pActiveWindow (mrSlideSorter.GetContentWindow()); switch (pEvent->GetId()) { case VCLEVENT_WINDOW_ACTIVATE: case VCLEVENT_WINDOW_SHOW: - if (pActiveWindow != NULL && pWindow == pActiveWindow->GetParent()) + if (pActiveWindow && pWindow == pActiveWindow->GetParent()) mrView.RequestRepaint(); break; + case VCLEVENT_WINDOW_HIDE: + if (pActiveWindow && pWindow == pActiveWindow->GetParent()) + mrView.SetPageUnderMouse(SharedPageDescriptor()); + break; + case VCLEVENT_WINDOW_GETFOCUS: - if (pActiveWindow != NULL && pWindow == pActiveWindow) - GetFocusManager().ShowFocus(false); + if (pActiveWindow) + if (pWindow == pActiveWindow.get()) + GetFocusManager().ShowFocus(false); break; case VCLEVENT_WINDOW_LOSEFOCUS: - if (pActiveWindow != NULL && pWindow == pActiveWindow) + if (pActiveWindow && pWindow == pActiveWindow.get()) + { GetFocusManager().HideFocus(); + mrView.GetToolTip().Hide(); + + // Select the current slide so that it is properly + // visualized when the focus is moved to the edit view. + GetPageSelector().SelectPage(GetCurrentSlideManager()->GetCurrentSlide()); + } break; case VCLEVENT_APPLICATION_DATACHANGED: @@ -601,6 +672,11 @@ IMPL_LINK(SlideSorterController, WindowEventHandler, VclWindowEvent*, pEvent) // When the system font has changed a layout has to be done. mrView.Resize(); FontProvider::Instance().Invalidate(); + + // Update theme colors. + mrSlideSorter.GetProperties()->HandleDataChangeEvent(); + mrSlideSorter.GetTheme()->Update(mrSlideSorter.GetProperties()); + mrView.HandleDataChangeEvent(); } break; @@ -639,10 +715,9 @@ void SlideSorterController::GetCtrlState (SfxItemSet& rSet) ||rSet.GetItemState(SID_OUTPUT_QUALITY_BLACKWHITE)==SFX_ITEM_AVAILABLE ||rSet.GetItemState(SID_OUTPUT_QUALITY_CONTRAST)==SFX_ITEM_AVAILABLE) { - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow != NULL) + if (mrSlideSorter.GetContentWindow()) { - ULONG nMode = pWindow->GetDrawMode(); + ULONG nMode = mrSlideSorter.GetContentWindow()->GetDrawMode(); UINT16 nQuality = 0; switch (nMode) @@ -715,7 +790,7 @@ void SlideSorterController::ExecStatusBar (SfxRequest& ) void SlideSorterController::UpdateAllPages (void) { // Do a redraw. - mrView.InvalidateAllWin(); + mrSlideSorter.GetContentWindow()->Invalidate(); } @@ -741,20 +816,35 @@ Rectangle SlideSorterController::Rearrange (bool bForce) { Rectangle aNewContentArea (maTotalWindowArea); - ::boost::shared_ptr<sd::Window> pWindow = mrSlideSorter.GetContentWindow(); - if (pWindow.get() != NULL) + if (aNewContentArea.IsEmpty()) + return aNewContentArea; + + if (mnModelChangeLockCount>0) { + mbIsForcedRearrangePending |= bForce; + return aNewContentArea; + } + else + mbIsForcedRearrangePending = false; + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + if (bForce) + mrView.UpdateOrientation(); + // Place the scroll bars. - aNewContentArea = GetScrollBarManager().PlaceScrollBars(maTotalWindowArea); + aNewContentArea = GetScrollBarManager().PlaceScrollBars( + maTotalWindowArea, + mrView.GetOrientation() != view::Layouter::VERTICAL, + mrView.GetOrientation() != view::Layouter::HORIZONTAL); bool bSizeHasChanged (false); // Only when bForce is not true we have to test for a size change in // order to determine whether the window and the view have to be resized. if ( ! bForce) { - Rectangle aCurrentContentArea ( - pWindow->GetPosPixel(), - pWindow->GetOutputSizePixel()); + Rectangle aCurrentContentArea (pWindow->GetPosPixel(), pWindow->GetOutputSizePixel()); bSizeHasChanged = (aNewContentArea != aCurrentContentArea); } if (bForce || bSizeHasChanged) @@ -767,6 +857,11 @@ Rectangle SlideSorterController::Rearrange (bool bForce) // Adapt the scroll bars to the new zoom factor of the browser // window and the arrangement of the page objects. GetScrollBarManager().UpdateScrollBars(false, !bForce); + + // Keep the current slide in the visible area. + GetVisibleAreaManager().RequestCurrentSlideVisible(); + + mrView.RequestRepaint(); } return aNewContentArea; @@ -784,6 +879,15 @@ FunctionReference SlideSorterController::CreateSelectionFunction (SfxRequest& rR +::rtl::Reference<SelectionFunction> SlideSorterController::GetCurrentSelectionFunction (void) +{ + FunctionReference pFunction (mrSlideSorter.GetViewShell()->GetCurrentFunction()); + return ::rtl::Reference<SelectionFunction>(dynamic_cast<SelectionFunction*>(pFunction.get())); +} + + + + void SlideSorterController::PrepareEditModeChange (void) { // Before we throw away the page descriptors we prepare for selecting @@ -887,8 +991,8 @@ void SlideSorterController::PageNameHasChanged (int nPageIndex, const String& rs // that of the name change. do { - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow == NULL) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if ( ! pWindow) break; ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > @@ -937,14 +1041,6 @@ bool SlideSorterController::IsContextMenuOpen (void) const -::boost::shared_ptr<Properties> SlideSorterController::GetProperties (void) const -{ - return mpProperties; -} - - - - void SlideSorterController::SetDocumentSlides (const Reference<container::XIndexAccess>& rxSlides) { if (mrModel.GetDocumentSlides() != rxSlides) @@ -954,6 +1050,11 @@ void SlideSorterController::SetDocumentSlides (const Reference<container::XIndex mrModel.SetDocumentSlides(rxSlides); mrView.Layout(); + + // Select just the current slide. + PageSelector::BroadcastLock aBroadcastLock (*mpPageSelector); + mpPageSelector->DeselectAllPages(); + mpPageSelector->SelectPage(mpCurrentSlideManager->GetCurrentSlide()); } } @@ -968,6 +1069,35 @@ void SlideSorterController::SetDocumentSlides (const Reference<container::XIndex +VisibleAreaManager& SlideSorterController::GetVisibleAreaManager (void) const +{ + OSL_ASSERT(mpVisibleAreaManager); + return *mpVisibleAreaManager; +} + + + + +void SlideSorterController::CheckForMasterPageAssignment (void) +{ + if (mrModel.GetPageCount()%2==0) + return; + PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + while (aAllPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + if (pDescriptor->UpdateMasterPage()) + { + mrView.GetPreviewCache()->InvalidatePreviewBitmap ( + pDescriptor->GetPage(), + true); + } + } +} + + + + //===== SlideSorterController::ModelChangeLock ================================ SlideSorterController::ModelChangeLock::ModelChangeLock ( diff --git a/sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx b/sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx new file mode 100644 index 000000000000..71b6c024ae7a --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx @@ -0,0 +1,294 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" +#include "controller/SlsAnimationFunction.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" + + +#include <osl/diagnose.hxx> +#include <rtl/math.hxx> + +namespace sd { namespace slidesorter { namespace controller { + + +double AnimationFunction::Linear (const double nTime) +{ + OSL_ASSERT(nTime>=0.0 && nTime<=1.0); + return nTime; +} + + + + +double AnimationFunction::FastInSlowOut_Sine (const double nTime) +{ + OSL_ASSERT(nTime>=0.0 && nTime<=1.0); + + const double nResult (sin(nTime * M_PI/2)); + + OSL_ASSERT(nResult>=0.0 && nResult<=1.0); + return nResult; +} + + + + +double AnimationFunction::FastInSlowOut_Root (const double nTime) +{ + OSL_ASSERT(nTime>=0.0 && nTime<=1.0); + + const double nResult (sqrt(nTime)); + + OSL_ASSERT(nResult>=0.0 && nResult<=1.0); + return nResult; +} + + + + +double AnimationFunction::SlowInSlowOut_0to0_Sine (const double nTime) +{ + OSL_ASSERT(nTime>=0.0 && nTime<=1.0); + + const double nResult (sin(nTime * M_PI)); + + OSL_ASSERT(nResult>=0.0 && nResult<=1.0); + return nResult; +} + + + + +double AnimationFunction::Vibrate_Sine (const double nTime) +{ + return sin(nTime*M_PI*8); +} + + + + +Point AnimationFunction::ScalePoint (const Point& rPoint, const double nTime) +{ + return Point( + sal_Int32(::rtl::math::round(rPoint.X() * nTime)), + sal_Int32(::rtl::math::round(rPoint.Y() * nTime))); +} + + + + +double AnimationFunction::Blend ( + const double nStartValue, + const double nEndValue, + const double nTime) +{ + return nStartValue*(1-nTime) + nEndValue*nTime; +} + + + + +void AnimationFunction::ApplyVisualStateChange ( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const double nTime) +{ + if (rpDescriptor) + { + rpDescriptor->GetVisualState().SetVisualStateBlend(nTime); + rView.RequestRepaint(rpDescriptor); + } +} + + + + +void AnimationFunction::ApplyLocationOffsetChange ( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const Point aLocationOffset) +{ + if (rpDescriptor) + { + const Rectangle aOldBoundingBox(rpDescriptor->GetBoundingBox()); + rpDescriptor->GetVisualState().SetLocationOffset(aLocationOffset); + rView.RequestRepaint(aOldBoundingBox); + rView.RequestRepaint(rpDescriptor); + } +} + + + + +void AnimationFunction::ApplyButtonAlphaChange( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const double nButtonAlpha, + const double nButtonBarAlpha) +{ + if (rpDescriptor) + { + rpDescriptor->GetVisualState().SetButtonAlpha(nButtonAlpha); + rpDescriptor->GetVisualState().SetButtonBarAlpha(nButtonBarAlpha); + rView.RequestRepaint(rpDescriptor); + } +} + + + + +//===== AnimationBezierFunction =============================================== + +AnimationBezierFunction::AnimationBezierFunction ( + const double nX1, + const double nY1, + const double nX2, + const double nY2) + : mnX1(nX1), + mnY1(nY1), + mnX2(nX2), + mnY2(nY2) +{ +} + + + + +AnimationBezierFunction::AnimationBezierFunction ( + const double nX1, + const double nY1) + : mnX1(nX1), + mnY1(nY1), + mnX2(1-nY1), + mnY2(1-nX1) +{ +} + + + + +::basegfx::B2DPoint AnimationBezierFunction::operator() (const double nT) +{ + return ::basegfx::B2DPoint( + EvaluateComponent(nT, mnX1, mnX2), + EvaluateComponent(nT, mnY1, mnY2)); +} + + + + +double AnimationBezierFunction::EvaluateComponent ( + const double nT, + const double nV1, + const double nV2) +{ + const double nS (1-nT); + + // While the control point values 1 and 2 are explicitly given the start + // and end values are implicitly given. + const double nV0 (0); + const double nV3 (1); + + const double nV01 (nS*nV0 + nT*nV1); + const double nV12 (nS*nV1 + nT*nV2); + const double nV23 (nS*nV2 + nT*nV3); + + const double nV012 (nS*nV01 + nT*nV12); + const double nV123 (nS*nV12 + nT*nV23); + + const double nV0123 (nS*nV012 + nT*nV123); + + return nV0123; +} + + + + +//===== AnimationParametricFunction =========================================== + +AnimationParametricFunction::AnimationParametricFunction (const ParametricFunction& rFunction) + : maY() +{ + const sal_Int32 nSampleCount (64); + + // Sample the given parametric function. + ::std::vector<basegfx::B2DPoint> aPoints; + aPoints.reserve(nSampleCount); + for (sal_Int32 nIndex=0; nIndex<nSampleCount; ++nIndex) + { + const double nT (nIndex/double(nSampleCount-1)); + aPoints.push_back(basegfx::B2DPoint(rFunction(nT))); + } + + // Interpolate at evenly spaced points. + maY.clear(); + maY.reserve(nSampleCount); + double nX0 (aPoints[0].getX()); + double nY0 (aPoints[0].getY()); + double nX1 (aPoints[1].getX()); + double nY1 (aPoints[1].getY()); + sal_Int32 nIndex (1); + for (sal_Int32 nIndex2=0; nIndex2<nSampleCount; ++nIndex2) + { + const double nX (nIndex2 / double(nSampleCount-1)); + while (nX > nX1 && nIndex<nSampleCount) + { + nX0 = nX1; + nY0 = nY1; + nX1 = aPoints[nIndex].getX(); + nY1 = aPoints[nIndex].getY(); + ++nIndex; + } + const double nU ((nX-nX1) / (nX0 - nX1)); + const double nY (nY0*nU + nY1*(1-nU)); + maY.push_back(nY); + } +} + + + + +double AnimationParametricFunction::operator() (const double nX) +{ + const sal_Int32 nIndex0 (nX * maY.size()); + const double nX0 (nIndex0 / double(maY.size()-1)); + const sal_uInt32 nIndex1 (nIndex0 + 1); + const double nX1 (nIndex1 / double(maY.size()-1)); + + if (nIndex0<=0) + return maY[0]; + else if (sal_uInt32(nIndex0)>=maY.size() || nIndex1>=maY.size()) + return maY[maY.size()-1]; + + const double nU ((nX-nX1) / (nX0 - nX1)); + return maY[nIndex0]*nU + maY[nIndex1]*(1-nU); +} + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsAnimator.cxx b/sd/source/ui/slidesorter/controller/SlsAnimator.cxx index 56505d9756e6..28756b3766d9 100644..100755 --- a/sd/source/ui/slidesorter/controller/SlsAnimator.cxx +++ b/sd/source/ui/slidesorter/controller/SlsAnimator.cxx @@ -29,6 +29,7 @@ #include "controller/SlsAnimator.hxx" #include "view/SlideSorterView.hxx" #include "View.hxx" +#include <boost/bind.hpp> namespace sd { namespace slidesorter { namespace controller { @@ -42,27 +43,32 @@ class Animator::Animation { public: Animation ( - const Animator::AnimationFunction& rAnimation, - const double nDelta); + const Animator::AnimationFunctor& rAnimation, + const double nStartOffset, + const double nDuration, + const double nGlobalTime, + const Animator::AnimationId nAnimationId, + const Animator::FinishFunctor& rFinishFunctor); ~Animation (void); - bool Run (void); + /** Run next animation step. If animation has reached its end it is + expired. + */ + bool Run (const double nGlobalTime); + + /** Typically called when an animation has finished, but also from + Animator::Disposed(). The finish functor is called and the + animation is marked as expired to prevent another run. + */ + void Expire (void); bool IsExpired (void); - Animator::AnimationFunction maAnimation; - double mnValue; - double mnDelta; -}; - - - - -class Animator::DrawLock -{ -public: - DrawLock (View& rView); - ~DrawLock (void); -private: - View& mrView; + Animator::AnimationFunctor maAnimation; + Animator::FinishFunctor maFinishFunctor; + const Animator::AnimationId mnAnimationId; + const double mnDuration; + const double mnEnd; + const double mnGlobalTimeAtStart; + bool mbIsExpired; }; @@ -71,8 +77,11 @@ private: Animator::Animator (SlideSorter& rSlideSorter) : mrSlideSorter(rSlideSorter), maTimer(), + mbIsDisposed(false), maAnimations(), - mpDrawLock() + maElapsedTime(), + mpDrawLock(), + mnNextAnimationId(0) { maTimer.SetTimeout(gnResolution); maTimer.SetTimeoutHdl(LINK(this,Animator,TimeoutHandler)); @@ -83,39 +92,161 @@ Animator::Animator (SlideSorter& rSlideSorter) Animator::~Animator (void) { + if ( ! mbIsDisposed) + { + OSL_ASSERT(mbIsDisposed); + Dispose(); + } +} + + + + +void Animator::Dispose (void) +{ + mbIsDisposed = true; + + AnimationList aCopy (maAnimations); + AnimationList::const_iterator iAnimation; + for (iAnimation=aCopy.begin(); iAnimation!=aCopy.end(); ++iAnimation) + (*iAnimation)->Expire(); + maTimer.Stop(); - mpDrawLock.reset(); + if (mpDrawLock) + { + mpDrawLock->Dispose(); + mpDrawLock.reset(); + } } -void Animator::AddAnimation ( - const AnimationFunction& rAnimation, - const sal_Int32 nDuration) +Animator::AnimationId Animator::AddAnimation ( + const AnimationFunctor& rAnimation, + const sal_Int32 nStartOffset, + const sal_Int32 nDuration, + const FinishFunctor& rFinishFunctor) { - const double nDelta = double(gnResolution) / double(nDuration); - maAnimations.push_back(boost::shared_ptr<Animation>(new Animation(rAnimation, nDelta))); + // When the animator is already disposed then ignore this call + // silently (well, we show an assertion, but do not throw an exception.) + OSL_ASSERT( ! mbIsDisposed); + if (mbIsDisposed) + return -1; + + boost::shared_ptr<Animation> pAnimation ( + new Animation( + rAnimation, + nStartOffset / 1000.0, + nDuration / 1000.0, + maElapsedTime.getElapsedTime(), + ++mnNextAnimationId, + rFinishFunctor)); + maAnimations.push_back(pAnimation); + + RequestNextFrame(); + + return pAnimation->mnAnimationId; +} + - // Prevent redraws except for the ones in TimeoutHandler. - // While the Animator is active it will schedule repaints regularly. - // Repaints in between would only lead to visual artifacts. - mpDrawLock.reset(new DrawLock(mrSlideSorter.GetView())); - maTimer.Start(); + + +Animator::AnimationId Animator::AddInfiniteAnimation ( + const AnimationFunctor& rAnimation, + const double nDelta) +{ + (void)nDelta; + + // When the animator is already disposed then ignore this call + // silently (well, we show an assertion, but do not throw an exception.) + OSL_ASSERT( ! mbIsDisposed); + if (mbIsDisposed) + return -1; + + boost::shared_ptr<Animation> pAnimation ( + new Animation( + rAnimation, + 0, + -1, + maElapsedTime.getElapsedTime(), + mnNextAnimationId++, + FinishFunctor())); + maAnimations.push_back(pAnimation); + + RequestNextFrame(); + + return pAnimation->mnAnimationId; } -bool Animator::ServeAnimations (void) +void Animator::RemoveAnimation (const Animator::AnimationId nId) +{ + OSL_ASSERT( ! mbIsDisposed); + + const AnimationList::iterator iAnimation (::std::find_if( + maAnimations.begin(), + maAnimations.end(), + ::boost::bind( + ::std::equal_to<Animator::AnimationId>(), + nId, + ::boost::bind(&Animation::mnAnimationId, _1)))); + if (iAnimation != maAnimations.end()) + { + OSL_ASSERT((*iAnimation)->mnAnimationId == nId); + (*iAnimation)->Expire(); + maAnimations.erase(iAnimation); + } + + if (maAnimations.empty()) + { + // Reset the animation id when we can. + mnNextAnimationId = 0; + + // No more animations => we do not have to suppress painting + // anymore. + mpDrawLock.reset(); + } +} + + + + +void Animator::RemoveAllAnimations (void) +{ + ::std::for_each( + maAnimations.begin(), + maAnimations.end(), + ::boost::bind( + &Animation::Expire, + _1)); + maAnimations.clear(); + mnNextAnimationId = 0; + + // No more animations => we do not have to suppress painting + // anymore. + mpDrawLock.reset(); +} + + + + +bool Animator::ProcessAnimations (const double nTime) { bool bExpired (false); + OSL_ASSERT( ! mbIsDisposed); + if (mbIsDisposed) + return bExpired; + + AnimationList aCopy (maAnimations); AnimationList::const_iterator iAnimation; for (iAnimation=aCopy.begin(); iAnimation!=aCopy.end(); ++iAnimation) { - bExpired |= (*iAnimation)->Run(); + bExpired |= (*iAnimation)->Run(nTime); } return bExpired; @@ -126,6 +257,10 @@ bool Animator::ServeAnimations (void) void Animator::CleanUpAnimationList (void) { + OSL_ASSERT( ! mbIsDisposed); + if (mbIsDisposed) + return; + AnimationList aActiveAnimations; AnimationList::const_iterator iAnimation; @@ -141,19 +276,35 @@ void Animator::CleanUpAnimationList (void) +void Animator::RequestNextFrame (const double nFrameStart) +{ + (void)nFrameStart; + if ( ! maTimer.IsActive()) + { + // Prevent redraws except for the ones in TimeoutHandler. While the + // Animator is active it will schedule repaints regularly. Repaints + // in between would only lead to visual artifacts. + mpDrawLock.reset(new view::SlideSorterView::DrawLock(mrSlideSorter)); + maTimer.Start(); + } +} + + + + IMPL_LINK(Animator, TimeoutHandler, Timer*, EMPTYARG) { - if (ServeAnimations()) + if (mbIsDisposed) + return 0; + + if (ProcessAnimations(maElapsedTime.getElapsedTime())) CleanUpAnimationList(); // Unlock the draw lock. This should lead to a repaint. mpDrawLock.reset(); if (maAnimations.size() > 0) - { - mpDrawLock.reset(new DrawLock(mrSlideSorter.GetView())); - maTimer.Start(); - } + RequestNextFrame(); return 0; } @@ -164,16 +315,21 @@ IMPL_LINK(Animator, TimeoutHandler, Timer*, EMPTYARG) //===== Animator::Animation =================================================== Animator::Animation::Animation ( - const Animator::AnimationFunction& rAnimation, - const double nDelta) + const Animator::AnimationFunctor& rAnimation, + const double nStartOffset, + const double nDuration, + const double nGlobalTime, + const Animator::AnimationId nId, + const Animator::FinishFunctor& rFinishFunctor) : maAnimation(rAnimation), - mnValue(0), - mnDelta(nDelta) + maFinishFunctor(rFinishFunctor), + mnAnimationId(nId), + mnDuration(nDuration), + mnEnd(nGlobalTime + nDuration + nStartOffset), + mnGlobalTimeAtStart(nGlobalTime + nStartOffset), + mbIsExpired(false) { - - maAnimation(mnValue); - mnValue = mnDelta; - + Run(nGlobalTime); } @@ -186,47 +342,54 @@ Animator::Animation::~Animation (void) -bool Animator::Animation::Run (void) +bool Animator::Animation::Run (const double nGlobalTime) { - if (mnValue < 1.0) + if ( ! mbIsExpired) { - maAnimation(mnValue); - mnValue += mnDelta; - return false; - } - else - { - maAnimation(1.0); - return true; + if (mnDuration > 0) + { + if (nGlobalTime >= mnEnd) + { + maAnimation(1.0); + Expire(); + } + else if (nGlobalTime >= mnGlobalTimeAtStart) + { + maAnimation((nGlobalTime - mnGlobalTimeAtStart) / mnDuration); + } + } + else if (mnDuration < 0) + { + // Animations without end have to be expired by their owner. + maAnimation(nGlobalTime); + } } + + return mbIsExpired; } -bool Animator::Animation::IsExpired (void) +void Animator::Animation::Expire (void) { - return mnValue >= 1.0; + if ( ! mbIsExpired) + { + mbIsExpired = true; + if (maFinishFunctor) + maFinishFunctor(); + } } -//===== Animator::DrawLock ==================================================== - -Animator::DrawLock::DrawLock (View& rView) - : mrView(rView) +bool Animator::Animation::IsExpired (void) { - mrView.LockRedraw(TRUE); + return mbIsExpired; } -Animator::DrawLock::~DrawLock (void) -{ - mrView.LockRedraw(FALSE); -} - - } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsClipboard.cxx b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx index d226a8c2e294..68ae50e091e7 100644..100755 --- a/sd/source/ui/slidesorter/controller/SlsClipboard.cxx +++ b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx @@ -35,16 +35,18 @@ #include "model/SlsPageDescriptor.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "view/SlideSorterView.hxx" -#include "view/SlsViewOverlay.hxx" -#include "view/SlsPageObject.hxx" +#include "view/SlsTheme.hxx" #include "controller/SlideSorterController.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" #include "controller/SlsPageSelector.hxx" #include "controller/SlsSelectionFunction.hxx" #include "controller/SlsCurrentSlideManager.hxx" #include "controller/SlsScrollBarManager.hxx" #include "controller/SlsFocusManager.hxx" #include "controller/SlsSelectionManager.hxx" -#include "SlsTransferable.hxx" +#include "controller/SlsTransferable.hxx" +#include "controller/SlsSelectionObserver.hxx" +#include "cache/SlsPageCache.hxx" #include "ViewShellBase.hxx" #include "DrawViewShell.hxx" @@ -74,6 +76,7 @@ #include <sfx2/bindings.hxx> #include <sfx2/docfile.hxx> #include <svx/svxids.hrc> +#include <svx/svdstr.hrc> #include <vcl/msgbox.hxx> #include <tools/urlobj.hxx> #include <rtl/ustring.hxx> @@ -82,6 +85,43 @@ namespace sd { namespace slidesorter { namespace controller { +class Clipboard::UndoContext +{ +public: + UndoContext ( + SdDrawDocument* pDocument, + const ::boost::shared_ptr<ViewShell>& rpMainViewShell, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : mpDocument(pDocument), + mpMainViewShell(rpMainViewShell) + { + if (mpDocument!=NULL && mpDocument->IsUndoEnabled()) + { + if (mpMainViewShell && mpMainViewShell->GetShellType() == ViewShell::ST_DRAW) + mpDocument->BegUndo(rpTheme->GetString(view::Theme::String_DragAndDropPages)); + else + mpDocument->BegUndo(rpTheme->GetString(view::Theme::String_DragAndDropSlides)); + } + } + + ~UndoContext (void) + { + if (mpDocument!=NULL && mpDocument->IsUndoEnabled()) + mpDocument->EndUndo(); + if (mpMainViewShell && mpMainViewShell->GetViewFrame()!=NULL) + { + SfxBindings& rBindings = mpMainViewShell->GetViewFrame()->GetBindings(); + rBindings.Invalidate(SID_UNDO); + rBindings.Invalidate(SID_REDO); + } + } +private: + SdDrawDocument* mpDocument; + ::boost::shared_ptr<ViewShell> mpMainViewShell; +}; + + + Clipboard::Clipboard (SlideSorter& rSlideSorter) : ViewClipboard(rSlideSorter.GetView()), @@ -89,7 +129,10 @@ Clipboard::Clipboard (SlideSorter& rSlideSorter) mrController(mrSlideSorter.GetController()), maPagesToRemove(), maPagesToSelect(), - mbUpdateSelectionPending(false) + mbUpdateSelectionPending(false), + mpUndoContext(), + mpSelectionObserverContext(), + mnDragFinishedUserEventId(0) { } @@ -98,6 +141,8 @@ Clipboard::Clipboard (SlideSorter& rSlideSorter) Clipboard::~Clipboard (void) { + if (mnDragFinishedUserEventId != 0) + Application::RemoveUserEvent(mnDragFinishedUserEventId); } @@ -143,13 +188,12 @@ void Clipboard::HandleSlotCall (SfxRequest& rRequest) // a crash. if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE) { - mrSlideSorter.GetView().LockRedraw (TRUE); + view::SlideSorterView::DrawLock aLock (mrSlideSorter); + SelectionObserver::Context aContext (mrSlideSorter); if(xFunc.is()) xFunc->DoPaste(); else DoPaste(); - mrController.GetSelectionManager()->MakeSelectionVisible(); - mrSlideSorter.GetView().LockRedraw(FALSE); } rRequest.Done(); break; @@ -209,7 +253,7 @@ void Clipboard::DoPaste (::Window* pWindow) sal_Int32 nInsertPageCount = PasteTransferable(nInsertPosition); // Select the pasted pages and make the first of them the // current page. - mrSlideSorter.GetView().GetWindow()->GrabFocus(); + mrSlideSorter.GetContentWindow()->GrabFocus(); SelectPageRange(nInsertPosition, nInsertPageCount); } } @@ -230,14 +274,22 @@ sal_Int32 Clipboard::GetInsertionPosition (::Window* pWindow) // selection. // d) After the last page when there is no selection and no focus. - view::InsertionIndicatorOverlay& rInsertionIndicatorOverlay ( - mrSlideSorter.GetView().GetOverlay().GetInsertionIndicatorOverlay()); - if (rInsertionIndicatorOverlay.isVisible()) + ::boost::shared_ptr<controller::InsertionIndicatorHandler> pInsertionIndicatorHandler ( + mrController.GetInsertionIndicatorHandler()); + if (pInsertionIndicatorHandler->IsActive()) + { + // Use the insertion index of an active insertion indicator. + nInsertPosition = pInsertionIndicatorHandler->GetInsertionPageIndex(); + } + else if (mrController.GetSelectionManager()->GetInsertionPosition() >= 0) { - nInsertPosition = rInsertionIndicatorOverlay.GetInsertionPageIndex(); + // Use the insertion index of an insertion indicator that has been + // deactivated a short while ago. + nInsertPosition = mrController.GetSelectionManager()->GetInsertionPosition(); } else if (mrController.GetFocusManager().IsFocusShowing()) { + // Use the focus to determine the insertion position. SdInsertPasteDlg aDialog (pWindow); if (aDialog.Execute() == RET_OK) { @@ -246,10 +298,6 @@ sal_Int32 Clipboard::GetInsertionPosition (::Window* pWindow) nInsertPosition ++; } } - else - { - nInsertPosition = mrController.GetSelectionManager()->GetInsertionPosition(); - } return nInsertPosition; } @@ -260,9 +308,9 @@ sal_Int32 Clipboard::GetInsertionPosition (::Window* pWindow) sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition) { SdTransferable* pClipTransferable = SD_MOD()->pTransferClip; - bool bMergeMasterPages = !pClipTransferable->HasSourceDoc ( - mrSlideSorter.GetModel().GetDocument()); - USHORT nInsertIndex ((USHORT)(nInsertPosition * 2 + 1)); + model::SlideSorterModel& rModel (mrSlideSorter.GetModel()); + bool bMergeMasterPages = !pClipTransferable->HasSourceDoc (rModel.GetDocument()); + USHORT nInsertIndex (rModel.GetCoreIndex(nInsertPosition)); sal_Int32 nInsertPageCount (0); if (pClipTransferable->HasPageBookmarks()) { @@ -270,7 +318,7 @@ sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition) const ::vos::OGuard aGuard (Application::GetSolarMutex()); nInsertPageCount = (USHORT) rBookmarkList.Count(); - mrSlideSorter.GetModel().GetDocument()->InsertBookmarkAsPage( + rModel.GetDocument()->InsertBookmarkAsPage( const_cast<List*>(&rBookmarkList), NULL, FALSE, @@ -293,9 +341,9 @@ sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition) { const ::vos::OGuard aGuard (Application::GetSolarMutex()); - bMergeMasterPages = (pDataDoc != mrSlideSorter.GetModel().GetDocument()); + bMergeMasterPages = (pDataDoc != rModel.GetDocument()); nInsertPageCount = pDataDoc->GetSdPageCount( PK_STANDARD ); - mrSlideSorter.GetModel().GetDocument()->InsertBookmarkAsPage( + rModel.GetDocument()->InsertBookmarkAsPage( NULL, NULL, FALSE, @@ -332,7 +380,6 @@ void Clipboard::SelectPageRange (sal_Int32 nFirstIndex, sal_Int32 nPageCount) if (i == 0) { mrController.GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor); - mrController.GetFocusManager().SetFocusedPage(pDescriptor); } } } @@ -361,6 +408,27 @@ void Clipboard::CreateSlideTransferable ( maPagesToRemove.push_back (pDescriptor->GetPage()); } + // Create a small set of representatives of the selection for which + // previews are included into the transferable so that an insertion + // indicator can be rendered. + aSelectedPages.Rewind(); + ::std::vector<Transferable::Representative> aRepresentatives; + aRepresentatives.reserve(3); + ::boost::shared_ptr<cache::PageCache> pPreviewCache ( + mrSlideSorter.GetView().GetPreviewCache()); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + if ( ! pDescriptor || pDescriptor->GetPage()==NULL) + continue; + Bitmap aPreview (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage(), false)); + aRepresentatives.push_back(Transferable::Representative( + aPreview, + pDescriptor->HasState(model::PageDescriptor::ST_Excluded))); + if (aRepresentatives.size() >= 3) + break; + } + if (aBookmarkList.Count() > 0) { mrSlideSorter.GetView().BrkAction(); @@ -369,7 +437,8 @@ void Clipboard::CreateSlideTransferable ( pDocument, NULL, FALSE, - dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell())); + dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()), + aRepresentatives); if (bDrag) SD_MOD()->pTransferDrag = pTransferable; @@ -423,13 +492,17 @@ void Clipboard::CreateSlideTransferable ( void Clipboard::StartDrag ( - const Point&, + const Point& rPosition, ::Window* pWindow) { maPagesToRemove.clear(); maPagesToSelect.clear(); mbUpdateSelectionPending = false; - CreateSlideTransferable (pWindow, TRUE); + CreateSlideTransferable(pWindow, TRUE); + + mrController.GetInsertionIndicatorHandler()->UpdatePosition( + rPosition, + InsertionIndicatorHandler::UnknownMode); } @@ -437,15 +510,36 @@ void Clipboard::StartDrag ( void Clipboard::DragFinished (sal_Int8 nDropAction) { - // Hide the substitution display and insertion indicator. - mrSlideSorter.GetView().GetOverlay().GetSubstitutionOverlay().setVisible(false); - mrSlideSorter.GetView().GetOverlay().GetInsertionIndicatorOverlay().setVisible(false); - SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; - if (pDragTransferable != NULL) pDragTransferable->SetView (NULL); + if (mnDragFinishedUserEventId == 0) + { + if ( ! Application::PostUserEvent( + mnDragFinishedUserEventId, + LINK(this, Clipboard, ProcessDragFinished), + reinterpret_cast<void*>(nDropAction))) + { + mnDragFinishedUserEventId = 0; + } + } +} + + + + +IMPL_LINK(Clipboard, ProcessDragFinished, void*, pUserData) +{ + const sal_Int8 nDropAction (static_cast<sal_Int8>(reinterpret_cast<sal_IntPtr>(pUserData))); + + mnDragFinishedUserEventId = 0; + + // Hide the substitution display and insertion indicator. + ::rtl::Reference<SelectionFunction> pFunction (mrController.GetCurrentSelectionFunction()); + if (pFunction.is()) + pFunction->NotifyDragFinished(); + PageSelector& rSelector (mrController.GetPageSelector()); if ((nDropAction & DND_ACTION_MOVE) != 0 && ! maPagesToRemove.empty()) @@ -458,12 +552,14 @@ void Clipboard::DragFinished (sal_Int8 nDropAction) aDraggedPage!=maPagesToRemove.end(); aDraggedPage++) { - rSelector.SelectPage (*aDraggedPage); + rSelector.SelectPage(*aDraggedPage); } - mrController.GetSelectionManager()->DeleteSelectedPages (); + mrController.GetSelectionManager()->DeleteSelectedPages(); } + mpUndoContext.reset(); + mpSelectionObserverContext.reset(); - SelectPages(); + return 1; } @@ -492,14 +588,16 @@ sal_Int8 Clipboard::AcceptDrop ( USHORT nPage, USHORT nLayer) { - sal_Int8 nResult = DND_ACTION_NONE; + sal_Int8 nAction (DND_ACTION_NONE); - switch (IsDropAccepted()) + const Clipboard::DropType eDropType (IsDropAccepted()); + + switch (eDropType) { case DT_PAGE: { // Accept a drop. - nResult = rEvent.mnAction; + nAction = rEvent.mnAction; // Use the copy action when the drop action is the default, i.e. not // explicitly set to move or link, and when the source and @@ -512,23 +610,27 @@ sal_Int8 Clipboard::AcceptDrop ( && (mrSlideSorter.GetModel().GetDocument()->GetDocSh() != pDragTransferable->GetPageDocShell())) { - nResult = DND_ACTION_COPY; + nAction = DND_ACTION_COPY; + } + else if (mrController.GetInsertionIndicatorHandler()->IsInsertionTrivial(nAction)) + { + nAction = DND_ACTION_NONE; } // Show the insertion marker and the substitution for a drop. Point aPosition = pTargetWindow->PixelToLogic (rEvent.maPosPixel); - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - rOverlay.GetInsertionIndicatorOverlay().SetPosition (aPosition); - rOverlay.GetInsertionIndicatorOverlay().setVisible(true); - rOverlay.GetSubstitutionOverlay().SetPosition (aPosition); + SelectionFunction* pSelectionFunction = dynamic_cast<SelectionFunction*>( + mrSlideSorter.GetViewShell()->GetCurrentFunction().get()); + if (pSelectionFunction != NULL) + pSelectionFunction->MouseDragged(rEvent, nAction); // Scroll the window when the mouse reaches the window border. - mrController.GetScrollBarManager().AutoScroll (rEvent.maPosPixel); + // mrController.GetScrollBarManager().AutoScroll (rEvent.maPosPixel); } break; case DT_SHAPE: - nResult = ExecuteOrAcceptShapeDrop( + nAction = ExecuteOrAcceptShapeDrop( DC_ACCEPT, rEvent.maPosPixel, &rEvent, @@ -537,11 +639,13 @@ sal_Int8 Clipboard::AcceptDrop ( nPage, nLayer); break; + default: + nAction = DND_ACTION_NONE; break; } - return nResult; + return nAction; } @@ -555,6 +659,7 @@ sal_Int8 Clipboard::ExecuteDrop ( USHORT nLayer) { sal_Int8 nResult = DND_ACTION_NONE; + mpUndoContext.reset(); switch (IsDropAccepted()) { @@ -563,54 +668,57 @@ sal_Int8 Clipboard::ExecuteDrop ( const SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; const Point aEventModelPosition ( pTargetWindow->PixelToLogic (rEvent.maPosPixel)); - long int nXOffset = labs (pDragTransferable->GetStartPos().X() - - aEventModelPosition.X()); - long int nYOffset = labs (pDragTransferable->GetStartPos().Y() - - aEventModelPosition.Y()); - const bool bContinue = + const sal_Int32 nXOffset (labs (pDragTransferable->GetStartPos().X() + - aEventModelPosition.X())); + const sal_Int32 nYOffset (labs (pDragTransferable->GetStartPos().Y() + - aEventModelPosition.Y())); + bool bContinue = ( pDragTransferable->GetView() != &mrSlideSorter.GetView() ) || ( nXOffset >= 2 && nYOffset >= 2 ); + ::boost::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler( + mrController.GetInsertionIndicatorHandler()); // Get insertion position and then turn off the insertion indicator. - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - rOverlay.GetInsertionIndicatorOverlay().SetPosition( - aEventModelPosition); - USHORT nIndex = DetermineInsertPosition (*pDragTransferable); - OSL_TRACE ("Clipboard::AcceptDrop() called for index %d", - nIndex); - rOverlay.GetInsertionIndicatorOverlay().setVisible(false); + pInsertionIndicatorHandler->UpdatePosition(aEventModelPosition, rEvent.mnAction); + // USHORT nIndex = DetermineInsertPosition(*pDragTransferable); + + // Do not process the insertion when it is trivial, + // i.e. would insert pages at their original place. + if (pInsertionIndicatorHandler->IsInsertionTrivial(rEvent.mnAction)) + bContinue = false; + + // Tell the insertion indicator handler to hide before the model + // is modified. Doing it later may result in page objects whose + // animation state is not properly reset because they are then + // in another run then before the model change. + pInsertionIndicatorHandler->End(Animator::AM_Immediate); if (bContinue) { SlideSorterController::ModelChangeLock aModelChangeLock (mrController); - if (pDragTransferable->GetView() == &mrSlideSorter.GetView() - && rEvent.mnAction == DND_ACTION_MOVE) - { - // We are asked to move pages inside one view. For this we - // call MoveSelectedPages() which is faster than going the - // generic way. - - // Remember to select the moved pages afterwards. - maPagesToRemove.swap(maPagesToSelect); - maPagesToRemove.clear(); - - USHORT nSdrModelIndex; - if (nIndex != SDRPAGE_NOTFOUND) - nSdrModelIndex = nIndex / 2 - 1; - else - nSdrModelIndex = SDRPAGE_NOTFOUND; - mrController.GetSelectionManager()->MoveSelectedPages(nSdrModelIndex); - mbUpdateSelectionPending = true; - nResult = DND_ACTION_NONE; - } - else - { - // Handle a general drop operation. - HandlePageDrop (*pDragTransferable); - nResult = rEvent.mnAction; - } + // Handle a general drop operation. + mpUndoContext.reset(new UndoContext ( + mrSlideSorter.GetModel().GetDocument(), + mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell(), + mrSlideSorter.GetTheme())); + mpSelectionObserverContext.reset(new SelectionObserver::Context(mrSlideSorter)); + + HandlePageDrop(*pDragTransferable); + nResult = rEvent.mnAction; + + // We leave the undo context alive for when moving or + // copying inside one view then the actions in + // NotifyDragFinished should be covered as well as + // well as the ones above. } + + // Notify the receiving selection function that drag-and-drop is + // finished and the substitution handler can be released. + ::rtl::Reference<SelectionFunction> pFunction ( + mrController.GetCurrentSelectionFunction()); + if (pFunction.is()) + pFunction->NotifyDragFinished(); } break; @@ -634,23 +742,31 @@ sal_Int8 Clipboard::ExecuteDrop ( -USHORT Clipboard::DetermineInsertPosition (const SdTransferable& ) +void Clipboard::Abort (void) { - USHORT nInsertPosition = SDRPAGE_NOTFOUND; + if (mpSelectionObserverContext) + { + mpSelectionObserverContext->Abort(); + mpSelectionObserverContext.reset(); + } +} + + + +USHORT Clipboard::DetermineInsertPosition (const SdTransferable& ) +{ // Tell the model to move the dragged pages behind the one with the // index nInsertionIndex which first has to be transformed into an index // understandable by the document. - view::InsertionIndicatorOverlay& rOverlay ( - mrSlideSorter.GetView().GetOverlay().GetInsertionIndicatorOverlay()); - sal_Int32 nInsertionIndex (rOverlay.GetInsertionPageIndex()); + const sal_Int32 nInsertionIndex ( + mrController.GetInsertionIndicatorHandler()->GetInsertionPageIndex()); - // The index returned by the overlay starts with 1 for the first slide. - // This is now converted that to an SdModel index that also starts with 1. + // Convert to insertion index to that of an SdModel. if (nInsertionIndex >= 0) - nInsertPosition = (USHORT)nInsertionIndex * 2 + 1; - - return nInsertPosition; + return mrSlideSorter.GetModel().GetCoreIndex(nInsertionIndex); + else + return 0; } @@ -666,14 +782,12 @@ USHORT Clipboard::InsertSlides ( // Remember the inserted pages so that they can be selected when the // operation is finished. - int nDocumentIndex = nInsertPosition / 2 - 1; - for (USHORT i=1; i<=nInsertedPageCount; i++) - { - model::SharedPageDescriptor pDescriptor ( - mrSlideSorter.GetModel().GetPageDescriptor(nDocumentIndex + i)); - if (pDescriptor.get() != NULL) - maPagesToSelect.push_back (pDescriptor->GetPage()); - } + maPagesToSelect.clear(); + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + if (pDocument != NULL) + for (sal_Int32 i=0; i<=nInsertedPageCount; i+=2) + maPagesToSelect.push_back( + dynamic_cast<SdPage*>(pDocument->GetPage(nInsertPosition+i))); mbUpdateSelectionPending |= (nInsertedPageCount>0); @@ -739,8 +853,8 @@ sal_Int8 Clipboard::ExecuteOrAcceptShapeDrop ( model::SharedPageDescriptor pDescriptor ( mrSlideSorter.GetModel().GetPageDescriptor( mrSlideSorter.GetView().GetPageIndexAtPoint(rPosition))); - if (pDescriptor.get() != NULL && pDescriptor->GetPage()!=NULL) - nPage = (pDescriptor->GetPage()->GetPageNum() - 1) / 2; + if (pDescriptor) + nPage = pDescriptor->GetPageIndex(); } // Now comes the code that is different for the Execute and Accept: diff --git a/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx b/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx index f5864c3307a1..7b2ca60cb4f0 100755..100644 --- a/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx +++ b/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx @@ -33,8 +33,8 @@ #include "controller/SlsPageSelector.hxx" #include "controller/SlideSorterController.hxx" #include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsFocusManager.hxx" #include "view/SlideSorterView.hxx" -#include "view/SlsPageObjectViewObjectContact.hxx" #include "ViewShellBase.hxx" #include "ViewShell.hxx" #include "DrawViewShell.hxx" @@ -47,13 +47,18 @@ using namespace ::com::sun::star::uno; using namespace ::sd::slidesorter::model; + namespace sd { namespace slidesorter { namespace controller { + CurrentSlideManager::CurrentSlideManager (SlideSorter& rSlideSorter) : mrSlideSorter(rSlideSorter), mnCurrentSlideIndex(-1), - mpCurrentSlide() + mpCurrentSlide(), + maSwitchPageDelayTimer() { + maSwitchPageDelayTimer.SetTimeout(100); + maSwitchPageDelayTimer.SetTimeoutHdl(LINK(this,CurrentSlideManager,SwitchPageCallback)); } @@ -66,7 +71,22 @@ CurrentSlideManager::~CurrentSlideManager (void) -void CurrentSlideManager::CurrentSlideHasChanged (const sal_Int32 nSlideIndex) +void CurrentSlideManager::NotifyCurrentSlideChange (const SdPage* pPage) +{ + if (pPage != NULL) + NotifyCurrentSlideChange( + mrSlideSorter.GetModel().GetIndex( + Reference<drawing::XDrawPage>( + const_cast<SdPage*>(pPage)->getUnoPage(), + UNO_QUERY))); + else + NotifyCurrentSlideChange(-1); +} + + + + +void CurrentSlideManager::NotifyCurrentSlideChange (const sal_Int32 nSlideIndex) { if (mnCurrentSlideIndex != nSlideIndex) { @@ -75,8 +95,11 @@ void CurrentSlideManager::CurrentSlideHasChanged (const sal_Int32 nSlideIndex) // Update the selection. mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); - if (mpCurrentSlide.get() != NULL) + if (mpCurrentSlide) + { mrSlideSorter.GetController().GetPageSelector().SelectPage(mpCurrentSlide); + mrSlideSorter.GetController().GetFocusManager().SetFocusedPage(mpCurrentSlide); + } } } @@ -86,10 +109,7 @@ void CurrentSlideManager::CurrentSlideHasChanged (const sal_Int32 nSlideIndex) void CurrentSlideManager::ReleaseCurrentSlide (void) { if (mpCurrentSlide.get() != NULL) - { - mpCurrentSlide->SetIsCurrentPage(false); - mrSlideSorter.GetView().RequestRepaint(mpCurrentSlide); - } + mrSlideSorter.GetView().SetState(mpCurrentSlide, PageDescriptor::ST_Current, false); mpCurrentSlide.reset(); mnCurrentSlideIndex = -1; @@ -117,48 +137,64 @@ void CurrentSlideManager::AcquireCurrentSlide (const sal_Int32 nSlideIndex) // document. mpCurrentSlide = mrSlideSorter.GetModel().GetPageDescriptor(mnCurrentSlideIndex); if (mpCurrentSlide.get() != NULL) - { - mpCurrentSlide->SetIsCurrentPage(true); - mrSlideSorter.GetView().RequestRepaint(mpCurrentSlide); - } + mrSlideSorter.GetView().SetState(mpCurrentSlide, PageDescriptor::ST_Current, true); } } -void CurrentSlideManager::SwitchCurrentSlide (const sal_Int32 nSlideIndex) +void CurrentSlideManager::SwitchCurrentSlide ( + const sal_Int32 nSlideIndex, + const bool bUpdateSelection) { - SwitchCurrentSlide(mrSlideSorter.GetModel().GetPageDescriptor(nSlideIndex)); + SwitchCurrentSlide(mrSlideSorter.GetModel().GetPageDescriptor(nSlideIndex), bUpdateSelection); } -void CurrentSlideManager::SwitchCurrentSlide (const SharedPageDescriptor& rpDescriptor) +void CurrentSlideManager::SwitchCurrentSlide ( + const SharedPageDescriptor& rpDescriptor, + const bool bUpdateSelection) { - if (rpDescriptor.get() != NULL) + if (rpDescriptor.get() != NULL && mpCurrentSlide!=rpDescriptor) { - mpCurrentSlide = rpDescriptor; - mnCurrentSlideIndex = (rpDescriptor->GetPage()->GetPageNum()-1)/2; + ReleaseCurrentSlide(); + AcquireCurrentSlide((rpDescriptor->GetPage()->GetPageNum()-1)/2); ViewShell* pViewShell = mrSlideSorter.GetViewShell(); if (pViewShell != NULL && pViewShell->IsMainViewShell()) { + // The slide sorter is the main view. FrameView* pFrameView = pViewShell->GetFrameView(); if (pFrameView != NULL) pFrameView->SetSelectedPage(sal::static_int_cast<USHORT>(mnCurrentSlideIndex)); + mrSlideSorter.GetController().GetPageSelector().SetCoreSelection(); } - else + + // We do not tell the XController/ViewShellBase about the new + // slide right away. This is done asynchronously after a short + // delay to allow for more slide switches in the slide sorter. + // This goes under the assumption that slide switching inside + // the slide sorter is fast (no expensive redraw of the new page + // (unless the preview of the new slide is not yet preset)) and + // that slide switching in the edit view is slow (all shapes of + // the new slide have to be repainted.) + maSwitchPageDelayTimer.Start(); + + // We have to store the (index of the) new current slide at + // the tab control because there are other asynchronous + // notifications of the slide switching that otherwise + // overwrite the correct value. + SetCurrentSlideAtTabControl(mpCurrentSlide); + + if (bUpdateSelection) { - // Set current page. At the moment we have to do this in two - // different ways. The UNO way is the preferable one but, alas, - // it does not work always correctly (after some kinds of model - // changes). Therefore, we call DrawViewShell::SwitchPage(), - // too. - SetCurrentSlideAtViewShellBase(rpDescriptor); - SetCurrentSlideAtXController(rpDescriptor); + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); } + mrSlideSorter.GetController().GetFocusManager().SetFocusedPage(rpDescriptor); } } @@ -180,19 +216,26 @@ void CurrentSlideManager::SetCurrentSlideAtViewShellBase (const SharedPageDescri pDrawViewShell->SwitchPage(nPageNumber); pDrawViewShell->GetPageTabControl()->SetCurPageId(nPageNumber+1); } - /* - else + } +} + + + + +void CurrentSlideManager::SetCurrentSlideAtTabControl (const SharedPageDescriptor& rpDescriptor) +{ + OSL_ASSERT(rpDescriptor.get() != NULL); + + ViewShellBase* pBase = mrSlideSorter.GetViewShellBase(); + if (pBase != NULL) + { + ::boost::shared_ptr<DrawViewShell> pDrawViewShell ( + ::boost::dynamic_pointer_cast<DrawViewShell>(pBase->GetMainViewShell())); + if (pDrawViewShell) { - presenter::PresenterViewShell* pPresenterViewShell - = dynamic_cast<presenter::PresenterViewShell*>(pBase->GetMainViewShell()); - if (pPresenterViewShell != NULL) - { - pPresenterViewShell->SetCurrentSlide( - Reference<drawing::XDrawPage>( - rpDescriptor->GetPage()->getUnoPage(), UNO_QUERY)); - } + USHORT nPageNumber = (rpDescriptor->GetPage()->GetPageNum()-1)/2; + pDrawViewShell->GetPageTabControl()->SetCurPageId(nPageNumber+1); } - */ } } @@ -215,7 +258,7 @@ void CurrentSlideManager::SetCurrentSlideAtXController (const SharedPageDescript aPage); } } - catch (beans::UnknownPropertyException aException) + catch (Exception aException) { // We have not been able to set the current page at the main view. // This is sad but still leaves us in a valid state. Therefore, @@ -246,11 +289,31 @@ void CurrentSlideManager::HandleModelChange (void) { if (mnCurrentSlideIndex >= 0) { - mpCurrentSlide = mrSlideSorter.GetModel().GetPageDescriptor( - mnCurrentSlideIndex); + mpCurrentSlide = mrSlideSorter.GetModel().GetPageDescriptor(mnCurrentSlideIndex); if (mpCurrentSlide.get() != NULL) - mpCurrentSlide->SetIsCurrentPage(true); + mrSlideSorter.GetView().SetState(mpCurrentSlide, PageDescriptor::ST_Current, true); } } + + + +IMPL_LINK(CurrentSlideManager, SwitchPageCallback, void*, EMPTYARG) +{ + if (mpCurrentSlide) + { + // Set current page. At the moment we have to do this in two + // different ways. The UNO way is the preferable one but, alas, + // it does not work always correctly (after some kinds of model + // changes). Therefore, we call DrawViewShell::SwitchPage(), + // too. + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell==NULL || ! pViewShell->IsMainViewShell()) + SetCurrentSlideAtViewShellBase(mpCurrentSlide); + SetCurrentSlideAtXController(mpCurrentSlide); + } + + return 1; +} + } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx new file mode 100644 index 000000000000..88b294f3202f --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx @@ -0,0 +1,199 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsDragAndDropContext.hxx" + +#include "SlideSorter.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "view/SlideSorterView.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsSelectionFunction.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsTransferable.hxx" +#include "DrawDocShell.hxx" +#include "drawdoc.hxx" +#include "app.hrc" +#include <sfx2/bindings.hxx> +#include <boost/bind.hpp> + +namespace sd { namespace slidesorter { namespace controller { + +DragAndDropContext::DragAndDropContext (SlideSorter& rSlideSorter) + : mpTargetSlideSorter(&rSlideSorter), + mnInsertionIndex(-1) +{ + ::std::vector<const SdPage*> aPages; + + // No Drag-and-Drop for master pages. + if (rSlideSorter.GetModel().GetEditMode() != EM_PAGE) + return; + + rSlideSorter.GetController().GetInsertionIndicatorHandler()->UpdateIndicatorIcon( + dynamic_cast<Transferable*>(SD_MOD()->pTransferDrag)); +} + + + + +DragAndDropContext::~DragAndDropContext (void) +{ + SetTargetSlideSorter (NULL, Point(0,0), InsertionIndicatorHandler::UnknownMode, false); +} + + + + +void DragAndDropContext::GetPagesFromBookmarks ( + ::std::vector<const SdPage*>& rPages, + sal_Int32& rnSelectionCount, + DrawDocShell* pDocShell, + const List& rBookmarks) const +{ + if (pDocShell == NULL) + return; + + const SdDrawDocument* pDocument = pDocShell->GetDoc(); + if (pDocument == NULL) + return; + + for (ULONG nIndex=0,nCount=rBookmarks.Count(); nIndex<nCount; ++nIndex) + { + const String sPageName (*static_cast<String*>(rBookmarks.GetObject(nIndex))); + BOOL bIsMasterPage (FALSE); + const USHORT nPageIndex (pDocument->GetPageByName(sPageName, bIsMasterPage)); + if (nPageIndex == SDRPAGE_NOTFOUND) + continue; + + const SdPage* pPage = dynamic_cast<const SdPage*>(pDocument->GetPage(nPageIndex)); + if (pPage != NULL) + rPages.push_back(pPage); + } + rnSelectionCount = rBookmarks.Count(); +} + + + + +void DragAndDropContext::GetPagesFromSelection ( + ::std::vector<const SdPage*>& rPages, + sal_Int32& rnSelectionCount, + model::PageEnumeration& rSelection) const +{ + // Show a new substitution for the selected page objects. + rnSelectionCount = 0; + + while (rSelection.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (rSelection.GetNextElement()); + if (rPages.size() < 3) + rPages.push_back(pDescriptor->GetPage()); + ++rnSelectionCount; + } +} + + + + +void DragAndDropContext::Dispose (void) +{ + mnInsertionIndex = -1; +} + + + + +void DragAndDropContext::UpdatePosition ( + const Point& rMousePosition, + const InsertionIndicatorHandler::Mode eMode, + const bool bAllowAutoScroll) +{ + if (mpTargetSlideSorter == NULL) + return; + + if (mpTargetSlideSorter->GetProperties()->IsUIReadOnly()) + return; + + // Convert window coordinates into model coordinates (we need the + // window coordinates for auto-scrolling because that remains + // constant while scrolling.) + SharedSdWindow pWindow (mpTargetSlideSorter->GetContentWindow()); + const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition)); + ::boost::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler ( + mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()); + + if ( ! (bAllowAutoScroll + && mpTargetSlideSorter->GetController().GetScrollBarManager().AutoScroll( + rMousePosition, + ::boost::bind( + &DragAndDropContext::UpdatePosition, this, rMousePosition, eMode, false)))) + { + pInsertionIndicatorHandler->UpdatePosition(aMouseModelPosition, eMode); + + // Remember the new insertion index. + mnInsertionIndex = pInsertionIndicatorHandler->GetInsertionPageIndex(); + if (pInsertionIndicatorHandler->IsInsertionTrivial(mnInsertionIndex, eMode)) + mnInsertionIndex = -1; + } +} + + + + +void DragAndDropContext::SetTargetSlideSorter ( + SlideSorter* pSlideSorter, + const Point aMousePosition, + const InsertionIndicatorHandler::Mode eMode, + const bool bIsOverSourceView) +{ + if (mpTargetSlideSorter != NULL) + { + mpTargetSlideSorter->GetController().GetScrollBarManager().StopAutoScroll(); + mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()->End( + Animator::AM_Animated); + } + + mpTargetSlideSorter = pSlideSorter; + + if (mpTargetSlideSorter != NULL) + { + mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()->Start( + bIsOverSourceView); + mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()->UpdatePosition( + aMousePosition, + eMode); + + } +} + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx new file mode 100644 index 000000000000..7536f88d9474 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx @@ -0,0 +1,100 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_SUBSTITUTION_HANDLER_HXX +#define SD_SLIDESORTER_SUBSTITUTION_HANDLER_HXX + +#include <tools/gen.hxx> + +#include "model/SlsSharedPageDescriptor.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include <vector> + + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + + + +namespace sd { namespace slidesorter { namespace controller { + +/** A DragAndDropContext object handles an active drag and drop operation. + When the mouse is moved from one slide sorter window to another the + target SlideSorter object is exchanged accordingly. +*/ +class DragAndDropContext +{ +public: + /** Create a substitution display of the currently selected pages or, + when provided, the pages in the transferable. + */ + DragAndDropContext (SlideSorter& rSlideSorter); + ~DragAndDropContext (void); + + /** Call this method (for example as reaction to ESC key press) to avoid + processing (ie moving or inserting) the substition when the called + DragAndDropContext object is destroyed. + */ + void Dispose (void); + + /** Move the substitution display by the distance the mouse has + travelled since the last call to this method or to + CreateSubstitution(). The given point becomes the new anchor. + */ + void UpdatePosition ( + const Point& rMousePosition, + const InsertionIndicatorHandler::Mode eMode, + const bool bAllowAutoScroll = true); + + void SetTargetSlideSorter ( + SlideSorter* pSlideSorter = NULL, + const Point aMousePosition = Point(0,0), + const InsertionIndicatorHandler::Mode eMode = InsertionIndicatorHandler::UnknownMode, + const bool bIsOverSourceView = false); + +private: + SlideSorter* mpTargetSlideSorter; + model::SharedPageDescriptor mpHitDescriptor; + sal_Int32 mnInsertionIndex; + + void GetPagesFromBookmarks ( + ::std::vector<const SdPage*>& rPages, + sal_Int32& rnSelectionCount, + DrawDocShell* pDocShell, + const List& rBookmarks) const; + void GetPagesFromSelection ( + ::std::vector<const SdPage*>& rPages, + sal_Int32& rnSelectionCount, + model::PageEnumeration& rSelection) const; +}; + + + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx b/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx index dcda73d38dba..445354cd9830 100755 --- a/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx +++ b/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx @@ -31,7 +31,8 @@ #include "SlideSorter.hxx" #include "PaneDockingWindow.hxx" #include "controller/SlideSorterController.hxx" -#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsVisibleAreaManager.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageDescriptor.hxx" #include "view/SlideSorterView.hxx" @@ -41,12 +42,15 @@ #include "Window.hxx" #include "sdpage.hxx" +#define UNIFY_FOCUS_AND_CURRENT_PAGE + namespace sd { namespace slidesorter { namespace controller { FocusManager::FocusManager (SlideSorter& rSlideSorter) : mrSlideSorter(rSlideSorter), mnPageIndex(0), - mbPageIsFocused(false) + mbPageIsFocused(false), + mbIsVerticalWrapActive(false) { if (mrSlideSorter.GetModel().GetPageCount() > 0) mnPageIndex = 0; @@ -68,69 +72,101 @@ void FocusManager::MoveFocus (FocusMoveDirection eDirection) { HideFocusIndicator (GetFocusedPageDescriptor()); - int nColumnCount (mrSlideSorter.GetView().GetLayouter().GetColumnCount()); + const sal_Int32 nColumnCount (mrSlideSorter.GetView().GetLayouter().GetColumnCount()); + const sal_Int32 nPageCount (mrSlideSorter.GetModel().GetPageCount()); switch (eDirection) { case FMD_NONE: - if (mnPageIndex >= mrSlideSorter.GetModel().GetPageCount()) - mnPageIndex = mrSlideSorter.GetModel().GetPageCount() - 1; + // Nothing to be done. break; case FMD_LEFT: - mnPageIndex -= 1; - if (mnPageIndex < 0) - { - mnPageIndex = mrSlideSorter.GetModel().GetPageCount() - 1; - SetFocusToToolBox(); - } + if (mnPageIndex > 0) + mnPageIndex -= 1; + else if (mbIsVerticalWrapActive) + mnPageIndex = nPageCount-1; break; case FMD_RIGHT: - mnPageIndex += 1; - if (mnPageIndex >= mrSlideSorter.GetModel().GetPageCount()) - { + if (mnPageIndex < nPageCount-1) + mnPageIndex += 1; + else if (mbIsVerticalWrapActive) mnPageIndex = 0; - SetFocusToToolBox(); - } break; case FMD_UP: { - int nColumn = mnPageIndex % nColumnCount; - mnPageIndex -= nColumnCount; - if (mnPageIndex < 0) + const sal_Int32 nCandidate (mnPageIndex - nColumnCount); + if (nCandidate < 0) { - // Wrap arround to the bottom row or the one above and - // go to the correct column. - int nCandidate = mrSlideSorter.GetModel().GetPageCount()-1; - int nCandidateColumn = nCandidate % nColumnCount; - if (nCandidateColumn > nColumn) - mnPageIndex = nCandidate - (nCandidateColumn-nColumn); - else if (nCandidateColumn < nColumn) - mnPageIndex = nCandidate - - nColumnCount - + (nColumn - nCandidateColumn); - else - mnPageIndex = nCandidate; + if (mbIsVerticalWrapActive) + { + // Wrap arround to the bottom row or the one above + // and go to the correct column. + const sal_Int32 nLastIndex (nPageCount-1); + const sal_Int32 nLastColumn (nLastIndex % nColumnCount); + const sal_Int32 nCurrentColumn (mnPageIndex%nColumnCount); + if (nLastColumn >= nCurrentColumn) + { + // The last row contains the current column. + mnPageIndex = nLastIndex - (nLastColumn-nCurrentColumn); + } + else + { + // Only the second to last row contains the current column. + mnPageIndex = nLastIndex - nLastColumn + - nColumnCount + + nCurrentColumn; + } + } + } + else + { + // Move the focus the previous row. + mnPageIndex = nCandidate; } } break; case FMD_DOWN: { - int nColumn = mnPageIndex % nColumnCount; - mnPageIndex += nColumnCount; - if (mnPageIndex >= mrSlideSorter.GetModel().GetPageCount()) + const sal_Int32 nCandidate (mnPageIndex + nColumnCount); + if (nCandidate >= nPageCount) + { + if (mbIsVerticalWrapActive) + { + // Wrap arround to the correct column. + mnPageIndex = mnPageIndex % nColumnCount; + } + else + { + // Do not move the focus. + } + } + else { - // Wrap arround to the correct column. - mnPageIndex = nColumn; + // Move the focus to the next row. + mnPageIndex = nCandidate; } } break; } + if (mnPageIndex < 0) + { + OSL_ASSERT(mnPageIndex>=0); + mnPageIndex = 0; + } + else if (mnPageIndex >= nPageCount) + { + OSL_ASSERT(mnPageIndex<nPageCount); + mnPageIndex = nPageCount - 1; + } + if (mbPageIsFocused) + { ShowFocusIndicator(GetFocusedPageDescriptor(), true); + } } } @@ -172,7 +208,7 @@ bool FocusManager::ToggleFocus (void) bool FocusManager::HasFocus (void) const { - return mrSlideSorter.GetView().GetWindow()->HasFocus(); + return mrSlideSorter.GetContentWindow()->HasFocus(); } @@ -193,7 +229,7 @@ sal_Int32 FocusManager::GetFocusedPageIndex (void) const - +/* void FocusManager::FocusPage (sal_Int32 nPageIndex) { if (nPageIndex != mnPageIndex) @@ -206,7 +242,7 @@ void FocusManager::FocusPage (sal_Int32 nPageIndex) if (HasFocus() && !IsFocusShowing()) ShowFocus(); } - +*/ @@ -231,6 +267,14 @@ void FocusManager::SetFocusedPage (sal_Int32 nPageIndex) +void FocusManager::SetFocusedPageToCurrentPage (void) +{ + SetFocusedPage(mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()); +} + + + + bool FocusManager::IsFocusShowing (void) const { return HasFocus() && mbPageIsFocused; @@ -243,8 +287,7 @@ void FocusManager::HideFocusIndicator (const model::SharedPageDescriptor& rpDesc { if (rpDescriptor.get() != NULL) { - rpDescriptor->RemoveFocus(); - mrSlideSorter.GetView().RequestRepaint(rpDescriptor); + mrSlideSorter.GetView().SetState(rpDescriptor, model::PageDescriptor::ST_Focused, false); } } @@ -257,21 +300,16 @@ void FocusManager::ShowFocusIndicator ( { if (rpDescriptor.get() != NULL) { - rpDescriptor->SetFocus (); + mrSlideSorter.GetView().SetState(rpDescriptor, model::PageDescriptor::ST_Focused, true); if (bScrollToFocus) { // Scroll the focused page object into the visible area and repaint // it, so that the focus indicator becomes visible. - view::SlideSorterView& rView (mrSlideSorter.GetView()); - mrSlideSorter.GetController().GetSelectionManager()->MakeRectangleVisible ( - rView.GetPageBoundingBox ( - GetFocusedPageDescriptor(), - view::SlideSorterView::CS_MODEL, - view::SlideSorterView::BBT_INFO)); + mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor,true); } + mrSlideSorter.GetView().RequestRepaint(rpDescriptor); - mrSlideSorter.GetView().RequestRepaint (rpDescriptor); NotifyFocusChangeListeners(); } } diff --git a/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx b/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx index 666d4b017302..dbb65b0f657a 100644..100755 --- a/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx +++ b/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx @@ -109,8 +109,10 @@ void HideSlideFunction::DoExecute (SfxRequest& rRequest) while (aSelectedPages.HasMoreElements()) { model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); - pDescriptor->GetPage()->SetExcluded (eState==EXCLUDED); - static_cast<view::SlideSorterView*>(mpView)->RequestRepaint(pDescriptor); + static_cast<view::SlideSorterView*>(mpView)->SetState( + pDescriptor, + model::PageDescriptor::ST_Excluded, + eState==EXCLUDED); } } diff --git a/sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx b/sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx new file mode 100644 index 000000000000..882adab932a8 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx @@ -0,0 +1,327 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include "controller/SlsProperties.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsInsertionIndicatorOverlay.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> + +#include "SlideSorter.hxx" + +using namespace ::com::sun::star::datatransfer::dnd::DNDConstants; + +namespace sd { namespace slidesorter { namespace controller { + + +InsertionIndicatorHandler::InsertionIndicatorHandler (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mpInsertAnimator(), + mpInsertionIndicatorOverlay(new view::InsertionIndicatorOverlay(rSlideSorter)), + maInsertPosition(), + meMode(MoveMode), + mbIsActive(false), + mbIsReadOnly(mrSlideSorter.GetModel().IsReadOnly()), + mbIsOverSourceView(true), + maIconSize(0,0), + mbIsForcedShow(false) +{ +} + + + + +InsertionIndicatorHandler::~InsertionIndicatorHandler (void) +{ +} + + + + +void InsertionIndicatorHandler::Start (const bool bIsOverSourceView) +{ + if (mbIsActive) + { + OSL_ASSERT(!mbIsActive); + } + + mbIsReadOnly = mrSlideSorter.GetModel().IsReadOnly(); + if (mbIsReadOnly) + return; + + mbIsActive = true; + mbIsOverSourceView = bIsOverSourceView; +} + + + + +void InsertionIndicatorHandler::End (const controller::Animator::AnimationMode eMode) +{ + if (mbIsForcedShow || ! mbIsActive || mbIsReadOnly) + return; + + GetInsertAnimator()->Reset(eMode); + + mbIsActive = false; + // maInsertPosition = view::InsertPosition(); + meMode = UnknownMode; + + mpInsertionIndicatorOverlay->Hide(); + mpInsertionIndicatorOverlay.reset(new view::InsertionIndicatorOverlay(mrSlideSorter)); +} + + + + +void InsertionIndicatorHandler::ForceShow (void) +{ + mbIsForcedShow = true; +} + + + + +void InsertionIndicatorHandler::ForceEnd (void) +{ + mbIsForcedShow = false; + End(Animator::AM_Immediate); +} + + + + +void InsertionIndicatorHandler::UpdateIndicatorIcon (const Transferable* pTransferable) +{ + mpInsertionIndicatorOverlay->Create(pTransferable); + maIconSize = mpInsertionIndicatorOverlay->GetSize(); +} + + + + +InsertionIndicatorHandler::Mode InsertionIndicatorHandler::GetModeFromDndAction ( + const sal_Int8 nDndAction) +{ + if ((nDndAction & ACTION_MOVE) != 0) + return MoveMode; + else if ((nDndAction & ACTION_COPY) != 0) + return CopyMode; + else + return UnknownMode; +} + + + + +void InsertionIndicatorHandler::UpdatePosition ( + const Point& rMouseModelPosition, + const Mode eMode) +{ + if ( ! mbIsActive) + return; + + if (mbIsReadOnly) + return; + + SetPosition(rMouseModelPosition, eMode); +} + + + + +void InsertionIndicatorHandler::UpdatePosition ( + const Point& rMouseModelPosition, + const sal_Int8 nDndAction) +{ + UpdatePosition(rMouseModelPosition, GetModeFromDndAction(nDndAction)); +} + + + + +bool InsertionIndicatorHandler::IsActive (void) const +{ + return mbIsActive; +} + + + + +sal_Int32 InsertionIndicatorHandler::GetInsertionPageIndex (void) const +{ + if (mbIsReadOnly) + return -1; + else + return maInsertPosition.GetIndex(); +} + + + + +void InsertionIndicatorHandler::SetPosition ( + const Point& rPoint, + const Mode eMode) +{ + view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter()); + + const view::InsertPosition aInsertPosition (rLayouter.GetInsertPosition( + rPoint, + maIconSize, + mrSlideSorter.GetModel())); + + static sal_Int32 TargetIndex (1); + if (aInsertPosition.GetIndex() == TargetIndex) + { + const view::InsertPosition aPosition (rLayouter.GetInsertPosition( + rPoint, + maIconSize, + mrSlideSorter.GetModel())); + const view::InsertPosition aPosition2 (rLayouter.GetInsertPosition( + rPoint, + maIconSize, + mrSlideSorter.GetModel())); + } + + if (maInsertPosition != aInsertPosition + || meMode != eMode + // || ! mpInsertionIndicatorOverlay->IsVisible() + ) + { + maInsertPosition = aInsertPosition; + meMode = eMode; + mbIsInsertionTrivial = IsInsertionTrivial(maInsertPosition.GetIndex(), eMode); + if (maInsertPosition.GetIndex()>=0 && ! mbIsInsertionTrivial) + { + mpInsertionIndicatorOverlay->SetLocation(maInsertPosition.GetLocation()); + + GetInsertAnimator()->SetInsertPosition(maInsertPosition); + mpInsertionIndicatorOverlay->Show(); + } + else + { + GetInsertAnimator()->Reset(Animator::AM_Animated); + mpInsertionIndicatorOverlay->Hide(); + } + } +} + + + + +::boost::shared_ptr<view::InsertAnimator> InsertionIndicatorHandler::GetInsertAnimator (void) +{ + if ( ! mpInsertAnimator) + mpInsertAnimator.reset(new view::InsertAnimator(mrSlideSorter)); + return mpInsertAnimator; +} + + + + +bool InsertionIndicatorHandler::IsInsertionTrivial ( + const sal_Int32 nInsertionIndex, + const Mode eMode) const +{ + if (eMode == CopyMode) + return false; + else if (eMode == UnknownMode) + return true; + + if ( ! mbIsOverSourceView) + return false; + + // Iterate over all selected pages and check whether there are + // holes. While we do this we remember the indices of the first and + // last selected page as preparation for the next step. + sal_Int32 nCurrentIndex = -1; + sal_Int32 nFirstIndex = -1; + sal_Int32 nLastIndex = -1; + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + + // Get the page number and compare it to the last one. + const sal_Int32 nPageNumber (pDescriptor->GetPageIndex()); + if (nCurrentIndex>=0 && nPageNumber>(nCurrentIndex+1)) + return false; + else + nCurrentIndex = nPageNumber; + + // Remember indices of the first and last page of the selection. + if (nFirstIndex == -1) + nFirstIndex = nPageNumber; + nLastIndex = nPageNumber; + } + + // When we come here then the selection has no holes. We still have + // to check that the insertion position is not directly in front or + // directly behind the selection and thus moving the selection there + // would not change the model. + if (nInsertionIndex<nFirstIndex || nInsertionIndex>(nLastIndex+1)) + return false; + + return true; +} + + + + +bool InsertionIndicatorHandler::IsInsertionTrivial (const sal_Int8 nDndAction) +{ + return IsInsertionTrivial(GetInsertionPageIndex(), GetModeFromDndAction(nDndAction)); +} + + + + +//===== InsertionIndicatorHandler::ForceShowContext =========================== + +InsertionIndicatorHandler::ForceShowContext::ForceShowContext ( + const ::boost::shared_ptr<InsertionIndicatorHandler>& rpHandler) + : mpHandler(rpHandler) +{ + mpHandler->ForceShow(); +} + + + + +InsertionIndicatorHandler::ForceShowContext::~ForceShowContext (void) +{ + mpHandler->ForceEnd(); +} + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsListener.cxx b/sd/source/ui/slidesorter/controller/SlsListener.cxx index 94b3b4afe717..9f1218013e16 100755 --- a/sd/source/ui/slidesorter/controller/SlsListener.cxx +++ b/sd/source/ui/slidesorter/controller/SlsListener.cxx @@ -25,8 +25,8 @@ * ************************************************************************/ -// MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sd.hxx" + #include "SlsListener.hxx" #include "SlideSorter.hxx" @@ -35,9 +35,15 @@ #include "controller/SlideSorterController.hxx" #include "controller/SlsPageSelector.hxx" #include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsSelectionObserver.hxx" #include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" #include "view/SlideSorterView.hxx" +#include "cache/SlsPageCache.hxx" +#include "cache/SlsPageCacheManager.hxx" #include "drawdoc.hxx" +#include "DrawDocShell.hxx" #include "glob.hrc" #include "ViewShellBase.hxx" @@ -75,7 +81,8 @@ Listener::Listener ( mxFrameWeak(), mpModelChangeLock() { - StartListening (*mrSlideSorter.GetModel().GetDocument()); + StartListening(*mrSlideSorter.GetModel().GetDocument()); + StartListening(*mrSlideSorter.GetModel().GetDocument()->GetDocSh()); mbListeningToDocument = true; // Connect to the UNO document. @@ -127,7 +134,7 @@ Listener::Listener ( if (pMainViewShell != NULL && pMainViewShell!=pViewShell) { - StartListening (*pMainViewShell); + StartListening(*pMainViewShell); } Link aLink (LINK(this, Listener, EventMultiplexerCallback)); @@ -157,7 +164,8 @@ void Listener::ReleaseListeners (void) { if (mbListeningToDocument) { - EndListening (*mrSlideSorter.GetModel().GetDocument()); + EndListening(*mrSlideSorter.GetModel().GetDocument()->GetDocSh()); + EndListening(*mrSlideSorter.GetModel().GetDocument()); mbListeningToDocument = false; } @@ -303,18 +311,15 @@ void Listener::Notify ( if (rHint.ISA(SdrHint)) { SdrHint& rSdrHint (*PTR_CAST(SdrHint,&rHint)); - if(rSdrHint.GetKind() == HINT_PAGEORDERCHG ) + switch (rSdrHint.GetKind()) { - if (rBroadcaster.ISA(SdDrawDocument)) - { - SdDrawDocument& rDocument ( - static_cast<SdDrawDocument&>(rBroadcaster)); - if (rDocument.GetMasterSdPageCount(PK_STANDARD) - == rDocument.GetMasterSdPageCount(PK_NOTES)) - { - mrController.HandleModelChange(); - } - } + case HINT_PAGEORDERCHG: + if (&rBroadcaster == mrSlideSorter.GetModel().GetDocument()) + HandleModelChange(rSdrHint.GetPage()); + break; + + default: + break; } } else if (rHint.ISA(ViewShellHint)) @@ -351,6 +356,16 @@ void Listener::Notify ( break; } } + else if (rHint.ISA(SfxSimpleHint)) + { + SfxSimpleHint& rSfxSimpleHint (*PTR_CAST(SfxSimpleHint,&rHint)); + switch (rSfxSimpleHint.GetId()) + { + case SFX_HINT_DOCCHANGED: + mrController.CheckForMasterPageAssignment(); + break; + } + } } @@ -392,7 +407,7 @@ IMPL_LINK(Listener, EventMultiplexerCallback, ::sd::tools::EventMultiplexerEvent case tools::EventMultiplexerEvent::EID_CONTROLLER_ATTACHED: { ConnectToController(); - mrController.GetPageSelector().UpdateAllPages(); + // mrController.GetPageSelector().GetCoreSelection(); UpdateEditMode(); } break; @@ -402,6 +417,12 @@ IMPL_LINK(Listener, EventMultiplexerCallback, ::sd::tools::EventMultiplexerEvent DisconnectFromController(); break; + case tools::EventMultiplexerEvent::EID_SHAPE_CHANGED: + case tools::EventMultiplexerEvent::EID_SHAPE_INSERTED: + case tools::EventMultiplexerEvent::EID_SHAPE_REMOVED: + HandleShapeModification(static_cast<const SdrPage*>(pEvent->mpUserData)); + break; + default: break; } @@ -463,7 +484,7 @@ void SAL_CALL Listener::propertyChange ( static const ::rtl::OUString sEditModePropertyName ( RTL_CONSTASCII_USTRINGPARAM("IsMasterPageMode")); - if (rEvent.PropertyName.equals (sCurrentPagePropertyName)) + if (rEvent.PropertyName.equals(sCurrentPagePropertyName)) { Any aCurrentPage = rEvent.NewValue; Reference<beans::XPropertySet> xPageSet (aCurrentPage, UNO_QUERY); @@ -475,13 +496,13 @@ void SAL_CALL Listener::propertyChange ( String(RTL_CONSTASCII_USTRINGPARAM("Number"))); sal_Int32 nCurrentPage = 0; aPageNumber >>= nCurrentPage; - mrController.GetPageSelector().UpdateAllPages (); + mrController.GetPageSelector().GetCoreSelection(); // The selection is already set but we call SelectPage() // nevertheless in order to make the new current page the // last recently selected page of the PageSelector. This is // used when making the selection visible. mrController.GetPageSelector().SelectPage(nCurrentPage-1); - mrController.GetCurrentSlideManager()->CurrentSlideHasChanged(nCurrentPage-1); + mrController.GetCurrentSlideManager()->NotifyCurrentSlideChange(nCurrentPage-1); } catch (beans::UnknownPropertyException aEvent) { @@ -520,7 +541,7 @@ void SAL_CALL Listener::frameAction (const frame::FrameActionEvent& rEvent) case frame::FrameAction_COMPONENT_REATTACHED: { ConnectToController(); - mrController.GetPageSelector().UpdateAllPages(); + mrController.GetPageSelector().GetCoreSelection(); UpdateEditMode(); } break; @@ -580,6 +601,84 @@ void Listener::UpdateEditMode (void) +void Listener::HandleModelChange (const SdrPage* pPage) +{ + // Notify model and selection observer about the page. The return value + // of the model call acts as filter as to which events to pass to the + // selection observer. + if (mrSlideSorter.GetModel().NotifyPageEvent(pPage)) + { + // The page of the hint belongs (or belonged) to the model. + + // Tell the cache manager that the preview bitmaps for a deleted + // page can be removed from all caches. + if (pPage!=NULL && ! pPage->IsInserted()) + cache::PageCacheManager::Instance()->ReleasePreviewBitmap(pPage); + + mrController.GetSelectionManager()->GetSelectionObserver()->NotifyPageEvent(pPage); + } + + // Tell the controller about the model change only when the document is + // in a sane state, not just in the middle of a larger change. + SdDrawDocument* pDocument (mrSlideSorter.GetModel().GetDocument()); + if (pDocument != NULL + && pDocument->GetMasterSdPageCount(PK_STANDARD) == pDocument->GetMasterSdPageCount(PK_NOTES)) + { + // A model change can make updates of some text fields necessary + // (like page numbers and page count.) Invalidate all previews in + // the cache to cope with this. Doing this on demand would be a + // nice optimization. + cache::PageCacheManager::Instance()->InvalidateAllPreviewBitmaps(pDocument->getUnoModel()); + + mrController.HandleModelChange(); + } +} + + + +void Listener::HandleShapeModification (const SdrPage* pPage) +{ + if (pPage == NULL) + return; + + // Invalidate the preview of the page (in all slide sorters that display + // it.) + ::boost::shared_ptr<cache::PageCacheManager> pCacheManager (cache::PageCacheManager::Instance()); + if ( ! pCacheManager) + return; + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + if (pDocument == NULL) + { + OSL_ASSERT(pDocument!=NULL); + return; + } + pCacheManager->InvalidatePreviewBitmap(pDocument->getUnoModel(), pPage); + mrSlideSorter.GetView().GetPreviewCache()->RequestPreviewBitmap(pPage); + + // When the page is a master page then invalidate the previews of all + // pages that are linked to this master page. + if (pPage->IsMasterPage()) + { + for (USHORT nIndex=0,nCount=pDocument->GetSdPageCount(PK_STANDARD); + nIndex<nCount; + ++nIndex) + { + const SdPage* pCandidate = pDocument->GetSdPage(nIndex, PK_STANDARD); + if (pCandidate!=NULL && pCandidate->TRG_HasMasterPage()) + { + if (&pCandidate->TRG_GetMasterPage() == pPage) + pCacheManager->InvalidatePreviewBitmap(pDocument->getUnoModel(), pCandidate); + } + else + { + OSL_ASSERT(pCandidate!=NULL && pCandidate->TRG_HasMasterPage()); + } + } + } +} + + + void Listener::ThrowIfDisposed (void) throw (::com::sun::star::lang::DisposedException) diff --git a/sd/source/ui/slidesorter/controller/SlsListener.hxx b/sd/source/ui/slidesorter/controller/SlsListener.hxx index 5613452a1b59..7f65435ff738 100644..100755 --- a/sd/source/ui/slidesorter/controller/SlsListener.hxx +++ b/sd/source/ui/slidesorter/controller/SlsListener.hxx @@ -31,9 +31,7 @@ #include "MutexOwner.hxx" #include "controller/SlideSorterController.hxx" #include <com/sun/star/document/XEventListener.hpp> -#ifndef _COM_SUN_STAR_DOCUMENT_XPROPERTYCHANGELISTENER_HPP_ #include <com/sun/star/beans/XPropertyChangeListener.hpp> -#endif #include <com/sun/star/accessibility/XAccessibleEventListener.hpp> #include <com/sun/star/lang/DisposedException.hpp> #include <com/sun/star/beans/XPropertySet.hpp> @@ -171,6 +169,17 @@ private: */ void UpdateEditMode (void); + /** Handle a change in the order of slides or when the set of slides has + changed, i.e. a slide has been created. + */ + void HandleModelChange (const SdrPage* pPage); + + /** Handle a modification to a shape on the given page. When this is a + regular page then update its preview. When it is a master page then + additionally update the previews of all pages linked to it. + */ + void HandleShapeModification (const SdrPage* pPage); + /** This method throws a DisposedException when the object has already been disposed. */ diff --git a/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx b/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx index 0e8f5e100d1c..51eb81fae214 100755..100644 --- a/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx +++ b/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx @@ -33,6 +33,9 @@ #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" @@ -44,14 +47,16 @@ #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 { +namespace sd { namespace slidesorter { namespace controller { PageSelector::PageSelector (SlideSorter& rSlideSorter) : mrModel(rSlideSorter.GetModel()), @@ -61,7 +66,10 @@ PageSelector::PageSelector (SlideSorter& rSlideSorter) mnBroadcastDisableLevel(0), mbSelectionChangeBroadcastPending(false), mpMostRecentlySelectedPage(), - mpSelectionAnchor() + mpSelectionAnchor(), + mpCurrentPage(), + mnUpdateLockCount(0), + mbIsUpdateCurrentPagePending(false) { CountSelectedPages (); } @@ -71,9 +79,12 @@ PageSelector::PageSelector (SlideSorter& rSlideSorter) 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); + SelectPage(nPageIndex); } @@ -81,21 +92,26 @@ void PageSelector::SelectAllPages (void) 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); + DeselectPage(nPageIndex); + DBG_ASSERT (mnSelectedPageCount==0, "PageSelector::DeselectAllPages: the selected pages counter is not 0"); mnSelectedPageCount = 0; - mpMostRecentlySelectedPage.reset(); mpSelectionAnchor.reset(); } -void PageSelector::UpdateAllPages (void) +void PageSelector::GetCoreSelection (void) { + PageSelector::UpdateLock aLock (*this); + bool bSelectionHasChanged (true); mnSelectedPageCount = 0; model::PageEnumeration aAllPages ( @@ -103,13 +119,14 @@ void PageSelector::UpdateAllPages (void) while (aAllPages.HasMoreElements()) { model::SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); - if (pDescriptor->UpdateSelection()) + if (pDescriptor->GetCoreSelection()) { + mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(pDescriptor); mrSlideSorter.GetView().RequestRepaint(pDescriptor); bSelectionHasChanged = true; } - if (pDescriptor->IsSelected()) + if (pDescriptor->HasState(PageDescriptor::ST_Selected)) mnSelectedPageCount++; } @@ -125,6 +142,20 @@ void PageSelector::UpdateAllPages (void) +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)); @@ -137,7 +168,7 @@ void PageSelector::SelectPage (int nPageIndex) void PageSelector::SelectPage (const SdPage* pPage) { - int nPageIndex = (pPage->GetPageNum()-1) / 2; + const sal_Int32 nPageIndex (mrModel.GetIndex(pPage)); SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); if (pDescriptor.get()!=NULL && pDescriptor->GetPage()==pPage) SelectPage(pDescriptor); @@ -148,9 +179,11 @@ void PageSelector::SelectPage (const SdPage* pPage) void PageSelector::SelectPage (const SharedPageDescriptor& rpDescriptor) { - if (rpDescriptor.get()!=NULL && rpDescriptor->Select()) + if (rpDescriptor.get()!=NULL + && mrSlideSorter.GetView().SetState(rpDescriptor, PageDescriptor::ST_Selected, true)) { - mnSelectedPageCount ++; + ++mnSelectedPageCount; + mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor,true); mrSlideSorter.GetView().RequestRepaint(rpDescriptor); mpMostRecentlySelectedPage = rpDescriptor; @@ -161,27 +194,49 @@ void PageSelector::SelectPage (const SharedPageDescriptor& rpDescriptor) mbSelectionChangeBroadcastPending = true; else mrController.GetSelectionManager()->SelectionHasChanged(); + UpdateCurrentPage(); + + CheckConsistency(); } } -void PageSelector::DeselectPage (int nPageIndex) +void PageSelector::DeselectPage ( + int nPageIndex, + const bool bUpdateCurrentPage) { model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); if (pDescriptor.get() != NULL) - DeselectPage(pDescriptor); + DeselectPage(pDescriptor, bUpdateCurrentPage); } -void PageSelector::DeselectPage (const SharedPageDescriptor& rpDescriptor) +void PageSelector::DeselectPage ( + const SdPage* pPage, + const bool bUpdateCurrentPage) { - if (rpDescriptor.get()!=NULL && rpDescriptor->Deselect()) + 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 --; + --mnSelectedPageCount; + mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor); mrSlideSorter.GetView().RequestRepaint(rpDescriptor); if (mpMostRecentlySelectedPage == rpDescriptor) mpMostRecentlySelectedPage.reset(); @@ -189,6 +244,29 @@ void PageSelector::DeselectPage (const SharedPageDescriptor& rpDescriptor) 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) + { + assert(nSelectionCount==mnSelectedPageCount); } } @@ -199,7 +277,7 @@ bool PageSelector::IsPageSelected (int nPageIndex) { SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); if (pDescriptor.get() != NULL) - return pDescriptor->IsSelected(); + return pDescriptor->HasState(PageDescriptor::ST_Selected); else return false; } @@ -223,30 +301,6 @@ int PageSelector::GetSelectedPageCount (void) const -void PageSelector::PrepareModelChange (void) -{ - DeselectAllPages (); -} - - - - -void PageSelector::HandleModelChange (void) -{ - UpdateAllPages(); -} - - - - -SharedPageDescriptor PageSelector::GetMostRecentlySelectedPage (void) const -{ - return mpMostRecentlySelectedPage; -} - - - - SharedPageDescriptor PageSelector::GetSelectionAnchor (void) const { return mpSelectionAnchor; @@ -270,13 +324,13 @@ void PageSelector::CountSelectedPages (void) -void PageSelector::EnableBroadcasting (bool bMakeSelectionVisible) +void PageSelector::EnableBroadcasting (void) { if (mnBroadcastDisableLevel > 0) mnBroadcastDisableLevel --; if (mnBroadcastDisableLevel==0 && mbSelectionChangeBroadcastPending) { - mrController.GetSelectionManager()->SelectionHasChanged(bMakeSelectionVisible); + mrController.GetSelectionManager()->SelectionHasChanged(); mbSelectionChangeBroadcastPending = false; } } @@ -301,7 +355,7 @@ void PageSelector::DisableBroadcasting (void) for (int nIndex=0; nIndex<nPageCount; nIndex++) { SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex)); - if (pDescriptor.get()!=NULL && pDescriptor->IsSelected()) + if (pDescriptor.get()!=NULL && pDescriptor->HasState(PageDescriptor::ST_Selected)) pSelection->push_back(pDescriptor->GetPage()); } @@ -311,14 +365,124 @@ void PageSelector::DisableBroadcasting (void) -void PageSelector::SetPageSelection (const ::boost::shared_ptr<PageSelection>& rpSelection) +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. + const sal_Int32 nPageCount (GetPageCount()); + for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex) + { + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex)); + if (pDescriptor && pDescriptor->HasState(PageDescriptor::ST_Selected)) + { + // 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(pDescriptor); + + // Restore the selection and prevent a recursive call to + // UpdateCurrentPage(). + SetPageSelection(pSelection, false); + return; + } + } + + // No page is selected. Do not change the current slide. +} + + + + +//===== 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 diff --git a/sd/source/ui/slidesorter/controller/SlsProperties.cxx b/sd/source/ui/slidesorter/controller/SlsProperties.cxx index 7382d769bbe2..532047cfaefe 100644..100755 --- a/sd/source/ui/slidesorter/controller/SlsProperties.cxx +++ b/sd/source/ui/slidesorter/controller/SlsProperties.cxx @@ -37,13 +37,16 @@ Properties::Properties (void) mbIsShowSelection(true), mbIsShowFocus(true), mbIsCenterSelection(false), - mbIsSmoothSelectionScrolling(false), + mbIsSmoothSelectionScrolling(true), mbIsSuspendPreviewUpdatesDuringFullScreenPresentation(true), maBackgroundColor(Application::GetSettings().GetStyleSettings().GetWindowColor()), maTextColor(Application::GetSettings().GetStyleSettings().GetActiveTextColor()), - maSelectionColor(Application::GetSettings().GetStyleSettings().GetMenuHighlightColor()), + maSelectionColor(Application::GetSettings().GetStyleSettings().GetHighlightColor()), maHighlightColor(Application::GetSettings().GetStyleSettings().GetMenuHighlightColor()), - mbIsUIReadOnly(false) + mbIsUIReadOnly(false), + mbIsOnlyPreviewTriggersMouseOver(true), + mbIsHighContrastModeActive( + Application::GetSettings().GetStyleSettings().GetHighContrastMode()) { } @@ -57,6 +60,19 @@ Properties::~Properties (void) +void Properties::HandleDataChangeEvent (void) +{ + maBackgroundColor = Application::GetSettings().GetStyleSettings().GetWindowColor(); + maTextColor = Application::GetSettings().GetStyleSettings().GetActiveTextColor(); + maSelectionColor = Application::GetSettings().GetStyleSettings().GetHighlightColor(); + maHighlightColor = Application::GetSettings().GetStyleSettings().GetMenuHighlightColor(); + mbIsHighContrastModeActive + = Application::GetSettings().GetStyleSettings().GetHighContrastMode(); +} + + + + bool Properties::IsHighlightCurrentSlide (void) const { return mbIsHighlightCurrentSlide; @@ -230,4 +246,28 @@ void Properties::SetUIReadOnly (const bool bIsUIReadOnly) } + + +bool Properties::IsOnlyPreviewTriggersMouseOver (void) const +{ + return mbIsOnlyPreviewTriggersMouseOver; +} + + + + +void Properties::SetOnlyPreviewTriggersMouseOver (const bool bFlag) +{ + mbIsOnlyPreviewTriggersMouseOver = bFlag; +} + + + + +bool Properties::IsHighContrastModeActive (void) const +{ + return mbIsHighContrastModeActive; +} + + } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx b/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx index 5ee7f6f58b82..c94dd6d550b0 100755..100644 --- a/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx +++ b/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx @@ -31,11 +31,12 @@ #include "SlideSorter.hxx" #include "controller/SlideSorterController.hxx" +#include "controller/SlsVisibleAreaManager.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageDescriptor.hxx" #include "view/SlideSorterView.hxx" #include "view/SlsLayouter.hxx" -#include "view/SlsViewOverlay.hxx" +#include "view/SlsTheme.hxx" #include "Window.hxx" #include "sdpage.hxx" @@ -51,11 +52,15 @@ ScrollBarManager::ScrollBarManager (SlideSorter& rSlideSorter) mpVerticalScrollBar(mrSlideSorter.GetVerticalScrollBar()), mnHorizontalPosition (0), mnVerticalPosition (0), - maScrollBorder (10,10), - mnHorizontalScrollFactor (0.1), - mnVerticalScrollFactor (0.1), + maScrollBorder (20,20), + mnHorizontalScrollFactor (0.15), + mnVerticalScrollFactor (0.25), mpScrollBarFiller(mrSlideSorter.GetScrollBarFiller()), - mpContentWindow(mrSlideSorter.GetContentWindow()) + maAutoScrollTimer(), + maAutoScrollOffset(0,0), + mbIsAutoScrollActive(false), + mpContentWindow(mrSlideSorter.GetContentWindow()), + maAutoScrollFunctor() { // Hide the scroll bars by default to prevent display errors while // switching between view shells: In the short time between initiating @@ -66,7 +71,7 @@ ScrollBarManager::ScrollBarManager (SlideSorter& rSlideSorter) mpVerticalScrollBar->Hide(); mpScrollBarFiller->Hide(); - maAutoScrollTimer.SetTimeout(50); + maAutoScrollTimer.SetTimeout(25); maAutoScrollTimer.SetTimeoutHdl ( LINK(this, ScrollBarManager, AutoScrollTimeoutHandler)); } @@ -91,17 +96,15 @@ void ScrollBarManager::LateInitialization (void) void ScrollBarManager::Connect (void) { if (mpVerticalScrollBar != NULL) + { mpVerticalScrollBar->SetScrollHdl ( - LINK( - this, - ScrollBarManager, - VerticalScrollBarHandler)); + LINK(this, ScrollBarManager, VerticalScrollBarHandler)); + } if (mpHorizontalScrollBar != NULL) - mpHorizontalScrollBar->SetScrollHdl ( - LINK( - this, - ScrollBarManager, - HorizontalScrollBarHandler)); + { + mpHorizontalScrollBar->SetScrollHdl( + LINK(this, ScrollBarManager, HorizontalScrollBarHandler)); + } } @@ -110,9 +113,13 @@ void ScrollBarManager::Connect (void) void ScrollBarManager::Disconnect (void) { if (mpVerticalScrollBar != NULL) + { mpVerticalScrollBar->SetScrollHdl (Link()); + } if (mpHorizontalScrollBar != NULL) + { mpHorizontalScrollBar->SetScrollHdl (Link()); + } } @@ -129,12 +136,24 @@ void ScrollBarManager::Disconnect (void) window changes and a second call to the layouter becomes necessary. That call is made anyway after this method returns. */ -Rectangle ScrollBarManager::PlaceScrollBars (const Rectangle& rAvailableArea) +Rectangle ScrollBarManager::PlaceScrollBars ( + const Rectangle& rAvailableArea, + const bool bIsHorizontalScrollBarAllowed, + const bool bIsVerticalScrollBarAllowed) { - Rectangle aRemainingSpace (DetermineScrollBarVisibilities(rAvailableArea)); - PlaceHorizontalScrollBar (rAvailableArea); - PlaceVerticalScrollBar (rAvailableArea); - PlaceFiller (rAvailableArea); + Rectangle aRemainingSpace (DetermineScrollBarVisibilities( + rAvailableArea, + bIsHorizontalScrollBarAllowed, + bIsVerticalScrollBarAllowed)); + + if (mpHorizontalScrollBar!=NULL && mpHorizontalScrollBar->IsVisible()) + PlaceHorizontalScrollBar (rAvailableArea); + + if (mpVerticalScrollBar!=NULL && mpVerticalScrollBar->IsVisible()) + PlaceVerticalScrollBar (rAvailableArea); + + if (mpScrollBarFiller!=NULL && mpScrollBarFiller->IsVisible()) + PlaceFiller (rAvailableArea); return aRemainingSpace; } @@ -144,25 +163,21 @@ Rectangle ScrollBarManager::PlaceScrollBars (const Rectangle& rAvailableArea) void ScrollBarManager::PlaceHorizontalScrollBar (const Rectangle& aAvailableArea) { - if (mpHorizontalScrollBar != NULL - && mpHorizontalScrollBar->IsVisible()) - { - // Save the current relative position. - mnHorizontalPosition = double(mpHorizontalScrollBar->GetThumbPos()) - / double(mpHorizontalScrollBar->GetRange().Len()); - - // Place the scroll bar. - Size aScrollBarSize (mpHorizontalScrollBar->GetSizePixel()); - mpHorizontalScrollBar->SetPosSizePixel ( - Point(aAvailableArea.Left(), - aAvailableArea.Bottom()-aScrollBarSize.Height()+1), - Size (aAvailableArea.GetWidth() - GetVerticalScrollBarWidth(), - aScrollBarSize.Height())); - - // Restore the relative position. - mpHorizontalScrollBar->SetThumbPos( - (long)(0.5 + mnHorizontalPosition * mpHorizontalScrollBar->GetRange().Len())); - } + // Save the current relative position. + mnHorizontalPosition = double(mpHorizontalScrollBar->GetThumbPos()) + / double(mpHorizontalScrollBar->GetRange().Len()); + + // Place the scroll bar. + Size aScrollBarSize (mpHorizontalScrollBar->GetSizePixel()); + mpHorizontalScrollBar->SetPosSizePixel ( + Point(aAvailableArea.Left(), + aAvailableArea.Bottom()-aScrollBarSize.Height()+1), + Size (aAvailableArea.GetWidth() - GetVerticalScrollBarWidth(), + aScrollBarSize.Height())); + + // Restore the relative position. + mpHorizontalScrollBar->SetThumbPos( + (long)(0.5 + mnHorizontalPosition * mpHorizontalScrollBar->GetRange().Len())); } @@ -170,26 +185,17 @@ void ScrollBarManager::PlaceHorizontalScrollBar (const Rectangle& aAvailableArea void ScrollBarManager::PlaceVerticalScrollBar (const Rectangle& aArea) { - if (mpVerticalScrollBar != NULL - && mpVerticalScrollBar->IsVisible()) - { - view::Layouter::DoublePoint aLayouterPosition - = mrSlideSorter.GetView().GetLayouter().ConvertModelToLayouterCoordinates ( - Point (0, mpVerticalScrollBar->GetThumbPos())); - - // Place the scroll bar. - Size aScrollBarSize (mpVerticalScrollBar->GetSizePixel()); - Point aPosition (aArea.Right()-aScrollBarSize.Width()+1, aArea.Top()); - Size aSize (aScrollBarSize.Width(), aArea.GetHeight() - GetHorizontalScrollBarHeight()); - mpVerticalScrollBar->SetPosSizePixel(aPosition, aSize); - - // Restore the position. - mpVerticalScrollBar->SetThumbPos( - mrSlideSorter.GetView().GetLayouter().ConvertLayouterToModelCoordinates( - aLayouterPosition).Y()); - mnVerticalPosition = double(mpVerticalScrollBar->GetThumbPos()) - / double(mpVerticalScrollBar->GetRange().Len()); - } + const double nThumbPosition (mpVerticalScrollBar->GetThumbPos()); + + // Place the scroll bar. + Size aScrollBarSize (mpVerticalScrollBar->GetSizePixel()); + Point aPosition (aArea.Right()-aScrollBarSize.Width()+1, aArea.Top()); + Size aSize (aScrollBarSize.Width(), aArea.GetHeight() - GetHorizontalScrollBarHeight()); + mpVerticalScrollBar->SetPosSizePixel(aPosition, aSize); + + // Restore the position. + mpVerticalScrollBar->SetThumbPos(nThumbPosition); + mnVerticalPosition = nThumbPosition / double(mpVerticalScrollBar->GetRange().Len()); } @@ -197,23 +203,13 @@ void ScrollBarManager::PlaceVerticalScrollBar (const Rectangle& aArea) void ScrollBarManager::PlaceFiller (const Rectangle& aArea) { - // Place the filler when both scroll bars are visible. - if (mpHorizontalScrollBar != NULL - && mpVerticalScrollBar != NULL - && mpHorizontalScrollBar->IsVisible() - && mpVerticalScrollBar->IsVisible()) - { - mpScrollBarFiller->SetPosSizePixel( - Point( - aArea.Right()-mpVerticalScrollBar->GetSizePixel().Width()+1, - aArea.Bottom()-mpHorizontalScrollBar->GetSizePixel().Height()+1), - Size ( - mpVerticalScrollBar->GetSizePixel().Width(), - mpHorizontalScrollBar->GetSizePixel().Height())); - mpScrollBarFiller->Show(); - } - else - mpScrollBarFiller->Hide(); + mpScrollBarFiller->SetPosSizePixel( + Point( + aArea.Right()-mpVerticalScrollBar->GetSizePixel().Width()+1, + aArea.Bottom()-mpHorizontalScrollBar->GetSizePixel().Height()+1), + Size ( + mpVerticalScrollBar->GetSizePixel().Width(), + mpHorizontalScrollBar->GetSizePixel().Height())); } @@ -222,7 +218,7 @@ void ScrollBarManager::PlaceFiller (const Rectangle& aArea) void ScrollBarManager::UpdateScrollBars (bool bResetThumbPosition, bool bUseScrolling) { Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); - ::sd::Window* pWindow = mrSlideSorter.GetView().GetWindow(); + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); Size aWindowModelSize (pWindow->PixelToLogic(pWindow->GetSizePixel())); // The horizontal scroll bar is only shown when the window is @@ -306,14 +302,13 @@ IMPL_LINK(ScrollBarManager, VerticalScrollBarHandler, ScrollBar*, pScrollBar) if (pScrollBar!=NULL && pScrollBar==mpVerticalScrollBar.get() && pScrollBar->IsVisible() - && mrSlideSorter.GetView().GetWindow()!=NULL) + && mrSlideSorter.GetContentWindow()!=NULL) { double nRelativePosition = double(pScrollBar->GetThumbPos()) / double(pScrollBar->GetRange().Len()); mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); - mrSlideSorter.GetView().GetWindow()->SetVisibleXY ( - -1, - nRelativePosition); + mrSlideSorter.GetContentWindow()->SetVisibleXY(-1, nRelativePosition); + mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking(); } return TRUE; } @@ -326,12 +321,13 @@ IMPL_LINK(ScrollBarManager, HorizontalScrollBarHandler, ScrollBar*, pScrollBar) if (pScrollBar!=NULL && pScrollBar==mpHorizontalScrollBar.get() && pScrollBar->IsVisible() - && mrSlideSorter.GetView().GetWindow()!=NULL) + && mrSlideSorter.GetContentWindow()!=NULL) { double nRelativePosition = double(pScrollBar->GetThumbPos()) / double(pScrollBar->GetRange().Len()); mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); - mrSlideSorter.GetView().GetWindow()->SetVisibleXY (nRelativePosition, -1); + mrSlideSorter.GetContentWindow()->SetVisibleXY(nRelativePosition, -1); + mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking(); } return TRUE; } @@ -346,7 +342,7 @@ void ScrollBarManager::SetWindowOrigin ( mnHorizontalPosition = nHorizontalPosition; mnVerticalPosition = nVerticalPosition; - ::sd::Window* pWindow = mrSlideSorter.GetView().GetWindow(); + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); Size aViewSize (pWindow->GetViewSize()); Point aOrigin ( (long int) (mnHorizontalPosition * aViewSize.Width()), @@ -371,31 +367,42 @@ void ScrollBarManager::SetWindowOrigin ( b) when not showing a scroll bar the area used by the page objects fits into the available area in the scroll bars orientation. */ -Rectangle ScrollBarManager::DetermineScrollBarVisibilities (const Rectangle& rAvailableArea) +Rectangle ScrollBarManager::DetermineScrollBarVisibilities ( + const Rectangle& rAvailableArea, + const bool bIsHorizontalScrollBarAllowed, + const bool bIsVerticalScrollBarAllowed) { // Test which combination of scroll bars is the best. bool bShowHorizontal = false; bool bShowVertical = false; - do + if (mrSlideSorter.GetModel().GetPageCount() == 0) { - if (mrSlideSorter.GetModel().GetPageCount() == 0) - // No pages => no scroll bars. - break; - - if (TestScrollBarVisibilities(bShowHorizontal=false, bShowVertical=false, rAvailableArea)) - break; - if (TestScrollBarVisibilities(bShowHorizontal=true, bShowVertical=false, rAvailableArea)) - break; - if (TestScrollBarVisibilities(bShowHorizontal=false, bShowVertical=true, rAvailableArea)) - break; - if (TestScrollBarVisibilities(bShowHorizontal=true, bShowVertical=true, rAvailableArea)) - break; + // No pages => no scroll bars. + } + else if (TestScrollBarVisibilities(false, false, rAvailableArea)) + { + // Nothing to be done. + } + else if (bIsHorizontalScrollBarAllowed + && TestScrollBarVisibilities(true, false, rAvailableArea)) + { + bShowHorizontal = true; + } + else if (bIsVerticalScrollBarAllowed + && TestScrollBarVisibilities(false, true, rAvailableArea)) + { + bShowVertical = true; + } + else + { + bShowHorizontal = true; + bShowVertical = true; } - while (false); // Make the visibility of the scroll bars permanent. mpVerticalScrollBar->Show(bShowVertical); mpHorizontalScrollBar->Show(bShowHorizontal); + mpScrollBarFiller->Show(bShowVertical && bShowHorizontal); // Adapt the remaining space accordingly. Rectangle aRemainingSpace (rAvailableArea); @@ -415,7 +422,7 @@ bool ScrollBarManager::TestScrollBarVisibilities ( bool bVerticalScrollBarVisible, const Rectangle& rAvailableArea) { - bool bAreVisibilitiesOK = true; + model::SlideSorterModel& rModel (mrSlideSorter.GetModel()); // Adapt the available size by subtracting the sizes of the scroll bars // visible in this combination. @@ -427,74 +434,81 @@ bool ScrollBarManager::TestScrollBarVisibilities ( // Tell the view to rearrange its page objects and check whether the // page objects can be shown without clipping. - bool bRearrangeSuccess (false); - if (mrSlideSorter.GetView().GetOrientation() == view::SlideSorterView::HORIZONTAL) - { - bRearrangeSuccess = mrSlideSorter.GetView().GetLayouter().RearrangeHorizontal ( - aBrowserSize, - mrSlideSorter.GetModel().GetPageDescriptor(0)->GetPage()->GetSize(), - mpContentWindow.get(), - mrSlideSorter.GetModel().GetPageCount()); - } - else - { - bRearrangeSuccess = mrSlideSorter.GetView().GetLayouter().RearrangeVertical ( - aBrowserSize, - mrSlideSorter.GetModel().GetPageDescriptor(0)->GetPage()->GetSize(), - mpContentWindow.get()); - } + bool bRearrangeSuccess (mrSlideSorter.GetView().GetLayouter().Rearrange ( + mrSlideSorter.GetView().GetOrientation(), + aBrowserSize, + rModel.GetPageDescriptor(0)->GetPage()->GetSize(), + rModel.GetPageCount())); if (bRearrangeSuccess) { - Size aPageSize = mrSlideSorter.GetView().GetLayouter().GetPageBox ( - mrSlideSorter.GetModel().GetPageCount()).GetSize(); + Size aPageSize = mrSlideSorter.GetView().GetLayouter().GetTotalBoundingBox().GetSize(); Size aWindowModelSize = mpContentWindow->PixelToLogic(aBrowserSize); - bool bHorizontallyClipped = (aPageSize.Width() > aWindowModelSize.Width()); - bool bVerticallyClipped = (aPageSize.Height() > aWindowModelSize.Height()); - bAreVisibilitiesOK = (bHorizontallyClipped == bHorizontalScrollBarVisible) - && (bVerticallyClipped == bVerticalScrollBarVisible); + // The content may be clipped, i.e. not fully visible, in one + // direction only when the scroll bar is visible in that direction. + if (aPageSize.Width() > aWindowModelSize.Width()) + if ( ! bHorizontalScrollBarVisible) + return false; + if (aPageSize.Height() > aWindowModelSize.Height()) + if ( ! bVerticalScrollBarVisible) + return false; + + return true; } else - bAreVisibilitiesOK = false; - - return bAreVisibilitiesOK; + return false; } -void ScrollBarManager::SetTop (const sal_Int32 nNewTop) +void ScrollBarManager::SetTopLeft (const Point aNewTopLeft) { - if (mpVerticalScrollBar != NULL - && mpVerticalScrollBar->GetThumbPos() != nNewTop) - { - // Flush pending repaints before scrolling to avoid temporary artifacts. - mrSlideSorter.GetView().GetWindow()->Update(); + if (( ! mpVerticalScrollBar + || mpVerticalScrollBar->GetThumbPos() == aNewTopLeft.Y()) + && ( ! mpHorizontalScrollBar + || mpHorizontalScrollBar->GetThumbPos() == aNewTopLeft.X())) + return; + + // Flush pending repaints before scrolling to avoid temporary artifacts. + mrSlideSorter.GetContentWindow()->Update(); - mpVerticalScrollBar->SetThumbPos(nNewTop); - mnVerticalPosition = double(nNewTop) / double(mpVerticalScrollBar->GetRange().Len()); - mrSlideSorter.GetView().GetWindow()->SetVisibleXY ( - mnHorizontalPosition, mnVerticalPosition); + if (mpVerticalScrollBar) + { + mpVerticalScrollBar->SetThumbPos(aNewTopLeft.Y()); + mnVerticalPosition = aNewTopLeft.Y() / double(mpVerticalScrollBar->GetRange().Len()); + } + if (mpHorizontalScrollBar) + { + mpHorizontalScrollBar->SetThumbPos(aNewTopLeft.X()); + mnHorizontalPosition = aNewTopLeft.X() / double(mpHorizontalScrollBar->GetRange().Len()); } + + mrSlideSorter.GetContentWindow()->SetVisibleXY(mnHorizontalPosition, mnVerticalPosition); + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); } -void ScrollBarManager::SetLeft (const sal_Int32 nNewLeft) +sal_Int32 ScrollBarManager::GetTop (void) const { - if (mpHorizontalScrollBar != NULL - && mpHorizontalScrollBar->GetThumbPos() != nNewLeft) - { - // Flush pending repaints before scrolling to avoid temporary artifacts. - mrSlideSorter.GetView().GetWindow()->Update(); + if (mpVerticalScrollBar != NULL) + return mpVerticalScrollBar->GetThumbPos(); + else + return 0; +} - mpHorizontalScrollBar->SetThumbPos(nNewLeft); - mnHorizontalPosition = double(nNewLeft) / double(mpHorizontalScrollBar->GetRange().Len()); - mrSlideSorter.GetView().GetWindow()->SetVisibleXY ( - mnHorizontalPosition, mnVerticalPosition); - } + + + +sal_Int32 ScrollBarManager::GetLeft (void) const +{ + if (mpHorizontalScrollBar != NULL) + return mpHorizontalScrollBar->GetThumbPos(); + else + return 0; } @@ -524,7 +538,7 @@ int ScrollBarManager::GetHorizontalScrollBarHeight (void) const void ScrollBarManager::CalcAutoScrollOffset (const Point& rMouseWindowPosition) { - ::sd::Window* pWindow = mrSlideSorter.GetView().GetWindow(); + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); int nDx = 0; int nDy = 0; @@ -579,14 +593,16 @@ void ScrollBarManager::CalcAutoScrollOffset (const Point& rMouseWindowPosition) -bool ScrollBarManager::AutoScroll (const Point& rMouseWindowPosition) +bool ScrollBarManager::AutoScroll ( + const Point& rMouseWindowPosition, + const ::boost::function<void(void)>& rAutoScrollFunctor) { - CalcAutoScrollOffset (rMouseWindowPosition); - bool bResult = RepeatAutoScroll(); - if (bResult) - { - maAutoScrollTimer.Start(); - } + maAutoScrollFunctor = rAutoScrollFunctor; + CalcAutoScrollOffset(rMouseWindowPosition); + bool bResult (true); + if ( ! mbIsAutoScrollActive) + bResult = RepeatAutoScroll(); + return bResult; } @@ -596,6 +612,7 @@ bool ScrollBarManager::AutoScroll (const Point& rMouseWindowPosition) void ScrollBarManager::StopAutoScroll (void) { maAutoScrollTimer.Stop(); + mbIsAutoScrollActive = false; } @@ -607,13 +624,23 @@ bool ScrollBarManager::RepeatAutoScroll (void) { if (mrSlideSorter.GetViewShell() != NULL) { - mrSlideSorter.GetViewShell()->ScrollLines( + mrSlideSorter.GetViewShell()->Scroll( maAutoScrollOffset.Width(), - maAutoScrollOffset.Height()); + maAutoScrollOffset.Height()); + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); + + if (maAutoScrollFunctor) + maAutoScrollFunctor(); + + mbIsAutoScrollActive = true; + maAutoScrollTimer.Start(); + return true; } } + maAutoScrollFunctor = ::boost::function<void(void)>(); + mbIsAutoScrollActive = false; return false; } @@ -628,4 +655,83 @@ IMPL_LINK(ScrollBarManager, AutoScrollTimeoutHandler, Timer *, EMPTYARG) } + + +void ScrollBarManager::Scroll( + const Orientation eOrientation, + const Unit eUnit, + const sal_Int32 nDistance) +{ + bool bIsVertical (false); + switch (eOrientation) + { + case Orientation_Horizontal: bIsVertical = false; break; + case Orientation_Vertical: bIsVertical = true; break; + default: + OSL_ASSERT(eOrientation==Orientation_Horizontal || eOrientation==Orientation_Vertical); + return; + } + + Point aNewTopLeft ( + mpHorizontalScrollBar ? mpHorizontalScrollBar->GetThumbPos() : 0, + mpVerticalScrollBar ? mpVerticalScrollBar->GetThumbPos() : 0); + switch (eUnit) + { + case Unit_Pixel: + if (bIsVertical) + aNewTopLeft.Y() += nDistance; + else + aNewTopLeft.X() += nDistance; + break; + + case Unit_Slide: + { + view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter()); + + // Calculate estimate of new location. + if (bIsVertical) + aNewTopLeft.Y() += nDistance * rLayouter.GetPageObjectSize().Height(); + else + aNewTopLeft.X() += nDistance * rLayouter.GetPageObjectSize().Width(); + + // Adapt location to show whole slides. + if (bIsVertical) + if (nDistance > 0) + { + const sal_Int32 nIndex (rLayouter.GetIndexAtPoint( + Point(aNewTopLeft.X(), aNewTopLeft.Y()+mpVerticalScrollBar->GetVisibleSize()), + true)); + aNewTopLeft.Y() = rLayouter.GetPageObjectBox(nIndex,true).Bottom() + - mpVerticalScrollBar->GetVisibleSize(); + } + else + { + const sal_Int32 nIndex (rLayouter.GetIndexAtPoint( + Point(aNewTopLeft.X(), aNewTopLeft.Y()), + true)); + aNewTopLeft.Y() = rLayouter.GetPageObjectBox(nIndex,true).Top(); + } + else + if (nDistance > 0) + { + const sal_Int32 nIndex (rLayouter.GetIndexAtPoint( + Point(aNewTopLeft.X()+mpVerticalScrollBar->GetVisibleSize(), aNewTopLeft.Y()), + true)); + aNewTopLeft.X() = rLayouter.GetPageObjectBox(nIndex,true).Right() + - mpVerticalScrollBar->GetVisibleSize(); + } + else + { + const sal_Int32 nIndex (rLayouter.GetIndexAtPoint( + Point(aNewTopLeft.X(), aNewTopLeft.Y()), + true)); + aNewTopLeft.X() = rLayouter.GetPageObjectBox(nIndex,true).Left(); + } + } + } + mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking(); + SetTopLeft(aNewTopLeft); +} + + } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx index c1d742ce7158..1d4d075fc3ce 100755..100644 --- a/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx +++ b/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx @@ -31,38 +31,49 @@ #include "SlideSorter.hxx" #include "SlideSorterViewShell.hxx" +#include "SlsDragAndDropContext.hxx" +#include "controller/SlsTransferable.hxx" #include "controller/SlideSorterController.hxx" #include "controller/SlsPageSelector.hxx" #include "controller/SlsFocusManager.hxx" #include "controller/SlsScrollBarManager.hxx" #include "controller/SlsClipboard.hxx" #include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" #include "controller/SlsSelectionManager.hxx" #include "controller/SlsProperties.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsSlotManager.hxx" +#include "controller/SlsVisibleAreaManager.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageDescriptor.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "view/SlideSorterView.hxx" -#include "view/SlsViewOverlay.hxx" #include "view/SlsLayouter.hxx" -#include "view/SlsPageObjectViewObjectContact.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsButtonBar.hxx" #include "framework/FrameworkHelper.hxx" #include "ViewShellBase.hxx" #include "DrawController.hxx" -#include <vcl/sound.hxx> -#include <sfx2/viewfrm.hxx> -#include <sfx2/dispatch.hxx> -#include <svx/svdpagv.hxx> -#include <vcl/msgbox.hxx> #include "Window.hxx" #include "sdpage.hxx" #include "drawdoc.hxx" +#include "DrawDocShell.hxx" +#include "sdxfer.hxx" #include "ViewShell.hxx" #include "ViewShellBase.hxx" #include "FrameView.hxx" #include "app.hrc" #include "sdresid.hxx" #include "strings.hrc" +#include <vcl/sound.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/svdpagv.hxx> +#include <vcl/msgbox.hxx> +#include <svx/svxids.hrc> +#include <boost/bind.hpp> +#include <boost/optional.hpp> namespace { static const sal_uInt32 SINGLE_CLICK (0x00000001); @@ -73,109 +84,304 @@ static const sal_uInt32 MIDDLE_BUTTON (0x00000040); static const sal_uInt32 BUTTON_DOWN (0x00000100); static const sal_uInt32 BUTTON_UP (0x00000200); static const sal_uInt32 MOUSE_MOTION (0x00000400); +static const sal_uInt32 MOUSE_DRAG (0x00000800); // The rest leaves the lower 16 bit untouched so that it can be used with // key codes. static const sal_uInt32 OVER_SELECTED_PAGE (0x00010000); static const sal_uInt32 OVER_UNSELECTED_PAGE (0x00020000); static const sal_uInt32 OVER_FADE_INDICATOR (0x00040000); -static const sal_uInt32 SHIFT_MODIFIER (0x00100000); -static const sal_uInt32 CONTROL_MODIFIER (0x00200000); -static const sal_uInt32 SUBSTITUTION_VISIBLE (0x01000000); -static const sal_uInt32 RECTANGLE_VISIBLE (0x02000000); +static const sal_uInt32 OVER_BUTTON_AREA (0x00080000); +static const sal_uInt32 OVER_BUTTON (0x00100000); +static const sal_uInt32 SHIFT_MODIFIER (0x00200000); +static const sal_uInt32 CONTROL_MODIFIER (0x00400000); static const sal_uInt32 KEY_EVENT (0x10000000); // Some absent events are defined so they can be expressed explicitly. static const sal_uInt32 NO_MODIFIER (0x00000000); -static const sal_uInt32 SUBSTITUTION_NOT_VISIBLE (0x00000000); static const sal_uInt32 NOT_OVER_PAGE (0x00000000); +// Masks +static const sal_uInt32 MODIFIER_MASK (SHIFT_MODIFIER | CONTROL_MODIFIER); +static const sal_uInt32 BUTTON_MASK (LEFT_BUTTON | RIGHT_BUTTON | MIDDLE_BUTTON); } // end of anonymous namespace + +// Define some macros to make the following switch statement more readable. +#define ANY_MODIFIER(code) \ + code|NO_MODIFIER: \ + case code|SHIFT_MODIFIER: \ + case code|CONTROL_MODIFIER + namespace sd { namespace slidesorter { namespace controller { -class SelectionFunction::SubstitutionHandler +//===== SelectionFunction::EventDescriptor ==================================== + +class SelectionFunction::EventDescriptor { public: - SubstitutionHandler (SlideSorter& rSlideSorter); - ~SubstitutionHandler (void); + Point maMousePosition; + Point maMouseModelPosition; + model::SharedPageDescriptor mpHitDescriptor; + SdrPage* mpHitPage; + sal_uInt32 mnEventCode; + bool mbIsOverButton; + InsertionIndicatorHandler::Mode meDragMode; + bool mbMakeSelectionVisible; + bool mbIsLeaving; - /** Create a substitution display of the currently selected pages and - use the given position as the anchor point. + EventDescriptor ( + sal_uInt32 nEventType, + const MouseEvent& rEvent, + SlideSorter& rSlideSorter); + EventDescriptor ( + sal_uInt32 nEventType, + const AcceptDropEvent& rEvent, + const sal_Int8 nDragAction, + SlideSorter& rSlideSorter); + EventDescriptor ( + const KeyEvent& rEvent, + SlideSorter& rSlideSorter); + + void SetDragMode (const InsertionIndicatorHandler::Mode eMode); + +private: + /** Compute a numerical code that describes a mouse event and that can + be used for fast look up of the appropriate reaction. */ - void Start (const Point& rMouseModelPosition); + sal_uInt32 EncodeMouseEvent (const MouseEvent& rEvent) const; - /** Move the substitution display by the distance the mouse has - travelled since the last call to this method or to - CreateSubstitution(). The given point becomes the new anchor. + /** Compute a numerical code that describes a key event and that can + be used for fast look up of the appropriate reaction. */ - void UpdatePosition (const Point& rMouseModelPosition); + sal_uInt32 EncodeKeyEvent (const KeyEvent& rEvent) const; - /** Move the substitution display of the currently selected pages. + /** Compute a numerical code that describes the current state like + whether the selection rectangle is visible or whether the page under + the mouse or the one that has the focus is selected. */ - void Process (void); + sal_uInt32 EncodeState (void) const; +}; - void End (void); - bool HasBeenMoved (void) const; -private: + +//===== SelectionFunction::ModeHandler ======================================== + +class SelectionFunction::ModeHandler +{ +public: + ModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const bool bIsMouseOverIndicatorAllowed); + virtual ~ModeHandler (void); + + virtual Mode GetMode (void) const = 0; + virtual void Abort (void) = 0; + virtual void ProcessEvent (EventDescriptor& rDescriptor); + + /** Set the selection to exactly the specified page and also set it as + the current page. + */ + void SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor); + + /// Deselect all pages. + void DeselectAllPages (void); + void SelectOnePage (const model::SharedPageDescriptor& rpDescriptor); + + /** When the view on which this selection function is working is the + main view then the view is switched to the regular editing view. + */ + void SwitchView (const model::SharedPageDescriptor& rpDescriptor); + + void StartDrag ( + const Point& rMousePosition, + const InsertionIndicatorHandler::Mode eMode); + + bool IsMouseOverIndicatorAllowed (void) const; + +protected: SlideSorter& mrSlideSorter; + SelectionFunction& mrSelectionFunction; + + virtual bool ProcessButtonDownEvent (EventDescriptor& rDescriptor); + virtual bool ProcessButtonUpEvent (EventDescriptor& rDescriptor); + virtual bool ProcessMotionEvent (EventDescriptor& rDescriptor); + virtual bool ProcessDragEvent (EventDescriptor& rDescriptor); + virtual bool HandleUnprocessedEvent (EventDescriptor& rDescriptor); - bool mbHasBeenMoved; + void ReprocessEvent (EventDescriptor& rDescriptor); - /** Determine whether there is a) a substitution and b) its insertion at - the current position of the insertion marker would alter the - document. This would be the case when the substitution has been - moved or is not consecutive. +private: + const bool mbIsMouseOverIndicatorAllowed; +}; + + +/** This is the default handler for processing events. It activates the + multi selection or drag-and-drop when the right conditions are met. +*/ +class NormalModeHandler : public SelectionFunction::ModeHandler +{ +public: + NormalModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction); + virtual ~NormalModeHandler (void); + + virtual SelectionFunction::Mode GetMode (void) const; + virtual void Abort (void); + + void ResetButtonDownLocation (void); + +protected: + virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor); + +private: + ::boost::optional<Point> maButtonDownLocation; + + /** Select all pages between and including the selection anchor and the + specified page. */ - bool IsSubstitutionInsertionNonTrivial (void) const; + void RangeSelect (const model::SharedPageDescriptor& rpDescriptor); }; -class SelectionFunction::EventDescriptor +/** Handle events during a multi selection, which typically is started by + pressing the left mouse button when not over a page. +*/ +class MultiSelectionModeHandler : public SelectionFunction::ModeHandler { public: + /** Start a rectangle selection at the given position. + */ + MultiSelectionModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const Point& rMouseModelPosition, + const sal_uInt32 nEventCode); + virtual ~MultiSelectionModeHandler (void); - Point maMousePosition; - Point maMouseModelPosition; - ::boost::weak_ptr<model::PageDescriptor> mpHitDescriptor; - SdrPage* mpHitPage; - sal_uInt32 mnEventCode; + virtual SelectionFunction::Mode GetMode (void) const; + virtual void Abort (void); + virtual void ProcessEvent (SelectionFunction::EventDescriptor& rDescriptor); - EventDescriptor ( - sal_uInt32 nEventType, - const MouseEvent& rEvent, - SlideSorter& rSlideSorter); - EventDescriptor ( - const KeyEvent& rEvent, - SlideSorter& rSlideSorter); + enum SelectionMode { SM_Normal, SM_Add, SM_Toggle }; + + void SetSelectionMode (const SelectionMode eSelectionMode); + void SetSelectionModeFromModifier (const sal_uInt32 nEventCode); + +protected: + virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool HandleUnprocessedEvent (SelectionFunction::EventDescriptor& rDescriptor); + +private: + SelectionMode meSelectionMode; + Point maSecondCorner; + Pointer maSavedPointer; + sal_Int32 mnAnchorIndex; + sal_Int32 mnSecondIndex; + view::ButtonBar::Lock maButtonBarLock; + + virtual void UpdateModelPosition (const Point& rMouseModelPosition); + virtual void UpdateSelection (void); + + /** Update the rectangle selection so that the given position becomes + the new second point of the selection rectangle. + */ + void UpdatePosition ( + const Point& rMousePosition, + const bool bAllowAutoScroll); + + void UpdateSelectionState ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bIsInSelection) const; }; +/** Handle events during drag-and-drop. +*/ +class DragAndDropModeHandler : public SelectionFunction::ModeHandler +{ +public: + DragAndDropModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const Point& rMousePosition, + ::Window* pWindow); + virtual ~DragAndDropModeHandler (void); + + virtual SelectionFunction::Mode GetMode (void) const; + virtual void Abort (void); + +protected: + virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor); + +private: + ::boost::scoped_ptr<DragAndDropContext> mpDragAndDropContext; +}; + + +/** Handle events while the left mouse button is pressed over the button + bar. +*/ +class ButtonModeHandler : public SelectionFunction::ModeHandler +{ +public: + ButtonModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction); + virtual ~ButtonModeHandler (void); + virtual void Abort (void); + + virtual SelectionFunction::Mode GetMode (void) const; + +protected: + virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor); +}; + + + + +//===== SelectionFunction ===================================================== + TYPEINIT1(SelectionFunction, FuPoor); SelectionFunction::SelectionFunction ( SlideSorter& rSlideSorter, SfxRequest& rRequest) - : SlideFunction (rSlideSorter, rRequest), + : FuPoor ( + rSlideSorter.GetViewShell(), + rSlideSorter.GetContentWindow().get(), + &rSlideSorter.GetView(), + rSlideSorter.GetModel().GetDocument(), + rRequest), mrSlideSorter(rSlideSorter), mrController(mrSlideSorter.GetController()), mbDragSelection(false), maInsertionMarkerBox(), mbProcessingMouseButtonDown(false), - mpSubstitutionHandler(new SubstitutionHandler(mrSlideSorter)) + mnShiftKeySelectionAnchor(-1), + mpModeHandler(new NormalModeHandler(rSlideSorter, *this)) { - //af aDelayToScrollTimer.SetTimeout(50); - aDragTimer.SetTimeoutHdl( LINK( this, SelectionFunction, DragSlideHdl ) ); } + + + SelectionFunction::~SelectionFunction (void) { - aDragTimer.Stop(); + mpModeHandler.reset(); } @@ -196,9 +402,10 @@ BOOL SelectionFunction::MouseButtonDown (const MouseEvent& rEvent) { // #95491# remember button state for creation of own MouseEvents SetMouseButtonCode (rEvent.GetButtons()); + aMDPos = rEvent.GetPosPixel(); mbProcessingMouseButtonDown = true; - mpWindow->CaptureMouse(); + // mpWindow->CaptureMouse(); ProcessMouseEvent(BUTTON_DOWN, rEvent); @@ -210,45 +417,7 @@ BOOL SelectionFunction::MouseButtonDown (const MouseEvent& rEvent) BOOL SelectionFunction::MouseMove (const MouseEvent& rEvent) { - Point aMousePosition (rEvent.GetPosPixel()); - - // Determine page under mouse and show the mouse over effect. - model::SharedPageDescriptor pHitDescriptor (mrController.GetPageAt(aMousePosition)); - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - rOverlay.GetMouseOverIndicatorOverlay().SetSlideUnderMouse( - rEvent.IsLeaveWindow() ? model::SharedPageDescriptor() : pHitDescriptor); - if (pHitDescriptor.get() != NULL) - rOverlay.GetMouseOverIndicatorOverlay().setVisible(true); - else - rOverlay.GetMouseOverIndicatorOverlay().setVisible(false); - - // Allow one mouse move before the drag timer is disabled. - if (aDragTimer.IsActive()) - { - if (bFirstMouseMove) - bFirstMouseMove = FALSE; - else - aDragTimer.Stop(); - } - - Rectangle aRectangle (Point(0,0),mpWindow->GetOutputSizePixel()); - if ( ! aRectangle.IsInside(aMousePosition) - && rOverlay.GetSubstitutionOverlay().isVisible()) - { - // Mouse left the window with pressed left button. Make it a drag. - StartDrag(); - } - else - { - // Call ProcessMouseEvent() only when one of the buttons is - // pressed. This prevents calling the method on every motion. - if (rEvent.GetButtons() != 0 - && mbProcessingMouseButtonDown) - { - ProcessMouseEvent(MOUSE_MOTION, rEvent); - } - } - + ProcessMouseEvent(MOUSE_MOTION, rEvent); return TRUE; } @@ -259,16 +428,10 @@ BOOL SelectionFunction::MouseButtonUp (const MouseEvent& rEvent) { mrController.GetScrollBarManager().StopAutoScroll (); - // #95491# remember button state for creation of own MouseEvents - SetMouseButtonCode (rEvent.GetButtons()); - - if (aDragTimer.IsActive()) - aDragTimer.Stop(); - ProcessMouseEvent(BUTTON_UP, rEvent); mbProcessingMouseButtonDown = false; - mpWindow->ReleaseMouse(); +// mpWindow->ReleaseMouse(); return TRUE; } @@ -276,39 +439,62 @@ BOOL SelectionFunction::MouseButtonUp (const MouseEvent& rEvent) +void SelectionFunction::NotifyDragFinished (void) +{ + SwitchToNormalMode(); +} + + + + BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) { + view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + PageSelector::UpdateLock aLock (mrSlideSorter); FocusManager& rFocusManager (mrController.GetFocusManager()); BOOL bResult = FALSE; - switch (rEvent.GetKeyCode().GetCode()) + const KeyCode& rCode (rEvent.GetKeyCode()); + switch (rCode.GetCode()) { case KEY_RETURN: - if (rFocusManager.HasFocus()) + { + model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (rFocusManager.HasFocus() && pDescriptor && pViewShell!=NULL) { - model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); - if (pDescriptor.get() != NULL) + // The Return key triggers different functions depending on + // whether the slide sorter is the main view or displayed in + // the right pane. + if (pViewShell->IsMainViewShell()) + { + mpModeHandler->SetCurrentPage(pDescriptor); + mpModeHandler->SwitchView(pDescriptor); + } + else { - SetCurrentPage(pDescriptor); - SwitchView(pDescriptor); + pViewShell->GetDispatcher()->Execute( + SID_INSERTPAGE, + SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD); } bResult = TRUE; } break; + } case KEY_TAB: if ( ! rFocusManager.IsFocusShowing()) + { rFocusManager.ShowFocus(); - else - if (rEvent.GetKeyCode().IsShift()) - rFocusManager.MoveFocus (FocusManager::FMD_LEFT); - else - rFocusManager.MoveFocus (FocusManager::FMD_RIGHT); - bResult = TRUE; + bResult = TRUE; + } break; case KEY_ESCAPE: - rFocusManager.SetFocusToToolBox(); + // When there is an active multiselection or drag-and-drop + // operation then stop that. + mpModeHandler->Abort(); + SwitchToNormalMode(); bResult = TRUE; break; @@ -316,12 +502,10 @@ BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) { // Toggle the selection state. model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); - if (pDescriptor.get() != NULL) + if (pDescriptor && rCode.IsMod1()) { - // Doing a multi selection by default. Can we ask the event - // for the state of the shift key? - if (pDescriptor->IsSelected()) - mrController.GetPageSelector().DeselectPage(pDescriptor); + if (pDescriptor->HasState(model::PageDescriptor::ST_Selected)) + mrController.GetPageSelector().DeselectPage(pDescriptor, false); else mrController.GetPageSelector().SelectPage(pDescriptor); } @@ -332,25 +516,25 @@ BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) // Move the focus indicator left. case KEY_LEFT: - rFocusManager.MoveFocus (FocusManager::FMD_LEFT); + MoveFocus(FocusManager::FMD_LEFT, rCode.IsShift(), rCode.IsMod1()); bResult = TRUE; break; // Move the focus indicator right. case KEY_RIGHT: - rFocusManager.MoveFocus (FocusManager::FMD_RIGHT); + MoveFocus(FocusManager::FMD_RIGHT, rCode.IsShift(), rCode.IsMod1()); bResult = TRUE; break; // Move the focus indicator up. case KEY_UP: - rFocusManager.MoveFocus (FocusManager::FMD_UP); + MoveFocus(FocusManager::FMD_UP, rCode.IsShift(), rCode.IsMod1()); bResult = TRUE; break; // Move the focus indicator down. case KEY_DOWN: - rFocusManager.MoveFocus (FocusManager::FMD_DOWN); + MoveFocus(FocusManager::FMD_DOWN, rCode.IsShift(), rCode.IsMod1()); bResult = TRUE; break; @@ -366,36 +550,35 @@ BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) bResult = TRUE; break; + case KEY_HOME: + GotoPage(0); + bResult = TRUE; + break; + + case KEY_END: + GotoPage(mrSlideSorter.GetModel().GetPageCount()-1); + bResult = TRUE; + break; + case KEY_DELETE: case KEY_BACKSPACE: { - if (mrController.GetProperties()->IsUIReadOnly()) + if (mrSlideSorter.GetProperties()->IsUIReadOnly()) break; - int nSelectedPagesCount = 0; - - // Count the selected pages and look if there any objects on any - // of the selected pages so that we can warn the user and - // prevent an accidental deletion. - model::PageEnumeration aSelectedPages ( - model::PageEnumerationProvider::CreateSelectedPagesEnumeration( - mrSlideSorter.GetModel())); - while (aSelectedPages.HasMoreElements()) - { - nSelectedPagesCount++; - aSelectedPages.GetNextElement(); - } - - if (nSelectedPagesCount > 0) - mrController.GetSelectionManager()->DeleteSelectedPages(); + mrController.GetSelectionManager()->DeleteSelectedPages(rCode.GetCode()==KEY_DELETE); + mnShiftKeySelectionAnchor = -1; bResult = TRUE; } break; case KEY_F10: - if (rEvent.GetKeyCode().IsShift()) - ProcessKeyEvent(rEvent); + if (rCode.IsShift()) + { + mpModeHandler->SelectOnePage( + mrSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor()); + } break; default: @@ -403,7 +586,7 @@ BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) } if ( ! bResult) - bResult = SlideFunction::KeyInput (rEvent); + bResult = FuPoor::KeyInput(rEvent); return bResult; } @@ -411,6 +594,73 @@ BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) +void SelectionFunction::MoveFocus ( + const FocusManager::FocusMoveDirection eDirection, + const bool bIsShiftDown, + const bool bIsControlDown) +{ + // Remember the anchor of shift key multi selection. + if (bIsShiftDown) + { + if (mnShiftKeySelectionAnchor<0) + { + model::SharedPageDescriptor pFocusedDescriptor ( + mrController.GetFocusManager().GetFocusedPageDescriptor()); + mnShiftKeySelectionAnchor = pFocusedDescriptor->GetPageIndex(); + } + } + else if ( ! bIsControlDown) + ResetShiftKeySelectionAnchor(); + + mrController.GetFocusManager().MoveFocus(eDirection); + + PageSelector& rSelector (mrController.GetPageSelector()); + model::SharedPageDescriptor pFocusedDescriptor ( + mrController.GetFocusManager().GetFocusedPageDescriptor()); + if (bIsShiftDown) + { + // When shift is pressed then select all pages in the range between + // the currently and the previously focused pages, including them. + if (pFocusedDescriptor) + { + sal_Int32 nPageRangeEnd (pFocusedDescriptor->GetPageIndex()); + model::PageEnumeration aPages ( + model::PageEnumerationProvider::CreateAllPagesEnumeration( + mrSlideSorter.GetModel())); + while (aPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aPages.GetNextElement()); + if (pDescriptor) + { + const sal_Int32 nPageIndex(pDescriptor->GetPageIndex()); + if ((nPageIndex>=mnShiftKeySelectionAnchor && nPageIndex<=nPageRangeEnd) + || (nPageIndex<=mnShiftKeySelectionAnchor && nPageIndex>=nPageRangeEnd)) + { + rSelector.SelectPage(pDescriptor); + } + else + { + rSelector.DeselectPage(pDescriptor); + } + } + } + } + } + else if (bIsControlDown) + { + // When control is pressed then do not alter the selection or the + // current page, just move the focus. + } + else + { + // Without shift just select the focused page. + mpModeHandler->SelectOnePage(pFocusedDescriptor); + } +} + + + + void SelectionFunction::Activate() { FuPoor::Activate(); @@ -442,7 +692,7 @@ void SelectionFunction::ScrollEnd (void) void SelectionFunction::DoCut (void) { - if ( ! mrController.GetProperties()->IsUIReadOnly()) + if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) { mrController.GetClipboard().DoCut(); } @@ -461,7 +711,7 @@ void SelectionFunction::DoCopy (void) void SelectionFunction::DoPaste (void) { - if ( ! mrController.GetProperties()->IsUIReadOnly()) + if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) { mrController.GetClipboard().DoPaste(); } @@ -470,258 +720,316 @@ void SelectionFunction::DoPaste (void) -void SelectionFunction::Paint (const Rectangle&, ::sd::Window* ) +bool SelectionFunction::cancel (void) { + mrController.GetFocusManager().ToggleFocus(); + return true; } -IMPL_LINK( SelectionFunction, DragSlideHdl, Timer*, EMPTYARG ) +void SelectionFunction::GotoNextPage (int nOffset) { - StartDrag(); - return 0; + model::SharedPageDescriptor pDescriptor + = mrController.GetCurrentSlideManager()->GetCurrentSlide(); + if (pDescriptor.get() != NULL) + { + SdPage* pPage = pDescriptor->GetPage(); + OSL_ASSERT(pPage!=NULL); + sal_Int32 nIndex = (pPage->GetPageNum()-1) / 2; + GotoPage(nIndex + nOffset); + } + ResetShiftKeySelectionAnchor(); } -void SelectionFunction::StartDrag (void) +void SelectionFunction::GotoPage (int nIndex) { - if (mbPageHit - && ! mrController.GetProperties()->IsUIReadOnly()) + USHORT nPageCount = (USHORT)mrSlideSorter.GetModel().GetPageCount(); + + if (nIndex >= nPageCount) + nIndex = nPageCount - 1; + if (nIndex < 0) + nIndex = 0; + + mrController.GetFocusManager().SetFocusedPage(nIndex); + model::SharedPageDescriptor pNextPageDescriptor ( + mrSlideSorter.GetModel().GetPageDescriptor (nIndex)); + if (pNextPageDescriptor.get() != NULL) + mpModeHandler->SetCurrentPage(pNextPageDescriptor); + else { - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - mpSubstitutionHandler->Start(rOverlay.GetSubstitutionOverlay().GetPosition()); - mbPageHit = false; - mpWindow->ReleaseMouse(); - - if (mrSlideSorter.GetViewShell() != NULL) - { - SlideSorterViewShell* pSlideSorterViewShell - = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); - pSlideSorterViewShell->StartDrag ( - rOverlay.GetSubstitutionOverlay().GetPosition(), - mpWindow); - } + OSL_ASSERT(pNextPageDescriptor.get() != NULL); } + ResetShiftKeySelectionAnchor(); } -bool SelectionFunction::cancel (void) +void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent) { - mrController.GetFocusManager().ToggleFocus(); - return true; + // #95491# remember button state for creation of own MouseEvents + SetMouseButtonCode (rEvent.GetButtons()); + + EventDescriptor aEventDescriptor (nEventType, rEvent, mrSlideSorter); + ProcessEvent(aEventDescriptor); } -void SelectionFunction::SelectHitPage (const model::SharedPageDescriptor& rpDescriptor) +void SelectionFunction::MouseDragged ( + const AcceptDropEvent& rEvent, + const sal_Int8 nDragAction) { - mrController.GetPageSelector().SelectPage(rpDescriptor); + EventDescriptor aEventDescriptor (MOUSE_DRAG, rEvent, nDragAction, mrSlideSorter); + ProcessEvent(aEventDescriptor); } -void SelectionFunction::DeselectHitPage (const model::SharedPageDescriptor& rpDescriptor) +void SelectionFunction::ProcessKeyEvent (const KeyEvent& rEvent) { - mrController.GetPageSelector().DeselectPage(rpDescriptor); + EventDescriptor aEventDescriptor (rEvent, mrSlideSorter); + ProcessEvent(aEventDescriptor); } -void SelectionFunction::DeselectAllPages (void) +void SelectionFunction::ProcessEvent (EventDescriptor& rDescriptor) { - mrController.GetPageSelector().DeselectAllPages(); + // The call to ProcessEvent may switch to another mode handler. + // Prevent the untimely destruction of the called handler by aquiring a + // temporary reference here. + ::boost::shared_ptr<ModeHandler> pModeHandler (mpModeHandler); + pModeHandler->ProcessEvent(rDescriptor); } -void SelectionFunction::StartRectangleSelection (const Point& rMouseModelPosition) +bool Match ( + const sal_uInt32 nEventCode, + const sal_uInt32 nPositivePattern) { - if (mrController.GetProperties()->IsShowSelection()) - { - mrSlideSorter.GetView().GetOverlay().GetSelectionRectangleOverlay().Start( - rMouseModelPosition); - } + return (nEventCode & nPositivePattern)==nPositivePattern; +} + + + + +void SelectionFunction::SwitchToNormalMode (void) +{ + if (mpModeHandler->GetMode() != NormalMode) + SwitchMode(::boost::shared_ptr<ModeHandler>( + new NormalModeHandler(mrSlideSorter, *this))); } -void SelectionFunction::UpdateRectangleSelection (const Point& rMouseModelPosition) +void SelectionFunction::SwitchToDragAndDropMode (const Point aMousePosition) { - if (mrController.GetProperties()->IsShowSelection()) + if (mpModeHandler->GetMode() != DragAndDropMode) { - mrSlideSorter.GetView().GetOverlay().GetSelectionRectangleOverlay().Update( - rMouseModelPosition); + SwitchMode(::boost::shared_ptr<ModeHandler>( + new DragAndDropModeHandler(mrSlideSorter, *this, aMousePosition, mpWindow))); } } -void SelectionFunction::ProcessRectangleSelection (bool bToggleSelection) +void SelectionFunction::SwitchToMultiSelectionMode ( + const Point aMousePosition, + const sal_uInt32 nEventCode) { - if ( ! mrController.GetProperties()->IsShowSelection()) - return; + if (mpModeHandler->GetMode() != MultiSelectionMode) + SwitchMode(::boost::shared_ptr<ModeHandler>( + new MultiSelectionModeHandler(mrSlideSorter, *this, aMousePosition, nEventCode))); +} - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - if (rOverlay.GetSelectionRectangleOverlay().isVisible()) + + + +bool SelectionFunction::SwitchToButtonMode (void) +{ + // Do not show the buttons for draw pages. + ::boost::shared_ptr<ViewShell> pMainViewShell (mrSlideSorter.GetViewShellBase()->GetMainViewShell()); + if (pMainViewShell + && pMainViewShell->GetShellType()!=ViewShell::ST_DRAW + && mpModeHandler->GetMode() != ButtonMode) { - PageSelector& rSelector (mrController.GetPageSelector()); - - rOverlay.GetSelectionRectangleOverlay().setVisible(false); - - // Select all pages whose page object lies completly inside the drag - // rectangle. - const Rectangle& rSelectionRectangle ( - rOverlay.GetSelectionRectangleOverlay().GetSelectionRectangle()); - model::PageEnumeration aPages ( - model::PageEnumerationProvider::CreateAllPagesEnumeration( - mrSlideSorter.GetModel())); - while (aPages.HasMoreElements()) - { - model::SharedPageDescriptor pDescriptor (aPages.GetNextElement()); - Rectangle aPageBox (mrSlideSorter.GetView().GetPageBoundingBox( - pDescriptor, - view::SlideSorterView::CS_MODEL, - view::SlideSorterView::BBT_SHAPE)); - if (rSelectionRectangle.IsOver(aPageBox)) - { - // When we are extending the selection (shift key is - // pressed) then toggle the selection state of the page. - // Otherwise select it: this results in the previously - // selected pages becoming deslected. - if (bToggleSelection && pDescriptor->IsSelected()) - rSelector.DeselectPage(pDescriptor); - else - rSelector.SelectPage(pDescriptor); - } - } + SwitchMode(::boost::shared_ptr<ModeHandler>(new ButtonModeHandler(mrSlideSorter, *this))); + return true; } + else + return false; } -void SelectionFunction::PrepareMouseMotion (const Point& ) +void SelectionFunction::SwitchMode (const ::boost::shared_ptr<ModeHandler>& rpHandler) { - if ( ! mrController.GetProperties()->IsUIReadOnly()) + // Not all modes allow mouse over indicator. + if (mpModeHandler->IsMouseOverIndicatorAllowed() != rpHandler->IsMouseOverIndicatorAllowed()) { - bFirstMouseMove = TRUE; - aDragTimer.Start(); + if ( ! rpHandler->IsMouseOverIndicatorAllowed()) + { + mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor()); + mrSlideSorter.GetView().GetButtonBar().ResetPage(); + } + else + mrSlideSorter.GetView().UpdatePageUnderMouse(false); } + + mpModeHandler = rpHandler; } -void SelectionFunction::RangeSelect (const model::SharedPageDescriptor& rpDescriptor) +void SelectionFunction::ResetShiftKeySelectionAnchor (void) { - PageSelector& rSelector (mrController.GetPageSelector()); + mnShiftKeySelectionAnchor = -1; +} - model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor()); - DeselectAllPages(); - if (pAnchor.get() != NULL) - { - // Select all pages between the anchor and the given one, including - // the two. - USHORT nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2); - USHORT nOtherIndex ((rpDescriptor->GetPage()->GetPageNum()-1) / 2); - // Iterate over all pages in the range. Start with the anchor - // page. This way the PageSelector will recognize it again as - // anchor (the first selected page after a DeselectAllPages() - // becomes the anchor.) - USHORT nStep = (nAnchorIndex < nOtherIndex) ? +1 : -1; - USHORT nIndex = nAnchorIndex; - while (true) - { - rSelector.SelectPage(nIndex); - if (nIndex == nOtherIndex) - break; - nIndex = nIndex + nStep; - } + +void SelectionFunction::ResetMouseAnchor (void) +{ + if (mpModeHandler && mpModeHandler->GetMode() == NormalMode) + { + ::boost::shared_ptr<NormalModeHandler> pHandler ( + ::boost::dynamic_pointer_cast<NormalModeHandler>(mpModeHandler)); + if (pHandler) + pHandler->ResetButtonDownLocation(); } } -void SelectionFunction::GotoNextPage (int nOffset) +//===== EventDescriptor ======================================================= + +SelectionFunction::EventDescriptor::EventDescriptor ( + const sal_uInt32 nEventType, + const MouseEvent& rEvent, + SlideSorter& rSlideSorter) + : maMousePosition(rEvent.GetPosPixel()), + maMouseModelPosition(), + mpHitDescriptor(), + mpHitPage(), + mnEventCode(nEventType), + mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()), + meDragMode(InsertionIndicatorHandler::MoveMode), + mbMakeSelectionVisible(true), + mbIsLeaving(false) { - model::SharedPageDescriptor pDescriptor - = mrController.GetCurrentSlideManager()->GetCurrentSlide(); - if (pDescriptor.get() != NULL) + maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition); + mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition); + if (mpHitDescriptor) { - SdPage* pPage = pDescriptor->GetPage(); - OSL_ASSERT(pPage!=NULL); - sal_Int32 nIndex = (pPage->GetPageNum()-1) / 2; - nIndex += nOffset; - USHORT nPageCount = (USHORT)mrSlideSorter.GetModel().GetPageCount(); - - if (nIndex >= nPageCount) - nIndex = nPageCount - 1; - if (nIndex < 0) - nIndex = 0; - - mrController.GetFocusManager().SetFocusedPage(nIndex); - model::SharedPageDescriptor pNextPageDescriptor ( - mrSlideSorter.GetModel().GetPageDescriptor (nIndex)); - if (pNextPageDescriptor.get() != NULL) - SetCurrentPage(pNextPageDescriptor); - else - { - OSL_ASSERT(pNextPageDescriptor.get() != NULL); - } + mpHitPage = mpHitDescriptor->GetPage(); } + + mnEventCode |= EncodeMouseEvent(rEvent); + mnEventCode |= EncodeState(); + + // Detect the mouse leaving the window. When not button is pressed then + // we can call IsLeaveWindow at the event. Otherwise we have to make an + // explicit test. + mbIsLeaving = rEvent.IsLeaveWindow() + || ! Rectangle(Point(0,0), + rSlideSorter.GetContentWindow()->GetOutputSizePixel()).IsInside(maMousePosition); } -void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent) +SelectionFunction::EventDescriptor::EventDescriptor ( + const sal_uInt32 nEventType, + const AcceptDropEvent& rEvent, + const sal_Int8 nDragAction, + SlideSorter& rSlideSorter) + : maMousePosition(rEvent.maPosPixel), + maMouseModelPosition(), + mpHitDescriptor(), + mpHitPage(), + mnEventCode(nEventType), + mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()), + meDragMode(InsertionIndicatorHandler::GetModeFromDndAction(nDragAction)), + mbMakeSelectionVisible(true), + mbIsLeaving(false) { - // #95491# remember button state for creation of own MouseEvents - SetMouseButtonCode (rEvent.GetButtons()); + maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition); + mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition); + if (mpHitDescriptor) + { + mpHitPage = mpHitDescriptor->GetPage(); + } + + mnEventCode |= EncodeState(); + + // Detect the mouse leaving the window. When not button is pressed then + // we can call IsLeaveWindow at the event. Otherwise we have to make an + // explicit test. + mbIsLeaving = rEvent.mbLeaving + || ! Rectangle(Point(0,0), + rSlideSorter.GetContentWindow()->GetOutputSizePixel()).IsInside(maMousePosition); +} - // 1. Compute some frequently used values relating to the event. - ::std::auto_ptr<EventDescriptor> pEventDescriptor ( - new EventDescriptor(nEventType, rEvent, mrSlideSorter)); - // 2. Compute a numerical code that describes the event and that is used - // for fast look-up of the associated reaction. - pEventDescriptor->mnEventCode = EncodeMouseEvent(*pEventDescriptor, rEvent); - // 3. Process the event. - EventPreprocessing(*pEventDescriptor); - if ( ! EventProcessing(*pEventDescriptor)) + +SelectionFunction::EventDescriptor::EventDescriptor ( + const KeyEvent& rEvent, + SlideSorter& rSlideSorter) + : maMousePosition(), + maMouseModelPosition(), + mpHitDescriptor(), + mpHitPage(), + mnEventCode(KEY_EVENT), + mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()), + meDragMode(InsertionIndicatorHandler::MoveMode), + mbMakeSelectionVisible(true), + mbIsLeaving(false) +{ + model::SharedPageDescriptor pHitDescriptor ( + rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor()); + if (pHitDescriptor.get() != NULL) { - OSL_TRACE ("can not handle event code %x", pEventDescriptor->mnEventCode); + mpHitPage = pHitDescriptor->GetPage(); + mpHitDescriptor = pHitDescriptor; } - EventPostprocessing(*pEventDescriptor); - if (nEventType == BUTTON_UP) - mbPageHit = false; + mnEventCode |= EncodeKeyEvent(rEvent) | EncodeState(); } -sal_uInt32 SelectionFunction::EncodeMouseEvent ( - const EventDescriptor& rDescriptor, +void SelectionFunction::EventDescriptor::SetDragMode (const InsertionIndicatorHandler::Mode eMode) +{ + meDragMode = eMode; +} + + + + +sal_uInt32 SelectionFunction::EventDescriptor::EncodeMouseEvent ( const MouseEvent& rEvent) const { // Initialize with the type of mouse event. - sal_uInt32 nEventCode (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION)); + sal_uInt32 nEventCode (mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION)); // Detect the affected button. switch (rEvent.GetButtons()) @@ -738,28 +1046,16 @@ sal_uInt32 SelectionFunction::EncodeMouseEvent ( case 2: nEventCode |= DOUBLE_CLICK; break; } - // Detect whether the event has happened over a page object. - if (rDescriptor.mpHitPage != NULL && ! rDescriptor.mpHitDescriptor.expired()) - { - model::SharedPageDescriptor pHitDescriptor (rDescriptor.mpHitDescriptor); - if (pHitDescriptor->IsSelected()) - nEventCode |= OVER_SELECTED_PAGE; - else - nEventCode |= OVER_UNSELECTED_PAGE; - } - // Detect pressed modifier keys. if (rEvent.IsShift()) nEventCode |= SHIFT_MODIFIER; if (rEvent.IsMod1()) nEventCode |= CONTROL_MODIFIER; - // Detect whether we are dragging pages or dragging a selection rectangle. - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - if (rOverlay.GetSubstitutionOverlay().isVisible()) - nEventCode |= SUBSTITUTION_VISIBLE; - if (rOverlay.GetSelectionRectangleOverlay().isVisible()) - nEventCode |= RECTANGLE_VISIBLE; + // Detect whether the mouse is over one of the active elements inside a + // page object. + if (mbIsOverButton) + nEventCode |= OVER_BUTTON; return nEventCode; } @@ -767,551 +1063,962 @@ sal_uInt32 SelectionFunction::EncodeMouseEvent ( -void SelectionFunction::ProcessKeyEvent (const KeyEvent& rEvent) +sal_uInt32 SelectionFunction::EventDescriptor::EncodeKeyEvent (const KeyEvent& rEvent) const { - // 1. Compute some frequently used values relating to the event. - ::std::auto_ptr<EventDescriptor> pEventDescriptor ( - new EventDescriptor(rEvent, mrSlideSorter)); + // The key code in the lower 16 bit. + sal_uInt32 nEventCode (rEvent.GetKeyCode().GetCode()); - // 2. Encode the event. - pEventDescriptor->mnEventCode = EncodeKeyEvent(*pEventDescriptor, rEvent); + // Detect pressed modifier keys. + if (rEvent.GetKeyCode().IsShift()) + nEventCode |= SHIFT_MODIFIER; + if (rEvent.GetKeyCode().IsMod1()) + nEventCode |= CONTROL_MODIFIER; - // 3. Process the event. - EventPreprocessing(*pEventDescriptor); - if ( ! EventProcessing(*pEventDescriptor)) - OSL_TRACE ("can not handle event code %x", pEventDescriptor->mnEventCode); - EventPostprocessing(*pEventDescriptor); + return nEventCode; } -sal_uInt32 SelectionFunction::EncodeKeyEvent ( - const EventDescriptor& rDescriptor, - const KeyEvent& rEvent) const +sal_uInt32 SelectionFunction::EventDescriptor::EncodeState (void) const { - // Initialize as key event. - sal_uInt32 nEventCode (KEY_EVENT); - - // Add the actual key code in the lower 16 bit. - nEventCode |= rEvent.GetKeyCode().GetCode(); - - // Detect pressed modifier keys. - if (rEvent.GetKeyCode().IsShift()) - nEventCode |= SHIFT_MODIFIER; - if (rEvent.GetKeyCode().IsMod1()) - nEventCode |= CONTROL_MODIFIER; + sal_uInt32 nEventCode (0); // Detect whether the event has happened over a page object. - if (rDescriptor.mpHitPage != NULL && ! rDescriptor.mpHitDescriptor.expired()) + if (mpHitPage!=NULL && mpHitDescriptor) { - model::SharedPageDescriptor pHitDescriptor (rDescriptor.mpHitDescriptor); - if (pHitDescriptor->IsSelected()) + if (mpHitDescriptor->HasState(model::PageDescriptor::ST_Selected)) nEventCode |= OVER_SELECTED_PAGE; else nEventCode |= OVER_UNSELECTED_PAGE; - } - // Detect whether we are dragging pages or dragging a selection rectangle. - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - if (rOverlay.GetSubstitutionOverlay().isVisible()) - nEventCode |= SUBSTITUTION_VISIBLE; - if (rOverlay.GetSelectionRectangleOverlay().isVisible()) - nEventCode |= RECTANGLE_VISIBLE; + // Detect whether the mouse is over one of the active elements + // inside a page object. + if (mbIsOverButton) + nEventCode |= OVER_BUTTON; + } return nEventCode; } -void SelectionFunction::EventPreprocessing (const EventDescriptor& rDescriptor) + +//===== SelectionFunction::ModeHandler ======================================== + +SelectionFunction::ModeHandler::ModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const bool bIsMouseOverIndicatorAllowed) + : mrSlideSorter(rSlideSorter), + mrSelectionFunction(rSelectionFunction), + mbIsMouseOverIndicatorAllowed(bIsMouseOverIndicatorAllowed) +{ +} + + + + +SelectionFunction::ModeHandler::~ModeHandler (void) { - // Some general processing that is not specific to the exact event code. - if (rDescriptor.mnEventCode & BUTTON_DOWN) - mbPageHit = (rDescriptor.mpHitPage!=NULL); +} + + - // Set the focus to the slide under the mouse. - if (rDescriptor.mpHitPage != NULL) - mrController.GetFocusManager().FocusPage((rDescriptor.mpHitPage->GetPageNum()-1)/2); + +void SelectionFunction::ModeHandler::ReprocessEvent (EventDescriptor& rDescriptor) +{ + mrSelectionFunction.ProcessEvent(rDescriptor); } -bool SelectionFunction::EventProcessing (const EventDescriptor& rDescriptor) +void SelectionFunction::ModeHandler::ProcessEvent ( + SelectionFunction::EventDescriptor& rDescriptor) { - // Define some macros to make the following switch statement more readable. -#define ANY_MODIFIER(code) \ - code|NO_MODIFIER: \ - case code|SHIFT_MODIFIER: \ - case code|CONTROL_MODIFIER -#define ANY_PAGE(code) \ - code|NOT_OVER_PAGE: \ - case code|OVER_UNSELECTED_PAGE: \ - case code|OVER_SELECTED_PAGE -#define ANY_PAGE_AND_MODIFIER(code) \ - ANY_PAGE(code|NO_MODIFIER): \ - case ANY_PAGE(code|SHIFT_MODIFIER): \ - case ANY_PAGE(code|CONTROL_MODIFIER) + PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + + bool bIsProcessed (false); + switch (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION | MOUSE_DRAG)) + { + case BUTTON_DOWN: + bIsProcessed = ProcessButtonDownEvent(rDescriptor); + break; + + case BUTTON_UP: + bIsProcessed = ProcessButtonUpEvent(rDescriptor); + break; + + case MOUSE_MOTION: + bIsProcessed = ProcessMotionEvent(rDescriptor); + break; + + case MOUSE_DRAG: + bIsProcessed = ProcessDragEvent(rDescriptor); + break; + } + + if ( ! bIsProcessed) + HandleUnprocessedEvent(rDescriptor); +} + + + + +bool SelectionFunction::ModeHandler::ProcessButtonDownEvent (EventDescriptor&) +{ + return false; +} + + + + +bool SelectionFunction::ModeHandler::ProcessButtonUpEvent (EventDescriptor&) +{ + mrSelectionFunction.SwitchToNormalMode(); + return false; +} + + + + +bool SelectionFunction::ModeHandler::ProcessMotionEvent (EventDescriptor& rDescriptor) +{ + if (mbIsMouseOverIndicatorAllowed) + mrSlideSorter.GetView().UpdatePageUnderMouse( + rDescriptor.maMousePosition, + (rDescriptor.mnEventCode & LEFT_BUTTON) != 0, + true); + + if (rDescriptor.mbIsLeaving) + { + mrSelectionFunction.SwitchToNormalMode(); + mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor()); + + return true; + } + else + return false; +} + + + + +bool SelectionFunction::ModeHandler::ProcessDragEvent (EventDescriptor&) +{ + return false; +} + + + + +bool SelectionFunction::ModeHandler::HandleUnprocessedEvent (EventDescriptor&) +{ + return false; +} + + + + +void SelectionFunction::ModeHandler::SetCurrentPage ( + const model::SharedPageDescriptor& rpDescriptor) +{ + SelectOnePage(rpDescriptor); + mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor); +} + + - bool bResult (true); - bool bMakeSelectionVisible (true); +void SelectionFunction::ModeHandler::DeselectAllPages (void) +{ + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + mrSelectionFunction.ResetShiftKeySelectionAnchor(); +} + + + + +void SelectionFunction::ModeHandler::SelectOnePage ( + const model::SharedPageDescriptor& rpDescriptor) +{ + DeselectAllPages(); + mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); +} + + + + +void SelectionFunction::ModeHandler::SwitchView (const model::SharedPageDescriptor& rpDescriptor) +{ + // Switch to the draw view. This is done only when the current + // view is the main view. + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell!=NULL && pViewShell->IsMainViewShell()) + { + if (rpDescriptor.get()!=NULL && rpDescriptor->GetPage()!=NULL) + { + mrSlideSorter.GetModel().GetDocument()->SetSelected(rpDescriptor->GetPage(), TRUE); + pViewShell->GetFrameView()->SetSelectedPage( + (rpDescriptor->GetPage()->GetPageNum()-1)/2); + } + if (mrSlideSorter.GetViewShellBase() != NULL) + framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase())->RequestView( + framework::FrameworkHelper::msImpressViewURL, + framework::FrameworkHelper::msCenterPaneURL); + } +} + + + + +void SelectionFunction::ModeHandler::StartDrag ( + const Point& rMousePosition, + const InsertionIndicatorHandler::Mode eMode) +{ + (void)eMode; + // Do not start a drag-and-drop operation when one is already active. + // (when dragging pages from one document into another, pressing a + // modifier key can trigger a MouseMotion event in the originating + // window (focus still in there). Together with the mouse button pressed + // (drag-and-drop is active) this triggers the start of drag-and-drop.) + if (SD_MOD()->pTransferDrag != NULL) + return; + + if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) + { + mrSelectionFunction.SwitchToDragAndDropMode(rMousePosition); + } +} + + + + +bool SelectionFunction::ModeHandler::IsMouseOverIndicatorAllowed (void) const +{ + return mbIsMouseOverIndicatorAllowed; +} + + + + +//===== NormalModeHandler ===================================================== + +NormalModeHandler::NormalModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction) + : ModeHandler(rSlideSorter, rSelectionFunction, true), + maButtonDownLocation() +{ +} + + + + +NormalModeHandler::~NormalModeHandler (void) +{ +} + + + + +SelectionFunction::Mode NormalModeHandler::GetMode (void) const +{ + return SelectionFunction::NormalMode; +} + + + + +void NormalModeHandler::Abort (void) +{ +} + - mrController.GetPageSelector().DisableBroadcasting(); - // 2b. With the event code determine the type of operation with which to - // react to the event. - // Acquire a shared_ptr to the hit page descriptor. - model::SharedPageDescriptor pHitDescriptor; - if ( ! rDescriptor.mpHitDescriptor.expired()) - pHitDescriptor = model::SharedPageDescriptor(rDescriptor.mpHitDescriptor); +bool NormalModeHandler::ProcessButtonDownEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + // Remember the location where the left button is pressed. With + // that we can filter away motion events that are caused by key + // presses. We also can tune the minimal motion distance that + // triggers a drag-and-drop operation. + if ((rDescriptor.mnEventCode & BUTTON_DOWN) != 0) + maButtonDownLocation = rDescriptor.maMousePosition; switch (rDescriptor.mnEventCode) { case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE: - SetCurrentPage(pHitDescriptor); - PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition)); - mpSubstitutionHandler->Start(rDescriptor.maMouseModelPosition); - break; - - case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: - SetCurrentPage(pHitDescriptor); - mpSubstitutionHandler->End(); + SetCurrentPage(rDescriptor.mpHitDescriptor); break; case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: - PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition)); - mpSubstitutionHandler->Start(rDescriptor.maMouseModelPosition); break; case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_SELECTED_PAGE: case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_UNSELECTED_PAGE: // A double click allways shows the selected slide in the center // pane in an edit view. - SetCurrentPage(pHitDescriptor); - SwitchView(pHitDescriptor); - break; - - // Multi selection with the control modifier. - case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | CONTROL_MODIFIER: - DeselectHitPage(pHitDescriptor); - PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition)); - break; - - case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | CONTROL_MODIFIER: - SelectHitPage(pHitDescriptor); - PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition)); - + SetCurrentPage(rDescriptor.mpHitDescriptor); + SwitchView(rDescriptor.mpHitDescriptor); break; - // Range selection with the shift modifier. case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | SHIFT_MODIFIER: case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | SHIFT_MODIFIER: - RangeSelect(pHitDescriptor); + // Range selection with the shift modifier. + RangeSelect(rDescriptor.mpHitDescriptor); break; - // Was: Preview of the page transition effect. - case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_FADE_INDICATOR: - // No action. + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | OVER_BUTTON: + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | OVER_BUTTON: + OSL_ASSERT(mrSlideSorter.GetView().GetButtonBar().IsMouseOverButton()); + + // Switch to button mode only when the buttons are visible + // (or being faded in.) + if (mrSlideSorter.GetView().GetButtonBar().IsVisible(rDescriptor.mpHitDescriptor)) + { + if (mrSelectionFunction.SwitchToButtonMode()) + ReprocessEvent(rDescriptor); + } + else + { + // When the buttons are not (yet) visible then behave like + // the left button had been clicked over any other part of + // the slide. + SetCurrentPage(rDescriptor.mpHitDescriptor); + } break; - // Right button for context menu. + // Right button for context menu. case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE: - case KEY_EVENT | KEY_F10 | SHIFT_MODIFIER | OVER_UNSELECTED_PAGE: // Single right click and shift+F10 select as preparation to // show the context menu. Change the selection only when the // page under the mouse is not selected. In this case the // selection is set to this single page. Otherwise the // selection is not modified. - DeselectAllPages(); - SelectHitPage(pHitDescriptor); - SetCurrentPage(pHitDescriptor); - bMakeSelectionVisible = false; + SetCurrentPage(rDescriptor.mpHitDescriptor); + rDescriptor.mbMakeSelectionVisible = false; break; case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: - case KEY_EVENT | KEY_F10 | OVER_SELECTED_PAGE | SHIFT_MODIFIER: // Do not change the selection. Just adjust the insertion indicator. - bMakeSelectionVisible = false; + rDescriptor.mbMakeSelectionVisible = false; break; case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE: - // The Shift+F10 key event is here just for completeness. It should - // not be possible to really receive this (not being over a page.) - case KEY_EVENT | KEY_F10 | SHIFT_MODIFIER | NOT_OVER_PAGE: + // Remember the current selection so that when a multi selection + // is started, we can restore the previous selection. + mrSlideSorter.GetModel().SaveCurrentSelection(); DeselectAllPages(); - bMakeSelectionVisible = false; break; - // A mouse motion without visible substitution starts that. - case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE): - mrController.GetScrollBarManager().AutoScroll(rDescriptor.maMousePosition); - mpSubstitutionHandler->Start(rDescriptor.maMouseModelPosition); + case ANY_MODIFIER(BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE): + // Remember the current selection so that when a multi selection + // is started, we can restore the previous selection. + mrSlideSorter.GetModel().SaveCurrentSelection(); + DeselectAllPages(); break; - // Move substitution. - case ANY_PAGE_AND_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | SUBSTITUTION_VISIBLE): - if ((rDescriptor.mnEventCode & CONTROL_MODIFIER) != 0) - StartDrag(); - mrController.GetScrollBarManager().AutoScroll(rDescriptor.maMousePosition); - mpSubstitutionHandler->UpdatePosition(rDescriptor.maMouseModelPosition); + default: + return false; + } + return true; +} + + + + +bool NormalModeHandler::ProcessButtonUpEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + bool bIsProcessed (true); + switch (rDescriptor.mnEventCode) + { + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: + SetCurrentPage(rDescriptor.mpHitDescriptor); break; - // Place substitution. - case ANY_PAGE_AND_MODIFIER(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | SUBSTITUTION_VISIBLE): - // When the substitution has not been moved the button up event - // is taken to be part of a single click. The selected pages - // are therefore not moved (which technically would be necessary - // for unconsecutive multi selections). Instead the page under - // the mouse becomes the only selected page. - if (mpSubstitutionHandler->HasBeenMoved()) - { - // The following Process() call may lead to the desctruction - // of pHitDescriptor so release our reference to it. - pHitDescriptor.reset(); - mpSubstitutionHandler->Process(); - } - else - if (pHitDescriptor != NULL) - SetCurrentPage(pHitDescriptor); - mpSubstitutionHandler->End(); + // Multi selection with the control modifier. + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | CONTROL_MODIFIER: + mrSlideSorter.GetController().GetPageSelector().DeselectPage( + rDescriptor.mpHitDescriptor); break; - // Rectangle selection. - case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | NO_MODIFIER: - DeselectAllPages(); - StartRectangleSelection(rDescriptor.maMouseModelPosition); + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | CONTROL_MODIFIER: + mrSlideSorter.GetController().GetPageSelector().SelectPage( + rDescriptor.mpHitDescriptor); + mrSlideSorter.GetView().UpdatePageUnderMouse( + rDescriptor.mpHitDescriptor, + rDescriptor.maMousePosition, + false); + break; + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE: break; - case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | SHIFT_MODIFIER: - case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | CONTROL_MODIFIER: - StartRectangleSelection(rDescriptor.maMouseModelPosition); + default: + bIsProcessed = false; break; + } + mrSelectionFunction.SwitchToNormalMode(); + return bIsProcessed; +} - case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE): + + + + +bool NormalModeHandler::ProcessMotionEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + if (ModeHandler::ProcessMotionEvent(rDescriptor)) + return true; + + bool bIsProcessed (true); + switch (rDescriptor.mnEventCode) + { case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE): - case ANY_PAGE_AND_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE): - mrController.GetScrollBarManager().AutoScroll(rDescriptor.maMousePosition); - UpdateRectangleSelection(rDescriptor.maMouseModelPosition); - break; + // SetCurrentPage(rDescriptor.mpHitDescriptor); + // Fallthrough - case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | NO_MODIFIER): - ProcessRectangleSelection(false); - break; + // A mouse motion without visible substitution starts that. + case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE): + { + if (maButtonDownLocation) + { + const sal_Int32 nDistance (maButtonDownLocation + ? ::std::max ( + abs(maButtonDownLocation->X() - rDescriptor.maMousePosition.X()), + abs(maButtonDownLocation->Y() - rDescriptor.maMousePosition.Y())) + : 0); + if (nDistance > 3) + StartDrag( + rDescriptor.maMousePosition, + (rDescriptor.mnEventCode & CONTROL_MODIFIER) != 0 + ? InsertionIndicatorHandler::CopyMode + : InsertionIndicatorHandler::MoveMode); + } + } + break; - case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | SHIFT_MODIFIER): - case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | CONTROL_MODIFIER): - ProcessRectangleSelection(true); + // A mouse motion not over a page starts a rectangle selection. + case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE): + mrSelectionFunction.SwitchToMultiSelectionMode( + rDescriptor.maMouseModelPosition, + rDescriptor.mnEventCode); break; default: - bResult = false; + bIsProcessed = false; break; } - mrController.GetPageSelector().EnableBroadcasting(bMakeSelectionVisible); + return bIsProcessed; +} - return bResult; + + + +bool NormalModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + mrSelectionFunction.SwitchToDragAndDropMode(rDescriptor.maMousePosition); + ReprocessEvent(rDescriptor); + return true; } -void SelectionFunction::EventPostprocessing (const EventDescriptor& rDescriptor) +void NormalModeHandler::RangeSelect (const model::SharedPageDescriptor& rpDescriptor) { - if (rDescriptor.mnEventCode & BUTTON_UP) + PageSelector::UpdateLock aLock (mrSlideSorter); + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + + model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor()); + DeselectAllPages(); + + if (pAnchor.get() != NULL) { - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - - mpWindow->ReleaseMouse(); - - // The overlays should not be visible anymore. Warn when one of - // them still is. An exception is th insertion indicator in the - // case that the context menu is visible. - DBG_ASSERT( - mrController.IsContextMenuOpen() - || !rOverlay.GetInsertionIndicatorOverlay().isVisible(), - "slidesorter::SelectionFunction: insertion indicator still visible"); - DBG_ASSERT( - !rOverlay.GetSubstitutionOverlay().isVisible(), - "slidesorter::SelectionFunction: substitution still visible"); - DBG_ASSERT( - !rOverlay.GetSelectionRectangleOverlay().isVisible(), - "slidesorter::SelectionFunction: selection rectangle still visible"); - - // Now turn them off. - if ( ! mrController.IsContextMenuOpen()) - rOverlay.GetInsertionIndicatorOverlay().setVisible(false); - rOverlay.GetSubstitutionOverlay().setVisible(false); - rOverlay.GetSelectionRectangleOverlay().setVisible(false); + // Select all pages between the anchor and the given one, including + // the two. + const USHORT nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2); + const USHORT nOtherIndex ((rpDescriptor->GetPage()->GetPageNum()-1) / 2); + + // Iterate over all pages in the range. Start with the anchor + // page. This way the PageSelector will recognize it again as + // anchor (the first selected page after a DeselectAllPages() + // becomes the anchor.) + const USHORT nStep ((nAnchorIndex < nOtherIndex) ? +1 : -1); + USHORT nIndex (nAnchorIndex); + while (true) + { + rSelector.SelectPage(nIndex); + if (nIndex == nOtherIndex) + break; + nIndex = nIndex + nStep; + } } } -void SelectionFunction::SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor) +void NormalModeHandler::ResetButtonDownLocation (void) { - PageSelector& rSelector (mrController.GetPageSelector()); - rSelector.DeselectAllPages (); - rSelector.SelectPage(rpDescriptor); + maButtonDownLocation = ::boost::optional<Point>(); +} + + - mrController.GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor); + +//===== MultiSelectionModeHandler ============================================= + +MultiSelectionModeHandler::MultiSelectionModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const Point& rMouseModelPosition, + const sal_uInt32 nEventCode) + : ModeHandler(rSlideSorter, rSelectionFunction, false), + meSelectionMode(SM_Normal), + maSecondCorner(rMouseModelPosition), + maSavedPointer(mrSlideSorter.GetContentWindow()->GetPointer()), + mnAnchorIndex(-1), + mnSecondIndex(-1), + maButtonBarLock(rSlideSorter) +{ + const Pointer aSelectionPointer (POINTER_TEXT); + mrSlideSorter.GetContentWindow()->SetPointer(aSelectionPointer); + SetSelectionModeFromModifier(nEventCode); } -void SelectionFunction::SwitchView (const model::SharedPageDescriptor& rpDescriptor) + +MultiSelectionModeHandler::~MultiSelectionModeHandler (void) { - // Switch to the draw view. This is done only when the current - // view is the main view. - ViewShell* pViewShell = mrSlideSorter.GetViewShell(); - if (pViewShell!=NULL && pViewShell->IsMainViewShell()) + mrSlideSorter.GetContentWindow()->SetPointer(maSavedPointer); +} + + + + +SelectionFunction::Mode MultiSelectionModeHandler::GetMode (void) const +{ + return SelectionFunction::MultiSelectionMode; +} + + + + +void MultiSelectionModeHandler::Abort (void) +{ + mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection()); +} + + + + +void MultiSelectionModeHandler::ProcessEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + // During a multi selection we do not want sudden jumps of the + // visible area caused by moving newly selected pages into view. + // Therefore disable that temporarily. The disabler object is + // released at the end of the event processing, after the focus and + // current slide have been updated. + VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter); + + ModeHandler::ProcessEvent(rDescriptor); +} + + + + +bool MultiSelectionModeHandler::ProcessButtonUpEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK)) { - if (rpDescriptor.get()!=NULL && rpDescriptor->GetPage()!=NULL) - { - mrSlideSorter.GetModel().GetDocument()->SetSelected(rpDescriptor->GetPage(), TRUE); - mpViewShell->GetFrameView()->SetSelectedPage( - (rpDescriptor->GetPage()->GetPageNum()-1)/2); - } - if (mrSlideSorter.GetViewShellBase() != NULL) - framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase())->RequestView( - framework::FrameworkHelper::msImpressViewURL, - framework::FrameworkHelper::msCenterPaneURL); + mrSelectionFunction.SwitchToNormalMode(); + return true; } + else + return false; } -//===== EventDescriptor ======================================================= +bool MultiSelectionModeHandler::ProcessMotionEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + // The selection rectangle is visible. Handle events accordingly. + if (Match(rDescriptor.mnEventCode, MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK)) + { + SetSelectionModeFromModifier(rDescriptor.mnEventCode); + UpdatePosition(rDescriptor.maMousePosition, true); + rDescriptor.mbMakeSelectionVisible = false; + return true; + } + else + return false; +} -SelectionFunction::EventDescriptor::EventDescriptor ( - sal_uInt32 nEventType, - const MouseEvent& rEvent, - SlideSorter& rSlideSorter) - : maMousePosition(), - maMouseModelPosition(), - mpHitDescriptor(), - mpHitPage(), - mnEventCode(nEventType) + + +bool MultiSelectionModeHandler::HandleUnprocessedEvent ( + SelectionFunction::EventDescriptor& rDescriptor) { - ::Window* pWindow = rSlideSorter.GetActiveWindow(); + if ( ! ModeHandler::HandleUnprocessedEvent(rDescriptor)) + { + // If the event has not been processed then stop multi selection. + mrSelectionFunction.SwitchToNormalMode(); + ReprocessEvent(rDescriptor); + } + return true; +} - maMousePosition = rEvent.GetPosPixel(); - maMouseModelPosition = pWindow->PixelToLogic(maMousePosition); - model::SharedPageDescriptor pHitDescriptor ( - rSlideSorter.GetController().GetPageAt(maMousePosition)); - if (pHitDescriptor.get() != NULL) + + + +void MultiSelectionModeHandler::UpdatePosition ( + const Point& rMousePosition, + const bool bAllowAutoScroll) +{ + VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter); + + // Convert window coordinates into model coordinates (we need the + // window coordinates for auto-scrolling because that remains + // constant while scrolling.) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition)); + + if ( ! (bAllowAutoScroll && mrSlideSorter.GetController().GetScrollBarManager().AutoScroll( + rMousePosition, + ::boost::bind( + &MultiSelectionModeHandler::UpdatePosition, + this, + rMousePosition, + false)))) { - mpHitDescriptor = pHitDescriptor; - mpHitPage = pHitDescriptor->GetPage(); + UpdateModelPosition(aMouseModelPosition); } } +void MultiSelectionModeHandler::SetSelectionModeFromModifier ( + const sal_uInt32 nEventCode) +{ + switch (nEventCode & MODIFIER_MASK) + { + case NO_MODIFIER: + SetSelectionMode(SM_Normal); + break; -SelectionFunction::EventDescriptor::EventDescriptor ( - const KeyEvent&, - SlideSorter& rSlideSorter) - : maMousePosition(), - maMouseModelPosition(), - mpHitDescriptor(), - mpHitPage(), - mnEventCode(0) + case SHIFT_MODIFIER: + SetSelectionMode(SM_Add); + break; + + case CONTROL_MODIFIER: + SetSelectionMode(SM_Toggle); + break; + } +} + + + + +void MultiSelectionModeHandler::SetSelectionMode (const SelectionMode eSelectionMode) { - mpHitDescriptor = rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor(); - model::SharedPageDescriptor pHitDescriptor ( - rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor()); - if (pHitDescriptor.get() != NULL) + if (meSelectionMode != eSelectionMode) { - mpHitPage = pHitDescriptor->GetPage(); - mpHitDescriptor = pHitDescriptor; + meSelectionMode = eSelectionMode; + UpdateSelection(); } } +void MultiSelectionModeHandler::UpdateSelectionState ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bIsInSelection) const +{ + // Determine whether the page was selected before the rectangle + // selection was started. + const bool bWasSelected (rpDescriptor->HasState(model::PageDescriptor::ST_WasSelected)); + + // Combine the two selection states depending on the selection mode. + bool bSelect (false); + switch(meSelectionMode) + { + case SM_Normal: + bSelect = bIsInSelection; + break; -//===== SubstitutionHandler =================================================== + case SM_Add: + bSelect = bIsInSelection || bWasSelected; + break; -SelectionFunction::SubstitutionHandler::SubstitutionHandler (SlideSorter& rSlideSorter) - : mrSlideSorter(rSlideSorter), - mbHasBeenMoved(false) + case SM_Toggle: + if (bIsInSelection) + bSelect = !bWasSelected; + else + bSelect = bWasSelected; + break; + } + + // Set the new selection state. + if (bSelect) + mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); + else + mrSlideSorter.GetController().GetPageSelector().DeselectPage(rpDescriptor); +} + + + + +void MultiSelectionModeHandler::UpdateModelPosition (const Point& rMouseModelPosition) { + maSecondCorner = rMouseModelPosition; + UpdateSelection(); } -SelectionFunction::SubstitutionHandler::~SubstitutionHandler (void) +void MultiSelectionModeHandler::UpdateSelection (void) { - if (mrSlideSorter.IsValid()) + view::SlideSorterView::DrawLock aLock (mrSlideSorter); + + model::SlideSorterModel& rModel (mrSlideSorter.GetModel()); + const sal_Int32 nPageCount (rModel.GetPageCount()); + + const sal_Int32 nIndexUnderMouse ( + mrSlideSorter.GetView().GetLayouter().GetIndexAtPoint ( + maSecondCorner, + false, + false)); + if (nIndexUnderMouse>=0 && nIndexUnderMouse<nPageCount) { - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - rOverlay.GetSubstitutionOverlay().setVisible(false); - rOverlay.GetSubstitutionOverlay().Clear(); + if (mnAnchorIndex < 0) + mnAnchorIndex = nIndexUnderMouse; + mnSecondIndex = nIndexUnderMouse; + + Range aRange (mnAnchorIndex, mnSecondIndex); + aRange.Justify(); + + for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex) + { + UpdateSelectionState(rModel.GetPageDescriptor(nIndex), aRange.IsInside(nIndex)); + } } } -void SelectionFunction::SubstitutionHandler::Start (const Point& rMouseModelPosition) +//===== DragAndDropModeHandler ================================================ + +DragAndDropModeHandler::DragAndDropModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const Point& rMousePosition, + ::Window* pWindow) + : ModeHandler(rSlideSorter, rSelectionFunction, false) { - // No Drag-and-Drop for master pages. - if (mrSlideSorter.GetModel().GetEditMode() != EM_PAGE) - return; + SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; + if (pDragTransferable==NULL && mrSlideSorter.GetViewShell() != NULL) + { + SlideSorterViewShell* pSlideSorterViewShell + = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); + if (pSlideSorterViewShell != NULL) + pSlideSorterViewShell->StartDrag(rMousePosition, pWindow); + pDragTransferable = SD_MOD()->pTransferDrag; + } - if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly()) - return; + mpDragAndDropContext.reset(new DragAndDropContext(mrSlideSorter)); + mrSlideSorter.GetController().GetInsertionIndicatorHandler()->Start( + pDragTransferable != NULL + && pDragTransferable->GetView()==&mrSlideSorter.GetView()); +} - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - if ( ! rOverlay.GetSubstitutionOverlay().isVisible()) + + +DragAndDropModeHandler::~DragAndDropModeHandler (void) +{ + if (mpDragAndDropContext) { - // Show a new substitution for the selected page objects. - model::PageEnumeration aSelectedPages( - model::PageEnumerationProvider::CreateSelectedPagesEnumeration( - mrSlideSorter.GetModel())); - rOverlay.GetSubstitutionOverlay().Create(aSelectedPages, rMouseModelPosition); - rOverlay.GetSubstitutionOverlay().setVisible(true); - mbHasBeenMoved = false; + // Disconnect the substitution handler from this selection function. + mpDragAndDropContext->SetTargetSlideSorter(); + mpDragAndDropContext.reset(); } - else - UpdatePosition(rMouseModelPosition); + mrSlideSorter.GetController().GetInsertionIndicatorHandler()->End(Animator::AM_Animated); } -void SelectionFunction::SubstitutionHandler::UpdatePosition (const Point& rMouseModelPosition) +SelectionFunction::Mode DragAndDropModeHandler::GetMode (void) const { - if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly()) - return; + return SelectionFunction::DragAndDropMode; +} - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - // Move the existing substitution to the new position. - rOverlay.GetSubstitutionOverlay().SetPosition(rMouseModelPosition); - rOverlay.GetInsertionIndicatorOverlay().SetPosition(rMouseModelPosition); - rOverlay.GetInsertionIndicatorOverlay().setVisible(true); - mbHasBeenMoved = true; +void DragAndDropModeHandler::Abort (void) +{ + mrSlideSorter.GetController().GetClipboard().Abort(); + if (mpDragAndDropContext) + mpDragAndDropContext->Dispose(); + // mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection()); } -void SelectionFunction::SubstitutionHandler::Process (void) +bool DragAndDropModeHandler::ProcessButtonUpEvent ( + SelectionFunction::EventDescriptor& rDescriptor) { - if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly()) - return; + if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON)) + { + // The following Process() call may lead to the desctruction + // of rDescriptor.mpHitDescriptor so release our reference to it. + rDescriptor.mpHitDescriptor.reset(); + mrSelectionFunction.SwitchToNormalMode(); + return true; + } + else + return false; +} - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - if (IsSubstitutionInsertionNonTrivial()) - { - // Tell the model to move the selected pages behind the one with the - // index mnInsertionIndex which first has to transformed into an index - // understandable by the document. - sal_Int32 nInsertionIndex = rOverlay.GetInsertionIndicatorOverlay().GetInsertionPageIndex(); - if (nInsertionIndex >= 0) - { - USHORT nDocumentIndex = (USHORT)nInsertionIndex-1; - mrSlideSorter.GetController().GetSelectionManager()->MoveSelectedPages(nDocumentIndex); - } - ViewShell* pViewShell = mrSlideSorter.GetViewShell(); - if (pViewShell != NULL) - pViewShell->GetViewFrame()->GetBindings().Invalidate(SID_STATUS_PAGE); + +bool DragAndDropModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + OSL_ASSERT(mpDragAndDropContext); + + if (rDescriptor.mbIsLeaving) + { + mrSelectionFunction.SwitchToNormalMode(); + } + else if (mpDragAndDropContext) + { + mpDragAndDropContext->UpdatePosition( + rDescriptor.maMousePosition, + rDescriptor.meDragMode); } + + return true; } -void SelectionFunction::SubstitutionHandler::End (void) +//===== ButtonModeHandler ===================================================== + +ButtonModeHandler::ButtonModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction) + : ModeHandler(rSlideSorter, rSelectionFunction, true) { - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - rOverlay.GetSubstitutionOverlay().setVisible(false); - rOverlay.GetSubstitutionOverlay().Clear(); - rOverlay.GetInsertionIndicatorOverlay().setVisible(false); } -bool SelectionFunction::SubstitutionHandler::HasBeenMoved (void) const +ButtonModeHandler::~ButtonModeHandler (void) { - return mbHasBeenMoved; } -bool SelectionFunction::SubstitutionHandler::IsSubstitutionInsertionNonTrivial (void) const +SelectionFunction::Mode ButtonModeHandler::GetMode (void) const { - bool bIsNonTrivial = false; + return SelectionFunction::ButtonMode; +} + + + - do +void ButtonModeHandler::Abort (void) +{ +} + + + + +bool ButtonModeHandler::ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + switch (rDescriptor.mnEventCode) { - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | OVER_BUTTON: + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | OVER_BUTTON: + // Remember page and button index. When mouse button is + // released over same page and button then invoke action of that + // button. + mrSlideSorter.GetView().GetButtonBar().ProcessButtonDownEvent( + rDescriptor.mpHitDescriptor, + rDescriptor.maMouseModelPosition); + return true; + + default: + return false; + } +} - // Make sure that the substitution and the insertion indicator are visible. - if ( ! rOverlay.GetSubstitutionOverlay().isVisible()) - break; - if ( ! rOverlay.GetInsertionIndicatorOverlay().isVisible()) - break; - // Iterate over all selected pages and check whether there are - // holes. While we do this we remember the indices of the first and - // last selected page as preparation for the next step. - sal_Int32 nCurrentIndex = -1; - sal_Int32 nFirstIndex = -1; - sal_Int32 nLastIndex = -1; - model::PageEnumeration aSelectedPages ( - model::PageEnumerationProvider::CreateSelectedPagesEnumeration( - mrSlideSorter.GetModel())); - while (aSelectedPages.HasMoreElements() && ! bIsNonTrivial) - { - model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); - SdPage* pPage = pDescriptor->GetPage(); - if (pPage != NULL) - { - // Get the page number and compare it to the last one. - sal_Int32 nPageNumber = (pPage->GetPageNum()-1)/2; - if (nCurrentIndex>=0 && nPageNumber>(nCurrentIndex+1)) - bIsNonTrivial = true; - else - nCurrentIndex = nPageNumber; - // Remember indices of the first and last page of the selection. - if (nFirstIndex == -1) - nFirstIndex = nPageNumber; - nLastIndex = nPageNumber; - } - } - if (bIsNonTrivial) - break; - // When we come here then the selection is consecutive. We still - // have to check that the insertion position is not directly in - // front or directly behind the selection and thus moving the - // selection there would not change the model. - sal_Int32 nInsertionIndex = rOverlay.GetInsertionIndicatorOverlay().GetInsertionPageIndex(); - if (nInsertionIndex<nFirstIndex || nInsertionIndex>(nLastIndex+1)) - bIsNonTrivial = true; +bool ButtonModeHandler::ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + switch (rDescriptor.mnEventCode & BUTTON_MASK) + { + case LEFT_BUTTON: + mrSlideSorter.GetView().GetButtonBar().ProcessButtonUpEvent( + rDescriptor.mpHitDescriptor, + rDescriptor.maMouseModelPosition); + mrSelectionFunction.SwitchToNormalMode(); + return true; } - while (false); - return bIsNonTrivial; + return false; } + + + +bool ButtonModeHandler::ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + switch (rDescriptor.mnEventCode & (MOUSE_MOTION | BUTTON_MASK)) + { + case MOUSE_MOTION | LEFT_BUTTON: + mrSlideSorter.GetView().GetButtonBar().ProcessMouseMotionEvent( + rDescriptor.mpHitDescriptor, + rDescriptor.maMouseModelPosition, + true); + return true; + + case MOUSE_MOTION: + mrSlideSorter.GetView().GetButtonBar().ProcessMouseMotionEvent( + rDescriptor.mpHitDescriptor, + rDescriptor.maMouseModelPosition, + false); + return true; + } + + return false; +} + + + + } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx index f1b4cb6c39be..d9062a4ef2b1 100755 --- a/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx +++ b/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx @@ -30,18 +30,22 @@ #include "controller/SlsSelectionManager.hxx" #include "SlideSorter.hxx" -#include "SlsSelectionCommand.hxx" +#include "SlsCommand.hxx" #include "controller/SlideSorterController.hxx" #include "controller/SlsAnimator.hxx" +#include "controller/SlsAnimationFunction.hxx" #include "controller/SlsCurrentSlideManager.hxx" #include "controller/SlsFocusManager.hxx" +#include "controller/SlsPageSelector.hxx" #include "controller/SlsProperties.hxx" #include "controller/SlsScrollBarManager.hxx" #include "controller/SlsSlotManager.hxx" +#include "controller/SlsSelectionObserver.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "model/SlsPageDescriptor.hxx" #include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" #include "drawdoc.hxx" #include "Window.hxx" #include <svx/svxids.hrc> @@ -65,39 +69,24 @@ using namespace ::sd::slidesorter::controller; namespace sd { namespace slidesorter { namespace controller { -namespace { - class VerticalVisibleAreaScroller - { - public: - VerticalVisibleAreaScroller (SlideSorter& rSlideSorter, - const double nStart, const double nEnd); - void operator() (const double nValue); - private: - SlideSorter& mrSlideSorter; - double mnStart; - double mnEnd; - }; - class HorizontalVisibleAreaScroller - { - public: - HorizontalVisibleAreaScroller (SlideSorter& rSlideSorter, - const double nStart, const double nEnd); - void operator() (const double nValue); - private: - SlideSorter& mrSlideSorter; - double mnStart; - double mnEnd; - }; -} - +class SelectionManager::PageInsertionListener + : public SfxListener +{ +public: +}; SelectionManager::SelectionManager (SlideSorter& rSlideSorter) : mrSlideSorter(rSlideSorter), mrController(rSlideSorter.GetController()), maSelectionBeforeSwitch(), - mbIsMakeSelectionVisiblePending(true) + mbIsMakeSelectionVisiblePending(true), + mnInsertionPosition(-1), + mnAnimationId(Animator::NotAnAnimationId), + maRequestedTopLeft(), + mpPageInsertionListener(), + mpSelectionObserver(new SelectionObserver(rSlideSorter)) { } @@ -106,14 +95,20 @@ SelectionManager::SelectionManager (SlideSorter& rSlideSorter) SelectionManager::~SelectionManager (void) { + if (mnAnimationId != Animator::NotAnAnimationId) + mrController.GetAnimator()->RemoveAnimation(mnAnimationId); } -void SelectionManager::DeleteSelectedPages (void) +void SelectionManager::DeleteSelectedPages (const bool bSelectFollowingPage) { + // Create some locks to prevent updates of the model, view, selection + // state while modifying any of them. SlideSorterController::ModelChangeLock aLock (mrController); + SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + PageSelector::UpdateLock aSelectionLock (mrSlideSorter); // Hide focus. bool bIsFocusShowing = mrController.GetFocusManager().IsFocusShowing(); @@ -125,8 +120,23 @@ void SelectionManager::DeleteSelectedPages (void) model::PageEnumeration aPageEnumeration ( PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel())); ::std::vector<SdPage*> aSelectedPages; + sal_Int32 nNewCurrentSlide (-1); while (aPageEnumeration.HasMoreElements()) - aSelectedPages.push_back (aPageEnumeration.GetNextElement()->GetPage()); + { + SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement()); + aSelectedPages.push_back(pDescriptor->GetPage()); + if (bSelectFollowingPage || nNewCurrentSlide<0) + nNewCurrentSlide = pDescriptor->GetPageIndex(); + } + if (aSelectedPages.empty()) + return; + + // Determine the slide to select (and thereby make the current slide) + // after the deletion. + if (bSelectFollowingPage) + nNewCurrentSlide -= aSelectedPages.size() - 1; + else + --nNewCurrentSlide; // The actual deletion of the selected pages is done in one of two // helper functions. They are specialized for normal respectively for @@ -143,8 +153,16 @@ void SelectionManager::DeleteSelectedPages (void) // Show focus and move it to next valid location. if (bIsFocusShowing) - mrController.GetFocusManager().ToggleFocus (); - mrController.GetFocusManager().MoveFocus (FocusManager::FMD_NONE); + mrController.GetFocusManager().ToggleFocus(); + + // Set the new current slide. + if (nNewCurrentSlide < 0) + nNewCurrentSlide = 0; + else if (nNewCurrentSlide >= mrSlideSorter.GetModel().GetPageCount()) + nNewCurrentSlide = mrSlideSorter.GetModel().GetPageCount()-1; + mrController.GetPageSelector().CountSelectedPages(); + mrController.GetPageSelector().SelectPage(nNewCurrentSlide); + mrController.GetFocusManager().SetFocusedPage(nNewCurrentSlide); } @@ -171,7 +189,7 @@ void SelectionManager::DeleteSelectedNormalPages (const ::std::vector<SdPage*>& if (xPages->getCount() <= 1) break; - USHORT nPage = ((*aI)->GetPageNum()-1) / 2; + const USHORT nPage (model::FromCoreIndex((*aI)->GetPageNum())); Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW ); xPages->remove(xPage); @@ -207,7 +225,7 @@ void SelectionManager::DeleteSelectedMasterPages (const ::std::vector<SdPage*>& if (xPages->getCount() <= 1) break; - USHORT nPage = ((*aI)->GetPageNum()-1) / 2; + const USHORT nPage (model::FromCoreIndex((*aI)->GetPageNum())); Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW ); xPages->remove(xPage); @@ -222,60 +240,6 @@ void SelectionManager::DeleteSelectedMasterPages (const ::std::vector<SdPage*>& -bool SelectionManager::MoveSelectedPages (const sal_Int32 nTargetPageIndex) -{ - bool bMoved (false); - PageSelector& rSelector (mrController.GetPageSelector()); - - mrSlideSorter.GetView().LockRedraw (TRUE); - SlideSorterController::ModelChangeLock aLock (mrController); - - // Transfer selection of the slide sorter to the document. - mrSlideSorter.GetModel().SynchronizeDocumentSelection (); - - // Detect how many pages lie between document start and insertion - // position. - sal_Int32 nPageCountBeforeTarget (0); - ::boost::shared_ptr<PageSelector::PageSelection> pSelection (rSelector.GetPageSelection()); - PageSelector::PageSelection::const_iterator iSelectedPage (pSelection->begin()); - PageSelector::PageSelection::const_iterator iSelectionEnd (pSelection->end()); - for ( ; iSelectedPage!=iSelectionEnd; ++iSelectedPage) - { - if (*iSelectedPage==NULL) - continue; - if (((*iSelectedPage)->GetPageNum()-1)/2 <= nTargetPageIndex) - ++nPageCountBeforeTarget; - else - break; - } - - // Prepare to select the moved pages. - SelectionCommand* pCommand = new SelectionCommand( - rSelector,mrController.GetCurrentSlideManager(),mrSlideSorter.GetModel()); - sal_Int32 nSelectedPageCount (rSelector.GetSelectedPageCount()); - for (sal_Int32 nOffset=0; nOffset<nSelectedPageCount; ++nOffset) - pCommand->AddSlide(sal::static_int_cast<USHORT>( - nTargetPageIndex + nOffset - nPageCountBeforeTarget + 1)); - - // At the moment we can not move master pages. - if (nTargetPageIndex>=0) - { - if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE) - bMoved = mrSlideSorter.GetModel().GetDocument()->MovePages( - sal::static_int_cast<sal_uInt16>(nTargetPageIndex)); - } - if (bMoved) - mrController.GetSlotManager()->ExecuteCommandAsynchronously( - ::std::auto_ptr<controller::Command>(pCommand)); - - mrSlideSorter.GetView().LockRedraw (FALSE); - - return bMoved; -} - - - - void SelectionManager::SelectionHasChanged (const bool bMakeSelectionVisible) { if (bMakeSelectionVisible) @@ -318,166 +282,6 @@ void SelectionManager::SelectionHasChanged (const bool bMakeSelectionVisible) -bool SelectionManager::IsMakeSelectionVisiblePending (void) const -{ - return mbIsMakeSelectionVisiblePending; -} - - - - -/** We have to distinguish three cases: 1) the selection is empty, 2) the - selection fits completely into the visible area, 3) it does not. - 1) The visible area is not modified. - 2) When the selection fits completely into the visible area we have to - decide how to align it. It is done by scrolling it there and thus when - we scoll up the (towards the end of the document) the bottom of the - selection is aligned with the bottom of the window. When we scroll - down (towards the beginning of the document) the top of the selection is - aligned with the top of the window. - 3) We have to decide what part of the selection to make visible. Here - we use the eSelectionHint and concentrate on either the first, the last, - or the most recently selected page. We then again apply the algorithm - of a). - -*/ -Size SelectionManager::MakeSelectionVisible (const SelectionHint eSelectionHint) -{ - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow == NULL) - return Size(0,0); - - mbIsMakeSelectionVisiblePending = false; - - // Determine the descriptors of the first and last selected page and the - // bounding box that encloses their page objects. - model::SharedPageDescriptor pFirst; - model::SharedPageDescriptor pLast; - Rectangle aSelectionBox; - model::PageEnumeration aSelectedPages ( - PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel())); - while (aSelectedPages.HasMoreElements()) - { - model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); - - if (pFirst.get() == NULL) - pFirst = pDescriptor; - pLast = pDescriptor; - - aSelectionBox.Union (mrSlideSorter.GetView().GetPageBoundingBox ( - pDescriptor, - view::SlideSorterView::CS_MODEL, - view::SlideSorterView::BBT_INFO)); - } - - if (pFirst != NULL) - { - // Determine scroll direction and the position in model coordinates - // that will be aligned with the top/left or bottom/right window - // border. - if (DoesSelectionExceedVisibleArea(aSelectionBox)) - { - // We can show only a part of the selection. - aSelectionBox = ResolveLargeSelection(pFirst,pLast, eSelectionHint); - } - - return MakeRectangleVisible(aSelectionBox); - } - - return Size(0,0); -} - - - - -Size SelectionManager::MakeRectangleVisible (const Rectangle& rBox) -{ - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow == NULL) - return Size(0,0); - - Rectangle aVisibleArea (pWindow->PixelToLogic( - Rectangle( - Point(0,0), - pWindow->GetOutputSizePixel()))); - - if (mrSlideSorter.GetView().GetOrientation() == SlideSorterView::VERTICAL) - { - // Scroll the visible area to make aSelectionBox visible. - sal_Int32 nNewTop (aVisibleArea.Top()); - if (mrSlideSorter.GetController().GetProperties()->IsCenterSelection()) - { - nNewTop = rBox.Top() - (aVisibleArea.GetHeight() - rBox.GetHeight()) / 2; - } - else - { - if (rBox.Top() < aVisibleArea.Top()) - nNewTop = rBox.Top(); - else if (rBox.Bottom() > aVisibleArea.Bottom()) - nNewTop = rBox.Bottom() - aVisibleArea.GetHeight(); - // otherwise we do not modify the visible area. - } - - // Make some corrections of the new visible area. - Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); - if (nNewTop + aVisibleArea.GetHeight() > aModelArea.Bottom()) - nNewTop = aModelArea.GetHeight() - aVisibleArea.GetHeight(); - if (nNewTop < aModelArea.Top()) - nNewTop = aModelArea.Top(); - - // Scroll. - if (nNewTop != aVisibleArea.Top()) - { - mrController.GetAnimator()->AddAnimation( - VerticalVisibleAreaScroller(mrSlideSorter, aVisibleArea.Top(), nNewTop), - mrSlideSorter.GetController().GetProperties()->IsSmoothSelectionScrolling() ? - 1000 : 0 - ); - } - - return Size(0,aVisibleArea.Top() - nNewTop); - } - else - { - // Scroll the visible area to make aSelectionBox visible. - sal_Int32 nNewLeft (aVisibleArea.Left()); - if (mrSlideSorter.GetController().GetProperties()->IsCenterSelection()) - { - nNewLeft = rBox.Left() - (aVisibleArea.GetWidth() - rBox.GetWidth()) / 2; - } - else - { - if (rBox.Left() < aVisibleArea.Left()) - nNewLeft = rBox.Left(); - else if (rBox.Right() > aVisibleArea.Right()) - nNewLeft = rBox.Right() - aVisibleArea.GetWidth(); - // otherwise we do not modify the visible area. - } - - // Make some corrections of the new visible area. - Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); - if (nNewLeft + aVisibleArea.GetWidth() > aModelArea.Right()) - nNewLeft = aModelArea.GetWidth() - aVisibleArea.GetWidth(); - if (nNewLeft < aModelArea.Left()) - nNewLeft = aModelArea.Left(); - - // Scroll. - if (nNewLeft != aVisibleArea.Left()) - { - mrController.GetAnimator()->AddAnimation( - HorizontalVisibleAreaScroller(mrSlideSorter, aVisibleArea.Left(), nNewLeft), - mrSlideSorter.GetController().GetProperties()->IsSmoothSelectionScrolling() ? - 1000 : 0 - ); - } - - return Size(aVisibleArea.Left() - nNewLeft, 0); - } -} - - - - void SelectionManager::AddSelectionChangeListener (const Link& rListener) { if (::std::find ( @@ -504,70 +308,6 @@ void SelectionManager::RemoveSelectionChangeListener(const Link&rListener) -bool SelectionManager::DoesSelectionExceedVisibleArea (const Rectangle& rSelectionBox) const -{ - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow == NULL) - return true; - - Rectangle aVisibleArea (pWindow->PixelToLogic( - Rectangle( - Point(0,0), - pWindow->GetOutputSizePixel()))); - if (mrSlideSorter.GetView().GetOrientation() == SlideSorterView::VERTICAL) - return rSelectionBox.GetHeight() > aVisibleArea.GetHeight(); - else - return rSelectionBox.GetWidth() > aVisibleArea.GetWidth(); -} - - - - -Rectangle SelectionManager::ResolveLargeSelection ( - const SharedPageDescriptor& rpFirst, - const SharedPageDescriptor& rpLast, - const SelectionHint eSelectionHint) -{ - OSL_ASSERT(rpFirst.get()!=NULL); - OSL_ASSERT(rpLast.get()!=NULL); - - // The mose recently selected page is assumed to lie in the range - // between first and last selected page. Therefore the bounding box is - // not modified. - model::SharedPageDescriptor pRecent ( - mrController.GetPageSelector().GetMostRecentlySelectedPage()); - - // Get the bounding box of the page object on which to concentrate. - model::SharedPageDescriptor pRepresentative; - switch (eSelectionHint) - { - case SH_FIRST: - pRepresentative = rpFirst; - break; - - case SH_LAST: - pRepresentative = rpLast; - break; - - case SH_RECENT: - default: - if (pRecent.get() == NULL) - pRepresentative = rpFirst; - else - pRepresentative = pRecent; - break; - } - OSL_ASSERT(pRepresentative.get() != NULL); - - return mrSlideSorter.GetView().GetPageBoundingBox ( - pRepresentative, - view::SlideSorterView::CS_MODEL, - view::SlideSorterView::BBT_INFO); -} - - - - sal_Int32 SelectionManager::GetInsertionPosition (void) const { sal_Int32 nInsertionPosition (mnInsertionPosition); @@ -584,7 +324,7 @@ sal_Int32 SelectionManager::GetInsertionPosition (void) const const sal_Int32 nPosition (aSelectedPages.GetNextElement()->GetPage()->GetPageNum()); // Convert *2+1 index to straight index (n-1)/2 after the page // (+1). - nInsertionPosition = (nPosition-1)/2 + 1; + nInsertionPosition = model::FromCoreIndex(nPosition) + 1; } } @@ -611,52 +351,9 @@ void SelectionManager::SetInsertionPosition (const sal_Int32 nInsertionPosition) -//===== VerticalVisibleAreaScroller =========================================== - -namespace { - -VerticalVisibleAreaScroller::VerticalVisibleAreaScroller ( - SlideSorter& rSlideSorter, - const double nStart, - const double nEnd) - : mrSlideSorter(rSlideSorter), - mnStart(nStart), - mnEnd(nEnd) +::boost::shared_ptr<SelectionObserver> SelectionManager::GetSelectionObserver (void) const { + return mpSelectionObserver; } - - -void VerticalVisibleAreaScroller::operator() (const double nValue) -{ - mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); - mrSlideSorter.GetController().GetScrollBarManager().SetTop( - int(mnStart * (1.0 - nValue) + mnEnd * nValue)); -} - - - - -HorizontalVisibleAreaScroller::HorizontalVisibleAreaScroller ( - SlideSorter& rSlideSorter, - const double nStart, - const double nEnd) - : mrSlideSorter(rSlideSorter), - mnStart(nStart), - mnEnd(nEnd) -{ -} - - - - -void HorizontalVisibleAreaScroller::operator() (const double nValue) -{ - mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); - mrSlideSorter.GetController().GetScrollBarManager().SetLeft( - int(mnStart * (1.0 - nValue) + mnEnd * nValue)); -} - -} // end of anonymous namespace - } } } // end of namespace ::sd::slidesorter diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx new file mode 100644 index 000000000000..b40bd667131c --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx @@ -0,0 +1,173 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlideSorter.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsSelectionObserver.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsFocusManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include <svx/svdmodel.hxx> +#include "drawdoc.hxx" + + +namespace sd { namespace slidesorter { namespace controller { + +SelectionObserver::Context::Context (SlideSorter& rSlideSorter) + : mpSelectionObserver( + rSlideSorter.GetController().GetSelectionManager()->GetSelectionObserver()) +{ + if (mpSelectionObserver) + mpSelectionObserver->StartObservation(); +} + + + + +SelectionObserver::Context::~Context(void) +{ + if (mpSelectionObserver) + mpSelectionObserver->EndObservation(); +} + + + + +void SelectionObserver::Context::Abort(void) +{ + if (mpSelectionObserver) + { + mpSelectionObserver->AbortObservation(); + mpSelectionObserver.reset(); + } +} + + + + +//===== SelectionObserver ===================================================== + +SelectionObserver::SelectionObserver (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mpDocument(mrSlideSorter.GetModel().GetDocument()), + mbIsOvservationActive(false), + maInsertedPages(), + maDeletedPages() +{ +} + + + + +SelectionObserver::~SelectionObserver (void) +{ +} + + + + +void SelectionObserver::NotifyPageEvent (const SdrPage* pSdrPage) +{ + if ( ! mbIsOvservationActive) + return; + + const SdPage* pPage = dynamic_cast<const SdPage*>(pSdrPage); + if (pPage == NULL) + return; + + if (pPage->IsInserted()) + maInsertedPages.push_back(pPage); + else + { + ::std::vector<const SdPage*>::iterator iPage( + ::std::find(maInsertedPages.begin(), maInsertedPages.end(), pPage)); + if (iPage != maInsertedPages.end()) + maInsertedPages.erase(iPage); + + maDeletedPages.push_back(pPage->GetPageNum()); + } +} + + + +void SelectionObserver::StartObservation (void) +{ + OSL_ASSERT(!mbIsOvservationActive); + maInsertedPages.clear(); + maDeletedPages.clear(); + mbIsOvservationActive = true; +} + + + + +void SelectionObserver::AbortObservation (void) +{ + OSL_ASSERT(mbIsOvservationActive); + mbIsOvservationActive = false; + maInsertedPages.clear(); + maDeletedPages.clear(); +} + + + + +void SelectionObserver::EndObservation (void) +{ + OSL_ASSERT(mbIsOvservationActive); + mbIsOvservationActive = false; + + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + rSelector.DeselectAllPages(); + if ( ! maInsertedPages.empty()) + { + // Select the inserted pages. + for (::std::vector<const SdPage*>::const_iterator + iPage(maInsertedPages.begin()), + iEnd(maInsertedPages.end()); + iPage!=iEnd; + ++iPage) + { + rSelector.SelectPage(*iPage); + } + maInsertedPages.clear(); + } + maDeletedPages.clear(); + + aUpdateLock.Release(); + mrSlideSorter.GetController().GetFocusManager().SetFocusedPageToCurrentPage(); + +} + + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx b/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx index 7fe090ad5541..1af831c2ad8a 100755 --- a/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx +++ b/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx @@ -46,7 +46,7 @@ SlideFunction::SlideFunction ( SfxRequest& rRequest) : FuPoor ( rSlideSorter.GetViewShell(), - rSlideSorter.GetView().GetWindow(), + rSlideSorter.GetContentWindow().get(), &rSlideSorter.GetView(), rSlideSorter.GetModel().GetDocument(), rRequest) diff --git a/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx b/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx index e571a765bdad..ded7c2ebfdde 100755..100644 --- a/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx +++ b/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx @@ -33,20 +33,20 @@ #include "SlideSorter.hxx" #include "SlideSorterViewShell.hxx" #include "controller/SlideSorterController.hxx" -#include "controller/SlsPageSelector.hxx" #include "controller/SlsClipboard.hxx" -#include "controller/SlsSelectionFunction.hxx" -#include "controller/SlsFocusManager.hxx" #include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsFocusManager.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsSelectionFunction.hxx" #include "controller/SlsSelectionManager.hxx" -#include "SlsHideSlideFunction.hxx" +#include "controller/SlsSelectionObserver.hxx" #include "SlsCommand.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "model/SlsPageDescriptor.hxx" #include "view/SlideSorterView.hxx" #include "view/SlsLayouter.hxx" -#include "view/SlsViewOverlay.hxx" #include "framework/FrameworkHelper.hxx" #include "Window.hxx" #include "fupoor.hxx" @@ -92,12 +92,30 @@ #include <com/sun/star/drawing/XDrawPages.hpp> #include <vcl/svapp.hxx> +#include <boost/bind.hpp> + using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::presentation; namespace sd { namespace slidesorter { namespace controller { +namespace { + +/** The state of a set of slides with respect to being excluded from the + slide show. +*/ +enum SlideExclusionState {UNDEFINED, EXCLUDED, INCLUDED, MIXED}; + +/** Return for the given set of slides whether they included are + excluded from the slide show. +*/ +SlideExclusionState GetSlideExclusionState (model::PageEnumeration& rPageSet); + +} // end of anonymous namespace + + + SlotManager::SlotManager (SlideSorter& rSlideSorter) : mrSlideSorter(rSlideSorter), maCommandQueue() @@ -133,8 +151,11 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) break; case SID_HIDE_SLIDE: + ChangeSlideExclusionState(model::SharedPageDescriptor(), true); + break; + case SID_SHOW_SLIDE: - HideSlideFunction::Create(mrSlideSorter, rRequest); + ChangeSlideExclusionState(model::SharedPageDescriptor(), false); break; case SID_PAGES_PER_ROW: @@ -145,15 +166,16 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) if (pPagesPerRow != NULL) { sal_Int32 nColumnCount = pPagesPerRow->GetValue(); - // Force the given number of columns by setting the - // minimal and maximal number of columns to the same - // value. + // Force the given number of columns by setting + // the minimal and maximal number of columns to + // the same value. mrSlideSorter.GetView().GetLayouter().SetColumnCount ( nColumnCount, nColumnCount); // Force a repaint and re-layout. pShell->ArrangeGUIElements (); // Rearrange the UI-elements controlled by the - // controller and force a rearrangement of the view. + // controller and force a rearrangement of the + // view. mrSlideSorter.GetController().Rearrange(true); } } @@ -167,11 +189,11 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) case SID_SLIDE_TRANSITIONS_PANEL: { - // Make the slide transition panel visible (expand it) in the - // tool pane. + // Make the slide transition panel visible (expand it) + // in the tool pane. if (mrSlideSorter.GetViewShellBase() != NULL) - framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase()) - ->RequestTaskPanel(sd::framework::FrameworkHelper::msSlideTransitionTaskPanelURL); + framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase()) + ->RequestTaskPanel(sd::framework::FrameworkHelper::msSlideTransitionTaskPanelURL); rRequest.Ignore (); break; } @@ -179,7 +201,7 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) case SID_PRESENTATION_DLG: FuSlideShowDlg::Create ( pShell, - mrSlideSorter.GetView().GetWindow(), + mrSlideSorter.GetContentWindow().get(), &mrSlideSorter.GetView(), pDocument, rRequest); @@ -188,16 +210,16 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) case SID_CUSTOMSHOW_DLG: FuCustomShowDlg::Create ( pShell, - mrSlideSorter.GetView().GetWindow(), + mrSlideSorter.GetContentWindow().get(), &mrSlideSorter.GetView(), pDocument, rRequest); - break; + break; case SID_EXPAND_PAGE: FuExpandPage::Create ( pShell, - mrSlideSorter.GetView().GetWindow(), + mrSlideSorter.GetContentWindow().get(), &mrSlideSorter.GetView(), pDocument, rRequest); @@ -206,7 +228,7 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) case SID_SUMMARY_PAGE: FuSummaryPage::Create ( pShell, - mrSlideSorter.GetView().GetWindow(), + mrSlideSorter.GetContentWindow().get(), &mrSlideSorter.GetView(), pDocument, rRequest); @@ -218,17 +240,22 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) rRequest.Done(); break; + case SID_DUPLICATE_PAGE: + DuplicateSelectedSlides(rRequest); + rRequest.Done(); + break; + case SID_DELETE_PAGE: case SID_DELETE_MASTER_PAGE: case SID_DELETE: // we need SID_CUT to handle the delete key - // (DEL -> accelerator -> SID_CUT). - if (mrSlideSorter.GetModel().GetPageCount() > 1) - { - mrSlideSorter.GetController().GetSelectionManager()->DeleteSelectedPages(); - } + // (DEL -> accelerator -> SID_CUT). + if (mrSlideSorter.GetModel().GetPageCount() > 1) + { + mrSlideSorter.GetController().GetSelectionManager()->DeleteSelectedPages(); + } - rRequest.Done(); - break; + rRequest.Done(); + break; case SID_RENAMEPAGE: case SID_RENAME_MASTER_PAGE: @@ -361,21 +388,33 @@ void SlotManager::FuSupport (SfxRequest& rRequest) break; } - case SID_UNDO : + case SID_UNDO: { SlideSorterViewShell* pViewShell = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); if (pViewShell != NULL) + { + view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + SlideSorterController::ModelChangeLock aModelLock (mrSlideSorter.GetController()); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + SelectionObserver::Context aContext (mrSlideSorter); pViewShell->ImpSidUndo (FALSE, rRequest); + } break; } - case SID_REDO : + case SID_REDO: { SlideSorterViewShell* pViewShell = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); if (pViewShell != NULL) + { + view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + SlideSorterController::ModelChangeLock aModelLock (mrSlideSorter.GetController()); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + SelectionObserver::Context aContext (mrSlideSorter); pViewShell->ImpSidRedo (FALSE, rRequest); + } break; } @@ -477,7 +516,7 @@ void SlotManager::GetAttrState (SfxItemSet& rSet) } } -void SlotManager::GetMenuState ( SfxItemSet& rSet) +void SlotManager::GetMenuState (SfxItemSet& rSet) { EditMode eEditMode = mrSlideSorter.GetModel().GetEditMode(); ViewShell* pShell = mrSlideSorter.GetViewShell(); @@ -592,39 +631,48 @@ void SlotManager::GetMenuState ( SfxItemSet& rSet) model::PageEnumeration aSelectedPages ( model::PageEnumerationProvider::CreateSelectedPagesEnumeration( mrSlideSorter.GetModel())); - HideSlideFunction::ExclusionState eState ( - HideSlideFunction::GetExclusionState(aSelectedPages)); + const SlideExclusionState eState (GetSlideExclusionState(aSelectedPages)); switch (eState) { - case HideSlideFunction::MIXED: + case MIXED: // Show both entries. break; - case HideSlideFunction::EXCLUDED: + case EXCLUDED: rSet.DisableItem(SID_HIDE_SLIDE); break; - case HideSlideFunction::INCLUDED: + case INCLUDED: rSet.DisableItem(SID_SHOW_SLIDE); break; - case HideSlideFunction::UNDEFINED: + case UNDEFINED: rSet.DisableItem(SID_HIDE_SLIDE); rSet.DisableItem(SID_SHOW_SLIDE); break; } } + PageKind ePageKind = mrSlideSorter.GetModel().GetPageType(); - if( (eEditMode == EM_MASTERPAGE) && (ePageKind != PK_HANDOUT ) ) + if ((eEditMode == EM_MASTERPAGE) && (ePageKind != PK_HANDOUT)) { rSet.DisableItem(SID_ASSIGN_LAYOUT); } - if( (eEditMode == EM_MASTERPAGE) || (ePageKind==PK_NOTES) ) + if ((eEditMode == EM_MASTERPAGE) || (ePageKind==PK_NOTES)) { rSet.DisableItem(SID_INSERTPAGE); } + + // Disable some slots when in master page mode. + if (eEditMode == EM_MASTERPAGE) + { + if (rSet.GetItemState(SID_INSERTPAGE) == SFX_ITEM_AVAILABLE) + rSet.DisableItem(SID_INSERTPAGE); + if (rSet.GetItemState(SID_DUPLICATE_PAGE) == SFX_ITEM_AVAILABLE) + rSet.DisableItem(SID_DUPLICATE_PAGE); + } } @@ -774,18 +822,22 @@ void SlotManager::GetStatusBarState (SfxItemSet& rSet) model::PageEnumeration aSelectedPages ( model::PageEnumerationProvider::CreateSelectedPagesEnumeration( mrSlideSorter.GetModel())); - pPage = aSelectedPages.GetNextElement()->GetPage(); - nFirstPage = pPage->GetPageNum()/2; - pFirstPage = pPage; - - aPageStr += sal_Unicode(' '); - aPageStr += String::CreateFromInt32( nFirstPage + 1 ); - aPageStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( " / " )); - aPageStr += String::CreateFromInt32( - mrSlideSorter.GetModel().GetPageCount()); - - aLayoutStr = pFirstPage->GetLayoutName(); - aLayoutStr.Erase( aLayoutStr.SearchAscii( SD_LT_SEPARATOR ) ); + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + if (pDescriptor) + { + pPage = pDescriptor->GetPage(); + nFirstPage = pPage->GetPageNum()/2; + pFirstPage = pPage; + + aPageStr += sal_Unicode(' '); + aPageStr += String::CreateFromInt32( nFirstPage + 1 ); + aPageStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( " / " )); + aPageStr += String::CreateFromInt32( + mrSlideSorter.GetModel().GetPageCount()); + + aLayoutStr = pFirstPage->GetLayoutName(); + aLayoutStr.Erase( aLayoutStr.SearchAscii( SD_LT_SEPARATOR ) ); + } } rSet.Put( SfxStringItem( SID_STATUS_PAGE, aPageStr ) ); @@ -836,7 +888,7 @@ void SlotManager::RenameSlide (void) SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); DBG_ASSERT(pFact, "Dialogdiet fail!"); AbstractSvxNameDialog* aNameDlg = pFact->CreateSvxNameDialog( - mrSlideSorter.GetActiveWindow(), + mrSlideSorter.GetContentWindow().get(), aPageName, aDescr); DBG_ASSERT(aNameDlg, "Dialogdiet fail!"); aNameDlg->SetText( aTitle ); @@ -984,123 +1036,110 @@ bool SlotManager::RenameSlideFromDrawViewShell( USHORT nPageId, const String & r */ void SlotManager::InsertSlide (SfxRequest& rRequest) { - PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); - // The fallback insertion position is after the last slide. - sal_Int32 nInsertionIndex (rSelector.GetPageCount() - 1); - if (rSelector.GetSelectedPageCount() > 0) + const sal_Int32 nInsertionIndex (GetInsertionPosition()); + + PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter); + + SdPage* pNewPage = NULL; + if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE) { - // Deselect all but the last selected slide. - bool bLastSelectedSlideSeen (false); - for (int nIndex=rSelector.GetPageCount()-1; nIndex>=0; --nIndex) + SlideSorterViewShell* pShell = dynamic_cast<SlideSorterViewShell*>( + mrSlideSorter.GetViewShell()); + if (pShell != NULL) { - if (rSelector.IsPageSelected(nIndex)) - { - if (bLastSelectedSlideSeen) - rSelector.DeselectPage (nIndex); - else - { - nInsertionIndex = nIndex; - bLastSelectedSlideSeen = true; - } - } + pNewPage = pShell->CreateOrDuplicatePage ( + rRequest, + mrSlideSorter.GetModel().GetPageType(), + nInsertionIndex>=0 + ? mrSlideSorter.GetModel().GetPageDescriptor(nInsertionIndex)->GetPage() + : NULL); } } - - // No selection. Is there an insertion indicator? - else if (mrSlideSorter.GetView().GetOverlay() - .GetInsertionIndicatorOverlay().isVisible()) - { - // Select the page before the insertion indicator. - nInsertionIndex = mrSlideSorter.GetView().GetOverlay() - .GetInsertionIndicatorOverlay().GetInsertionPageIndex(); - nInsertionIndex --; - rSelector.SelectPage (nInsertionIndex); - } - - // Is there a stored insertion position? - else if (mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() >= 0) + else { - nInsertionIndex - = mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() - 1; - rSelector.SelectPage(nInsertionIndex); - } + // Use the API to create a new page. + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + Reference<drawing::XMasterPagesSupplier> xMasterPagesSupplier ( + pDocument->getUnoModel(), UNO_QUERY); + if (xMasterPagesSupplier.is()) + { + Reference<drawing::XDrawPages> xMasterPages ( + xMasterPagesSupplier->getMasterPages()); + if (xMasterPages.is()) + { + xMasterPages->insertNewByIndex (nInsertionIndex+1); - // Select the last page when there is at least one page. - else if (rSelector.GetPageCount() > 0) - { - nInsertionIndex = rSelector.GetPageCount() - 1; - rSelector.SelectPage (nInsertionIndex); + // Create shapes for the default layout. + pNewPage = pDocument->GetMasterSdPage( + (USHORT)(nInsertionIndex+1), PK_STANDARD); + pNewPage->CreateTitleAndLayout (TRUE,TRUE); + } + } } + if (pNewPage == NULL) + return; - // Hope for the best that CreateOrDuplicatePage() can cope with an empty - // selection. - else - { - nInsertionIndex = -1; - } + // When a new page has been inserted then select it, make it the + // current page, and focus it. + view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + mrSlideSorter.GetController().GetPageSelector().SelectPage(pNewPage); +} - USHORT nPageCount ((USHORT)mrSlideSorter.GetModel().GetPageCount()); - rSelector.DisableBroadcasting(); - // In order for SlideSorterController::GetActualPage() to select the - // selected page as current page we have to turn off the focus - // temporarily. - { - FocusManager::FocusHider aTemporaryFocusHider ( - mrSlideSorter.GetController().GetFocusManager()); - SdPage* pPreviousPage = NULL; - if (nInsertionIndex >= 0) - pPreviousPage = mrSlideSorter.GetModel() - .GetPageDescriptor(nInsertionIndex)->GetPage(); - if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE) - { - SlideSorterViewShell* pShell = dynamic_cast<SlideSorterViewShell*>( - mrSlideSorter.GetViewShell()); - if (pShell != NULL) - { - pShell->CreateOrDuplicatePage ( - rRequest, - mrSlideSorter.GetModel().GetPageType(), - pPreviousPage); - } - } - else +void SlotManager::DuplicateSelectedSlides (SfxRequest& rRequest) +{ + // Create a list of the pages that are to be duplicated. The process of + // duplication alters the selection. + sal_Int32 nInsertPosition (0); + ::std::vector<SdPage*> aPagesToDuplicate; + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + if (pDescriptor && pDescriptor->GetPage()) { - // Use the API to create a new page. - SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); - Reference<drawing::XMasterPagesSupplier> xMasterPagesSupplier ( - pDocument->getUnoModel(), UNO_QUERY); - if (xMasterPagesSupplier.is()) - { - Reference<drawing::XDrawPages> xMasterPages ( - xMasterPagesSupplier->getMasterPages()); - if (xMasterPages.is()) - { - xMasterPages->insertNewByIndex (nInsertionIndex+1); - - // Create shapes for the default layout. - SdPage* pMasterPage = pDocument->GetMasterSdPage( - (USHORT)(nInsertionIndex+1), PK_STANDARD); - pMasterPage->CreateTitleAndLayout (TRUE,TRUE); - } - } + aPagesToDuplicate.push_back(pDescriptor->GetPage()); + nInsertPosition = pDescriptor->GetPage()->GetPageNum()+2; } } - // When a new page has been inserted then select it and make it the - // current page. - mrSlideSorter.GetView().LockRedraw(TRUE); - if (mrSlideSorter.GetModel().GetPageCount() > nPageCount) + // Duplicate the pages in aPagesToDuplicate and collect the newly + // created pages in aPagesToSelect. + const bool bUndo (aPagesToDuplicate.size()>1 && mrSlideSorter.GetView().IsUndoEnabled()); + if (bUndo) + mrSlideSorter.GetView().BegUndo(String(SdResId(STR_INSERTPAGE))); + + ::std::vector<SdPage*> aPagesToSelect; + for(::std::vector<SdPage*>::const_iterator + iPage(aPagesToDuplicate.begin()), + iEnd(aPagesToDuplicate.end()); + iPage!=iEnd; + ++iPage, nInsertPosition+=2) { - nInsertionIndex++; - model::SharedPageDescriptor pDescriptor = mrSlideSorter.GetModel().GetPageDescriptor(nInsertionIndex); - if (pDescriptor.get() != NULL) - mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor); + aPagesToSelect.push_back( + mrSlideSorter.GetViewShell()->CreateOrDuplicatePage( + rRequest, PK_STANDARD, *iPage, nInsertPosition)); } - rSelector.EnableBroadcasting(); - mrSlideSorter.GetView().LockRedraw(FALSE); + aPagesToDuplicate.clear(); + + if (bUndo) + mrSlideSorter.GetView().EndUndo(); + + // Set the selection to the pages in aPagesToSelect. + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + rSelector.DeselectAllPages(); + ::std::for_each ( + aPagesToSelect.begin(), + aPagesToSelect.end(), + ::boost::bind( + static_cast<void (PageSelector::*)(const SdPage*)>(&PageSelector::SelectPage), + rSelector, + _1)); } void SlotManager::ExecuteCommandAsynchronously (::std::auto_ptr<Command> pCommand) @@ -1130,5 +1169,154 @@ IMPL_LINK(SlotManager, UserEventCallback, void*, EMPTYARG) return 1; } + + + +void SlotManager::ChangeSlideExclusionState ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bExcludeSlide) +{ + if (rpDescriptor) + { + mrSlideSorter.GetView().SetState( + rpDescriptor, + model::PageDescriptor::ST_Excluded, + bExcludeSlide); + } + else + { + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + mrSlideSorter.GetView().SetState( + pDescriptor, + model::PageDescriptor::ST_Excluded, + bExcludeSlide); + } + } + + SfxBindings& rBindings (mrSlideSorter.GetViewShell()->GetViewFrame()->GetBindings()); + rBindings.Invalidate(SID_PRESENTATION); + rBindings.Invalidate(SID_REHEARSE_TIMINGS); + rBindings.Invalidate(SID_HIDE_SLIDE); + rBindings.Invalidate(SID_SHOW_SLIDE); + mrSlideSorter.GetModel().GetDocument()->SetChanged(); +} + + + + +sal_Int32 SlotManager::GetInsertionPosition (void) +{ + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + + // The insertion indicator is preferred. After all the user explicitly + // used it to define the insertion position. + if (mrSlideSorter.GetController().GetInsertionIndicatorHandler()->IsActive()) + { + // Select the page before the insertion indicator. + return mrSlideSorter.GetController().GetInsertionIndicatorHandler()->GetInsertionPageIndex() + - 1; + } + + // Is there a stored insertion position? + else if (mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() >= 0) + { + return mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() - 1; + } + + // Use the index of the last selected slide. + else if (rSelector.GetSelectedPageCount() > 0) + { + for (int nIndex=rSelector.GetPageCount()-1; nIndex>=0; --nIndex) + if (rSelector.IsPageSelected(nIndex)) + return nIndex; + + // We should never get here. + OSL_ASSERT(false); + return rSelector.GetPageCount() - 1; + } + + // Select the last page when there is at least one page. + else if (rSelector.GetPageCount() > 0) + { + return rSelector.GetPageCount() - 1; + } + + // Hope for the best that CreateOrDuplicatePage() can cope with an empty + // selection. + else + { + // We should never get here because there has to be at least one page. + OSL_ASSERT(false); + return -1; + } +} + + + + +void SlotManager::NotifyEditModeChange (void) +{ + SfxBindings& rBindings (mrSlideSorter.GetViewShell()->GetViewFrame()->GetBindings()); + rBindings.Invalidate(SID_PRESENTATION); + rBindings.Invalidate(SID_INSERTPAGE); + rBindings.Invalidate(SID_DUPLICATE_PAGE); +} + + + + +//----------------------------------------------------------------------------- + +namespace { + + + +SlideExclusionState GetSlideExclusionState (model::PageEnumeration& rPageSet) +{ + SlideExclusionState eState (UNDEFINED); + BOOL bState; + + // Get toggle state of the selected pages. + while (rPageSet.HasMoreElements() && eState!=MIXED) + { + bState = rPageSet.GetNextElement()->GetPage()->IsExcluded(); + switch (eState) + { + case UNDEFINED: + // Use the first selected page to set the inital value. + eState = bState ? EXCLUDED : INCLUDED; + break; + + case EXCLUDED: + // The pages before where all not part of the show, + // this one is. + if ( ! bState) + eState = MIXED; + break; + + case INCLUDED: + // The pages before where all part of the show, + // this one is not. + if (bState) + eState = MIXED; + break; + + case MIXED: + default: + // No need to change anything. + break; + } + } + + return eState; +} + +} // end of anonymous namespace + } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsTransferable.cxx b/sd/source/ui/slidesorter/controller/SlsTransferable.cxx index 20ddc937469c..efda2eb1e4eb 100644..100755 --- a/sd/source/ui/slidesorter/controller/SlsTransferable.cxx +++ b/sd/source/ui/slidesorter/controller/SlsTransferable.cxx @@ -28,7 +28,7 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sd.hxx" -#include "SlsTransferable.hxx" +#include "controller/SlsTransferable.hxx" #include "SlideSorterViewShell.hxx" #include "View.hxx" @@ -39,9 +39,11 @@ Transferable::Transferable ( SdDrawDocument* pSrcDoc, ::sd::View* pWorkView, BOOL bInitOnGetData, - SlideSorterViewShell* pViewShell) + SlideSorterViewShell* pViewShell, + const ::std::vector<Representative>& rRepresentatives) : SdTransferable (pSrcDoc, pWorkView, bInitOnGetData), - mpViewShell(pViewShell) + mpViewShell(pViewShell), + maRepresentatives(rRepresentatives) { if (mpViewShell != NULL) StartListening(*mpViewShell); @@ -49,6 +51,7 @@ Transferable::Transferable ( + Transferable::~Transferable (void) { if (mpViewShell != NULL) @@ -89,4 +92,10 @@ void Transferable::Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) +const ::std::vector<Transferable::Representative>& Transferable::GetRepresentatives (void) const +{ + return maRepresentatives; +} + + } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx b/sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx new file mode 100644 index 000000000000..6a85192f8418 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx @@ -0,0 +1,301 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "controller/SlsVisibleAreaManager.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsAnimationFunction.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsCurrentSlideManager.hxx" + + +namespace sd { namespace slidesorter { namespace controller { + +namespace { + class VisibleAreaScroller + { + public: + VisibleAreaScroller ( + SlideSorter& rSlideSorter, + const Point aStart, + const Point aEnd); + void operator() (const double nValue); + private: + SlideSorter& mrSlideSorter; + Point maStart; + const Point maEnd; + const ::boost::function<double(double)> maAccelerationFunction; + }; + +} // end of anonymous namespace + + + +VisibleAreaManager::VisibleAreaManager (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + maVisibleRequests(), + mnScrollAnimationId(Animator::NotAnAnimationId), + maRequestedVisibleTopLeft(), + meRequestedAnimationMode(Animator::AM_Immediate), + mbIsCurrentSlideTrackingActive(true), + mnDisableCount(0) +{ +} + + + + +VisibleAreaManager::~VisibleAreaManager (void) +{ +} + + + + +void VisibleAreaManager::ActivateCurrentSlideTracking (void) +{ + mbIsCurrentSlideTrackingActive = true; +} + + + + +void VisibleAreaManager::DeactivateCurrentSlideTracking (void) +{ + mbIsCurrentSlideTrackingActive = false; +} + + + + +void VisibleAreaManager::RequestVisible ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bForce) +{ + if (rpDescriptor) + { + if (mnDisableCount == 0) + { + maVisibleRequests.push_back( + mrSlideSorter.GetView().GetLayouter().GetPageObjectBox( + rpDescriptor->GetPageIndex(), + true)); + } + if (bForce && ! mbIsCurrentSlideTrackingActive) + ActivateCurrentSlideTracking(); + MakeVisible(); + } +} + + + + +void VisibleAreaManager::RequestCurrentSlideVisible (void) +{ + if (mbIsCurrentSlideTrackingActive && mnDisableCount==0) + RequestVisible( + mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()); +} + + + + +void VisibleAreaManager::MakeVisible (void) +{ + if (maVisibleRequests.empty()) + return; + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if ( ! pWindow) + return; + const Point aCurrentTopLeft (pWindow->PixelToLogic(Point(0,0))); + + const ::boost::optional<Point> aNewVisibleTopLeft (GetRequestedTopLeft()); + maVisibleRequests.clear(); + if ( ! aNewVisibleTopLeft) + return; + + // We now know what the visible area shall be. Scroll accordingly + // unless that is not already the visible area or a running scroll + // animation has it as its target area. + if (mnScrollAnimationId!=Animator::NotAnAnimationId + && maRequestedVisibleTopLeft==aNewVisibleTopLeft) + return; + + // Stop a running animation. + if (mnScrollAnimationId != Animator::NotAnAnimationId) + mrSlideSorter.GetController().GetAnimator()->RemoveAnimation(mnScrollAnimationId); + + maRequestedVisibleTopLeft = aNewVisibleTopLeft.get(); + VisibleAreaScroller aAnimation( + mrSlideSorter, + aCurrentTopLeft, + maRequestedVisibleTopLeft); + if (meRequestedAnimationMode==Animator::AM_Animated + && mrSlideSorter.GetProperties()->IsSmoothSelectionScrolling()) + { + mnScrollAnimationId = mrSlideSorter.GetController().GetAnimator()->AddAnimation( + aAnimation, + 0, + 300); + } + else + { + // Execute the animation at its final value. + aAnimation(1.0); + } + meRequestedAnimationMode = Animator::AM_Immediate; +} + + + + +::boost::optional<Point> VisibleAreaManager::GetRequestedTopLeft (void) const +{ + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if ( ! pWindow) + return ::boost::optional<Point>(); + + // Get the currently visible area and the model area. + const Rectangle aVisibleArea (pWindow->PixelToLogic( + Rectangle( + Point(0,0), + pWindow->GetOutputSizePixel()))); + const Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); + + sal_Int32 nVisibleTop (aVisibleArea.Top()); + const sal_Int32 nVisibleWidth (aVisibleArea.GetWidth()); + sal_Int32 nVisibleLeft (aVisibleArea.Left()); + const sal_Int32 nVisibleHeight (aVisibleArea.GetHeight()); + + // Find the longest run of boxes whose union fits into the visible area. + Rectangle aBoundingBox; + for (::std::vector<Rectangle>::const_iterator + iBox(maVisibleRequests.begin()), + iEnd(maVisibleRequests.end()); + iBox!=iEnd; + ++iBox) + { + if (nVisibleTop+nVisibleHeight <= iBox->Bottom()) + nVisibleTop = iBox->Bottom()-nVisibleHeight; + if (nVisibleTop > iBox->Top()) + nVisibleTop = iBox->Top(); + + if (nVisibleLeft+nVisibleWidth <= iBox->Right()) + nVisibleLeft = iBox->Right()-nVisibleWidth; + if (nVisibleLeft > iBox->Left()) + nVisibleLeft = iBox->Left(); + + // Make sure the visible area does not move outside the model area. + if (nVisibleTop + nVisibleHeight > aModelArea.Bottom()) + nVisibleTop = aModelArea.Bottom() - nVisibleHeight; + if (nVisibleTop < aModelArea.Top()) + nVisibleTop = aModelArea.Top(); + + if (nVisibleLeft + nVisibleWidth > aModelArea.Right()) + nVisibleLeft = aModelArea.Right() - nVisibleWidth; + if (nVisibleLeft < aModelArea.Left()) + nVisibleLeft = aModelArea.Left(); + } + + const Point aRequestedTopLeft (nVisibleLeft, nVisibleTop); + if (aRequestedTopLeft == aVisibleArea.TopLeft()) + return ::boost::optional<Point>(); + else + return ::boost::optional<Point>(aRequestedTopLeft); +} + + + + +//===== VisibleAreaManager::TemporaryDisabler ================================= + +VisibleAreaManager::TemporaryDisabler::TemporaryDisabler (SlideSorter& rSlideSorter) + : mrVisibleAreaManager(rSlideSorter.GetController().GetVisibleAreaManager()) +{ + ++mrVisibleAreaManager.mnDisableCount; +} + + + + +VisibleAreaManager::TemporaryDisabler::~TemporaryDisabler (void) +{ + --mrVisibleAreaManager.mnDisableCount; +} + + + +//===== VerticalVisibleAreaScroller =========================================== + +namespace { + +const static sal_Int32 gnMaxScrollDistance = 300; + +VisibleAreaScroller::VisibleAreaScroller ( + SlideSorter& rSlideSorter, + const Point aStart, + const Point aEnd) + : mrSlideSorter(rSlideSorter), + maStart(aStart), + maEnd(aEnd), + maAccelerationFunction( + controller::AnimationParametricFunction( + controller::AnimationBezierFunction (0.1,0.6))) +{ + // When the distance to scroll is larger than a threshold then first + // jump to within this distance of the final value and start the + // animation from there. + if (abs(aStart.X()-aEnd.X()) > gnMaxScrollDistance) + if (aStart.X() < aEnd.X()) + maStart.X() = aEnd.X()-gnMaxScrollDistance; + else + maStart.X() = aEnd.X()+gnMaxScrollDistance; + if (abs(aStart.Y()-aEnd.Y()) > gnMaxScrollDistance) + if (aStart.Y() < aEnd.Y()) + maStart.Y() = aEnd.Y()-gnMaxScrollDistance; + else + maStart.Y() = aEnd.Y()+gnMaxScrollDistance; +} + + + + +void VisibleAreaScroller::operator() (const double nTime) +{ + const double nLocalTime (maAccelerationFunction(nTime)); + mrSlideSorter.GetController().GetScrollBarManager().SetTopLeft( + Point( + sal_Int32(0.5 + maStart.X() * (1.0 - nLocalTime) + maEnd.X() * nLocalTime), + sal_Int32 (0.5 + maStart.Y() * (1.0 - nLocalTime) + maEnd.Y() * nLocalTime))); +} + +} // end of anonymous namespace + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/makefile.mk b/sd/source/ui/slidesorter/controller/makefile.mk index 8ab63ddf776c..460ef16ed3f1 100644..100755 --- a/sd/source/ui/slidesorter/controller/makefile.mk +++ b/sd/source/ui/slidesorter/controller/makefile.mk @@ -45,25 +45,23 @@ PRJINC=..$/.. SLOFILES = \ $(SLO)$/SlideSorterController.obj \ $(SLO)$/SlsAnimator.obj \ + $(SLO)$/SlsAnimationFunction.obj \ $(SLO)$/SlsClipboard.obj \ $(SLO)$/SlsCurrentSlideManager.obj \ + $(SLO)$/SlsDragAndDropContext.obj \ $(SLO)$/SlsFocusManager.obj \ + $(SLO)$/SlsInsertionIndicatorHandler.obj\ $(SLO)$/SlsListener.obj \ - $(SLO)$/SlsPageObjectFactory.obj \ $(SLO)$/SlsPageSelector.obj \ $(SLO)$/SlsProperties.obj \ $(SLO)$/SlsScrollBarManager.obj \ $(SLO)$/SlsSelectionCommand.obj \ + $(SLO)$/SlsSelectionFunction.obj \ $(SLO)$/SlsSelectionManager.obj \ + $(SLO)$/SlsSelectionObserver.obj \ $(SLO)$/SlsSlotManager.obj \ $(SLO)$/SlsTransferable.obj \ - \ - $(SLO)$/SlsHideSlideFunction.obj \ - $(SLO)$/SlsSelectionFunction.obj \ - $(SLO)$/SlsSlideFunction.obj - -EXCEPTIONSFILES= \ - $(SLO)$/SlideSorterController.obj + $(SLO)$/SlsVisibleAreaManager.obj # --- Tagets ------------------------------------------------------- diff --git a/sd/source/ui/slidesorter/inc/cache/SlsCacheContext.hxx b/sd/source/ui/slidesorter/inc/cache/SlsCacheContext.hxx index c828e95d1d02..ba3e9346f28f 100644..100755 --- a/sd/source/ui/slidesorter/inc/cache/SlsCacheContext.hxx +++ b/sd/source/ui/slidesorter/inc/cache/SlsCacheContext.hxx @@ -33,8 +33,8 @@ #include <boost/shared_ptr.hpp> #include <vector> -class BitmapEx; class SdrPage; +class Bitmap; namespace sd { namespace slidesorter { namespace cache { @@ -55,7 +55,7 @@ public: */ virtual void NotifyPreviewCreation ( CacheKey aKey, - const ::boost::shared_ptr<BitmapEx>& rPreview) = 0; + const Bitmap& rPreview) = 0; /** Called to determine whether the system is idle and a preview can be created without annoying the user. diff --git a/sd/source/ui/slidesorter/inc/cache/SlsPageCache.hxx b/sd/source/ui/slidesorter/inc/cache/SlsPageCache.hxx index 4a5c2b51ac28..bd2b542c5d87 100755..100644 --- a/sd/source/ui/slidesorter/inc/cache/SlsPageCache.hxx +++ b/sd/source/ui/slidesorter/inc/cache/SlsPageCache.hxx @@ -30,10 +30,10 @@ #include "cache/SlsCacheContext.hxx" #include <sal/types.h> -#include <vcl/bitmapex.hxx> -#include <boost/function.hpp> +#include <tools/gen.hxx> #include <boost/scoped_ptr.hpp> -#include <boost/shared_ptr.hpp> +#include <vcl/bitmap.hxx> + namespace sd { namespace slidesorter { namespace view { class PageObjectViewObjectContact; @@ -87,37 +87,68 @@ public: */ PageCache ( const Size& rPreviewSize, + const bool bDoSuperSampling, const SharedCacheContext& rpCacheContext); ~PageCache (void); - void ChangeSize(const Size& rPreviewSize); + void ChangeSize( + const Size& rPreviewSize, + const bool bDoSuperSampling); /** Request a preview bitmap for the specified page object in the specified size. The returned bitmap may be a preview of the preview, i.e. either a scaled (up or down) version of a previous preview (of the wrong size) or an empty bitmap. In this case a request for the generation of a new preview is created and inserted - into the request queue. When the preview is available the page - shape will be told to paint itself again. When it then calls this - method again if receives the correctly sized preview bitmap. + into the request queue. When the preview is available in the right + size the page shape will be told to paint itself again. When it + then calls this method again if receives the correctly sized preview + bitmap. @param rRequestData This data is used to determine the preview. - @param rSize - The size of the requested preview bitmap. + @param bResize + When <TRUE/> then when the available bitmap has not the + requested size, it is scaled before it is returned. When + <FALSE/> then the bitmap is returned in the wrong size and it is + the task of the caller to scale it. @return Returns a bitmap that is either empty, contains a scaled (up or down) version or is the requested bitmap. */ - BitmapEx GetPreviewBitmap ( - CacheKey aKey, - const Size& rSize); + Bitmap GetPreviewBitmap ( + const CacheKey aKey, + const bool bResize); + + Bitmap GetMarkedPreviewBitmap ( + const CacheKey aKey, + const bool bResize); + void SetMarkedPreviewBitmap ( + const CacheKey aKey, + const Bitmap& rBitmap); + + /** When the requested preview bitmap does not yet exist or is not + up-to-date then the rendering of one is scheduled. Otherwise this + method does nothing. + */ + void RequestPreviewBitmap (const CacheKey aKey); + + /** Tell the cache that the bitmap associated with the given request + data is not up-to-date anymore. This will invalidate all previews + in other caches that represent the same page as well. + @param bRequestPreview + When <TRUE/> then a new preview is requested and will lead + eventually to a repaint of the associated page object. + */ + void InvalidatePreviewBitmap ( + const CacheKey aKey, + const bool bRequestPreview); /** Call this method when a view-object-contact object is being deleted and does not need (a) its current bitmap in the cache and (b) a requested new bitmap. */ - void ReleasePreviewBitmap (CacheKey aKey); + void ReleasePreviewBitmap (const CacheKey aKey); /** Call this method when all preview bitmaps have to be generated anew. This is the case when the size of the page objects on the screen has @@ -127,14 +158,14 @@ public: are created. When it is <FALSE/> the existing previews are only marked as not being up-to-date anymore. */ - void InvalidateCache (bool bUpdateCache = true); + void InvalidateCache (const bool bUpdateCache = true); /** With the precious flag you can control whether a bitmap can be removed or reduced in size to make room for other bitmaps or is so precious that it will not touched. A typical use is to set the precious flag for exactly the visible pages. */ - void SetPreciousFlag (CacheKey aKey, bool bIsPrecious); + void SetPreciousFlag (const CacheKey aKey, const bool bIsPrecious); void Pause (void); void Resume (void); diff --git a/sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx b/sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx index 50202a7eed3d..71d7778f549f 100644..100755 --- a/sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx +++ b/sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx @@ -103,16 +103,27 @@ public: marked as out-of-date and will be re-created when they are requested the next time. */ - void InvalidatePreviewBitmap ( + bool InvalidatePreviewBitmap ( DocumentKey pDocument, const SdrPage* pPage); + /** Invalidate the preview bitmaps for all slides that belong to the + specified document. This is necessary after model changes that + affect e.g. page number fiels. + */ + void InvalidateAllPreviewBitmaps (DocumentKey pDocument); + /** Invalidate all the caches that are currently in use and destroy those that are not. This is used for example when the high contrast mode is turned on or off. */ void InvalidateAllCaches (void); + /** Call this method when a page has been deleted and its preview + is not needed anymore. + */ + void ReleasePreviewBitmap (const SdrPage* pPage); + private: /** Singleton instance of the cache manager. Note that this is a weak pointer. The (implementation class of) ViewShellBase holds a diff --git a/sd/source/ui/slidesorter/inc/controller/SlideSorterController.hxx b/sd/source/ui/slidesorter/inc/controller/SlideSorterController.hxx index 667aa768ee8f..b6309f80d0b4 100755 --- a/sd/source/ui/slidesorter/inc/controller/SlideSorterController.hxx +++ b/sd/source/ui/slidesorter/inc/controller/SlideSorterController.hxx @@ -37,7 +37,6 @@ #include <sfx2/viewfac.hxx> #include <tools/link.hxx> #include <tools/gen.hxx> -#include <memory> #include <comphelper/implementationreference.hxx> namespace sd { namespace slidesorter { @@ -61,12 +60,15 @@ class Animator; class Clipboard; class CurrentSlideManager; class FocusManager; +class InsertionIndicatorHandler; class Listener; class PageSelector; -class Properties; class ScrollBarManager; +class SelectionFunction; class SelectionManager; +class SelectionObserver; class SlotManager; +class VisibleAreaManager; class SlideSorterController { @@ -85,6 +87,8 @@ public: virtual ~SlideSorterController (void); + void Dispose (void); + /** Place and size the scroll bars and the browser window so that the given rectangle is filled. @return @@ -106,7 +110,8 @@ public: Rectangle Rearrange (bool bForce = false); /** Return the descriptor of the page that is rendered under the - given position. + given position. This takes the IsOnlyPreviewTriggersMouseOver + property into account. @return Returns a pointer to a page descriptor instead of a reference because when no page is found at the position @@ -125,9 +130,7 @@ public: ::boost::shared_ptr<CurrentSlideManager> GetCurrentSlideManager (void) const; ::boost::shared_ptr<SlotManager> GetSlotManager (void) const; ::boost::shared_ptr<SelectionManager> GetSelectionManager (void) const; - - // forward VCLs PrePaint window event to DrawingLayer - void PrePaint(); + ::boost::shared_ptr<InsertionIndicatorHandler> GetInsertionIndicatorHandler (void) const; /** This method forwards the call to the SlideSorterView and executes pending operations like moving selected pages into the visible area. @@ -183,6 +186,12 @@ public: */ virtual FunctionReference CreateSelectionFunction (SfxRequest& rRequest); + /** When the current function of the view shell is the slide sorter + selection function then return a reference to it. Otherwise return + an empty reference. + */ + ::rtl::Reference<SelectionFunction> GetCurrentSelectionFunction (void); + /** Prepare for a change of the edit mode. Depending on the current edit mode we may save the selection so that it can be restored when later changing back to the current edit mode. @@ -219,11 +228,6 @@ public: */ bool IsContextMenuOpen (void) const; - /** Return a collection of properties that are used througout the slide - sorter. - */ - ::boost::shared_ptr<Properties> GetProperties (void) const; - /** Provide the set of pages to be displayed in the slide sorter. The GetDocumentSlides() method can be found only in the SlideSorterModel. */ @@ -233,18 +237,24 @@ public: */ ::boost::shared_ptr<Animator> GetAnimator (void) const; + VisibleAreaManager& GetVisibleAreaManager (void) const; + + void CheckForMasterPageAssignment (void); + private: SlideSorter& mrSlideSorter; model::SlideSorterModel& mrModel; view::SlideSorterView& mrView; - ::std::auto_ptr<PageSelector> mpPageSelector; - ::std::auto_ptr<FocusManager> mpFocusManager; + ::boost::scoped_ptr<PageSelector> mpPageSelector; + ::boost::scoped_ptr<FocusManager> mpFocusManager; ::boost::shared_ptr<SlotManager> mpSlotManager; - ::std::auto_ptr<controller::Clipboard> mpClipboard; - ::std::auto_ptr<ScrollBarManager> mpScrollBarManager; + ::boost::scoped_ptr<controller::Clipboard> mpClipboard; + ::boost::scoped_ptr<ScrollBarManager> mpScrollBarManager; mutable ::boost::shared_ptr<CurrentSlideManager> mpCurrentSlideManager; ::boost::shared_ptr<SelectionManager> mpSelectionManager; + ::boost::shared_ptr<InsertionIndicatorHandler> mpInsertionIndicatorHandler; ::boost::shared_ptr<Animator> mpAnimator; + ::boost::scoped_ptr<VisibleAreaManager> mpVisibleAreaManager; // The listener listens to UNO events and thus is a UNO object. // For proper life time management and at the same time free access to @@ -252,6 +262,7 @@ private: ::rtl::Reference<controller::Listener> mpListener; int mnModelChangeLockCount; + bool mbIsForcedRearrangePending; bool mbPreModelChangeDone; bool mbPostModelChangePending; @@ -286,11 +297,6 @@ private: */ bool mbIsContextMenuOpen; - /** Some slide sorter wide properties that are used in different - classes. - */ - ::boost::shared_ptr<Properties> mpProperties; - /** Delete the given list of normal pages. This method is a helper function for DeleteSelectedPages(). @param rSelectedNormalPages diff --git a/sd/source/ui/slidesorter/inc/controller/SlsAnimationFunction.hxx b/sd/source/ui/slidesorter/inc/controller/SlsAnimationFunction.hxx new file mode 100644 index 000000000000..38d0b2b22749 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsAnimationFunction.hxx @@ -0,0 +1,180 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_CONTROLLER_ANIMATION_FUNCTION_HXX +#define SD_SLIDESORTER_CONTROLLER_ANIMATION_FUNCTION_HXX + +#include "model/SlsSharedPageDescriptor.hxx" +#include <basegfx/point/b2dpoint.hxx> +#include <boost/noncopyable.hpp> +#include <boost/function.hpp> +#include <tools/gen.hxx> +#include <vector> + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +} } } + + + +namespace sd { namespace slidesorter { namespace controller { + +/** A collection of functions that are usefull when creating animations. + They are collected here until a better place is found. +*/ +class AnimationFunction + : private ::boost::noncopyable +{ +public: + /** Acceleration function that maps [0,1] to [0,1] linearly, ie it + returns the given time value unaltered. + */ + static double Linear (const double nTime); + + /** Acceleration function that maps [0,1] to [0,1]. Speed starts fast + and ends slow following the sine function. + */ + static double FastInSlowOut_Sine (const double nTime); + + /** Acceleration function that maps [0,1] to [0,1]. Speed starts fast + and ends slow following the square root function. + */ + static double FastInSlowOut_Root (const double nTime); + + /** Acceleration function that maps [0,1] to [0,0]. Speed starts slow, + rises, drops and ends slow following the sine function. + */ + static double SlowInSlowOut_0to0_Sine (const double nTime); + + /** Acceleration function that maps [0,1] to [0,0]. Speed starts slow, + rises and drops several times and ends slow following multiple + cycles of the the sine function. + */ + static double Vibrate_Sine (const double nTime); + + /** Scale point linearly. + */ + static Point ScalePoint (const Point& rPoint, const double nTime); + + /** Blend two points together according to the given weight. + */ + static double Blend (const double nStartValue, const double nEndValue, const double nWeight); + + /** Apply a gradual visual state change. The kind of change, i.e. the + previous and the new states are expected to be already set. This + method only adjusts the blending of the visual representation from + one state to the other. + */ + static void ApplyVisualStateChange ( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const double nTime); + + /** Apply a gradual change of a previously set offset to the location of + a page object. + */ + static void ApplyLocationOffsetChange ( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const Point aLocationOffset); + + /** Apply a gradual change the alpha value from the old value to a + new value (set prior to this call.) + */ + static void ApplyButtonAlphaChange( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const double nButtonAlpha, + const double nButtonBarAlpha); +}; + + + + +class AnimationBezierFunction +{ +public: + /** Create a cubic bezier curve whose start and end points are given + implicitly as P0=(0,0) and P3=(1,1). + */ + AnimationBezierFunction ( + const double nX1, + const double nY1, + const double nX2, + const double nY2); + + /** Create a cubic bezier curve whose start and end points are given + implicitly as P0=(0,0) and P3=(1,1). The second control point is + implicitly given as P2=(1-nY1,1-nX1). + */ + AnimationBezierFunction ( + const double nX1, + const double nY1); + + ::basegfx::B2DPoint operator() (const double nT); + +private: + const double mnX1; + const double mnY1; + const double mnX2; + const double mnY2; + + double EvaluateComponent ( + const double nT, + const double nV1, + const double nV2); +}; + + + + +/** Turn a parametric function into one whose y-Values depend on its + x-Values. Note a lot of interpolation takes place. The resulting + accuracy should be good enough for the purpose of acceleration + function for animations. +*/ +class AnimationParametricFunction +{ +public: + typedef ::boost::function<basegfx::B2DPoint(double)> ParametricFunction; + AnimationParametricFunction (const ParametricFunction& rFunction); + + double operator() (const double nX); + +private: + /** y-Values of the parametric function given to the constructor + evaluated (and interpolated) for evenly spaced x-Values. + */ + ::std::vector<double> maY; +}; + + + + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlsAnimator.hxx b/sd/source/ui/slidesorter/inc/controller/SlsAnimator.hxx index 50c23e3dff4e..2d8418e49631 100644..100755 --- a/sd/source/ui/slidesorter/inc/controller/SlsAnimator.hxx +++ b/sd/source/ui/slidesorter/inc/controller/SlsAnimator.hxx @@ -29,6 +29,8 @@ #define SD_SLIDESORTER_CONTROLLER_ANIMATOR_HXX #include "SlideSorter.hxx" +#include "view/SlideSorterView.hxx" +#include <canvas/elapsedtime.hxx> #include <vcl/timer.hxx> #include <sal/types.h> #include <vector> @@ -46,51 +48,94 @@ class Animator : private ::boost::noncopyable { public: + /** In some circumstances we have to avoid animation and jump to the + final animation state immediately. Use this enum instead of a bool + to be more expressive. + */ + enum AnimationMode { AM_Animated, AM_Immediate }; + Animator (SlideSorter& rSlideSorter); ~Animator (void); + /** When disposed the animator will stop its work immediately and not + process any timer events anymore. + */ + void Dispose (void); + /** An animation object is called with values between 0 and 1 as single argument to its operator() method. */ - typedef ::boost::function1<void, double> AnimationFunction; + typedef ::boost::function1<void, double> AnimationFunctor; + typedef ::boost::function0<void> FinishFunctor; + + typedef sal_Int32 AnimationId; + static const AnimationId NotAnAnimationId = -1; /** Schedule a new animation for execution. The () operator of that animation will be called with increasing values between 0 and 1 for the specified duration. @param rAnimation The animation operation. + @param nStartOffset + Time in milli seconds before the animation is started. @param nDuration The duration in milli seconds. */ - void AddAnimation ( - const AnimationFunction& rAnimation, - const sal_Int32 nDuration); + AnimationId AddAnimation ( + const AnimationFunctor& rAnimation, + const sal_Int32 nStartOffset, + const sal_Int32 nDuration, + const FinishFunctor& rFinishFunctor = FinishFunctor()); + + AnimationId AddInfiniteAnimation ( + const AnimationFunctor& rAnimation, + const double nDelta); + + /** Abort and remove an animation. In order to reduce the bookkeeping + on the caller side, it is OK to call this method with an animation + function that is not currently being animated. Such a call is + silently ignored. + */ + void RemoveAnimation (const AnimationId nAnimationId); + + /** A typical use case for this method is the temporary shutdown of the + slidesorter when the slide sorter bar is put into a cache due to a + change of the edit mode. + */ + void RemoveAllAnimations (void); private: SlideSorter& mrSlideSorter; Timer maTimer; - + bool mbIsDisposed; class Animation; typedef ::std::vector<boost::shared_ptr<Animation> > AnimationList; AnimationList maAnimations; + ::canvas::tools::ElapsedTime maElapsedTime; - class DrawLock; - ::boost::scoped_ptr<DrawLock> mpDrawLock; + ::boost::scoped_ptr<view::SlideSorterView::DrawLock> mpDrawLock; + + AnimationId mnNextAnimationId; DECL_LINK(TimeoutHandler, Timer*); /** Execute one step of every active animation. + @param nTime + Time measured in milli seconds with some arbitrary reference point. @return When one or more animation has finished then <TRUE/> is returned. Call CleanUpAnimationList() in this case. */ - bool ServeAnimations (void); + bool ProcessAnimations (const double nTime); /** Remove animations that have expired. */ void CleanUpAnimationList (void); + + void RequestNextFrame (const double nFrameStart = 0); }; + } } } // end of namespace ::sd::slidesorter::controller #endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx b/sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx index 0bdbd7cb569f..9b7b1f5ec2d3 100644..100755 --- a/sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx +++ b/sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx @@ -24,11 +24,12 @@ * for a copy of the LGPLv3 License. * ************************************************************************/ + #ifndef SD_SLIDESORTER_CLIPBOARD #define SD_SLIDESORTER_CLIPBOARD #include "ViewClipboard.hxx" - +#include "controller/SlsSelectionObserver.hxx" #include <sal/types.h> #include <tools/solar.h> #include <svx/svdpage.hxx> @@ -96,6 +97,8 @@ public: USHORT nPage = SDRPAGE_NOTFOUND, USHORT nLayer = SDRPAGE_NOTFOUND); + void Abort (void); + protected: virtual USHORT DetermineInsertPosition ( const SdTransferable& rTransferable); @@ -127,6 +130,15 @@ private: */ bool mbUpdateSelectionPending; + /** Used when a drop is executed to combine all undo actions into one. + Typically created in ExecuteDrop() and released in DragFinish(). + */ + class UndoContext; + ::boost::scoped_ptr<UndoContext> mpUndoContext; + + ::boost::scoped_ptr<SelectionObserver::Context> mpSelectionObserverContext; + ULONG mnDragFinishedUserEventId; + void CreateSlideTransferable ( ::Window* pWindow, bool bDrag); @@ -208,6 +220,11 @@ private: ::sd::Window* pTargetWindow, USHORT nPage, USHORT nLayer); + + /** Asynchronous part of DragFinished. The argument is the sal_Int8 + nDropAction, disguised as void*. + */ + DECL_LINK(ProcessDragFinished, void*); }; } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/inc/controller/SlsCurrentSlideManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsCurrentSlideManager.hxx index b0f3a75b540c..f49207a0bd48 100644..100755 --- a/sd/source/ui/slidesorter/inc/controller/SlsCurrentSlideManager.hxx +++ b/sd/source/ui/slidesorter/inc/controller/SlsCurrentSlideManager.hxx @@ -29,6 +29,8 @@ #define SD_SLIDESORTER_CURRENT_SLIDE_MANAGER_HXX #include "model/SlsSharedPageDescriptor.hxx" +#include <vcl/timer.hxx> +#include <tools/link.hxx> #include <com/sun/star/drawing/XDrawPage.hpp> class SdPage; @@ -43,6 +45,10 @@ namespace sd { namespace slidesorter { namespace controller { /** Manage the current slide. This includes setting the according flags at the PageDescriptor objects and setting the current slide at the main view shell. + + Switching pages is triggered only after a little delay. This allows + fast travelling through a larger set of slides without having to wait + for the edit view to update its content after every slide change. */ class CurrentSlideManager { @@ -57,14 +63,24 @@ public: /** Call this when the current page of the main view shell has been switched. Use SwitchCurrentSlide() to initiate such a switch. */ - void CurrentSlideHasChanged (const sal_Int32 nSlideIndex); + void NotifyCurrentSlideChange (const sal_Int32 nSlideIndex); + void NotifyCurrentSlideChange (const SdPage* pPage); /** Call this method to switch the current page of the main view shell to the given slide. Use CurrentSlideHasChanged() when the current slide change has been initiated by someone else. + @param nSlideIndex + Zero based index in the range [0,number-of-slides). + @param bUpdateSelection + When <TRUE/> then the page selection is cleared and only the new + current slide is selected. */ - void SwitchCurrentSlide (const sal_Int32 nSlideIndex); - void SwitchCurrentSlide (const model::SharedPageDescriptor& rpSlide); + void SwitchCurrentSlide ( + const sal_Int32 nSlideIndex, + const bool bUpdateSelection = false); + void SwitchCurrentSlide ( + const model::SharedPageDescriptor& rpSlide, + const bool bUpdateSelection = false); /** Return the page descriptor for the current slide. Note, that when there is no current slide then the returned pointer is empty. @@ -83,9 +99,14 @@ private: SlideSorter& mrSlideSorter; sal_Int32 mnCurrentSlideIndex; model::SharedPageDescriptor mpCurrentSlide; + /** Timer to control the delay after which to ask + XController/ViewShellBase to switch to another slide. + */ + Timer maSwitchPageDelayTimer; bool IsCurrentSlideIsValid (void); void SetCurrentSlideAtViewShellBase (const model::SharedPageDescriptor& rpSlide); + void SetCurrentSlideAtTabControl (const model::SharedPageDescriptor& rpSlide); void SetCurrentSlideAtXController (const model::SharedPageDescriptor& rpSlide); /** When switching from one slide to a new current slide then this @@ -97,6 +118,8 @@ private: method connects to the new current slide. */ void AcquireCurrentSlide (const sal_Int32 nSlideIndex); + + DECL_LINK(SwitchPageCallback,void*); }; diff --git a/sd/source/ui/slidesorter/inc/controller/SlsFocusManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsFocusManager.hxx index ecc02e8590c1..1d5aaee7a130 100644..100755 --- a/sd/source/ui/slidesorter/inc/controller/SlsFocusManager.hxx +++ b/sd/source/ui/slidesorter/inc/controller/SlsFocusManager.hxx @@ -120,16 +120,6 @@ public: */ sal_Int32 GetFocusedPageIndex (void) const; - /** DEPRECATED. (Use equivalent SetFocusedPage(sal_Int32) instead. - - Set the focus to the page with the given index. This does not make - the focus visible. - @param nPageIndex - Index of a page as it is accepted by the slide sorter model. - The index is not checked for validity. - */ - void FocusPage (sal_Int32 nPageIndex); - /** Set the focused page to the one described by the given page descriptor. The visibility of the focus indicator is not modified. @param rDescriptor @@ -145,6 +135,8 @@ public: */ void SetFocusedPage (sal_Int32 nPageIndex); + void SetFocusedPageToCurrentPage (void); + /** Return <TRUE/> when the focus inidcator is currently shown. A prerequisite is that the window managed by this focus manager has the input focus as indicated by a <TRUE/> return value of @@ -203,6 +195,12 @@ private: ::std::vector<Link> maFocusChangeListeners; + /** When vertical wrap is active then pressing UP in the top row moves + the focus to the bottom row, DOWN in the bottom row moves the focus + to the top row. + */ + bool mbIsVerticalWrapActive; + /** Reset the focus state of the given descriptor and request a repaint so that the focus indicator is hidden. @param pDescriptor diff --git a/sd/source/ui/slidesorter/inc/controller/SlsInsertionIndicatorHandler.hxx b/sd/source/ui/slidesorter/inc/controller/SlsInsertionIndicatorHandler.hxx new file mode 100644 index 000000000000..e257c5729b10 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsInsertionIndicatorHandler.hxx @@ -0,0 +1,153 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_INSERTION_INDICATOR_HANDLER_HXX +#define SD_SLIDESORTER_INSERTION_INDICATOR_HANDLER_HXX + +#include "view/SlsInsertAnimator.hxx" + +#include "view/SlsLayouter.hxx" + +namespace sd { namespace slidesorter { class SlideSorter; } } +namespace sd { namespace slidesorter { namespace model { +class PageEnumeration; +} } } +namespace sd { namespace slidesorter { namespace view { +class InsertAnimator; +class InsertionIndicatorOverlay; +} } } + + +namespace sd { namespace slidesorter { namespace controller { + +class Transferable; + + +/** Manage the visibility and location of the insertion indicator. Its + actual display is controlled by the InsertionIndicatorOverlay. +*/ +class InsertionIndicatorHandler +{ +public: + InsertionIndicatorHandler (SlideSorter& rSlideSorter); + ~InsertionIndicatorHandler (void); + + enum Mode { CopyMode, MoveMode, UnknownMode }; + static Mode GetModeFromDndAction (const sal_Int8 nDndAction); + + /** Activate the insertion marker at the given coordinates. + */ + void Start (const bool bIsOverSourceView); + + /** Deactivate the insertion marker. + */ + void End (const controller::Animator::AnimationMode eMode); + + /** This context make sure that the insertion indicator is shown + (provided that the clipboard is not empty) while the context is + alive. Typically used while a context menu is displayed. + */ + class ForceShowContext + { + public: + ForceShowContext (const ::boost::shared_ptr<InsertionIndicatorHandler>& rpHandler); + ~ForceShowContext (void); + private: + const ::boost::shared_ptr<InsertionIndicatorHandler> mpHandler; + }; + + /** Update the indicator icon from the current transferable (from the + clipboard or an active drag and drop operation.) + */ + void UpdateIndicatorIcon (const Transferable* pTransferable); + + /** Set the position of the insertion marker to the given coordinates. + */ + void UpdatePosition ( + const Point& rMouseModelPosition, + const Mode eMode); + void UpdatePosition ( + const Point& rMouseModelPosition, + const sal_Int8 nDndAction); + + /** Return whether the insertion marker is active. + */ + bool IsActive (void) const; + + /** Return the insertion index that corresponds with the current + graphical location of the insertion indicator. + */ + sal_Int32 GetInsertionPageIndex (void) const; + + /** Determine whether moving the current selection to the current + position of the insertion marker would alter the document. This + would be the case when the selection is not consecutive or would be + moved to a position outside and not adjacent to the selection. + */ + bool IsInsertionTrivial ( + const sal_Int32 nInsertionIndex, + const Mode eMode) const; + /** This method is like the other variant. It operates implicitly + on the current insertion index as would be returned by + GetInsertionPageIndex(). + */ + bool IsInsertionTrivial (const sal_Int8 nDndAction); + +private: + SlideSorter& mrSlideSorter; + ::boost::shared_ptr<view::InsertAnimator> mpInsertAnimator; + ::boost::shared_ptr<view::InsertionIndicatorOverlay> mpInsertionIndicatorOverlay; + view::InsertPosition maInsertPosition; + Mode meMode; + bool mbIsInsertionTrivial; + bool mbIsActive; + bool mbIsReadOnly; + bool mbIsOverSourceView; + Size maIconSize; + bool mbIsForcedShow; + + void SetPosition ( + const Point& rPoint, + const Mode eMode); + ::boost::shared_ptr<view::InsertAnimator> GetInsertAnimator (void); + + /** Make the insertion indicator visible (that is the show part) and + keep it visible, even when the mouse leaves the window (that is the + force part). We need this when a context menu is displayed (mouse + over the popup menu triggers a mouse leave event) while the + insertion indicator remains visible in the background. + + In effect all calls to End() are ignored until ForceEnd() is called. + */ + void ForceShow (void); + void ForceEnd (void); +}; + + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlsPageSelector.hxx b/sd/source/ui/slidesorter/inc/controller/SlsPageSelector.hxx index 57aaf9293301..b0a9cfa148cb 100755..100644 --- a/sd/source/ui/slidesorter/inc/controller/SlsPageSelector.hxx +++ b/sd/source/ui/slidesorter/inc/controller/SlsPageSelector.hxx @@ -69,16 +69,29 @@ public: void SelectAllPages (void); void DeselectAllPages (void); + /** Update the selection state of all page descriptors to be the same as - that of the pages of the SdDrawDocument they describe and issue + that of the corresponding pages of the SdPage objects and issue redraw requests where necessary. */ - void UpdateAllPages (void); + void GetCoreSelection (void); + + /** Update the selection state of the SdPage objects to be the same as + that of the correspinding page descriptors. + */ + void SetCoreSelection (void); + /** Select the specified descriptor. The selection state of the other + descriptors is not affected. + */ void SelectPage (int nPageIndex); - /** Select the descriptor that is associated with the given page. + /** Select the descriptor that is associated with the given page. The + selection state of the other descriptors is not affected. */ void SelectPage (const SdPage* pPage); + /** Select the specified descriptor. The selection state of the other + descriptors is not affected. + */ void SelectPage (const model::SharedPageDescriptor& rpDescriptor); /** Return whether the specified page is selected. This convenience @@ -89,9 +102,19 @@ public: bool IsPageSelected (int nPageIndex); /** Deselect the descriptor that is associated with the given page. + @param bUpdateCurrentPage + When <TRUE/> then the current page is updated to the first slide + of the remaining selection. */ - void DeselectPage (int nPageIndex); - void DeselectPage (const model::SharedPageDescriptor& rpDescriptor); + void DeselectPage ( + int nPageIndex, + const bool bUpdateCurrentPage = true); + void DeselectPage ( + const SdPage* pPage, + const bool bUpdateCurrentPage = true); + void DeselectPage ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bUpdateCurrentPage = true); /** This convenience method returns the same number of pages that SlideSorterModel.GetPageCount() returns. It is included here so @@ -101,35 +124,6 @@ public: int GetPageCount (void) const; int GetSelectedPageCount (void) const; - void PrepareModelChange (void); - void HandleModelChange (void); - - /** Enable the broadcasting of selection change events. This calls the - SlideSorterController::SelectionHasChanged() method to do the actual - work. When EnableBroadcasting has been called as many times as - DisableBroadcasting() was called before and the selection has been - changed in the mean time, this change will be broadcasted. - */ - void EnableBroadcasting (bool bMakeSelectionVisible = true); - - /** Disable the broadcasting o selectio change events. Subsequent - changes of the selection will set a flag that triggers the sending - of events when EnableBroadcasting() is called. - */ - void DisableBroadcasting (void); - - /** Return the descriptor of the most recently selected page. This - works only when the page has not been de-selected in the mean time. - This method helps the view when it scrolls the selection into the - visible area. - @return - When the selection is empty or when the most recently selected - page has been deselected already (but other pages are still - selected) then NULL is returned, even when a selection did exist - but has been cleared. - */ - model::SharedPageDescriptor GetMostRecentlySelectedPage (void) const; - /** Return the anchor for a range selection. This usually is the first selected page after all pages have been deselected. @return @@ -156,10 +150,46 @@ public: the last call to GetPageSelection() it is still valid to call this method with the selection. When pages have been inserted or removed the result may be unexpected. + @param bUpdateCurrentPage + When <TRUE/> (the default value) then after setting the + selection update the current page to the first page of the + selection. + When called from withing UpdateCurrentPage() then this flag is + used to prevent a recursion loop. */ - void SetPageSelection (const ::boost::shared_ptr<PageSelection>& rSelection); + void SetPageSelection ( + const ::boost::shared_ptr<PageSelection>& rSelection, + const bool bUpdateCurrentPage = true); - void UpdateCurrentPage (const model::SharedPageDescriptor& rCurrentPageDescriptor); + /** Call this method after the the model has changed to set the number + of selected pages. + */ + void CountSelectedPages (void); + + /** Use the UpdateLock whenever you do a complex selection, i.e. call + more than one method in a row. An active lock prevents intermediate + changes of the current slide. + */ + class UpdateLock + { + public: + UpdateLock (SlideSorter& rSlideSorter); + UpdateLock (PageSelector& rPageSelector); + ~UpdateLock (void); + void Release (void); + private: + PageSelector* mpSelector; + }; + + class BroadcastLock + { + public: + BroadcastLock (SlideSorter& rSlideSorter); + BroadcastLock (PageSelector& rPageSelector); + ~BroadcastLock (void); + private: + PageSelector& mrSelector; + }; private: model::SlideSorterModel& mrModel; @@ -172,8 +202,26 @@ private: /// Anchor for a range selection. model::SharedPageDescriptor mpSelectionAnchor; model::SharedPageDescriptor mpCurrentPage; + sal_Int32 mnUpdateLockCount; + bool mbIsUpdateCurrentPagePending; - void CountSelectedPages (void); + /** Enable the broadcasting of selection change events. This calls the + SlideSorterController::SelectionHasChanged() method to do the actual + work. When EnableBroadcasting has been called as many times as + DisableBroadcasting() was called before and the selection has been + changed in the mean time, this change will be broadcasted. + */ + void EnableBroadcasting (void); + + /** Disable the broadcasting of selection change events. Subsequent + changes of the selection will set a flag that triggers the sending + of events when EnableBroadcasting() is called. + */ + void DisableBroadcasting (void); + + void UpdateCurrentPage (const bool bUpdateOnlyWhenPending = false); + + void CheckConsistency (void) const; }; } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/inc/controller/SlsProperties.hxx b/sd/source/ui/slidesorter/inc/controller/SlsProperties.hxx index 51e353d696b9..06d239c81da3 100644..100755 --- a/sd/source/ui/slidesorter/inc/controller/SlsProperties.hxx +++ b/sd/source/ui/slidesorter/inc/controller/SlsProperties.hxx @@ -40,6 +40,11 @@ public: Properties (void); ~Properties (void); + /** Call this method after receiving a VCLEVENT_APPLICATION_DATACHANGED + event. + */ + void HandleDataChangeEvent (void); + /** When this method returns <TRUE/> then the current slide is highlighted in the view. The default value is <FALSE/>. */ @@ -108,6 +113,15 @@ public: bool IsUIReadOnly (void) const; void SetUIReadOnly (const bool bIsUIReadOnly); + /** The mouse over effect (and whether a mouse motion starts a multi + selection or a drag-and-drop) can be triggered by just the preview + area or the whole page object area. + */ + bool IsOnlyPreviewTriggersMouseOver (void) const; + void SetOnlyPreviewTriggersMouseOver (const bool bFlag); + + bool IsHighContrastModeActive (void) const; + private: bool mbIsHighlightCurrentSlide; bool mbIsShowSelection; @@ -120,6 +134,8 @@ private: Color maSelectionColor; Color maHighlightColor; bool mbIsUIReadOnly; + bool mbIsOnlyPreviewTriggersMouseOver; + bool mbIsHighContrastModeActive; }; } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/inc/controller/SlsScrollBarManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsScrollBarManager.hxx index c93ed7708650..fa2aae6111fb 100755 --- a/sd/source/ui/slidesorter/inc/controller/SlsScrollBarManager.hxx +++ b/sd/source/ui/slidesorter/inc/controller/SlsScrollBarManager.hxx @@ -28,10 +28,13 @@ #ifndef SD_SLIDESORTER_SLIDE_SORTER_SCROLL_BAR_MANAGER_HXX #define SD_SLIDESORTER_SLIDE_SORTER_SCROLL_BAR_MANAGER_HXX +#include "SlideSorter.hxx" + #include <tools/link.hxx> #include <tools/gen.hxx> #include <vcl/timer.hxx> #include <boost/shared_ptr.hpp> +#include <boost/function.hpp> class Point; class Rectangle; @@ -110,30 +113,34 @@ public: bool bScrollToCurrentPosition = true); /** Place the scroll bars inside the given area. When the available - area is not large enough for the content to display the resulting - behaviour depends on the mbUseVerticalScrollBar flag. When it is - set to true then a vertical scroll bar is shown. Otherwise the - height of the returned area is enlarged so that the content fits - into it. + area is not large enough for the content to display the horizontal + and/or vertical scroll bar is enabled. @param rAvailableArea The scroll bars will be placed inside this rectangle. It is expected to be given in pixel relative to its parent. + @param bIsHorizontalScrollBarAllowed + Only when this flag is <TRUE/> the horizontal scroll may be + displayed. + @param bIsVerticalScrollBarAllowed + Only when this flag is <TRUE/> the horizontal scroll may be + displayed. @return Returns the space that remains after the scroll bars are - placed. When the mbUseVerticalScrollBar flag is false then the - returned rectangle may be larger than the given one. + placed. */ - Rectangle PlaceScrollBars (const Rectangle& rAvailableArea); + Rectangle PlaceScrollBars ( + const Rectangle& rAvailableArea, + const bool bIsHorizontalScrollBarAllowed, + const bool bIsVerticalScrollBarAllowed); - /** Update the vertical scroll bar so that the visible area has the - given top value. + /** Update the vertical and horizontal scroll bars so that the visible + area has the given top and left values. */ - void SetTop (const sal_Int32 nTop); + void SetTopLeft (const Point aNewTopLeft); - /** Update the horizontal scroll bar so that the visible area has the - given left value. - */ - void SetLeft (const sal_Int32 nLeft); + sal_Int32 GetTop (void) const; + + sal_Int32 GetLeft (void) const; /** Return the width of the vertical scroll bar, which--when shown--should be fixed in contrast to its height. @@ -154,14 +161,35 @@ public: /** Call this method to scroll a window while the mouse is in dragging a selection. If the mouse is near the window border or is outside the window then scroll the window accordingly. + @param rMouseWindowPosition + The mouse position for which the scroll amount is calculated. + @param rAutoScrollFunctor + Every time when the window is scrolled then this functor is executed. @return When the window is scrolled then this method returns <TRUE/>. When the window is not changed then <FALSE/> is returned. */ - bool AutoScroll (const Point& rMouseWindowPosition); + bool AutoScroll ( + const Point& rMouseWindowPosition, + const ::boost::function<void(void)>& rAutoScrollFunctor); void StopAutoScroll (void); + enum Orientation { Orientation_Horizontal, Orientation_Vertical }; + enum Unit { Unit_Pixel, Unit_Slide }; + /** Scroll the slide sorter by setting the thumbs of the scroll bars and + by moving the content of the content window. + @param eOrientation + Defines whether to scroll horizontally or vertically. + @param eUnit + Defines whether the distance is a pixel value or the number of + slides to scroll. + */ + void Scroll( + const Orientation eOrientation, + const Unit eUnit, + const sal_Int32 nDistance); + private: SlideSorter& mrSlideSorter; @@ -197,11 +225,14 @@ private: */ Timer maAutoScrollTimer; Size maAutoScrollOffset; + bool mbIsAutoScrollActive; /** The content window is the one whose view port is controlled by the scroll bars. */ - ::boost::shared_ptr<sd::Window> mpContentWindow; + SharedSdWindow mpContentWindow; + + ::boost::function<void(void)> maAutoScrollFunctor; void SetWindowOrigin ( double nHorizontalPosition, @@ -217,7 +248,10 @@ private: The area that is enclosed by the scroll bars is returned. It will be filled with the SlideSorterView. */ - Rectangle DetermineScrollBarVisibilities (const Rectangle& rAvailableArea); + Rectangle DetermineScrollBarVisibilities( + const Rectangle& rAvailableArea, + const bool bIsHorizontalScrollBarAllowed, + const bool bIsVerticalScrollBarAllowed); /** Typically called by DetermineScrollBarVisibilities() this method tests a specific configuration of the two scroll bars being visible diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSelectionFunction.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSelectionFunction.hxx index 79b8a1ff5d44..9dcd0abb646c 100755..100644 --- a/sd/source/ui/slidesorter/inc/controller/SlsSelectionFunction.hxx +++ b/sd/source/ui/slidesorter/inc/controller/SlsSelectionFunction.hxx @@ -28,10 +28,13 @@ #ifndef SD_SLIDESORTER_SELECTION_FUNCTION_HXX #define SD_SLIDESORTER_SELECTION_FUNCTION_HXX -#include "controller/SlsSlideFunction.hxx" #include "model/SlsSharedPageDescriptor.hxx" -#include <tools/list.hxx> -#include <memory> +#include "controller/SlsFocusManager.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include "fupoor.hxx" +#include <svtools/transfer.hxx> +#include <boost/noncopyable.hpp> +#include <boost/scoped_ptr.hpp> class SdSlideViewShell; class SdWindow; @@ -46,9 +49,12 @@ class SlideSorter; namespace sd { namespace slidesorter { namespace controller { class SlideSorterController; +class DragAndDropContext; + class SelectionFunction - : public SlideFunction + : public FuPoor, + private ::boost::noncopyable { public: TYPEINFO(); @@ -60,10 +66,9 @@ public: virtual BOOL MouseMove(const MouseEvent& rMEvt); virtual BOOL MouseButtonUp(const MouseEvent& rMEvt); virtual BOOL MouseButtonDown(const MouseEvent& rMEvt); - virtual void Paint(const Rectangle&, ::sd::Window* ); - virtual void Activate(); // Function aktivieren - virtual void Deactivate(); // Function deaktivieren + virtual void Activate(); + virtual void Deactivate(); virtual void ScrollStart(); virtual void ScrollEnd(); @@ -86,6 +91,42 @@ public: */ virtual bool cancel(); + void MouseDragged ( + const AcceptDropEvent& rEvent, + const sal_Int8 nDragAction); + + /** Turn of substitution display and insertion indicator. + */ + void NotifyDragFinished (void); + + /** Call when drag-and-drop or multi selection is started or stopped in + order to update permission of mouse over indication. + */ + void UpdateMouseOverIndicationPermission (void); + + class EventDescriptor; + class ModeHandler; + friend class ModeHandler; + enum Mode + { + NormalMode, + MultiSelectionMode, + DragAndDropMode, + ButtonMode + }; + void SwitchToNormalMode (void); + void SwitchToDragAndDropMode(const Point aMousePosition); + void SwitchToMultiSelectionMode (const Point aMousePosition, const sal_uInt32 nEventCode); + bool SwitchToButtonMode (void); + + void ResetShiftKeySelectionAnchor (void); + /** Special case handling for when the context menu is hidden. This + method will reinitialize the current mouse position to prevent the + mouse motion during the time the context menu is displayed from + being interpreted as drag-and-drop start. + */ + void ResetMouseAnchor (void); + protected: SlideSorter& mrSlideSorter; SlideSorterController& mrController; @@ -97,11 +138,6 @@ protected: virtual ~SelectionFunction(); private: - class SubstitutionHandler; - class EventDescriptor; - - /// Set in MouseButtonDown this flag indicates that a page has been hit. - bool mbPageHit; /// The rectangle of the mouse drag selection. Rectangle maDragSelectionRectangle; @@ -118,20 +154,17 @@ private: */ bool mbProcessingMouseButtonDown; - ::std::auto_ptr<SubstitutionHandler> mpSubstitutionHandler; + bool mbIsDeselectionPending; - DECL_LINK( DragSlideHdl, Timer* ); - void StartDrag (void); - - /** Set the selection to exactly the specified page and also set it as - the current page. + /** Remember the slide where the shift key was pressed and started a + multiselection via keyboard. */ - void SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor); + sal_Int32 mnShiftKeySelectionAnchor; - /** When the view on which this selection function is working is the - main view then the view is switched to the regular editing view. + /** The selection function can be in one of several mutually + exclusive modes. */ - void SwitchView (const model::SharedPageDescriptor& rpDescriptor); + ::boost::shared_ptr<ModeHandler> mpModeHandler; /** Make the slide nOffset slides away of the current one the new current slide. When the new index is outside the range of valid @@ -142,63 +175,31 @@ private: */ void GotoNextPage (int nOffset); + /** Make the slide with the given index the new current slide. + @param nIndex + Index of the new current slide. When the new index is outside + the range of valid page numbers it is clipped to that range. + */ + void GotoPage (int nIndex); + void ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent); void ProcessKeyEvent (const KeyEvent& rEvent); // What follows are a couple of helper methods that are used by // ProcessMouseEvent(). - /// Select the specified page and set the selection anchor. - void SelectHitPage (const model::SharedPageDescriptor& rpDescriptor); - /// Deselect the specified page. - void DeselectHitPage (const model::SharedPageDescriptor& rpDescriptor); - /// Deselect all pages. - void DeselectAllPages (void); + void ProcessEvent (EventDescriptor& rEvent); - /** for a possibly following mouse motion by starting the drag timer - that after a short time of pressed but un-moved mouse starts a drag - operation. - */ - void PrepareMouseMotion (const Point& aMouseModelPosition); - - /** Select all pages between and including the selection anchor and the - specified page. - */ - void RangeSelect (const model::SharedPageDescriptor& rpDescriptor); + void MoveFocus ( + const FocusManager::FocusMoveDirection eDirection, + const bool bIsShiftDown, + const bool bIsControlDown); - /** Start a rectangle selection at the given position. - */ - void StartRectangleSelection (const Point& aMouseModelPosition); + void StopDragAndDrop (void); - /** Update the rectangle selection so that the given position becomes - the new second point of the selection rectangle. - */ - void UpdateRectangleSelection (const Point& aMouseModelPosition); - - /** Select all pages that lie completly in the selection rectangle. - */ - void ProcessRectangleSelection (bool bToggleSelection); - - /** Compute a numerical code that describes a mouse event and that can - be used for fast look up of the appropriate reaction. - */ - sal_uInt32 EncodeMouseEvent ( - const EventDescriptor& rDescriptor, - const MouseEvent& rEvent) const; - - /** Compute a numerical code that describes a key event and that can - be used for fast look up of the appropriate reaction. - */ - sal_uInt32 EncodeKeyEvent ( - const EventDescriptor& rDescriptor, - const KeyEvent& rEvent) const; - - void EventPreprocessing (const EventDescriptor& rEvent); - bool EventProcessing (const EventDescriptor& rEvent); - void EventPostprocessing (const EventDescriptor& rEvent); + void SwitchMode (const ::boost::shared_ptr<ModeHandler>& rpHandler); }; } } } // end of namespace ::sd::slidesorter::controller #endif - diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSelectionManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSelectionManager.hxx index c0fab6da84c6..a9617a88c2e6 100644..100755 --- a/sd/source/ui/slidesorter/inc/controller/SlsSelectionManager.hxx +++ b/sd/source/ui/slidesorter/inc/controller/SlsSelectionManager.hxx @@ -29,8 +29,10 @@ #define SD_SLIDESORTER_CONTROLLER_SELECTION_MANAGER_HXX #include "model/SlsSharedPageDescriptor.hxx" +#include "controller/SlsAnimator.hxx" #include <sal/types.h> #include <tools/gen.hxx> +#include <basegfx/range/b2irectangle.hxx> #include <vector> class Link; @@ -43,6 +45,7 @@ class SlideSorter; namespace sd { namespace slidesorter { namespace controller { class SlideSorterController; +class SelectionObserver; /** This class is a part of the controller and handles the selection of slides. @@ -62,12 +65,13 @@ public: /** Delete the currently selected slides. When this method returns the selection is empty. + @param bSelectFollowingPage + When <TRUE/> then after deleting the selected pages make the + slide after the last selected page the new current page. + When <FALSE/> then make the first slide before the selected + pages the new current slide. */ - void DeleteSelectedPages (void); - - /** Move the maked pages to a position directly after the specified page. - */ - bool MoveSelectedPages (const sal_Int32 nTargetPage); + void DeleteSelectedPages (const bool bSelectFollowingPage = true); /** Call this method after the selection has changed (possible several calls to the PageSelector) to invalidate the relevant slots and send @@ -75,42 +79,6 @@ public: */ void SelectionHasChanged (const bool bMakeSelectionVisible = true); - /** Return <TRUE/> when the selection has changed but has not yet been - moved to the visible area of the slide sorter view. - */ - bool IsMakeSelectionVisiblePending (void) const; - - enum SelectionHint { SH_FIRST, SH_LAST, SH_RECENT }; - - /** Try to make all currently selected page objects visible, i.e. set - the origin so that the page objects lie inside the visible area. - When the selection is empty then the visible area is not modified. - - <p>This method, and the ones is calls, look into the Properties - object of the SlideSorter in order to determine whether the current - selection is to be displayed centered.</p> - @param eSelectionHint - This is an advice on which selected page object to handle with - the highest priority when the whole selection does not fit into - the visible area. - @return - Returns the vertical translation of the visible area. It is 0 - when no update of the visible area was done. - */ - Size MakeSelectionVisible ( - const SelectionHint eSelectionHint = SH_RECENT); - - /** Modify the origin of the visible area so that the given rectangle - comes into view. This is done with the smallest change: no - scrolling takes place when the given rectangle already lies in the - visible area. Otherwise either the top or the bottom of the given - rectangle is aligned with the top or the bottom of the visible area. - @return - Returns the vertical translation of the visible area. It is 0 - when no update of the visible area was done. - */ - Size MakeRectangleVisible (const Rectangle& rBox); - /** Add a listener that is called when the selection of the slide sorter changes. @param rListener @@ -143,6 +111,8 @@ public: */ void SetInsertionPosition (const sal_Int32 nInsertionPosition); + ::boost::shared_ptr<SelectionObserver> GetSelectionObserver (void) const; + private: SlideSorter& mrSlideSorter; SlideSorterController& mrController; @@ -166,6 +136,17 @@ private: */ sal_Int32 mnInsertionPosition; + /** Animation id for a scroll animation the will eventually set the top + and left of the visible area to maRequestedTopLeft. + */ + Animator::AnimationId mnAnimationId; + Point maRequestedTopLeft; + + class PageInsertionListener; + ::boost::scoped_ptr<PageInsertionListener> mpPageInsertionListener; + + ::boost::shared_ptr<SelectionObserver> mpSelectionObserver; + /** Delete the given list of normal pages. This method is a helper function for DeleteSelectedPages(). @param rSelectedNormalPages @@ -179,31 +160,6 @@ private: A list of master pages. Supplying normal pages is an error. */ void DeleteSelectedMasterPages (const ::std::vector<SdPage*>& rSelectedMasterPages); - - /** Return <TRUE/> when the given rectangle, that typically is the - bounding box of all currently selected slides, does not fit entirely - into the visible area of the slide sorter view. - */ - bool DoesSelectionExceedVisibleArea (const Rectangle& rSelectionBox) const; - - /** When not all currently selected slides fit into the visible area of - the slide sorter view, and thus DoesSelectionExceedVisibleArea() - would return <TRUE/>, then it is the task of this method to - determine which part of the selection to move into the visible area. - @param rpFirst - The first selected slide. Must not be an empty pointer. - @param rpLast - The last selected slide. Must not be an empty pointer. - @param eSelectionHint - This hint tells the method on which slide to concentrate, - i.e. which slide has to be inside the returned visible area. - @return - Returns the new visible area. - */ - Rectangle ResolveLargeSelection ( - const model::SharedPageDescriptor& rpFirst, - const model::SharedPageDescriptor& rpLast, - const SelectionHint eSelectionHint); }; } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSelectionObserver.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSelectionObserver.hxx new file mode 100644 index 000000000000..0fb45b403af1 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsSelectionObserver.hxx @@ -0,0 +1,85 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_CONTROLLER_SELECTION_OBSERVER_HXX +#define SD_SLIDESORTER_CONTROLLER_SELECTION_OBSERVER_HXX + +#include <tools/gen.hxx> +#include <vector> +#include <boost/shared_ptr.hpp> + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +class SdDrawDocument; +class SdrPage; + +namespace sd { namespace slidesorter { namespace controller { + +/** Observe insertions and deletions of pages between calls to + StartObservation() and EndObservation(). When the later is called + the selection is set to just the newly inserted pages. +*/ +class SelectionObserver +{ +public: + SelectionObserver (SlideSorter& rSlideSorter); + virtual ~SelectionObserver (void); + + void NotifyPageEvent (const SdrPage* pPage); + void StartObservation (void); + void AbortObservation (void); + void EndObservation (void); + + /** Use this little class instead of calling StartObservation and + EndObservation directly so that EndObservation is not forgotten or + omitted due to an exception or some break or return in the middle of + code. + */ + class Context + { + public: + Context (SlideSorter& rSlideSorter); + ~Context(void); + void Abort (void); + private: + ::boost::shared_ptr<SelectionObserver> mpSelectionObserver; + }; + +private: + SlideSorter& mrSlideSorter; + SdDrawDocument* mpDocument; + bool mbIsOvservationActive; + + ::std::vector<const SdPage*> maInsertedPages; + ::std::vector<sal_Int32> maDeletedPages; +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSlotManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSlotManager.hxx index 0e58d5d3b411..d2c9f7481624 100755..100644 --- a/sd/source/ui/slidesorter/inc/controller/SlsSlotManager.hxx +++ b/sd/source/ui/slidesorter/inc/controller/SlsSlotManager.hxx @@ -27,6 +27,7 @@ #ifndef SD_SLIDESORTER_SLOT_MANAGER_HXX #define SD_SLIDESORTER_SLOT_MANAGER_HXX +#include "model/SlsSharedPageDescriptor.hxx" #include <tools/link.hxx> #include <memory> #include <queue> @@ -71,6 +72,21 @@ public: void ExecuteCommandAsynchronously (::std::auto_ptr<Command> pCommand); + /** Exclude or include one slide or all selected slides. + @param rpDescriptor + When the pointer is empty then apply the new state to all + selected pages. Otherwise apply the new state to just the + specified state. + */ + void ChangeSlideExclusionState ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bExcludeSlide); + + /** Call this after a change from normal mode to master mode or back. + The affected slots are invalidated. + */ + void NotifyEditModeChange (void); + private: /// The controller for which we manage the slot calls. SlideSorter& mrSlideSorter; @@ -93,6 +109,13 @@ private: */ void InsertSlide (SfxRequest& rRequest); + void DuplicateSelectedSlides (SfxRequest& rRequest); + + /** Use one of several ways to determine where to insert a new page. + This can be the current selection or the insertion indicator. + */ + sal_Int32 GetInsertionPosition (void); + DECL_LINK(UserEventCallback, void*); }; diff --git a/sd/source/ui/slidesorter/controller/SlsTransferable.hxx b/sd/source/ui/slidesorter/inc/controller/SlsTransferable.hxx index f527fd4768b9..289fb1f5f072 100644 --- a/sd/source/ui/slidesorter/controller/SlsTransferable.hxx +++ b/sd/source/ui/slidesorter/inc/controller/SlsTransferable.hxx @@ -31,17 +31,13 @@ #include "sdxfer.hxx" class SdDrawDocument; -namespace sd -{ - class pWorkView; - namespace slidesorter - { - class SlideSorterViewShell; - } -} +namespace sd { namespace slidesorter { +class SlideSorterViewShell; +} } namespace sd { namespace slidesorter { namespace controller { + /** This class exists to have DragFinished call the correct object: the SlideSorterViewShell instead of the old SlideView. */ @@ -49,18 +45,39 @@ class Transferable : public SdTransferable { public: + class Representative + { + public: + Representative (const Bitmap& rBitmap, const bool bIsExcluded) + : maBitmap(rBitmap), mbIsExcluded(bIsExcluded) {} + Representative (const Representative& rOther) + : maBitmap(rOther.maBitmap), mbIsExcluded(rOther.mbIsExcluded) {} + Representative operator= (Representative& rOther) + { if (&rOther != this) {maBitmap = rOther.maBitmap; mbIsExcluded = rOther.mbIsExcluded; } + return *this; + } + + Bitmap maBitmap; + bool mbIsExcluded; + }; + + Transferable ( SdDrawDocument* pSrcDoc, ::sd::View* pWorkView, BOOL bInitOnGetData, - SlideSorterViewShell* pViewShell); + SlideSorterViewShell* pViewShell, + const ::std::vector<Representative>& rRepresentatives); virtual ~Transferable (void); virtual void DragFinished (sal_Int8 nDropAction); + const ::std::vector<Representative>& GetRepresentatives (void) const; + private: SlideSorterViewShell* mpViewShell; + const ::std::vector<Representative> maRepresentatives; virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint); }; diff --git a/sd/source/ui/slidesorter/inc/controller/SlsVisibleAreaManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsVisibleAreaManager.hxx new file mode 100644 index 000000000000..cdaf9b1588ea --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsVisibleAreaManager.hxx @@ -0,0 +1,100 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VISIBLE_AREA_MANAGER_HXX +#define SD_SLIDESORTER_VISIBLE_AREA_MANAGER_HXX + +#include "controller/SlsAnimator.hxx" +#include "model/SlsSharedPageDescriptor.hxx" +#include <boost/noncopyable.hpp> +#include <boost/optional.hpp> + +namespace sd { namespace slidesorter { namespace controller { + + +/** Manage requests for scrolling page objects into view. +*/ +class VisibleAreaManager + : public ::boost::noncopyable +{ +public: + VisibleAreaManager (SlideSorter& rSlideSorter); + ~VisibleAreaManager (void); + + void ActivateCurrentSlideTracking (void); + void DeactivateCurrentSlideTracking (void); + + /** Request the current slide to be moved into the visible area. + This request is only obeyed when the current slide tracking is + active. + @see ActivateCurrentSlideTracking() and DeactivateCurrentSlideTracking() + */ + void RequestCurrentSlideVisible (void); + + /** Request to make the specified page object visible. + */ + void RequestVisible ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bForce = false); + + /** Temporarily disable the update of the visible area. + */ + class TemporaryDisabler + { + public: + TemporaryDisabler (SlideSorter& rSlideSorter); + ~TemporaryDisabler (void); + private: + VisibleAreaManager& mrVisibleAreaManager; + }; + +private: + SlideSorter& mrSlideSorter; + + /** List of rectangle that someone wants to be moved into the visible + area. + Cleared on every call to ForgetVisibleRequests() and MakeVisible(). + */ + ::std::vector<Rectangle> maVisibleRequests; + + /** Animation id for a scroll animation that sets the top + and left of the visible area to maRequestedVisibleTopLeft. + */ + Animator::AnimationId mnScrollAnimationId; + Point maRequestedVisibleTopLeft; + Animator::AnimationMode meRequestedAnimationMode; + bool mbIsCurrentSlideTrackingActive; + int mnDisableCount; + + void MakeVisible (void); + ::boost::optional<Point> GetRequestedTopLeft (void) const; +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/model/SlideSorterModel.hxx b/sd/source/ui/slidesorter/inc/model/SlideSorterModel.hxx index 4ade19087304..9dfd861fd5cf 100755..100644 --- a/sd/source/ui/slidesorter/inc/model/SlideSorterModel.hxx +++ b/sd/source/ui/slidesorter/inc/model/SlideSorterModel.hxx @@ -36,6 +36,7 @@ class SdDrawDocument; #include "pres.hxx" #include <com/sun/star/drawing/XDrawPage.hpp> #include <osl/mutex.hxx> +#include <vcl/region.hxx> #include <memory> #include <vector> @@ -43,6 +44,9 @@ class SdDrawDocument; namespace css = ::com::sun::star; +class SdrPage; +class SdPage; + namespace sd { namespace slidesorter { class SlideSorter; } } @@ -55,6 +59,9 @@ namespace sd { namespace slidesorter { namespace model { class DocumentPageContainer; +inline sal_Int32 FromCoreIndex (const USHORT nCoreIndex) { return (nCoreIndex-1)/2; } +inline USHORT ToCoreIndex (const sal_Int32 nIndex) { return nIndex*2+1; } + /** The model of the slide sorter gives access to the slides that are to be displayed in the slide sorter view. Via the SetDocumentSlides() method this set of slides can be modified (but do not call it directly, use @@ -64,8 +71,10 @@ class SlideSorterModel { public: SlideSorterModel (SlideSorter& rSlideSorter); + void Init (void); virtual ~SlideSorterModel (void); + void Dispose (void); /** This method is present to let the view create a ShowView for displaying slides. @@ -83,6 +92,9 @@ public: */ bool SetEditMode (EditMode eEditMode); + /** Set the edit mode to that currently used by the controller. + */ + bool SetEditModeFromController (void); EditMode GetEditMode (void) const; PageKind GetPageType (void) const; @@ -126,6 +138,25 @@ public: sal_Int32 GetIndex ( const ::com::sun::star::uno::Reference<com::sun::star::drawing::XDrawPage>& rxSlide) const; + /** Return a page descriptor for the given SdrPage. Page descriptors + are created on demand. The page descriptor is found (or not found) + in (at most) linear time. Note that all page descriptors in front of + the one associated with the given XDrawPage are created when not yet + present. When the SdrPage is not found then all descriptors are + created. + @return + Returns the index to the requested page descriptor or -1 when + there is no such page descriptor. + */ + sal_Int32 GetIndex (const SdrPage* pPage) const; + + /** Return an index for accessing an SdrModel that corresponds to the + given SlideSorterModel index. In many cases we just have to apply + the n*2+1 magic. Only when a special model is set, like a custom + slide show, then the returned value is different. + */ + USHORT GetCoreIndex (const sal_Int32 nIndex) const; + /** Call this method after the document has changed its structure. This will get the model in sync with the SdDrawDocument. This method tries not to throw away to much information already gathered. This @@ -144,16 +175,9 @@ public: */ void SynchronizeDocumentSelection (void); - /** Replace the factory for the creation of the page objects and - contacts with the given object. The old factory is destroyed. - */ - void SetPageObjectFactory( - ::std::auto_ptr<controller::PageObjectFactory> pPageObjectFactory); - - /** Return the page object factory. It none has been set so far or it - has been reset, then a new one is created. + /** Set the selection of the called model to exactly that of the document. */ - const controller::PageObjectFactory& GetPageObjectFactory (void) const; + void SynchronizeModelSelection (void); /** Return the mutex so that the caller can lock it and then safely access the model. @@ -179,6 +203,29 @@ public: */ void UpdatePageList (void); + bool IsReadOnly (void) const; + + /** The current selection is saved by copying the ST_Selected state into + ST_WasSelected for slides. + */ + void SaveCurrentSelection (void); + + /** The current selection is restored from the ST_WasSelected state from + the slides. + @returns + The returned region has to be repainted to reflect the updated + selection states. + */ + Region RestoreSelection (void); + + /** Typically called from controller::Listener this method handles the + insertion and deletion of single pages. + @return + Returns <TRUE/> when the given page is relevant for the current + page kind and edit mode. + */ + bool NotifyPageEvent (const SdrPage* pPage); + private: mutable ::osl::Mutex maMutex; SlideSorter& mrSlideSorter; @@ -187,13 +234,16 @@ private: EditMode meEditMode; typedef ::std::vector<SharedPageDescriptor> DescriptorContainer; mutable DescriptorContainer maPageDescriptors; - mutable ::std::auto_ptr<controller::PageObjectFactory> mpPageObjectFactory; /** Resize the descriptor container according to current values of page kind and edit mode. */ void AdaptSize (void); + SdPage* GetPage (const sal_Int32 nCoreIndex) const; + void InsertSlide (SdPage* pPage); + void DeleteSlide (const SdPage* pPage); + void UpdateIndices (const sal_Int32 nFirstIndex); }; } } } // end of namespace ::sd::slidesorter::model diff --git a/sd/source/ui/slidesorter/inc/model/SlsPageDescriptor.hxx b/sd/source/ui/slidesorter/inc/model/SlsPageDescriptor.hxx index 81877ce7465c..276f1a7c10a7 100755..100644 --- a/sd/source/ui/slidesorter/inc/model/SlsPageDescriptor.hxx +++ b/sd/source/ui/slidesorter/inc/model/SlsPageDescriptor.hxx @@ -28,6 +28,7 @@ #ifndef SD_SLIDESORTER_PAGE_DESCRIPTOR_HXX #define SD_SLIDESORTER_PAGE_DESCRIPTOR_HXX +#include "model/SlsVisualState.hxx" #include <com/sun/star/drawing/XDrawPage.hpp> #include <tools/gen.hxx> #include <tools/link.hxx> @@ -36,21 +37,11 @@ #include <memory> #include <boost/enable_shared_from_this.hpp> +#include <boost/scoped_ptr.hpp> -class SdPage; - -namespace sdr { namespace contact { -class ObjectContact; -} } - -namespace sd { namespace slidesorter { namespace view { -class PageObject; -class PageObjectViewObjectContact; -} } } -namespace sd { namespace slidesorter { namespace controller { -class PageObjectFactory; -} } } +class SdPage; +class SdrPage; namespace sd { namespace slidesorter { namespace model { @@ -87,8 +78,7 @@ public: PageDescriptor ( const css::uno::Reference<css::drawing::XDrawPage>& rxPage, SdPage* pPage, - const sal_Int32 nIndex, - const controller::PageObjectFactory& rPageObjectFactory); + const sal_Int32 nIndex); ~PageDescriptor (void); @@ -100,33 +90,22 @@ public: */ css::uno::Reference<css::drawing::XDrawPage> GetXDrawPage (void) const; - /** Return the page shape that is used for visualizing the page. + /** Returns the index of the page as it is displayed in the view as page + number. The value may differ from the index returned by the + XDrawPage when there are hidden slides and the XIndexAccess used to + access the model filters them out. */ - view::PageObject* GetPageObject (void); - void ReleasePageObject (void); + sal_Int32 GetPageIndex (void) const; + void SetPageIndex (const sal_Int32 nIndex); - /** Return <TRUE/> when the page object is fully or parially visible. */ - bool IsVisible (void) const; + bool UpdateMasterPage (void); - /** Set the visible state that is returned by the IsVisible() method. - This method is typically called by the view who renders the object - onto the screen. - */ - void SetVisible (bool bVisible); + enum State { ST_Visible, ST_Selected, ST_WasSelected, + ST_Focused, ST_MouseOver, ST_Current, ST_Excluded }; - /** Make sure that the page is selected and return whether the - selection state changed. - */ - bool Select (void); - /** Make sure that the page is not selected and return whether the - selection state changed. - */ - bool Deselect (void); + bool HasState (const State eState) const; - /** Return whether the page is selected (and thus bypasses the internal - mbIsSelected flag. - */ - bool IsSelected (void) const; + bool SetState (const State eState, const bool bStateValue); /** Set the internal mbIsSelected flag to the selection state of the page. Use this method to synchronize a page descriptor with the @@ -137,70 +116,39 @@ public: returned. When they were the same this method returns <FALSE/>. */ - bool UpdateSelection (void); - - bool IsFocused (void) const; - void SetFocus (void); - void RemoveFocus (void); - - view::PageObjectViewObjectContact* GetViewObjectContact (void) const; - - void SetViewObjectContact ( - view::PageObjectViewObjectContact* pViewObjectContact); + bool GetCoreSelection (void); - /** Return the currently used page object factory. + /** Set the selection flags of the SdPage objects to the corresponding + selection states of the page descriptors. */ - const controller::PageObjectFactory& GetPageObjectFactory (void) const; + void SetCoreSelection (void); - /** Replace the current page object factory by the given one. - */ - void SetPageObjectFactory (const controller::PageObjectFactory& rFactory); - - void SetModelBorder (const SvBorder& rBorder); - SvBorder GetModelBorder (void) const; + VisualState& GetVisualState (void); - /** The size of the area in which the page number is displayed is - calculated by the SlideSorterView and then stored in the page - descriptors so that the contact objects can access them. The - contact objects can not calculate them on demand because the total - number of slides is needed to do that and this number is not known - to the contact objects. - */ - void SetPageNumberAreaModelSize (const Size& rSize); - Size GetPageNumberAreaModelSize (void) const; - - /** Set or revoke the state of this slide being the current slide. - */ - void SetIsCurrentPage (const bool bIsCurrent); + Rectangle GetBoundingBox (void) const; + Point GetLocation (const bool bIgnoreLocation = false) const; + void SetBoundingBox (const Rectangle& rBoundingBox); private: SdPage* mpPage; css::uno::Reference<css::drawing::XDrawPage> mxPage; - /** This index is displayed as page number in the view. It may or may - not be actual page index. - */ - const sal_Int32 mnIndex; - - /// The factory that is used to create PageObject objects. - const controller::PageObjectFactory* mpPageObjectFactory; + SdrPage const* mpMasterPage; - /** The page object will be destroyed by the page into which it has - been inserted. + /** This index is displayed as page number in the view. It may or may + not be the actual page index. */ - view::PageObject* mpPageObject; - - bool mbIsSelected; - bool mbIsVisible; - bool mbIsFocused; - bool mbIsCurrent; + sal_Int32 mnIndex; - view::PageObjectViewObjectContact* mpViewObjectContact; + Rectangle maBoundingBox; + VisualState maVisualState; - /// The borders in model coordinates arround the page object. - SvBorder maModelBorder; + bool mbIsSelected : 1; + bool mbWasSelected : 1; + bool mbIsVisible : 1; + bool mbIsFocused : 1; + bool mbIsCurrent : 1; + bool mbIsMouseOver : 1; - /// The size of the page number area in model coordinates. - Size maPageNumberAreaModelSize; // Do not use the copy constructor operator. It is not implemented. PageDescriptor (const PageDescriptor& rDescriptor); diff --git a/sd/source/ui/slidesorter/inc/model/SlsVisualState.hxx b/sd/source/ui/slidesorter/inc/model/SlsVisualState.hxx new file mode 100644 index 000000000000..03b242fdd29a --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlsVisualState.hxx @@ -0,0 +1,101 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VISUAL_STATE_HXX +#define SD_SLIDESORTER_VISUAL_STATE_HXX + +#include <sal/types.h> +#include <tools/gen.hxx> +#include <boost/function.hpp> + +namespace sd { namespace slidesorter { namespace model { + +class PageDescriptor; + +/** This class gives access to values related to the visualization of page + objects. This includes animation state when blending from one state to + another. +*/ +class VisualState +{ +public: + enum State { + VS_Selected, + VS_Focused, + VS_Current, + VS_Excluded, + VS_None }; + + VisualState (const sal_Int32 nPageId); + ~VisualState (void); + + State GetCurrentVisualState (void) const; + State GetOldVisualState (void) const; + void SetVisualState (const State eState); + double GetVisualStateBlend (void) const; + void SetVisualStateBlend (const double nBlend); + + void UpdateVisualState (const PageDescriptor& rDescriptor); + + void SetMouseOverState (const bool bIsMouseOver); + + sal_Int32 GetStateAnimationId (void) const; + void SetStateAnimationId (const sal_Int32 nAnimationId); + + Point GetLocationOffset (void) const; + bool SetLocationOffset (const Point& rPoint); + sal_Int32 GetLocationAnimationId (void) const; + void SetLocationAnimationId (const sal_Int32 nAnimationId); + + double GetButtonAlpha (void) const; + void SetButtonAlpha (const double nAlpha); + double GetButtonBarAlpha (void) const; + void SetButtonBarAlpha (const double nAlpha); + sal_Int32 GetButtonAlphaAnimationId (void) const; + void SetButtonAlphaAnimationId (const sal_Int32 nAnimationId); + + sal_Int32 mnPageId; // For debugging + +private: + State meCurrentVisualState; + State meOldVisualState; + double mnVisualStateBlend; + sal_Int32 mnStateAnimationId; + bool mbOldMouseOverState; + bool mbCurrentMouseOverState; + + Point maLocationOffset; + sal_Int32 mnLocationAnimationId; + + double mnButtonAlpha; + double mnButtonBarAlpha; + sal_Int32 mnButtonAlphaAnimationId; +}; + +} } } // end of namespace ::sd::slidesorter::model + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlideSorterView.hxx b/sd/source/ui/slidesorter/inc/view/SlideSorterView.hxx index 2ef520b1df89..f28287b15a0e 100755..100644 --- a/sd/source/ui/slidesorter/inc/view/SlideSorterView.hxx +++ b/sd/source/ui/slidesorter/inc/view/SlideSorterView.hxx @@ -28,28 +28,29 @@ #ifndef SD_SLIDESORTER_SLIDE_SORTER_VIEW_HXX #define SD_SLIDESORTER_SLIDE_SORTER_VIEW_HXX -#include "View.hxx" - +#include "SlideSorter.hxx" +#include "model/SlsPageDescriptor.hxx" #include "model/SlsSharedPageDescriptor.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsILayerPainter.hxx" +#include "View.hxx" #include <sfx2/viewfrm.hxx> #include "pres.hxx" #include <tools/gen.hxx> +#include <svx/svdmodel.hxx> +#include <vcl/region.hxx> +#include <vcl/outdev.hxx> +#include <drawinglayer/primitive2d/baseprimitive2d.hxx> #include <memory> #include <boost/shared_ptr.hpp> +#include <boost/noncopyable.hpp> class Point; -namespace sdr { namespace contact { -class ObjectContact; -} } - -namespace sd { namespace slidesorter { -class SlideSorter; -} } - namespace sd { namespace slidesorter { namespace controller { class SlideSorterController; +class Properties; } } } namespace sd { namespace slidesorter { namespace cache { @@ -62,15 +63,20 @@ class SlideSorterModel; namespace sd { namespace slidesorter { namespace view { +class ButtonBar; +class LayeredDevice; class Layouter; -class ViewOverlay; +class PageObjectPainter; +class SelectionPainter; +class ToolTip; class SlideSorterView - : public View + : public sd::View, + public ::boost::noncopyable { public: - TYPEINFO(); + TYPEINFO (); /** Create a new view for the slide sorter. @param rViewShell @@ -79,53 +85,24 @@ public: */ SlideSorterView (SlideSorter& rSlideSorter); + void Init (void); virtual ~SlideSorterView (void); + void Dispose (void); - enum Orientation { HORIZONTAL, VERTICAL }; - void SetOrientation (const Orientation eOrientation); - Orientation GetOrientation (void) const; + /** Set the general way of layouting the page objects. Note that this + method does not trigger any repaints or layouts. + */ + bool SetOrientation (const Layouter::Orientation eOrientation); + Layouter::Orientation GetOrientation (void) const; void RequestRepaint (void); void RequestRepaint (const model::SharedPageDescriptor& rDescriptor); + void RequestRepaint (const Rectangle& rRepaintBox); + void RequestRepaint (const Region& rRepaintRegion); Rectangle GetModelArea (void); - enum CoordinateSystem { CS_SCREEN, CS_MODEL }; - enum BoundingBoxType { BBT_SHAPE, BBT_INFO }; - - /** Return the rectangle that bounds the page object represented by the - given page descriptor. - @param rDescriptor - The descriptor of the page for which to return the bounding box. - @param eCoordinateSystem - Specifies whether to return the screen or model coordinates. - @param eBoundingBoxType - Specifies whether to return the bounding box of only the page - object or the one that additionally includes other displayed - information like page name and fader symbol. - */ - Rectangle GetPageBoundingBox ( - const model::SharedPageDescriptor& rpDescriptor, - CoordinateSystem eCoordinateSystem, - BoundingBoxType eBoundingBoxType) const; - - /** Return the rectangle that bounds the page object represented by the - given page index . - @param nIndex - The index of the page for which to return the bounding box. - @param eCoordinateSystem - Specifies whether to return the screen or model coordinates. - @param eBoundingBoxType - Specifies whether to return the bounding box of only the page - object or the one that additionally includes other displayed - information like page name and fader symbol. - */ - Rectangle GetPageBoundingBox ( - sal_Int32 nIndex, - CoordinateSystem eCoordinateSystem, - BoundingBoxType eBoundingBoxType) const; - /** Return the index of the page that is rendered at the given position. @param rPosition The position is expected to be in pixel coordinates. @@ -163,12 +140,17 @@ public: void HandleDrawModeChange (void); virtual void Resize (void); - virtual void CompleteRedraw (OutputDevice* pDevice, const Region& rPaintArea, sdr::contact::ViewObjectContactRedirector* pRedirector = 0L); - virtual void InvalidateOneWin ( - ::Window& rWindow); - virtual void InvalidateOneWin ( - ::Window& rWindow, - const Rectangle& rPaintArea ); + virtual void CompleteRedraw ( + OutputDevice* pDevice, + const Region& rPaintArea, + sdr::contact::ViewObjectContactRedirector* pRedirector = NULL); + void Paint (OutputDevice& rDevice, const Rectangle& rRepaintArea); + + virtual void ConfigurationChanged ( + utl::ConfigurationBroadcaster* pBroadcaster, + sal_uInt32 nHint); + + void HandleDataChangeEvent (void); void Layout (void); /** This tells the view that it has to re-determine the visibility of @@ -178,13 +160,10 @@ public: /** Return the window to which this view renders its output. */ - ::sd::Window* GetWindow (void) const; - + // ::boost::shared_ptr<sd::Window> GetWindow (void) const; ::boost::shared_ptr<cache::PageCache> GetPreviewCache (void); - view::ViewOverlay& GetOverlay (void); - /** Set the bounding box of the insertion marker in model coordinates. It will be painted as a dark rectangle that fills the given box. @@ -205,19 +184,18 @@ public: */ void SetSelectionRectangleVisibility (bool bVisible); - typedef ::std::pair<sal_Int32,sal_Int32> PageRange; /** Return the range of currently visible page objects including the first and last one in that range. @return The returned pair of page object indices is empty when the second index is lower than the first. */ - PageRange GetVisiblePageRange (void); + Pair GetVisiblePageRange (void); /** Add a shape to the page. Typically used from inside PostModelChange(). */ - void AddSdrObject (SdrObject& rObject); + // void AddSdrObject (SdrObject& rObject); /** Add a listener that is called when the set of visible slides. @param rListener @@ -234,71 +212,87 @@ public: */ void RemoveVisibilityChangeListener (const Link& rListener); + /** The page under the mouse is not highlighted in some contexts. Call + this method on context changes. + */ + void UpdatePageUnderMouse (bool bAnimate); + void UpdatePageUnderMouse ( + const Point& rMousePosition, + const bool bIsMouseButtonDown, + const bool bAnimate = true); + void UpdatePageUnderMouse ( + const model::SharedPageDescriptor& rpDescriptor, + const Point& rMousePosition, + const bool bIsMouseButtonDown, + const bool bAnimate = true); + void SetPageUnderMouse ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bAnimate = true); + + bool SetState ( + const model::SharedPageDescriptor& rpDescriptor, + const model::PageDescriptor::State eState, + const bool bStateValue, + const bool bAnimate = true); + + void UpdateOrientation (void); + + ::boost::shared_ptr<PageObjectPainter> GetPageObjectPainter (void); + ::boost::shared_ptr<LayeredDevice> GetLayeredDevice (void) const; + + class DrawLock + { + public: + DrawLock (view::SlideSorterView& rView, const SharedSdWindow& rpWindow); + DrawLock (SlideSorter& rSlideSorter); + ~DrawLock (void); + /** When the DrawLock is disposed then it will not request a repaint + on destruction. + */ + void Dispose (void); + private: + view::SlideSorterView& mrView; + SharedSdWindow mpWindow; + }; + + ButtonBar& GetButtonBar (void) const; + ToolTip& GetToolTip (void) const; + protected: virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint); private: SlideSorter& mrSlideSorter; model::SlideSorterModel& mrModel; - /// This model is used for the maPage object and for the page visualizers - /// (SdrPageObj) - SdrModel maPageModel; - /** This page acts as container for the page objects that represent the - pages of the document that is represented by the SlideSorterModel. - */ - SdrPage* mpPage; + bool mbIsDisposed; ::std::auto_ptr<Layouter> mpLayouter; bool mbPageObjectVisibilitiesValid; ::boost::shared_ptr<cache::PageCache> mpPreviewCache; - ::std::auto_ptr<ViewOverlay> mpViewOverlay; - - int mnFirstVisiblePageIndex; - int mnLastVisiblePageIndex; - - SvBorder maPagePixelBorder; - + ::boost::shared_ptr<LayeredDevice> mpLayeredDevice; + Range maVisiblePageRange; bool mbModelChangedWhileModifyEnabled; - Size maPreviewSize; - bool mbPreciousFlagUpdatePending; - - Size maPageNumberAreaModelSize; - SvBorder maModelBorder; - - Orientation meOrientation; - + Layouter::Orientation meOrientation; + ::boost::shared_ptr<controller::Properties> mpProperties; + model::SharedPageDescriptor mpPageUnderMouse; + sal_Int32 mnButtonUnderMouse; + ::boost::shared_ptr<PageObjectPainter> mpPageObjectPainter; + ::boost::shared_ptr<SelectionPainter> mpSelectionPainter; + Region maRedrawRegion; + SharedILayerPainter mpBackgroundPainter; + ::boost::scoped_ptr<ButtonBar> mpButtonBar; + ::boost::scoped_ptr<ToolTip> mpToolTip; + bool mbIsRearrangePending; ::std::vector<Link> maVisibilityChangeListeners; - /** Adapt the coordinates of the given bounding box according to the - other parameters. - @param rModelPageObjectBoundingBox - Bounding box given in model coordinates that bounds only the - page object. - @param eCoordinateSystem - When CS_SCREEN is given then the bounding box is converted into - screen coordinates. - @param eBoundingBoxType - When BBT_INFO is given then the bounding box is made larger so - that it encloses all relevant displayed information. - */ - void AdaptBoundingBox ( - Rectangle& rModelPageObjectBoundingBox, - CoordinateSystem eCoordinateSystem, - BoundingBoxType eBoundingBoxType) const; - /** Determine the visibility of all page objects. */ void DeterminePageObjectVisibilities (void); - /** Update the page borders used by the layouter by using those returned - by the first page. Call this function when the model changes, - especially when the number of pages changes, or when the window is - resized as the borders may be device dependent. - */ - void UpdatePageBorders (void); - void UpdatePreciousFlags (void); + void RequestRearrange (void); + void Rearrange (void); }; diff --git a/sd/source/ui/slidesorter/inc/view/SlsButtonBar.hxx b/sd/source/ui/slidesorter/inc/view/SlsButtonBar.hxx new file mode 100644 index 000000000000..460c915f8a56 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsButtonBar.hxx @@ -0,0 +1,362 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_BUTTON_BAR_HXX +#define SD_SLIDESORTER_VIEW_BUTTON_BAR_HXX + +#include "model/SlsSharedPageDescriptor.hxx" +#include <tools/gen.hxx> +#include <rtl/ustring.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/bmpacc.hxx> +#include <boost/scoped_ptr.hpp> + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + + +namespace sd { namespace slidesorter { namespace view { + +class Theme; + +class Button; +typedef ::boost::shared_ptr<Button> SharedButton; + +/** This is a container of buttons and a coordinating controller. + The last means that it receives mouse events and forwards them to + the right button. +*/ +class ButtonBar +{ +public: + ButtonBar (SlideSorter& rSlideSorter); + ~ButtonBar (void); + + void ProcessButtonDownEvent ( + const model::SharedPageDescriptor& rpDescriptor, + const Point aMouseModelLocation); + void ProcessButtonUpEvent ( + const model::SharedPageDescriptor& rpDescriptor, + const Point aMouseModelLocation); + void ProcessMouseMotionEvent ( + const model::SharedPageDescriptor& rpDescriptor, + const Point aMouseModelLocation, + const bool bIsMouseButtonDown); + + void ResetPage (void); + + /** Return the number of buttons that are to be displayed in page + objects which the mouse hovers over. + @param bIsExcluded + When this flag is <TRUE/> then return the number of + buttons that is to be displayed for pages that are + excluded from the slide show. + */ + sal_Int32 GetButtonCount (const bool bIsExcluded) const; + + /** Return the specified button. + @param nIndex + Valid values lie in the range [0,GetButtonCount()). + @param bIsExcluded + When this flag is <TRUE/> then return a button that is to + be displayed for pages that are excluded from the slide + show. + @return + Returns an empty pointer when the given index is not valid. + */ + ::boost::shared_ptr<Button> GetButton ( + const bool bIsExcluded, + const sal_Int32 nIndex) const; + + bool IsMouseOverBar (void) const; + + /** Paint the specified page object. When this is not the same as the + one under the mouse (mpDescriptor) then the buttons are all + painted in their normal state. + */ + void Paint ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpPageDescriptor); + + bool IsMouseOverButton (void) const; + + void RequestLayout (void); + + /** Return the help text for the button under the mouse. + @return + When the mouse is not over a button then an empty string + is returned. + */ + ::rtl::OUString GetButtonHelpText (void) const; + + /** Request the button bar to be shown. + @param bAnimate + This flag controls whether to just show the button bar (<FALSE/>) + or to fade it in smoothly (<TRUE/>.) + */ + void RequestFadeIn ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bAnimate); + + /** Request the button bar to be hidden. + @param bAnimate + This flag controls whether to just hide the button bar (<FALSE/>) + or to fade it out smoothly (<TRUE/>.) + */ + void RequestFadeOut ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bAnimate); + + /** Return whether the button bar is visible for the givn descriptor (or + being faded in.) + */ + bool IsVisible (const model::SharedPageDescriptor& rpDescriptor); + + void HandleDataChangeEvent (void); + + class BackgroundTheme; + + /** While at least one Lock object exists the button bar will not be + displayed. Used, e.g. during a mouse multiselection to avoid + confusing and unhelpfull visual signals. + */ + class Lock + { + public: + Lock (SlideSorter& rSlideSorter); + ~Lock (void); + private: + ButtonBar& mrButtonBar; + }; + +private: + SlideSorter& mrSlideSorter; + Size maPageObjectSize; + Rectangle maButtonBoundingBox; + Point maBackgroundLocation; + model::SharedPageDescriptor mpDescriptor; + bool mbIsExcluded; + boost::shared_ptr<Button> mpButtonUnderMouse; + // The button on which the mouse button was pressed. + boost::shared_ptr<Button> mpDownButton; + ::std::vector<SharedButton> maRegularButtons; + ::std::vector<SharedButton> maExcludedButtons; + BitmapEx maNormalBackground; + BitmapEx maButtonDownBackground; + bool mbIsMouseOverBar; + ::boost::scoped_ptr<BackgroundTheme> mpBackgroundTheme; + int mnLockCount; + + /** Remember the specified page. If it differs from mpDescriptor then + the buttons are placed anew. + @return + The returned flag indicates wether the mpDescriptor member + is set to a new value. + */ + bool SetPage (const model::SharedPageDescriptor& rpDescriptor); + SharedButton GetButtonAt (const Point aModelLocation); + bool SetButtonUnderMouse (const SharedButton& rButton = SharedButton()); + void PaintButtonBackground ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpPageDescriptor, + const Point aOffset); + void LayoutButtons (const Size aPageModelSize); + bool LayoutButtons (void); + BitmapEx CreateBackground ( + const OutputDevice& rTemplateDevice, + const bool bIsButtonDown) const; + bool IsMouseOverBar (const Point aModelLocation) const; + void StartFadeAnimation ( + const model::SharedPageDescriptor& rpDescriptor, + const double nTargetAlpha, + const bool bFadeIn); + + void AcquireLock (void); + void ReleaseLock (void); +}; + + + + +class Button +{ +public: + Button ( + SlideSorter& rSlideSorter, + const ::rtl::OUString& rsHelpText); + virtual ~Button (void); + + enum State { State_Normal, State_Hover, State_Down }; + enum IconSize { IconSize_Large, IconSize_Medium, IconSize_Small }; + + /** Set a new state. + @return + When the new state is different from the old state + then <TRUE/> is returned. + */ + bool SetState (const State eState); + State GetState (void) const; + + virtual void Place (const Rectangle aButtonBarBox) = 0; + virtual void Paint ( + OutputDevice& rDevice, + const Point aOffset, + const double nAlpha, + const ::boost::shared_ptr<Theme>& rpTheme) const = 0; + virtual void ProcessClick (const model::SharedPageDescriptor& rpDescriptor) = 0; + + /** Return the bounding box of the layouted button. + */ + Rectangle GetBoundingBox (void) const; + /** Return the minimum size required to completely paint the + button. + */ + virtual Size GetSize (void) const = 0; + virtual Size GetSize (const IconSize eIconSize) const = 0; + ::rtl::OUString GetHelpText (void) const; + bool IsDown (void) const; + void SetActiveState (const bool bIsActive); + bool IsActive (void) const; + void SetIconSize (const IconSize eIconSize); + IconSize GetIconSize (void) const; + /** By default a button is always enabled. Override to change this. + */ + virtual bool IsEnabled (void) const; + +protected: + SlideSorter& mrSlideSorter; + State meState; + Rectangle maBoundingBox; + const ::rtl::OUString msHelpText; + // Buttons that lie (partly) outside the button bar are deactivated. + bool mbIsActive; + IconSize meIconSize; +}; + + + +class TextButton : public Button +{ +public: + TextButton ( + SlideSorter& rSlideSorter, + const ::rtl::OUString& rsText, + const ::rtl::OUString& rsHelpText); + + virtual void Place (const Rectangle aButtonBarBox); + virtual void Paint ( + OutputDevice& rDevice, + const Point aOffset, + const double nAlpha, + const ::boost::shared_ptr<Theme>& rpTheme) const; + virtual Size GetSize (void) const; + virtual Size GetSize (const IconSize eIconSize) const; + +private: + const ::rtl::OUString msText; +}; + + + +class ImageButton : public Button +{ +public: + ImageButton ( + SlideSorter& rSlideSorter, + const BitmapEx& rLargeIcon, + const BitmapEx& rLargeHoverIcon, + const BitmapEx& rMediumIcon, + const BitmapEx& rMediumHoverIcon, + const BitmapEx& rSmallIcon, + const BitmapEx& rSmallHoverIcon, + const ::rtl::OUString& rsHelpText); + + virtual void Place (const Rectangle aButtonBarBox); + virtual void Paint ( + OutputDevice& rDevice, + const Point aOffset, + const double nAlpha, + const ::boost::shared_ptr<Theme>& rpTheme) const; + virtual Size GetSize (void) const; + virtual Size GetSize (const IconSize eIconSize) const; + +private: + const BitmapEx maLargeIcon; + const BitmapEx maLargeHoverIcon; + const BitmapEx maMediumIcon; + const BitmapEx maMediumHoverIcon; + const BitmapEx maSmallIcon; + const BitmapEx maSmallHoverIcon; +}; + + +class UnhideButton : public ImageButton +{ +public: + UnhideButton (SlideSorter& rSlideSorter); + +protected: + virtual void ProcessClick (const model::SharedPageDescriptor& rpDescriptor); +}; + + +class StartShowButton : public ImageButton +{ +public: + StartShowButton (SlideSorter& rSlideSorter); + virtual bool IsEnabled (void) const; + +protected: + virtual void ProcessClick (const model::SharedPageDescriptor& rpDescriptor); +}; + + +class HideButton : public ImageButton +{ +public: + HideButton (SlideSorter& rSlideSorter); + +protected: + virtual void ProcessClick (const model::SharedPageDescriptor& rpDescriptor); +}; + + +class DuplicateButton : public ImageButton +{ +public: + DuplicateButton (SlideSorter& rSlideSorter); + virtual bool IsEnabled (void) const; + +protected: + virtual void ProcessClick (const model::SharedPageDescriptor& rpDescriptor); +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsILayerPainter.hxx b/sd/source/ui/slidesorter/inc/view/SlsILayerPainter.hxx new file mode 100644 index 000000000000..853890ee5894 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsILayerPainter.hxx @@ -0,0 +1,60 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_LAYER_PAINTER_HXX +#define SD_SLIDESORTER_VIEW_LAYER_PAINTER_HXX + +#include <boost/shared_ptr.hpp> +#include <sal/types.h> + +class OutputDevice; +class Rectangle; + +namespace sd { namespace slidesorter { namespace view { + +class ILayerInvalidator +{ +public: + virtual void Invalidate (const Rectangle& rInvalidationBox) = 0; +}; +typedef ::boost::shared_ptr<ILayerInvalidator> SharedILayerInvalidator; + +class ILayerPainter +{ +public: + virtual void SetLayerInvalidator ( + const SharedILayerInvalidator& rpInvalidator) = 0; + virtual void Paint ( + OutputDevice& rDevice, + const Rectangle& rRepaintArea) = 0; +}; +typedef ::boost::shared_ptr<ILayerPainter> SharedILayerPainter; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsInsertAnimator.hxx b/sd/source/ui/slidesorter/inc/view/SlsInsertAnimator.hxx new file mode 100644 index 000000000000..cfd789818408 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsInsertAnimator.hxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_INSERT_ANIMATOR_HXX +#define SD_SLIDESORTER_VIEW_INSERT_ANIMATOR_HXX + +#include "controller/SlsAnimator.hxx" +#include <boost/scoped_ptr.hpp> +#include <boost/noncopyable.hpp> + +namespace sd { namespace slidesorter { namespace view { + +class InsertPosition; + + +/** Animate the positions of page objects to make room at the insert + position while a move or copy operation takes place. +*/ +class InsertAnimator + : private ::boost::noncopyable +{ +public: + InsertAnimator (SlideSorter& rSlideSorter); + + /** Set the position at which we have to make room for the display of an + icon. + */ + void SetInsertPosition (const InsertPosition& rInsertPosition); + + enum ResetMode { RM_Normal, RM_AbortAnimations }; + /** Restore the normal position of all page objects. + @param eMode + This flag controls wether to start an animation that ends in the + normal positions of all slides (AM_Animated) or to restore the + normal positions immediately (AM_Immediate). + */ + void Reset (const controller::Animator::AnimationMode eMode); + +private: + class Implementation; + ::boost::shared_ptr<Implementation> mpImplementation; +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsInsertionIndicatorOverlay.hxx b/sd/source/ui/slidesorter/inc/view/SlsInsertionIndicatorOverlay.hxx new file mode 100644 index 000000000000..a9a640d978cf --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsInsertionIndicatorOverlay.hxx @@ -0,0 +1,131 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_INSERTION_INDICATOR_OVERLAY_HXX +#define SD_SLIDESORTER_INSERTION_INDICATOR_OVERLAY_HXX + +#include "model/SlsSharedPageDescriptor.hxx" +#include "view/SlsILayerPainter.hxx" +#include "controller/SlsTransferable.hxx" + +#include <tools/gen.hxx> +#include <vcl/bitmapex.hxx> +#include <boost/scoped_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <vector> + +class OutputDevice; +class SdPage; + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace model { +class PageEnumeration; +} } } + +namespace sd { namespace slidesorter { namespace controller { +class Transferable; +} } } + +namespace sd { namespace slidesorter { namespace view { + +class FramePainter; +class LayeredDevice; + +/** The insertion indicator is painted as a vertical or horizonal bar + in the space between slides. +*/ +class InsertionIndicatorOverlay + : public ILayerPainter, + public ::boost::enable_shared_from_this<InsertionIndicatorOverlay> +{ +public: + InsertionIndicatorOverlay (SlideSorter& rSlideSorter); + virtual ~InsertionIndicatorOverlay (void); + + virtual void SetLayerInvalidator (const SharedILayerInvalidator& rpInvalidator); + + void Create (const controller::Transferable* pTransferable); + + /** Given a position in model coordinates this method calculates the + insertion marker both as an index in the document and as a location + used for drawing the insertion indicator. + */ + void SetLocation (const Point& rPosition); + + Size GetSize (void) const; + + virtual void Paint ( + OutputDevice& rDevice, + const Rectangle& rRepaintArea); + + bool IsVisible (void) const; + void Hide (void); + void Show (void); + + Rectangle GetBoundingBox (void) const; + +private: + SlideSorter& mrSlideSorter; + bool mbIsVisible; + const sal_Int32 mnLayerIndex; + SharedILayerInvalidator mpLayerInvalidator; + // Center of the insertion indicator. + Point maLocation; + BitmapEx maIcon; + Point maIconOffset; + ::boost::scoped_ptr<FramePainter> mpShadowPainter; + + void SetPositionAndSize (const Rectangle& rBoundingBox); + void SelectRepresentatives ( + model::PageEnumeration& rSelection, + ::std::vector<model::SharedPageDescriptor>& rDescriptors) const; + Point PaintRepresentatives ( + OutputDevice& rContent, + const Size aPreviewSize, + const sal_Int32 nOffset, + const ::std::vector<controller::Transferable::Representative>& rPages) const; + void PaintPageCount ( + OutputDevice& rDevice, + const sal_Int32 nSelectionCount, + const Size aPreviewSize, + const Point aFirstPageOffset) const; + /** Setup the insertion indicator by creating the icon. It consists of + scaled down previews of some of the selected pages. + */ + void Create ( + const ::std::vector<controller::Transferable::Representative>& rPages, + const sal_Int32 nSelectionCount); +}; + + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsLayouter.hxx b/sd/source/ui/slidesorter/inc/view/SlsLayouter.hxx index 9b1fd996e9c0..4d19e41e881b 100755..100644 --- a/sd/source/ui/slidesorter/inc/view/SlsLayouter.hxx +++ b/sd/source/ui/slidesorter/inc/view/SlsLayouter.hxx @@ -28,18 +28,26 @@ #ifndef SD_SLIDESORTER_VIEW_LAYOUTER_HXX #define SD_SLIDESORTER_VIEW_LAYOUTER_HXX +#include "SlideSorter.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsTheme.hxx" #include <sal/types.h> #include <tools/fract.hxx> #include <vcl/mapmod.hxx> #include <vector> #include <utility> + class MapMode; class OutputDevice; class Size; namespace sd { namespace slidesorter { namespace view { +class InsertPosition; + + + /** Calculate the size and position of page objects displayed by a slide sorter. The layouter takes into account various input values: 1.) Size of the window in which the slide sorter is displayed. @@ -66,9 +74,14 @@ namespace sd { namespace slidesorter { namespace view { class Layouter { public: - Layouter (void); + enum Orientation { HORIZONTAL, VERTICAL, GRID }; + + Layouter ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<Theme>& rpTheme); ~Layouter (void); + ::boost::shared_ptr<PageObjectLayouter> GetPageObjectLayouter (void) const; /** Set the horizontal and vertical borders in pixel coordinates between the enclosing window and page objects. The borders may be painted larger then the given values when the space for the insertion marker @@ -89,23 +102,6 @@ public: void SetBorders (sal_Int32 nLeftBorder, sal_Int32 nRightBorder, sal_Int32 nTopBorder, sal_Int32 nBottomBorder); - /** Set the borders arround every page object. - @param nLeftBorder - A negative value indicates that the left border shall not be - modified. A value of 0 is the default. - @param nRightBorder - A negative value indicates that the left border shall not be - modified. A value of 0 is the default. - @param nTopBorder - A negative value indicates that the left border shall not be - modified. A value of 0 is the default. - @param nBottomBorder - A negative value indicates that the left border shall not be - modified. A value of 0 is the default. - */ - void SetPageBorders (sal_Int32 nLeftBorder, sal_Int32 nRightBorder, - sal_Int32 nTopBorder, sal_Int32 nBottomBorder); - /** Set the interval of valid column counts. When nMinimalColumnCount <= nMaximalColumnCount is not fullfilled then the call is ignored. @param nMinimalColumnCount @@ -120,37 +116,46 @@ public: /** Central method of this class. It takes the input values and calculates the output values. Both given sizes must not be 0 in any dimension or the call is ignored. + @param eOrientation + This defines the generaly layout and specifies whether there may + be more than one row or more than one column. @param rWindowSize The size of the window in pixels that the slide sorter is - displayed in. - @param rPageObjectSize + displayed in. This can differ from the size of mpWindow during + detection of whether or not the scroll bars should be visible. + @param rPreviewModelSize Size of each page in model coordinates. - @param pDevice - The map mode of this output device is adapted to the new layout - of the page objects. + @param rpWindow + The map mode of this window is adapted to the new layout of the + page objects. @return The return value indicates whether the Get... methods can be used to obtain valid values (<TRUE/>). */ - bool RearrangeHorizontal ( + bool Rearrange ( + const Orientation eOrientation, const Size& rWindowSize, - const Size& rPageObjectSize, - OutputDevice* pDevice, + const Size& rPreviewModelSize, const sal_uInt32 nPageCount); - bool RearrangeVertical ( - const Size& rWindowSize, - const Size& rPageObjectSize, - OutputDevice* pDevice); /** Change the zoom factor. This does not change the general layout (number of columns). */ - void SetZoom (Fraction nZoomFactor, OutputDevice* pDevice); + void _SetZoom (double nZoomFactor); + void _SetZoom (Fraction nZoomFactor); /** Return the number of columns. */ sal_Int32 GetColumnCount (void) const; + sal_Int32 GetRowCount (void) const; + + sal_Int32 GetRow (const sal_Int32 nIndex) const; + + sal_Int32 GetColumn (const sal_Int32 nIndex) const; + + sal_Int32 GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) const; + /** Return the scale factor that can be set at the map mode of the output window. */ @@ -158,52 +163,25 @@ public: Size GetPageObjectSize (void) const; - /** Return the bounding box in model coordinates of the nIndex-th page + /** Return the bounding box in window coordinates of the nIndex-th page object. */ - Rectangle GetPageObjectBox (sal_Int32 nIndex) const; + Rectangle GetPageObjectBox ( + const sal_Int32 nIndex, + const bool bIncludeBorderAndGap = false) const; /** Return the bounding box in model coordinates of the page that contains the given amount of page objects. */ - Rectangle GetPageBox (sal_Int32 nObjectCount) const; - - /** Return the rectangle that bounds the insertion marker that is - specified by the parameters. - @param nIndex - Index of the page object from which the position of the marker - will be calculated. - @param bVertical - When <TRUE/> then the insertion marker will be calculated with a - vertical orientation positioned to the left or right of the - specified page object. A horizontal orientation is indicated by - <FALSE/>. In this case the marker will be positioned above or - below the page object. - @param bLeftOrTop - This flag indicates whether the insertion marker will be - positioned above or to the left (<TRUE/>) the page object. When - <FALSE/> is given then the marker will be positioned below or to - the right of the page object. - */ - Rectangle GetInsertionMarkerBox ( - sal_Int32 nIndex, - bool bVertical, - bool bLeftOrTop) const; + Rectangle GetTotalBoundingBox (void) const; /** Return the index of the first fully or partially visible page object. This takes into account only the vertical dimension. - */ - sal_Int32 GetIndexOfFirstVisiblePageObject ( - const Rectangle& rVisibleArea) const; - - /** Return the index of the last fully or partially visible page - object. This takes into account only the vertical dimension. @return - The returned index may be larger than the number of existing + The second index may be larger than the number of existing page objects. */ - sal_Int32 GetIndexOfLastVisiblePageObject ( - const Rectangle& rVisibleArea) const; + Range GetRangeOfVisiblePageObjects (const Rectangle& rVisibleArea) const; /** Return the index of the page object that is rendered at the given point. @@ -216,167 +194,103 @@ public: the actual page area the index of that page is returned; otherwise -1 would be returned to indicate that no page object has been hit. + @param bClampToValidRange + When <TRUE/> then values outside the valid range [0,mnPageCount) + are mapped to 0 (when smaller than 0) or mnPageCount-1 when + equal to or larger than mnPageCount. + When <FALSE/> then -1 is returned for values outside the valid range. @return The returned index may be larger than the number of existing page objects. */ sal_Int32 GetIndexAtPoint ( const Point& rModelPosition, - bool bIncludePageBorders = false) const; - - /** Return the page index of where to do an insert operation when the - user would release the the mouse button at the given position after - a drag operation. - @param rPosition + const bool bIncludePageBorders = false, + const bool bClampToValidRange = true) const; + + /** Return an object that describes the logical and visual properties of + where to do an insert operation when the user would release the the + mouse button at the given position after a drag operation and of + where and how to display an insertion indicator. + @param rModelPosition The position in the model coordinate system for which to determine the insertion page index. The position does not have to be over a page object to return a valid value. - @param bAllowVerticalPosition - When this flag is <TRUE/> then the vertical gaps between rows - may be taken into account for calculating the insertion index as - well as the horizontal gaps between columns. This will happen - only when there is only one column. - (better name, anyone?) - @return - Returns the page index, as accepted by the slide sorter model, - of the page after which an insertion would take place. An index - of 0 means that insertion will take place before the first page, - An index equal to or greater than the page count means to insert - after the last page. - A value of -1 indicates that no valid insertion index exists for - the given point. + @param rIndicatorSize + The size of the insertion indicator. This size is used to adapt + the location when at the left or right of a row or at the top or + bottom of a column. + @param rModel + The model is used to get access to the selection states of the + pages. This in turn is used to determine the visual bounding + boxes. */ - sal_Int32 GetInsertionIndex ( + InsertPosition GetInsertPosition ( const Point& rModelPosition, - bool bAllowVerticalPosition) const; + const Size& rIndicatorSize, + model::SlideSorterModel& rModel) const; + + Range GetValidHorizontalSizeRange (void) const; + Range GetValidVerticalSizeRange (void) const; + + class Implementation; + +private: + ::boost::scoped_ptr<Implementation> mpImplementation; + SharedSdWindow mpWindow; +}; - typedef ::std::pair<double,double> DoublePoint; - /** Transform a point given in model coordinates in to layouter - coordinates. Layouter coordinates are floating point numbers where - the integer part denotes a row or a column and the part after the - decimal point is a relative position in that row or column. - */ - DoublePoint ConvertModelToLayouterCoordinates ( - const Point& rModelPoint) const; - /** Transform a point given in layouter coordinates to model - coordinates. See ConvertModelToLayouterCoordinates for a - description of layouter coordinates. - */ - Point ConvertLayouterToModelCoordinates ( - const DoublePoint&rLayouterPoint) const; - typedef ::std::vector<Rectangle> BackgroundRectangleList; + + +/** Collect all values concerning the logical and visual properties of the + insertion position that is used for drag-and-drop and copy-and-past. +*/ +class InsertPosition +{ +public: + InsertPosition (void); + InsertPosition& operator= (const InsertPosition& rInsertPosition); + bool operator== (const InsertPosition& rInsertPosition) const; + bool operator!= (const InsertPosition& rInsertPosition) const; + + void SetLogicalPosition ( + const sal_Int32 nRow, + const sal_Int32 nColumn, + const sal_Int32 nIndex, + const bool bIsAtRunStart, + const bool bIsAtRunEnd, + const bool bIsExtraSpaceNeeded); + void SetGeometricalPosition( + const Point aLocation, + const Point aLeadingOffset, + const Point aTrailingOffset); + + sal_Int32 GetRow (void) const { return mnRow; } + sal_Int32 GetColumn (void) const { return mnColumn; } + sal_Int32 GetIndex (void) const { return mnIndex; } + Point GetLocation (void) const { return maLocation; } + Point GetLeadingOffset (void) const { return maLeadingOffset; } + Point GetTrailingOffset (void) const { return maTrailingOffset; } + bool IsAtRunStart (void) const { return mbIsAtRunStart; } + bool IsAtRunEnd (void) const { return mbIsAtRunEnd; } + bool IsExtraSpaceNeeded (void) const { return mbIsExtraSpaceNeeded; } private: - class ScreenAndModelValue {public: - sal_Int32 mnScreen,mnModel; - explicit ScreenAndModelValue (sal_Int32 nScreen, sal_Int32 nModel = 0) - : mnScreen(nScreen),mnModel(nModel) {} - }; - ScreenAndModelValue mnRequestedLeftBorder; - ScreenAndModelValue mnRequestedRightBorder; - ScreenAndModelValue mnRequestedTopBorder; - ScreenAndModelValue mnRequestedBottomBorder; - ScreenAndModelValue mnLeftBorder; - ScreenAndModelValue mnRightBorder; - ScreenAndModelValue mnTopBorder; - ScreenAndModelValue mnBottomBorder; - ScreenAndModelValue mnLeftPageBorder; - ScreenAndModelValue mnRightPageBorder; - ScreenAndModelValue mnTopPageBorder; - ScreenAndModelValue mnBottomPageBorder; - ScreenAndModelValue mnVerticalGap; - ScreenAndModelValue mnHorizontalGap; - ScreenAndModelValue mnInsertionMarkerThickness; - ScreenAndModelValue mnTotalVerticalGap; - ScreenAndModelValue mnTotalHorizontalGap; - sal_Int32 mnMinimalWidth; - sal_Int32 mnPreferredWidth; - sal_Int32 mnMaximalWidth; - sal_Int32 mnMinimalColumnCount; - sal_Int32 mnMaximalColumnCount; - sal_Int32 mnColumnCount; - Size maPageObjectModelSize; - Size maPageObjectPixelSize; - - BackgroundRectangleList maBackgroundRectangleList; - - enum GapMembership { GM_NONE, GM_PREVIOUS, GM_BOTH, GM_NEXT, - GM_PAGE_BORDER}; - - /** Calculate the row that the point with the given vertical coordinate - is over. The horizontal component is ignored. - @param nYPosition - Vertical position in model coordinates. - @param bIncludeBordersAndGaps - When this flag is <TRUE/> then the area of borders and gaps are - interpreted as belonging to one of the rows. - @param eGapMembership - Specifies to what row the gap areas belong. Here GM_NONE - corresponds to bIncludeBordersAndGaps being <FALSE/>. When - GM_BOTH is given then the upper half is associated to the row - above and the lower half to the row below. Values of - GM_PREVIOUS and GM_NEXT associate the whole gap area with the - row above or below respectively. - */ - sal_Int32 GetRowAtPosition ( - sal_Int32 nYPosition, - bool bIncludeBordersAndGaps, - GapMembership eGapMembership = GM_NONE) const; - - /** Calculate the column that the point with the given horizontal - coordinate is over. The verical component is ignored. - @param nXPosition - Horizontal position in model coordinates. - @param bIncludeBordersAndGaps - When this flag is <TRUE/> then the area of borders and gaps are - interpreted as belonging to one of the columns. - @param eGapMembership - Specifies to what column the gap areas belong. Here GM_NONE - corresponds to bIncludeBordersAndGaps being <FALSE/>. When - GM_BOTH is given then the left half is associated with the - column at the left and the right half with the column to the - right. Values of GM_PREVIOUS and GM_NEXT associate the whole - gap area with the column to the left or right respectively. - */ - sal_Int32 GetColumnAtPosition ( - sal_Int32 nXPosition, - bool bIncludeBordersAndGaps, - GapMembership eGapMembership = GM_NONE) const; - - /** This method is typically called from GetRowAtPosition() and - GetColumnAtPosition() to handle a position that lies inside the gap - between two adjacent rows or columns. - @param nDistanceIntoGap - Vertical distance from the bottom of the upper row down into the - gap or or horizontal distance from the right edge right into the - gap. - @param eGapMemberhship - This value decides what areas in the gap belong to which (or no) - row or column. - @param nIndex - The row index of the upper row or the column index of the left - column. - @param nLeftOrTopPageBorder - Width in model coordinates of the border the the right of or - below a page. - @param nGap - Width or height of the gap in model coordiantes between the - page borders. - @return - Returns either the index of the upper row (as given as nRow), the - index of the lower row (nRow+1) or -1 to indicate that the - position belongs to no row. - */ - sal_Int32 ResolvePositionInGap ( - sal_Int32 nDistanceIntoGap, - GapMembership eGapMembership, - sal_Int32 nIndex, - sal_Int32 nLeftOrTopPageBorder, - sal_Int32 nGap) const; + sal_Int32 mnRow; + sal_Int32 mnColumn; + sal_Int32 mnIndex; + bool mbIsAtRunStart : 1; + bool mbIsAtRunEnd : 1; + bool mbIsExtraSpaceNeeded : 1; + Point maLocation; + Point maLeadingOffset; + Point maTrailingOffset; }; + + } } } // end of namespace ::sd::slidesorter::view #endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsPageObjectLayouter.hxx b/sd/source/ui/slidesorter/inc/view/SlsPageObjectLayouter.hxx new file mode 100644 index 000000000000..8e61a8b1b47c --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsPageObjectLayouter.hxx @@ -0,0 +1,145 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_PAGE_OBJECT_LAYOUTER_HXX +#define SD_SLIDESORTER_PAGE_OBJECT_LAYOUTER_HXX + +#include "SlideSorter.hxx" +#include "model/SlsSharedPageDescriptor.hxx" +#include "tools/gen.hxx" +#include <vcl/image.hxx> + +namespace sd { namespace slidesorter { namespace view { + + +/** In contrast to the Layouter that places page objects in the view, the + PageObjectLayouter places the parts of individual page objects like page + number area, borders, preview. +*/ +class PageObjectLayouter +{ +public: + /** Create a new PageObjectLayouter object. + @param rPageObjectSize + In general either the width or the height will be 0 in order to + signal that this size component has to be calculated from the other. + This calculation will make the preview as large as possible. + @param nPageCount + The page count is used to determine how wide the page number + area has to be, how many digits to except for the largest page number. + */ + PageObjectLayouter( + const ::boost::shared_ptr<Theme>& rpTheme, + const Size& rPageObjectWindowSize, + const Size& rPreviewModelSize, + const SharedSdWindow& rpWindow, + const sal_Int32 nPageCount); + ~PageObjectLayouter(void); + + enum Part { + // The focus indicator is painted outside the actual page object. + FocusIndicator, + // This is the outer bounding box that includes the preview, page + // number, title. + PageObject, + // Bounding box of the actual preview. + Preview, + // Bounding box of the mouse indicator indicator frame. + MouseOverIndicator, + // Bounding box of the page number. + PageNumber, + // Bounding box of the pane name. + Name, + // Indicator whether or not there is a slide transition associated + // with this slide. + TransitionEffectIndicator + }; + /** Two coordinate systems are supported. They differ only in + translation not in scale. Both relate to pixel values in the window. + A position in the model coordinate system does not change when the window content is + scrolled up or down. In the window coordinate system (relative + to the top left point of the window)scrolling leads to different values. + */ + enum CoordinateSystem { + WindowCoordinateSystem, + ModelCoordinateSystem + }; + + /** Return the bounding box of the page object or one of its graphical + parts. + @param rWindow + This device is used to translate between model and window + coordinates. + @param rpPageDescriptor + The page for which to calculate the bounding box. This may be + NULL. When it is NULL then a generic bounding box is calculated + for the location (0,0). + @param ePart + The part of the page object for which to return the bounding + box. + @param eCoodinateSystem + The bounding box can be returned in model and in pixel + (window) coordinates. + */ + Rectangle GetBoundingBox ( + const model::SharedPageDescriptor& rpPageDescriptor, + const Part ePart, + const CoordinateSystem eCoordinateSystem); + Rectangle GetBoundingBox ( + const Point& rPageObjectLocation, + const Part ePart, + const CoordinateSystem eCoordinateSystem); + Size GetSize ( + const Part ePart, + const CoordinateSystem eCoordinateSystem); + + Image GetTransitionEffectIcon (void) const; + +private: + SharedSdWindow mpWindow; + Size maPageObjectSize; + double mnModelToWindowScale; + Rectangle maFocusIndicatorBoundingBox; + Rectangle maPageObjectBoundingBox; + Rectangle maPageNumberAreaBoundingBox; + Rectangle maPreviewBoundingBox; + Rectangle maTransitionEffectBoundingBox; + const Image maTransitionEffectIcon; + const ::boost::shared_ptr<Font> mpPageNumberFont; + + Size GetPageNumberAreaSize (const int nPageCount); + Rectangle CalculatePreviewBoundingBox ( + Size& rPageObjectSize, + const Size& rPreviewModelSize, + const sal_Int32 nPageNumberAreaWidth, + const sal_Int32 nFocusIndicatorWidth); +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsPageObjectPainter.hxx b/sd/source/ui/slidesorter/inc/view/SlsPageObjectPainter.hxx new file mode 100644 index 000000000000..e4e28a2e38b2 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsPageObjectPainter.hxx @@ -0,0 +1,138 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_PAGE_OBJECT_PAINTER_HEADER +#define SD_SLIDESORTER_PAGE_OBJECT_PAINTER_HEADER + +#include "SlideSorter.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsTheme.hxx" +#include <boost/scoped_ptr.hpp> + +namespace sd { namespace slidesorter { namespace cache { +class PageCache; +} } } + +namespace sd { namespace slidesorter { namespace view { + +class ButtonBar; +class Layouter; +class PageObjectLayouter; +class FramePainter; + +class PageObjectPainter +{ +public: + PageObjectPainter (const SlideSorter& rSlideSorter); + ~PageObjectPainter (void); + + void PaintPageObject ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor); + + void NotifyResize (const bool bForce = false); + + /** Called when the theme changes, either because it is replaced with + another or because the system colors have changed. So, even when + the given theme is the same object as the one already in use by this + painter everything that depends on the theme is updated. + */ + void SetTheme (const ::boost::shared_ptr<view::Theme>& rpTheme); + + /** Return a preview bitmap for the given page descriptor. When the + page is excluded from the show then the preview is marked + accordingly. + @rpDescriptor + Defines the page for which to return the preview. + @pReferenceDevice + When not <NULL/> then this reference device is used to created a + compatible bitmap. + @return + The returned bitmap may have a different size then the preview area. + */ + Bitmap GetPreviewBitmap ( + const model::SharedPageDescriptor& rpDescriptor, + const OutputDevice* pReferenceDevice) const; + +private: + const Layouter& mrLayouter; + ::boost::shared_ptr<PageObjectLayouter> mpPageObjectLayouter; + ::boost::shared_ptr<cache::PageCache> mpCache; + ::boost::shared_ptr<controller::Properties> mpProperties; + ::boost::shared_ptr<view::Theme> mpTheme; + ::boost::shared_ptr<Font> mpPageNumberFont; + ::boost::scoped_ptr<FramePainter> mpShadowPainter; + ::boost::scoped_ptr<FramePainter> mpFocusBorderPainter; + Bitmap maNormalBackground; + Bitmap maSelectionBackground; + Bitmap maFocusedSelectionBackground; + Bitmap maFocusedBackground; + Bitmap maMouseOverBackground; + Bitmap maMouseOverFocusedBackground; + Bitmap maMouseOverSelectedAndFocusedBackground; + ::rtl::OUString msUnhideString; + ButtonBar& mrButtonBar; + + void PaintBackground ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor); + void PaintPreview ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const; + void PaintPageNumber ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const; + void PaintTransitionEffect ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const; + void PaintBorder ( + OutputDevice& rDevice, + const Theme::GradientColorType eColorType, + const Rectangle& rBox) const; + Bitmap& GetBackgroundForState ( + const model::SharedPageDescriptor& rpDescriptor, + const OutputDevice& rTemplateDevice); + Bitmap& GetBackground( + Bitmap& rBackground, + Theme::GradientColorType eType, + const OutputDevice& rTemplateDevice, + const bool bHasFocusBorder); + Bitmap CreateBackgroundBitmap( + const OutputDevice& rReferenceDevice, + const Theme::GradientColorType eType, + const bool bHasFocusBorder) const; + Bitmap CreateMarkedPreview( + const Size& rSize, + const Bitmap& rPreview, + const BitmapEx& rOverlay, + const OutputDevice* pReferenceDevice) const; +}; + +} } } // end of namespace sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsResource.hrc b/sd/source/ui/slidesorter/inc/view/SlsResource.hrc new file mode 100644 index 000000000000..2b85a37d35dc --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsResource.hrc @@ -0,0 +1,111 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_ICONS_HRC +#define SD_SLIDESORTER_ICONS_HRC + +#include "glob.hrc" + +#define IMAGE_COMMAND1_LARGE 1 +#define IMAGE_COMMAND1_LARGE_HOVER 2 +#define IMAGE_COMMAND1_MEDIUM 3 +#define IMAGE_COMMAND1_MEDIUM_HOVER 4 +#define IMAGE_COMMAND1_SMALL 5 +#define IMAGE_COMMAND1_SMALL_HOVER 6 + +#define IMAGE_COMMAND1_LARGE_HC 7 +#define IMAGE_COMMAND1_LARGE_HOVER_HC 8 +#define IMAGE_COMMAND1_MEDIUM_HC 9 +#define IMAGE_COMMAND1_MEDIUM_HOVER_HC 10 +#define IMAGE_COMMAND1_SMALL_HC 11 +#define IMAGE_COMMAND1_SMALL_HOVER_HC 12 + + +#define IMAGE_COMMAND2_LARGE 20 +#define IMAGE_COMMAND2_LARGE_HOVER 21 +#define IMAGE_COMMAND2_MEDIUM 22 +#define IMAGE_COMMAND2_MEDIUM_HOVER 23 +#define IMAGE_COMMAND2_SMALL 24 +#define IMAGE_COMMAND2_SMALL_HOVER 25 + +#define IMAGE_COMMAND2_LARGE_HC 26 +#define IMAGE_COMMAND2_LARGE_HOVER_HC 27 +#define IMAGE_COMMAND2_MEDIUM_HC 28 +#define IMAGE_COMMAND2_MEDIUM_HOVER_HC 29 +#define IMAGE_COMMAND2_SMALL_HC 30 +#define IMAGE_COMMAND2_SMALL_HOVER_HC 31 + +#define IMAGE_COMMAND2B_LARGE 40 +#define IMAGE_COMMAND2B_LARGE_HOVER 41 +#define IMAGE_COMMAND2B_MEDIUM 42 +#define IMAGE_COMMAND2B_MEDIUM_HOVER 43 +#define IMAGE_COMMAND2B_SMALL 44 +#define IMAGE_COMMAND2B_SMALL_HOVER 45 + +#define IMAGE_COMMAND2B_LARGE_HC 46 +#define IMAGE_COMMAND2B_LARGE_HOVER_HC 47 +#define IMAGE_COMMAND2B_MEDIUM_HC 48 +#define IMAGE_COMMAND2B_MEDIUM_HOVER_HC 49 +#define IMAGE_COMMAND2B_SMALL_HC 50 +#define IMAGE_COMMAND2B_SMALL_HOVER_HC 51 + + +#define IMAGE_COMMAND3_LARGE 60 +#define IMAGE_COMMAND3_LARGE_HOVER 61 +#define IMAGE_COMMAND3_MEDIUM 62 +#define IMAGE_COMMAND3_MEDIUM_HOVER 63 +#define IMAGE_COMMAND3_SMALL 64 +#define IMAGE_COMMAND3_SMALL_HOVER 65 + +#define IMAGE_COMMAND3_LARGE_HC 66 +#define IMAGE_COMMAND3_LARGE_HOVER_HC 67 +#define IMAGE_COMMAND3_MEDIUM_HC 68 +#define IMAGE_COMMAND3_MEDIUM_HOVER_HC 69 +#define IMAGE_COMMAND3_SMALL_HC 70 +#define IMAGE_COMMAND3_SMALL_HOVER_HC 71 + +#define IMAGE_BUTTONBAR_LARGE 80 +#define IMAGE_BUTTONBAR_LARGE_HC 81 +#define IMAGE_BUTTONBAR_MEDIUM 82 +#define IMAGE_BUTTONBAR_MEDIUM_HC 83 +#define IMAGE_BUTTONBAR_SMALL 84 +#define IMAGE_BUTTONBAR_SMALL_HC 85 + +#define IMAGE_SHADOW 90 +#define IMAGE_INSERT_SHADOW 91 +#define IMAGE_HIDE_SLIDE_OVERLAY 92 +#define IMAGE_FOCUS_BORDER 93 + +#define STRING_DRAG_AND_DROP_PAGES 101 +#define STRING_DRAG_AND_DROP_SLIDES 102 + +#define STRING_COMMAND1 110 +#define STRING_COMMAND2_A 111 +#define STRING_COMMAND2_B 112 +#define STRING_COMMAND3 113 + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsTheme.hxx b/sd/source/ui/slidesorter/inc/view/SlsTheme.hxx new file mode 100644 index 000000000000..2b39e6d2a3ee --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsTheme.hxx @@ -0,0 +1,236 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_THEME_HXX +#define SD_SLIDESORTER_VIEW_THEME_HXX + +#include "model/SlsVisualState.hxx" + +#include <vcl/bitmapex.hxx> +#include <vcl/font.hxx> +#include <vcl/gradient.hxx> +#include <tools/color.hxx> + +#include <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> + + +namespace sd { namespace slidesorter { namespace controller { +class Properties; +} } } + +namespace sd { namespace slidesorter { namespace view { + + +/** Collection of colors and styles that are used to paint the slide sorter + view. +*/ +class Theme +{ +public: + Theme (const ::boost::shared_ptr<controller::Properties>& rpProperties); + + /** Call this method to update some colors as response to a change of + a system color change. + */ + void Update ( + const ::boost::shared_ptr<controller::Properties>& rpProperties); + + // BitmapEx GetInsertIndicatorIcon (void) const; + + enum FontType { + Font_PageNumber, + Font_PageCount, + Font_Button + }; + static ::boost::shared_ptr<Font> GetFont ( + const FontType eType, + const OutputDevice& rDevice); + + enum ColorType { + Color_Background, + Color_ButtonBackground, + Color_ButtonText, + Color_ButtonTextHover, + Color_PageNumberDefault, + Color_PageNumberHover, + Color_PageNumberHighContrast, + Color_PageNumberBrightBackground, + Color_PageNumberDarkBackground, + Color_Selection, + Color_PreviewBorder, + Color_PageCountFontColor, + _ColorType_Size_ + }; + ColorData GetColor (const ColorType eType); + void SetColor (const ColorType eType, const ColorData aColorData); + + enum GradientColorType { + Gradient_NormalPage, + Gradient_SelectedPage, + Gradient_SelectedAndFocusedPage, + Gradient_MouseOverPage, + Gradient_MouseOverSelectedAndFocusedPage, + Gradient_FocusedPage, + Gradient_ButtonBackground, + _GradientColorType_Size_ + }; + enum GradientColorClass { + Border1, + Border2, + Fill1, + Fill2, + Base + }; + ColorData GetGradientColor ( + const GradientColorType eType, + const GradientColorClass eClass); + sal_Int32 GetGradientOffset ( + const GradientColorType eType, + const GradientColorClass eClass); + void SetGradient ( + const GradientColorType eType, + const ColorData aBaseColor, + const sal_Int32 nSaturationOverride, + const sal_Int32 nBrightnessOverride, + const sal_Int32 nFillStartOffset, + const sal_Int32 nFillEndOffset, + const sal_Int32 nBorderStartOffset, + const sal_Int32 nBorderEndOffset); + sal_Int32 GetGradientSaturationOverride (const GradientColorType eType); + sal_Int32 GetGradientBrightnessOverride (const GradientColorType eType); + void SetGradientSaturationOverride (const GradientColorType eType, const sal_Int32 nValue); + void SetGradientBrightnessOverride (const GradientColorType eType, const sal_Int32 nValue); + + enum IconType + { + Icon_RawShadow, + Icon_RawInsertShadow, + Icon_HideSlideOverlay, + Icon_FocusBorder, + Icon_ButtonBarLarge, + Icon_ButtonBarMedium, + Icon_ButtonBarSmall, + Icon_Command1Large, + Icon_Command1LargeHover, + Icon_Command1Medium, + Icon_Command1MediumHover, + Icon_Command1Small, + Icon_Command1SmallHover, + Icon_Command2Large, + Icon_Command2LargeHover, + Icon_Command2Medium, + Icon_Command2MediumHover, + Icon_Command2Small, + Icon_Command2SmallHover, + Icon_Command2BLarge, + Icon_Command2BLargeHover, + Icon_Command2BMedium, + Icon_Command2BMediumHover, + Icon_Command2BSmall, + Icon_Command2BSmallHover, + Icon_Command3Large, + Icon_Command3LargeHover, + Icon_Command3Medium, + Icon_Command3MediumHover, + Icon_Command3Small, + Icon_Command3SmallHover, + _IconType_Size_ + }; + const BitmapEx& GetIcon (const IconType eType); + + enum IntegerValueType + { + Integer_ButtonCornerRadius, + Integer_ButtonMaxAlpha, + Integer_ButtonBarMaxAlpha, + Integer_ButtonPaintType, + Integer_ButtonBorder, + Integer_ButtonGap, + Integer_ButtonFadeInDelay, + Integer_ButtonFadeInDuration, + Integer_ButtonFadeOutDelay, + Integer_ButtonFadeOutDuration, + Integer_ToolTipDelay, + Integer_FocusIndicatorWidth, + _IntegerValueType_Size_ + }; + sal_Int32 GetIntegerValue (const IntegerValueType eType) const; + void SetIntegerValue (const IntegerValueType eType, const sal_Int32 nValue); + + enum StringType + { + String_Unhide, + String_DragAndDropPages, + String_DragAndDropSlides, + String_Command1, + String_Command2, + String_Command2B, + String_Command3, + _StringType_Size_ + }; + ::rtl::OUString GetString (const StringType eType) const; + +private: + bool mbIsHighContrastMode; + class GradientDescriptor + { + public: + ColorData maBaseColor; + + sal_Int32 mnSaturationOverride; + sal_Int32 mnBrightnessOverride; + + ColorData maFillColor1; + ColorData maFillColor2; + ColorData maBorderColor1; + ColorData maBorderColor2; + + sal_Int32 mnFillOffset1; + sal_Int32 mnFillOffset2; + sal_Int32 mnBorderOffset1; + sal_Int32 mnBorderOffset2; + }; + ColorData maBackgroundColor; + ColorData maPageBackgroundColor; + ::std::vector<GradientDescriptor> maGradients; + ::std::vector<BitmapEx> maIcons; + ::std::vector<ColorData> maColor; + ::std::vector<sal_Int32> maIntegerValues; + ::std::vector<rtl::OUString> maStrings; + + GradientDescriptor& GetGradient (const GradientColorType eType); + /** Guarded initialization of the specified icon in the maIcons + container. Call only while a LocalResource object is active. + */ + void InitializeIcon (const IconType eType, USHORT nResourceId); +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsToolTip.hxx b/sd/source/ui/slidesorter/inc/view/SlsToolTip.hxx new file mode 100644 index 000000000000..b633b1f3f5ca --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsToolTip.hxx @@ -0,0 +1,97 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_TOOL_TIP_HXX +#define SD_SLIDESORTER_VIEW_TOOL_TIP_HXX + +#include "SlideSorter.hxx" +#include "model/SlsSharedPageDescriptor.hxx" + +namespace sd { namespace slidesorter { namespace view { + +/** Manage the display of tool tips. The tool tip text changes when the + mouse is moved from slide to slide or from button to button. + After the mouse enters a slide the first display of the tool tip is + delayed for a short time in order to not draw attention from the slide + or its button bar. +*/ +class ToolTip +{ +public: + ToolTip (SlideSorter& rSlideSorter); + ~ToolTip (void); + + /** Set a new page. This modifies the default help text. After a page + change a timer is started to delay the display of the tool tip for + the new page. + @param rpPage + When this is empty then the tool tip is hidden. + */ + void SetPage (const model::SharedPageDescriptor& rpPage); + + /** Set and show the default help text. + */ + void ShowDefaultHelpText (const ::rtl::OUString& rsHelpText); + + /** Show a previously set default help text. + */ + void ShowDefaultHelpText (void); + + /** Show a temporary help text. + */ + void ShowHelpText (const ::rtl::OUString& rsHelpText); + + /** Hide the tool tip. + @return + Returns whether the tool tip was visible at the time this method + was called. + */ + bool Hide (void); + +private: + SlideSorter& mrSlideSorter; + model::SharedPageDescriptor mpDescriptor; + ::rtl::OUString msDefaultHelpText; + ::rtl::OUString msCurrentHelpText; + ULONG mnHelpWindowHandle; + Timer maTimer; + + /** Request to show the tool tip. + @param bForce + When <TRUE/> then the tool tip is show right away. Otherwise it + is shown after a short delay. + */ + void Show (const bool bForce); + void DoShow (void); + + DECL_LINK(DelayTrigger, void*); +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsViewOverlay.hxx b/sd/source/ui/slidesorter/inc/view/SlsViewOverlay.hxx deleted file mode 100644 index 4ff076f72560..000000000000 --- a/sd/source/ui/slidesorter/inc/view/SlsViewOverlay.hxx +++ /dev/null @@ -1,273 +0,0 @@ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -#ifndef SD_SLIDESORTER_VIEW_OVERLAY_HXX -#define SD_SLIDESORTER_VIEW_OVERLAY_HXX - -#include "model/SlsSharedPageDescriptor.hxx" - -#include <basegfx/polygon/b2dpolypolygon.hxx> -#include <osl/mutex.hxx> -#include <svx/sdr/overlay/overlayobject.hxx> -#include <tools/gen.hxx> -#include <vector> -#include <boost/weak_ptr.hpp> -#include <boost/noncopyable.hpp> - -class OutputDevice; -class Region; - - -namespace sd { namespace slidesorter { -class SlideSorter; -} } - -namespace sd { namespace slidesorter { namespace model { -class PageEnumeration; -} } } - -namespace sd { namespace slidesorter { namespace controller { -class SlideSorterController; -} } } - -namespace sdr { namespace overlay { -class OverlayManager; -} } - -namespace sd { namespace slidesorter { namespace view { - - -class InsertionIndicatorOverlay; -class PageObjectViewObjectContact; -class SelectionRectangleOverlay; -class SubstitutionOverlay; -class ViewOverlay; - -/** This base class of slide sorter overlays uses the drawing layer overlay - support for the display. -*/ -class OverlayBase - : public sdr::overlay::OverlayObject -{ -public: - OverlayBase (ViewOverlay& rViewOverlay); - virtual ~OverlayBase (void); - -protected: - ::osl::Mutex maMutex; - - ViewOverlay& mrViewOverlay; - - /** Make sure that the overlay object is registered at the - OverlayManager. This registration is done on demand. - */ - void EnsureRegistration (void); - void RemoveRegistration(); -}; - - - - -/** During internal drag and drop the outlines of the selected slides are - painted at the mouse position in dashed lines. -*/ -class SubstitutionOverlay - : public OverlayBase -{ -public: - SubstitutionOverlay (ViewOverlay& rViewOverlay); - virtual ~SubstitutionOverlay (void); - - /** Setup the substitution display of the given set of selected pages. - The given mouse position is remembered so that it later can be - returned by GetPosition(). This is a convenience feature. - */ - void Create ( - model::PageEnumeration& rSelection, - const Point& rPosition); - - /** Clear the substitution display. Until the next call of Create() no - substution is painted. - */ - void Clear (void); - - /** Move the substitution display by the given amount of pixels. - */ - void Move (const Point& rOffset); - void SetPosition (const Point& rPosition); - Point GetPosition (void) const; - - // react on stripe definition change - virtual void stripeDefinitionHasChanged(); - -protected: - // geometry creation for OverlayObject - virtual drawinglayer::primitive2d::Primitive2DSequence createOverlayObjectPrimitive2DSequence(); - -private: - Point maPosition; - basegfx::B2DPolyPolygon maShapes; -}; - - - - -/** Slides can be selected by drawing a selection rectangle in the slide - sorter. When the left mouse button is released all slides that are at - least partially in the rectangle are selected. -*/ -class SelectionRectangleOverlay - : public OverlayBase -{ -public: - SelectionRectangleOverlay (ViewOverlay& rViewOverlay); - virtual ~SelectionRectangleOverlay(); - - void Start (const Point& rAnchor); - void Update (const Point& rSecondCorner); - - Rectangle GetSelectionRectangle (void); - - // react on stripe definition change - virtual void stripeDefinitionHasChanged(); - -protected: - // geometry creation for OverlayObject - virtual drawinglayer::primitive2d::Primitive2DSequence createOverlayObjectPrimitive2DSequence(); - -private: - Point maAnchor; - Point maSecondCorner; -}; - - - - -/** The insertion indicator is painted as a vertical or horizonal bar - in the space between slides. -*/ -class InsertionIndicatorOverlay - : public OverlayBase -{ -public: - InsertionIndicatorOverlay (ViewOverlay& rViewOverlay); - virtual ~InsertionIndicatorOverlay(); - - /** Given a position in model coordinates this method calculates the - insertion marker both as an index in the document and as a rectangle - used for drawing the insertion indicator. - */ - void SetPosition (const Point& rPosition); - - sal_Int32 GetInsertionPageIndex (void) const; - -protected: - // geometry creation for OverlayObject - virtual drawinglayer::primitive2d::Primitive2DSequence createOverlayObjectPrimitive2DSequence(); - -private: - sal_Int32 mnInsertionIndex; - Rectangle maBoundingBox; - - void SetPositionAndSize (const Rectangle& rBoundingBox); -}; - - - - -/** Paint a frame around the slide preview under the mouse. The actual - painting is done by the PageObjectViewObjectContact of the slidesorter. -*/ -class MouseOverIndicatorOverlay - : public OverlayBase -{ -public: - MouseOverIndicatorOverlay (ViewOverlay& rViewOverlay); - virtual ~MouseOverIndicatorOverlay (void); - - /** Set the page object for which to paint a mouse over indicator. - @param pContact - A value of <NULL/> indicates to not paint the mouse over indicator. - */ - void SetSlideUnderMouse (const model::SharedPageDescriptor& rpDescriptor); - -protected: - // geometry creation for OverlayObject - virtual drawinglayer::primitive2d::Primitive2DSequence createOverlayObjectPrimitive2DSequence(); - -private: - /** The page under the mouse is stored as weak shared pointer so that - model changes can be handled without having the SlideSorterModel - inform this class explicitly. - */ - ::boost::weak_ptr<model::PageDescriptor> mpPageUnderMouse; - - view::PageObjectViewObjectContact* GetViewObjectContact (void) const; -}; - - - - -/** The view overlay manages and paints some indicators that are painted on - top of the regular view content (the page objects). It is separated - from the view to allow the indicators to be altered in position and size - without repainting the whole view content (inside that the bounding box - of the indicator). This is achieved by using the drawing layer overlay - support. - - The view overlay itself simply gives access to the more specialized - classes that handle individual indicators. - -*/ -class ViewOverlay -{ -public: - ViewOverlay (SlideSorter& rSlideSorter); - ~ViewOverlay (void); - - SelectionRectangleOverlay& GetSelectionRectangleOverlay (void); - MouseOverIndicatorOverlay& GetMouseOverIndicatorOverlay (void); - InsertionIndicatorOverlay& GetInsertionIndicatorOverlay (void); - SubstitutionOverlay& GetSubstitutionOverlay (void); - - SlideSorter& GetSlideSorter (void) const; - - sdr::overlay::OverlayManager* GetOverlayManager (void) const; - -private: - SlideSorter& mrSlideSorter; - SelectionRectangleOverlay maSelectionRectangleOverlay; - MouseOverIndicatorOverlay maMouseOverIndicatorOverlay; - InsertionIndicatorOverlay maInsertionIndicatorOverlay; - SubstitutionOverlay maSubstitutionOverlay; -}; - - - -} } } // end of namespace ::sd::slidesorter::view - -#endif diff --git a/sd/source/ui/slidesorter/model/SlideSorterModel.cxx b/sd/source/ui/slidesorter/model/SlideSorterModel.cxx index 0bf9052f5382..5eaf64db7bf8 100755..100644 --- a/sd/source/ui/slidesorter/model/SlideSorterModel.cxx +++ b/sd/source/ui/slidesorter/model/SlideSorterModel.cxx @@ -33,10 +33,10 @@ #include "model/SlsPageDescriptor.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "controller/SlideSorterController.hxx" -#include "controller/SlsPageObjectFactory.hxx" #include "controller/SlsProperties.hxx" #include "controller/SlsPageSelector.hxx" #include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsSlotManager.hxx" #include "view/SlideSorterView.hxx" #include "taskpane/SlideSorterCacheDisplay.hxx" #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> @@ -46,6 +46,7 @@ #include "ViewShellBase.hxx" #include "DrawViewShell.hxx" +#include "DrawDocShell.hxx" #include "drawdoc.hxx" #include "sdpage.hxx" #include "FrameView.hxx" @@ -67,6 +68,56 @@ namespace { private: Reference<drawing::XDrawPage> mxSlide; }; + + bool PrintModel (const SlideSorterModel& rModel) + { + for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex) + { + SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex)); + if (pDescriptor) + { + OSL_TRACE("%d %d %d %d %x", + nIndex, + pDescriptor->GetPageIndex(), + pDescriptor->GetVisualState().mnPageId, + FromCoreIndex(pDescriptor->GetPage()->GetPageNum()), + pDescriptor->GetPage()); + } + else + { + OSL_TRACE("%d", nIndex); + } + } + + return true; + } + bool CheckModel (const SlideSorterModel& rModel) + { + for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex) + { + SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex)); + if ( ! pDescriptor) + { + PrintModel(rModel); + OSL_ASSERT(pDescriptor); + return false; + } + if (nIndex != pDescriptor->GetPageIndex()) + { + PrintModel(rModel); + OSL_ASSERT(nIndex == pDescriptor->GetPageIndex()); + return false; + } + if (nIndex != pDescriptor->GetVisualState().mnPageId) + { + PrintModel(rModel); + OSL_ASSERT(nIndex == pDescriptor->GetVisualState().mnPageId); + return false; + } + } + + return true; + } } @@ -78,8 +129,7 @@ SlideSorterModel::SlideSorterModel (SlideSorter& rSlideSorter) mxSlides(), mePageKind(PK_STANDARD), meEditMode(EM_PAGE), - maPageDescriptors(0), - mpPageObjectFactory(NULL) + maPageDescriptors(0) { } @@ -94,6 +144,21 @@ SlideSorterModel::~SlideSorterModel (void) +void SlideSorterModel::Init (void) +{ +} + + + + +void SlideSorterModel::Dispose (void) +{ + ClearDescriptorList (); +} + + + + SdDrawDocument* SlideSorterModel::GetDocument (void) { if (mrSlideSorter.GetViewShellBase() != NULL) @@ -158,20 +223,11 @@ SharedPageDescriptor SlideSorterModel::GetPageDescriptor ( pDescriptor = maPageDescriptors[nPageIndex]; if (pDescriptor == NULL && bCreate && mxSlides.is()) { - SdDrawDocument* pModel = const_cast<SlideSorterModel*>(this)->GetDocument(); - SdPage* pPage = NULL; - if (pModel != NULL) - { - if (meEditMode == EM_PAGE) - pPage = pModel->GetSdPage ((USHORT)nPageIndex, mePageKind); - else - pPage = pModel->GetMasterSdPage ((USHORT)nPageIndex, mePageKind); - } + SdPage* pPage = GetPage(nPageIndex); pDescriptor.reset(new PageDescriptor ( Reference<drawing::XDrawPage>(mxSlides->getByIndex(nPageIndex),UNO_QUERY), pPage, - nPageIndex, - GetPageObjectFactory())); + nPageIndex)); maPageDescriptors[nPageIndex] = pDescriptor; } } @@ -234,6 +290,59 @@ sal_Int32 SlideSorterModel::GetIndex (const Reference<drawing::XDrawPage>& rxSli +sal_Int32 SlideSorterModel::GetIndex (const SdrPage* pPage) const +{ + if (pPage == NULL) + return -1; + + ::osl::MutexGuard aGuard (maMutex); + + // First try to guess the right index. + sal_Int16 nNumber ((pPage->GetPageNum()-1)/2); + SharedPageDescriptor pDescriptor (GetPageDescriptor(nNumber, false)); + if (pDescriptor.get() != NULL + && pDescriptor->GetPage() == pPage) + { + return nNumber; + } + + // Guess was wrong, iterate over all slides and search for the right + // one. + const sal_Int32 nCount (maPageDescriptors.size()); + for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex) + { + pDescriptor = maPageDescriptors[nIndex]; + + // Make sure that the descriptor exists. Without it the given slide + // can not be found. + if (pDescriptor.get() == NULL) + { + // Call GetPageDescriptor() to create the missing descriptor. + pDescriptor = GetPageDescriptor(nIndex, true); + } + + if (pDescriptor->GetPage() == pPage) + return nIndex; + } + + return -1; +} + + + + +USHORT SlideSorterModel::GetCoreIndex (const sal_Int32 nIndex) const +{ + SharedPageDescriptor pDescriptor (GetPageDescriptor(nIndex)); + if (pDescriptor) + return pDescriptor->GetPage()->GetPageNum(); + else + return mxSlides->getCount()*2+1; +} + + + + /** For now this method uses a trivial algorithm: throw away all descriptors and create them anew (on demand). The main problem that we are facing when designing a better algorithm is that we can not compare pointers to @@ -244,8 +353,39 @@ sal_Int32 SlideSorterModel::GetIndex (const Reference<drawing::XDrawPage>& rxSli void SlideSorterModel::Resync (void) { ::osl::MutexGuard aGuard (maMutex); - ClearDescriptorList (); - AdaptSize(); + + // Check if document and this model really differ. + bool bIsUpToDate (true); + SdDrawDocument* pDocument = GetDocument(); + if (pDocument!=NULL && maPageDescriptors.size()==pDocument->GetSdPageCount(mePageKind)) + { + for (sal_Int32 nIndex=0,nCount=maPageDescriptors.size(); nIndex<nCount; ++nIndex) + { + if (maPageDescriptors[nIndex] + && maPageDescriptors[nIndex]->GetPage() + != GetPage(nIndex)) + { + OSL_TRACE("page %d differs\n", nIndex); + bIsUpToDate = false; + break; + } + } + } + else + { + bIsUpToDate = false; + OSL_TRACE("models differ"); + } + + if ( ! bIsUpToDate) + { + SynchronizeDocumentSelection(); // Try to make the current selection persistent. + ClearDescriptorList (); + AdaptSize(); + SynchronizeModelSelection(); + mrSlideSorter.GetController().GetPageSelector().CountSelectedPages(); + } + CheckModel(*this); } @@ -253,21 +393,26 @@ void SlideSorterModel::Resync (void) void SlideSorterModel::ClearDescriptorList (void) { - ::osl::MutexGuard aGuard (maMutex); + DescriptorContainer aDescriptors; + + { + ::osl::MutexGuard aGuard (maMutex); + aDescriptors.swap(maPageDescriptors); + } - // Clear the cache of page descriptors. - DescriptorContainer::iterator I; - for (I=maPageDescriptors.begin(); I!=maPageDescriptors.end(); I++) + for (DescriptorContainer::iterator iDescriptor=aDescriptors.begin(), iEnd=aDescriptors.end(); + iDescriptor!=iEnd; + ++iDescriptor) { - if (I->get() != NULL) + if (iDescriptor->get() != NULL) { - if ( ! I->unique()) + if ( ! iDescriptor->unique()) { - OSL_TRACE("SlideSorterModel::ClearDescriptorList: trying to delete page descriptor that is still used with count %d", I->use_count()); + OSL_TRACE("SlideSorterModel::ClearDescriptorList: trying to delete page descriptor that is still used with count %d", iDescriptor->use_count()); // No assertion here because that can hang the office when // opening a dialog from here. } - I->reset(); + iDescriptor->reset(); } } } @@ -283,44 +428,23 @@ void SlideSorterModel::SynchronizeDocumentSelection (void) while (aAllPages.HasMoreElements()) { SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); - pDescriptor->GetPage()->SetSelected (pDescriptor->IsSelected()); - } -} - -void SlideSorterModel::SetPageObjectFactory( - ::std::auto_ptr<controller::PageObjectFactory> pPageObjectFactory) -{ - ::osl::MutexGuard aGuard (maMutex); - - mpPageObjectFactory = pPageObjectFactory; - // When a NULL pointer was given then create a default factory. - const controller::PageObjectFactory& rFactory (GetPageObjectFactory()); - PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); - while (aAllPages.HasMoreElements()) - { - SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); - pDescriptor->SetPageObjectFactory(rFactory); + pDescriptor->GetPage()->SetSelected(pDescriptor->HasState(PageDescriptor::ST_Selected)); } } -const controller::PageObjectFactory& - SlideSorterModel::GetPageObjectFactory (void) const +void SlideSorterModel::SynchronizeModelSelection (void) { ::osl::MutexGuard aGuard (maMutex); - if (mpPageObjectFactory.get() == NULL) + PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aAllPages.HasMoreElements()) { - // We have to create a new factory. The pointer is mutable so we - // are alowed to do so. - mpPageObjectFactory = ::std::auto_ptr<controller::PageObjectFactory> ( - new controller::PageObjectFactory( - mrSlideSorter.GetView().GetPreviewCache(), - mrSlideSorter.GetController().GetProperties())); + SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + pDescriptor->SetState(PageDescriptor::ST_Selected, pDescriptor->GetPage()->IsSelected()); } - return *mpPageObjectFactory.get(); } @@ -340,7 +464,7 @@ void SlideSorterModel::SetDocumentSlides ( ::osl::MutexGuard aGuard (maMutex); // Reset the current page so to cause everbody to release references to it. - mrSlideSorter.GetController().GetCurrentSlideManager()->CurrentSlideHasChanged(-1); + mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(-1); mxSlides = rxSlides; Resync(); @@ -350,24 +474,27 @@ void SlideSorterModel::SetDocumentSlides ( { SdPage* pPage = pViewShell->getCurrentPage(); if (pPage != NULL) - mrSlideSorter.GetController().GetCurrentSlideManager()->CurrentSlideHasChanged( - GetIndex(Reference<drawing::XDrawPage>(pPage->getUnoPage(), UNO_QUERY))); + mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( + pPage); else { // No current page. This can only be when the slide sorter is // the main view shell. Get current slide form frame view. const FrameView* pFrameView = pViewShell->GetFrameView(); if (pFrameView != NULL) - mrSlideSorter.GetController().GetCurrentSlideManager()->CurrentSlideHasChanged( + mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( pFrameView->GetSelectedPage()); else { // No frame view. As a last resort use the first slide as // current slide. - mrSlideSorter.GetController().GetCurrentSlideManager()->CurrentSlideHasChanged(0); + mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( + sal_Int32(0)); } } } + + mrSlideSorter.GetController().GetSlotManager()->NotifyEditModeChange(); } @@ -439,4 +566,170 @@ void SlideSorterModel::AdaptSize (void) maPageDescriptors.resize(0); } + + + +bool SlideSorterModel::IsReadOnly (void) const +{ + if (mrSlideSorter.GetViewShellBase() != NULL + && mrSlideSorter.GetViewShellBase()->GetDocShell()) + return mrSlideSorter.GetViewShellBase()->GetDocShell()->IsReadOnly(); + else + return true; +} + + + + +void SlideSorterModel::SaveCurrentSelection (void) +{ + PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aPages.GetNextElement()); + pDescriptor->SetState( + PageDescriptor::ST_WasSelected, + pDescriptor->HasState(PageDescriptor::ST_Selected)); + } +} + + + + +Region SlideSorterModel::RestoreSelection (void) +{ + Region aRepaintRegion; + PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aPages.GetNextElement()); + if (pDescriptor->SetState( + PageDescriptor::ST_Selected, + pDescriptor->HasState(PageDescriptor::ST_WasSelected))) + { + aRepaintRegion.Union(pDescriptor->GetBoundingBox()); + } + } + return aRepaintRegion; +} + + + + +bool SlideSorterModel::NotifyPageEvent (const SdrPage* pSdrPage) +{ + ::osl::MutexGuard aGuard (maMutex); + + SdPage* pPage = const_cast<SdPage*>(dynamic_cast<const SdPage*>(pSdrPage)); + if (pPage == NULL) + return false; + + // We are only interested in pages that are currently served by this + // model. + if (pPage->GetPageKind() != mePageKind) + return false; + if (pPage->IsMasterPage() != (meEditMode==EM_MASTERPAGE)) + return false; + + if (pPage->IsInserted()) + InsertSlide(pPage); + else + DeleteSlide(pPage); + CheckModel(*this); + + return true; +} + + + + +void SlideSorterModel::InsertSlide (SdPage* pPage) +{ + // Find the index at which to insert the given page. + USHORT nCoreIndex (pPage->GetPageNum()); + sal_Int32 nIndex (FromCoreIndex(nCoreIndex)); + if (pPage != GetPage(nIndex)) + return; + + // Check that the pages in the document before and after the given page + // are present in this model. + if (nIndex>0) + if (GetPage(nIndex-1) != GetPageDescriptor(nIndex-1)->GetPage()) + return; + if (size_t(nIndex)<maPageDescriptors.size()-1) + if (GetPage(nIndex+1) != GetPageDescriptor(nIndex)->GetPage()) + return; + + // Insert the given page at index nIndex + maPageDescriptors.insert( + maPageDescriptors.begin()+nIndex, + SharedPageDescriptor( + new PageDescriptor ( + Reference<drawing::XDrawPage>(mxSlides->getByIndex(nIndex),UNO_QUERY), + pPage, + nIndex))); + + // Update page indices. + UpdateIndices(nIndex+1); + OSL_TRACE("page inserted"); +} + + + + +void SlideSorterModel::DeleteSlide (const SdPage* pPage) +{ + const sal_Int32 nIndex (GetIndex(pPage)); + if (maPageDescriptors[nIndex]) + if (maPageDescriptors[nIndex]->GetPage() != pPage) + return; + + maPageDescriptors.erase(maPageDescriptors.begin()+nIndex); + UpdateIndices(nIndex); + OSL_TRACE("page removed"); +} + + + + +void SlideSorterModel::UpdateIndices (const sal_Int32 nFirstIndex) +{ + for (sal_Int32 nDescriptorIndex=0,nCount=maPageDescriptors.size(); + nDescriptorIndex<nCount; + ++nDescriptorIndex) + { + SharedPageDescriptor& rpDescriptor (maPageDescriptors[nDescriptorIndex]); + if (rpDescriptor) + if (nDescriptorIndex < nFirstIndex) + { + if (rpDescriptor->GetPageIndex()!=nDescriptorIndex) + { + OSL_ASSERT(rpDescriptor->GetPageIndex()==nDescriptorIndex); + } + } + else + { + rpDescriptor->SetPageIndex(nDescriptorIndex); + } + } +} + + + + +SdPage* SlideSorterModel::GetPage (const sal_Int32 nSdIndex) const +{ + SdDrawDocument* pModel = const_cast<SlideSorterModel*>(this)->GetDocument(); + if (pModel != NULL) + { + if (meEditMode == EM_PAGE) + return pModel->GetSdPage ((USHORT)nSdIndex, mePageKind); + else + return pModel->GetMasterSdPage ((USHORT)nSdIndex, mePageKind); + } + else + return NULL; +} + + } } } // end of namespace ::sd::slidesorter::model diff --git a/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx b/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx index ffd93cbf0a13..24d744e459d6 100755..100644 --- a/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx +++ b/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx @@ -29,9 +29,6 @@ #include "precompiled_sd.hxx" #include "model/SlsPageDescriptor.hxx" -#include "view/SlsPageObject.hxx" -#include "view/SlsPageObjectViewObjectContact.hxx" -#include "controller/SlsPageObjectFactory.hxx" #include "sdpage.hxx" #include "drawdoc.hxx" @@ -39,31 +36,35 @@ #include <svx/svdopage.hxx> #include <svx/svdpagv.hxx> #include <svx/sdr/contact/viewcontact.hxx> +#include <svx/sdr/contact/viewobjectcontact.hxx> using namespace ::com::sun::star::uno; using namespace ::com::sun::star; namespace sd { namespace slidesorter { namespace model { + PageDescriptor::PageDescriptor ( const Reference<drawing::XDrawPage>& rxPage, SdPage* pPage, - const sal_Int32 nIndex, - const controller::PageObjectFactory& rPageObjectFactory) + const sal_Int32 nIndex) : mpPage(pPage), mxPage(rxPage), + mpMasterPage(NULL), mnIndex(nIndex), - mpPageObjectFactory(&rPageObjectFactory), - mpPageObject(NULL), + maBoundingBox(), + maVisualState(nIndex), mbIsSelected(false), + mbWasSelected(false), mbIsVisible(false), mbIsFocused(false), mbIsCurrent(false), - mpViewObjectContact(NULL), - maModelBorder(0,0,0,0), - maPageNumberAreaModelSize(0,0) + mbIsMouseOver(false) { + OSL_ASSERT(mpPage); OSL_ASSERT(mpPage == SdPage::getImplementation(rxPage)); + if (mpPage!=NULL && mpPage->TRG_HasMasterPage()) + mpMasterPage = &mpPage->TRG_GetMasterPage(); } @@ -92,48 +93,31 @@ Reference<drawing::XDrawPage> PageDescriptor::GetXDrawPage (void) const -view::PageObject* PageDescriptor::GetPageObject (void) +sal_Int32 PageDescriptor::GetPageIndex (void) const { - if (mpPageObject==NULL && mpPageObjectFactory!=NULL && mpPage != NULL) - { - mpPageObject = mpPageObjectFactory->CreatePageObject(mpPage, shared_from_this()); - } - - return mpPageObject; + return mnIndex; } -void PageDescriptor::ReleasePageObject (void) +void PageDescriptor::SetPageIndex (const sal_Int32 nNewIndex) { - mpPageObject = NULL; + mnIndex = nNewIndex; + maVisualState.mnPageId = nNewIndex; } -bool PageDescriptor::IsVisible (void) const +bool PageDescriptor::UpdateMasterPage (void) { - return mbIsVisible; -} - - - - -void PageDescriptor::SetVisible (bool bIsVisible) -{ - mbIsVisible = bIsVisible; -} - - - - -bool PageDescriptor::Select (void) -{ - if ( ! IsSelected()) + const SdrPage* pMaster = NULL; + if (mpPage!=NULL && mpPage->TRG_HasMasterPage()) + pMaster = &mpPage->TRG_GetMasterPage(); + if (mpMasterPage != pMaster) { - mbIsSelected = true; + mpMasterPage = pMaster; return true; } else @@ -143,137 +127,161 @@ bool PageDescriptor::Select (void) -bool PageDescriptor::Deselect (void) +bool PageDescriptor::HasState (const State eState) const { - if (IsSelected()) + switch (eState) { - mbIsSelected = false; - return true; - } - else - return false; -} + case ST_Visible: + return mbIsVisible; + case ST_Selected: + return mbIsSelected; + case ST_WasSelected: + return mbWasSelected; + case ST_Focused: + return mbIsFocused; -bool PageDescriptor::IsSelected (void) const -{ - return mbIsSelected; -} - + case ST_MouseOver: + return mbIsMouseOver; + case ST_Current: + return mbIsCurrent; + case ST_Excluded: + return mpPage!=NULL && mpPage->IsExcluded(); -bool PageDescriptor::UpdateSelection (void) -{ - if (mpPage!=NULL && (mpPage->IsSelected()==TRUE) != mbIsSelected) - { - mbIsSelected = ! mbIsSelected; - return true; + default: + OSL_ASSERT(false); + return false; } - else - return false; -} - - - - -bool PageDescriptor::IsFocused (void) const -{ - return mbIsFocused; -} - - - - -void PageDescriptor::SetFocus (void) -{ - mbIsFocused = true; -} - - - - -void PageDescriptor::RemoveFocus (void) -{ - mbIsFocused = false; -} - - - - -view::PageObjectViewObjectContact* - PageDescriptor::GetViewObjectContact (void) const -{ - return mpViewObjectContact; } -void PageDescriptor::SetViewObjectContact ( - view::PageObjectViewObjectContact* pViewObjectContact) +bool PageDescriptor::SetState (const State eState, const bool bNewStateValue) { - mpViewObjectContact = pViewObjectContact; -} - - - + bool bModified (false); + switch (eState) + { + case ST_Visible: + bModified = (bNewStateValue!=mbIsVisible); + if (bModified) + mbIsVisible = bNewStateValue; + break; + + case ST_Selected: + bModified = (bNewStateValue!=mbIsSelected); + if (bModified) + mbIsSelected = bNewStateValue; + break; + + case ST_WasSelected: + bModified = (bNewStateValue!=mbWasSelected); + if (bModified) + mbWasSelected = bNewStateValue; + break; + + case ST_Focused: + bModified = (bNewStateValue!=mbIsFocused); + if (bModified) + mbIsFocused = bNewStateValue; + break; + + case ST_MouseOver: + bModified = (bNewStateValue!=mbIsMouseOver); + if (bModified) + mbIsMouseOver = bNewStateValue; + break; + + case ST_Current: + bModified = (bNewStateValue!=mbIsCurrent); + if (bModified) + mbIsCurrent = bNewStateValue; + break; + + case ST_Excluded: + // This is a state of the page and has to be handled differently + // from the view-only states. + if (mpPage != NULL) + if (bNewStateValue != (mpPage->IsExcluded()==TRUE)) + { + mpPage->SetExcluded(bNewStateValue); + bModified = true; + } + break; + } -const controller::PageObjectFactory& - PageDescriptor::GetPageObjectFactory (void) const -{ - return *mpPageObjectFactory; + if (bModified) + maVisualState.UpdateVisualState(*this); + return bModified; } -void PageDescriptor::SetPageObjectFactory ( - const controller::PageObjectFactory& rFactory) +VisualState& PageDescriptor::GetVisualState (void) { - mpPageObjectFactory = &rFactory; + return maVisualState; } -void PageDescriptor::SetModelBorder (const SvBorder& rBorder) +bool PageDescriptor::GetCoreSelection (void) { - maModelBorder = rBorder; + if (mpPage!=NULL && (mpPage->IsSelected()==TRUE) != mbIsSelected) + return SetState(ST_Selected, !mbIsSelected); + else + return false; } -SvBorder PageDescriptor::GetModelBorder (void) const +void PageDescriptor::SetCoreSelection (void) { - return maModelBorder; + if (mpPage != NULL) + if (HasState(ST_Selected)) + mpPage->SetSelected(TRUE); + else + mpPage->SetSelected(FALSE); + else + { + OSL_ASSERT(mpPage!=NULL); + } } -void PageDescriptor::SetPageNumberAreaModelSize (const Size& rSize) +Rectangle PageDescriptor::GetBoundingBox (void) const { - maPageNumberAreaModelSize = rSize; + Rectangle aBox (maBoundingBox); + const Point aOffset (maVisualState.GetLocationOffset()); + aBox.Move(aOffset.X(), aOffset.Y()); + return aBox; } -Size PageDescriptor::GetPageNumberAreaModelSize (void) const +Point PageDescriptor::GetLocation (const bool bIgnoreOffset) const { - return maPageNumberAreaModelSize; + if (bIgnoreOffset) + return maBoundingBox.TopLeft(); + else + return maBoundingBox.TopLeft() + maVisualState.GetLocationOffset(); } -void PageDescriptor::SetIsCurrentPage (const bool bIsCurrent) +void PageDescriptor::SetBoundingBox (const Rectangle& rBoundingBox) { - mbIsCurrent = bIsCurrent; + maBoundingBox = rBoundingBox; } diff --git a/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx b/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx index c8c17e21819e..3a25989f084e 100644..100755 --- a/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx +++ b/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx @@ -56,7 +56,7 @@ class SelectedPagesPredicate public: bool operator() (const SharedPageDescriptor& rpDescriptor) { - return rpDescriptor->IsSelected(); + return rpDescriptor->HasState(PageDescriptor::ST_Selected); } }; @@ -68,7 +68,7 @@ class VisiblePagesPredicate public: bool operator() (const SharedPageDescriptor& rpDescriptor) { - return rpDescriptor->IsVisible(); + return rpDescriptor->HasState(PageDescriptor::ST_Visible); } }; diff --git a/sd/source/ui/slidesorter/model/SlsVisualState.cxx b/sd/source/ui/slidesorter/model/SlsVisualState.cxx new file mode 100644 index 000000000000..3dee5e914ab9 --- /dev/null +++ b/sd/source/ui/slidesorter/model/SlsVisualState.cxx @@ -0,0 +1,236 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "model/SlsVisualState.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "controller/SlsAnimator.hxx" + +namespace sd { namespace slidesorter { namespace model { + +VisualState::VisualState (const sal_Int32 nPageId) + : mnPageId(nPageId), + meCurrentVisualState(VS_None), + meOldVisualState(VS_None), + mnVisualStateBlend(1.0), + mnStateAnimationId(controller::Animator::NotAnAnimationId), + maLocationOffset(0,0), + mnLocationAnimationId(controller::Animator::NotAnAnimationId), + mnButtonAlpha(1.0), + mnButtonBarAlpha(1.0), + mnButtonAlphaAnimationId(controller::Animator::NotAnAnimationId) +{ +} + + + + +VisualState::~VisualState (void) +{ + if (mnStateAnimationId != controller::Animator::NotAnAnimationId + || mnLocationAnimationId != controller::Animator::NotAnAnimationId) + { + OSL_ASSERT(mnStateAnimationId == controller::Animator::NotAnAnimationId); + OSL_ASSERT(mnLocationAnimationId == controller::Animator::NotAnAnimationId); + } +} + + + + +VisualState::State VisualState::GetCurrentVisualState (void) const +{ + return meCurrentVisualState; +} + + + + +VisualState::State VisualState::GetOldVisualState (void) const +{ + return meOldVisualState; +} + + + + +void VisualState::SetVisualState (const State eState) +{ + meOldVisualState = meCurrentVisualState; + meCurrentVisualState = eState; + mnVisualStateBlend = 1.0; +} + + + + +double VisualState::GetVisualStateBlend (void) const +{ + return mnVisualStateBlend; +} + + + + +void VisualState::SetVisualStateBlend (const double nBlend) +{ + mnVisualStateBlend = nBlend; +} + + + + +void VisualState::UpdateVisualState (const PageDescriptor& rDescriptor) +{ + if (rDescriptor.HasState(PageDescriptor::ST_Excluded)) + SetVisualState(VS_Excluded); + else if (rDescriptor.HasState(PageDescriptor::ST_Current)) + SetVisualState(VS_Current); + else if (rDescriptor.HasState(PageDescriptor::ST_Focused)) + SetVisualState(VS_Focused); + else if (rDescriptor.HasState(PageDescriptor::ST_Selected)) + SetVisualState(VS_Selected); + else + SetVisualState(VS_None); + + SetMouseOverState(rDescriptor.HasState(PageDescriptor::ST_MouseOver)); +} + + + + +void VisualState::SetMouseOverState (const bool bIsMouseOver) +{ + mbOldMouseOverState = mbCurrentMouseOverState; + mbCurrentMouseOverState = bIsMouseOver; +} + + + + +sal_Int32 VisualState::GetStateAnimationId (void) const +{ + return mnStateAnimationId; +} + + + + +void VisualState::SetStateAnimationId (const sal_Int32 nAnimationId) +{ + mnStateAnimationId = nAnimationId; +} + + + + +Point VisualState::GetLocationOffset (void) const +{ + return maLocationOffset; +} + + + + +bool VisualState::SetLocationOffset (const Point& rOffset) +{ + if (maLocationOffset != rOffset) + { + maLocationOffset = rOffset; + return true; + } + else + return false; +} + + + + +sal_Int32 VisualState::GetLocationAnimationId (void) const +{ + return mnLocationAnimationId; +} + + + + +void VisualState::SetLocationAnimationId (const sal_Int32 nAnimationId) +{ + mnLocationAnimationId = nAnimationId; +} + + + + +double VisualState::GetButtonAlpha (void) const +{ + return mnButtonAlpha; +} + + + + +void VisualState::SetButtonAlpha (const double nAlpha) +{ + mnButtonAlpha = nAlpha; +} + + + + +double VisualState::GetButtonBarAlpha (void) const +{ + return mnButtonBarAlpha; +} + + + + +void VisualState::SetButtonBarAlpha (const double nAlpha) +{ + mnButtonBarAlpha = nAlpha; +} + + + + +sal_Int32 VisualState::GetButtonAlphaAnimationId (void) const +{ + return mnButtonAlphaAnimationId; +} + + + + +void VisualState::SetButtonAlphaAnimationId (const sal_Int32 nAnimationId) +{ + mnButtonAlphaAnimationId = nAnimationId; +} + + +} } } // end of namespace ::sd::slidesorter::model diff --git a/sd/source/ui/slidesorter/model/makefile.mk b/sd/source/ui/slidesorter/model/makefile.mk index 9c8979fe3767..0347d05a8100 100644..100755 --- a/sd/source/ui/slidesorter/model/makefile.mk +++ b/sd/source/ui/slidesorter/model/makefile.mk @@ -46,6 +46,7 @@ SLOFILES = \ $(SLO)$/SlsPageDescriptor.obj \ $(SLO)$/SlsPageEnumeration.obj \ $(SLO)$/SlsPageEnumerationProvider.obj \ + $(SLO)$/SlsVisualState.obj \ $(SLO)$/SlideSorterModel.obj EXCEPTIONSFILES= diff --git a/sd/source/ui/slidesorter/shell/SlideSorter.cxx b/sd/source/ui/slidesorter/shell/SlideSorter.cxx index 768dd5f9458a..c19c6c331d28 100644..100755 --- a/sd/source/ui/slidesorter/shell/SlideSorter.cxx +++ b/sd/source/ui/slidesorter/shell/SlideSorter.cxx @@ -33,7 +33,10 @@ #include "SlideSorterViewShell.hxx" #include "controller/SlideSorterController.hxx" #include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsAnimator.hxx" #include "view/SlideSorterView.hxx" +#include "view/SlsTheme.hxx" #include "model/SlideSorterModel.hxx" #include "glob.hrc" @@ -132,10 +135,13 @@ SlideSorter::SlideSorter ( mpViewShell(&rViewShell), mpViewShellBase(&rViewShell.GetViewShellBase()), mpContentWindow(rpContentWindow), + mbOwnesContentWindow(false), mpHorizontalScrollBar(rpHorizontalScrollBar), mpVerticalScrollBar(rpVerticalScrollBar), mpScrollBarBox(rpScrollBarBox), - mbLayoutPending(true) + mbLayoutPending(true), + mpProperties(new controller::Properties()), + mpTheme(new view::Theme(mpProperties)) { } @@ -154,10 +160,13 @@ SlideSorter::SlideSorter ( mpViewShell(pViewShell), mpViewShellBase(&rBase), mpContentWindow(new ContentWindow(rParentWindow,*this )), + mbOwnesContentWindow(true), mpHorizontalScrollBar(new ScrollBar(&rParentWindow,WinBits(WB_HSCROLL | WB_DRAG))), mpVerticalScrollBar(new ScrollBar(&rParentWindow,WinBits(WB_VSCROLL | WB_DRAG))), mpScrollBarBox(new ScrollBarBox(&rParentWindow)), - mbLayoutPending(true) + mbLayoutPending(true), + mpProperties(new controller::Properties()), + mpTheme(new view::Theme(mpProperties)) { } @@ -169,24 +178,37 @@ void SlideSorter::Init (void) if (mpViewShellBase != NULL) mxControllerWeak = mpViewShellBase->GetController(); + // Reinitialize colors in Properties with window specific values. + if (mpContentWindow) + { + mpProperties->SetBackgroundColor( + mpContentWindow->GetSettings().GetStyleSettings().GetWindowColor()); + mpProperties->SetTextColor( + mpContentWindow->GetSettings().GetStyleSettings().GetWindowTextColor()); + mpProperties->SetSelectionColor( + mpContentWindow->GetSettings().GetStyleSettings().GetMenuHighlightColor()); + mpProperties->SetHighlightColor( + mpContentWindow->GetSettings().GetStyleSettings().GetMenuHighlightColor()); + } + CreateModelViewController (); SetupListeners (); // Initialize the window. - ::sd::Window* pWindow = GetActiveWindow(); - if (pWindow != NULL) + SharedSdWindow pContentWindow (GetContentWindow()); + if (pContentWindow) { - ::Window* pParentWindow = pWindow->GetParent(); + ::Window* pParentWindow = pContentWindow->GetParent(); if (pParentWindow != NULL) pParentWindow->SetBackground(Wallpaper()); - pWindow->SetBackground(Wallpaper()); - pWindow->SetViewOrigin (Point(0,0)); + pContentWindow->SetBackground(Wallpaper()); + pContentWindow->SetViewOrigin (Point(0,0)); // We do our own scrolling while dragging a page selection. - pWindow->SetUseDropScroll (false); + pContentWindow->SetUseDropScroll (false); // Change the winbits so that the active window accepts the focus. - pWindow->SetStyle ((pWindow->GetStyle() & ~WB_DIALOGCONTROL) | WB_TABSTOP); - pWindow->Hide(); + pContentWindow->SetStyle ((pContentWindow->GetStyle() & ~WB_DIALOGCONTROL) | WB_TABSTOP); + pContentWindow->Hide(); // Set view pointer of base class. SetupControls(pParentWindow); @@ -204,6 +226,12 @@ SlideSorter::~SlideSorter (void) ReleaseListeners(); + // Dispose model, view and controller to avoid calls between them when + // they are being destructed and one or two of them are already gone. + mpSlideSorterController->Dispose(); + mpSlideSorterView->Dispose(); + mpSlideSorterModel->Dispose(); + // Reset the auto pointers explicitly to control the order of destruction. mpSlideSorterController.reset(); mpSlideSorterView.reset(); @@ -212,6 +240,17 @@ SlideSorter::~SlideSorter (void) mpHorizontalScrollBar.reset(); mpVerticalScrollBar.reset(); mpScrollBarBox.reset(); + + if (mbOwnesContentWindow) + { + OSL_ASSERT(mpContentWindow.unique()); + } + else + { + // Assume that outside this class only the owner holds a reference + // to the content window. + OSL_ASSERT(mpContentWindow.use_count()==2); + } mpContentWindow.reset(); } @@ -297,7 +336,7 @@ void SlideSorter::Paint (const Rectangle& rRepaintArea) -::boost::shared_ptr<sd::Window> SlideSorter::GetContentWindow (void) const +::SharedSdWindow SlideSorter::GetContentWindow (void) const { return mpContentWindow; } @@ -305,17 +344,6 @@ void SlideSorter::Paint (const Rectangle& rRepaintArea) -::sd::Window* SlideSorter::GetActiveWindow (void) const -{ - if (mpViewShell != NULL) - return mpViewShell->GetActiveWindow(); - else - return mpContentWindow.get(); -} - - - - ViewShellBase* SlideSorter::GetViewShellBase (void) const { return mpViewShellBase; @@ -343,8 +371,8 @@ void SlideSorter::SetupControls (::Window* ) void SlideSorter::SetupListeners (void) { - ::sd::Window* pWindow = GetActiveWindow(); - if (pWindow != NULL) + SharedSdWindow pWindow (GetContentWindow()); + if (pWindow) { ::Window* pParentWindow = pWindow->GetParent(); if (pParentWindow != NULL) @@ -375,10 +403,9 @@ void SlideSorter::ReleaseListeners (void) { mpSlideSorterController->GetScrollBarManager().Disconnect(); - ::sd::Window* pWindow = GetActiveWindow(); - if (pWindow != NULL) + SharedSdWindow pWindow (GetContentWindow()); + if (pWindow) { - pWindow->RemoveEventListener( LINK(mpSlideSorterController.get(), controller::SlideSorterController, @@ -413,7 +440,12 @@ void SlideSorter::CreateModelViewController (void) mpSlideSorterController.reset(CreateController()); DBG_ASSERT (mpSlideSorterController.get()!=NULL, "Can not create controller for slide browser"); + + // Now that model, view, and controller are constructed, do the + // initialization that relies on all three being in place. + mpSlideSorterModel->Init(); mpSlideSorterController->Init(); + mpSlideSorterView->Init(); } @@ -460,26 +492,21 @@ void SlideSorter::ArrangeGUIElements ( { Point aOrigin (rOffset); - if (rSize.Width()!=0 && rSize.Height()!=0) + if (rSize.Width()>0 + && rSize.Height()>0 + && GetContentWindow() + && GetContentWindow()->IsVisible()) { // Prevent untimely redraws while the view is not yet correctly // resized. - mpSlideSorterView->LockRedraw (TRUE); - if (GetActiveWindow() != NULL) - GetActiveWindow()->EnablePaint (FALSE); + view::SlideSorterView::DrawLock aLock (*this); + GetContentWindow()->EnablePaint (FALSE); - // maAllWindowRectangle = mpSlideSorterController->Resize (Rectangle(aOrigin, rSize)); - if (GetActiveWindow() != NULL) - GetActiveWindow()->EnablePaint (TRUE); + GetContentWindow()->EnablePaint (TRUE); mbLayoutPending = false; - mpSlideSorterView->LockRedraw (FALSE); - } - else - { - // maAllWindowRectangle = Rectangle(); } } @@ -506,6 +533,9 @@ SvBorder SlideSorter::GetBorder (void) bool SlideSorter::RelocateToWindow (::Window* pParentWindow) { + // Stop all animations for they have been started for the old window. + mpSlideSorterController->GetAnimator()->RemoveAllAnimations(); + ReleaseListeners(); if (mpViewShell != NULL) @@ -517,8 +547,8 @@ bool SlideSorter::RelocateToWindow (::Window* pParentWindow) // For accessibility we have to shortly hide the content window. This // triggers the construction of a new accessibility object for the new // view shell. (One is created earlier while the construtor of the base - // class is executed. At that time the correct accessibility object can - // not be constructed.) + // class is executed. But because at that time the correct + // accessibility object can not be constructed we do that now.) if (mpContentWindow.get() !=NULL) { mpContentWindow->Hide(); @@ -540,9 +570,8 @@ void SlideSorter::SetCurrentFunction (const FunctionReference& rpFunction) } else { - ::boost::shared_ptr<ContentWindow> pWindow - = ::boost::dynamic_pointer_cast<ContentWindow>(GetContentWindow()); - if (pWindow.get() != NULL) + ContentWindow* pWindow = dynamic_cast<ContentWindow*>(GetContentWindow().get()); + if (pWindow != NULL) pWindow->SetCurrentFunction(rpFunction); } } @@ -550,6 +579,24 @@ void SlideSorter::SetCurrentFunction (const FunctionReference& rpFunction) +::boost::shared_ptr<controller::Properties> SlideSorter::GetProperties (void) const +{ + OSL_ASSERT(mpProperties); + return mpProperties; +} + + + + +::boost::shared_ptr<view::Theme> SlideSorter::GetTheme (void) const +{ + OSL_ASSERT(mpTheme); + return mpTheme; +} + + + + //===== ContentWindow ========================================================= namespace { @@ -644,8 +691,10 @@ long ContentWindow::Notify (NotifyEvent& rEvent) - } // end of anonymous namespace + + + } } // end of namespace ::sd::slidesorter diff --git a/sd/source/ui/slidesorter/shell/SlideSorterService.cxx b/sd/source/ui/slidesorter/shell/SlideSorterService.cxx index 787086b4596e..89388734bf8c 100755 --- a/sd/source/ui/slidesorter/shell/SlideSorterService.cxx +++ b/sd/source/ui/slidesorter/shell/SlideSorterService.cxx @@ -34,6 +34,7 @@ #include "model/SlideSorterModel.hxx" #include "model/SlsPageDescriptor.hxx" #include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" #include "DrawController.hxx" #include <toolkit/helper/vclunohelper.hxx> #include <com/sun/star/beans/PropertyAttribute.hpp> @@ -46,7 +47,7 @@ using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::drawing::framework; using ::rtl::OUString; -using ::sd::slidesorter::view::SlideSorterView; +using ::sd::slidesorter::view::Layouter; namespace sd { namespace slidesorter { @@ -266,7 +267,7 @@ void SAL_CALL SlideSorterService::setCurrentPage(const Reference<drawing::XDrawP { ThrowIfDisposed(); if (mpSlideSorter.get() != NULL) - mpSlideSorter->GetController().GetCurrentSlideManager()->CurrentSlideHasChanged( + mpSlideSorter->GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( mpSlideSorter->GetModel().GetIndex(rxSlide)); } @@ -317,7 +318,7 @@ sal_Bool SAL_CALL SlideSorterService::getIsHighlightCurrentSlide (void) if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) return false; else - return mpSlideSorter->GetController().GetProperties()->IsHighlightCurrentSlide(); + return mpSlideSorter->GetProperties()->IsHighlightCurrentSlide(); } @@ -329,7 +330,7 @@ void SAL_CALL SlideSorterService::setIsHighlightCurrentSlide (sal_Bool bValue) ThrowIfDisposed(); if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) { - mpSlideSorter->GetController().GetProperties()->SetHighlightCurrentSlide(bValue); + mpSlideSorter->GetProperties()->SetHighlightCurrentSlide(bValue); controller::SlideSorterController::ModelChangeLock aLock (mpSlideSorter->GetController()); mpSlideSorter->GetController().HandleModelChange(); } @@ -345,7 +346,7 @@ sal_Bool SAL_CALL SlideSorterService::getIsShowSelection (void) if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) return false; else - return mpSlideSorter->GetController().GetProperties()->IsShowSelection(); + return mpSlideSorter->GetProperties()->IsShowSelection(); } @@ -356,7 +357,7 @@ void SAL_CALL SlideSorterService::setIsShowSelection (sal_Bool bValue) { ThrowIfDisposed(); if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) - mpSlideSorter->GetController().GetProperties()->SetShowSelection(bValue); + mpSlideSorter->GetProperties()->SetShowSelection(bValue); } @@ -369,7 +370,7 @@ sal_Bool SAL_CALL SlideSorterService::getIsShowFocus (void) if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) return false; else - return mpSlideSorter->GetController().GetProperties()->IsShowFocus(); + return mpSlideSorter->GetProperties()->IsShowFocus(); } @@ -380,7 +381,7 @@ void SAL_CALL SlideSorterService::setIsShowFocus (sal_Bool bValue) { ThrowIfDisposed(); if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) - mpSlideSorter->GetController().GetProperties()->SetShowFocus(bValue); + mpSlideSorter->GetProperties()->SetShowFocus(bValue); } @@ -393,7 +394,7 @@ sal_Bool SAL_CALL SlideSorterService::getIsCenterSelection (void) if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) return false; else - return mpSlideSorter->GetController().GetProperties()->IsCenterSelection(); + return mpSlideSorter->GetProperties()->IsCenterSelection(); } @@ -404,7 +405,7 @@ void SAL_CALL SlideSorterService::setIsCenterSelection (sal_Bool bValue) { ThrowIfDisposed(); if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) - mpSlideSorter->GetController().GetProperties()->SetCenterSelection(bValue); + mpSlideSorter->GetProperties()->SetCenterSelection(bValue); } @@ -417,7 +418,7 @@ sal_Bool SAL_CALL SlideSorterService::getIsSuspendPreviewUpdatesDuringFullScreen if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) return true; else - return mpSlideSorter->GetController().GetProperties() + return mpSlideSorter->GetProperties() ->IsSuspendPreviewUpdatesDuringFullScreenPresentation(); } @@ -430,7 +431,7 @@ void SAL_CALL SlideSorterService::setIsSuspendPreviewUpdatesDuringFullScreenPres { ThrowIfDisposed(); if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) - mpSlideSorter->GetController().GetProperties() + mpSlideSorter->GetProperties() ->SetSuspendPreviewUpdatesDuringFullScreenPresentation(bValue); } @@ -444,7 +445,7 @@ sal_Bool SAL_CALL SlideSorterService::getIsOrientationVertical (void) if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) return true; else - return mpSlideSorter->GetView().GetOrientation() == SlideSorterView::VERTICAL; + return mpSlideSorter->GetView().GetOrientation() != Layouter::HORIZONTAL; } @@ -456,8 +457,8 @@ void SAL_CALL SlideSorterService::setIsOrientationVertical (sal_Bool bValue) ThrowIfDisposed(); if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) mpSlideSorter->GetView().SetOrientation(bValue - ? SlideSorterView::VERTICAL - : SlideSorterView::HORIZONTAL); + ? Layouter::GRID + : Layouter::HORIZONTAL); } @@ -470,7 +471,7 @@ sal_Bool SAL_CALL SlideSorterService::getIsSmoothScrolling (void) if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) return false; else - return mpSlideSorter->GetController().GetProperties()->IsSmoothSelectionScrolling(); + return mpSlideSorter->GetProperties()->IsSmoothSelectionScrolling(); } @@ -481,7 +482,7 @@ void SAL_CALL SlideSorterService::setIsSmoothScrolling (sal_Bool bValue) { ThrowIfDisposed(); if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) - mpSlideSorter->GetController().GetProperties()->SetSmoothSelectionScrolling(bValue); + mpSlideSorter->GetProperties()->SetSmoothSelectionScrolling(bValue); } @@ -495,7 +496,7 @@ util::Color SAL_CALL SlideSorterService::getBackgroundColor (void) return util::Color(); else return util::Color( - mpSlideSorter->GetController().GetProperties()->GetBackgroundColor().GetColor()); + mpSlideSorter->GetProperties()->GetBackgroundColor().GetColor()); } @@ -506,8 +507,7 @@ void SAL_CALL SlideSorterService::setBackgroundColor (util::Color aBackgroundCol { ThrowIfDisposed(); if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) - mpSlideSorter->GetController().GetProperties()->SetBackgroundColor( - Color(aBackgroundColor)); + mpSlideSorter->GetProperties()->SetBackgroundColor(Color(aBackgroundColor)); } @@ -521,7 +521,7 @@ util::Color SAL_CALL SlideSorterService::getTextColor (void) return util::Color(); else return util::Color( - mpSlideSorter->GetController().GetProperties()->GetTextColor().GetColor()); + mpSlideSorter->GetProperties()->GetTextColor().GetColor()); } @@ -532,8 +532,7 @@ void SAL_CALL SlideSorterService::setTextColor (util::Color aTextColor) { ThrowIfDisposed(); if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) - mpSlideSorter->GetController().GetProperties()->SetTextColor( - Color(aTextColor)); + mpSlideSorter->GetProperties()->SetTextColor(Color(aTextColor)); } @@ -547,7 +546,7 @@ util::Color SAL_CALL SlideSorterService::getSelectionColor (void) return util::Color(); else return util::Color( - mpSlideSorter->GetController().GetProperties()->GetSelectionColor().GetColor()); + mpSlideSorter->GetProperties()->GetSelectionColor().GetColor()); } @@ -558,8 +557,7 @@ void SAL_CALL SlideSorterService::setSelectionColor (util::Color aSelectionColor { ThrowIfDisposed(); if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) - mpSlideSorter->GetController().GetProperties()->SetSelectionColor( - Color(aSelectionColor)); + mpSlideSorter->GetProperties()->SetSelectionColor(Color(aSelectionColor)); } @@ -573,7 +571,7 @@ util::Color SAL_CALL SlideSorterService::getHighlightColor (void) return util::Color(); else return util::Color( - mpSlideSorter->GetController().GetProperties()->GetHighlightColor().GetColor()); + mpSlideSorter->GetProperties()->GetHighlightColor().GetColor()); } @@ -584,8 +582,7 @@ void SAL_CALL SlideSorterService::setHighlightColor (util::Color aHighlightColor { ThrowIfDisposed(); if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) - mpSlideSorter->GetController().GetProperties()->SetHighlightColor( - Color(aHighlightColor)); + mpSlideSorter->GetProperties()->SetHighlightColor(Color(aHighlightColor)); } @@ -597,7 +594,7 @@ sal_Bool SAL_CALL SlideSorterService::getIsUIReadOnly (void) if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) return true; else - return mpSlideSorter->GetController().GetProperties()->IsUIReadOnly(); + return mpSlideSorter->GetProperties()->IsUIReadOnly(); } @@ -608,8 +605,7 @@ void SAL_CALL SlideSorterService::setIsUIReadOnly (sal_Bool bIsUIReadOnly) { ThrowIfDisposed(); if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) - mpSlideSorter->GetController().GetProperties()->SetUIReadOnly( - bIsUIReadOnly); + mpSlideSorter->GetProperties()->SetUIReadOnly(bIsUIReadOnly); } diff --git a/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx b/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx index 86ec4002cd02..f8e7e13cdd2b 100755 --- a/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx +++ b/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx @@ -39,6 +39,8 @@ #include "controller/SlsSlotManager.hxx" #include "controller/SlsCurrentSlideManager.hxx" #include "controller/SlsSelectionManager.hxx" +#include "controller/SlsSelectionFunction.hxx" +#include "controller/SlsProperties.hxx" #include "view/SlideSorterView.hxx" #include "view/SlsLayouter.hxx" #include "model/SlideSorterModel.hxx" @@ -97,8 +99,11 @@ TYPEINIT1(SlideSorterViewShell, ViewShell); SfxViewFrame* pFrame, ViewShellBase& rViewShellBase, ::Window* pParentWindow, - FrameView* pFrameViewArgument) + FrameView* pFrameViewArgument, + const bool bIsCenterPane) { + (void)bIsCenterPane; + ::boost::shared_ptr<SlideSorterViewShell> pViewShell; try { @@ -124,7 +129,8 @@ SlideSorterViewShell::SlideSorterViewShell ( ::Window* pParentWindow, FrameView* pFrameViewArgument) : ViewShell (pFrame, pParentWindow, rViewShellBase), - mpSlideSorter() + mpSlideSorter(), + mbIsArrangeGUIElementsPending(true) { meShellType = ST_SLIDE_SORTER; @@ -188,8 +194,8 @@ void SlideSorterViewShell::Initialize (void) // the new view shell. (One is created earlier while the construtor // of the base class is executed. At that time the correct // accessibility object can not be constructed.) - ::Window* pWindow = mpSlideSorter->GetActiveWindow(); - if (pWindow != NULL) + SharedSdWindow pWindow (mpSlideSorter->GetContentWindow()); + if (pWindow) { pWindow->Hide(); pWindow->Show(); @@ -299,8 +305,17 @@ SlideSorter& SlideSorterViewShell::GetSlideSorter (void) const bool SlideSorterViewShell::RelocateToParentWindow (::Window* pParentWindow) { - OSL_ASSERT(mpSlideSorter.get()!=NULL); - return mpSlideSorter->RelocateToWindow(pParentWindow); + OSL_ASSERT(mpSlideSorter); + if ( ! mpSlideSorter) + return false; + + if (pParentWindow == NULL) + WriteFrameViewData(); + const bool bSuccess (mpSlideSorter->RelocateToWindow(pParentWindow)); + if (pParentWindow != NULL) + ReadFrameViewData(mpFrameView); + + return bSuccess; } @@ -377,6 +392,11 @@ SdPage* SlideSorterViewShell::GetActualPage (void) pCurrentPage = pDescriptor->GetPage(); } + if (pCurrentPage == NULL) + { + + } + return pCurrentPage; } @@ -496,23 +516,13 @@ void SlideSorterViewShell::ExecStatusBar (SfxRequest& rRequest) -void SlideSorterViewShell::PrePaint() -{ - OSL_ASSERT(mpSlideSorter.get()!=NULL); - if (mpSlideSorter.get() != NULL) - mpSlideSorter->GetController().PrePaint(); -} - - - - void SlideSorterViewShell::Paint ( const Rectangle& rBBox, ::sd::Window* pWindow) { SetActiveWindow (pWindow); - OSL_ASSERT(mpSlideSorter.get()!=NULL); - if (mpSlideSorter.get() != NULL) + OSL_ASSERT(mpSlideSorter); + if (mpSlideSorter) mpSlideSorter->GetController().Paint(rBBox,pWindow); } @@ -521,10 +531,24 @@ void SlideSorterViewShell::Paint ( void SlideSorterViewShell::ArrangeGUIElements (void) { - OSL_ASSERT(mpSlideSorter.get()!=NULL); - mpSlideSorter->ArrangeGUIElements( - maViewPos, - maViewSize); + if (IsActive()) + { + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->ArrangeGUIElements(maViewPos, maViewSize); + mbIsArrangeGUIElementsPending = false; + } + else + mbIsArrangeGUIElementsPending = true; +} + + + + +void SlideSorterViewShell::Activate (BOOL bIsMDIActivate) +{ + ViewShell::Activate(bIsMDIActivate); + if (mbIsArrangeGUIElementsPending) + ArrangeGUIElements(); } @@ -559,28 +583,38 @@ void SlideSorterViewShell::ReadFrameViewData (FrameView* pFrameView) view::SlideSorterView& rView (mpSlideSorter->GetView()); USHORT nSlidesPerRow (pFrameView->GetSlidesPerRow()); - if (nSlidesPerRow == 0 || ! IsMainViewShell()) + if (nSlidesPerRow > 0 + && rView.GetOrientation() == view::Layouter::GRID + && IsMainViewShell()) { - // When a value of 0 (automatic) is given or the the slide - // sorter is displayed in a side pane then we ignore the value - // of the frame view and adapt the number of columns - // automatically to the window width. - rView.GetLayouter().SetColumnCount(1,5); - } - else rView.GetLayouter().SetColumnCount(nSlidesPerRow,nSlidesPerRow); + } + if (IsMainViewShell()) + mpSlideSorter->GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( + mpFrameView->GetSelectedPage()); mpSlideSorter->GetController().Rearrange(true); // DrawMode for 'main' window if (GetActiveWindow()->GetDrawMode() != pFrameView->GetDrawMode() ) GetActiveWindow()->SetDrawMode( pFrameView->GetDrawMode() ); } + + // When this slide sorter is not displayed in the main window then we do + // not share the same frame view and have to find other ways to acquire + // certain values. + if ( ! IsMainViewShell()) + { + ::boost::shared_ptr<ViewShell> pMainViewShell = GetViewShellBase().GetMainViewShell(); + if (pMainViewShell.get() != NULL) + mpSlideSorter->GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( + pMainViewShell->getCurrentPage()); + } } -void SlideSorterViewShell::WriteFrameViewData() +void SlideSorterViewShell::WriteFrameViewData (void) { OSL_ASSERT(mpSlideSorter.get()!=NULL); if (mpFrameView != NULL) @@ -595,9 +629,11 @@ void SlideSorterViewShell::WriteFrameViewData() SdPage* pActualPage = GetActualPage(); if (pActualPage != NULL) { + if (IsMainViewShell()) + mpFrameView->SetSelectedPage((pActualPage->GetPageNum()- 1) / 2); + // else // The slide sorter is not expected to switch the current page // other then by double clicks. That is handled seperatly. - // mpFrameView->SetSelectedPage((pActualPage->GetPageNum()- 1) / 2); } else { @@ -619,13 +655,13 @@ void SlideSorterViewShell::SetZoom (long int ) // the window. } + + + void SlideSorterViewShell::SetZoomRect (const Rectangle& rZoomRect) { OSL_ASSERT(mpSlideSorter.get()!=NULL); - Size aPageSize (mpSlideSorter->GetView().GetPageBoundingBox( - 0, - view::SlideSorterView::CS_MODEL, - view::SlideSorterView::BBT_SHAPE).GetSize()); + Size aPageSize (mpSlideSorter->GetView().GetLayouter().GetPageObjectSize()); Rectangle aRect(rZoomRect); diff --git a/sd/source/ui/slidesorter/shell/makefile.mk b/sd/source/ui/slidesorter/shell/makefile.mk index 94209c34dc2b..94209c34dc2b 100644..100755 --- a/sd/source/ui/slidesorter/shell/makefile.mk +++ b/sd/source/ui/slidesorter/shell/makefile.mk diff --git a/sd/source/ui/slidesorter/view/SlideSorterView.cxx b/sd/source/ui/slidesorter/view/SlideSorterView.cxx index d2c2310329a6..f3637e55e63c 100755..100644 --- a/sd/source/ui/slidesorter/view/SlideSorterView.cxx +++ b/sd/source/ui/slidesorter/view/SlideSorterView.cxx @@ -34,11 +34,14 @@ #include "SlideSorterViewShell.hxx" #include "ViewShell.hxx" #include "SlsViewCacheContext.hxx" +#include "SlsLayeredDevice.hxx" #include "view/SlsLayouter.hxx" -#include "view/SlsViewOverlay.hxx" -#include "view/SlsPageObjectViewObjectContact.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsPageObjectPainter.hxx" +#include "view/SlsILayerPainter.hxx" +#include "view/SlsButtonBar.hxx" +#include "view/SlsToolTip.hxx" #include "controller/SlideSorterController.hxx" -#include "controller/SlsPageObjectFactory.hxx" #include "controller/SlsProperties.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageEnumerationProvider.hxx" @@ -46,10 +49,9 @@ #include "cache/SlsPageCache.hxx" #include "cache/SlsPageCacheManager.hxx" #include "cache/SlsCacheContext.hxx" -#include "view/SlsPageObject.hxx" -#include "view/SlsPageObjectViewObjectContact.hxx" #include "taskpane/SlideSorterCacheDisplay.hxx" #include "DrawDocShell.hxx" +#include "PaneDockingWindow.hxx" #include "drawdoc.hxx" #include "sdpage.hxx" @@ -62,60 +64,135 @@ #include <svx/svdopage.hxx> #include <svx/xlndsit.hxx> #include <svx/xlnclit.hxx> -#include <com/sun/star/presentation/FadeEffect.hpp> #include <vcl/svapp.hxx> +#include <vcl/scrbar.hxx> #include <tools/poly.hxx> #include <vcl/lineinfo.hxx> #include <algorithm> -#include <svx/sdr/contact/objectcontact.hxx> #include <svx/sdrpagewindow.hxx> #include <svl/itempool.hxx> -#include <svl/itempool.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <canvas/elapsedtime.hxx> +//#define DEBUG_TIMING +#include <svl/itempool.hxx> +#ifdef DEBUG_TIMING +#include <vector> +#endif #include <boost/foreach.hpp> + using namespace std; using namespace ::sd::slidesorter::model; +using namespace ::drawinglayer::primitive2d; + namespace sd { namespace slidesorter { namespace view { -TYPEINIT1(SlideSorterView, ::sd::View); +namespace { + /** Wrapper around the SlideSorterView that supports the IPainter + interface and that allows the LayeredDevice to hold the + SlideSorterView (held as scoped_ptr by the SlideSorter) as + shared_ptr. + */ + class Painter : public ILayerPainter + { + public: + Painter (SlideSorterView& rView) : mrView(rView) {} + virtual ~Painter (void) {} + + virtual void Paint (OutputDevice& rDevice, const Rectangle& rRepaintArea) + { + mrView.Paint(rDevice,rRepaintArea); + } + + virtual void SetLayerInvalidator (const SharedILayerInvalidator&) {} + + private: + SlideSorterView& mrView; + }; +} + + + +class BackgroundPainter + : public ILayerPainter, + public ::boost::noncopyable +{ +public: + BackgroundPainter (const Color aBackgroundColor) : maBackgroundColor(aBackgroundColor) {} + virtual ~BackgroundPainter (void) {} + + virtual void Paint (OutputDevice& rDevice, const Rectangle& rRepaintArea) + { + rDevice.SetFillColor(maBackgroundColor); + rDevice.SetLineColor(); + rDevice.DrawRect(rRepaintArea); + } + + virtual void SetLayerInvalidator (const SharedILayerInvalidator&) {} + + void SetColor (const Color aColor) { maBackgroundColor = aColor; } + +private: + Color maBackgroundColor; +}; + +TYPEINIT1(SlideSorterView, ::sd::View); + SlideSorterView::SlideSorterView (SlideSorter& rSlideSorter) : ::sd::View ( - rSlideSorter.GetModel().GetDocument(), - NULL, - rSlideSorter.GetViewShell()), - mrSlideSorter(rSlideSorter), - mrModel(rSlideSorter.GetModel()), - maPageModel(), - mpPage(new SdrPage(maPageModel)), - mpLayouter (new Layouter ()), - mbPageObjectVisibilitiesValid (false), - mpPreviewCache(), - mpViewOverlay (new ViewOverlay(rSlideSorter)), - mnFirstVisiblePageIndex(0), - mnLastVisiblePageIndex(-1), - mbModelChangedWhileModifyEnabled(true), - maPreviewSize(0,0), - mbPreciousFlagUpdatePending(true), - maPageNumberAreaModelSize(0,0), - maModelBorder(), - meOrientation(VERTICAL) + rSlideSorter.GetModel().GetDocument(), + rSlideSorter.GetContentWindow().get(), + rSlideSorter.GetViewShell()), + mrSlideSorter(rSlideSorter), + mrModel(rSlideSorter.GetModel()), + mbIsDisposed(false), + mpLayouter (new Layouter(rSlideSorter.GetContentWindow(), rSlideSorter.GetTheme())), + mbPageObjectVisibilitiesValid (false), + mpPreviewCache(), + mpLayeredDevice(new LayeredDevice(rSlideSorter.GetContentWindow())), + maVisiblePageRange(-1,-1), + mbModelChangedWhileModifyEnabled(true), + maPreviewSize(0,0), + mbPreciousFlagUpdatePending(true), + meOrientation(Layouter::GRID), + mpProperties(rSlideSorter.GetProperties()), + mpPageUnderMouse(), + mnButtonUnderMouse(-1), + mpPageObjectPainter(), + mpSelectionPainter(), + mpBackgroundPainter( + new BackgroundPainter(mrSlideSorter.GetTheme()->GetColor(Theme::Color_Background))), + mpButtonBar(new ButtonBar(mrSlideSorter)), + mpToolTip(new ToolTip(mrSlideSorter)), + mbIsRearrangePending(true), + maVisibilityChangeListeners() { // Hide the page that contains the page objects. SetPageVisible (FALSE); - // call FreezeIdRanges() at the pool from the newly constructed SdrModel, - // else creating SfxItemSets on it will complain - maPageModel.GetItemPool().FreezeIdRanges(); - // add the page to the model (no, this is NOT done by the constructor :-( ) - maPageModel.InsertPage(mpPage); + // Register the background painter on level 1 to avoid the creation of a + // background buffer. + mpLayeredDevice->RegisterPainter(mpBackgroundPainter, 1); + + // Wrap a shared_ptr-held-wrapper around this view and register it as + // painter at the layered device. There is no explicit destruction: in + // the SlideSorterView destructor the layered device is destroyed and + // with it the only reference to the wrapper which therefore is also + // destroyed. + SharedILayerPainter pPainter (new Painter(*this)); - // show page - LocalModelHasChanged(); + // The painter is placed on level 1 to avoid buffering. This should be + // a little faster during animations because the previews are painted + // directly into the window, not via the buffer. + mpLayeredDevice->RegisterPainter(pPainter, 1); } @@ -123,41 +200,57 @@ SlideSorterView::SlideSorterView (SlideSorter& rSlideSorter) SlideSorterView::~SlideSorterView (void) { - // Inform the contact objects to disconnect from the preview cache. - // Otherwise each dying contact object invalidates its preview. When - // the previews are kept for a later re-use than this invalidation is - // not wanted. - ::boost::shared_ptr<cache::PageCache> pEmptyCache; - model::PageEnumeration aPageEnumeration ( - model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); - while (aPageEnumeration.HasMoreElements()) + if ( ! mbIsDisposed) { - view::PageObjectViewObjectContact* pContact - = aPageEnumeration.GetNextElement()->GetViewObjectContact(); - if (pContact != NULL) - pContact->SetCache(pEmptyCache); + OSL_ASSERT(mbIsDisposed); + Dispose(); } +} + + + + +void SlideSorterView::Init (void) +{ + HandleModelChange(); +} + + + + +void SlideSorterView::Dispose (void) +{ + mpSelectionPainter.reset(); + + mpLayeredDevice->Dispose(); mpPreviewCache.reset(); - // hide the page to avoid problems in the view when deleting + SetPageUnderMouse(SharedPageDescriptor(),false); + + // Hide the page to avoid problems in the view when deleting // visualized objects HideSdrPage(); // Deletion of the objects and the page will be done in SdrModel // destructor (as long as objects and pages are added) + + OSL_ASSERT(mpLayeredDevice.unique()); + mpLayeredDevice.reset(); + + mbIsDisposed = true; } -sal_Int32 SlideSorterView::GetPageIndexAtPoint (const Point& rPosition) const +sal_Int32 SlideSorterView::GetPageIndexAtPoint (const Point& rWindowPosition) const { sal_Int32 nIndex (-1); - ::sd::Window* pWindow = GetWindow(); - if (pWindow != NULL) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) { - nIndex = mpLayouter->GetIndexAtPoint (pWindow->PixelToLogic (rPosition)); + nIndex = mpLayouter->GetIndexAtPoint(pWindow->PixelToLogic(rWindowPosition), false, false); // Clip the page index against the page count. if (nIndex >= mrModel.GetPageCount()) @@ -180,12 +273,8 @@ Layouter& SlideSorterView::GetLayouter (void) void SlideSorterView::ModelHasChanged (void) { - if (mbModelChangedWhileModifyEnabled) - { - controller::SlideSorterController::ModelChangeLock alock( mrSlideSorter.GetController() ); - mrSlideSorter.GetController().HandleModelChange(); - LocalModelHasChanged(); - } + // Ignore this call. Rely on hints sent by the model to get informed of + // model changes. } @@ -197,16 +286,6 @@ void SlideSorterView::LocalModelHasChanged(void) // First call our base class. View::ModelHasChanged (); - - // Then re-set the page as current page that contains the page objects. - ShowSdrPage(mpPage); - - // Initialize everything that depends on a page view, now that we have - // one. - // SetApplicationDocumentColor( - // Application::GetSettings().GetStyleSettings().GetWindowColor()); - - UpdatePageBorders(); } @@ -214,19 +293,8 @@ void SlideSorterView::LocalModelHasChanged(void) void SlideSorterView::PreModelChange (void) { - // Reset the slide under the mouse. It will be set to the correct slide - // on the next mouse motion. - GetOverlay().GetMouseOverIndicatorOverlay().SetSlideUnderMouse(SharedPageDescriptor()); - - // Tell the page descriptors of the model that the page objects do not - // exist anymore. - model::PageEnumeration aPageEnumeration ( - model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); - while (aPageEnumeration.HasMoreElements()) - aPageEnumeration.GetNextElement()->ReleasePageObject(); - - // Remove all page objects from the page. - mpPage->Clear(); + // Reset the slide under the mouse. It will be re-set in PostModelChange(). + SetPageUnderMouse(SharedPageDescriptor()); } @@ -240,16 +308,10 @@ void SlideSorterView::PostModelChange (void) model::PageEnumeration aPageEnumeration ( model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); - UpdatePageBorders(); - while (aPageEnumeration.HasMoreElements()) - { - SdrPageObj* pPageObject = aPageEnumeration.GetNextElement()->GetPageObject(); - if (pPageObject != NULL) - AddSdrObject(*pPageObject); - } // The new page objects have to be scaled and positioned. - Layout (); + RequestRearrange(); + RequestRepaint(); } @@ -271,18 +333,30 @@ void SlideSorterView::HandleModelChange (void) void SlideSorterView::HandleDrawModeChange (void) { - UpdatePageBorders(); - // Replace the preview cache with a new and empty one. The // PreviewRenderer that is used by the cache is replaced by this as // well. mpPreviewCache.reset(); GetPreviewCache()->InvalidateCache(true); - mrModel.SetPageObjectFactory( - ::std::auto_ptr<controller::PageObjectFactory>( - new controller::PageObjectFactory( - GetPreviewCache(), - mrSlideSorter.GetController().GetProperties()))); + + RequestRepaint(); +} + + + + +void SlideSorterView::HandleDataChangeEvent (void) +{ + GetPageObjectPainter()->SetTheme(mrSlideSorter.GetTheme()); + + // Update the color used by the background painter. + ::boost::shared_ptr<BackgroundPainter> pPainter ( + ::boost::dynamic_pointer_cast<BackgroundPainter>(mpBackgroundPainter)); + if (pPainter) + pPainter->SetColor(mrSlideSorter.GetTheme()->GetColor(Theme::Color_Background)); + + if (mpButtonBar) + mpButtonBar->HandleDataChangeEvent(); RequestRepaint(); } @@ -292,31 +366,120 @@ void SlideSorterView::HandleDrawModeChange (void) void SlideSorterView::Resize (void) { - ::sd::Window* pWindow = GetWindow(); - if (mrModel.GetPageCount()>0 && pWindow != NULL) + UpdateOrientation(); + + mpLayeredDevice->Resize(); + RequestRearrange(); +} + + + + +void SlideSorterView::RequestRearrange (void) +{ + mbIsRearrangePending = true; + Rearrange(); +} + + + + +void SlideSorterView::Rearrange (void) +{ + if ( ! mbIsRearrangePending) + return; + if (mrModel.GetPageCount() <= 0) + return; + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if ( ! pWindow) + return; + const Size aWindowSize (pWindow->GetSizePixel()); + if (aWindowSize.Width()<=0 || aWindowSize.Height()<=0) + return; + + const bool bRearrangeSuccess ( + mpLayouter->Rearrange ( + meOrientation, + aWindowSize, + mrModel.GetPageDescriptor(0)->GetPage()->GetSize(), + mrModel.GetPageCount())); + if (bRearrangeSuccess) + { + mbIsRearrangePending = false; + Layout(); + UpdatePageUnderMouse(false); + // RequestRepaint(); + } +} + + + + +void SlideSorterView::UpdateOrientation (void) +{ + // The layout of slides depends on whether the slide sorter is + // displayed in the center or the side pane. + if (mrSlideSorter.GetViewShell()->IsMainViewShell()) + SetOrientation(Layouter::GRID); + else { - UpdatePageBorders(); - bool bRearrangeSuccess (false); - if (meOrientation == HORIZONTAL) + // Get access to the docking window. + ::Window* pWindow = mrSlideSorter.GetContentWindow().get(); + PaneDockingWindow* pDockingWindow = NULL; + while (pWindow!=NULL && pDockingWindow==NULL) { - bRearrangeSuccess = mpLayouter->RearrangeHorizontal ( - pWindow->GetSizePixel(), - mrModel.GetPageDescriptor(0)->GetPage()->GetSize(), - pWindow, - mrModel.GetPageCount()); + pDockingWindow = dynamic_cast<PaneDockingWindow*>(pWindow); + pWindow = pWindow->GetParent(); } - else + + if (pDockingWindow != NULL) { - bRearrangeSuccess = mpLayouter->RearrangeVertical ( - pWindow->GetSizePixel(), - mrModel.GetPageDescriptor(0)->GetPage()->GetSize(), - pWindow); + const long nScrollBarSize ( + Application::GetSettings().GetStyleSettings().GetScrollBarSize()); + switch (pDockingWindow->GetOrientation()) + { + case PaneDockingWindow::HorizontalOrientation: + if (SetOrientation(Layouter::HORIZONTAL)) + { + const Range aRange (mpLayouter->GetValidVerticalSizeRange()); + pDockingWindow->SetValidSizeRange(Range( + aRange.Min() + nScrollBarSize, + aRange.Max() + nScrollBarSize)); + } + break; + + case PaneDockingWindow::VerticalOrientation: + if (SetOrientation(Layouter::VERTICAL)) + { + const Range aRange (mpLayouter->GetValidHorizontalSizeRange()); + pDockingWindow->SetValidSizeRange(Range( + aRange.Min() + nScrollBarSize, + aRange.Max() + nScrollBarSize)); + } + break; + + case PaneDockingWindow::UnknownOrientation: + if (SetOrientation(Layouter::GRID)) + { + const sal_Int32 nAdditionalSize (10); + pDockingWindow->SetMinOutputSizePixel(Size( + mpLayouter->GetValidHorizontalSizeRange().Min() + + nScrollBarSize + + nAdditionalSize, + mpLayouter->GetValidVerticalSizeRange().Min() + + nScrollBarSize + + nAdditionalSize)); + } + return; + } } - - if (bRearrangeSuccess) + else { - Layout(); - pWindow->Invalidate(); + // We are not placed in a docking window. One possible reason + // is that the slide sorter is temporarily into a cache and was + // reparented to a non-docking window. + SetOrientation(Layouter::GRID); } } } @@ -326,38 +489,40 @@ void SlideSorterView::Resize (void) void SlideSorterView::Layout () { - ::sd::Window* pWindow = GetWindow(); - if (pWindow != NULL) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) { // Set the model area, i.e. the smallest rectangle that includes all // page objects. - Rectangle aViewBox (mpLayouter->GetPageBox(mrModel.GetPageCount())); + const Rectangle aViewBox (mpLayouter->GetTotalBoundingBox()); pWindow->SetViewOrigin (aViewBox.TopLeft()); pWindow->SetViewSize (aViewBox.GetSize()); - Size aPageObjectPixelSize (pWindow->LogicToPixel(mpLayouter->GetPageObjectSize())); - if (maPreviewSize != aPageObjectPixelSize && mpPreviewCache.get()!=NULL) + ::boost::shared_ptr<PageObjectLayouter> pPageObjectLayouter( + mpLayouter->GetPageObjectLayouter()); + if (pPageObjectLayouter) { - mpPreviewCache->ChangeSize(aPageObjectPixelSize); - maPreviewSize = aPageObjectPixelSize; + const Size aNewPreviewSize (mpLayouter->GetPageObjectLayouter()->GetSize( + PageObjectLayouter::Preview, + PageObjectLayouter::WindowCoordinateSystem)); + if (maPreviewSize != aNewPreviewSize && GetPreviewCache()) + { + mpPreviewCache->ChangeSize(aNewPreviewSize, true); + maPreviewSize = aNewPreviewSize; + } } // Iterate over all page objects and place them relative to the // containing page. model::PageEnumeration aPageEnumeration ( model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); - int nIndex = 0; while (aPageEnumeration.HasMoreElements()) { model::SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement()); - SdrPageObj* pPageObject = pDescriptor->GetPageObject(); - Rectangle aPageObjectBox (mpLayouter->GetPageObjectBox (nIndex)); - pPageObject->SetSnapRect(aPageObjectBox); - - nIndex += 1; + pDescriptor->SetBoundingBox(mpLayouter->GetPageObjectBox(pDescriptor->GetPageIndex())); } - // Set the page so that it encloses all page objects. - mpPage->SetSize (aViewBox.GetSize()); + + GetPageObjectPainter()->NotifyResize(); } InvalidatePageObjectVisibilities (); @@ -376,71 +541,56 @@ void SlideSorterView::InvalidatePageObjectVisibilities (void) void SlideSorterView::DeterminePageObjectVisibilities (void) { - ::sd::Window* pWindow = GetWindow(); - if (pWindow != NULL) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) { // Set this flag to true here so that an invalidate during the // visibility calculation can correctly invalidate it again. mbPageObjectVisibilitiesValid = true; - Rectangle aViewArea ( - Point(0,0), - pWindow->GetSizePixel()); - aViewArea = pWindow->PixelToLogic (aViewArea); - int nFirstIndex = - mpLayouter->GetIndexOfFirstVisiblePageObject (aViewArea); - int nLastIndex = - mpLayouter->GetIndexOfLastVisiblePageObject (aViewArea); + Rectangle aViewArea (pWindow->PixelToLogic(Rectangle(Point(0,0),pWindow->GetSizePixel()))); + const Range aRange (mpLayouter->GetRangeOfVisiblePageObjects(aViewArea)); + const Range aUnion( + ::std::min(maVisiblePageRange.Min(), aRange.Min()), + ::std::max(maVisiblePageRange.Max(), aRange.Max())); // For page objects that just dropped off the visible area we // decrease the priority of pending requests for preview bitmaps. - - int nMinIndex = ::std::min (mnFirstVisiblePageIndex, nFirstIndex); - int nMaxIndex = ::std::max (mnLastVisiblePageIndex, nLastIndex); - if (mnFirstVisiblePageIndex!=nFirstIndex || mnLastVisiblePageIndex!=nLastIndex) + if (maVisiblePageRange != aRange) mbPreciousFlagUpdatePending |= true; + model::SharedPageDescriptor pDescriptor; - view::PageObjectViewObjectContact* pContact; - for (int nIndex=nMinIndex; nIndex<=nMaxIndex; nIndex++) + for (int nIndex=aUnion.Min(); nIndex<=aUnion.Max(); nIndex++) { - // Determine the visibility before and after the change so that - // we can handle the page objects for which the visibility has - // changed. - bool bWasVisible = nIndex>=mnFirstVisiblePageIndex - && nIndex<=mnLastVisiblePageIndex; - bool bIsVisible = nIndex>=nFirstIndex && nIndex<=nLastIndex; - - // Get the view-object-contact. - if (bWasVisible != bIsVisible) - { - pContact = NULL; - pDescriptor = mrModel.GetPageDescriptor(nIndex); - if (pDescriptor.get() != NULL) - pContact = pDescriptor->GetViewObjectContact(); - - if (pDescriptor.get() != NULL) - pDescriptor->SetVisible(bIsVisible); - } - + pDescriptor = mrModel.GetPageDescriptor(nIndex); + if (pDescriptor.get() != NULL) + SetState( + pDescriptor, + PageDescriptor::ST_Visible, + aRange.IsInside(nIndex)); } - if (mnFirstVisiblePageIndex != nFirstIndex - || mnLastVisiblePageIndex != nLastIndex) + // Broadcast a change of the set of visible page objects. + if (maVisiblePageRange != aRange) { - mnFirstVisiblePageIndex = nFirstIndex; - mnLastVisiblePageIndex = nLastIndex; + maVisiblePageRange = aRange; - // Tell the listeners that the visibility of some objects has changed. - ::std::vector<Link> aChangeListeners (maVisibilityChangeListeners); + // Tell the listeners that the visibility of some objects has + // changed. + ::std::vector<Link>& aChangeListeners (maVisibilityChangeListeners); for (::std::vector<Link>::const_iterator - iListener=aChangeListeners.begin(), - iEnd=aChangeListeners.end(); - iListener!=iEnd; - ++iListener) + iLink(aChangeListeners.begin()), + iEnd(aChangeListeners.end()); + iLink!=iEnd; + ++iLink) { - iListener->Call(NULL); + iLink->Call(NULL); } } + + + // Restore the mouse over state. + UpdatePageUnderMouse(true); } } @@ -464,9 +614,9 @@ void SlideSorterView::UpdatePreciousFlags (void) { pCache->SetPreciousFlag( pDescriptor->GetPage(), - (nIndex>=mnFirstVisiblePageIndex && nIndex<=mnLastVisiblePageIndex)); + maVisiblePageRange.IsInside(nIndex)); SSCD_SET_VISIBILITY(mrModel.GetDocument(), nIndex, - (nIndex>=mnFirstVisiblePageIndex && nIndex<=mnLastVisiblePageIndex)); + maVisiblePageRange.IsInside(nIndex)); } else { @@ -482,16 +632,21 @@ void SlideSorterView::UpdatePreciousFlags (void) -void SlideSorterView::SetOrientation (const Orientation eOrientation) +bool SlideSorterView::SetOrientation (const Layouter::Orientation eOrientation) { - meOrientation = eOrientation; - RequestRepaint(); + if (meOrientation != eOrientation) + { + meOrientation = eOrientation; + return true; + } + else + return false; } -SlideSorterView::Orientation SlideSorterView::GetOrientation (void) const +Layouter::Orientation SlideSorterView::GetOrientation (void) const { return meOrientation; } @@ -501,9 +656,15 @@ SlideSorterView::Orientation SlideSorterView::GetOrientation (void) const void SlideSorterView::RequestRepaint (void) { - ::sd::Window* pWindow = GetWindow(); - if (pWindow != NULL) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + mpLayeredDevice->InvalidateAllLayers( + Rectangle( + pWindow->PixelToLogic(Point(0,0)), + pWindow->PixelToLogic(pWindow->GetSizePixel()))); pWindow->Invalidate(); + } } @@ -511,197 +672,230 @@ void SlideSorterView::RequestRepaint (void) void SlideSorterView::RequestRepaint (const model::SharedPageDescriptor& rpDescriptor) { - ::sd::Window* pWindow = GetWindow(); - if (pWindow != NULL) - pWindow->Invalidate( - GetPageBoundingBox ( - rpDescriptor, - CS_MODEL, - BBT_INFO)); + if (rpDescriptor) + RequestRepaint(rpDescriptor->GetBoundingBox()); } -Rectangle SlideSorterView::GetModelArea (void) +void SlideSorterView::RequestRepaint (const Rectangle& rRepaintBox) { - return Rectangle ( - Point (0,0), - Size (mpPage->GetSize().Width(),mpPage->GetSize().Height())); + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + mpLayeredDevice->InvalidateAllLayers(rRepaintBox); + pWindow->Invalidate(rRepaintBox); + } } - -Rectangle SlideSorterView::GetPageBoundingBox ( - const model::SharedPageDescriptor& rpDescriptor, - CoordinateSystem eCoordinateSystem, - BoundingBoxType eBoundingBoxType) const +void SlideSorterView::RequestRepaint (const Region& rRepaintRegion) { - Rectangle aBBox; - SdrObject* pPageObject = rpDescriptor->GetPageObject(); - if (pPageObject != NULL) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) { - aBBox = pPageObject->GetCurrentBoundRect(); - AdaptBoundingBox (aBBox, eCoordinateSystem, eBoundingBoxType); + mpLayeredDevice->InvalidateAllLayers(rRepaintRegion); + pWindow->Invalidate(rRepaintRegion); } - - return aBBox; } -Rectangle SlideSorterView::GetPageBoundingBox ( - sal_Int32 nIndex, - CoordinateSystem eCoordinateSystem, - BoundingBoxType eBoundingBoxType) const +Rectangle SlideSorterView::GetModelArea (void) { - Rectangle aBBox; - if (nIndex >= 0 && nIndex<mrModel.GetPageCount()) + return mpLayouter->GetTotalBoundingBox(); +} + + +#ifdef DEBUG_TIMING +static ::canvas::tools::ElapsedTime gaTimer; +static const size_t gFrameTimeCount (10); +static size_t gFrameTimeIndex (0); +static ::std::vector<double> gFrameTimes (gFrameTimeCount, 0); +static double gFrameTimeSum (0); +static const Rectangle gFrameTimeBox (10,10,150,20); +static double gnLastFrameStart = 0; +#endif + +void SlideSorterView::CompleteRedraw ( + OutputDevice* pDevice, + const Region& rPaintArea, + sdr::contact::ViewObjectContactRedirector* pRedirector) +{ + (void)pRedirector; +#ifdef DEBUG_TIMING + const double nStartTime (gaTimer.getElapsedTime()); + OSL_TRACE("SlideSorterView::CompleteRedraw start at %f, %s", + nStartTime, + mnLockRedrawSmph ? "locked" : ""); +#endif + + if (pDevice == NULL || pDevice!=mrSlideSorter.GetContentWindow().get()) + return; + + // The parent implementation of CompleteRedraw is called only when + // painting is locked. We do all the painting ourself. When painting + // is locked the parent implementation keeps track of the repaint + // requests and later, when painting is unlocked, calls CompleteRedraw + // for all missed repaints. + + if (mnLockRedrawSmph == 0) + { + mrSlideSorter.GetContentWindow()->IncrementLockCount(); + if (mpLayeredDevice->HandleMapModeChange()) + DeterminePageObjectVisibilities(); + mpLayeredDevice->Repaint(rPaintArea); + mrSlideSorter.GetContentWindow()->DecrementLockCount(); + } + else { - aBBox = mpLayouter->GetPageObjectBox(nIndex); - AdaptBoundingBox (aBBox, eCoordinateSystem, eBoundingBoxType); + maRedrawRegion.Union(rPaintArea); } - return aBBox; +#ifdef DEBUG_TIMING + const double nEndTime (gaTimer.getElapsedTime()); + OSL_TRACE("SlideSorterView::CompleteRedraw end at %f after %fms", nEndTime, (nEndTime-nStartTime)*1000); + gFrameTimeSum -= gFrameTimes[gFrameTimeIndex]; + gFrameTimes[gFrameTimeIndex] = nStartTime - gnLastFrameStart; + gnLastFrameStart = nStartTime; + gFrameTimeSum += gFrameTimes[gFrameTimeIndex]; + gFrameTimeIndex = (gFrameTimeIndex+1) % gFrameTimeCount; + + + mrSlideSorter.GetContentWindow()->SetFillColor(COL_BLUE); + mrSlideSorter.GetContentWindow()->DrawRect(gFrameTimeBox); + mrSlideSorter.GetContentWindow()->SetTextColor(COL_WHITE); + mrSlideSorter.GetContentWindow()->DrawText( + gFrameTimeBox, + ::rtl::OUString::valueOf(1 / (gFrameTimeSum / gFrameTimeCount)), + TEXT_DRAW_RIGHT | TEXT_DRAW_VCENTER); + // mrSlideSorter.GetContentWindow()->Invalidate(gFrameTimeBox); +#endif } -void SlideSorterView::CompleteRedraw(OutputDevice* pDevice, const Region& rPaintArea, sdr::contact::ViewObjectContactRedirector* pRedirector) +void SlideSorterView::Paint ( + OutputDevice& rDevice, + const Rectangle& rRepaintArea) { - if (mnLockRedrawSmph == 0) - { - // Update the page visibilities when they have been invalidated. - if ( ! mbPageObjectVisibilitiesValid) - DeterminePageObjectVisibilities(); + if ( ! mpPageObjectPainter) + if ( ! GetPageObjectPainter()) + return; - if (mbPreciousFlagUpdatePending) - UpdatePreciousFlags(); + // Update the page visibilities when they have been invalidated. + if ( ! mbPageObjectVisibilitiesValid) + DeterminePageObjectVisibilities(); - // Call the base class InitRedraw even when re-drawing is locked to - // let it remember the request for a redraw. - View::CompleteRedraw (pDevice, rPaintArea, pRedirector); - } - else + if (mbPreciousFlagUpdatePending) + UpdatePreciousFlags(); + + if (mbIsRearrangePending) + Rearrange(); + + // Paint all page objects that are fully or partially inside the + // repaint region. + const Range aRange (mpLayouter->GetRangeOfVisiblePageObjects(rRepaintArea)); + for (sal_Int32 nIndex=aRange.Min(); nIndex<=aRange.Max(); ++nIndex) { - // In sd::View::CompleteRedraw() this call is recorded and given - // region is painted when the view is unlocked. - View::CompleteRedraw (pDevice, rPaintArea, pRedirector); + model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex)); + if (!pDescriptor || ! pDescriptor->HasState(PageDescriptor::ST_Visible)) + continue; + + mpPageObjectPainter->PaintPageObject(rDevice, pDescriptor); } } -void SlideSorterView::InvalidateOneWin (::Window& rWindow) +void SlideSorterView::ConfigurationChanged ( + utl::ConfigurationBroadcaster* pBroadcaster, + sal_uInt32 nHint) { - // if ( IsInvalidateAllowed() ) - View::InvalidateOneWin (rWindow); + // Some changes of the configuration (some of the colors for example) + // may affect the previews. Throw away the old ones and create new ones. + cache::PageCacheManager::Instance()->InvalidateAllCaches(); + + ::sd::View::ConfigurationChanged(pBroadcaster, nHint); + RequestRepaint(); + } -void SlideSorterView::InvalidateOneWin ( - ::Window& rWindow, - const Rectangle& rPaintArea) +::boost::shared_ptr<cache::PageCache> SlideSorterView::GetPreviewCache (void) { - // if( IsInvalidateAllowed() ) - View::InvalidateOneWin (rWindow, rPaintArea); + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow && mpPreviewCache.get() == NULL) + { + mpPreviewCache.reset( + new cache::PageCache( + mpLayouter->GetPageObjectSize(), + false, + cache::SharedCacheContext(new ViewCacheContext(mrSlideSorter)))); + } + + return mpPreviewCache; } -::sd::Window* SlideSorterView::GetWindow (void) const +Pair SlideSorterView::GetVisiblePageRange (void) { - return static_cast< ::sd::Window*>(GetFirstOutputDevice()); + if ( ! mbPageObjectVisibilitiesValid) + DeterminePageObjectVisibilities(); + return maVisiblePageRange; } -void SlideSorterView::AdaptBoundingBox ( - Rectangle& rModelPageObjectBoundingBox, - CoordinateSystem eCoordinateSystem, - BoundingBoxType eBoundingBoxType) const +void SlideSorterView::AddVisibilityChangeListener (const Link& rListener) { - CoordinateSystem aCurrentCoordinateSystem = CS_MODEL; - ::sd::Window* pWindow = GetWindow(); - if (pWindow != NULL) + if (::std::find ( + maVisibilityChangeListeners.begin(), + maVisibilityChangeListeners.end(), + rListener) == maVisibilityChangeListeners.end()) { - if (eBoundingBoxType == BBT_INFO) - { - // Make the box larger so that it encloses all relevant - // displayed information. - if (aCurrentCoordinateSystem == CS_MODEL) - { - // The relevant offsets are given in pixel values. Therefore - // transform the box first into screen coordinates. - rModelPageObjectBoundingBox - = pWindow->LogicToPixel (rModelPageObjectBoundingBox); - aCurrentCoordinateSystem = CS_SCREEN; - } - rModelPageObjectBoundingBox.Left() -= maPagePixelBorder.Left(); - rModelPageObjectBoundingBox.Right() += maPagePixelBorder.Right(); - rModelPageObjectBoundingBox.Top() -= maPagePixelBorder.Top(); - rModelPageObjectBoundingBox.Bottom() += maPagePixelBorder.Bottom(); - } - - // Make sure that the bounding box is given in the correct coordinate - // system. - if (eCoordinateSystem != aCurrentCoordinateSystem) - { - if (eCoordinateSystem == CS_MODEL) - rModelPageObjectBoundingBox - = pWindow->PixelToLogic (rModelPageObjectBoundingBox); - else - rModelPageObjectBoundingBox - = pWindow->LogicToPixel (rModelPageObjectBoundingBox); - } + maVisibilityChangeListeners.push_back(rListener); } } -::boost::shared_ptr<cache::PageCache> SlideSorterView::GetPreviewCache (void) +void SlideSorterView::RemoveVisibilityChangeListener(const Link&rListener) { - ::sd::Window* pWindow = GetWindow(); - if (pWindow != NULL && mpPreviewCache.get() == NULL) - { - maPreviewSize = pWindow->LogicToPixel(mpLayouter->GetPageObjectSize()); - mpPreviewCache.reset( - new cache::PageCache( - maPreviewSize, - cache::SharedCacheContext(new ViewCacheContext(mrSlideSorter.GetModel(), *this)))); - } - - return mpPreviewCache; + maVisibilityChangeListeners.erase ( + ::std::find ( + maVisibilityChangeListeners.begin(), + maVisibilityChangeListeners.end(), + rListener)); } -ViewOverlay& SlideSorterView::GetOverlay (void) +ButtonBar& SlideSorterView::GetButtonBar (void) const { - return *mpViewOverlay.get(); + OSL_ASSERT(mpButtonBar); + return *mpButtonBar; } -SlideSorterView::PageRange SlideSorterView::GetVisiblePageRange (void) +ToolTip& SlideSorterView::GetToolTip (void) const { - const int nMaxPageIndex (mrModel.GetPageCount() - 1); - if ( ! mbPageObjectVisibilitiesValid) - DeterminePageObjectVisibilities(); - return PageRange( - ::std::min(mnFirstVisiblePageIndex,nMaxPageIndex), - ::std::min(mnLastVisiblePageIndex, nMaxPageIndex)); + OSL_ASSERT(mpToolTip); + return *mpToolTip; } @@ -719,103 +913,220 @@ void SlideSorterView::Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint -void SlideSorterView::UpdatePageBorders (void) +void SlideSorterView::UpdatePageUnderMouse (bool bAnimate) { - maPagePixelBorder = SvBorder(); - ::sd::Window* pWindow = GetWindow(); - if (mrModel.GetPageCount()>0 && pWindow!=NULL) + ::boost::shared_ptr<ScrollBar> pVScrollBar (mrSlideSorter.GetVerticalScrollBar()); + ::boost::shared_ptr<ScrollBar> pHScrollBar (mrSlideSorter.GetHorizontalScrollBar()); + if ((pVScrollBar && pVScrollBar->IsVisible() && pVScrollBar->IsTracking()) + || (pHScrollBar && pHScrollBar->IsVisible() && pHScrollBar->IsTracking())) { - // Calculate the border in model coordinates. - maPageNumberAreaModelSize = PageObjectViewObjectContact::CalculatePageNumberAreaModelSize ( - pWindow, - mrModel.GetPageCount()); - maModelBorder = PageObjectViewObjectContact::CalculatePageModelBorder ( - pWindow, - mrModel.GetPageCount()); - - // Depending on values in the global properties the border has to be - // extended a little bit. - ::boost::shared_ptr<controller::Properties> pProperties( - mrSlideSorter.GetController().GetProperties()); - if (pProperties.get()!=NULL && pProperties->IsHighlightCurrentSlide()) + // One of the scroll bars is tracking mouse movement. Do not + // highlight the slide under the mouse in this case. + SetPageUnderMouse(SharedPageDescriptor(),false); + return; + } + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow && pWindow->IsVisible() && ! pWindow->IsMouseCaptured()) + { + const Window::PointerState aPointerState (pWindow->GetPointerState()); + const Rectangle aWindowBox (pWindow->GetPosPixel(), pWindow->GetSizePixel()); + if (aWindowBox.IsInside(aPointerState.maPos)) { - Size aBorderSize (pWindow->PixelToLogic (Size(3,3))); - maModelBorder.Left() += aBorderSize.Width(); - maModelBorder.Right() += aBorderSize.Width(); - maModelBorder.Top() += aBorderSize.Height(); - maModelBorder.Bottom() += aBorderSize.Height(); + UpdatePageUnderMouse ( + aPointerState.maPos, + (aPointerState.mnState & MOUSE_LEFT)!=0, + bAnimate); + return; } + } - // Set the border at all page descriptors so that the contact - // objects have access to them. - model::PageEnumeration aPageEnumeration ( - model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); - while (aPageEnumeration.HasMoreElements()) + SetPageUnderMouse(SharedPageDescriptor(),false); +} + + + + +void SlideSorterView::UpdatePageUnderMouse ( + const Point& rMousePosition, + const bool bIsMouseButtonDown, + const bool bAnimate) +{ + UpdatePageUnderMouse( + mrSlideSorter.GetController().GetPageAt(rMousePosition), + rMousePosition, + bIsMouseButtonDown, + bAnimate); +} + + + + +void SlideSorterView::UpdatePageUnderMouse ( + const model::SharedPageDescriptor& rpDescriptor, + const Point& rMousePosition, + const bool bIsMouseButtonDown, + const bool bAnimate) +{ + // Update the page under the mouse. + SetPageUnderMouse(rpDescriptor, bAnimate); + + // Tell the button bar about the new mouse position. + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition)); + + ::boost::shared_ptr<ViewShell> pMainViewShell (mrSlideSorter.GetViewShellBase()->GetMainViewShell()); + if (pMainViewShell + && pMainViewShell->GetShellType()!=ViewShell::ST_DRAW) + { + const bool bIsMouseOverButtonBar (GetButtonBar().IsMouseOverBar()); + GetButtonBar().ProcessMouseMotionEvent(rpDescriptor, aMouseModelPosition, bIsMouseButtonDown); + // Set the help text of the slide when the mouse was moved from the + // button bar back over the preview. + if (rpDescriptor + && GetButtonBar().IsMouseOverBar() != bIsMouseOverButtonBar + && bIsMouseOverButtonBar) { - model::SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement()); - pDescriptor->SetModelBorder(maModelBorder); - pDescriptor->SetPageNumberAreaModelSize(maPageNumberAreaModelSize); + mpToolTip->ShowDefaultHelpText(); } - - // Convert the borders to pixel coordinates and store them for later - // use. - Size aTopLeftBorders(pWindow->LogicToPixel( - Size (maModelBorder.Left(), maModelBorder.Top()))); - Size aBottomRightBorders(pWindow->LogicToPixel( - Size (maModelBorder.Right(), maModelBorder.Bottom()))); - maPagePixelBorder = SvBorder ( - aTopLeftBorders.Width(), - aTopLeftBorders.Height(), - aBottomRightBorders.Width(), - aBottomRightBorders.Height()); } - - // Finally tell the layouter about the borders. - mpLayouter->SetBorders (2,5,4,5); - mpLayouter->SetPageBorders ( - maPagePixelBorder.Left(), - maPagePixelBorder.Right(), - maPagePixelBorder.Top(), - maPagePixelBorder.Bottom()); } -void SlideSorterView::AddSdrObject (SdrObject& rObject) +void SlideSorterView::SetPageUnderMouse ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bAnimate) { - mpPage->InsertObject(&rObject); - rObject.SetModel(&maPageModel); + if (mpPageUnderMouse != rpDescriptor) + { + if (mpPageUnderMouse) + SetState(mpPageUnderMouse, PageDescriptor::ST_MouseOver, false, bAnimate); + + mpPageUnderMouse = rpDescriptor; + + if (mpPageUnderMouse) + SetState(mpPageUnderMouse, PageDescriptor::ST_MouseOver, true, bAnimate); + + // Change the quick help text to display the name of the page under + // the mouse. + mpToolTip->SetPage(rpDescriptor); + } } -void SlideSorterView::AddVisibilityChangeListener (const Link& rListener) +bool SlideSorterView::SetState ( + const model::SharedPageDescriptor& rpDescriptor, + const PageDescriptor::State eState, + const bool bStateValue, + const bool bAnimate) { - if (::std::find ( - maVisibilityChangeListeners.begin(), - maVisibilityChangeListeners.end(), - rListener) == maVisibilityChangeListeners.end()) + model::SharedPageDescriptor pDescriptor (rpDescriptor); + if ( ! pDescriptor) + return false; + + const bool bModified (pDescriptor->SetState(eState, bStateValue)); + if ( ! bModified) + return false; + + // When the page object is not visible (i.e. not on the screen then + // nothing has to be painted. + if (pDescriptor->HasState(PageDescriptor::ST_Visible)) { - maVisibilityChangeListeners.push_back(rListener); + // For most states a change of that state leads to visible + // difference and we have to request a repaint. + if (eState != PageDescriptor::ST_WasSelected) + RequestRepaint(pDescriptor); } + + ::boost::shared_ptr<ViewShell> pMainViewShell(mrSlideSorter.GetViewShellBase()->GetMainViewShell()); + if (pMainViewShell + && pMainViewShell->GetShellType()!=ViewShell::ST_DRAW) + { + // Fade in or out the buttons. + if (eState == PageDescriptor::ST_MouseOver) + { + if (bStateValue) + GetButtonBar().RequestFadeIn(rpDescriptor, bAnimate); + else + GetButtonBar().RequestFadeOut(rpDescriptor, bAnimate); + } + } + + return bModified; } -void SlideSorterView::RemoveVisibilityChangeListener(const Link&rListener) +::boost::shared_ptr<PageObjectPainter> SlideSorterView::GetPageObjectPainter (void) { - maVisibilityChangeListeners.erase ( - ::std::find ( - maVisibilityChangeListeners.begin(), - maVisibilityChangeListeners.end(), - rListener)); + if ( ! mpPageObjectPainter) + mpPageObjectPainter.reset(new PageObjectPainter(mrSlideSorter)); + return mpPageObjectPainter; +} + + + + +::boost::shared_ptr<LayeredDevice> SlideSorterView::GetLayeredDevice (void) const +{ + return mpLayeredDevice; } +//===== SlideSorterView::DrawLock ============================================= + +SlideSorterView::DrawLock::DrawLock ( + view::SlideSorterView& rView, + const SharedSdWindow& rpWindow) + : mrView(rView), + mpWindow(rpWindow) +{ + if (mrView.mnLockRedrawSmph == 0) + mrView.maRedrawRegion.SetEmpty(); + ++mrView.mnLockRedrawSmph; +} + + + + +SlideSorterView::DrawLock::DrawLock (SlideSorter& rSlideSorter) + : mrView(rSlideSorter.GetView()), + mpWindow(rSlideSorter.GetContentWindow()) +{ + if (mrView.mnLockRedrawSmph == 0) + mrView.maRedrawRegion.SetEmpty(); + ++mrView.mnLockRedrawSmph; +} + + + + +SlideSorterView::DrawLock::~DrawLock (void) +{ + OSL_ASSERT(mrView.mnLockRedrawSmph>0); + --mrView.mnLockRedrawSmph; + if (mrView.mnLockRedrawSmph == 0) + if (mpWindow) + { + mpWindow->Invalidate(mrView.maRedrawRegion); + mpWindow->Update(); + } +} + + + + +void SlideSorterView::DrawLock::Dispose (void) +{ + mpWindow.reset(); +} + } } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsButtonBar.cxx b/sd/source/ui/slidesorter/view/SlsButtonBar.cxx new file mode 100644 index 000000000000..70655caeda2a --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsButtonBar.cxx @@ -0,0 +1,1558 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsButtonBar.hxx" + +#include "SlideSorter.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlideSorterModel.hxx" +#include "view/SlsTheme.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsToolTip.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsSlotManager.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsAnimator.hxx" +#include "controller/SlsAnimationFunction.hxx" +#include "app.hrc" +#include "drawdoc.hxx" +#include <svx/svxids.hrc> +#include <sfx2/dispatch.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/virdev.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <com/sun/star/presentation/XPresentation2.hpp> +#include <boost/bind.hpp> + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::presentation::XPresentation2; + +namespace sd { namespace slidesorter { namespace view { + +/** Base class for the painter of the background bar onto which the buttons + are painted. It also provides some size information. +*/ +class ButtonBar::BackgroundTheme +{ +public: + BackgroundTheme( + const ::boost::shared_ptr<Theme>& rpTheme, + const ::std::vector<SharedButton>& rButtons); + /** Set the preview bounding box, the maximal area in which to display + buttons. A call to this method triggers a call to Layout(). + */ + void SetPreviewBoundingBox (const Rectangle& rPreviewBoundingBox); + Button::IconSize GetIconSize (void) const; + + virtual BitmapEx CreateBackground ( + const OutputDevice& rTemplateDevice, + const bool bIsButtonDown) const = 0; + virtual Point GetBackgroundLocation (void) = 0; + virtual Rectangle GetButtonArea (void) = 0; + +protected: + ::boost::shared_ptr<Theme> mpTheme; + Rectangle maPreviewBoundingBox; + Size maMinimumLargeButtonAreaSize; + Size maMinimumMediumButtonAreaSize; + Size maMinimumSmallButtonAreaSize; + Button::IconSize meIconSize; + + virtual void Layout (void) = 0; + +private: + void UpdateMinimumIconSizes(const ::std::vector<SharedButton>& rButtons); +}; + + +namespace { + /** Rectangular button bar that covers the whole width of the preview. + */ + class RectangleBackgroundTheme : public ButtonBar::BackgroundTheme + { + public: + RectangleBackgroundTheme( + const ::boost::shared_ptr<Theme>& rpTheme, + const ::std::vector<SharedButton>& rButtons); + virtual BitmapEx CreateBackground ( + const OutputDevice& rTemplateDevice, + const bool bIsButtonDown) const; + virtual Point GetBackgroundLocation (void); + virtual Rectangle GetButtonArea (void); + protected: + virtual void Layout (void); + private: + sal_Int32 mnBarHeight; + }; + + /** Button bar is composed of three images, the left and right end of + the bar and the center image. Buttons are only placed over the + center image. The center image is painted as is, it is not scaled. + */ + class BitmapBackgroundTheme : public ButtonBar::BackgroundTheme + { + public: + BitmapBackgroundTheme( + const ::boost::shared_ptr<Theme>& rpTheme, + const ::std::vector<SharedButton>& rButtons); + virtual BitmapEx CreateBackground ( + const OutputDevice& rTemplateDevice, + const bool bIsButtonDown) const; + virtual Point GetBackgroundLocation (void); + virtual Rectangle GetButtonArea (void); + protected: + virtual void Layout (void); + private: + Rectangle maButtonArea; + Point maBackgroundLocation; + }; + + /** The source mask is essentially multiplied with the given alpha value. + The result is writen to the result mask. + */ + void AdaptTransparency (AlphaMask& rMask, const AlphaMask& rSourceMask, const double nAlpha) + { + BitmapWriteAccess* pBitmap = rMask.AcquireWriteAccess(); + const BitmapReadAccess* pSourceBitmap = const_cast<AlphaMask&>(rSourceMask).AcquireReadAccess(); + + if (pBitmap!=NULL && pSourceBitmap!=NULL) + { + const sal_Int32 nWidth (pBitmap->Width()); + const sal_Int32 nHeight (pBitmap->Height()); + + for (sal_Int32 nY = 0; nY<nHeight; ++nY) + for (sal_Int32 nX = 0; nX<nWidth; ++nX) + { + const BYTE nValue (255 - pSourceBitmap->GetPixel(nY, nX).GetBlueOrIndex()); + const BYTE nNewValue (nValue * (1-nAlpha)); + pBitmap->SetPixel(nY, nX, 255-nNewValue); + } + } + } + +} // end of anonymous namespace + + +//===== ButtonBar::Lock ======================================================= + +ButtonBar::Lock::Lock (SlideSorter& rSlideSorter) + : mrButtonBar(rSlideSorter.GetView().GetButtonBar()) +{ + mrButtonBar.AcquireLock(); +} + + + + +ButtonBar::Lock::~Lock (void) +{ + mrButtonBar.ReleaseLock(); +} + + + + +//===== ButtonBar ============================================================= + +ButtonBar::ButtonBar (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + maPageObjectSize(0,0), + maButtonBoundingBox(), + maBackgroundLocation(), + mpDescriptor(), + mbIsExcluded(false), + mpButtonUnderMouse(), + mpDownButton(), + maRegularButtons(), + maExcludedButtons(), + maNormalBackground(), + maButtonDownBackground(), + mbIsMouseOverBar(false), + mpBackgroundTheme(), + mnLockCount(0) +{ + HandleDataChangeEvent(); +} + + + + +ButtonBar::~ButtonBar (void) +{ +} + + + + +void ButtonBar::ProcessButtonDownEvent ( + const model::SharedPageDescriptor& rpDescriptor, + const Point aMouseModelLocation) +{ + SetButtonUnderMouse(GetButtonAt(aMouseModelLocation)); + if (mpButtonUnderMouse) + mpButtonUnderMouse->SetState(Button::State_Down); + mpDownButton = mpButtonUnderMouse; + + mrSlideSorter.GetView().RequestRepaint(rpDescriptor); +} + + + + +void ButtonBar::ProcessButtonUpEvent ( + const model::SharedPageDescriptor& rpDescriptor, + const Point aMouseModelLocation) +{ + SetButtonUnderMouse(GetButtonAt(aMouseModelLocation)); + if (mpButtonUnderMouse) + { + mpButtonUnderMouse->SetState(Button::State_Hover); + if (mpButtonUnderMouse == mpDownButton) + { + // This is done only when the buttons are sufficiently visible. + if (mpDescriptor->GetVisualState().GetButtonAlpha()<0.7) + { + mpButtonUnderMouse->ProcessClick(mpDescriptor); + mbIsExcluded = mpDescriptor->HasState(model::PageDescriptor::ST_Excluded); + ProcessMouseMotionEvent (rpDescriptor, aMouseModelLocation, false); + } + } + } + mpDownButton.reset(); + mrSlideSorter.GetView().RequestRepaint(rpDescriptor); +} + + + + +void ButtonBar::ProcessMouseMotionEvent ( + const model::SharedPageDescriptor& rpDescriptor, + const Point aMouseModelLocation, + const bool bIsMouseButtonDown) +{ + model::SharedPageDescriptor pOldDescriptor (mpDescriptor); + bool bPageHasChanged (false); + bool bButtonHasChanged (false); + bool bButtonStateHasChanged (false); + + // Update the page object for which to manage the buttons. + bPageHasChanged = SetPage(rpDescriptor); + mbIsMouseOverBar = IsMouseOverBar(aMouseModelLocation); + + // Update button under mouse. + if (rpDescriptor) + { + bButtonHasChanged = SetButtonUnderMouse(GetButtonAt(aMouseModelLocation)); + + if (mpButtonUnderMouse) + { + // When the mouse button is down, mark the button under the + // mouse only as pressed when it is the same button the mouse + // button was pressed over, and where the button release would + // lead to a click action. + if (bIsMouseButtonDown) + { + if (mpButtonUnderMouse==mpDownButton) + bButtonStateHasChanged = mpButtonUnderMouse->SetState(Button::State_Down); + } + else + bButtonStateHasChanged = mpButtonUnderMouse->SetState(Button::State_Hover); + } + } + + // Show a quick help text when the mouse is over a button. + if (bButtonHasChanged) + { + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + if (mpButtonUnderMouse) + mrSlideSorter.GetView().GetToolTip().ShowHelpText(mpButtonUnderMouse->GetHelpText()); + else + mrSlideSorter.GetView().GetToolTip().ShowDefaultHelpText(); + } + } + + if (bPageHasChanged || bButtonHasChanged || bButtonStateHasChanged) + { + if (pOldDescriptor) + mrSlideSorter.GetView().RequestRepaint(pOldDescriptor); + if (mpDescriptor && pOldDescriptor!=mpDescriptor) + mrSlideSorter.GetView().RequestRepaint(mpDescriptor); + } +} + + + + +void ButtonBar::ResetPage (void) +{ + SetPage(model::SharedPageDescriptor()); +} + + + + +bool ButtonBar::SetPage (const model::SharedPageDescriptor& rpDescriptor) +{ + if (mpDescriptor != rpDescriptor) + { + mpDescriptor = rpDescriptor; + + if (mpDescriptor) + mbIsExcluded = mpDescriptor->HasState(model::PageDescriptor::ST_Excluded); + else + mbIsExcluded = false; + SetButtonUnderMouse(); + mpDownButton.reset(); + + return true; + } + else + return false; +} + + + + +sal_Int32 ButtonBar::GetButtonCount (const bool bIsExcluded) const +{ + if (bIsExcluded) + return maExcludedButtons.size(); + else + return maRegularButtons.size(); +} + + + + +::boost::shared_ptr<Button> ButtonBar::GetButton ( + const bool bIsExcluded, + const sal_Int32 nIndex) const +{ + const ::std::vector<boost::shared_ptr<Button> >& rButtons (bIsExcluded + ? maExcludedButtons + : maRegularButtons); + + if (nIndex<0 || sal_uInt32(nIndex)>=rButtons.size()) + { + OSL_ASSERT(nIndex<0 || sal_uInt32(nIndex)>=rButtons.size()); + return ::boost::shared_ptr<Button>(); + } + else + return rButtons[sal_uInt32(nIndex)]; +} + + + + +SharedButton ButtonBar::GetButtonAt (const Point aModelLocation) +{ + if (IsMouseOverBar(aModelLocation)) + { + const Point aLocalLocation (aModelLocation - mpDescriptor->GetBoundingBox().TopLeft()); + ::std::vector<SharedButton>& rButtons ( + mbIsExcluded ? maExcludedButtons : maRegularButtons); + for (sal_uInt32 nIndex=0; nIndex<rButtons.size(); ++nIndex) + { + if (rButtons[sal_uInt32(nIndex)]->GetBoundingBox().IsInside(aLocalLocation)) + { + if (rButtons[sal_uInt32(nIndex)]->IsEnabled()) + return rButtons[sal_uInt32(nIndex)]; + else + return SharedButton(); + } + } + } + + return SharedButton(); +} + + + + +bool ButtonBar::IsMouseOverBar (void) const +{ + return mbIsMouseOverBar; +} + + + + +bool ButtonBar::SetButtonUnderMouse (const SharedButton& rButton) +{ + if (mpButtonUnderMouse != rButton) + { + if (mpButtonUnderMouse) + mpButtonUnderMouse->SetState(Button::State_Normal); + + mpButtonUnderMouse = rButton; + + return true; + } + else + return false; +} + + + + +void ButtonBar::Paint ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) +{ + if ( ! rpDescriptor) + return; + + const double nButtonBarAlpha (rpDescriptor->GetVisualState().GetButtonBarAlpha()); + if (nButtonBarAlpha >= 1) + return; + + LayoutButtons(rpDescriptor->GetBoundingBox().GetSize()); + + const Point aOffset (rpDescriptor->GetBoundingBox().TopLeft()); + + // Paint the background. + PaintButtonBackground(rDevice, rpDescriptor, aOffset); + + // Paint the buttons. + const ::std::vector<SharedButton>& rButtons ( + rpDescriptor->HasState(model::PageDescriptor::ST_Excluded) + ? maExcludedButtons + : maRegularButtons); + + + const double nButtonAlpha (rpDescriptor->GetVisualState().GetButtonAlpha()); + for (sal_uInt32 nIndex=0; nIndex<rButtons.size(); ++nIndex) + rButtons[nIndex]->Paint( + rDevice, + aOffset, + nButtonAlpha, + mrSlideSorter.GetTheme()); +} + + + + +bool ButtonBar::IsMouseOverButton (void) const +{ + return mpButtonUnderMouse; +} + + + + +void ButtonBar::PaintButtonBackground ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor, + const Point aOffset) +{ + BitmapEx* pBitmap = NULL; + if (maButtonDownBackground.IsEmpty() || maNormalBackground.IsEmpty()) + { + if (mpBackgroundTheme) + { + maButtonDownBackground = mpBackgroundTheme->CreateBackground(rDevice, true); + maNormalBackground = mpBackgroundTheme->CreateBackground(rDevice, false); + } + } + if (mpButtonUnderMouse && mpButtonUnderMouse->IsDown()) + pBitmap = &maButtonDownBackground; + else + pBitmap = &maNormalBackground; + if (pBitmap != NULL) + { + AlphaMask aMask (pBitmap->GetSizePixel()); + AdaptTransparency( + aMask, + pBitmap->GetAlpha(), + rpDescriptor->GetVisualState().GetButtonBarAlpha()); + rDevice.DrawBitmapEx(maBackgroundLocation+aOffset, BitmapEx(pBitmap->GetBitmap(), aMask)); + } +} + + + + +bool ButtonBar::IsMouseOverBar (const Point aModelLocation) const +{ + if ( ! mpDescriptor || ! mpDescriptor->GetBoundingBox().IsInside(aModelLocation)) + return false; + + if ( ! maButtonBoundingBox.IsInside(aModelLocation - mpDescriptor->GetBoundingBox().TopLeft())) + return false; + + return true; +} + + + + +void ButtonBar::RequestLayout (void) +{ + maPageObjectSize = Size(0,0); +} + + + + +void ButtonBar::LayoutButtons (const Size aPageObjectSize) +{ + if (maPageObjectSize != aPageObjectSize) + { + maPageObjectSize = aPageObjectSize; + + if (mpBackgroundTheme) + { + mpBackgroundTheme->SetPreviewBoundingBox( + mrSlideSorter.GetView().GetLayouter().GetPageObjectLayouter()->GetBoundingBox( + Point(0,0), + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + LayoutButtons(); + } + + // Release the background bitmaps so that on the next paint + // they are created anew in the right size. + maNormalBackground.SetEmpty(); + maButtonDownBackground.SetEmpty(); + } +} + + + + +bool ButtonBar::LayoutButtons (void) +{ + const sal_Int32 nGap (mrSlideSorter.GetTheme()->GetIntegerValue(Theme::Integer_ButtonGap)); + const sal_Int32 nBorder (mrSlideSorter.GetTheme()->GetIntegerValue(Theme::Integer_ButtonBorder)); + + const Button::IconSize eIconSize (mpBackgroundTheme->GetIconSize()); + + // Tell buttons which size they are. + for (sal_uInt32 nIndex=0; nIndex<maExcludedButtons.size(); ++nIndex) + maExcludedButtons[nIndex]->SetIconSize(eIconSize); + for (sal_uInt32 nIndex=0; nIndex<maRegularButtons.size(); ++nIndex) + maRegularButtons[nIndex]->SetIconSize(eIconSize); + + // Determine maximal height and total width of the buttons. + // Start with the buttons used for the excluded state. + sal_Int32 nMaximumHeight (0); + sal_Int32 nExcludedTotalWidth ((maExcludedButtons.size()-1) * nGap + 2*nBorder); + for (sal_uInt32 nIndex=0; nIndex<maExcludedButtons.size(); ++nIndex) + { + const Size aSize (maExcludedButtons[nIndex]->GetSize()); + if (aSize.Height() > nMaximumHeight) + nMaximumHeight = aSize.Height(); + nExcludedTotalWidth += aSize.Width(); + } + + // Do the same for the regular buttons. + sal_Int32 nRegularTotalWidth ((maRegularButtons.size()-1) * nGap + 2*nBorder); + for (sal_uInt32 nIndex=0; nIndex<maRegularButtons.size(); ++nIndex) + { + const Size aSize (maRegularButtons[nIndex]->GetSize()); + if (aSize.Height() > nMaximumHeight) + nMaximumHeight = aSize.Height(); + nRegularTotalWidth += aSize.Width(); + } + nMaximumHeight += 2*nBorder; + + // Set up the bounding box of the button bar. + maButtonBoundingBox = mpBackgroundTheme->GetButtonArea(); + maBackgroundLocation = mpBackgroundTheme->GetBackgroundLocation(); + if (mrSlideSorter.GetTheme()->GetIntegerValue(Theme::Integer_ButtonPaintType) == 1) + { + // Center the buttons. + maButtonBoundingBox.Left() += (maButtonBoundingBox.GetWidth() - nRegularTotalWidth)/2; + maButtonBoundingBox.Right() = maButtonBoundingBox.Left() + nRegularTotalWidth - 1; + } + + // Place the buttons. + Rectangle aBox (maButtonBoundingBox); + aBox.Right() -= nBorder; + for (sal_Int32 nIndex=maRegularButtons.size()-1; nIndex>=0; --nIndex) + { + maRegularButtons[nIndex]->Place(aBox); + aBox.Right() = maRegularButtons[nIndex]->GetBoundingBox().Left() - nGap; + } + + // For slides excluded from the show there is only one icon placed + // exactly like the second of the regular icons. + if (maRegularButtons.size()>=2 && maExcludedButtons.size()>=1) + { + aBox = maRegularButtons[1]->GetBoundingBox(); + maExcludedButtons[0]->Place(aBox); + } + + // We return true only when there is no inactive button. + for (sal_uInt32 nIndex=0; nIndex<maExcludedButtons.size(); ++nIndex) + if ( ! maExcludedButtons[nIndex]->IsActive()) + return false; + for (sal_uInt32 nIndex=0; nIndex<maRegularButtons.size(); ++nIndex) + if ( ! maRegularButtons[nIndex]->IsActive()) + return false; + + return true; +} + + + + +void ButtonBar::RequestFadeIn ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bAnimate) +{ + if ( ! rpDescriptor) + return; + if (mnLockCount > 0) + return; + + const double nMinAlpha (0); + if ( ! bAnimate) + { + rpDescriptor->GetVisualState().SetButtonAlpha(nMinAlpha); + rpDescriptor->GetVisualState().SetButtonBarAlpha(nMinAlpha); + } + else + StartFadeAnimation(rpDescriptor, nMinAlpha, true); +} + + + + +void ButtonBar::RequestFadeOut ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bAnimate) +{ + if ( ! rpDescriptor) + return; + if (mnLockCount > 0) + return; + + const double nMaxAlpha (1); + if ( ! bAnimate) + { + rpDescriptor->GetVisualState().SetButtonAlpha(nMaxAlpha); + rpDescriptor->GetVisualState().SetButtonBarAlpha(nMaxAlpha); + } + else + StartFadeAnimation(rpDescriptor, nMaxAlpha, false); +} + + + + +bool ButtonBar::IsVisible (const model::SharedPageDescriptor& rpDescriptor) +{ + const double nMaxAlpha (1); + return rpDescriptor && rpDescriptor->GetVisualState().GetButtonBarAlpha() < nMaxAlpha; +} + + + + +void ButtonBar::HandleDataChangeEvent (void) +{ + maExcludedButtons.clear(); + maExcludedButtons.push_back(::boost::shared_ptr<Button>(new UnhideButton(mrSlideSorter))); + + maRegularButtons.clear(); + maRegularButtons.push_back(::boost::shared_ptr<Button>(new StartShowButton(mrSlideSorter))); + maRegularButtons.push_back(::boost::shared_ptr<Button>(new HideButton(mrSlideSorter))); + maRegularButtons.push_back(::boost::shared_ptr<Button>(new DuplicateButton(mrSlideSorter))); + + mpBackgroundTheme.reset( + new BitmapBackgroundTheme( + mrSlideSorter.GetTheme(), + maRegularButtons)); + + // Force layout on next Paint(). + maPageObjectSize = Size(0,0); +} + + + + +void ButtonBar::StartFadeAnimation ( + const model::SharedPageDescriptor& rpDescriptor, + const double nTargetAlpha, + const bool bFadeIn) +{ + model::SharedPageDescriptor pDescriptor (rpDescriptor); + + const double nCurrentButtonAlpha (pDescriptor->GetVisualState().GetButtonAlpha()); + const double nCurrentButtonBarAlpha (pDescriptor->GetVisualState().GetButtonBarAlpha()); + + // Stop a running animation. + const controller::Animator::AnimationId nId ( + pDescriptor->GetVisualState().GetButtonAlphaAnimationId()); + if (nId != controller::Animator::NotAnAnimationId) + mrSlideSorter.GetController().GetAnimator()->RemoveAnimation(nId); + + // Prepare the blending functors that translate [0,1] animation + // times into alpha values of buttons and button bar. + const ::boost::function<double(double)> aButtonBlendFunctor ( + ::boost::bind( + controller::AnimationFunction::Blend, + nCurrentButtonAlpha, + nTargetAlpha, + ::boost::bind(controller::AnimationFunction::Linear, _1))); + const ::boost::function<double(double)> aButtonBarBlendFunctor ( + ::boost::bind( + controller::AnimationFunction::Blend, + nCurrentButtonBarAlpha, + nTargetAlpha, + ::boost::bind(controller::AnimationFunction::Linear, _1))); + + // Delay the fade in a little bit when the buttons are not visible at + // all so that we do not leave a trail of half-visible buttons when the + // mouse is moved across the screen. No delay on fade out or when the + // buttons are already showing. Fade out is faster than fade in. + const double nDelay (nCurrentButtonBarAlpha>0 && nCurrentButtonBarAlpha<1 + ? 0 + : (mrSlideSorter.GetTheme()->GetIntegerValue(bFadeIn + ? Theme::Integer_ButtonFadeInDelay + : Theme::Integer_ButtonFadeOutDelay))); + const double nDuration (mrSlideSorter.GetTheme()->GetIntegerValue(bFadeIn + ? Theme::Integer_ButtonFadeInDuration + : Theme::Integer_ButtonFadeOutDuration)); + pDescriptor->GetVisualState().SetButtonAlphaAnimationId( + mrSlideSorter.GetController().GetAnimator()->AddAnimation( + ::boost::bind( + controller::AnimationFunction::ApplyButtonAlphaChange, + pDescriptor, + ::boost::ref(mrSlideSorter.GetView()), + ::boost::bind(aButtonBlendFunctor, _1), + ::boost::bind(aButtonBarBlendFunctor, _1)), + nDelay, + nDuration, + ::boost::bind( + &model::VisualState::SetButtonAlphaAnimationId, + ::boost::ref(pDescriptor->GetVisualState()), + controller::Animator::NotAnAnimationId) + )); +} + + + + +void ButtonBar::AcquireLock (void) +{ + if (mnLockCount == 0 && mpDescriptor) + RequestFadeOut(mpDescriptor, true); + + ++mnLockCount; +} + + + + +void ButtonBar::ReleaseLock (void) +{ + --mnLockCount; + + if (mnLockCount == 0 && mpDescriptor) + RequestFadeIn(mpDescriptor, true); +} + + + + +//===== BackgroundTheme ===================================================== + +ButtonBar::BackgroundTheme::BackgroundTheme ( + const ::boost::shared_ptr<Theme>& rpTheme, + const ::std::vector<SharedButton>& rButtons) + : mpTheme(rpTheme) +{ + UpdateMinimumIconSizes(rButtons); +} + + + + +void ButtonBar::BackgroundTheme::SetPreviewBoundingBox (const Rectangle& rPreviewBoundingBox) +{ + maPreviewBoundingBox = rPreviewBoundingBox; + Layout(); +} + + + + +void ButtonBar::BackgroundTheme::UpdateMinimumIconSizes ( + const ::std::vector<SharedButton>& rButtons) +{ + OSL_ASSERT(mpTheme); + + sal_Int32 nMaximumHeightLarge (0); + sal_Int32 nMaximumHeightMedium (0); + sal_Int32 nMaximumHeightSmall (0); + const sal_Int32 nGap (mpTheme->GetIntegerValue(Theme::Integer_ButtonGap)); + const sal_Int32 nBorder (mpTheme->GetIntegerValue(Theme::Integer_ButtonBorder)); + sal_Int32 nTotalWidthLarge ((rButtons.size()-1) * nGap + 2*nBorder); + sal_Int32 nTotalWidthMedium ((rButtons.size()-1) * nGap + 2*nBorder); + sal_Int32 nTotalWidthSmall ((rButtons.size()-1) * nGap + 2*nBorder); + for (sal_uInt32 nIndex=0; nIndex<rButtons.size(); ++nIndex) + { + // Update large size. + Size aSize = rButtons[nIndex]->GetSize(Button::IconSize_Large); + if (aSize.Height() > nMaximumHeightLarge) + nMaximumHeightLarge = aSize.Height(); + nTotalWidthLarge += aSize.Width(); + + // Update medium size. + aSize = rButtons[nIndex]->GetSize(Button::IconSize_Medium); + if (aSize.Height() > nMaximumHeightMedium) + nMaximumHeightMedium = aSize.Height(); + nTotalWidthMedium += aSize.Width(); + + // Update small size. + aSize = rButtons[nIndex]->GetSize(Button::IconSize_Small); + if (aSize.Height() > nMaximumHeightSmall) + nMaximumHeightSmall = aSize.Height(); + nTotalWidthSmall += aSize.Width(); + } + maMinimumLargeButtonAreaSize = Size(nTotalWidthLarge, nMaximumHeightLarge+2*nBorder); + maMinimumMediumButtonAreaSize = Size(nTotalWidthMedium, nMaximumHeightMedium+2*nBorder); + maMinimumSmallButtonAreaSize = Size(nTotalWidthSmall, nMaximumHeightSmall+2*nBorder); +} + + + + +Button::IconSize ButtonBar::BackgroundTheme::GetIconSize (void) const +{ + return meIconSize; +} + + + + +//===== RectangleBackgroundTheme ============================================ + +RectangleBackgroundTheme::RectangleBackgroundTheme ( + const ::boost::shared_ptr<Theme>& rpTheme, + const ::std::vector<SharedButton>& rButtons) + : BackgroundTheme(rpTheme, rButtons), + mnBarHeight(0) +{ +} + + + + +BitmapEx RectangleBackgroundTheme::CreateBackground ( + const OutputDevice& rTemplateDevice, + const bool bIsButtonDown) const +{ + OSL_ASSERT(mpTheme); + + // Setup background color. + Color aTopFillColor (mpTheme->GetGradientColor( + Theme::Gradient_ButtonBackground, + Theme::Fill1)); + Color aTopBorderColor (mpTheme->GetGradientColor( + Theme::Gradient_ButtonBackground, + Theme::Border1)); + Color aBottomFillColor (mpTheme->GetGradientColor( + Theme::Gradient_ButtonBackground, + Theme::Fill2)); + Color aBottomBorderColor (mpTheme->GetGradientColor( + Theme::Gradient_ButtonBackground, + Theme::Border2)); + if (bIsButtonDown) + { + aTopFillColor.DecreaseLuminance(50); + aTopBorderColor.DecreaseLuminance(50); + aBottomFillColor.DecreaseLuminance(50); + aBottomBorderColor.DecreaseLuminance(50); + } + + const int nWidth (maPreviewBoundingBox.GetWidth()+2); + const int nHeight (mnBarHeight); + const int nCenter (nHeight / 2); + + VirtualDevice aDevice (rTemplateDevice, 0, 8); + aDevice.SetOutputSizePixel(Size(nWidth,nHeight)); + + // Fill upper and lower half. + aDevice.SetLineColor(); + aDevice.SetFillColor(aTopFillColor); + aDevice.DrawRect(Rectangle(0,0,nWidth-1,nCenter)); + aDevice.SetFillColor(aBottomFillColor); + aDevice.DrawRect(Rectangle(0,nCenter,nWidth-1,nHeight-1)); + + // Draw border. + aDevice.SetFillColor(); + aDevice.SetLineColor(aTopBorderColor); + aDevice.DrawLine(Point(0,nCenter),Point(0,0)); + aDevice.DrawLine(Point(0,0), Point(nWidth-1,0)); + aDevice.DrawLine(Point(nWidth-1,0),Point(nWidth-1,nCenter)); + aDevice.SetLineColor(aBottomBorderColor); + aDevice.DrawLine(Point(0,nCenter),Point(0,nHeight-1)); + aDevice.DrawLine(Point(0,nHeight-1), Point(nWidth-1,nHeight-1)); + aDevice.DrawLine(Point(nWidth-1,nHeight-1),Point(nWidth-1,nCenter)); + + return aDevice.GetBitmapEx(Point(0,0), Size(nWidth,nHeight)); +} + + + + +Point RectangleBackgroundTheme::GetBackgroundLocation (void) +{ + return Point( + maPreviewBoundingBox.Left()-1, + maPreviewBoundingBox.Bottom() - mnBarHeight + 2); +} + + + + +Rectangle RectangleBackgroundTheme::GetButtonArea (void) +{ + return Rectangle( + maPreviewBoundingBox.Left(), + maPreviewBoundingBox.Bottom() - mnBarHeight + 2, + maPreviewBoundingBox.Right(), + maPreviewBoundingBox.Bottom()); +} + + + + +void RectangleBackgroundTheme::Layout (void) +{ + if (maPreviewBoundingBox.GetWidth() < maMinimumLargeButtonAreaSize.Width()) + if (maPreviewBoundingBox.GetWidth() < maMinimumMediumButtonAreaSize.Width()) + { + meIconSize = Button::IconSize_Small; + mnBarHeight = maMinimumSmallButtonAreaSize.Height(); + } + else + { + meIconSize = Button::IconSize_Medium; + mnBarHeight = maMinimumMediumButtonAreaSize.Height(); + } + else + { + meIconSize = Button::IconSize_Large; + mnBarHeight = maMinimumLargeButtonAreaSize.Height(); + } +} + + + + +//===== BitmapBackgroundTheme ================================================= + +BitmapBackgroundTheme::BitmapBackgroundTheme ( + const ::boost::shared_ptr<Theme>& rpTheme, + const ::std::vector<SharedButton>& rButtons) + : BackgroundTheme(rpTheme, rButtons), + maButtonArea(), + maBackgroundLocation() +{ +} + + + + +BitmapEx BitmapBackgroundTheme::CreateBackground ( + const OutputDevice& rTemplateDevice, + const bool bIsButtonDown) const +{ + (void)rTemplateDevice; + (void)bIsButtonDown; + + OSL_ASSERT(mpTheme); + + // Get images. + switch (meIconSize) + { + case Button::IconSize_Large: + default: + return mpTheme->GetIcon(Theme::Icon_ButtonBarLarge); + + case Button::IconSize_Medium: + return mpTheme->GetIcon(Theme::Icon_ButtonBarMedium); + + case Button::IconSize_Small: + return mpTheme->GetIcon(Theme::Icon_ButtonBarSmall); + } +} + + + + +Point BitmapBackgroundTheme::GetBackgroundLocation (void) +{ + return maBackgroundLocation; +} + + + + +Rectangle BitmapBackgroundTheme::GetButtonArea (void) +{ + return maButtonArea; +} + + + + +void BitmapBackgroundTheme::Layout (void) +{ + Size aImageSize (mpTheme->GetIcon(Theme::Icon_ButtonBarLarge).GetSizePixel()); + if (aImageSize.Width() >= maPreviewBoundingBox.GetWidth()) + { + aImageSize = mpTheme->GetIcon(Theme::Icon_ButtonBarMedium).GetSizePixel(); + if (aImageSize.Width() >= maPreviewBoundingBox.GetWidth()) + { + meIconSize = Button::IconSize_Small; + aImageSize = mpTheme->GetIcon(Theme::Icon_ButtonBarSmall).GetSizePixel(); + } + else + meIconSize = Button::IconSize_Medium; + } + else + { + meIconSize = Button::IconSize_Large; + } + + maBackgroundLocation = Point( + maPreviewBoundingBox.Left() + + (maPreviewBoundingBox.GetWidth()-aImageSize.Width())/2, + maPreviewBoundingBox.Bottom() - aImageSize.Height()); + maButtonArea = Rectangle(maBackgroundLocation, aImageSize); +} + + + + +//===== Button ================================================================ + +Button::Button ( + SlideSorter& rSlideSorter, + const ::rtl::OUString& rsHelpText) + : mrSlideSorter(rSlideSorter), + meState(State_Normal), + maBoundingBox(), + msHelpText(rsHelpText), + mbIsActive(false), + meIconSize(IconSize_Large) +{ +} + + + + +Button::~Button (void) +{ +} + + + + +bool Button::SetState (const State eState) +{ + if (meState != eState) + { + meState = eState; + return true; + } + else + return false; +} + + + + +Button::State Button::GetState (void) const +{ + return meState; +} + + + + +Rectangle Button::GetBoundingBox (void) const +{ + if (mbIsActive) + return maBoundingBox; + else + return Rectangle(); +} + + + + +::rtl::OUString Button::GetHelpText (void) const +{ + if (mbIsActive) + return msHelpText; + else + return ::rtl::OUString(); +} + + + + +bool Button::IsDown (void) const +{ + return mbIsActive && meState==State_Down; +} + + + + +void Button::SetActiveState (const bool bIsActive) +{ + mbIsActive = bIsActive; +} + + + + +bool Button::IsActive (void) const +{ + return mbIsActive; +} + + + + +void Button::SetIconSize (const IconSize eIconSize) +{ + meIconSize = eIconSize; +} + + + + +Button::IconSize Button::GetIconSize (void) const +{ + return meIconSize; +} + + + + +bool Button::IsEnabled (void) const +{ + return true; +} + + + + +//===== TextButton ============================================================ + +TextButton::TextButton ( + SlideSorter& rSlideSorter, + const ::rtl::OUString& rsText, + const ::rtl::OUString& rsHelpText) + : Button(rSlideSorter, rsHelpText), + msText(rsText) +{ +} + + + + +void TextButton::Place (const Rectangle aButtonBarBox) +{ + maBoundingBox = aButtonBarBox; + SetActiveState(true); +} + + + + +void TextButton::Paint ( + OutputDevice& rDevice, + const Point aOffset, + const double nAlpha, + const ::boost::shared_ptr<Theme>& rpTheme) const +{ + (void)nAlpha; + + if (mbIsActive) + { + // Paint text over the button background. + if (meState == State_Normal) + rDevice.SetTextColor(rpTheme->GetColor(Theme::Color_ButtonText)); + else + rDevice.SetTextColor(rpTheme->GetColor(Theme::Color_ButtonTextHover)); + Rectangle aBox (maBoundingBox); + aBox += aOffset; + rDevice.DrawText(aBox, msText, TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER); + } +} + + + + +Size TextButton::GetSize (void) const +{ + return Size(); +} + + + + +Size TextButton::GetSize (const Button::IconSize) const +{ + return Size(); +} + + + + +//===== ImageButon ============================================================ + +ImageButton::ImageButton ( + SlideSorter& rSlideSorter, + const BitmapEx& rLargeIcon, + const BitmapEx& rLargeHoverIcon, + const BitmapEx& rMediumIcon, + const BitmapEx& rMediumHoverIcon, + const BitmapEx& rSmallIcon, + const BitmapEx& rSmallHoverIcon, + const ::rtl::OUString& rsHelpText) + : Button(rSlideSorter, rsHelpText), + maLargeIcon(rLargeIcon), + maLargeHoverIcon(rLargeHoverIcon.IsEmpty() ? rLargeIcon : rLargeHoverIcon), + maMediumIcon(rMediumIcon), + maMediumHoverIcon(rMediumHoverIcon.IsEmpty() ? rMediumIcon : rMediumHoverIcon), + maSmallIcon(rSmallIcon), + maSmallHoverIcon(rSmallHoverIcon.IsEmpty() ? rSmallIcon : rSmallHoverIcon) +{ +} + + + + +void ImageButton::Place (const Rectangle aButtonBarBox) +{ + const sal_Int32 nWidth (GetSize().Width()); + maBoundingBox = Rectangle( + aButtonBarBox.Right() - nWidth, + aButtonBarBox.Top(), + aButtonBarBox.Right(), + aButtonBarBox.Bottom()); + SetActiveState(aButtonBarBox.IsInside(maBoundingBox)); +} + + + + +void ImageButton::Paint ( + OutputDevice& rDevice, + const Point aOffset, + const double nAlpha, + const ::boost::shared_ptr<Theme>& rpTheme) const +{ + (void)rpTheme; + + if ( ! mbIsActive) + return; + + const USHORT nSavedAntialiasingMode (rDevice.GetAntialiasing()); + rDevice.SetAntialiasing(nSavedAntialiasingMode | ANTIALIASING_ENABLE_B2DDRAW); + + rDevice.SetLineColor(); + + // Choose icon. + BitmapEx aIcon; + switch (meIconSize) + { + case IconSize_Large: + default: + if (meState == State_Normal) + aIcon = maLargeIcon; + else + aIcon = maLargeHoverIcon; + break; + + case IconSize_Medium: + if (meState == State_Normal) + aIcon = maMediumIcon; + else + aIcon = maMediumHoverIcon; + break; + + case IconSize_Small: + if (meState == State_Normal) + aIcon = maSmallIcon; + else + aIcon = maSmallHoverIcon; + break; + } + + // Paint icon. + if ( ! aIcon.IsEmpty()) + { + AlphaMask aMask (aIcon.GetSizePixel()); + AdaptTransparency(aMask, aIcon.GetAlpha(), nAlpha); + rDevice.DrawBitmapEx( + Point( + maBoundingBox.Left() + + aOffset.X() + + (maBoundingBox.GetWidth()-aIcon.GetSizePixel().Width())/2, + maBoundingBox.Top() + + aOffset.Y() + + (maBoundingBox.GetHeight()-aIcon.GetSizePixel().Height())/2), + BitmapEx(aIcon.GetBitmap(), aMask)); + } + + rDevice.SetAntialiasing(nSavedAntialiasingMode); +} + + + + +Size ImageButton::GetSize (void) const +{ + return GetSize(meIconSize); +} + + + + +Size ImageButton::GetSize (const Button::IconSize eIconSize) const +{ + switch (eIconSize) + { + case IconSize_Large: + default: + return maLargeIcon.GetSizePixel(); + + case IconSize_Medium: + return maMediumIcon.GetSizePixel(); + + case IconSize_Small: + return maSmallIcon.GetSizePixel(); + } +} + + + + +//===== UnhideButton ========================================================== + +UnhideButton::UnhideButton (SlideSorter& rSlideSorter) + : ImageButton( + rSlideSorter, + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BLarge), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BLargeHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BMedium), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BMediumHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BSmall), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BSmallHover), + rSlideSorter.GetTheme()->GetString(Theme::String_Command2B)) +{ +} + + + + +void UnhideButton::ProcessClick (const model::SharedPageDescriptor& rpDescriptor) +{ + if ( ! rpDescriptor) + return; + mrSlideSorter.GetController().GetSlotManager()->ChangeSlideExclusionState( + (rpDescriptor->HasState(model::PageDescriptor::ST_Selected) + ? model::SharedPageDescriptor() + : rpDescriptor), + false); +} + + + + +//===== StartSlideShowButton ================================================== + +StartShowButton::StartShowButton (SlideSorter& rSlideSorter) + : ImageButton( + rSlideSorter, + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1Large), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1LargeHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1Medium), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1MediumHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1Small), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1SmallHover), + rSlideSorter.GetTheme()->GetString(Theme::String_Command1)) +{ +} + + + + +bool StartShowButton::IsEnabled (void) const +{ + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell == NULL) + return false; + SfxDispatcher* pDispatcher = pViewShell->GetDispatcher(); + if (pDispatcher == NULL) + return false; + + const SfxPoolItem* pState = NULL; + const SfxItemState eState (pDispatcher->QueryState(SID_PRESENTATION, pState)); + return (eState & SFX_ITEM_DISABLED) == 0; +} + + + + +void StartShowButton::ProcessClick (const model::SharedPageDescriptor& rpDescriptor) +{ + // Hide the tool tip early, while the slide show still intializes. + mrSlideSorter.GetView().GetToolTip().SetPage(model::SharedPageDescriptor()); + + Reference< XPresentation2 > xPresentation( + mrSlideSorter.GetModel().GetDocument()->getPresentation()); + if (xPresentation.is()) + { + Sequence<PropertyValue> aProperties (1); + aProperties[0].Name = ::rtl::OUString::createFromAscii("FirstPage"); + const ::rtl::OUString sName (rpDescriptor->GetPage()->GetName()); + aProperties[0].Value = Any(sName); + xPresentation->startWithArguments(aProperties); + } +} + + + + +//===== HideButton ============================================================ + +HideButton::HideButton (SlideSorter& rSlideSorter) + : ImageButton( + rSlideSorter, + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2Large), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2LargeHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2Medium), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2MediumHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2Small), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2SmallHover), + rSlideSorter.GetTheme()->GetString(Theme::String_Command2)) +{ +} + + + + +void HideButton::ProcessClick (const model::SharedPageDescriptor& rpDescriptor) +{ + if ( ! rpDescriptor) + return; + mrSlideSorter.GetController().GetSlotManager()->ChangeSlideExclusionState( + (rpDescriptor->HasState(model::PageDescriptor::ST_Selected) + ? model::SharedPageDescriptor() + : rpDescriptor), + true); +} + + + + +//===== DuplicateButton ======================================================= + +DuplicateButton::DuplicateButton (SlideSorter& rSlideSorter) + : ImageButton( + rSlideSorter, + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3Large), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3LargeHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3Medium), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3MediumHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3Small), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3SmallHover), + rSlideSorter.GetTheme()->GetString(Theme::String_Command3)) +{ +} + + + + +bool DuplicateButton::IsEnabled (void) const +{ + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell == NULL) + return false; + SfxDispatcher* pDispatcher = pViewShell->GetDispatcher(); + if (pDispatcher == NULL) + return false; + + const SfxPoolItem* pState = NULL; + const SfxItemState eState (pDispatcher->QueryState( + SID_DUPLICATE_PAGE, + pState)); + return (eState & SFX_ITEM_DISABLED) == 0; +} + + + + +void DuplicateButton::ProcessClick (const model::SharedPageDescriptor& rpDescriptor) +{ + if ( ! rpDescriptor) + return; + + mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor(),false); + + // When the page under the button is not selected then set the + // selection to just this page. + if ( ! rpDescriptor->HasState(model::PageDescriptor::ST_Selected)) + { + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); + } + // Duplicate the selected pages. Insert the new pages right + // after the current selection and select them + if (mrSlideSorter.GetViewShell() != NULL + && mrSlideSorter.GetViewShell()->GetDispatcher() != NULL) + { + mrSlideSorter.GetViewShell()->GetDispatcher()->Execute( + SID_DUPLICATE_PAGE, + SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD); + } +} + + + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsFramePainter.cxx b/sd/source/ui/slidesorter/view/SlsFramePainter.cxx new file mode 100644 index 000000000000..c62c32e7d841 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsFramePainter.cxx @@ -0,0 +1,265 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsFramePainter.hxx" +#include <vcl/outdev.hxx> +#include <vcl/bmpacc.hxx> + + +namespace sd { namespace slidesorter { namespace view { + +FramePainter::FramePainter (const BitmapEx& rShadowBitmap) + : maTopLeft(rShadowBitmap,-1,-1), + maTop(rShadowBitmap,0,-1), + maTopRight(rShadowBitmap,+1,-1), + maLeft(rShadowBitmap,-1,0), + maRight(rShadowBitmap,+1,0), + maBottomLeft(rShadowBitmap,-1,+1), + maBottom(rShadowBitmap,0,+1), + maBottomRight(rShadowBitmap,+1,+1), + maCenter(rShadowBitmap,0,0), + mbIsValid(false) +{ + if (rShadowBitmap.GetSizePixel().Width() == rShadowBitmap.GetSizePixel().Height() + && (rShadowBitmap.GetSizePixel().Width()-1)%2 == 0 + && ((rShadowBitmap.GetSizePixel().Width()-1)/2)%2 == 1) + { + mbIsValid = true; + } + else + { + OSL_ASSERT(rShadowBitmap.GetSizePixel().Width() == rShadowBitmap.GetSizePixel().Height()); + OSL_ASSERT((rShadowBitmap.GetSizePixel().Width()-1)%2 == 0); + OSL_ASSERT(((rShadowBitmap.GetSizePixel().Width()-1)/2)%2 == 1); + } +} + + + + +FramePainter::~FramePainter (void) +{ +} + + + + +void FramePainter::PaintFrame ( + OutputDevice& rDevice, + const Rectangle aBox) const +{ + if ( ! mbIsValid) + return; + + // Paint the shadow. + maTopLeft.PaintCorner(rDevice, aBox.TopLeft()); + maTopRight.PaintCorner(rDevice, aBox.TopRight()); + maBottomLeft.PaintCorner(rDevice, aBox.BottomLeft()); + maBottomRight.PaintCorner(rDevice, aBox.BottomRight()); + maLeft.PaintSide(rDevice, aBox.TopLeft(), aBox.BottomLeft(), maTopLeft, maBottomLeft); + maRight.PaintSide(rDevice, aBox.TopRight(), aBox.BottomRight(), maTopRight, maBottomRight); + maTop.PaintSide(rDevice, aBox.TopLeft(), aBox.TopRight(), maTopLeft, maTopRight); + maBottom.PaintSide(rDevice, aBox.BottomLeft(), aBox.BottomRight(), maBottomLeft, maBottomRight); + maCenter.PaintCenter(rDevice,aBox); +} + + + + +void FramePainter::AdaptColor ( + const Color aNewColor, + const bool bEraseCenter) +{ + // Get the source color. + if (maCenter.maBitmap.IsEmpty()) + return; + BitmapReadAccess* pReadAccess = maCenter.maBitmap.GetBitmap().AcquireReadAccess(); + if (pReadAccess == NULL) + return; + const Color aSourceColor = pReadAccess->GetColor(0,0); + maCenter.maBitmap.GetBitmap().ReleaseAccess(pReadAccess); + + // Erase the center bitmap. + if (bEraseCenter) + maCenter.maBitmap.SetEmpty(); + + // Replace the color in all bitmaps. + maTopLeft.maBitmap.Replace(aSourceColor, aNewColor, 0); + maTop.maBitmap.Replace(aSourceColor, aNewColor, 0); + maTopRight.maBitmap.Replace(aSourceColor, aNewColor, 0); + maLeft.maBitmap.Replace(aSourceColor, aNewColor, 0); + maCenter.maBitmap.Replace(aSourceColor, aNewColor, 0); + maRight.maBitmap.Replace(aSourceColor, aNewColor, 0); + maBottomLeft.maBitmap.Replace(aSourceColor, aNewColor, 0); + maBottom.maBitmap.Replace(aSourceColor, aNewColor, 0); + maBottomRight.maBitmap.Replace(aSourceColor, aNewColor, 0); +} + + + + +//===== FramePainter::OffsetBitmap ============================================ + +FramePainter::OffsetBitmap::OffsetBitmap ( + const BitmapEx& rBitmap, + const sal_Int32 nHorizontalPosition, + const sal_Int32 nVerticalPosition) + : maBitmap(), + maOffset() +{ + OSL_ASSERT(nHorizontalPosition>=-1 && nHorizontalPosition<=+1); + OSL_ASSERT(nVerticalPosition>=-1 && nVerticalPosition<=+1); + + const sal_Int32 nS (1); + const sal_Int32 nC (::std::max<sal_Int32>(0,(rBitmap.GetSizePixel().Width()-nS)/2)); + const sal_Int32 nO (nC/2); + + const Point aOrigin( + nHorizontalPosition<0 ? 0 : (nHorizontalPosition == 0 ? nC : nC+nS), + nVerticalPosition<0 ? 0 : (nVerticalPosition == 0 ? nC : nC+nS)); + const Size aSize( + nHorizontalPosition==0 ? nS : nC, + nVerticalPosition==0 ? nS : nC); + maBitmap = BitmapEx(rBitmap, aOrigin, aSize); + if (maBitmap.IsEmpty()) + return; + maOffset = Point( + nHorizontalPosition<0 ? -nO : nHorizontalPosition>0 ? -nO : 0, + nVerticalPosition<0 ? -nO : nVerticalPosition>0 ? -nO : 0); + + // Enlarge the side bitmaps so that painting the frame requires less + // paint calls. + const sal_Int32 nSideBitmapSize (64); + if (nHorizontalPosition == 0 && nVerticalPosition == 0) + { + maBitmap.Scale(Size(nSideBitmapSize,nSideBitmapSize), BMP_SCALE_FAST); + } + else if (nHorizontalPosition == 0) + { + maBitmap.Scale(Size(nSideBitmapSize,aSize.Height()), BMP_SCALE_FAST); + } + else if (nVerticalPosition == 0) + { + maBitmap.Scale(Size(maBitmap.GetSizePixel().Width(), nSideBitmapSize), BMP_SCALE_FAST); + } +} + + + + +void FramePainter::OffsetBitmap::PaintCorner ( + OutputDevice& rDevice, + const Point& rAnchor) const +{ + if ( ! maBitmap.IsEmpty()) + rDevice.DrawBitmapEx(rAnchor+maOffset, maBitmap); +} + + + + +void FramePainter::OffsetBitmap::PaintSide ( + OutputDevice& rDevice, + const Point& rAnchor1, + const Point& rAnchor2, + const OffsetBitmap& rCornerBitmap1, + const OffsetBitmap& rCornerBitmap2) const +{ + if (maBitmap.IsEmpty()) + return; + + const Size aBitmapSize (maBitmap.GetSizePixel()); + if (rAnchor1.Y() == rAnchor2.Y()) + { + // Side is horizontal. + const sal_Int32 nY (rAnchor1.Y() + maOffset.Y()); + const sal_Int32 nLeft ( + rAnchor1.X() + + rCornerBitmap1.maBitmap.GetSizePixel().Width() + + rCornerBitmap1.maOffset.X()); + const sal_Int32 nRight ( + rAnchor2.X() + + rCornerBitmap2.maOffset.X()\ + - 1); + for (sal_Int32 nX=nLeft; nX<=nRight; nX+=aBitmapSize.Width()) + { + rDevice.DrawBitmapEx( + Point(nX,nY), + Size(std::min(aBitmapSize.Width(),static_cast<long>(nRight-nX+1)),aBitmapSize.Height()), + maBitmap); + } + } + else if (rAnchor1.X() == rAnchor2.X()) + { + // Side is vertical. + const sal_Int32 nX (rAnchor1.X() + maOffset.X()); + const sal_Int32 nTop ( + rAnchor1.Y() + + rCornerBitmap1.maBitmap.GetSizePixel().Height() + + rCornerBitmap1.maOffset.Y()); + const sal_Int32 nBottom ( + rAnchor2.Y() + + rCornerBitmap2.maOffset.Y() + - 1); + for (sal_Int32 nY=nTop; nY<=nBottom; nY+=aBitmapSize.Height()) + { + rDevice.DrawBitmapEx( + Point(nX,nY), + Size(aBitmapSize.Width(), std::min(aBitmapSize.Height(), static_cast<long>(nBottom-nY+1))), + maBitmap); + } + } + else + { + // Diagonal sides indicatee an error. + OSL_ASSERT(false); + } +} + + + + +void FramePainter::OffsetBitmap::PaintCenter ( + OutputDevice& rDevice, + const Rectangle& rBox) const +{ + const Size aBitmapSize (maBitmap.GetSizePixel()); + for (sal_Int32 nY=rBox.Top(); nY<=rBox.Bottom(); nY+=aBitmapSize.Height()) + for (sal_Int32 nX=rBox.Left(); nX<=rBox.Right(); nX+=aBitmapSize.Width()) + rDevice.DrawBitmapEx( + Point(nX,nY), + Size( + ::std::min(aBitmapSize.Width(), rBox.Right()-nX+1), + std::min(aBitmapSize.Height(), rBox.Bottom()-nY+1)), + maBitmap); +} + + + +} } } // end of namespace sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsFramePainter.hxx b/sd/source/ui/slidesorter/view/SlsFramePainter.hxx new file mode 100644 index 000000000000..96ccf51c6323 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsFramePainter.hxx @@ -0,0 +1,121 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_FRAME_PAINTER_HXX +#define SD_SLIDESORTER_VIEW_FRAME_PAINTER_HXX + +#include <vcl/bitmapex.hxx> + + +namespace sd { namespace slidesorter { namespace view { + +class FramePainter +{ +public: + FramePainter (const BitmapEx& rBitmap); + ~FramePainter (void); + + /** Paint a border around the given box by using a set of bitmaps for + the corners and sides. + */ + void PaintFrame (OutputDevice&rDevice, const Rectangle aBox) const; + + /** Special functionality that takes the color from the center + bitmap and replaces that color in all bitmaps by the given new + color. Alpha values are not modified. + @param bClearCenterBitmap + When <TRUE/> then the center bitmap is erased. + */ + void AdaptColor (const Color aNewColor, const bool bClearCenterBitmap); + +private: + /** Bitmap with offset that is used when the bitmap is painted. The bitmap + */ + class OffsetBitmap { + public: + BitmapEx maBitmap; + Point maOffset; + + /** Create one of the eight shadow bitmaps from one that combines + them all. This larger bitmap is expected to have dimension NxN + with N=1+2*M. Of this larger bitmap there are created four + corner bitmaps of size 2*M x 2*M and four side bitmaps of sizes + 1xM (top and bottom) and Mx1 (left and right). The corner + bitmaps have each one quadrant of size MxM that is painted under + the interior of the frame. + @param rBitmap + The larger bitmap of which the eight shadow bitmaps are cut + out from. + @param nHorizontalPosition + Valid values are -1 (left), 0 (center), and +1 (right). + @param nVerticalPosition + Valid values are -1 (top), 0 (center), and +1 (bottom). + */ + OffsetBitmap ( + const BitmapEx& rBitmap, + const sal_Int32 nHorizontalPosition, + const sal_Int32 nVerticalPosition); + + /** Use the given device to paint the bitmap at the location that is + the sum of the given anchor and the internal offset. + */ + void PaintCorner (OutputDevice& rDevice, const Point& rAnchor) const; + + /** Use the given device to paint the bitmap stretched between the + two given locations. Offsets of the adjacent corner bitmaps and + the offset of the side bitmap are used to determine the area + that is to be filled with the side bitmap. + */ + void PaintSide ( + OutputDevice& rDevice, + const Point& rAnchor1, + const Point& rAnchor2, + const OffsetBitmap& rCornerBitmap1, + const OffsetBitmap& rCornerBitmap2) const; + + /** Fill the given rectangle with the bitmap. + */ + void PaintCenter ( + OutputDevice& rDevice, + const Rectangle& rBox) const; + }; + OffsetBitmap maTopLeft; + OffsetBitmap maTop; + OffsetBitmap maTopRight; + OffsetBitmap maLeft; + OffsetBitmap maRight; + OffsetBitmap maBottomLeft; + OffsetBitmap maBottom; + OffsetBitmap maBottomRight; + OffsetBitmap maCenter; + bool mbIsValid; +}; + + +} } } // end of namespace sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/view/SlsInsertAnimator.cxx b/sd/source/ui/slidesorter/view/SlsInsertAnimator.cxx new file mode 100644 index 000000000000..1d98a217ff90 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsInsertAnimator.cxx @@ -0,0 +1,535 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsInsertAnimator.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsAnimationFunction.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" + +#include <set> +#include <boost/bind.hpp> +#include <boost/enable_shared_from_this.hpp> + +namespace sd { namespace slidesorter { namespace view { + +namespace { + +class PageObjectRun; + +class AnimatorAccess +{ +public: + virtual void AddRun (const ::boost::shared_ptr<PageObjectRun> pRun) = 0; + virtual void RemoveRun (const ::boost::shared_ptr<PageObjectRun> pRun) = 0; + virtual model::SlideSorterModel& GetModel (void) const = 0; + virtual view::SlideSorterView& GetView (void) const = 0; + virtual ::boost::shared_ptr<controller::Animator> GetAnimator (void) = 0; + virtual SharedSdWindow GetContentWindow (void) = 0; +}; + + +/** Controller of the position offsets of all page objects in one row or one + column. +*/ +class PageObjectRun : public ::boost::enable_shared_from_this<PageObjectRun> +{ +public: + PageObjectRun ( + AnimatorAccess& rAnimatorAccess, + const sal_Int32 nRunIndex, + const sal_Int32 nStartIndex, + const sal_Int32 nEndIndex); + ~PageObjectRun (void); + + void operator () (const double nTime); + + void UpdateOffsets( + const InsertPosition& rInsertPosition, + const view::Layouter& GetLayouter); + void ResetOffsets (const controller::Animator::AnimationMode eMode); + + /// Index of the row or column that this run represents. + sal_Int32 mnRunIndex; + /// The index at which to make place for the insertion indicator (-1 for + /// no indicator). + sal_Int32 mnLocalInsertIndex; + /// Index of the first page in the run. + sal_Int32 mnStartIndex; + /// Index of the last page in the run. + sal_Int32 mnEndIndex; + /// Offset of each item in the run at the start of the current animation. + ::std::vector<Point> maStartOffset; + /// Target offset of each item in the run at the end of the current animation. + ::std::vector<Point> maEndOffset; + /// Time at which the current animation started. + double mnStartTime; + + class Comparator + { + public: bool operator() ( + const ::boost::shared_ptr<PageObjectRun>& rpRunA, + const ::boost::shared_ptr<PageObjectRun>& rpRunB) const + { + return rpRunA->mnRunIndex < rpRunB->mnRunIndex; + } + }; +private: + controller::Animator::AnimationId mnAnimationId; + AnimatorAccess& mrAnimatorAccess; + ::boost::function<double(double)> maAccelerationFunction; + + Rectangle GetInnerBoundingBox ( + const view::Layouter& rLayouter, + const sal_Int32 nIndex) const; + void RestartAnimation (void); +}; +typedef ::boost::shared_ptr<PageObjectRun> SharedPageObjectRun; + + +Point Blend (const Point& rPointA, const Point& rPointB, const double nT) +{ + return Point( + sal_Int32(rPointA.X() * (1-nT) + rPointB.X() * nT), + sal_Int32(rPointA.Y() * (1-nT) + rPointB.Y() * nT)); +} + +} // end of anonymous namespace + + + +class InsertAnimator::Implementation : public AnimatorAccess +{ +public: + Implementation (SlideSorter& rSlideSorter); + virtual ~Implementation (void); + + void SetInsertPosition ( + const InsertPosition& rInsertPosition, + const controller::Animator::AnimationMode eAnimationMode); + + virtual void AddRun (const ::boost::shared_ptr<PageObjectRun> pRun); + virtual void RemoveRun (const ::boost::shared_ptr<PageObjectRun> pRun); + + virtual model::SlideSorterModel& GetModel (void) const { return mrModel; } + virtual view::SlideSorterView& GetView (void) const { return mrView; } + virtual ::boost::shared_ptr<controller::Animator> GetAnimator (void) { return mpAnimator; } + virtual SharedSdWindow GetContentWindow (void) { return mrSlideSorter.GetContentWindow(); } + +private: + model::SlideSorterModel& mrModel; + view::SlideSorterView& mrView; + SlideSorter& mrSlideSorter; + ::boost::shared_ptr<controller::Animator> mpAnimator; + typedef ::std::set<SharedPageObjectRun, PageObjectRun::Comparator> RunContainer; + RunContainer maRuns; + InsertPosition maInsertPosition; + + void StopAnimation (void); + SharedPageObjectRun GetRun ( + view::Layouter& rLayouter, + const InsertPosition& rInsertPosition, + const bool bCreate = true); + RunContainer::iterator FindRun (const sal_Int32 nRunIndex) const; +}; + + + + + +//===== InsertAnimator ======================================================== + +InsertAnimator::InsertAnimator (SlideSorter& rSlideSorter) + : mpImplementation(new Implementation(rSlideSorter)) +{ +} + + + + +void InsertAnimator::SetInsertPosition (const InsertPosition& rInsertPosition) +{ + mpImplementation->SetInsertPosition(rInsertPosition, controller::Animator::AM_Animated); +} + + + + +void InsertAnimator::Reset (const controller::Animator::AnimationMode eMode) +{ + mpImplementation->SetInsertPosition(InsertPosition(), eMode); +} + + + + +//===== InsertAnimator::Implementation ======================================== + +InsertAnimator::Implementation::Implementation (SlideSorter& rSlideSorter) + : mrModel(rSlideSorter.GetModel()), + mrView(rSlideSorter.GetView()), + mrSlideSorter(rSlideSorter), + mpAnimator(rSlideSorter.GetController().GetAnimator()), + maRuns(), + maInsertPosition() +{ +} + + + + +InsertAnimator::Implementation::~Implementation (void) +{ + SetInsertPosition(InsertPosition(), controller::Animator::AM_Immediate); +} + + + + +void InsertAnimator::Implementation::SetInsertPosition ( + const InsertPosition& rInsertPosition, + const controller::Animator::AnimationMode eMode) +{ + if (maInsertPosition == rInsertPosition) + return; + + SharedPageObjectRun pOldRun (GetRun(mrView.GetLayouter(), maInsertPosition)); + SharedPageObjectRun pCurrentRun (GetRun(mrView.GetLayouter(), rInsertPosition)); + maInsertPosition = rInsertPosition; + + // When the new insert position is in a different run then move the page + // objects in the old run to their default positions. + if (pOldRun != pCurrentRun) + { + if (pOldRun) + pOldRun->ResetOffsets(eMode); + } + + if (pCurrentRun) + { + pCurrentRun->UpdateOffsets(rInsertPosition, mrView.GetLayouter()); + } +} + + + + +SharedPageObjectRun InsertAnimator::Implementation::GetRun ( + view::Layouter& rLayouter, + const InsertPosition& rInsertPosition, + const bool bCreate) +{ + const sal_Int32 nRow (rInsertPosition.GetRow()); + if (nRow < 0) + return SharedPageObjectRun(); + + RunContainer::iterator iRun (maRuns.end()); + if (rLayouter.GetColumnCount() == 1) + { + // There is only one run that contains all slides. + if (maRuns.empty() && bCreate) + maRuns.insert(SharedPageObjectRun(new PageObjectRun( + *this, + 0, + 0, + mrModel.GetPageCount()-1))); + iRun = maRuns.begin(); + } + else + { + iRun = FindRun(nRow); + if (iRun == maRuns.end() && bCreate) + { + // Create a new run. + const sal_Int32 nStartIndex (rLayouter.GetIndex(nRow, 0)); + const sal_Int32 nEndIndex (rLayouter.GetIndex(nRow, rLayouter.GetColumnCount()-1)); + if (nStartIndex <= nEndIndex) + { + iRun = maRuns.insert(SharedPageObjectRun(new PageObjectRun( + *this, + nRow, + nStartIndex, + nEndIndex))).first; + OSL_ASSERT(iRun != maRuns.end()); + } + } + } + + if (iRun != maRuns.end()) + return *iRun; + else + return SharedPageObjectRun(); +} + + + + +InsertAnimator::Implementation::RunContainer::iterator + InsertAnimator::Implementation::FindRun (const sal_Int32 nRunIndex) const +{ + return std::find_if( + maRuns.begin(), + maRuns.end(), + ::boost::bind( + ::std::equal_to<sal_Int32>(), + ::boost::bind(&PageObjectRun::mnRunIndex, _1), + nRunIndex)); +} + + + + +void InsertAnimator::Implementation::AddRun (const ::boost::shared_ptr<PageObjectRun> pRun) +{ + if (pRun) + { + maRuns.insert(pRun); + } + else + { + OSL_ASSERT(pRun); + } +} + + + + + +void InsertAnimator::Implementation::RemoveRun (const ::boost::shared_ptr<PageObjectRun> pRun) +{ + if (pRun) + { + // Do not remove runs that show the space for the insertion indicator. + if (pRun->mnLocalInsertIndex == -1) + { + InsertAnimator::Implementation::RunContainer::iterator iRun (FindRun(pRun->mnRunIndex)); + if (iRun != maRuns.end()) + { + OSL_ASSERT(*iRun == pRun); + maRuns.erase(iRun); + } + } + } + else + { + OSL_ASSERT(pRun); + } +} + + + + + +//===== PageObjectRun ========================================================= + +PageObjectRun::PageObjectRun ( + AnimatorAccess& rAnimatorAccess, + const sal_Int32 nRunIndex, + const sal_Int32 nStartIndex, + const sal_Int32 nEndIndex) + : mnRunIndex(nRunIndex), + mnLocalInsertIndex(-1), + mnStartIndex(nStartIndex), + mnEndIndex(nEndIndex), + maStartOffset(), + maEndOffset(), + mnStartTime(-1), + mnAnimationId(controller::Animator::NotAnAnimationId), + mrAnimatorAccess(rAnimatorAccess), + maAccelerationFunction( + controller::AnimationParametricFunction( + controller::AnimationBezierFunction (0.1,0.7))) +{ + maStartOffset.resize(nEndIndex - nStartIndex + 1); + maEndOffset.resize(nEndIndex - nStartIndex + 1); +} + + + + +PageObjectRun::~PageObjectRun (void) +{ +} + + + + +Rectangle PageObjectRun::GetInnerBoundingBox ( + const view::Layouter& rLayouter, + const sal_Int32 nIndex) const +{ + model::SharedPageDescriptor pDescriptor ( + mrAnimatorAccess.GetModel().GetPageDescriptor(nIndex)); + if (pDescriptor) + if (pDescriptor->HasState(model::PageDescriptor::ST_Selected)) + return rLayouter.GetPageObjectLayouter()->GetBoundingBox( + pDescriptor, + PageObjectLayouter::PageObject, + PageObjectLayouter::ModelCoordinateSystem); + else + return rLayouter.GetPageObjectLayouter()->GetBoundingBox( + pDescriptor, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem); + else + return Rectangle(); +} + + + + +void PageObjectRun::UpdateOffsets( + const InsertPosition& rInsertPosition, + const view::Layouter& rLayouter) +{ + const bool bIsVertical (rLayouter.GetColumnCount()==1); + const sal_Int32 nLocalInsertIndex(bIsVertical + ? rInsertPosition.GetRow() + : rInsertPosition.GetColumn()); + if (nLocalInsertIndex != mnLocalInsertIndex) + { + mnLocalInsertIndex = nLocalInsertIndex; + + model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel()); + const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1); + for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex) + { + model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex)); + if (pDescriptor) + maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset(); + maEndOffset[nIndex] = nIndex < mnLocalInsertIndex + ? rInsertPosition.GetLeadingOffset() + : rInsertPosition.GetTrailingOffset(); + if (bIsVertical) + maEndOffset[nIndex].X() = 0; + else + maEndOffset[nIndex].Y() = 0; + } + RestartAnimation(); + } +} + + + + +void PageObjectRun::ResetOffsets (const controller::Animator::AnimationMode eMode) +{ + mnLocalInsertIndex = -1; + const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1); + model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel()); + view::SlideSorterView& rView (mrAnimatorAccess.GetView()); + for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex) + { + model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex)); + if (pDescriptor) + if (eMode == controller::Animator::AM_Animated) + maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset(); + else + { + const Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox()); + pDescriptor->GetVisualState().SetLocationOffset(Point(0,0)); + rView.RequestRepaint(aOldBoundingBox); + rView.RequestRepaint(pDescriptor); + } + maEndOffset[nIndex] = Point(0,0); + } + if (eMode == controller::Animator::AM_Animated) + RestartAnimation(); + else + mrAnimatorAccess.RemoveRun(shared_from_this()); +} + + + + +void PageObjectRun::RestartAnimation (void) +{ + // Stop the current animation. + if (mnAnimationId != controller::Animator::NotAnAnimationId) + { + mrAnimatorAccess.GetAnimator()->RemoveAnimation(mnAnimationId); + } + + // Restart the animation. + mrAnimatorAccess.AddRun(shared_from_this()); + mnAnimationId = mrAnimatorAccess.GetAnimator()->AddAnimation( + ::boost::ref(*this), + 0, + 300, + ::boost::bind( + &AnimatorAccess::RemoveRun, + ::boost::ref(mrAnimatorAccess), + shared_from_this())); +} + + + + +void PageObjectRun::operator () (const double nGlobalTime) +{ + if (mnStartTime < 0) + mnStartTime = nGlobalTime; + + double nLocalTime (nGlobalTime - mnStartTime); + if (nLocalTime > 1.0) + nLocalTime = 1.0; + nLocalTime = maAccelerationFunction(nLocalTime); + + model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel()); + view::SlideSorterView& rView (mrAnimatorAccess.GetView()); + for (sal_Int32 nIndex=mnStartIndex; nIndex<=mnEndIndex; ++nIndex) + { + model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex)); + if ( ! pDescriptor) + continue; + const Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox()); + pDescriptor->GetVisualState().SetLocationOffset( + Blend( + maStartOffset[nIndex-mnStartIndex], + maEndOffset[nIndex-mnStartIndex], + nLocalTime)); + + // Request a repaint of the old and new bounding box (which largely overlap.) + rView.RequestRepaint(aOldBoundingBox); + rView.RequestRepaint(pDescriptor); + } + + // Call Flush to make + // a) animations a bit more smooth and + // b) on Mac without the Flush a Reset of the page locations is not properly + // visualized when the mouse leaves the window during drag-and-drop. + mrAnimatorAccess.GetContentWindow()->Flush(); +} + + + + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx b/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx new file mode 100644 index 000000000000..abaa5a43b215 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx @@ -0,0 +1,448 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsInsertionIndicatorOverlay.hxx" + +#include "SlideSorter.hxx" +#include "model/SlsPageEnumeration.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsTheme.hxx" +#include "cache/SlsPageCache.hxx" +#include "SlsFramePainter.hxx" +#include "SlsLayeredDevice.hxx" +#include "DrawDocShell.hxx" +#include "drawdoc.hxx" +#include "sdpage.hxx" +#include "sdmod.hxx" + +#include <vcl/virdev.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + + +namespace { + + +static const double gnPreviewOffsetScale = 1.0 / 8.0; + + + +Rectangle GrowRectangle (const Rectangle& rBox, const sal_Int32 nOffset) +{ + return Rectangle ( + rBox.Left() - nOffset, + rBox.Top() - nOffset, + rBox.Right() + nOffset, + rBox.Bottom() + nOffset); +} + +sal_Int32 RoundToInt (const double nValue) { return sal_Int32(::rtl::math::round(nValue)); } + +} // end of anonymous namespace + + +namespace sd { namespace slidesorter { namespace view { + + +//===== InsertionIndicatorOverlay =========================================== + +const static sal_Int32 gnShadowBorder = 3; +const static sal_Int32 gnSuperScaleFactor = 1; + +InsertionIndicatorOverlay::InsertionIndicatorOverlay (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mbIsVisible(false), + mnLayerIndex(2), + mpLayerInvalidator(), + maLocation(), + maIcon(), + maIconOffset(), + mpShadowPainter( + new FramePainter(mrSlideSorter.GetTheme()->GetIcon(Theme::Icon_RawInsertShadow))) +{ +} + + + + +InsertionIndicatorOverlay::~InsertionIndicatorOverlay (void) +{ + Hide(); +} + + + + +void InsertionIndicatorOverlay::Create (const controller::Transferable* pTransferable) +{ + if (pTransferable == NULL) + return; + + sal_Int32 nSelectionCount (0); + if (pTransferable->HasPageBookmarks()) + nSelectionCount = pTransferable->GetPageBookmarks().Count(); + else + { + DrawDocShell* pDataDocShell = dynamic_cast<DrawDocShell*>(&pTransferable->GetDocShell()); + if (pDataDocShell != NULL) + { + SdDrawDocument* pDataDocument = pDataDocShell->GetDoc(); + if (pDataDocument != NULL) + nSelectionCount = pDataDocument->GetSdPageCount(PK_STANDARD); + } + } + Create(pTransferable->GetRepresentatives(), nSelectionCount); +} + + + + +void InsertionIndicatorOverlay::Create ( + const ::std::vector<controller::Transferable::Representative>& rRepresentatives, + const sal_Int32 nSelectionCount) +{ + view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter()); + ::boost::shared_ptr<view::PageObjectLayouter> pPageObjectLayouter ( + rLayouter.GetPageObjectLayouter()); + ::boost::shared_ptr<view::Theme> pTheme (mrSlideSorter.GetTheme()); + const Size aOriginalPreviewSize (pPageObjectLayouter->GetSize( + PageObjectLayouter::Preview, + PageObjectLayouter::WindowCoordinateSystem)); + + const double nPreviewScale (0.5); + const Size aPreviewSize ( + RoundToInt(aOriginalPreviewSize.Width()*nPreviewScale), + RoundToInt(aOriginalPreviewSize.Height()*nPreviewScale)); + const sal_Int32 nOffset ( + RoundToInt(Min(aPreviewSize.Width(),aPreviewSize.Height()) * gnPreviewOffsetScale)); + + // Determine size and offset depending on the number of previews. + sal_Int32 nCount (rRepresentatives.size()); + if (nCount > 0) + --nCount; + Size aIconSize( + aPreviewSize.Width() + 2 * gnShadowBorder + nCount*nOffset, + aPreviewSize.Height() + 2 * gnShadowBorder + nCount*nOffset); + maIconOffset = Point(gnShadowBorder, gnShadowBorder); + + // Create virtual devices for bitmap and mask whose bitmaps later be + // combined to form the BitmapEx of the icon. + VirtualDevice aContent ( + *mrSlideSorter.GetContentWindow(), + 0, + 0); + aContent.SetOutputSizePixel(aIconSize); + + aContent.SetFillColor(); + aContent.SetLineColor(pTheme->GetColor(Theme::Color_PreviewBorder)); + const Point aOffset = PaintRepresentatives(aContent, aPreviewSize, nOffset, rRepresentatives); + + PaintPageCount(aContent, nSelectionCount, aPreviewSize, aOffset); + + maIcon = aContent.GetBitmapEx(Point(0,0), aIconSize); + maIcon.Scale(aIconSize); +} + + + + +void InsertionIndicatorOverlay::SelectRepresentatives ( + model::PageEnumeration& rSelection, + ::std::vector<model::SharedPageDescriptor>& rDescriptors) const +{ + sal_Int32 nCount (0); + while (rSelection.HasMoreElements()) + { + if (nCount++ >= 3) + break; + rDescriptors.push_back(rSelection.GetNextElement()); + } +} + + + + +Point InsertionIndicatorOverlay::PaintRepresentatives ( + OutputDevice& rContent, + const Size aPreviewSize, + const sal_Int32 nOffset, + const ::std::vector<controller::Transferable::Representative>& rRepresentatives) const +{ + const Point aOffset (0,rRepresentatives.size()==1 ? -nOffset : 0); + + // Paint the pages. + Point aPageOffset (0,0); + double nTransparency (0); + const BitmapEx aExclusionOverlay (mrSlideSorter.GetTheme()->GetIcon(Theme::Icon_HideSlideOverlay)); + for (sal_Int32 nIndex=2; nIndex>=0; --nIndex) + { + if (rRepresentatives.size() <= sal_uInt32(nIndex)) + continue; + switch(nIndex) + { + case 0 : + aPageOffset = Point(0, nOffset); + nTransparency = 0.85; + break; + case 1: + aPageOffset = Point(nOffset, 0); + nTransparency = 0.75; + break; + case 2: + aPageOffset = Point(2*nOffset, 2*nOffset); + nTransparency = 0.65; + break; + } + aPageOffset += aOffset; + aPageOffset.X() += gnShadowBorder; + aPageOffset.Y() += gnShadowBorder; + + // Paint the preview. + Bitmap aPreview (rRepresentatives[nIndex].maBitmap); + const Size aSuperSampleSize( + aPreviewSize.Width()*gnSuperScaleFactor, + aPreviewSize.Height()*gnSuperScaleFactor); + aPreview.Scale(aPreviewSize, BMP_SCALE_INTERPOLATE); + rContent.DrawBitmapEx(aPageOffset, aPreview); + + // When the page is marked as excluded from the slide show then + // paint an overlay that visualizes this. + if (rRepresentatives[nIndex].mbIsExcluded) + { + const Region aSavedClipRegion (rContent.GetClipRegion()); + rContent.IntersectClipRegion(Rectangle(aPageOffset, aPreviewSize)); + // Paint bitmap tiled over the preview to mark it as excluded. + const sal_Int32 nIconWidth (aExclusionOverlay.GetSizePixel().Width()); + const sal_Int32 nIconHeight (aExclusionOverlay.GetSizePixel().Height()); + if (nIconWidth>0 && nIconHeight>0) + { + for (sal_Int32 nX=0; nX<aPreviewSize.Width(); nX+=nIconWidth) + for (sal_Int32 nY=0; nY<aPreviewSize.Height(); nY+=nIconHeight) + rContent.DrawBitmapEx(Point(nX,nY)+aPageOffset, aExclusionOverlay); + } + rContent.SetClipRegion(aSavedClipRegion); + } + + // Tone down the bitmap. The further back the darker it becomes. + Rectangle aBox ( + aPageOffset.X(), + aPageOffset.Y(), + aPageOffset.X()+aPreviewSize.Width()-1, + aPageOffset.Y()+aPreviewSize.Height()-1); + rContent.SetFillColor(COL_BLACK); + rContent.SetLineColor(); + rContent.DrawTransparent( + ::basegfx::B2DPolyPolygon(::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle(aBox.Left(), aBox.Top(), aBox.Right()+1, aBox.Bottom()+1), + 0, + 0)), + nTransparency); + + // Draw border around preview. + Rectangle aBorderBox (GrowRectangle(aBox, 1)); + rContent.SetLineColor(COL_GRAY); + rContent.SetFillColor(); + rContent.DrawRect(aBorderBox); + + // Draw shadow around preview. + mpShadowPainter->PaintFrame(rContent, aBorderBox); + } + + return aPageOffset; +} + + + + +void InsertionIndicatorOverlay::PaintPageCount ( + OutputDevice& rDevice, + const sal_Int32 nSelectionCount, + const Size aPreviewSize, + const Point aFirstPageOffset) const +{ + // Paint the number of slides. + ::boost::shared_ptr<view::Theme> pTheme (mrSlideSorter.GetTheme()); + ::boost::shared_ptr<Font> pFont(Theme::GetFont(Theme::Font_PageCount, rDevice)); + if (pFont) + { + ::rtl::OUString sNumber (::rtl::OUString::valueOf(nSelectionCount)); + + // Determine the size of the (painted) text and create a bounding + // box that centers the text on the first preview. + rDevice.SetFont(*pFont); + Rectangle aTextBox; + rDevice.GetTextBoundRect(aTextBox, sNumber); + Point aTextOffset (aTextBox.TopLeft()); + Size aTextSize (aTextBox.GetSize()); + // Place text inside the first page preview. + Point aTextLocation(aFirstPageOffset); + // Center the text. + aTextLocation += Point( + (aPreviewSize.Width()-aTextBox.GetWidth())/2, + (aPreviewSize.Height()-aTextBox.GetHeight())/2); + aTextBox = Rectangle(aTextLocation, aTextSize); + + // Paint background, border and text. + static const sal_Int32 nBorder = 5; + rDevice.SetFillColor(pTheme->GetColor(Theme::Color_Selection)); + rDevice.SetLineColor(pTheme->GetColor(Theme::Color_Selection)); + rDevice.DrawRect(GrowRectangle(aTextBox, nBorder)); + + rDevice.SetFillColor(); + rDevice.SetLineColor(pTheme->GetColor(Theme::Color_PageCountFontColor)); + rDevice.DrawRect(GrowRectangle(aTextBox, nBorder-1)); + + rDevice.SetTextColor(pTheme->GetColor(Theme::Color_PageCountFontColor)); + rDevice.DrawText(aTextBox.TopLeft()-aTextOffset, sNumber); + } +} + + + + +void InsertionIndicatorOverlay::SetLocation (const Point& rLocation) +{ + const Point aTopLeft ( + rLocation - Point( + maIcon.GetSizePixel().Width()/2, + maIcon.GetSizePixel().Height()/2)); + if (maLocation != aTopLeft) + { + const Rectangle aOldBoundingBox (GetBoundingBox()); + + maLocation = aTopLeft; + + if (mpLayerInvalidator && IsVisible()) + { + mpLayerInvalidator->Invalidate(aOldBoundingBox); + mpLayerInvalidator->Invalidate(GetBoundingBox()); + } + } +} + + + + +void InsertionIndicatorOverlay::Paint ( + OutputDevice& rDevice, + const Rectangle& rRepaintArea) +{ + (void)rRepaintArea; + + if ( ! IsVisible()) + return; + + rDevice.DrawImage(maLocation, maIcon); +} + + + + +void InsertionIndicatorOverlay::SetLayerInvalidator (const SharedILayerInvalidator& rpInvalidator) +{ + mpLayerInvalidator = rpInvalidator; + + if (mbIsVisible && mpLayerInvalidator) + mpLayerInvalidator->Invalidate(GetBoundingBox()); +} + + + + +bool InsertionIndicatorOverlay::IsVisible (void) const +{ + return mbIsVisible; +} + + + + +void InsertionIndicatorOverlay::Show (void) +{ + if ( ! mbIsVisible) + { + mbIsVisible = true; + + ::boost::shared_ptr<LayeredDevice> pLayeredDevice ( + mrSlideSorter.GetView().GetLayeredDevice()); + if (pLayeredDevice) + { + pLayeredDevice->RegisterPainter(shared_from_this(), mnLayerIndex); + if (mpLayerInvalidator) + mpLayerInvalidator->Invalidate(GetBoundingBox()); + } + } +} + + + + +void InsertionIndicatorOverlay::Hide (void) +{ + if (mbIsVisible) + { + mbIsVisible = false; + + ::boost::shared_ptr<LayeredDevice> pLayeredDevice ( + mrSlideSorter.GetView().GetLayeredDevice()); + if (pLayeredDevice) + { + if (mpLayerInvalidator) + mpLayerInvalidator->Invalidate(GetBoundingBox()); + pLayeredDevice->RemovePainter(shared_from_this(), mnLayerIndex); + } + } +} + + + + +Rectangle InsertionIndicatorOverlay::GetBoundingBox (void) const +{ + return Rectangle(maLocation, maIcon.GetSizePixel()); +} + + + + +Size InsertionIndicatorOverlay::GetSize (void) const +{ + return Size( + maIcon.GetSizePixel().Width() + 10, + maIcon.GetSizePixel().Height() + 10); +} + + + +} } } // end of namespace ::sd::slidesorter::view + diff --git a/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx b/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx new file mode 100644 index 000000000000..e3303278111f --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx @@ -0,0 +1,565 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsLayeredDevice.hxx" + +#include <vcl/window.hxx> +#include <vcl/virdev.hxx> + +#include <boost/bind.hpp> +#include <boost/function.hpp> + + +namespace sd { namespace slidesorter { namespace view { + +namespace { +static const sal_Int32 gnMaximumLayerCount = 8; + +class LayerInvalidator : public ILayerInvalidator +{ +public: + LayerInvalidator ( + const ::boost::shared_ptr<LayeredDevice>& rpLayeredDevice, + const SharedSdWindow& rpTargetWindow, + const int nLayer) + : mpLayeredDevice(rpLayeredDevice), + mpTargetWindow(rpTargetWindow), + mnLayer(nLayer) + { + } + + virtual void Invalidate (const Rectangle& rInvalidationBox) + { + mpLayeredDevice->Invalidate(rInvalidationBox, mnLayer); + mpTargetWindow->Invalidate(rInvalidationBox); + } + +private: + const ::boost::shared_ptr<LayeredDevice> mpLayeredDevice; + SharedSdWindow mpTargetWindow; + const int mnLayer; +}; + +void DeviceCopy ( + OutputDevice& rTargetDevice, + OutputDevice& rSourceDevice, + const Rectangle& rBox) +{ + rTargetDevice.DrawOutDev( + rBox.TopLeft(), + rBox.GetSize(), + rBox.TopLeft(), + rBox.GetSize(), + rSourceDevice); +} + + +void ForAllRectangles (const Region& rRegion, ::boost::function<void(const Rectangle&)> aFunction) +{ + OSL_ASSERT(aFunction); + + if (rRegion.GetRectCount() <= 1) + { + aFunction(rRegion.GetBoundRect()); + } + else + { + Region aMutableRegionCopy (rRegion); + RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects()); + Rectangle aBox; + while (aMutableRegionCopy.GetNextEnumRect(aHandle, aBox)) + aFunction(aBox); + aMutableRegionCopy.EndEnumRects(aHandle); + } +} + +class Layer : private ::boost::noncopyable +{ +public: + Layer (void); + ~Layer (void); + + void Initialize (const SharedSdWindow& rpTargetWindow); + void InvalidateRectangle (const Rectangle& rInvalidationBox); + void InvalidateRegion (const Region& rInvalidationRegion); + void Validate (const MapMode& rMapMode); + void Repaint ( + OutputDevice& rTargetDevice, + const Rectangle& rRepaintRectangle); + void Resize (const Size& rSize); + void AddPainter (const SharedILayerPainter& rpPainter); + void RemovePainter (const SharedILayerPainter& rpPainter); + bool HasPainter (void) const; + void Dispose (void); + +private: + ::boost::shared_ptr<VirtualDevice> mpLayerDevice; + ::std::vector<SharedILayerPainter> maPainters; + Region maInvalidationRegion; + + void ValidateRectangle (const Rectangle& rBox); +}; +typedef ::boost::shared_ptr<Layer> SharedLayer; + + +} // end of anonymous namespace + + +class LayeredDevice::LayerContainer : public ::std::vector<SharedLayer> +{ +public: + LayerContainer (void) {} + ~LayerContainer (void) {} +}; + + + + +//===== LayeredDevice ========================================================= + +LayeredDevice::LayeredDevice (const SharedSdWindow& rpTargetWindow) + : mpTargetWindow(rpTargetWindow), + mpLayers(new LayerContainer()), + mpBackBuffer(new VirtualDevice(*mpTargetWindow)), + maSavedMapMode(rpTargetWindow->GetMapMode()) +{ + mpBackBuffer->SetOutputSizePixel(mpTargetWindow->GetSizePixel()); +} + + + + +LayeredDevice::~LayeredDevice (void) +{ +} + + + + +void LayeredDevice::Invalidate ( + const Rectangle& rInvalidationArea, + const sal_Int32 nLayer) +{ + if (nLayer<0 || size_t(nLayer)>=mpLayers->size()) + { + OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size()); + return; + } + + (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea); +} + + + + +void LayeredDevice::InvalidateAllLayers (const Rectangle& rInvalidationArea) +{ + for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer) + (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea); +} + + + + +void LayeredDevice::InvalidateAllLayers (const Region& rInvalidationRegion) +{ + for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer) + (*mpLayers)[nLayer]->InvalidateRegion(rInvalidationRegion); +} + + + + +void LayeredDevice::RegisterPainter ( + const SharedILayerPainter& rpPainter, + const sal_Int32 nLayer) +{ + OSL_ASSERT(mpLayers); + if ( ! rpPainter) + { + OSL_ASSERT(rpPainter); + return; + } + if (nLayer<0 || nLayer>=gnMaximumLayerCount) + { + OSL_ASSERT(nLayer>=0 && nLayer<gnMaximumLayerCount); + return; + } + + // Provide the layers. + if (sal_uInt32(nLayer) >= mpLayers->size()) + { + const sal_Int32 nOldLayerCount (mpLayers->size()); + mpLayers->resize(nLayer+1); + + for (size_t nIndex=nOldLayerCount; nIndex<mpLayers->size(); ++nIndex) + (*mpLayers)[nIndex].reset(new Layer()); + } + + (*mpLayers)[nLayer]->AddPainter(rpPainter); + if (nLayer == 0) + (*mpLayers)[nLayer]->Initialize(mpTargetWindow); + + rpPainter->SetLayerInvalidator( + SharedILayerInvalidator(new LayerInvalidator(shared_from_this(),mpTargetWindow,nLayer))); +} + + + + +void LayeredDevice::RemovePainter ( + const SharedILayerPainter& rpPainter, + const sal_Int32 nLayer) +{ + if ( ! rpPainter) + { + OSL_ASSERT(rpPainter); + return; + } + if (nLayer<0 || size_t(nLayer)>=mpLayers->size()) + { + OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size()); + return; + } + + rpPainter->SetLayerInvalidator(SharedILayerInvalidator()); + + (*mpLayers)[nLayer]->RemovePainter(rpPainter); + + // Remove top most layers that do not contain any painters. + while ( ! mpLayers->empty() && ! mpLayers->back()->HasPainter()) + mpLayers->erase(mpLayers->end()-1); +} + + + + +bool LayeredDevice::HasPainter (const sal_Int32 nLayer) +{ + return nLayer>=0 + && sal_uInt32(nLayer)<mpLayers->size() + && (*mpLayers)[nLayer]->HasPainter(); +} + + + + +void LayeredDevice::Repaint (const Region& rRepaintRegion) +{ + // Validate the contents of all layers (that have their own devices.) + ::std::for_each( + mpLayers->begin(), + mpLayers->end(), + ::boost::bind(&Layer::Validate, _1, mpTargetWindow->GetMapMode())); + + ForAllRectangles(rRepaintRegion, ::boost::bind(&LayeredDevice::RepaintRectangle, this, _1)); +} + + + + +void LayeredDevice::RepaintRectangle (const Rectangle& rRepaintRectangle) +{ + if (mpLayers->size() == 0) + return; + else if (mpLayers->size() == 1) + { + // Just copy the main layer into the target device. + (*mpLayers)[0]->Repaint(*mpTargetWindow, rRepaintRectangle); + } + else + { + // Paint all layers first into the back buffer (to avoid flickering + // due to synchronous paints) and then copy that into the target + // device. + mpBackBuffer->SetMapMode(mpTargetWindow->GetMapMode()); + ::std::for_each( + mpLayers->begin(), + mpLayers->end(), + ::boost::bind(&Layer::Repaint, _1, ::boost::ref(*mpBackBuffer), rRepaintRectangle)); + + DeviceCopy(*mpTargetWindow, *mpBackBuffer, rRepaintRectangle); + } +} + + + + +void LayeredDevice::Resize (void) +{ + const Size aSize (mpTargetWindow->GetSizePixel()); + mpBackBuffer->SetOutputSizePixel(aSize); + ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Resize, _1, aSize)); +} + + + + +void LayeredDevice::Dispose (void) +{ + ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Dispose, _1)); + mpLayers->clear(); +} + + + + +bool LayeredDevice::HandleMapModeChange (void) +{ + const MapMode& rMapMode (mpTargetWindow->GetMapMode()); + if (maSavedMapMode == rMapMode) + return false; + + const Rectangle aLogicWindowBox ( + mpTargetWindow->PixelToLogic(Rectangle(Point(0,0), mpTargetWindow->GetSizePixel()))); + if (maSavedMapMode.GetScaleX() != rMapMode.GetScaleX() + || maSavedMapMode.GetScaleY() != rMapMode.GetScaleY() + || maSavedMapMode.GetMapUnit() != rMapMode.GetMapUnit()) + { + // When the scale has changed then we have to paint everything. + InvalidateAllLayers(aLogicWindowBox); + } + else if (maSavedMapMode.GetOrigin() != rMapMode.GetOrigin()) + { + // Window has been scrolled. Adapt contents of backbuffers and + // layer devices. + const Point aDelta (rMapMode.GetOrigin() - maSavedMapMode.GetOrigin()); + mpBackBuffer->CopyArea( + aLogicWindowBox.TopLeft(), + mpTargetWindow->PixelToLogic(Point(0,0), maSavedMapMode), + aLogicWindowBox.GetSize()); + + // Invalidate the area(s) that have been exposed. + const Rectangle aWindowBox (Point(0,0), mpTargetWindow->GetSizePixel()); + if (aDelta.Y() < 0) + InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( + aWindowBox.Left(), + aWindowBox.Bottom()+aDelta.Y(), + aWindowBox.Right(), + aWindowBox.Bottom()))); + else if (aDelta.Y() > 0) + InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( + aWindowBox.Left(), + aWindowBox.Top(), + aWindowBox.Right(), + aWindowBox.Top()+aDelta.Y()))); + if (aDelta.X() < 0) + InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( + aWindowBox.Right()+aDelta.X(), + aWindowBox.Top(), + aWindowBox.Right(), + aWindowBox.Bottom()))); + else if (aDelta.X() > 0) + InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( + aWindowBox.Left(), + aWindowBox.Top(), + aWindowBox.Left()+aDelta.X(), + aWindowBox.Bottom()))); + } + else + { + // Can this happen? Lets trigger a warning when it does. + OSL_ASSERT(false); + } + + maSavedMapMode = rMapMode; + + return true; +} + + + + +//===== Layer ================================================================= + +Layer::Layer (void) + : mpLayerDevice(), + maPainters(), + maInvalidationRegion() +{ +} + + + + +Layer::~Layer (void) +{ +} + + + + +void Layer::Initialize (const SharedSdWindow& rpTargetWindow) +{ +#if 0 + (void)rpTargetWindow; +#else + if ( ! mpLayerDevice) + { + mpLayerDevice.reset(new VirtualDevice(*rpTargetWindow)); + mpLayerDevice->SetOutputSizePixel(rpTargetWindow->GetSizePixel()); + } +#endif +} + + + + +void Layer::InvalidateRectangle (const Rectangle& rInvalidationBox) +{ + maInvalidationRegion.Union(rInvalidationBox); +} + + + + +void Layer::InvalidateRegion (const Region& rInvalidationRegion) +{ + maInvalidationRegion.Union(rInvalidationRegion); +} + + + + +void Layer::Validate (const MapMode& rMapMode) +{ + if (mpLayerDevice && ! maInvalidationRegion.IsEmpty()) + { + Region aRegion (maInvalidationRegion); + maInvalidationRegion.SetEmpty(); + + mpLayerDevice->SetMapMode(rMapMode); + ForAllRectangles( + aRegion, + ::boost::bind(&Layer::ValidateRectangle, this, _1)); + } +} + + + + +void Layer::ValidateRectangle (const Rectangle& rBox) +{ + if ( ! mpLayerDevice) + return; + const Region aSavedClipRegion (mpLayerDevice->GetClipRegion()); + mpLayerDevice->IntersectClipRegion(rBox); + + for (::std::vector<SharedILayerPainter>::const_iterator + iPainter(maPainters.begin()), + iEnd(maPainters.end()); + iPainter!=iEnd; + ++iPainter) + { + (*iPainter)->Paint(*mpLayerDevice, rBox); + } + + mpLayerDevice->SetClipRegion(aSavedClipRegion); +} + + + + +void Layer::Repaint ( + OutputDevice& rTargetDevice, + const Rectangle& rRepaintRectangle) +{ + if (mpLayerDevice) + { + DeviceCopy(rTargetDevice, *mpLayerDevice, rRepaintRectangle); + } + else + { + ::std::for_each( + maPainters.begin(), + maPainters.end(), + ::boost::bind(&ILayerPainter::Paint, + _1, + ::boost::ref(rTargetDevice), + rRepaintRectangle)); + } +} + + + + +void Layer::Resize (const Size& rSize) +{ + if (mpLayerDevice) + { + mpLayerDevice->SetOutputSizePixel(rSize); + maInvalidationRegion = Rectangle(Point(0,0), rSize); + } +} + + + + +void Layer::AddPainter (const SharedILayerPainter& rpPainter) +{ + OSL_ASSERT(::std::find(maPainters.begin(), maPainters.end(), rpPainter) == maPainters.end()); + + maPainters.push_back(rpPainter); +} + + + + +void Layer::RemovePainter (const SharedILayerPainter& rpPainter) +{ + const ::std::vector<SharedILayerPainter>::iterator iPainter ( + ::std::find(maPainters.begin(), maPainters.end(), rpPainter)); + if (iPainter != maPainters.end()) + { + maPainters.erase(iPainter); + } + else + { + DBG_ASSERT(false,"LayeredDevice::RemovePainter called for painter that is not registered"); + } +} + + + + +bool Layer::HasPainter (void) const +{ + return !maPainters.empty(); +} + + + + +void Layer::Dispose (void) +{ + maPainters.clear(); +} + + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsLayeredDevice.hxx b/sd/source/ui/slidesorter/view/SlsLayeredDevice.hxx new file mode 100644 index 000000000000..8b2398221548 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsLayeredDevice.hxx @@ -0,0 +1,99 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_LAYERED_DEVICE_HXX +#define SD_SLIDESORTER_VIEW_LAYERED_DEVICE_HXX + +#include "view/SlsILayerPainter.hxx" +#include "SlideSorter.hxx" + +#include <tools/gen.hxx> +#include <vcl/region.hxx> +#include <vcl/virdev.hxx> + +#include <boost/noncopyable.hpp> +#include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <vector> + +class Window; + +namespace sd { namespace slidesorter { namespace view { + +/** A simple wrapper around an OutputDevice that provides support for + independent layers and buffering. + Each layer may contain any number of painters. +*/ +class LayeredDevice + : public ::boost::enable_shared_from_this<LayeredDevice> + +{ +public: + LayeredDevice (const SharedSdWindow& rpTargetWindow); + ~LayeredDevice (void); + + void Invalidate ( + const Rectangle& rInvalidationBox, + const sal_Int32 nLayer); + void InvalidateAllLayers ( + const Rectangle& rInvalidationBox); + void InvalidateAllLayers ( + const Region& rInvalidationRegion); + + void RegisterPainter ( + const SharedILayerPainter& rPainter, + const sal_Int32 nLayer); + + void RemovePainter ( + const SharedILayerPainter& rPainter, + const sal_Int32 nLayer); + + bool HasPainter (const sal_Int32 nLayer); + + bool HandleMapModeChange (void); + void Repaint (const Region& rRepaintRegion); + + void Resize (void); + + void Dispose (void); + +private: + SharedSdWindow mpTargetWindow; + class LayerContainer; + ::boost::scoped_ptr<LayerContainer> mpLayers; + ::boost::scoped_ptr<VirtualDevice> mpBackBuffer; + MapMode maSavedMapMode; + + void RepaintRectangle (const Rectangle& rRepaintRectangle); +}; + + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/view/SlsLayouter.cxx b/sd/source/ui/slidesorter/view/SlsLayouter.cxx index 3767a655c48b..ee81dbc45202 100755..100644 --- a/sd/source/ui/slidesorter/view/SlsLayouter.cxx +++ b/sd/source/ui/slidesorter/view/SlsLayouter.cxx @@ -28,38 +28,304 @@ #include "precompiled_sd.hxx" #include "view/SlsLayouter.hxx" - -#include <vcl/outdev.hxx> +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "Window.hxx" #include <rtl/math.hxx> +#include <basegfx/numeric/ftools.hxx> + +namespace { + sal_Int32 RoundToInt (const double nValue) + { + return sal_Int32(::rtl::math::round(nValue)); + } +} + namespace sd { namespace slidesorter { namespace view { -Layouter::Layouter (void) - : mnRequestedLeftBorder(10), - mnRequestedRightBorder(10), - mnRequestedTopBorder(10), - mnRequestedBottomBorder(10), - mnLeftBorder(10), - mnRightBorder(10), - mnTopBorder(10), - mnBottomBorder(10), - mnLeftPageBorder(0), - mnRightPageBorder(0), - mnTopPageBorder(0), - mnBottomPageBorder(0), - mnVerticalGap (20), - mnHorizontalGap (20), - mnInsertionMarkerThickness (4), - mnTotalVerticalGap(0), - mnTotalHorizontalGap(0), - mnMinimalWidth (100), - mnPreferredWidth (200), - mnMaximalWidth (300), - mnMinimalColumnCount (1), - mnMaximalColumnCount (5), - mnColumnCount (1), - maPageObjectModelSize (1,1), - maPageObjectPixelSize (1,1) +class Layouter::Implementation +{ +public: + SharedSdWindow mpWindow; + sal_Int32 mnRequestedLeftBorder; + sal_Int32 mnRequestedRightBorder; + sal_Int32 mnRequestedTopBorder; + sal_Int32 mnRequestedBottomBorder; + sal_Int32 mnLeftBorder; + sal_Int32 mnRightBorder; + sal_Int32 mnTopBorder; + sal_Int32 mnBottomBorder; + sal_Int32 mnVerticalGap; + sal_Int32 mnHorizontalGap; + Size maMinimalSize; + Size maPreferredSize; + Size maMaximalSize; + sal_Int32 mnMinimalColumnCount; + sal_Int32 mnMaximalColumnCount; + sal_Int32 mnPageCount; + sal_Int32 mnColumnCount; + sal_Int32 mnRowCount; + /// The maximum number of columns. Can only be larger than the current + /// number of columns when there are not enough pages to fill all + /// available columns. + sal_Int32 mnMaxColumnCount; + /// The maximum number of rows. Can only be larger than the current + /// number of rows when there are not enough pages to fill all available + /// rows. + sal_Int32 mnMaxRowCount; + Size maPageObjectSize; + ::boost::shared_ptr<PageObjectLayouter> mpPageObjectLayouter; + ::boost::shared_ptr<view::Theme> mpTheme; + + /** Specify how the gap between two page objects is associated with the + page objects. + */ + enum GapMembership { + GM_NONE, // Gap is not associated with any page object. + GM_PREVIOUS, // The whole gap is associated with the previous page + // object (left or above the gap.) + GM_BOTH, // Half of the gap is associated with previous, half + // with the next page object. + GM_NEXT, // The whole gap is associated with the next page + // object (right or below the gap.) + GM_PAGE_BORDER + }; + + static Implementation* Create ( + const Implementation& rImplementation, + const Layouter::Orientation eOrientation); + + virtual Layouter::Orientation GetOrientation (void) const = 0; + + bool Rearrange ( + const Size& rWindowSize, + const Size& rPreviewModelSize, + const sal_uInt32 nPageCount); + + /** Calculate the row that the point with the given vertical coordinate + is over. The horizontal component is ignored. + @param nYPosition + Vertical position in model coordinates. + @param bIncludeBordersAndGaps + When this flag is <TRUE/> then the area of borders and gaps are + interpreted as belonging to one of the rows. + @param eGapMembership + Specifies to what row the gap areas belong. Here GM_NONE + corresponds to bIncludeBordersAndGaps being <FALSE/>. When + GM_BOTH is given then the upper half is associated to the row + above and the lower half to the row below. Values of + GM_PREVIOUS and GM_NEXT associate the whole gap area with the + row above or below respectively. + */ + sal_Int32 GetRowAtPosition ( + sal_Int32 nYPosition, + bool bIncludeBordersAndGaps, + GapMembership eGapMembership = GM_NONE) const; + + /** Calculate the column that the point with the given horizontal + coordinate is over. The verical component is ignored. + @param nXPosition + Horizontal position in model coordinates. + @param bIncludeBordersAndGaps + When this flag is <TRUE/> then the area of borders and gaps are + interpreted as belonging to one of the columns. + @param eGapMembership + Specifies to what column the gap areas belong. + */ + sal_Int32 GetColumnAtPosition ( + sal_Int32 nXPosition, + bool bIncludeBordersAndGaps, + GapMembership eGapMembership = GM_NONE) const; + + /** This method is typically called from GetRowAtPosition() and + GetColumnAtPosition() to handle a position that lies inside the gap + between two adjacent rows or columns. + @param nDistanceIntoGap + Vertical distance from the bottom of the upper row down into the + gap or or horizontal distance from the right edge right into the + gap. + @param eGapMemberhship + This value decides what areas in the gap belong to which (or no) + row or column. + @param nIndex + The row index of the upper row or the column index of the left + column. + @param nGap + Width or height of the gap in model coordiantes between the + page borders. + @return + Returns either the index of the upper row (as given as nRow), the + index of the lower row (nRow+1) or -1 to indicate that the + position belongs to no row. + */ + sal_Int32 ResolvePositionInGap ( + sal_Int32 nDistanceIntoGap, + GapMembership eGapMembership, + sal_Int32 nIndex, + sal_Int32 nGap) const; + + /** Calculate the logical part of the insert position, i.e. the page + after whicht to insert. + */ + virtual void CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const = 0; + + /** Calculate the geometrical part of the insert position, i.e. the + location of where to display the insertion indicator and the + distances about which the leading and trailing pages have to be + moved to make room for the indicator. + */ + void CalculateGeometricPosition ( + InsertPosition& rPosition, + const Size& rIndicatorSize, + const bool bIsVertical, + model::SlideSorterModel& rModel) const; + + /** Return the bounding box of the preview or, when selected, of the page + object. Thus, it returns something like a visual bounding box. + */ + Rectangle GetInnerBoundingBox ( + model::SlideSorterModel& rModel, + const sal_Int32 nIndex) const; + + Range GetValidHorizontalSizeRange (void) const; + Range GetValidVerticalSizeRange (void) const; + + Range GetRangeOfVisiblePageObjects (const Rectangle& aVisibleArea) const; + sal_Int32 GetIndex ( + const sal_Int32 nRow, + const sal_Int32 nColumn, + const bool bClampToValidRange) const; + + Rectangle GetPageObjectBox ( + const sal_Int32 nIndex, + const bool bIncludeBorderAndGap = false) const; + + Rectangle GetPageObjectBox ( + const sal_Int32 nRow, + const sal_Int32 nColumn) const; + + Rectangle AddBorderAndGap ( + const Rectangle& rBoundingBox, + const sal_Int32 nRow, + const sal_Int32 nColumn) const; + + Rectangle GetTotalBoundingBox (void) const; + + virtual ~Implementation (void); + +protected: + Implementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme); + Implementation (const Implementation& rImplementation); + + virtual void CalculateRowAndColumnCount (const Size& rWindowSize) = 0; + virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize) = 0; + virtual Size CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const = 0; + Size GetTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize, + const bool bCalculateWidth, + const bool bCalculateHeight) const; + void CalculateVerticalLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const; +}; + + +/** The vertical layouter has one column and as many rows as there are + pages. +*/ +class VerticalImplementation : public Layouter::Implementation +{ +public: + VerticalImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme); + VerticalImplementation (const Implementation& rImplementation); + + virtual Layouter::Orientation GetOrientation (void) const; + + void CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const; + +protected: + virtual void CalculateRowAndColumnCount (const Size& rWindowSize); + virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize); + virtual Size CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const; +}; + + +/** The horizontal layouter has one row and as many columns as there are + pages. +*/ +class HorizontalImplementation : public Layouter::Implementation +{ +public: + HorizontalImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme); + HorizontalImplementation (const Implementation& rImplementation); + + virtual Layouter::Orientation GetOrientation (void) const; + + void CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const; + +protected: + virtual void CalculateRowAndColumnCount (const Size& rWindowSize); + virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize); + virtual Size CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const; +}; + + +/** The number of columns of the grid layouter is defined via a control in + the slide sorter tool bar. The number of rows is calculated from the + number of columns and the number of pages. +*/ +class GridImplementation : public Layouter::Implementation +{ +public: + GridImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme); + GridImplementation (const Implementation& rImplementation); + + virtual Layouter::Orientation GetOrientation (void) const; + + void CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const; + +protected: + virtual void CalculateRowAndColumnCount (const Size& rWindowSize); + virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize); + virtual Size CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const; +}; + + + + +//===== Layouter ============================================================== + +Layouter::Layouter ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<Theme>& rpTheme) + : mpImplementation(new GridImplementation(rpWindow, rpTheme)), + mpWindow(rpWindow) { } @@ -71,39 +337,30 @@ Layouter::~Layouter (void) } -void Layouter::SetBorders ( - sal_Int32 nLeftBorder, - sal_Int32 nRightBorder, - sal_Int32 nTopBorder, - sal_Int32 nBottomBorder) + + +::boost::shared_ptr<PageObjectLayouter> Layouter::GetPageObjectLayouter (void) const { - if (nLeftBorder >= 0) - mnRequestedLeftBorder.mnScreen = nLeftBorder; - if (nRightBorder >= 0) - mnRequestedRightBorder.mnScreen = nRightBorder; - if (nTopBorder >= 0) - mnRequestedTopBorder.mnScreen = nTopBorder; - if (nBottomBorder >= 0) - mnRequestedBottomBorder.mnScreen = nBottomBorder; + return mpImplementation->mpPageObjectLayouter; } -void Layouter::SetPageBorders ( +void Layouter::SetBorders ( sal_Int32 nLeftBorder, sal_Int32 nRightBorder, sal_Int32 nTopBorder, sal_Int32 nBottomBorder) { if (nLeftBorder >= 0) - mnLeftPageBorder.mnScreen = nLeftBorder; + mpImplementation->mnRequestedLeftBorder = nLeftBorder; if (nRightBorder >= 0) - mnRightPageBorder.mnScreen = nRightBorder; + mpImplementation->mnRequestedRightBorder = nRightBorder; if (nTopBorder >= 0) - mnTopPageBorder.mnScreen = nTopBorder; + mpImplementation->mnRequestedTopBorder = nTopBorder; if (nBottomBorder >= 0) - mnBottomPageBorder.mnScreen = nBottomBorder; + mpImplementation->mnRequestedBottomBorder = nBottomBorder; } @@ -115,389 +372,157 @@ void Layouter::SetColumnCount ( { if (nMinimalColumnCount <= nMaximalColumnCount) { - mnMinimalColumnCount = nMinimalColumnCount; - mnMaximalColumnCount = nMaximalColumnCount; + mpImplementation->mnMinimalColumnCount = nMinimalColumnCount; + mpImplementation->mnMaximalColumnCount = nMaximalColumnCount; } } -bool Layouter::RearrangeHorizontal ( +bool Layouter::Rearrange ( + const Orientation eOrientation, const Size& rWindowSize, - const Size& rPageObjectSize, - OutputDevice* pDevice, + const Size& rPageSize, const sal_uInt32 nPageCount) { - if (rWindowSize.Width() > 0 - && rWindowSize.Height() > 0 - && rPageObjectSize.Width() > 0 - && rPageObjectSize.Height() > 0) - { - mnTotalHorizontalGap.mnScreen = mnHorizontalGap.mnScreen - + mnRightPageBorder.mnScreen + mnLeftPageBorder.mnScreen; - mnTotalVerticalGap.mnScreen = mnVerticalGap.mnScreen - + mnTopPageBorder.mnScreen + mnBottomPageBorder.mnScreen; - - // Calculate the column count. - mnColumnCount = nPageCount; - - // Update the border values. The insertion marker has to have space. - mnLeftBorder.mnScreen = mnRequestedLeftBorder.mnScreen; - mnTopBorder.mnScreen = mnRequestedTopBorder.mnScreen; - mnRightBorder.mnScreen = mnRequestedRightBorder.mnScreen; - mnBottomBorder.mnScreen = mnRequestedBottomBorder.mnScreen; - if (mnColumnCount > 1) - { - int nMinimumBorderWidth = mnInsertionMarkerThickness.mnScreen - + mnHorizontalGap.mnScreen/2; - if (mnLeftBorder.mnScreen < nMinimumBorderWidth) - mnLeftBorder.mnScreen = nMinimumBorderWidth; - if (mnRightBorder.mnScreen < nMinimumBorderWidth) - mnRightBorder.mnScreen = nMinimumBorderWidth; - } - else - { - int nMinimumBorderHeight = mnInsertionMarkerThickness.mnScreen - + mnVerticalGap.mnScreen/2; - if (mnTopBorder.mnScreen < nMinimumBorderHeight) - mnTopBorder.mnScreen = nMinimumBorderHeight; - if (mnBottomBorder.mnScreen < nMinimumBorderHeight) - mnBottomBorder.mnScreen = nMinimumBorderHeight; - } + OSL_ASSERT(mpWindow); - // Calculate the width of each page object. - sal_uInt32 nTargetHeight = 0; - sal_uInt32 nRowCount = 1; - if (mnColumnCount > 0) - nTargetHeight = (rWindowSize.Height() - - mnTopBorder.mnScreen - - mnBottomBorder.mnScreen - - nRowCount * (mnTopPageBorder.mnScreen - + mnBottomPageBorder.mnScreen) - - (nRowCount-1) * mnTotalVerticalGap.mnScreen - ) - / nRowCount; - sal_uInt32 nMinimalHeight ( - mnMinimalWidth * rPageObjectSize.Height() / rPageObjectSize.Width()); - sal_uInt32 nMaximalHeight ( - mnMaximalWidth * rPageObjectSize.Height() / rPageObjectSize.Width()); - if (nTargetHeight < nMinimalHeight) - nTargetHeight = nMinimalHeight; - if (nTargetHeight > nMaximalHeight) - nTargetHeight = nMaximalHeight; - - // Initialize the device with some arbitrary zoom factor just in - // case that the current zoom factor is numerically instable when - // used in a multiplication. - MapMode aMapMode (pDevice->GetMapMode()); - aMapMode.SetScaleX (Fraction(1,1)); - aMapMode.SetScaleY (Fraction(1,1)); - pDevice->SetMapMode (aMapMode); - - // Calculate the resulting scale factor and the page object size in - // pixels. - maPageObjectModelSize = rPageObjectSize; - int nPagePixelHeight (pDevice->LogicToPixel(maPageObjectModelSize).Height()); - - // Adapt the layout of the given output device to the new layout of - // page objects. The zoom factor is set so that the page objects in - // one column fill the screen. - Fraction aScaleFactor (nTargetHeight, nPagePixelHeight); - SetZoom (aMapMode.GetScaleX() * aScaleFactor, pDevice); - - return true; - } - else - return false; + if (eOrientation != mpImplementation->GetOrientation()) + mpImplementation.reset(Implementation::Create(*mpImplementation, eOrientation)); + + return mpImplementation->Rearrange(rWindowSize, rPageSize, nPageCount); } -bool Layouter::RearrangeVertical ( - const Size& rWindowSize, - const Size& rPageObjectSize, - OutputDevice* pDevice) +void Layouter::_SetZoom (double nZoomFactor) { - if (rWindowSize.Width() > 0 - && rWindowSize.Height() > 0 - && rPageObjectSize.Width() > 0 - && rPageObjectSize.Height() > 0) - { - mnTotalHorizontalGap.mnScreen = mnHorizontalGap.mnScreen - + mnRightPageBorder.mnScreen + mnLeftPageBorder.mnScreen; - mnTotalVerticalGap.mnScreen = mnVerticalGap.mnScreen - + mnTopPageBorder.mnScreen + mnBottomPageBorder.mnScreen; - - // Calculate the column count. - mnColumnCount = (rWindowSize.Width() - - mnRequestedLeftBorder.mnScreen - mnRequestedRightBorder.mnScreen) - / (mnPreferredWidth + mnTotalHorizontalGap.mnScreen); - if (mnColumnCount < mnMinimalColumnCount) - mnColumnCount = mnMinimalColumnCount; - if (mnColumnCount > mnMaximalColumnCount) - mnColumnCount = mnMaximalColumnCount; - - // Update the border values. The insertion marker has to have space. - mnLeftBorder.mnScreen = mnRequestedLeftBorder.mnScreen; - mnTopBorder.mnScreen = mnRequestedTopBorder.mnScreen; - mnRightBorder.mnScreen = mnRequestedRightBorder.mnScreen; - mnBottomBorder.mnScreen = mnRequestedBottomBorder.mnScreen; - if (mnColumnCount > 1) - { - int nMinimumBorderWidth = mnInsertionMarkerThickness.mnScreen - + mnHorizontalGap.mnScreen/2; - if (mnLeftBorder.mnScreen < nMinimumBorderWidth) - mnLeftBorder.mnScreen = nMinimumBorderWidth; - if (mnRightBorder.mnScreen < nMinimumBorderWidth) - mnRightBorder.mnScreen = nMinimumBorderWidth; - } - else - { - int nMinimumBorderHeight = mnInsertionMarkerThickness.mnScreen - + mnVerticalGap.mnScreen/2; - if (mnTopBorder.mnScreen < nMinimumBorderHeight) - mnTopBorder.mnScreen = nMinimumBorderHeight; - if (mnBottomBorder.mnScreen < nMinimumBorderHeight) - mnBottomBorder.mnScreen = nMinimumBorderHeight; - } - - // Calculate the width of each page object. - sal_Int32 nTargetWidth = 0; - if (mnColumnCount > 0) - nTargetWidth = (rWindowSize.Width() - - mnLeftBorder.mnScreen - - mnRightBorder.mnScreen - - mnColumnCount * (mnRightPageBorder.mnScreen - + mnLeftPageBorder.mnScreen) - - (mnColumnCount-1) * mnTotalHorizontalGap.mnScreen - ) - / mnColumnCount; - if (nTargetWidth < mnMinimalWidth) - nTargetWidth = mnMinimalWidth; - if (nTargetWidth > mnMaximalWidth) - nTargetWidth = mnMaximalWidth; - - // Initialize the device with some arbitrary zoom factor just in - // case that the current zoom factor is numerically instable when - // used in a multiplication. - MapMode aMapMode (pDevice->GetMapMode()); - aMapMode.SetScaleX (Fraction(1,1)); - aMapMode.SetScaleY (Fraction(1,1)); - pDevice->SetMapMode (aMapMode); - - // Calculate the resulting scale factor and the page object size in - // pixels. - maPageObjectModelSize = rPageObjectSize; - int nPagePixelWidth (pDevice->LogicToPixel (maPageObjectModelSize).Width()); - - // Adapt the layout of the given output device to the new layout of - // page objects. The zoom factor is set so that the page objects in - // one row fill the screen. - Fraction aScaleFactor (nTargetWidth, nPagePixelWidth); - SetZoom (aMapMode.GetScaleX() * aScaleFactor, pDevice); - - return true; - } - else - return false; + _SetZoom(Fraction(nZoomFactor)); } -void Layouter::SetZoom (Fraction nZoomFactor, OutputDevice* pDevice) +void Layouter::_SetZoom (Fraction nZoomFactor) { - MapMode aMapMode (pDevice->GetMapMode()); + OSL_ASSERT(mpWindow); + + MapMode aMapMode (mpWindow->GetMapMode()); aMapMode.SetScaleX (nZoomFactor); aMapMode.SetScaleY (nZoomFactor); - maPageObjectPixelSize = pDevice->LogicToPixel (maPageObjectModelSize); - pDevice->SetMapMode (aMapMode); + mpWindow->SetMapMode (aMapMode); +} - // Transform frequently used values from pixel to model coordinates. - Size aTotalGap (pDevice->PixelToLogic (Size ( - mnTotalHorizontalGap.mnScreen, - mnTotalVerticalGap.mnScreen))); - mnTotalHorizontalGap.mnModel = aTotalGap.Width(); - mnTotalVerticalGap.mnModel = aTotalGap.Height(); - Size aGap (pDevice->PixelToLogic (Size ( - mnHorizontalGap.mnScreen, - mnVerticalGap.mnScreen))); - mnHorizontalGap.mnModel = aGap.Width(); - mnVerticalGap.mnModel = aGap.Height(); - Size aTopLeftBorder (pDevice->PixelToLogic (Size ( - mnLeftBorder.mnScreen, - mnTopBorder.mnScreen))); - mnLeftBorder.mnModel = aTopLeftBorder.Width(); - mnTopBorder.mnModel = aTopLeftBorder.Height(); +sal_Int32 Layouter::GetColumnCount (void) const +{ + return mpImplementation->mnColumnCount; +} - Size aBottomRightBorder (pDevice->PixelToLogic (Size ( - mnLeftBorder.mnScreen, - mnTopBorder.mnScreen))); - mnRightBorder.mnModel = aBottomRightBorder.Width(); - mnBottomBorder.mnModel = aBottomRightBorder.Height(); - Size aTopLeftPageBorder (pDevice->PixelToLogic (Size ( - mnLeftPageBorder.mnScreen, - mnTopPageBorder.mnScreen))); - mnLeftPageBorder.mnModel = aTopLeftPageBorder.Width(); - mnTopPageBorder.mnModel = aTopLeftPageBorder.Height(); - Size aBottomRightPageBorder (pDevice->PixelToLogic (Size ( - mnRightPageBorder.mnScreen, - mnBottomPageBorder.mnScreen))); - mnRightPageBorder.mnModel = aBottomRightPageBorder.Width(); - mnBottomPageBorder.mnModel = aBottomRightPageBorder.Height(); - mnInsertionMarkerThickness.mnModel = pDevice->PixelToLogic ( - Size(mnInsertionMarkerThickness.mnScreen,0)).Width(); +sal_Int32 Layouter::GetRowCount (void) const +{ + return mpImplementation->mnRowCount; } -sal_Int32 Layouter::GetColumnCount (void) const +sal_Int32 Layouter::GetRow (const sal_Int32 nIndex) const { - return mnColumnCount; + return nIndex / mpImplementation->mnColumnCount; } -Size Layouter::GetPageObjectSize (void) const +sal_Int32 Layouter::GetColumn (const sal_Int32 nIndex) const { - return maPageObjectModelSize; + return nIndex % mpImplementation->mnColumnCount; } -Rectangle Layouter::GetPageObjectBox (sal_Int32 nIndex) const +sal_Int32 Layouter::GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) const { - int nColumn = nIndex % mnColumnCount; - int nRow = nIndex / mnColumnCount; - return Rectangle ( - Point (mnLeftBorder.mnModel - + nColumn * maPageObjectModelSize.Width() - + mnLeftPageBorder.mnModel - + (nColumn>0 ? nColumn : 0) * mnTotalHorizontalGap.mnModel, - mnTopBorder.mnModel - + nRow * maPageObjectModelSize.Height() - + mnTopPageBorder.mnModel - + (nRow>0 ? nRow : 0) * mnTotalVerticalGap.mnModel), - maPageObjectModelSize); + return mpImplementation->GetIndex(nRow,nColumn,true); } -Rectangle Layouter::GetPageBox (sal_Int32 nObjectCount) const +Size Layouter::GetPageObjectSize (void) const { - sal_Int32 nHorizontalSize = 0; - sal_Int32 nVerticalSize = 0; - if (mnColumnCount > 0) - { - sal_Int32 nRowCount = (nObjectCount+mnColumnCount-1) / mnColumnCount; - nHorizontalSize = - mnLeftBorder.mnModel - + mnRightBorder.mnModel - + mnColumnCount * maPageObjectModelSize.Width() - + mnLeftPageBorder.mnModel + mnRightPageBorder.mnModel; - if (mnColumnCount > 1) - nHorizontalSize - += (mnColumnCount-1) * mnTotalHorizontalGap.mnModel; - nVerticalSize = - mnTopBorder.mnModel - + mnBottomBorder.mnModel - + nRowCount * maPageObjectModelSize.Height() - + mnTopPageBorder.mnModel + mnBottomPageBorder.mnModel; - if (nRowCount > 1) - nVerticalSize += (nRowCount-1) * mnTotalVerticalGap.mnModel; - } + return mpImplementation->maPageObjectSize; +} - return Rectangle ( - Point(0,0), - Size (nHorizontalSize, nVerticalSize) - ); + + + +Rectangle Layouter::GetPageObjectBox ( + const sal_Int32 nIndex, + const bool bIncludeBorderAndGap) const +{ + return mpImplementation->GetPageObjectBox(nIndex, bIncludeBorderAndGap); } -Rectangle Layouter::GetInsertionMarkerBox ( - sal_Int32 nIndex, - bool bVertical, - bool bLeftOrTop) const +Rectangle Layouter::GetTotalBoundingBox (void) const { - Rectangle aBox (GetPageObjectBox (nIndex)); + return mpImplementation->GetTotalBoundingBox(); +} + + + + +InsertPosition Layouter::GetInsertPosition ( + const Point& rModelPosition, + const Size& rIndicatorSize, + model::SlideSorterModel& rModel) const +{ + InsertPosition aPosition; + mpImplementation->CalculateLogicalInsertPosition( + rModelPosition, + aPosition); + mpImplementation->CalculateGeometricPosition( + aPosition, + rIndicatorSize, + GetColumnCount()==1, + rModel); + return aPosition; +} - if (bVertical) - { - sal_Int32 nHorizontalInsertionMarkerOffset - = (mnHorizontalGap.mnModel-mnInsertionMarkerThickness.mnModel) / 2; - if (bLeftOrTop) - { - // Left. - aBox.Left() -= mnLeftPageBorder.mnModel - + mnHorizontalGap.mnModel - - nHorizontalInsertionMarkerOffset; - } - else - { - // Right. - aBox.Left() = aBox.Right() - + mnRightPageBorder.mnModel - + nHorizontalInsertionMarkerOffset; - } - aBox.Right() = aBox.Left() + mnInsertionMarkerThickness.mnModel; - } - else - { - sal_Int32 nVerticalInsertionMarkerOffset - = (mnVerticalGap.mnModel - mnInsertionMarkerThickness.mnModel) / 2; - if (bLeftOrTop) - { - // Above. - aBox.Top() -= mnTopPageBorder.mnModel - + mnVerticalGap.mnModel - - nVerticalInsertionMarkerOffset; - } - else - { - // Below. - aBox.Top() = aBox.Bottom() - + mnBottomPageBorder.mnModel - + nVerticalInsertionMarkerOffset; - } - aBox.Bottom() = aBox.Top() + mnInsertionMarkerThickness.mnModel; - } - return aBox; + + +Range Layouter::GetValidHorizontalSizeRange (void) const +{ + return mpImplementation->GetValidHorizontalSizeRange(); } -sal_Int32 Layouter::GetIndexOfFirstVisiblePageObject ( - const Rectangle& aVisibleArea) const +Range Layouter::GetValidVerticalSizeRange (void) const { - sal_Int32 nRow = GetRowAtPosition (aVisibleArea.Top(), true, GM_BOTH); - return nRow * mnColumnCount; + return mpImplementation->GetValidVerticalSizeRange(); } -sal_Int32 Layouter::GetIndexOfLastVisiblePageObject ( - const Rectangle& aVisibleArea) const +Range Layouter::GetRangeOfVisiblePageObjects (const Rectangle& aVisibleArea) const { - sal_Int32 nRow = GetRowAtPosition (aVisibleArea.Bottom(), - true, GM_BOTH); - return (nRow+1) * mnColumnCount - 1; + return mpImplementation->GetRangeOfVisiblePageObjects(aVisibleArea); } @@ -505,128 +530,188 @@ sal_Int32 Layouter::GetIndexOfLastVisiblePageObject ( sal_Int32 Layouter::GetIndexAtPoint ( const Point& rPosition, - bool bIncludePageBorders) const + const bool bIncludePageBorders, + const bool bClampToValidRange) const { - sal_Int32 nRow = GetRowAtPosition (rPosition.Y(), - bIncludePageBorders, - bIncludePageBorders ? GM_PAGE_BORDER : GM_NONE); - sal_Int32 nColumn = GetColumnAtPosition (rPosition.X(), - bIncludePageBorders, - bIncludePageBorders ? GM_PAGE_BORDER : GM_NONE); - - if (nRow >= 0 && nColumn >= 0) - return nRow * mnColumnCount + nColumn; - else - return -1; + const sal_Int32 nRow ( + mpImplementation->GetRowAtPosition ( + rPosition.Y(), + bIncludePageBorders, + bIncludePageBorders ? Implementation::GM_PAGE_BORDER : Implementation::GM_NONE)); + const sal_Int32 nColumn ( + mpImplementation->GetColumnAtPosition ( + rPosition.X(), + bIncludePageBorders, + bIncludePageBorders ? Implementation::GM_PAGE_BORDER : Implementation::GM_NONE)); + + return mpImplementation->GetIndex(nRow,nColumn,bClampToValidRange); } -/** Calculation of the insertion index: - 1. Determine the row. rPoint has to be in the row between upper and - lower border. If it is in a horizontal gap or border an invalid - insertion index (-1, which is a valid return value) will be returned. - 2. Determine the column. Here both vertical borders and vertical gaps - will yield valid return values. The horizontal positions between the - center of page objects in column i and the center of page objects in - column i+1 will return column i+1 as insertion index. +//===== Layouter::Implementation ============================================== - When there is only one column and bAllowVerticalPosition is true than - take the vertical areas between rows into account as well. -*/ -sal_Int32 Layouter::GetInsertionIndex ( - const Point& rPosition, - bool bAllowVerticalPosition) const +Layouter::Implementation* Layouter::Implementation::Create ( + const Implementation& rImplementation, + const Layouter::Orientation eOrientation) { - sal_Int32 nIndex = -1; + switch (eOrientation) + { + case HORIZONTAL: return new HorizontalImplementation(rImplementation); + case VERTICAL: return new VerticalImplementation(rImplementation); + case GRID: + default: return new GridImplementation(rImplementation); + } +} - sal_Int32 nRow = GetRowAtPosition (rPosition.Y(), true, - (mnColumnCount==1 && bAllowVerticalPosition) ? GM_BOTH : GM_BOTH); - sal_Int32 nColumn = GetColumnAtPosition (rPosition.X(), true, GM_BOTH); - if (nRow >= 0 && nColumn >= 0) - nIndex = nRow * mnColumnCount + nColumn; - return nIndex; + +Layouter::Implementation::Implementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : mpWindow(rpWindow), + mnRequestedLeftBorder(5), + mnRequestedRightBorder(5), + mnRequestedTopBorder(5), + mnRequestedBottomBorder(5), + mnLeftBorder(5), + mnRightBorder(5), + mnTopBorder(5), + mnBottomBorder(5), + mnVerticalGap (10 - 2*rpTheme->GetIntegerValue(Theme::Integer_FocusIndicatorWidth)), + mnHorizontalGap(10 - 2*rpTheme->GetIntegerValue(Theme::Integer_FocusIndicatorWidth)), + maMinimalSize(132,98), + maPreferredSize(200,150), + maMaximalSize(300,200), + mnMinimalColumnCount(1), + mnMaximalColumnCount(15), + mnPageCount(0), + mnColumnCount(1), + mnRowCount(0), + mnMaxColumnCount(0), + mnMaxRowCount(0), + maPageObjectSize(1,1), + mpPageObjectLayouter(), + mpTheme(rpTheme) +{ } -Layouter::DoublePoint - Layouter::ConvertModelToLayouterCoordinates ( - const Point& rModelPoint) const +Layouter::Implementation::Implementation (const Implementation& rImplementation) + : mpWindow(rImplementation.mpWindow), + mnRequestedLeftBorder(rImplementation.mnRequestedLeftBorder), + mnRequestedRightBorder(rImplementation.mnRequestedRightBorder), + mnRequestedTopBorder(rImplementation.mnRequestedTopBorder), + mnRequestedBottomBorder(rImplementation.mnRequestedBottomBorder), + mnLeftBorder(rImplementation.mnLeftBorder), + mnRightBorder(rImplementation.mnRightBorder), + mnTopBorder(rImplementation.mnTopBorder), + mnBottomBorder(rImplementation.mnBottomBorder), + mnVerticalGap(rImplementation.mnVerticalGap), + mnHorizontalGap(rImplementation.mnHorizontalGap), + maMinimalSize(rImplementation.maMinimalSize), + maPreferredSize(rImplementation.maPreferredSize), + maMaximalSize(rImplementation.maMaximalSize), + mnMinimalColumnCount(rImplementation.mnMinimalColumnCount), + mnMaximalColumnCount(rImplementation.mnMaximalColumnCount), + mnPageCount(rImplementation.mnPageCount), + mnColumnCount(rImplementation.mnColumnCount), + mnRowCount(rImplementation.mnRowCount), + mnMaxColumnCount(rImplementation.mnMaxColumnCount), + mnMaxRowCount(rImplementation.mnMaxRowCount), + maPageObjectSize(rImplementation.maPageObjectSize), + mpPageObjectLayouter(), + mpTheme(rImplementation.mpTheme) { - sal_Int32 nColumn = GetColumnAtPosition (rModelPoint.X(), true, GM_BOTH); - sal_Int32 nColumnWidth - = maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel; - sal_Int32 nDistanceIntoColumn = - rModelPoint.X() - mnLeftBorder.mnModel - mnLeftPageBorder.mnModel - - nColumn * nColumnWidth; +} + + - sal_Int32 nRow = GetRowAtPosition (rModelPoint.Y(), true, GM_BOTH); - sal_Int32 nRowHeight - = maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel; - sal_Int32 nDistanceIntoRow = - rModelPoint.Y() - mnTopBorder.mnModel - mnTopPageBorder.mnModel - - nRow * nRowHeight; - return DoublePoint ( - nColumn + double(nDistanceIntoColumn) / double(nColumnWidth), - nRow + double(nDistanceIntoRow) / double(nRowHeight)); +Layouter::Implementation::~Implementation (void) +{ } -Point Layouter::ConvertLayouterToModelCoordinates ( - const DoublePoint & rLayouterPoint) const +bool Layouter::Implementation::Rearrange ( + const Size& rWindowSize, + const Size& rPreviewModelSize, + const sal_uInt32 nPageCount) { - sal_Int32 nColumn = (sal_Int32) ::rtl::math::round(rLayouterPoint.first, - 0,rtl_math_RoundingMode_Floor); - sal_Int32 nColumnWidth - = maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel; - sal_Int32 nDistanceIntoColumn - = (sal_Int32)((rLayouterPoint.first - nColumn) * nColumnWidth); + mnPageCount = nPageCount; - sal_Int32 nRow = (sal_Int32) ::rtl::math::round(rLayouterPoint.second, - 0,rtl_math_RoundingMode_Floor); - sal_Int32 nRowHeight - = maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel; - sal_Int32 nDistanceIntoRow - = (sal_Int32)((rLayouterPoint.second - nRow) * nRowHeight); + // Return early when the window or the model have not yet been initialized. + if (rWindowSize.Width()<=0 || rWindowSize.Height()<=0) + return false; + if (rPreviewModelSize.Width()<=0 || rPreviewModelSize.Height()<=0) + return false; - return Point ( - mnLeftBorder.mnModel + mnLeftPageBorder.mnModel - + nColumn * nColumnWidth + nDistanceIntoColumn, - mnTopBorder.mnModel + mnTopPageBorder.mnModel - + nRow * nRowHeight + nDistanceIntoRow); + CalculateRowAndColumnCount(rWindowSize); + + // Update the border values. + mnLeftBorder = mnRequestedLeftBorder; + mnTopBorder = mnRequestedTopBorder; + mnRightBorder = mnRequestedRightBorder; + mnBottomBorder = mnRequestedBottomBorder; + if (mnColumnCount > 1) + { + int nMinimumBorderWidth = mnHorizontalGap/2; + if (mnLeftBorder < nMinimumBorderWidth) + mnLeftBorder = nMinimumBorderWidth; + if (mnRightBorder < nMinimumBorderWidth) + mnRightBorder = nMinimumBorderWidth; + } + else + { + int nMinimumBorderHeight = mnVerticalGap/2; + if (mnTopBorder < nMinimumBorderHeight) + mnTopBorder = nMinimumBorderHeight; + if (mnBottomBorder < nMinimumBorderHeight) + mnBottomBorder = nMinimumBorderHeight; + } + + mpPageObjectLayouter.reset( + new PageObjectLayouter( + mpTheme, + CalculateTargetSize(rWindowSize, rPreviewModelSize), + rPreviewModelSize, + mpWindow, + mnPageCount)); + maPageObjectSize = mpPageObjectLayouter->GetSize( + PageObjectLayouter::FocusIndicator, + PageObjectLayouter::WindowCoordinateSystem); + + CalculateMaxRowAndColumnCount(rWindowSize); + + return true; } -sal_Int32 Layouter::GetRowAtPosition ( +sal_Int32 Layouter::Implementation::GetRowAtPosition ( sal_Int32 nYPosition, bool bIncludeBordersAndGaps, GapMembership eGapMembership) const { sal_Int32 nRow = -1; - const sal_Int32 nY = nYPosition - - mnTopBorder.mnModel - mnTopPageBorder.mnModel; + const sal_Int32 nY = nYPosition - mnTopBorder; if (nY >= 0) { // Vertical distance from one row to the next. - const sal_Int32 nRowOffset ( - maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel); + const sal_Int32 nRowOffset (maPageObjectSize.Height() + mnVerticalGap); // Calculate row consisting of page objects and gap below. nRow = nY / nRowOffset; - const sal_Int32 nDistanceIntoGap ( - (nY - nRow*nRowOffset) - maPageObjectModelSize.Height()); + const sal_Int32 nDistanceIntoGap ((nY - nRow*nRowOffset) - maPageObjectSize.Height()); // When inside the gap below then nYPosition is not over a page // object. if (nDistanceIntoGap > 0) @@ -634,8 +719,7 @@ sal_Int32 Layouter::GetRowAtPosition ( nDistanceIntoGap, eGapMembership, nRow, - mnBottomPageBorder.mnModel, - mnVerticalGap.mnModel); + mnVerticalGap); } else if (bIncludeBordersAndGaps) { @@ -650,20 +734,18 @@ sal_Int32 Layouter::GetRowAtPosition ( -sal_Int32 Layouter::GetColumnAtPosition ( +sal_Int32 Layouter::Implementation::GetColumnAtPosition ( sal_Int32 nXPosition, bool bIncludeBordersAndGaps, GapMembership eGapMembership) const { sal_Int32 nColumn = -1; - sal_Int32 nX = nXPosition - - mnLeftBorder.mnModel - mnLeftPageBorder.mnModel; + sal_Int32 nX = nXPosition - mnLeftBorder; if (nX >= 0) { // Horizontal distance from one column to the next. - const sal_Int32 nColumnOffset ( - maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel); + const sal_Int32 nColumnOffset (maPageObjectSize.Width() + mnHorizontalGap); // Calculate row consisting of page objects and gap below. nColumn = nX / nColumnOffset; @@ -672,8 +754,7 @@ sal_Int32 Layouter::GetColumnAtPosition ( else if (nColumn >= mnColumnCount) nColumn = mnColumnCount-1; - const sal_Int32 nDistanceIntoGap ( - (nX - nColumn*nColumnOffset) - maPageObjectModelSize.Width()); + const sal_Int32 nDistanceIntoGap ((nX - nColumn*nColumnOffset) - maPageObjectSize.Width()); // When inside the gap at the right then nXPosition is not over a // page object. if (nDistanceIntoGap > 0) @@ -681,8 +762,7 @@ sal_Int32 Layouter::GetColumnAtPosition ( nDistanceIntoGap, eGapMembership, nColumn, - mnRightPageBorder.mnModel, - mnHorizontalGap.mnModel); + mnHorizontalGap); } else if (bIncludeBordersAndGaps) { @@ -697,11 +777,10 @@ sal_Int32 Layouter::GetColumnAtPosition ( -sal_Int32 Layouter::ResolvePositionInGap ( +sal_Int32 Layouter::Implementation::ResolvePositionInGap ( sal_Int32 nDistanceIntoGap, GapMembership eGapMembership, sal_Int32 nIndex, - sal_Int32 nLeftOrTopPageBorder, sal_Int32 nGap) const { switch (eGapMembership) @@ -714,7 +793,7 @@ sal_Int32 Layouter::ResolvePositionInGap ( case GM_BOTH: { // The lower half of the gap belongs to the next row or column. - sal_Int32 nFirstHalfGapWidth = nLeftOrTopPageBorder + nGap / 2; + sal_Int32 nFirstHalfGapWidth = nGap / 2; if (nDistanceIntoGap > nFirstHalfGapWidth) nIndex ++; break; @@ -730,9 +809,9 @@ sal_Int32 Layouter::ResolvePositionInGap ( break; case GM_PAGE_BORDER: - if (nDistanceIntoGap > nLeftOrTopPageBorder) + if (nDistanceIntoGap > 0) { - if (nDistanceIntoGap > nLeftOrTopPageBorder + nGap) + if (nDistanceIntoGap > nGap) { // Inside the border of the next row or column. nIndex ++; @@ -755,4 +834,719 @@ sal_Int32 Layouter::ResolvePositionInGap ( +void Layouter::Implementation::CalculateGeometricPosition ( + InsertPosition& rPosition, + const Size& rIndicatorSize, + const bool bIsVertical, + model::SlideSorterModel& rModel) const +{ + // 1. Determine right/bottom of the leading page and the left/top of the + // trailing page object and how to distribute the missing space. + sal_Int32 nLeadingLocation (0); + sal_Int32 nTrailingLocation (0); + bool bIsLeadingFixed (false); + bool bIsTrailingFixed (false); + sal_Int32 nSecondaryLocation (0); + const sal_Int32 nIndex (rPosition.GetIndex()); + + if (rPosition.IsAtRunStart()) + { + // Place indicator at the top of the column. + const Rectangle aOuterBox (GetPageObjectBox(nIndex)); + const Rectangle aInnerBox (GetInnerBoundingBox(rModel, nIndex)); + if (bIsVertical) + { + nLeadingLocation = aOuterBox.Top(); + nTrailingLocation = aInnerBox.Top(); + nSecondaryLocation = aInnerBox.Center().X(); + } + else + { + nLeadingLocation = aOuterBox.Left(); + nTrailingLocation = aInnerBox.Left(); + nSecondaryLocation = aInnerBox.Center().Y(); + } + bIsLeadingFixed = true; + } + else if (rPosition.IsAtRunEnd()) + { + // Place indicator at the bottom/right of the column/row. + + const Rectangle aOuterBox (GetPageObjectBox(nIndex-1)); + const Rectangle aInnerBox (GetInnerBoundingBox(rModel, nIndex-1)); + if (bIsVertical) + { + nLeadingLocation = aInnerBox.Bottom(); + nTrailingLocation = aOuterBox.Bottom(); + nSecondaryLocation = aInnerBox.Center().X(); + } + else + { + nLeadingLocation = aInnerBox.Right(); + nTrailingLocation = aOuterBox.Right(); + nSecondaryLocation = aInnerBox.Center().Y(); + } + bIsTrailingFixed = true; + if ( ! rPosition.IsExtraSpaceNeeded()) + bIsLeadingFixed = true; + } + else + { + // Place indicator between two rows/columns. + const Rectangle aBox1 (GetInnerBoundingBox(rModel, nIndex-1)); + const Rectangle aBox2 (GetInnerBoundingBox(rModel, nIndex)); + if (bIsVertical) + { + nLeadingLocation = aBox1.Bottom(); + nTrailingLocation = aBox2.Top(); + nSecondaryLocation = (aBox1.Center().X() + aBox2.Center().X()) / 2; + } + else + { + nLeadingLocation = aBox1.Right(); + nTrailingLocation = aBox2.Left(); + nSecondaryLocation = (aBox1.Center().Y() + aBox2.Center().Y()) / 2; + } + } + + // 2. Calculate the location of the insert indicator and the offsets of + // leading and trailing pages. + const sal_Int32 nAvailableSpace (nTrailingLocation - nLeadingLocation); + const sal_Int32 nRequiredSpace (bIsVertical ? rIndicatorSize.Height():rIndicatorSize.Width()); + const sal_Int32 nMissingSpace (::std::max(sal_Int32(0), nRequiredSpace - nAvailableSpace)); + sal_Int32 nPrimaryLocation (0); + sal_Int32 nLeadingOffset (0); + sal_Int32 nTrailingOffset (0); + if (bIsLeadingFixed) + { + nPrimaryLocation = nLeadingLocation + nRequiredSpace/2; + if ( ! bIsTrailingFixed) + nTrailingOffset = nMissingSpace; + } + else if (bIsTrailingFixed) + { + nPrimaryLocation = nTrailingLocation - nRequiredSpace/2; + nLeadingOffset = -nMissingSpace; + } + else + { + nPrimaryLocation = (nLeadingLocation + nTrailingLocation) /2; + nLeadingOffset = -nMissingSpace/2; + nTrailingOffset = nMissingSpace + nLeadingOffset; + } + + if (bIsVertical) + { + rPosition.SetGeometricalPosition( + Point(nSecondaryLocation, nPrimaryLocation), + Point(0, nLeadingOffset), + Point(0, nTrailingOffset)); + } + else + { + rPosition.SetGeometricalPosition( + Point(nPrimaryLocation, nSecondaryLocation), + Point(nLeadingOffset, 0), + Point(nTrailingOffset, 0)); + } +} + + + + +Rectangle Layouter::Implementation::GetInnerBoundingBox ( + model::SlideSorterModel& rModel, + const sal_Int32 nIndex) const +{ + model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex)); + if ( ! pDescriptor) + return Rectangle(); + + const Point aLocation (pDescriptor->GetLocation(true)); + if (pDescriptor->HasState(model::PageDescriptor::ST_Selected)) + return mpPageObjectLayouter->GetBoundingBox( + aLocation, + PageObjectLayouter::PageObject, + PageObjectLayouter::ModelCoordinateSystem); + else + return mpPageObjectLayouter->GetBoundingBox( + aLocation, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem); +} + + + + +Range Layouter::Implementation::GetValidHorizontalSizeRange (void) const +{ + return Range( + mnLeftBorder + maMinimalSize.Width() + mnRightBorder, + mnLeftBorder + maMaximalSize.Width() + mnRightBorder); +} + + + + +Range Layouter::Implementation::GetValidVerticalSizeRange (void) const +{ + return Range( + mnTopBorder + maMinimalSize.Height() + mnBottomBorder, + mnTopBorder + maMaximalSize.Height() + mnBottomBorder); +} + + + + +Range Layouter::Implementation::GetRangeOfVisiblePageObjects (const Rectangle& aVisibleArea) const +{ + const sal_Int32 nRow0 (GetRowAtPosition(aVisibleArea.Top(), true, GM_NEXT)); + const sal_Int32 nCol0 (GetColumnAtPosition(aVisibleArea.Left(),true, GM_NEXT)); + const sal_Int32 nRow1 (GetRowAtPosition(aVisibleArea.Bottom(), true, GM_PREVIOUS)); + const sal_Int32 nCol1 (GetColumnAtPosition(aVisibleArea.Right(), true, GM_PREVIOUS)); + + // When start and end lie in different rows then the range may include + // slides outside (left or right of) the given area. + return Range(GetIndex(nRow0,nCol0,true), GetIndex(nRow1,nCol1,true)); +} + + + + +Size Layouter::Implementation::GetTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize, + const bool bCalculateWidth, + const bool bCalculateHeight) const +{ + (void)rPreviewModelSize; + + if (mnColumnCount<=0 || mnRowCount<=0) + return maPreferredSize; + if ( ! (bCalculateWidth || bCalculateHeight)) + { + OSL_ASSERT(bCalculateWidth || bCalculateHeight); + return maPreferredSize; + } + + // Calculate the width of each page object. + Size aTargetSize (0,0); + if (bCalculateWidth) + aTargetSize.setWidth( + (rWindowSize.Width() - mnLeftBorder - mnRightBorder + - (mnColumnCount-1) * mnHorizontalGap) + / mnColumnCount); + else if (bCalculateHeight) + aTargetSize.setHeight( + (rWindowSize.Height() - mnTopBorder - mnBottomBorder + - (mnRowCount-1) * mnVerticalGap) + / mnRowCount); + + if (bCalculateWidth) + { + if (aTargetSize.Width() < maMinimalSize.Width()) + aTargetSize.setWidth(maMinimalSize.Width()); + else if (aTargetSize.Width() > maMaximalSize.Width()) + aTargetSize.setWidth(maMaximalSize.Width()); + } + else if (bCalculateHeight) + { + if (aTargetSize.Height() < maMinimalSize.Height()) + aTargetSize.setHeight(maMinimalSize.Height()); + else if (aTargetSize.Height() > maMaximalSize.Height()) + aTargetSize.setHeight(maMaximalSize.Height()); + } + + return aTargetSize; +} + + + + +sal_Int32 Layouter::Implementation::GetIndex ( + const sal_Int32 nRow, + const sal_Int32 nColumn, + const bool bClampToValidRange) const +{ + if (nRow >= 0 && nColumn >= 0) + { + const sal_Int32 nIndex (nRow * mnColumnCount + nColumn); + if (nIndex >= mnPageCount) + if (bClampToValidRange) + return mnPageCount-1; + else + return -1; + else + return nIndex; + } + else if (bClampToValidRange) + return 0; + else + return -1; +} + + + + +Rectangle Layouter::Implementation::GetPageObjectBox ( + const sal_Int32 nIndex, + const bool bIncludeBorderAndGap) const +{ + const sal_Int32 nRow (nIndex / mnColumnCount); + const sal_Int32 nColumn (nIndex % mnColumnCount); + + const Rectangle aBoundingBox (GetPageObjectBox(nRow,nColumn)); + if (bIncludeBorderAndGap) + return AddBorderAndGap(aBoundingBox, nRow, nColumn); + else + return aBoundingBox; +} + + + + +Rectangle Layouter::Implementation::GetPageObjectBox ( + const sal_Int32 nRow, + const sal_Int32 nColumn) const +{ + return Rectangle( + Point (mnLeftBorder + + nColumn * maPageObjectSize.Width() + + (nColumn>0 ? nColumn : 0) * mnHorizontalGap, + mnTopBorder + + nRow * maPageObjectSize.Height() + + (nRow>0 ? nRow : 0) * mnVerticalGap), + maPageObjectSize); +} + + + + + +Rectangle Layouter::Implementation::AddBorderAndGap ( + const Rectangle& rBoundingBox, + const sal_Int32 nRow, + const sal_Int32 nColumn) const +{ + Rectangle aBoundingBox (rBoundingBox); + + if (nColumn == 0) + aBoundingBox.Left() = 0; + else + aBoundingBox.Left() -= mnHorizontalGap/2; + if (nColumn == mnColumnCount-1) + aBoundingBox.Right() += mnRightBorder; + else + aBoundingBox.Right() += mnHorizontalGap/2; + if (nRow == 0) + aBoundingBox.Top() = 0; + else + aBoundingBox.Top() -= mnVerticalGap/2; + if (nRow == mnRowCount-1) + aBoundingBox.Bottom() += mnBottomBorder; + else + aBoundingBox.Bottom() += mnVerticalGap/2; + return aBoundingBox; +} + + + + +Rectangle Layouter::Implementation::GetTotalBoundingBox (void) const +{ + sal_Int32 nHorizontalSize = 0; + sal_Int32 nVerticalSize = 0; + if (mnColumnCount > 0) + { + sal_Int32 nRowCount = (mnPageCount+mnColumnCount-1) / mnColumnCount; + nHorizontalSize = + mnLeftBorder + + mnRightBorder + + mnColumnCount * maPageObjectSize.Width(); + if (mnColumnCount > 1) + nHorizontalSize += (mnColumnCount-1) * mnHorizontalGap; + nVerticalSize = + mnTopBorder + + mnBottomBorder + + nRowCount * maPageObjectSize.Height(); + if (nRowCount > 1) + nVerticalSize += (nRowCount-1) * mnVerticalGap; + } + + return Rectangle ( + Point(0,0), + Size (nHorizontalSize, nVerticalSize) + ); +} + + + + +void Layouter::Implementation::CalculateVerticalLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const +{ + const sal_Int32 nY = rModelPosition.Y() - mnTopBorder + maPageObjectSize.Height()/2; + const sal_Int32 nRowHeight (maPageObjectSize.Height() + mnVerticalGap); + const sal_Int32 nRow (::std::min(mnPageCount, nY / nRowHeight)); + rPosition.SetLogicalPosition ( + nRow, + 0, + nRow, + (nRow == 0), + (nRow == mnRowCount), + (nRow >= mnMaxRowCount)); +} + + + + +//===== HorizontalImplementation ================================================ + +HorizontalImplementation::HorizontalImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : Implementation(rpWindow, rpTheme) +{ +} + + + + +HorizontalImplementation::HorizontalImplementation (const Implementation& rImplementation) + : Implementation(rImplementation) +{ +} + + + + +Layouter::Orientation HorizontalImplementation::GetOrientation (void) const +{ + return Layouter::HORIZONTAL; +} + + + + +void HorizontalImplementation::CalculateRowAndColumnCount (const Size& rWindowSize) +{ + (void)rWindowSize; + + // Row and column count are fixed (for a given page count.) + mnColumnCount = mnPageCount; + mnRowCount = 1; +} + + + + +void HorizontalImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize) +{ + mnMaxColumnCount = (rWindowSize.Width() - mnLeftBorder - mnRightBorder) + / (maPageObjectSize.Width() + mnHorizontalGap); + mnMaxRowCount = 1; +} + + + + +Size HorizontalImplementation::CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const +{ + return Implementation::GetTargetSize(rWindowSize, rPreviewModelSize, false, true); +} + + + + +void HorizontalImplementation::CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const +{ + const sal_Int32 nX = rModelPosition.X() - mnLeftBorder + maPageObjectSize.Width()/2; + const sal_Int32 nColumnWidth (maPageObjectSize.Width() + mnHorizontalGap); + const sal_Int32 nColumn (::std::min(mnPageCount, nX / nColumnWidth)); + rPosition.SetLogicalPosition ( + 0, + nColumn, + nColumn, + (nColumn == 0), + (nColumn == mnColumnCount), + (nColumn >= mnMaxColumnCount)); +} + + + + +//===== VerticalImplementation ================================================ + +VerticalImplementation::VerticalImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : Implementation(rpWindow, rpTheme) +{ +} + + + + +VerticalImplementation::VerticalImplementation (const Implementation& rImplementation) + : Implementation(rImplementation) +{ +} + + + + +Layouter::Orientation VerticalImplementation::GetOrientation (void) const +{ + return Layouter::VERTICAL; +} + + + + +void VerticalImplementation::CalculateRowAndColumnCount (const Size& rWindowSize) +{ + (void)rWindowSize; + + // Row and column count are fixed (for a given page count.) + mnRowCount = mnPageCount; + mnColumnCount = 1; + +} + + + + +void VerticalImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize) +{ + mnMaxRowCount = (rWindowSize.Height() - mnTopBorder - mnBottomBorder) + / (maPageObjectSize.Height() + mnVerticalGap); + mnMaxColumnCount = 1; +} + + + + +Size VerticalImplementation::CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const +{ + return Implementation::GetTargetSize(rWindowSize, rPreviewModelSize, true, false); +} + + + + +void VerticalImplementation::CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const +{ + return CalculateVerticalLogicalInsertPosition(rModelPosition, rPosition); +} + + + + +//===== GridImplementation ================================================ + +GridImplementation::GridImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : Implementation(rpWindow, rpTheme) +{ +} + + + + +GridImplementation::GridImplementation (const Implementation& rImplementation) + : Implementation(rImplementation) +{ +} + + + + +Layouter::Orientation GridImplementation::GetOrientation (void) const +{ + return Layouter::GRID; +} + + + + +void GridImplementation::CalculateRowAndColumnCount (const Size& rWindowSize) +{ + // Calculate the column count. + mnColumnCount + = (rWindowSize.Width() - mnRequestedLeftBorder - mnRequestedRightBorder) + / (maPreferredSize.Width() + mnHorizontalGap); + if (mnColumnCount < mnMinimalColumnCount) + mnColumnCount = mnMinimalColumnCount; + if (mnColumnCount > mnMaximalColumnCount) + mnColumnCount = mnMaximalColumnCount; + mnRowCount = (mnPageCount + mnColumnCount-1)/mnColumnCount; +} + + + + +void GridImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize) +{ + mnMaxColumnCount = (rWindowSize.Width() - mnLeftBorder - mnRightBorder) + / (maPageObjectSize.Width() + mnHorizontalGap); + mnMaxRowCount = (rWindowSize.Height() - mnTopBorder - mnBottomBorder) + / (maPageObjectSize.Height() + mnVerticalGap); +} + + + + + +Size GridImplementation::CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const +{ + return Implementation::GetTargetSize(rWindowSize, rPreviewModelSize, true, true); +} + + + + +void GridImplementation::CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const +{ + if (mnColumnCount == 1) + { + CalculateVerticalLogicalInsertPosition(rModelPosition, rPosition); + } + else + { + // Handle the general case of more than one column. + sal_Int32 nRow (::std::min( + mnRowCount-1, + GetRowAtPosition (rModelPosition.Y(), true, GM_BOTH))); + const sal_Int32 nX = rModelPosition.X() - mnLeftBorder + maPageObjectSize.Width()/2; + const sal_Int32 nColumnWidth (maPageObjectSize.Width() + mnHorizontalGap); + sal_Int32 nColumn (::std::min(mnColumnCount, nX / nColumnWidth)); + sal_Int32 nIndex (nRow * mnColumnCount + nColumn); + bool bIsAtRunEnd (nColumn == mnColumnCount); + + if (nIndex >= mnPageCount) + { + nIndex = mnPageCount; + nRow = mnRowCount-1; + nColumn = ::std::min(::std::min(mnPageCount, mnColumnCount), nColumn); + bIsAtRunEnd = true; + } + + rPosition.SetLogicalPosition ( + nRow, + nColumn, + nIndex, + (nColumn == 0), + bIsAtRunEnd, + (nColumn >= mnMaxColumnCount)); + } +} + + + + +//===== InsertPosition ======================================================== + +InsertPosition::InsertPosition (void) + : mnRow(-1), + mnColumn(-1), + mnIndex(-1), + mbIsAtRunStart(false), + mbIsAtRunEnd(false), + mbIsExtraSpaceNeeded(false), + maLocation(0,0), + maLeadingOffset(0,0), + maTrailingOffset(0,0) +{ +} + + + + +InsertPosition& InsertPosition::operator= (const InsertPosition& rInsertPosition) +{ + if (this != &rInsertPosition) + { + mnRow = rInsertPosition.mnRow; + mnColumn = rInsertPosition.mnColumn; + mnIndex = rInsertPosition.mnIndex; + mbIsAtRunStart = rInsertPosition.mbIsAtRunStart; + mbIsAtRunEnd = rInsertPosition.mbIsAtRunEnd; + mbIsExtraSpaceNeeded = rInsertPosition.mbIsExtraSpaceNeeded; + maLocation = rInsertPosition.maLocation; + maLeadingOffset = rInsertPosition.maLeadingOffset; + maTrailingOffset = rInsertPosition.maTrailingOffset; + } + return *this; +} + + + + +bool InsertPosition::operator== (const InsertPosition& rInsertPosition) const +{ + // Do not compare the geometrical information (maLocation). + return mnRow==rInsertPosition.mnRow + && mnColumn==rInsertPosition.mnColumn + && mnIndex==rInsertPosition.mnIndex + && mbIsAtRunStart==rInsertPosition.mbIsAtRunStart + && mbIsAtRunEnd==rInsertPosition.mbIsAtRunEnd + && mbIsExtraSpaceNeeded==rInsertPosition.mbIsExtraSpaceNeeded; +} + + + + +bool InsertPosition::operator!= (const InsertPosition& rInsertPosition) const +{ + return !operator==(rInsertPosition); +} + + + + +void InsertPosition::SetLogicalPosition ( + const sal_Int32 nRow, + const sal_Int32 nColumn, + const sal_Int32 nIndex, + const bool bIsAtRunStart, + const bool bIsAtRunEnd, + const bool bIsExtraSpaceNeeded) +{ + mnRow = nRow; + mnColumn = nColumn; + mnIndex = nIndex; + mbIsAtRunStart = bIsAtRunStart; + mbIsAtRunEnd = bIsAtRunEnd; + mbIsExtraSpaceNeeded = bIsExtraSpaceNeeded; +} + + + + +void InsertPosition::SetGeometricalPosition( + const Point aLocation, + const Point aLeadingOffset, + const Point aTrailingOffset) +{ + maLocation = aLocation; + maLeadingOffset = aLeadingOffset; + maTrailingOffset = aTrailingOffset; +} + + + } } } // end of namespace ::sd::slidesorter::namespace diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectLayouter.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectLayouter.cxx new file mode 100644 index 000000000000..d798fa27accb --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsPageObjectLayouter.cxx @@ -0,0 +1,287 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsPageObjectLayouter.hxx" + +#include "model/SlsPageDescriptor.hxx" +#include "view/SlsFontProvider.hxx" +#include "view/SlsTheme.hxx" +#include "tools/IconCache.hxx" +#include "Window.hxx" +#include "res_bmp.hrc" + +namespace sd { namespace slidesorter { namespace view { + +namespace { +const static sal_Int32 gnLeftPageNumberOffset = 2; +const static sal_Int32 gnRightPageNumberOffset = 5; +const static sal_Int32 gnOuterBorderWidth = 5; +const static sal_Int32 gnInfoAreaMinWidth = 26; +} + +PageObjectLayouter::PageObjectLayouter ( + const ::boost::shared_ptr<Theme>& rpTheme, + const Size& rPageObjectWindowSize, + const Size& rPageSize, + const SharedSdWindow& rpWindow, + const sal_Int32 nPageCount) + : mpWindow(rpWindow), + maPageObjectSize(rPageObjectWindowSize.Width(), rPageObjectWindowSize.Height()), + mnModelToWindowScale(1), + maPageObjectBoundingBox(), + maPageNumberAreaBoundingBox(), + maPreviewBoundingBox(), + maTransitionEffectBoundingBox(), + maTransitionEffectIcon(IconCache::Instance().GetIcon(BMP_FADE_EFFECT_INDICATOR)), + mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rpWindow)) +{ + const Size aPageNumberAreaSize (GetPageNumberAreaSize(nPageCount)); + + const int nMaximumBorderWidth (gnOuterBorderWidth); + const int nFocusIndicatorWidth (rpTheme->GetIntegerValue(Theme::Integer_FocusIndicatorWidth)); + + maPreviewBoundingBox = CalculatePreviewBoundingBox( + maPageObjectSize, + Size(rPageSize.Width(), rPageSize.Height()), + aPageNumberAreaSize.Width(), + nFocusIndicatorWidth); + maFocusIndicatorBoundingBox = Rectangle(Point(0,0), maPageObjectSize); + maPageObjectBoundingBox = Rectangle( + Point( + nFocusIndicatorWidth, + nFocusIndicatorWidth), + Size( + maPageObjectSize.Width()-2*nFocusIndicatorWidth, + maPageObjectSize.Height()-2*nFocusIndicatorWidth)); + + maPageNumberAreaBoundingBox = Rectangle( + Point( + std::max(gnLeftPageNumberOffset, + sal_Int32(maPreviewBoundingBox.Left() + - gnRightPageNumberOffset + - aPageNumberAreaSize.Width())), + nMaximumBorderWidth), + aPageNumberAreaSize); + + const Size aIconSize (maTransitionEffectIcon.GetSizePixel()); + maTransitionEffectBoundingBox = Rectangle( + Point( + (maPreviewBoundingBox.Left() - aIconSize.Width()) / 2, + maPreviewBoundingBox.Bottom() - aIconSize.Height()), + aIconSize); +} + + + + +PageObjectLayouter::~PageObjectLayouter(void) +{ +} + + + + +Rectangle PageObjectLayouter::CalculatePreviewBoundingBox ( + Size& rPageObjectSize, + const Size& rPageSize, + const sal_Int32 nPageNumberAreaWidth, + const sal_Int32 nFocusIndicatorWidth) +{ + const sal_Int32 nIconWidth (maTransitionEffectIcon.GetSizePixel().Width()); + const sal_Int32 nLeftAreaWidth ( + ::std::max( + gnInfoAreaMinWidth, + gnRightPageNumberOffset + + ::std::max( + nPageNumberAreaWidth, + nIconWidth))); + sal_Int32 nPreviewWidth; + sal_Int32 nPreviewHeight; + const double nPageAspectRatio (double(rPageSize.Width()) / double(rPageSize.Height())); + if (rPageObjectSize.Height() == 0) + { + // Calculate height so that the preview fills the available + // horizontal space completely while observing the aspect ratio of + // the preview. + nPreviewWidth = rPageObjectSize.Width() + - nLeftAreaWidth - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1; + nPreviewHeight = ::basegfx::fround(nPreviewWidth / nPageAspectRatio); + rPageObjectSize.setHeight(nPreviewHeight + 2*gnOuterBorderWidth + 2*nFocusIndicatorWidth + 1); + } + else if (rPageObjectSize.Width() == 0) + { + // Calculate the width of the page object so that the preview fills + // the available vertical space completely while observing the + // aspect ratio of the preview. + nPreviewHeight = rPageObjectSize.Height() - 2*gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1; + nPreviewWidth = ::basegfx::fround(nPreviewHeight * nPageAspectRatio); + rPageObjectSize.setWidth(nPreviewWidth + + nLeftAreaWidth + gnOuterBorderWidth + 2*nFocusIndicatorWidth + 1); + + } + else + { + // The size of the page object is given. Calculate the size of the + // preview. + nPreviewWidth = rPageObjectSize.Width() + - nLeftAreaWidth - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1; + nPreviewHeight = rPageObjectSize.Height() + - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1; + if (double(nPreviewWidth)/double(nPreviewHeight) > nPageAspectRatio) + nPreviewWidth = ::basegfx::fround(nPreviewHeight * nPageAspectRatio); + else + nPreviewHeight = ::basegfx::fround(nPreviewWidth / nPageAspectRatio); + } + // When the preview does not fill the available space completely then + // place it flush right and vertically centered. + const int nLeft (rPageObjectSize.Width() + - gnOuterBorderWidth - nPreviewWidth - nFocusIndicatorWidth - 1); + const int nTop ((rPageObjectSize.Height() - nPreviewHeight)/2); + return Rectangle( + nLeft, + nTop, + nLeft + nPreviewWidth, + nTop + nPreviewHeight); +} + + + + +Rectangle PageObjectLayouter::GetBoundingBox ( + const model::SharedPageDescriptor& rpPageDescriptor, + const Part ePart, + const CoordinateSystem eCoordinateSystem) +{ + OSL_ASSERT(rpPageDescriptor); + Point aLocation (rpPageDescriptor ? rpPageDescriptor->GetLocation() : Point(0,0)); + return GetBoundingBox(aLocation, ePart, eCoordinateSystem); +} + + + + +Rectangle PageObjectLayouter::GetBoundingBox ( + const Point& rPageObjectLocation, + const Part ePart, + const CoordinateSystem eCoordinateSystem) +{ + Rectangle aBoundingBox; + switch (ePart) + { + case FocusIndicator: + aBoundingBox = maFocusIndicatorBoundingBox; + break; + + case PageObject: + case MouseOverIndicator: + aBoundingBox = maPageObjectBoundingBox; + break; + + case Preview: + aBoundingBox = maPreviewBoundingBox; + break; + + case PageNumber: + aBoundingBox = maPageNumberAreaBoundingBox; + break; + + case Name: + aBoundingBox = maPageNumberAreaBoundingBox; + break; + + case TransitionEffectIndicator: + aBoundingBox = maTransitionEffectBoundingBox; + break; + } + + // Adapt coordinates to the requested coordinate system. + Point aLocation (rPageObjectLocation); + if (eCoordinateSystem == WindowCoordinateSystem) + aLocation += mpWindow->GetMapMode().GetOrigin(); + + return Rectangle( + aBoundingBox.TopLeft() + aLocation, + aBoundingBox.BottomRight() + aLocation); +} + + + + +Size PageObjectLayouter::GetSize ( + const Part ePart, + const CoordinateSystem eCoordinateSystem) +{ + return GetBoundingBox(Point(0,0), ePart, eCoordinateSystem).GetSize(); +} + + + + +Size PageObjectLayouter::GetPageNumberAreaSize (const int nPageCount) +{ + OSL_ASSERT(mpWindow); + + // Set the correct font. + Font aOriginalFont (mpWindow->GetFont()); + if (mpPageNumberFont) + mpWindow->SetFont(*mpPageNumberFont); + + String sPageNumberTemplate; + if (nPageCount < 10) + sPageNumberTemplate = String::CreateFromAscii("9"); + else if (nPageCount < 100) + sPageNumberTemplate = String::CreateFromAscii("99"); + else if (nPageCount < 200) + // Just for the case that 1 is narrower than 9. + sPageNumberTemplate = String::CreateFromAscii("199"); + else if (nPageCount < 1000) + sPageNumberTemplate = String::CreateFromAscii("999"); + else + sPageNumberTemplate = String::CreateFromAscii("9999"); + // More then 9999 pages are not handled. + + const Size aSize ( + mpWindow->GetTextWidth(sPageNumberTemplate), + mpWindow->GetTextHeight()); + + mpWindow->SetFont(aOriginalFont); + + return aSize; +} + + + + +Image PageObjectLayouter::GetTransitionEffectIcon (void) const +{ + return maTransitionEffectIcon; +} + + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx new file mode 100644 index 000000000000..8d5b1cfbcdc8 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx @@ -0,0 +1,580 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsPageObjectPainter.hxx" + +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsTheme.hxx" +#include "view/SlsButtonBar.hxx" +#include "SlsFramePainter.hxx" +#include "cache/SlsPageCache.hxx" +#include "controller/SlsProperties.hxx" +#include "Window.hxx" +#include "sdpage.hxx" +#include "sdresid.hxx" +#include <vcl/svapp.hxx> +#include <vcl/vclenum.hxx> +#include <vcl/virdev.hxx> +#include <boost/scoped_ptr.hpp> + +using namespace ::drawinglayer::primitive2d; + +namespace sd { namespace slidesorter { namespace view { + +namespace { + +UINT8 Blend ( + const UINT8 nValue1, + const UINT8 nValue2, + const double nWeight) +{ + const double nValue (nValue1*(1-nWeight) + nValue2 * nWeight); + if (nValue < 0) + return 0; + else if (nValue > 255) + return 255; + else + return (UINT8)nValue; +} + +sal_uInt8 ClampColorChannel (const double nValue) +{ + if (nValue <= 0) + return 0; + else if (nValue >= 255) + return 255; + else + return sal_uInt8(nValue); +} + +sal_uInt8 CalculateColorChannel( + const double nColor1, + const double nColor2, + const double nAlpha1, + const double nAlpha2, + const double nAlpha0) +{ + if (nAlpha0 == 0) + return 0; + + const double nColor0 ((nAlpha1*nColor1 + nAlpha1*nAlpha2*nColor1 + nAlpha2*nColor2) / nAlpha0); + return ClampColorChannel(255 * nColor0); +} + +} // end of anonymous namespace + + + + +//===== PageObjectPainter ===================================================== + +PageObjectPainter::PageObjectPainter ( + const SlideSorter& rSlideSorter) + : mrLayouter(rSlideSorter.GetView().GetLayouter()), + mpPageObjectLayouter(), + mpCache(rSlideSorter.GetView().GetPreviewCache()), + mpProperties(rSlideSorter.GetProperties()), + mpTheme(rSlideSorter.GetTheme()), + mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rSlideSorter.GetContentWindow())), + mpShadowPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_RawShadow))), + mpFocusBorderPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_FocusBorder))), + maNormalBackground(), + maSelectionBackground(), + maFocusedSelectionBackground(), + maMouseOverBackground(), + maMouseOverFocusedBackground(), + msUnhideString(mpTheme->GetString(Theme::String_Unhide)), + mrButtonBar(rSlideSorter.GetView().GetButtonBar()) +{ + // Replace the color (not the alpha values) in the focus border with a + // color derived from the current selection color. + Color aColor (mpTheme->GetColor(Theme::Color_Selection)); + USHORT nHue, nSat, nBri; + aColor.RGBtoHSB(nHue, nSat, nBri); + aColor = Color::HSBtoRGB(nHue, 28, 65); + mpFocusBorderPainter->AdaptColor(aColor, true); +} + + + + +PageObjectPainter::~PageObjectPainter (void) +{ +} + + + + +void PageObjectPainter::PaintPageObject ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) +{ + // The page object layouter is quite volatile. It may have been replaced + // since the last call. Update it now. + mpPageObjectLayouter = mrLayouter.GetPageObjectLayouter(); + if ( ! mpPageObjectLayouter) + { + OSL_ASSERT(mpPageObjectLayouter); + return; + } + + // Turn off antialiasing to avoid the bitmaps from being shifted by + // fractions of a pixel and thus show blurry edges. + const USHORT nSavedAntialiasingMode (rDevice.GetAntialiasing()); + rDevice.SetAntialiasing(nSavedAntialiasingMode & ~ANTIALIASING_ENABLE_B2DDRAW); + + PaintBackground(rDevice, rpDescriptor); + PaintPreview(rDevice, rpDescriptor); + PaintPageNumber(rDevice, rpDescriptor); + PaintTransitionEffect(rDevice, rpDescriptor); + mrButtonBar.Paint(rDevice, rpDescriptor); + + rDevice.SetAntialiasing(nSavedAntialiasingMode); +} + + + + +void PageObjectPainter::NotifyResize (const bool bForce) +{ + (void)bForce; + maNormalBackground.SetEmpty(); + maSelectionBackground.SetEmpty(); + maFocusedSelectionBackground.SetEmpty(); + maFocusedBackground.SetEmpty(); + maMouseOverBackground.SetEmpty(); + maMouseOverFocusedBackground.SetEmpty(); + maMouseOverSelectedAndFocusedBackground.SetEmpty(); +} + + + + +void PageObjectPainter::SetTheme (const ::boost::shared_ptr<view::Theme>& rpTheme) +{ + mpTheme = rpTheme; + NotifyResize(true); +} + + + + +void PageObjectPainter::PaintBackground ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) +{ + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::FocusIndicator, + PageObjectLayouter::ModelCoordinateSystem)); + + const Bitmap& rBackground (GetBackgroundForState(rpDescriptor, rDevice)); + rDevice.DrawBitmap(aBox.TopLeft(), rBackground); + + // Fill the interior of the preview area with the default background + // color of the page. + SdPage* pPage = rpDescriptor->GetPage(); + if (pPage != NULL) + { + rDevice.SetFillColor(pPage->GetPageBackgroundColor(NULL)); + rDevice.SetLineColor(pPage->GetPageBackgroundColor(NULL)); + const Rectangle aPreviewBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + rDevice.DrawRect(aPreviewBox); + } +} + + + + +void PageObjectPainter::PaintPreview ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const +{ + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + + if (mpCache != NULL) + { + const SdrPage* pPage = rpDescriptor->GetPage(); + mpCache->SetPreciousFlag(pPage, true); + + const Bitmap aPreview (GetPreviewBitmap(rpDescriptor, &rDevice)); + if ( ! aPreview.IsEmpty()) + if (aPreview.GetSizePixel() != aBox.GetSize()) + rDevice.DrawBitmap(aBox.TopLeft(), aBox.GetSize(), aPreview); + else + rDevice.DrawBitmap(aBox.TopLeft(), aPreview); + } +} + + + + +Bitmap PageObjectPainter::CreateMarkedPreview ( + const Size& rSize, + const Bitmap& rPreview, + const BitmapEx& rOverlay, + const OutputDevice* pReferenceDevice) const +{ + ::boost::scoped_ptr<VirtualDevice> pDevice; + if (pReferenceDevice != NULL) + pDevice.reset(new VirtualDevice(*pReferenceDevice)); + else + pDevice.reset(new VirtualDevice()); + pDevice->SetOutputSizePixel(rSize); + + pDevice->DrawBitmap(Point(0,0), rSize, rPreview); + + // Paint bitmap tiled over the preview to mark it as excluded. + const sal_Int32 nIconWidth (rOverlay.GetSizePixel().Width()); + const sal_Int32 nIconHeight (rOverlay.GetSizePixel().Height()); + if (nIconWidth>0 && nIconHeight>0) + { + for (sal_Int32 nX=0; nX<rSize.Width(); nX+=nIconWidth) + for (sal_Int32 nY=0; nY<rSize.Height(); nY+=nIconHeight) + pDevice->DrawBitmapEx(Point(nX,nY), rOverlay); + } + return pDevice->GetBitmap(Point(0,0), rSize); +} + + + + +Bitmap PageObjectPainter::GetPreviewBitmap ( + const model::SharedPageDescriptor& rpDescriptor, + const OutputDevice* pReferenceDevice) const +{ + const SdrPage* pPage = rpDescriptor->GetPage(); + const bool bIsExcluded (rpDescriptor->HasState(model::PageDescriptor::ST_Excluded)); + + if (bIsExcluded) + { + Bitmap aMarkedPreview (mpCache->GetMarkedPreviewBitmap(pPage,false)); + const Rectangle aPreviewBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + if (aMarkedPreview.IsEmpty() || aMarkedPreview.GetSizePixel()!=aPreviewBox.GetSize()) + { + aMarkedPreview = CreateMarkedPreview( + aPreviewBox.GetSize(), + mpCache->GetPreviewBitmap(pPage,true), + mpTheme->GetIcon(Theme::Icon_HideSlideOverlay), + pReferenceDevice); + mpCache->SetMarkedPreviewBitmap(pPage, aMarkedPreview); + } + return aMarkedPreview; + } + else + { + return mpCache->GetPreviewBitmap(pPage,false); + } +} + + + + +void PageObjectPainter::PaintPageNumber ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const +{ + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::PageNumber, + PageObjectLayouter::ModelCoordinateSystem)); + + // Determine the color of the page number. + Color aPageNumberColor (mpTheme->GetColor(Theme::Color_PageNumberDefault)); + if (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) || + rpDescriptor->HasState(model::PageDescriptor::ST_Selected)) + { + // Page number is painted on background for hover or selection or + // both. Each of these background colors has a predefined luminance + // which is compatible with the PageNumberHover color. + aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberHover)); + } + else + { + const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background)); + const sal_Int32 nBackgroundLuminance (aBackgroundColor.GetLuminance()); + // When the background color is black then this is interpreted as + // high contrast mode and the font color is set to white. + if (nBackgroundLuminance == 0) + aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberHighContrast)); + else + { + // Compare luminance of default page number color and background + // color. When the two are similar then use a darker + // (preferred) or brighter font color. + const sal_Int32 nFontLuminance (aPageNumberColor.GetLuminance()); + if (abs(nBackgroundLuminance - nFontLuminance) < 60) + if (nBackgroundLuminance > nFontLuminance-30) + aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberBrightBackground)); + else + aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberDarkBackground)); + } + } + + // Paint the page number. + OSL_ASSERT(rpDescriptor->GetPage()!=NULL); + const sal_Int32 nPageNumber ((rpDescriptor->GetPage()->GetPageNum() - 1) / 2 + 1); + const String sPageNumber (String::CreateFromInt32(nPageNumber)); + rDevice.SetFont(*mpPageNumberFont); + rDevice.SetTextColor(aPageNumberColor); + rDevice.DrawText(aBox, sPageNumber, TEXT_DRAW_RIGHT | TEXT_DRAW_VCENTER); +} + + + + +void PageObjectPainter::PaintTransitionEffect ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const +{ + const SdPage* pPage = rpDescriptor->GetPage(); + if (pPage!=NULL && pPage->getTransitionType() > 0) + { + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::TransitionEffectIndicator, + PageObjectLayouter::ModelCoordinateSystem)); + + rDevice.DrawBitmapEx( + aBox.TopLeft(), + mpPageObjectLayouter->GetTransitionEffectIcon().GetBitmapEx()); + } +} + + + + +Bitmap& PageObjectPainter::GetBackgroundForState ( + const model::SharedPageDescriptor& rpDescriptor, + const OutputDevice& rReferenceDevice) +{ + enum State { None = 0x00, Selected = 0x01, MouseOver = 0x02, Focused = 0x04 }; + const State eState (State( + (rpDescriptor->HasState(model::PageDescriptor::ST_Selected) ? Selected : None) + | (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ? MouseOver : None) + | (rpDescriptor->HasState(model::PageDescriptor::ST_Focused) ? Focused : None))); + + switch (eState) + { + case MouseOver | Selected | Focused: + return GetBackground( + maMouseOverSelectedAndFocusedBackground, + Theme::Gradient_MouseOverSelectedAndFocusedPage, + rReferenceDevice, + true); + + case MouseOver | Selected: + case MouseOver: + return GetBackground( + maMouseOverBackground, + Theme::Gradient_MouseOverPage, + rReferenceDevice, + false); + + case MouseOver | Focused: + return GetBackground( + maMouseOverFocusedBackground, + Theme::Gradient_MouseOverPage, + rReferenceDevice, + true); + + case Selected | Focused: + return GetBackground( + maFocusedSelectionBackground, + Theme::Gradient_SelectedAndFocusedPage, + rReferenceDevice, + true); + + case Selected: + return GetBackground( + maSelectionBackground, + Theme::Gradient_SelectedPage, + rReferenceDevice, + false); + + case Focused: + return GetBackground( + maFocusedBackground, + Theme::Gradient_FocusedPage, + rReferenceDevice, + true); + + case None: + default: + return GetBackground( + maNormalBackground, + Theme::Gradient_NormalPage, + rReferenceDevice, + false); + } +} + + + + +Bitmap& PageObjectPainter::GetBackground( + Bitmap& rBackground, + Theme::GradientColorType eType, + const OutputDevice& rReferenceDevice, + const bool bHasFocusBorder) +{ + if (rBackground.IsEmpty()) + rBackground = CreateBackgroundBitmap(rReferenceDevice, eType, bHasFocusBorder); + return rBackground; +} + + + + +Bitmap PageObjectPainter::CreateBackgroundBitmap( + const OutputDevice& rReferenceDevice, + const Theme::GradientColorType eColorType, + const bool bHasFocusBorder) const +{ + const Size aSize (mpPageObjectLayouter->GetSize( + PageObjectLayouter::FocusIndicator, + PageObjectLayouter::WindowCoordinateSystem)); + const Rectangle aPageObjectBox (mpPageObjectLayouter->GetBoundingBox( + Point(0,0), + PageObjectLayouter::PageObject, + PageObjectLayouter::ModelCoordinateSystem)); + VirtualDevice aBitmapDevice (rReferenceDevice); + aBitmapDevice.SetOutputSizePixel(aSize); + + // Fill the background with the background color of the slide sorter. + const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background)); + OSL_TRACE("filling background of page object bitmap with color %x", aBackgroundColor.GetColor()); + aBitmapDevice.SetFillColor(aBackgroundColor); + aBitmapDevice.SetLineColor(aBackgroundColor); + aBitmapDevice.DrawRect(Rectangle(Point(0,0), aSize)); + + // Paint the slide area with a linear gradient that starts some pixels + // below the top and ends some pixels above the bottom. + const Color aTopColor(mpTheme->GetGradientColor(eColorType, Theme::Fill1)); + const Color aBottomColor(mpTheme->GetGradientColor(eColorType, Theme::Fill2)); + if (aTopColor != aBottomColor) + { + const sal_Int32 nHeight (aPageObjectBox.GetHeight()); + const sal_Int32 nDefaultConstantSize(nHeight/4); + const sal_Int32 nMinimalGradientSize(40); + const sal_Int32 nY1 ( + ::std::max<sal_Int32>( + 0, + ::std::min<sal_Int32>( + nDefaultConstantSize, + (nHeight - nMinimalGradientSize)/2))); + const sal_Int32 nY2 (nHeight-nY1); + const sal_Int32 nTop (aPageObjectBox.Top()); + for (sal_Int32 nY=0; nY<nHeight; ++nY) + { + if (nY<=nY1) + aBitmapDevice.SetLineColor(aTopColor); + else if (nY>=nY2) + aBitmapDevice.SetLineColor(aBottomColor); + else + { + Color aColor (aTopColor); + aColor.Merge(aBottomColor, 255 * (nY2-nY) / (nY2-nY1)); + aBitmapDevice.SetLineColor(aColor); + } + aBitmapDevice.DrawLine( + Point(aPageObjectBox.Left(), nY+nTop), + Point(aPageObjectBox.Right(), nY+nTop)); + } + } + else + { + aBitmapDevice.SetFillColor(aTopColor); + aBitmapDevice.DrawRect(aPageObjectBox); + } + + // Paint the simple border and, for some backgrounds, the focus border. + if (bHasFocusBorder) + mpFocusBorderPainter->PaintFrame(aBitmapDevice, aPageObjectBox); + else + PaintBorder(aBitmapDevice, eColorType, aPageObjectBox); + + // Get bounding box of the preview around which a shadow is painted. + // Compensate for the border around the preview. + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + Point(0,0), + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + Rectangle aFrameBox (aBox.Left()-1,aBox.Top()-1,aBox.Right()+1,aBox.Bottom()+1); + mpShadowPainter->PaintFrame(aBitmapDevice, aFrameBox); + + return aBitmapDevice.GetBitmap (Point(0,0),aSize); +} + + + + +void PageObjectPainter::PaintBorder ( + OutputDevice& rDevice, + const Theme::GradientColorType eColorType, + const Rectangle& rBox) const +{ + rDevice.SetFillColor(); + const sal_Int32 nBorderWidth (1); + for (int nIndex=0; nIndex<nBorderWidth; ++nIndex) + { + const int nDelta (nIndex); + rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::Border2)); + rDevice.DrawLine( + Point(rBox.Left()-nDelta, rBox.Top()-nDelta), + Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta)); + rDevice.DrawLine( + Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta), + Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta)); + rDevice.DrawLine( + Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta), + Point(rBox.Right()+nDelta, rBox.Top()-nDelta)); + + rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::Border1)); + rDevice.DrawLine( + Point(rBox.Left()-nDelta, rBox.Top()-nDelta), + Point(rBox.Right()+nDelta, rBox.Top()-nDelta)); + } +} + + + +} } } // end of namespace sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectViewContact.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectViewContact.cxx deleted file mode 100755 index 303e78eeff61..000000000000 --- a/sd/source/ui/slidesorter/view/SlsPageObjectViewContact.cxx +++ /dev/null @@ -1,125 +0,0 @@ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -#include "precompiled_sd.hxx" - -#include "view/SlsPageObjectViewContact.hxx" - -#include "model/SlsPageDescriptor.hxx" -#include "controller/SlsPageObjectFactory.hxx" - -#include <svx/svdopage.hxx> -#include <tools/debug.hxx> - -#include <basegfx/polygon/b2dpolygontools.hxx> -#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> - -using namespace ::sdr::contact; - -namespace sd { namespace slidesorter { namespace view { - - -PageObjectViewContact::PageObjectViewContact ( - SdrPageObj& rPageObj, - const model::SharedPageDescriptor& rpDescriptor) - : ViewContactOfPageObj (rPageObj), - mbInDestructor(false), - mpDescriptor(rpDescriptor) -{ -} - -PageObjectViewContact::~PageObjectViewContact (void) -{ - // remember that this instance is in destruction - mbInDestructor = true; -} - - - -ViewObjectContact& - PageObjectViewContact::CreateObjectSpecificViewObjectContact( - ObjectContact& rObjectContact) -{ - OSL_ASSERT(mpDescriptor.get()!=NULL); - - ViewObjectContact* pResult - = mpDescriptor->GetPageObjectFactory().CreateViewObjectContact ( - rObjectContact, - *this); - DBG_ASSERT (pResult!=NULL, - "PageObjectViewContact::CreateObjectSpecificViewObjectContact() was not able to create object."); - return *pResult; -} - -const SdrPage* PageObjectViewContact::GetPage (void) const -{ - // when this instance itself is in destruction, do no longer - // provide the referenced page to VOC childs of this OC. This - // happens e.g. in destructor which destroys all child-VOCs which - // may in their implementation still reference their VC from - // their own destructor - if (!mbInDestructor) - return GetReferencedPage(); - else - return NULL; -} - -void PageObjectViewContact::ActionChanged (void) -{ - ViewContactOfPageObj::ActionChanged(); -} - -SdrPageObj& PageObjectViewContact::GetPageObject (void) const -{ - return ViewContactOfPageObj::GetPageObj(); -} - -drawinglayer::primitive2d::Primitive2DSequence PageObjectViewContact::createViewIndependentPrimitive2DSequence() const -{ - // ceate graphical visualisation data. Since this is the view-independent version which should not be used, - // create a replacement graphic visualisation here. Use GetLastBoundRect to access the model data directly - // which is aOutRect for SdrPageObj. - OSL_ASSERT(mpDescriptor.get()!=NULL); - Rectangle aModelRectangle(GetPageObj().GetLastBoundRect()); - const SvBorder aBorder(mpDescriptor->GetModelBorder()); - - aModelRectangle.Left() -= aBorder.Left(); - aModelRectangle.Right() += aBorder.Right(); - aModelRectangle.Top() -= aBorder.Top(); - aModelRectangle.Bottom() += aBorder.Bottom(); - - const basegfx::B2DRange aModelRange(aModelRectangle.Left(), aModelRectangle.Top(), aModelRectangle.Right(), aModelRectangle.Bottom()); - const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aModelRange)); - const basegfx::BColor aYellow(1.0, 1.0, 0.0); - const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aYellow)); - - return drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); -} - -} } } // end of namespace ::sd::slidesorter::view - -// eof diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx deleted file mode 100755 index b1e4e80fdf1f..000000000000 --- a/sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx +++ /dev/null @@ -1,1403 +0,0 @@ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -#include "precompiled_sd.hxx" - -#include "view/SlsPageObjectViewObjectContact.hxx" - -#include "controller/SlsProperties.hxx" -#include "view/SlideSorterView.hxx" -#include "view/SlsPageObjectViewContact.hxx" -#include "view/SlsPageObject.hxx" -#include "view/SlsFontProvider.hxx" -#include "model/SlsPageDescriptor.hxx" -#include "cache/SlsPageCache.hxx" -#include "cache/SlsPageCacheManager.hxx" -#include "res_bmp.hrc" -#include "tools/IconCache.hxx" -#include "PreviewRenderer.hxx" - -#include "sdpage.hxx" -#include "sdresid.hxx" -#include "glob.hrc" -#include "drawdoc.hxx" -#include <svx/sdr/contact/displayinfo.hxx> -#include <svx/sdr/contact/viewcontact.hxx> -#include <svx/svdopage.hxx> -#include <svx/svdpagv.hxx> -#include <svx/xlndsit.hxx> -#include <svx/xlnclit.hxx> -#include <svx/svdoutl.hxx> -#include <svx/sdrpagewindow.hxx> -#include <vcl/bitmap.hxx> -#include <vcl/outdev.hxx> -#include <vcl/virdev.hxx> -#include <vcl/lineinfo.hxx> -#include <tools/color.hxx> -#include <boost/shared_ptr.hpp> -#include <com/sun/star/uno/Exception.hpp> -#include <vcl/svapp.hxx> -#include <tools/diagnose_ex.h> - -using namespace ::sdr::contact; -using namespace ::sd::slidesorter::model; - -using drawinglayer::primitive2d::Primitive2DReference; -using drawinglayer::primitive2d::Primitive2DSequence; - -namespace sd { namespace slidesorter { namespace view { - - -const sal_Int32 PageObjectViewObjectContact::mnSelectionIndicatorOffset = 2; -const sal_Int32 PageObjectViewObjectContact::mnSelectionIndicatorThickness = 3; -const sal_Int32 PageObjectViewObjectContact::mnFocusIndicatorOffset = 3; -const sal_Int32 PageObjectViewObjectContact::mnFadeEffectIndicatorOffset = 9; -const sal_Int32 PageObjectViewObjectContact::mnFadeEffectIndicatorSize = 14; -const sal_Int32 PageObjectViewObjectContact::mnPageNumberOffset = 9; -const sal_Int32 PageObjectViewObjectContact::mnMouseOverEffectOffset = 3; -const sal_Int32 PageObjectViewObjectContact::mnMouseOverEffectThickness = 1; - -PageObjectViewObjectContact::PageObjectViewObjectContact ( - ObjectContact& rObjectContact, - ViewContact& rViewContact, - const ::boost::shared_ptr<cache::PageCache>& rpCache, - const ::boost::shared_ptr<controller::Properties>& rpProperties) - : ViewObjectContactOfPageObj(rObjectContact, rViewContact), - mbInDestructor(false), - mxCurrentPageContents(), - mpCache(rpCache), - mpProperties(rpProperties) -{ - SharedPageDescriptor pDescriptor (GetPageDescriptor()); - OSL_ASSERT(pDescriptor.get()!=NULL); - if (pDescriptor.get() != NULL) - pDescriptor->SetViewObjectContact(this); -} - - - - -PageObjectViewObjectContact::~PageObjectViewObjectContact (void) -{ - mbInDestructor = true; - - GetPageDescriptor()->SetViewObjectContact(NULL); - - if (mpCache.get() != NULL) - { - const SdrPage* pPage = GetPage(); - - if(pPage) - { - mpCache->ReleasePreviewBitmap(GetPage()); - } - } -} - - - - -void PageObjectViewObjectContact::SetCache (const ::boost::shared_ptr<cache::PageCache>& rpCache) -{ - mpCache = rpCache; -} - - - - -Rectangle PageObjectViewObjectContact::GetBoundingBox ( - OutputDevice& rDevice, - BoundingBoxType eType, - CoordinateSystem eCoordinateSystem) const -{ - // Most of the bounding boxes are based on the bounding box of the preview. - // SdrPageObj is a SdrObject, so use SdrObject::aOutRect as model data - const PageObjectViewContact& rPaObVOC(static_cast<PageObjectViewContact&>(GetViewContact())); - Rectangle aBoundingBox(rPaObVOC.GetPageObject().GetLastBoundRect()); - - CoordinateSystem eCurrentCoordinateSystem (ModelCoordinateSystem); - switch(eType) - { - case PageObjectBoundingBox: - { - const SvBorder aPageDescriptorBorder(GetPageDescriptor()->GetModelBorder()); - aBoundingBox.Left() -= aPageDescriptorBorder.Left(); - aBoundingBox.Top() -= aPageDescriptorBorder.Top(); - aBoundingBox.Right() += aPageDescriptorBorder.Right(); - aBoundingBox.Bottom() += aPageDescriptorBorder.Bottom(); - break; - } - case PreviewBoundingBox: - { - // The aBoundingBox already has the right value. - break; - } - case MouseOverIndicatorBoundingBox: - { - const sal_Int32 nBorderWidth (mnMouseOverEffectOffset+mnMouseOverEffectThickness); - const Size aBorderSize (rDevice.PixelToLogic(Size(nBorderWidth,nBorderWidth))); - aBoundingBox.Left() -= aBorderSize.Width(); - aBoundingBox.Top() -= aBorderSize.Height(); - aBoundingBox.Right() += aBorderSize.Width(); - aBoundingBox.Bottom() += aBorderSize.Height(); - break; - } - case FocusIndicatorBoundingBox: - { - const sal_Int32 nBorderWidth (mnFocusIndicatorOffset+1); - const Size aBorderSize (rDevice.PixelToLogic(Size(nBorderWidth,nBorderWidth))); - aBoundingBox.Left() -= aBorderSize.Width(); - aBoundingBox.Top() -= aBorderSize.Height(); - aBoundingBox.Right() += aBorderSize.Width(); - aBoundingBox.Bottom() += aBorderSize.Height(); - break; - } - case SelectionIndicatorBoundingBox: - { - const sal_Int32 nBorderWidth(mnSelectionIndicatorOffset+mnSelectionIndicatorThickness); - const Size aBorderSize (rDevice.PixelToLogic(Size(nBorderWidth,nBorderWidth))); - aBoundingBox.Left() -= aBorderSize.Width(); - aBoundingBox.Top() -= aBorderSize.Height(); - aBoundingBox.Right() += aBorderSize.Width(); - aBoundingBox.Bottom() += aBorderSize.Height(); - break; - } - case PageNumberBoundingBox: - { - Size aModelOffset = rDevice.PixelToLogic(Size(mnPageNumberOffset,mnPageNumberOffset)); - Size aNumberSize (GetPageDescriptor()->GetPageNumberAreaModelSize()); - aBoundingBox = Rectangle ( - Point ( - aBoundingBox.Left() - aModelOffset.Width() - aNumberSize.Width(), - aBoundingBox.Top()), - aNumberSize); - break; - } - - case NameBoundingBox: - break; - - case FadeEffectIndicatorBoundingBox: - Size aModelOffset = rDevice.PixelToLogic(Size (0, mnFadeEffectIndicatorOffset)); - // Flush left just outside the selection rectangle. - aBoundingBox = Rectangle ( - Point ( - aBoundingBox.Left(), - aBoundingBox.Bottom() + aModelOffset.Height() - ), - rDevice.PixelToLogic ( - IconCache::Instance().GetIcon(BMP_FADE_EFFECT_INDICATOR).GetSizePixel()) - ); - break; - } - - // Make sure the bounding box uses the requested coordinate system. - if (eCurrentCoordinateSystem != eCoordinateSystem) - { - if (eCoordinateSystem == ModelCoordinateSystem) - aBoundingBox = Rectangle( - rDevice.PixelToLogic(aBoundingBox.TopLeft()), - rDevice.PixelToLogic(aBoundingBox.GetSize())); - else - aBoundingBox = Rectangle( - rDevice.LogicToPixel(aBoundingBox.TopLeft()), - rDevice.LogicToPixel(aBoundingBox.GetSize())); - } - return aBoundingBox; -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -// example implementation for primitive usage for PageObjectViewObjectContact - -} } } // end of namespace ::sd::slidesorter::view - -#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> -#include <basegfx/polygon/b2dpolygontools.hxx> -#include <basegfx/matrix/b2dhommatrix.hxx> -#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> -#include <sd_primitivetypes2d.hxx> -#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> -#include <drawinglayer/primitive2d/textlayoutdevice.hxx> -#include <drawinglayer/primitive2d/textprimitive2d.hxx> -#include <drawinglayer/geometry/viewinformation2d.hxx> -#include <svx/sdr/contact/objectcontact.hxx> - -namespace sd { namespace slidesorter { namespace view { - -/////////////////////////////////////////////////////////////////////////////////////////////// -// All primitives for SdrPageObject visualisation are based on one range which describes -// the size of the inner rectangle for PagePreview visualisation. Use a common implementation -// class for all derived SdPageObjectPrimitives. The SdPageObjectBasePrimitive itself -// is pure virtual - -class SdPageObjectBasePrimitive : public drawinglayer::primitive2d::BufferedDecompositionPrimitive2D -{ -private: - // the inner range of the SdPageObject visualisation - basegfx::B2DRange maRange; - -public: - // constructor and destructor - SdPageObjectBasePrimitive(const basegfx::B2DRange& rRange); - virtual ~SdPageObjectBasePrimitive(); - - // data access - const basegfx::B2DRange& getPageObjectRange() const { return maRange; } - - // compare operator - virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const; -}; - -SdPageObjectBasePrimitive::SdPageObjectBasePrimitive(const basegfx::B2DRange& rRange) -: drawinglayer::primitive2d::BufferedDecompositionPrimitive2D(), - maRange(rRange) -{ -} - -SdPageObjectBasePrimitive::~SdPageObjectBasePrimitive() -{ -} - -bool SdPageObjectBasePrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const -{ - if(drawinglayer::primitive2d::BufferedDecompositionPrimitive2D::operator==(rPrimitive)) - { - const SdPageObjectBasePrimitive& rCompare = static_cast< const SdPageObjectBasePrimitive& >(rPrimitive); - return (getPageObjectRange() == rCompare.getPageObjectRange()); - } - - return false; -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -// SdPageObjectPrimitive for selected visualisation - -class SdPageObjectPageBitmapPrimitive : public SdPageObjectBasePrimitive -{ -private: - // the bitmap containing the PagePreview - BitmapEx maBitmapEx; - -protected: - // method which is to be used to implement the local decomposition of a 2D primitive. - virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const; - -public: - // constructor and destructor - SdPageObjectPageBitmapPrimitive( - const basegfx::B2DRange& rRange, - const BitmapEx& rBitmapEx); - ~SdPageObjectPageBitmapPrimitive(); - - // data access - const BitmapEx& getBitmapEx() const { return maBitmapEx; } - - // compare operator - virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const; - - // provide unique ID - DeclPrimitrive2DIDBlock() -}; - -Primitive2DSequence SdPageObjectPageBitmapPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const -{ - // add bitmap primitive - // to avoid scaling, use the Bitmap pixel size as primitive size - basegfx::B2DHomMatrix aBitmapTransform; - const Size aBitmapSize(getBitmapEx().GetSizePixel()); - const basegfx::B2DVector aBitmapSizeLogic(rViewInformation.getInverseObjectToViewTransformation() * - basegfx::B2DVector(aBitmapSize.getWidth() - 1, aBitmapSize.getHeight() - 1)); - - // short form for scale and translate transformation - aBitmapTransform.set(0L, 0L, aBitmapSizeLogic.getX()); - aBitmapTransform.set(1L, 1L, aBitmapSizeLogic.getY()); - aBitmapTransform.set(0L, 2L, getPageObjectRange().getMinX()); - aBitmapTransform.set(1L, 2L, getPageObjectRange().getMinY()); - - // add a BitmapPrimitive2D to the result - const Primitive2DReference xReference( - new drawinglayer::primitive2d::BitmapPrimitive2D(getBitmapEx(), aBitmapTransform)); - return Primitive2DSequence(&xReference, 1); -} - -SdPageObjectPageBitmapPrimitive::SdPageObjectPageBitmapPrimitive( - const basegfx::B2DRange& rRange, - const BitmapEx& rBitmapEx) -: SdPageObjectBasePrimitive(rRange), - maBitmapEx(rBitmapEx) -{ -} - -SdPageObjectPageBitmapPrimitive::~SdPageObjectPageBitmapPrimitive() -{ -} - -bool SdPageObjectPageBitmapPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const -{ - if(SdPageObjectBasePrimitive::operator==(rPrimitive)) - { - const SdPageObjectPageBitmapPrimitive& rCompare = static_cast< const SdPageObjectPageBitmapPrimitive& >(rPrimitive); - return (getBitmapEx() == rCompare.getBitmapEx()); - } - - return false; -} - -ImplPrimitrive2DIDBlock(SdPageObjectPageBitmapPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTPAGEBITMAPPRIMITIVE) - -/////////////////////////////////////////////////////////////////////////////////////////////// -// SdPageObjectPrimitive for selected visualisation - -class SdPageObjectSelectPrimitive : public SdPageObjectBasePrimitive -{ -private: - /// Gap between border of page object and inside of selection rectangle. - static const sal_Int32 mnSelectionIndicatorOffset; - - /// Thickness of the selection rectangle. - static const sal_Int32 mnSelectionIndicatorThickness; - -protected: - // method which is to be used to implement the local decomposition of a 2D primitive. - virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const; - -public: - // constructor and destructor - SdPageObjectSelectPrimitive(const basegfx::B2DRange& rRange); - ~SdPageObjectSelectPrimitive(); - - // provide unique ID - DeclPrimitrive2DIDBlock() -}; - -const sal_Int32 SdPageObjectSelectPrimitive::mnSelectionIndicatorOffset(1); -const sal_Int32 SdPageObjectSelectPrimitive::mnSelectionIndicatorThickness(3); - -Primitive2DSequence SdPageObjectSelectPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const -{ - Primitive2DSequence xRetval(2); - - // since old Width/Height calculations always added a single pixel value, - // it is necessary to create a inner range which is one display unit less - // at the bottom right. - const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0)); - const basegfx::B2DRange aAdaptedInnerRange( - getPageObjectRange().getMinX(), getPageObjectRange().getMinY(), - getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY()); - - // PaintSelectionIndicator replacement. Grow by offset first - basegfx::B2DRange aDiscreteOuterRange(aAdaptedInnerRange); - aDiscreteOuterRange.grow(mnSelectionIndicatorOffset * aDiscretePixel.getX()); - - // Remember inner border. Make it one bigger in top left since polygons - // do not paint their lower-right corners. Since this is the inner polygon, - // the top-left corders are the ones to grow here - const basegfx::B2DRange aDiscreteInnerRange( - aDiscreteOuterRange.getMinimum() + aDiscretePixel, - aDiscreteOuterRange.getMaximum() - aDiscretePixel); - - // grow by line width - aDiscreteOuterRange.grow((mnSelectionIndicatorThickness - 1) * aDiscretePixel.getX()); - - // create a PolyPolygon from those ranges. For the outer polygon, round edges by - // giving a relative radius to the polygon creator (use mnSelectionIndicatorThickness here, too) - const double fPixelFactor(aDiscretePixel.getX() * (mnSelectionIndicatorThickness + 2.5)); - const double fRelativeRadiusX(fPixelFactor / ::std::max(aDiscreteOuterRange.getWidth(), 1.0)); - const double fRelativeRadiusY(fPixelFactor / ::std::max(aDiscreteOuterRange.getHeight(), 1.0)); - basegfx::B2DPolyPolygon aFramePolyPolygon; - const basegfx::B2DPolygon aRoundedOuterPolygon(basegfx::tools::createPolygonFromRect(aDiscreteOuterRange, fRelativeRadiusX, fRelativeRadiusY)); - - aFramePolyPolygon.append(aRoundedOuterPolygon); - aFramePolyPolygon.append(basegfx::tools::createPolygonFromRect(aDiscreteInnerRange)); - - // add colored PolyPolygon - const svtools::ColorConfig aColorConfig; - static bool bTestWithBrightColors(false); - const basegfx::BColor aFrameColor(bTestWithBrightColors ? basegfx::BColor(0,1,0) : Application::GetSettings().GetStyleSettings().GetMenuHighlightColor().getBColor()); - - xRetval[0] = Primitive2DReference( - new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(aFramePolyPolygon, aFrameColor)); - - // add aRoundedOuterPolygon again as non-filled line polygon to get the roundungs - // painted correctly - xRetval[1] = Primitive2DReference( - new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aRoundedOuterPolygon, aFrameColor)); - - return xRetval; -} - -SdPageObjectSelectPrimitive::SdPageObjectSelectPrimitive(const basegfx::B2DRange& rRange) -: SdPageObjectBasePrimitive(rRange) -{ -} - -SdPageObjectSelectPrimitive::~SdPageObjectSelectPrimitive() -{ -} - -ImplPrimitrive2DIDBlock(SdPageObjectSelectPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTSELECTPRIMITIVE) - -/////////////////////////////////////////////////////////////////////////////////////////////// -// SdPageObjectPrimitive for border around bitmap visualisation - -class SdPageObjectBorderPrimitive : public SdPageObjectBasePrimitive -{ -protected: - // method which is to be used to implement the local decomposition of a 2D primitive. - virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const; - -public: - // constructor and destructor - SdPageObjectBorderPrimitive(const basegfx::B2DRange& rRange); - ~SdPageObjectBorderPrimitive(); - - // provide unique ID - DeclPrimitrive2DIDBlock() -}; - -Primitive2DSequence SdPageObjectBorderPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const -{ - // since old Width/Height calculations always added a single pixel value, - // it is necessary to create a inner range which is one display unit less - // at the bottom right. - const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0)); - const basegfx::B2DRange aAdaptedInnerRange( - getPageObjectRange().getMinX(), getPageObjectRange().getMinY(), - getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY()); - - // Paint_Border replacement. (use aBorderColor) - static bool bTestWithBrightColors(false); - const svtools::ColorConfig aColorConfig; - const basegfx::BColor aBorderColor(bTestWithBrightColors ? basegfx::BColor(1,0,0) : Color(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor).getBColor()); - - const Primitive2DReference xReference( - new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(basegfx::tools::createPolygonFromRect(aAdaptedInnerRange), aBorderColor)); - return Primitive2DSequence(&xReference, 1); -} - -SdPageObjectBorderPrimitive::SdPageObjectBorderPrimitive(const basegfx::B2DRange& rRange) -: SdPageObjectBasePrimitive(rRange) -{ -} - -SdPageObjectBorderPrimitive::~SdPageObjectBorderPrimitive() -{ -} - -ImplPrimitrive2DIDBlock(SdPageObjectBorderPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTBORDERPRIMITIVE) - -/////////////////////////////////////////////////////////////////////////////////////////////// -// SdPageObjectPrimitive for focus visualisation - -class SdPageObjectFocusPrimitive : public SdPageObjectBasePrimitive -{ -private: - /// Gap between border of page object and inside of focus rectangle. - static const sal_Int32 mnFocusIndicatorOffset; - const bool mbContrastToSelected; - -protected: - // method which is to be used to implement the local decomposition of a 2D primitive. - virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const; - -public: - // constructor and destructor - SdPageObjectFocusPrimitive(const basegfx::B2DRange& rRange, const bool bContrast); - ~SdPageObjectFocusPrimitive(); - - // provide unique ID - DeclPrimitrive2DIDBlock() -}; - -const sal_Int32 SdPageObjectFocusPrimitive::mnFocusIndicatorOffset(2); - -Primitive2DSequence SdPageObjectFocusPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const -{ - Primitive2DSequence xRetval(2); - - // since old Width/Height calculations always added a single pixel value, - // it is necessary to create a inner range which is one display unit less - // at the bottom right. - const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0)); - const basegfx::B2DRange aAdaptedInnerRange( - getPageObjectRange().getMinX(), getPageObjectRange().getMinY(), - getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY()); - - // Paint_FocusIndicator replacement. (black and white). - // imitate Paint_DottedRectangle: First paint a white rectangle and above it a black dotted one - basegfx::B2DRange aFocusIndicatorRange(aAdaptedInnerRange); - aFocusIndicatorRange.grow(mnFocusIndicatorOffset * aDiscretePixel.getX()); - - // create polygon - const basegfx::B2DPolygon aIndicatorPolygon(basegfx::tools::createPolygonFromRect(aFocusIndicatorRange)); - - const StyleSettings& rStyleSettings(Application::GetSettings().GetStyleSettings()); - - // "background" rectangle - const Color aBackgroundColor(mbContrastToSelected ? rStyleSettings.GetMenuHighlightColor() : rStyleSettings.GetWindowColor()); - xRetval[0] = Primitive2DReference( - new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aIndicatorPolygon, Color(COL_WHITE).getBColor())); - - // dotted black rectangle with same geometry - ::std::vector< double > aDotDashArray; - - const sal_Int32 nFocusIndicatorWidth (3); - aDotDashArray.push_back(nFocusIndicatorWidth *aDiscretePixel.getX()); - aDotDashArray.push_back(nFocusIndicatorWidth * aDiscretePixel.getX()); - - // prepare line and stroke attributes - const Color aLineColor(mbContrastToSelected ? rStyleSettings.GetMenuHighlightTextColor() : rStyleSettings.GetWindowTextColor()); - const drawinglayer::attribute::LineAttribute aLineAttribute(aLineColor.getBColor()); - const drawinglayer::attribute::StrokeAttribute aStrokeAttribute( - aDotDashArray, 2.0 * nFocusIndicatorWidth * aDiscretePixel.getX()); - - - xRetval[1] = Primitive2DReference( - new drawinglayer::primitive2d::PolygonStrokePrimitive2D(aIndicatorPolygon, aLineAttribute, aStrokeAttribute)); - - return xRetval; -} - -SdPageObjectFocusPrimitive::SdPageObjectFocusPrimitive(const basegfx::B2DRange& rRange, const bool bContrast) - : SdPageObjectBasePrimitive(rRange), - mbContrastToSelected(bContrast) -{ -} - -SdPageObjectFocusPrimitive::~SdPageObjectFocusPrimitive() -{ -} - -ImplPrimitrive2DIDBlock(SdPageObjectFocusPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTFOCUSPRIMITIVE) - -/////////////////////////////////////////////////////////////////////////////////////////////// -// SdPageObjectPrimitive for fade effect visualisation - -class SdPageObjectFadeNameNumberPrimitive : public SdPageObjectBasePrimitive -{ -private: - /// Size of width and height of the fade effect indicator in pixels. - static const sal_Int32 mnFadeEffectIndicatorOffset; - - /// Size of width and height of the comments indicator in pixels. - static const sal_Int32 mnCommentsIndicatorOffset; - - /// Gap between border of page object and number rectangle. - static const sal_Int32 mnPageNumberOffset; - - /// the indicator bitmaps. Static since it is usable outside this primitive - /// for size comparisons - static BitmapEx* mpFadeEffectIconBitmap; - static BitmapEx* mpCommentsIconBitmap; - - /// page name, number and needed infos - String maPageName; - sal_uInt32 mnPageNumber; - Font maPageNameFont; - Size maPageNumberAreaModelSize; - - // bitfield - bool mbShowFadeEffectIcon : 1; - bool mbShowCommentsIcon : 1; - bool mbExcluded : 1; - - // private helpers - const BitmapEx& getFadeEffectIconBitmap() const; - -protected: - // method which is to be used to implement the local decomposition of a 2D primitive. - virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const; - -public: - // constructor and destructor - SdPageObjectFadeNameNumberPrimitive( - const basegfx::B2DRange& rRange, - const String& rPageName, - sal_uInt32 nPageNumber, - const Font& rPageNameFont, - const Size& rPageNumberAreaModelSize, - bool bShowFadeEffectIcon, - bool bShowCommentsIcon, - bool bExcluded); - ~SdPageObjectFadeNameNumberPrimitive(); - - // data access - const String& getPageName() const { return maPageName; } - sal_uInt32 getPageNumber() const { return mnPageNumber; } - const Font& getPageNameFont() const { return maPageNameFont; } - const Size& getPageNumberAreaModelSize() const { return maPageNumberAreaModelSize; } - bool getShowFadeEffectIcon() const { return mbShowFadeEffectIcon; } - bool getShowCommentsIcon() const { return mbShowCommentsIcon; } - bool getExcluded() const { return mbExcluded; } - - // compare operator - virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const; - - // provide unique ID - DeclPrimitrive2DIDBlock() -}; - -const sal_Int32 SdPageObjectFadeNameNumberPrimitive::mnFadeEffectIndicatorOffset(9); -const sal_Int32 SdPageObjectFadeNameNumberPrimitive::mnPageNumberOffset(9); -BitmapEx* SdPageObjectFadeNameNumberPrimitive::mpFadeEffectIconBitmap = 0; - -const BitmapEx& SdPageObjectFadeNameNumberPrimitive::getFadeEffectIconBitmap() const -{ - if(mpFadeEffectIconBitmap == NULL) - { - // prepare FadeEffectIconBitmap on demand - const sal_uInt16 nIconId(Application::GetSettings().GetStyleSettings().GetHighContrastMode() - ? BMP_FADE_EFFECT_INDICATOR_H - : BMP_FADE_EFFECT_INDICATOR); - const BitmapEx aFadeEffectIconBitmap(IconCache::Instance().GetIcon(nIconId).GetBitmapEx()); - const_cast< SdPageObjectFadeNameNumberPrimitive* >(this)->mpFadeEffectIconBitmap = new BitmapEx(aFadeEffectIconBitmap); - } - - return *mpFadeEffectIconBitmap; -} - - -const sal_Int32 SdPageObjectFadeNameNumberPrimitive::mnCommentsIndicatorOffset(9); -BitmapEx* SdPageObjectFadeNameNumberPrimitive::mpCommentsIconBitmap = 0; - -Primitive2DSequence SdPageObjectFadeNameNumberPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const -{ - const xub_StrLen nTextLength(getPageName().Len()); - const sal_uInt32 nCount( - (getShowFadeEffectIcon() ? 1 : 0) + // FadeEffect icon - (nTextLength ? 1 : 0) + // PageName - 1 + // PageNumber (always) - (getExcluded() ? 2 : 0) // PageNumber crossed out - ); - sal_uInt32 nInsert(0); - Primitive2DSequence xRetval(nCount); - - // since old Width/Height calculations always added a single pixel value, - // it is necessary to create a inner range which is one display unit less - // at the bottom right. - const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0)); - const basegfx::B2DRange aAdaptedInnerRange( - getPageObjectRange().getMinX(), getPageObjectRange().getMinY(), - getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY()); - - // preapre TextLayouter - drawinglayer::primitive2d::TextLayouterDevice aTextLayouter; - aTextLayouter.setFont(getPageNameFont()); - - // get font attributes - basegfx::B2DVector aTextSizeAttribute; - const drawinglayer::attribute::FontAttribute aFontAttribute( - drawinglayer::primitive2d::getFontAttributeFromVclFont( - aTextSizeAttribute, - getPageNameFont(), - false, - false)); - - // prepare locale; this may need some more information in the future - const ::com::sun::star::lang::Locale aLocale; - - // prepare font color from System - const basegfx::BColor aFontColor(Application::GetSettings().GetStyleSettings().GetFontColor().getBColor()); - - if(getShowFadeEffectIcon()) - { - // prepare fFadeEffect Sizes - const basegfx::B2DVector aFadeEffectBitmapSizeLogic(rViewInformation.getInverseObjectToViewTransformation() * - basegfx::B2DVector( - getFadeEffectIconBitmap().GetSizePixel().getWidth() - 1, - getFadeEffectIconBitmap().GetSizePixel().getHeight() - 1)); - - // Paint_FadeEffectIndicator replacement. - // create transformation. To avoid bitmap scaling, use bitmap size as size - basegfx::B2DHomMatrix aBitmapTransform; - - // short form for scale and translate transformation - aBitmapTransform.set(0L, 0L, aFadeEffectBitmapSizeLogic.getX()); - aBitmapTransform.set(1L, 1L, aFadeEffectBitmapSizeLogic.getY()); - aBitmapTransform.set(0L, 2L, aAdaptedInnerRange.getMinX()); - aBitmapTransform.set(1L, 2L, aAdaptedInnerRange.getMaxY() + ((mnFadeEffectIndicatorOffset + 1) * aDiscretePixel.getX())); - - xRetval[nInsert++] = Primitive2DReference( - new drawinglayer::primitive2d::BitmapPrimitive2D(getFadeEffectIconBitmap(), aBitmapTransform)); - } - - if(nTextLength) - { - // prepare fFadeEffect Sizes since it consumes from text size - const basegfx::B2DVector aFadeEffectBitmapSizeLogic(rViewInformation.getInverseObjectToViewTransformation() * - basegfx::B2DVector( - getFadeEffectIconBitmap().GetSizePixel().getWidth() - 1, - getFadeEffectIconBitmap().GetSizePixel().getHeight() - 1)); - - // Paint_PageName replacement. Get text size - const double fTextWidth(aTextLayouter.getTextWidth(getPageName(), 0, nTextLength)); - const double fTextHeight(getPageNameFont().GetHeight()); - const double fFadeEffectWidth(aFadeEffectBitmapSizeLogic.getX() * 2.0); - const double fFadeEffectTextGap(((mnFadeEffectIndicatorOffset + 2) * aDiscretePixel.getX())); - String aPageName(getPageName()); - - // calculate text start position - double fStartX( - aAdaptedInnerRange.getMaxX() - - fTextWidth - + (aDiscretePixel.getX() * 3.0)); - const double fStartY( - aAdaptedInnerRange.getMaxY() - + fTextHeight - + fFadeEffectTextGap); - const bool bNeedClipping(fStartX < aAdaptedInnerRange.getMinX() + fFadeEffectWidth); - - // if text is too big, clip it - if(bNeedClipping) - { - // new left start - fStartX = aAdaptedInnerRange.getMinX() + fFadeEffectWidth; - - // find out how many characters to use - const double fAvailableLength(aAdaptedInnerRange.getWidth() - fFadeEffectWidth); - static const String aThreePoints(String::CreateFromAscii("...")); - const double fWidthThreePoints(aTextLayouter.getTextWidth(aThreePoints, 0, aThreePoints.Len())); - xub_StrLen a(1); - - for(; a < (xub_StrLen)nTextLength; a++) - { - const double fSnippetLength(aTextLayouter.getTextWidth(aPageName, 0, a)); - - if(fSnippetLength + fWidthThreePoints > fAvailableLength) - { - break; - } - } - - // build new string - aPageName = String(aPageName, 0, a - 1); - aPageName += aThreePoints; - } - - // fill text matrix - basegfx::B2DHomMatrix aTextMatrix; - - aTextMatrix.set(0, 0, aTextSizeAttribute.getX()); - aTextMatrix.set(1, 1, aTextSizeAttribute.getY()); - aTextMatrix.set(0, 2, fStartX); - aTextMatrix.set(1, 2, fStartY); - - // prepare DXTextArray (can be empty one) - const ::std::vector< double > aDXArray; - - // create Text primitive and add to target - xRetval[nInsert++] = Primitive2DReference( - new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( - aTextMatrix, - aPageName, - 0, - aPageName.Len(), - aDXArray, - aFontAttribute, - aLocale, - aFontColor)); - } - - { - // Paint_PageNumber replacement. Get the range where it shall be centered and prepare the string - const double fLeft(aAdaptedInnerRange.getMinX() - (mnPageNumberOffset * aDiscretePixel.getX()) - getPageNumberAreaModelSize().Width()); - const double fTop(aAdaptedInnerRange.getMinY()); - const basegfx::B2DRange aNumberRange(fLeft, fTop, - fLeft + getPageNumberAreaModelSize().Width(), fTop + getPageNumberAreaModelSize().Height()); - const String aPageNumber(String::CreateFromInt32(getPageNumber())); - const xub_StrLen nNumberLen(aPageNumber.Len()); - - // Get text size - const double fTextWidth(aTextLayouter.getTextWidth(aPageNumber, 0, nNumberLen)); - const double fTextHeight(getPageNameFont().GetHeight()); - - // get text start postion - const double fStartX(aNumberRange.getCenterX() - (fTextWidth / 2.0)); - const double fStartY(aNumberRange.getMinY() + fTextHeight + aDiscretePixel.getX()); - - // fill text matrix - basegfx::B2DHomMatrix aTextMatrix; - - aTextMatrix.set(0, 0, aTextSizeAttribute.getX()); - aTextMatrix.set(1, 1, aTextSizeAttribute.getY()); - aTextMatrix.set(0, 2, fStartX); - aTextMatrix.set(1, 2, fStartY); - - // prepare DXTextArray (can be empty one) - const ::std::vector< double > aDXArray; - - // create Text primitive - xRetval[nInsert++] = Primitive2DReference( - new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( - aTextMatrix, - aPageNumber, - 0, - nNumberLen, - aDXArray, - aFontAttribute, - aLocale, - aFontColor)); - - if(getExcluded()) - { - // create a box with strikethrough from top left to bottom right - const basegfx::BColor aActiveColor(Application::GetSettings().GetStyleSettings().GetActiveColor().getBColor()); - basegfx::B2DPolygon aStrikethrough; - - aStrikethrough.append(aNumberRange.getMinimum()); - aStrikethrough.append(aNumberRange.getMaximum()); - - xRetval[nInsert++] = Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( - basegfx::tools::createPolygonFromRect(aNumberRange), aActiveColor)); - - xRetval[nInsert++] = Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( - aStrikethrough, aActiveColor)); - } - } - - return xRetval; -} - -SdPageObjectFadeNameNumberPrimitive::SdPageObjectFadeNameNumberPrimitive( - const basegfx::B2DRange& rRange, - const String& rPageName, - sal_uInt32 nPageNumber, - const Font& rPageNameFont, - const Size& rPageNumberAreaModelSize, - bool bShowFadeEffectIcon, - bool bShowCommentsIcon, - bool bExcluded) -: SdPageObjectBasePrimitive(rRange), - maPageName(rPageName), - mnPageNumber(nPageNumber), - maPageNameFont(rPageNameFont), - maPageNumberAreaModelSize(rPageNumberAreaModelSize), - mbShowFadeEffectIcon(bShowFadeEffectIcon), - mbShowCommentsIcon(bShowCommentsIcon), - mbExcluded(bExcluded) -{ -} - -SdPageObjectFadeNameNumberPrimitive::~SdPageObjectFadeNameNumberPrimitive() -{ -} - -bool SdPageObjectFadeNameNumberPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const -{ - if(SdPageObjectBasePrimitive::operator==(rPrimitive)) - { - const SdPageObjectFadeNameNumberPrimitive& rCompare = static_cast< const SdPageObjectFadeNameNumberPrimitive& >(rPrimitive); - - return (getPageName() == rCompare.getPageName() - && getPageNumber() == rCompare.getPageNumber() - && getPageNameFont() == rCompare.getPageNameFont() - && getPageNumberAreaModelSize() == rCompare.getPageNumberAreaModelSize() - && getShowFadeEffectIcon() == rCompare.getShowFadeEffectIcon() - && getExcluded() == rCompare.getExcluded()); - } - - return false; -} - -ImplPrimitrive2DIDBlock(SdPageObjectFadeNameNumberPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTFADENAMENUMBERPRIMITIVE) - -/////////////////////////////////////////////////////////////////////////////////////////////// -// createPrimitive2DSequence -// -// This method will replace the whole painting mechanism. Task is no longer to paint stuff to an OutDev, -// but to provide the necessary geometrical information using primitives. - -Primitive2DSequence PageObjectViewObjectContact::createPrimitive2DSequence(const sdr::contact::DisplayInfo& rDisplayInfo) const -{ - // OutputDevice* pDevice = rDisplayInfo.GetDIOutputDevice(); - OutputDevice* pDevice = GetObjectContact().TryToGetOutputDevice(); - - // get primitive vector from parent class. Do remember the contents for later use; this - // is done to create the page content renderer (see PagePrimitiveExtractor in svx) at the - // original object and to setup the draw hierarchy there so that changes to VCs of displayed - // objects will lead to InvalidatePartOfView-calls which will be forwarded from the helper-OC - // to this VOC in calling a ActionChanged(). - // - // This already produces the displayable page content as a primitive sequence, complete with - // embedding in the page visualizer, clipping if needed and object and aspect ratio - // preparations. It would thus be the base for creating the cached visualisation, too, - // by just painting extactly this primitive sequence. - // - // Currently, this slows down PagePane display heavily. Reason is that the current mechanism - // to react on a SdrObject change in an edit view is to react on the ModelChange and to completely - // reset the PagePane (delete SdrPageObjs, re-create and layout them). This works, but kicks - // the complete sequence of primitive creation at VOCs and VCs and their buffering out of - // memory each time. So there are two choices: - // - // 1, disable getting the sequence of primtives - // -> invalidate uses ModelChange - // -> cache repaint uses complete view creation and repainting - // - // 2, create and use the sequence of primitives - // -> invalidate would not need ModelChange, no destroy/recreate of SdrObjects, no rearrange, - // the invalidate and the following repaint would exactly update the SdrPages involved and - // use the DrawingLayer provided ActionChanged() invalidations over the VOCs and VCs - // -> cache repaint could use the here offered sequence of primitives to re-create the bitmap - // (just hand over the local member to the cache) - // - // For the moment i will use (1) and disable primitive creation for SdrPageObj contents here - - // const_cast< PageObjectViewObjectContact* >(this)->mxCurrentPageContents = ViewObjectContactOfPageObj::createPrimitive2DSequence(rDisplayInfo); - - // assert when this call is issued indirectly from the destructor of - // this instance. This is not allowed and needs to be looked at -#ifdef DBG_UTIL - if(mbInDestructor) - { - OSL_ENSURE(false, "Higher call inside PageObjectViewObjectContact in destructor (!)"); - } -#endif - - // Check if buffering can and shall be done. - if (pDevice != NULL - && !GetObjectContact().isOutputToPrinter() - && !GetObjectContact().isOutputToRecordingMetaFile() - && !mbInDestructor) - { - // get inner and outer logic rectangles. Use model data directly for creation. Do NOT use getBoundRect()/ - // getSnapRect() functionality; these will use the sequence of primitives in the long run itself. SdrPageObj - // is a SdrObject, so use SdrObject::aOutRect as model data. Access using GetLastBoundRect() to not execute anything - PageObjectViewContact& rPaObVOC(static_cast< PageObjectViewContact& >(GetViewContact())); - const Rectangle aInnerLogic(rPaObVOC.GetPageObject().GetLastBoundRect()); - - // get BitmapEx from cache. Do exactly the same as Paint_Preview() to avoid a repaint loop - // caused by slightly different pixel sizes of what the cache sees as pixel size and what is - // calculated here in discrete coordinates. This includes to not use LogicToPiyel on the Rectangle, - // but to do the same as the GetBoundingBox() implementation - const Rectangle aInnerPixel(Rectangle(pDevice->LogicToPixel(aInnerLogic.TopLeft()), pDevice->LogicToPixel(aInnerLogic.GetSize()))); - BitmapEx aBitmapEx(const_cast< PageObjectViewObjectContact* >(this)->GetPreview(rDisplayInfo, aInnerPixel)); - - // prepare inner range - const basegfx::B2DRange aInnerRange(aInnerLogic.Left(), aInnerLogic.Top(), aInnerLogic.Right(), aInnerLogic.Bottom()); - - // provide default parameters - String aPageName; - Font aPageNameFont; - sal_uInt32 nPageNumber(0); - Size aPageNumberAreaModelSize; - bool bShowFadeEffectIcon(false); - bool bShowCommentsIcon(false); - bool bExcluded(false); - - if(GetPage()) - { - const SdPage* pPage = static_cast<const SdPage*>(GetPage()); - - // decide if fade effect indicator will be painted - if(pPage->getTransitionType() > 0) - { - bShowFadeEffectIcon = true; - } - - bShowCommentsIcon = !pPage->getAnnotations().empty(); - - // prepare PageName, PageNumber, font and AreaModelSize - aPageName = pPage->GetName(); - aPageNameFont = *FontProvider::Instance().GetFont(*pDevice); - nPageNumber = ((pPage->GetPageNum() - 1) / 2) + 1; - aPageNumberAreaModelSize = GetPageDescriptor()->GetPageNumberAreaModelSize(); - - if(!aPageName.Len()) - { - aPageName = String(SdResId(STR_PAGE)); - aPageName += String::CreateFromInt32(nPageNumber); - } - - // decide if page is excluded - bExcluded = pPage->IsExcluded(); - } - - // create specialized primitives for focus, select and PagePreview itself - const bool bCreateBitmap(!aBitmapEx.IsEmpty()); - const bool bCreateFocused(GetPageDescriptor()->IsFocused()); - const bool bCreateSelected(GetPageDescriptor()->IsSelected()); - - const sal_uInt32 nCount( - (bCreateBitmap ? 1 : 0) + // bitmap itself - 1 + // border around bitmap (always) - 1 + // FadeEffect, PageName and PageNumber visualisation (always) - (bCreateFocused ? 1 : 0) + // create focused - (bCreateSelected ? 1 : 0) // create selected - ); - sal_uInt32 nInsert(0); - Primitive2DSequence xRetval(nCount); - - if(bCreateBitmap) - { - // add selection indicator if used - xRetval[nInsert++] = Primitive2DReference(new SdPageObjectPageBitmapPrimitive(aInnerRange, aBitmapEx)); - } - - if(true) - { - // add border (always) - xRetval[nInsert++] = Primitive2DReference(new SdPageObjectBorderPrimitive(aInnerRange)); - } - - if(true) - { - // add fade effext, page name and number if used - xRetval[nInsert++] = Primitive2DReference(new SdPageObjectFadeNameNumberPrimitive( - aInnerRange, - aPageName, - nPageNumber, - aPageNameFont, - aPageNumberAreaModelSize, - bShowFadeEffectIcon, - bShowCommentsIcon, - bExcluded)); - } - - if(bCreateSelected) - { - // add selection indicator if used - xRetval[nInsert++] = Primitive2DReference(new SdPageObjectSelectPrimitive(aInnerRange)); - } - - if(bCreateFocused) - { - // add focus indicator if used - xRetval[nInsert++] = Primitive2DReference(new SdPageObjectFocusPrimitive(aInnerRange, bCreateSelected)); - } - - return xRetval; - } - else - { - // Call parent. Output to printer or metafile will use vector data, not cached bitmaps - return ViewObjectContactOfPageObj::createPrimitive2DSequence(rDisplayInfo); - } -} - -BitmapEx PageObjectViewObjectContact::CreatePreview (const DisplayInfo& /*rDisplayInfo*/) -{ - const SdPage* pPage = static_cast<const SdPage*>(GetPage()); - OutputDevice* pDevice = GetObjectContact().TryToGetOutputDevice(); - - if(pDevice) - { - Rectangle aPreviewPixelBox (GetBoundingBox(*pDevice,PreviewBoundingBox,PixelCoordinateSystem)); - - PreviewRenderer aRenderer (pDevice); - Image aPreview (aRenderer.RenderPage( - pPage, - aPreviewPixelBox.GetSize(), - String())); - - return aPreview.GetBitmapEx(); - } - else - { - return BitmapEx(); - } -} - - - - -BitmapEx PageObjectViewObjectContact::GetPreview ( - const DisplayInfo& rDisplayInfo, - const Rectangle& rNewSizePixel) -{ - BitmapEx aBitmap; - - try - { - // assert when this call is issued indirectly from the destructor of - // this instance. This is not allowed and needs to be looked at - OSL_ENSURE(!mbInDestructor, "Higher call inside PageObjectViewObjectContact in destructor (!)"); - - if (!mbInDestructor) - { - if (mpCache != NULL) - { - aBitmap = mpCache->GetPreviewBitmap( - GetPage(), - rNewSizePixel.GetSize()); - mpCache->SetPreciousFlag(GetPage(), true); - } - else - aBitmap = CreatePreview(rDisplayInfo); - } - } - catch (const ::com::sun::star::uno::Exception&) - { - DBG_UNHANDLED_EXCEPTION(); - } - - return aBitmap; -} - - - - -const SdrPage* PageObjectViewObjectContact::GetPage (void) const -{ - return static_cast<PageObjectViewContact&>(GetViewContact()).GetPage(); -} - - - - -void PageObjectViewObjectContact::ActionChanged (void) -{ - // Even when we are called from destructor we still have to invalide - // the preview bitmap in the cache. - const SdrPage* pPage = GetPage(); - - if(pPage) - { - SdDrawDocument* pDocument = dynamic_cast<SdDrawDocument*>(pPage->GetModel()); - if (mpCache!=NULL && pPage!=NULL && pDocument!=NULL) - { - cache::PageCacheManager::Instance()->InvalidatePreviewBitmap( - pDocument->getUnoModel(), - pPage); - } - } - - // call parent - ViewObjectContactOfPageObj::ActionChanged(); -} - -////////////////////////////////////////////////////////////////////////////// -// helper MouseOverEffectPrimitive -// -// Used to allow view-dependent primitive definition. For that purpose, the -// initially created primitive (here: in createMouseOverEffectPrimitive2DSequence()) -// always has to be view-independent, but the decomposition is made view-dependent. -// Very simple primitive which just remembers the discrete data and applies -// it at decomposition time. - -class MouseOverEffectPrimitive : public drawinglayer::primitive2d::BufferedDecompositionPrimitive2D -{ -private: - basegfx::B2DRange maLogicRange; - sal_uInt32 mnDiscreteOffset; - sal_uInt32 mnDiscreteWidth; - basegfx::BColor maRGBColor; - -protected: - virtual drawinglayer::primitive2d::Primitive2DSequence create2DDecomposition( - const drawinglayer::geometry::ViewInformation2D& rViewInformation) const; - -public: - MouseOverEffectPrimitive( - const basegfx::B2DRange& rLogicRange, - sal_uInt32 nDiscreteOffset, - sal_uInt32 nDiscreteWidth, - const basegfx::BColor& rRGBColor) - : drawinglayer::primitive2d::BufferedDecompositionPrimitive2D(), - maLogicRange(rLogicRange), - mnDiscreteOffset(nDiscreteOffset), - mnDiscreteWidth(nDiscreteWidth), - maRGBColor(rRGBColor) - {} - - // data access - const basegfx::B2DRange& getLogicRange() const { return maLogicRange; } - sal_uInt32 getDiscreteOffset() const { return mnDiscreteOffset; } - sal_uInt32 getDiscreteWidth() const { return mnDiscreteWidth; } - const basegfx::BColor& getRGBColor() const { return maRGBColor; } - - virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const; - - DeclPrimitrive2DIDBlock() -}; - -drawinglayer::primitive2d::Primitive2DSequence MouseOverEffectPrimitive::create2DDecomposition( - const drawinglayer::geometry::ViewInformation2D& rViewInformation) const -{ - // get logic sizes in object coordinate system - const double fDiscreteWidth((rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength()); - const double fOffset(fDiscreteWidth * getDiscreteOffset()); - const double fWidth(fDiscreteWidth * getDiscreteWidth()); - - // create range (one pixel less to get a good fitting) - basegfx::B2DRange aRange( - getLogicRange().getMinimum(), - getLogicRange().getMaximum() - basegfx::B2DTuple(fDiscreteWidth, fDiscreteWidth)); - - // grow range - aRange.grow(fOffset - (fWidth * 0.5)); - - // create fat line with parameters. The formerly hand-painted edge - // roundings will now be done using rounded edges of this fat line - const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(aRange)); - const drawinglayer::attribute::LineAttribute aLineAttribute(getRGBColor(), fWidth); - const drawinglayer::primitive2d::Primitive2DReference xReference( - new drawinglayer::primitive2d::PolygonStrokePrimitive2D( - aPolygon, - aLineAttribute)); - - return drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); -} - -bool MouseOverEffectPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const -{ - if(drawinglayer::primitive2d::BufferedDecompositionPrimitive2D::operator==(rPrimitive)) - { - const MouseOverEffectPrimitive& rCompare = static_cast< const MouseOverEffectPrimitive& >(rPrimitive); - - return (getLogicRange() == rCompare.getLogicRange() - && getDiscreteOffset() == rCompare.getDiscreteOffset() - && getDiscreteWidth() == rCompare.getDiscreteWidth() - && getRGBColor() == rCompare.getRGBColor()); - } - - return false; -} - -ImplPrimitrive2DIDBlock(MouseOverEffectPrimitive, PRIMITIVE2D_ID_SDMOUSEOVEREFFECTPRIMITIVE) - -////////////////////////////////////////////////////////////////////////////// - -drawinglayer::primitive2d::Primitive2DSequence PageObjectViewObjectContact::createMouseOverEffectPrimitive2DSequence() -{ - drawinglayer::primitive2d::Primitive2DSequence aRetval; - - if(GetPageDescriptor()->IsSelected() && mpProperties.get() && mpProperties->IsShowSelection()) - { - // When the selection frame is visualized the mouse over frame is not - // visible and does not have to be created. - } - else - { - const PageObjectViewContact& rPaObVOC(static_cast<PageObjectViewContact&>(GetViewContact())); - const Rectangle aBoundingBox(rPaObVOC.GetPageObject().GetLastBoundRect()); - const basegfx::B2DRange aLogicRange(aBoundingBox.Left(), aBoundingBox.Top(), aBoundingBox.Right(), aBoundingBox.Bottom()); - const basegfx::BColor aSelectionColor(mpProperties->GetSelectionColor().getBColor()); - const drawinglayer::primitive2d::Primitive2DReference aReference( - new MouseOverEffectPrimitive( - aLogicRange, - mnMouseOverEffectOffset, - mnMouseOverEffectThickness, - aSelectionColor)); - - aRetval = drawinglayer::primitive2d::Primitive2DSequence(&aReference, 1); - } - - return aRetval; -} - - - - -SvBorder PageObjectViewObjectContact::CalculatePageModelBorder ( - OutputDevice* pDevice, - int nPageCount) -{ - SvBorder aModelBorder; - - if (pDevice != NULL) - { - // 1. Initialize the border with the values that do not depend on - // the device. - Size aTopLeftBorders (pDevice->PixelToLogic (Size ( - mnPageNumberOffset+1, - mnSelectionIndicatorOffset + mnSelectionIndicatorThickness))); - Size aBottomRightBorders (pDevice->PixelToLogic (Size ( - mnSelectionIndicatorOffset + mnSelectionIndicatorThickness, - mnFadeEffectIndicatorOffset))); - aModelBorder = SvBorder ( - aTopLeftBorders.Width(), - aTopLeftBorders.Height(), - aBottomRightBorders.Width(), - aBottomRightBorders.Height()); - - - // 2. Add the device dependent values. - - // Calculate the area of the page number. - Size aPageNumberModelSize ( - CalculatePageNumberAreaModelSize (pDevice, nPageCount)); - - // Update the border. - aModelBorder.Left() += aPageNumberModelSize.Width(); - // The height of the page number area is the same as the height of - // the page name area. - aModelBorder.Bottom() += aPageNumberModelSize.Height(); - } - - return aModelBorder; -} - - - - -Size PageObjectViewObjectContact::CalculatePageNumberAreaModelSize ( - OutputDevice* pDevice, - int nPageCount) -{ - // Set the correct font. - Font aOriginalFont (pDevice->GetFont()); - pDevice->SetFont(*FontProvider::Instance().GetFont(*pDevice)); - - String sPageNumberTemplate; - if (nPageCount < 10) - sPageNumberTemplate = String::CreateFromAscii("9"); - else if (nPageCount < 100) - sPageNumberTemplate = String::CreateFromAscii("99"); - else if (nPageCount < 200) - // Just for the case that 1 is narrower than 9. - sPageNumberTemplate = String::CreateFromAscii("199"); - else if (nPageCount < 1000) - sPageNumberTemplate = String::CreateFromAscii("999"); - else - sPageNumberTemplate = String::CreateFromAscii("9999"); - // More then 9999 pages are not handled. - - Size aSize ( - pDevice->GetTextWidth (sPageNumberTemplate), - pDevice->GetTextHeight ()); - - pDevice->SetFont (aOriginalFont); - - return aSize; -} - - - - -model::SharedPageDescriptor - PageObjectViewObjectContact::GetPageDescriptor (void) const -{ - PageObjectViewContact& rViewContact ( - static_cast<PageObjectViewContact&>(GetViewContact())); - PageObject& rPageObject ( - static_cast<PageObject&>(rViewContact.GetPageObject())); - return rPageObject.GetDescriptor(); -} - - - -} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsResource.hxx b/sd/source/ui/slidesorter/view/SlsResource.hxx new file mode 100644 index 000000000000..515c3a79a0ec --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsResource.hxx @@ -0,0 +1,47 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_RESOURCE_HXX +#define SD_SLIDESORTER_RESOURCE_HXX + +#include "view/SlsResource.hrc" +#include "sdresid.hxx" +#include <tools/rc.hxx> + +namespace sd { namespace slidesorter { namespace view { + +class LocalResource : public Resource +{ +public: + LocalResource (const sal_uInt16 nResourceId) : Resource(SdResId(nResourceId)){} + ~LocalResource (void) { FreeResource(); } +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/view/SlsResource.src b/sd/source/ui/slidesorter/view/SlsResource.src new file mode 100644 index 000000000000..13f6cd08c775 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsResource.src @@ -0,0 +1,314 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "view/SlsResource.hrc" + +Resource RID_SLIDESORTER_ICONS +{ + Image IMAGE_COMMAND1_LARGE + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_large.png" ; }; + }; + Image IMAGE_COMMAND1_LARGE_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_large_hover.png" ; }; + }; + Image IMAGE_COMMAND1_MEDIUM + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_medium.png" ; }; + }; + Image IMAGE_COMMAND1_MEDIUM_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_medium_hover.png" ; }; + }; + Image IMAGE_COMMAND1_SMALL + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_small.png" ; }; + }; + Image IMAGE_COMMAND1_SMALL_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_small_hover.png" ; }; + }; + + Image IMAGE_COMMAND1_LARGE_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_large_hc.png" ; }; + }; + Image IMAGE_COMMAND1_LARGE_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_large_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND1_MEDIUM_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_medium_hc.png" ; }; + }; + Image IMAGE_COMMAND1_MEDIUM_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_medium_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND1_SMALL_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_small_hc.png" ; }; + }; + Image IMAGE_COMMAND1_SMALL_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_small_hover_hc.png" ; }; + }; + + + Image IMAGE_COMMAND2_LARGE + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_large.png" ; }; + }; + Image IMAGE_COMMAND2_LARGE_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_large_hover.png" ; }; + }; + Image IMAGE_COMMAND2_MEDIUM + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_medium.png" ; }; + }; + Image IMAGE_COMMAND2_MEDIUM_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_medium_hover.png" ; }; + }; + Image IMAGE_COMMAND2_SMALL + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_small.png" ; }; + }; + Image IMAGE_COMMAND2_SMALL_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_small_hover.png" ; }; + }; + + Image IMAGE_COMMAND2_LARGE_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_large_hc.png" ; }; + }; + Image IMAGE_COMMAND2_LARGE_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_large_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND2_MEDIUM_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_medium_hc.png" ; }; + }; + Image IMAGE_COMMAND2_MEDIUM_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_medium_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND2_SMALL_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_small_hc.png" ; }; + }; + Image IMAGE_COMMAND2_SMALL_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_small_hover_hc.png" ; }; + }; + + + Image IMAGE_COMMAND2B_LARGE + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_large.png" ; }; + }; + Image IMAGE_COMMAND2B_LARGE_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_large_hover.png" ; }; + }; + Image IMAGE_COMMAND2B_MEDIUM + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_medium.png" ; }; + }; + Image IMAGE_COMMAND2B_MEDIUM_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_medium_hover.png" ; }; + }; + Image IMAGE_COMMAND2B_SMALL + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_small.png" ; }; + }; + Image IMAGE_COMMAND2B_SMALL_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_small_hover.png" ; }; + }; + + Image IMAGE_COMMAND2B_LARGE_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_large_hc.png" ; }; + }; + Image IMAGE_COMMAND2B_LARGE_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_large_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND2B_MEDIUM_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_medium_hc.png" ; }; + }; + Image IMAGE_COMMAND2B_MEDIUM_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_medium_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND2B_SMALL_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_small_hc.png" ; }; + }; + Image IMAGE_COMMAND2B_SMALL_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_small_hover_hc.png" ; }; + }; + + + Image IMAGE_COMMAND3_LARGE + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_large.png" ; }; + }; + Image IMAGE_COMMAND3_LARGE_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_large_hover.png" ; }; + }; + Image IMAGE_COMMAND3_MEDIUM + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_medium.png" ; }; + }; + Image IMAGE_COMMAND3_MEDIUM_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_medium_hover.png" ; }; + }; + Image IMAGE_COMMAND3_SMALL + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_small.png" ; }; + }; + Image IMAGE_COMMAND3_SMALL_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_small_hover.png" ; }; + }; + + Image IMAGE_COMMAND3_LARGE_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_large_hc.png" ; }; + }; + Image IMAGE_COMMAND3_LARGE_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_large_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND3_MEDIUM_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_medium_hc.png" ; }; + }; + Image IMAGE_COMMAND3_MEDIUM_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_medium_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND3_SMALL_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_small_hc.png" ; }; + }; + Image IMAGE_COMMAND3_SMALL_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_small_hover_hc.png" ; }; + }; + + + Image IMAGE_BUTTONBAR_LARGE + { + ImageBitmap = Bitmap { File = "slide_sorter_command_background_large.png" ; }; + }; + Image IMAGE_BUTTONBAR_MEDIUM + { + ImageBitmap = Bitmap { File = "slide_sorter_command_background_medium.png" ; }; + }; + Image IMAGE_BUTTONBAR_SMALL + { + ImageBitmap = Bitmap { File = "slide_sorter_command_background_small.png" ; }; + }; + + Image IMAGE_BUTTONBAR_LARGE_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command_background_large_hc.png" ; }; + }; + Image IMAGE_BUTTONBAR_MEDIUM_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command_background_medium_hc.png" ; }; + }; + Image IMAGE_BUTTONBAR_SMALL_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command_background_small_hc.png" ; }; + }; + + + + Image IMAGE_SHADOW + { + ImageBitmap = Bitmap { File = "slide_sorter_shadow.png" ; }; + }; + + Image IMAGE_INSERT_SHADOW + { + ImageBitmap = Bitmap { File = "slide_sorter_insert_shadow.png" ; }; + }; + + Image IMAGE_HIDE_SLIDE_OVERLAY + { + ImageBitmap = Bitmap { File = "slide_sorter_hide_slide_overlay.png" ; }; + }; + + Image IMAGE_FOCUS_BORDER + { + ImageBitmap = Bitmap { File = "slide_sorter_focus_border.png" ; }; + }; + + + String STRING_DRAG_AND_DROP_PAGES + { + Text [ en-US ] = "Drag and Drop Pages" ; + }; + + String STRING_DRAG_AND_DROP_SLIDES + { + Text [ en-US ] = "Drag and Drop Slides" ; + }; + + String STRING_COMMAND1 + { + Text [ en-US ] = "Start Slide Show" ; + }; + + String STRING_COMMAND2_A + { + Text [ en-US ] = "Hide Slide" ; + }; + + String STRING_COMMAND2_B + { + Text [ en-US ] = "Show Slide" ; + }; + + String STRING_COMMAND3 + { + Text [ en-US ] = "Duplicate Slide" ; + }; +}; diff --git a/sd/source/ui/slidesorter/view/SlsTheme.cxx b/sd/source/ui/slidesorter/view/SlsTheme.cxx new file mode 100644 index 000000000000..7357d7ea00b8 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsTheme.cxx @@ -0,0 +1,535 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsTheme.hxx" +#include "SlsResource.hxx" +#include "controller/SlsProperties.hxx" +#include "sdresid.hxx" +#include <tools/color.hxx> +#include <vcl/outdev.hxx> +#include <vcl/image.hxx> +#include <vcl/svapp.hxx> +#include <svtools/colorcfg.hxx> + +namespace sd { namespace slidesorter { namespace view { + +const static ColorData Black = 0x000000; +const static ColorData White = 0xffffff; + + + +ColorData ChangeLuminance (const ColorData aColorData, const int nValue) +{ + Color aColor (aColorData); + if (nValue > 0) + aColor.IncreaseLuminance(nValue); + else + aColor.DecreaseLuminance(-nValue); + return aColor.GetColor(); +} + +ColorData HGBAdapt ( + const ColorData aColorData, + const sal_Int32 nNewSaturation, + const sal_Int32 nNewBrightness) +{ + USHORT nHue (0); + USHORT nSaturation (0); + USHORT nBrightness (0); + Color(aColorData).RGBtoHSB(nHue, nSaturation, nBrightness); + return Color::HSBtoRGB( + nHue, + nNewSaturation>=0 ? nNewSaturation : nSaturation, + nNewBrightness>=0 ? nNewBrightness : nBrightness); +} + + + + +Theme::Theme (const ::boost::shared_ptr<controller::Properties>& rpProperties) + : maBackgroundColor(rpProperties->GetBackgroundColor().GetColor()), + maPageBackgroundColor(COL_WHITE), + maGradients(), + maIcons(), + maColor(), + maIntegerValues() +{ + { + LocalResource aResource (RID_SLIDESORTER_ICONS); + + maStrings.resize(_StringType_Size_); + maStrings[String_DragAndDropPages] = String(SdResId(STRING_DRAG_AND_DROP_PAGES)); + maStrings[String_DragAndDropSlides] = String(SdResId(STRING_DRAG_AND_DROP_SLIDES)); + maStrings[String_Command1] = String(SdResId(STRING_COMMAND1)); + maStrings[String_Command2] = String(SdResId(STRING_COMMAND2_A)); + maStrings[String_Command2B] = String(SdResId(STRING_COMMAND2_B)); + maStrings[String_Command3] = String(SdResId(STRING_COMMAND3)); + + maColor.resize(_ColorType_Size_); + maColor[Color_Background] = maBackgroundColor; + maColor[Color_ButtonBackground] = Black; + maColor[Color_ButtonText] = 0xc0c0c0; + maColor[Color_ButtonTextHover] = White; + maColor[Color_PageNumberDefault] = 0x0808080; + maColor[Color_PageNumberHover] = 0x4c4c4c; + maColor[Color_PageNumberHighContrast] = White; + maColor[Color_PageNumberBrightBackground] = 0x333333; + maColor[Color_PageNumberDarkBackground] = 0xcccccc; + maColor[Color_PreviewBorder] = 0x949599; + + maIntegerValues.resize(_IntegerValueType_Size_); + maIntegerValues[Integer_ButtonCornerRadius] = 3; + maIntegerValues[Integer_ButtonMaxAlpha] = 0; + maIntegerValues[Integer_ButtonBarMaxAlpha] = 0; + maIntegerValues[Integer_ButtonPaintType] = 1; + maIntegerValues[Integer_ButtonBorder] = 4; + maIntegerValues[Integer_ButtonGap] = 0; + maIntegerValues[Integer_ButtonFadeInDelay] = 800; + maIntegerValues[Integer_ButtonFadeInDuration] = 100; + maIntegerValues[Integer_ButtonFadeOutDelay] = 0; + maIntegerValues[Integer_ButtonFadeOutDuration] = 100; + maIntegerValues[Integer_ToolTipDelay] = 1000; + maIntegerValues[Integer_FocusIndicatorWidth] = 3; + } + + Update(rpProperties); +} + + + + +void Theme::Update (const ::boost::shared_ptr<controller::Properties>& rpProperties) +{ + const bool bSavedHighContrastMode (mbIsHighContrastMode); + mbIsHighContrastMode = rpProperties->IsHighContrastModeActive(); + + // Set up colors. + maBackgroundColor = rpProperties->GetBackgroundColor().GetColor(); + maPageBackgroundColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; + + maColor[Color_Background] = maBackgroundColor; + + maGradients.resize(_GradientColorType_Size_); + + maColor[Color_Background] = maBackgroundColor; + const ColorData aSelectionColor (rpProperties->GetSelectionColor().GetColor()); + maColor[Color_Selection] = aSelectionColor; + if (Color(aSelectionColor).IsBright()) + maColor[Color_PageCountFontColor] = Black; + else + maColor[Color_PageCountFontColor] = White; + + // Set up gradients. + SetGradient(Gradient_SelectedPage, aSelectionColor, 50, 50, +100,+100, +50,+25); + SetGradient(Gradient_MouseOverPage, aSelectionColor, 75, 75, +100,+100, +50,+25); + SetGradient(Gradient_SelectedAndFocusedPage, aSelectionColor, 50, 50, +100,+100, -50,-75); + SetGradient(Gradient_MouseOverSelectedAndFocusedPage, aSelectionColor, 75, 75, +100,+100, -50,-75); + SetGradient(Gradient_FocusedPage, aSelectionColor, -1,-1, 0,0, -50,-75); + + SetGradient(Gradient_ButtonBackground, Black, -1,-1, 0,0, 0,0); + SetGradient(Gradient_NormalPage, maBackgroundColor, -1,-1, 0,0, 0,0); + + // The focused gradient needs special handling because its fill color is + // like that of the NormalPage gradient. + GetGradient(Gradient_FocusedPage).maFillColor1 = GetGradient(Gradient_NormalPage).maFillColor1; + GetGradient(Gradient_FocusedPage).maFillColor2 = GetGradient(Gradient_NormalPage).maFillColor2; + + // Set up icons. + if (bSavedHighContrastMode != mbIsHighContrastMode || maIcons.empty()) + { + LocalResource aResource (RID_SLIDESORTER_ICONS); + + maIcons.resize(_IconType_Size_); + if (mbIsHighContrastMode) + { + InitializeIcon(Icon_RawShadow, IMAGE_SHADOW); + InitializeIcon(Icon_RawInsertShadow, IMAGE_INSERT_SHADOW); + InitializeIcon(Icon_HideSlideOverlay, IMAGE_HIDE_SLIDE_OVERLAY); + + InitializeIcon(Icon_ButtonBarLarge, IMAGE_BUTTONBAR_LARGE_HC); + InitializeIcon(Icon_ButtonBarMedium, IMAGE_BUTTONBAR_MEDIUM_HC); + InitializeIcon(Icon_ButtonBarSmall, IMAGE_BUTTONBAR_SMALL_HC); + + InitializeIcon(Icon_Command1Large, IMAGE_COMMAND1_LARGE_HC); + InitializeIcon(Icon_Command1LargeHover, IMAGE_COMMAND1_LARGE_HOVER_HC); + InitializeIcon(Icon_Command1Medium, IMAGE_COMMAND1_MEDIUM_HC); + InitializeIcon(Icon_Command1MediumHover, IMAGE_COMMAND1_MEDIUM_HOVER_HC); + InitializeIcon(Icon_Command1Small, IMAGE_COMMAND1_SMALL_HC); + InitializeIcon(Icon_Command1SmallHover, IMAGE_COMMAND1_SMALL_HOVER_HC); + + InitializeIcon(Icon_Command2Large, IMAGE_COMMAND2_LARGE_HC); + InitializeIcon(Icon_Command2LargeHover, IMAGE_COMMAND2_LARGE_HOVER_HC); + InitializeIcon(Icon_Command2Medium, IMAGE_COMMAND2_MEDIUM_HC); + InitializeIcon(Icon_Command2MediumHover, IMAGE_COMMAND2_MEDIUM_HOVER_HC); + InitializeIcon(Icon_Command2Small, IMAGE_COMMAND2_SMALL_HC); + InitializeIcon(Icon_Command2SmallHover, IMAGE_COMMAND2_SMALL_HOVER_HC); + + InitializeIcon(Icon_Command2BLarge, IMAGE_COMMAND2B_LARGE_HC); + InitializeIcon(Icon_Command2BLargeHover, IMAGE_COMMAND2B_LARGE_HOVER_HC); + InitializeIcon(Icon_Command2BMedium, IMAGE_COMMAND2B_MEDIUM_HC); + InitializeIcon(Icon_Command2BMediumHover, IMAGE_COMMAND2B_MEDIUM_HOVER_HC); + InitializeIcon(Icon_Command2BSmall, IMAGE_COMMAND2B_SMALL_HC); + InitializeIcon(Icon_Command2BSmallHover, IMAGE_COMMAND2B_SMALL_HOVER_HC); + + InitializeIcon(Icon_Command3Large, IMAGE_COMMAND3_LARGE_HC); + InitializeIcon(Icon_Command3LargeHover, IMAGE_COMMAND3_LARGE_HOVER_HC); + InitializeIcon(Icon_Command3Medium, IMAGE_COMMAND3_SMALL_HC); + InitializeIcon(Icon_Command3MediumHover, IMAGE_COMMAND3_SMALL_HOVER_HC); + InitializeIcon(Icon_Command3Small, IMAGE_COMMAND3_SMALL_HC); + InitializeIcon(Icon_Command3SmallHover, IMAGE_COMMAND3_SMALL_HOVER_HC); + } + else + { + InitializeIcon(Icon_RawShadow, IMAGE_SHADOW); + InitializeIcon(Icon_RawInsertShadow, IMAGE_INSERT_SHADOW); + InitializeIcon(Icon_HideSlideOverlay, IMAGE_HIDE_SLIDE_OVERLAY); + + InitializeIcon(Icon_ButtonBarLarge, IMAGE_BUTTONBAR_LARGE); + InitializeIcon(Icon_ButtonBarMedium, IMAGE_BUTTONBAR_MEDIUM); + InitializeIcon(Icon_ButtonBarSmall, IMAGE_BUTTONBAR_SMALL); + + InitializeIcon(Icon_Command1Large, IMAGE_COMMAND1_LARGE); + InitializeIcon(Icon_Command1LargeHover, IMAGE_COMMAND1_LARGE_HOVER); + InitializeIcon(Icon_Command1Medium, IMAGE_COMMAND1_MEDIUM); + InitializeIcon(Icon_Command1MediumHover, IMAGE_COMMAND1_MEDIUM_HOVER); + InitializeIcon(Icon_Command1Small, IMAGE_COMMAND1_SMALL); + InitializeIcon(Icon_Command1SmallHover, IMAGE_COMMAND1_SMALL_HOVER); + + InitializeIcon(Icon_Command2Large, IMAGE_COMMAND2_LARGE); + InitializeIcon(Icon_Command2LargeHover, IMAGE_COMMAND2_LARGE_HOVER); + InitializeIcon(Icon_Command2Medium, IMAGE_COMMAND2_MEDIUM); + InitializeIcon(Icon_Command2MediumHover, IMAGE_COMMAND2_MEDIUM_HOVER); + InitializeIcon(Icon_Command2Small, IMAGE_COMMAND2_SMALL); + InitializeIcon(Icon_Command2SmallHover, IMAGE_COMMAND2_SMALL_HOVER); + + InitializeIcon(Icon_Command2BLarge, IMAGE_COMMAND2B_LARGE); + InitializeIcon(Icon_Command2BLargeHover, IMAGE_COMMAND2B_LARGE_HOVER); + InitializeIcon(Icon_Command2BMedium, IMAGE_COMMAND2B_MEDIUM); + InitializeIcon(Icon_Command2BMediumHover, IMAGE_COMMAND2B_MEDIUM_HOVER); + InitializeIcon(Icon_Command2BSmall, IMAGE_COMMAND2B_SMALL); + InitializeIcon(Icon_Command2BSmallHover, IMAGE_COMMAND2B_SMALL_HOVER); + + InitializeIcon(Icon_Command3Large, IMAGE_COMMAND3_LARGE); + InitializeIcon(Icon_Command3LargeHover, IMAGE_COMMAND3_LARGE_HOVER); + InitializeIcon(Icon_Command3Medium, IMAGE_COMMAND3_MEDIUM); + InitializeIcon(Icon_Command3MediumHover, IMAGE_COMMAND3_MEDIUM_HOVER); + InitializeIcon(Icon_Command3Small, IMAGE_COMMAND3_SMALL); + InitializeIcon(Icon_Command3SmallHover, IMAGE_COMMAND3_SMALL_HOVER); + } + InitializeIcon(Icon_FocusBorder, IMAGE_FOCUS_BORDER); + } +} + + + + +::boost::shared_ptr<Font> Theme::GetFont ( + const FontType eType, + const OutputDevice& rDevice) +{ + ::boost::shared_ptr<Font> pFont; + + switch (eType) + { + case Font_PageNumber: + pFont.reset(new Font(Application::GetSettings().GetStyleSettings().GetAppFont())); + pFont->SetTransparent(TRUE); + pFont->SetWeight(WEIGHT_BOLD); + break; + + case Font_PageCount: + pFont.reset(new Font(Application::GetSettings().GetStyleSettings().GetAppFont())); + pFont->SetTransparent(TRUE); + pFont->SetWeight(WEIGHT_NORMAL); + { + const Size aSize (pFont->GetSize()); + pFont->SetSize(Size(aSize.Width()*5/3, aSize.Height()*5/3)); + } + break; + + case Font_Button: + pFont.reset(new Font(Application::GetSettings().GetStyleSettings().GetAppFont())); + pFont->SetTransparent(TRUE); + pFont->SetWeight(WEIGHT_BOLD); + { + const Size aSize (pFont->GetSize()); + pFont->SetSize(Size(aSize.Width()*4/3, aSize.Height()*4/3)); + } + break; + } + + if (pFont) + { + // Transform the point size to pixel size. + const MapMode aFontMapMode (MAP_POINT); + const Size aFontSize (rDevice.LogicToPixel(pFont->GetSize(), aFontMapMode)); + + // Transform the font size to the logical coordinates of the device. + pFont->SetSize(rDevice.PixelToLogic(aFontSize)); + } + + return pFont; +} + + + + +ColorData Theme::GetColor (const ColorType eType) +{ + if (eType>=0 && sal_uInt32(eType)<maColor.size()) + return maColor[eType]; + else + return 0; +} + + + + +void Theme::SetColor ( + const ColorType eType, + const ColorData aData) +{ + if (eType>=0 && sal_uInt32(eType)<maColor.size()) + maColor[eType] = aData; +} + + + + +ColorData Theme::GetGradientColor ( + const GradientColorType eType, + const GradientColorClass eClass) +{ + GradientDescriptor& rDescriptor (GetGradient(eType)); + + switch (eClass) + { + case Border1: return rDescriptor.maBorderColor1; + case Border2: return rDescriptor.maBorderColor2; + case Fill1: return rDescriptor.maFillColor1; + case Fill2: return rDescriptor.maFillColor2; + default: OSL_ASSERT(false); // fall through + case Base: return rDescriptor.maBaseColor; + } +} + + + + +sal_Int32 Theme::GetGradientOffset ( + const GradientColorType eType, + const GradientColorClass eClass) +{ + GradientDescriptor& rDescriptor (GetGradient(eType)); + + switch (eClass) + { + case Border1: return rDescriptor.mnBorderOffset1; + case Border2: return rDescriptor.mnBorderOffset2; + case Fill1: return rDescriptor.mnFillOffset1; + case Fill2: return rDescriptor.mnFillOffset2; + default: OSL_ASSERT(false); // fall through + case Base: return 0; + } +} + + + + +void Theme::SetGradient ( + const GradientColorType eType, + const ColorData aBaseColor, + const sal_Int32 nSaturationOverride, + const sal_Int32 nBrightnessOverride, + const sal_Int32 nFillStartOffset, + const sal_Int32 nFillEndOffset, + const sal_Int32 nBorderStartOffset, + const sal_Int32 nBorderEndOffset) +{ + GradientDescriptor& rGradient (GetGradient(eType)); + + rGradient.maBaseColor = aBaseColor; + + rGradient.mnSaturationOverride = nSaturationOverride; + rGradient.mnBrightnessOverride = nBrightnessOverride; + const ColorData aColor (nSaturationOverride>=0 || nBrightnessOverride>=0 + ? HGBAdapt(aBaseColor, nSaturationOverride, nBrightnessOverride) + : aBaseColor); + + rGradient.maFillColor1 = ChangeLuminance(aColor, nFillStartOffset); + rGradient.maFillColor2 = ChangeLuminance(aColor, nFillEndOffset); + rGradient.maBorderColor1 = ChangeLuminance(aColor, nBorderStartOffset); + rGradient.maBorderColor2 = ChangeLuminance(aColor, nBorderEndOffset); + + rGradient.mnFillOffset1 = nFillStartOffset; + rGradient.mnFillOffset2 = nFillEndOffset; + rGradient.mnBorderOffset1 = nBorderStartOffset; + rGradient.mnBorderOffset2 = nBorderEndOffset; +} + + + + +sal_Int32 Theme::GetGradientSaturationOverride (const GradientColorType eType) +{ + GradientDescriptor& rGradient (GetGradient(eType)); + return rGradient.mnSaturationOverride; +} + + + + +sal_Int32 Theme::GetGradientBrightnessOverride (const GradientColorType eType) +{ + GradientDescriptor& rGradient (GetGradient(eType)); + return rGradient.mnBrightnessOverride; +} + + + + +void Theme::SetGradientSaturationOverride (const GradientColorType eType, const sal_Int32 nValue) +{ + GradientDescriptor& rGradient (GetGradient(eType)); + SetGradient( + eType, + rGradient.maBaseColor, + nValue, + rGradient.mnBrightnessOverride, + rGradient.mnFillOffset1, + rGradient.mnFillOffset2, + rGradient.mnBorderOffset1, + rGradient.mnBorderOffset2); +} + + + + +void Theme::SetGradientBrightnessOverride (const GradientColorType eType, const sal_Int32 nValue) +{ + GradientDescriptor& rGradient (GetGradient(eType)); + SetGradient(eType, + rGradient.maBaseColor, + rGradient.mnSaturationOverride, + nValue, + rGradient.mnFillOffset1, + rGradient.mnFillOffset2, + rGradient.mnBorderOffset1, + rGradient.mnBorderOffset2); +} + + + + +const BitmapEx& Theme::GetIcon (const IconType eType) +{ + if (eType>=0 && size_t(eType)<maIcons.size()) + return maIcons[eType]; + else + { + OSL_ASSERT(eType>=0 && size_t(eType)<maIcons.size()); + return maIcons[0]; + } +} + + + + +sal_Int32 Theme::GetIntegerValue (const IntegerValueType eType) const +{ + if (eType>=0 && size_t(eType)<maIntegerValues.size()) + return maIntegerValues[eType]; + else + { + OSL_ASSERT(eType>=0 && size_t(eType)<maIntegerValues.size()); + return 0; + } +} + + + + +void Theme::SetIntegerValue (const IntegerValueType eType, const sal_Int32 nValue) +{ + if (eType>=0 && size_t(eType)<maIntegerValues.size()) + maIntegerValues[eType] = nValue; + else + { + OSL_ASSERT(eType>=0 && size_t(eType)<maIntegerValues.size()); + } +} + + + + +::rtl::OUString Theme::GetString (const StringType eType) const +{ + if (eType>=0 && size_t(eType)<maStrings.size()) + return maStrings[eType]; + else + { + OSL_ASSERT(eType>=0 && size_t(eType)<maStrings.size()); + return ::rtl::OUString(); + } +} + + + + +Theme::GradientDescriptor& Theme::GetGradient (const GradientColorType eType) +{ + if (eType>=0 && size_t(eType)<maGradients.size()) + return maGradients[eType]; + else + { + OSL_ASSERT(eType>=0 && size_t(eType)<maGradients.size()); + return maGradients[0]; + } +} + + + + +void Theme::InitializeIcon (const IconType eType, USHORT nResourceId) +{ + if (eType>=0 && size_t(eType)<maIcons.size()) + { + const BitmapEx aIcon (Image(SdResId(nResourceId)).GetBitmapEx()); + maIcons[eType] = aIcon; + } + else + { + OSL_ASSERT(eType>=0 && size_t(eType)<maIcons.size()); + } +} + + + + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsToolTip.cxx b/sd/source/ui/slidesorter/view/SlsToolTip.cxx new file mode 100644 index 000000000000..211760ef2002 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsToolTip.cxx @@ -0,0 +1,230 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsToolTip.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsTheme.hxx" +#include "sdpage.hxx" +#include "sdresid.hxx" +#include "glob.hrc" +#include <vcl/help.hxx> + +using ::rtl::OUString; + +namespace sd { namespace slidesorter { namespace view { + +ToolTip::ToolTip (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + msDefaultHelpText(), + msCurrentHelpText(), + mnHelpWindowHandle(0), + maTimer() +{ + maTimer.SetTimeout(rSlideSorter.GetTheme()->GetIntegerValue(Theme::Integer_ToolTipDelay)); + maTimer.SetTimeoutHdl(LINK(this, ToolTip, DelayTrigger)); +} + + + + +ToolTip::~ToolTip (void) +{ + maTimer.Stop(); + Hide(); +} + + + + +void ToolTip::SetPage (const model::SharedPageDescriptor& rpDescriptor) +{ + if (mpDescriptor != rpDescriptor) + { + maTimer.Stop(); + Hide(); + + mpDescriptor = rpDescriptor; + + if (mpDescriptor) + { + SdPage* pPage = mpDescriptor->GetPage(); + OUString sHelpText; + if (pPage != NULL) + sHelpText = pPage->GetName(); + else + { + OSL_ASSERT(mpDescriptor->GetPage() != NULL); + } + if (sHelpText.getLength() == 0) + { + sHelpText = String(SdResId(STR_PAGE)); + sHelpText += String::CreateFromInt32(mpDescriptor->GetPageIndex()+1); + } + + msDefaultHelpText = sHelpText; + msCurrentHelpText = sHelpText; + Show(false); + } + else + { + msDefaultHelpText = OUString(); + msCurrentHelpText = OUString(); + } + } +} + + + + +void ToolTip::ShowDefaultHelpText (const ::rtl::OUString& rsHelpText) +{ + if (msDefaultHelpText != rsHelpText) + { + const bool bIsVisible (Hide()); + + msDefaultHelpText = rsHelpText; + msCurrentHelpText = rsHelpText; + + Show(bIsVisible); + } +} + + + + +void ToolTip::ShowDefaultHelpText (void) +{ + if (msCurrentHelpText != msDefaultHelpText) + { + const bool bIsVisible (Hide()); + + msCurrentHelpText = msDefaultHelpText; + + Show(bIsVisible); + } +} + + + + +void ToolTip::ShowHelpText (const ::rtl::OUString& rsHelpText) +{ + if (msCurrentHelpText != rsHelpText) + { + const bool bIsVisible (Hide()); + + msCurrentHelpText = rsHelpText; + + Show(bIsVisible); + } +} + + + + +void ToolTip::Show (const bool bNoDelay) +{ + if (bNoDelay) + DoShow(); + else + maTimer.Start(); +} + + + + +void ToolTip::DoShow (void) +{ + if (maTimer.IsActive()) + { + // The delay timer is active. Wait for it to trigger the showing of + // the tool tip. + return; + } + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (msCurrentHelpText.getLength()>0 && pWindow) + { + Rectangle aBox ( + mrSlideSorter.GetView().GetLayouter().GetPageObjectLayouter()->GetBoundingBox( + mpDescriptor, + PageObjectLayouter::Preview, + PageObjectLayouter::WindowCoordinateSystem)); + + // Do not show the help text when the (lower edge of the ) preview + // is not visible. The tool tip itself may still be outside the + // window. + if (aBox.Bottom() >= pWindow->GetSizePixel().Height()) + return; + + ::Window* pParent (pWindow.get()); + while (pParent!=NULL && pParent->GetParent()!=NULL) + pParent = pParent->GetParent(); + const Point aOffset (pWindow->GetWindowExtentsRelative(pParent).TopLeft()); + + // We do not know how high the tool tip will be but want its top + // edge not its bottom to be at a specific position (a little below + // the preview). Therefore we use a little trick and place the tool + // tip at the top of a rectangle that is placed below the preview. + aBox.Move(aOffset.X(), aOffset.Y() + aBox.GetHeight() + 3); + mnHelpWindowHandle = Help::ShowTip( + pWindow.get(), + aBox, + msCurrentHelpText, + QUICKHELP_CENTER | QUICKHELP_TOP); + } +} + + + + +bool ToolTip::Hide (void) +{ + if (mnHelpWindowHandle>0) + { + Help::HideTip(mnHelpWindowHandle); + mnHelpWindowHandle = 0; + return true; + } + else + return false; +} + + + + +IMPL_LINK(ToolTip, DelayTrigger, void*, EMPTYARG) +{ + DoShow(); + + return 0; +} + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx b/sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx index 57872105e1cc..f46e205e7ba8 100644..100755 --- a/sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx +++ b/sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx @@ -24,18 +24,16 @@ * for a copy of the LGPLv3 License. * ************************************************************************/ -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_sd.hxx" #include "precompiled_sd.hxx" #include "SlsViewCacheContext.hxx" +#include "SlideSorter.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageDescriptor.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "view/SlideSorterView.hxx" -#include "view/SlsPageObjectViewObjectContact.hxx" #include "sdpage.hxx" #include "Window.hxx" #include "drawdoc.hxx" @@ -48,11 +46,9 @@ namespace sd { namespace slidesorter { namespace view { -ViewCacheContext::ViewCacheContext ( - model::SlideSorterModel& rModel, - SlideSorterView& rView) - : mrModel(rModel), - mrView(rView) +ViewCacheContext::ViewCacheContext (SlideSorter& rSlideSorter) + : mrModel(rSlideSorter.GetModel()), + mrSlideSorter(rSlideSorter) { } @@ -68,22 +64,17 @@ ViewCacheContext::~ViewCacheContext (void) void ViewCacheContext::NotifyPreviewCreation ( cache::CacheKey aKey, - const ::boost::shared_ptr<BitmapEx>& rPreview) + const Bitmap&) { - (void)rPreview; const model::SharedPageDescriptor pDescriptor (GetDescriptor(aKey)); if (pDescriptor.get() != NULL) { - // Use direct view-invalidate here and no ActionChanged() at the VC - // since the VC is a PageObjectViewObjectContact and in its ActionChanged() - // implementation invalidates the cache entry again. - view::PageObjectViewObjectContact* pContact = pDescriptor->GetViewObjectContact(); - if (pContact != NULL) - pContact->GetObjectContact().InvalidatePartOfView(pContact->getObjectRange()); + // Force a repaint that will trigger their re-creation. + mrSlideSorter.GetView().RequestRepaint(pDescriptor); } else { - OSL_ASSERT(pDescriptor.get() != NULL); + OSL_ASSERT(pDescriptor); } } @@ -92,7 +83,7 @@ void ViewCacheContext::NotifyPreviewCreation ( bool ViewCacheContext::IsIdle (void) { - sal_Int32 nIdleState (tools::IdleDetection::GetIdleState(mrView.GetWindow())); + sal_Int32 nIdleState (tools::IdleDetection::GetIdleState(mrSlideSorter.GetContentWindow().get())); if (nIdleState == tools::IdleDetection::IDET_IDLE) return true; else @@ -104,7 +95,8 @@ bool ViewCacheContext::IsIdle (void) bool ViewCacheContext::IsVisible (cache::CacheKey aKey) { - return GetDescriptor(aKey)->IsVisible(); + const model::SharedPageDescriptor pDescriptor (GetDescriptor(aKey)); + return pDescriptor && pDescriptor->HasState(model::PageDescriptor::ST_Visible); } diff --git a/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx b/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx index e29b65068d1d..0f52047b4769 100644..100755 --- a/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx +++ b/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx @@ -35,9 +35,11 @@ namespace sd { namespace slidesorter { namespace model { class SlideSorterModel; } } } -namespace sd { namespace slidesorter { namespace view { +namespace sd { namespace slidesorter { +class SlideSorter; +} } -class SlideSorterView; +namespace sd { namespace slidesorter { namespace view { /** The cache context for the SlideSorter as used by Draw and Impress. See the base class for documentation of the individual methods. @@ -45,11 +47,9 @@ class SlideSorterView; class ViewCacheContext : public cache::CacheContext { public: - ViewCacheContext ( - model::SlideSorterModel& rModel, - SlideSorterView& rView); + ViewCacheContext (SlideSorter& rSlideSorter); virtual ~ViewCacheContext (void); - virtual void NotifyPreviewCreation (cache::CacheKey aKey, const ::boost::shared_ptr<BitmapEx>& rPreview); + virtual void NotifyPreviewCreation (cache::CacheKey aKey, const Bitmap& rPreview); virtual bool IsIdle (void); virtual bool IsVisible (cache::CacheKey aKey); virtual const SdrPage* GetPage (cache::CacheKey aKey); @@ -59,7 +59,7 @@ public: private: model::SlideSorterModel& mrModel; - SlideSorterView& mrView; + SlideSorter& mrSlideSorter; model::SharedPageDescriptor GetDescriptor (cache::CacheKey aKey); }; diff --git a/sd/source/ui/slidesorter/view/SlsViewOverlay.cxx b/sd/source/ui/slidesorter/view/SlsViewOverlay.cxx deleted file mode 100644 index 32576240036c..000000000000 --- a/sd/source/ui/slidesorter/view/SlsViewOverlay.cxx +++ /dev/null @@ -1,606 +0,0 @@ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -#include "precompiled_sd.hxx" - -#include "view/SlsViewOverlay.hxx" - -#include "SlideSorter.hxx" -#include "model/SlideSorterModel.hxx" -#include "model/SlsPageDescriptor.hxx" -#include "model/SlsPageEnumeration.hxx" -#include "view/SlideSorterView.hxx" -#include "SlideSorterViewShell.hxx" -#include "view/SlsLayouter.hxx" -#include "view/SlsPageObject.hxx" -#include "view/SlsPageObjectViewObjectContact.hxx" -#include "ViewShell.hxx" -#include "ViewShellBase.hxx" -#include "UpdateLockManager.hxx" - -#include "Window.hxx" -#include "sdpage.hxx" - -#include <basegfx/range/b2drectangle.hxx> -#include <basegfx/range/b2drange.hxx> -#include <basegfx/range/b2irange.hxx> -#include <basegfx/matrix/b2dhommatrix.hxx> -#include <basegfx/polygon/b2dpolygon.hxx> -#include <basegfx/polygon/b2dpolygontools.hxx> -#include <basegfx/polygon/b2dpolypolygontools.hxx> -#include <basegfx/matrix/b2dhommatrixtools.hxx> - -#include <svx/sdr/overlay/overlaymanager.hxx> -#include <svx/svdpagv.hxx> -#include <svx/sdrpagewindow.hxx> -#include <vcl/svapp.hxx> - -#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> -#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> - -using namespace ::sdr::overlay; - -namespace { - const static sal_Int32 gnSubstitutionStripeLength (3); -} - -namespace sd { namespace slidesorter { namespace view { - -//===== ViewOverlay ========================================================= - -ViewOverlay::ViewOverlay (SlideSorter& rSlideSorter) - : mrSlideSorter(rSlideSorter), - maSelectionRectangleOverlay(*this), - maMouseOverIndicatorOverlay(*this), - maInsertionIndicatorOverlay(*this), - maSubstitutionOverlay(*this) -{ -} - - - - -ViewOverlay::~ViewOverlay (void) -{ -} - - - - -SelectionRectangleOverlay& ViewOverlay::GetSelectionRectangleOverlay (void) -{ - return maSelectionRectangleOverlay; -} - - - - -MouseOverIndicatorOverlay& ViewOverlay::GetMouseOverIndicatorOverlay (void) -{ - return maMouseOverIndicatorOverlay; -} - - - - -InsertionIndicatorOverlay& ViewOverlay::GetInsertionIndicatorOverlay (void) -{ - return maInsertionIndicatorOverlay; -} - - - - -SubstitutionOverlay& ViewOverlay::GetSubstitutionOverlay (void) -{ - return maSubstitutionOverlay; -} - - - - -SlideSorter& ViewOverlay::GetSlideSorter (void) const -{ - return mrSlideSorter; -} - - - - -OverlayManager* ViewOverlay::GetOverlayManager (void) const -{ - OverlayManager* pOverlayManager = NULL; - - SlideSorterView& rView (mrSlideSorter.GetView()); - SdrPageView* pPageView = rView.GetSdrPageView(); - if (pPageView != NULL && pPageView->PageWindowCount()>0) - { - SdrPageWindow* pPageWindow = pPageView->GetPageWindow(0); - if (pPageWindow != NULL) - pOverlayManager = pPageWindow->GetOverlayManager(); - } - - return pOverlayManager; -} - - - - -//===== OverlayBase ========================================================= - -OverlayBase::OverlayBase (ViewOverlay& rViewOverlay) - : OverlayObject(Color(0,0,0)), - mrViewOverlay(rViewOverlay) -{ - setVisible(false); -} - - - - -OverlayBase::~OverlayBase (void) -{ - OSL_ENSURE(!getOverlayManager(), "Please call RemoveRegistration() in the derived class; it's too late to call it in the base class since virtual methods will be missing when called in the destructor."); -} - - - - -void OverlayBase::EnsureRegistration (void) -{ - if (getOverlayManager() == NULL) - { - OverlayManager* pOverlayManager = mrViewOverlay.GetOverlayManager(); - if (pOverlayManager != NULL) - pOverlayManager->add(*this); - } -} - - - - -void OverlayBase::RemoveRegistration() -{ - OverlayManager* pOverlayManager = getOverlayManager(); - if (pOverlayManager != NULL) - pOverlayManager->remove(*this); -} - - - - -//===== SubstitutionOverlay ================================================= - -SubstitutionOverlay::SubstitutionOverlay (ViewOverlay& rViewOverlay) - : OverlayBase(rViewOverlay), - maPosition(0,0), - maShapes() -{ -} - - - - -SubstitutionOverlay::~SubstitutionOverlay (void) -{ - RemoveRegistration(); -} - - - - -void SubstitutionOverlay::Create ( - model::PageEnumeration& rSelection, - const Point& rPosition) -{ - EnsureRegistration(); - - maPosition = rPosition; - - maShapes.clear(); - while (rSelection.HasMoreElements()) - { - const Rectangle aBox (rSelection.GetNextElement()->GetPageObject()->GetCurrentBoundRect()); - basegfx::B2DRectangle aB2DBox( - aBox.Left(), - aBox.Top(), - aBox.Right(), - aBox.Bottom()); - maShapes.append(basegfx::tools::createPolygonFromRect(aB2DBox), 4); - } - - setVisible(maShapes.count() > 0); - // The selection indicator may have been visible already so call - // objectChange() to enforce an update. - objectChange(); -} - - - - -void SubstitutionOverlay::Clear (void) -{ - maShapes.clear(); - setVisible(false); -} - - - - -void SubstitutionOverlay::Move (const Point& rOffset) -{ - const basegfx::B2DHomMatrix aTranslation(basegfx::tools::createTranslateB2DHomMatrix(rOffset.X(), rOffset.Y())); - - maShapes.transform(aTranslation); - maPosition += rOffset; - - objectChange(); -} - - - - -void SubstitutionOverlay::SetPosition (const Point& rPosition) -{ - Move(rPosition - GetPosition()); -} - - - - -Point SubstitutionOverlay::GetPosition (void) const -{ - return maPosition; -} - - - - -drawinglayer::primitive2d::Primitive2DSequence SubstitutionOverlay::createOverlayObjectPrimitive2DSequence() -{ - drawinglayer::primitive2d::Primitive2DSequence aRetval; - const sal_uInt32 nCount(maShapes.count()); - - if(nCount && getOverlayManager()) - { - aRetval.realloc(nCount); - const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor()); - const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor()); - - for(sal_uInt32 a(0); a < nCount; a++) - { - aRetval[a] = drawinglayer::primitive2d::Primitive2DReference( - new drawinglayer::primitive2d::PolygonMarkerPrimitive2D( - maShapes.getB2DPolygon(a), - aRGBColorA, - aRGBColorB, - gnSubstitutionStripeLength)); - } - } - - return aRetval; -} - -void SubstitutionOverlay::stripeDefinitionHasChanged() -{ - // react on OverlayManager's stripe definition change - objectChange(); -} - - -//===== SelectionRectangleOverlay =========================================== - -SelectionRectangleOverlay::SelectionRectangleOverlay (ViewOverlay& rViewOverlay) - : OverlayBase (rViewOverlay), - maAnchor(0,0), - maSecondCorner(0,0) -{ -} - - - -SelectionRectangleOverlay::~SelectionRectangleOverlay() -{ - RemoveRegistration(); -} - - - - -Rectangle SelectionRectangleOverlay::GetSelectionRectangle (void) -{ - return Rectangle(maAnchor, maSecondCorner); -} - - - - -void SelectionRectangleOverlay::Start (const Point& rAnchor) -{ - EnsureRegistration(); - setVisible(false); - maAnchor = rAnchor; -} - - - - -void SelectionRectangleOverlay::Update (const Point& rSecondCorner) -{ - maSecondCorner = rSecondCorner; - setVisible(true); - // The selection rectangle may have been visible already so call - // objectChange() to enforce an update. - objectChange(); -} - - - - -drawinglayer::primitive2d::Primitive2DSequence SelectionRectangleOverlay::createOverlayObjectPrimitive2DSequence() -{ - drawinglayer::primitive2d::Primitive2DSequence aRetval; - const basegfx::B2DRange aRange(maAnchor.X(), maAnchor.Y(), maSecondCorner.X(), maSecondCorner.Y()); - const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(aRange)); - - if(aPolygon.count()) - { - const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor()); - const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor()); - const drawinglayer::primitive2d::Primitive2DReference xReference( - new drawinglayer::primitive2d::PolygonMarkerPrimitive2D( - aPolygon, - aRGBColorA, - aRGBColorB, - gnSubstitutionStripeLength)); - - aRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); - } - - return aRetval; -} - -void SelectionRectangleOverlay::stripeDefinitionHasChanged() -{ - // react on OverlayManager's stripe definition change - objectChange(); -} - - - - -//===== InsertionIndicatorOverlay =========================================== - -InsertionIndicatorOverlay::InsertionIndicatorOverlay (ViewOverlay& rViewOverlay) - : OverlayBase (rViewOverlay), - mnInsertionIndex(-1), - maBoundingBox() -{ -} - - - - -InsertionIndicatorOverlay::~InsertionIndicatorOverlay() -{ - RemoveRegistration(); -} - - - - -void InsertionIndicatorOverlay::SetPositionAndSize (const Rectangle& aNewBoundingBox) -{ - EnsureRegistration(); - maBoundingBox = aNewBoundingBox; - setVisible( ! maBoundingBox.IsEmpty()); - // The insertion indicator may have been visible already so call - // objectChange() to enforce an update. - objectChange(); -} - - - - -void InsertionIndicatorOverlay::SetPosition (const Point& rPoint) -{ - static const bool bAllowHorizontalInsertMarker = true; - Layouter& rLayouter (mrViewOverlay.GetSlideSorter().GetView().GetLayouter()); - USHORT nPageCount - = (USHORT)mrViewOverlay.GetSlideSorter().GetModel().GetPageCount(); - - sal_Int32 nInsertionIndex = rLayouter.GetInsertionIndex (rPoint, - bAllowHorizontalInsertMarker); - if (nInsertionIndex >= nPageCount) - nInsertionIndex = nPageCount-1; - sal_Int32 nDrawIndex = nInsertionIndex; - - bool bVertical = false; - bool bLeftOrTop = false; - if (nInsertionIndex >= 0) - { - // Now that we know where to insert, we still have to determine - // where to draw the marker. There are two decisions to make: - // 1. Draw a vertical or a horizontal insert marker. - // The horizontal one may only be chosen when there is only one - // column. - // 2. The vertical (standard) insert marker may be painted left to - // the insert page or right of the previous one. When both pages - // are in the same row this makes no difference. Otherwise the - // posiotions are at the left and right ends of two rows. - - Point aPageCenter (rLayouter.GetPageObjectBox ( - nInsertionIndex).Center()); - - if (bAllowHorizontalInsertMarker - && rLayouter.GetColumnCount() == 1) - { - bVertical = false; - bLeftOrTop = (rPoint.Y() <= aPageCenter.Y()); - } - else - { - bVertical = true; - bLeftOrTop = (rPoint.X() <= aPageCenter.X()); - } - - // Add one when the mark was painted below or to the right of the - // page object. - if ( ! bLeftOrTop) - nInsertionIndex += 1; - } - - mnInsertionIndex = nInsertionIndex; - - Rectangle aBox; - if (mnInsertionIndex >= 0) - aBox = rLayouter.GetInsertionMarkerBox ( - nDrawIndex, - bVertical, - bLeftOrTop); - SetPositionAndSize (aBox); -} - - - - -sal_Int32 InsertionIndicatorOverlay::GetInsertionPageIndex (void) const -{ - return mnInsertionIndex; -} - - - - -drawinglayer::primitive2d::Primitive2DSequence InsertionIndicatorOverlay::createOverlayObjectPrimitive2DSequence() -{ - drawinglayer::primitive2d::Primitive2DSequence aRetval(2); - const basegfx::B2DRange aRange(maBoundingBox.Left(), maBoundingBox.Top(), maBoundingBox.Right(), maBoundingBox.Bottom()); - const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(aRange)); - const basegfx::BColor aRGBColor(Application::GetDefaultDevice()->GetSettings().GetStyleSettings().GetFontColor().getBColor()); - - aRetval[0] = drawinglayer::primitive2d::Primitive2DReference( - new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( - basegfx::B2DPolyPolygon(aPolygon), - aRGBColor)); - aRetval[1] = drawinglayer::primitive2d::Primitive2DReference( - new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( - aPolygon, - aRGBColor)); - - return aRetval; -} - - - - -//===== MouseOverIndicatorOverlay =========================================== - -MouseOverIndicatorOverlay::MouseOverIndicatorOverlay (ViewOverlay& rViewOverlay) - : OverlayBase (rViewOverlay), - mpPageUnderMouse() -{ -} - - - - -MouseOverIndicatorOverlay::~MouseOverIndicatorOverlay (void) -{ - RemoveRegistration(); -} - - - - -void MouseOverIndicatorOverlay::SetSlideUnderMouse ( - const model::SharedPageDescriptor& rpDescriptor) -{ - ViewShellBase* pBase = mrViewOverlay.GetSlideSorter().GetViewShellBase(); - if (pBase==NULL || ! pBase->GetUpdateLockManager()->IsLocked()) - { - model::SharedPageDescriptor pDescriptor; - if ( ! mpPageUnderMouse.expired()) - { - try - { - pDescriptor = model::SharedPageDescriptor(mpPageUnderMouse); - } - catch (::boost::bad_weak_ptr) - { - } - } - - if (pDescriptor != rpDescriptor) - { - // Switch to the new (possibly empty) descriptor. - mpPageUnderMouse = rpDescriptor; - - EnsureRegistration(); - - // Show the indicator when a valid page descriptor is given. - setVisible( ! mpPageUnderMouse.expired()); - // The mouse over indicator may have been visible already so call - // objectChange() to enforce an update. - objectChange(); - } - } -} - - - - -drawinglayer::primitive2d::Primitive2DSequence MouseOverIndicatorOverlay::createOverlayObjectPrimitive2DSequence() -{ - view::PageObjectViewObjectContact* pContact = GetViewObjectContact(); - - if(pContact) - { - return pContact->createMouseOverEffectPrimitive2DSequence(); - } - - return drawinglayer::primitive2d::Primitive2DSequence(); -} - - - - -view::PageObjectViewObjectContact* MouseOverIndicatorOverlay::GetViewObjectContact (void) const -{ - if ( ! mpPageUnderMouse.expired()) - { - model::SharedPageDescriptor pDescriptor (mpPageUnderMouse); - return pDescriptor->GetViewObjectContact(); - } - return NULL; -} - - - - -} } } // end of namespace ::sd::slidesorter::view - diff --git a/sd/source/ui/slidesorter/view/makefile.mk b/sd/source/ui/slidesorter/view/makefile.mk index 388139b1cee9..3c5fc39c3ede 100644..100755 --- a/sd/source/ui/slidesorter/view/makefile.mk +++ b/sd/source/ui/slidesorter/view/makefile.mk @@ -35,6 +35,8 @@ ENABLE_EXCEPTIONS=TRUE AUTOSEG=true PRJINC=..$/.. +IMGLST_SRS=$(SRS)$/$(TARGET).srs + # --- Settings ----------------------------------------------------- .INCLUDE : settings.mk @@ -42,18 +44,24 @@ PRJINC=..$/.. # --- Files -------------------------------------------------------- -SLOFILES = \ - $(SLO)$/SlsFontProvider.obj \ - $(SLO)$/SlsPageObject.obj \ - $(SLO)$/SlsPageObjectViewContact.obj \ - $(SLO)$/SlsPageObjectViewObjectContact.obj \ - $(SLO)$/SlsLayouter.obj \ - $(SLO)$/SlideSorterView.obj \ - $(SLO)$/SlsViewCacheContext.obj \ - $(SLO)$/SlsViewOverlay.obj - -EXCEPTIONSFILES= \ - $(SLO)$/SlsPageObjectViewObjectContact.obj +SRS1NAME=$(TARGET) +SRC1FILES = \ + SlsResource.src + +SLOFILES = \ + $(SLO)$/SlideSorterView.obj \ + $(SLO)$/SlsButtonBar.obj \ + $(SLO)$/SlsFontProvider.obj \ + $(SLO)$/SlsFramePainter.obj \ + $(SLO)$/SlsInsertAnimator.obj \ + $(SLO)$/SlsInsertionIndicatorOverlay.obj\ + $(SLO)$/SlsLayeredDevice.obj \ + $(SLO)$/SlsLayouter.obj \ + $(SLO)$/SlsPageObjectLayouter.obj \ + $(SLO)$/SlsPageObjectPainter.obj \ + $(SLO)$/SlsTheme.obj \ + $(SLO)$/SlsToolTip.obj \ + $(SLO)$/SlsViewCacheContext.obj # --- Tagets ------------------------------------------------------- diff --git a/sd/source/ui/toolpanel/controls/MasterPageContainerQueue.cxx b/sd/source/ui/toolpanel/controls/MasterPageContainerQueue.cxx index 35b02497575e..94940d19ebd1 100644..100755 --- a/sd/source/ui/toolpanel/controls/MasterPageContainerQueue.cxx +++ b/sd/source/ui/toolpanel/controls/MasterPageContainerQueue.cxx @@ -153,7 +153,7 @@ bool MasterPageContainerQueue::RequestPreview (const SharedMasterPageDescriptor& PreviewCreationRequest::CompareToken(rpDescriptor->maToken))); // When a request for the same token exists then the lowest of the // two priorities is used. - if (HasRequest(rpDescriptor->maToken)) + if (iRequest != mpRequestQueue->end()) if (iRequest->mnPriority < nPriority) { mpRequestQueue->erase(iRequest); diff --git a/sd/source/ui/tools/PreviewRenderer.cxx b/sd/source/ui/tools/PreviewRenderer.cxx index c416e689efcf..3b6e8339c22d 100755..100644 --- a/sd/source/ui/tools/PreviewRenderer.cxx +++ b/sd/source/ui/tools/PreviewRenderer.cxx @@ -43,6 +43,11 @@ #include <tools/link.hxx> #include <vcl/svapp.hxx> #include <tools/diagnose_ex.h> +#include <svx/sdr/contact/viewobjectcontact.hxx> +#include <svx/sdr/contact/viewcontact.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; namespace sd { @@ -50,6 +55,26 @@ namespace sd { const int PreviewRenderer::snSubstitutionTextSize = 11; const int PreviewRenderer::snFrameWidth = 1; +namespace { + /** This incarnation of the ViewObjectContactRedirector filters away all + PageObj objects, unconditionally. + */ + class ViewRedirector : public ::sdr::contact::ViewObjectContactRedirector + { + public: + ViewRedirector (void); + virtual ~ViewRedirector (void); + virtual drawinglayer::primitive2d::Primitive2DSequence createRedirectedPrimitive2DSequence( + const sdr::contact::ViewObjectContact& rOriginal, + const sdr::contact::DisplayInfo& rDisplayInfo); + }; +} + + + + +//===== PreviewRenderer ======================================================= + PreviewRenderer::PreviewRenderer ( OutputDevice* pTemplate, const bool bHasFrame) @@ -66,7 +91,10 @@ PreviewRenderer::PreviewRenderer ( mpPreviewDevice->SetBackground(pTemplate->GetBackground()); } else - mpPreviewDevice->SetBackground(Wallpaper(COL_WHITE)); + { + mpPreviewDevice->SetBackground(Wallpaper( + Application::GetSettings().GetStyleSettings().GetWindowColor())); + } } @@ -85,7 +113,8 @@ Image PreviewRenderer::RenderPage ( const SdPage* pPage, const sal_Int32 nWidth, const String& rSubstitutionText, - const bool bObeyHighContrastMode) + const bool bObeyHighContrastMode, + const bool bDisplayPresentationObjects) { if (pPage != NULL) { @@ -95,7 +124,12 @@ Image PreviewRenderer::RenderPage ( const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0); const sal_Int32 nHeight (sal::static_int_cast<sal_Int32>( (nWidth - 2*nFrameWidth) / nAspectRatio + 2*nFrameWidth + 0.5)); - return RenderPage (pPage, Size(nWidth,nHeight), rSubstitutionText, bObeyHighContrastMode); + return RenderPage ( + pPage, + Size(nWidth,nHeight), + rSubstitutionText, + bObeyHighContrastMode, + bDisplayPresentationObjects); } else return Image(); @@ -108,7 +142,8 @@ Image PreviewRenderer::RenderPage ( const SdPage* pPage, Size aPixelSize, const String& rSubstitutionText, - const bool bObeyHighContrastMode) + const bool bObeyHighContrastMode, + const bool bDisplayPresentationObjects) { Image aPreview; @@ -116,10 +151,10 @@ Image PreviewRenderer::RenderPage ( { try { - if (Initialize (pPage, aPixelSize, bObeyHighContrastMode)) + if (Initialize(pPage, aPixelSize, bObeyHighContrastMode)) { - PaintPage (pPage); - PaintSubstitutionText (rSubstitutionText); + PaintPage(pPage, bDisplayPresentationObjects); + PaintSubstitutionText(rSubstitutionText); PaintFrame(); Size aSize (mpPreviewDevice->GetOutputSizePixel()); @@ -154,17 +189,17 @@ Image PreviewRenderer::RenderSubstitution ( mpPreviewDevice->SetOutputSizePixel(rPreviewPixelSize); // Adjust contrast mode. - bool bUseContrast = Application::GetSettings().GetStyleSettings(). - GetHighContrastMode(); + const bool bUseContrast ( + Application::GetSettings().GetStyleSettings().GetHighContrastMode()); mpPreviewDevice->SetDrawMode (bUseContrast ? ViewShell::OUTPUT_DRAWMODE_CONTRAST : ViewShell::OUTPUT_DRAWMODE_COLOR); - // Set a map mode makes a typical substitution text completely + // Set a map mode that makes a typical substitution text completely // visible. MapMode aMapMode (mpPreviewDevice->GetMapMode()); aMapMode.SetMapUnit(MAP_100TH_MM); - double nFinalScale (25.0 * rPreviewPixelSize.Width() / 28000.0); + const double nFinalScale (25.0 * rPreviewPixelSize.Width() / 28000.0); aMapMode.SetScaleX(nFinalScale); aMapMode.SetScaleY(nFinalScale); const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0); @@ -173,7 +208,7 @@ Image PreviewRenderer::RenderSubstitution ( mpPreviewDevice->SetMapMode (aMapMode); // Clear the background. - Rectangle aPaintRectangle ( + const Rectangle aPaintRectangle ( Point(0,0), mpPreviewDevice->GetOutputSizePixel()); mpPreviewDevice->EnableMapMode(FALSE); @@ -187,7 +222,7 @@ Image PreviewRenderer::RenderSubstitution ( PaintSubstitutionText (rSubstitutionText); PaintFrame(); - Size aSize (mpPreviewDevice->GetOutputSizePixel()); + const Size aSize (mpPreviewDevice->GetOutputSizePixel()); aPreview = mpPreviewDevice->GetBitmap ( mpPreviewDevice->PixelToLogic(Point(0,0)), mpPreviewDevice->PixelToLogic(aSize)); @@ -261,6 +296,8 @@ bool PreviewRenderer::Initialize ( rOutliner.SetDefaultLanguage(pDocument->GetLanguage(EE_CHAR_LANGUAGE)); mpView->SetApplicationBackgroundColor( Color(aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor)); + mpPreviewDevice->SetBackground(Wallpaper(aPageBackgroundColor)); + mpPreviewDevice->Erase(); bSuccess = true; } @@ -280,7 +317,9 @@ void PreviewRenderer::Cleanup (void) -void PreviewRenderer::PaintPage (const SdPage* pPage) +void PreviewRenderer::PaintPage ( + const SdPage* pPage, + const bool bDisplayPresentationObjects) { // Paint the page. Rectangle aPaintRectangle (Point(0,0), pPage->GetSize()); @@ -288,18 +327,22 @@ void PreviewRenderer::PaintPage (const SdPage* pPage) // Turn off online spelling and redlining. SdrOutliner* pOutliner = NULL; - ULONG nOriginalControlWord = 0; + ULONG nSavedControlWord (0); if (mpDocShellOfView!=NULL && mpDocShellOfView->GetDoc()!=NULL) { pOutliner = &mpDocShellOfView->GetDoc()->GetDrawOutliner(); - nOriginalControlWord = pOutliner->GetControlWord(); - pOutliner->SetControlWord( - (nOriginalControlWord & ~EE_CNTRL_ONLINESPELLING)); + nSavedControlWord = pOutliner->GetControlWord(); + pOutliner->SetControlWord((nSavedControlWord & ~EE_CNTRL_ONLINESPELLING)); } + // Use a special redirector to prevent PresObj shapes from being painted. + boost::scoped_ptr<ViewRedirector> pRedirector; + if ( ! bDisplayPresentationObjects) + pRedirector.reset(new ViewRedirector()); + try { - mpView->CompleteRedraw (mpPreviewDevice.get(), aRegion); + mpView->CompleteRedraw(mpPreviewDevice.get(), aRegion, pRedirector.get()); } catch (const ::com::sun::star::uno::Exception&) { @@ -308,7 +351,7 @@ void PreviewRenderer::PaintPage (const SdPage* pPage) // Restore the previous online spelling and redlining states. if (pOutliner != NULL) - pOutliner->SetControlWord(nOriginalControlWord); + pOutliner->SetControlWord(nSavedControlWord); } @@ -371,23 +414,26 @@ void PreviewRenderer::SetupOutputSize ( // First set the map mode to some arbitrary scale that is numerically // stable. MapMode aMapMode (mpPreviewDevice->GetMapMode()); - aMapMode.SetMapUnit(MAP_100TH_MM); - double nInitialScale = 1; - aMapMode.SetScaleX (Fraction(nInitialScale)); - aMapMode.SetScaleY (Fraction(nInitialScale)); - aMapMode.SetOrigin (Point(0,0)); + aMapMode.SetMapUnit(MAP_PIXEL); // Adapt it to the desired width. const Size aPageModelSize (rPage.GetSize()); - const Size aOutputSize = mpPreviewDevice->LogicToPixel(rPage.GetSize(), aMapMode); - const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0); - const double nFinalScale (nInitialScale * (rFramePixelSize.Width()-2*nFrameWidth) - / aOutputSize.Width()); - aMapMode.SetScaleX (nFinalScale); - aMapMode.SetScaleY (nFinalScale); - aMapMode.SetOrigin (mpPreviewDevice->PixelToLogic( - Point(nFrameWidth,nFrameWidth),aMapMode)); - + if (aPageModelSize.Width()>0 || aPageModelSize.Height()>0) + { + const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0); + aMapMode.SetScaleX( + Fraction(rFramePixelSize.Width()-2*nFrameWidth-1, aPageModelSize.Width())); + aMapMode.SetScaleY( + Fraction(rFramePixelSize.Height()-2*nFrameWidth-1, aPageModelSize.Height())); + aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic(Point(nFrameWidth,nFrameWidth),aMapMode)); + } + else + { + // We should never get here. + OSL_ASSERT(false); + aMapMode.SetScaleX(1.0); + aMapMode.SetScaleY(1.0); + } mpPreviewDevice->SetMapMode (aMapMode); mpPreviewDevice->SetOutputSizePixel(rFramePixelSize); } @@ -414,10 +460,17 @@ void PreviewRenderer::ProvideView (DrawDocShell* pDocShell) { mpView.reset (new DrawView (pDocShell, mpPreviewDevice.get(), NULL)); } - mpView->SetPreviewRenderer( sal_True ); - mpView->SetBordVisible(FALSE); - mpView->SetPageBorderVisible(FALSE); - mpView->SetPageVisible(TRUE); + mpView->SetPreviewRenderer(true); +#if 1 + mpView->SetPageVisible(false); + mpView->SetPageBorderVisible(true); + mpView->SetBordVisible(false); +#else + // This works in the slide sorter but prevents the master page + // background being painted in the list of current master pages in the + // task manager. + mpView->SetPagePaintingAllowed(false); +#endif } @@ -499,4 +552,56 @@ void PreviewRenderer::Notify(SfxBroadcaster&, const SfxHint& rHint) + +//===== ViewRedirector ======================================================== + +namespace { + +ViewRedirector::ViewRedirector (void) +{ +} + + + + +ViewRedirector::~ViewRedirector (void) +{ +} + + + + +drawinglayer::primitive2d::Primitive2DSequence ViewRedirector::createRedirectedPrimitive2DSequence( + const sdr::contact::ViewObjectContact& rOriginal, + const sdr::contact::DisplayInfo& rDisplayInfo) +{ + SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject(); + + if (pObject==NULL || pObject->GetPage() == NULL) + { + // not a SdrObject visualisation (maybe e.g. page) or no page + return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence( + rOriginal, + rDisplayInfo); + } + + const bool bDoCreateGeometry (pObject->GetPage()->checkVisibility( rOriginal, rDisplayInfo, true)); + + if ( ! bDoCreateGeometry + && (pObject->GetObjInventor() != SdrInventor || pObject->GetObjIdentifier() != OBJ_PAGE)) + { + return drawinglayer::primitive2d::Primitive2DSequence(); + } + + if (pObject->IsEmptyPresObj()) + return drawinglayer::primitive2d::Primitive2DSequence(); + + return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence( + rOriginal, + rDisplayInfo); +} + +} // end of anonymous namespace + + } // end of namespace ::sd diff --git a/sd/source/ui/unoidl/DrawController.cxx b/sd/source/ui/unoidl/DrawController.cxx index 2bc98cd66de3..3c99baa3ee79 100755 --- a/sd/source/ui/unoidl/DrawController.cxx +++ b/sd/source/ui/unoidl/DrawController.cxx @@ -812,14 +812,16 @@ sal_Bool DrawController::convertFastPropertyValue ( else if (mxSubController.is()) { rConvertedValue = rValue; - rOldValue = mxSubController->getFastPropertyValue(nHandle); - bResult = (rOldValue != rConvertedValue); - /* bResult = mpSubController->convertFastPropertyValue( - rConvertedValue, - rOldValue, - nHandle, - rValue); - */ + try + { + rOldValue = mxSubController->getFastPropertyValue(nHandle); + bResult = (rOldValue != rConvertedValue); + } + catch(beans::UnknownPropertyException aException) + { + // The prperty is unknown and thus an illegal argument to this method. + throw com::sun::star::lang::IllegalArgumentException(); + } } return bResult; diff --git a/sd/source/ui/unoidl/SdUnoSlideView.cxx b/sd/source/ui/unoidl/SdUnoSlideView.cxx index a6502711ee72..4e788db90928 100755 --- a/sd/source/ui/unoidl/SdUnoSlideView.cxx +++ b/sd/source/ui/unoidl/SdUnoSlideView.cxx @@ -35,7 +35,7 @@ #include "SlideSorter.hxx" #include "controller/SlideSorterController.hxx" #include "controller/SlsPageSelector.hxx" -#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsCurrentSlideManager.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageDescriptor.hxx" @@ -104,7 +104,6 @@ sal_Bool SAL_CALL SdUnoSlideView::select (const Any& aSelection) } } } - rSlideSorterController.GetSelectionManager()->MakeSelectionVisible(); return bOk; } @@ -161,19 +160,30 @@ void SAL_CALL SdUnoSlideView::removeSelectionChangeListener ( //----- XDrawView ------------------------------------------------------------- void SAL_CALL SdUnoSlideView::setCurrentPage ( - const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& ) - throw(::com::sun::star::uno::RuntimeException) + const css::uno::Reference<css::drawing::XDrawPage>& rxDrawPage) + throw(css::uno::RuntimeException) { + Reference<beans::XPropertySet> xProperties (rxDrawPage, UNO_QUERY); + if (xProperties.is()) + { + sal_uInt16 nPageNumber(0); + if (xProperties->getPropertyValue(::rtl::OUString::createFromAscii("Number")) >>= nPageNumber) + { + mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide( + nPageNumber-1, + true); + } + } } -::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage > SAL_CALL +css::uno::Reference<css::drawing::XDrawPage > SAL_CALL SdUnoSlideView::getCurrentPage (void) - throw(::com::sun::star::uno::RuntimeException) + throw(css::uno::RuntimeException) { - return Reference<drawing::XDrawPage>(); + return mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()->GetXDrawPage(); } diff --git a/sd/source/ui/view/drviews2.cxx b/sd/source/ui/view/drviews2.cxx index 3102dc726a61..7aaba7d9c4fa 100755 --- a/sd/source/ui/view/drviews2.cxx +++ b/sd/source/ui/view/drviews2.cxx @@ -958,7 +958,8 @@ void DrawViewShell::FuTemporary(SfxRequest& rReq) SdPage* DrawViewShell::CreateOrDuplicatePage ( SfxRequest& rRequest, PageKind ePageKind, - SdPage* pPage) + SdPage* pPage, + const sal_Int32 nInsertPosition) { SdPage* pNewPage = NULL; if (ePageKind == PK_STANDARD && meEditMode != EM_MASTERPAGE) @@ -967,7 +968,7 @@ SdPage* DrawViewShell::CreateOrDuplicatePage ( { mpDrawView->SdrEndTextEdit(); } - pNewPage = ViewShell::CreateOrDuplicatePage (rRequest, ePageKind, pPage); + pNewPage = ViewShell::CreateOrDuplicatePage (rRequest, ePageKind, pPage, nInsertPosition); } return pNewPage; } diff --git a/sd/source/ui/view/viewshe3.cxx b/sd/source/ui/view/viewshe3.cxx index 8bfdefd240da..7ce0b577ed9e 100755..100644 --- a/sd/source/ui/view/viewshe3.cxx +++ b/sd/source/ui/view/viewshe3.cxx @@ -215,7 +215,8 @@ void ViewShell::GetMenuState( SfxItemSet &rSet ) SdPage* ViewShell::CreateOrDuplicatePage ( SfxRequest& rRequest, PageKind ePageKind, - SdPage* pPage) + SdPage* pPage, + const sal_Int32 nInsertPosition) { USHORT nSId = rRequest.GetSlot(); SdDrawDocument* pDocument = GetDoc(); @@ -254,7 +255,8 @@ SdPage* ViewShell::CreateOrDuplicatePage ( && rBase.GetMainViewShell()->GetShellType()!=ViewShell::ST_DRAW) { framework::FrameworkHelper::Instance(GetViewShellBase())->RequestTaskPanel( - framework::FrameworkHelper::msLayoutTaskPanelURL); + framework::FrameworkHelper::msLayoutTaskPanelURL, + false); } */ @@ -376,7 +378,8 @@ SdPage* ViewShell::CreateOrDuplicatePage ( eStandardLayout, eNotesLayout, bIsPageBack, - bIsPageObj); + bIsPageObj, + nInsertPosition); // Select exactly the new page. USHORT nPageCount (pDocument->GetSdPageCount(ePageKind)); for (USHORT i=0; i<nPageCount; i++) @@ -399,7 +402,8 @@ SdPage* ViewShell::CreateOrDuplicatePage ( eStandardLayout, eNotesLayout, bIsPageBack, - bIsPageObj); + bIsPageObj, + nInsertPosition); break; case SID_DUPLICATE_PAGE: @@ -413,7 +417,8 @@ SdPage* ViewShell::CreateOrDuplicatePage ( eStandardLayout, eNotesLayout, bIsPageBack, - bIsPageObj); + bIsPageObj, + nInsertPosition); break; default: diff --git a/sd/source/ui/view/viewshel.cxx b/sd/source/ui/view/viewshel.cxx index c1f4bc070bcf..7885d07e5f2c 100755 --- a/sd/source/ui/view/viewshel.cxx +++ b/sd/source/ui/view/viewshel.cxx @@ -684,9 +684,9 @@ long ViewShell::Notify(NotifyEvent& rNEvt, ::sd::Window* pWin) } -BOOL ViewShell::HandleScrollCommand(const CommandEvent& rCEvt, ::sd::Window* pWin) +bool ViewShell::HandleScrollCommand(const CommandEvent& rCEvt, ::sd::Window* pWin) { - BOOL bDone = FALSE; + bool bDone = false; switch( rCEvt.GetCommand() ) { @@ -736,7 +736,7 @@ BOOL ViewShell::HandleScrollCommand(const CommandEvent& rCEvt, ::sd::Window* pWi Invalidate( SID_ATTR_ZOOM ); Invalidate( SID_ATTR_ZOOMSLIDER ); - bDone = TRUE; + bDone = true; } } else @@ -752,7 +752,7 @@ BOOL ViewShell::HandleScrollCommand(const CommandEvent& rCEvt, ::sd::Window* pWi rCEvt.IsMouseEvent(),(const void *) &aWheelData ); bDone = pWin->HandleScrollCommand( aReWrite, mpHorizontalScrollBar.get(), - mpVerticalScrollBar.get()); + mpVerticalScrollBar.get()) == TRUE; } } } |