summaryrefslogtreecommitdiff
path: root/sd/source/ui/slidesorter/view
diff options
context:
space:
mode:
Diffstat (limited to 'sd/source/ui/slidesorter/view')
-rw-r--r--sd/source/ui/slidesorter/view/SlideSorterView.cxx846
-rw-r--r--sd/source/ui/slidesorter/view/SlsFontProvider.cxx132
-rw-r--r--sd/source/ui/slidesorter/view/SlsLayouter.cxx813
-rw-r--r--sd/source/ui/slidesorter/view/SlsPageObject.cxx80
-rw-r--r--sd/source/ui/slidesorter/view/SlsPageObjectViewContact.cxx140
-rwxr-xr-xsd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx1419
-rw-r--r--sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx167
-rw-r--r--sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx70
-rw-r--r--sd/source/ui/slidesorter/view/SlsViewOverlay.cxx606
-rw-r--r--sd/source/ui/slidesorter/view/makefile.mk61
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
+