summaryrefslogtreecommitdiff
path: root/sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx')
-rwxr-xr-xsd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx1403
1 files changed, 1403 insertions, 0 deletions
diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx
new file mode 100755
index 000000000000..b1e4e80fdf1f
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx
@@ -0,0 +1,1403 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_sd.hxx"
+
+#include "view/SlsPageObjectViewObjectContact.hxx"
+
+#include "controller/SlsProperties.hxx"
+#include "view/SlideSorterView.hxx"
+#include "view/SlsPageObjectViewContact.hxx"
+#include "view/SlsPageObject.hxx"
+#include "view/SlsFontProvider.hxx"
+#include "model/SlsPageDescriptor.hxx"
+#include "cache/SlsPageCache.hxx"
+#include "cache/SlsPageCacheManager.hxx"
+#include "res_bmp.hrc"
+#include "tools/IconCache.hxx"
+#include "PreviewRenderer.hxx"
+
+#include "sdpage.hxx"
+#include "sdresid.hxx"
+#include "glob.hrc"
+#include "drawdoc.hxx"
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/svdopage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/lineinfo.hxx>
+#include <tools/color.hxx>
+#include <boost/shared_ptr.hpp>
+#include <com/sun/star/uno/Exception.hpp>
+#include <vcl/svapp.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::sdr::contact;
+using namespace ::sd::slidesorter::model;
+
+using drawinglayer::primitive2d::Primitive2DReference;
+using drawinglayer::primitive2d::Primitive2DSequence;
+
+namespace sd { namespace slidesorter { namespace view {
+
+
+const sal_Int32 PageObjectViewObjectContact::mnSelectionIndicatorOffset = 2;
+const sal_Int32 PageObjectViewObjectContact::mnSelectionIndicatorThickness = 3;
+const sal_Int32 PageObjectViewObjectContact::mnFocusIndicatorOffset = 3;
+const sal_Int32 PageObjectViewObjectContact::mnFadeEffectIndicatorOffset = 9;
+const sal_Int32 PageObjectViewObjectContact::mnFadeEffectIndicatorSize = 14;
+const sal_Int32 PageObjectViewObjectContact::mnPageNumberOffset = 9;
+const sal_Int32 PageObjectViewObjectContact::mnMouseOverEffectOffset = 3;
+const sal_Int32 PageObjectViewObjectContact::mnMouseOverEffectThickness = 1;
+
+PageObjectViewObjectContact::PageObjectViewObjectContact (
+ ObjectContact& rObjectContact,
+ ViewContact& rViewContact,
+ const ::boost::shared_ptr<cache::PageCache>& rpCache,
+ const ::boost::shared_ptr<controller::Properties>& rpProperties)
+ : ViewObjectContactOfPageObj(rObjectContact, rViewContact),
+ mbInDestructor(false),
+ mxCurrentPageContents(),
+ mpCache(rpCache),
+ mpProperties(rpProperties)
+{
+ SharedPageDescriptor pDescriptor (GetPageDescriptor());
+ OSL_ASSERT(pDescriptor.get()!=NULL);
+ if (pDescriptor.get() != NULL)
+ pDescriptor->SetViewObjectContact(this);
+}
+
+
+
+
+PageObjectViewObjectContact::~PageObjectViewObjectContact (void)
+{
+ mbInDestructor = true;
+
+ GetPageDescriptor()->SetViewObjectContact(NULL);
+
+ if (mpCache.get() != NULL)
+ {
+ const SdrPage* pPage = GetPage();
+
+ if(pPage)
+ {
+ mpCache->ReleasePreviewBitmap(GetPage());
+ }
+ }
+}
+
+
+
+
+void PageObjectViewObjectContact::SetCache (const ::boost::shared_ptr<cache::PageCache>& rpCache)
+{
+ mpCache = rpCache;
+}
+
+
+
+
+Rectangle PageObjectViewObjectContact::GetBoundingBox (
+ OutputDevice& rDevice,
+ BoundingBoxType eType,
+ CoordinateSystem eCoordinateSystem) const
+{
+ // Most of the bounding boxes are based on the bounding box of the preview.
+ // SdrPageObj is a SdrObject, so use SdrObject::aOutRect as model data
+ const PageObjectViewContact& rPaObVOC(static_cast<PageObjectViewContact&>(GetViewContact()));
+ Rectangle aBoundingBox(rPaObVOC.GetPageObject().GetLastBoundRect());
+
+ CoordinateSystem eCurrentCoordinateSystem (ModelCoordinateSystem);
+ switch(eType)
+ {
+ case PageObjectBoundingBox:
+ {
+ const SvBorder aPageDescriptorBorder(GetPageDescriptor()->GetModelBorder());
+ aBoundingBox.Left() -= aPageDescriptorBorder.Left();
+ aBoundingBox.Top() -= aPageDescriptorBorder.Top();
+ aBoundingBox.Right() += aPageDescriptorBorder.Right();
+ aBoundingBox.Bottom() += aPageDescriptorBorder.Bottom();
+ break;
+ }
+ case PreviewBoundingBox:
+ {
+ // The aBoundingBox already has the right value.
+ break;
+ }
+ case MouseOverIndicatorBoundingBox:
+ {
+ const sal_Int32 nBorderWidth (mnMouseOverEffectOffset+mnMouseOverEffectThickness);
+ const Size aBorderSize (rDevice.PixelToLogic(Size(nBorderWidth,nBorderWidth)));
+ aBoundingBox.Left() -= aBorderSize.Width();
+ aBoundingBox.Top() -= aBorderSize.Height();
+ aBoundingBox.Right() += aBorderSize.Width();
+ aBoundingBox.Bottom() += aBorderSize.Height();
+ break;
+ }
+ case FocusIndicatorBoundingBox:
+ {
+ const sal_Int32 nBorderWidth (mnFocusIndicatorOffset+1);
+ const Size aBorderSize (rDevice.PixelToLogic(Size(nBorderWidth,nBorderWidth)));
+ aBoundingBox.Left() -= aBorderSize.Width();
+ aBoundingBox.Top() -= aBorderSize.Height();
+ aBoundingBox.Right() += aBorderSize.Width();
+ aBoundingBox.Bottom() += aBorderSize.Height();
+ break;
+ }
+ case SelectionIndicatorBoundingBox:
+ {
+ const sal_Int32 nBorderWidth(mnSelectionIndicatorOffset+mnSelectionIndicatorThickness);
+ const Size aBorderSize (rDevice.PixelToLogic(Size(nBorderWidth,nBorderWidth)));
+ aBoundingBox.Left() -= aBorderSize.Width();
+ aBoundingBox.Top() -= aBorderSize.Height();
+ aBoundingBox.Right() += aBorderSize.Width();
+ aBoundingBox.Bottom() += aBorderSize.Height();
+ break;
+ }
+ case PageNumberBoundingBox:
+ {
+ Size aModelOffset = rDevice.PixelToLogic(Size(mnPageNumberOffset,mnPageNumberOffset));
+ Size aNumberSize (GetPageDescriptor()->GetPageNumberAreaModelSize());
+ aBoundingBox = Rectangle (
+ Point (
+ aBoundingBox.Left() - aModelOffset.Width() - aNumberSize.Width(),
+ aBoundingBox.Top()),
+ aNumberSize);
+ break;
+ }
+
+ case NameBoundingBox:
+ break;
+
+ case FadeEffectIndicatorBoundingBox:
+ Size aModelOffset = rDevice.PixelToLogic(Size (0, mnFadeEffectIndicatorOffset));
+ // Flush left just outside the selection rectangle.
+ aBoundingBox = Rectangle (
+ Point (
+ aBoundingBox.Left(),
+ aBoundingBox.Bottom() + aModelOffset.Height()
+ ),
+ rDevice.PixelToLogic (
+ IconCache::Instance().GetIcon(BMP_FADE_EFFECT_INDICATOR).GetSizePixel())
+ );
+ break;
+ }
+
+ // Make sure the bounding box uses the requested coordinate system.
+ if (eCurrentCoordinateSystem != eCoordinateSystem)
+ {
+ if (eCoordinateSystem == ModelCoordinateSystem)
+ aBoundingBox = Rectangle(
+ rDevice.PixelToLogic(aBoundingBox.TopLeft()),
+ rDevice.PixelToLogic(aBoundingBox.GetSize()));
+ else
+ aBoundingBox = Rectangle(
+ rDevice.LogicToPixel(aBoundingBox.TopLeft()),
+ rDevice.LogicToPixel(aBoundingBox.GetSize()));
+ }
+ return aBoundingBox;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// example implementation for primitive usage for PageObjectViewObjectContact
+
+} } } // end of namespace ::sd::slidesorter::view
+
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <sd_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+
+namespace sd { namespace slidesorter { namespace view {
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// All primitives for SdrPageObject visualisation are based on one range which describes
+// the size of the inner rectangle for PagePreview visualisation. Use a common implementation
+// class for all derived SdPageObjectPrimitives. The SdPageObjectBasePrimitive itself
+// is pure virtual
+
+class SdPageObjectBasePrimitive : public drawinglayer::primitive2d::BufferedDecompositionPrimitive2D
+{
+private:
+ // the inner range of the SdPageObject visualisation
+ basegfx::B2DRange maRange;
+
+public:
+ // constructor and destructor
+ SdPageObjectBasePrimitive(const basegfx::B2DRange& rRange);
+ virtual ~SdPageObjectBasePrimitive();
+
+ // data access
+ const basegfx::B2DRange& getPageObjectRange() const { return maRange; }
+
+ // compare operator
+ virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const;
+};
+
+SdPageObjectBasePrimitive::SdPageObjectBasePrimitive(const basegfx::B2DRange& rRange)
+: drawinglayer::primitive2d::BufferedDecompositionPrimitive2D(),
+ maRange(rRange)
+{
+}
+
+SdPageObjectBasePrimitive::~SdPageObjectBasePrimitive()
+{
+}
+
+bool SdPageObjectBasePrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const
+{
+ if(drawinglayer::primitive2d::BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdPageObjectBasePrimitive& rCompare = static_cast< const SdPageObjectBasePrimitive& >(rPrimitive);
+ return (getPageObjectRange() == rCompare.getPageObjectRange());
+ }
+
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// SdPageObjectPrimitive for selected visualisation
+
+class SdPageObjectPageBitmapPrimitive : public SdPageObjectBasePrimitive
+{
+private:
+ // the bitmap containing the PagePreview
+ BitmapEx maBitmapEx;
+
+protected:
+ // method which is to be used to implement the local decomposition of a 2D primitive.
+ virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
+
+public:
+ // constructor and destructor
+ SdPageObjectPageBitmapPrimitive(
+ const basegfx::B2DRange& rRange,
+ const BitmapEx& rBitmapEx);
+ ~SdPageObjectPageBitmapPrimitive();
+
+ // data access
+ const BitmapEx& getBitmapEx() const { return maBitmapEx; }
+
+ // compare operator
+ virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const;
+
+ // provide unique ID
+ DeclPrimitrive2DIDBlock()
+};
+
+Primitive2DSequence SdPageObjectPageBitmapPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const
+{
+ // add bitmap primitive
+ // to avoid scaling, use the Bitmap pixel size as primitive size
+ basegfx::B2DHomMatrix aBitmapTransform;
+ const Size aBitmapSize(getBitmapEx().GetSizePixel());
+ const basegfx::B2DVector aBitmapSizeLogic(rViewInformation.getInverseObjectToViewTransformation() *
+ basegfx::B2DVector(aBitmapSize.getWidth() - 1, aBitmapSize.getHeight() - 1));
+
+ // short form for scale and translate transformation
+ aBitmapTransform.set(0L, 0L, aBitmapSizeLogic.getX());
+ aBitmapTransform.set(1L, 1L, aBitmapSizeLogic.getY());
+ aBitmapTransform.set(0L, 2L, getPageObjectRange().getMinX());
+ aBitmapTransform.set(1L, 2L, getPageObjectRange().getMinY());
+
+ // add a BitmapPrimitive2D to the result
+ const Primitive2DReference xReference(
+ new drawinglayer::primitive2d::BitmapPrimitive2D(getBitmapEx(), aBitmapTransform));
+ return Primitive2DSequence(&xReference, 1);
+}
+
+SdPageObjectPageBitmapPrimitive::SdPageObjectPageBitmapPrimitive(
+ const basegfx::B2DRange& rRange,
+ const BitmapEx& rBitmapEx)
+: SdPageObjectBasePrimitive(rRange),
+ maBitmapEx(rBitmapEx)
+{
+}
+
+SdPageObjectPageBitmapPrimitive::~SdPageObjectPageBitmapPrimitive()
+{
+}
+
+bool SdPageObjectPageBitmapPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const
+{
+ if(SdPageObjectBasePrimitive::operator==(rPrimitive))
+ {
+ const SdPageObjectPageBitmapPrimitive& rCompare = static_cast< const SdPageObjectPageBitmapPrimitive& >(rPrimitive);
+ return (getBitmapEx() == rCompare.getBitmapEx());
+ }
+
+ return false;
+}
+
+ImplPrimitrive2DIDBlock(SdPageObjectPageBitmapPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTPAGEBITMAPPRIMITIVE)
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// SdPageObjectPrimitive for selected visualisation
+
+class SdPageObjectSelectPrimitive : public SdPageObjectBasePrimitive
+{
+private:
+ /// Gap between border of page object and inside of selection rectangle.
+ static const sal_Int32 mnSelectionIndicatorOffset;
+
+ /// Thickness of the selection rectangle.
+ static const sal_Int32 mnSelectionIndicatorThickness;
+
+protected:
+ // method which is to be used to implement the local decomposition of a 2D primitive.
+ virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
+
+public:
+ // constructor and destructor
+ SdPageObjectSelectPrimitive(const basegfx::B2DRange& rRange);
+ ~SdPageObjectSelectPrimitive();
+
+ // provide unique ID
+ DeclPrimitrive2DIDBlock()
+};
+
+const sal_Int32 SdPageObjectSelectPrimitive::mnSelectionIndicatorOffset(1);
+const sal_Int32 SdPageObjectSelectPrimitive::mnSelectionIndicatorThickness(3);
+
+Primitive2DSequence SdPageObjectSelectPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const
+{
+ Primitive2DSequence xRetval(2);
+
+ // since old Width/Height calculations always added a single pixel value,
+ // it is necessary to create a inner range which is one display unit less
+ // at the bottom right.
+ const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
+ const basegfx::B2DRange aAdaptedInnerRange(
+ getPageObjectRange().getMinX(), getPageObjectRange().getMinY(),
+ getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY());
+
+ // PaintSelectionIndicator replacement. Grow by offset first
+ basegfx::B2DRange aDiscreteOuterRange(aAdaptedInnerRange);
+ aDiscreteOuterRange.grow(mnSelectionIndicatorOffset * aDiscretePixel.getX());
+
+ // Remember inner border. Make it one bigger in top left since polygons
+ // do not paint their lower-right corners. Since this is the inner polygon,
+ // the top-left corders are the ones to grow here
+ const basegfx::B2DRange aDiscreteInnerRange(
+ aDiscreteOuterRange.getMinimum() + aDiscretePixel,
+ aDiscreteOuterRange.getMaximum() - aDiscretePixel);
+
+ // grow by line width
+ aDiscreteOuterRange.grow((mnSelectionIndicatorThickness - 1) * aDiscretePixel.getX());
+
+ // create a PolyPolygon from those ranges. For the outer polygon, round edges by
+ // giving a relative radius to the polygon creator (use mnSelectionIndicatorThickness here, too)
+ const double fPixelFactor(aDiscretePixel.getX() * (mnSelectionIndicatorThickness + 2.5));
+ const double fRelativeRadiusX(fPixelFactor / ::std::max(aDiscreteOuterRange.getWidth(), 1.0));
+ const double fRelativeRadiusY(fPixelFactor / ::std::max(aDiscreteOuterRange.getHeight(), 1.0));
+ basegfx::B2DPolyPolygon aFramePolyPolygon;
+ const basegfx::B2DPolygon aRoundedOuterPolygon(basegfx::tools::createPolygonFromRect(aDiscreteOuterRange, fRelativeRadiusX, fRelativeRadiusY));
+
+ aFramePolyPolygon.append(aRoundedOuterPolygon);
+ aFramePolyPolygon.append(basegfx::tools::createPolygonFromRect(aDiscreteInnerRange));
+
+ // add colored PolyPolygon
+ const svtools::ColorConfig aColorConfig;
+ static bool bTestWithBrightColors(false);
+ const basegfx::BColor aFrameColor(bTestWithBrightColors ? basegfx::BColor(0,1,0) : Application::GetSettings().GetStyleSettings().GetMenuHighlightColor().getBColor());
+
+ xRetval[0] = Primitive2DReference(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(aFramePolyPolygon, aFrameColor));
+
+ // add aRoundedOuterPolygon again as non-filled line polygon to get the roundungs
+ // painted correctly
+ xRetval[1] = Primitive2DReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aRoundedOuterPolygon, aFrameColor));
+
+ return xRetval;
+}
+
+SdPageObjectSelectPrimitive::SdPageObjectSelectPrimitive(const basegfx::B2DRange& rRange)
+: SdPageObjectBasePrimitive(rRange)
+{
+}
+
+SdPageObjectSelectPrimitive::~SdPageObjectSelectPrimitive()
+{
+}
+
+ImplPrimitrive2DIDBlock(SdPageObjectSelectPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTSELECTPRIMITIVE)
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// SdPageObjectPrimitive for border around bitmap visualisation
+
+class SdPageObjectBorderPrimitive : public SdPageObjectBasePrimitive
+{
+protected:
+ // method which is to be used to implement the local decomposition of a 2D primitive.
+ virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
+
+public:
+ // constructor and destructor
+ SdPageObjectBorderPrimitive(const basegfx::B2DRange& rRange);
+ ~SdPageObjectBorderPrimitive();
+
+ // provide unique ID
+ DeclPrimitrive2DIDBlock()
+};
+
+Primitive2DSequence SdPageObjectBorderPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const
+{
+ // since old Width/Height calculations always added a single pixel value,
+ // it is necessary to create a inner range which is one display unit less
+ // at the bottom right.
+ const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
+ const basegfx::B2DRange aAdaptedInnerRange(
+ getPageObjectRange().getMinX(), getPageObjectRange().getMinY(),
+ getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY());
+
+ // Paint_Border replacement. (use aBorderColor)
+ static bool bTestWithBrightColors(false);
+ const svtools::ColorConfig aColorConfig;
+ const basegfx::BColor aBorderColor(bTestWithBrightColors ? basegfx::BColor(1,0,0) : Color(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor).getBColor());
+
+ const Primitive2DReference xReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(basegfx::tools::createPolygonFromRect(aAdaptedInnerRange), aBorderColor));
+ return Primitive2DSequence(&xReference, 1);
+}
+
+SdPageObjectBorderPrimitive::SdPageObjectBorderPrimitive(const basegfx::B2DRange& rRange)
+: SdPageObjectBasePrimitive(rRange)
+{
+}
+
+SdPageObjectBorderPrimitive::~SdPageObjectBorderPrimitive()
+{
+}
+
+ImplPrimitrive2DIDBlock(SdPageObjectBorderPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTBORDERPRIMITIVE)
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// SdPageObjectPrimitive for focus visualisation
+
+class SdPageObjectFocusPrimitive : public SdPageObjectBasePrimitive
+{
+private:
+ /// Gap between border of page object and inside of focus rectangle.
+ static const sal_Int32 mnFocusIndicatorOffset;
+ const bool mbContrastToSelected;
+
+protected:
+ // method which is to be used to implement the local decomposition of a 2D primitive.
+ virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
+
+public:
+ // constructor and destructor
+ SdPageObjectFocusPrimitive(const basegfx::B2DRange& rRange, const bool bContrast);
+ ~SdPageObjectFocusPrimitive();
+
+ // provide unique ID
+ DeclPrimitrive2DIDBlock()
+};
+
+const sal_Int32 SdPageObjectFocusPrimitive::mnFocusIndicatorOffset(2);
+
+Primitive2DSequence SdPageObjectFocusPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const
+{
+ Primitive2DSequence xRetval(2);
+
+ // since old Width/Height calculations always added a single pixel value,
+ // it is necessary to create a inner range which is one display unit less
+ // at the bottom right.
+ const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
+ const basegfx::B2DRange aAdaptedInnerRange(
+ getPageObjectRange().getMinX(), getPageObjectRange().getMinY(),
+ getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY());
+
+ // Paint_FocusIndicator replacement. (black and white).
+ // imitate Paint_DottedRectangle: First paint a white rectangle and above it a black dotted one
+ basegfx::B2DRange aFocusIndicatorRange(aAdaptedInnerRange);
+ aFocusIndicatorRange.grow(mnFocusIndicatorOffset * aDiscretePixel.getX());
+
+ // create polygon
+ const basegfx::B2DPolygon aIndicatorPolygon(basegfx::tools::createPolygonFromRect(aFocusIndicatorRange));
+
+ const StyleSettings& rStyleSettings(Application::GetSettings().GetStyleSettings());
+
+ // "background" rectangle
+ const Color aBackgroundColor(mbContrastToSelected ? rStyleSettings.GetMenuHighlightColor() : rStyleSettings.GetWindowColor());
+ xRetval[0] = Primitive2DReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aIndicatorPolygon, Color(COL_WHITE).getBColor()));
+
+ // dotted black rectangle with same geometry
+ ::std::vector< double > aDotDashArray;
+
+ const sal_Int32 nFocusIndicatorWidth (3);
+ aDotDashArray.push_back(nFocusIndicatorWidth *aDiscretePixel.getX());
+ aDotDashArray.push_back(nFocusIndicatorWidth * aDiscretePixel.getX());
+
+ // prepare line and stroke attributes
+ const Color aLineColor(mbContrastToSelected ? rStyleSettings.GetMenuHighlightTextColor() : rStyleSettings.GetWindowTextColor());
+ const drawinglayer::attribute::LineAttribute aLineAttribute(aLineColor.getBColor());
+ const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(
+ aDotDashArray, 2.0 * nFocusIndicatorWidth * aDiscretePixel.getX());
+
+
+ xRetval[1] = Primitive2DReference(
+ new drawinglayer::primitive2d::PolygonStrokePrimitive2D(aIndicatorPolygon, aLineAttribute, aStrokeAttribute));
+
+ return xRetval;
+}
+
+SdPageObjectFocusPrimitive::SdPageObjectFocusPrimitive(const basegfx::B2DRange& rRange, const bool bContrast)
+ : SdPageObjectBasePrimitive(rRange),
+ mbContrastToSelected(bContrast)
+{
+}
+
+SdPageObjectFocusPrimitive::~SdPageObjectFocusPrimitive()
+{
+}
+
+ImplPrimitrive2DIDBlock(SdPageObjectFocusPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTFOCUSPRIMITIVE)
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// SdPageObjectPrimitive for fade effect visualisation
+
+class SdPageObjectFadeNameNumberPrimitive : public SdPageObjectBasePrimitive
+{
+private:
+ /// Size of width and height of the fade effect indicator in pixels.
+ static const sal_Int32 mnFadeEffectIndicatorOffset;
+
+ /// Size of width and height of the comments indicator in pixels.
+ static const sal_Int32 mnCommentsIndicatorOffset;
+
+ /// Gap between border of page object and number rectangle.
+ static const sal_Int32 mnPageNumberOffset;
+
+ /// the indicator bitmaps. Static since it is usable outside this primitive
+ /// for size comparisons
+ static BitmapEx* mpFadeEffectIconBitmap;
+ static BitmapEx* mpCommentsIconBitmap;
+
+ /// page name, number and needed infos
+ String maPageName;
+ sal_uInt32 mnPageNumber;
+ Font maPageNameFont;
+ Size maPageNumberAreaModelSize;
+
+ // bitfield
+ bool mbShowFadeEffectIcon : 1;
+ bool mbShowCommentsIcon : 1;
+ bool mbExcluded : 1;
+
+ // private helpers
+ const BitmapEx& getFadeEffectIconBitmap() const;
+
+protected:
+ // method which is to be used to implement the local decomposition of a 2D primitive.
+ virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
+
+public:
+ // constructor and destructor
+ SdPageObjectFadeNameNumberPrimitive(
+ const basegfx::B2DRange& rRange,
+ const String& rPageName,
+ sal_uInt32 nPageNumber,
+ const Font& rPageNameFont,
+ const Size& rPageNumberAreaModelSize,
+ bool bShowFadeEffectIcon,
+ bool bShowCommentsIcon,
+ bool bExcluded);
+ ~SdPageObjectFadeNameNumberPrimitive();
+
+ // data access
+ const String& getPageName() const { return maPageName; }
+ sal_uInt32 getPageNumber() const { return mnPageNumber; }
+ const Font& getPageNameFont() const { return maPageNameFont; }
+ const Size& getPageNumberAreaModelSize() const { return maPageNumberAreaModelSize; }
+ bool getShowFadeEffectIcon() const { return mbShowFadeEffectIcon; }
+ bool getShowCommentsIcon() const { return mbShowCommentsIcon; }
+ bool getExcluded() const { return mbExcluded; }
+
+ // compare operator
+ virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const;
+
+ // provide unique ID
+ DeclPrimitrive2DIDBlock()
+};
+
+const sal_Int32 SdPageObjectFadeNameNumberPrimitive::mnFadeEffectIndicatorOffset(9);
+const sal_Int32 SdPageObjectFadeNameNumberPrimitive::mnPageNumberOffset(9);
+BitmapEx* SdPageObjectFadeNameNumberPrimitive::mpFadeEffectIconBitmap = 0;
+
+const BitmapEx& SdPageObjectFadeNameNumberPrimitive::getFadeEffectIconBitmap() const
+{
+ if(mpFadeEffectIconBitmap == NULL)
+ {
+ // prepare FadeEffectIconBitmap on demand
+ const sal_uInt16 nIconId(Application::GetSettings().GetStyleSettings().GetHighContrastMode()
+ ? BMP_FADE_EFFECT_INDICATOR_H
+ : BMP_FADE_EFFECT_INDICATOR);
+ const BitmapEx aFadeEffectIconBitmap(IconCache::Instance().GetIcon(nIconId).GetBitmapEx());
+ const_cast< SdPageObjectFadeNameNumberPrimitive* >(this)->mpFadeEffectIconBitmap = new BitmapEx(aFadeEffectIconBitmap);
+ }
+
+ return *mpFadeEffectIconBitmap;
+}
+
+
+const sal_Int32 SdPageObjectFadeNameNumberPrimitive::mnCommentsIndicatorOffset(9);
+BitmapEx* SdPageObjectFadeNameNumberPrimitive::mpCommentsIconBitmap = 0;
+
+Primitive2DSequence SdPageObjectFadeNameNumberPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const
+{
+ const xub_StrLen nTextLength(getPageName().Len());
+ const sal_uInt32 nCount(
+ (getShowFadeEffectIcon() ? 1 : 0) + // FadeEffect icon
+ (nTextLength ? 1 : 0) + // PageName
+ 1 + // PageNumber (always)
+ (getExcluded() ? 2 : 0) // PageNumber crossed out
+ );
+ sal_uInt32 nInsert(0);
+ Primitive2DSequence xRetval(nCount);
+
+ // since old Width/Height calculations always added a single pixel value,
+ // it is necessary to create a inner range which is one display unit less
+ // at the bottom right.
+ const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
+ const basegfx::B2DRange aAdaptedInnerRange(
+ getPageObjectRange().getMinX(), getPageObjectRange().getMinY(),
+ getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY());
+
+ // preapre TextLayouter
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
+ aTextLayouter.setFont(getPageNameFont());
+
+ // get font attributes
+ basegfx::B2DVector aTextSizeAttribute;
+ const drawinglayer::attribute::FontAttribute aFontAttribute(
+ drawinglayer::primitive2d::getFontAttributeFromVclFont(
+ aTextSizeAttribute,
+ getPageNameFont(),
+ false,
+ false));
+
+ // prepare locale; this may need some more information in the future
+ const ::com::sun::star::lang::Locale aLocale;
+
+ // prepare font color from System
+ const basegfx::BColor aFontColor(Application::GetSettings().GetStyleSettings().GetFontColor().getBColor());
+
+ if(getShowFadeEffectIcon())
+ {
+ // prepare fFadeEffect Sizes
+ const basegfx::B2DVector aFadeEffectBitmapSizeLogic(rViewInformation.getInverseObjectToViewTransformation() *
+ basegfx::B2DVector(
+ getFadeEffectIconBitmap().GetSizePixel().getWidth() - 1,
+ getFadeEffectIconBitmap().GetSizePixel().getHeight() - 1));
+
+ // Paint_FadeEffectIndicator replacement.
+ // create transformation. To avoid bitmap scaling, use bitmap size as size
+ basegfx::B2DHomMatrix aBitmapTransform;
+
+ // short form for scale and translate transformation
+ aBitmapTransform.set(0L, 0L, aFadeEffectBitmapSizeLogic.getX());
+ aBitmapTransform.set(1L, 1L, aFadeEffectBitmapSizeLogic.getY());
+ aBitmapTransform.set(0L, 2L, aAdaptedInnerRange.getMinX());
+ aBitmapTransform.set(1L, 2L, aAdaptedInnerRange.getMaxY() + ((mnFadeEffectIndicatorOffset + 1) * aDiscretePixel.getX()));
+
+ xRetval[nInsert++] = Primitive2DReference(
+ new drawinglayer::primitive2d::BitmapPrimitive2D(getFadeEffectIconBitmap(), aBitmapTransform));
+ }
+
+ if(nTextLength)
+ {
+ // prepare fFadeEffect Sizes since it consumes from text size
+ const basegfx::B2DVector aFadeEffectBitmapSizeLogic(rViewInformation.getInverseObjectToViewTransformation() *
+ basegfx::B2DVector(
+ getFadeEffectIconBitmap().GetSizePixel().getWidth() - 1,
+ getFadeEffectIconBitmap().GetSizePixel().getHeight() - 1));
+
+ // Paint_PageName replacement. Get text size
+ const double fTextWidth(aTextLayouter.getTextWidth(getPageName(), 0, nTextLength));
+ const double fTextHeight(getPageNameFont().GetHeight());
+ const double fFadeEffectWidth(aFadeEffectBitmapSizeLogic.getX() * 2.0);
+ const double fFadeEffectTextGap(((mnFadeEffectIndicatorOffset + 2) * aDiscretePixel.getX()));
+ String aPageName(getPageName());
+
+ // calculate text start position
+ double fStartX(
+ aAdaptedInnerRange.getMaxX()
+ - fTextWidth
+ + (aDiscretePixel.getX() * 3.0));
+ const double fStartY(
+ aAdaptedInnerRange.getMaxY()
+ + fTextHeight
+ + fFadeEffectTextGap);
+ const bool bNeedClipping(fStartX < aAdaptedInnerRange.getMinX() + fFadeEffectWidth);
+
+ // if text is too big, clip it
+ if(bNeedClipping)
+ {
+ // new left start
+ fStartX = aAdaptedInnerRange.getMinX() + fFadeEffectWidth;
+
+ // find out how many characters to use
+ const double fAvailableLength(aAdaptedInnerRange.getWidth() - fFadeEffectWidth);
+ static const String aThreePoints(String::CreateFromAscii("..."));
+ const double fWidthThreePoints(aTextLayouter.getTextWidth(aThreePoints, 0, aThreePoints.Len()));
+ xub_StrLen a(1);
+
+ for(; a < (xub_StrLen)nTextLength; a++)
+ {
+ const double fSnippetLength(aTextLayouter.getTextWidth(aPageName, 0, a));
+
+ if(fSnippetLength + fWidthThreePoints > fAvailableLength)
+ {
+ break;
+ }
+ }
+
+ // build new string
+ aPageName = String(aPageName, 0, a - 1);
+ aPageName += aThreePoints;
+ }
+
+ // fill text matrix
+ basegfx::B2DHomMatrix aTextMatrix;
+
+ aTextMatrix.set(0, 0, aTextSizeAttribute.getX());
+ aTextMatrix.set(1, 1, aTextSizeAttribute.getY());
+ aTextMatrix.set(0, 2, fStartX);
+ aTextMatrix.set(1, 2, fStartY);
+
+ // prepare DXTextArray (can be empty one)
+ const ::std::vector< double > aDXArray;
+
+ // create Text primitive and add to target
+ xRetval[nInsert++] = Primitive2DReference(
+ new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ aTextMatrix,
+ aPageName,
+ 0,
+ aPageName.Len(),
+ aDXArray,
+ aFontAttribute,
+ aLocale,
+ aFontColor));
+ }
+
+ {
+ // Paint_PageNumber replacement. Get the range where it shall be centered and prepare the string
+ const double fLeft(aAdaptedInnerRange.getMinX() - (mnPageNumberOffset * aDiscretePixel.getX()) - getPageNumberAreaModelSize().Width());
+ const double fTop(aAdaptedInnerRange.getMinY());
+ const basegfx::B2DRange aNumberRange(fLeft, fTop,
+ fLeft + getPageNumberAreaModelSize().Width(), fTop + getPageNumberAreaModelSize().Height());
+ const String aPageNumber(String::CreateFromInt32(getPageNumber()));
+ const xub_StrLen nNumberLen(aPageNumber.Len());
+
+ // Get text size
+ const double fTextWidth(aTextLayouter.getTextWidth(aPageNumber, 0, nNumberLen));
+ const double fTextHeight(getPageNameFont().GetHeight());
+
+ // get text start postion
+ const double fStartX(aNumberRange.getCenterX() - (fTextWidth / 2.0));
+ const double fStartY(aNumberRange.getMinY() + fTextHeight + aDiscretePixel.getX());
+
+ // fill text matrix
+ basegfx::B2DHomMatrix aTextMatrix;
+
+ aTextMatrix.set(0, 0, aTextSizeAttribute.getX());
+ aTextMatrix.set(1, 1, aTextSizeAttribute.getY());
+ aTextMatrix.set(0, 2, fStartX);
+ aTextMatrix.set(1, 2, fStartY);
+
+ // prepare DXTextArray (can be empty one)
+ const ::std::vector< double > aDXArray;
+
+ // create Text primitive
+ xRetval[nInsert++] = Primitive2DReference(
+ new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ aTextMatrix,
+ aPageNumber,
+ 0,
+ nNumberLen,
+ aDXArray,
+ aFontAttribute,
+ aLocale,
+ aFontColor));
+
+ if(getExcluded())
+ {
+ // create a box with strikethrough from top left to bottom right
+ const basegfx::BColor aActiveColor(Application::GetSettings().GetStyleSettings().GetActiveColor().getBColor());
+ basegfx::B2DPolygon aStrikethrough;
+
+ aStrikethrough.append(aNumberRange.getMinimum());
+ aStrikethrough.append(aNumberRange.getMaximum());
+
+ xRetval[nInsert++] = Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ basegfx::tools::createPolygonFromRect(aNumberRange), aActiveColor));
+
+ xRetval[nInsert++] = Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ aStrikethrough, aActiveColor));
+ }
+ }
+
+ return xRetval;
+}
+
+SdPageObjectFadeNameNumberPrimitive::SdPageObjectFadeNameNumberPrimitive(
+ const basegfx::B2DRange& rRange,
+ const String& rPageName,
+ sal_uInt32 nPageNumber,
+ const Font& rPageNameFont,
+ const Size& rPageNumberAreaModelSize,
+ bool bShowFadeEffectIcon,
+ bool bShowCommentsIcon,
+ bool bExcluded)
+: SdPageObjectBasePrimitive(rRange),
+ maPageName(rPageName),
+ mnPageNumber(nPageNumber),
+ maPageNameFont(rPageNameFont),
+ maPageNumberAreaModelSize(rPageNumberAreaModelSize),
+ mbShowFadeEffectIcon(bShowFadeEffectIcon),
+ mbShowCommentsIcon(bShowCommentsIcon),
+ mbExcluded(bExcluded)
+{
+}
+
+SdPageObjectFadeNameNumberPrimitive::~SdPageObjectFadeNameNumberPrimitive()
+{
+}
+
+bool SdPageObjectFadeNameNumberPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const
+{
+ if(SdPageObjectBasePrimitive::operator==(rPrimitive))
+ {
+ const SdPageObjectFadeNameNumberPrimitive& rCompare = static_cast< const SdPageObjectFadeNameNumberPrimitive& >(rPrimitive);
+
+ return (getPageName() == rCompare.getPageName()
+ && getPageNumber() == rCompare.getPageNumber()
+ && getPageNameFont() == rCompare.getPageNameFont()
+ && getPageNumberAreaModelSize() == rCompare.getPageNumberAreaModelSize()
+ && getShowFadeEffectIcon() == rCompare.getShowFadeEffectIcon()
+ && getExcluded() == rCompare.getExcluded());
+ }
+
+ return false;
+}
+
+ImplPrimitrive2DIDBlock(SdPageObjectFadeNameNumberPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTFADENAMENUMBERPRIMITIVE)
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// createPrimitive2DSequence
+//
+// This method will replace the whole painting mechanism. Task is no longer to paint stuff to an OutDev,
+// but to provide the necessary geometrical information using primitives.
+
+Primitive2DSequence PageObjectViewObjectContact::createPrimitive2DSequence(const sdr::contact::DisplayInfo& rDisplayInfo) const
+{
+ // OutputDevice* pDevice = rDisplayInfo.GetDIOutputDevice();
+ OutputDevice* pDevice = GetObjectContact().TryToGetOutputDevice();
+
+ // get primitive vector from parent class. Do remember the contents for later use; this
+ // is done to create the page content renderer (see PagePrimitiveExtractor in svx) at the
+ // original object and to setup the draw hierarchy there so that changes to VCs of displayed
+ // objects will lead to InvalidatePartOfView-calls which will be forwarded from the helper-OC
+ // to this VOC in calling a ActionChanged().
+ //
+ // This already produces the displayable page content as a primitive sequence, complete with
+ // embedding in the page visualizer, clipping if needed and object and aspect ratio
+ // preparations. It would thus be the base for creating the cached visualisation, too,
+ // by just painting extactly this primitive sequence.
+ //
+ // Currently, this slows down PagePane display heavily. Reason is that the current mechanism
+ // to react on a SdrObject change in an edit view is to react on the ModelChange and to completely
+ // reset the PagePane (delete SdrPageObjs, re-create and layout them). This works, but kicks
+ // the complete sequence of primitive creation at VOCs and VCs and their buffering out of
+ // memory each time. So there are two choices:
+ //
+ // 1, disable getting the sequence of primtives
+ // -> invalidate uses ModelChange
+ // -> cache repaint uses complete view creation and repainting
+ //
+ // 2, create and use the sequence of primitives
+ // -> invalidate would not need ModelChange, no destroy/recreate of SdrObjects, no rearrange,
+ // the invalidate and the following repaint would exactly update the SdrPages involved and
+ // use the DrawingLayer provided ActionChanged() invalidations over the VOCs and VCs
+ // -> cache repaint could use the here offered sequence of primitives to re-create the bitmap
+ // (just hand over the local member to the cache)
+ //
+ // For the moment i will use (1) and disable primitive creation for SdrPageObj contents here
+
+ // const_cast< PageObjectViewObjectContact* >(this)->mxCurrentPageContents = ViewObjectContactOfPageObj::createPrimitive2DSequence(rDisplayInfo);
+
+ // assert when this call is issued indirectly from the destructor of
+ // this instance. This is not allowed and needs to be looked at
+#ifdef DBG_UTIL
+ if(mbInDestructor)
+ {
+ OSL_ENSURE(false, "Higher call inside PageObjectViewObjectContact in destructor (!)");
+ }
+#endif
+
+ // Check if buffering can and shall be done.
+ if (pDevice != NULL
+ && !GetObjectContact().isOutputToPrinter()
+ && !GetObjectContact().isOutputToRecordingMetaFile()
+ && !mbInDestructor)
+ {
+ // get inner and outer logic rectangles. Use model data directly for creation. Do NOT use getBoundRect()/
+ // getSnapRect() functionality; these will use the sequence of primitives in the long run itself. SdrPageObj
+ // is a SdrObject, so use SdrObject::aOutRect as model data. Access using GetLastBoundRect() to not execute anything
+ PageObjectViewContact& rPaObVOC(static_cast< PageObjectViewContact& >(GetViewContact()));
+ const Rectangle aInnerLogic(rPaObVOC.GetPageObject().GetLastBoundRect());
+
+ // get BitmapEx from cache. Do exactly the same as Paint_Preview() to avoid a repaint loop
+ // caused by slightly different pixel sizes of what the cache sees as pixel size and what is
+ // calculated here in discrete coordinates. This includes to not use LogicToPiyel on the Rectangle,
+ // but to do the same as the GetBoundingBox() implementation
+ const Rectangle aInnerPixel(Rectangle(pDevice->LogicToPixel(aInnerLogic.TopLeft()), pDevice->LogicToPixel(aInnerLogic.GetSize())));
+ BitmapEx aBitmapEx(const_cast< PageObjectViewObjectContact* >(this)->GetPreview(rDisplayInfo, aInnerPixel));
+
+ // prepare inner range
+ const basegfx::B2DRange aInnerRange(aInnerLogic.Left(), aInnerLogic.Top(), aInnerLogic.Right(), aInnerLogic.Bottom());
+
+ // provide default parameters
+ String aPageName;
+ Font aPageNameFont;
+ sal_uInt32 nPageNumber(0);
+ Size aPageNumberAreaModelSize;
+ bool bShowFadeEffectIcon(false);
+ bool bShowCommentsIcon(false);
+ bool bExcluded(false);
+
+ if(GetPage())
+ {
+ const SdPage* pPage = static_cast<const SdPage*>(GetPage());
+
+ // decide if fade effect indicator will be painted
+ if(pPage->getTransitionType() > 0)
+ {
+ bShowFadeEffectIcon = true;
+ }
+
+ bShowCommentsIcon = !pPage->getAnnotations().empty();
+
+ // prepare PageName, PageNumber, font and AreaModelSize
+ aPageName = pPage->GetName();
+ aPageNameFont = *FontProvider::Instance().GetFont(*pDevice);
+ nPageNumber = ((pPage->GetPageNum() - 1) / 2) + 1;
+ aPageNumberAreaModelSize = GetPageDescriptor()->GetPageNumberAreaModelSize();
+
+ if(!aPageName.Len())
+ {
+ aPageName = String(SdResId(STR_PAGE));
+ aPageName += String::CreateFromInt32(nPageNumber);
+ }
+
+ // decide if page is excluded
+ bExcluded = pPage->IsExcluded();
+ }
+
+ // create specialized primitives for focus, select and PagePreview itself
+ const bool bCreateBitmap(!aBitmapEx.IsEmpty());
+ const bool bCreateFocused(GetPageDescriptor()->IsFocused());
+ const bool bCreateSelected(GetPageDescriptor()->IsSelected());
+
+ const sal_uInt32 nCount(
+ (bCreateBitmap ? 1 : 0) + // bitmap itself
+ 1 + // border around bitmap (always)
+ 1 + // FadeEffect, PageName and PageNumber visualisation (always)
+ (bCreateFocused ? 1 : 0) + // create focused
+ (bCreateSelected ? 1 : 0) // create selected
+ );
+ sal_uInt32 nInsert(0);
+ Primitive2DSequence xRetval(nCount);
+
+ if(bCreateBitmap)
+ {
+ // add selection indicator if used
+ xRetval[nInsert++] = Primitive2DReference(new SdPageObjectPageBitmapPrimitive(aInnerRange, aBitmapEx));
+ }
+
+ if(true)
+ {
+ // add border (always)
+ xRetval[nInsert++] = Primitive2DReference(new SdPageObjectBorderPrimitive(aInnerRange));
+ }
+
+ if(true)
+ {
+ // add fade effext, page name and number if used
+ xRetval[nInsert++] = Primitive2DReference(new SdPageObjectFadeNameNumberPrimitive(
+ aInnerRange,
+ aPageName,
+ nPageNumber,
+ aPageNameFont,
+ aPageNumberAreaModelSize,
+ bShowFadeEffectIcon,
+ bShowCommentsIcon,
+ bExcluded));
+ }
+
+ if(bCreateSelected)
+ {
+ // add selection indicator if used
+ xRetval[nInsert++] = Primitive2DReference(new SdPageObjectSelectPrimitive(aInnerRange));
+ }
+
+ if(bCreateFocused)
+ {
+ // add focus indicator if used
+ xRetval[nInsert++] = Primitive2DReference(new SdPageObjectFocusPrimitive(aInnerRange, bCreateSelected));
+ }
+
+ return xRetval;
+ }
+ else
+ {
+ // Call parent. Output to printer or metafile will use vector data, not cached bitmaps
+ return ViewObjectContactOfPageObj::createPrimitive2DSequence(rDisplayInfo);
+ }
+}
+
+BitmapEx PageObjectViewObjectContact::CreatePreview (const DisplayInfo& /*rDisplayInfo*/)
+{
+ const SdPage* pPage = static_cast<const SdPage*>(GetPage());
+ OutputDevice* pDevice = GetObjectContact().TryToGetOutputDevice();
+
+ if(pDevice)
+ {
+ Rectangle aPreviewPixelBox (GetBoundingBox(*pDevice,PreviewBoundingBox,PixelCoordinateSystem));
+
+ PreviewRenderer aRenderer (pDevice);
+ Image aPreview (aRenderer.RenderPage(
+ pPage,
+ aPreviewPixelBox.GetSize(),
+ String()));
+
+ return aPreview.GetBitmapEx();
+ }
+ else
+ {
+ return BitmapEx();
+ }
+}
+
+
+
+
+BitmapEx PageObjectViewObjectContact::GetPreview (
+ const DisplayInfo& rDisplayInfo,
+ const Rectangle& rNewSizePixel)
+{
+ BitmapEx aBitmap;
+
+ try
+ {
+ // assert when this call is issued indirectly from the destructor of
+ // this instance. This is not allowed and needs to be looked at
+ OSL_ENSURE(!mbInDestructor, "Higher call inside PageObjectViewObjectContact in destructor (!)");
+
+ if (!mbInDestructor)
+ {
+ if (mpCache != NULL)
+ {
+ aBitmap = mpCache->GetPreviewBitmap(
+ GetPage(),
+ rNewSizePixel.GetSize());
+ mpCache->SetPreciousFlag(GetPage(), true);
+ }
+ else
+ aBitmap = CreatePreview(rDisplayInfo);
+ }
+ }
+ catch (const ::com::sun::star::uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ }
+
+ return aBitmap;
+}
+
+
+
+
+const SdrPage* PageObjectViewObjectContact::GetPage (void) const
+{
+ return static_cast<PageObjectViewContact&>(GetViewContact()).GetPage();
+}
+
+
+
+
+void PageObjectViewObjectContact::ActionChanged (void)
+{
+ // Even when we are called from destructor we still have to invalide
+ // the preview bitmap in the cache.
+ const SdrPage* pPage = GetPage();
+
+ if(pPage)
+ {
+ SdDrawDocument* pDocument = dynamic_cast<SdDrawDocument*>(pPage->GetModel());
+ if (mpCache!=NULL && pPage!=NULL && pDocument!=NULL)
+ {
+ cache::PageCacheManager::Instance()->InvalidatePreviewBitmap(
+ pDocument->getUnoModel(),
+ pPage);
+ }
+ }
+
+ // call parent
+ ViewObjectContactOfPageObj::ActionChanged();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// helper MouseOverEffectPrimitive
+//
+// Used to allow view-dependent primitive definition. For that purpose, the
+// initially created primitive (here: in createMouseOverEffectPrimitive2DSequence())
+// always has to be view-independent, but the decomposition is made view-dependent.
+// Very simple primitive which just remembers the discrete data and applies
+// it at decomposition time.
+
+class MouseOverEffectPrimitive : public drawinglayer::primitive2d::BufferedDecompositionPrimitive2D
+{
+private:
+ basegfx::B2DRange maLogicRange;
+ sal_uInt32 mnDiscreteOffset;
+ sal_uInt32 mnDiscreteWidth;
+ basegfx::BColor maRGBColor;
+
+protected:
+ virtual drawinglayer::primitive2d::Primitive2DSequence create2DDecomposition(
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
+
+public:
+ MouseOverEffectPrimitive(
+ const basegfx::B2DRange& rLogicRange,
+ sal_uInt32 nDiscreteOffset,
+ sal_uInt32 nDiscreteWidth,
+ const basegfx::BColor& rRGBColor)
+ : drawinglayer::primitive2d::BufferedDecompositionPrimitive2D(),
+ maLogicRange(rLogicRange),
+ mnDiscreteOffset(nDiscreteOffset),
+ mnDiscreteWidth(nDiscreteWidth),
+ maRGBColor(rRGBColor)
+ {}
+
+ // data access
+ const basegfx::B2DRange& getLogicRange() const { return maLogicRange; }
+ sal_uInt32 getDiscreteOffset() const { return mnDiscreteOffset; }
+ sal_uInt32 getDiscreteWidth() const { return mnDiscreteWidth; }
+ const basegfx::BColor& getRGBColor() const { return maRGBColor; }
+
+ virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const;
+
+ DeclPrimitrive2DIDBlock()
+};
+
+drawinglayer::primitive2d::Primitive2DSequence MouseOverEffectPrimitive::create2DDecomposition(
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation) const
+{
+ // get logic sizes in object coordinate system
+ const double fDiscreteWidth((rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength());
+ const double fOffset(fDiscreteWidth * getDiscreteOffset());
+ const double fWidth(fDiscreteWidth * getDiscreteWidth());
+
+ // create range (one pixel less to get a good fitting)
+ basegfx::B2DRange aRange(
+ getLogicRange().getMinimum(),
+ getLogicRange().getMaximum() - basegfx::B2DTuple(fDiscreteWidth, fDiscreteWidth));
+
+ // grow range
+ aRange.grow(fOffset - (fWidth * 0.5));
+
+ // create fat line with parameters. The formerly hand-painted edge
+ // roundings will now be done using rounded edges of this fat line
+ const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(aRange));
+ const drawinglayer::attribute::LineAttribute aLineAttribute(getRGBColor(), fWidth);
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
+ aPolygon,
+ aLineAttribute));
+
+ return drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1);
+}
+
+bool MouseOverEffectPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const
+{
+ if(drawinglayer::primitive2d::BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const MouseOverEffectPrimitive& rCompare = static_cast< const MouseOverEffectPrimitive& >(rPrimitive);
+
+ return (getLogicRange() == rCompare.getLogicRange()
+ && getDiscreteOffset() == rCompare.getDiscreteOffset()
+ && getDiscreteWidth() == rCompare.getDiscreteWidth()
+ && getRGBColor() == rCompare.getRGBColor());
+ }
+
+ return false;
+}
+
+ImplPrimitrive2DIDBlock(MouseOverEffectPrimitive, PRIMITIVE2D_ID_SDMOUSEOVEREFFECTPRIMITIVE)
+
+//////////////////////////////////////////////////////////////////////////////
+
+drawinglayer::primitive2d::Primitive2DSequence PageObjectViewObjectContact::createMouseOverEffectPrimitive2DSequence()
+{
+ drawinglayer::primitive2d::Primitive2DSequence aRetval;
+
+ if(GetPageDescriptor()->IsSelected() && mpProperties.get() && mpProperties->IsShowSelection())
+ {
+ // When the selection frame is visualized the mouse over frame is not
+ // visible and does not have to be created.
+ }
+ else
+ {
+ const PageObjectViewContact& rPaObVOC(static_cast<PageObjectViewContact&>(GetViewContact()));
+ const Rectangle aBoundingBox(rPaObVOC.GetPageObject().GetLastBoundRect());
+ const basegfx::B2DRange aLogicRange(aBoundingBox.Left(), aBoundingBox.Top(), aBoundingBox.Right(), aBoundingBox.Bottom());
+ const basegfx::BColor aSelectionColor(mpProperties->GetSelectionColor().getBColor());
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new MouseOverEffectPrimitive(
+ aLogicRange,
+ mnMouseOverEffectOffset,
+ mnMouseOverEffectThickness,
+ aSelectionColor));
+
+ aRetval = drawinglayer::primitive2d::Primitive2DSequence(&aReference, 1);
+ }
+
+ return aRetval;
+}
+
+
+
+
+SvBorder PageObjectViewObjectContact::CalculatePageModelBorder (
+ OutputDevice* pDevice,
+ int nPageCount)
+{
+ SvBorder aModelBorder;
+
+ if (pDevice != NULL)
+ {
+ // 1. Initialize the border with the values that do not depend on
+ // the device.
+ Size aTopLeftBorders (pDevice->PixelToLogic (Size (
+ mnPageNumberOffset+1,
+ mnSelectionIndicatorOffset + mnSelectionIndicatorThickness)));
+ Size aBottomRightBorders (pDevice->PixelToLogic (Size (
+ mnSelectionIndicatorOffset + mnSelectionIndicatorThickness,
+ mnFadeEffectIndicatorOffset)));
+ aModelBorder = SvBorder (
+ aTopLeftBorders.Width(),
+ aTopLeftBorders.Height(),
+ aBottomRightBorders.Width(),
+ aBottomRightBorders.Height());
+
+
+ // 2. Add the device dependent values.
+
+ // Calculate the area of the page number.
+ Size aPageNumberModelSize (
+ CalculatePageNumberAreaModelSize (pDevice, nPageCount));
+
+ // Update the border.
+ aModelBorder.Left() += aPageNumberModelSize.Width();
+ // The height of the page number area is the same as the height of
+ // the page name area.
+ aModelBorder.Bottom() += aPageNumberModelSize.Height();
+ }
+
+ return aModelBorder;
+}
+
+
+
+
+Size PageObjectViewObjectContact::CalculatePageNumberAreaModelSize (
+ OutputDevice* pDevice,
+ int nPageCount)
+{
+ // Set the correct font.
+ Font aOriginalFont (pDevice->GetFont());
+ pDevice->SetFont(*FontProvider::Instance().GetFont(*pDevice));
+
+ String sPageNumberTemplate;
+ if (nPageCount < 10)
+ sPageNumberTemplate = String::CreateFromAscii("9");
+ else if (nPageCount < 100)
+ sPageNumberTemplate = String::CreateFromAscii("99");
+ else if (nPageCount < 200)
+ // Just for the case that 1 is narrower than 9.
+ sPageNumberTemplate = String::CreateFromAscii("199");
+ else if (nPageCount < 1000)
+ sPageNumberTemplate = String::CreateFromAscii("999");
+ else
+ sPageNumberTemplate = String::CreateFromAscii("9999");
+ // More then 9999 pages are not handled.
+
+ Size aSize (
+ pDevice->GetTextWidth (sPageNumberTemplate),
+ pDevice->GetTextHeight ());
+
+ pDevice->SetFont (aOriginalFont);
+
+ return aSize;
+}
+
+
+
+
+model::SharedPageDescriptor
+ PageObjectViewObjectContact::GetPageDescriptor (void) const
+{
+ PageObjectViewContact& rViewContact (
+ static_cast<PageObjectViewContact&>(GetViewContact()));
+ PageObject& rPageObject (
+ static_cast<PageObject&>(rViewContact.GetPageObject()));
+ return rPageObject.GetDescriptor();
+}
+
+
+
+} } } // end of namespace ::sd::slidesorter::view