diff options
Diffstat (limited to 'svx/source/svdraw/svdpntv.cxx')
-rw-r--r-- | svx/source/svdraw/svdpntv.cxx | 1218 |
1 files changed, 1218 insertions, 0 deletions
diff --git a/svx/source/svdraw/svdpntv.cxx b/svx/source/svdraw/svdpntv.cxx new file mode 100644 index 0000000000..4584e7f831 --- /dev/null +++ b/svx/source/svdraw/svdpntv.cxx @@ -0,0 +1,1218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <memory> +#include <svx/svdpntv.hxx> +#include <vcl/weld.hxx> +#include <vcl/window.hxx> +#include <svx/sdrpaintwindow.hxx> +#include <svx/svdmodel.hxx> + +#include <svx/svdpage.hxx> +#include <svx/svdpagv.hxx> +#include <svl/hint.hxx> + +#include <svx/svdview.hxx> +#include <svx/svdglue.hxx> +#include <svx/svdobj.hxx> +#include <sxlayitm.hxx> +#include <svl/itemiter.hxx> +#include <editeng/eeitem.hxx> +#include <svl/whiter.hxx> +#include <svl/style.hxx> +#include <svx/sdrpagewindow.hxx> +#include <vcl/svapp.hxx> +#include <svx/sdr/contact/objectcontact.hxx> +#include <svx/sdr/animation/objectanimator.hxx> +#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> +#include <drawinglayer/converters.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <comphelper/lok.hxx> +#include <svx/svdviter.hxx> +#include <svtools/optionsdrawinglayer.hxx> +#include <osl/diagnose.h> + +using namespace ::com::sun::star; + +// interface to SdrPaintWindow + +SdrPaintWindow* SdrPaintView::FindPaintWindow(const OutputDevice& rOut) const +{ + // back to loop - there is more to test than a std::find_if and a lambda can do + for(auto& candidate : maPaintWindows) + { + if(&(candidate->GetOutputDevice()) == &rOut) + { + return candidate.get(); + } + + // check for patched to allow finding in that state, too + if(nullptr != candidate->getPatched() && &(candidate->getPatched()->GetOutputDevice()) == &rOut) + { + return candidate->getPatched(); + } + } + + return nullptr; +} + +SdrPaintWindow* SdrPaintView::GetPaintWindow(sal_uInt32 nIndex) const +{ + return maPaintWindows[nIndex].get(); +} + +void SdrPaintView::DeletePaintWindow(const SdrPaintWindow& rOld) +{ + auto aFindResult = ::std::find_if(maPaintWindows.begin(), maPaintWindows.end(), + [&](const std::unique_ptr<SdrPaintWindow>& p) { return p.get() == &rOld; }); + + if(aFindResult != maPaintWindows.end()) + { + maPaintWindows.erase(aFindResult); + } +} + +OutputDevice* SdrPaintView::GetFirstOutputDevice() const +{ + if(PaintWindowCount()) + { + return &(GetPaintWindow(0)->GetOutputDevice()); + } + + return nullptr; +} + + +SvxViewChangedHint::SvxViewChangedHint() : SfxHint(SfxHintId::SvxViewChanged) +{ +} + + +BitmapEx convertMetafileToBitmapEx( + const GDIMetaFile& rMtf, + const basegfx::B2DRange& rTargetRange, + const sal_uInt32 nMaximumQuadraticPixels) +{ + BitmapEx aBitmapEx; + + if(rMtf.GetActionSize()) + { + const drawinglayer::primitive2d::Primitive2DReference aMtf( + new drawinglayer::primitive2d::MetafilePrimitive2D( + basegfx::utils::createScaleTranslateB2DHomMatrix( + rTargetRange.getRange(), + rTargetRange.getMinimum()), + rMtf)); + aBitmapEx = drawinglayer::convertPrimitive2DContainerToBitmapEx( + drawinglayer::primitive2d::Primitive2DContainer { aMtf }, + rTargetRange, + nMaximumQuadraticPixels); + } + + return aBitmapEx; +} + +SdrPaintView::SdrPaintView(SdrModel& rSdrModel, OutputDevice* pOut) + : mrModel(rSdrModel) + , mpActualOutDev(nullptr) + , mpDragWin(nullptr) + , mpDefaultStyleSheet(nullptr) + , maDefaultAttr(rSdrModel.GetItemPool()) + , maComeBackIdle( "svx::SdrPaintView aComeBackIdle" ) + , meAnimationMode(SdrAnimationMode::Animate) + , mnHitTolPix(2) + , mnMinMovPix(3) + , mnHitTolLog(0) + , mnMinMovLog(0) + , mbPageVisible(true) + , mbPageShadowVisible(true) + , mbPageBorderVisible(true) + , mbBordVisible(true) + , mbGridVisible(true) + , mbGridFront(false) + , mbHlplVisible(true) + , mbHlplFront(true) + , mbGlueVisible(false) + , mbGlueVisible2(false) + , mbGlueVisible3(false) + , mbGlueVisible4(false) + , mbSomeObjChgdFlag(false) + , mbSwapAsynchron(false) + , mbPrintPreview(false) + , mbAnimationPause(false) + , mbBufferedOutputAllowed(false) + , mbBufferedOverlayAllowed(false) + , mbPageDecorationAllowed(true) + , mbMasterPageVisualizationAllowed(true) + , mbPreviewRenderer(false) + , mbHideOle(false) + , mbHideChart(false) + , mbHideDraw(false) + , mbHideFormControl(false) + , mbPaintTextEdit(true) + , maGridColor(COL_BLACK) +{ + maComeBackIdle.SetPriority(TaskPriority::REPAINT); + maComeBackIdle.SetInvokeHandler(LINK(this,SdrPaintView,ImpComeBackHdl)); + + SetDefaultStyleSheet(GetModel().GetDefaultStyleSheet(), true); + + if (pOut) + AddDeviceToPaintView(*pOut, nullptr); + + maColorConfig.AddListener(this); + onChangeColorConfig(); +} + +SdrPaintView::~SdrPaintView() +{ + if (mpDefaultStyleSheet) + EndListening(*mpDefaultStyleSheet); + + maColorConfig.RemoveListener(this); + ClearPageView(); + + // delete existing SdrPaintWindows + maPaintWindows.clear(); +} + + +void SdrPaintView::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) +{ + //If the stylesheet has been destroyed + if (&rBC == mpDefaultStyleSheet) + { + if (rHint.GetId() == SfxHintId::Dying) + mpDefaultStyleSheet = nullptr; + return; + } + + if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint) + return; + const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint); + SdrHintKind eKind = pSdrHint->GetKind(); + if (eKind==SdrHintKind::ObjectChange || eKind==SdrHintKind::ObjectInserted || eKind==SdrHintKind::ObjectRemoved) + { + bool bObjChg = !mbSomeObjChgdFlag; // if true, evaluate for ComeBack timer + if (bObjChg) + { + mbSomeObjChgdFlag=true; + maComeBackIdle.Start(); + } + } + + if (eKind==SdrHintKind::PageOrderChange) + { + const SdrPage* pPg=pSdrHint->GetPage(); + if (pPg && !pPg->IsInserted()) + { + if(mpPageView && mpPageView->GetPage() == pPg) + { + HideSdrPage(); + } + } + } +} + +void SdrPaintView::ConfigurationChanged( ::utl::ConfigurationBroadcaster* , ConfigurationHints eHint) +{ + if (eHint == ConfigurationHints::OnlyCurrentDocumentColorScheme) + return; + onChangeColorConfig(); + InvalidateAllWin(); +} + +IMPL_LINK_NOARG(SdrPaintView, ImpComeBackHdl, Timer *, void) +{ + if (mbSomeObjChgdFlag) { + mbSomeObjChgdFlag=false; + ModelHasChanged(); + } +} + +void SdrPaintView::FlushComeBackTimer() const +{ + if (mbSomeObjChgdFlag) { + // casting to nonconst + const_cast<SdrPaintView*>(this)->ImpComeBackHdl(&const_cast<SdrPaintView*>(this)->maComeBackIdle); + const_cast<SdrPaintView*>(this)->maComeBackIdle.Stop(); + } +} + +void SdrPaintView::ModelHasChanged() +{ + // broadcast to all PageViews + if(mpPageView && !mpPageView->GetPage()->IsInserted()) + { + HideSdrPage(); + } + + // test mpPageView here again, HideSdrPage() may have invalidated it. + if(mpPageView) + { + mpPageView->ModelHasChanged(); + } +} + + +bool SdrPaintView::IsAction() const +{ + return false; +} + +void SdrPaintView::MovAction(const Point&) +{ +} + +void SdrPaintView::EndAction() +{ +} + +void SdrPaintView::BckAction() +{ +} + +void SdrPaintView::BrkAction() +{ +} + +void SdrPaintView::TakeActionRect(tools::Rectangle&) const +{ +} + + +// info about TextEdit. Default is false. +bool SdrPaintView::IsTextEdit() const +{ + return false; +} + +sal_uInt16 SdrPaintView::ImpGetMinMovLogic(short nMinMov, const OutputDevice* pOut) const +{ + if (nMinMov>=0) return sal_uInt16(nMinMov); + if (pOut==nullptr) + { + pOut = GetFirstOutputDevice(); + } + if (pOut!=nullptr) { + return short(-pOut->PixelToLogic(Size(nMinMov,0)).Width()); + } else { + return 0; + } +} + +sal_uInt16 SdrPaintView::ImpGetHitTolLogic(short nHitTol, const OutputDevice* pOut) const +{ + if (nHitTol>=0) return sal_uInt16(nHitTol); + if (pOut==nullptr) + { + pOut = GetFirstOutputDevice(); + } + if (pOut!=nullptr) { + return short(-pOut->PixelToLogic(Size(nHitTol,0)).Width()); + } else { + return 0; + } +} + +void SdrPaintView::TheresNewMapMode() +{ + if (mpActualOutDev) { + mnHitTolLog=static_cast<sal_uInt16>(mpActualOutDev->PixelToLogic(Size(mnHitTolPix,0)).Width()); + mnMinMovLog=static_cast<sal_uInt16>(mpActualOutDev->PixelToLogic(Size(mnMinMovPix,0)).Width()); + } +} + +void SdrPaintView::SetActualWin(const OutputDevice* pWin) +{ + mpActualOutDev = const_cast<OutputDevice *>(pWin); + TheresNewMapMode(); +} + + +void SdrPaintView::ClearPageView() +{ + BrkAction(); + + if(mpPageView) + { + InvalidateAllWin(); + mpPageView.reset(); + } +} + +SdrPageView* SdrPaintView::ShowSdrPage(SdrPage* pPage) +{ + if(pPage && (!mpPageView || mpPageView->GetPage() != pPage)) + { + if(mpPageView) + { + InvalidateAllWin(); + mpPageView.reset(); + } + + if (SdrView *pView = dynamic_cast<SdrView*>(this)) + { + mpPageView.reset(new SdrPageView(pPage, *pView)); + mpPageView->Show(); + } + } + + return mpPageView.get(); +} + +void SdrPaintView::HideSdrPage() +{ + if(mpPageView) + { + mpPageView->Hide(); + mpPageView.reset(); + } +} + +void SdrPaintView::AddDeviceToPaintView(OutputDevice& rNewDev, vcl::Window *pWindow) +{ + SdrPaintWindow* pNewPaintWindow = new SdrPaintWindow(*this, rNewDev, pWindow); + maPaintWindows.emplace_back(pNewPaintWindow); + + if(mpPageView) + { + mpPageView->AddPaintWindowToPageView(*pNewPaintWindow); + } +} + +void SdrPaintView::DeleteDeviceFromPaintView(OutputDevice& rOldDev) +{ + SdrPaintWindow* pCandidate = FindPaintWindow(rOldDev); + + if(pCandidate) + { + if(mpPageView) + { + mpPageView->RemovePaintWindowFromPageView(*pCandidate); + } + + DeletePaintWindow(*pCandidate); + } +} + +void SdrPaintView::SetLayerVisible(const OUString& rName, bool bShow) +{ + if(mpPageView) + { + mpPageView->SetLayerVisible(rName, bShow); + } + + InvalidateAllWin(); +} + +bool SdrPaintView::IsLayerVisible(const OUString& rName) const +{ + if(mpPageView) + { + return mpPageView->IsLayerVisible(rName); + } + + return false; +} + +void SdrPaintView::SetLayerLocked(const OUString& rName, bool bLock) +{ + if(mpPageView) + { + mpPageView->SetLayerLocked(rName,bLock); + } +} + +bool SdrPaintView::IsLayerLocked(const OUString& rName) const +{ + if(mpPageView) + { + return mpPageView->IsLayerLocked(rName); + } + + return false; +} + +void SdrPaintView::SetLayerPrintable(const OUString& rName, bool bPrn) +{ + if(mpPageView) + { + mpPageView->SetLayerPrintable(rName,bPrn); + } +} + +bool SdrPaintView::IsLayerPrintable(const OUString& rName) const +{ + if(mpPageView) + { + return mpPageView->IsLayerPrintable(rName); + } + + return false; +} + +void SdrPaintView::PrePaint() +{ + if(mpPageView) + { + mpPageView->PrePaint(); + } +} + + +// #define SVX_REPAINT_TIMER_TEST + +void SdrPaintView::CompleteRedraw(OutputDevice* pOut, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector) +{ +#ifdef SVX_REPAINT_TIMER_TEST +#define REMEMBERED_TIMES_COUNT (10) + static bool bDoTimerTest(false); + static bool bTimesInited(false); + static sal_uInt32 nRepeatCount(10); + static double fLastTimes[REMEMBERED_TIMES_COUNT]; + const sal_uInt64 nStartTime(tools::Time::GetSystemTicks()); + sal_uInt32 count(1); + sal_uInt32 a; + + if(bDoTimerTest) + { + count = nRepeatCount; + } + + for(a = 0; a < count; a++) + { +#endif // SVX_REPAINT_TIMER_TEST + + // #i74769# check if pOut is a win and has a ClipRegion. If Yes, the Region + // rReg may be made more granular (fine) with using it. Normally, rReg + // does come from Window::Paint() anyways and thus is based on a single + // rectangle which was derived from exactly that repaint region + vcl::Region aOptimizedRepaintRegion(rReg); + + if(pOut && OUTDEV_WINDOW == pOut->GetOutDevType()) + { + vcl::Window* pWindow = pOut->GetOwnerWindow(); + + if(pWindow->IsInPaint()) + { + if(!pWindow->GetPaintRegion().IsEmpty()) + { + aOptimizedRepaintRegion.Intersect(pWindow->GetPaintRegion()); + } + } + } + + SdrPaintWindow* pPaintWindow = BeginCompleteRedraw(pOut); + OSL_ENSURE(pPaintWindow, "SdrPaintView::CompleteRedraw: No OutDev (!)"); + + DoCompleteRedraw(*pPaintWindow, aOptimizedRepaintRegion, pRedirector); + EndCompleteRedraw(*pPaintWindow, true); + +#ifdef SVX_REPAINT_TIMER_TEST + } + + if(bDoTimerTest) + { + const sal_uInt64 nStopTime(tools::Time::GetSystemTicks()); + const sal_uInt64 nNeededTime(nStopTime - nStartTime); + const double fTimePerPaint((double)nNeededTime / (double)nRepeatCount); + + if(!bTimesInited) + { + for(a = 0; a < REMEMBERED_TIMES_COUNT; a++) + { + fLastTimes[a] = fTimePerPaint; + } + + bTimesInited = true; + } + else + { + for(a = 1; a < REMEMBERED_TIMES_COUNT; a++) + { + fLastTimes[a - 1] = fLastTimes[a]; + } + + fLastTimes[REMEMBERED_TIMES_COUNT - 1] = fTimePerPaint; + } + + double fAddedTimes(0.0); + + for(a = 0; a < REMEMBERED_TIMES_COUNT; a++) + { + fAddedTimes += fLastTimes[a]; + } + + const double fAverageTimePerPaint(fAddedTimes / (double)REMEMBERED_TIMES_COUNT); + + fprintf(stderr, "-----------(start result)----------\n"); + fprintf(stderr, "StartTime : %" SAL_PRIuUINT64 ", StopTime: %" SAL_PRIuUINT64 ", NeededTime: %" SAL_PRIuUINT64 ", TimePerPaint: %f\n", nStartTime, nStopTime, nNeededTime, fTimePerPaint); + fprintf(stderr, "Remembered times: "); + + for(a = 0; a < REMEMBERED_TIMES_COUNT; a++) + { + fprintf(stderr, "%d: %f ", a, fLastTimes[a]); + } + + fprintf(stderr, "\n"); + fprintf(stderr, "AverageTimePerPaint: %f\n", fAverageTimePerPaint); + fprintf(stderr, "-----------(stop result)----------\n"); + } +#endif // SVX_REPAINT_TIMER_TEST +} + + +// #i72889# + +SdrPaintWindow* SdrPaintView::BeginCompleteRedraw(OutputDevice* pOut) +{ + OSL_ENSURE(pOut, "SdrPaintView::BeginCompleteRedraw: No OutDev (!)"); + SdrPaintWindow* pPaintWindow = FindPaintWindow(*pOut); + + if(pPaintWindow) + { + // draw preprocessing, only for known devices + // prepare PreRendering + pPaintWindow->PreparePreRenderDevice(); + } + else + { + // None of the known OutputDevices is the target of this paint, use + // a temporary SdrPaintWindow for this Redraw. + pPaintWindow = new SdrPaintWindow(*this, *pOut); + pPaintWindow->setTemporaryTarget(true); + } + + return pPaintWindow; +} + +void SdrPaintView::DoCompleteRedraw(SdrPaintWindow& rPaintWindow, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector) +{ + // redraw all PageViews with the target. This may expand the RedrawRegion + // at the PaintWindow, plus taking care of FormLayer expansion + if(mpPageView) + { + mpPageView->CompleteRedraw(rPaintWindow, rReg, pRedirector); + } +} + +void SdrPaintView::EndCompleteRedraw(SdrPaintWindow& rPaintWindow, bool bPaintFormLayer) +{ + std::unique_ptr<SdrPaintWindow> pPaintWindow; + if (comphelper::LibreOfficeKit::isActive() && rPaintWindow.getTemporaryTarget()) + { + // Tiled rendering, we must paint the TextEdit to the output device. + pPaintWindow.reset(&rPaintWindow); + pPaintWindow->setTemporaryTarget(false); + } + + if(rPaintWindow.getTemporaryTarget()) + { + // get rid of temp target again + delete &rPaintWindow; + } + else + { + // draw postprocessing, only for known devices + // it is necessary to always paint FormLayer + // In the LOK case control rendering is performed through LokControlHandler + if(!comphelper::LibreOfficeKit::isActive() && bPaintFormLayer) + { + ImpFormLayerDrawing(rPaintWindow); + } + + // look for active TextEdit. As long as this cannot be painted to a VDev, + // it cannot get part of buffering. In that case, output evtl. prerender + // early and paint text edit to window. + SdrPageView* pPageView = GetSdrPageView(); + if(IsTextEdit() && pPageView) + { + if (!comphelper::LibreOfficeKit::isActive() || mbPaintTextEdit) + static_cast< SdrView* >(this)->TextEditDrawing(rPaintWindow); + } + + if (comphelper::LibreOfficeKit::isActive() && pPageView) + { + // Look for active text edits in other views showing the same page, + // and show them as well. Show only if Page/MasterPage mode is matching. + bool bRequireMasterPage = pPageView->GetPage() ? pPageView->GetPage()->IsMasterPage() : false; + SdrViewIter::ForAllViews(pPageView->GetPage(), + [this, &bRequireMasterPage, &rPaintWindow] (SdrView* pView) + { + SdrPageView* pCurrentPageView = pView->GetSdrPageView(); + bool bIsCurrentMasterPage = (pCurrentPageView && pCurrentPageView->GetPage()) ? + pCurrentPageView->GetPage()->IsMasterPage() : false; + + if (pView == this || bRequireMasterPage != bIsCurrentMasterPage) + return false; + + if (pView->IsTextEdit() && pView->GetSdrPageView()) + { + pView->TextEditDrawing(rPaintWindow); + } + return false; + }); + } + + // draw Overlay, also to PreRender device if exists + rPaintWindow.DrawOverlay(rPaintWindow.GetRedrawRegion()); + + // output PreRendering + rPaintWindow.OutputPreRenderDevice(rPaintWindow.GetRedrawRegion()); + } +} + + +SdrPaintWindow* SdrPaintView::BeginDrawLayers(OutputDevice* pOut, const vcl::Region& rReg, bool bDisableIntersect) +{ + // #i74769# use BeginCompleteRedraw() as common base + SdrPaintWindow* pPaintWindow = BeginCompleteRedraw(pOut); + OSL_ENSURE(pPaintWindow, "SdrPaintView::BeginDrawLayers: No SdrPaintWindow (!)"); + + if(mpPageView) + { + SdrPageWindow* pKnownTarget = mpPageView->FindPageWindow(*pPaintWindow); + + if(pKnownTarget) + { + vcl::Region aOptimizedRepaintRegion = OptimizeDrawLayersRegion( pOut, rReg, bDisableIntersect ); + + // prepare redraw + pKnownTarget->PrepareRedraw(aOptimizedRepaintRegion); + + // remember prepared SdrPageWindow + mpPageView->setPreparedPageWindow(pKnownTarget); + } + } + + return pPaintWindow; +} + +void SdrPaintView::EndDrawLayers(SdrPaintWindow& rPaintWindow, bool bPaintFormLayer) +{ + // #i74769# use EndCompleteRedraw() as common base + EndCompleteRedraw(rPaintWindow, bPaintFormLayer); + + if(mpPageView) + { + // forget prepared SdrPageWindow + mpPageView->setPreparedPageWindow(nullptr); + } +} + +void SdrPaintView::UpdateDrawLayersRegion(const OutputDevice* pOut, const vcl::Region& rReg) +{ + SdrPaintWindow* pPaintWindow = FindPaintWindow(*pOut); + OSL_ENSURE(pPaintWindow, "SdrPaintView::UpdateDrawLayersRegion: No SdrPaintWindow (!)"); + + if(mpPageView) + { + SdrPageWindow* pKnownTarget = mpPageView->FindPageWindow(*pPaintWindow); + + if(pKnownTarget) + { + vcl::Region aOptimizedRepaintRegion = OptimizeDrawLayersRegion( pOut, rReg, false/*bDisableIntersect*/ ); + pKnownTarget->GetPaintWindow().SetRedrawRegion(aOptimizedRepaintRegion); + mpPageView->setPreparedPageWindow(pKnownTarget); // already set actually + } + } +} + +vcl::Region SdrPaintView::OptimizeDrawLayersRegion(const OutputDevice* pOut, const vcl::Region& rReg, bool bDisableIntersect) +{ + // #i74769# check if pOut is a win and has a ClipRegion. If Yes, the Region + // rReg may be made more granular (fine) with using it. Normally, rReg + // does come from Window::Paint() anyways and thus is based on a single + // rectangle which was derived from exactly that repaint region + vcl::Region aOptimizedRepaintRegion(rReg); + + // #i76114# Intersecting the region with the Window's paint region is disabled + // for print preview in Calc, because the intersection can be empty (if the paint + // region is outside of the table area of the page), and then no clip region + // would be set. + if(pOut && OUTDEV_WINDOW == pOut->GetOutDevType() && !bDisableIntersect) + { + vcl::Window* pWindow = pOut->GetOwnerWindow(); + + if(pWindow->IsInPaint()) + { + if(!pWindow->GetPaintRegion().IsEmpty()) + { + aOptimizedRepaintRegion.Intersect(pWindow->GetPaintRegion()); + } + } + } + return aOptimizedRepaintRegion; +} + + +void SdrPaintView::ImpFormLayerDrawing( SdrPaintWindow& rPaintWindow ) +{ + if(!mpPageView) + return; + + SdrPageWindow* pKnownTarget = mpPageView->FindPageWindow(rPaintWindow); + + if(pKnownTarget) + { + const SdrModel& rModel = GetModel(); + const SdrLayerAdmin& rLayerAdmin = rModel.GetLayerAdmin(); + const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID(rLayerAdmin.GetControlLayerName()); + + // BUFFERED use GetTargetOutputDevice() now, it may be targeted to VDevs, too + // need to set PreparedPageWindow to make DrawLayer use the correct ObjectContact + mpPageView->setPreparedPageWindow(pKnownTarget); + mpPageView->DrawLayer(nControlLayerId, &rPaintWindow.GetTargetOutputDevice()); + mpPageView->setPreparedPageWindow(nullptr); + } +} + + +bool SdrPaintView::KeyInput(const KeyEvent& /*rKEvt*/, vcl::Window* /*pWin*/) +{ + return false; +} + +void SdrPaintView::GlueInvalidate() const +{ + // Do not invalidate GluePoints in Online + // They are handled on front-end + if (comphelper::LibreOfficeKit::isActive()) + return; + + const sal_uInt32 nWindowCount(PaintWindowCount()); + + for(sal_uInt32 nWinNum(0); nWinNum < nWindowCount; nWinNum++) + { + SdrPaintWindow* pPaintWindow = GetPaintWindow(nWinNum); + + if(pPaintWindow->OutputToWindow()) + { + OutputDevice& rOutDev = pPaintWindow->GetOutputDevice(); + + if(mpPageView) + { + const SdrObjList* pOL=mpPageView->GetObjList(); + for (const rtl::Reference<SdrObject>& pObj : *pOL) { + const SdrGluePointList* pGPL=pObj->GetGluePointList(); + if (pGPL!=nullptr && pGPL->GetCount()!=0) { + pGPL->Invalidate(*rOutDev.GetOwnerWindow(), pObj.get()); + } + } + } + } + } +} + +void SdrPaintView::InvalidateAllWin() +{ + const sal_uInt32 nWindowCount(PaintWindowCount()); + + for(sal_uInt32 a(0); a < nWindowCount; a++) + { + SdrPaintWindow* pPaintWindow = GetPaintWindow(a); + + if(pPaintWindow->OutputToWindow()) + { + InvalidateOneWin(pPaintWindow->GetOutputDevice()); + } + } +} + +void SdrPaintView::InvalidateAllWin(const tools::Rectangle& rRect) +{ + const sal_uInt32 nWindowCount(PaintWindowCount()); + + for(sal_uInt32 a(0); a < nWindowCount; a++) + { + SdrPaintWindow* pPaintWindow = GetPaintWindow(a); + + if(pPaintWindow->OutputToWindow()) + { + OutputDevice& rOutDev = pPaintWindow->GetOutputDevice(); + tools::Rectangle aRect(rRect); + + Point aOrg(rOutDev.GetMapMode().GetOrigin()); + aOrg.setX(-aOrg.X() ); aOrg.setY(-aOrg.Y() ); + tools::Rectangle aOutRect(aOrg, rOutDev.GetOutputSize()); + + // In case of tiled rendering we want to get all invalidations, so visual area is not interesting. + if (aRect.Overlaps(aOutRect) || comphelper::LibreOfficeKit::isActive()) + { + InvalidateOneWin(rOutDev, aRect); + } + } + } +} + +void SdrPaintView::InvalidateOneWin(OutputDevice& rDevice) +{ + // do not erase background, that causes flicker (!) + rDevice.GetOwnerWindow()->Invalidate(InvalidateFlags::NoErase); +} + +void SdrPaintView::InvalidateOneWin(OutputDevice& rDevice, const tools::Rectangle& rRect) +{ + // do not erase background, that causes flicker (!) + rDevice.GetOwnerWindow()->Invalidate(rRect, InvalidateFlags::NoErase); +} + +void SdrPaintView::LeaveOneGroup() +{ + if(mpPageView) + { + mpPageView->LeaveOneGroup(); + } +} + +void SdrPaintView::LeaveAllGroup() +{ + if(mpPageView) + { + mpPageView->LeaveAllGroup(); + } +} + +bool SdrPaintView::IsGroupEntered() const +{ + if(mpPageView) + { + return (mpPageView->GetEnteredLevel() != 0); + } + + return false; +} + +void SdrPaintView::SetNotPersistDefaultAttr(const SfxItemSet& rAttr) +{ + // bReplaceAll has no effect here at all. + bool bMeasure= dynamic_cast<const SdrView*>(this) != nullptr && static_cast<SdrView*>(this)->IsMeasureTool(); + + if (const SdrLayerIdItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LAYERID)) + { + SdrLayerID nLayerId = pPoolItem->GetValue(); + const SdrLayer* pLayer = GetModel().GetLayerAdmin().GetLayerPerID(nLayerId); + if (pLayer!=nullptr) { + if (bMeasure) maMeasureLayer=pLayer->GetName(); + else maActualLayer=pLayer->GetName(); + } + } + if (const SdrLayerNameItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LAYERNAME)) + { + if (bMeasure) maMeasureLayer = pPoolItem->GetValue(); + else maActualLayer = pPoolItem->GetValue(); + } +} + +void SdrPaintView::MergeNotPersistDefaultAttr(SfxItemSet& rAttr) const +{ + // bOnlyHardAttr has no effect here at all. + bool bMeasure= dynamic_cast<const SdrView*>(this) != nullptr && static_cast<const SdrView*>(this)->IsMeasureTool(); + const OUString& aNam = bMeasure ? maMeasureLayer : maActualLayer; + rAttr.Put(SdrLayerNameItem(aNam)); + SdrLayerID nLayer = GetModel().GetLayerAdmin().GetLayerID(aNam); + if (nLayer!=SDRLAYER_NOTFOUND) { + rAttr.Put(SdrLayerIdItem(nLayer)); + } +} + +void SdrPaintView::SetDefaultAttr(const SfxItemSet& rAttr, bool bReplaceAll) +{ +#ifdef DBG_UTIL + { + bool bHasEEFeatureItems=false; + SfxItemIter aIter(rAttr); + for (const SfxPoolItem* pItem = aIter.GetCurItem(); !bHasEEFeatureItems && pItem; + pItem = aIter.NextItem()) + { + if (!IsInvalidItem(pItem)) { + sal_uInt16 nW=pItem->Which(); + if (nW>=EE_FEATURE_START && nW<=EE_FEATURE_END) bHasEEFeatureItems=true; + } + } + + if(bHasEEFeatureItems) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr, + VclMessageType::Info, VclButtonsType::Ok, + "SdrPaintView::SetDefaultAttr(): Setting EE_FEATURE items at the SdrView does not make sense! It only leads to overhead and unreadable documents.")); + xInfoBox->run(); + } + } +#endif + if (bReplaceAll) maDefaultAttr.Set(rAttr); + else maDefaultAttr.Put(rAttr,false); // if FALSE, regard InvalidItems as "holes," not as Default + SetNotPersistDefaultAttr(rAttr); +} + +void SdrPaintView::SetDefaultStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr) +{ + if (mpDefaultStyleSheet) + EndListening(*mpDefaultStyleSheet); + mpDefaultStyleSheet=pStyleSheet; + if (mpDefaultStyleSheet) + StartListening(*mpDefaultStyleSheet); + + if (pStyleSheet!=nullptr && !bDontRemoveHardAttr) { + SfxWhichIter aIter(pStyleSheet->GetItemSet()); + sal_uInt16 nWhich=aIter.FirstWhich(); + while (nWhich!=0) { + if (aIter.GetItemState()==SfxItemState::SET) { + maDefaultAttr.ClearItem(nWhich); + } + nWhich=aIter.NextWhich(); + } + } +} + +void SdrPaintView::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const +{ + if(bOnlyHardAttr || !mpDefaultStyleSheet) + { + rTargetSet.Put(maDefaultAttr, false); + } + else + { + // else merge with DefStyleSheet + rTargetSet.Put(mpDefaultStyleSheet->GetItemSet(), false); + rTargetSet.Put(maDefaultAttr, false); + } + MergeNotPersistDefaultAttr(rTargetSet); +} + +void SdrPaintView::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll) +{ + SetDefaultAttr(rSet,bReplaceAll); +} + +SfxStyleSheet* SdrPaintView::GetStyleSheet() const +{ + return mpDefaultStyleSheet; +} + +void SdrPaintView::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr) +{ + SetDefaultStyleSheet(pStyleSheet,bDontRemoveHardAttr); +} + +void SdrPaintView::MakeVisible(const tools::Rectangle& rRect, vcl::Window& rWin) +{ + // TODO: handle when the text cursor goes out of the chart area + // However this hack avoids that the cursor gets misplaced wrt the text. + if (comphelper::LibreOfficeKit::isActive() && rWin.IsChart()) + { + return; + } + + MapMode aMap(rWin.GetMapMode()); + Size aActualSize(rWin.GetOutDev()->GetOutputSize()); + + if( aActualSize.IsEmpty() ) + return; + + Size aNewSize(rRect.GetSize()); + bool bNewScale=false; + bool bNeedMoreX=aNewSize.Width()>aActualSize.Width(); + bool bNeedMoreY=aNewSize.Height()>aActualSize.Height(); + if (bNeedMoreX || bNeedMoreY) + { + bNewScale=true; + // set new MapMode (Size+Org) and invalidate everything + Fraction aXFact(aNewSize.Width(),aActualSize.Width()); + Fraction aYFact(aNewSize.Height(),aActualSize.Height()); + if (aYFact>aXFact) aXFact=aYFact; + aXFact*=aMap.GetScaleX(); + aXFact.ReduceInaccurate(10); // to avoid runovers and BigInt mapping + aMap.SetScaleX(aXFact); + aMap.SetScaleY(aYFact); + rWin.SetMapMode(aMap); + aActualSize=rWin.GetOutDev()->GetOutputSize(); + } + Point aOrg(aMap.GetOrigin()); + tools::Long dx=0,dy=0; + tools::Long l=-aOrg.X(); + tools::Long r=-aOrg.X()+aActualSize.Width()-1; + tools::Long o=-aOrg.Y(); + tools::Long u=-aOrg.Y()+aActualSize.Height()-1; + if (l>rRect.Left()) dx=rRect.Left()-l; + else if (r<rRect.Right()) dx=rRect.Right()-r; + if (o>rRect.Top()) dy=rRect.Top()-o; + else if (u<rRect.Bottom()) dy=rRect.Bottom()-u; + aMap.SetOrigin(Point(aOrg.X()-dx,aOrg.Y()-dy)); + if (!bNewScale) { + if (dx!=0 || dy!=0) { + rWin.Scroll(-dx,-dy); + rWin.SetMapMode(aMap); + rWin.PaintImmediately(); + } + } else { + rWin.SetMapMode(aMap); + InvalidateOneWin(*rWin.GetOutDev()); + } +} + +void SdrPaintView::DoConnect(SdrOle2Obj* /*pOleObj*/) +{ +} + +void SdrPaintView::SetAnimationEnabled( bool bEnable ) +{ + SetAnimationMode( bEnable ? SdrAnimationMode::Animate : SdrAnimationMode::Disable ); +} + +void SdrPaintView::SetAnimationPause( bool bSet ) +{ + if(mbAnimationPause == bSet) + return; + + mbAnimationPause = bSet; + + if(!mpPageView) + return; + + for(sal_uInt32 b(0); b < mpPageView->PageWindowCount(); b++) + { + SdrPageWindow& rPageWindow = *(mpPageView->GetPageWindow(b)); + sdr::contact::ObjectContact& rObjectContact = rPageWindow.GetObjectContact(); + sdr::animation::primitiveAnimator& rAnimator = rObjectContact.getPrimitiveAnimator(); + + if(rAnimator.IsPaused() != bSet) + { + rAnimator.SetPaused(bSet); + } + } +} + +void SdrPaintView::SetAnimationMode( const SdrAnimationMode eMode ) +{ + meAnimationMode = eMode; +} + +void SdrPaintView::VisAreaChanged(const OutputDevice* pOut) +{ + if(!mpPageView) + return; + + if (pOut) + { + SdrPageWindow* pWindow = mpPageView->FindPageWindow(*const_cast<OutputDevice*>(pOut)); + + if(pWindow) + { + VisAreaChanged(); + } + } + else + { + VisAreaChanged(); + } +} + +void SdrPaintView::VisAreaChanged() +{ + // notify SfxListener + Broadcast(SvxViewChangedHint()); +} + + +void SdrPaintView::onChangeColorConfig() +{ + maGridColor = maColorConfig.GetColorValue( svtools::DRAWGRID ).nColor; +} + + +// Set background color for svx at SdrPageViews +void SdrPaintView::SetApplicationBackgroundColor(Color aBackgroundColor) +{ + if(mpPageView) + { + mpPageView->SetApplicationBackgroundColor(aBackgroundColor); + } +} + +// Set document color for svx at SdrPageViews +void SdrPaintView::SetApplicationDocumentColor(Color aDocumentColor) +{ + if(mpPageView) + { + mpPageView->SetApplicationDocumentColor(aDocumentColor); + } +} + +bool SdrPaintView::IsBufferedOutputAllowed() const +{ + return (mbBufferedOutputAllowed && SvtOptionsDrawinglayer::IsPaintBuffer()); +} + +void SdrPaintView::SetBufferedOutputAllowed(bool bNew) +{ + if(bNew != mbBufferedOutputAllowed) + { + mbBufferedOutputAllowed = bNew; + } +} + +bool SdrPaintView::IsBufferedOverlayAllowed() const +{ + return (mbBufferedOverlayAllowed && SvtOptionsDrawinglayer::IsOverlayBuffer()); +} + +void SdrPaintView::SetBufferedOverlayAllowed(bool bNew) +{ + if(bNew != mbBufferedOverlayAllowed) + { + mbBufferedOverlayAllowed = bNew; + } +} + + +void SdrPaintView::SetPageDecorationAllowed(bool bNew) +{ + if(bNew != mbPageDecorationAllowed) + { + mbPageDecorationAllowed = bNew; + } +} + +void SdrPaintView::SetMasterPageVisualizationAllowed(bool bNew) +{ + if(bNew != mbMasterPageVisualizationAllowed) + { + mbMasterPageVisualizationAllowed = bNew; + } +} + +// #i38135# Sets the timer for Object animations and restarts. +void SdrPaintView::SetAnimationTimer(sal_uInt32 nTime) +{ + if(mpPageView) + { + // first, reset all timers at all windows to 0L + for(sal_uInt32 a(0); a < mpPageView->PageWindowCount(); a++) + { + SdrPageWindow& rPageWindow = *mpPageView->GetPageWindow(a); + sdr::contact::ObjectContact& rObjectContact = rPageWindow.GetObjectContact(); + sdr::animation::primitiveAnimator& rAnimator = rObjectContact.getPrimitiveAnimator(); + rAnimator.SetTime(nTime); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |