diff options
Diffstat (limited to 'sd/source/ui/slidesorter/view')
-rw-r--r-- | sd/source/ui/slidesorter/view/SlideSorterView.cxx | 846 | ||||
-rw-r--r-- | sd/source/ui/slidesorter/view/SlsFontProvider.cxx | 132 | ||||
-rw-r--r-- | sd/source/ui/slidesorter/view/SlsLayouter.cxx | 813 | ||||
-rw-r--r-- | sd/source/ui/slidesorter/view/SlsPageObject.cxx | 80 | ||||
-rw-r--r-- | sd/source/ui/slidesorter/view/SlsPageObjectViewContact.cxx | 140 | ||||
-rwxr-xr-x | sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx | 1419 | ||||
-rw-r--r-- | sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx | 167 | ||||
-rw-r--r-- | sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx | 70 | ||||
-rw-r--r-- | sd/source/ui/slidesorter/view/SlsViewOverlay.cxx | 606 | ||||
-rw-r--r-- | sd/source/ui/slidesorter/view/makefile.mk | 61 |
10 files changed, 4334 insertions, 0 deletions
diff --git a/sd/source/ui/slidesorter/view/SlideSorterView.cxx b/sd/source/ui/slidesorter/view/SlideSorterView.cxx new file mode 100644 index 000000000000..82aac5b2cd9e --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlideSorterView.cxx @@ -0,0 +1,846 @@ +/************************************************************************* + * + * 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/SlideSorterView.hxx" + +#include "ViewShellBase.hxx" +#include "SlideSorter.hxx" +#include "SlideSorterViewShell.hxx" +#include "ViewShell.hxx" +#include "SlsViewCacheContext.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsViewOverlay.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsPageObjectFactory.hxx" +#include "controller/SlsProperties.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "model/SlsPageDescriptor.hxx" +#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 "drawdoc.hxx" +#include "sdpage.hxx" +#include "Window.hxx" +#include "sdresid.hxx" +#include "glob.hrc" + +#include <svl/itempool.hxx> +#include <svx/svdpagv.hxx> +#include <svx/svdopage.hxx> +#include <svx/xlndsit.hxx> +#include <svx/xlnclit.hxx> +#include <com/sun/star/presentation/FadeEffect.hpp> +#include <vcl/svapp.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> + +#ifndef _SFXITEMPOOL_HXX +#include <svl/itempool.hxx> +#endif + +using namespace std; +using namespace ::sd::slidesorter::model; + +namespace sd { namespace slidesorter { namespace view { + +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) +{ + // 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); + + // show page + LocalModelHasChanged(); +} + + + + +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()) + { + view::PageObjectViewObjectContact* pContact + = aPageEnumeration.GetNextElement()->GetViewObjectContact(); + if (pContact != NULL) + pContact->SetCache(pEmptyCache); + } + mpPreviewCache.reset(); + + // 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) +} + + + + +sal_Int32 SlideSorterView::GetPageIndexAtPoint (const Point& rPosition) const +{ + sal_Int32 nIndex (-1); + + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + { + nIndex = mpLayouter->GetIndexAtPoint (pWindow->PixelToLogic (rPosition)); + + // Clip the page index against the page count. + if (nIndex >= mrModel.GetPageCount()) + nIndex = -1; + } + + return nIndex; +} + + + + +sal_Int32 SlideSorterView::GetFadePageIndexAtPoint ( + const Point& rPosition) const +{ + sal_Int32 nIndex (-1); + + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + { + Point aModelPosition (pWindow->PixelToLogic (rPosition)); + nIndex = mpLayouter->GetIndexAtPoint( + aModelPosition, + true // Include page borders into hit test + ); + + // Clip the page index against the page count. + if (nIndex >= mrModel.GetPageCount()) + nIndex = -1; + + if (nIndex >= 0) + { + // Now test whether the given position is inside the area of the + // fade effect indicator. + view::PageObjectViewObjectContact* pContact + = mrModel.GetPageDescriptor(nIndex)->GetViewObjectContact(); + if (pContact != NULL) + { + if ( ! pContact->GetBoundingBox( + *pWindow, + PageObjectViewObjectContact::FadeEffectIndicatorBoundingBox, + PageObjectViewObjectContact::ModelCoordinateSystem).IsInside ( + aModelPosition)) + { + nIndex = -1; + } + } + else + nIndex = -1; + } + } + + return nIndex; +} + + + + +Layouter& SlideSorterView::GetLayouter (void) +{ + return *mpLayouter.get(); +} + + + + +void SlideSorterView::ModelHasChanged (void) +{ + if (mbModelChangedWhileModifyEnabled) + { + controller::SlideSorterController::ModelChangeLock alock( mrSlideSorter.GetController() ); + mrSlideSorter.GetController().HandleModelChange(); + LocalModelHasChanged(); + } +} + + + + +void SlideSorterView::LocalModelHasChanged(void) +{ + mbModelChangedWhileModifyEnabled = false; + + // 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(); +} + + + + +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(); +} + + + + +void SlideSorterView::PostModelChange (void) +{ + // In PreModelChange() the page objects have been released. Here we + // create new ones. + ::osl::MutexGuard aGuard (mrModel.GetMutex()); + + 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 (); +} + + + + +/** At the moment for every model change all page objects are destroyed and + re-created again. This can be optimized by accepting hints that + describe the type of change so that existing page objects can be + reused. +*/ +void SlideSorterView::HandleModelChange (void) +{ + PreModelChange (); + PostModelChange(); +} + + + + +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::Resize (void) +{ + ::sd::Window* pWindow = GetWindow(); + if (mrModel.GetPageCount()>0 && pWindow != NULL) + { + UpdatePageBorders(); + bool bRearrangeSuccess (false); + if (meOrientation == HORIZONTAL) + { + bRearrangeSuccess = mpLayouter->RearrangeHorizontal ( + pWindow->GetSizePixel(), + mrModel.GetPageDescriptor(0)->GetPage()->GetSize(), + pWindow, + mrModel.GetPageCount()); + } + else + { + bRearrangeSuccess = mpLayouter->RearrangeVertical ( + pWindow->GetSizePixel(), + mrModel.GetPageDescriptor(0)->GetPage()->GetSize(), + pWindow); + } + + if (bRearrangeSuccess) + { + Layout(); + pWindow->Invalidate(); + } + } +} + + + + +void SlideSorterView::Layout () +{ + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + { + // Set the model area, i.e. the smallest rectangle that includes all + // page objects. + Rectangle aViewBox (mpLayouter->GetPageBox(mrModel.GetPageCount())); + pWindow->SetViewOrigin (aViewBox.TopLeft()); + pWindow->SetViewSize (aViewBox.GetSize()); + + Size aPageObjectPixelSize (pWindow->LogicToPixel(mpLayouter->GetPageObjectSize())); + if (maPreviewSize != aPageObjectPixelSize && mpPreviewCache.get()!=NULL) + { + mpPreviewCache->ChangeSize(aPageObjectPixelSize); + maPreviewSize = aPageObjectPixelSize; + } + + // 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; + } + // Set the page so that it encloses all page objects. + mpPage->SetSize (aViewBox.GetSize()); + } + + InvalidatePageObjectVisibilities (); +} + + + + +void SlideSorterView::InvalidatePageObjectVisibilities (void) +{ + mbPageObjectVisibilitiesValid = false; +} + + + + +void SlideSorterView::DeterminePageObjectVisibilities (void) +{ + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + { + // 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); + + // 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) + mbPreciousFlagUpdatePending |= true; + model::SharedPageDescriptor pDescriptor; + view::PageObjectViewObjectContact* pContact; + for (int nIndex=nMinIndex; nIndex<=nMaxIndex; 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); + } + + } + mnFirstVisiblePageIndex = nFirstIndex; + mnLastVisiblePageIndex = nLastIndex; + } +} + + + + +void SlideSorterView::UpdatePreciousFlags (void) +{ + if (mbPreciousFlagUpdatePending) + { + mbPreciousFlagUpdatePending = false; + + model::SharedPageDescriptor pDescriptor; + ::boost::shared_ptr<cache::PageCache> pCache = GetPreviewCache(); + sal_Int32 nPageCount (mrModel.GetPageCount()); + + for (int nIndex=0; nIndex<=nPageCount; ++nIndex) + { + pDescriptor = mrModel.GetPageDescriptor(nIndex); + if (pDescriptor.get() != NULL) + { + pCache->SetPreciousFlag( + pDescriptor->GetPage(), + (nIndex>=mnFirstVisiblePageIndex && nIndex<=mnLastVisiblePageIndex)); + SSCD_SET_VISIBILITY(mrModel.GetDocument(), nIndex, + (nIndex>=mnFirstVisiblePageIndex && nIndex<=mnLastVisiblePageIndex)); + } + else + { + // At least one cache entry can not be updated. Remember to + // repeat the whole updating later and leave the loop now. + mbPreciousFlagUpdatePending = true; + break; + } + } + } +} + + + + +void SlideSorterView::SetOrientation (const Orientation eOrientation) +{ + meOrientation = eOrientation; + RequestRepaint(); +} + + + + +SlideSorterView::Orientation SlideSorterView::GetOrientation (void) const +{ + return meOrientation; +} + + + + +void SlideSorterView::RequestRepaint (void) +{ + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + pWindow->Invalidate(); +} + + + + +void SlideSorterView::RequestRepaint (const model::SharedPageDescriptor& rpDescriptor) +{ + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + pWindow->Invalidate( + GetPageBoundingBox ( + rpDescriptor, + CS_MODEL, + BBT_INFO)); +} + + + + +Rectangle SlideSorterView::GetModelArea (void) +{ + return Rectangle ( + Point (0,0), + Size (mpPage->GetSize().Width(),mpPage->GetSize().Height())); +} + + + + +Rectangle SlideSorterView::GetPageBoundingBox ( + const model::SharedPageDescriptor& rpDescriptor, + CoordinateSystem eCoordinateSystem, + BoundingBoxType eBoundingBoxType) const +{ + Rectangle aBBox; + SdrObject* pPageObject = rpDescriptor->GetPageObject(); + if (pPageObject != NULL) + { + aBBox = pPageObject->GetCurrentBoundRect(); + AdaptBoundingBox (aBBox, eCoordinateSystem, eBoundingBoxType); + } + + return aBBox; +} + + + + +Rectangle SlideSorterView::GetPageBoundingBox ( + sal_Int32 nIndex, + CoordinateSystem eCoordinateSystem, + BoundingBoxType eBoundingBoxType) const +{ + Rectangle aBBox; + if (nIndex >= 0 && nIndex<mrModel.GetPageCount()) + { + aBBox = mpLayouter->GetPageObjectBox(nIndex); + AdaptBoundingBox (aBBox, eCoordinateSystem, eBoundingBoxType); + } + + return aBBox; +} + + + + +void SlideSorterView::CompleteRedraw(OutputDevice* pDevice, const Region& rPaintArea, sdr::contact::ViewObjectContactRedirector* pRedirector) +{ + if (mnLockRedrawSmph == 0) + { + // Update the page visibilities when they have been invalidated. + if ( ! mbPageObjectVisibilitiesValid) + DeterminePageObjectVisibilities(); + + if (mbPreciousFlagUpdatePending) + UpdatePreciousFlags(); + + // 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 + { + // In sd::View::CompleteRedraw() this call is recorded and given + // region is painted when the view is unlocked. + View::CompleteRedraw (pDevice, rPaintArea, pRedirector); + } +} + + + + +void SlideSorterView::InvalidateOneWin (::Window& rWindow) +{ + // if ( IsInvalidateAllowed() ) + View::InvalidateOneWin (rWindow); +} + + + + +void SlideSorterView::InvalidateOneWin ( + ::Window& rWindow, + const Rectangle& rPaintArea) +{ + // if( IsInvalidateAllowed() ) + View::InvalidateOneWin (rWindow, rPaintArea); +} + + + + +::sd::Window* SlideSorterView::GetWindow (void) const +{ + return static_cast< ::sd::Window*>(GetFirstOutputDevice()); +} + + + + +void SlideSorterView::AdaptBoundingBox ( + Rectangle& rModelPageObjectBoundingBox, + CoordinateSystem eCoordinateSystem, + BoundingBoxType eBoundingBoxType) const +{ + CoordinateSystem aCurrentCoordinateSystem = CS_MODEL; + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + { + 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); + } + } +} + + + + +::boost::shared_ptr<cache::PageCache> SlideSorterView::GetPreviewCache (void) +{ + ::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; +} + + + + +ViewOverlay& SlideSorterView::GetOverlay (void) +{ + return *mpViewOverlay.get(); +} + + + + +::sdr::contact::ObjectContact& SlideSorterView::GetObjectContact (void) const +{ + return GetSdrPageView()->GetPageWindow(0)->GetObjectContact(); +} + + + + +SlideSorterView::PageRange SlideSorterView::GetVisiblePageRange (void) +{ + const int nMaxPageIndex (mrModel.GetPageCount() - 1); + if ( ! mbPageObjectVisibilitiesValid) + DeterminePageObjectVisibilities(); + return PageRange( + ::std::min(mnFirstVisiblePageIndex,nMaxPageIndex), + ::std::min(mnLastVisiblePageIndex, nMaxPageIndex)); +} + + + + +void SlideSorterView::Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) +{ + ::sd::DrawDocShell* pDocShell = mrModel.GetDocument()->GetDocSh(); + if (pDocShell!=NULL && pDocShell->IsEnableSetModified()) + mbModelChangedWhileModifyEnabled = true; + + ::sd::View::Notify(rBroadcaster, rHint); +} + + + + +void SlideSorterView::UpdatePageBorders (void) +{ + maPagePixelBorder = SvBorder(); + ::sd::Window* pWindow = GetWindow(); + if (mrModel.GetPageCount()>0 && pWindow!=NULL) + { + // 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()) + { + Size aBorderSize (pWindow->PixelToLogic (Size(3,3))); + maModelBorder.Left() += aBorderSize.Width(); + maModelBorder.Right() += aBorderSize.Width(); + maModelBorder.Top() += aBorderSize.Height(); + maModelBorder.Bottom() += aBorderSize.Height(); + } + + // 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()) + { + model::SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement()); + pDescriptor->SetModelBorder(maModelBorder); + pDescriptor->SetPageNumberAreaModelSize(maPageNumberAreaModelSize); + } + + // 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()); +} + + + + +Size SlideSorterView::GetPageNumberAreaModelSize (void) const +{ + return maPageNumberAreaModelSize; +} + + + + +SvBorder SlideSorterView::GetModelBorder (void) const +{ + return maModelBorder; +} + + + + +void SlideSorterView::AddSdrObject (SdrObject& rObject) +{ + mpPage->InsertObject(&rObject); + rObject.SetModel(&maPageModel); +} + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsFontProvider.cxx b/sd/source/ui/slidesorter/view/SlsFontProvider.cxx new file mode 100644 index 000000000000..9d2e224aefdf --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsFontProvider.cxx @@ -0,0 +1,132 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "view/SlsFontProvider.hxx" + +#include "controller/SlideSorterController.hxx" + +#include <sfx2/app.hxx> +#include <com/sun/star/uno/RuntimeException.hpp> + + +using namespace ::sd::slidesorter; + +namespace sd { namespace slidesorter { namespace view { + +FontProvider* FontProvider::mpInstance = NULL; + +FontProvider& FontProvider::Instance (void) +{ + if (mpInstance == NULL) + { + ::osl::GetGlobalMutex aMutexFunctor; + ::osl::MutexGuard aGuard (aMutexFunctor()); + if (mpInstance == NULL) + { + // Create an instance of the class and register it at the + // SdGlobalResourceContainer so that it is eventually released. + FontProvider* pInstance = new FontProvider(); + SdGlobalResourceContainer::Instance().AddResource ( + ::std::auto_ptr<SdGlobalResource>(pInstance)); + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + mpInstance = pInstance; + } + } + else + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } + + // We throw an exception when for some strange reason no instance of + // this class exists. + if (mpInstance == NULL) + throw ::com::sun::star::uno::RuntimeException(::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("com.sun.star.document.IndexedPropertyValues")), + NULL); + + return *mpInstance; +} + + + + +FontProvider::FontProvider (void) + : maFont(), + maMapMode() +{ +} + + + + +FontProvider::~FontProvider (void) +{ +} + + + + +void FontProvider::Invalidate (void) +{ + maFont.reset(); +} + + + + +FontProvider::SharedFontPointer FontProvider::GetFont (const OutputDevice& rDevice) +{ + // Reset the font when the map mode has changed since its creation. + if (maMapMode != rDevice.GetMapMode()) + maFont.reset(); + + if (maFont.get() == NULL) + { + // Initialize the font from the application style settings. + maFont.reset(new Font (Application::GetSettings().GetStyleSettings().GetAppFont())); + maFont->SetTransparent(TRUE); + maFont->SetWeight(WEIGHT_NORMAL); + + // Transform the point size to pixel size. + MapMode aFontMapMode (MAP_POINT); + Size aFontSize (rDevice.LogicToPixel(maFont->GetSize(), aFontMapMode)); + + // Transform the font size to the logical coordinates of the device. + maFont->SetSize (rDevice.PixelToLogic(aFontSize)); + + // Remember the map mode of the given device to detect different + // devices or modified zoom scales on future calls. + maMapMode = rDevice.GetMapMode(); + } + + return maFont; +} + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsLayouter.cxx b/sd/source/ui/slidesorter/view/SlsLayouter.cxx new file mode 100644 index 000000000000..1ba44caa24b0 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsLayouter.cxx @@ -0,0 +1,813 @@ +/************************************************************************* + * + * 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/SlsLayouter.hxx" + +#include <vcl/outdev.hxx> +#include <rtl/math.hxx> + +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) +{ +} + + + + +Layouter::~Layouter (void) +{ +} + + +void Layouter::SetObjectWidth ( + sal_Int32 nMinimalWidth, + sal_Int32 nMaximalWidth, + sal_Int32 nPreferredWidth) +{ + if (nMinimalWidth <= nPreferredWidth && nPreferredWidth <= nMaximalWidth) + { + mnMinimalWidth = nMinimalWidth; + mnPreferredWidth = nMaximalWidth; + mnMaximalWidth = nPreferredWidth; + } +} + + + + +void Layouter::SetBorders ( + sal_Int32 nLeftBorder, + sal_Int32 nRightBorder, + sal_Int32 nTopBorder, + sal_Int32 nBottomBorder) +{ + if (nLeftBorder >= 0) + mnRequestedLeftBorder.mnScreen = nLeftBorder; + if (nRightBorder >= 0) + mnRequestedRightBorder.mnScreen = nRightBorder; + if (nTopBorder >= 0) + mnRequestedTopBorder.mnScreen = nTopBorder; + if (nBottomBorder >= 0) + mnRequestedBottomBorder.mnScreen = nBottomBorder; +} + + + + +void Layouter::SetPageBorders ( + sal_Int32 nLeftBorder, + sal_Int32 nRightBorder, + sal_Int32 nTopBorder, + sal_Int32 nBottomBorder) +{ + if (nLeftBorder >= 0) + mnLeftPageBorder.mnScreen = nLeftBorder; + if (nRightBorder >= 0) + mnRightPageBorder.mnScreen = nRightBorder; + if (nTopBorder >= 0) + mnTopPageBorder.mnScreen = nTopBorder; + if (nBottomBorder >= 0) + mnBottomPageBorder.mnScreen = nBottomBorder; +} + + + + +void Layouter::SetGaps ( + sal_Int32 nHorizontalGap, + sal_Int32 nVerticalGap) +{ + if (nHorizontalGap >= 0) + mnHorizontalGap.mnScreen = nHorizontalGap; + if (nVerticalGap >= 0) + mnVerticalGap.mnScreen = nVerticalGap; +} + + + + + +void Layouter::SetColumnCount ( + sal_Int32 nMinimalColumnCount, + sal_Int32 nMaximalColumnCount) +{ + if (nMinimalColumnCount <= nMaximalColumnCount) + { + mnMinimalColumnCount = nMinimalColumnCount; + mnMaximalColumnCount = nMaximalColumnCount; + } +} + + + + +bool Layouter::RearrangeHorizontal ( + const Size& rWindowSize, + const Size& rPageObjectSize, + OutputDevice* pDevice, + 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; + } + + // 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; +} + + + + +bool Layouter::RearrangeVertical ( + const Size& rWindowSize, + const Size& rPageObjectSize, + OutputDevice* pDevice) +{ + 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; +} + + + + +void Layouter::SetZoom (double nZoomFactor, OutputDevice* pDevice) +{ + SetZoom(Fraction(nZoomFactor), pDevice); +} + + + + +void Layouter::SetZoom (Fraction nZoomFactor, OutputDevice* pDevice) +{ + MapMode aMapMode (pDevice->GetMapMode()); + aMapMode.SetScaleX (nZoomFactor); + aMapMode.SetScaleY (nZoomFactor); + maPageObjectPixelSize = pDevice->LogicToPixel (maPageObjectModelSize); + pDevice->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(); + + 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::GetColumnCount (void) const +{ + return mnColumnCount; +} + + + + +bool Layouter::IsColumnCountFixed (void) const +{ + return mnMinimalColumnCount == mnMaximalColumnCount; +} + + + + +Size Layouter::GetPageObjectSize (void) const +{ + return maPageObjectModelSize; +} + + + + +Rectangle Layouter::GetPageObjectBox (sal_Int32 nIndex) 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); +} + + + + +Rectangle Layouter::GetPageBox (sal_Int32 nObjectCount) 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 Rectangle ( + Point(0,0), + Size (nHorizontalSize, nVerticalSize) + ); +} + + + + +Rectangle Layouter::GetInsertionMarkerBox ( + sal_Int32 nIndex, + bool bVertical, + bool bLeftOrTop) const +{ + Rectangle aBox (GetPageObjectBox (nIndex)); + + 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; +} + + + + +sal_Int32 Layouter::GetIndexOfFirstVisiblePageObject ( + const Rectangle& aVisibleArea) const +{ + sal_Int32 nRow = GetRowAtPosition (aVisibleArea.Top(), true, GM_BOTH); + return nRow * mnColumnCount; +} + + + + +sal_Int32 Layouter::GetIndexOfLastVisiblePageObject ( + const Rectangle& aVisibleArea) const +{ + sal_Int32 nRow = GetRowAtPosition (aVisibleArea.Bottom(), + true, GM_BOTH); + return (nRow+1) * mnColumnCount - 1; +} + + + + +sal_Int32 Layouter::GetIndexAtPoint ( + const Point& rPosition, + bool bIncludePageBorders) 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; +} + + + + +/** 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. + + 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 +{ + sal_Int32 nIndex = -1; + + 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::DoublePoint + Layouter::ConvertModelToLayouterCoordinates ( + const Point& rModelPoint) const +{ + 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)); +} + + + + +Point Layouter::ConvertLayouterToModelCoordinates ( + const DoublePoint & rLayouterPoint) const +{ + 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); + + 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 Point ( + mnLeftBorder.mnModel + mnLeftPageBorder.mnModel + + nColumn * nColumnWidth + nDistanceIntoColumn, + mnTopBorder.mnModel + mnTopPageBorder.mnModel + + nRow * nRowHeight + nDistanceIntoRow); +} + + + + +sal_Int32 Layouter::GetRowAtPosition ( + sal_Int32 nYPosition, + bool bIncludeBordersAndGaps, + GapMembership eGapMembership) const +{ + sal_Int32 nRow = -1; + + const sal_Int32 nY = nYPosition + - mnTopBorder.mnModel - mnTopPageBorder.mnModel; + if (nY >= 0) + { + // Vertical distance from one row to the next. + const sal_Int32 nRowOffset ( + maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel); + + // Calculate row consisting of page objects and gap below. + nRow = nY / nRowOffset; + + const sal_Int32 nDistanceIntoGap ( + (nY - nRow*nRowOffset) - maPageObjectModelSize.Height()); + // When inside the gap below then nYPosition is not over a page + // object. + if (nDistanceIntoGap > 0) + nRow = ResolvePositionInGap ( + nDistanceIntoGap, + eGapMembership, + nRow, + mnBottomPageBorder.mnModel, + mnVerticalGap.mnModel); + } + else if (bIncludeBordersAndGaps) + { + // We are in the top border area. Set nRow to the first row when + // the top border shall be considered to belong to the first row. + nRow = 0; + } + + return nRow; +} + + + + +sal_Int32 Layouter::GetColumnAtPosition ( + sal_Int32 nXPosition, + bool bIncludeBordersAndGaps, + GapMembership eGapMembership) const +{ + sal_Int32 nColumn = -1; + + sal_Int32 nX = nXPosition + - mnLeftBorder.mnModel - mnLeftPageBorder.mnModel; + if (nX >= 0) + { + // Horizontal distance from one column to the next. + const sal_Int32 nColumnOffset ( + maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel); + + // Calculate row consisting of page objects and gap below. + nColumn = nX / nColumnOffset; + if (nColumn < 0) + nColumn = 0; + else if (nColumn >= mnColumnCount) + nColumn = mnColumnCount-1; + + const sal_Int32 nDistanceIntoGap ( + (nX - nColumn*nColumnOffset) - maPageObjectModelSize.Width()); + // When inside the gap at the right then nXPosition is not over a + // page object. + if (nDistanceIntoGap > 0) + nColumn = ResolvePositionInGap ( + nDistanceIntoGap, + eGapMembership, + nColumn, + mnRightPageBorder.mnModel, + mnHorizontalGap.mnModel); + } + else if (bIncludeBordersAndGaps) + { + // We are in the left border area. Set nColumn to the first column + // when the left border shall be considered to belong to the first + // column. + nColumn = 0; + } + return nColumn; +} + + + + +sal_Int32 Layouter::ResolvePositionInGap ( + sal_Int32 nDistanceIntoGap, + GapMembership eGapMembership, + sal_Int32 nIndex, + sal_Int32 nLeftOrTopPageBorder, + sal_Int32 nGap) const +{ + switch (eGapMembership) + { + case GM_NONE: + // The gap is no man's land. + nIndex = -1; + break; + + case GM_BOTH: + { + // The lower half of the gap belongs to the next row or column. + sal_Int32 nFirstHalfGapWidth = nLeftOrTopPageBorder + nGap / 2; + if (nDistanceIntoGap > nFirstHalfGapWidth) + nIndex ++; + break; + } + + case GM_PREVIOUS: + // Row or column already at correct value. + break; + + case GM_NEXT: + // The complete gap belongs to the next row or column. + nIndex ++; + break; + + case GM_PAGE_BORDER: + if (nDistanceIntoGap > nLeftOrTopPageBorder) + { + if (nDistanceIntoGap > nLeftOrTopPageBorder + nGap) + { + // Inside the border of the next row or column. + nIndex ++; + } + else + { + // Inside the gap between the page borders. + nIndex = -1; + } + } + break; + + default: + nIndex = -1; + } + + return nIndex; +} + + + + +const Layouter::BackgroundRectangleList& + Layouter::GetBackgroundRectangleList (void) const +{ + return maBackgroundRectangleList; +} + + + + +} } } // end of namespace ::sd::slidesorter::namespace diff --git a/sd/source/ui/slidesorter/view/SlsPageObject.cxx b/sd/source/ui/slidesorter/view/SlsPageObject.cxx new file mode 100644 index 000000000000..28c572de9594 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsPageObject.cxx @@ -0,0 +1,80 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "view/SlsPageObject.hxx" + +#include "model/SlsPageDescriptor.hxx" +#include "controller/SlsPageObjectFactory.hxx" + +using namespace ::sdr::contact; +using namespace ::sd::slidesorter::model; + + +namespace sd { namespace slidesorter { namespace view { + + +PageObject::PageObject ( + const Rectangle& rRectangle, + SdrPage* _pPage, + const SharedPageDescriptor& rpDescriptor) + : SdrPageObj(rRectangle, _pPage), + mpDescriptor(rpDescriptor) +{ +} + + + + +PageObject::~PageObject (void) +{ +} + + + + +SharedPageDescriptor PageObject::GetDescriptor (void) const +{ + return mpDescriptor; +} + + + + +sdr::contact::ViewContact* PageObject::CreateObjectSpecificViewContact() +{ + if (mpDescriptor.get() != NULL) + return mpDescriptor->GetPageObjectFactory().CreateViewContact(this, mpDescriptor); + else + return NULL; +} + + + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectViewContact.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectViewContact.cxx new file mode 100644 index 000000000000..5ef90ad2830b --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsPageObjectViewContact.cxx @@ -0,0 +1,140 @@ +/************************************************************************* + * + * 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(); +} + +Rectangle PageObjectViewContact::GetPageObjectBoundingBox (void) const +{ + // use model data directly here + OSL_ASSERT(mpDescriptor.get()!=NULL); + Rectangle aRetval(GetPageObject().GetLastBoundRect()); + const SvBorder aPageDescriptorBorder(mpDescriptor->GetModelBorder()); + + aRetval.Left() -= aPageDescriptorBorder.Left(); + aRetval.Top() -= aPageDescriptorBorder.Top(); + aRetval.Right() += aPageDescriptorBorder.Right(); + aRetval.Bottom() += aPageDescriptorBorder.Bottom(); + + return aRetval; +} + +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 new file mode 100755 index 000000000000..32098abb523f --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx @@ -0,0 +1,1419 @@ +/************************************************************************* + * + * 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; + const BitmapEx& getCommentsIconBitmap() 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; + +const BitmapEx& SdPageObjectFadeNameNumberPrimitive::getCommentsIconBitmap() const +{ + if(mpCommentsIconBitmap == NULL) + { + // prepare CommentsIconBitmap on demand + const sal_uInt16 nIconId(Application::GetSettings().GetStyleSettings().GetHighContrastMode() + ? BMP_COMMENTS_INDICATOR_H + : BMP_COMMENTS_INDICATOR); + const BitmapEx aCommentsIconBitmap(IconCache::Instance().GetIcon(nIconId).GetBitmapEx()); + const_cast< SdPageObjectFadeNameNumberPrimitive* >(this)->mpCommentsIconBitmap = new BitmapEx(aCommentsIconBitmap); + } + + return *mpCommentsIconBitmap; +} + +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/SlsViewCacheContext.cxx b/sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx new file mode 100644 index 000000000000..57872105e1cc --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx @@ -0,0 +1,167 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "precompiled_sd.hxx" + +#include "SlsViewCacheContext.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" +#include "tools/IdleDetection.hxx" +#include <svx/svdpage.hxx> +#include <svx/sdr/contact/viewcontact.hxx> +#include <vcl/window.hxx> +#include <svx/sdr/contact/objectcontact.hxx> + +namespace sd { namespace slidesorter { namespace view { + + +ViewCacheContext::ViewCacheContext ( + model::SlideSorterModel& rModel, + SlideSorterView& rView) + : mrModel(rModel), + mrView(rView) +{ +} + + + + +ViewCacheContext::~ViewCacheContext (void) +{ +} + + + + +void ViewCacheContext::NotifyPreviewCreation ( + cache::CacheKey aKey, + const ::boost::shared_ptr<BitmapEx>& rPreview) +{ + (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()); + } + else + { + OSL_ASSERT(pDescriptor.get() != NULL); + } +} + + + + +bool ViewCacheContext::IsIdle (void) +{ + sal_Int32 nIdleState (tools::IdleDetection::GetIdleState(mrView.GetWindow())); + if (nIdleState == tools::IdleDetection::IDET_IDLE) + return true; + else + return false; +} + + + + +bool ViewCacheContext::IsVisible (cache::CacheKey aKey) +{ + return GetDescriptor(aKey)->IsVisible(); +} + + + + +const SdrPage* ViewCacheContext::GetPage (cache::CacheKey aKey) +{ + return static_cast<const SdrPage*>(aKey); +} + + + + +::boost::shared_ptr<std::vector<cache::CacheKey> > ViewCacheContext::GetEntryList (bool bVisible) +{ + ::boost::shared_ptr<std::vector<cache::CacheKey> > pKeys (new std::vector<cache::CacheKey>()); + + model::PageEnumeration aPageEnumeration ( + bVisible + ? model::PageEnumerationProvider::CreateVisiblePagesEnumeration(mrModel) + : model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + + while (aPageEnumeration.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement()); + pKeys->push_back(pDescriptor->GetPage()); + } + + return pKeys; +} + + + + +sal_Int32 ViewCacheContext::GetPriority (cache::CacheKey aKey) +{ + return - (static_cast<const SdrPage*>(aKey)->GetPageNum()-1) / 2; +} + + + + +model::SharedPageDescriptor ViewCacheContext::GetDescriptor (cache::CacheKey aKey) +{ + sal_uInt16 nPageIndex ((static_cast<const SdrPage*>(aKey)->GetPageNum() - 1) / 2); + return mrModel.GetPageDescriptor(nPageIndex); +} + + + + +::com::sun::star::uno::Reference<com::sun::star::uno::XInterface> ViewCacheContext::GetModel (void) +{ + if (mrModel.GetDocument() == NULL) + return NULL; + else + return mrModel.GetDocument()->getUnoModel(); +} + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx b/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx new file mode 100644 index 000000000000..e29b65068d1d --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx @@ -0,0 +1,70 @@ +/************************************************************************* + * + * 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_VIEW_CACHE_CONTEXT_HXX +#define SD_SLIDESORTER_VIEW_VIEW_CACHE_CONTEXT_HXX + +#include "cache/SlsCacheContext.hxx" +#include "model/SlsSharedPageDescriptor.hxx" + +namespace sd { namespace slidesorter { namespace model { +class SlideSorterModel; +} } } + +namespace sd { namespace slidesorter { namespace view { + +class SlideSorterView; + +/** The cache context for the SlideSorter as used by Draw and Impress. See + the base class for documentation of the individual methods. +*/ +class ViewCacheContext : public cache::CacheContext +{ +public: + ViewCacheContext ( + model::SlideSorterModel& rModel, + SlideSorterView& rView); + virtual ~ViewCacheContext (void); + virtual void NotifyPreviewCreation (cache::CacheKey aKey, const ::boost::shared_ptr<BitmapEx>& rPreview); + virtual bool IsIdle (void); + virtual bool IsVisible (cache::CacheKey aKey); + virtual const SdrPage* GetPage (cache::CacheKey aKey); + virtual ::boost::shared_ptr<std::vector<cache::CacheKey> > GetEntryList (bool bVisible); + virtual sal_Int32 GetPriority (cache::CacheKey aKey); + virtual ::com::sun::star::uno::Reference<com::sun::star::uno::XInterface> GetModel (void); + +private: + model::SlideSorterModel& mrModel; + SlideSorterView& mrView; + + model::SharedPageDescriptor GetDescriptor (cache::CacheKey aKey); +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/view/SlsViewOverlay.cxx b/sd/source/ui/slidesorter/view/SlsViewOverlay.cxx new file mode 100644 index 000000000000..32576240036c --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsViewOverlay.cxx @@ -0,0 +1,606 @@ +/************************************************************************* + * + * 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 new file mode 100644 index 000000000000..388139b1cee9 --- /dev/null +++ b/sd/source/ui/slidesorter/view/makefile.mk @@ -0,0 +1,61 @@ +#************************************************************************* +# +# 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. +# +#************************************************************************* + +PRJ=..$/..$/..$/.. + +PROJECTPCH=sd +PROJECTPCHSOURCE=$(PRJ)$/util$/sd +PRJNAME=sd +TARGET=slsview +ENABLE_EXCEPTIONS=TRUE +AUTOSEG=true +PRJINC=..$/.. + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- 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 + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + |