simplify writeBitmapObject
[LibreOffice.git] / sw / source / core / view / viewsh.cxx
blobe8db55ee359c75b8c08775bbe414a57763672e89
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/themecolors.hxx>
21 #include <officecfg/Office/Common.hxx>
22 #include <config_wasm_strip.h>
24 #include <com/sun/star/accessibility/XAccessible.hpp>
25 #include <sfx2/viewfrm.hxx>
26 #include <sfx2/progress.hxx>
27 #include <svx/srchdlg.hxx>
28 #include <sfx2/viewsh.hxx>
29 #include <sfx2/ipclient.hxx>
30 #include <sal/log.hxx>
31 #include <drawdoc.hxx>
32 #include <swwait.hxx>
33 #include <crsrsh.hxx>
34 #include <doc.hxx>
35 #include <IDocumentDeviceAccess.hxx>
36 #include <IDocumentDrawModelAccess.hxx>
37 #include <IDocumentOutlineNodes.hxx>
38 #include <IDocumentFieldsAccess.hxx>
39 #include <IDocumentLayoutAccess.hxx>
40 #include <IDocumentState.hxx>
41 #include <rootfrm.hxx>
42 #include <pagefrm.hxx>
43 #include <viewimp.hxx>
44 #include <frmtool.hxx>
45 #include <viewopt.hxx>
46 #include <dview.hxx>
47 #include <swregion.hxx>
48 #include <hints.hxx>
49 #include <docufld.hxx>
50 #include <txtfrm.hxx>
51 #include <layact.hxx>
52 #include <mdiexp.hxx>
53 #include <fntcache.hxx>
54 #include <ptqueue.hxx>
55 #include <docsh.hxx>
56 #include <bookmark.hxx>
57 #include <ndole.hxx>
58 #include <ndindex.hxx>
59 #include <accmap.hxx>
60 #include <vcl/bitmapex.hxx>
61 #include <accessibilityoptions.hxx>
62 #include <strings.hrc>
63 #include <bitmaps.hlst>
64 #include <pagepreviewlayout.hxx>
65 #include <sortedobjs.hxx>
66 #include <anchoredobject.hxx>
67 #include <DocumentSettingManager.hxx>
68 #include <DocumentRedlineManager.hxx>
69 #include <DocumentLayoutManager.hxx>
71 #include <unotxdoc.hxx>
72 #include <view.hxx>
73 #include <PostItMgr.hxx>
74 #include <unotools/configmgr.hxx>
75 #include <vcl/virdev.hxx>
76 #include <vcl/svapp.hxx>
77 #include <svx/sdrpaintwindow.hxx>
78 #include <svx/sdrpagewindow.hxx>
79 #include <svx/svdpagv.hxx>
80 #include <comphelper/lok.hxx>
81 #include <sfx2/lokhelper.hxx>
82 #include <tools/UnitConversion.hxx>
84 #if !HAVE_FEATURE_DESKTOP
85 #include <vcl/sysdata.hxx>
86 #endif
88 #include <frameformats.hxx>
89 #include <fmtcntnt.hxx>
91 bool SwViewShell::sbLstAct = false;
92 ShellResource *SwViewShell::spShellRes = nullptr;
94 static tools::DeleteOnDeinit<std::shared_ptr<weld::Window>>& getCareDialog()
96 static tools::DeleteOnDeinit<std::shared_ptr<weld::Window>> spCareDialog {}; ///< Avoid this window.
97 return spCareDialog;
100 static bool bInSizeNotify = false;
103 using namespace ::com::sun::star;
105 void SwViewShell::SetShowHeaderFooterSeparator( FrameControlType eControl, bool bShow ) {
107 //tdf#118621 - Optionally disable floating header/footer menu
108 if ( bShow )
109 bShow = GetViewOptions()->IsUseHeaderFooterMenu();
111 if ( eControl == FrameControlType::Header )
112 mbShowHeaderSeparator = bShow;
113 else
114 mbShowFooterSeparator = bShow;
117 void SwViewShell::ToggleHeaderFooterEdit()
119 mbHeaderFooterEdit = !mbHeaderFooterEdit;
120 if ( !mbHeaderFooterEdit )
122 SetShowHeaderFooterSeparator( FrameControlType::Header, false );
123 SetShowHeaderFooterSeparator( FrameControlType::Footer, false );
126 // Avoid corner case
127 if ( ( GetViewOptions()->IsUseHeaderFooterMenu() ) &&
128 ( !IsShowHeaderFooterSeparator( FrameControlType::Header ) &&
129 !IsShowHeaderFooterSeparator( FrameControlType::Footer ) ) )
131 mbHeaderFooterEdit = false;
134 InvalidatePageAndHFSubsidiaryLines();
137 // Invalidate Subsidiary Lines around headers/footers and page frames to repaint
138 void SwViewShell::InvalidatePageAndHFSubsidiaryLines()
140 RectangleVector aInvalidRects;
141 SwPageFrame *pPg = static_cast<SwPageFrame*>(GetLayout()->Lower());
142 while (pPg)
144 pPg->AddSubsidiaryLinesBounds(*this, aInvalidRects);
145 pPg = static_cast<SwPageFrame*>(pPg->GetNext());
148 for (const auto &rRect : aInvalidRects)
149 GetWin()->Invalidate(rRect);
152 void SwViewShell::setOutputToWindow(bool bOutputToWindow)
154 mbOutputToWindow = bOutputToWindow;
157 bool SwViewShell::isOutputToWindow() const
159 return mbOutputToWindow;
162 void SwViewShell::dumpAsXml(xmlTextWriterPtr pWriter) const
164 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwViewShell"));
165 mpOpt->dumpAsXml(pWriter);
166 (void)xmlTextWriterEndElement(pWriter);
169 static void
170 lcl_PaintTransparentFormControls(SwViewShell const & rShell, SwRect const& rRect)
172 // Direct paint has been performed: the background of transparent child
173 // windows has been painted, so need to paint the child windows now.
174 if (rShell.GetWin())
176 vcl::Window& rWindow = *(rShell.GetWin());
177 const tools::Rectangle aRectanglePixel(rShell.GetOut()->LogicToPixel(rRect.SVRect()));
178 PaintTransparentChildren(rWindow, aRectanglePixel);
182 // #i72754# 2nd set of Pre/PostPaints
183 // This time it uses the lock counter (mPrePostPaintRegions empty/non-empty) to allow only one activation
184 // and deactivation and mpPrePostOutDev to remember the OutDev from the BeginDrawLayers
185 // call. That way, all places where paint take place can be handled the same way, even
186 // when calling other paint methods. This is the case at the places where SW paints
187 // buffered into VDevs to avoid flicker. It is in general problematic and should be
188 // solved once using the BufferedOutput functionality of the DrawView.
190 void SwViewShell::PrePaint()
192 // forward PrePaint event from VCL Window to DrawingLayer
193 if(HasDrawView())
195 Imp()->GetDrawView()->PrePaint();
199 void SwViewShell::DLPrePaint2(const vcl::Region& rRegion)
201 if(mPrePostPaintRegions.empty())
203 mPrePostPaintRegions.push( rRegion );
204 // #i75172# ensure DrawView to use DrawingLayer bufferings
205 if ( !HasDrawView() )
206 MakeDrawView();
208 // Prefer window; if not available, get mpOut (e.g. printer)
209 const bool bWindow = GetWin() && !comphelper::LibreOfficeKit::isActive() && !isOutputToWindow();
210 mpPrePostOutDev = bWindow ? GetWin()->GetOutDev() : GetOut();
212 // #i74769# use SdrPaintWindow now direct
213 mpTargetPaintWindow = Imp()->GetDrawView()->BeginDrawLayers(mpPrePostOutDev, rRegion);
214 assert(mpTargetPaintWindow && "BeginDrawLayers: Got no SdrPaintWindow (!)");
216 // #i74769# if prerender, save OutDev and redirect to PreRenderDevice
217 if(mpTargetPaintWindow->GetPreRenderDevice())
219 mpBufferedOut = mpOut;
220 mpOut = &(mpTargetPaintWindow->GetTargetOutputDevice());
222 else if (isOutputToWindow())
223 // In case mpOut is used without buffering and we're not printing, need to set clipping.
224 mpOut->SetClipRegion(rRegion);
226 // remember original paint MapMode for wrapped FlyFrame paints
227 maPrePostMapMode = mpOut->GetMapMode();
229 else
231 // region needs to be updated to the given one
232 if( mPrePostPaintRegions.top() != rRegion )
233 Imp()->GetDrawView()->UpdateDrawLayersRegion(mpPrePostOutDev, rRegion);
234 mPrePostPaintRegions.push( rRegion );
238 void SwViewShell::DLPostPaint2(bool bPaintFormLayer)
240 OSL_ENSURE(!mPrePostPaintRegions.empty(), "SwViewShell::DLPostPaint2: Pre/PostPaint encapsulation broken (!)");
242 if( mPrePostPaintRegions.size() > 1 )
244 vcl::Region current = std::move(mPrePostPaintRegions.top());
245 mPrePostPaintRegions.pop();
246 if( current != mPrePostPaintRegions.top())
247 Imp()->GetDrawView()->UpdateDrawLayersRegion(mpPrePostOutDev, mPrePostPaintRegions.top());
248 return;
250 mPrePostPaintRegions.pop(); // clear
251 if(nullptr != mpTargetPaintWindow)
253 // #i74769# restore buffered OutDev
254 if(mpTargetPaintWindow->GetPreRenderDevice())
256 mpOut = mpBufferedOut;
259 // #i74769# use SdrPaintWindow now direct
260 SwViewObjectContactRedirector aSwRedirector(*this);
261 Imp()->GetDrawView()->EndDrawLayers(*mpTargetPaintWindow, bPaintFormLayer, &aSwRedirector);
262 mpTargetPaintWindow = nullptr;
265 // end of Pre/PostPaints
267 void SwViewShell::StartAllAction()
269 for (SwViewShell & rCurrentShell : GetRingContainer())
271 rCurrentShell.StartAction();
275 void SwViewShell::EndAllAction()
277 for (SwViewShell & rCurrentShell : GetRingContainer())
279 rCurrentShell.EndAction();
283 void SwViewShell::StartAction()
285 if (!mnStartAction++)
286 ImplStartAction();
289 void SwViewShell::EndAction(const bool bIdleEnd)
291 if (0 == (mnStartAction - 1))
292 ImplEndAction(bIdleEnd);
293 --mnStartAction;
296 void SwViewShell::ImplEndAction( const bool bIdleEnd )
298 // Nothing to do for the printer?
299 if ( !GetWin() || IsPreview() )
301 mbPaintWorks = true;
302 UISizeNotify();
303 // tdf#101464 print preview may generate events if another view shell
304 // performs layout...
305 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
306 if (IsPreview() && Imp()->IsAccessible())
308 Imp()->FireAccessibleEvents();
310 #endif
311 return;
314 mbInEndAction = true;
315 //will this put the EndAction of the last shell in the sequence?
317 SwViewShell::sbLstAct = true;
318 for(SwViewShell& rShell : GetRingContainer())
320 if(&rShell != this && rShell.ActionPend())
322 SwViewShell::sbLstAct = false;
323 break;
327 const bool bIsShellForCheckViewLayout = ( this == GetLayout()->GetCurrShell() );
329 CurrShell aCurr( this );
330 if ( Imp()->HasDrawView() && !Imp()->GetDrawView()->areMarkHandlesHidden() )
331 Imp()->StartAction();
333 if ( Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea() )
334 Imp()->DeletePaintRegion();
336 const bool bExtraData = ::IsExtraData( GetDoc() );
338 if ( !bIdleEnd )
340 SwLayAction aAction( GetLayout(), Imp() );
341 aAction.SetComplete( false );
342 if ( mnLockPaint )
343 aAction.SetPaint( false );
344 aAction.SetInputType( VclInputFlags::KEYBOARD );
345 aAction.Action(GetWin()->GetOutDev());
348 if ( bIsShellForCheckViewLayout )
349 GetLayout()->CheckViewLayout( GetViewOptions(), &maVisArea );
351 //If we don't call Paints, we wait for the Paint of the system.
352 //Then the clipping is set correctly; e.g. shifting of a Draw object
353 if ( Imp()->HasPaintRegion() ||
354 maInvalidRect.HasArea() ||
355 bExtraData )
357 if ( !mnLockPaint )
359 SolarMutexGuard aGuard;
361 bool bPaintsFromSystem = maInvalidRect.HasArea();
362 GetWin()->PaintImmediately();
363 if ( maInvalidRect.HasArea() )
365 if ( bPaintsFromSystem )
366 Imp()->AddPaintRect( maInvalidRect );
368 ResetInvalidRect();
369 bPaintsFromSystem = true;
371 mbPaintWorks = true;
373 std::optional<SwRegionRects> oRegion = Imp()->TakePaintRegion();
375 //JP 27.11.97: what hid the selection, must also Show it,
376 // else we get Paint errors!
377 // e.g. additional mode, page half visible vertically, in the
378 // middle a selection and with another cursor jump to left
379 // right border. Without ShowCursor the selection disappears.
380 bool bShowCursor = oRegion && dynamic_cast<const SwCursorShell*>(this) != nullptr;
381 if( bShowCursor )
382 static_cast<SwCursorShell*>(this)->HideCursors();
384 if ( oRegion )
386 SwRootFrame* pCurrentLayout = GetLayout();
388 oRegion->LimitToOrigin();
389 oRegion->Compress( SwRegionRects::CompressFuzzy );
391 while ( !oRegion->empty() )
393 SwRect aRect( oRegion->back() );
394 oRegion->pop_back();
396 if (GetWin()->SupportsDoubleBuffering())
397 InvalidateWindows(aRect);
398 else
400 // #i75172# begin DrawingLayer paint
401 // need to do begin/end DrawingLayer preparation for each single rectangle of the
402 // repaint region. I already tried to prepare only once for the whole Region. This
403 // seems to work (and does technically) but fails with transparent objects. Since the
404 // region given to BeginDrawLayers() defines the clip region for DrawingLayer paint,
405 // transparent objects in the single rectangles will indeed be painted multiple times.
406 if (!comphelper::LibreOfficeKit::isActive())
408 DLPrePaint2(vcl::Region(aRect.SVRect()));
411 if ( bPaintsFromSystem )
412 PaintDesktop(*GetOut(), aRect);
413 if (!comphelper::LibreOfficeKit::isActive())
414 pCurrentLayout->PaintSwFrame( *mpOut, aRect );
415 else
416 pCurrentLayout->GetCurrShell()->InvalidateWindows(aRect);
418 // #i75172# end DrawingLayer paint
419 if (!comphelper::LibreOfficeKit::isActive())
421 DLPostPaint2(true);
425 lcl_PaintTransparentFormControls(*this, aRect); // i#107365
428 if( bShowCursor )
429 static_cast<SwCursorShell*>(this)->ShowCursors( true );
431 else
433 Imp()->DeletePaintRegion();
434 mbPaintWorks = true;
437 else
438 mbPaintWorks = true;
440 mbInEndAction = false;
441 SwViewShell::sbLstAct = false;
442 Imp()->EndAction();
444 //We artificially end the action here to enable the automatic scrollbars
445 //to adjust themselves correctly
446 //EndAction sends a Notify, and that must call Start-/EndAction to
447 //adjust the scrollbars correctly
448 --mnStartAction;
449 UISizeNotify();
450 ++mnStartAction;
452 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
453 if( Imp()->IsAccessible() )
454 Imp()->FireAccessibleEvents();
455 #endif
458 void SwViewShell::ImplStartAction()
460 mbPaintWorks = false;
461 Imp()->StartAction();
464 void SwViewShell::ImplLockPaint()
466 if ( GetWin() && GetWin()->IsVisible() && !comphelper::LibreOfficeKit::isActive())
467 GetWin()->EnablePaint( false ); //Also cut off the controls.
468 Imp()->LockPaint();
471 void SwViewShell::ImplUnlockPaint(std::vector<LockPaintReason>& rReasons, bool bVirDev)
473 CurrShell aCurr( this );
474 if ( GetWin() && GetWin()->IsVisible() )
476 if ( (bInSizeNotify || bVirDev ) && VisArea().HasArea() && !comphelper::LibreOfficeKit::isActive())
478 //Refresh with virtual device to avoid flickering.
479 VclPtrInstance<VirtualDevice> pVout( *mpOut );
480 pVout->SetMapMode( mpOut->GetMapMode() );
481 Size aSize( VisArea().SSize() );
482 aSize.AdjustWidth(20 );
483 aSize.AdjustHeight(20 );
484 if( pVout->SetOutputSize( aSize ) )
486 GetWin()->EnablePaint( true );
487 GetWin()->Validate();
489 Imp()->UnlockPaint();
490 pVout->SetLineColor( mpOut->GetLineColor() );
491 pVout->SetFillColor( mpOut->GetFillColor() );
493 // #i72754# start Pre/PostPaint encapsulation before mpOut is changed to the buffering VDev
494 const vcl::Region aRepaintRegion(VisArea().SVRect());
495 DLPrePaint2(aRepaintRegion);
497 OutputDevice *pOld = mpOut;
498 mpOut = pVout.get();
499 Paint(*mpOut, VisArea().SVRect());
500 mpOut = pOld;
501 mpOut->DrawOutDev( VisArea().Pos(), aSize,
502 VisArea().Pos(), aSize, *pVout );
504 // #i72754# end Pre/PostPaint encapsulation when mpOut is back and content is painted
505 DLPostPaint2(true);
507 lcl_PaintTransparentFormControls(*this, VisArea()); // fdo#63949
509 else
511 Imp()->UnlockPaint();
512 GetWin()->EnablePaint( true );
513 InvalidateAll(rReasons);
515 pVout.disposeAndClear();
517 else
519 Imp()->UnlockPaint();
520 GetWin()->EnablePaint( true );
521 InvalidateAll(rReasons);
524 else
525 Imp()->UnlockPaint();
528 namespace
530 std::string_view to_string(LockPaintReason eReason)
532 switch(eReason)
534 case LockPaintReason::ViewLayout:
535 return "ViewLayout";
536 case LockPaintReason::OuterResize:
537 return "OuterResize";
538 case LockPaintReason::Undo:
539 return "Undo";
540 case LockPaintReason::Redo:
541 return "Redo";
542 case LockPaintReason::OutlineFolding:
543 return "OutlineFolding";
544 case LockPaintReason::EndSdrCreate:
545 return "EndSdrCreate";
546 case LockPaintReason::SwLayIdle:
547 return "SwLayIdle";
548 case LockPaintReason::InvalidateLayout:
549 return "InvalidateLayout";
550 case LockPaintReason::StartDrag:
551 return "StartDrag";
552 case LockPaintReason::DataChanged:
553 return "DataChanged";
554 case LockPaintReason::InsertFrame:
555 return "InsertFrame";
556 case LockPaintReason::GotoPage:
557 return "GotoPage";
558 case LockPaintReason::InsertGraphic:
559 return "InsertGraphic";
560 case LockPaintReason::SetZoom:
561 return "SetZoom";
562 case LockPaintReason::ExampleFrame:
563 return "ExampleFram";
565 return "";
569 void SwViewShell::InvalidateAll(std::vector<LockPaintReason>& rReasons)
571 assert(!rReasons.empty() && "there must be a reason to InvalidateAll");
573 for (const auto& reason : rReasons)
574 SAL_INFO("sw.core", "InvalidateAll because of: " << to_string(reason));
576 if (comphelper::LibreOfficeKit::isActive())
578 // https://github.com/CollaboraOnline/online/issues/6379
579 // ditch OuterResize as a reason to invalidate all in the online case
580 std::erase(rReasons, LockPaintReason::OuterResize);
583 if (!rReasons.empty())
584 GetWin()->Invalidate(InvalidateFlags::Children);
585 rReasons.clear();
588 bool SwViewShell::AddPaintRect( const SwRect & rRect )
590 bool bRet = false;
591 for(SwViewShell& rSh : GetRingContainer())
593 if( rSh.Imp() )
595 if ( rSh.IsPreview() && rSh.GetWin() )
596 ::RepaintPagePreview( &rSh, rRect );
597 else
598 bRet |= rSh.Imp()->AddPaintRect( rRect );
601 return bRet;
604 void SwViewShell::InvalidateWindows( const SwRect &rRect )
606 if ( Imp()->IsCalcLayoutProgress() )
607 return;
609 if(comphelper::LibreOfficeKit::isActive())
611 // If we are inside tiled painting, invalidations are ignored.
612 // Ignore them right now to save work, but also to avoid the problem
613 // that this state could be reset before FlushPendingLOKInvalidateTiles()
614 // gets called.
615 if(comphelper::LibreOfficeKit::isTiledPainting())
616 return;
617 // First collect all invalidations and perform them only later,
618 // otherwise the number of Invalidate() calls would be at least
619 // O(n^2) if not worse. The problem is that if any change in a document
620 // is made, SwEditShell::EndAllAction() is called, which calls EndAction()
621 // for every view. And every view does it own handling of paint rectangles,
622 // and then calls InvalidateWindows() based on that. On then this code
623 // would call Invalidate() for all views for each rectangle.
624 // So collect the rectangles, avoid duplicates (which there usually will
625 // be many because of the repetitions), FlushPendingLOKInvalidateTiles()
626 // will collect all rectangles from all related views, compress them
627 // and only with those relatively few rectangle it'd call Invalidate()
628 // for all views.
629 Imp()->AddPendingLOKInvalidation(rRect);
630 return;
633 for(SwViewShell& rSh : GetRingContainer())
635 if ( rSh.GetWin() )
637 if ( rSh.IsPreview() )
638 ::RepaintPagePreview( &rSh, rRect );
639 // In case of tiled rendering, invalidation is wanted even if
640 // the rectangle is outside the visual area.
641 else if ( rSh.VisArea().Overlaps( rRect ) || comphelper::LibreOfficeKit::isActive() )
642 rSh.GetWin()->Invalidate( rRect.SVRect() );
647 void SwViewShell::FlushPendingLOKInvalidateTiles()
649 assert(comphelper::LibreOfficeKit::isActive());
650 SwRegionRects rects;
651 for(SwViewShell& rSh : GetRingContainer())
653 std::vector<SwRect> tmpRects = rSh.Imp()->TakePendingLOKInvalidations();
654 rects.insert( rects.end(), tmpRects.begin(), tmpRects.end());
656 rects.Compress( SwRegionRects::CompressFuzzy );
657 if(rects.empty())
658 return;
659 // This is basically the loop from SwViewShell::InvalidateWindows().
660 for(SwViewShell& rSh : GetRingContainer())
662 if ( rSh.GetWin() )
664 if ( rSh.IsPreview() )
666 for( const SwRect& rect : rects )
667 ::RepaintPagePreview( &rSh, rect );
669 else
671 for( const SwRect& rect : rects )
672 rSh.GetWin()->Invalidate( rect.SVRect() );
678 const SwRect& SwViewShell::VisArea() const
680 // when using the tiled rendering, consider the entire document as our
681 // visible area
682 return comphelper::LibreOfficeKit::isActive()? GetLayout()->getFrameArea(): maVisArea;
685 void SwViewShell::MakeVisible( const SwRect &rRect, ScrollSizeMode eScrollSizeMode )
687 if ( !(!VisArea().Contains( rRect ) || IsScrollMDI( this, rRect ) || GetCareDialog(*this)) )
688 return;
690 if ( IsViewLocked() )
691 return;
693 if( mpWin )
695 const SwFrame* pRoot = GetLayout();
696 int nLoopCnt = 3;
697 tools::Long nOldH;
699 nOldH = pRoot->getFrameArea().Height();
700 SwViewShell::StartAction();
701 ScrollMDI( this, rRect, USHRT_MAX, USHRT_MAX, eScrollSizeMode );
702 SwViewShell::EndAction(); // DO NOT call virtual here!
703 } while( nOldH != pRoot->getFrameArea().Height() && nLoopCnt-- );
705 #if OSL_DEBUG_LEVEL > 0
706 else
708 //MA: 04. Nov. 94, no one needs this, does one?
709 OSL_ENSURE( false, "Is MakeVisible still needed for printers?" );
712 #endif
715 weld::Window* SwViewShell::CareChildWin(SwViewShell const & rVSh)
717 if (!rVSh.mpSfxViewShell)
718 return nullptr;
719 #if HAVE_FEATURE_DESKTOP
720 const sal_uInt16 nId = SvxSearchDialogWrapper::GetChildWindowId();
721 SfxViewFrame& rVFrame = rVSh.mpSfxViewShell->GetViewFrame();
722 SfxChildWindow* pChWin = rVFrame.GetChildWindow( nId );
723 if (!pChWin)
724 return nullptr;
725 weld::DialogController* pController = pChWin->GetController().get();
726 if (!pController)
727 return nullptr;
728 weld::Window* pWin = pController->getDialog();
729 if (pWin && pWin->get_visible())
730 return pWin;
731 #endif
732 return nullptr;
735 Point SwViewShell::GetPagePos( sal_uInt16 nPageNum ) const
737 return GetLayout()->GetPagePos( nPageNum );
740 sal_uInt16 SwViewShell::GetNumPages() const
742 //It is possible that no layout exists when the method from
743 //root-Ctor is called.
744 return GetLayout() ? GetLayout()->GetPageNum() : 0;
747 bool SwViewShell::IsDummyPage( sal_uInt16 nPageNum ) const
749 return GetLayout() && GetLayout()->IsDummyPage( nPageNum );
753 * Forces update of each field.
754 * It notifies all fields with pNewHt. If that is 0 (default), the field
755 * type is sent (???).
756 * @param[in] bCloseDB Passed in to GetDoc()->UpdateFields. [TODO] Purpose???
758 void SwViewShell::UpdateFields(bool bCloseDB, bool bSetModified)
760 CurrShell aCurr( this );
762 StartAction();
764 GetDoc()->getIDocumentFieldsAccess().UpdateFields(bCloseDB, bSetModified);
766 EndAction();
769 void SwViewShell::UpdateOleObjectPreviews()
771 SwDoc* pDoc = GetDoc();
772 for(sw::SpzFrameFormat* pFormat: *pDoc->GetSpzFrameFormats())
774 if (pFormat->Which() != RES_FLYFRMFMT)
776 continue;
779 const SwNodeIndex* pNodeIndex = pFormat->GetContent().GetContentIdx();
780 if (!pNodeIndex || !pNodeIndex->GetNodes().IsDocNodes())
782 continue;
785 SwNode* pNode = pDoc->GetNodes()[pNodeIndex->GetIndex() + 1];
786 SwOLENode* pOleNode = pNode->GetOLENode();
787 if (!pOleNode)
789 continue;
792 SwOLEObj& rOleObj = pOleNode->GetOLEObj();
793 svt::EmbeddedObjectRef& rObject = rOleObj.GetObject();
794 rObject.UpdateReplacement( true );
795 // Trigger the repaint.
796 pOleNode->SetChanged();
800 /** update all charts for which any table exists */
801 void SwViewShell::UpdateAllCharts()
803 CurrShell aCurr( this );
804 // Start-/EndAction handled in the SwDoc-Method!
805 GetDoc()->UpdateAllCharts();
808 bool SwViewShell::HasCharts() const
810 bool bRet = false;
811 SwNodeIndex aIdx( *GetDoc()->GetNodes().GetEndOfAutotext().
812 StartOfSectionNode(), 1 );
813 while (aIdx.GetNode().GetStartNode())
815 ++aIdx;
816 const SwOLENode *pNd = aIdx.GetNode().GetOLENode();
817 if( pNd && !pNd->GetChartTableName().isEmpty() )
819 bRet = true;
820 break;
823 return bRet;
826 void SwViewShell::LayoutIdle()
828 if( !mpOpt->IsIdle() || !GetWin() || HasDrawViewDrag() )
829 return;
831 //No idle when printing is going on.
832 for(const SwViewShell& rSh : GetRingContainer())
834 if ( !rSh.GetWin() )
835 return;
838 CurrShell aCurr( this );
840 #ifdef DBG_UTIL
841 // If Test5 has been set, the IdleFormatter is disabled.
842 if( mpOpt->IsTest5() )
843 return;
844 #endif
847 // Preserve top of the text frame cache.
848 SwSaveSetLRUOfst aSaveLRU;
849 // #125243# there are lots of stacktraces indicating that Imp() returns NULL
850 // this SwViewShell seems to be invalid - but it's not clear why
851 // this return is only a workaround!
852 OSL_ENSURE(Imp(), "SwViewShell already deleted?");
853 if(!Imp())
854 return;
855 SwLayIdle aIdle( GetLayout(), Imp() );
859 static void lcl_InvalidateAllContent( SwViewShell& rSh, SwInvalidateFlags nInv )
861 rSh.StartAction();
862 rSh.GetLayout()->InvalidateAllContent( nInv );
863 rSh.EndAction();
865 rSh.GetDoc()->getIDocumentState().SetModified();
868 /** local method to invalidate/re-calculate positions of floating screen
869 * objects (Writer fly frame and drawing objects), which are anchored
870 * to paragraph or to character. #i11860#
872 static void lcl_InvalidateAllObjPos( SwViewShell &_rSh )
874 _rSh.StartAction();
876 _rSh.GetLayout()->InvalidateAllObjPos();
878 _rSh.EndAction();
880 _rSh.GetDoc()->getIDocumentState().SetModified();
883 void SwViewShell::SetParaSpaceMax( bool bNew )
885 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
886 if( rIDSA.get(DocumentSettingId::PARA_SPACE_MAX) != bNew )
888 SwWait aWait( *GetDoc()->GetDocShell(), true );
889 rIDSA.set(DocumentSettingId::PARA_SPACE_MAX, bNew );
890 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
891 lcl_InvalidateAllContent( *this, nInv );
895 void SwViewShell::SetParaSpaceMaxAtPages( bool bNew )
897 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
898 if( rIDSA.get(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES) != bNew )
900 SwWait aWait( *GetDoc()->GetDocShell(), true );
901 rIDSA.set(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES, bNew );
902 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
903 lcl_InvalidateAllContent( *this, nInv );
907 void SwViewShell::SetTabCompat( bool bNew )
909 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
910 if( rIDSA.get(DocumentSettingId::TAB_COMPAT) != bNew )
912 SwWait aWait( *GetDoc()->GetDocShell(), true );
913 rIDSA.set(DocumentSettingId::TAB_COMPAT, bNew );
914 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
915 lcl_InvalidateAllContent( *this, nInv );
919 void SwViewShell::SetAddExtLeading( bool bNew )
921 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
922 if ( rIDSA.get(DocumentSettingId::ADD_EXT_LEADING) != bNew )
924 SwWait aWait( *GetDoc()->GetDocShell(), true );
925 rIDSA.set(DocumentSettingId::ADD_EXT_LEADING, bNew );
926 SwDrawModel* pTmpDrawModel = getIDocumentDrawModelAccess().GetDrawModel();
927 if ( pTmpDrawModel )
928 pTmpDrawModel->SetAddExtLeading( bNew );
929 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
930 lcl_InvalidateAllContent( *this, nInv );
934 /** Sets if paragraph and table spacing is added at bottom of table cells.
935 * #106629#
936 * @param[in] (bool) setting of the new value
938 void SwViewShell::SetAddParaSpacingToTableCells( bool _bAddParaSpacingToTableCells )
940 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
941 if (rIDSA.get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS) != _bAddParaSpacingToTableCells
942 || rIDSA.get(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS) != _bAddParaSpacingToTableCells)
944 SwWait aWait( *GetDoc()->GetDocShell(), true );
945 rIDSA.set(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS, _bAddParaSpacingToTableCells );
946 // note: the dialog can't change the value to indeterminate, so only false/false and true/true
947 rIDSA.set(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS, _bAddParaSpacingToTableCells );
948 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea;
949 lcl_InvalidateAllContent( *this, nInv );
954 * Sets if former formatting of text lines with proportional line spacing should used.
955 * #i11859#
956 * @param[in] (bool) setting of the new value
958 void SwViewShell::SetUseFormerLineSpacing( bool _bUseFormerLineSpacing )
960 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
961 if ( rIDSA.get(DocumentSettingId::OLD_LINE_SPACING) != _bUseFormerLineSpacing )
963 SwWait aWait( *GetDoc()->GetDocShell(), true );
964 rIDSA.set(DocumentSettingId::OLD_LINE_SPACING, _bUseFormerLineSpacing );
965 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea;
966 lcl_InvalidateAllContent( *this, nInv );
971 * Sets IDocumentSettingAccess if former object positioning should be used.
972 * #i11860#
973 * @param[in] (bool) setting the new value
975 void SwViewShell::SetUseFormerObjectPositioning( bool _bUseFormerObjPos )
977 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
978 if ( rIDSA.get(DocumentSettingId::USE_FORMER_OBJECT_POS) != _bUseFormerObjPos )
980 SwWait aWait( *GetDoc()->GetDocShell(), true );
981 rIDSA.set(DocumentSettingId::USE_FORMER_OBJECT_POS, _bUseFormerObjPos );
982 lcl_InvalidateAllObjPos( *this );
986 // #i28701#
987 void SwViewShell::SetConsiderWrapOnObjPos( bool _bConsiderWrapOnObjPos )
989 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
990 if ( rIDSA.get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) != _bConsiderWrapOnObjPos )
992 SwWait aWait( *GetDoc()->GetDocShell(), true );
993 rIDSA.set(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION, _bConsiderWrapOnObjPos );
994 lcl_InvalidateAllObjPos( *this );
998 void SwViewShell::SetUseFormerTextWrapping( bool _bUseFormerTextWrapping )
1000 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1001 if ( rIDSA.get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) != _bUseFormerTextWrapping )
1003 SwWait aWait( *GetDoc()->GetDocShell(), true );
1004 rIDSA.set(DocumentSettingId::USE_FORMER_TEXT_WRAPPING, _bUseFormerTextWrapping );
1005 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
1006 lcl_InvalidateAllContent( *this, nInv );
1010 // #i45491#
1011 void SwViewShell::SetDoNotJustifyLinesWithManualBreak( bool _bDoNotJustifyLinesWithManualBreak )
1013 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1014 if ( rIDSA.get(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK) != _bDoNotJustifyLinesWithManualBreak )
1016 SwWait aWait( *GetDoc()->GetDocShell(), true );
1017 rIDSA.set(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK, _bDoNotJustifyLinesWithManualBreak );
1018 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
1019 lcl_InvalidateAllContent( *this, nInv );
1023 void SwViewShell::SetProtectForm( bool _bProtectForm )
1025 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1026 rIDSA.set(DocumentSettingId::PROTECT_FORM, _bProtectForm );
1029 void SwViewShell::SetMsWordCompTrailingBlanks( bool _bMsWordCompTrailingBlanks )
1031 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1032 if (rIDSA.get(DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS) != _bMsWordCompTrailingBlanks)
1034 SwWait aWait(*GetDoc()->GetDocShell(), true);
1035 rIDSA.set(DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS, _bMsWordCompTrailingBlanks);
1036 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
1037 lcl_InvalidateAllContent(*this, nInv);
1041 void SwViewShell::SetSubtractFlysAnchoredAtFlys(bool bSubtractFlysAnchoredAtFlys)
1043 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1044 rIDSA.set(DocumentSettingId::SUBTRACT_FLYS, bSubtractFlysAnchoredAtFlys);
1047 void SwViewShell::SetEmptyDbFieldHidesPara(bool bEmptyDbFieldHidesPara)
1049 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1050 if (rIDSA.get(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA) == bEmptyDbFieldHidesPara)
1051 return;
1053 SwWait aWait(*GetDoc()->GetDocShell(), true);
1054 rIDSA.set(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA, bEmptyDbFieldHidesPara);
1055 SwViewShell::StartAction();
1056 GetDoc()->getIDocumentState().SetModified();
1057 for (auto const & pFieldType : *GetDoc()->getIDocumentFieldsAccess().GetFieldTypes())
1059 if(pFieldType->Which() == SwFieldIds::Database)
1060 pFieldType->UpdateFields();
1062 SwViewShell::EndAction();
1065 void SwViewShell::SetNoGapAfterNoteNumber(bool bNew)
1067 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1068 if (rIDSA.get(DocumentSettingId::NO_GAP_AFTER_NOTE_NUMBER) != bNew)
1070 SwWait aWait(*GetDoc()->GetDocShell(), true);
1071 rIDSA.set(DocumentSettingId::NO_GAP_AFTER_NOTE_NUMBER, bNew);
1072 const SwInvalidateFlags nInv = SwInvalidateFlags::Size | SwInvalidateFlags::Pos | SwInvalidateFlags::PrtArea;
1073 lcl_InvalidateAllContent(*this, nInv);
1077 void SwViewShell::SetTabsRelativeToIndent(bool bNew)
1079 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1080 if (rIDSA.get(DocumentSettingId::TABS_RELATIVE_TO_INDENT) != bNew)
1082 SwWait aWait(*GetDoc()->GetDocShell(), true);
1083 rIDSA.set(DocumentSettingId::TABS_RELATIVE_TO_INDENT, bNew);
1084 const SwInvalidateFlags nInv = SwInvalidateFlags::Size | SwInvalidateFlags::Section | SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Pos;
1085 lcl_InvalidateAllContent(*this, nInv);
1089 void SwViewShell::SetTabOverMargin(bool bNew)
1091 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1092 if (rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN) != bNew)
1094 SwWait aWait(*GetDoc()->GetDocShell(), true);
1095 rIDSA.set(DocumentSettingId::TAB_OVER_MARGIN, bNew);
1096 const SwInvalidateFlags nInv = SwInvalidateFlags::Size | SwInvalidateFlags::Section | SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Pos;
1097 lcl_InvalidateAllContent(*this, nInv);
1101 void SwViewShell::SetDoNotMirrorRtlDrawObjs(bool bDoNotMirrorRtlDrawObjs)
1103 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1104 if (rIDSA.get(DocumentSettingId::DO_NOT_MIRROR_RTL_DRAW_OBJS) != bDoNotMirrorRtlDrawObjs)
1106 SwWait aWait(*GetDoc()->GetDocShell(), true);
1107 rIDSA.set(DocumentSettingId::DO_NOT_MIRROR_RTL_DRAW_OBJS, bDoNotMirrorRtlDrawObjs);
1108 lcl_InvalidateAllObjPos(*this);
1112 void SwViewShell::SetContinuousEndnotes(bool bContinuousEndnotes)
1114 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1115 if (rIDSA.get(DocumentSettingId::CONTINUOUS_ENDNOTES) != bContinuousEndnotes)
1117 SwWait aWait(*GetDoc()->GetDocShell(), true);
1118 rIDSA.set(DocumentSettingId::CONTINUOUS_ENDNOTES, bContinuousEndnotes);
1119 SwViewShell::StartAction();
1120 GetLayout()->RemoveFootnotes(/*pPage=*/nullptr, /*pPageOnly=*/false, /*bEndNotes=*/true);
1121 SwViewShell::EndAction();
1122 GetDoc()->getIDocumentState().SetModified();
1126 void SwViewShell::SetMsWordCompGridMetrics(bool _bMsWordCompGridMetrics)
1128 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1129 if (rIDSA.get(DocumentSettingId::MS_WORD_COMP_GRID_METRICS) != _bMsWordCompGridMetrics)
1131 SwWait aWait(*GetDoc()->GetDocShell(), true);
1132 rIDSA.set(DocumentSettingId::MS_WORD_COMP_GRID_METRICS, _bMsWordCompGridMetrics);
1133 const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Pos
1134 | SwInvalidateFlags::Size | SwInvalidateFlags::Table
1135 | SwInvalidateFlags::Section;
1136 lcl_InvalidateAllContent(*this, nInv);
1140 void SwViewShell::SetIgnoreTabsAndBlanksForLineCalculation(bool val)
1142 IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
1143 if (rIDSA.get(DocumentSettingId::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION) != val)
1145 SwWait aWait(*GetDoc()->GetDocShell(), true);
1146 rIDSA.set(DocumentSettingId::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION, val);
1147 const SwInvalidateFlags nInv = SwInvalidateFlags::Size | SwInvalidateFlags::Section
1148 | SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table
1149 | SwInvalidateFlags::Pos;
1150 lcl_InvalidateAllContent(*this, nInv);
1154 void SwViewShell::Reformat()
1156 SwWait aWait( *GetDoc()->GetDocShell(), true );
1158 // we go for safe: get rid of the old font information,
1159 // when the printer resolution or zoom factor changes.
1160 // Init() and Reformat() are the safest locations.
1161 pFntCache->Flush( );
1163 if( GetLayout()->IsCallbackActionEnabled() )
1165 SwViewShell::StartAction();
1166 GetLayout()->InvalidateAllContent( SwInvalidateFlags::Size | SwInvalidateFlags::Pos | SwInvalidateFlags::PrtArea );
1167 SwViewShell::EndAction();
1171 void SwViewShell::ChgNumberDigits()
1173 SdrModel* pTmpDrawModel = getIDocumentDrawModelAccess().GetDrawModel();
1174 if ( pTmpDrawModel )
1175 pTmpDrawModel->ReformatAllTextObjects();
1176 Reformat();
1179 void SwViewShell::CalcLayout()
1181 // extremely likely to be a Bad Idea to call this without StartAction
1182 // (except the Page Preview apparently only has a non-subclassed ViewShell)
1183 assert((typeid(*this) == typeid(SwViewShell)) || mnStartAction);
1185 CurrShell aCurr( this );
1186 SwWait aWait( *GetDoc()->GetDocShell(), true );
1188 // Preserve top of the text frame cache.
1189 SwSaveSetLRUOfst aSaveLRU;
1191 //switch on Progress when none is running yet.
1192 const bool bEndProgress = SfxProgress::GetActiveProgress( GetDoc()->GetDocShell() ) == nullptr;
1193 if ( bEndProgress )
1195 tools::Long nEndPage = GetLayout()->GetPageNum();
1196 nEndPage += nEndPage * 10 / 100;
1197 ::StartProgress( STR_STATSTR_REFORMAT, 0, nEndPage, GetDoc()->GetDocShell() );
1200 SwLayAction aAction( GetLayout(), Imp() );
1201 aAction.SetPaint( false );
1202 aAction.SetStatBar( true );
1203 aAction.SetCalcLayout( true );
1204 aAction.SetReschedule( true );
1205 GetDoc()->getIDocumentFieldsAccess().LockExpFields();
1206 aAction.Action(GetOut());
1207 GetDoc()->getIDocumentFieldsAccess().UnlockExpFields();
1209 //the SetNewFieldLst() on the Doc was cut off and must be fetched again
1210 //(see flowfrm.cxx, txtfld.cxx)
1211 if ( aAction.IsExpFields() )
1213 aAction.Reset();
1214 aAction.SetPaint( false );
1215 aAction.SetStatBar( true );
1216 aAction.SetReschedule( true );
1218 GetDoc()->getIDocumentFieldsAccess().UpdatePageFields(0);
1219 GetDoc()->getIDocumentFieldsAccess().UpdateExpFields(nullptr, true);
1221 aAction.Action(GetOut());
1224 if ( VisArea().HasArea() )
1225 InvalidateWindows( VisArea() );
1226 if ( bEndProgress )
1227 ::EndProgress( GetDoc()->GetDocShell() );
1230 void SwViewShell::SetFirstVisPageInvalid()
1232 for(SwViewShell& rSh : GetRingContainer())
1234 if ( rSh.Imp() )
1235 rSh.Imp()->SetFirstVisPageInvalid();
1239 void SwViewShell::SizeChgNotify()
1241 if ( !mpWin )
1242 mbDocSizeChgd = true;
1243 else if( ActionPend() || Imp()->IsCalcLayoutProgress() || mbPaintInProgress )
1245 mbDocSizeChgd = true;
1247 if ( !Imp()->IsCalcLayoutProgress() && dynamic_cast<const SwCursorShell*>( this ) != nullptr )
1249 PageNumNotify(this);
1251 if (comphelper::LibreOfficeKit::isActive())
1253 Size aDocSize = GetDocSize();
1254 OString sPayload = OString::number(aDocSize.Width() + 2 * DOCUMENTBORDER) +
1255 ", " + OString::number(aDocSize.Height() + 2 * DOCUMENTBORDER);
1257 SwXTextDocument* pModel = comphelper::getFromUnoTunnel<SwXTextDocument>(GetSfxViewShell()->GetCurrentDocument());
1258 SfxLokHelper::notifyDocumentSizeChanged(GetSfxViewShell(), sPayload, pModel);
1262 else
1264 mbDocSizeChgd = false;
1265 ::SizeNotify( this, GetDocSize() );
1269 void SwViewShell::VisPortChgd( const SwRect &rRect)
1271 OSL_ENSURE( GetWin(), "VisPortChgd without Window." );
1273 if ( rRect == VisArea() )
1274 return;
1276 // Is someone spuriously rescheduling again?
1277 SAL_WARN_IF(mbInEndAction, "sw.core", "Scrolling during EndAction");
1279 //First get the old visible page, so we don't have to look
1280 //for it afterwards.
1281 const SwFrame *pOldPage = Imp()->GetFirstVisPage(GetWin()->GetOutDev());
1283 const SwRect aPrevArea( VisArea() );
1284 const bool bFull = aPrevArea.IsEmpty();
1285 maVisArea = rRect;
1286 SetFirstVisPageInvalid();
1288 //When there a PaintRegion still exists and the VisArea has changed,
1289 //the PaintRegion is at least by now obsolete. The PaintRegion can
1290 //have been created by RootFrame::PaintSwFrame.
1291 if ( !mbInEndAction &&
1292 Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea() )
1293 Imp()->DeletePaintRegion();
1295 CurrShell aCurr( this );
1297 bool bScrolled = false;
1299 SwPostItMgr* pPostItMgr = GetPostItMgr();
1301 if ( bFull )
1302 GetWin()->Invalidate();
1303 else
1305 //Calculate amount to be scrolled.
1306 const tools::Long nXDiff = aPrevArea.Left() - VisArea().Left();
1307 const tools::Long nYDiff = aPrevArea.Top() - VisArea().Top();
1309 if( !nXDiff && !GetViewOptions()->getBrowseMode() &&
1310 (!Imp()->HasDrawView() || !Imp()->GetDrawView()->IsGridVisible() ) )
1312 // If possible, don't scroll the application background
1313 // (PaintDesktop). Also limit the left and right side of
1314 // the scroll range to the pages.
1315 const SwPageFrame *pPage = static_cast<SwPageFrame*>(GetLayout()->Lower());
1316 if ( pPage->getFrameArea().Top() > pOldPage->getFrameArea().Top() )
1317 pPage = static_cast<const SwPageFrame*>(pOldPage);
1318 SwRect aBoth( VisArea() );
1319 aBoth.Union( aPrevArea );
1320 const SwTwips nBottom = aBoth.Bottom();
1321 SwTwips nMinLeft = SAL_MAX_INT32;
1322 SwTwips nMaxRight= 0;
1324 const bool bBookMode = GetViewOptions()->IsViewLayoutBookMode();
1326 while ( pPage && pPage->getFrameArea().Top() <= nBottom )
1328 SwRect aPageRect( pPage->GetBoundRect(GetWin()->GetOutDev()) );
1329 if ( bBookMode )
1331 const SwPageFrame& rFormatPage = pPage->GetFormatPage();
1332 aPageRect.SSize( rFormatPage.GetBoundRect(GetWin()->GetOutDev()).SSize() );
1335 // #i9719# - consider new border and shadow width
1336 if ( aPageRect.Overlaps( aBoth ) )
1338 SwTwips nPageLeft = 0;
1339 SwTwips nPageRight = 0;
1340 const sw::sidebarwindows::SidebarPosition aSidebarPos = pPage->SidebarPosition();
1342 if( aSidebarPos != sw::sidebarwindows::SidebarPosition::NONE )
1344 nPageLeft = aPageRect.Left();
1345 nPageRight = aPageRect.Right();
1348 if( nPageLeft < nMinLeft )
1349 nMinLeft = nPageLeft;
1350 if( nPageRight > nMaxRight )
1351 nMaxRight = nPageRight;
1352 //match with the draw objects
1353 //take nOfst into account as the objects have been
1354 //selected and have handles attached.
1355 if ( pPage->GetSortedObjs() )
1357 const tools::Long nOfst = GetOut()->PixelToLogic(
1358 Size(Imp()->GetDrawView()->GetMarkHdlSizePixel()/2,0)).Width();
1359 for (SwAnchoredObject* pObj : *pPage->GetSortedObjs())
1361 // ignore objects that are not actually placed on the page
1362 if (pObj->IsFormatPossible())
1364 const tools::Rectangle aBound = pObj->GetObjRect().SVRect();
1365 if (aBound.Left() != FAR_AWAY) {
1366 // OD 03.03.2003 #107927# - use correct datatype
1367 const SwTwips nL = std::max( SwTwips(0), SwTwips(aBound.Left() - nOfst) );
1368 if ( nL < nMinLeft )
1369 nMinLeft = nL;
1370 if( aBound.Right() + nOfst > nMaxRight )
1371 nMaxRight = aBound.Right() + nOfst;
1377 pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
1379 tools::Rectangle aRect( aPrevArea.SVRect() );
1380 aRect.SetLeft( nMinLeft );
1381 aRect.SetRight( nMaxRight );
1382 if( VisArea().Overlaps( aPrevArea ) && !mnLockPaint )
1384 bScrolled = true;
1385 maVisArea.Pos() = aPrevArea.Pos();
1386 if ( SmoothScroll( nXDiff, nYDiff, &aRect ) )
1387 return;
1388 maVisArea.Pos() = rRect.Pos();
1390 else if (!comphelper::LibreOfficeKit::isActive())
1391 GetWin()->Invalidate( aRect );
1393 else if ( !mnLockPaint ) //will be released in Unlock
1395 if( VisArea().Overlaps( aPrevArea ) )
1397 bScrolled = true;
1398 maVisArea.Pos() = aPrevArea.Pos();
1399 if ( SmoothScroll( nXDiff, nYDiff, nullptr ) )
1400 return;
1401 maVisArea.Pos() = rRect.Pos();
1403 else
1404 GetWin()->Invalidate();
1408 // When tiled rendering, the map mode of the window is disabled, avoid
1409 // enabling it here.
1410 if (!comphelper::LibreOfficeKit::isActive())
1412 Point aPt( VisArea().Pos() );
1413 aPt.setX( -aPt.X() ); aPt.setY( -aPt.Y() );
1414 MapMode aMapMode( GetWin()->GetMapMode() );
1415 aMapMode.SetOrigin( aPt );
1416 GetWin()->SetMapMode( aMapMode );
1419 if ( HasDrawView() )
1421 Imp()->GetDrawView()->VisAreaChanged( GetWin()->GetOutDev() );
1422 Imp()->GetDrawView()->SetActualWin( GetWin()->GetOutDev() );
1424 GetWin()->PaintImmediately();
1426 if ( pPostItMgr ) // #i88070#
1428 pPostItMgr->Rescale();
1429 pPostItMgr->CalcRects();
1430 pPostItMgr->LayoutPostIts();
1433 if ( !bScrolled && pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
1434 pPostItMgr->CorrectPositions();
1436 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1437 if( Imp()->IsAccessible() )
1438 Imp()->UpdateAccessible();
1439 #endif
1442 bool SwViewShell::SmoothScroll( tools::Long lXDiff, tools::Long lYDiff, const tools::Rectangle *pRect )
1444 #if !defined(MACOSX) && !defined(ANDROID) && !defined(IOS)
1445 // #i98766# - disable smooth scrolling for Mac
1447 const sal_uLong nBitCnt = mpOut->GetBitCount();
1448 tools::Long lMult = 1, lMax = LONG_MAX;
1449 if ( nBitCnt == 16 )
1451 lMax = 7000;
1452 lMult = 2;
1454 if ( nBitCnt == 24 )
1456 lMax = 5000;
1457 lMult = 6;
1459 else if ( nBitCnt == 1 )
1461 lMax = 3000;
1462 lMult = 12;
1465 // #i75172# isolated static conditions
1466 const bool bOnlyYScroll(!lXDiff && std::abs(lYDiff) != 0 && std::abs(lYDiff) < lMax);
1467 const bool bAllowedWithChildWindows(GetWin()->GetWindowClipRegionPixel().IsNull());
1468 const bool bSmoothScrollAllowed(bOnlyYScroll && mbEnableSmooth && GetViewOptions()->IsSmoothScroll() && bAllowedWithChildWindows);
1470 if(bSmoothScrollAllowed)
1472 Imp()->m_bStopSmooth = false;
1474 const SwRect aOldVis( VisArea() );
1476 //create virtual device and set.
1477 const Size aPixSz = GetWin()->PixelToLogic(Size(1,1));
1478 VclPtrInstance<VirtualDevice> pVout( *GetWin()->GetOutDev() );
1479 pVout->SetLineColor( GetWin()->GetOutDev()->GetLineColor() );
1480 pVout->SetFillColor( GetWin()->GetOutDev()->GetFillColor() );
1481 MapMode aMapMode( GetWin()->GetMapMode() );
1482 pVout->SetMapMode( aMapMode );
1483 Size aSize( maVisArea.Width()+2*aPixSz.Width(), std::abs(lYDiff)+(2*aPixSz.Height()) );
1484 if ( pRect )
1485 aSize.setWidth( std::min(aSize.Width(), pRect->GetWidth()+2*aPixSz.Width()) );
1486 if ( pVout->SetOutputSize( aSize ) )
1488 mnLockPaint++;
1490 //First Paint everything in the virtual device.
1491 SwRect aRect( VisArea() );
1492 aRect.Height( aSize.Height() );
1493 if ( pRect )
1495 aRect.Pos().setX( std::max(aRect.Left(),pRect->Left()-aPixSz.Width()) );
1496 aRect.Right( std::min(aRect.Right()+2*aPixSz.Width(), pRect->Right()+aPixSz.Width()));
1498 else
1499 aRect.AddWidth(2*aPixSz.Width() );
1500 aRect.Pos().setY( lYDiff < 0 ? aOldVis.Bottom() - aPixSz.Height()
1501 : aRect.Top() - aSize.Height() + aPixSz.Height() );
1502 aRect.Pos().setX( std::max( tools::Long(0), aRect.Left()-aPixSz.Width() ) );
1503 aRect.Pos() = GetWin()->PixelToLogic( GetWin()->LogicToPixel( aRect.Pos()));
1504 aRect.SSize( GetWin()->PixelToLogic( GetWin()->LogicToPixel( aRect.SSize())) );
1505 maVisArea = aRect;
1506 const Point aPt( -aRect.Left(), -aRect.Top() );
1507 aMapMode.SetOrigin( aPt );
1508 pVout->SetMapMode( aMapMode );
1509 OutputDevice *pOld = mpOut;
1510 mpOut = pVout.get();
1513 // #i75172# To get a clean repaint, a new ObjectContact is needed here. Without, the
1514 // repaint would not be correct since it would use the wrong DrawPage visible region.
1515 // This repaint IS about painting something currently outside the visible part (!).
1516 // For that purpose, AddDeviceToPaintView is used which creates a new SdrPageViewWindow
1517 // and all the necessary stuff. It's not cheap, but necessary here. Alone because repaint
1518 // target really is NOT the current window.
1519 // Also will automatically NOT use PreRendering and overlay (since target is VirtualDevice)
1520 if(!HasDrawView())
1521 MakeDrawView();
1522 SdrView* pDrawView = GetDrawView();
1523 pDrawView->AddDeviceToPaintView(*pVout, nullptr);
1525 // clear mpWin during DLPrePaint2 to get paint preparation for mpOut, but set it again
1526 // immediately afterwards. There are many decisions in SW which imply that Printing
1527 // is used when mpWin == 0 (wrong but widely used).
1528 vcl::Window* pOldWin = mpWin;
1529 mpWin = nullptr;
1530 DLPrePaint2(vcl::Region(aRect.SVRect()));
1531 mpWin = pOldWin;
1533 // SW paint stuff
1534 PaintDesktop(*GetOut(), aRect);
1535 SwViewShell::sbLstAct = true;
1536 GetLayout()->PaintSwFrame( *GetOut(), aRect );
1537 SwViewShell::sbLstAct = false;
1539 // end paint and destroy ObjectContact again
1540 DLPostPaint2(true);
1541 pDrawView->DeleteDeviceFromPaintView(*pVout);
1544 mpOut = pOld;
1545 maVisArea = aOldVis;
1547 //Now shift in parts and copy the new Pixel from the virtual device.
1549 // ??????????????????????
1550 // or is it better to get the scrollfactor from the User
1551 // as option?
1552 // ??????????????????????
1553 tools::Long lMaDelta = aPixSz.Height();
1554 if ( std::abs(lYDiff) > ( maVisArea.Height() / 3 ) )
1555 lMaDelta *= 6;
1556 else
1557 lMaDelta *= 2;
1559 lMaDelta *= lMult;
1561 if ( lYDiff < 0 )
1562 lMaDelta = -lMaDelta;
1564 tools::Long lDiff = lYDiff;
1565 while ( lDiff )
1567 tools::Long lScroll;
1568 if ( Imp()->m_bStopSmooth || std::abs(lDiff) <= std::abs(lMaDelta) )
1570 lScroll = lDiff;
1571 lDiff = 0;
1573 else
1575 lScroll = lMaDelta;
1576 lDiff -= lMaDelta;
1579 const SwRect aTmpOldVis = VisArea();
1580 maVisArea.Pos().AdjustY( -lScroll );
1581 maVisArea.Pos() = GetWin()->PixelToLogic( GetWin()->LogicToPixel( VisArea().Pos()));
1582 lScroll = aTmpOldVis.Top() - VisArea().Top();
1583 if ( pRect )
1585 tools::Rectangle aTmp( aTmpOldVis.SVRect() );
1586 aTmp.SetLeft( pRect->Left() );
1587 aTmp.SetRight( pRect->Right() );
1588 GetWin()->Scroll( 0, lScroll, aTmp, ScrollFlags::Children);
1590 else
1591 GetWin()->Scroll( 0, lScroll, ScrollFlags::Children );
1593 const Point aTmpPt( -VisArea().Left(), -VisArea().Top() );
1594 MapMode aTmpMapMode( GetWin()->GetMapMode() );
1595 aTmpMapMode.SetOrigin( aTmpPt );
1596 GetWin()->SetMapMode( aTmpMapMode );
1598 if ( Imp()->HasDrawView() )
1599 Imp()->GetDrawView()->VisAreaChanged( GetWin()->GetOutDev() );
1601 SetFirstVisPageInvalid();
1602 if ( !Imp()->m_bStopSmooth )
1604 const bool bScrollDirectionIsUp(lScroll > 0);
1605 Imp()->m_aSmoothRect = VisArea();
1607 if(bScrollDirectionIsUp)
1609 Imp()->m_aSmoothRect.Bottom( VisArea().Top() + lScroll + aPixSz.Height());
1611 else
1613 Imp()->m_aSmoothRect.Top( VisArea().Bottom() + lScroll - aPixSz.Height());
1616 Imp()->m_bSmoothUpdate = true;
1617 GetWin()->PaintImmediately();
1618 Imp()->m_bSmoothUpdate = false;
1620 if(!Imp()->m_bStopSmooth)
1622 // start paint on logic base
1623 const tools::Rectangle aTargetLogic(Imp()->m_aSmoothRect.SVRect());
1624 DLPrePaint2(vcl::Region(aTargetLogic));
1626 // get target rectangle in discrete pixels
1627 OutputDevice& rTargetDevice = mpTargetPaintWindow->GetTargetOutputDevice();
1628 const tools::Rectangle aTargetPixel(rTargetDevice.LogicToPixel(aTargetLogic));
1630 // get source top-left in discrete pixels
1631 const Point aSourceTopLeft(pVout->LogicToPixel(aTargetLogic.TopLeft()));
1633 // switch off MapModes
1634 const bool bMapModeWasEnabledDest(rTargetDevice.IsMapModeEnabled());
1635 const bool bMapModeWasEnabledSource(pVout->IsMapModeEnabled());
1636 rTargetDevice.EnableMapMode(false);
1637 pVout->EnableMapMode(false);
1639 rTargetDevice.DrawOutDev(
1640 aTargetPixel.TopLeft(), aTargetPixel.GetSize(), // dest
1641 aSourceTopLeft, aTargetPixel.GetSize(), // source
1642 *pVout);
1644 // restore MapModes
1645 rTargetDevice.EnableMapMode(bMapModeWasEnabledDest);
1646 pVout->EnableMapMode(bMapModeWasEnabledSource);
1648 // end paint on logoc base
1649 DLPostPaint2(true);
1651 else
1652 --mnLockPaint;
1655 pVout.disposeAndClear();
1656 GetWin()->PaintImmediately();
1657 if ( !Imp()->m_bStopSmooth )
1658 --mnLockPaint;
1659 SetFirstVisPageInvalid();
1660 return true;
1662 pVout.disposeAndClear();
1664 #endif
1666 maVisArea.Pos().AdjustX( -lXDiff );
1667 maVisArea.Pos().AdjustY( -lYDiff );
1668 if ( pRect )
1669 GetWin()->Scroll( lXDiff, lYDiff, *pRect, ScrollFlags::Children);
1670 else
1671 GetWin()->Scroll( lXDiff, lYDiff, ScrollFlags::Children);
1672 return false;
1675 void SwViewShell::PaintDesktop(const vcl::RenderContext& rRenderContext, const SwRect &rRect)
1677 if ( !GetWin() && !GetOut()->GetConnectMetaFile() )
1678 return; //for the printer we don't do anything here.
1680 if(comphelper::LibreOfficeKit::isActive())
1681 return;
1683 //Catch exceptions, so that it doesn't look so surprising.
1684 //Can e.g. happen during Idle.
1685 //Unfortunately we must at any rate Paint the rectangles next to the pages,
1686 //as these are not painted at VisPortChgd.
1687 bool bBorderOnly = false;
1688 const SwRootFrame *pRoot = GetLayout();
1689 if ( rRect.Top() > pRoot->getFrameArea().Bottom() )
1691 const SwFrame *pPg = pRoot->Lower();
1692 while ( pPg && pPg->GetNext() )
1693 pPg = pPg->GetNext();
1694 if ( !pPg || !pPg->getFrameArea().Overlaps( VisArea() ) )
1695 bBorderOnly = true;
1698 const bool bBookMode = GetViewOptions()->IsViewLayoutBookMode();
1700 SwRegionRects aRegion( rRect );
1702 //mod #i6193: remove sidebar area to avoid flickering
1703 const SwPostItMgr* pPostItMgr = GetPostItMgr();
1704 const SwTwips nSidebarWidth = pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() ?
1705 pPostItMgr->GetSidebarWidth() + pPostItMgr->GetSidebarBorderWidth() :
1708 if ( bBorderOnly )
1710 const SwFrame *pPage =pRoot->Lower();
1711 SwRect aLeft( rRect ), aRight( rRect );
1712 while ( pPage )
1714 tools::Long nTmp = pPage->getFrameArea().Left();
1715 if ( nTmp < aLeft.Right() )
1716 aLeft.Right( nTmp );
1717 nTmp = pPage->getFrameArea().Right();
1718 if ( nTmp > aRight.Left() )
1720 aRight.Left( nTmp + nSidebarWidth );
1722 pPage = pPage->GetNext();
1724 aRegion.clear();
1725 if ( aLeft.HasArea() )
1726 aRegion.push_back( aLeft );
1727 if ( aRight.HasArea() )
1728 aRegion.push_back( aRight );
1730 else
1732 const SwFrame *pPage = Imp()->GetFirstVisPage(&rRenderContext);
1733 const SwTwips nBottom = rRect.Bottom();
1734 while ( pPage && !aRegion.empty() &&
1735 (pPage->getFrameArea().Top() <= nBottom) )
1737 SwRect aPageRect( pPage->getFrameArea() );
1738 if ( bBookMode )
1740 const SwPageFrame& rFormatPage = static_cast<const SwPageFrame*>(pPage)->GetFormatPage();
1741 aPageRect.SSize( rFormatPage.getFrameArea().SSize() );
1744 const bool bSidebarRight =
1745 static_cast<const SwPageFrame*>(pPage)->SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT;
1746 aPageRect.Pos().AdjustX( -(bSidebarRight ? 0 : nSidebarWidth) );
1747 aPageRect.AddWidth(nSidebarWidth );
1749 if ( aPageRect.Overlaps( rRect ) )
1750 aRegion -= aPageRect;
1752 pPage = pPage->GetNext();
1755 if ( !aRegion.empty() )
1756 PaintDesktop_(aRegion);
1759 bool SwViewShell::DrawAppBackgroundBitmap(vcl::RenderContext* rRenderContext, const SwRect& rRect)
1761 if (Application::IsHeadlessModeEnabled()
1762 || !ThemeColors::GetThemeColors().GetAppBackUseBitmap())
1763 return false;
1765 const BitmapEx& aAppBackImg
1766 = Application::GetSettings().GetStyleSettings().GetAppBackgroundBitmap();
1767 if (aAppBackImg.IsEmpty())
1768 return false;
1770 Wallpaper aWallpaper(aAppBackImg);
1771 aWallpaper.SetStyle(WallpaperStyle::Tile);
1773 rRenderContext->DrawWallpaper(rRect.SVRect(), aWallpaper);
1774 return true;
1777 // PaintDesktop is split in two, this part is also used by PreviewPage
1778 void SwViewShell::PaintDesktop_(const SwRegionRects &rRegion)
1780 if (DrawAppBackgroundBitmap(GetOut(), rRegion.GetOrigin()))
1781 return;
1783 // OD 2004-04-23 #116347#
1784 GetOut()->Push( vcl::PushFlags::FILLCOLOR|vcl::PushFlags::LINECOLOR );
1785 GetOut()->SetLineColor();
1787 for ( auto &rRgn : rRegion )
1789 const tools::Rectangle aRectangle(rRgn.SVRect());
1791 // #i93170#
1792 // Here we have a real Problem. On the one hand we have the buffering for paint
1793 // and overlay which needs an embracing pair of DLPrePaint2/DLPostPaint2 calls,
1794 // on the other hand the MapMode is not set correctly when this code is executed.
1795 // This is done in the users of this method, for each SWpage before painting it.
1796 // Since the MapMode is not correct here, the call to DLPostPaint2 will paint
1797 // existing FormControls due to the current MapMode.
1799 // There are basically three solutions for this:
1801 // (1) Set the MapMode correct, move the background painting to the users of
1802 // this code
1804 // (2) Do no DLPrePaint2/DLPostPaint2 here; no SdrObjects are allowed to lie in
1805 // the desktop region. Disadvantage: the desktop will not be part of the
1806 // buffers, e.g. overlay. Thus, as soon as overlay will be used over the
1807 // desktop, it will not work.
1809 // (3) expand DLPostPaint2 with a flag to signal if FormControl paints shall
1810 // be done or not
1812 // Currently, (3) will be the best possible solution. It will keep overlay and
1813 // buffering intact and work without MapMode for single pages. In the medium
1814 // to long run, (1) will need to be used and the bool bPaintFormLayer needs
1815 // to be removed again
1817 // #i68597# inform Drawinglayer about display change
1818 DLPrePaint2(vcl::Region(aRectangle));
1820 // #i75172# needed to move line/Fill color setters into loop since DLPrePaint2
1821 // may exchange GetOut(), that's it's purpose. This happens e.g. at print preview.
1822 GetOut()->SetFillColor( GetViewOptions()->GetAppBackgroundColor());
1823 GetOut()->SetLineColor();
1824 GetOut()->DrawRect(aRectangle);
1826 DLPostPaint2(false);
1829 GetOut()->Pop();
1832 bool SwViewShell::CheckInvalidForPaint( const SwRect &rRect )
1834 if ( !GetWin() )
1835 return false;
1837 const SwPageFrame *pPage = Imp()->GetFirstVisPage(GetOut());
1838 const SwTwips nBottom = VisArea().Bottom();
1839 const SwTwips nRight = VisArea().Right();
1840 bool bRet = false;
1841 while ( !bRet && pPage && ((pPage->getFrameArea().Top() <= nBottom) &&
1842 (pPage->getFrameArea().Left() <= nRight)))
1844 if ( pPage->IsInvalid() || pPage->IsInvalidFly() )
1845 bRet = true;
1846 pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
1849 if ( bRet )
1851 //Unfortunately Start/EndAction won't help here, as the Paint originated
1852 //from GUI and so Clipping has been set against getting through.
1853 //Ergo: do it all yourself (see ImplEndAction())
1854 if ( Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea())
1855 Imp()->DeletePaintRegion();
1857 SwLayAction aAction( GetLayout(), Imp() );
1858 aAction.SetComplete( false );
1859 // We increment the action counter to avoid a recursive call of actions
1860 // e.g. from a SwFEShell::RequestObjectResize(..) in bug 95829.
1861 // A recursive call of actions is no good idea because the inner action
1862 // can't format frames which are locked by the outer action. This may
1863 // cause and endless loop.
1864 ++mnStartAction;
1865 aAction.Action(GetWin()->GetOutDev());
1866 --mnStartAction;
1868 std::optional<SwRegionRects> oRegion = Imp()->TakePaintRegion();
1869 if ( oRegion && aAction.IsBrowseActionStop() )
1871 //only of interest when something has changed in the visible range
1872 bool bAllNoOverlap = std::all_of(oRegion->begin(), oRegion->end(), [this](const SwRect &rTmp) {
1873 return rTmp.Overlaps( VisArea() );
1875 if ( bAllNoOverlap )
1876 oRegion.reset();
1879 if ( oRegion )
1881 oRegion->LimitToOrigin();
1882 oRegion->Compress( SwRegionRects::CompressFuzzy );
1883 bRet = false;
1884 if ( !oRegion->empty() )
1886 SwRegionRects aRegion( rRect );
1887 for ( const SwRect &rTmp : *oRegion )
1889 if ( !rRect.Contains( rTmp ) )
1891 InvalidateWindows( rTmp );
1892 if ( rTmp.Overlaps( VisArea() ) )
1893 { aRegion -= rTmp;
1894 bRet = true;
1898 if ( bRet )
1900 for ( size_t i = 0; i < aRegion.size(); ++i )
1901 GetWin()->Invalidate( aRegion[i].SVRect() );
1903 if ( rRect != VisArea() )
1905 //rRect == VisArea is the special case for new or
1906 //Shift-Ctrl-R, when it shouldn't be necessary to
1907 //hold the rRect again in Document coordinates.
1908 if ( maInvalidRect.IsEmpty() )
1909 maInvalidRect = rRect;
1910 else
1911 maInvalidRect.Union( rRect );
1915 else
1916 bRet = false;
1918 else
1919 bRet = false;
1921 return bRet;
1924 namespace
1926 /// Similar to comphelper::FlagRestorationGuard, but for vcl::RenderContext.
1927 class RenderContextGuard
1929 std::unique_ptr<SdrPaintWindow> m_TemporaryPaintWindow;
1930 SdrPageWindow* m_pPatchedPageWindow;
1931 SdrPaintWindow* m_pPreviousPaintWindow = nullptr;
1933 public:
1934 RenderContextGuard(VclPtr<vcl::RenderContext>& pRef, vcl::RenderContext* pValue, SwViewShell* pShell)
1935 : m_pPatchedPageWindow(nullptr)
1937 pRef = pValue;
1939 if (pValue == pShell->GetWin()->GetOutDev())
1940 return;
1942 SdrView* pDrawView(pShell->Imp()->GetDrawView());
1944 if (nullptr == pDrawView)
1945 return;
1947 SdrPageView* pSdrPageView(pDrawView->GetSdrPageView());
1949 if (nullptr != pSdrPageView)
1951 m_pPatchedPageWindow = pSdrPageView->FindPageWindow(*pShell->GetWin()->GetOutDev());
1953 if (nullptr != m_pPatchedPageWindow)
1955 m_TemporaryPaintWindow.reset(new SdrPaintWindow(*pDrawView, *pValue));
1956 m_pPreviousPaintWindow = m_pPatchedPageWindow->patchPaintWindow(*m_TemporaryPaintWindow);
1961 ~RenderContextGuard()
1963 if(nullptr != m_pPatchedPageWindow)
1965 m_pPatchedPageWindow->unpatchPaintWindow(m_pPreviousPaintWindow);
1971 void SwViewShell::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle &rRect)
1973 RenderContextGuard aGuard(mpOut, &rRenderContext, this);
1974 if ( mnLockPaint )
1976 if ( Imp()->m_bSmoothUpdate )
1978 SwRect aTmp( rRect );
1979 if ( !Imp()->m_aSmoothRect.Contains( aTmp ) )
1980 Imp()->m_bStopSmooth = true;
1981 else
1983 Imp()->m_aSmoothRect = aTmp;
1984 return;
1987 else
1988 return;
1991 if ( SwRootFrame::IsInPaint() )
1993 //During the publication of a page at printing the Paint is buffered.
1994 SwPaintQueue::Add( this, SwRect( rRect ) );
1995 return;
1998 //With !nStartAction I try to protect me against erroneous code at other places.
1999 //Hopefully it will not lead to problems!?
2000 if ( mbPaintWorks && !mnStartAction )
2002 if( GetWin() && GetWin()->IsVisible() )
2004 SwRect aRect( rRect );
2005 if ( mbPaintInProgress ) //Guard against double Paints!
2007 GetWin()->Invalidate( rRect );
2008 return;
2011 mbPaintInProgress = true;
2012 CurrShell aCurr( this );
2013 SwRootFrame::SetNoVirDev( true );
2015 //We don't want to Clip to and from, we trust that all are limited
2016 //to the rectangle and only need to calculate the clipping once.
2017 //The ClipRect is removed here once and not recovered, as externally
2018 //no one needs it anymore anyway.
2019 //Not when we paint a Metafile.
2020 if( !GetOut()->GetConnectMetaFile() && GetOut()->IsClipRegion())
2021 GetOut()->SetClipRegion();
2023 if ( IsPreview() )
2025 //When useful, process or destroy the old InvalidRect.
2026 if ( aRect.Contains( maInvalidRect ) )
2027 ResetInvalidRect();
2028 SwViewShell::sbLstAct = true;
2029 GetLayout()->PaintSwFrame( rRenderContext, aRect );
2030 SwViewShell::sbLstAct = false;
2032 else
2034 //When one of the visible pages still has anything entered for
2035 //Repaint, Repaint must be triggered.
2036 if ( !CheckInvalidForPaint( aRect ) )
2038 // --> OD 2009-08-12 #i101192#
2039 // start Pre/PostPaint encapsulation to avoid screen blinking
2040 const vcl::Region aRepaintRegion(aRect.SVRect());
2041 DLPrePaint2(aRepaintRegion);
2043 // <--
2044 PaintDesktop(rRenderContext, aRect);
2046 //When useful, process or destroy the old InvalidRect.
2047 if ( aRect.Contains( maInvalidRect ) )
2048 ResetInvalidRect();
2049 SwViewShell::sbLstAct = true;
2050 GetLayout()->PaintSwFrame( rRenderContext, aRect );
2051 SwViewShell::sbLstAct = false;
2052 // --> OD 2009-08-12 #i101192#
2053 // end Pre/PostPaint encapsulation
2054 DLPostPaint2(true);
2055 // <--
2058 SwRootFrame::SetNoVirDev( false );
2059 mbPaintInProgress = false;
2060 UISizeNotify();
2063 else
2065 if ( maInvalidRect.IsEmpty() )
2066 maInvalidRect = SwRect( rRect );
2067 else
2068 maInvalidRect.Union( SwRect( rRect ) );
2070 if ( mbInEndAction && GetWin() )
2072 const vcl::Region aRegion(GetWin()->GetPaintRegion());
2073 RectangleVector aRectangles;
2074 aRegion.GetRegionRectangles(aRectangles);
2076 for(const auto& rRectangle : aRectangles)
2078 Imp()->AddPaintRect(SwRect(rRectangle));
2081 //RegionHandle hHdl( aRegion.BeginEnumRects() );
2082 //Rectangle aRect;
2083 //while ( aRegion.GetEnumRects( hHdl, aRect ) )
2084 // Imp()->AddPaintRect( aRect );
2085 //aRegion.EndEnumRects( hHdl );
2087 else if ( SfxProgress::GetActiveProgress( GetDoc()->GetDocShell() ) &&
2088 GetOut() == GetWin()->GetOutDev() )
2090 // #i68597#
2091 const vcl::Region aDLRegion(rRect);
2092 DLPrePaint2(aDLRegion);
2094 rRenderContext.Push( vcl::PushFlags::FILLCOLOR|vcl::PushFlags::LINECOLOR );
2095 rRenderContext.SetFillColor( Imp()->GetRetoucheColor() );
2096 rRenderContext.SetLineColor();
2097 rRenderContext.DrawRect( rRect );
2098 rRenderContext.Pop();
2099 // #i68597#
2100 DLPostPaint2(true);
2105 void SwViewShell::PaintTile(VirtualDevice &rDevice, int contextWidth, int contextHeight, int tilePosX, int tilePosY, tools::Long tileWidth, tools::Long tileHeight)
2107 // SwViewShell's output device setup
2108 // TODO clean up SwViewShell's approach to output devices (the many of
2109 // them - mpBufferedOut, mpOut, mpWin, ...)
2110 OutputDevice *pSaveOut = mpOut;
2111 comphelper::LibreOfficeKit::setTiledPainting(true);
2112 mpOut = &rDevice;
2114 // resizes the virtual device so to contain the entries context
2115 rDevice.SetOutputSizePixel(Size(contextWidth, contextHeight), /*bErase*/false);
2117 // setup the output device to draw the tile
2118 MapMode aMapMode(rDevice.GetMapMode());
2119 aMapMode.SetMapUnit(MapUnit::MapTwip);
2120 aMapMode.SetOrigin(Point(-tilePosX, -tilePosY));
2122 // Scaling. Must convert from pixels to twips. We know
2123 // that VirtualDevices use a DPI of 96.
2124 const Fraction scale = conversionFract(o3tl::Length::px, o3tl::Length::twip);
2125 Fraction scaleX = Fraction(contextWidth, tileWidth) * scale;
2126 Fraction scaleY = Fraction(contextHeight, tileHeight) * scale;
2127 aMapMode.SetScaleX(scaleX);
2128 aMapMode.SetScaleY(scaleY);
2129 rDevice.SetMapMode(aMapMode);
2131 // Update scaling of SwEditWin and its sub-widgets, needed for comments.
2132 sal_uInt16 nOldZoomValue = 0;
2133 if (GetWin() && GetWin()->GetMapMode().GetScaleX() != scaleX)
2135 double fScale = double(scaleX);
2136 SwViewOption aOption(*GetViewOptions());
2137 nOldZoomValue = aOption.GetZoom();
2138 aOption.SetZoom(fScale * 100);
2139 ApplyViewOptions(aOption);
2140 // Make sure the map mode (disabled in SwXTextDocument::initializeForTiledRendering()) is still disabled.
2141 GetWin()->EnableMapMode(false);
2144 tools::Rectangle aOutRect(Point(tilePosX, tilePosY),
2145 rDevice.PixelToLogic(Size(contextWidth, contextHeight)));
2147 // Make the requested area visible -- we can't use MakeVisible as that will
2148 // only scroll the contents, but won't zoom/resize if needed.
2149 // Without this, items/text that are outside the visible area (in the SwView)
2150 // won't be painted when rendering tiles (at least when using either the
2151 // tiledrendering app, or the gtktiledviewer) -- although ultimately we
2152 // probably want to fix things so that the SwView's area doesn't affect
2153 // tiled rendering?
2154 VisPortChgd(SwRect(aOutRect));
2156 // Invoke SwLayAction if layout is not yet ready.
2157 CheckInvalidForPaint(SwRect(aOutRect));
2159 // draw - works in logic coordinates
2160 Paint(rDevice, aOutRect);
2162 SwPostItMgr* pPostItMgr = GetPostItMgr();
2163 if (GetViewOptions()->IsPostIts() && pPostItMgr)
2164 pPostItMgr->PaintTile(rDevice);
2166 // SwViewShell's output device tear down
2168 // A view shell can get a PaintTile call for a tile at a zoom level
2169 // different from the one, the related client really is.
2170 // In such a case it is better to reset the current scale value to
2171 // the original one, since such a value should be in synchronous with
2172 // the zoom level in the client (see setClientZoom).
2173 // At present the zoom value returned by GetViewOptions()->GetZoom() is
2174 // used in SwXTextDocument methods (postMouseEvent and setGraphicSelection)
2175 // for passing the correct mouse position to an edited chart (if any).
2176 if (nOldZoomValue !=0)
2178 SwViewOption aOption(*GetViewOptions());
2179 aOption.SetZoom(nOldZoomValue);
2180 ApplyViewOptions(aOption);
2182 // Changing the zoom value doesn't always trigger the updating of
2183 // the client ole object area, so we call it directly.
2184 SfxInPlaceClient* pIPClient = GetSfxViewShell()->GetIPClient();
2185 if (pIPClient)
2187 pIPClient->VisAreaChanged();
2189 // Make sure the map mode (disabled in SwXTextDocument::initializeForTiledRendering()) is still disabled.
2190 GetWin()->EnableMapMode(false);
2193 mpOut = pSaveOut;
2194 comphelper::LibreOfficeKit::setTiledPainting(false);
2197 void SwViewShell::SetBrowseBorder( const Size& rNew )
2199 if( rNew != maBrowseBorder )
2201 maBrowseBorder = rNew;
2202 if ( maVisArea.HasArea() )
2203 InvalidateLayout( false );
2207 const Size& SwViewShell::GetBrowseBorder() const
2209 return maBrowseBorder;
2212 sal_Int32 SwViewShell::GetBrowseWidth() const
2214 const SwPostItMgr* pPostItMgr = GetPostItMgr();
2215 if ( pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
2217 Size aBorder( maBrowseBorder );
2218 aBorder.AdjustWidth(maBrowseBorder.Width() );
2219 aBorder.AdjustWidth(pPostItMgr->GetSidebarWidth(true) + pPostItMgr->GetSidebarBorderWidth(true) );
2220 return maVisArea.Width() - GetOut()->PixelToLogic(aBorder).Width();
2222 else
2223 return maVisArea.Width() - 2 * GetOut()->PixelToLogic(maBrowseBorder).Width();
2226 void SwViewShell::InvalidateLayout( bool bSizeChanged )
2228 if ( !bSizeChanged && !GetViewOptions()->getBrowseMode() &&
2229 !GetViewOptions()->IsWhitespaceHidden() )
2230 return;
2232 CurrShell aCurr( this );
2234 OSL_ENSURE( GetLayout(), "Layout not ready" );
2236 // When the Layout doesn't have a height yet, nothing is formatted.
2237 // That leads to problems with Invalidate, e.g. when setting up a new View
2238 // the content is inserted and formatted (regardless of empty VisArea).
2239 // Therefore the pages must be roused for formatting.
2240 if( !GetLayout()->getFrameArea().Height() )
2242 SwFrame* pPage = GetLayout()->Lower();
2243 while( pPage )
2245 pPage->InvalidateSize_();
2246 pPage = pPage->GetNext();
2248 return;
2251 LockPaint(LockPaintReason::InvalidateLayout);
2252 SwViewShell::StartAction();
2254 SwPageFrame *pPg = static_cast<SwPageFrame*>(GetLayout()->Lower());
2256 { pPg->InvalidateSize();
2257 pPg->InvalidatePrt_();
2258 pPg->InvaPercentLowers();
2259 if ( bSizeChanged )
2261 pPg->PrepareHeader();
2262 pPg->PrepareFooter();
2264 pPg = static_cast<SwPageFrame*>(pPg->GetNext());
2265 } while ( pPg );
2267 // When the size ratios in browse mode change,
2268 // the Position and PrtArea of the Content and Tab frames must be Invalidated.
2269 SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Pos;
2270 // In case of layout or mode change, the ContentFrames need a size-Invalidate
2271 // because of printer/screen formatting.
2272 if ( bSizeChanged )
2273 nInv |= SwInvalidateFlags::Size | SwInvalidateFlags::Direction;
2275 GetLayout()->InvalidateAllContent( nInv );
2277 SwFrame::CheckPageDescs( static_cast<SwPageFrame*>(GetLayout()->Lower()) );
2279 SwViewShell::EndAction();
2280 UnlockPaint();
2283 SwRootFrame *SwViewShell::GetLayout() const
2285 return mpLayout.get();
2288 vcl::RenderContext& SwViewShell::GetRefDev() const
2290 OutputDevice* pTmpOut = nullptr;
2291 if ( GetWin() &&
2292 GetViewOptions()->getBrowseMode() &&
2293 !GetViewOptions()->IsPrtFormat() )
2294 pTmpOut = GetWin()->GetOutDev();
2295 else
2296 pTmpOut = GetDoc()->getIDocumentDeviceAccess().getReferenceDevice( true );
2298 return *pTmpOut;
2301 const SwNodes& SwViewShell::GetNodes() const
2303 return mxDoc->GetNodes();
2306 void SwViewShell::DrawSelChanged()
2310 Size SwViewShell::GetDocSize() const
2312 Size aSz;
2313 const SwRootFrame* pRoot = GetLayout();
2314 if( pRoot )
2315 aSz = pRoot->getFrameArea().SSize();
2317 return aSz;
2320 SfxItemPool& SwViewShell::GetAttrPool()
2322 return GetDoc()->GetAttrPool();
2325 void SwViewShell::ApplyViewOptions( const SwViewOption &rOpt )
2327 for(SwViewShell& rSh : GetRingContainer())
2328 rSh.SwViewShell::StartAction();
2330 ImplApplyViewOptions( rOpt );
2332 // With one layout per view it is no longer necessary
2333 // to sync these "layout related" view options
2334 // But as long as we have to disable "multiple layout"
2336 for(SwViewShell& rSh : GetRingContainer())
2338 if(&rSh == this)
2339 continue;
2340 SwViewOption aOpt( *rSh.GetViewOptions() );
2341 aOpt.SyncLayoutRelatedViewOptions(rOpt);
2342 if ( !(aOpt == *rSh.GetViewOptions()) )
2343 rSh.ImplApplyViewOptions( aOpt );
2345 // End of disabled multiple window
2347 for(SwViewShell& rSh : GetRingContainer())
2348 rSh.SwViewShell::EndAction();
2351 static bool
2352 IsCursorInFieldmarkHidden(SwPaM const& rCursor, sw::FieldmarkMode const eMode)
2354 if (eMode == sw::FieldmarkMode::ShowBoth)
2356 return false;
2358 IDocumentMarkAccess const& rIDMA(*rCursor.GetDoc().getIDocumentMarkAccess());
2359 // iterate, for nested fieldmarks
2360 for (auto iter = rIDMA.getFieldmarksBegin(); iter != rIDMA.getFieldmarksEnd(); ++iter)
2362 if (*rCursor.GetPoint() <= (**iter).GetMarkStart())
2364 return false;
2366 if (*rCursor.GetPoint() < (**iter).GetMarkEnd())
2368 SwPosition const sepPos(sw::mark::FindFieldSep(**iter));
2369 if (eMode == sw::FieldmarkMode::ShowResult)
2371 if (*rCursor.GetPoint() <= sepPos
2372 && *rCursor.GetPoint() != (**iter).GetMarkStart())
2374 return true;
2377 else
2379 if (sepPos < *rCursor.GetPoint())
2381 return true;
2386 return false;
2389 void SwViewShell::ImplApplyViewOptions( const SwViewOption &rOpt )
2391 if (*mpOpt == rOpt)
2392 return;
2394 vcl::Window *pMyWin = GetWin();
2395 if( !pMyWin )
2397 OSL_ENSURE( pMyWin, "SwViewShell::ApplyViewOptions: no window" );
2398 return;
2401 CurrShell aCurr( this );
2403 bool bReformat = false;
2405 if( mpOpt->IsShowHiddenField() != rOpt.IsShowHiddenField() )
2407 static_cast<SwHiddenTextFieldType*>(mxDoc->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::HiddenText ))->
2408 SetHiddenFlag( !rOpt.IsShowHiddenField() );
2409 bReformat = true;
2411 if ( mpOpt->IsShowHiddenPara() != rOpt.IsShowHiddenPara() )
2413 SwHiddenParaFieldType* pFieldType = static_cast<SwHiddenParaFieldType*>(GetDoc()->
2414 getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::HiddenPara));
2415 if( pFieldType && pFieldType->HasWriterListeners() )
2416 pFieldType->PrintHiddenPara();
2417 bReformat = true;
2419 if ( !bReformat && mpOpt->IsShowHiddenChar() != rOpt.IsShowHiddenChar() )
2421 bReformat = GetDoc()->ContainsHiddenChars();
2423 if ( mpOpt->IsShowChangesInMargin() != rOpt.IsShowChangesInMargin() ||
2424 mpOpt->IsShowChangesInMargin2() != rOpt.IsShowChangesInMargin2() )
2426 if (rOpt.IsShowChangesInMargin())
2427 GetDoc()->GetDocumentRedlineManager().HideAll(
2428 /*bDeletion=*/!rOpt.IsShowChangesInMargin2() );
2429 else
2430 GetDoc()->GetDocumentRedlineManager().ShowAll();
2431 GetLayout()->SetHideRedlines( false );
2434 // bReformat becomes true, if ...
2435 // - fieldnames apply or not ...
2436 // ( - SwEndPortion must _no_ longer be generated. )
2437 // - Of course, the screen is something completely different than the printer ...
2438 bool const isToggleFieldNames(mpOpt->IsFieldName() != rOpt.IsFieldName());
2440 if (mpOpt->IsFieldName() != rOpt.IsFieldName()
2441 || mpOpt->IsParagraph() != rOpt.IsParagraph())
2443 GetLayout()->SetFieldmarkMode( rOpt.IsFieldName()
2444 ? sw::FieldmarkMode::ShowCommand
2445 : sw::FieldmarkMode::ShowResult,
2446 rOpt.IsParagraph()
2447 ? sw::ParagraphBreakMode::Shown
2448 : sw::ParagraphBreakMode::Hidden);
2449 bReformat = true;
2452 // The map mode is changed, minima/maxima will be attended by UI
2453 if( mpOpt->GetZoom() != rOpt.GetZoom() && !IsPreview() )
2455 MapMode aMode( pMyWin->GetMapMode() );
2456 Fraction aNewFactor( rOpt.GetZoom(), 100 );
2457 aMode.SetScaleX( aNewFactor );
2458 aMode.SetScaleY( aNewFactor );
2459 pMyWin->SetMapMode( aMode );
2460 // if not a reference device (printer) is used for formatting,
2461 // but the screen, new formatting is needed for zoomfactor changes.
2462 if (mpOpt->getBrowseMode() || mpOpt->IsWhitespaceHidden())
2463 bReformat = true;
2466 bool bBrowseModeChanged = false;
2467 if( mpOpt->getBrowseMode() != rOpt.getBrowseMode() )
2469 bBrowseModeChanged = true;
2470 bReformat = true;
2472 else if( mpOpt->getBrowseMode() && mpOpt->IsPrtFormat() != rOpt.IsPrtFormat() )
2473 bReformat = true;
2475 bool bHideWhitespaceModeChanged = false;
2476 if (mpOpt->IsWhitespaceHidden() != rOpt.IsWhitespaceHidden())
2478 // When whitespace is hidden, view change needs reformatting.
2479 bHideWhitespaceModeChanged = true;
2480 bReformat = true;
2483 if ( HasDrawView() || rOpt.IsGridVisible() )
2485 if ( !HasDrawView() )
2486 MakeDrawView();
2488 SwDrawView *pDView = Imp()->GetDrawView();
2489 if ( pDView->IsDragStripes() != rOpt.IsCrossHair() )
2490 pDView->SetDragStripes( rOpt.IsCrossHair() );
2492 if ( pDView->IsGridSnap() != rOpt.IsSnap() )
2493 pDView->SetGridSnap( rOpt.IsSnap() );
2495 if ( pDView->IsGridVisible() != rOpt.IsGridVisible() )
2496 pDView->SetGridVisible( rOpt.IsGridVisible() );
2498 const Size &rSz = rOpt.GetSnapSize();
2499 pDView->SetGridCoarse( rSz );
2501 const Size aFSize
2502 ( rSz.Width() ? rSz.Width() / (rOpt.GetDivisionX()+1) : 0,
2503 rSz.Height()? rSz.Height()/ (rOpt.GetDivisionY()+1) : 0);
2504 pDView->SetGridFine( aFSize );
2505 Fraction aSnGrWdtX(rSz.Width(), rOpt.GetDivisionX() + 1);
2506 Fraction aSnGrWdtY(rSz.Height(), rOpt.GetDivisionY() + 1);
2507 pDView->SetSnapGridWidth( aSnGrWdtX, aSnGrWdtY );
2509 // set handle size to 9 pixels, always
2510 pDView->SetMarkHdlSizePixel(9);
2513 bool bOnlineSpellChgd = mpOpt->IsOnlineSpell() != rOpt.IsOnlineSpell();
2515 *mpOpt = rOpt; // First the options are taken.
2516 mpOpt->SetUIOptions(rOpt);
2518 mxDoc->GetDocumentSettingManager().set(DocumentSettingId::HTML_MODE, 0 != ::GetHtmlMode(mxDoc->GetDocShell()));
2520 if( bBrowseModeChanged || bHideWhitespaceModeChanged )
2522 // #i44963# Good occasion to check if page sizes in
2523 // page descriptions are still set to (LONG_MAX, LONG_MAX) (html import)
2524 mxDoc->CheckDefaultPageFormat();
2525 InvalidateLayout( true );
2528 SwXTextDocument* pModel = comphelper::getFromUnoTunnel<SwXTextDocument>(GetSfxViewShell()->GetCurrentDocument());
2529 SfxLokHelper::notifyViewRenderState(GetSfxViewShell(), pModel);
2531 pMyWin->Invalidate();
2532 if ( bReformat )
2534 // Nothing helps, we need to send all ContentFrames a
2535 // Prepare, we format anew:
2536 SwViewShell::StartAction();
2537 Reformat();
2538 SwViewShell::EndAction();
2541 if (isToggleFieldNames)
2543 for(SwViewShell& rSh : GetRingContainer())
2545 if (SwCursorShell *const pSh = dynamic_cast<SwCursorShell *>(&rSh))
2547 if ((mpOpt->IsFieldName() && pSh->CursorInsideInputField())
2548 || IsCursorInFieldmarkHidden(*pSh->GetCursor(),
2549 pSh->GetLayout()->GetFieldmarkMode()))
2550 { // move cursor out of field
2551 pSh->Left(1, SwCursorSkipMode::Chars);
2555 // the layout changes but SetModified() wasn't called so do it here:
2556 mxDoc->GetDocumentLayoutManager().ClearSwLayouterEntries();
2559 if( !bOnlineSpellChgd )
2560 return;
2562 if ( !comphelper::LibreOfficeKit::isActive() )
2564 bool bOnlineSpl = rOpt.IsOnlineSpell();
2565 for(SwViewShell& rSh : GetRingContainer())
2567 if(&rSh == this)
2568 continue;
2569 rSh.mpOpt->SetOnlineSpell( bOnlineSpl );
2570 vcl::Window *pTmpWin = rSh.GetWin();
2571 if( pTmpWin )
2572 pTmpWin->Invalidate();
2577 void SwViewShell::SetUIOptions( const SwViewOption &rOpt )
2579 mpOpt->SetUIOptions(rOpt);
2580 //the API-Flag of the view options is set but never reset
2581 //it is required to set scroll bars in readonly documents
2582 if(rOpt.IsStarOneSetting())
2583 mpOpt->SetStarOneSetting(true);
2585 mpOpt->SetSymbolFont(rOpt.GetSymbolFont());
2588 void SwViewShell::SetReadonlyOption(bool bSet)
2590 //JP 01.02.99: at readonly flag query properly
2591 // and if need be format; Bug 61335
2593 // Are we switching from readonly to edit?
2594 if( bSet == mpOpt->IsReadonly() )
2595 return;
2597 // so that the flags can be queried properly.
2598 mpOpt->SetReadonly( false );
2600 bool bReformat = mpOpt->IsFieldName();
2602 mpOpt->SetReadonly( bSet );
2604 if( bReformat )
2606 SwViewShell::StartAction();
2607 Reformat();
2608 if ( GetWin() && !comphelper::LibreOfficeKit::isActive() )
2609 GetWin()->Invalidate();
2610 SwViewShell::EndAction();
2612 else if ( GetWin() && !comphelper::LibreOfficeKit::isActive() )
2613 GetWin()->Invalidate();
2614 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
2615 if( Imp()->IsAccessible() )
2616 Imp()->InvalidateAccessibleEditableState( false );
2617 #endif
2620 void SwViewShell::SetPDFExportOption(bool bSet)
2622 if( bSet != mpOpt->IsPDFExport() )
2624 if( bSet && mpOpt->getBrowseMode() )
2625 mpOpt->SetPrtFormat( true );
2626 mpOpt->SetPDFExport(bSet);
2630 void SwViewShell::SetReadonlySelectionOption(bool bSet)
2632 if( bSet != mpOpt->IsSelectionInReadonly() )
2634 mpOpt->SetSelectionInReadonly(bSet);
2638 void SwViewShell::SetPrtFormatOption( bool bSet )
2640 mpOpt->SetPrtFormat( bSet );
2643 void SwViewShell::UISizeNotify()
2645 if ( mbDocSizeChgd )
2647 mbDocSizeChgd = false;
2648 bool bOld = bInSizeNotify;
2649 bInSizeNotify = true;
2650 ::SizeNotify( this, GetDocSize() );
2651 bInSizeNotify = bOld;
2655 void SwViewShell::SetRestoreActions(sal_uInt16 nSet)
2657 OSL_ENSURE(!GetRestoreActions()||!nSet, "multiple restore of the Actions ?");
2658 Imp()->SetRestoreActions(nSet);
2660 sal_uInt16 SwViewShell::GetRestoreActions() const
2662 return Imp()->GetRestoreActions();
2665 bool SwViewShell::IsNewLayout() const
2667 return GetLayout()->IsNewLayout();
2670 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
2671 uno::Reference< css::accessibility::XAccessible > SwViewShell::CreateAccessible()
2673 uno::Reference< css::accessibility::XAccessible > xAcc;
2675 // We require a layout and an XModel to be accessible.
2676 OSL_ENSURE( mpLayout, "no layout, no access" );
2677 OSL_ENSURE( GetWin(), "no window, no access" );
2679 if( mxDoc->getIDocumentLayoutAccess().GetCurrentViewShell() && GetWin() )
2680 xAcc = Imp()->GetAccessibleMap().GetDocumentView();
2682 return xAcc;
2685 uno::Reference< css::accessibility::XAccessible > SwViewShell::CreateAccessiblePreview()
2687 OSL_ENSURE( IsPreview(),
2688 "Can't create accessible preview for non-preview SwViewShell" );
2690 // We require a layout and an XModel to be accessible.
2691 OSL_ENSURE( mpLayout, "no layout, no access" );
2692 OSL_ENSURE( GetWin(), "no window, no access" );
2694 if ( IsPreview() && GetLayout()&& GetWin() )
2696 return Imp()->GetAccessibleMap().GetDocumentPreview(
2697 PagePreviewLayout()->maPreviewPages,
2698 GetWin()->GetMapMode().GetScaleX(),
2699 GetLayout()->GetPageByPageNum( PagePreviewLayout()->mnSelectedPageNum ),
2700 PagePreviewLayout()->maWinSize );
2702 return nullptr;
2705 void SwViewShell::InvalidateAccessibleFocus()
2707 if( Imp() && Imp()->IsAccessible() )
2708 Imp()->GetAccessibleMap().InvalidateFocus();
2712 * invalidate CONTENT_FLOWS_FROM/_TO relation for paragraphs #i27138#
2714 void SwViewShell::InvalidateAccessibleParaFlowRelation( const SwTextFrame* _pFromTextFrame,
2715 const SwTextFrame* _pToTextFrame )
2717 if ( GetLayout() && GetLayout()->IsAnyShellAccessible() )
2719 Imp()->InvalidateAccessibleParaFlowRelation_( _pFromTextFrame, _pToTextFrame );
2724 * invalidate text selection for paragraphs #i27301#
2726 void SwViewShell::InvalidateAccessibleParaTextSelection()
2728 if ( GetLayout() && GetLayout()->IsAnyShellAccessible() )
2730 Imp()->InvalidateAccessibleParaTextSelection_();
2735 * invalidate attributes for paragraphs #i88069#
2737 void SwViewShell::InvalidateAccessibleParaAttrs( const SwTextFrame& rTextFrame )
2739 if ( GetLayout() && GetLayout()->IsAnyShellAccessible() )
2741 Imp()->InvalidateAccessibleParaAttrs_( rTextFrame );
2745 SwAccessibleMap* SwViewShell::GetAccessibleMap()
2747 if ( Imp()->IsAccessible() )
2749 return &(Imp()->GetAccessibleMap());
2752 return nullptr;
2755 void SwViewShell::ApplyAccessibilityOptions()
2757 if (comphelper::IsFuzzing())
2758 return;
2759 if (mpOpt->IsPagePreview() && !officecfg::Office::Common::Accessibility::IsForPagePreviews::get())
2761 mpAccOptions->SetAlwaysAutoColor(false);
2762 mpAccOptions->SetStopAnimatedGraphics(false);
2764 else
2766 mpAccOptions->SetAlwaysAutoColor(officecfg::Office::Common::Accessibility::IsAutomaticFontColor::get());
2767 // tdf#161765: Let user choose which animation settings to use: OS's / LO's
2768 // New options: "System"/"No"/"Yes".
2769 // Do respect OS's animation setting if the user has selected the option "System"
2770 mpAccOptions->SetStopAnimatedGraphics(! MiscSettings::IsAnimatedGraphicAllowed());
2772 // Form view
2773 // Always set this option, not only if document is read-only:
2774 mpOpt->SetSelectionInReadonly(officecfg::Office::Common::Accessibility::IsSelectionInReadonly::get());
2777 #endif // ENABLE_WASM_STRIP_ACCESSIBILITY
2779 ShellResource* SwViewShell::GetShellRes()
2781 return spShellRes;
2784 //static
2785 void SwViewShell::SetCareDialog(const std::shared_ptr<weld::Window>& rNew)
2787 auto& spCareDialog = getCareDialog();
2788 (*spCareDialog.get()) = rNew;
2791 //static
2792 weld::Window* SwViewShell::GetCareDialog(SwViewShell const & rVSh)
2794 auto& spCareDialog = getCareDialog();
2795 return (*spCareDialog.get()) ? spCareDialog.get()->get() : CareChildWin(rVSh);
2798 sal_uInt16 SwViewShell::GetPageCount() const
2800 return GetLayout() ? GetLayout()->GetPageNum() : 1;
2803 Size SwViewShell::GetPageSize( sal_uInt16 nPageNum, bool bSkipEmptyPages ) const
2805 Size aSize;
2806 const SwRootFrame* pTmpRoot = GetLayout();
2807 if( pTmpRoot && nPageNum )
2809 const SwPageFrame* pPage = static_cast<const SwPageFrame*>
2810 (pTmpRoot->Lower());
2812 while( --nPageNum && pPage && pPage->GetNext() )
2813 pPage = static_cast<const SwPageFrame*>( pPage->GetNext() );
2815 if( !bSkipEmptyPages && pPage && pPage->IsEmptyPage() && pPage->GetNext() )
2816 pPage = static_cast<const SwPageFrame*>( pPage->GetNext() );
2818 if (pPage)
2819 aSize = pPage->getFrameArea().SSize();
2821 return aSize;
2824 void SwViewShell::OnGraphicArrived(const SwRect& rRect)
2826 for(SwViewShell& rShell : GetRingContainer())
2828 CurrShell aCurr(&rShell);
2829 if(rShell.IsPreview())
2831 if(rShell.GetWin())
2832 ::RepaintPagePreview(&rShell, rRect);
2834 else if(rShell.VisArea().Overlaps(rRect) && OUTDEV_WINDOW == rShell.GetOut()->GetOutDevType())
2836 // invalidate instead of painting
2837 rShell.GetWin()->Invalidate(rRect.SVRect());
2841 // #i12836# enhanced pdf export
2842 sal_Int32 SwViewShell::GetPageNumAndSetOffsetForPDF( OutputDevice& rOut, const SwRect& rRect ) const
2844 OSL_ENSURE( GetLayout(), "GetPageNumAndSetOffsetForPDF assumes presence of layout" );
2846 sal_Int32 nRet = -1;
2848 // #i40059# Position out of bounds:
2849 SwRect aRect( rRect );
2850 aRect.Pos().setX( std::max( aRect.Left(), GetLayout()->getFrameArea().Left() ) );
2852 const SwPageFrame* pPage = GetLayout()->GetPageAtPos( aRect.Center() );
2853 if ( pPage )
2855 OSL_ENSURE( pPage, "GetPageNumAndSetOffsetForPDF: No page found" );
2857 Point aOffset( pPage->getFrameArea().Pos() );
2858 aOffset.setX( -aOffset.X() );
2859 aOffset.setY( -aOffset.Y() );
2861 MapMode aMapMode( rOut.GetMapMode() );
2862 aMapMode.SetOrigin( aOffset );
2863 rOut.SetMapMode( aMapMode );
2865 nRet = pPage->GetPhyPageNum() - 1;
2868 return nRet;
2871 // --> PB 2007-05-30 #146850#
2872 const BitmapEx& SwViewShell::GetReplacementBitmap( bool bIsErrorState )
2874 if (bIsErrorState)
2876 if (!m_xErrorBmp)
2877 m_xErrorBmp.reset(new BitmapEx(RID_GRAPHIC_ERRORBMP));
2878 return *m_xErrorBmp;
2881 if (!m_xReplaceBmp)
2882 m_xReplaceBmp.reset(new BitmapEx(RID_GRAPHIC_REPLACEBMP));
2883 return *m_xReplaceBmp;
2886 void SwViewShell::DeleteReplacementBitmaps()
2888 m_xErrorBmp.reset();
2889 m_xReplaceBmp.reset();
2892 SwPostItMgr* SwViewShell::GetPostItMgr()
2894 SwView* pView = GetDoc()->GetDocShell() ? GetDoc()->GetDocShell()->GetView() : nullptr;
2895 if ( pView )
2896 return pView->GetPostItMgr();
2898 return nullptr;
2901 void SwViewShell::GetFirstLastVisPageNumbers(SwVisiblePageNumbers& rVisiblePageNumbers, SwView& rView)
2903 SwRect rViewVisArea(rView.GetVisArea());
2904 vcl::RenderContext* pRenderContext = GetOut();
2905 const SwPageFrame* pPageFrame = Imp()->GetFirstVisPage(pRenderContext);
2906 SwRect rPageRect = pPageFrame->getFrameArea();
2907 rPageRect.AddBottom(-pPageFrame->GetBottomMargin());
2908 while (!rPageRect.Overlaps(rViewVisArea) && pPageFrame->GetNext())
2910 pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetNext());
2911 rPageRect = pPageFrame->getFrameArea();
2912 if (rPageRect.Top() > 0)
2913 rPageRect.AddBottom(-pPageFrame->GetBottomMargin());
2915 rVisiblePageNumbers.nFirstPhy = pPageFrame->GetPhyPageNum();
2916 rVisiblePageNumbers.nFirstVirt = pPageFrame->GetVirtPageNum();
2917 const SvxNumberType& rFirstVisNum = pPageFrame->GetPageDesc()->GetNumType();
2918 rVisiblePageNumbers.sFirstCustomPhy = rFirstVisNum.GetNumStr(rVisiblePageNumbers.nFirstPhy);
2919 rVisiblePageNumbers.sFirstCustomVirt = rFirstVisNum.GetNumStr(rVisiblePageNumbers.nFirstVirt);
2920 pPageFrame = Imp()->GetLastVisPage(pRenderContext);
2921 rPageRect = pPageFrame->getFrameArea();
2922 rPageRect.AddTop(pPageFrame->GetTopMargin());
2923 while (!rPageRect.Overlaps(rViewVisArea) && pPageFrame->GetPrev())
2925 pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetPrev());
2926 rPageRect = pPageFrame->getFrameArea();
2927 rPageRect.AddTop(pPageFrame->GetTopMargin());
2929 rVisiblePageNumbers.nLastPhy = pPageFrame->GetPhyPageNum();
2930 rVisiblePageNumbers.nLastVirt = pPageFrame->GetVirtPageNum();
2931 const SvxNumberType& rLastVisNum = pPageFrame->GetPageDesc()->GetNumType();
2932 rVisiblePageNumbers.sLastCustomPhy = rLastVisNum.GetNumStr(rVisiblePageNumbers.nLastPhy);
2933 rVisiblePageNumbers.sLastCustomVirt = rLastVisNum.GetNumStr(rVisiblePageNumbers.nLastVirt);
2937 * Document Interface Access
2939 const IDocumentSettingAccess& SwViewShell::getIDocumentSettingAccess() const { return mxDoc->GetDocumentSettingManager(); }
2940 IDocumentSettingAccess& SwViewShell::getIDocumentSettingAccess() { return mxDoc->GetDocumentSettingManager(); }
2941 const IDocumentDeviceAccess& SwViewShell::getIDocumentDeviceAccess() const { return mxDoc->getIDocumentDeviceAccess(); }
2942 IDocumentDeviceAccess& SwViewShell::getIDocumentDeviceAccess() { return mxDoc->getIDocumentDeviceAccess(); }
2943 const IDocumentMarkAccess* SwViewShell::getIDocumentMarkAccess() const { return mxDoc->getIDocumentMarkAccess(); }
2944 IDocumentMarkAccess* SwViewShell::getIDocumentMarkAccess() { return mxDoc->getIDocumentMarkAccess(); }
2945 const IDocumentDrawModelAccess& SwViewShell::getIDocumentDrawModelAccess() const { return mxDoc->getIDocumentDrawModelAccess(); }
2946 IDocumentDrawModelAccess& SwViewShell::getIDocumentDrawModelAccess() { return mxDoc->getIDocumentDrawModelAccess(); }
2947 const IDocumentRedlineAccess& SwViewShell::getIDocumentRedlineAccess() const { return mxDoc->getIDocumentRedlineAccess(); }
2948 IDocumentRedlineAccess& SwViewShell::getIDocumentRedlineAccess() { return mxDoc->getIDocumentRedlineAccess(); }
2949 const IDocumentLayoutAccess& SwViewShell::getIDocumentLayoutAccess() const { return mxDoc->getIDocumentLayoutAccess(); }
2950 IDocumentLayoutAccess& SwViewShell::getIDocumentLayoutAccess() { return mxDoc->getIDocumentLayoutAccess(); }
2951 IDocumentContentOperations& SwViewShell::getIDocumentContentOperations() { return mxDoc->getIDocumentContentOperations(); }
2952 IDocumentStylePoolAccess& SwViewShell::getIDocumentStylePoolAccess() { return mxDoc->getIDocumentStylePoolAccess(); }
2953 const IDocumentStatistics& SwViewShell::getIDocumentStatistics() const { return mxDoc->getIDocumentStatistics(); }
2955 IDocumentUndoRedo & SwViewShell::GetIDocumentUndoRedo()
2956 { return mxDoc->GetIDocumentUndoRedo(); }
2957 IDocumentUndoRedo const& SwViewShell::GetIDocumentUndoRedo() const
2958 { return mxDoc->GetIDocumentUndoRedo(); }
2960 // --> OD 2007-11-14 #i83479#
2961 const IDocumentListItems* SwViewShell::getIDocumentListItemsAccess() const
2963 return &mxDoc->getIDocumentListItems();
2966 const IDocumentOutlineNodes* SwViewShell::getIDocumentOutlineNodesAccess() const
2968 return &mxDoc->getIDocumentOutlineNodes();
2971 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */