Bug Summary

File:home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin4.cxx
Warning:line 1397, column 9
Value stored to 'nEndCol' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name gridwin4.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SC_DLLIMPLEMENTATION -D SC_INFO_OSVERSION="LINUX" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/liborcus/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/clew/source/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sc/source/core/inc -I /home/maarten/src/libreoffice/core/sc/source/filter/inc -I /home/maarten/src/libreoffice/core/sc/source/ui/inc -I /home/maarten/src/libreoffice/core/sc/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sc/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin4.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <memory>
21#include <scitems.hxx>
22#include <editeng/eeitem.hxx>
23
24#include <svtools/colorcfg.hxx>
25#include <editeng/colritem.hxx>
26#include <editeng/editview.hxx>
27#include <editeng/fhgtitem.hxx>
28#include <sfx2/bindings.hxx>
29#include <sfx2/printer.hxx>
30#include <vcl/cursor.hxx>
31#include <vcl/settings.hxx>
32
33#include <LibreOfficeKit/LibreOfficeKitEnums.h>
34#include <comphelper/lok.hxx>
35#include <sfx2/lokhelper.hxx>
36
37#include <svx/svdview.hxx>
38#include <svx/svdpagv.hxx>
39#include <svx/sdrpagewindow.hxx>
40#include <svx/sdr/contact/objectcontactofpageview.hxx>
41#include <svx/sdr/contact/viewobjectcontact.hxx>
42#include <svx/sdr/contact/viewcontact.hxx>
43#include <tabvwsh.hxx>
44
45#include <gridwin.hxx>
46#include <viewdata.hxx>
47#include <output.hxx>
48#include <document.hxx>
49#include <attrib.hxx>
50#include <patattr.hxx>
51#include <dbdata.hxx>
52#include <docoptio.hxx>
53#include <notemark.hxx>
54#include <dbfunc.hxx>
55#include <scmod.hxx>
56#include <inputhdl.hxx>
57#include <rfindlst.hxx>
58#include <hiranges.hxx>
59#include <pagedata.hxx>
60#include <docpool.hxx>
61#include <globstr.hrc>
62#include <scresid.hxx>
63#include <docsh.hxx>
64#include <cbutton.hxx>
65#include <invmerge.hxx>
66#include <editutil.hxx>
67#include <inputopt.hxx>
68#include <fillinfo.hxx>
69#include <dpcontrol.hxx>
70#include <queryparam.hxx>
71#include <queryentry.hxx>
72#include <markdata.hxx>
73#include <sc.hrc>
74#include <vcl/virdev.hxx>
75#include <svx/sdrpaintwindow.hxx>
76#include <drwlayer.hxx>
77
78static void lcl_LimitRect( tools::Rectangle& rRect, const tools::Rectangle& rVisible )
79{
80 if ( rRect.Top() < rVisible.Top()-1 ) rRect.SetTop( rVisible.Top()-1 );
81 if ( rRect.Bottom() > rVisible.Bottom()+1 ) rRect.SetBottom( rVisible.Bottom()+1 );
82
83 // The header row must be drawn also when the inner rectangle is not visible,
84 // that is why there is no return value anymore.
85 // When it is far away, then lcl_DrawOneFrame is not even called.
86}
87
88static void lcl_DrawOneFrame( vcl::RenderContext* pDev, const tools::Rectangle& rInnerPixel,
89 const OUString& rTitle, const Color& rColor, bool bTextBelow,
90 double nPPTX, double nPPTY, const Fraction& rZoomY,
91 ScDocument& rDoc, ScViewData& rButtonViewData, bool bLayoutRTL )
92{
93 // rButtonViewData is only used to set the button size,
94
95 tools::Rectangle aInner = rInnerPixel;
96 if ( bLayoutRTL )
97 {
98 aInner.SetLeft( rInnerPixel.Right() );
99 aInner.SetRight( rInnerPixel.Left() );
100 }
101
102 tools::Rectangle aVisible( Point(0,0), pDev->GetOutputSizePixel() );
103 lcl_LimitRect( aInner, aVisible );
104
105 tools::Rectangle aOuter = aInner;
106 long nHor = static_cast<long>( SC_SCENARIO_HSPACE60 * nPPTX );
107 long nVer = static_cast<long>( SC_SCENARIO_VSPACE50 * nPPTY );
108 aOuter.AdjustLeft( -nHor );
109 aOuter.AdjustRight(nHor );
110 aOuter.AdjustTop( -nVer );
111 aOuter.AdjustBottom(nVer );
112
113 // use ScPatternAttr::GetFont only for font size
114 vcl::Font aAttrFont;
115 rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN).
116 GetFont(aAttrFont,SC_AUTOCOL_BLACK,pDev,&rZoomY);
117
118 // everything else from application font
119 vcl::Font aAppFont = pDev->GetSettings().GetStyleSettings().GetAppFont();
120 aAppFont.SetFontSize( aAttrFont.GetFontSize() );
121
122 aAppFont.SetAlignment( ALIGN_TOP );
123 pDev->SetFont( aAppFont );
124
125 Size aTextSize( pDev->GetTextWidth( rTitle ), pDev->GetTextHeight() );
126
127 if ( bTextBelow )
128 aOuter.AdjustBottom(aTextSize.Height() );
129 else
130 aOuter.AdjustTop( -(aTextSize.Height()) );
131
132 pDev->SetLineColor();
133 pDev->SetFillColor( rColor );
134 // left, top, right, bottom
135 pDev->DrawRect( tools::Rectangle( aOuter.Left(), aOuter.Top(), aInner.Left(), aOuter.Bottom() ) );
136 pDev->DrawRect( tools::Rectangle( aOuter.Left(), aOuter.Top(), aOuter.Right(), aInner.Top() ) );
137 pDev->DrawRect( tools::Rectangle( aInner.Right(), aOuter.Top(), aOuter.Right(), aOuter.Bottom() ) );
138 pDev->DrawRect( tools::Rectangle( aOuter.Left(), aInner.Bottom(), aOuter.Right(), aOuter.Bottom() ) );
139
140 long nButtonY = bTextBelow ? aInner.Bottom() : aOuter.Top();
141
142 ScDDComboBoxButton aComboButton(pDev);
143 aComboButton.SetOptSizePixel();
144 long nBWidth = long(aComboButton.GetSizePixel().Width() * rZoomY);
145 long nBHeight = nVer + aTextSize.Height() + 1;
146 Size aButSize( nBWidth, nBHeight );
147 long nButtonPos = bLayoutRTL ? aOuter.Left() : aOuter.Right()-nBWidth+1;
148 aComboButton.Draw( Point(nButtonPos, nButtonY), aButSize );
149 rButtonViewData.SetScenButSize( aButSize );
150
151 long nTextStart = bLayoutRTL ? aInner.Right() - aTextSize.Width() + 1 : aInner.Left();
152
153 bool bWasClip = false;
154 vcl::Region aOldClip;
155 bool bClip = ( aTextSize.Width() > aOuter.Right() - nBWidth - aInner.Left() );
156 if ( bClip )
157 {
158 if (pDev->IsClipRegion())
159 {
160 bWasClip = true;
161 aOldClip = pDev->GetActiveClipRegion();
162 }
163 long nClipStartX = bLayoutRTL ? aOuter.Left() + nBWidth : aInner.Left();
164 long nClipEndX = bLayoutRTL ? aInner.Right() : aOuter.Right() - nBWidth;
165 pDev->SetClipRegion( vcl::Region(tools::Rectangle( nClipStartX, nButtonY + nVer/2,
166 nClipEndX, nButtonY + nVer/2 + aTextSize.Height())) );
167 }
168
169 pDev->DrawText( Point( nTextStart, nButtonY + nVer/2 ), rTitle );
170
171 if ( bClip )
172 {
173 if ( bWasClip )
174 pDev->SetClipRegion(aOldClip);
175 else
176 pDev->SetClipRegion();
177 }
178
179 pDev->SetFillColor();
180 pDev->SetLineColor( COL_BLACK );
181 pDev->DrawRect( aInner );
182 pDev->DrawRect( aOuter );
183}
184
185static void lcl_DrawScenarioFrames( OutputDevice* pDev, ScViewData& rViewData, ScSplitPos eWhich,
186 SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2 )
187{
188 ScDocument& rDoc = rViewData.GetDocument();
189 SCTAB nTab = rViewData.GetTabNo();
190 SCTAB nTabCount = rDoc.GetTableCount();
191 if ( nTab+1 >= nTabCount || !rDoc.IsScenario(nTab+1) || rDoc.IsScenario(nTab) )
192 return;
193
194 if ( nX1 > 0 ) --nX1;
195 if ( nY1>=2 ) nY1 -= 2; // Hack: Header row affects two cells
196 else if ( nY1 > 0 ) --nY1;
197 if ( nX2 < rDoc.MaxCol() ) ++nX2;
198 if ( nY2 < rDoc.MaxRow()-1 ) nY2 += 2; // Hack: Header row affects two cells
199 else if ( nY2 < rDoc.MaxRow() ) ++nY2;
200 ScRange aViewRange( nX1,nY1,nTab, nX2,nY2,nTab );
201
202 //! cache the ranges in table!!!!
203
204 ScMarkData aMarks(rDoc.GetSheetLimits());
205 for (SCTAB i=nTab+1; i<nTabCount && rDoc.IsScenario(i); i++)
206 rDoc.MarkScenario( i, nTab, aMarks, false, ScScenarioFlags::ShowFrame );
207 ScRangeListRef xRanges = new ScRangeList;
208 aMarks.FillRangeListWithMarks( xRanges.get(), false );
209
210 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
211 long nLayoutSign = bLayoutRTL ? -1 : 1;
212
213 for (size_t j = 0, n = xRanges->size(); j < n; ++j)
214 {
215 ScRange aRange = (*xRanges)[j];
216 // Always extend scenario frame to merged cells where no new non-covered cells
217 // are framed
218 rDoc.ExtendTotalMerge( aRange );
219
220 //! -> Extend repaint when merging !!!
221
222 if ( aRange.Intersects( aViewRange ) ) //! Space for Text/Button?
223 {
224 Point aStartPos = rViewData.GetScrPos(
225 aRange.aStart.Col(), aRange.aStart.Row(), eWhich, true );
226 Point aEndPos = rViewData.GetScrPos(
227 aRange.aEnd.Col()+1, aRange.aEnd.Row()+1, eWhich, true );
228 // on the grid:
229 aStartPos.AdjustX( -nLayoutSign );
230 aStartPos.AdjustY( -1 );
231 aEndPos.AdjustX( -nLayoutSign );
232 aEndPos.AdjustY( -1 );
233
234 bool bTextBelow = ( aRange.aStart.Row() == 0 );
235
236 OUString aCurrent;
237 Color aColor( COL_LIGHTGRAY );
238 for (SCTAB nAct=nTab+1; nAct<nTabCount && rDoc.IsScenario(nAct); nAct++)
239 if ( rDoc.IsActiveScenario(nAct) && rDoc.HasScenarioRange(nAct,aRange) )
240 {
241 OUString aDummyComment;
242 ScScenarioFlags nDummyFlags;
243 rDoc.GetName( nAct, aCurrent );
244 rDoc.GetScenarioData( nAct, aDummyComment, aColor, nDummyFlags );
245 }
246
247 if (aCurrent.isEmpty())
248 aCurrent = ScResId( STR_EMPTYDATAreinterpret_cast<char const *>("STR_EMPTYDATA" "\004" u8"(empty)"
)
);
249
250 //! Own text "(None)" instead of "(Empty)" ???
251
252 lcl_DrawOneFrame( pDev, tools::Rectangle( aStartPos, aEndPos ),
253 aCurrent, aColor, bTextBelow,
254 rViewData.GetPPTX(), rViewData.GetPPTY(), rViewData.GetZoomY(),
255 rDoc, rViewData, bLayoutRTL );
256 }
257 }
258}
259
260static void lcl_DrawHighlight( ScOutputData& rOutputData, const ScViewData& rViewData,
261 const std::vector<ScHighlightEntry>& rHighlightRanges )
262{
263 SCTAB nTab = rViewData.GetTabNo();
264 for ( const auto& rHighlightRange : rHighlightRanges)
265 {
266 ScRange aRange = rHighlightRange.aRef;
267 if ( nTab >= aRange.aStart.Tab() && nTab <= aRange.aEnd.Tab() )
268 {
269 rOutputData.DrawRefMark(
270 aRange.aStart.Col(), aRange.aStart.Row(),
271 aRange.aEnd.Col(), aRange.aEnd.Row(),
272 rHighlightRange.aColor, false );
273 }
274 }
275}
276
277void ScGridWindow::DoInvertRect( const tools::Rectangle& rPixel )
278{
279 if ( rPixel == aInvertRect )
280 aInvertRect = tools::Rectangle(); // Cancel
281 else
282 {
283 OSL_ENSURE( aInvertRect.IsEmpty(), "DoInvertRect no pairs" )do { if (true && (!(aInvertRect.IsEmpty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin4.cxx"
":" "283" ": "), "%s", "DoInvertRect no pairs"); } } while (
false)
;
284
285 aInvertRect = rPixel; // Mark new rectangle
286 }
287
288 UpdateHeaderOverlay(); // uses aInvertRect
289}
290
291void ScGridWindow::PrePaint(vcl::RenderContext& /*rRenderContext*/)
292{
293 // forward PrePaint to DrawingLayer
294 ScTabViewShell* pTabViewShell = mrViewData.GetViewShell();
295
296 if(pTabViewShell)
297 {
298 SdrView* pDrawView = pTabViewShell->GetScDrawView();
299
300 if (pDrawView)
301 {
302 pDrawView->PrePaint();
303 }
304 }
305}
306
307bool ScGridWindow::NeedLOKCursorInvalidation(const tools::Rectangle& rCursorRect,
308 const Fraction aScaleX, const Fraction aScaleY)
309{
310 // Don't see the need for a map as there will be only a few zoom levels
311 // and as of now X and Y zooms in online are the same.
312 for (auto& rEntry : maLOKLastCursor)
313 {
314 if (aScaleX == rEntry.aScaleX && aScaleY == rEntry.aScaleY)
315 {
316 if (rCursorRect == rEntry.aRect)
317 return false; // No change
318
319 // Update and allow invalidate.
320 rEntry.aRect = rCursorRect;
321 return true;
322 }
323 }
324
325 maLOKLastCursor.push_back(LOKCursorEntry{aScaleX, aScaleY, rCursorRect});
326 return true;
327}
328
329void ScGridWindow::InvalidateLOKViewCursor(const tools::Rectangle& rCursorRect,
330 const Fraction aScaleX, const Fraction aScaleY)
331{
332 if (!NeedLOKCursorInvalidation(rCursorRect, aScaleX, aScaleY))
333 return;
334
335 ScTabViewShell* pThisViewShell = mrViewData.GetViewShell();
336 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
337
338 while (pViewShell)
339 {
340 if (pViewShell != pThisViewShell && pViewShell->GetDocId() == pThisViewShell->GetDocId())
341 {
342 ScTabViewShell* pOtherViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
343 if (pOtherViewShell)
344 {
345 ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
346 Fraction aZoomX = rOtherViewData.GetZoomX();
347 Fraction aZoomY = rOtherViewData.GetZoomY();
348 if (aZoomX == aScaleX && aZoomY == aScaleY)
349 {
350 SfxLokHelper::notifyOtherView(pThisViewShell, pOtherViewShell,
351 LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, "rectangle", rCursorRect.toString());
352 }
353 }
354 }
355
356 pViewShell = SfxViewShell::GetNext(*pViewShell);
357 }
358}
359
360void ScGridWindow::Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect )
361{
362 ScDocument& rDoc = mrViewData.GetDocument();
363 if ( rDoc.IsInInterpreter() )
364 {
365 // Via Reschedule, interpreted cells do not trigger Invalidate again,
366 // otherwise for instance an error box would never appear (bug 36381).
367 // Later, through bNeedsRepaint everything is painted again.
368 if ( bNeedsRepaint )
369 {
370 //! Merge Rectangle?
371 aRepaintPixel = tools::Rectangle(); // multiple -> paint all
372 }
373 else
374 {
375 bNeedsRepaint = true;
376 aRepaintPixel = LogicToPixel(rRect); // only affected ranges
377 }
378 return;
379 }
380
381 // #i117893# If GetSizePixel needs to call the resize handler, the resulting nested Paint call
382 // (possibly for a larger rectangle) has to be allowed. Call GetSizePixel before setting bIsInPaint.
383 GetSizePixel();
384
385 if (bIsInPaint)
386 return;
387
388 bIsInPaint = true;
389
390 tools::Rectangle aPixRect = LogicToPixel( rRect );
391
392 SCCOL nX1 = mrViewData.GetPosX(eHWhich);
393 SCROW nY1 = mrViewData.GetPosY(eVWhich);
394
395 SCTAB nTab = mrViewData.GetTabNo();
396
397 double nPPTX = mrViewData.GetPPTX();
398 double nPPTY = mrViewData.GetPPTY();
399
400 tools::Rectangle aMirroredPixel = aPixRect;
401 if ( rDoc.IsLayoutRTL( nTab ) )
402 {
403 // mirror and swap
404 long nWidth = GetSizePixel().Width();
405 aMirroredPixel.SetLeft( nWidth - 1 - aPixRect.Right() );
406 aMirroredPixel.SetRight( nWidth - 1 - aPixRect.Left() );
407 }
408
409 long nScrX = ScViewData::ToPixel( rDoc.GetColWidth( nX1, nTab ), nPPTX );
410 while ( nScrX <= aMirroredPixel.Left() && nX1 < rDoc.MaxCol() )
411 {
412 ++nX1;
413 nScrX += ScViewData::ToPixel( rDoc.GetColWidth( nX1, nTab ), nPPTX );
414 }
415 SCCOL nX2 = nX1;
416 while ( nScrX <= aMirroredPixel.Right() && nX2 < rDoc.MaxCol() )
417 {
418 ++nX2;
419 nScrX += ScViewData::ToPixel( rDoc.GetColWidth( nX2, nTab ), nPPTX );
420 }
421
422 long nScrY = 0;
423 ScViewData::AddPixelsWhile( nScrY, aPixRect.Top(), nY1, rDoc.MaxRow(), nPPTY, &rDoc, nTab);
424 SCROW nY2 = nY1;
425 if (nScrY <= aPixRect.Bottom() && nY2 < rDoc.MaxRow())
426 {
427 ++nY2;
428 ScViewData::AddPixelsWhile( nScrY, aPixRect.Bottom(), nY2, rDoc.MaxRow(), nPPTY, &rDoc, nTab);
429 }
430
431 Draw( nX1,nY1,nX2,nY2, ScUpdateMode::Marks ); // don't continue with painting
432
433 bIsInPaint = false;
434}
435
436void ScGridWindow::Draw( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, ScUpdateMode eMode )
437{
438 ScDocument& rDoc = mrViewData.GetDocument();
439
440 // let's ignore the normal Draw() attempts when doing the tiled rendering,
441 // all the rendering should go through PaintTile() in that case.
442 // TODO revisit if we can actually turn this into an assert(), and clean
443 // up the callers
444 if (comphelper::LibreOfficeKit::isActive())
445 return;
446
447 ScModule* pScMod = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
;
448 bool bTextWysiwyg = pScMod->GetInputOptions().GetTextWysiwyg();
449
450 if (mrViewData.IsMinimized())
451 return;
452
453 PutInOrder( nX1, nX2 );
454 PutInOrder( nY1, nY2 );
455
456 OSL_ENSURE( rDoc.ValidCol(nX2) && rDoc.ValidRow(nY2), "GridWin Draw area too big" )do { if (true && (!(rDoc.ValidCol(nX2) && rDoc
.ValidRow(nY2)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin4.cxx"
":" "456" ": "), "%s", "GridWin Draw area too big"); } } while
(false)
;
457
458 UpdateVisibleRange();
459
460 if (nX2 < maVisibleRange.mnCol1 || nY2 < maVisibleRange.mnRow1)
461 return;
462 // invisible
463 if (nX1 < maVisibleRange.mnCol1)
464 nX1 = maVisibleRange.mnCol1;
465 if (nY1 < maVisibleRange.mnRow1)
466 nY1 = maVisibleRange.mnRow1;
467
468 if (nX1 > maVisibleRange.mnCol2 || nY1 > maVisibleRange.mnRow2)
469 return;
470
471 if (nX2 > maVisibleRange.mnCol2)
472 nX2 = maVisibleRange.mnCol2;
473 if (nY2 > maVisibleRange.mnRow2)
474 nY2 = maVisibleRange.mnRow2;
475
476 if ( eMode != ScUpdateMode::Marks && nX2 < maVisibleRange.mnCol2)
477 nX2 = maVisibleRange.mnCol2; // to continue painting
478
479 // point of no return
480
481 ++nPaintCount; // mark that painting is in progress
482
483 SCTAB nTab = mrViewData.GetTabNo();
484 rDoc.ExtendHidden( nX1, nY1, nX2, nY2, nTab );
485
486 Point aScrPos = mrViewData.GetScrPos( nX1, nY1, eWhich );
487 long nMirrorWidth = GetSizePixel().Width();
488 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
489 if ( bLayoutRTL )
490 {
491 long nEndPixel = mrViewData.GetScrPos( nX2+1, maVisibleRange.mnRow1, eWhich ).X();
492 nMirrorWidth = aScrPos.X() - nEndPixel;
493 aScrPos.setX( nEndPixel + 1 );
494 }
495
496 long nScrX = aScrPos.X();
497 long nScrY = aScrPos.Y();
498
499 SCCOL nCurX = mrViewData.GetCurX();
500 SCROW nCurY = mrViewData.GetCurY();
501 SCCOL nCurEndX = nCurX;
502 SCROW nCurEndY = nCurY;
503 rDoc.ExtendMerge( nCurX, nCurY, nCurEndX, nCurEndY, nTab );
504 bool bCurVis = nCursorHideCount==0 &&
505 ( nCurEndX+1 >= nX1 && nCurX <= nX2+1 && nCurEndY+1 >= nY1 && nCurY <= nY2+1 );
506
507 // AutoFill Handles
508 if ( !bCurVis && nCursorHideCount==0 && bAutoMarkVisible && aAutoMarkPos.Tab() == nTab &&
509 ( aAutoMarkPos.Col() != nCurX || aAutoMarkPos.Row() != nCurY ) )
510 {
511 SCCOL nHdlX = aAutoMarkPos.Col();
512 SCROW nHdlY = aAutoMarkPos.Row();
513 rDoc.ExtendMerge( nHdlX, nHdlY, nHdlX, nHdlY, nTab );
514 // left and top is unaffected
515
516 //! Paint AutoFill handles alone (without Cursor) ???
517 }
518
519 double nPPTX = mrViewData.GetPPTX();
520 double nPPTY = mrViewData.GetPPTY();
521
522 const ScViewOptions& rOpts = mrViewData.GetOptions();
523
524 // data block
525
526 ScTableInfo aTabInfo;
527 rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nTab,
528 nPPTX, nPPTY, false, rOpts.GetOption(VOPT_FORMULAS),
529 &mrViewData.GetMarkData() );
530
531 Fraction aZoomX = mrViewData.GetZoomX();
532 Fraction aZoomY = mrViewData.GetZoomY();
533 ScOutputData aOutputData( this, OUTTYPE_WINDOW, aTabInfo, &rDoc, nTab,
534 nScrX, nScrY, nX1, nY1, nX2, nY2, nPPTX, nPPTY,
535 &aZoomX, &aZoomY );
536
537 aOutputData.SetMirrorWidth( nMirrorWidth ); // needed for RTL
538 aOutputData.SetSpellCheckContext(mpSpellCheckCxt.get());
539
540 ScopedVclPtr< VirtualDevice > xFmtVirtDev;
541 bool bLogicText = bTextWysiwyg; // call DrawStrings in logic MapMode?
542
543 if ( bTextWysiwyg )
544 {
545 // use printer for text formatting
546
547 OutputDevice* pFmtDev = rDoc.GetPrinter();
548 pFmtDev->SetMapMode( mrViewData.GetLogicMode(eWhich) );
549 aOutputData.SetFmtDevice( pFmtDev );
550 }
551 else if ( aZoomX != aZoomY && mrViewData.IsOle() )
552 {
553 // #i45033# For OLE inplace editing with different zoom factors,
554 // use a virtual device with 1/100th mm as text formatting reference
555
556 xFmtVirtDev.disposeAndReset( VclPtr<VirtualDevice>::Create() );
557 xFmtVirtDev->SetMapMode(MapMode(MapUnit::Map100thMM));
558 aOutputData.SetFmtDevice( xFmtVirtDev.get() );
559
560 bLogicText = true; // use logic MapMode
561 }
562
563 DrawContent(*this, aTabInfo, aOutputData, bLogicText);
564
565 // If something was inverted during the Paint (selection changed from Basic Macro)
566 // then this is now mixed up and has to be repainted
567 OSL_ENSURE(nPaintCount, "Wrong nPaintCount")do { if (true && (!(nPaintCount))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin4.cxx"
":" "567" ": "), "%s", "Wrong nPaintCount"); } } while (false
)
;
568 --nPaintCount;
569 if (!nPaintCount)
570 CheckNeedsRepaint();
571
572 // Flag drawn formula cells "unchanged".
573 rDoc.ResetChanged(ScRange(nX1, nY1, nTab, nX2, nY2, nTab));
574 rDoc.PrepareFormulaCalc();
575}
576
577namespace {
578
579class SuppressEditViewMessagesGuard
580{
581public:
582 SuppressEditViewMessagesGuard(EditView& rEditView) :
583 mrEditView(rEditView),
584 mbOrigSuppressFlag(rEditView.IsSuppressLOKMessages())
585 {
586 if (!mbOrigSuppressFlag)
587 mrEditView.SuppressLOKMessages(true);
588 }
589
590 ~SuppressEditViewMessagesGuard()
591 {
592 if (mrEditView.IsSuppressLOKMessages() != mbOrigSuppressFlag)
593 mrEditView.SuppressLOKMessages(mbOrigSuppressFlag);
594 }
595
596private:
597 EditView& mrEditView;
598 const bool mbOrigSuppressFlag;
599};
600
601}
602
603void ScGridWindow::DrawContent(OutputDevice &rDevice, const ScTableInfo& rTableInfo, ScOutputData& aOutputData,
604 bool bLogicText)
605{
606 ScModule* pScMod = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
;
607 ScDocument& rDoc = mrViewData.GetDocument();
608 const ScViewOptions& rOpts = mrViewData.GetOptions();
609 bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
610 bool bNoBackgroundAndGrid = bIsTiledRendering
611 && comphelper::LibreOfficeKit::isCompatFlagSet(
612 comphelper::LibreOfficeKit::Compat::scNoGridBackground);
613
614 SCTAB nTab = aOutputData.nTab;
615 SCCOL nX1 = aOutputData.nX1;
616 SCROW nY1 = aOutputData.nY1;
617 SCCOL nX2 = aOutputData.nX2;
618 SCROW nY2 = aOutputData.nY2;
619 long nScrX = aOutputData.nScrX;
620 long nScrY = aOutputData.nScrY;
621
622 const svtools::ColorConfig& rColorCfg = pScMod->GetColorConfig();
623 Color aGridColor( rColorCfg.GetColorValue( svtools::CALCGRID, false ).nColor );
624 if ( aGridColor == COL_TRANSPARENT )
625 {
626 // use view options' grid color only if color config has "automatic" color
627 aGridColor = rOpts.GetGridColor();
628 }
629
630 aOutputData.SetSyntaxMode ( mrViewData.IsSyntaxMode() );
631 aOutputData.SetGridColor ( aGridColor );
632 aOutputData.SetShowNullValues ( rOpts.GetOption( VOPT_NULLVALS ) );
633 aOutputData.SetShowFormulas ( rOpts.GetOption( VOPT_FORMULAS ) );
634 aOutputData.SetShowSpellErrors ( rDoc.GetDocOptions().IsAutoSpell() );
635 aOutputData.SetMarkClipped ( rOpts.GetOption( VOPT_CLIPMARKS ) );
636
637 aOutputData.SetUseStyleColor( true ); // always set in table view
638
639 aOutputData.SetViewShell( mrViewData.GetViewShell() );
640
641 bool bGrid = rOpts.GetOption( VOPT_GRID ) && mrViewData.GetShowGrid();
642 bool bGridFirst = !rOpts.GetOption( VOPT_GRID_ONTOP );
643
644 bool bPage = rOpts.GetOption( VOPT_PAGEBREAKS ) && !bIsTiledRendering;
645
646 bool bPageMode = mrViewData.IsPagebreakMode();
647 if (bPageMode) // after FindChanged
648 {
649 // SetPagebreakMode also initializes bPrinted Flags
650 aOutputData.SetPagebreakMode( mrViewData.GetView()->GetPageBreakData() );
651 }
652
653 EditView* pEditView = nullptr;
654 bool bEditMode = mrViewData.HasEditView(eWhich);
655 if ( bEditMode && mrViewData.GetRefTabNo() == nTab )
656 {
657 SCCOL nEditCol;
658 SCROW nEditRow;
659 mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
660 SCCOL nEditEndCol = mrViewData.GetEditEndCol();
661 SCROW nEditEndRow = mrViewData.GetEditEndRow();
662
663 if ( nEditEndCol >= nX1 && nEditCol <= nX2 && nEditEndRow >= nY1 && nEditRow <= nY2 )
664 aOutputData.SetEditCell( nEditCol, nEditRow );
665 else
666 bEditMode = false;
667 }
668
669 const MapMode aOriginalMode = rDevice.GetMapMode();
670
671 // define drawing layer map mode and paint rectangle
672 MapMode aDrawMode = GetDrawMapMode();
673 if (bIsTiledRendering)
674 {
675 // FIXME this shouldn't be necessary once we change the entire Calc to
676 // work in the logic coordinates (ideally 100ths of mm - so that it is
677 // the same as editeng and drawinglayer), and get rid of all the
678 // SetMapMode's and other unnecessary fun we have with pixels
679 // See also ScGridWindow::GetDrawMapMode() for the rest of this hack
680 aDrawMode.SetOrigin(PixelToLogic(Point(nScrX, nScrY), aDrawMode));
681 }
682 tools::Rectangle aDrawingRectLogic;
683 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
684
685 {
686 // get drawing pixel rect
687 tools::Rectangle aDrawingRectPixel(Point(nScrX, nScrY), Size(aOutputData.GetScrW(), aOutputData.GetScrH()));
688
689 // correct for border (left/right)
690 if(rDoc.MaxCol() == nX2)
691 {
692 if(bLayoutRTL)
693 {
694 aDrawingRectPixel.SetLeft( 0 );
695 }
696 else
697 {
698 aDrawingRectPixel.SetRight( GetOutputSizePixel().getWidth() );
699 }
700 }
701
702 // correct for border (bottom)
703 if(rDoc.MaxRow() == nY2)
704 {
705 aDrawingRectPixel.SetBottom( GetOutputSizePixel().getHeight() );
706 }
707
708 // get logic positions
709 aDrawingRectLogic = PixelToLogic(aDrawingRectPixel, aDrawMode);
710 }
711
712 OutputDevice* pContentDev = &rDevice; // device for document content, used by overlay manager
713 SdrPaintWindow* pTargetPaintWindow = nullptr; // #i74769# work with SdrPaintWindow directly
714
715 {
716 // init redraw
717 ScTabViewShell* pTabViewShell = mrViewData.GetViewShell();
718
719 if(pTabViewShell)
720 {
721 MapMode aCurrentMapMode(pContentDev->GetMapMode());
722 pContentDev->SetMapMode(aDrawMode);
723 SdrView* pDrawView = pTabViewShell->GetScDrawView();
724
725 if(pDrawView)
726 {
727 // #i74769# Use new BeginDrawLayers() interface
728 vcl::Region aDrawingRegion(aDrawingRectLogic);
729 pTargetPaintWindow = pDrawView->BeginDrawLayers(pContentDev, aDrawingRegion);
730 OSL_ENSURE(pTargetPaintWindow, "BeginDrawLayers: Got no SdrPaintWindow (!)")do { if (true && (!(pTargetPaintWindow))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin4.cxx"
":" "730" ": "), "%s", "BeginDrawLayers: Got no SdrPaintWindow (!)"
); } } while (false)
;
731
732 if (!bIsTiledRendering)
733 {
734 // #i74769# get target device from SdrPaintWindow, this may be the prerender
735 // device now, too.
736 pContentDev = &(pTargetPaintWindow->GetTargetOutputDevice());
737 aOutputData.SetContentDevice(pContentDev);
738 }
739 }
740
741 pContentDev->SetMapMode(aCurrentMapMode);
742 }
743 }
744
745 // edge (area) (Pixel)
746 if ( nX2==rDoc.MaxCol() || nY2==rDoc.MaxRow() )
747 {
748 // save MapMode and set to pixel
749 MapMode aCurrentMapMode(pContentDev->GetMapMode());
750 pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
751
752 tools::Rectangle aPixRect( Point(), GetOutputSizePixel() );
753 pContentDev->SetFillColor( rColorCfg.GetColorValue(svtools::APPBACKGROUND).nColor );
754 pContentDev->SetLineColor();
755 if ( nX2==rDoc.MaxCol() )
756 {
757 tools::Rectangle aDrawRect( aPixRect );
758 if ( bLayoutRTL )
759 aDrawRect.SetRight( nScrX - 1 );
760 else
761 aDrawRect.SetLeft( nScrX + aOutputData.GetScrW() );
762 if (aDrawRect.Right() >= aDrawRect.Left())
763 pContentDev->DrawRect( aDrawRect );
764 }
765 if ( nY2==rDoc.MaxRow() )
766 {
767 tools::Rectangle aDrawRect( aPixRect );
768 aDrawRect.SetTop( nScrY + aOutputData.GetScrH() );
769 if ( nX2==rDoc.MaxCol() )
770 {
771 // no double painting of the corner
772 if ( bLayoutRTL )
773 aDrawRect.SetLeft( nScrX );
774 else
775 aDrawRect.SetRight( nScrX + aOutputData.GetScrW() - 1 );
776 }
777 if (aDrawRect.Bottom() >= aDrawRect.Top())
778 pContentDev->DrawRect( aDrawRect );
779 }
780
781 // restore MapMode
782 pContentDev->SetMapMode(aCurrentMapMode);
783 }
784
785 if ( rDoc.HasBackgroundDraw( nTab, aDrawingRectLogic ) )
786 {
787 pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
788 aOutputData.DrawClear();
789
790 // drawing background
791
792 pContentDev->SetMapMode(aDrawMode);
793 DrawRedraw( aOutputData, SC_LAYER_BACK );
794 }
795 else
796 aOutputData.SetSolidBackground(!bNoBackgroundAndGrid);
797
798 aOutputData.DrawDocumentBackground();
799
800 if (bGridFirst && (bGrid || bPage) && !bNoBackgroundAndGrid)
801 aOutputData.DrawGrid(*pContentDev, bGrid, bPage);
802
803 aOutputData.DrawBackground(*pContentDev);
804
805 if (!bGridFirst && (bGrid || bPage) && !bNoBackgroundAndGrid)
806 aOutputData.DrawGrid(*pContentDev, bGrid, bPage);
807
808 pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
809
810 if ( bPageMode )
811 {
812 // DrawPagePreview draws complete lines/page numbers, must always be clipped
813 if ( aOutputData.SetChangedClip() )
814 {
815 DrawPagePreview(nX1,nY1,nX2,nY2, *pContentDev);
816 pContentDev->SetClipRegion();
817 }
818 }
819
820 aOutputData.DrawShadow();
821 aOutputData.DrawFrame(*pContentDev);
822
823 // Show Note Mark
824 if ( rOpts.GetOption( VOPT_NOTES ) )
825 aOutputData.DrawNoteMarks(*pContentDev);
826
827 if ( !bLogicText )
828 aOutputData.DrawStrings(); // in pixel MapMode
829
830 // edit cells and printer-metrics text must be before the buttons
831 // (DataPilot buttons contain labels in UI font)
832
833 pContentDev->SetMapMode(mrViewData.GetLogicMode(eWhich));
834 if ( bLogicText )
835 aOutputData.DrawStrings(true); // in logic MapMode if bLogicText is set
836 aOutputData.DrawEdit(true);
837
838 // the buttons are painted in absolute coordinates
839 if (bIsTiledRendering)
840 {
841 // Tiled offset nScrX, nScrY
842 MapMode aMap( MapUnit::MapPixel );
843 Point aOrigin = aOriginalMode.GetOrigin();
844 aOrigin.setX(aOrigin.getX() / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0) + nScrX);
845 aOrigin.setY(aOrigin.getY() / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0) + nScrY);
846 aMap.SetOrigin(aOrigin);
847 pContentDev->SetMapMode(aMap);
848 }
849 else
850 pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
851
852 // Autofilter- and Pivot-Buttons
853
854 DrawButtons(nX1, nX2, rTableInfo, pContentDev); // Pixel
855
856 pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
857
858 aOutputData.DrawClipMarks();
859
860 // In any case, Scenario / ChangeTracking must happen after DrawGrid, also for !bGridFirst
861
862 //! test if ChangeTrack display is active
863 //! Disable scenario frame via view option?
864
865 SCTAB nTabCount = rDoc.GetTableCount();
866 const std::vector<ScHighlightEntry> &rHigh = mrViewData.GetView()->GetHighlightRanges();
867 bool bHasScenario = ( nTab+1<nTabCount && rDoc.IsScenario(nTab+1) && !rDoc.IsScenario(nTab) );
868 bool bHasChange = ( rDoc.GetChangeTrack() != nullptr );
869
870 if ( bHasChange || bHasScenario || !rHigh.empty() )
871 {
872 //! Merge SetChangedClip() with DrawMarks() ?? (different MapMode!)
873
874 if ( bHasChange )
875 aOutputData.DrawChangeTrack();
876
877 if ( bHasScenario )
878 lcl_DrawScenarioFrames( pContentDev, mrViewData, eWhich, nX1,nY1,nX2,nY2 );
879
880 lcl_DrawHighlight( aOutputData, mrViewData, rHigh );
881 }
882
883 // Drawing foreground
884
885 pContentDev->SetMapMode(aDrawMode);
886
887 // Bitmaps and buttons are in absolute pixel coordinates.
888 const MapMode aOrig = pContentDev->GetMapMode();
889 if (bIsTiledRendering)
890 {
891 Point aOrigin = aOriginalMode.GetOrigin();
892 Size aPixelOffset(aOrigin.getX() / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0), aOrigin.getY() / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0));
893 pContentDev->SetPixelOffset(aPixelOffset);
894 comphelper::LibreOfficeKit::setLocalRendering();
895 }
896
897 DrawRedraw( aOutputData, SC_LAYER_FRONT );
898 DrawRedraw( aOutputData, SC_LAYER_INTERN );
899 DrawSdrGrid( aDrawingRectLogic, pContentDev );
900
901 if (bIsTiledRendering)
902 {
903 pContentDev->SetPixelOffset(Size());
904 pContentDev->SetMapMode(aOrig);
905 }
906
907 pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
908
909 if ( mrViewData.IsRefMode() && nTab >= mrViewData.GetRefStartZ() && nTab <= mrViewData.GetRefEndZ() )
910 {
911 Color aRefColor( rColorCfg.GetColorValue(svtools::CALCREFERENCE).nColor );
912 aOutputData.DrawRefMark( mrViewData.GetRefStartX(), mrViewData.GetRefStartY(),
913 mrViewData.GetRefEndX(), mrViewData.GetRefEndY(),
914 aRefColor, false );
915 }
916
917 // range finder
918
919 ScInputHandler* pHdl = pScMod->GetInputHdl( mrViewData.GetViewShell() );
920 if (pHdl)
921 {
922 ScDocShell* pDocSh = mrViewData.GetDocShell();
923 ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList();
924 if ( pRangeFinder && !pRangeFinder->IsHidden() &&
925 pRangeFinder->GetDocName() == pDocSh->GetTitle() )
926 {
927 sal_uInt16 nCount = static_cast<sal_uInt16>(pRangeFinder->Count());
928 for (sal_uInt16 i=0; i<nCount; i++)
929 {
930 ScRangeFindData& rData = pRangeFinder->GetObject(i);
931
932 ScRange aRef = rData.aRef;
933 aRef.PutInOrder();
934 if ( aRef.aStart.Tab() >= nTab && aRef.aEnd.Tab() <= nTab )
935 aOutputData.DrawRefMark( aRef.aStart.Col(), aRef.aStart.Row(),
936 aRef.aEnd.Col(), aRef.aEnd.Row(),
937 rData.nColor,
938 true );
939 }
940 }
941 }
942
943 {
944 // end redraw
945 ScTabViewShell* pTabViewShell = mrViewData.GetViewShell();
946
947 if(pTabViewShell)
948 {
949 MapMode aCurrentMapMode(pContentDev->GetMapMode());
950 pContentDev->SetMapMode(aDrawMode);
951
952 if (bIsTiledRendering)
953 {
954 Point aOrigin = aOriginalMode.GetOrigin();
955 aOrigin.setX(aOrigin.getX() / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0) + aOutputData.nScrX);
956 aOrigin.setY(aOrigin.getY() / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0) + aOutputData.nScrY);
957 const double twipFactor = 15 * 1.76388889; // 26.45833335
958 aOrigin = Point(aOrigin.getX() * twipFactor,
959 aOrigin.getY() * twipFactor);
960 MapMode aNew = rDevice.GetMapMode();
961 aNew.SetOrigin(aOrigin);
962 rDevice.SetMapMode(aNew);
963 }
964
965 SdrView* pDrawView = pTabViewShell->GetScDrawView();
966
967 if(pDrawView)
968 {
969 // #i74769# work with SdrPaintWindow directly
970 pDrawView->EndDrawLayers(*pTargetPaintWindow, true);
971 }
972
973 pContentDev->SetMapMode(aCurrentMapMode);
974 }
975 }
976
977 // paint in-place editing on other views
978 if (bIsTiledRendering)
979 {
980 ScTabViewShell* pThisViewShell = mrViewData.GetViewShell();
981 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
982
983 while (pViewShell)
984 {
985 if (pViewShell != pThisViewShell && pViewShell->GetDocId() == pThisViewShell->GetDocId())
986 {
987 ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
988 if (pTabViewShell)
989 {
990 ScViewData& rOtherViewData = pTabViewShell->GetViewData();
991 ScSplitPos eOtherWhich = rOtherViewData.GetEditActivePart();
992
993 bool bOtherEditMode = rOtherViewData.HasEditView(eOtherWhich);
994 SCCOL nCol1 = rOtherViewData.GetEditStartCol();
995 SCROW nRow1 = rOtherViewData.GetEditStartRow();
996 SCCOL nCol2 = rOtherViewData.GetEditEndCol();
997 SCROW nRow2 = rOtherViewData.GetEditEndRow();
998 bOtherEditMode = bOtherEditMode
999 && ( nCol2 >= nX1 && nCol1 <= nX2 && nRow2 >= nY1 && nRow1 <= nY2 );
1000 if (bOtherEditMode && rOtherViewData.GetRefTabNo() == nTab)
1001 {
1002 EditView* pOtherEditView = rOtherViewData.GetEditView(eOtherWhich);
1003 if (pOtherEditView)
1004 {
1005 long nScreenX = aOutputData.nScrX;
1006 long nScreenY = aOutputData.nScrY;
1007
1008 rDevice.SetLineColor();
1009 rDevice.SetFillColor(pOtherEditView->GetBackgroundColor());
1010 Point aStart = mrViewData.GetScrPos( nCol1, nRow1, eOtherWhich );
1011 Point aEnd = mrViewData.GetScrPos( nCol2+1, nRow2+1, eOtherWhich );
1012
1013 // don't overwrite grid
1014 long nLayoutSign = bLayoutRTL ? -1 : 1;
1015 aEnd.AdjustX( -(2 * nLayoutSign) );
1016 aEnd.AdjustY( -2 );
1017
1018 tools::Rectangle aBackground(aStart, aEnd);
1019
1020 // Need to draw the background in absolute coords.
1021 Point aOrigin = aOriginalMode.GetOrigin();
1022 aOrigin.setX(aOrigin.getX() / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0) + nScreenX);
1023 aOrigin.setY(aOrigin.getY() / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0) + nScreenY);
1024 aBackground += aOrigin;
1025 rDevice.SetMapMode(aDrawMode);
1026
1027 static const double twipFactor = 15 * 1.76388889; // 26.45833335
1028 // keep into account the zoom factor
1029 aOrigin = Point((aOrigin.getX() * twipFactor) / static_cast<double>(aDrawMode.GetScaleX()),
1030 (aOrigin.getY() * twipFactor) / static_cast<double>(aDrawMode.GetScaleY()));
1031
1032 MapMode aNew = rDevice.GetMapMode();
1033 aNew.SetOrigin(aOrigin);
1034 rDevice.SetMapMode(aNew);
1035
1036 // paint the background
1037 rDevice.DrawRect(rDevice.PixelToLogic(aBackground));
1038
1039 tools::Rectangle aEditRect(aBackground);
1040 aEditRect.AdjustLeft(1);
1041 aEditRect.AdjustTop(1);
1042
1043 // EditView has an 'output area' which is used to clip the 'paint area' we provide below.
1044 // So they need to be in the same coordinates/units. This is tied to the mapmode of the gridwin
1045 // attached to the EditView, so we have to change its mapmode too (temporarily). We save the
1046 // original mapmode and 'output area' and roll them back when we finish painting to rDevice.
1047 vcl::Window* pOtherWin = pOtherEditView->GetWindow();
1048 const tools::Rectangle aOrigOutputArea(pOtherEditView->GetOutputArea()); // Not in pixels.
1049 const MapMode aOrigMapMode = pOtherWin->GetMapMode();
1050 pOtherWin->SetMapMode(rDevice.GetMapMode());
1051
1052 // Avoid sending wrong cursor/selection messages by the 'other' view, as the output-area is going
1053 // to be tweaked temporarily to match the current view's zoom.
1054 SuppressEditViewMessagesGuard aGuard(*pOtherEditView);
1055
1056 pOtherEditView->SetOutputArea(rDevice.PixelToLogic(aEditRect));
1057 pOtherEditView->Paint(rDevice.PixelToLogic(aEditRect), &rDevice);
1058
1059 // Rollback the mapmode and 'output area'.
1060 pOtherWin->SetMapMode(aOrigMapMode);
1061 pOtherEditView->SetOutputArea(aOrigOutputArea);
1062 rDevice.SetMapMode(MapMode(MapUnit::MapPixel));
1063 }
1064 }
1065 }
1066 }
1067
1068 pViewShell = SfxViewShell::GetNext(*pViewShell);
1069 }
1070
1071 }
1072
1073 // In-place editing - when the user is typing, we need to paint the text
1074 // using the editeng.
1075 // It's being done after EndDrawLayers() to get it outside the overlay
1076 // buffer and on top of everything.
1077 if ( bEditMode && (mrViewData.GetRefTabNo() == mrViewData.GetTabNo()) )
1078 {
1079 // get the coordinates of the area we need to clear (overpaint by
1080 // the background)
1081 SCCOL nCol1 = mrViewData.GetEditStartCol();
1082 SCROW nRow1 = mrViewData.GetEditStartRow();
1083 SCCOL nCol2 = mrViewData.GetEditEndCol();
1084 SCROW nRow2 = mrViewData.GetEditEndRow();
1085 rDevice.SetLineColor();
1086 rDevice.SetFillColor(pEditView->GetBackgroundColor());
1087 Point aStart = mrViewData.GetScrPos( nCol1, nRow1, eWhich );
1088 Point aEnd = mrViewData.GetScrPos( nCol2+1, nRow2+1, eWhich );
1089
1090 // don't overwrite grid
1091 long nLayoutSign = bLayoutRTL ? -1 : 1;
1092 aEnd.AdjustX( -(2 * nLayoutSign) );
1093 aEnd.AdjustY( -2 );
1094
1095 // toggle the cursor off if its on to ensure the cursor invert
1096 // background logic remains valid after the background is cleared on
1097 // the next cursor flash
1098 vcl::Cursor* pCrsr = pEditView->GetCursor();
1099 const bool bVisCursor = pCrsr && pCrsr->IsVisible();
1100 if (bVisCursor)
1101 pCrsr->Hide();
1102
1103 // set the correct mapmode
1104 tools::Rectangle aBackground(aStart, aEnd);
1105 tools::Rectangle aBGAbs(aStart, aEnd);
1106
1107 if (bIsTiledRendering)
1108 {
1109 // Need to draw the background in absolute coords.
1110 Point aOrigin = aOriginalMode.GetOrigin();
1111 aOrigin.setX(aOrigin.getX() / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0) + nScrX);
1112 aOrigin.setY(aOrigin.getY() / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0) + nScrY);
1113 aBackground += aOrigin;
1114 rDevice.SetMapMode(aDrawMode);
1115 }
1116 else
1117 rDevice.SetMapMode(mrViewData.GetLogicMode());
1118
1119 if (bIsTiledRendering)
1120 {
1121 Point aOrigin = aOriginalMode.GetOrigin();
1122 aOrigin.setX(aOrigin.getX() / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0) + nScrX);
1123 aOrigin.setY(aOrigin.getY() / TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0) + nScrY);
1124 static const double twipFactor = 15 * 1.76388889; // 26.45833335
1125 // keep into account the zoom factor
1126 aOrigin = Point((aOrigin.getX() * twipFactor) / static_cast<double>(aDrawMode.GetScaleX()),
1127 (aOrigin.getY() * twipFactor) / static_cast<double>(aDrawMode.GetScaleY()));
1128 MapMode aNew = rDevice.GetMapMode();
1129 aNew.SetOrigin(aOrigin);
1130 rDevice.SetMapMode(aNew);
1131 }
1132
1133 // paint the background
1134 tools::Rectangle aLogicRect(rDevice.PixelToLogic(aBackground));
1135 //tdf#100925, rhbz#1283420, Draw some text here, to get
1136 //X11CairoTextRender::getCairoContext called, so that the forced read
1137 //from the underlying X Drawable gets it to sync.
1138 rDevice.DrawText(aLogicRect.BottomLeft(), " ");
1139 rDevice.DrawRect(aLogicRect);
1140
1141 // paint the editeng text
1142 if (bIsTiledRendering)
1143 {
1144 tools::Rectangle aEditRect(aBackground);
1145 aEditRect.AdjustLeft(1);
1146 aEditRect.AdjustTop(1);
1147 // EditView has an 'output area' which is used to clip the paint area we provide below.
1148 // So they need to be in the same coordinates/units. This is tied to the mapmode of the gridwin
1149 // attached to the EditView, so we have to change its mapmode too (temporarily). We save the
1150 // original mapmode and 'output area' and roll them back when we finish painting to rDevice.
1151 const tools::Rectangle aOrigOutputArea(pEditView->GetOutputArea()); // Not in pixels.
1152 const MapMode aOrigMapMode = GetMapMode();
1153 SetMapMode(rDevice.GetMapMode());
1154
1155 // Avoid sending wrong cursor/selection messages by the current view, as the output-area is going
1156 // to be tweaked temporarily to match other view's zoom. (This does not affect the manual
1157 // cursor-messaging done in the non print-twips mode)
1158 SuppressEditViewMessagesGuard aGuard(*pEditView);
1159
1160 pEditView->SetOutputArea(rDevice.PixelToLogic(aEditRect));
1161 pEditView->Paint(rDevice.PixelToLogic(aEditRect), &rDevice);
1162
1163 // EditView will do the cursor notifications correctly if we're in
1164 // print-twips messaging mode.
1165 if (!comphelper::LibreOfficeKit::isCompatFlagSet(
1166 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
1167 {
1168 // Now we need to get relative cursor position within the editview.
1169 // This is for sending the pixel-aligned twips position of the cursor to the specific views with
1170 // the same given zoom level.
1171 tools::Rectangle aCursorRect = pEditView->GetEditCursor();
1172 Point aCursPos = OutputDevice::LogicToLogic(aCursorRect.TopLeft(),
1173 MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
1174
1175 const MapMode& rDevMM = rDevice.GetMapMode();
1176 MapMode aMM(MapUnit::MapTwip);
1177 aMM.SetScaleX(rDevMM.GetScaleX());
1178 aMM.SetScaleY(rDevMM.GetScaleY());
1179
1180 aBGAbs.AdjustLeft(1);
1181 aBGAbs.AdjustTop(1);
1182 aCursorRect = OutputDevice::PixelToLogic(aBGAbs, aMM);
1183 aCursorRect.setWidth(0);
1184 aCursorRect.Move(aCursPos.getX(), 0);
1185 // Sends view cursor position to views of all matching zooms if needed (avoids duplicates).
1186 InvalidateLOKViewCursor(aCursorRect, aMM.GetScaleX(), aMM.GetScaleY());
1187 }
1188
1189 // Rollback the mapmode and 'output area'.
1190 SetMapMode(aOrigMapMode);
1191 pEditView->SetOutputArea(aOrigOutputArea);
1192 }
1193 else
1194 {
1195 tools::Rectangle aEditRect(Point(nScrX, nScrY), Size(aOutputData.GetScrW(), aOutputData.GetScrH()));
1196 pEditView->Paint(rDevice.PixelToLogic(aEditRect), &rDevice);
1197 }
1198
1199 rDevice.SetMapMode(MapMode(MapUnit::MapPixel));
1200
1201 // restore the cursor it was originally visible
1202 if (bVisCursor)
1203 pCrsr->Show();
1204 }
1205
1206 if (mrViewData.HasEditView(eWhich))
1207 {
1208 // flush OverlayManager before changing the MapMode
1209 flushOverlayManager();
1210
1211 // set MapMode for text edit
1212 rDevice.SetMapMode(mrViewData.GetLogicMode());
1213 }
1214 else
1215 rDevice.SetMapMode(aDrawMode);
1216
1217 if (mpNoteMarker)
1218 mpNoteMarker->Draw(); // Above the cursor, in drawing map mode
1219}
1220
1221namespace
1222{
1223 template<typename IndexType>
1224 void lcl_getBoundingRowColumnforTile(ScViewData& rViewData,
1225 long nTileStartPosPx, long nTileEndPosPx,
1226 sal_Int32& nTopLeftTileOffset, sal_Int32& nTopLeftTileOrigin,
1227 sal_Int32& nTopLeftTileIndex, sal_Int32& nBottomRightTileIndex)
1228 {
1229 const bool bColumnHeader = std::is_same<IndexType, SCCOL>::value;
1230
1231 SCTAB nTab = rViewData.GetTabNo();
1232
1233 IndexType nStartIndex = -1;
1234 IndexType nEndIndex = -1;
1235 long nStartPosPx = 0;
1236 long nEndPosPx = 0;
1237
1238 ScPositionHelper& rPositionHelper =
1239 bColumnHeader ? rViewData.GetLOKWidthHelper() : rViewData.GetLOKHeightHelper();
1240 const auto& rStartNearest = rPositionHelper.getNearestByPosition(nTileStartPosPx);
1241 const auto& rEndNearest = rPositionHelper.getNearestByPosition(nTileEndPosPx);
1242
1243 ScBoundsProvider aBoundsProvider(rViewData, nTab, bColumnHeader);
1244 aBoundsProvider.Compute(rStartNearest, rEndNearest, nTileStartPosPx, nTileEndPosPx);
1245 aBoundsProvider.GetStartIndexAndPosition(nStartIndex, nStartPosPx); ++nStartIndex;
1246 aBoundsProvider.GetEndIndexAndPosition(nEndIndex, nEndPosPx);
1247
1248 nTopLeftTileOffset = nTileStartPosPx - nStartPosPx;
1249 nTopLeftTileOrigin = nStartPosPx;
1250 nTopLeftTileIndex = nStartIndex;
1251 nBottomRightTileIndex = nEndIndex;
1252 }
1253
1254 class ScLOKProxyObjectContact final : public sdr::contact::ObjectContactOfPageView
1255 {
1256 private:
1257 sdr::contact::ObjectContact& mrRealObjectContact;
1258
1259 public:
1260 explicit ScLOKProxyObjectContact(
1261 sdr::contact::ObjectContact& rRealOC,
1262 SdrPageWindow& rPageWindow,
1263 const char* pDebugName) :
1264 ObjectContactOfPageView(rPageWindow, pDebugName),
1265 mrRealObjectContact(rRealOC)
1266 {
1267 }
1268
1269 virtual bool supportsGridOffsets() const override { return true; }
1270
1271 virtual void calculateGridOffsetForViewOjectContact(
1272 basegfx::B2DVector& rTarget,
1273 const sdr::contact::ViewObjectContact& rClient) const override
1274 {
1275 SdrObject* pTargetSdrObject(rClient.GetViewContact().TryToGetSdrObject());
1276 if (pTargetSdrObject)
1277 rTarget = pTargetSdrObject->GetViewContact().GetViewObjectContact(mrRealObjectContact).getGridOffset();
1278 }
1279 };
1280
1281 class ScLOKDrawView : public FmFormView
1282 {
1283 public:
1284 ScLOKDrawView(OutputDevice* pOut, ScViewData& rData) :
1285 FmFormView(*rData.GetDocument().GetDrawLayer(), pOut),
1286 pScDrawView(rData.GetScDrawView())
1287 {
1288 }
1289
1290 virtual sdr::contact::ObjectContact* createViewSpecificObjectContact(
1291 SdrPageWindow& rPageWindow, const char* pDebugName) const override
1292 {
1293 if (!pScDrawView)
1294 return SdrView::createViewSpecificObjectContact(rPageWindow, pDebugName);
1295
1296 SdrPageView* pPageView(pScDrawView->GetSdrPageView());
1297 if (!pPageView)
1298 return SdrView::createViewSpecificObjectContact(rPageWindow, pDebugName);
1299
1300 SdrPageWindow* pSdrPageWindow = pPageView->GetPageWindow(0);
1301 if (!pSdrPageWindow)
1302 return SdrView::createViewSpecificObjectContact(rPageWindow, pDebugName);
1303
1304 return new ScLOKProxyObjectContact(pSdrPageWindow->GetObjectContact(), rPageWindow, pDebugName);
1305 }
1306
1307 private:
1308 ScDrawView* pScDrawView;
1309 };
1310} // anonymous namespace
1311
1312void ScGridWindow::PaintTile( VirtualDevice& rDevice,
1313 int nOutputWidth, int nOutputHeight,
1314 int nTilePosX, int nTilePosY,
1315 long nTileWidth, long nTileHeight )
1316{
1317 Fraction origZoomX = mrViewData.GetZoomX();
1318 Fraction origZoomY = mrViewData.GetZoomY();
1319
1320 // Output size is in pixels while tile position and size are in logical units (twips).
1321
1322 // Assumption: always paint the whole sheet i.e. "visible" range is always
1323 // from (0,0) to last data position.
1324
1325 // Tile geometry is independent of the zoom level, but the output size is
1326 // dependent of the zoom level. Determine the correct zoom level before
1327 // we start.
1328
1329 // FIXME the painting works using a mixture of drawing with coordinates in
1330 // pixels and in logic coordinates; it should be cleaned up to use logic
1331 // coords only, and avoid all the SetMapMode()'s.
1332 // Similarly to Writer, we should set the mapmode once on the rDevice, and
1333 // not care about any zoom settings.
1334
1335 Fraction aFracX(long(nOutputWidth * TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0)), nTileWidth);
1336 Fraction aFracY(long(nOutputHeight * TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0)), nTileHeight);
1337
1338 const bool bChangeZoom = (aFracX != origZoomX || aFracY != origZoomY);
1339
1340 // page break zoom, and aLogicMode in ScViewData
1341 // FIXME: there are issues when SetZoom is called conditionally.
1342 mrViewData.SetZoom(aFracX, aFracY, true);
1343 if (bChangeZoom)
1344 {
1345 if (ScDrawView* pDrawView = mrViewData.GetScDrawView())
1346 pDrawView->resetGridOffsetsForAllSdrPageViews();
1347 }
1348
1349 const double fTilePosXPixel = static_cast<double>(nTilePosX) * nOutputWidth / nTileWidth;
1350 const double fTilePosYPixel = static_cast<double>(nTilePosY) * nOutputHeight / nTileHeight;
1351 const double fTileBottomPixel = static_cast<double>(nTilePosY + nTileHeight) * nOutputHeight / nTileHeight;
1352 const double fTileRightPixel = static_cast<double>(nTilePosX + nTileWidth) * nOutputWidth / nTileWidth;
1353
1354 SCTAB nTab = mrViewData.GetTabNo();
1355 ScDocument& rDoc = mrViewData.GetDocument();
1356
1357 const double fPPTX = mrViewData.GetPPTX();
1358 const double fPPTY = mrViewData.GetPPTY();
1359
1360 // find approximate col/row offsets of nearby.
1361 sal_Int32 nTopLeftTileRowOffset = 0;
1362 sal_Int32 nTopLeftTileColOffset = 0;
1363 sal_Int32 nTopLeftTileRowOrigin = 0;
1364 sal_Int32 nTopLeftTileColOrigin = 0;
1365
1366 sal_Int32 nTopLeftTileRow = 0;
1367 sal_Int32 nTopLeftTileCol = 0;
1368 sal_Int32 nBottomRightTileRow = 0;
1369 sal_Int32 nBottomRightTileCol = 0;
1370
1371 lcl_getBoundingRowColumnforTile<SCROW>(mrViewData,
1372 fTilePosYPixel, fTileBottomPixel,
1373 nTopLeftTileRowOffset, nTopLeftTileRowOrigin,
1374 nTopLeftTileRow, nBottomRightTileRow);
1375
1376 lcl_getBoundingRowColumnforTile<SCCOL>(mrViewData,
1377 fTilePosXPixel, fTileRightPixel,
1378 nTopLeftTileColOffset, nTopLeftTileColOrigin,
1379 nTopLeftTileCol, nBottomRightTileCol);
1380
1381 // Enlarge
1382 nBottomRightTileCol++;
1383 nBottomRightTileRow++;
1384
1385 if (nBottomRightTileCol > rDoc.MaxCol())
1386 nBottomRightTileCol = rDoc.MaxCol();
1387
1388 if (nBottomRightTileRow > MAXTILEDROW)
1389 nBottomRightTileRow = MAXTILEDROW;
1390
1391 // size of the document including drawings, charts, etc.
1392 SCCOL nEndCol = 0;
1393 SCROW nEndRow = 0;
1394 rDoc.GetTiledRenderingArea(nTab, nEndCol, nEndRow);
1395
1396 if (nEndCol < nBottomRightTileCol)
1397 nEndCol = nBottomRightTileCol;
Value stored to 'nEndCol' is never read
1398
1399 if (nEndRow < nBottomRightTileRow)
1400 nEndRow = nBottomRightTileRow;
1401
1402 nTopLeftTileCol = std::max<sal_Int32>(nTopLeftTileCol, 0);
1403 nTopLeftTileRow = std::max<sal_Int32>(nTopLeftTileRow, 0);
1404 nTopLeftTileColOrigin = nTopLeftTileColOrigin * TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0);
1405 nTopLeftTileRowOrigin = nTopLeftTileRowOrigin * TWIPS_PER_PIXEL((20.0 * 72.0) / 96.0);
1406
1407 // Checkout -> 'rDoc.ExtendMerge' ... if we miss merged cells.
1408
1409 // Origin must be the offset of the first col and row
1410 // containing our top-left pixel.
1411 const MapMode aOriginalMode = rDevice.GetMapMode();
1412 MapMode aAbsMode = aOriginalMode;
1413 const Point aOrigin(-nTopLeftTileColOrigin, -nTopLeftTileRowOrigin);
1414 aAbsMode.SetOrigin(aOrigin);
1415 rDevice.SetMapMode(aAbsMode);
1416
1417 ScTableInfo aTabInfo(nEndRow + 3);
1418 rDoc.FillInfo(aTabInfo, nTopLeftTileCol, nTopLeftTileRow,
1419 nBottomRightTileCol, nBottomRightTileRow,
1420 nTab, fPPTX, fPPTY, false, false);
1421
1422// FIXME: is this called some
1423// Point aScrPos = mrViewData.GetScrPos( nX1, nY1, eWhich );
1424
1425 ScOutputData aOutputData(&rDevice, OUTTYPE_WINDOW, aTabInfo, &rDoc, nTab,
1426 -nTopLeftTileColOffset,
1427 -nTopLeftTileRowOffset,
1428 nTopLeftTileCol, nTopLeftTileRow,
1429 nBottomRightTileCol, nBottomRightTileRow,
1430 fPPTX, fPPTY, nullptr, nullptr);
1431
1432 // setup the SdrPage so that drawinglayer works correctly
1433 ScDrawLayer* pModel = rDoc.GetDrawLayer();
1434 if (pModel)
1435 {
1436 bool bPrintTwipsMsgs = comphelper::LibreOfficeKit::isCompatFlagSet(
1437 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
1438 mpLOKDrawView.reset(bPrintTwipsMsgs ?
1439 new ScLOKDrawView(
1440 &rDevice,
1441 mrViewData) :
1442 new FmFormView(
1443 *pModel,
1444 &rDevice));
1445 mpLOKDrawView->ShowSdrPage(mpLOKDrawView->GetModel()->GetPage(nTab));
1446 aOutputData.SetDrawView(mpLOKDrawView.get());
1447 aOutputData.SetSpellCheckContext(mpSpellCheckCxt.get());
1448 }
1449
1450 // draw the content
1451 DrawContent(rDevice, aTabInfo, aOutputData, true);
1452 rDevice.SetMapMode(aOriginalMode);
1453
1454 // Flag drawn formula cells "unchanged".
1455 rDoc.ResetChanged(ScRange(nTopLeftTileCol, nTopLeftTileRow, nTab, nBottomRightTileCol, nBottomRightTileRow, nTab));
1456 rDoc.PrepareFormulaCalc();
1457
1458 mrViewData.SetZoom(origZoomX, origZoomY, true);
1459 if (bChangeZoom)
1460 {
1461 if (ScDrawView* pDrawView = mrViewData.GetScDrawView())
1462 pDrawView->resetGridOffsetsForAllSdrPageViews();
1463 }
1464}
1465
1466void ScGridWindow::LogicInvalidate(const tools::Rectangle* pRectangle)
1467{
1468 OString sRectangle;
1469 if (!pRectangle)
1470 sRectangle = "EMPTY";
1471 else
1472 {
1473 tools::Rectangle aRectangle(*pRectangle);
1474 // When dragging shapes the map mode is disabled.
1475 if (IsMapModeEnabled())
1476 {
1477 if (GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
1478 aRectangle = OutputDevice::LogicToLogic(aRectangle, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
1479 }
1480 else
1481 aRectangle = PixelToLogic(aRectangle, MapMode(MapUnit::MapTwip));
1482 sRectangle = aRectangle.toString();
1483 }
1484
1485 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
1486 SfxLokHelper::notifyInvalidation(pViewShell, sRectangle);
1487}
1488
1489void ScGridWindow::SetCellSelectionPixel(int nType, int nPixelX, int nPixelY)
1490{
1491 ScTabView* pTabView = mrViewData.GetView();
1492 ScTabViewShell* pViewShell = mrViewData.GetViewShell();
1493 ScInputHandler* pInputHandler = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetInputHdl(pViewShell);
1494
1495 if (pInputHandler && pInputHandler->IsInputMode())
1496 {
1497 // we need to switch off the editeng
1498 ScTabView::UpdateInputLine();
1499 pViewShell->UpdateInputHandler();
1500 }
1501
1502 if (nType == LOK_SETTEXTSELECTION_RESET)
1503 {
1504 pTabView->DoneBlockMode();
1505 return;
1506 }
1507
1508 // obtain the current selection
1509 ScRangeList aRangeList = mrViewData.GetMarkData().GetMarkedRanges();
1510
1511 SCCOL nCol1, nCol2;
1512 SCROW nRow1, nRow2;
1513 SCTAB nTab1, nTab2;
1514
1515 bool bWasEmpty = false;
1516 if (aRangeList.empty())
1517 {
1518 nCol1 = nCol2 = mrViewData.GetCurX();
1519 nRow1 = nRow2 = mrViewData.GetCurY();
1520 bWasEmpty = true;
1521 }
1522 else
1523 aRangeList.Combine().GetVars(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
1524
1525 // convert the coordinates to column/row
1526 SCCOL nNewPosX;
1527 SCROW nNewPosY;
1528 SCTAB nTab = mrViewData.GetTabNo();
1529 mrViewData.GetPosFromPixel(nPixelX, nPixelY, eWhich, nNewPosX, nNewPosY);
1530
1531 // change the selection
1532 switch (nType)
1533 {
1534 case LOK_SETTEXTSELECTION_START:
1535 if (nNewPosX != nCol1 || nNewPosY != nRow1 || bWasEmpty)
1536 {
1537 pTabView->SetCursor(nNewPosX, nNewPosY);
1538 pTabView->DoneBlockMode();
1539 pTabView->InitBlockMode(nNewPosX, nNewPosY, nTab, true);
1540 pTabView->MarkCursor(nCol2, nRow2, nTab);
1541 }
1542 break;
1543 case LOK_SETTEXTSELECTION_END:
1544 if (nNewPosX != nCol2 || nNewPosY != nRow2 || bWasEmpty)
1545 {
1546 pTabView->SetCursor(nCol1, nRow1);
1547 pTabView->DoneBlockMode();
1548 pTabView->InitBlockMode(nCol1, nRow1, nTab, true);
1549 pTabView->MarkCursor(nNewPosX, nNewPosY, nTab);
1550 }
1551 break;
1552 default:
1553 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", "/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin4.cxx"
, 1553, __extension__ __PRETTY_FUNCTION__))
;
1554 break;
1555 }
1556}
1557
1558void ScGridWindow::CheckNeedsRepaint()
1559{
1560 // called at the end of painting, and from timer after background text width calculation
1561
1562 if (!bNeedsRepaint)
1563 return;
1564
1565 bNeedsRepaint = false;
1566 if (aRepaintPixel.IsEmpty())
1567 Invalidate();
1568 else
1569 Invalidate(PixelToLogic(aRepaintPixel));
1570 aRepaintPixel = tools::Rectangle();
1571
1572 // selection function in status bar might also be invalid
1573 SfxBindings& rBindings = mrViewData.GetBindings();
1574 rBindings.Invalidate( SID_STATUS_SUM((26000 + 100) + 30) );
1575 rBindings.Invalidate( SID_ATTR_SIZETypedWhichId<SvxSizeItem>( 10000 + 224 ) );
1576 rBindings.Invalidate( SID_TABLE_CELL( 10000 + 225 ) );
1577}
1578
1579void ScGridWindow::DrawPagePreview( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, vcl::RenderContext& rRenderContext)
1580{
1581 ScPageBreakData* pPageData = mrViewData.GetView()->GetPageBreakData();
1582 if (!pPageData)
1583 return;
1584
1585 ScDocument& rDoc = mrViewData.GetDocument();
1586 SCTAB nTab = mrViewData.GetTabNo();
1587 Size aWinSize = GetOutputSizePixel();
1588 const svtools::ColorConfig& rColorCfg = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetColorConfig();
1589 Color aManual( rColorCfg.GetColorValue(svtools::CALCPAGEBREAKMANUAL).nColor );
1590 Color aAutomatic( rColorCfg.GetColorValue(svtools::CALCPAGEBREAK).nColor );
1591
1592 OUString aPageStr = ScResId( STR_PGNUMreinterpret_cast<char const *>("STR_PGNUM" "\004" u8"Page %1"
)
);
1593 if ( nPageScript == SvtScriptType::NONE )
1594 {
1595 // get script type of translated "Page" string only once
1596 nPageScript = rDoc.GetStringScriptType( aPageStr );
1597 if (nPageScript == SvtScriptType::NONE)
1598 nPageScript = ScGlobal::GetDefaultScriptType();
1599 }
1600
1601 vcl::Font aFont;
1602 std::unique_ptr<ScEditEngineDefaulter> pEditEng;
1603 const ScPatternAttr& rDefPattern = rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN);
1604 if ( nPageScript == SvtScriptType::LATIN )
1605 {
1606 // use single font and call DrawText directly
1607 rDefPattern.GetFont( aFont, SC_AUTOCOL_BLACK );
1608 aFont.SetColor( COL_LIGHTGRAY );
1609 // font size is set as needed
1610 }
1611 else
1612 {
1613 // use EditEngine to draw mixed-script string
1614 pEditEng.reset(new ScEditEngineDefaulter( EditEngine::CreatePool(), true ));
1615 pEditEng->SetRefMapMode(rRenderContext.GetMapMode());
1616 auto pEditDefaults = std::make_unique<SfxItemSet>( pEditEng->GetEmptyItemSet() );
1617 rDefPattern.FillEditItemSet( pEditDefaults.get() );
1618 pEditDefaults->Put( SvxColorItem( COL_LIGHTGRAY, EE_CHAR_COLOR ) );
1619 pEditEng->SetDefaults( std::move(pEditDefaults) );
1620 }
1621
1622 sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( pPageData->GetCount() );
1623 for (sal_uInt16 nPos=0; nPos<nCount; nPos++)
1624 {
1625 ScPrintRangeData& rData = pPageData->GetData(nPos);
1626 ScRange aRange = rData.GetPrintRange();
1627 if ( aRange.aStart.Col() <= nX2+1 && aRange.aEnd.Col()+1 >= nX1 &&
1628 aRange.aStart.Row() <= nY2+1 && aRange.aEnd.Row()+1 >= nY1 )
1629 {
1630 // 3 pixel frame around the print area
1631 // (middle pixel on the grid lines)
1632
1633 rRenderContext.SetLineColor();
1634 if (rData.IsAutomatic())
1635 rRenderContext.SetFillColor( aAutomatic );
1636 else
1637 rRenderContext.SetFillColor( aManual );
1638
1639 Point aStart = mrViewData.GetScrPos(
1640 aRange.aStart.Col(), aRange.aStart.Row(), eWhich, true );
1641 Point aEnd = mrViewData.GetScrPos(
1642 aRange.aEnd.Col() + 1, aRange.aEnd.Row() + 1, eWhich, true );
1643 aStart.AdjustX( -2 );
1644 aStart.AdjustY( -2 );
1645
1646 // Prevent overflows:
1647 if ( aStart.X() < -10 ) aStart.setX( -10 );
1648 if ( aStart.Y() < -10 ) aStart.setY( -10 );
1649 if ( aEnd.X() > aWinSize.Width() + 10 )
1650 aEnd.setX( aWinSize.Width() + 10 );
1651 if ( aEnd.Y() > aWinSize.Height() + 10 )
1652 aEnd.setY( aWinSize.Height() + 10 );
1653
1654 rRenderContext.DrawRect( tools::Rectangle( aStart, Point(aEnd.X(),aStart.Y()+2) ) );
1655 rRenderContext.DrawRect( tools::Rectangle( aStart, Point(aStart.X()+2,aEnd.Y()) ) );
1656 rRenderContext.DrawRect( tools::Rectangle( Point(aStart.X(),aEnd.Y()-2), aEnd ) );
1657 rRenderContext.DrawRect( tools::Rectangle( Point(aEnd.X()-2,aStart.Y()), aEnd ) );
1658
1659 // Page breaks
1660 //! Display differently (dashed ????)
1661
1662 size_t nColBreaks = rData.GetPagesX();
1663 const SCCOL* pColEnd = rData.GetPageEndX();
1664 size_t nColPos;
1665 for (nColPos=0; nColPos+1<nColBreaks; nColPos++)
1666 {
1667 SCCOL nBreak = pColEnd[nColPos]+1;
1668 if ( nBreak >= nX1 && nBreak <= nX2+1 )
1669 {
1670 //! Search for hidden
1671 if (rDoc.HasColBreak(nBreak, nTab) & ScBreakType::Manual)
1672 rRenderContext.SetFillColor( aManual );
1673 else
1674 rRenderContext.SetFillColor( aAutomatic );
1675 Point aBreak = mrViewData.GetScrPos(
1676 nBreak, aRange.aStart.Row(), eWhich, true );
1677 rRenderContext.DrawRect( tools::Rectangle( aBreak.X()-1, aStart.Y(), aBreak.X(), aEnd.Y() ) );
1678 }
1679 }
1680
1681 size_t nRowBreaks = rData.GetPagesY();
1682 const SCROW* pRowEnd = rData.GetPageEndY();
1683 size_t nRowPos;
1684 for (nRowPos=0; nRowPos+1<nRowBreaks; nRowPos++)
1685 {
1686 SCROW nBreak = pRowEnd[nRowPos]+1;
1687 if ( nBreak >= nY1 && nBreak <= nY2+1 )
1688 {
1689 //! Search for hidden
1690 if (rDoc.HasRowBreak(nBreak, nTab) & ScBreakType::Manual)
1691 rRenderContext.SetFillColor( aManual );
1692 else
1693 rRenderContext.SetFillColor( aAutomatic );
1694 Point aBreak = mrViewData.GetScrPos(
1695 aRange.aStart.Col(), nBreak, eWhich, true );
1696 rRenderContext.DrawRect( tools::Rectangle( aStart.X(), aBreak.Y()-1, aEnd.X(), aBreak.Y() ) );
1697 }
1698 }
1699
1700 // Page numbers
1701
1702 SCROW nPrStartY = aRange.aStart.Row();
1703 for (nRowPos=0; nRowPos<nRowBreaks; nRowPos++)
1704 {
1705 SCROW nPrEndY = pRowEnd[nRowPos];
1706 if ( nPrEndY >= nY1 && nPrStartY <= nY2 )
1707 {
1708 SCCOL nPrStartX = aRange.aStart.Col();
1709 for (nColPos=0; nColPos<nColBreaks; nColPos++)
1710 {
1711 SCCOL nPrEndX = pColEnd[nColPos];
1712 if ( nPrEndX >= nX1 && nPrStartX <= nX2 )
1713 {
1714 Point aPageStart = mrViewData.GetScrPos(
1715 nPrStartX, nPrStartY, eWhich, true );
1716 Point aPageEnd = mrViewData.GetScrPos(
1717 nPrEndX+1,nPrEndY+1, eWhich, true );
1718
1719 long nPageNo = rData.GetFirstPage();
1720 if ( rData.IsTopDown() )
1721 nPageNo += static_cast<long>(nColPos)*nRowBreaks+nRowPos;
1722 else
1723 nPageNo += static_cast<long>(nRowPos)*nColBreaks+nColPos;
1724
1725 OUString aThisPageStr = aPageStr.replaceFirst("%1", OUString::number(nPageNo));
1726
1727 if ( pEditEng )
1728 {
1729 // find right font size with EditEngine
1730 long nHeight = 100;
1731 pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
1732 pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
1733 pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) );
1734 pEditEng->SetTextCurrentDefaults( aThisPageStr );
1735 Size aSize100( pEditEng->CalcTextWidth(), pEditEng->GetTextHeight() );
1736
1737 // 40% of width or 60% of height
1738 long nSizeX = 40 * ( aPageEnd.X() - aPageStart.X() ) / aSize100.Width();
1739 long nSizeY = 60 * ( aPageEnd.Y() - aPageStart.Y() ) / aSize100.Height();
1740 nHeight = std::min(nSizeX,nSizeY);
1741 pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
1742 pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
1743 pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) );
1744
1745 // centered output with EditEngine
1746 Size aTextSize( pEditEng->CalcTextWidth(), pEditEng->GetTextHeight() );
1747 Point aPos( (aPageStart.X()+aPageEnd.X()-aTextSize.Width())/2,
1748 (aPageStart.Y()+aPageEnd.Y()-aTextSize.Height())/2 );
1749 pEditEng->Draw( &rRenderContext, aPos );
1750 }
1751 else
1752 {
1753 // find right font size for DrawText
1754 aFont.SetFontSize( Size( 0,100 ) );
1755 rRenderContext.SetFont( aFont );
1756 Size aSize100(rRenderContext.GetTextWidth( aThisPageStr ), rRenderContext.GetTextHeight() );
1757
1758 // 40% of width or 60% of height
1759 long nSizeX = 40 * ( aPageEnd.X() - aPageStart.X() ) / aSize100.Width();
1760 long nSizeY = 60 * ( aPageEnd.Y() - aPageStart.Y() ) / aSize100.Height();
1761 aFont.SetFontSize( Size( 0,std::min(nSizeX,nSizeY) ) );
1762 rRenderContext.SetFont( aFont );
1763
1764 // centered output with DrawText
1765 Size aTextSize(rRenderContext.GetTextWidth( aThisPageStr ), rRenderContext.GetTextHeight() );
1766 Point aPos( (aPageStart.X()+aPageEnd.X()-aTextSize.Width())/2,
1767 (aPageStart.Y()+aPageEnd.Y()-aTextSize.Height())/2 );
1768 rRenderContext.DrawText( aPos, aThisPageStr );
1769 }
1770 }
1771 nPrStartX = nPrEndX + 1;
1772 }
1773 }
1774 nPrStartY = nPrEndY + 1;
1775 }
1776 }
1777 }
1778}
1779
1780void ScGridWindow::DrawButtons(SCCOL nX1, SCCOL nX2, const ScTableInfo& rTabInfo, OutputDevice* pContentDev)
1781{
1782 aComboButton.SetOutputDevice( pContentDev );
1783
1784 ScDocument& rDoc = mrViewData.GetDocument();
1785 ScDPFieldButton aCellBtn(pContentDev, &GetSettings().GetStyleSettings(), &mrViewData.GetZoomY(), &rDoc);
1786
1787 SCCOL nCol;
1788 SCROW nRow;
1789 SCSIZE nArrY;
1790 SCSIZE nQuery;
1791 SCTAB nTab = mrViewData.GetTabNo();
1792 ScDBData* pDBData = nullptr;
1793 std::unique_ptr<ScQueryParam> pQueryParam;
1794
1795 RowInfo* pRowInfo = rTabInfo.mpRowInfo.get();
1796 sal_uInt16 nArrCount = rTabInfo.mnArrCount;
1797
1798 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
1799
1800 Point aOldPos = aComboButton.GetPosPixel(); // store state for MouseDown/Up
1801 Size aOldSize = aComboButton.GetSizePixel();
1802
1803 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
1804 {
1805 if ( pRowInfo[nArrY].bAutoFilter && pRowInfo[nArrY].bChanged )
1806 {
1807 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1808
1809 nRow = pThisRowInfo->nRowNo;
1810
1811 for (nCol=nX1; nCol<=nX2; nCol++)
1812 {
1813 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nCol+1];
1814 //if several columns merged on a row, there should be only one auto button at the end of the columns.
1815 //if several rows merged on a column, the button may be in the middle, so "!pInfo->bVOverlapped" should not be used
1816 if ( pInfo->bAutoFilter && !pInfo->bHOverlapped )
1817 {
1818 if (!pQueryParam)
1819 pQueryParam.reset(new ScQueryParam);
1820
1821 bool bNewData = true;
1822 if (pDBData)
1823 {
1824 SCCOL nStartCol;
1825 SCROW nStartRow;
1826 SCCOL nEndCol;
1827 SCROW nEndRow;
1828 SCTAB nAreaTab;
1829 pDBData->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
1830 if ( nCol >= nStartCol && nCol <= nEndCol &&
1831 nRow >= nStartRow && nRow <= nEndRow )
1832 bNewData = false;
1833 }
1834 if (bNewData)
1835 {
1836 pDBData = rDoc.GetDBAtCursor( nCol, nRow, nTab, ScDBDataPortion::AREA );
1837 if (pDBData)
1838 pDBData->GetQueryParam( *pQueryParam );
1839 else
1840 {
1841 // can also be part of DataPilot table
1842 }
1843 }
1844
1845 // pQueryParam can only include MAXQUERY entries
1846
1847 bool bSimpleQuery = true;
1848 bool bColumnFound = false;
1849 if (!pQueryParam->bInplace)
1850 bSimpleQuery = false;
1851 SCSIZE nCount = pQueryParam->GetEntryCount();
1852 for (nQuery = 0; nQuery < nCount && bSimpleQuery; ++nQuery)
1853 if (pQueryParam->GetEntry(nQuery).bDoQuery)
1854 {
1855 // Do no restrict to EQUAL here
1856 // (Column head should become blue also when ">1")
1857
1858 if (pQueryParam->GetEntry(nQuery).nField == nCol)
1859 bColumnFound = true;
1860 if (nQuery > 0)
1861 if (pQueryParam->GetEntry(nQuery).eConnect != SC_AND)
1862 bSimpleQuery = false;
1863 }
1864
1865 bool bArrowState = bSimpleQuery && bColumnFound;
1866 long nSizeX;
1867 long nSizeY;
1868 SCCOL nStartCol= nCol;
1869 SCROW nStartRow = nRow;
1870 //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.
1871 //should first get the start pos of the merge area, then get the nSizeX through the start pos.
1872 rDoc.ExtendOverlapped(nStartCol, nStartRow,nCol, nRow, nTab);//get nStartCol,nStartRow
1873 mrViewData.GetMergeSizePixel( nStartCol, nStartRow, nSizeX, nSizeY );//get nSizeX
1874 nSizeY = ScViewData::ToPixel(rDoc.GetRowHeight(nRow, nTab), mrViewData.GetPPTY());
1875 Point aScrPos = mrViewData.GetScrPos( nCol, nRow, eWhich );
1876
1877 aCellBtn.setBoundingBox(aScrPos, Size(nSizeX-1, nSizeY-1), bLayoutRTL);
1878 aCellBtn.setPopupLeft(bLayoutRTL); // #i114944# AutoFilter button is left-aligned in RTL
1879 aCellBtn.setDrawBaseButton(false);
1880 aCellBtn.setDrawPopupButton(true);
1881 aCellBtn.setHasHiddenMember(bArrowState);
1882 aCellBtn.draw();
1883 }
1884 }
1885 }
1886
1887 if ( pRowInfo[nArrY].bPivotButton && pRowInfo[nArrY].bChanged )
1888 {
1889 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1890 nRow = pThisRowInfo->nRowNo;
1891 for (nCol=nX1; nCol<=nX2; nCol++)
1892 {
1893 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nCol+1];
1894 if (pInfo->bHOverlapped || pInfo->bVOverlapped)
1895 continue;
1896
1897 Point aScrPos = mrViewData.GetScrPos( nCol, nRow, eWhich );
1898 long nSizeX;
1899 long nSizeY;
1900 mrViewData.GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
1901 long nPosX = aScrPos.X();
1902 long nPosY = aScrPos.Y();
1903 // bLayoutRTL is handled in setBoundingBox
1904
1905 OUString aStr = rDoc.GetString(nCol, nRow, nTab);
1906 aCellBtn.setText(aStr);
1907 aCellBtn.setBoundingBox(Point(nPosX, nPosY), Size(nSizeX-1, nSizeY-1), bLayoutRTL);
1908 aCellBtn.setPopupLeft(false); // DataPilot popup is always right-aligned for now
1909 aCellBtn.setDrawBaseButton(pInfo->bPivotButton);
1910 aCellBtn.setDrawPopupButton(pInfo->bPivotPopupButton);
1911 aCellBtn.setHasHiddenMember(pInfo->bFilterActive);
1912 aCellBtn.draw();
1913 }
1914 }
1915
1916 if ( !comphelper::LibreOfficeKit::isActive() && bListValButton && pRowInfo[nArrY].nRowNo == aListValPos.Row() && pRowInfo[nArrY].bChanged )
1917 {
1918 tools::Rectangle aRect = GetListValButtonRect( aListValPos );
1919 aComboButton.SetPosPixel( aRect.TopLeft() );
1920 aComboButton.SetSizePixel( aRect.GetSize() );
1921 pContentDev->SetClipRegion(vcl::Region(aRect));
1922 aComboButton.Draw();
1923 pContentDev->SetClipRegion(); // always called from Draw() without clip region
1924 aComboButton.SetPosPixel( aOldPos ); // restore old state
1925 aComboButton.SetSizePixel( aOldSize ); // for MouseUp/Down (AutoFilter)
1926 }
1927 }
1928
1929 pQueryParam.reset();
1930 aComboButton.SetOutputDevice( this );
1931}
1932
1933tools::Rectangle ScGridWindow::GetListValButtonRect( const ScAddress& rButtonPos )
1934{
1935 ScDocument& rDoc = mrViewData.GetDocument();
1936 SCTAB nTab = mrViewData.GetTabNo();
1937 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
1938 long nLayoutSign = bLayoutRTL ? -1 : 1;
1939
1940 ScDDComboBoxButton aButton( this ); // for optimal size
1941 Size aBtnSize = aButton.GetSizePixel();
1942
1943 SCCOL nCol = rButtonPos.Col();
1944 SCROW nRow = rButtonPos.Row();
1945
1946 long nCellSizeX; // width of this cell, including merged
1947 long nDummy;
1948 mrViewData.GetMergeSizePixel( nCol, nRow, nCellSizeX, nDummy );
1949
1950 // for height, only the cell's row is used, excluding merged cells
1951 long nCellSizeY = ScViewData::ToPixel( rDoc.GetRowHeight( nRow, nTab ), mrViewData.GetPPTY() );
1952 long nAvailable = nCellSizeX;
1953
1954 // left edge of next cell if there is a non-hidden next column
1955 SCCOL nNextCol = nCol + 1;
1956 const ScMergeAttr* pMerge = rDoc.GetAttr( nCol,nRow,nTab, ATTR_MERGE );
1957 if ( pMerge->GetColMerge() > 1 )
1958 nNextCol = nCol + pMerge->GetColMerge(); // next cell after the merged area
1959 while ( nNextCol <= rDoc.MaxCol() && rDoc.ColHidden(nNextCol, nTab) )
1960 ++nNextCol;
1961 bool bNextCell = ( nNextCol <= rDoc.MaxCol() );
1962 if ( bNextCell )
1963 nAvailable = ScViewData::ToPixel( rDoc.GetColWidth( nNextCol, nTab ), mrViewData.GetPPTX() );
1964
1965 if ( nAvailable < aBtnSize.Width() )
1966 aBtnSize.setWidth( nAvailable );
1967 if ( nCellSizeY < aBtnSize.Height() )
1968 aBtnSize.setHeight( nCellSizeY );
1969
1970 Point aPos = mrViewData.GetScrPos( nCol, nRow, eWhich, true );
1971 aPos.AdjustX(nCellSizeX * nLayoutSign ); // start of next cell
1972 if (!bNextCell)
1973 aPos.AdjustX( -(aBtnSize.Width() * nLayoutSign) ); // right edge of cell if next cell not available
1974 aPos.AdjustY(nCellSizeY - aBtnSize.Height() );
1975 // X remains at the left edge
1976
1977 if ( bLayoutRTL )
1978 aPos.AdjustX( -(aBtnSize.Width()-1) ); // align right edge of button with cell border
1979
1980 return tools::Rectangle( aPos, aBtnSize );
1981}
1982
1983bool ScGridWindow::IsAutoFilterActive( SCCOL nCol, SCROW nRow, SCTAB nTab )
1984{
1985 ScDocument& rDoc = mrViewData.GetDocument();
1986 ScDBData* pDBData = rDoc.GetDBAtCursor( nCol, nRow, nTab, ScDBDataPortion::AREA );
1987 ScQueryParam aQueryParam;
1988
1989 if ( pDBData )
1990 pDBData->GetQueryParam( aQueryParam );
1991 else
1992 {
1993 OSL_FAIL("Auto filter button without DBData")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/view/gridwin4.cxx"
":" "1993" ": "), "%s", "Auto filter button without DBData")
; } } while (false)
;
1994 }
1995
1996 bool bSimpleQuery = true;
1997 bool bColumnFound = false;
1998 SCSIZE nQuery;
1999
2000 if ( !aQueryParam.bInplace )
2001 bSimpleQuery = false;
2002
2003 // aQueryParam can only include MAXQUERY entries
2004
2005 SCSIZE nCount = aQueryParam.GetEntryCount();
2006 for (nQuery = 0; nQuery < nCount && bSimpleQuery; ++nQuery)
2007 if ( aQueryParam.GetEntry(nQuery).bDoQuery )
2008 {
2009 if (aQueryParam.GetEntry(nQuery).nField == nCol)
2010 bColumnFound = true;
2011
2012 if (nQuery > 0)
2013 if (aQueryParam.GetEntry(nQuery).eConnect != SC_AND)
2014 bSimpleQuery = false;
2015 }
2016
2017 return ( bSimpleQuery && bColumnFound );
2018}
2019
2020void ScGridWindow::GetSelectionRects( ::std::vector< tools::Rectangle >& rPixelRects ) const
2021{
2022 GetPixelRectsFor( mrViewData.GetMarkData(), rPixelRects );
2023}
2024
2025void ScGridWindow::GetSelectionRectsPrintTwips(::std::vector< tools::Rectangle >& rRects) const
2026{
2027 GetRectsAnyFor(mrViewData.GetMarkData(), rRects, true);
2028}
2029
2030/// convert rMarkData into pixel rectangles for this view
2031void ScGridWindow::GetPixelRectsFor( const ScMarkData &rMarkData,
2032 ::std::vector< tools::Rectangle >& rPixelRects ) const
2033{
2034 GetRectsAnyFor(rMarkData, rPixelRects, false);
2035}
2036
2037void ScGridWindow::GetRectsAnyFor(const ScMarkData &rMarkData,
2038 ::std::vector< tools::Rectangle >& rRects,
2039 bool bInPrintTwips) const
2040{
2041 ScMarkData aMultiMark( rMarkData );
2042 aMultiMark.SetMarking( false );
2043 aMultiMark.MarkToMulti();
2044 ScDocument& rDoc = mrViewData.GetDocument();
2045 SCTAB nTab = mrViewData.GetTabNo();
2046
2047 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
2048 long nLayoutSign = bLayoutRTL ? -1 : 1;
2049 if ( !aMultiMark.IsMultiMarked() )
2050 return;
2051 ScRange aMultiRange;
2052 aMultiMark.GetMultiMarkArea( aMultiRange );
2053 SCCOL nX1 = aMultiRange.aStart.Col();
2054 SCROW nY1 = aMultiRange.aStart.Row();
2055 SCCOL nX2 = aMultiRange.aEnd.Col();
2056 SCROW nY2 = aMultiRange.aEnd.Row();
2057
2058 PutInOrder( nX1, nX2 );
2059 PutInOrder( nY1, nY2 );
2060
2061 SCCOL nTestX2 = nX2;
2062 SCROW nTestY2 = nY2;
2063
2064 rDoc.ExtendMerge( nX1,nY1, nTestX2,nTestY2, nTab );
2065
2066 SCCOL nPosX = mrViewData.GetPosX( eHWhich );
2067 SCROW nPosY = mrViewData.GetPosY( eVWhich );
2068 // is the selection visible at all?
2069 if (nTestX2 < nPosX || nTestY2 < nPosY)
2070 return;
2071 SCCOL nRealX1 = nX1;
2072 if (nX1 < nPosX)
2073 nX1 = nPosX;
2074 if (nY1 < nPosY)
2075 nY1 = nPosY;
2076
2077 if (!comphelper::LibreOfficeKit::isActive())
2078 {
2079 // limit the selection to only what is visible on the screen
2080 SCCOL nXRight = nPosX + mrViewData.VisibleCellsX(eHWhich);
2081 if (nXRight > rDoc.MaxCol())
2082 nXRight = rDoc.MaxCol();
2083
2084 SCROW nYBottom = nPosY + mrViewData.VisibleCellsY(eVWhich);
2085 if (nYBottom > rDoc.MaxRow())
2086 nYBottom = rDoc.MaxRow();
2087
2088 // is the selection visible at all?
2089 if (nX1 > nXRight || nY1 > nYBottom)
2090 return;
2091
2092 if (nX2 > nXRight)
2093 nX2 = nXRight;
2094 if (nY2 > nYBottom)
2095 nY2 = nYBottom;
2096 }
2097 else
2098 {
2099 SCCOL nMaxTiledCol;
2100 SCROW nMaxTiledRow;
2101 rDoc.GetTiledRenderingArea(nTab, nMaxTiledCol, nMaxTiledRow);
2102
2103 if (nX2 > nMaxTiledCol)
2104 nX2 = nMaxTiledCol;
2105 if (nY2 > nMaxTiledRow)
2106 nY2 = nMaxTiledRow;
2107 }
2108
2109 double nPPTX = mrViewData.GetPPTX();
2110 double nPPTY = mrViewData.GetPPTY();
2111
2112 ScInvertMerger aInvert( &rRects );
2113
2114 Point aScrPos = bInPrintTwips ? mrViewData.GetPrintTwipsPos(nX1, nY1) :
2115 mrViewData.GetScrPos(nX1, nY1, eWhich);
2116 long nScrY = aScrPos.Y();
2117 bool bWasHidden = false;
2118 for (SCROW nY=nY1; nY<=nY2; nY++)
2119 {
2120 bool bFirstRow = ( nY == nPosY ); // first visible row?
2121 bool bDoHidden = false; // repeat hidden ?
2122 sal_uInt16 nHeightTwips = rDoc.GetRowHeight( nY,nTab );
2123 bool bDoRow = ( nHeightTwips != 0 );
2124 if (bDoRow)
2125 {
2126 if (bWasHidden) // test hidden merge
2127 {
2128 bDoHidden = true;
2129 bDoRow = true;
2130 }
2131
2132 bWasHidden = false;
2133 }
2134 else
2135 {
2136 bWasHidden = true;
2137 if (nY==nY2)
2138 bDoRow = true; // last cell of the block
2139 }
2140
2141 if ( bDoRow )
2142 {
2143 SCCOL nLoopEndX = nX2;
2144 if (nX2 < nX1) // the rest of the merge
2145 {
2146 SCCOL nStartX = nX1;
2147 while ( rDoc.GetAttr(nStartX,nY,nTab,ATTR_MERGE_FLAG)->IsHorOverlapped() )
2148 --nStartX;
2149 if (nStartX <= nX2)
2150 nLoopEndX = nX1;
2151 }
2152
2153 const long nHeight = bInPrintTwips ?
2154 nHeightTwips : ScViewData::ToPixel(nHeightTwips, nPPTY);
2155 long nEndY = nScrY + nHeight - 1;
2156 long nScrX = aScrPos.X();
2157 for (SCCOL nX=nX1; nX<=nLoopEndX; nX++)
2158 {
2159 long nWidth = rDoc.GetColWidth(nX, nTab);
2160 if (!bInPrintTwips)
2161 nWidth = ScViewData::ToPixel(nWidth, nPPTX);
2162
2163 if ( nWidth > 0 )
2164 {
2165 long nEndX = nScrX + ( nWidth - 1 ) * nLayoutSign;
2166
2167 SCROW nThisY = nY;
2168 const ScPatternAttr* pPattern = rDoc.GetPattern( nX, nY, nTab );
2169 const ScMergeFlagAttr* pMergeFlag = &pPattern->GetItem(ATTR_MERGE_FLAG);
2170 if ( pMergeFlag->IsVerOverlapped() && ( bDoHidden || bFirstRow ) )
2171 {
2172 while ( pMergeFlag->IsVerOverlapped() && nThisY > 0 &&
2173 (rDoc.RowHidden(nThisY-1, nTab) || bFirstRow) )
2174 {
2175 --nThisY;
2176 pPattern = rDoc.GetPattern( nX, nThisY, nTab );
2177 pMergeFlag = &pPattern->GetItem(ATTR_MERGE_FLAG);
2178 }
2179 }
2180
2181 // only the rest of the merged is seen ?
2182 SCCOL nThisX = nX;
2183 if ( pMergeFlag->IsHorOverlapped() && nX == nPosX && nX > nRealX1 )
2184 {
2185 while ( pMergeFlag->IsHorOverlapped() )
2186 {
2187 --nThisX;
2188 pPattern = rDoc.GetPattern( nThisX, nThisY, nTab );
2189 pMergeFlag = &pPattern->GetItem(ATTR_MERGE_FLAG);
2190 }
2191 }
2192
2193 if ( aMultiMark.IsCellMarked( nThisX, nThisY, true ) )
2194 {
2195 if ( !pMergeFlag->IsOverlapped() )
2196 {
2197 const ScMergeAttr* pMerge = &pPattern->GetItem(ATTR_MERGE);
2198 if (pMerge->GetColMerge() > 0 || pMerge->GetRowMerge() > 0)
2199 {
2200 const SCCOL nEndColMerge = nThisX + pMerge->GetColMerge();
2201 const SCROW nEndRowMerge = nThisY + pMerge->GetRowMerge();
2202 Point aEndPos = bInPrintTwips ?
2203 mrViewData.GetPrintTwipsPos(nEndColMerge, nEndRowMerge) :
2204 mrViewData.GetScrPos(nEndColMerge, nEndRowMerge, eWhich);
2205 if ( aEndPos.X() * nLayoutSign > nScrX * nLayoutSign && aEndPos.Y() > nScrY )
2206 {
2207 aInvert.AddRect( tools::Rectangle( nScrX,nScrY,
2208 aEndPos.X()-nLayoutSign,aEndPos.Y()-1 ) );
2209 }
2210 }
2211 else if ( nEndX * nLayoutSign >= nScrX * nLayoutSign && nEndY >= nScrY )
2212 {
2213 aInvert.AddRect( tools::Rectangle( nScrX,nScrY,nEndX,nEndY ) );
2214 }
2215 }
2216 }
2217
2218 nScrX = nEndX + nLayoutSign;
2219 }
2220 }
2221 nScrY = nEndY + 1;
2222 }
2223 }
2224}
2225
2226void ScGridWindow::DataChanged( const DataChangedEvent& rDCEvt )
2227{
2228 Window::DataChanged(rDCEvt);
2229
2230 if ( !((rDCEvt.GetType() == DataChangedEventType::PRINTER) ||
2231 (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
2232 (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
2233 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
2234 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
2235 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))) )
2236 return;
2237
2238 if ( rDCEvt.GetType() == DataChangedEventType::FONTS && eWhich == mrViewData.GetActivePart() )
2239 mrViewData.GetDocShell()->UpdateFontList();
2240
2241 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
2242 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
2243 {
2244 if ( eWhich == mrViewData.GetActivePart() ) // only once for the view
2245 {
2246 ScTabView* pView = mrViewData.GetView();
2247
2248 pView->RecalcPPT();
2249
2250 // RepeatResize in case scroll bar sizes have changed
2251 pView->RepeatResize();
2252 pView->UpdateAllOverlays();
2253
2254 // invalidate cell attribs in input handler, in case the
2255 // EditEngine BackgroundColor has to be changed
2256 if ( mrViewData.IsActive() )
2257 {
2258 ScInputHandler* pHdl = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetInputHdl();
2259 if (pHdl)
2260 pHdl->ForgetLastPattern();
2261 }
2262 }
2263 }
2264
2265 Invalidate();
2266}
2267
2268/* vim:set shiftwidth=4 softtabstop=4 expandtab: */