1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <scitems.hxx>
22 #include <editeng/eeitem.hxx>
24 #include <svtools/colorcfg.hxx>
25 #include <editeng/colritem.hxx>
26 #include <editeng/editview.hxx>
27 #include <editeng/fhgtitem.hxx>
28 #include <editeng/brushitem.hxx>
29 #include <sfx2/bindings.hxx>
30 #include <sfx2/printer.hxx>
31 #include <vcl/cursor.hxx>
32 #include <vcl/settings.hxx>
33 #include <o3tl/unit_conversion.hxx>
34 #include <osl/diagnose.h>
36 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
37 #include <comphelper/lok.hxx>
38 #include <comphelper/scopeguard.hxx>
39 #include <sfx2/lokhelper.hxx>
40 #include <sfx2/lokcomponenthelpers.hxx>
42 #include <svx/svdview.hxx>
43 #include <svx/svdpagv.hxx>
44 #include <svx/sdrpagewindow.hxx>
45 #include <svx/sdr/contact/objectcontactofpageview.hxx>
46 #include <svx/sdr/contact/viewobjectcontact.hxx>
47 #include <svx/sdr/contact/viewcontact.hxx>
48 #include <tabvwsh.hxx>
49 #include <vcl/lineinfo.hxx>
50 #include <vcl/sysdata.hxx>
52 #include <gridwin.hxx>
53 #include <viewdata.hxx>
55 #include <document.hxx>
57 #include <patattr.hxx>
59 #include <docoptio.hxx>
60 #include <notemark.hxx>
63 #include <inputhdl.hxx>
64 #include <rfindlst.hxx>
65 #include <hiranges.hxx>
66 #include <pagedata.hxx>
67 #include <docpool.hxx>
68 #include <globstr.hrc>
69 #include <scresid.hxx>
71 #include <cbutton.hxx>
72 #include <invmerge.hxx>
73 #include <editutil.hxx>
74 #include <inputopt.hxx>
75 #include <fillinfo.hxx>
76 #include <dpcontrol.hxx>
77 #include <queryparam.hxx>
78 #include <queryentry.hxx>
79 #include <markdata.hxx>
81 #include <vcl/virdev.hxx>
82 #include <svx/sdrpaintwindow.hxx>
83 #include <drwlayer.hxx>
85 static void lcl_LimitRect( tools::Rectangle
& rRect
, const tools::Rectangle
& rVisible
)
87 if ( rRect
.Top() < rVisible
.Top()-1 ) rRect
.SetTop( rVisible
.Top()-1 );
88 if ( rRect
.Bottom() > rVisible
.Bottom()+1 ) rRect
.SetBottom( rVisible
.Bottom()+1 );
90 // The header row must be drawn also when the inner rectangle is not visible,
91 // that is why there is no return value anymore.
92 // When it is far away, then lcl_DrawOneFrame is not even called.
95 static void lcl_DrawOneFrame( vcl::RenderContext
* pDev
, const tools::Rectangle
& rInnerPixel
,
96 const OUString
& rTitle
, const Color
& rColor
, bool bTextBelow
,
97 double nPPTX
, double nPPTY
, const Fraction
& rZoomY
,
98 ScDocument
& rDoc
, ScViewData
& rButtonViewData
, bool bLayoutRTL
)
100 // rButtonViewData is only used to set the button size,
102 tools::Rectangle aInner
= rInnerPixel
;
105 aInner
.SetLeft( rInnerPixel
.Right() );
106 aInner
.SetRight( rInnerPixel
.Left() );
109 tools::Rectangle
aVisible( Point(0,0), pDev
->GetOutputSizePixel() );
110 lcl_LimitRect( aInner
, aVisible
);
112 tools::Rectangle aOuter
= aInner
;
113 tools::Long nHor
= static_cast<tools::Long
>( SC_SCENARIO_HSPACE
* nPPTX
);
114 tools::Long nVer
= static_cast<tools::Long
>( SC_SCENARIO_VSPACE
* nPPTY
);
115 aOuter
.AdjustLeft( -nHor
);
116 aOuter
.AdjustRight(nHor
);
117 aOuter
.AdjustTop( -nVer
);
118 aOuter
.AdjustBottom(nVer
);
120 // use ScPatternAttr::GetFont only for font size
122 rDoc
.GetPool()->GetDefaultItem(ATTR_PATTERN
).
123 fillFontOnly(aAttrFont
, pDev
, &rZoomY
);
125 // everything else from application font
126 vcl::Font aAppFont
= pDev
->GetSettings().GetStyleSettings().GetAppFont();
127 aAppFont
.SetFontSize( aAttrFont
.GetFontSize() );
129 aAppFont
.SetAlignment( ALIGN_TOP
);
130 pDev
->SetFont( aAppFont
);
132 Size
aTextSize( pDev
->GetTextWidth( rTitle
), pDev
->GetTextHeight() );
135 aOuter
.AdjustBottom(aTextSize
.Height() );
137 aOuter
.AdjustTop( -(aTextSize
.Height()) );
139 pDev
->SetLineColor();
140 pDev
->SetFillColor( rColor
);
141 // left, top, right, bottom
142 pDev
->DrawRect( tools::Rectangle( aOuter
.Left(), aOuter
.Top(), aInner
.Left(), aOuter
.Bottom() ) );
143 pDev
->DrawRect( tools::Rectangle( aOuter
.Left(), aOuter
.Top(), aOuter
.Right(), aInner
.Top() ) );
144 pDev
->DrawRect( tools::Rectangle( aInner
.Right(), aOuter
.Top(), aOuter
.Right(), aOuter
.Bottom() ) );
145 pDev
->DrawRect( tools::Rectangle( aOuter
.Left(), aInner
.Bottom(), aOuter
.Right(), aOuter
.Bottom() ) );
147 tools::Long nButtonY
= bTextBelow
? aInner
.Bottom() : aOuter
.Top();
149 ScDDComboBoxButton
aComboButton(pDev
);
150 aComboButton
.SetOptSizePixel();
151 tools::Long nBWidth
= tools::Long(aComboButton
.GetSizePixel().Width() * rZoomY
);
152 tools::Long nBHeight
= nVer
+ aTextSize
.Height() + 1;
153 Size
aButSize( nBWidth
, nBHeight
);
154 tools::Long nButtonPos
= bLayoutRTL
? aOuter
.Left() : aOuter
.Right()-nBWidth
+1;
155 aComboButton
.Draw( Point(nButtonPos
, nButtonY
), aButSize
);
156 rButtonViewData
.SetScenButSize( aButSize
);
158 tools::Long nTextStart
= bLayoutRTL
? aInner
.Right() - aTextSize
.Width() + 1 : aInner
.Left();
160 bool bWasClip
= false;
161 vcl::Region aOldClip
;
162 bool bClip
= ( aTextSize
.Width() > aOuter
.Right() - nBWidth
- aInner
.Left() );
165 if (pDev
->IsClipRegion())
168 aOldClip
= pDev
->GetActiveClipRegion();
170 tools::Long nClipStartX
= bLayoutRTL
? aOuter
.Left() + nBWidth
: aInner
.Left();
171 tools::Long nClipEndX
= bLayoutRTL
? aInner
.Right() : aOuter
.Right() - nBWidth
;
172 pDev
->SetClipRegion( vcl::Region(tools::Rectangle( nClipStartX
, nButtonY
+ nVer
/2,
173 nClipEndX
, nButtonY
+ nVer
/2 + aTextSize
.Height())) );
176 pDev
->DrawText( Point( nTextStart
, nButtonY
+ nVer
/2 ), rTitle
);
181 pDev
->SetClipRegion(aOldClip
);
183 pDev
->SetClipRegion();
186 pDev
->SetFillColor();
187 pDev
->SetLineColor( COL_BLACK
);
188 pDev
->DrawRect( aInner
);
189 pDev
->DrawRect( aOuter
);
192 static void lcl_DrawScenarioFrames( OutputDevice
* pDev
, ScViewData
& rViewData
, ScSplitPos eWhich
,
193 SCCOL nX1
, SCROW nY1
, SCCOL nX2
, SCROW nY2
)
195 ScDocument
& rDoc
= rViewData
.GetDocument();
196 SCTAB nTab
= rViewData
.GetTabNo();
197 SCTAB nTabCount
= rDoc
.GetTableCount();
198 if ( nTab
+1 >= nTabCount
|| !rDoc
.IsScenario(nTab
+1) || rDoc
.IsScenario(nTab
) )
201 if ( nX1
> 0 ) --nX1
;
202 if ( nY1
>=2 ) nY1
-= 2; // Hack: Header row affects two cells
203 else if ( nY1
> 0 ) --nY1
;
204 if ( nX2
< rDoc
.MaxCol() ) ++nX2
;
205 if ( nY2
< rDoc
.MaxRow()-1 ) nY2
+= 2; // Hack: Header row affects two cells
206 else if ( nY2
< rDoc
.MaxRow() ) ++nY2
;
207 ScRange
aViewRange( nX1
,nY1
,nTab
, nX2
,nY2
,nTab
);
209 //! cache the ranges in table!!!!
211 ScMarkData
aMarks(rDoc
.GetSheetLimits());
212 for (SCTAB i
=nTab
+1; i
<nTabCount
&& rDoc
.IsScenario(i
); i
++)
213 rDoc
.MarkScenario( i
, nTab
, aMarks
, false, ScScenarioFlags::ShowFrame
);
214 ScRangeListRef xRanges
= new ScRangeList
;
215 aMarks
.FillRangeListWithMarks( xRanges
.get(), false );
217 bool bLayoutRTL
= rDoc
.IsLayoutRTL( nTab
);
218 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
220 for (size_t j
= 0, n
= xRanges
->size(); j
< n
; ++j
)
222 ScRange aRange
= (*xRanges
)[j
];
223 // Always extend scenario frame to merged cells where no new non-covered cells
225 rDoc
.ExtendTotalMerge( aRange
);
227 //! -> Extend repaint when merging !!!
229 if ( aRange
.Intersects( aViewRange
) ) //! Space for Text/Button?
231 Point aStartPos
= rViewData
.GetScrPos(
232 aRange
.aStart
.Col(), aRange
.aStart
.Row(), eWhich
, true );
233 Point aEndPos
= rViewData
.GetScrPos(
234 aRange
.aEnd
.Col()+1, aRange
.aEnd
.Row()+1, eWhich
, true );
236 aStartPos
.AdjustX( -nLayoutSign
);
237 aStartPos
.AdjustY( -1 );
238 aEndPos
.AdjustX( -nLayoutSign
);
239 aEndPos
.AdjustY( -1 );
241 bool bTextBelow
= ( aRange
.aStart
.Row() == 0 );
244 Color
aColor( COL_LIGHTGRAY
);
245 for (SCTAB nAct
=nTab
+1; nAct
<nTabCount
&& rDoc
.IsScenario(nAct
); nAct
++)
246 if ( rDoc
.IsActiveScenario(nAct
) && rDoc
.HasScenarioRange(nAct
,aRange
) )
248 OUString aDummyComment
;
249 ScScenarioFlags nDummyFlags
;
250 rDoc
.GetName( nAct
, aCurrent
);
251 rDoc
.GetScenarioData( nAct
, aDummyComment
, aColor
, nDummyFlags
);
254 if (aCurrent
.isEmpty())
255 aCurrent
= ScResId( STR_EMPTYDATA
);
257 //! Own text "(None)" instead of "(Empty)" ???
259 lcl_DrawOneFrame( pDev
, tools::Rectangle( aStartPos
, aEndPos
),
260 aCurrent
, aColor
, bTextBelow
,
261 rViewData
.GetPPTX(), rViewData
.GetPPTY(), rViewData
.GetZoomY(),
262 rDoc
, rViewData
, bLayoutRTL
);
267 static void lcl_DrawHighlight( ScOutputData
& rOutputData
, const ScViewData
& rViewData
,
268 const std::vector
<ScHighlightEntry
>& rHighlightRanges
)
270 SCTAB nTab
= rViewData
.GetTabNo();
271 for ( const auto& rHighlightRange
: rHighlightRanges
)
273 ScRange aRange
= rHighlightRange
.aRef
;
274 if ( nTab
>= aRange
.aStart
.Tab() && nTab
<= aRange
.aEnd
.Tab() )
276 rOutputData
.DrawRefMark(
277 aRange
.aStart
.Col(), aRange
.aStart
.Row(),
278 aRange
.aEnd
.Col(), aRange
.aEnd
.Row(),
279 rHighlightRange
.aColor
, false );
284 // Calculates top-left offset to be applied based on margins and indent.
285 static void lcl_GetEditAreaTLOffset(tools::Long
& nOffsetX
, tools::Long
& nOffsetY
, const ScAddress
& rAddr
,
286 const ScViewData
& rViewData
, ScDocument
& rDoc
)
288 tools::Long nLeftMargin
= 0;
289 tools::Long nTopMargin
= 0;
290 tools::Long nIndent
= 0;
291 tools::Long nDummy
= 0;
292 ScEditUtil
aEUtil(&rDoc
, rAddr
.Col(), rAddr
.Row(), rAddr
.Tab(),
293 Point(0, 0), nullptr, rViewData
.GetPPTX(),
294 rViewData
.GetPPTY(), Fraction(1.0), Fraction(1.0),
295 false /* bPrintTwips */);
296 const ScPatternAttr
* pPattern
= rDoc
.GetPattern(rAddr
);
297 if (!rDoc
.IsLayoutRTL(rAddr
.Tab()))
298 nIndent
= aEUtil
.GetIndent(pPattern
);
299 aEUtil
.GetMargins(pPattern
, nLeftMargin
, nTopMargin
, nDummy
, nDummy
);
300 nOffsetX
= nIndent
+ nLeftMargin
;
301 nOffsetY
= nTopMargin
;
304 void ScGridWindow::DoInvertRect( const tools::Rectangle
& rPixel
)
306 if ( rPixel
== aInvertRect
)
307 aInvertRect
= tools::Rectangle(); // Cancel
310 OSL_ENSURE( aInvertRect
.IsEmpty(), "DoInvertRect no pairs" );
312 aInvertRect
= rPixel
; // Mark new rectangle
315 UpdateHeaderOverlay(); // uses aInvertRect
318 void ScGridWindow::PrePaint(vcl::RenderContext
& /*rRenderContext*/)
320 // forward PrePaint to DrawingLayer
321 ScTabViewShell
* pTabViewShell
= mrViewData
.GetViewShell();
325 SdrView
* pDrawView
= pTabViewShell
->GetScDrawView();
329 pDrawView
->PrePaint();
334 bool ScGridWindow::NeedLOKCursorInvalidation(const tools::Rectangle
& rCursorRect
,
335 const Fraction aScaleX
, const Fraction aScaleY
)
337 // Don't see the need for a map as there will be only a few zoom levels
338 // and as of now X and Y zooms in online are the same.
339 for (auto& rEntry
: maLOKLastCursor
)
341 if (aScaleX
== rEntry
.aScaleX
&& aScaleY
== rEntry
.aScaleY
)
343 if (rCursorRect
== rEntry
.aRect
)
344 return false; // No change
346 // Update and allow invalidate.
347 rEntry
.aRect
= rCursorRect
;
352 maLOKLastCursor
.push_back(LOKCursorEntry
{aScaleX
, aScaleY
, rCursorRect
});
356 void ScGridWindow::InvalidateLOKViewCursor(const tools::Rectangle
& rCursorRect
,
357 const Fraction aScaleX
, const Fraction aScaleY
)
359 if (!NeedLOKCursorInvalidation(rCursorRect
, aScaleX
, aScaleY
))
362 ScTabViewShell
* pThisViewShell
= mrViewData
.GetViewShell();
363 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
367 if (pViewShell
!= pThisViewShell
&& pViewShell
->GetDocId() == pThisViewShell
->GetDocId())
369 ScTabViewShell
* pOtherViewShell
= dynamic_cast<ScTabViewShell
*>(pViewShell
);
372 ScViewData
& rOtherViewData
= pOtherViewShell
->GetViewData();
373 Fraction aZoomX
= rOtherViewData
.GetZoomX();
374 Fraction aZoomY
= rOtherViewData
.GetZoomY();
375 if (aZoomX
== aScaleX
&& aZoomY
== aScaleY
)
377 SfxLokHelper::notifyOtherView(pThisViewShell
, pOtherViewShell
,
378 LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
, "rectangle", rCursorRect
.toString());
383 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
387 void ScGridWindow::Paint( vcl::RenderContext
& /*rRenderContext*/, const tools::Rectangle
& rRect
)
389 ScDocument
& rDoc
= mrViewData
.GetDocument();
390 if ( rDoc
.IsInInterpreter() )
392 // Via Reschedule, interpreted cells do not trigger Invalidate again,
393 // otherwise for instance an error box would never appear (bug 36381).
394 // Later, through bNeedsRepaint everything is painted again.
398 aRepaintPixel
= tools::Rectangle(); // multiple -> paint all
402 bNeedsRepaint
= true;
403 aRepaintPixel
= LogicToPixel(rRect
); // only affected ranges
408 // #i117893# If GetSizePixel needs to call the resize handler, the resulting nested Paint call
409 // (possibly for a larger rectangle) has to be allowed. Call GetSizePixel before setting bIsInPaint.
417 tools::Rectangle aPixRect
= LogicToPixel( rRect
);
419 SCCOL nX1
= mrViewData
.GetPosX(eHWhich
);
420 SCROW nY1
= mrViewData
.GetPosY(eVWhich
);
422 SCTAB nTab
= mrViewData
.GetTabNo();
424 double nPPTX
= mrViewData
.GetPPTX();
425 double nPPTY
= mrViewData
.GetPPTY();
427 tools::Rectangle aMirroredPixel
= aPixRect
;
428 if ( rDoc
.IsLayoutRTL( nTab
) )
431 tools::Long nWidth
= GetSizePixel().Width();
432 aMirroredPixel
.SetLeft( nWidth
- 1 - aPixRect
.Right() );
433 aMirroredPixel
.SetRight( nWidth
- 1 - aPixRect
.Left() );
436 tools::Long nScrX
= ScViewData::ToPixel( rDoc
.GetColWidth( nX1
, nTab
), nPPTX
);
437 while ( nScrX
<= aMirroredPixel
.Left() && nX1
< rDoc
.MaxCol() )
440 nScrX
+= ScViewData::ToPixel( rDoc
.GetColWidth( nX1
, nTab
), nPPTX
);
443 while ( nScrX
<= aMirroredPixel
.Right() && nX2
< rDoc
.MaxCol() )
446 nScrX
+= ScViewData::ToPixel( rDoc
.GetColWidth( nX2
, nTab
), nPPTX
);
449 tools::Long nScrY
= 0;
450 ScViewData::AddPixelsWhile( nScrY
, aPixRect
.Top(), nY1
, rDoc
.MaxRow(), nPPTY
, &rDoc
, nTab
);
452 if (nScrY
<= aPixRect
.Bottom() && nY2
< rDoc
.MaxRow())
455 ScViewData::AddPixelsWhile( nScrY
, aPixRect
.Bottom(), nY2
, rDoc
.MaxRow(), nPPTY
, &rDoc
, nTab
);
458 Draw( nX1
,nY1
,nX2
,nY2
, ScUpdateMode::Marks
); // don't continue with painting
463 void ScGridWindow::Draw( SCCOL nX1
, SCROW nY1
, SCCOL nX2
, SCROW nY2
, ScUpdateMode eMode
)
465 ScDocument
& rDoc
= mrViewData
.GetDocument();
467 // let's ignore the normal Draw() attempts when doing the tiled rendering,
468 // all the rendering should go through PaintTile() in that case.
469 // TODO revisit if we can actually turn this into an assert(), and clean
471 if (comphelper::LibreOfficeKit::isActive())
474 ScModule
* pScMod
= SC_MOD();
475 bool bTextWysiwyg
= pScMod
->GetInputOptions().GetTextWysiwyg();
477 if (mrViewData
.IsMinimized())
480 PutInOrder( nX1
, nX2
);
481 PutInOrder( nY1
, nY2
);
483 OSL_ENSURE( rDoc
.ValidCol(nX2
) && rDoc
.ValidRow(nY2
), "GridWin Draw area too big" );
485 UpdateVisibleRange();
487 if (nX2
< maVisibleRange
.mnCol1
|| nY2
< maVisibleRange
.mnRow1
)
490 if (nX1
< maVisibleRange
.mnCol1
)
491 nX1
= maVisibleRange
.mnCol1
;
492 if (nY1
< maVisibleRange
.mnRow1
)
493 nY1
= maVisibleRange
.mnRow1
;
495 if (nX1
> maVisibleRange
.mnCol2
|| nY1
> maVisibleRange
.mnRow2
)
498 if (nX2
> maVisibleRange
.mnCol2
)
499 nX2
= maVisibleRange
.mnCol2
;
500 if (nY2
> maVisibleRange
.mnRow2
)
501 nY2
= maVisibleRange
.mnRow2
;
503 if ( eMode
!= ScUpdateMode::Marks
&& nX2
< maVisibleRange
.mnCol2
)
504 nX2
= maVisibleRange
.mnCol2
; // to continue painting
506 // point of no return
508 ++nPaintCount
; // mark that painting is in progress
510 SCTAB nTab
= mrViewData
.GetTabNo();
511 rDoc
.ExtendHidden( nX1
, nY1
, nX2
, nY2
, nTab
);
513 Point aScrPos
= mrViewData
.GetScrPos( nX1
, nY1
, eWhich
);
514 tools::Long nMirrorWidth
= GetSizePixel().Width();
515 bool bLayoutRTL
= rDoc
.IsLayoutRTL( nTab
);
518 tools::Long nEndPixel
= mrViewData
.GetScrPos( nX2
+1, maVisibleRange
.mnRow1
, eWhich
).X();
519 nMirrorWidth
= aScrPos
.X() - nEndPixel
;
520 aScrPos
.setX( nEndPixel
+ 1 );
523 tools::Long nScrX
= aScrPos
.X();
524 tools::Long nScrY
= aScrPos
.Y();
526 SCCOL nCurX
= mrViewData
.GetCurX();
527 SCROW nCurY
= mrViewData
.GetCurY();
528 SCCOL nCurEndX
= nCurX
;
529 SCROW nCurEndY
= nCurY
;
530 rDoc
.ExtendMerge( nCurX
, nCurY
, nCurEndX
, nCurEndY
, nTab
);
531 bool bCurVis
= nCursorHideCount
==0 &&
532 ( nCurEndX
+1 >= nX1
&& nCurX
<= nX2
+1 && nCurEndY
+1 >= nY1
&& nCurY
<= nY2
+1 );
535 if ( !bCurVis
&& nCursorHideCount
==0 && bAutoMarkVisible
&& aAutoMarkPos
.Tab() == nTab
&&
536 ( aAutoMarkPos
.Col() != nCurX
|| aAutoMarkPos
.Row() != nCurY
) )
538 SCCOL nHdlX
= aAutoMarkPos
.Col();
539 SCROW nHdlY
= aAutoMarkPos
.Row();
540 rDoc
.ExtendMerge( nHdlX
, nHdlY
, nHdlX
, nHdlY
, nTab
);
541 // left and top is unaffected
543 //! Paint AutoFill handles alone (without Cursor) ???
546 double nPPTX
= mrViewData
.GetPPTX();
547 double nPPTY
= mrViewData
.GetPPTY();
549 const ScViewOptions
& rOpts
= mrViewData
.GetOptions();
553 ScTableInfo aTabInfo
;
554 rDoc
.FillInfo( aTabInfo
, nX1
, nY1
, nX2
, nY2
, nTab
,
555 nPPTX
, nPPTY
, false, rOpts
.GetOption(VOPT_FORMULAS
),
556 &mrViewData
.GetMarkData() );
558 Fraction aZoomX
= mrViewData
.GetZoomX();
559 Fraction aZoomY
= mrViewData
.GetZoomY();
560 ScOutputData
aOutputData( GetOutDev(), OUTTYPE_WINDOW
, aTabInfo
, &rDoc
, nTab
,
561 nScrX
, nScrY
, nX1
, nY1
, nX2
, nY2
, nPPTX
, nPPTY
,
564 aOutputData
.SetMirrorWidth( nMirrorWidth
); // needed for RTL
565 aOutputData
.SetSpellCheckContext(mpSpellCheckCxt
.get());
567 ScopedVclPtr
< VirtualDevice
> xFmtVirtDev
;
568 bool bLogicText
= bTextWysiwyg
; // call DrawStrings in logic MapMode?
572 // use printer for text formatting
574 OutputDevice
* pFmtDev
= rDoc
.GetPrinter();
575 pFmtDev
->SetMapMode( mrViewData
.GetLogicMode(eWhich
) );
576 aOutputData
.SetFmtDevice( pFmtDev
);
578 else if ( aZoomX
!= aZoomY
&& mrViewData
.IsOle() )
580 // #i45033# For OLE inplace editing with different zoom factors,
581 // use a virtual device with 1/100th mm as text formatting reference
583 xFmtVirtDev
.disposeAndReset( VclPtr
<VirtualDevice
>::Create() );
584 xFmtVirtDev
->SetMapMode(MapMode(MapUnit::Map100thMM
));
585 aOutputData
.SetFmtDevice( xFmtVirtDev
.get() );
587 bLogicText
= true; // use logic MapMode
590 DrawContent(*GetOutDev(), aTabInfo
, aOutputData
, bLogicText
);
592 // If something was inverted during the Paint (selection changed from Basic Macro)
593 // then this is now mixed up and has to be repainted
594 OSL_ENSURE(nPaintCount
, "Wrong nPaintCount");
599 // Flag drawn formula cells "unchanged".
600 rDoc
.ResetChanged(ScRange(nX1
, nY1
, nTab
, nX2
, nY2
, nTab
));
601 rDoc
.PrepareFormulaCalc();
606 class SuppressEditViewMessagesGuard
609 SuppressEditViewMessagesGuard(EditView
& rEditView
) :
610 mrEditView(rEditView
),
611 mbOrigSuppressFlag(rEditView
.IsSuppressLOKMessages())
613 if (!mbOrigSuppressFlag
)
614 mrEditView
.SuppressLOKMessages(true);
617 ~SuppressEditViewMessagesGuard()
619 if (mrEditView
.IsSuppressLOKMessages() != mbOrigSuppressFlag
)
620 mrEditView
.SuppressLOKMessages(mbOrigSuppressFlag
);
624 EditView
& mrEditView
;
625 const bool mbOrigSuppressFlag
;
631 * Used to store the necessary information about the (combined-)tile
632 * area relevant to coordinate transformations in RTL mode.
634 class ScLokRTLContext
637 ScLokRTLContext(const ScOutputData
& rOutputData
, const tools::Long nTileDeviceOriginPixelX
):
638 mrOutputData(rOutputData
),
639 mnTileDevOriginX(nTileDeviceOriginPixelX
)
643 * Converts from document x pixel position to the
644 * corresponding pixel position w.r.t the tile device origin.
646 tools::Long
docToTilePos(tools::Long nPosX
) const
648 tools::Long nMirrorX
= (-2 * mnTileDevOriginX
) + mrOutputData
.GetScrW();
649 return nMirrorX
- 1 - nPosX
;
654 const ScOutputData
& mrOutputData
;
655 const tools::Long mnTileDevOriginX
;
660 int lcl_GetMultiLineHeight(EditEngine
* pEditEngine
)
663 int nParagraphs
= pEditEngine
->GetParagraphCount();
664 if (nParagraphs
> 1 || (nParagraphs
> 0 && pEditEngine
->GetLineCount(0) > 1))
666 for (int nPara
= 0; nPara
< nParagraphs
; nPara
++)
668 nHeight
+= pEditEngine
->GetLineCount(nPara
) * pEditEngine
->GetLineHeight(nPara
);
675 tools::Rectangle
lcl_negateRectX(const tools::Rectangle
& rRect
)
677 return tools::Rectangle(-rRect
.Right(), rRect
.Top(), -rRect
.Left(), rRect
.Bottom());
681 void ScGridWindow::DrawContent(OutputDevice
&rDevice
, const ScTableInfo
& rTableInfo
, ScOutputData
& aOutputData
,
684 ScModule
* pScMod
= SC_MOD();
685 ScDocument
& rDoc
= mrViewData
.GetDocument();
686 const ScViewOptions
& rOpts
= mrViewData
.GetOptions();
687 bool bIsTiledRendering
= comphelper::LibreOfficeKit::isActive();
688 bool bNoBackgroundAndGrid
= bIsTiledRendering
689 && comphelper::LibreOfficeKit::isCompatFlagSet(
690 comphelper::LibreOfficeKit::Compat::scNoGridBackground
);
692 SCTAB nTab
= aOutputData
.nTab
;
693 SCCOL nX1
= aOutputData
.nX1
;
694 SCROW nY1
= aOutputData
.nY1
;
695 SCCOL nX2
= aOutputData
.nX2
;
696 SCROW nY2
= aOutputData
.nY2
;
697 tools::Long nScrX
= aOutputData
.nScrX
;
698 tools::Long nScrY
= aOutputData
.nScrY
;
700 const svtools::ColorConfig
& rColorCfg
= pScMod
->GetColorConfig();
701 Color
aGridColor( rColorCfg
.GetColorValue( svtools::CALCGRID
).nColor
);
702 if ( aGridColor
== COL_TRANSPARENT
)
704 // use view options' grid color only if color config has "automatic" color
705 aGridColor
= rOpts
.GetGridColor();
708 aOutputData
.SetSyntaxMode ( mrViewData
.IsSyntaxMode() );
709 aOutputData
.SetGridColor ( aGridColor
);
710 aOutputData
.SetShowNullValues ( rOpts
.GetOption( VOPT_NULLVALS
) );
711 aOutputData
.SetShowFormulas ( rOpts
.GetOption( VOPT_FORMULAS
) );
712 aOutputData
.SetShowSpellErrors ( rDoc
.GetDocOptions().IsAutoSpell() );
713 aOutputData
.SetMarkClipped ( rOpts
.GetOption( VOPT_CLIPMARKS
) );
715 aOutputData
.SetUseStyleColor( true ); // always set in table view
717 aOutputData
.SetViewShell( mrViewData
.GetViewShell() );
719 bool bGrid
= rOpts
.GetOption( VOPT_GRID
) && mrViewData
.GetShowGrid();
720 bool bGridFirst
= !rOpts
.GetOption( VOPT_GRID_ONTOP
);
722 bool bPage
= rOpts
.GetOption( VOPT_PAGEBREAKS
) && !bIsTiledRendering
;
724 bool bPageMode
= mrViewData
.IsPagebreakMode();
725 if (bPageMode
) // after FindChanged
727 // SetPagebreakMode also initializes bPrinted Flags
728 aOutputData
.SetPagebreakMode( mrViewData
.GetView()->GetPageBreakData() );
731 EditView
* pEditView
= nullptr;
732 bool bEditMode
= mrViewData
.HasEditView(eWhich
);
733 if ( bEditMode
&& mrViewData
.GetRefTabNo() == nTab
)
737 mrViewData
.GetEditView( eWhich
, pEditView
, nEditCol
, nEditRow
);
738 SCCOL nEditEndCol
= mrViewData
.GetEditEndCol();
739 SCROW nEditEndRow
= mrViewData
.GetEditEndRow();
741 if ( nEditEndCol
>= nX1
&& nEditCol
<= nX2
&& nEditEndRow
>= nY1
&& nEditRow
<= nY2
)
742 aOutputData
.SetEditCell( nEditCol
, nEditRow
);
747 const MapMode aOriginalMode
= rDevice
.GetMapMode();
749 // define drawing layer map mode and paint rectangle
750 MapMode aDrawMode
= GetDrawMapMode();
751 if (bIsTiledRendering
)
753 // FIXME this shouldn't be necessary once we change the entire Calc to
754 // work in the logic coordinates (ideally 100ths of mm - so that it is
755 // the same as editeng and drawinglayer), and get rid of all the
756 // SetMapMode's and other unnecessary fun we have with pixels
757 // See also ScGridWindow::GetDrawMapMode() for the rest of this hack
758 aDrawMode
.SetOrigin(PixelToLogic(Point(nScrX
, nScrY
), aDrawMode
));
760 tools::Rectangle aDrawingRectLogic
;
761 bool bLayoutRTL
= rDoc
.IsLayoutRTL( nTab
);
762 bool bLokRTL
= bLayoutRTL
&& bIsTiledRendering
;
763 std::unique_ptr
<ScLokRTLContext
> pLokRTLCtxt(
765 new ScLokRTLContext(aOutputData
, o3tl::convert(aOriginalMode
.GetOrigin().X(), o3tl::Length::twip
, o3tl::Length::px
)) :
769 // get drawing pixel rect
770 tools::Rectangle
aDrawingRectPixel(
771 bLokRTL
? Point(-(nScrX
+ aOutputData
.GetScrW()), nScrY
) : Point(nScrX
, nScrY
),
772 Size(aOutputData
.GetScrW(), aOutputData
.GetScrH()));
774 // correct for border (left/right)
775 if(rDoc
.MaxCol() == nX2
&& !bLokRTL
)
779 aDrawingRectPixel
.SetLeft( 0 );
783 aDrawingRectPixel
.SetRight( GetOutputSizePixel().getWidth() );
787 // correct for border (bottom)
788 if(rDoc
.MaxRow() == nY2
)
790 aDrawingRectPixel
.SetBottom( GetOutputSizePixel().getHeight() );
793 // get logic positions
794 aDrawingRectLogic
= PixelToLogic(aDrawingRectPixel
, aDrawMode
);
797 bool bInPlaceEditing
= bEditMode
&& (mrViewData
.GetRefTabNo() == mrViewData
.GetTabNo());
798 vcl::Cursor
* pInPlaceCrsr
= nullptr;
799 bool bInPlaceVisCursor
= false;
802 // toggle the cursor off if it's on to ensure the cursor invert
803 // background logic remains valid after the background is cleared on
804 // the next cursor flash
805 pInPlaceCrsr
= pEditView
->GetCursor();
806 bInPlaceVisCursor
= pInPlaceCrsr
&& pInPlaceCrsr
->IsVisible();
807 if (bInPlaceVisCursor
)
808 pInPlaceCrsr
->Hide();
811 OutputDevice
* pContentDev
= &rDevice
; // device for document content, used by overlay manager
812 SdrPaintWindow
* pTargetPaintWindow
= nullptr; // #i74769# work with SdrPaintWindow directly
816 ScTabViewShell
* pTabViewShell
= mrViewData
.GetViewShell();
820 MapMode
aCurrentMapMode(pContentDev
->GetMapMode());
821 pContentDev
->SetMapMode(aDrawMode
);
822 SdrView
* pDrawView
= pTabViewShell
->GetScDrawView();
826 // #i74769# Use new BeginDrawLayers() interface
827 vcl::Region
aDrawingRegion(aDrawingRectLogic
);
828 pTargetPaintWindow
= pDrawView
->BeginDrawLayers(pContentDev
, aDrawingRegion
);
829 OSL_ENSURE(pTargetPaintWindow
, "BeginDrawLayers: Got no SdrPaintWindow (!)");
831 if (!bIsTiledRendering
)
833 // #i74769# get target device from SdrPaintWindow, this may be the prerender
835 pContentDev
= &(pTargetPaintWindow
->GetTargetOutputDevice());
836 aOutputData
.SetContentDevice(pContentDev
);
840 pContentDev
->SetMapMode(aCurrentMapMode
);
844 // app-background / document edge (area) (Pixel)
845 if ( !bIsTiledRendering
&& ( nX2
== rDoc
.MaxCol() || nY2
== rDoc
.MaxRow() ) )
847 // save MapMode and set to pixel
848 MapMode
aCurrentMapMode(pContentDev
->GetMapMode());
849 pContentDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
851 tools::Rectangle
aPixRect( Point(), GetOutputSizePixel() );
852 pContentDev
->SetFillColor( rColorCfg
.GetColorValue(svtools::APPBACKGROUND
).nColor
);
853 pContentDev
->SetLineColor();
854 if ( nX2
==rDoc
.MaxCol() )
856 tools::Rectangle
aDrawRect( aPixRect
);
858 aDrawRect
.SetRight( nScrX
- 1 );
860 aDrawRect
.SetLeft( nScrX
+ aOutputData
.GetScrW() );
861 if (aDrawRect
.Right() >= aDrawRect
.Left())
862 pContentDev
->DrawRect( aDrawRect
);
864 if ( nY2
==rDoc
.MaxRow() )
866 tools::Rectangle
aDrawRect( aPixRect
);
867 aDrawRect
.SetTop( nScrY
+ aOutputData
.GetScrH() );
868 if ( nX2
==rDoc
.MaxCol() )
870 // no double painting of the corner
872 aDrawRect
.SetLeft( nScrX
);
874 aDrawRect
.SetRight( nScrX
+ aOutputData
.GetScrW() - 1 );
876 if (aDrawRect
.Bottom() >= aDrawRect
.Top())
877 pContentDev
->DrawRect( aDrawRect
);
881 pContentDev
->SetMapMode(aCurrentMapMode
);
884 if ( rDoc
.HasBackgroundDraw( nTab
, aDrawingRectLogic
) )
886 pContentDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
887 aOutputData
.DrawClear();
889 // drawing background
891 pContentDev
->SetMapMode(aDrawMode
);
892 DrawRedraw( aOutputData
, SC_LAYER_BACK
);
895 aOutputData
.SetSolidBackground(!bNoBackgroundAndGrid
);
897 aOutputData
.DrawDocumentBackground();
899 if (bGridFirst
&& (bGrid
|| bPage
))
901 // Draw lines in background color cover over lok client grid lines in merged cell areas if bNoBackgroundAndGrid is set.
902 if (bNoBackgroundAndGrid
)
903 aOutputData
.DrawGrid(*pContentDev
, false /* bGrid */, false /* bPage */, true /* bMergeCover */);
905 aOutputData
.DrawGrid(*pContentDev
, bGrid
, bPage
);
908 aOutputData
.DrawBackground(*pContentDev
);
910 if (!bGridFirst
&& (bGrid
|| bPage
) && !bNoBackgroundAndGrid
)
911 aOutputData
.DrawGrid(*pContentDev
, bGrid
, bPage
);
913 pContentDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
915 //tdf#128258 - draw a dotted line before hidden columns/rows
916 DrawHiddenIndicator(nX1
,nY1
,nX2
,nY2
, *pContentDev
);
920 // DrawPagePreview draws complete lines/page numbers, must always be clipped
921 if ( aOutputData
.SetChangedClip() )
923 DrawPagePreview(nX1
,nY1
,nX2
,nY2
, *pContentDev
);
924 pContentDev
->SetClipRegion();
928 aOutputData
.DrawShadow();
929 aOutputData
.DrawFrame(*pContentDev
);
931 aOutputData
.DrawSparklines(*pContentDev
);
934 if ( rOpts
.GetOption( VOPT_NOTES
) )
935 aOutputData
.DrawNoteMarks(*pContentDev
);
938 aOutputData
.DrawStrings(); // in pixel MapMode
940 // edit cells and printer-metrics text must be before the buttons
941 // (DataPilot buttons contain labels in UI font)
943 pContentDev
->SetMapMode(mrViewData
.GetLogicMode(eWhich
));
945 aOutputData
.DrawStrings(true); // in logic MapMode if bLogicText is set
946 aOutputData
.DrawEdit(true);
948 // the buttons are painted in absolute coordinates
949 if (bIsTiledRendering
)
951 // Tiled offset nScrX, nScrY
952 MapMode
aMap( MapUnit::MapPixel
);
953 Point aOrigin
= aOriginalMode
.GetOrigin();
954 aOrigin
.setX(o3tl::convert(aOrigin
.getX(), o3tl::Length::twip
, o3tl::Length::px
) + nScrX
);
955 aOrigin
.setY(o3tl::convert(aOrigin
.getY(), o3tl::Length::twip
, o3tl::Length::px
) + nScrY
);
956 aMap
.SetOrigin(aOrigin
);
957 pContentDev
->SetMapMode(aMap
);
960 pContentDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
962 // Autofilter- and Pivot-Buttons
963 DrawButtons(nX1
, nX2
, rTableInfo
, pContentDev
, pLokRTLCtxt
.get()); // Pixel
965 pContentDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
967 aOutputData
.DrawClipMarks();
969 // In any case, Scenario / ChangeTracking must happen after DrawGrid, also for !bGridFirst
971 //! test if ChangeTrack display is active
972 //! Disable scenario frame via view option?
974 SCTAB nTabCount
= rDoc
.GetTableCount();
975 const std::vector
<ScHighlightEntry
> &rHigh
= mrViewData
.GetView()->GetHighlightRanges();
976 bool bHasScenario
= ( nTab
+1<nTabCount
&& rDoc
.IsScenario(nTab
+1) && !rDoc
.IsScenario(nTab
) );
977 bool bHasChange
= ( rDoc
.GetChangeTrack() != nullptr );
979 if ( bHasChange
|| bHasScenario
|| !rHigh
.empty() )
981 //! Merge SetChangedClip() with DrawMarks() ?? (different MapMode!)
984 aOutputData
.DrawChangeTrack();
987 lcl_DrawScenarioFrames( pContentDev
, mrViewData
, eWhich
, nX1
,nY1
,nX2
,nY2
);
989 lcl_DrawHighlight( aOutputData
, mrViewData
, rHigh
);
992 // Drawing foreground
994 pContentDev
->SetMapMode(aDrawMode
);
996 // Bitmaps and buttons are in absolute pixel coordinates.
997 const MapMode aOrig
= pContentDev
->GetMapMode();
998 if (bIsTiledRendering
)
1000 Point aOrigin
= aOriginalMode
.GetOrigin();
1001 tools::Long nXOffset
= bLayoutRTL
?
1002 (-o3tl::convert(aOrigin
.getX(), o3tl::Length::twip
, o3tl::Length::px
) + aOutputData
.GetScrW()) :
1003 o3tl::convert(aOrigin
.getX(), o3tl::Length::twip
, o3tl::Length::px
);
1004 Size
aPixelOffset(nXOffset
, o3tl::convert(aOrigin
.getY(), o3tl::Length::twip
, o3tl::Length::px
));
1005 pContentDev
->SetPixelOffset(aPixelOffset
);
1006 comphelper::LibreOfficeKit::setLocalRendering();
1009 DrawRedraw( aOutputData
, SC_LAYER_FRONT
);
1010 DrawRedraw( aOutputData
, SC_LAYER_INTERN
);
1011 DrawSdrGrid( aDrawingRectLogic
, pContentDev
);
1013 if (bIsTiledRendering
)
1015 pContentDev
->SetPixelOffset(Size());
1016 pContentDev
->SetMapMode(aOrig
);
1019 pContentDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
1021 if ( mrViewData
.IsRefMode() && nTab
>= mrViewData
.GetRefStartZ() && nTab
<= mrViewData
.GetRefEndZ() )
1023 Color
aRefColor( rColorCfg
.GetColorValue(svtools::CALCREFERENCE
).nColor
);
1024 aOutputData
.DrawRefMark( mrViewData
.GetRefStartX(), mrViewData
.GetRefStartY(),
1025 mrViewData
.GetRefEndX(), mrViewData
.GetRefEndY(),
1031 ScInputHandler
* pHdl
= pScMod
->GetInputHdl( mrViewData
.GetViewShell() );
1034 ScDocShell
* pDocSh
= mrViewData
.GetDocShell();
1035 ScRangeFindList
* pRangeFinder
= pHdl
->GetRangeFindList();
1036 if ( pRangeFinder
&& !pRangeFinder
->IsHidden() &&
1037 pRangeFinder
->GetDocName() == pDocSh
->GetTitle() )
1039 sal_uInt16 nCount
= static_cast<sal_uInt16
>(pRangeFinder
->Count());
1040 for (sal_uInt16 i
=0; i
<nCount
; i
++)
1042 ScRangeFindData
& rData
= pRangeFinder
->GetObject(i
);
1044 ScRange aRef
= rData
.aRef
;
1046 if ( aRef
.aStart
.Tab() >= nTab
&& aRef
.aEnd
.Tab() <= nTab
)
1047 aOutputData
.DrawRefMark( aRef
.aStart
.Col(), aRef
.aStart
.Row(),
1048 aRef
.aEnd
.Col(), aRef
.aEnd
.Row(),
1057 ScTabViewShell
* pTabViewShell
= mrViewData
.GetViewShell();
1061 MapMode
aCurrentMapMode(pContentDev
->GetMapMode());
1062 pContentDev
->SetMapMode(aDrawMode
);
1064 if (bIsTiledRendering
)
1066 Point aOrigin
= aOriginalMode
.GetOrigin();
1068 aOrigin
.setX(-o3tl::convert(aOrigin
.getX(), o3tl::Length::twip
, o3tl::Length::px
)
1069 + aOutputData
.nScrX
+ aOutputData
.GetScrW());
1071 aOrigin
.setX(o3tl::convert(aOrigin
.getX(), o3tl::Length::twip
, o3tl::Length::px
)
1072 + aOutputData
.nScrX
);
1074 aOrigin
.setY(o3tl::convert(aOrigin
.getY(), o3tl::Length::twip
, o3tl::Length::px
)
1075 + aOutputData
.nScrY
);
1076 const double twipFactor
= 15 * 1.76388889; // 26.45833335
1077 aOrigin
= Point(aOrigin
.getX() * twipFactor
,
1078 aOrigin
.getY() * twipFactor
);
1079 MapMode aNew
= rDevice
.GetMapMode();
1080 aNew
.SetOrigin(aOrigin
);
1081 rDevice
.SetMapMode(aNew
);
1084 SdrView
* pDrawView
= pTabViewShell
->GetScDrawView();
1088 // #i74769# work with SdrPaintWindow directly
1089 pDrawView
->EndDrawLayers(*pTargetPaintWindow
, true);
1092 pContentDev
->SetMapMode(aCurrentMapMode
);
1096 // paint in-place editing
1097 if (bIsTiledRendering
)
1099 ScTabViewShell
* pThisViewShell
= mrViewData
.GetViewShell();
1100 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
1104 bool bEnterLoop
= bIsTiledRendering
|| pViewShell
!= pThisViewShell
;
1105 if (bEnterLoop
&& pViewShell
->GetDocId() == pThisViewShell
->GetDocId())
1107 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(pViewShell
);
1110 ScViewData
& rOtherViewData
= pTabViewShell
->GetViewData();
1111 ScSplitPos eOtherWhich
= rOtherViewData
.GetEditActivePart();
1113 bool bOtherEditMode
= rOtherViewData
.HasEditView(eOtherWhich
);
1114 SCCOL nCol1
= rOtherViewData
.GetEditStartCol();
1115 SCROW nRow1
= rOtherViewData
.GetEditStartRow();
1116 SCCOL nCol2
= rOtherViewData
.GetEditEndCol();
1117 SCROW nRow2
= rOtherViewData
.GetEditEndRow();
1118 bOtherEditMode
= bOtherEditMode
1119 && ( nCol2
>= nX1
&& nCol1
<= nX2
&& nRow2
>= nY1
&& nRow1
<= nY2
);
1120 if (bOtherEditMode
&& rOtherViewData
.GetRefTabNo() == nTab
)
1122 EditView
* pOtherEditView
= rOtherViewData
.GetEditView(eOtherWhich
);
1125 tools::Long nScreenX
= aOutputData
.nScrX
;
1126 tools::Long nScreenY
= aOutputData
.nScrY
;
1128 rDevice
.SetLineColor();
1129 SfxViewShell
* pSfxViewShell
= SfxViewShell::Current();
1130 ScTabViewShell
* pCurrentViewShell
= dynamic_cast<ScTabViewShell
*>(pSfxViewShell
);
1131 if (pCurrentViewShell
)
1133 const ScViewData
& pViewData
= pCurrentViewShell
->GetViewData();
1134 const ScViewOptions
& aViewOptions
= pViewData
.GetOptions();
1135 const ScPatternAttr
* pPattern
= rDoc
.GetPattern( nCol1
, nRow1
, nTab
);
1136 Color aCellColor
= pPattern
->GetItem(ATTR_BACKGROUND
).GetColor();
1137 if (aCellColor
.IsTransparent())
1139 aCellColor
= aViewOptions
.GetDocColor();
1141 rDevice
.SetFillColor(aCellColor
);
1142 pOtherEditView
->SetBackgroundColor(aCellColor
);
1144 Point aStart
= mrViewData
.GetScrPos( nCol1
, nRow1
, eOtherWhich
);
1145 Point aEnd
= mrViewData
.GetScrPos( nCol2
+1, nRow2
+1, eOtherWhich
);
1147 if (bIsTiledRendering
)
1149 EditEngine
* pEditEngine
= pOtherEditView
->GetEditEngine();
1151 aEnd
.AdjustY(lcl_GetMultiLineHeight(pEditEngine
));
1156 // Transform the cell range X coordinates such that the edit cell area is
1157 // horizontally mirrored w.r.t the (combined-)tile.
1158 aStart
.setX(pLokRTLCtxt
->docToTilePos(aStart
.X()));
1159 aEnd
.setX(pLokRTLCtxt
->docToTilePos(aEnd
.X()));
1162 // don't overwrite grid
1163 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
1164 aEnd
.AdjustX( -(2 * nLayoutSign
) );
1167 tools::Rectangle
aBackground(aStart
, aEnd
);
1169 aBackground
.Normalize();
1171 // Need to draw the background in absolute coords.
1172 Point aOrigin
= aOriginalMode
.GetOrigin();
1174 o3tl::convert(aOrigin
.getX(), o3tl::Length::twip
, o3tl::Length::px
)
1177 o3tl::convert(aOrigin
.getY(), o3tl::Length::twip
, o3tl::Length::px
)
1179 aBackground
+= aOrigin
;
1180 rDevice
.SetMapMode(aDrawMode
);
1182 static const double twipFactor
= 15 * 1.76388889; // 26.45833335
1183 // keep into account the zoom factor
1184 aOrigin
= Point((aOrigin
.getX() * twipFactor
) / static_cast<double>(aDrawMode
.GetScaleX()),
1185 (aOrigin
.getY() * twipFactor
) / static_cast<double>(aDrawMode
.GetScaleY()));
1187 MapMode aNew
= rDevice
.GetMapMode();
1188 aNew
.SetOrigin(aOrigin
);
1189 rDevice
.SetMapMode(aNew
);
1191 // paint the background
1192 rDevice
.DrawRect(rDevice
.PixelToLogic(aBackground
));
1193 tools::Rectangle
aBGAbs(aBackground
);
1195 tools::Rectangle
aEditRect(aBackground
);
1196 tools::Long nOffsetX
= 0, nOffsetY
= 0;
1197 // Get top-left offset because of margin and indent.
1198 lcl_GetEditAreaTLOffset(nOffsetX
, nOffsetY
, ScAddress(nCol1
, nRow1
, nTab
), mrViewData
, rDoc
);
1199 aEditRect
.AdjustLeft(nOffsetX
+ 1);
1200 aEditRect
.AdjustRight(1);
1201 aEditRect
.AdjustTop(nOffsetY
+ 1);
1202 aEditRect
.AdjustBottom(1);
1204 // EditView has an 'output area' which is used to clip the 'paint area' we provide below.
1205 // So they need to be in the same coordinates/units. This is tied to the mapmode of the gridwin
1206 // attached to the EditView, so we have to change its mapmode too (temporarily). We save the
1207 // original mapmode and 'output area' and roll them back when we finish painting to rDevice.
1208 OutputDevice
& rOtherWin
= pOtherEditView
->GetOutputDevice();
1209 const tools::Rectangle
aOrigOutputArea(pOtherEditView
->GetOutputArea()); // Not in pixels.
1210 const MapMode aOrigMapMode
= rOtherWin
.GetMapMode();
1211 rOtherWin
.SetMapMode(rDevice
.GetMapMode());
1213 // Avoid sending wrong cursor/selection messages by the 'other' view, as the output-area is going
1214 // to be tweaked temporarily to match the current view's zoom.
1215 SuppressEditViewMessagesGuard
aGuard(*pOtherEditView
);
1216 comphelper::ScopeGuard
aOutputGuard(
1217 [pOtherEditView
, aOrigOutputArea
, bLokRTL
] {
1218 if (bLokRTL
&& aOrigOutputArea
!= pOtherEditView
->GetOutputArea())
1219 pOtherEditView
->SetOutputArea(aOrigOutputArea
);
1222 aEditRect
= rDevice
.PixelToLogic(aEditRect
);
1223 if (bIsTiledRendering
)
1224 pOtherEditView
->SetOutputArea(aEditRect
);
1226 aEditRect
.Intersection(pOtherEditView
->GetOutputArea());
1227 pOtherEditView
->Paint(aEditRect
, &rDevice
);
1229 // EditView will do the cursor notifications correctly if we're in
1230 // print-twips messaging mode.
1231 if (bIsTiledRendering
&& !comphelper::LibreOfficeKit::isCompatFlagSet(
1232 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
))
1234 // Now we need to get relative cursor position within the editview.
1235 // This is for sending the pixel-aligned twips position of the cursor to the specific views with
1236 // the same given zoom level.
1237 tools::Rectangle aCursorRect
= pOtherEditView
->GetEditCursor();
1238 Point aCursPos
= OutputDevice::LogicToLogic(aCursorRect
.TopLeft(),
1239 MapMode(MapUnit::Map100thMM
), MapMode(MapUnit::MapTwip
));
1241 const MapMode
& rDevMM
= rDevice
.GetMapMode();
1242 MapMode
aMM(MapUnit::MapTwip
);
1243 aMM
.SetScaleX(rDevMM
.GetScaleX());
1244 aMM
.SetScaleY(rDevMM
.GetScaleY());
1246 aBGAbs
.AdjustLeft(1);
1247 aBGAbs
.AdjustTop(1);
1248 aCursorRect
= GetOutDev()->PixelToLogic(aBGAbs
, aMM
);
1249 aCursorRect
.setWidth(0);
1250 aCursorRect
.Move(aCursPos
.getX(), 0);
1251 // Sends view cursor position to views of all matching zooms if needed (avoids duplicates).
1252 InvalidateLOKViewCursor(aCursorRect
, aMM
.GetScaleX(), aMM
.GetScaleY());
1255 // Rollback the mapmode and 'output area'.
1256 rOtherWin
.SetMapMode(aOrigMapMode
);
1257 if (!bIsTiledRendering
)
1258 pOtherEditView
->SetOutputArea(aOrigOutputArea
);
1259 rDevice
.SetMapMode(MapMode(MapUnit::MapPixel
));
1265 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
1270 // In-place editing - when the user is typing, we need to paint the text
1271 // using the editeng.
1272 // It's being done after EndDrawLayers() to get it outside the overlay
1273 // buffer and on top of everything.
1274 if (bInPlaceEditing
)
1276 // get the coordinates of the area we need to clear (overpaint by
1278 SCCOL nCol1
= mrViewData
.GetEditStartCol();
1279 SCROW nRow1
= mrViewData
.GetEditStartRow();
1280 SCCOL nCol2
= mrViewData
.GetEditEndCol();
1281 SCROW nRow2
= mrViewData
.GetEditEndRow();
1282 rDevice
.SetLineColor();
1283 rDevice
.SetFillColor(pEditView
->GetBackgroundColor());
1284 Point aStart
= mrViewData
.GetScrPos( nCol1
, nRow1
, eWhich
);
1285 Point aEnd
= mrViewData
.GetScrPos( nCol2
+1, nRow2
+1, eWhich
);
1289 // Transform the cell range X coordinates such that the edit cell area is
1290 // horizontally mirrored w.r.t the (combined-)tile.
1291 aStart
.setX(pLokRTLCtxt
->docToTilePos(aStart
.X()));
1292 aEnd
.setX(pLokRTLCtxt
->docToTilePos(aEnd
.X()));
1295 // don't overwrite grid
1296 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
1297 aEnd
.AdjustX( -(2 * nLayoutSign
) );
1300 // set the correct mapmode
1301 tools::Rectangle
aBackground(aStart
, aEnd
);
1303 aBackground
.Normalize();
1304 tools::Rectangle
aBGAbs(aBackground
);
1306 if (bIsTiledRendering
)
1308 // Need to draw the background in absolute coords.
1309 Point aOrigin
= aOriginalMode
.GetOrigin();
1310 aOrigin
.setX(o3tl::convert(aOrigin
.getX(), o3tl::Length::twip
, o3tl::Length::px
)
1312 aOrigin
.setY(o3tl::convert(aOrigin
.getY(), o3tl::Length::twip
, o3tl::Length::px
)
1314 aBackground
+= aOrigin
;
1315 rDevice
.SetMapMode(aDrawMode
);
1318 rDevice
.SetMapMode(mrViewData
.GetLogicMode());
1320 if (bIsTiledRendering
)
1322 Point aOrigin
= aOriginalMode
.GetOrigin();
1323 aOrigin
.setX(o3tl::convert(aOrigin
.getX(), o3tl::Length::twip
, o3tl::Length::px
)
1325 aOrigin
.setY(o3tl::convert(aOrigin
.getY(), o3tl::Length::twip
, o3tl::Length::px
)
1327 static const double twipFactor
= 15 * 1.76388889; // 26.45833335
1328 // keep into account the zoom factor
1329 aOrigin
= Point((aOrigin
.getX() * twipFactor
) / static_cast<double>(aDrawMode
.GetScaleX()),
1330 (aOrigin
.getY() * twipFactor
) / static_cast<double>(aDrawMode
.GetScaleY()));
1331 MapMode aNew
= rDevice
.GetMapMode();
1332 aNew
.SetOrigin(aOrigin
);
1333 rDevice
.SetMapMode(aNew
);
1336 // paint the editeng text
1337 if (bIsTiledRendering
)
1339 // EditView has an 'output area' which is used to clip the paint area we provide below.
1340 // So they need to be in the same coordinates/units. This is tied to the mapmode of the gridwin
1341 // attached to the EditView, so we have to change its mapmode too (temporarily). We save the
1342 // original mapmode and 'output area' and roll them back when we finish painting to rDevice.
1343 const MapMode aOrigMapMode
= GetMapMode();
1344 SetMapMode(rDevice
.GetMapMode());
1346 // Avoid sending wrong cursor/selection messages by the current view, as the output-area is going
1347 // to be tweaked temporarily to match other view's zoom. (This does not affect the manual
1348 // cursor-messaging done in the non print-twips mode)
1349 SuppressEditViewMessagesGuard
aGuard(*pEditView
);
1351 // EditView will do the cursor notifications correctly if we're in
1352 // print-twips messaging mode.
1353 if (!comphelper::LibreOfficeKit::isCompatFlagSet(
1354 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
))
1356 // Now we need to get relative cursor position within the editview.
1357 // This is for sending the pixel-aligned twips position of the cursor to the specific views with
1358 // the same given zoom level.
1359 tools::Rectangle aCursorRect
= pEditView
->GetEditCursor();
1360 Point aCursPos
= o3tl::toTwips(aCursorRect
.TopLeft(), o3tl::Length::mm100
);
1362 const MapMode
& rDevMM
= rDevice
.GetMapMode();
1363 MapMode
aMM(MapUnit::MapTwip
);
1364 aMM
.SetScaleX(rDevMM
.GetScaleX());
1365 aMM
.SetScaleY(rDevMM
.GetScaleY());
1367 aBGAbs
.AdjustLeft(1);
1368 aBGAbs
.AdjustTop(1);
1369 aCursorRect
= GetOutDev()->PixelToLogic(aBGAbs
, aMM
);
1370 aCursorRect
.setWidth(0);
1371 aCursorRect
.Move(aCursPos
.getX(), 0);
1372 // Sends view cursor position to views of all matching zooms if needed (avoids duplicates).
1373 InvalidateLOKViewCursor(aCursorRect
, aMM
.GetScaleX(), aMM
.GetScaleY());
1376 // Rollback the mapmode and 'output area'.
1377 SetMapMode(aOrigMapMode
);
1381 // paint the background
1382 tools::Rectangle
aLogicRect(rDevice
.PixelToLogic(aBackground
));
1383 //tdf#100925, rhbz#1283420, Draw some text here, to get
1384 //X11CairoTextRender::getCairoContext called, so that the forced read
1385 //from the underlying X Drawable gets it to sync.
1386 rDevice
.DrawText(aLogicRect
.BottomLeft(), " ");
1387 rDevice
.DrawRect(aLogicRect
);
1389 tools::Rectangle
aEditRect(Point(nScrX
, nScrY
), Size(aOutputData
.GetScrW(), aOutputData
.GetScrH()));
1390 pEditView
->Paint(rDevice
.PixelToLogic(aEditRect
), &rDevice
);
1393 rDevice
.SetMapMode(MapMode(MapUnit::MapPixel
));
1395 // restore the cursor it was originally visible
1396 if (bInPlaceVisCursor
)
1397 pInPlaceCrsr
->Show();
1400 if (mrViewData
.HasEditView(eWhich
))
1402 // flush OverlayManager before changing the MapMode
1403 flushOverlayManager();
1405 // set MapMode for text edit
1406 rDevice
.SetMapMode(mrViewData
.GetLogicMode());
1409 rDevice
.SetMapMode(aDrawMode
);
1412 mpNoteMarker
->Draw(); // Above the cursor, in drawing map mode
1414 if (bPage
&& bInitialPageBreaks
)
1415 SetupInitialPageBreaks(rDoc
, nTab
);
1419 void ScGridWindow::SetupInitialPageBreaks(const ScDocument
& rDoc
, SCTAB nTab
)
1421 // tdf#124983, if option LibreOfficeDev Calc/View/Visual Aids/Page breaks
1422 // is enabled, breaks should be visible. If the document is opened the first
1423 // time, the breaks are not calculated yet, so for this initialization
1424 // a timer will be triggered here.
1425 std::set
<SCCOL
> aColBreaks
;
1426 std::set
<SCROW
> aRowBreaks
;
1427 rDoc
.GetAllColBreaks(aColBreaks
, nTab
, true, false);
1428 rDoc
.GetAllRowBreaks(aRowBreaks
, nTab
, true, false);
1429 if (aColBreaks
.size() == 0 || aRowBreaks
.size() == 0)
1431 maShowPageBreaksTimer
.SetPriority(TaskPriority::DEFAULT_IDLE
);
1432 maShowPageBreaksTimer
.Start();
1434 bInitialPageBreaks
= false;
1439 template<typename IndexType
>
1440 void lcl_getBoundingRowColumnforTile(ScViewData
& rViewData
,
1441 tools::Long nTileStartPosPx
, tools::Long nTileEndPosPx
,
1442 sal_Int32
& nTopLeftTileOffset
, sal_Int32
& nTopLeftTileOrigin
,
1443 sal_Int32
& nTopLeftTileIndex
, sal_Int32
& nBottomRightTileIndex
)
1445 const bool bColumnHeader
= std::is_same
<IndexType
, SCCOL
>::value
;
1447 SCTAB nTab
= rViewData
.GetTabNo();
1449 IndexType nStartIndex
= -1;
1450 IndexType nEndIndex
= -1;
1451 tools::Long nStartPosPx
= 0;
1452 tools::Long nEndPosPx
= 0;
1454 ScPositionHelper
& rPositionHelper
=
1455 bColumnHeader
? rViewData
.GetLOKWidthHelper() : rViewData
.GetLOKHeightHelper();
1456 const auto& rStartNearest
= rPositionHelper
.getNearestByPosition(nTileStartPosPx
);
1457 const auto& rEndNearest
= rPositionHelper
.getNearestByPosition(nTileEndPosPx
);
1459 ScBoundsProvider
aBoundsProvider(rViewData
, nTab
, bColumnHeader
);
1460 aBoundsProvider
.Compute(rStartNearest
, rEndNearest
, nTileStartPosPx
, nTileEndPosPx
);
1461 aBoundsProvider
.GetStartIndexAndPosition(nStartIndex
, nStartPosPx
); ++nStartIndex
;
1462 aBoundsProvider
.GetEndIndexAndPosition(nEndIndex
, nEndPosPx
);
1464 nTopLeftTileOffset
= nTileStartPosPx
- nStartPosPx
;
1465 nTopLeftTileOrigin
= nStartPosPx
;
1466 nTopLeftTileIndex
= nStartIndex
;
1467 nBottomRightTileIndex
= nEndIndex
;
1470 void lcl_RTLAdjustTileColOffset(ScViewData
& rViewData
, sal_Int32
& nTileColOffset
,
1471 tools::Long nTileEndPx
, sal_Int32 nEndCol
, SCTAB nTab
,
1472 const ScDocument
& rDoc
, double fPPTX
)
1474 auto GetColWidthPx
= [&rDoc
, nTab
, fPPTX
](SCCOL nCol
) {
1475 const sal_uInt16 nSize
= rDoc
.GetColWidth(nCol
, nTab
);
1476 const tools::Long nSizePx
= ScViewData::ToPixel(nSize
, fPPTX
);
1480 ScPositionHelper rHelper
= rViewData
.GetLOKWidthHelper();
1481 tools::Long nEndColPos
= rHelper
.computePosition(nEndCol
, GetColWidthPx
);
1483 nTileColOffset
+= (nEndColPos
- nTileEndPx
- nTileColOffset
);
1486 class ScLOKProxyObjectContact final
: public sdr::contact::ObjectContactOfPageView
1489 ScDrawView
* mpScDrawView
;
1492 explicit ScLOKProxyObjectContact(
1493 ScDrawView
* pDrawView
,
1494 SdrPageWindow
& rPageWindow
,
1495 const char* pDebugName
) :
1496 ObjectContactOfPageView(rPageWindow
, pDebugName
),
1497 mpScDrawView(pDrawView
)
1501 virtual bool supportsGridOffsets() const override
{ return true; }
1503 virtual void calculateGridOffsetForViewOjectContact(
1504 basegfx::B2DVector
& rTarget
,
1505 const sdr::contact::ViewObjectContact
& rClient
) const override
1510 SdrPageView
* pPageView(mpScDrawView
->GetSdrPageView());
1514 SdrPageWindow
* pSdrPageWindow
= nullptr;
1515 if (pPageView
->PageWindowCount() > 0)
1516 pSdrPageWindow
= pPageView
->GetPageWindow(0);
1517 if (!pSdrPageWindow
)
1520 sdr::contact::ObjectContact
& rObjContact(pSdrPageWindow
->GetObjectContact());
1522 SdrObject
* pTargetSdrObject(rClient
.GetViewContact().TryToGetSdrObject());
1523 if (pTargetSdrObject
)
1524 rTarget
= pTargetSdrObject
->GetViewContact().GetViewObjectContact(rObjContact
).getGridOffset();
1528 class ScLOKDrawView
: public FmFormView
1531 ScLOKDrawView(OutputDevice
* pOut
, ScViewData
& rData
) :
1532 FmFormView(*rData
.GetDocument().GetDrawLayer(), pOut
),
1533 mpScDrawView(rData
.GetScDrawView())
1537 virtual sdr::contact::ObjectContact
* createViewSpecificObjectContact(
1538 SdrPageWindow
& rPageWindow
, const char* pDebugName
) const override
1541 return SdrView::createViewSpecificObjectContact(rPageWindow
, pDebugName
);
1543 return new ScLOKProxyObjectContact(mpScDrawView
, rPageWindow
, pDebugName
);
1547 ScDrawView
* mpScDrawView
;
1549 } // anonymous namespace
1551 void ScGridWindow::PaintTile( VirtualDevice
& rDevice
,
1552 int nOutputWidth
, int nOutputHeight
,
1553 int nTilePosX
, int nTilePosY
,
1554 tools::Long nTileWidth
, tools::Long nTileHeight
,
1555 SCCOL nTiledRenderingAreaEndCol
, SCROW nTiledRenderingAreaEndRow
)
1557 Fraction origZoomX
= mrViewData
.GetZoomX();
1558 Fraction origZoomY
= mrViewData
.GetZoomY();
1560 // Output size is in pixels while tile position and size are in logical units (twips).
1562 // Assumption: always paint the whole sheet i.e. "visible" range is always
1563 // from (0,0) to last data position.
1565 // Tile geometry is independent of the zoom level, but the output size is
1566 // dependent of the zoom level. Determine the correct zoom level before
1569 // FIXME the painting works using a mixture of drawing with coordinates in
1570 // pixels and in logic coordinates; it should be cleaned up to use logic
1571 // coords only, and avoid all the SetMapMode()'s.
1572 // Similarly to Writer, we should set the mapmode once on the rDevice, and
1573 // not care about any zoom settings.
1575 Fraction
aFracX(o3tl::convert(nOutputWidth
, o3tl::Length::px
, o3tl::Length::twip
), nTileWidth
);
1576 Fraction
aFracY(o3tl::convert(nOutputHeight
, o3tl::Length::px
, o3tl::Length::twip
), nTileHeight
);
1578 const bool bChangeZoom
= (aFracX
!= origZoomX
|| aFracY
!= origZoomY
);
1580 // page break zoom, and aLogicMode in ScViewData
1581 // FIXME: there are issues when SetZoom is called conditionally.
1582 mrViewData
.SetZoom(aFracX
, aFracY
, true);
1585 if (ScDrawView
* pDrawView
= mrViewData
.GetScDrawView())
1586 pDrawView
->resetGridOffsetsForAllSdrPageViews();
1589 const double fTilePosXPixel
= static_cast<double>(nTilePosX
) * nOutputWidth
/ nTileWidth
;
1590 const double fTilePosYPixel
= static_cast<double>(nTilePosY
) * nOutputHeight
/ nTileHeight
;
1591 const double fTileBottomPixel
= static_cast<double>(nTilePosY
+ nTileHeight
) * nOutputHeight
/ nTileHeight
;
1592 const double fTileRightPixel
= static_cast<double>(nTilePosX
+ nTileWidth
) * nOutputWidth
/ nTileWidth
;
1594 SCTAB nTab
= mrViewData
.GetTabNo();
1595 ScDocument
& rDoc
= mrViewData
.GetDocument();
1597 const double fPPTX
= mrViewData
.GetPPTX();
1598 const double fPPTY
= mrViewData
.GetPPTY();
1600 // find approximate col/row offsets of nearby.
1601 sal_Int32 nTopLeftTileRowOffset
= 0;
1602 sal_Int32 nTopLeftTileColOffset
= 0;
1603 sal_Int32 nTopLeftTileRowOrigin
= 0;
1604 sal_Int32 nTopLeftTileColOrigin
= 0;
1606 sal_Int32 nTopLeftTileRow
= 0;
1607 sal_Int32 nTopLeftTileCol
= 0;
1608 sal_Int32 nBottomRightTileRow
= 0;
1609 sal_Int32 nBottomRightTileCol
= 0;
1611 lcl_getBoundingRowColumnforTile
<SCROW
>(mrViewData
,
1612 fTilePosYPixel
, fTileBottomPixel
,
1613 nTopLeftTileRowOffset
, nTopLeftTileRowOrigin
,
1614 nTopLeftTileRow
, nBottomRightTileRow
);
1616 lcl_getBoundingRowColumnforTile
<SCCOL
>(mrViewData
,
1617 fTilePosXPixel
, fTileRightPixel
,
1618 nTopLeftTileColOffset
, nTopLeftTileColOrigin
,
1619 nTopLeftTileCol
, nBottomRightTileCol
);
1622 nBottomRightTileCol
++;
1623 nBottomRightTileRow
++;
1625 if (nBottomRightTileCol
> rDoc
.MaxCol())
1626 nBottomRightTileCol
= rDoc
.MaxCol();
1628 if (nBottomRightTileRow
> MAXTILEDROW
)
1629 nBottomRightTileRow
= MAXTILEDROW
;
1631 bool bLayoutRTL
= rDoc
.IsLayoutRTL( nTab
);
1635 lcl_RTLAdjustTileColOffset(mrViewData
, nTopLeftTileColOffset
,
1636 fTileRightPixel
, nBottomRightTileCol
, nTab
,
1640 // size of the document including drawings, charts, etc.
1641 SCCOL nEndCol
= nTiledRenderingAreaEndCol
;
1642 SCROW nEndRow
= nTiledRenderingAreaEndRow
;
1644 if (nEndCol
< nBottomRightTileCol
)
1645 nEndCol
= nBottomRightTileCol
;
1647 if (nEndRow
< nBottomRightTileRow
)
1648 nEndRow
= nBottomRightTileRow
;
1650 nTopLeftTileCol
= std::max
<sal_Int32
>(nTopLeftTileCol
, 0);
1651 nTopLeftTileRow
= std::max
<sal_Int32
>(nTopLeftTileRow
, 0);
1652 nTopLeftTileColOrigin
= o3tl::convert(nTopLeftTileColOrigin
, o3tl::Length::px
, o3tl::Length::twip
);
1653 nTopLeftTileRowOrigin
= o3tl::convert(nTopLeftTileRowOrigin
, o3tl::Length::px
, o3tl::Length::twip
);
1655 // Checkout -> 'rDoc.ExtendMerge' ... if we miss merged cells.
1657 // Origin must be the offset of the first col and row
1658 // containing our top-left pixel.
1659 const MapMode aOriginalMode
= rDevice
.GetMapMode();
1660 MapMode aAbsMode
= aOriginalMode
;
1661 const Point
aOrigin(-nTopLeftTileColOrigin
, -nTopLeftTileRowOrigin
);
1662 aAbsMode
.SetOrigin(aOrigin
);
1663 rDevice
.SetMapMode(aAbsMode
);
1665 ScTableInfo
aTabInfo(nEndRow
+ 3);
1666 rDoc
.FillInfo(aTabInfo
, nTopLeftTileCol
, nTopLeftTileRow
,
1667 nBottomRightTileCol
, nBottomRightTileRow
,
1668 nTab
, fPPTX
, fPPTY
, false, false);
1670 // FIXME: is this called some
1671 // Point aScrPos = mrViewData.GetScrPos( nX1, nY1, eWhich );
1673 ScOutputData
aOutputData(&rDevice
, OUTTYPE_WINDOW
, aTabInfo
, &rDoc
, nTab
,
1674 -nTopLeftTileColOffset
,
1675 -nTopLeftTileRowOffset
,
1676 nTopLeftTileCol
, nTopLeftTileRow
,
1677 nBottomRightTileCol
, nBottomRightTileRow
,
1678 fPPTX
, fPPTY
, nullptr, nullptr);
1680 // setup the SdrPage so that drawinglayer works correctly
1681 ScDrawLayer
* pModel
= rDoc
.GetDrawLayer();
1684 bool bPrintTwipsMsgs
= comphelper::LibreOfficeKit::isCompatFlagSet(
1685 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
1688 mpLOKDrawView
.reset(bPrintTwipsMsgs
?
1697 mpLOKDrawView
->SetNegativeX(bLayoutRTL
);
1698 mpLOKDrawView
->ShowSdrPage(mpLOKDrawView
->GetModel()->GetPage(nTab
));
1699 aOutputData
.SetDrawView(mpLOKDrawView
.get());
1700 aOutputData
.SetSpellCheckContext(mpSpellCheckCxt
.get());
1704 DrawContent(rDevice
, aTabInfo
, aOutputData
, true);
1705 rDevice
.SetMapMode(aOriginalMode
);
1707 // Paint the chart(s) in edit mode.
1708 LokChartHelper::PaintAllChartsOnTile(rDevice
, nOutputWidth
, nOutputHeight
,
1709 nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
, bLayoutRTL
);
1711 rDevice
.SetMapMode(aOriginalMode
);
1713 // Flag drawn formula cells "unchanged".
1714 rDoc
.ResetChanged(ScRange(nTopLeftTileCol
, nTopLeftTileRow
, nTab
, nBottomRightTileCol
, nBottomRightTileRow
, nTab
));
1715 rDoc
.PrepareFormulaCalc();
1717 mrViewData
.SetZoom(origZoomX
, origZoomY
, true);
1720 if (ScDrawView
* pDrawView
= mrViewData
.GetScDrawView())
1721 pDrawView
->resetGridOffsetsForAllSdrPageViews();
1726 Bitmap aCellBMP
= rDevice
.GetBitmap(Point(0, 0), Size(nOutputWidth
, nOutputHeight
));
1727 aCellBMP
.Mirror(BmpMirrorFlags::Horizontal
);
1728 rDevice
.DrawBitmap(Point(0, 0), Size(nOutputWidth
, nOutputHeight
), aCellBMP
);
1732 void ScGridWindow::LogicInvalidatePart(const tools::Rectangle
* pRectangle
, int nPart
)
1734 tools::Rectangle aRectangle
;
1735 tools::Rectangle
* pResultRectangle
;
1737 pResultRectangle
= nullptr;
1740 aRectangle
= *pRectangle
;
1741 // When dragging shapes the map mode is disabled.
1742 if (IsMapModeEnabled())
1744 if (GetMapMode().GetMapUnit() == MapUnit::Map100thMM
)
1746 aRectangle
= o3tl::convert(aRectangle
, o3tl::Length::mm100
, o3tl::Length::twip
);
1750 aRectangle
= PixelToLogic(aRectangle
, MapMode(MapUnit::MapTwip
));
1751 pResultRectangle
= &aRectangle
;
1754 // Trim invalidation rectangle overlapping negative X region in RTL mode.
1755 if (pResultRectangle
&& pResultRectangle
->Left() < 0
1756 && mrViewData
.GetDocument().IsLayoutRTL(mrViewData
.GetTabNo()))
1758 pResultRectangle
->SetLeft(0);
1759 if (pResultRectangle
->Right() < 0)
1760 pResultRectangle
->SetRight(0);
1763 ScTabViewShell
* pViewShell
= mrViewData
.GetViewShell();
1764 SfxLokHelper::notifyInvalidation(pViewShell
, nPart
, pResultRectangle
);
1767 void ScGridWindow::LogicInvalidate(const tools::Rectangle
* pRectangle
)
1769 ScTabViewShell
* pViewShell
= mrViewData
.GetViewShell();
1770 LogicInvalidatePart(pRectangle
, pViewShell
->getPart());
1773 bool ScGridWindow::InvalidateByForeignEditView(EditView
* pEditView
)
1778 auto* pGridWin
= dynamic_cast<ScGridWindow
*>(pEditView
->GetWindow());
1782 const ScViewData
& rViewData
= pGridWin
->getViewData();
1783 tools::Long nRefTabNo
= rViewData
.GetRefTabNo();
1784 tools::Long nX
= rViewData
.GetCurXForTab(nRefTabNo
);
1785 tools::Long nY
= rViewData
.GetCurYForTab(nRefTabNo
);
1787 tools::Rectangle aPixRect
= getViewData().GetEditArea(eWhich
, nX
, nY
, this, nullptr, true);
1788 tools::Rectangle aLogicRect
= PixelToLogic(aPixRect
, getViewData().GetLogicMode());
1789 Invalidate(pEditView
->IsNegativeX() ? lcl_negateRectX(aLogicRect
) : aLogicRect
);
1794 void ScGridWindow::SetCellSelectionPixel(int nType
, int nPixelX
, int nPixelY
)
1796 ScTabView
* pTabView
= mrViewData
.GetView();
1797 ScTabViewShell
* pViewShell
= mrViewData
.GetViewShell();
1798 ScInputHandler
* pInputHandler
= SC_MOD()->GetInputHdl(pViewShell
);
1800 if (pInputHandler
&& pInputHandler
->IsInputMode())
1802 // we need to switch off the editeng
1803 ScTabView::UpdateInputLine();
1804 pViewShell
->UpdateInputHandler();
1807 if (nType
== LOK_SETTEXTSELECTION_RESET
)
1809 pTabView
->DoneBlockMode();
1813 // obtain the current selection
1814 ScRangeList aRangeList
= mrViewData
.GetMarkData().GetMarkedRanges();
1820 bool bWasEmpty
= false;
1821 if (aRangeList
.empty())
1823 nCol1
= nCol2
= mrViewData
.GetCurX();
1824 nRow1
= nRow2
= mrViewData
.GetCurY();
1828 aRangeList
.Combine().GetVars(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
1830 // convert the coordinates to column/row
1833 SCTAB nTab
= mrViewData
.GetTabNo();
1834 mrViewData
.GetPosFromPixel(nPixelX
, nPixelY
, eWhich
, nNewPosX
, nNewPosY
);
1836 // change the selection
1839 case LOK_SETTEXTSELECTION_START
:
1840 if (nNewPosX
!= nCol1
|| nNewPosY
!= nRow1
|| bWasEmpty
)
1842 pTabView
->SetCursor(nNewPosX
, nNewPosY
);
1843 pTabView
->DoneBlockMode();
1844 pTabView
->InitBlockMode(nNewPosX
, nNewPosY
, nTab
, true);
1845 pTabView
->MarkCursor(nCol2
, nRow2
, nTab
);
1848 case LOK_SETTEXTSELECTION_END
:
1849 if (nNewPosX
!= nCol2
|| nNewPosY
!= nRow2
|| bWasEmpty
)
1851 pTabView
->SetCursor(nCol1
, nRow1
);
1852 pTabView
->DoneBlockMode();
1853 pTabView
->InitBlockMode(nCol1
, nRow1
, nTab
, true);
1854 pTabView
->MarkCursor(nNewPosX
, nNewPosY
, nTab
);
1863 void ScGridWindow::CheckNeedsRepaint()
1865 // called at the end of painting, and from timer after background text width calculation
1870 bNeedsRepaint
= false;
1871 if (aRepaintPixel
.IsEmpty())
1874 Invalidate(PixelToLogic(aRepaintPixel
));
1875 aRepaintPixel
= tools::Rectangle();
1877 // selection function in status bar might also be invalid
1878 SfxBindings
& rBindings
= mrViewData
.GetBindings();
1879 rBindings
.Invalidate( SID_STATUS_SUM
);
1880 rBindings
.Invalidate( SID_ATTR_SIZE
);
1881 rBindings
.Invalidate( SID_TABLE_CELL
);
1884 void ScGridWindow::DrawHiddenIndicator( SCCOL nX1
, SCROW nY1
, SCCOL nX2
, SCROW nY2
, vcl::RenderContext
& rRenderContext
)
1886 ScDocument
& rDoc
= mrViewData
.GetDocument();
1887 SCTAB nTab
= mrViewData
.GetTabNo();
1888 const svtools::ColorConfig
& rColorCfg
= SC_MOD()->GetColorConfig();
1889 const svtools::ColorConfigValue aColorValue
= rColorCfg
.GetColorValue(svtools::CALCHIDDENROWCOL
);
1890 if (aColorValue
.bIsVisible
) {
1891 rRenderContext
.SetLineColor(aColorValue
.nColor
);
1892 LineInfo
aLineInfo(LineStyle::Dash
, 2);
1893 aLineInfo
.SetDashCount(0);
1894 aLineInfo
.SetDotCount(1);
1895 aLineInfo
.SetDistance(15);
1896 // round caps except when running VCL_PLUGIN=gen due to a performance issue
1897 // https://bugs.documentfoundation.org/show_bug.cgi?id=128258#c14
1898 if (mrViewData
.GetActiveWin()->GetSystemData()->toolkit
!= SystemEnvData::Toolkit::Gen
)
1899 aLineInfo
.SetLineCap(css::drawing::LineCap_ROUND
);
1900 aLineInfo
.SetDotLen(1);
1901 for (int i
=nX1
; i
<nX2
; i
++) {
1902 if (rDoc
.ColHidden(i
,nTab
) && (i
<rDoc
.MaxCol() ? !rDoc
.ColHidden(i
+1,nTab
) : true)) {
1903 Point aStart
= mrViewData
.GetScrPos(i
, nY1
, eWhich
, true );
1904 Point aEnd
= mrViewData
.GetScrPos(i
, nY2
, eWhich
, true );
1905 rRenderContext
.DrawLine(aStart
,aEnd
,aLineInfo
);
1908 for (int i
=nY1
; i
<nY2
; i
++) {
1909 if (rDoc
.RowHidden(i
,nTab
) && (i
<rDoc
.MaxRow() ? !rDoc
.RowHidden(i
+1,nTab
) : true)) {
1910 Point aStart
= mrViewData
.GetScrPos(nX1
, i
, eWhich
, true );
1911 Point aEnd
= mrViewData
.GetScrPos(nX2
, i
, eWhich
, true );
1912 rRenderContext
.DrawLine(aStart
,aEnd
,aLineInfo
);
1918 void ScGridWindow::DrawPagePreview( SCCOL nX1
, SCROW nY1
, SCCOL nX2
, SCROW nY2
, vcl::RenderContext
& rRenderContext
)
1920 ScPageBreakData
* pPageData
= mrViewData
.GetView()->GetPageBreakData();
1924 ScDocument
& rDoc
= mrViewData
.GetDocument();
1925 SCTAB nTab
= mrViewData
.GetTabNo();
1926 Size aWinSize
= GetOutputSizePixel();
1927 const svtools::ColorConfig
& rColorCfg
= SC_MOD()->GetColorConfig();
1928 Color
aManual( rColorCfg
.GetColorValue(svtools::CALCPAGEBREAKMANUAL
).nColor
);
1929 Color
aAutomatic( rColorCfg
.GetColorValue(svtools::CALCPAGEBREAK
).nColor
);
1931 OUString aPageStr
= ScResId( STR_PGNUM
);
1932 if ( nPageScript
== SvtScriptType::NONE
)
1934 // get script type of translated "Page" string only once
1935 nPageScript
= rDoc
.GetStringScriptType( aPageStr
);
1936 if (nPageScript
== SvtScriptType::NONE
)
1937 nPageScript
= ScGlobal::GetDefaultScriptType();
1941 std::unique_ptr
<ScEditEngineDefaulter
> pEditEng
;
1942 const ScPatternAttr
& rDefPattern
= rDoc
.GetPool()->GetDefaultItem(ATTR_PATTERN
);
1943 if ( nPageScript
== SvtScriptType::LATIN
)
1945 // use single font and call DrawText directly
1946 rDefPattern
.fillFontOnly(aFont
);
1947 aFont
.SetColor(COL_LIGHTGRAY
);
1948 // font size is set as needed
1952 // use EditEngine to draw mixed-script string
1953 pEditEng
.reset(new ScEditEngineDefaulter( EditEngine::CreatePool().get(), true ));
1954 pEditEng
->SetRefMapMode(rRenderContext
.GetMapMode());
1955 auto pEditDefaults
= std::make_unique
<SfxItemSet
>( pEditEng
->GetEmptyItemSet() );
1956 rDefPattern
.FillEditItemSet( pEditDefaults
.get() );
1957 pEditDefaults
->Put( SvxColorItem( COL_LIGHTGRAY
, EE_CHAR_COLOR
) );
1958 pEditEng
->SetDefaults( std::move(pEditDefaults
) );
1961 sal_uInt16 nCount
= sal::static_int_cast
<sal_uInt16
>( pPageData
->GetCount() );
1962 for (sal_uInt16 nPos
=0; nPos
<nCount
; nPos
++)
1964 ScPrintRangeData
& rData
= pPageData
->GetData(nPos
);
1965 ScRange aRange
= rData
.GetPrintRange();
1966 if ( aRange
.aStart
.Col() <= nX2
+1 && aRange
.aEnd
.Col()+1 >= nX1
&&
1967 aRange
.aStart
.Row() <= nY2
+1 && aRange
.aEnd
.Row()+1 >= nY1
)
1969 // 3 pixel frame around the print area
1970 // (middle pixel on the grid lines)
1972 rRenderContext
.SetLineColor();
1973 if (rData
.IsAutomatic())
1974 rRenderContext
.SetFillColor( aAutomatic
);
1976 rRenderContext
.SetFillColor( aManual
);
1978 Point aStart
= mrViewData
.GetScrPos(
1979 aRange
.aStart
.Col(), aRange
.aStart
.Row(), eWhich
, true );
1980 Point aEnd
= mrViewData
.GetScrPos(
1981 aRange
.aEnd
.Col() + 1, aRange
.aEnd
.Row() + 1, eWhich
, true );
1982 aStart
.AdjustX( -2 );
1983 aStart
.AdjustY( -2 );
1985 // Prevent overflows:
1986 if ( aStart
.X() < -10 ) aStart
.setX( -10 );
1987 if ( aStart
.Y() < -10 ) aStart
.setY( -10 );
1988 if ( aEnd
.X() > aWinSize
.Width() + 10 )
1989 aEnd
.setX( aWinSize
.Width() + 10 );
1990 if ( aEnd
.Y() > aWinSize
.Height() + 10 )
1991 aEnd
.setY( aWinSize
.Height() + 10 );
1993 rRenderContext
.DrawRect( tools::Rectangle( aStart
, Point(aEnd
.X(),aStart
.Y()+2) ) );
1994 rRenderContext
.DrawRect( tools::Rectangle( aStart
, Point(aStart
.X()+2,aEnd
.Y()) ) );
1995 rRenderContext
.DrawRect( tools::Rectangle( Point(aStart
.X(),aEnd
.Y()-2), aEnd
) );
1996 rRenderContext
.DrawRect( tools::Rectangle( Point(aEnd
.X()-2,aStart
.Y()), aEnd
) );
1999 //! Display differently (dashed ????)
2001 size_t nColBreaks
= rData
.GetPagesX();
2002 const SCCOL
* pColEnd
= rData
.GetPageEndX();
2004 for (nColPos
=0; nColPos
+1<nColBreaks
; nColPos
++)
2006 SCCOL nBreak
= pColEnd
[nColPos
]+1;
2007 if ( nBreak
>= nX1
&& nBreak
<= nX2
+1 )
2009 //! Search for hidden
2010 if (rDoc
.HasColBreak(nBreak
, nTab
) & ScBreakType::Manual
)
2011 rRenderContext
.SetFillColor( aManual
);
2013 rRenderContext
.SetFillColor( aAutomatic
);
2014 Point aBreak
= mrViewData
.GetScrPos(
2015 nBreak
, aRange
.aStart
.Row(), eWhich
, true );
2016 rRenderContext
.DrawRect( tools::Rectangle( aBreak
.X()-1, aStart
.Y(), aBreak
.X(), aEnd
.Y() ) );
2020 size_t nRowBreaks
= rData
.GetPagesY();
2021 const SCROW
* pRowEnd
= rData
.GetPageEndY();
2023 for (nRowPos
=0; nRowPos
+1<nRowBreaks
; nRowPos
++)
2025 SCROW nBreak
= pRowEnd
[nRowPos
]+1;
2026 if ( nBreak
>= nY1
&& nBreak
<= nY2
+1 )
2028 //! Search for hidden
2029 if (rDoc
.HasRowBreak(nBreak
, nTab
) & ScBreakType::Manual
)
2030 rRenderContext
.SetFillColor( aManual
);
2032 rRenderContext
.SetFillColor( aAutomatic
);
2033 Point aBreak
= mrViewData
.GetScrPos(
2034 aRange
.aStart
.Col(), nBreak
, eWhich
, true );
2035 rRenderContext
.DrawRect( tools::Rectangle( aStart
.X(), aBreak
.Y()-1, aEnd
.X(), aBreak
.Y() ) );
2041 SCROW nPrStartY
= aRange
.aStart
.Row();
2042 for (nRowPos
=0; nRowPos
<nRowBreaks
; nRowPos
++)
2044 SCROW nPrEndY
= pRowEnd
[nRowPos
];
2045 if ( nPrEndY
>= nY1
&& nPrStartY
<= nY2
)
2047 SCCOL nPrStartX
= aRange
.aStart
.Col();
2048 for (nColPos
=0; nColPos
<nColBreaks
; nColPos
++)
2050 SCCOL nPrEndX
= pColEnd
[nColPos
];
2051 if ( nPrEndX
>= nX1
&& nPrStartX
<= nX2
)
2053 Point aPageStart
= mrViewData
.GetScrPos(
2054 nPrStartX
, nPrStartY
, eWhich
, true );
2055 Point aPageEnd
= mrViewData
.GetScrPos(
2056 nPrEndX
+1,nPrEndY
+1, eWhich
, true );
2058 tools::Long nPageNo
= rData
.GetFirstPage();
2059 if ( rData
.IsTopDown() )
2060 nPageNo
+= static_cast<tools::Long
>(nColPos
)*nRowBreaks
+nRowPos
;
2062 nPageNo
+= static_cast<tools::Long
>(nRowPos
)*nColBreaks
+nColPos
;
2064 OUString aThisPageStr
= aPageStr
.replaceFirst("%1", OUString::number(nPageNo
));
2068 // find right font size with EditEngine
2069 tools::Long nHeight
= 100;
2070 pEditEng
->SetDefaultItem( SvxFontHeightItem( nHeight
, 100, EE_CHAR_FONTHEIGHT
) );
2071 pEditEng
->SetDefaultItem( SvxFontHeightItem( nHeight
, 100, EE_CHAR_FONTHEIGHT_CJK
) );
2072 pEditEng
->SetDefaultItem( SvxFontHeightItem( nHeight
, 100, EE_CHAR_FONTHEIGHT_CTL
) );
2073 pEditEng
->SetTextCurrentDefaults( aThisPageStr
);
2074 Size
aSize100( pEditEng
->CalcTextWidth(), pEditEng
->GetTextHeight() );
2076 // 40% of width or 60% of height
2077 tools::Long nSizeX
= 40 * ( aPageEnd
.X() - aPageStart
.X() ) / aSize100
.Width();
2078 tools::Long nSizeY
= 60 * ( aPageEnd
.Y() - aPageStart
.Y() ) / aSize100
.Height();
2079 nHeight
= std::min(nSizeX
,nSizeY
);
2080 pEditEng
->SetDefaultItem( SvxFontHeightItem( nHeight
, 100, EE_CHAR_FONTHEIGHT
) );
2081 pEditEng
->SetDefaultItem( SvxFontHeightItem( nHeight
, 100, EE_CHAR_FONTHEIGHT_CJK
) );
2082 pEditEng
->SetDefaultItem( SvxFontHeightItem( nHeight
, 100, EE_CHAR_FONTHEIGHT_CTL
) );
2084 // centered output with EditEngine
2085 Size
aTextSize( pEditEng
->CalcTextWidth(), pEditEng
->GetTextHeight() );
2086 Point
aPos( (aPageStart
.X()+aPageEnd
.X()-aTextSize
.Width())/2,
2087 (aPageStart
.Y()+aPageEnd
.Y()-aTextSize
.Height())/2 );
2088 pEditEng
->Draw(rRenderContext
, aPos
);
2092 // find right font size for DrawText
2093 aFont
.SetFontSize( Size( 0,100 ) );
2094 rRenderContext
.SetFont( aFont
);
2096 Size
aSize100(rRenderContext
.GetTextWidth( aThisPageStr
), rRenderContext
.GetTextHeight() );
2097 if (aSize100
.Width() && aSize100
.Height())
2099 // 40% of width or 60% of height
2100 tools::Long nSizeX
= 40 * ( aPageEnd
.X() - aPageStart
.X() ) / aSize100
.Width();
2101 tools::Long nSizeY
= 60 * ( aPageEnd
.Y() - aPageStart
.Y() ) / aSize100
.Height();
2102 aFont
.SetFontSize( Size( 0,std::min(nSizeX
,nSizeY
) ) );
2103 rRenderContext
.SetFont( aFont
);
2106 // centered output with DrawText
2107 Size
aTextSize(rRenderContext
.GetTextWidth( aThisPageStr
), rRenderContext
.GetTextHeight() );
2108 Point
aPos( (aPageStart
.X()+aPageEnd
.X()-aTextSize
.Width())/2,
2109 (aPageStart
.Y()+aPageEnd
.Y()-aTextSize
.Height())/2 );
2110 rRenderContext
.DrawText( aPos
, aThisPageStr
);
2113 nPrStartX
= nPrEndX
+ 1;
2116 nPrStartY
= nPrEndY
+ 1;
2122 void ScGridWindow::DrawButtons(SCCOL nX1
, SCCOL nX2
, const ScTableInfo
& rTabInfo
, OutputDevice
* pContentDev
, const ScLokRTLContext
* pLokRTLContext
)
2124 aComboButton
.SetOutputDevice( pContentDev
);
2126 ScDocument
& rDoc
= mrViewData
.GetDocument();
2127 ScDPFieldButton
aCellBtn(pContentDev
, &GetSettings().GetStyleSettings(), &mrViewData
.GetZoomY(), &rDoc
);
2133 SCTAB nTab
= mrViewData
.GetTabNo();
2134 ScDBData
* pDBData
= nullptr;
2135 std::unique_ptr
<ScQueryParam
> pQueryParam
;
2137 RowInfo
* pRowInfo
= rTabInfo
.mpRowInfo
.get();
2138 sal_uInt16 nArrCount
= rTabInfo
.mnArrCount
;
2140 bool bLayoutRTL
= rDoc
.IsLayoutRTL( nTab
);
2142 Point aOldPos
= aComboButton
.GetPosPixel(); // store state for MouseDown/Up
2143 Size aOldSize
= aComboButton
.GetSizePixel();
2145 for (nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
2147 if ( pRowInfo
[nArrY
].bAutoFilter
&& pRowInfo
[nArrY
].bChanged
)
2149 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
2151 nRow
= pThisRowInfo
->nRowNo
;
2153 for (nCol
=nX1
; nCol
<=nX2
; nCol
++)
2155 ScCellInfo
* pInfo
= &pThisRowInfo
->cellInfo(nCol
);
2156 //if several columns merged on a row, there should be only one auto button at the end of the columns.
2157 //if several rows merged on a column, the button may be in the middle, so "!pInfo->bVOverlapped" should not be used
2158 if ( pInfo
->bAutoFilter
&& !pInfo
->bHOverlapped
)
2161 pQueryParam
.reset(new ScQueryParam
);
2163 bool bNewData
= true;
2171 pDBData
->GetArea( nAreaTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
2172 if ( nCol
>= nStartCol
&& nCol
<= nEndCol
&&
2173 nRow
>= nStartRow
&& nRow
<= nEndRow
)
2178 pDBData
= rDoc
.GetDBAtCursor( nCol
, nRow
, nTab
, ScDBDataPortion::AREA
);
2180 pDBData
->GetQueryParam( *pQueryParam
);
2183 // can also be part of DataPilot table
2187 // pQueryParam can only include MAXQUERY entries
2189 bool bArrowState
= false;
2190 if (pQueryParam
->bInplace
)
2192 SCSIZE nCount
= pQueryParam
->GetEntryCount();
2193 for (nQuery
= 0; nQuery
< nCount
; ++nQuery
)
2195 // Do no restrict to EQUAL here
2196 // (Column head should become blue also when ">1")
2197 const ScQueryEntry
& rEntry
= pQueryParam
->GetEntry(nQuery
);
2198 if (rEntry
.bDoQuery
&& rEntry
.nField
== nCol
)
2208 SCCOL nStartCol
= nCol
;
2209 SCROW nStartRow
= nRow
;
2210 //if address(nCol,nRow) is not the start pos of the merge area, the value of the nSizeX will be incorrect, it will be the length of the cell.
2211 //should first get the start pos of the merge area, then get the nSizeX through the start pos.
2212 rDoc
.ExtendOverlapped(nStartCol
, nStartRow
,nCol
, nRow
, nTab
);//get nStartCol,nStartRow
2213 mrViewData
.GetMergeSizePixel( nStartCol
, nStartRow
, nSizeX
, nSizeY
);//get nSizeX
2214 nSizeY
= ScViewData::ToPixel(rDoc
.GetRowHeight(nRow
, nTab
), mrViewData
.GetPPTY());
2215 Point aScrPos
= mrViewData
.GetScrPos( nCol
, nRow
, eWhich
);
2217 aScrPos
.setX(pLokRTLContext
->docToTilePos(aScrPos
.X()));
2219 aCellBtn
.setBoundingBox(aScrPos
, Size(nSizeX
-1, nSizeY
-1), bLayoutRTL
);
2220 aCellBtn
.setPopupLeft(bLayoutRTL
); // #i114944# AutoFilter button is left-aligned in RTL
2221 aCellBtn
.setDrawBaseButton(false);
2222 aCellBtn
.setDrawPopupButton(true);
2223 aCellBtn
.setHasHiddenMember(bArrowState
);
2229 if ( (pRowInfo
[nArrY
].bPivotToggle
|| pRowInfo
[nArrY
].bPivotButton
) && pRowInfo
[nArrY
].bChanged
)
2231 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
2232 nRow
= pThisRowInfo
->nRowNo
;
2233 for (nCol
=nX1
; nCol
<=nX2
; nCol
++)
2235 ScCellInfo
* pInfo
= &pThisRowInfo
->cellInfo(nCol
);
2236 if (pInfo
->bHOverlapped
|| pInfo
->bVOverlapped
)
2239 Point aScrPos
= mrViewData
.GetScrPos( nCol
, nRow
, eWhich
);
2242 mrViewData
.GetMergeSizePixel( nCol
, nRow
, nSizeX
, nSizeY
);
2243 tools::Long nPosX
= aScrPos
.X();
2244 tools::Long nPosY
= aScrPos
.Y();
2245 // bLayoutRTL is handled in setBoundingBox
2247 bool bDrawToggle
= pInfo
->bPivotCollapseButton
|| pInfo
->bPivotExpandButton
;
2250 OUString aStr
= rDoc
.GetString(nCol
, nRow
, nTab
);
2251 aCellBtn
.setText(aStr
);
2254 sal_uInt16 nIndent
= 0;
2255 if (const ScIndentItem
* pIndentItem
= rDoc
.GetAttr(nCol
, nRow
, nTab
, ATTR_INDENT
))
2256 nIndent
= pIndentItem
->GetValue();
2257 aCellBtn
.setBoundingBox(Point(nPosX
, nPosY
), Size(nSizeX
-1, nSizeY
-1), bLayoutRTL
);
2258 aCellBtn
.setPopupLeft(false); // DataPilot popup is always right-aligned for now
2259 aCellBtn
.setDrawBaseButton(pInfo
->bPivotButton
);
2260 aCellBtn
.setDrawPopupButton(pInfo
->bPivotPopupButton
);
2261 aCellBtn
.setDrawPopupButtonMulti(pInfo
->bPivotPopupButtonMulti
);
2262 aCellBtn
.setDrawToggleButton(bDrawToggle
, pInfo
->bPivotCollapseButton
, nIndent
);
2263 aCellBtn
.setHasHiddenMember(pInfo
->bFilterActive
);
2268 if ( !comphelper::LibreOfficeKit::isActive() && bListValButton
&& pRowInfo
[nArrY
].nRowNo
== aListValPos
.Row() && pRowInfo
[nArrY
].bChanged
)
2270 tools::Rectangle aRect
= GetListValButtonRect( aListValPos
);
2271 aComboButton
.SetPosPixel( aRect
.TopLeft() );
2272 aComboButton
.SetSizePixel( aRect
.GetSize() );
2273 pContentDev
->SetClipRegion(vcl::Region(aRect
));
2274 aComboButton
.Draw();
2275 pContentDev
->SetClipRegion(); // always called from Draw() without clip region
2276 aComboButton
.SetPosPixel( aOldPos
); // restore old state
2277 aComboButton
.SetSizePixel( aOldSize
); // for MouseUp/Down (AutoFilter)
2281 pQueryParam
.reset();
2282 aComboButton
.SetOutputDevice( GetOutDev() );
2285 tools::Rectangle
ScGridWindow::GetListValButtonRect( const ScAddress
& rButtonPos
)
2287 ScDocument
& rDoc
= mrViewData
.GetDocument();
2288 SCTAB nTab
= mrViewData
.GetTabNo();
2289 bool bLayoutRTL
= rDoc
.IsLayoutRTL( nTab
);
2290 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
2292 ScDDComboBoxButton
aButton( GetOutDev() ); // for optimal size
2293 Size aBtnSize
= aButton
.GetSizePixel();
2295 SCCOL nCol
= rButtonPos
.Col();
2296 SCROW nRow
= rButtonPos
.Row();
2298 tools::Long nCellSizeX
; // width of this cell, including merged
2300 mrViewData
.GetMergeSizePixel( nCol
, nRow
, nCellSizeX
, nDummy
);
2302 // for height, only the cell's row is used, excluding merged cells
2303 tools::Long nCellSizeY
= ScViewData::ToPixel( rDoc
.GetRowHeight( nRow
, nTab
), mrViewData
.GetPPTY() );
2304 tools::Long nAvailable
= nCellSizeX
;
2306 // left edge of next cell if there is a non-hidden next column
2307 SCCOL nNextCol
= nCol
+ 1;
2308 const ScMergeAttr
* pMerge
= rDoc
.GetAttr( nCol
,nRow
,nTab
, ATTR_MERGE
);
2309 if ( pMerge
->GetColMerge() > 1 )
2310 nNextCol
= nCol
+ pMerge
->GetColMerge(); // next cell after the merged area
2311 while ( nNextCol
<= rDoc
.MaxCol() && rDoc
.ColHidden(nNextCol
, nTab
) )
2313 bool bNextCell
= ( nNextCol
<= rDoc
.MaxCol() );
2315 nAvailable
= ScViewData::ToPixel( rDoc
.GetColWidth( nNextCol
, nTab
), mrViewData
.GetPPTX() );
2317 if ( nAvailable
< aBtnSize
.Width() )
2318 aBtnSize
.setWidth( nAvailable
);
2319 if ( nCellSizeY
< aBtnSize
.Height() )
2320 aBtnSize
.setHeight( nCellSizeY
);
2322 Point aPos
= mrViewData
.GetScrPos( nCol
, nRow
, eWhich
, true );
2323 aPos
.AdjustX(nCellSizeX
* nLayoutSign
); // start of next cell
2325 aPos
.AdjustX( -(aBtnSize
.Width() * nLayoutSign
) ); // right edge of cell if next cell not available
2326 aPos
.AdjustY(nCellSizeY
- aBtnSize
.Height() );
2327 // X remains at the left edge
2330 aPos
.AdjustX( -(aBtnSize
.Width()-1) ); // align right edge of button with cell border
2332 return tools::Rectangle( aPos
, aBtnSize
);
2335 bool ScGridWindow::IsAutoFilterActive( SCCOL nCol
, SCROW nRow
, SCTAB nTab
)
2337 ScDocument
& rDoc
= mrViewData
.GetDocument();
2338 ScDBData
* pDBData
= rDoc
.GetDBAtCursor( nCol
, nRow
, nTab
, ScDBDataPortion::AREA
);
2339 ScQueryParam aQueryParam
;
2342 pDBData
->GetQueryParam( aQueryParam
);
2345 OSL_FAIL("Auto filter button without DBData");
2348 bool bSimpleQuery
= true;
2349 bool bColumnFound
= false;
2352 if ( !aQueryParam
.bInplace
)
2353 bSimpleQuery
= false;
2355 // aQueryParam can only include MAXQUERY entries
2357 SCSIZE nCount
= aQueryParam
.GetEntryCount();
2358 for (nQuery
= 0; nQuery
< nCount
&& bSimpleQuery
; ++nQuery
)
2359 if ( aQueryParam
.GetEntry(nQuery
).bDoQuery
)
2361 if (aQueryParam
.GetEntry(nQuery
).nField
== nCol
)
2362 bColumnFound
= true;
2365 if (aQueryParam
.GetEntry(nQuery
).eConnect
!= SC_AND
)
2366 bSimpleQuery
= false;
2369 return ( bSimpleQuery
&& bColumnFound
);
2372 void ScGridWindow::GetSelectionRects( ::std::vector
< tools::Rectangle
>& rPixelRects
) const
2374 GetPixelRectsFor( mrViewData
.GetMarkData(), rPixelRects
);
2377 void ScGridWindow::GetSelectionRectsPrintTwips(::std::vector
< tools::Rectangle
>& rRects
) const
2379 GetRectsAnyFor(mrViewData
.GetMarkData(), rRects
, true);
2382 /// convert rMarkData into pixel rectangles for this view
2383 void ScGridWindow::GetPixelRectsFor( const ScMarkData
&rMarkData
,
2384 ::std::vector
< tools::Rectangle
>& rPixelRects
) const
2386 GetRectsAnyFor(rMarkData
, rPixelRects
, false);
2389 void ScGridWindow::GetRectsAnyFor(const ScMarkData
&rMarkData
,
2390 ::std::vector
< tools::Rectangle
>& rRects
,
2391 bool bInPrintTwips
) const
2393 ScDocument
& rDoc
= mrViewData
.GetDocument();
2394 SCTAB nTab
= mrViewData
.GetTabNo();
2395 double nPPTX
= mrViewData
.GetPPTX();
2396 double nPPTY
= mrViewData
.GetPPTY();
2397 bool bLayoutRTL
= rDoc
.IsLayoutRTL( nTab
);
2398 // LOK clients needs exact document coordinates, so don't horizontally mirror them.
2399 tools::Long nLayoutSign
= (!comphelper::LibreOfficeKit::isActive() && bLayoutRTL
) ? -1 : 1;
2401 ScMarkData
aMultiMark( rMarkData
);
2402 aMultiMark
.SetMarking( false );
2404 if (!aMultiMark
.IsMultiMarked())
2406 // simple range case - simplify calculation
2407 const ScRange
& aSimpleRange
= aMultiMark
.GetMarkArea();
2409 aMultiMark
.MarkToMulti();
2410 if ( !aMultiMark
.IsMultiMarked() )
2413 SCCOL nX1
= aSimpleRange
.aStart
.Col();
2414 SCROW nY1
= aSimpleRange
.aStart
.Row();
2415 SCCOL nX2
= aSimpleRange
.aEnd
.Col();
2416 SCROW nY2
= aSimpleRange
.aEnd
.Row();
2418 PutInOrder( nX1
, nX2
);
2419 PutInOrder( nY1
, nY2
);
2421 SCCOL nPosX
= mrViewData
.GetPosX( eHWhich
);
2422 SCROW nPosY
= mrViewData
.GetPosY( eVWhich
);
2423 // is the selection visible at all?
2424 if (nX2
< nPosX
|| nY2
< nPosY
)
2427 Point aScrStartPos
= bInPrintTwips
? mrViewData
.GetPrintTwipsPos(nX1
, nY1
) :
2428 mrViewData
.GetScrPos(nX1
, nY1
, eWhich
);
2430 tools::Long nStartX
= aScrStartPos
.X();
2431 tools::Long nStartY
= aScrStartPos
.Y();
2433 Point aScrEndPos
= bInPrintTwips
? mrViewData
.GetPrintTwipsPos(nX2
, nY2
) :
2434 mrViewData
.GetScrPos(nX2
, nY2
, eWhich
);
2436 tools::Long nWidthTwips
= rDoc
.GetColWidth(nX2
, nTab
);
2437 const tools::Long nWidth
= bInPrintTwips
?
2438 nWidthTwips
: ScViewData::ToPixel(nWidthTwips
, nPPTX
);
2439 tools::Long nEndX
= aScrEndPos
.X() + (nWidth
- 1) * nLayoutSign
;
2441 sal_uInt16 nHeightTwips
= rDoc
.GetRowHeight( nY2
, nTab
);
2442 const tools::Long nHeight
= bInPrintTwips
?
2443 nHeightTwips
: ScViewData::ToPixel(nHeightTwips
, nPPTY
);
2444 tools::Long nEndY
= aScrEndPos
.Y() + nHeight
- 1;
2446 ScInvertMerger
aInvert( &rRects
);
2447 aInvert
.AddRect( tools::Rectangle( nStartX
, nStartY
, nEndX
, nEndY
) );
2452 aMultiMark
.MarkToMulti();
2453 if ( !aMultiMark
.IsMultiMarked() )
2455 const ScRange
& aMultiRange
= aMultiMark
.GetMultiMarkArea();
2456 SCCOL nX1
= aMultiRange
.aStart
.Col();
2457 SCROW nY1
= aMultiRange
.aStart
.Row();
2458 SCCOL nX2
= aMultiRange
.aEnd
.Col();
2459 SCROW nY2
= aMultiRange
.aEnd
.Row();
2461 PutInOrder( nX1
, nX2
);
2462 PutInOrder( nY1
, nY2
);
2464 SCCOL nTestX2
= nX2
;
2465 SCROW nTestY2
= nY2
;
2467 rDoc
.ExtendMerge( nX1
,nY1
, nTestX2
,nTestY2
, nTab
);
2469 SCCOL nPosX
= mrViewData
.GetPosX( eHWhich
);
2470 SCROW nPosY
= mrViewData
.GetPosY( eVWhich
);
2471 // is the selection visible at all?
2472 if (nTestX2
< nPosX
|| nTestY2
< nPosY
)
2474 SCCOL nRealX1
= nX1
;
2480 if (!comphelper::LibreOfficeKit::isActive())
2482 // limit the selection to only what is visible on the screen
2483 SCCOL nXRight
= nPosX
+ mrViewData
.VisibleCellsX(eHWhich
);
2484 if (nXRight
> rDoc
.MaxCol())
2485 nXRight
= rDoc
.MaxCol();
2487 SCROW nYBottom
= nPosY
+ mrViewData
.VisibleCellsY(eVWhich
);
2488 if (nYBottom
> rDoc
.MaxRow())
2489 nYBottom
= rDoc
.MaxRow();
2491 // is the selection visible at all?
2492 if (nX1
> nXRight
|| nY1
> nYBottom
)
2504 rDoc
.GetTiledRenderingArea(nTab
, nMaxTiledCol
, nMaxTiledRow
);
2506 if (nX2
> nMaxTiledCol
)
2508 if (nY2
> nMaxTiledRow
)
2512 ScInvertMerger
aInvert( &rRects
);
2514 Point aScrPos
= bInPrintTwips
? mrViewData
.GetPrintTwipsPos(nX1
, nY1
) :
2515 mrViewData
.GetScrPos(nX1
, nY1
, eWhich
);
2516 tools::Long nScrY
= aScrPos
.Y();
2517 bool bWasHidden
= false;
2518 for (SCROW nY
=nY1
; nY
<=nY2
; nY
++)
2520 bool bFirstRow
= ( nY
== nPosY
); // first visible row?
2521 bool bDoHidden
= false; // repeat hidden ?
2522 sal_uInt16 nHeightTwips
= rDoc
.GetRowHeight( nY
,nTab
);
2523 bool bDoRow
= ( nHeightTwips
!= 0 );
2526 if (bWasHidden
) // test hidden merge
2538 bDoRow
= true; // last cell of the block
2543 SCCOL nLoopEndX
= nX2
;
2544 if (nX2
< nX1
) // the rest of the merge
2546 SCCOL nStartX
= nX1
;
2547 while ( rDoc
.GetAttr(nStartX
,nY
,nTab
,ATTR_MERGE_FLAG
)->IsHorOverlapped() )
2553 const tools::Long nHeight
= bInPrintTwips
?
2554 nHeightTwips
: ScViewData::ToPixel(nHeightTwips
, nPPTY
);
2555 tools::Long nEndY
= nScrY
+ nHeight
- 1;
2556 tools::Long nScrX
= aScrPos
.X();
2557 for (SCCOL nX
=nX1
; nX
<=nLoopEndX
; nX
++)
2559 tools::Long nWidth
= rDoc
.GetColWidth(nX
, nTab
);
2561 nWidth
= ScViewData::ToPixel(nWidth
, nPPTX
);
2565 tools::Long nEndX
= nScrX
+ ( nWidth
- 1 ) * nLayoutSign
;
2568 const ScPatternAttr
* pPattern
= rDoc
.GetPattern( nX
, nY
, nTab
);
2569 const ScMergeFlagAttr
* pMergeFlag
= &pPattern
->GetItem(ATTR_MERGE_FLAG
);
2570 if ( pMergeFlag
->IsVerOverlapped() && ( bDoHidden
|| bFirstRow
) )
2572 while ( pMergeFlag
->IsVerOverlapped() && nThisY
> 0 &&
2573 (rDoc
.RowHidden(nThisY
-1, nTab
) || bFirstRow
) )
2576 pPattern
= rDoc
.GetPattern( nX
, nThisY
, nTab
);
2577 pMergeFlag
= &pPattern
->GetItem(ATTR_MERGE_FLAG
);
2581 // only the rest of the merged is seen ?
2583 if ( pMergeFlag
->IsHorOverlapped() && nX
== nPosX
&& nX
> nRealX1
)
2585 while ( pMergeFlag
->IsHorOverlapped() )
2588 pPattern
= rDoc
.GetPattern( nThisX
, nThisY
, nTab
);
2589 pMergeFlag
= &pPattern
->GetItem(ATTR_MERGE_FLAG
);
2593 if ( aMultiMark
.IsCellMarked( nThisX
, nThisY
, true ) )
2595 if ( !pMergeFlag
->IsOverlapped() )
2597 const ScMergeAttr
* pMerge
= &pPattern
->GetItem(ATTR_MERGE
);
2598 if (pMerge
->GetColMerge() > 0 || pMerge
->GetRowMerge() > 0)
2600 const SCCOL nEndColMerge
= nThisX
+ pMerge
->GetColMerge();
2601 const SCROW nEndRowMerge
= nThisY
+ pMerge
->GetRowMerge();
2602 Point aEndPos
= bInPrintTwips
?
2603 mrViewData
.GetPrintTwipsPos(nEndColMerge
, nEndRowMerge
) :
2604 mrViewData
.GetScrPos(nEndColMerge
, nEndRowMerge
, eWhich
);
2605 if ( aEndPos
.X() * nLayoutSign
> nScrX
* nLayoutSign
&& aEndPos
.Y() > nScrY
)
2607 aInvert
.AddRect( tools::Rectangle( nScrX
,nScrY
,
2608 aEndPos
.X()-nLayoutSign
,aEndPos
.Y()-1 ) );
2611 else if ( nEndX
* nLayoutSign
>= nScrX
* nLayoutSign
&& nEndY
>= nScrY
)
2613 aInvert
.AddRect( tools::Rectangle( nScrX
,nScrY
,nEndX
,nEndY
) );
2618 nScrX
= nEndX
+ nLayoutSign
;
2626 void ScGridWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
2628 Window::DataChanged(rDCEvt
);
2630 if ( !((rDCEvt
.GetType() == DataChangedEventType::PRINTER
) ||
2631 (rDCEvt
.GetType() == DataChangedEventType::DISPLAY
) ||
2632 (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2633 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2634 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2635 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))) )
2638 if ( rDCEvt
.GetType() == DataChangedEventType::FONTS
&& eWhich
== mrViewData
.GetActivePart() )
2639 mrViewData
.GetDocShell()->UpdateFontList();
2641 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2642 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
) )
2644 if ( eWhich
== mrViewData
.GetActivePart() ) // only once for the view
2646 ScTabView
* pView
= mrViewData
.GetView();
2650 // RepeatResize in case scroll bar sizes have changed
2651 pView
->RepeatResize();
2652 pView
->UpdateAllOverlays();
2654 // invalidate cell attribs in input handler, in case the
2655 // EditEngine BackgroundColor has to be changed
2656 if ( mrViewData
.IsActive() )
2658 ScInputHandler
* pHdl
= SC_MOD()->GetInputHdl();
2660 pHdl
->ForgetLastPattern();
2668 void ScGridWindow::initiatePageBreaks()
2670 bInitialPageBreaks
= true;
2673 IMPL_LINK(ScGridWindow
, InitiatePageBreaksTimer
, Timer
*, pTimer
, void)
2675 if (pTimer
!= &maShowPageBreaksTimer
)
2678 const ScViewOptions
& rOpts
= mrViewData
.GetOptions();
2679 const bool bPage
= rOpts
.GetOption(VOPT_PAGEBREAKS
);
2680 // tdf#124983, if option LibreOfficeDev Calc/View/Visual Aids/Page
2681 // breaks is enabled, breaks should be visible. If the document is
2682 // opened the first time or a tab is activated the first time, the
2683 // breaks are not calculated yet, so this initialization is done here.
2686 const SCTAB nCurrentTab
= mrViewData
.GetTabNo();
2687 ScDocument
& rDoc
= mrViewData
.GetDocument();
2688 const Size aPageSize
= rDoc
.GetPageSize(nCurrentTab
);
2689 // Do not attempt to calculate a page size here if it is empty if
2690 // that involves counting pages.
2691 // An earlier implementation did
2692 // ScPrintFunc(pDocSh, pDocSh->GetPrinter(), nCurrentTab);
2693 // rDoc.SetPageSize(nCurrentTab, rDoc.GetPageSize(nCurrentTab));
2694 // which resulted in tremendous waiting times after having loaded
2695 // larger documents i.e. imported from CSV, in which UI is entirely
2696 // blocked. All time is spent under ScPrintFunc::CountPages() in
2697 // ScTable::ExtendPrintArea() in the loop that calls
2698 // MaybeAddExtraColumn() to do stuff for each text string content
2699 // cell (each row in each column). Maybe that can be optimized, or
2700 // obtaining page size without that overhead would be possible, but
2701 // as is calling that from here is a no-no so this is a quick
2703 if (!aPageSize
.IsEmpty())
2705 ScDocShell
* pDocSh
= mrViewData
.GetDocShell();
2706 const bool bModified
= pDocSh
->IsModified();
2707 // Even setting the same size sets page size valid, so
2708 // UpdatePageBreaks() actually does something.
2709 rDoc
.SetPageSize( nCurrentTab
, aPageSize
);
2710 rDoc
.UpdatePageBreaks(nCurrentTab
);
2711 pDocSh
->PostPaint(0, 0, nCurrentTab
, rDoc
.MaxCol(), rDoc
.MaxRow(), nCurrentTab
, PaintPartFlags::Grid
);
2712 pDocSh
->SetModified(bModified
);
2718 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */