/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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& 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(&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(this)->ImpComeBackHdl(&const_cast(this)->maComeBackIdle); const_cast(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) { if (comphelper::LibreOfficeKit::isActive()) { mnHitTolLog=static_cast(OutputDevice::LogicToLogic(Size(mnHitTolPix,0), MapMode(MapUnit::MapPixel), mpActualOutDev->GetMapMode()).Width()); mnMinMovLog=static_cast(OutputDevice::LogicToLogic(Size(mnMinMovPix,0), MapMode(MapUnit::MapPixel), mpActualOutDev->GetMapMode()).Width()); } else { mnHitTolLog=static_cast(mpActualOutDev->PixelToLogic(Size(mnHitTolPix,0)).Width()); mnMinMovLog=static_cast(mpActualOutDev->PixelToLogic(Size(mnMinMovPix,0)).Width()); } } } void SdrPaintView::SetActualWin(const OutputDevice* pWin) { mpActualOutDev = const_cast(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(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) { const bool bChanged = mpPageView && mpPageView->SetLayerVisible(rName, bShow); if (!bChanged) return; InvalidateAllWin(); } bool SdrPaintView::IsLayerVisible(const OUString& rName) const { return mpPageView && mpPageView->IsLayerVisible(rName); } 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); assert(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) { assert(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 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); assert(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); assert(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& 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 (!) // tdf#160444 check device's owner window is a nullptr // Since commit 563f7077f1dbce31ff95ee8d2e8d17b629693db1, the // device's owner window gets deleted before this object is // deleted. if (rDevice.GetOwnerWindow()) 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(this) != nullptr && static_cast(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(this) != nullptr && static_cast(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 xInfoBox(Application::CreateMessageDialog(nullptr, VclMessageType::Info, VclButtonsType::Ok, u"SdrPaintView::SetDefaultAttr(): Setting EE_FEATURE items at the SdrView does not make sense! It only leads to overhead and unreadable documents."_ustr)); 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 (rrRect.Top()) dy=rRect.Top()-o; else if (uPageWindowCount(); 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(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 && officecfg::Office::Common::Drawinglayer::PaintBuffer::get()); } void SdrPaintView::SetBufferedOutputAllowed(bool bNew) { if(bNew != mbBufferedOutputAllowed) { mbBufferedOutputAllowed = bNew; } } bool SdrPaintView::IsBufferedOverlayAllowed() const { return (mbBufferedOverlayAllowed && officecfg::Office::Common::Drawinglayer::OverlayBuffer::get()); } 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: */