blob: eccf343dd47e8c21ebe59404843f028107fdd242 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"
#include <svx/sdr/contact/viewobjectcontactofpageobj.hxx>
#include <svx/sdr/contact/viewcontactofpageobj.hxx>
#include <svx/svdopage.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
#include <svx/sdr/contact/objectcontactofobjlistpainter.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <svx/svdpage.hxx>
#include <svx/unoapi.hxx>
#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
//////////////////////////////////////////////////////////////////////////////
using namespace com::sun::star;
//////////////////////////////////////////////////////////////////////////////
namespace sdr
{
namespace contact
{
class PagePrimitiveExtractor : public ObjectContactOfPagePainter, public Timer
{
private:
// the ViewObjectContactOfPageObj using this painter
ViewObjectContactOfPageObj& mrViewObjectContactOfPageObj;
public:
// basic constructor/destructor
PagePrimitiveExtractor(ViewObjectContactOfPageObj& rVOC);
virtual ~PagePrimitiveExtractor();
// LazyInvalidate request. Supported here to not automatically
// invalidate the second interaction state all the time at the
// original OC
virtual void setLazyInvalidate(ViewObjectContact& rVOC);
// From baseclass Timer, the timeout call triggered by te LazyInvalidate mechanism
virtual void Timeout();
// get primitive visualization
drawinglayer::primitive2d::Primitive2DSequence createPrimitive2DSequenceForPage(const DisplayInfo& rDisplayInfo);
// Own reaction on changes which will be forwarded to the OC of the owner-VOC
virtual void InvalidatePartOfView(const basegfx::B2DRange& rRange) const;
// forward access to SdrPageView of ViewObjectContactOfPageObj
virtual bool isOutputToPrinter() const;
virtual bool isOutputToWindow() const;
virtual bool isOutputToVirtualDevice() const;
virtual bool isOutputToRecordingMetaFile() const;
virtual bool isOutputToPDFFile() const;
virtual bool isDrawModeGray() const;
virtual bool isDrawModeBlackWhite() const;
virtual bool isDrawModeHighContrast() const;
virtual SdrPageView* TryToGetSdrPageView() const;
virtual OutputDevice* TryToGetOutputDevice() const;
};
PagePrimitiveExtractor::PagePrimitiveExtractor(
ViewObjectContactOfPageObj& rVOC)
: ObjectContactOfPagePainter(0, rVOC.GetObjectContact()),
mrViewObjectContactOfPageObj(rVOC)
{
// make this renderer a preview renderer
setPreviewRenderer(true);
// init timer
SetTimeout(1);
Stop();
}
PagePrimitiveExtractor::~PagePrimitiveExtractor()
{
// execute missing LazyInvalidates and stop timer
Timeout();
}
void PagePrimitiveExtractor::setLazyInvalidate(ViewObjectContact& /*rVOC*/)
{
// do NOT call parent, but remember that something is to do by
// starting the LazyInvalidateTimer
Start();
}
// From baseclass Timer, the timeout call triggered by te LazyInvalidate mechanism
void PagePrimitiveExtractor::Timeout()
{
// stop the timer
Stop();
// invalidate all LazyInvalidate VOCs new situations
const sal_uInt32 nVOCCount(getViewObjectContactCount());
for(sal_uInt32 a(0); a < nVOCCount; a++)
{
ViewObjectContact* pCandidate = getViewObjectContact(a);
pCandidate->triggerLazyInvalidate();
}
}
drawinglayer::primitive2d::Primitive2DSequence PagePrimitiveExtractor::createPrimitive2DSequenceForPage(const DisplayInfo& /*rDisplayInfo*/)
{
drawinglayer::primitive2d::Primitive2DSequence xRetval;
const SdrPage* pStartPage = GetStartPage();
if(pStartPage)
{
// update own ViewInformation2D for visualized page
const drawinglayer::geometry::ViewInformation2D& rOriginalViewInformation = mrViewObjectContactOfPageObj.GetObjectContact().getViewInformation2D();
const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D(
rOriginalViewInformation.getObjectTransformation(),
rOriginalViewInformation.getViewTransformation(),
// #i101075# use empty range for page content here to force
// the content not to be physically clipped in any way. This
// would be possible, but would require the internal transformation
// which maps between the page visualisation object and the page
// content, including the aspect ratios (for details see in
// PagePreviewPrimitive2D::create2DDecomposition)
basegfx::B2DRange(),
GetXDrawPageForSdrPage(const_cast< SdrPage* >(pStartPage)),
0.0, // no time; page previews are not animated
rOriginalViewInformation.getExtendedInformationSequence());
updateViewInformation2D(aNewViewInformation2D);
// create copy of DisplayInfo to set PagePainting
DisplayInfo aDisplayInfo;
// get page's VOC
ViewObjectContact& rDrawPageVOContact = pStartPage->GetViewContact().GetViewObjectContact(*this);
// get whole Primitive2DSequence
xRetval = rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo);
}
return xRetval;
}
void PagePrimitiveExtractor::InvalidatePartOfView(const basegfx::B2DRange& rRange) const
{
// an invalidate is called at this view, this needs to be translated to an invalidate
// for the using VOC. Coordinates are in page coordinate system.
const SdrPage* pStartPage = GetStartPage();
if(pStartPage && !rRange.isEmpty())
{
const basegfx::B2DRange aPageRange(0.0, 0.0, (double)pStartPage->GetWdt(), (double)pStartPage->GetHgt());
if(rRange.overlaps(aPageRange))
{
// if object on the page is inside or overlapping with page, create ActionChanged() for
// involved VOC
mrViewObjectContactOfPageObj.ActionChanged();
}
}
}
// forward access to SdrPageView to VOCOfPageObj
bool PagePrimitiveExtractor::isOutputToPrinter() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPrinter(); }
bool PagePrimitiveExtractor::isOutputToWindow() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToWindow(); }
bool PagePrimitiveExtractor::isOutputToVirtualDevice() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToVirtualDevice(); }
bool PagePrimitiveExtractor::isOutputToRecordingMetaFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToRecordingMetaFile(); }
bool PagePrimitiveExtractor::isOutputToPDFFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPDFFile(); }
bool PagePrimitiveExtractor::isDrawModeGray() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeGray(); }
bool PagePrimitiveExtractor::isDrawModeBlackWhite() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeBlackWhite(); }
bool PagePrimitiveExtractor::isDrawModeHighContrast() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeHighContrast(); }
SdrPageView* PagePrimitiveExtractor::TryToGetSdrPageView() const { return mrViewObjectContactOfPageObj.GetObjectContact().TryToGetSdrPageView(); }
OutputDevice* PagePrimitiveExtractor::TryToGetOutputDevice() const { return mrViewObjectContactOfPageObj.GetObjectContact().TryToGetOutputDevice(); }
} // end of namespace contact
} // end of namespace sdr
//////////////////////////////////////////////////////////////////////////////
namespace sdr
{
namespace contact
{
drawinglayer::primitive2d::Primitive2DSequence ViewObjectContactOfPageObj::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
{
drawinglayer::primitive2d::Primitive2DSequence xRetval;
const SdrPageObj& rPageObject((static_cast< ViewContactOfPageObj& >(GetViewContact())).GetPageObj());
const SdrPage* pPage = rPageObject.GetReferencedPage();
const svtools::ColorConfig aColorConfig;
// get PageObject's geometry
basegfx::B2DHomMatrix aPageObjectTransform;
{
const Rectangle aPageObjectModelData(rPageObject.GetLastBoundRect());
const basegfx::B2DRange aPageObjectBound(
aPageObjectModelData.Left(), aPageObjectModelData.Top(),
aPageObjectModelData.Right(), aPageObjectModelData.Bottom());
aPageObjectTransform.set(0, 0, aPageObjectBound.getWidth());
aPageObjectTransform.set(1, 1, aPageObjectBound.getHeight());
aPageObjectTransform.set(0, 2, aPageObjectBound.getMinX());
aPageObjectTransform.set(1, 2, aPageObjectBound.getMinY());
}
// #i102637# add gray frame also when printing and page exists (handout pages)
const bool bCreateGrayFrame(!GetObjectContact().isOutputToPrinter() || pPage);
// get displayed page's content. This is the uscaled page content
if(mpExtractor && pPage)
{
// get displayed page's geometry
drawinglayer::primitive2d::Primitive2DSequence xPageContent;
const Size aPageSize(pPage->GetSize());
const double fPageWidth(aPageSize.getWidth());
const double fPageHeight(aPageSize.getHeight());
// The case that a PageObject contains another PageObject which visualizes the
// same page again would lead to a recursion. Limit that recursion depth to one
// by using a local static bool
static bool bInCreatePrimitive2D(false);
if(bInCreatePrimitive2D)
{
// Recursion is possible. Create a replacement primitive
xPageContent.realloc(2);
const Color aDocColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
const Color aBorderColor(aColorConfig.GetColorValue(svtools::DOCBOUNDARIES).nColor);
const basegfx::B2DRange aPageBound(0.0, 0.0, fPageWidth, fPageHeight);
const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aPageBound));
// add replacement fill
xPageContent[0L] = drawinglayer::primitive2d::Primitive2DReference(
new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aOutline), aDocColor.getBColor()));
// add replacement border
xPageContent[1L] = drawinglayer::primitive2d::Primitive2DReference(
new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aBorderColor.getBColor()));
}
else
{
// set recursion flag
bInCreatePrimitive2D = true;
// init extractor, guarantee existance, set page there
mpExtractor->SetStartPage(pPage);
// #i105548# also need to copy the VOCRedirector for sub-content creation
mpExtractor->SetViewObjectContactRedirector(GetObjectContact().GetViewObjectContactRedirector());
// create page content
xPageContent = mpExtractor->createPrimitive2DSequenceForPage(rDisplayInfo);
// #i105548# reset VOCRedirector to not accidentially have a pointer to a
// temporary class, so calls to it are avoided safely
mpExtractor->SetViewObjectContactRedirector(0);
// reset recursion flag
bInCreatePrimitive2D = false;
}
// prepare retval
if(xPageContent.hasElements())
{
const uno::Reference< drawing::XDrawPage > xDrawPage(GetXDrawPageForSdrPage(const_cast< SdrPage*>(pPage)));
const drawinglayer::primitive2d::Primitive2DReference xPagePreview(new drawinglayer::primitive2d::PagePreviewPrimitive2D(
xDrawPage, aPageObjectTransform, fPageWidth, fPageHeight, xPageContent, true));
xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xPagePreview, 1);
}
}
else if(bCreateGrayFrame)
{
// #i105146# no content, but frame display. To make hitting the page preview objects
// on the handout page more simple, add hidden fill geometry
const drawinglayer::primitive2d::Primitive2DReference xFrameHit(
drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
false,
aPageObjectTransform));
xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xFrameHit, 1);
}
// add a gray outline frame, except not when printing
if(bCreateGrayFrame)
{
const Color aFrameColor(aColorConfig.GetColorValue(svtools::OBJECTBOUNDARIES).nColor);
basegfx::B2DPolygon aOwnOutline(basegfx::tools::createUnitPolygon());
aOwnOutline.transform(aPageObjectTransform);
const drawinglayer::primitive2d::Primitive2DReference xGrayFrame(
new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOwnOutline, aFrameColor.getBColor()));
drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, xGrayFrame);
}
return xRetval;
}
ViewObjectContactOfPageObj::ViewObjectContactOfPageObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
: ViewObjectContactOfSdrObj(rObjectContact, rViewContact),
mpExtractor(new PagePrimitiveExtractor(*this))
{
}
ViewObjectContactOfPageObj::~ViewObjectContactOfPageObj()
{
// delete the helper OC
if(mpExtractor)
{
// remember candidate and reset own pointer to avoid action when createPrimitive2DSequence()
// would be called for any reason
PagePrimitiveExtractor* pCandidate = mpExtractor;
mpExtractor = 0;
// also reset the StartPage to avoid ActionChanged() forwardings in the
// PagePrimitiveExtractor::InvalidatePartOfView() implementation
pCandidate->SetStartPage(0);
delete pCandidate;
}
}
} // end of namespace contact
} // end of namespace sdr
//////////////////////////////////////////////////////////////////////////////
// eof