diff options
Diffstat (limited to 'sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx')
-rwxr-xr-x | sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx | 1403 |
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 |