LibreOffice Module sc (master) 1
viewdata.cxx
Go to the documentation of this file.
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 <scitems.hxx>
21#include <editeng/eeitem.hxx>
22#include <o3tl/safeint.hxx>
24#include <o3tl/string_view.hxx>
25#include <sfx2/lokhelper.hxx>
26#include <sfx2/viewfrm.hxx>
28#include <editeng/brushitem.hxx>
29#include <svtools/colorcfg.hxx>
30#include <editeng/editview.hxx>
31#include <editeng/editstat.hxx>
32#include <editeng/outliner.hxx>
33#include <editeng/unolingu.hxx>
35
36#include <vcl/svapp.hxx>
37#include <rtl/math.hxx>
38#include <sal/log.hxx>
39
40#include <viewdata.hxx>
41#include <docoptio.hxx>
42#include <scmod.hxx>
43#include <global.hxx>
44#include <document.hxx>
45#include <drwlayer.hxx>
46#include <attrib.hxx>
47#include <tabview.hxx>
48#include <tabvwsh.hxx>
49#include <docsh.hxx>
50#include <patattr.hxx>
51#include <editutil.hxx>
52#include <scextopt.hxx>
53#include <miscuno.hxx>
54#include <unonames.hxx>
55#include <inputopt.hxx>
56#include <inputhdl.hxx>
57#include <inputwin.hxx>
58#include <viewutil.hxx>
59#include <markdata.hxx>
61#include <gridwin.hxx>
62#include <transobj.hxx>
63#include <clipparam.hxx>
65#include <comphelper/lok.hxx>
67#include <comphelper/string.hxx>
68
69#include <vcl/uitest/logger.hxx>
71
72#include <com/sun/star/container/XNameContainer.hpp>
73#include <com/sun/star/document/NamedPropertyValues.hpp>
74
75using namespace com::sun::star;
76
77#define SC_GROWY_SMALL_EXTRA 100
78#define SC_GROWY_BIG_EXTRA 200
79
80constexpr OUStringLiteral TAG_TABBARWIDTH = u"tw:";
81
82namespace {
83
84void lcl_LOKRemoveWindow(ScTabViewShell* pTabViewShell, ScSplitPos eWhich)
85{
87 {
88 auto lRemoveWindows =
89 [pTabViewShell, eWhich] (ScTabViewShell* pOtherViewShell)
90 { pOtherViewShell->RemoveWindowFromForeignEditView(pTabViewShell, eWhich); };
91
92 SfxLokHelper::forEachOtherView(pTabViewShell, lRemoveWindows);
93 }
94}
95
96} // anonymous namespace
97
98namespace {
99
100void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& rAction)
101{
102 EventDescription aDescription;
103 aDescription.aID = "grid_window";
104 aDescription.aAction = rAction;
105 aDescription.aParameters = std::move(aParameters);
106 aDescription.aParent = "MainWindow";
107 aDescription.aKeyWord = "ScGridWinUIObject";
108
109 UITestLogger::getInstance().logEvent(aDescription);
110}
111}
112
114
115bool ScPositionHelper::Comp::operator() (const value_type& rValue1, const value_type& rValue2) const
116{
117 if (rValue1.first == null || rValue2.first == null)
118 {
119 return rValue1.second < rValue2.second;
120 }
121 else
122 {
123 return rValue1.first < rValue2.first;
124 }
125}
126
128 : MAX_INDEX(bColumn ? (pDoc ? pDoc->MaxCol() : -1) : MAXTILEDROW)
129{
130 mData.insert(std::make_pair(-1, 0));
131}
132
133void ScPositionHelper::setDocument(const ScDocument& rDoc, bool bColumn)
134{
135 MAX_INDEX = bColumn ? rDoc.MaxCol() : MAXTILEDROW;
136}
137
139{
140 if (nIndex < 0) return;
141 SAL_INFO("sc.lok.poshelper", "ScPositionHelper::insert: nIndex: "
142 << nIndex << ", nPos: " << nPos << ", size: " << mData.size());
143 value_type aValue = std::make_pair(nIndex, nPos);
144 mData.erase(aValue);
145 mData.insert(aValue);
146 SAL_INFO("sc.lok.poshelper",
147 "ScPositionHelper::insert: after insert: size: " << mData.size());
148}
149
151{
152 if (nIndex < 0)
153 return;
154 SAL_INFO("sc.lok.poshelper", "ScPositionHelper::remove: nIndex: " << nIndex
155 << ", size: " << mData.size());
156 auto it = mData.find(std::make_pair(nIndex, 0));
157 if (it == mData.end()) return;
158 mData.erase(it);
159 SAL_INFO("sc.lok.poshelper",
160 "ScPositionHelper::remove: after erase: size: " << mData.size());
161}
162
164{
165 SAL_INFO("sc.lok.poshelper", "ScPositionHelper::invalidate: nIndex: " << nIndex);
166 if (nIndex < 0)
167 {
168 mData.clear();
169 mData.insert(std::make_pair(-1, 0));
170 }
171 else
172 {
173 auto it = mData.lower_bound(std::make_pair(nIndex, 0));
174 mData.erase(it, mData.end());
175 }
176}
177
179{
180 SAL_INFO("sc.lok.poshelper", "ScPositionHelper::invalidate: nPos: " << nPos);
181 if (nPos <= 0)
182 {
183 mData.clear();
184 mData.insert(std::make_pair(-1, 0));
185 }
186 else
187 {
188 auto it = mData.lower_bound(std::make_pair(null, nPos));
189 mData.erase(it, mData.end());
190 }
191}
192
195{
196 SAL_INFO("sc.lok.poshelper",
197 "ScPositionHelper::getNearest: nIndex: " << nIndex << ", size: " << mData.size());
198 auto posUB = mData.upper_bound(std::make_pair(nIndex, 0));
199 if (posUB == mData.begin())
200 {
201 return *posUB;
202 }
203
204 auto posLB = std::prev(posUB);
205 // coverity[copy_paste_error : FALSE] - posUB is correct
206 if (posUB == mData.end())
207 {
208 return *posLB;
209 }
210
211 tools::Long nDiffUB = posUB->first - nIndex;
212 tools::Long nDiffLB = posLB->first - nIndex;
213 if (nDiffUB < -nDiffLB)
214 {
215 return *posUB;
216 }
217 else
218 {
219 return *posLB;
220 }
221}
222
225{
226 SAL_INFO("sc.lok.poshelper",
227 "ScPositionHelper::getNearest: nPos: " << nPos << ", size: " << mData.size());
228 auto posUB = mData.upper_bound(std::make_pair(null, nPos));
229
230 if (posUB == mData.begin())
231 {
232 return *posUB;
233 }
234
235 auto posLB = std::prev(posUB);
236 // coverity[copy_paste_error : FALSE] - posUB is correct
237 if (posUB == mData.end())
238 {
239 return *posLB;
240 }
241
242 tools::Long nDiffUB = posUB->second - nPos;
243 tools::Long nDiffLB = posLB->second - nPos;
244
245 if (nDiffUB < -nDiffLB)
246 {
247 return *posUB;
248 }
249 else
250 {
251 return *posLB;
252 }
253}
254
256{
257 auto it = mData.find(std::make_pair(nIndex, 0));
258 if (it == mData.end()) return -1;
259 return it->second;
260}
261
262tools::Long ScPositionHelper::computePosition(index_type nIndex, const std::function<long (index_type)>& getSizePx)
263{
264 assert(MAX_INDEX > 0);
265 if (nIndex < 0) nIndex = 0;
267
268 const auto& rNearest = getNearestByIndex(nIndex);
269 index_type nStartIndex = rNearest.first;
270 tools::Long nTotalPixels = rNearest.second;
271
272 if (nStartIndex < nIndex)
273 {
274 for (index_type nIdx = nStartIndex + 1; nIdx <= nIndex; ++nIdx)
275 {
276 nTotalPixels += getSizePx(nIdx);
277 }
278 }
279 else
280 {
281 for (index_type nIdx = nStartIndex; nIdx > nIndex; --nIdx)
282 {
283 nTotalPixels -= getSizePx(nIdx);
284 }
285 }
286 return nTotalPixels;
287}
288
289ScBoundsProvider::ScBoundsProvider(const ScViewData &rView, SCTAB nT, bool bColHeader)
290 : rDoc(rView.GetDocument())
291 , nTab(nT)
292 , bColumnHeader(bColHeader)
293 , MAX_INDEX(bColHeader ? rDoc.MaxCol() : MAXTILEDROW)
294 , mfPPTX(rView.GetPPTX())
295 , mfPPTY(rView.GetPPTY())
296 , nFirstIndex(-1)
297 , nSecondIndex(-1)
298 , nFirstPositionPx(-1)
299 , nSecondPositionPx(-1)
300{}
301
303{
304 assert(bColumnHeader);
306 nPosition = nFirstPositionPx;
307}
308
310{
311 assert(bColumnHeader);
313 nPosition = nSecondPositionPx;
314}
315
317{
318 assert(!bColumnHeader);
320 nPosition = nFirstPositionPx;
321}
322
324{
325 assert(!bColumnHeader);
327 nPosition = nSecondPositionPx;
328}
329
331{
332 const sal_uInt16 nSize = bColumnHeader ? rDoc.GetColWidth(nIndex, nTab) : rDoc.GetRowHeight(nIndex, nTab);
334}
335
336void ScBoundsProvider::GetIndexAndPos(index_type nNearestIndex, tools::Long nNearestPosition,
337 tools::Long nBound, index_type& nFoundIndex, tools::Long& nPosition,
338 bool bTowards, tools::Long nDiff)
339{
340 if (nDiff > 0) // nBound < nNearestPosition
341 GeIndexBackwards(nNearestIndex, nNearestPosition, nBound,
342 nFoundIndex, nPosition, bTowards);
343 else
344 GetIndexTowards(nNearestIndex, nNearestPosition, nBound,
345 nFoundIndex, nPosition, bTowards);
346}
347
349 value_type aFirstNearest, value_type aSecondNearest,
350 tools::Long nFirstBound, tools::Long nSecondBound)
351{
352 SAL_INFO("sc.lok.header", "BoundsProvider: nFirstBound: " << nFirstBound
353 << ", nSecondBound: " << nSecondBound);
354
355 tools::Long nFirstDiff = aFirstNearest.second - nFirstBound;
356 tools::Long nSecondDiff = aSecondNearest.second - nSecondBound;
357 SAL_INFO("sc.lok.header", "BoundsProvider: rTopNearest: index: " << aFirstNearest.first
358 << ", pos: " << aFirstNearest.second << ", diff: " << nFirstDiff);
359 SAL_INFO("sc.lok.header", "BoundsProvider: rBottomNearest: index: " << aSecondNearest.first
360 << ", pos: " << aSecondNearest.second << ", diff: " << nSecondDiff);
361
362 bool bReverse = (std::abs(nFirstDiff) >= std::abs(nSecondDiff));
363
364 if(bReverse)
365 {
366 std::swap(aFirstNearest, aSecondNearest);
367 std::swap(nFirstBound, nSecondBound);
368 std::swap(nFirstDiff, nSecondDiff);
369 }
370
371 index_type nNearestIndex = aFirstNearest.first;
372 tools::Long nNearestPosition = aFirstNearest.second;
373 SAL_INFO("sc.lok.header", "BoundsProvider: nearest to first bound: nNearestIndex: "
374 << nNearestIndex << ", nNearestPosition: " << nNearestPosition);
375
376 GetIndexAndPos(nNearestIndex, nNearestPosition, nFirstBound,
377 nFirstIndex, nFirstPositionPx, !bReverse, nFirstDiff);
378 SAL_INFO("sc.lok.header", "BoundsProvider: nFirstIndex: " << nFirstIndex
379 << ", nFirstPositionPx: " << nFirstPositionPx);
380
381 if (std::abs(nSecondDiff) < std::abs(nSecondBound - nFirstPositionPx))
382 {
383 nNearestIndex = aSecondNearest.first;
384 nNearestPosition = aSecondNearest.second;
385 }
386 else
387 {
388 nNearestPosition = nFirstPositionPx;
389 nNearestIndex = nFirstIndex;
390 nSecondDiff = !bReverse ? -1 : 1;
391 }
392 SAL_INFO("sc.lok.header", "BoundsProvider: nearest to second bound: nNearestIndex: "
393 << nNearestIndex << ", nNearestPosition: " << nNearestPosition
394 << ", diff: " << nSecondDiff);
395
396 GetIndexAndPos(nNearestIndex, nNearestPosition, nSecondBound,
397 nSecondIndex, nSecondPositionPx, bReverse, nSecondDiff);
398 SAL_INFO("sc.lok.header", "BoundsProvider: nSecondIndex: " << nSecondIndex
399 << ", nSecondPositionPx: " << nSecondPositionPx);
400
401 if (bReverse)
402 {
403 std::swap(nFirstIndex, nSecondIndex);
405 }
406}
407
409{
410 const index_type nNewFirstIndex =
411 std::max(static_cast<index_type>(-1),
412 static_cast<index_type>(nFirstIndex - nOffset));
413 for (index_type nIndex = nFirstIndex; nIndex > nNewFirstIndex; --nIndex)
414 {
415 const tools::Long nSizePx = GetSize(nIndex);
416 nFirstPositionPx -= nSizePx;
417 }
418 nFirstIndex = nNewFirstIndex;
419 SAL_INFO("sc.lok.header", "BoundsProvider: added offset: nFirstIndex: " << nFirstIndex
420 << ", nFirstPositionPx: " << nFirstPositionPx);
421}
422
424{
425 const index_type nNewSecondIndex = std::min(MAX_INDEX, static_cast<index_type>(nSecondIndex + nOffset));
426 for (index_type nIndex = nSecondIndex + 1; nIndex <= nNewSecondIndex; ++nIndex)
427 {
428 const tools::Long nSizePx = GetSize(nIndex);
429 nSecondPositionPx += nSizePx;
430 }
431 nSecondIndex = nNewSecondIndex;
432 SAL_INFO("sc.lok.header", "BoundsProvider: added offset: nSecondIndex: " << nSecondIndex
433 << ", nSecondPositionPx: " << nSecondPositionPx);
434}
435
437 index_type nNearestIndex, tools::Long nNearestPosition,
438 tools::Long nBound, index_type& nFoundIndex, tools::Long& nPosition, bool bTowards)
439{
440 nFoundIndex = -1;
441 for (index_type nIndex = nNearestIndex; nIndex >= 0; --nIndex)
442 {
443 if (nBound >= nNearestPosition)
444 {
445 nFoundIndex = nIndex; // last index whose nPosition is less than nBound
446 nPosition = nNearestPosition;
447 break;
448 }
449
450 const tools::Long nSizePx = GetSize(nIndex);
451 nNearestPosition -= nSizePx;
452 }
453 if (!bTowards && nFoundIndex != -1)
454 {
455 nFoundIndex += 1;
456 nPosition += GetSize(nFoundIndex);
457 }
458}
459
461 index_type nNearestIndex, tools::Long nNearestPosition,
462 tools::Long nBound, index_type& nFoundIndex, tools::Long& nPosition, bool bTowards)
463{
464 nFoundIndex = -2;
465 for (index_type nIndex = nNearestIndex + 1; nIndex <= MAX_INDEX; ++nIndex)
466 {
467 const tools::Long nSizePx = GetSize(nIndex);
468 nNearestPosition += nSizePx;
469
470 if (nNearestPosition > nBound)
471 {
472 nFoundIndex = nIndex; // first index whose nPosition is greater than nBound
473 nPosition = nNearestPosition;
474 break;
475 }
476 }
477 if (nFoundIndex == -2)
478 {
479 nFoundIndex = MAX_INDEX;
480 nPosition = nNearestPosition;
481 }
482 else if (bTowards)
483 {
484 nPosition -= GetSize(nFoundIndex);
485 nFoundIndex -= 1;
486 }
487}
488
490 eZoomType( SvxZoomType::PERCENT ),
491 aZoomX( 1,1 ),
492 aZoomY( 1,1 ),
493 aPageZoomX( 3,5 ), // Page-Default: 60%
494 aPageZoomY( 3,5 ),
495 nHSplitPos( 0 ),
496 nVSplitPos( 0 ),
497 eHSplitMode( SC_SPLIT_NONE ),
498 eVSplitMode( SC_SPLIT_NONE ),
499 eWhichActive( SC_SPLIT_BOTTOMLEFT ),
500 nFixPosX( 0 ),
501 nFixPosY( 0 ),
502 nCurX( 0 ),
503 nCurY( 0 ),
504 nOldCurX( 0 ),
505 nOldCurY( 0 ),
506 aWidthHelper(pDoc, true),
507 aHeightHelper(pDoc, false),
508 nMaxTiledCol( 20 ),
509 nMaxTiledRow( 50 ),
510 bShowGrid( true ),
511 mbOldCursorValid( false )
512{
513 nPosX[0]=nPosX[1]=0;
514 nPosY[0]=nPosY[1]=0;
515 nTPosX[0]=nTPosX[1]=0;
516 nTPosY[0]=nTPosY[1]=0;
517 nMPosX[0]=nMPosX[1]=0;
518 nMPosY[0]=nMPosY[1]=0;
519 nPixPosX[0]=nPixPosX[1]=0;
520 nPixPosY[0]=nPixPosY[1]=0;
521}
522
524{
525 aWidthHelper.setDocument(rDoc, true);
526 aHeightHelper.setDocument(rDoc, false);
527}
528
529void ScViewDataTable::WriteUserDataSequence(uno::Sequence <beans::PropertyValue>& rSettings, const ScViewData& rViewData, SCTAB nTab) const
530{
531 rSettings.realloc(SC_TABLE_VIEWSETTINGS_COUNT);
532 beans::PropertyValue* pSettings = rSettings.getArray();
533
534 ScSplitMode eExHSplitMode = eHSplitMode;
535 ScSplitMode eExVSplitMode = eVSplitMode;
536 SCCOL nExFixPosX = nFixPosX;
537 SCROW nExFixPosY = nFixPosY;
538 tools::Long nExHSplitPos = nHSplitPos;
539 tools::Long nExVSplitPos = nVSplitPos;
540
542 {
543 rViewData.OverrideWithLOKFreeze(eExHSplitMode, eExVSplitMode,
544 nExFixPosX, nExFixPosY,
545 nExHSplitPos, nExVSplitPos, nTab);
546 }
547
548 pSettings[SC_CURSOR_X].Name = SC_CURSORPOSITIONX;
549 pSettings[SC_CURSOR_X].Value <<= sal_Int32(nCurX);
550 pSettings[SC_CURSOR_Y].Name = SC_CURSORPOSITIONY;
551 pSettings[SC_CURSOR_Y].Value <<= sal_Int32(nCurY);
552
553 // Write freezepan data only when freeze pans are set
554 if(nExFixPosX != 0 || nExFixPosY != 0 || nExHSplitPos != 0 || nExVSplitPos != 0)
555 {
557 pSettings[SC_HORIZONTAL_SPLIT_MODE].Value <<= sal_Int16(eExHSplitMode);
559 pSettings[SC_VERTICAL_SPLIT_MODE].Value <<= sal_Int16(eExVSplitMode);
561 if (eExHSplitMode == SC_SPLIT_FIX)
562 pSettings[SC_HORIZONTAL_SPLIT_POSITION].Value <<= sal_Int32(nExFixPosX);
563 else
564 pSettings[SC_HORIZONTAL_SPLIT_POSITION].Value <<= sal_Int32(nExHSplitPos);
566 if (eExVSplitMode == SC_SPLIT_FIX)
567 pSettings[SC_VERTICAL_SPLIT_POSITION].Value <<= sal_Int32(nExFixPosY);
568 else
569 pSettings[SC_VERTICAL_SPLIT_POSITION].Value <<= sal_Int32(nExVSplitPos);
570 }
571
572 // Prevent writing odd settings that would make crash versions that
573 // don't apply SanitizeWhichActive() when reading the settings.
574 // See tdf#117093
575 const ScSplitPos eActiveSplitRange = SanitizeWhichActive();
576 // And point out to give us a chance to inspect weird things (if anyone
577 // remembers what s/he did).
578 assert(eWhichActive == eActiveSplitRange);
580 pSettings[SC_ACTIVE_SPLIT_RANGE].Value <<= sal_Int16(eActiveSplitRange);
581 pSettings[SC_POSITION_LEFT].Name = SC_POSITIONLEFT;
582 pSettings[SC_POSITION_LEFT].Value <<= sal_Int32(nPosX[SC_SPLIT_LEFT]);
583 pSettings[SC_POSITION_RIGHT].Name = SC_POSITIONRIGHT;
584 pSettings[SC_POSITION_RIGHT].Value <<= sal_Int32(nPosX[SC_SPLIT_RIGHT]);
585 pSettings[SC_POSITION_TOP].Name = SC_POSITIONTOP;
586 pSettings[SC_POSITION_TOP].Value <<= sal_Int32(nPosY[SC_SPLIT_TOP]);
587 pSettings[SC_POSITION_BOTTOM].Name = SC_POSITIONBOTTOM;
588 pSettings[SC_POSITION_BOTTOM].Value <<= sal_Int32(nPosY[SC_SPLIT_BOTTOM]);
589
590 sal_Int32 nZoomValue = tools::Long(aZoomY * 100);
591 sal_Int32 nPageZoomValue = tools::Long(aPageZoomY * 100);
592 pSettings[SC_TABLE_ZOOM_TYPE].Name = SC_ZOOMTYPE;
593 pSettings[SC_TABLE_ZOOM_TYPE].Value <<= sal_Int16(eZoomType);
594 pSettings[SC_TABLE_ZOOM_VALUE].Name = SC_ZOOMVALUE;
595 pSettings[SC_TABLE_ZOOM_VALUE].Value <<= nZoomValue;
597 pSettings[SC_TABLE_PAGE_VIEW_ZOOM_VALUE].Value <<= nPageZoomValue;
598
599 pSettings[SC_TABLE_SHOWGRID].Name = SC_UNO_SHOWGRID;
600 pSettings[SC_TABLE_SHOWGRID].Value <<= bShowGrid;
601
602 // Common SdrModel processing
603 rViewData.GetDocument().GetDrawLayer()->WriteUserDataSequence(rSettings);
604}
605
606void ScViewDataTable::ReadUserDataSequence(const uno::Sequence <beans::PropertyValue>& aSettings, ScViewData& rViewData, SCTAB nTab, bool& rHasZoom )
607{
608 rHasZoom = false;
609
610 sal_Int32 nTemp32(0);
611 sal_Int16 nTemp16(0);
612 sal_Int32 nTempPosV(0);
613 sal_Int32 nTempPosH(0);
614 sal_Int32 nTempPosVTw(0);
615 sal_Int32 nTempPosHTw(0);
616 bool bHasVSplitInTwips = false;
617 bool bHasHSplitInTwips = false;
618 for (const auto& rSetting : aSettings)
619 {
620 OUString sName(rSetting.Name);
622 {
623 rSetting.Value >>= nTemp32;
624 nCurX = rViewData.GetDocument().SanitizeCol( static_cast<SCCOL>(nTemp32));
625 }
626 else if (sName == SC_CURSORPOSITIONY)
627 {
628 rSetting.Value >>= nTemp32;
629 nCurY = rViewData.GetDocument().SanitizeRow( static_cast<SCROW>(nTemp32));
630 }
631 else if (sName == SC_HORIZONTALSPLITMODE)
632 {
633 if ((rSetting.Value >>= nTemp16) && nTemp16 <= ScSplitMode::SC_SPLIT_MODE_MAX_ENUM)
634 eHSplitMode = static_cast<ScSplitMode>(nTemp16);
635 }
636 else if (sName == SC_VERTICALSPLITMODE)
637 {
638 if ((rSetting.Value >>= nTemp16) && nTemp16 <= ScSplitMode::SC_SPLIT_MODE_MAX_ENUM)
639 eVSplitMode = static_cast<ScSplitMode>(nTemp16);
640 }
642 {
643 rSetting.Value >>= nTempPosH;
644 bHasHSplitInTwips = false;
645 }
647 {
648 rSetting.Value >>= nTempPosV;
649 bHasVSplitInTwips = false;
650 }
652 {
653 rSetting.Value >>= nTempPosHTw;
654 bHasHSplitInTwips = true;
655 }
657 {
658 rSetting.Value >>= nTempPosVTw;
659 bHasVSplitInTwips = true;
660 }
661 else if (sName == SC_ACTIVESPLITRANGE)
662 {
663 if ((rSetting.Value >>= nTemp16) && nTemp16 <= ScSplitPos::SC_SPLIT_POS_MAX_ENUM)
664 eWhichActive = static_cast<ScSplitPos>(nTemp16);
665 }
666 else if (sName == SC_POSITIONLEFT)
667 {
668 rSetting.Value >>= nTemp32;
669 nPosX[SC_SPLIT_LEFT] = rViewData.GetDocument().SanitizeCol( static_cast<SCCOL>(nTemp32));
670 }
671 else if (sName == SC_POSITIONRIGHT)
672 {
673 rSetting.Value >>= nTemp32;
674 nPosX[SC_SPLIT_RIGHT] = rViewData.GetDocument().SanitizeCol( static_cast<SCCOL>(nTemp32));
675 }
676 else if (sName == SC_POSITIONTOP)
677 {
678 rSetting.Value >>= nTemp32;
679 nPosY[SC_SPLIT_TOP] = rViewData.GetDocument().SanitizeRow( static_cast<SCROW>(nTemp32));
680 }
681 else if (sName == SC_POSITIONBOTTOM)
682 {
683 rSetting.Value >>= nTemp32;
684 nPosY[SC_SPLIT_BOTTOM] = rViewData.GetDocument().SanitizeRow( static_cast<SCROW>(nTemp32));
685 }
686 else if (sName == SC_ZOOMTYPE)
687 {
688 rSetting.Value >>= nTemp16;
689 eZoomType = SvxZoomType(nTemp16);
690 rHasZoom = true; // set if there is any zoom information
691 }
692 else if (sName == SC_ZOOMVALUE)
693 {
694 rSetting.Value >>= nTemp32;
695 Fraction aZoom(nTemp32, 100);
696 aZoomX = aZoomY = aZoom;
697 rHasZoom = true;
698 }
699 else if (sName == SC_PAGEVIEWZOOMVALUE)
700 {
701 rSetting.Value >>= nTemp32;
702 Fraction aZoom(nTemp32, 100);
703 aPageZoomX = aPageZoomY = aZoom;
704 rHasZoom = true;
705 }
706 else if (sName == SC_UNO_SHOWGRID)
707 {
708 rSetting.Value >>= bShowGrid;
709 }
710 else if (sName == SC_TABLESELECTED)
711 {
712 bool bSelected = false;
713 rSetting.Value >>= bSelected;
714 rViewData.GetMarkData().SelectTable( nTab, bSelected );
715 }
716 else if (sName == SC_UNONAME_TABCOLOR)
717 {
718 // There are documents out there that have their tab color defined as a view setting.
719 Color aColor = COL_AUTO;
720 rSetting.Value >>= aColor;
721 if (aColor != COL_AUTO)
722 {
723 ScDocument& rDoc = rViewData.GetDocument();
724 rDoc.SetTabBgColor(nTab, aColor);
725 }
726 }
727 // Fallback to common SdrModel processing
728 else rViewData.GetDocument().GetDrawLayer()->ReadUserDataSequenceValue(&rSetting);
729 }
730
732 nFixPosX = rViewData.GetDocument().SanitizeCol( static_cast<SCCOL>( bHasHSplitInTwips ? nTempPosHTw : nTempPosH ));
733 else
734 nHSplitPos = bHasHSplitInTwips ? static_cast< tools::Long >( nTempPosHTw * rViewData.GetPPTX() ) : nTempPosH;
735
737 nFixPosY = rViewData.GetDocument().SanitizeRow( static_cast<SCROW>( bHasVSplitInTwips ? nTempPosVTw : nTempPosV ));
738 else
739 nVSplitPos = bHasVSplitInTwips ? static_cast< tools::Long >( nTempPosVTw * rViewData.GetPPTY() ) : nTempPosV;
740
742}
743
745{
748 {
749 SAL_WARN("sc.ui","ScViewDataTable::SanitizeWhichActive - bad eWhichActive " << eWhichActive);
750 // The default always initialized grid window is SC_SPLIT_BOTTOMLEFT.
751 return SC_SPLIT_BOTTOMLEFT;
752 }
753 return eWhichActive;
754}
755
757 : ScViewData(nullptr, &rDocSh, pViewSh)
758{
759}
760
762 : ScViewData(&rDoc, nullptr, nullptr)
763{
764}
765
767{
768 ScViewOptions aOptions;
769 aOptions.SetOption(VOPT_GRID, true);
770 aOptions.SetOption(VOPT_SYNTAX, false);
771 aOptions.SetOption(VOPT_HEADER, true);
772 aOptions.SetOption(VOPT_TABCONTROLS, true);
773 aOptions.SetOption(VOPT_VSCROLL, true);
774 aOptions.SetOption(VOPT_HSCROLL, true);
775 aOptions.SetOption(VOPT_OUTLINER, true);
776 return aOptions;
777}
778
779// Either pDoc or pDocSh must be valid
781 nPPTX(0.0),
782 nPPTY(0.0),
783 maMarkData (pDocSh ? pDocSh->GetDocument().GetSheetLimits() : pDoc->GetSheetLimits()),
784 pDocShell ( pDocSh ),
785 mrDoc (pDocSh ? pDocSh->GetDocument() : *pDoc),
786 pView ( pViewSh ),
787 maOptions (pDocSh ? pDocSh->GetDocument().GetViewOptions() : DefaultOptions()),
788 pSpellingView ( nullptr ),
789 aLogicMode ( MapUnit::Map100thMM ),
790 eDefZoomType( SvxZoomType::PERCENT ),
791 aDefZoomX ( 1,1 ),
792 aDefZoomY ( 1,1 ),
793 aDefPageZoomX( 3,5 ),
794 aDefPageZoomY( 3,5 ),
795 eRefType ( SC_REFTYPE_NONE ),
796 nTabNo ( 0 ),
797 nRefTabNo ( 0 ),
798 nRefStartX(0),
799 nRefStartY(0),
800 nRefStartZ(0),
801 nRefEndX(0),
802 nRefEndY(0),
803 nRefEndZ(0),
804 nFillStartX(0),
805 nFillStartY(0),
806 nFillEndX(0),
807 nFillEndY(0),
808 nPasteFlags ( ScPasteFlags::NONE ),
809 eEditActivePart( SC_SPLIT_BOTTOMLEFT ),
810 nFillMode ( ScFillMode::NONE ),
811 eEditAdjust ( SvxAdjust::Left ),
812 bActive ( true ), // how to initialize?
813 bIsRefMode ( false ),
814 bDelMarkValid( false ),
815 bPagebreak ( false ),
816 bSelCtrlMouseClick( false ),
817 bMoveArea ( false ),
818 bGrowing (false),
819 nFormulaBarLines(1),
820 m_nLOKPageUpDownOffset( 0 )
821{
822 assert(bool(pDoc) != bool(pDocSh)); // either one or the other, not both
823 maMarkData.SelectOneTable(0); // Sync with nTabNo
824
827 maTabData.emplace_back( new ScViewDataTable(nullptr) );
828 pThisTab = maTabData[nTabNo].get();
829
831 nEditEndRow = nEditRow = 0;
833
834 // don't show hidden tables
835 if (!mrDoc.IsVisible(nTabNo))
836 {
837 while (!mrDoc.IsVisible(nTabNo) && mrDoc.HasTable(nTabNo + 1))
838 {
839 ++nTabNo;
840 maTabData.emplace_back(nullptr);
841 }
842 maTabData[nTabNo].reset( new ScViewDataTable(nullptr) );
843 pThisTab = maTabData[nTabNo].get();
844 }
845
846 SCTAB nTableCount = mrDoc.GetTableCount();
847 EnsureTabDataSize(nTableCount);
848
849 for (auto& xTabData : maTabData)
850 {
851 if (xTabData)
852 xTabData->InitData(mrDoc);
853 }
854
855 CalcPPT();
856}
857
858ScViewData::~ScViewData() COVERITY_NOEXCEPT_FALSE
859{
860 KillEditView();
861}
862
864
866{
867 assert(0 <= nTabNo && o3tl::make_unsigned(nTabNo) < maTabData.size());
868 pThisTab = maTabData[nTabNo].get();
869 while (!pThisTab)
870 {
871 if (nTabNo > 0)
872 pThisTab = maTabData[--nTabNo].get();
873 else
874 {
875 maTabData[0].reset(new ScViewDataTable(&mrDoc));
876 pThisTab = maTabData[0].get();
877 }
878 }
879}
880
882{
883 if( nTab >= static_cast<SCTAB>(maTabData.size()))
884 maTabData.resize(nTab+1);
885 else
886 maTabData.insert( maTabData.begin() + nTab, nullptr );
887 CreateTabData( nTab );
888
890 maMarkData.InsertTab(nTab);
891
892 collectUIInformation({{}}, "InsertTab");
893}
894
895void ScViewData::InsertTabs( SCTAB nTab, SCTAB nNewSheets )
896{
897 if (nTab >= static_cast<SCTAB>(maTabData.size()))
898 maTabData.resize(nTab+nNewSheets);
899 else
900 {
901 // insert nNewSheets new tables at position nTab
902 auto prevSize = maTabData.size();
903 maTabData.resize(prevSize + nNewSheets);
904 std::move_backward(maTabData.begin() + nTab, maTabData.begin() + prevSize, maTabData.end());
905 }
906 for (SCTAB i = nTab; i < nTab + nNewSheets; ++i)
907 {
908 CreateTabData( i );
910 }
912}
913
915{
916 assert(nTab < static_cast<SCTAB>(maTabData.size()));
917 maTabData.erase(maTabData.begin() + nTab);
918
919 if (o3tl::make_unsigned(nTabNo) >= maTabData.size())
920 {
922 nTabNo = maTabData.size() - 1;
923 }
925 maMarkData.DeleteTab(nTab);
926}
927
928void ScViewData::DeleteTabs( SCTAB nTab, SCTAB nSheets )
929{
930 for (SCTAB i = 0; i < nSheets; ++i)
931 {
932 maMarkData.DeleteTab(nTab + i);
933 }
934 maTabData.erase(maTabData.begin() + nTab, maTabData.begin()+ nTab+nSheets);
935 if (o3tl::make_unsigned(nTabNo) >= maTabData.size())
936 {
938 nTabNo = maTabData.size() - 1;
939 }
941}
942
943void ScViewData::CopyTab( SCTAB nSrcTab, SCTAB nDestTab )
944{
945 if (nDestTab==SC_TAB_APPEND)
946 nDestTab = mrDoc.GetTableCount() - 1; // something had to have been copied
947
948 if (nDestTab > MAXTAB)
949 {
950 OSL_FAIL("too many sheets");
951 return;
952 }
953
954 if (nSrcTab >= static_cast<SCTAB>(maTabData.size()))
955 OSL_FAIL("pTabData out of bounds, FIX IT");
956
957 EnsureTabDataSize(nDestTab + 1);
958
959 if ( maTabData[nSrcTab] )
960 maTabData.emplace(maTabData.begin() + nDestTab, new ScViewDataTable( *maTabData[nSrcTab] ));
961 else
962 maTabData.insert(maTabData.begin() + nDestTab, nullptr);
963
965 maMarkData.InsertTab(nDestTab);
966}
967
968void ScViewData::MoveTab( SCTAB nSrcTab, SCTAB nDestTab )
969{
970 if (nDestTab==SC_TAB_APPEND)
971 nDestTab = mrDoc.GetTableCount() - 1;
972 std::unique_ptr<ScViewDataTable> pTab;
973 if (nSrcTab < static_cast<SCTAB>(maTabData.size()))
974 {
975 pTab = std::move(maTabData[nSrcTab]);
976 maTabData.erase( maTabData.begin() + nSrcTab );
977 }
978
979 if (nDestTab < static_cast<SCTAB>(maTabData.size()))
980 maTabData.insert( maTabData.begin() + nDestTab, std::move(pTab) );
981 else
982 {
983 EnsureTabDataSize(nDestTab + 1);
984 maTabData[nDestTab] = std::move(pTab);
985 }
986
988 maMarkData.DeleteTab(nSrcTab);
989 maMarkData.InsertTab(nDestTab); // adapted if needed
990}
991
992void ScViewData::CreateTabData( std::vector< SCTAB >& rvTabs )
993{
994 for ( const auto& rTab : rvTabs )
995 CreateTabData(rTab);
996}
997
998void ScViewData::SetZoomType( SvxZoomType eNew, std::vector< SCTAB >& tabs )
999{
1000 bool bAll = tabs.empty();
1001
1002 if ( !bAll ) // create associated table data
1003 CreateTabData( tabs );
1004
1005 if ( bAll )
1006 {
1007 for ( auto & i: maTabData )
1008 {
1009 if ( i )
1010 i->eZoomType = eNew;
1011 }
1012 eDefZoomType = eNew;
1013 }
1014 else
1015 {
1016 for ( const SCTAB& i : tabs )
1017 {
1018 if ( i < static_cast<SCTAB>(maTabData.size()) && maTabData[i] )
1019 maTabData[i]->eZoomType = eNew;
1020 }
1021 }
1022}
1023
1025{
1026 std::vector< SCTAB > vTabs; // Empty for all tabs
1027 if ( !bAll ) // get selected tabs
1028 {
1030 vTabs.insert(vTabs.begin(), itr, itrEnd);
1031 }
1032 SetZoomType( eNew, vTabs );
1033}
1034
1035void ScViewData::SetZoom( const Fraction& rNewX, const Fraction& rNewY, std::vector< SCTAB >& tabs )
1036{
1037 bool bAll = tabs.empty();
1038 if ( !bAll ) // create associated table data
1039 CreateTabData( tabs );
1040
1041 // sanity check - we shouldn't need something this low / big
1042 SAL_WARN_IF(rNewX < Fraction(1, 100) || rNewX > Fraction(100, 1), "sc.viewdata",
1043 "fraction rNewX not sensible: " << static_cast<double>(rNewX));
1044 SAL_WARN_IF(rNewY < Fraction(1, 100) || rNewY > Fraction(100, 1), "sc.viewdata",
1045 "fraction rNewY not sensible: " << static_cast<double>(rNewY));
1046
1047 if ( bAll )
1048 {
1049 for ( auto & i: maTabData )
1050 {
1051 if ( i )
1052 {
1053 if ( bPagebreak )
1054 {
1055 i->aPageZoomX = rNewX;
1056 i->aPageZoomY = rNewY;
1057 }
1058 else
1059 {
1060 i->aZoomX = rNewX;
1061 i->aZoomY = rNewY;
1062 }
1063 }
1064 }
1065 if ( bPagebreak )
1066 {
1067 aDefPageZoomX = rNewX;
1068 aDefPageZoomY = rNewY;
1069 }
1070 else
1071 {
1072 aDefZoomX = rNewX;
1073 aDefZoomY = rNewY;
1074 }
1075 }
1076 else
1077 {
1078 for ( const SCTAB& i : tabs )
1079 {
1080 if ( i < static_cast<SCTAB>(maTabData.size()) && maTabData[i] )
1081 {
1082 if ( bPagebreak )
1083 {
1084 maTabData[i]->aPageZoomX = rNewX;
1085 maTabData[i]->aPageZoomY = rNewY;
1086 }
1087 else
1088 {
1089 maTabData[i]->aZoomX = rNewX;
1090 maTabData[i]->aZoomY = rNewY;
1091 }
1092 }
1093 }
1094 }
1095 RefreshZoom();
1096}
1097
1098void ScViewData::SetZoom( const Fraction& rNewX, const Fraction& rNewY, bool bAll )
1099{
1100 std::vector< SCTAB > vTabs;
1101 if ( !bAll ) // get selected tabs
1102 {
1104 vTabs.insert(vTabs.begin(), itr, itrEnd);
1105 }
1106 SetZoom( rNewX, rNewY, vTabs );
1107}
1108
1109void ScViewData::SetShowGrid( bool bShow )
1110{
1112 maTabData[nTabNo]->bShowGrid = bShow;
1113}
1114
1116{
1117 // recalculate zoom-dependent values (only for current sheet)
1118
1119 CalcPPT();
1120 RecalcPixPos();
1121 aScenButSize = Size(0,0);
1124}
1125
1127{
1128 bPagebreak = bSet;
1129
1130 RefreshZoom();
1131}
1132
1134{
1135 ScMarkType eMarkType = SC_MARK_NONE;
1136
1137 if ( rNewMark.IsMarked() || rNewMark.IsMultiMarked() )
1138 {
1139 if ( rNewMark.IsMultiMarked() )
1140 rNewMark.MarkToSimple();
1141
1142 if ( rNewMark.IsMarked() && !rNewMark.IsMultiMarked() )
1143 {
1144 rRange = rNewMark.GetMarkArea();
1145 if (ScViewUtil::HasFiltered(rRange, GetDocument()))
1146 eMarkType = SC_MARK_SIMPLE_FILTERED;
1147 else
1148 eMarkType = SC_MARK_SIMPLE;
1149 }
1150 else
1151 eMarkType = SC_MARK_MULTI;
1152 }
1153 if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED)
1154 {
1155 if (eMarkType == SC_MARK_NONE)
1156 eMarkType = SC_MARK_SIMPLE;
1157 const ScPatternAttr* pMarkPattern = mrDoc.GetPattern(GetCurX(), GetCurY(), GetTabNo());
1158 if (pMarkPattern && pMarkPattern->GetItemSet().GetItemState(ATTR_MERGE, false) == SfxItemState::SET)
1159 {
1160 SCROW nRow = pMarkPattern->GetItem(ATTR_MERGE).GetRowMerge();
1161 SCCOL nCol = pMarkPattern->GetItem(ATTR_MERGE).GetColMerge();
1162 if ( nRow < 1 || nCol < 1 )
1163 {
1164 // This kind of cells do exist. Not sure if that is intended or a bug.
1165 rRange = ScRange(GetCurX(), GetCurY(), GetTabNo());
1166 }
1167 else
1168 {
1169 rRange = ScRange(GetCurX(), GetCurY(), GetTabNo(),
1170 GetCurX() + nCol - 1, GetCurY() + nRow - 1, GetTabNo());
1171 if ( ScViewUtil::HasFiltered(rRange, GetDocument()) )
1172 eMarkType = SC_MARK_SIMPLE_FILTERED;
1173 }
1174 }
1175 else
1176 rRange = ScRange(GetCurX(), GetCurY(), GetTabNo());
1177 }
1178 return eMarkType;
1179}
1180
1181ScMarkType ScViewData::GetSimpleArea( SCCOL& rStartCol, SCROW& rStartRow, SCTAB& rStartTab,
1182 SCCOL& rEndCol, SCROW& rEndRow, SCTAB& rEndTab ) const
1183{
1184 // parameter bMergeMark is no longer needed: The view's selection is never modified
1185 // (a local copy is used), and a multi selection that adds to a single range can always
1186 // be treated like a single selection (GetSimpleArea isn't used in selection
1187 // handling itself)
1188
1189 ScRange aRange;
1190 ScMarkData aNewMark(maMarkData); // use a local copy for MarkToSimple
1191 ScMarkType eMarkType = GetSimpleArea( aRange, aNewMark);
1192 aRange.GetVars( rStartCol, rStartRow, rStartTab, rEndCol, rEndRow, rEndTab);
1193 return eMarkType;
1194}
1195
1197{
1198 // parameter bMergeMark is no longer needed, see above
1199
1200 ScMarkData aNewMark(maMarkData); // use a local copy for MarkToSimple
1201 return GetSimpleArea( rRange, aNewMark);
1202}
1203
1205{
1206 // parameter bMergeMark is no longer needed, see GetSimpleArea
1207
1208 ScMarkData aNewMark(maMarkData); // use a local copy for MarkToSimple
1209
1210 bool bMulti = aNewMark.IsMultiMarked();
1211 if (bMulti)
1212 {
1213 aNewMark.MarkToSimple();
1214 bMulti = aNewMark.IsMultiMarked();
1215 }
1216 if (bMulti)
1217 {
1218 rRange = new ScRangeList;
1219 aNewMark.FillRangeListWithMarks( rRange.get(), false );
1220 }
1221 else
1222 {
1223 ScRange aSimple;
1224 GetSimpleArea(aSimple);
1225 rRange = new ScRangeList(aSimple);
1226 }
1227}
1228
1230{
1231 SCCOL nStartCol;
1232 SCROW nStartRow;
1233 SCTAB nStartTab;
1234 SCCOL nEndCol;
1235 SCROW nEndRow;
1236 SCTAB nEndTab;
1237 if (GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
1238 if (nStartRow == 0 && nEndRow == mrDoc.MaxRow())
1239 return true;
1240
1241 return false;
1242}
1243
1245{
1246 SCCOL nStartCol;
1247 SCROW nStartRow;
1248 SCTAB nStartTab;
1249 SCCOL nEndCol;
1250 SCROW nEndRow;
1251 SCTAB nEndTab;
1252 if (GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
1253 if (nStartCol == 0 && nEndCol == mrDoc.MaxCol())
1254 return true;
1255
1256 return false;
1257}
1258
1260{
1261 // Test for "real" multi selection, calling MarkToSimple on a local copy,
1262 // and taking filtered in simple area marks into account.
1263
1264 ScRange aDummy;
1265 ScMarkType eType = GetSimpleArea(aDummy);
1266 return (eType & SC_MARK_SIMPLE) != SC_MARK_SIMPLE;
1267}
1268
1270{
1271 if (!pClipDoc)
1272 {
1273 // Same as checkDestRanges() in sc/source/ui/view/cellsh.cxx but
1274 // different return details.
1275
1276 vcl::Window* pWin = GetActiveWin();
1277 if (!pWin)
1278 // No window doesn't mean paste would be forbidden.
1279 return false;
1280
1282 if (!pOwnClip)
1283 // Foreign content does not get repeatedly replicated.
1284 return false;
1285
1286 pClipDoc = pOwnClip->GetDocument();
1287 if (!pClipDoc)
1288 // No clipdoc doesn't mean paste would be forbidden.
1289 return false;
1290 }
1291
1292 const ScRange aSrcRange = pClipDoc->GetClipParam().getWholeRange();
1293 const SCROW nRowSize = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
1294 const SCCOL nColSize = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
1295
1296 return SelectionForbidsPaste( nColSize, nRowSize);
1297}
1298
1300{
1301 ScRange aSelRange( ScAddress::UNINITIALIZED );
1302 ScMarkType eMarkType = GetSimpleArea( aSelRange);
1303
1304 if (eMarkType == SC_MARK_MULTI)
1305 // Not because of DOOM.
1306 return false;
1307
1308 if (aSelRange.aEnd.Row() - aSelRange.aStart.Row() + 1 == nSrcRows)
1309 // This also covers entire col(s) copied to be pasted on entire cols.
1310 return false;
1311
1312 if (aSelRange.aEnd.Col() - aSelRange.aStart.Col() + 1 == nSrcCols)
1313 // This also covers entire row(s) copied to be pasted on entire rows.
1314 return false;
1315
1316 return SelectionFillDOOM( aSelRange);
1317}
1318
1320{
1321 ScRange aSelRange( ScAddress::UNINITIALIZED );
1322 ScMarkType eMarkType = GetSimpleArea( aSelRange);
1323 return eMarkType != SC_MARK_MULTI && SelectionFillDOOM( aSelRange);
1324}
1325
1326// static
1328{
1329 // Assume that more than 23 full columns (23M cells) will not be
1330 // successful... Even with only 10 bytes per cell that would already be
1331 // 230MB, formula cells would be 100 bytes and more per cell.
1332 // rows * columns > 23m => rows > 23m / columns
1333 // to not overflow in case number of available columns or rows would be
1334 // arbitrarily increased.
1335 // We could refine this and take some actual cell size into account,
1336 // evaluate available memory and what not, but...
1337 const sal_Int32 kMax = 23 * 1024 * 1024; // current MAXROWCOUNT1 is 1024*1024=1048576
1338 return (rRange.aEnd.Row() - rRange.aStart.Row() + 1) > (kMax / (rRange.aEnd.Col() - rRange.aStart.Col() + 1));
1339}
1340
1341void ScViewData::SetFillMode( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow )
1342{
1344 nFillStartX = nStartCol;
1345 nFillStartY = nStartRow;
1346 nFillEndX = nEndCol;
1347 nFillEndY = nEndRow;
1348}
1349
1350void ScViewData::SetDragMode( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1351 ScFillMode nMode )
1352{
1353 nFillMode = nMode;
1354 nFillStartX = nStartCol;
1355 nFillStartY = nStartRow;
1356 nFillEndX = nEndCol;
1357 nFillEndY = nEndRow;
1358}
1359
1361{
1363}
1364
1365void ScViewData::GetFillData( SCCOL& rStartCol, SCROW& rStartRow,
1366 SCCOL& rEndCol, SCROW& rEndRow )
1367{
1368 rStartCol = nFillStartX;
1369 rStartRow = nFillStartY;
1370 rEndCol = nFillEndX;
1371 rEndRow = nFillEndY;
1372}
1373
1375{
1377 return pThisTab->nOldCurX;
1378 else
1379 return pThisTab->nCurX;
1380}
1381
1383{
1385 return pThisTab->nOldCurY;
1386 else
1387 return pThisTab->nCurY;
1388}
1389
1391{
1392 pThisTab->nOldCurX = nNewX;
1393 pThisTab->nOldCurY = nNewY;
1394 pThisTab->mbOldCursorValid = true;
1395}
1396
1398{
1399 pThisTab->mbOldCursorValid = false;
1400}
1401
1403{
1405 return 0;
1406
1407 if (nForTab == -1)
1408 return pThisTab->nPosX[eWhich];
1409
1410 if (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size())))
1411 return -1;
1412
1413 return maTabData[nForTab]->nPosX[eWhich];
1414}
1415
1417{
1419 return 0;
1420
1421 if (nForTab == -1)
1422 return pThisTab->nPosY[eWhich];
1423
1424 if (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size())))
1425 return -1;
1426
1427 return maTabData[nForTab]->nPosY[eWhich];
1428}
1429
1431{
1432 if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())) || !maTabData[nTabIndex])
1433 return -1;
1434
1435 return maTabData[nTabIndex]->nCurX;
1436}
1437
1439{
1440 if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())))
1441 return -1;
1442
1443 return maTabData[nTabIndex]->nCurY;
1444}
1445
1446void ScViewData::SetCurXForTab( SCCOL nNewCurX, SCTAB nTabIndex )
1447{
1448 if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())))
1449 return;
1450
1451 maTabData[nTabIndex]->nCurX = nNewCurX;
1452}
1453
1454void ScViewData::SetCurYForTab( SCCOL nNewCurY, SCTAB nTabIndex )
1455{
1456 if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())))
1457 return;
1458
1459 maTabData[nTabIndex]->nCurY = nNewCurY;
1460}
1461
1463{
1464 nNewMaxCol = std::clamp(nNewMaxCol, SCCOL(0), mrDoc.MaxCol());
1465
1466 const SCTAB nTab = GetTabNo();
1467 auto GetColWidthPx = [this, nTab](SCCOL nCol) {
1468 const sal_uInt16 nSize = this->mrDoc.GetColWidth(nCol, nTab);
1469 const tools::Long nSizePx = ScViewData::ToPixel(nSize, nPPTX);
1470 return nSizePx;
1471 };
1472
1473 tools::Long nTotalPixels = GetLOKWidthHelper().computePosition(nNewMaxCol, GetColWidthPx);
1474
1475 SAL_INFO("sc.lok.docsize", "ScViewData::SetMaxTiledCol: nNewMaxCol: "
1476 << nNewMaxCol << ", nTotalPixels: " << nTotalPixels);
1477
1479 GetLOKWidthHelper().insert(nNewMaxCol, nTotalPixels);
1480
1481 pThisTab->nMaxTiledCol = nNewMaxCol;
1482}
1483
1485{
1486 if (nNewMaxRow < 0)
1487 nNewMaxRow = 0;
1488 if (nNewMaxRow > MAXTILEDROW)
1489 nNewMaxRow = MAXTILEDROW;
1490
1491 const SCTAB nTab = GetTabNo();
1492 auto GetRowHeightPx = [this, nTab](SCROW nRow) {
1493 const sal_uInt16 nSize = this->mrDoc.GetRowHeight(nRow, nTab);
1494 const tools::Long nSizePx = ScViewData::ToPixel(nSize, nPPTY);
1495 return nSizePx;
1496 };
1497
1498 tools::Long nTotalPixels = GetLOKHeightHelper().computePosition(nNewMaxRow, GetRowHeightPx);
1499
1500 SAL_INFO("sc.lok.docsize", "ScViewData::SetMaxTiledRow: nNewMaxRow: "
1501 << nNewMaxRow << ", nTotalPixels: " << nTotalPixels);
1502
1504 GetLOKHeightHelper().insert(nNewMaxRow, nTotalPixels);
1505
1506 pThisTab->nMaxTiledRow = nNewMaxRow;
1507}
1508
1510 vcl::Window* pWin, const ScPatternAttr* pPattern,
1511 bool bForceToTop, bool bInPrintTwips )
1512{
1513 Point aCellTopLeft = bInPrintTwips ?
1514 GetPrintTwipsPos(nPosX, nPosY) : GetScrPos(nPosX, nPosY, eWhich, true);
1515 return ScEditUtil(&mrDoc, nPosX, nPosY, nTabNo, aCellTopLeft,
1516 pWin->GetOutDev(), nPPTX, nPPTY, GetZoomX(), GetZoomY(), bInPrintTwips ).
1517 GetEditArea( pPattern, bForceToTop );
1518}
1519
1521 ScEditEngineDefaulter* pNewEngine,
1522 vcl::Window* pWin, SCCOL nNewX, SCROW nNewY )
1523{
1524 bool bLayoutRTL = mrDoc.IsLayoutRTL(nTabNo);
1525 ScHSplitPos eHWhich = WhichH(eWhich);
1526 ScVSplitPos eVWhich = WhichV(eWhich);
1527 bool bLOKActive = comphelper::LibreOfficeKit::isActive();
1528 bool bLOKPrintTwips = bLOKActive && comphelper::LibreOfficeKit::isCompatFlagSet(
1529 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
1530
1531 bool bWasThere = false;
1532 if (pEditView[eWhich])
1533 {
1534 // if the view is already there don't call anything that changes the cursor position
1535 if (bEditActive[eWhich])
1536 {
1537 bWasThere = true;
1538 }
1539 else
1540 {
1541 lcl_LOKRemoveWindow(GetViewShell(), eWhich);
1542 pEditView[eWhich]->SetEditEngine(pNewEngine);
1543 }
1544
1545 if (pEditView[eWhich]->GetWindow() != pWin)
1546 {
1547 lcl_LOKRemoveWindow(GetViewShell(), eWhich);
1548 pEditView[eWhich]->SetWindow(pWin);
1549 OSL_FAIL("EditView Window has changed");
1550 }
1551 }
1552 else
1553 {
1554 pEditView[eWhich].reset(new EditView( pNewEngine, pWin ));
1555
1556 if (bLOKActive)
1557 {
1558 // We can broadcast the view-cursor message in print-twips for all views.
1559 pEditView[eWhich]->SetBroadcastLOKViewCursor(bLOKPrintTwips);
1560 pEditView[eWhich]->RegisterViewShell(pView);
1561 }
1562 }
1563
1564 // add windows from other views
1565 if (!bWasThere && bLOKActive)
1566 {
1567 ScTabViewShell* pThisViewShell = GetViewShell();
1568 SCTAB nThisTabNo = GetTabNo();
1569 auto lAddWindows =
1570 [pThisViewShell, nThisTabNo, eWhich] (ScTabViewShell* pOtherViewShell)
1571 {
1572 ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
1573 SCTAB nOtherTabNo = rOtherViewData.GetTabNo();
1574 if (nThisTabNo == nOtherTabNo)
1575 pOtherViewShell->AddWindowToForeignEditView(pThisViewShell, eWhich);
1576 };
1577
1578 SfxLokHelper::forEachOtherView(pThisViewShell, lAddWindows);
1579 }
1580
1581 // if view is gone then during IdleFormat sometimes a cursor is drawn
1582
1583 EEControlBits nEC = pNewEngine->GetControlWord();
1584 pNewEngine->SetControlWord(nEC & ~EEControlBits::DOIDLEFORMAT);
1585
1586 EVControlBits nVC = pEditView[eWhich]->GetControlWord();
1587 pEditView[eWhich]->SetControlWord(nVC & ~EVControlBits::AUTOSCROLL);
1588
1589 bEditActive[eWhich] = true;
1590
1591 const ScPatternAttr* pPattern = mrDoc.GetPattern(nNewX, nNewY, nTabNo);
1592 SvxCellHorJustify eJust = pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue();
1593
1594 bool bBreak = ( eJust == SvxCellHorJustify::Block ) ||
1595 pPattern->GetItem(ATTR_LINEBREAK).GetValue();
1596
1597 bool bAsianVertical = pNewEngine->IsEffectivelyVertical(); // set by InputHandler
1598
1599 tools::Rectangle aPixRect = ScEditUtil(&mrDoc, nNewX, nNewY, nTabNo, GetScrPos(nNewX, nNewY, eWhich),
1600 pWin->GetOutDev(), nPPTX,nPPTY,GetZoomX(),GetZoomY() ).
1601 GetEditArea( pPattern, true );
1602
1603 tools::Rectangle aPTwipsRect;
1604 if (bLOKPrintTwips)
1605 {
1606 aPTwipsRect = ScEditUtil(&mrDoc, nNewX, nNewY, nTabNo, GetPrintTwipsPos(nNewX, nNewY),
1607 pWin->GetOutDev(), nPPTX, nPPTY, GetZoomX(), GetZoomY(), true /* bInPrintTwips */).
1608 GetEditArea(pPattern, true);
1609 }
1610
1611 // when right-aligned, leave space for the cursor
1612 // in vertical mode, editing is always right-aligned
1613 if ( GetEditAdjust() == SvxAdjust::Right || bAsianVertical )
1614 {
1615 aPixRect.AdjustRight(1 );
1616 if (bLOKPrintTwips)
1618 }
1619
1620 if (bLOKPrintTwips)
1621 {
1622 if (!pEditView[eWhich]->HasLOKSpecialPositioning())
1623 pEditView[eWhich]->InitLOKSpecialPositioning(MapUnit::MapTwip, aPTwipsRect, Point());
1624 else
1625 pEditView[eWhich]->SetLOKSpecialOutputArea(aPTwipsRect);
1626 }
1627
1628 tools::Rectangle aOutputArea = pWin->PixelToLogic( aPixRect, GetLogicMode() );
1629 pEditView[eWhich]->SetOutputArea( aOutputArea );
1630
1631 if ( bActive && eWhich == GetActivePart() )
1632 {
1633 // keep the part that has the active edit view available after
1634 // switching sheets or reference input on a different part
1635 eEditActivePart = eWhich;
1636
1637 // modify members nEditCol etc. only if also extending for needed area
1638 nEditCol = nNewX;
1639 nEditRow = nNewY;
1640 const ScMergeAttr* pMergeAttr = &pPattern->GetItem(ATTR_MERGE);
1642 if (pMergeAttr->GetColMerge() > 1)
1643 nEditEndCol += pMergeAttr->GetColMerge() - 1;
1645 if (pMergeAttr->GetRowMerge() > 1)
1646 nEditEndRow += pMergeAttr->GetRowMerge() - 1;
1648
1649 // For growing use only the alignment value from the attribute, numbers
1650 // (existing or started) with default alignment extend to the right.
1651 bool bGrowCentered = ( eJust == SvxCellHorJustify::Center );
1652 bool bGrowToLeft = ( eJust == SvxCellHorJustify::Right ); // visual left
1653 bool bLOKRTLInvert = (bLOKActive && bLayoutRTL);
1654 if ( bAsianVertical )
1655 bGrowCentered = bGrowToLeft = false; // keep old behavior for asian mode
1656
1657 tools::Long nSizeXPix, nSizeXPTwips = 0;
1658
1659 const tools::Long nGridWidthPx = pView->GetGridWidth(eHWhich);
1660 const tools::Long nGridHeightPx = pView->GetGridHeight(eVWhich);
1661 tools::Long nGridWidthTwips = 0, nGridHeightTwips = 0;
1662 if (bLOKPrintTwips)
1663 {
1664 Size aGridSize(nGridWidthPx, nGridHeightPx);
1665 const MapMode& rWinMapMode = GetLogicMode();
1666 aGridSize = OutputDevice::LogicToLogic(
1667 pWin->PixelToLogic(aGridSize, rWinMapMode),
1668 rWinMapMode, MapMode(MapUnit::MapTwip));
1669 nGridWidthTwips = aGridSize.Width();
1670 nGridHeightTwips = aGridSize.Height();
1671 }
1672
1673 if (bBreak && !bAsianVertical)
1674 {
1675 nSizeXPix = aPixRect.GetWidth(); // papersize -> no horizontal scrolling
1676 if (bLOKPrintTwips)
1677 nSizeXPTwips = aPTwipsRect.GetWidth();
1678 }
1679 else
1680 {
1681 OSL_ENSURE(pView,"no View for EditView");
1682
1683 if ( bGrowCentered )
1684 {
1685 // growing into both directions until one edge is reached
1687 tools::Long nLeft = aPixRect.Left();
1688 tools::Long nRight = nGridWidthPx - aPixRect.Right();
1689 nSizeXPix = aPixRect.GetWidth() + 2 * std::min( nLeft, nRight );
1690 if (bLOKPrintTwips)
1691 {
1692 tools::Long nLeftPTwips = aPTwipsRect.Left();
1693 tools::Long nRightPTwips = nGridWidthTwips - aPTwipsRect.Right();
1694 nSizeXPTwips = aPTwipsRect.GetWidth() + 2 * std::min(nLeftPTwips, nRightPTwips);
1695 }
1696 }
1697 else if ( (bGrowToLeft && !bLOKRTLInvert) || (!bGrowToLeft && bLOKRTLInvert) )
1698 {
1699 nSizeXPix = aPixRect.Right(); // space that's available in the window when growing to the left
1700 if (bLOKPrintTwips)
1701 nSizeXPTwips = aPTwipsRect.Right();
1702 }
1703 else
1704 {
1705 nSizeXPix = nGridWidthPx - aPixRect.Left();
1706 if (bLOKPrintTwips)
1707 nSizeXPTwips = nGridWidthTwips - aPTwipsRect.Left();
1708 }
1709
1710 if ( nSizeXPix <= 0 )
1711 {
1712 nSizeXPix = aPixRect.GetWidth(); // editing outside to the right of the window -> keep cell width
1713 if (bLOKPrintTwips)
1714 nSizeXPTwips = aPTwipsRect.GetWidth();
1715 }
1716 }
1717 OSL_ENSURE(pView,"no View for EditView");
1718 tools::Long nSizeYPix = nGridHeightPx - aPixRect.Top();
1719 tools::Long nSizeYPTwips = bLOKPrintTwips ? (nGridHeightTwips - aPTwipsRect.Top()) : 0;
1720
1721 if ( nSizeYPix <= 0 )
1722 {
1723 nSizeYPix = aPixRect.GetHeight(); // editing outside below the window -> keep cell height
1724 if (bLOKPrintTwips)
1725 nSizeYPTwips = aPTwipsRect.GetHeight();
1726 }
1727
1728 Size aPaperSize = pView->GetActiveWin()->PixelToLogic( Size( nSizeXPix, nSizeYPix ), GetLogicMode() );
1729 Size aPaperSizePTwips(nSizeXPTwips, nSizeYPTwips);
1730 if ( bBreak && !bAsianVertical && SC_MOD()->GetInputOptions().GetTextWysiwyg() )
1731 {
1732 // if text is formatted for printer, use the exact same paper width
1733 // (and same line breaks) as for output.
1734
1735 Fraction aFract(1,1);
1737 tools::Rectangle aUtilRect = ScEditUtil(&mrDoc, nNewX, nNewY, nTabNo, Point(0, 0), pWin->GetOutDev(),
1738 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( pPattern, false );
1739 aPaperSize.setWidth( aUtilRect.GetWidth() );
1740 if (bLOKPrintTwips)
1741 {
1742 aPaperSizePTwips.setWidth(o3tl::convert(aUtilRect.GetWidth(), o3tl::Length::mm100, o3tl::Length::twip));
1743 }
1744 }
1745
1746 pNewEngine->SetPaperSize( aPaperSize );
1747 if (bLOKPrintTwips)
1748 pNewEngine->SetLOKSpecialPaperSize(aPaperSizePTwips);
1749
1750 // sichtbarer Ausschnitt
1751 Size aPaper = pNewEngine->GetPaperSize();
1752 tools::Rectangle aVis = pEditView[eWhich]->GetVisArea();
1753 tools::Rectangle aVisPTwips;
1754 if (bLOKPrintTwips)
1755 aVisPTwips = pEditView[eWhich]->GetLOKSpecialVisArea();
1756
1757 tools::Long nDiff = aVis.Right() - aVis.Left();
1758 tools::Long nDiffPTwips = bLOKPrintTwips ? (aVisPTwips.Right() - aVisPTwips.Left()) : 0;
1759 if ( GetEditAdjust() == SvxAdjust::Right )
1760 {
1761 aVis.SetRight( aPaper.Width() - 1 );
1762 if (bLOKPrintTwips)
1763 aVisPTwips.SetRight( aPaperSizePTwips.Width() - 1 );
1764 bMoveArea = !bLayoutRTL;
1765 }
1766 else if ( GetEditAdjust() == SvxAdjust::Center )
1767 {
1768 aVis.SetRight( ( aPaper.Width() - 1 + nDiff ) / 2 );
1769 if (bLOKPrintTwips)
1770 aVisPTwips.SetRight( ( aPaperSizePTwips.Width() - 1 + nDiffPTwips ) / 2 );
1771 bMoveArea = true; // always
1772 }
1773 else
1774 {
1775 aVis.SetRight( nDiff );
1776 if (bLOKPrintTwips)
1777 aVisPTwips.SetRight(nDiffPTwips);
1778 bMoveArea = bLayoutRTL;
1779 }
1780 aVis.SetLeft( aVis.Right() - nDiff );
1781 if (bLOKPrintTwips)
1782 aVisPTwips.SetLeft(aVisPTwips.Right() - nDiffPTwips);
1783 // #i49561# Important note:
1784 // The set offset of the visible area of the EditView for centered and
1785 // right alignment in horizontal layout is consider by instances of
1786 // class <ScEditObjectViewForwarder> in its methods <LogicToPixel(..)>
1787 // and <PixelToLogic(..)>. This is needed for the correct visibility
1788 // of paragraphs in edit mode at the accessibility API.
1789 pEditView[eWhich]->SetVisArea(aVis);
1790 if (bLOKPrintTwips)
1791 pEditView[eWhich]->SetLOKSpecialVisArea(aVisPTwips);
1792 // UpdateMode has been disabled in ScInputHandler::StartTable
1793 // must be enabled before EditGrowY (GetTextHeight)
1794 pNewEngine->SetUpdateLayout( true );
1795
1796 pNewEngine->SetStatusEventHdl( LINK( this, ScViewData, EditEngineHdl ) );
1797
1798 EditGrowY( true ); // adjust to existing text content
1799 EditGrowX();
1800
1801 Point aDocPos = pEditView[eWhich]->GetWindowPosTopLeft(0);
1802 if (aDocPos.Y() < aOutputArea.Top())
1803 pEditView[eWhich]->Scroll( 0, aOutputArea.Top() - aDocPos.Y() );
1804 }
1805
1806 // here bEditActive needs to be set already
1807 // (due to Map-Mode during Paint)
1808 if (!bWasThere)
1809 pNewEngine->InsertView(pEditView[eWhich].get());
1810
1811 // background color of the cell
1812 Color aBackCol = pPattern->GetItem(ATTR_BACKGROUND).GetColor();
1813
1814 ScModule* pScMod = SC_MOD();
1815 if ( aBackCol.IsTransparent() )
1816 {
1818 }
1819 pEditView[eWhich]->SetBackgroundColor( aBackCol );
1820
1821 pEditView[eWhich]->Invalidate(); // needed?
1822 // needed, if position changed
1823}
1824
1825IMPL_LINK( ScViewData, EditEngineHdl, EditStatus&, rStatus, void )
1826{
1827 EditStatusFlags nStatus = rStatus.GetStatusWord();
1828 if (nStatus & (EditStatusFlags::HSCROLL | EditStatusFlags::TextHeightChanged | EditStatusFlags::TEXTWIDTHCHANGED | EditStatusFlags::CURSOROUT))
1829 {
1830 EditGrowY();
1831 EditGrowX();
1832
1833 if (nStatus & EditStatusFlags::CURSOROUT)
1834 {
1835 ScSplitPos eWhich = GetActivePart();
1836 if (pEditView[eWhich])
1837 pEditView[eWhich]->ShowCursor(false);
1838 }
1839 }
1840}
1841
1843{
1844 // It is insane to call EditGrowX while the output area is already growing.
1845 // That could occur because of the call to SetDefaultItem later.
1846 // We end up with wrong start/end edit columns and the changes
1847 // to the output area performed by the inner call to this method are
1848 // useless since they are discarded by the outer call.
1849 if (bGrowing)
1850 return;
1851
1853
1854 bool bLOKActive = comphelper::LibreOfficeKit::isActive();
1855 bool bLOKPrintTwips = bLOKActive && comphelper::LibreOfficeKit::isCompatFlagSet(
1856 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
1857
1858 ScDocument& rLocalDoc = GetDocument();
1859
1860 ScSplitPos eWhich = GetActivePart();
1861 ScHSplitPos eHWhich = WhichH(eWhich);
1862 EditView* pCurView = pEditView[eWhich].get();
1863
1864 if ( !pCurView || !bEditActive[eWhich])
1865 return;
1866
1867 bool bLayoutRTL = rLocalDoc.IsLayoutRTL( nTabNo );
1868
1869 ScEditEngineDefaulter* pEngine =
1870 static_cast<ScEditEngineDefaulter*>( pCurView->GetEditEngine() );
1871 vcl::Window* pWin = pCurView->GetWindow();
1872
1873 // Get the left- and right-most column positions.
1874 SCCOL nLeft = GetPosX(eHWhich);
1875 SCCOL nRight = nLeft + VisibleCellsX(eHWhich);
1876
1877 Size aSize = pEngine->GetPaperSize();
1878 Size aSizePTwips;
1879 if (bLOKPrintTwips)
1880 aSizePTwips = pEngine->GetLOKSpecialPaperSize();
1881
1882 tools::Rectangle aArea = pCurView->GetOutputArea();
1883 tools::Rectangle aAreaPTwips;
1884 if (bLOKPrintTwips)
1885 aAreaPTwips = pCurView->GetLOKSpecialOutputArea();
1886
1887 tools::Long nOldRight = aArea.Right();
1888
1889 // Margin is already included in the original width.
1890 tools::Long nTextWidth = pEngine->CalcTextWidth();
1891
1892 bool bChanged = false;
1893 bool bAsianVertical = pEngine->IsEffectivelyVertical();
1894
1895 // get bGrow... variables the same way as in SetEditEngine
1896 const ScPatternAttr* pPattern = rLocalDoc.GetPattern( nEditCol, nEditRow, nTabNo );
1897 SvxCellHorJustify eJust = pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue();
1898 bool bGrowCentered = ( eJust == SvxCellHorJustify::Center );
1899 bool bGrowToLeft = ( eJust == SvxCellHorJustify::Right ); // visual left
1900 bool bGrowBackwards = bGrowToLeft; // logical left
1901 if ( bLayoutRTL )
1902 bGrowBackwards = !bGrowBackwards; // invert on RTL sheet
1903 if ( bAsianVertical )
1904 bGrowCentered = bGrowToLeft = bGrowBackwards = false; // keep old behavior for asian mode
1905
1906 bool bUnevenGrow = false;
1907 if ( bGrowCentered )
1908 {
1909 while (aArea.GetWidth() + 0 < nTextWidth && ( nEditStartCol > nLeft || nEditEndCol < nRight ) )
1910 {
1911 tools::Long nLogicLeft = 0;
1912 tools::Long nLogicLeftPTwips = 0;
1913 if ( nEditStartCol > nLeft )
1914 {
1915 --nEditStartCol;
1916 tools::Long nColWidth = rLocalDoc.GetColWidth( nEditStartCol, nTabNo );
1917 tools::Long nLeftPix = ToPixel( nColWidth, nPPTX );
1918 nLogicLeft = pWin->PixelToLogic(Size(nLeftPix,0)).Width();
1919 if (bLOKPrintTwips)
1920 nLogicLeftPTwips = nColWidth;
1921 }
1922 tools::Long nLogicRight = 0;
1923 tools::Long nLogicRightPTwips = 0;
1924 if ( nEditEndCol < nRight )
1925 {
1926 ++nEditEndCol;
1927 tools::Long nColWidth = rLocalDoc.GetColWidth( nEditEndCol, nTabNo );
1928 tools::Long nRightPix = ToPixel( nColWidth, nPPTX );
1929 nLogicRight = pWin->PixelToLogic(Size(nRightPix,0)).Width();
1930 if (bLOKPrintTwips)
1931 nLogicRightPTwips = nColWidth;
1932 }
1933
1934 aArea.AdjustLeft( -((bLayoutRTL && !bLOKActive) ? nLogicRight : nLogicLeft) );
1935 aArea.AdjustRight((bLayoutRTL && !bLOKActive) ? nLogicLeft : nLogicRight );
1936 if (bLOKPrintTwips)
1937 {
1938 aAreaPTwips.AdjustLeft(-nLogicLeftPTwips);
1939 aAreaPTwips.AdjustRight(nLogicRightPTwips);
1940 }
1941
1942 if ( aArea.Right() > aArea.Left() + aSize.Width() - 1 )
1943 {
1944 tools::Long nCenter = ( aArea.Left() + aArea.Right() ) / 2;
1945 tools::Long nHalf = aSize.Width() / 2;
1946 aArea.SetLeft( nCenter - nHalf + 1 );
1947 aArea.SetRight( nCenter + aSize.Width() - nHalf - 1 );
1948
1949 if (bLOKPrintTwips)
1950 {
1951 tools::Long nCenterPTwips = ( aAreaPTwips.Left() + aAreaPTwips.Right() ) / 2;
1952 tools::Long nHalfPTwips = aSizePTwips.Width() / 2;
1953 aAreaPTwips.SetLeft( nCenterPTwips - nHalfPTwips + 1 );
1954 aAreaPTwips.SetRight( nCenterPTwips + aSizePTwips.Width() - nHalfPTwips - 1 );
1955 }
1956 }
1957
1958 bChanged = true;
1959 if ( nLogicLeft != nLogicRight )
1960 bUnevenGrow = true;
1961 }
1962 }
1963 else if ( bGrowBackwards )
1964 {
1965 while (aArea.GetWidth() + 0 < nTextWidth && nEditStartCol > nLeft)
1966 {
1967 --nEditStartCol;
1968 tools::Long nColWidth = rLocalDoc.GetColWidth( nEditStartCol, nTabNo );
1969 tools::Long nPix = ToPixel( nColWidth, nPPTX );
1970 tools::Long nLogicWidth = pWin->PixelToLogic(Size(nPix,0)).Width();
1971 tools::Long& nLogicWidthPTwips = nColWidth;
1972
1973 if ( !bLayoutRTL || bLOKActive )
1974 {
1975 aArea.AdjustLeft( -nLogicWidth );
1976 if (bLOKPrintTwips)
1977 aAreaPTwips.AdjustLeft( -nLogicWidthPTwips );
1978 }
1979 else
1980 {
1981 aArea.AdjustRight(nLogicWidth );
1982 if (bLOKPrintTwips)
1983 aAreaPTwips.AdjustRight(nLogicWidthPTwips);
1984 }
1985
1986 if ( aArea.Right() > aArea.Left() + aSize.Width() - 1 )
1987 {
1988 if ( !bLayoutRTL || bLOKActive )
1989 {
1990 aArea.SetLeft( aArea.Right() - aSize.Width() + 1 );
1991 if (bLOKPrintTwips)
1992 aAreaPTwips.SetLeft( aAreaPTwips.Right() - aSizePTwips.Width() + 1 );
1993 }
1994 else
1995 {
1996 aArea.SetRight( aArea.Left() + aSize.Width() - 1 );
1997 if (bLOKPrintTwips)
1998 aAreaPTwips.SetRight( aAreaPTwips.Left() + aSizePTwips.Width() - 1 );
1999 }
2000 }
2001
2002 bChanged = true;
2003 }
2004 }
2005 else
2006 {
2007 while (aArea.GetWidth() + 0 < nTextWidth && nEditEndCol < nRight)
2008 {
2009 ++nEditEndCol;
2010 tools::Long nColWidth = rLocalDoc.GetColWidth( nEditEndCol, nTabNo );
2011 tools::Long nPix = ToPixel( nColWidth, nPPTX );
2012 tools::Long nLogicWidth = pWin->PixelToLogic(Size(nPix,0)).Width();
2013 tools::Long& nLogicWidthPTwips = nColWidth;
2014 if ( bLayoutRTL && !bLOKActive )
2015 {
2016 aArea.AdjustLeft( -nLogicWidth );
2017 }
2018 else
2019 {
2020 aArea.AdjustRight(nLogicWidth );
2021 if (bLOKPrintTwips)
2022 aAreaPTwips.AdjustRight(nLogicWidthPTwips);
2023 }
2024
2025 if ( aArea.Right() > aArea.Left() + aSize.Width() - 1 )
2026 {
2027 if ( bLayoutRTL && !bLOKActive )
2028 {
2029 aArea.SetLeft( aArea.Right() - aSize.Width() + 1 );
2030 }
2031 else
2032 {
2033 aArea.SetRight( aArea.Left() + aSize.Width() - 1 );
2034 if (bLOKPrintTwips)
2035 aAreaPTwips.SetRight( aAreaPTwips.Left() + aSizePTwips.Width() - 1 );
2036 }
2037 }
2038
2039 bChanged = true;
2040 }
2041 }
2042
2043 if (!bChanged)
2044 return;
2045
2046 if ( bMoveArea || bGrowCentered || bGrowBackwards || bLayoutRTL )
2047 {
2048 tools::Rectangle aVis = pCurView->GetVisArea();
2049 tools::Rectangle aVisPTwips;
2050 if (bLOKPrintTwips)
2051 aVisPTwips = pCurView->GetLOKSpecialVisArea();
2052
2053 if ( bGrowCentered )
2054 {
2055 // switch to center-aligned (undo?) and reset VisArea to center
2056
2057 pEngine->SetDefaultItem( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) );
2058
2059 tools::Long nCenter = aSize.Width() / 2;
2060 tools::Long nVisSize = aArea.GetWidth();
2061 aVis.SetLeft( nCenter - nVisSize / 2 );
2062 aVis.SetRight( aVis.Left() + nVisSize - 1 );
2063
2064 if (bLOKPrintTwips)
2065 {
2066 tools::Long nCenterPTwips = aSizePTwips.Width() / 2;
2067 tools::Long nVisSizePTwips = aAreaPTwips.GetWidth();
2068 aVisPTwips.SetLeft( nCenterPTwips - nVisSizePTwips / 2 );
2069 aVisPTwips.SetRight( aVisPTwips.Left() + nVisSizePTwips - 1 );
2070 }
2071 }
2072 else if ( bGrowToLeft )
2073 {
2074 // switch to right-aligned (undo?) and reset VisArea to the right
2075
2076 pEngine->SetDefaultItem( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
2077
2078 aVis.SetRight( aSize.Width() - 1 );
2079 aVis.SetLeft( aSize.Width() - aArea.GetWidth() ); // with the new, increased area
2080
2081 if (bLOKPrintTwips)
2082 {
2083 aVisPTwips.SetRight( aSizePTwips.Width() - 1 );
2084 aVisPTwips.SetLeft( aSizePTwips.Width() - aAreaPTwips.GetWidth() ); // with the new, increased area
2085 }
2086 }
2087 else
2088 {
2089 // switch to left-aligned (undo?) and reset VisArea to the left
2090
2091 pEngine->SetDefaultItem( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
2092
2093 tools::Long nMove = aVis.Left();
2094 aVis.SetLeft( 0 );
2095 aVis.AdjustRight( -nMove );
2096
2097 if (bLOKPrintTwips)
2098 {
2099 tools::Long nMovePTwips = aVisPTwips.Left();
2100 aVisPTwips.SetLeft( 0 );
2101 aVisPTwips.AdjustRight( -nMovePTwips );
2102 }
2103 }
2104
2105 pCurView->SetVisArea( aVis );
2106 if (bLOKPrintTwips)
2107 pCurView->SetLOKSpecialVisArea( aVisPTwips );
2108
2109 bMoveArea = false;
2110 }
2111
2112 if (bLOKPrintTwips)
2113 pCurView->SetLOKSpecialOutputArea(aAreaPTwips);
2114
2115 pCurView->SetOutputArea(aArea);
2116
2117 // In vertical mode, the whole text is moved to the next cell (right-aligned),
2118 // so everything must be repainted. Otherwise, paint only the new area.
2119 // If growing in centered alignment, if the cells left and right have different sizes,
2120 // the whole text will move, and may not even obscure all of the original display.
2121 if ( bUnevenGrow )
2122 {
2123 aArea.SetLeft( pWin->PixelToLogic( Point(0,0) ).X() );
2124 aArea.SetRight( pWin->PixelToLogic( aScrSize ).Width() );
2125 }
2126 else if ( !bAsianVertical && !bGrowToLeft && !bGrowCentered )
2127 aArea.SetLeft( nOldRight );
2128 pWin->Invalidate(aArea);
2129
2130 // invalidate other views
2131 pCurView->InvalidateOtherViewWindows(aArea);
2132}
2133
2134void ScViewData::EditGrowY( bool bInitial )
2135{
2136 if (bGrowing)
2137 return;
2138
2140
2141 bool bLOKActive = comphelper::LibreOfficeKit::isActive();
2142 bool bLOKPrintTwips = bLOKActive && comphelper::LibreOfficeKit::isCompatFlagSet(
2143 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
2144
2145 ScSplitPos eWhich = GetActivePart();
2146 ScVSplitPos eVWhich = WhichV(eWhich);
2147 EditView* pCurView = pEditView[eWhich].get();
2148
2149 if ( !pCurView || !bEditActive[eWhich])
2150 return;
2151
2152 EVControlBits nControl = pEditView[eWhich]->GetControlWord();
2153 if ( nControl & EVControlBits::AUTOSCROLL )
2154 {
2155 // if end of screen had already been reached and scrolling enabled,
2156 // don't further try to grow the edit area
2157
2158 pCurView->SetOutputArea( pCurView->GetOutputArea() ); // re-align to pixels
2159 return;
2160 }
2161
2162 EditEngine* pEngine = pCurView->GetEditEngine();
2163 vcl::Window* pWin = pCurView->GetWindow();
2164
2165 SCROW nBottom = GetPosY(eVWhich) + VisibleCellsY(eVWhich);
2166
2167 Size aSize = pEngine->GetPaperSize();
2168 Size aSizePTwips;
2169 tools::Rectangle aArea = pCurView->GetOutputArea();
2170 tools::Rectangle aAreaPTwips;
2171
2172 if (bLOKPrintTwips)
2173 {
2174 aSizePTwips = pEngine->GetLOKSpecialPaperSize();
2175 aAreaPTwips = pCurView->GetLOKSpecialOutputArea();
2176 }
2177
2178 tools::Long nOldBottom = aArea.Bottom();
2179 tools::Long nTextHeight = pEngine->GetTextHeight();
2180
2181 // When editing a formula in a cell with optimal height, allow a larger portion
2182 // to be clipped before extending to following rows, to avoid obscuring cells for
2183 // reference input (next row is likely to be useful in formulas).
2184 tools::Long nAllowedExtra = SC_GROWY_SMALL_EXTRA;
2186 pEngine->GetParagraphCount() <= 1 )
2187 {
2188 // If the (only) paragraph starts with a '=', it's a formula.
2189 // If this is the initial call and the text is empty, allow the larger value, too,
2190 // because this occurs in the normal progress of editing a formula.
2191 // Subsequent calls with empty text might involve changed attributes (including
2192 // font height), so they are treated like normal text.
2193 OUString aText = pEngine->GetText( 0 );
2194 if ( ( aText.isEmpty() && bInitial ) || aText.startsWith("=") )
2195 nAllowedExtra = SC_GROWY_BIG_EXTRA;
2196 }
2197
2198 bool bChanged = false;
2199 bool bMaxReached = false;
2200 while (aArea.GetHeight() + nAllowedExtra < nTextHeight && nEditEndRow < nBottom && !bMaxReached)
2201 {
2202 ++nEditEndRow;
2203 ScDocument& rLocalDoc = GetDocument();
2204 tools::Long nRowHeight = rLocalDoc.GetRowHeight( nEditEndRow, nTabNo );
2205 tools::Long nPix = ToPixel( nRowHeight, nPPTY );
2206 aArea.AdjustBottom(pWin->PixelToLogic(Size(0,nPix)).Height() );
2207 if (bLOKPrintTwips)
2208 aAreaPTwips.AdjustBottom(nRowHeight);
2209
2210 if ( aArea.Bottom() > aArea.Top() + aSize.Height() - 1 )
2211 {
2212 aArea.SetBottom( aArea.Top() + aSize.Height() - 1 );
2213 if (bLOKPrintTwips)
2214 aAreaPTwips.SetBottom( aAreaPTwips.Top() + aSizePTwips.Height() - 1 );
2215 bMaxReached = true; // don't occupy more cells beyond paper size
2216 }
2217
2218 bChanged = true;
2219 nAllowedExtra = SC_GROWY_SMALL_EXTRA; // larger value is only for first row
2220 }
2221
2222 if (!bChanged)
2223 return;
2224
2225 if (bLOKPrintTwips)
2226 pCurView->SetLOKSpecialOutputArea(aAreaPTwips);
2227
2228 pCurView->SetOutputArea(aArea);
2229
2230 if (nEditEndRow >= nBottom || bMaxReached)
2231 {
2232 if (!(nControl & EVControlBits::AUTOSCROLL))
2233 pCurView->SetControlWord( nControl | EVControlBits::AUTOSCROLL );
2234 }
2235
2236 aArea.SetTop( nOldBottom );
2237 pWin->Invalidate(aArea);
2238
2239 // invalidate other views
2240 pCurView->InvalidateOtherViewWindows(aArea);
2241}
2242
2244{
2245 EditEngine* pEngine = nullptr;
2246 for (sal_uInt16 i=0; i<4; i++)
2247 if (pEditView[i])
2248 {
2249 if (bEditActive[i])
2250 {
2251 lcl_LOKRemoveWindow(GetViewShell(), static_cast<ScSplitPos>(i));
2252 pEngine = pEditView[i]->GetEditEngine();
2253 pEngine->RemoveView(pEditView[i].get());
2254 pEditView[i]->SetOutputArea( tools::Rectangle() );
2255 }
2256 bEditActive[i] = false;
2257 }
2258
2259 if (pEngine)
2261}
2262
2264{
2265 EditEngine* pEngine = nullptr;
2266 for (sal_uInt16 i=0; i<4; i++)
2267 if (pEditView[i])
2268 {
2269 if (bEditActive[i])
2270 {
2271 pEngine = pEditView[i]->GetEditEngine();
2272 if (pEngine)
2273 pEngine->RemoveView(pEditView[i].get());
2274 }
2275 pEditView[i].reset();
2276 }
2277}
2278
2279void ScViewData::GetEditView( ScSplitPos eWhich, EditView*& rViewPtr, SCCOL& rCol, SCROW& rRow )
2280{
2281 rViewPtr = pEditView[eWhich].get();
2282 rCol = nEditCol;
2283 rRow = nEditRow;
2284}
2285
2287{
2288 EnsureTabDataSize(nNewTab + 1);
2289
2290 if (!maTabData[nNewTab])
2291 {
2292 maTabData[nNewTab].reset(new ScViewDataTable(&mrDoc));
2293
2294 maTabData[nNewTab]->eZoomType = eDefZoomType;
2295 maTabData[nNewTab]->aZoomX = aDefZoomX;
2296 maTabData[nNewTab]->aZoomY = aDefZoomY;
2297 maTabData[nNewTab]->aPageZoomX = aDefPageZoomX;
2298 maTabData[nNewTab]->aPageZoomY = aDefPageZoomY;
2299 }
2300}
2301
2303{
2304 for (const auto& rTab : maMarkData)
2305 CreateTabData(rTab);
2306}
2307
2309{
2310 if (nSize > maTabData.size())
2311 maTabData.resize(nSize);
2312}
2313
2315{
2316 if (!ValidTab(nNewTab))
2317 {
2318 OSL_FAIL("wrong sheet number");
2319 return;
2320 }
2321
2322 nTabNo = nNewTab;
2324 pThisTab = maTabData[nTabNo].get();
2325
2326 CalcPPT(); // for common column width correction
2327 RecalcPixPos();
2328}
2329
2331{
2332 if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())) ||
2333 !maTabData[nTabIndex])
2334 {
2335 return nullptr;
2336 }
2337 return &(maTabData[nTabIndex]->aWidthHelper);
2338}
2339
2341{
2342 if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())) ||
2343 !maTabData[nTabIndex])
2344 {
2345 return nullptr;
2346 }
2347 return &(maTabData[nTabIndex]->aHeightHelper);
2348}
2349
2351{
2352 pThisTab->eWhichActive = eNewActive;
2353
2354 // Let's hope we find the culprit for tdf#117093
2355 // Don't sanitize the real value (yet?) because this function might be
2356 // called before setting the then corresponding split modes. For which in
2357 // fact then the order should be changed.
2358 assert(eNewActive == pThisTab->SanitizeWhichActive());
2359}
2360
2361Point ScViewData::GetScrPos( SCCOL nWhereX, SCROW nWhereY, ScHSplitPos eWhich ) const
2362{
2363 OSL_ENSURE( eWhich==SC_SPLIT_LEFT || eWhich==SC_SPLIT_RIGHT, "wrong position" );
2365 return GetScrPos( nWhereX, nWhereY, ePos );
2366}
2367
2368Point ScViewData::GetScrPos( SCCOL nWhereX, SCROW nWhereY, ScVSplitPos eWhich ) const
2369{
2370 OSL_ENSURE( eWhich==SC_SPLIT_TOP || eWhich==SC_SPLIT_BOTTOM, "wrong position" );
2372 return GetScrPos( nWhereX, nWhereY, ePos );
2373}
2374
2376 bool bAllowNeg, SCTAB nForTab ) const
2377{
2378 ScHSplitPos eWhichX = SC_SPLIT_LEFT;
2379 ScVSplitPos eWhichY = SC_SPLIT_BOTTOM;
2380 switch( eWhich )
2381 {
2382 case SC_SPLIT_TOPLEFT:
2383 eWhichX = SC_SPLIT_LEFT;
2384 eWhichY = SC_SPLIT_TOP;
2385 break;
2386 case SC_SPLIT_TOPRIGHT:
2387 eWhichX = SC_SPLIT_RIGHT;
2388 eWhichY = SC_SPLIT_TOP;
2389 break;
2391 eWhichX = SC_SPLIT_LEFT;
2392 eWhichY = SC_SPLIT_BOTTOM;
2393 break;
2395 eWhichX = SC_SPLIT_RIGHT;
2396 eWhichY = SC_SPLIT_BOTTOM;
2397 break;
2398 }
2399
2400 if (nForTab == -1)
2401 nForTab = nTabNo;
2402 bool bForCurTab = (nForTab == nTabNo);
2403 if (!bForCurTab && (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size()))))
2404 {
2405 SAL_WARN("sc.viewdata", "ScViewData::GetScrPos : invalid nForTab = " << nForTab);
2406 nForTab = nTabNo;
2407 bForCurTab = true;
2408 }
2409
2410 ScViewDataTable* pViewTable = bForCurTab ? pThisTab : maTabData[nForTab].get();
2411
2412 if (pView)
2413 {
2414 const_cast<ScViewData*>(this)->aScrSize.setWidth( pView->GetGridWidth(eWhichX) );
2415 const_cast<ScViewData*>(this)->aScrSize.setHeight( pView->GetGridHeight(eWhichY) );
2416 }
2417
2418 sal_uInt16 nTSize;
2419 bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
2420
2421 SCCOL nPosX = GetPosX(eWhichX, nForTab);
2422 tools::Long nScrPosX = 0;
2423
2424 if (bAllowNeg || nWhereX >= nPosX)
2425 {
2426 SCROW nStartPosX = nPosX;
2427 if (bIsTiledRendering)
2428 {
2429 OSL_ENSURE(nPosX == 0, "Unsupported case.");
2430 const auto& rNearest = pViewTable->aWidthHelper.getNearestByIndex(nWhereX - 1);
2431 nStartPosX = rNearest.first + 1;
2432 nScrPosX = rNearest.second;
2433 }
2434
2435 if (nWhereX >= nStartPosX)
2436 {
2437 for (SCCOL nX = nStartPosX; nX < nWhereX && (bAllowNeg || bIsTiledRendering || nScrPosX <= aScrSize.Width()); nX++)
2438 {
2439 if (nX > mrDoc.MaxCol())
2440 nScrPosX = 0x7FFFFFFF;
2441 else
2442 {
2443 nTSize = mrDoc.GetColWidth(nX, nForTab);
2444 if (nTSize)
2445 {
2446 tools::Long nSizeXPix = ToPixel( nTSize, nPPTX );
2447 nScrPosX += nSizeXPix;
2448 }
2449 else
2450 { // If the width is zero, the column is possibly hidden, skips groups of such columns.
2451 SCCOL lastHidden = -1;
2452 if(mrDoc.ColHidden(nX, nForTab, nullptr, &lastHidden) && lastHidden > nX)
2453 nX = lastHidden - 1;
2454 }
2455 }
2456 }
2457 }
2458 else
2459 {
2460 for (SCCOL nX = nStartPosX; nX > nWhereX;)
2461 {
2462 --nX;
2463 nTSize = mrDoc.GetColWidth(nX, nForTab);
2464 if (nTSize)
2465 {
2466 tools::Long nSizeXPix = ToPixel( nTSize, nPPTX );
2467 nScrPosX -= nSizeXPix;
2468 }
2469 else
2470 { // If the width is zero, the column is possibly hidden, skips groups of such columns.
2471 SCCOL firstHidden = -1;
2472 if(mrDoc.ColHidden(nX, nForTab, &firstHidden, nullptr) && firstHidden >= 0)
2473 nX = firstHidden;
2474 }
2475 }
2476 }
2477
2478 }
2479
2480
2481 SCROW nPosY = GetPosY(eWhichY, nForTab);
2482 tools::Long nScrPosY = 0;
2483
2484 if (bAllowNeg || nWhereY >= nPosY)
2485 {
2486 SCROW nStartPosY = nPosY;
2487 if (bIsTiledRendering)
2488 {
2489 OSL_ENSURE(nPosY == 0, "Unsupported case.");
2490 const auto& rNearest = pViewTable->aHeightHelper.getNearestByIndex(nWhereY - 1);
2491 nStartPosY = rNearest.first + 1;
2492 nScrPosY = rNearest.second;
2493 }
2494
2495 if (nWhereY >= nStartPosY)
2496 {
2497 for (SCROW nY = nStartPosY; nY < nWhereY && (bAllowNeg || bIsTiledRendering || nScrPosY <= aScrSize.Height()); nY++)
2498 {
2499 if ( nY > mrDoc.MaxRow() )
2500 nScrPosY = 0x7FFFFFFF;
2501 else
2502 {
2503 nTSize = mrDoc.GetRowHeight( nY, nTabNo );
2504 if (nTSize)
2505 {
2506 tools::Long nSizeYPix = ToPixel( nTSize, nPPTY );
2507 nScrPosY += nSizeYPix;
2508 }
2509 else if ( nY < mrDoc.MaxRow() )
2510 {
2511 // skip multiple hidden rows (forward only for now)
2512 SCROW nNext = mrDoc.FirstVisibleRow(nY + 1, mrDoc.MaxRow(), nTabNo);
2513 if ( nNext > mrDoc.MaxRow() )
2514 nY = mrDoc.MaxRow();
2515 else
2516 nY = nNext - 1; // +=nDir advances to next visible row
2517 }
2518 }
2519 }
2520 }
2521 else
2522 {
2523 for (SCROW nY = nStartPosY; nY > nWhereY;)
2524 {
2525 --nY;
2526 nTSize = mrDoc.GetRowHeight(nY, nForTab);
2527 if (nTSize)
2528 {
2529 tools::Long nSizeYPix = ToPixel( nTSize, nPPTY );
2530 nScrPosY -= nSizeYPix;
2531 }
2532 else
2533 { // If the height is zero, the row is possibly hidden, skips groups of such rows.
2534 SCROW firstHidden = -1;
2535 if(mrDoc.RowHidden(nY, nForTab, &firstHidden, nullptr) && firstHidden >= 0)
2536 nY = firstHidden;
2537 }
2538 }
2539 }
2540 }
2541
2542 if (mrDoc.IsLayoutRTL(nForTab) && !bIsTiledRendering)
2543 {
2544 // mirror horizontal position
2545 nScrPosX = aScrSize.Width() - 1 - nScrPosX;
2546 }
2547
2548 return Point( nScrPosX, nScrPosY );
2549}
2550
2552{
2553 // hidden ones are given 0 sizes by these by default.
2554 // TODO: rewrite this to loop over spans (matters for jumbosheets).
2555 tools::Long nPosX = nCol ? mrDoc.GetColWidth(0, nCol - 1, nTabNo) : 0;
2556 // This is now fast as it loops over spans.
2557 tools::Long nPosY = nRow ? mrDoc.GetRowHeight(0, nRow - 1, nTabNo) : 0;
2558 // TODO: adjust for RTL layout case.
2559
2560 return Point(nPosX, nPosY);
2561}
2562
2563Point ScViewData::GetPrintTwipsPosFromTileTwips(const Point& rTileTwipsPos) const
2564{
2565 const tools::Long nPixelX = static_cast<tools::Long>(rTileTwipsPos.X() * nPPTX);
2566 const tools::Long nPixelY = static_cast<tools::Long>(rTileTwipsPos.Y() * nPPTY);
2567 SCCOL nCol = 0;
2568 SCROW nRow = 0;
2569
2570 // The following call (with bTestMerge = false) will not modify any members.
2571 const_cast<ScViewData*>(this)->GetPosFromPixel(nPixelX, nPixelY, SC_SPLIT_TOPLEFT, nCol, nRow, false /* bTestMerge */);
2572 const Point aPixCellPos = GetScrPos(nCol, nRow, SC_SPLIT_TOPLEFT, true /* bAllowNeg */);
2573 const Point aTileTwipsCellPos(aPixCellPos.X() / nPPTX, aPixCellPos.Y() / nPPTY);
2574 const Point aPrintTwipsCellPos = GetPrintTwipsPos(nCol, nRow);
2575 return aPrintTwipsCellPos + (rTileTwipsPos - aTileTwipsCellPos);
2576}
2577
2578OString ScViewData::describeCellCursorAt(SCCOL nX, SCROW nY, bool bPixelAligned) const
2579{
2580 const bool bPosSizeInPixels = bPixelAligned;
2581 Point aCellPos = bPosSizeInPixels ? GetScrPos( nX, nY, SC_SPLIT_BOTTOMRIGHT, true ) :
2582 GetPrintTwipsPos(nX, nY);
2583
2584 tools::Long nSizeX;
2585 tools::Long nSizeY;
2586 if (bPosSizeInPixels)
2587 GetMergeSizePixel( nX, nY, nSizeX, nSizeY );
2588 else
2589 GetMergeSizePrintTwips(nX, nY, nSizeX, nSizeY);
2590
2592 if (bPosSizeInPixels)
2593 {
2594 double fPPTX = GetPPTX();
2595 double fPPTY = GetPPTY();
2596
2597 // make it a slim cell cursor, but not empty
2598 if (nSizeX == 0)
2599 nSizeX = 1;
2600
2601 if (nSizeY == 0)
2602 nSizeY = 1;
2603
2604 tools::Long nPosXTw = rtl::math::round(aCellPos.getX() / fPPTX);
2605 tools::Long nPosYTw = rtl::math::round(aCellPos.getY() / fPPTY);
2606 // look at Rectangle( const Point& rLT, const Size& rSize ) for the '- 1'
2607 tools::Long nSizeXTw = rtl::math::round(nSizeX / fPPTX) - 1;
2608 tools::Long nSizeYTw = rtl::math::round(nSizeY / fPPTY) - 1;
2609
2610 ss << nPosXTw << ", " << nPosYTw << ", " << nSizeXTw << ", " << nSizeYTw << ", "
2611 << nX << ", " << nY;
2612 }
2613 else
2614 {
2615 // look at Rectangle( const Point& rLT, const Size& rSize ) for the decrement.
2616 if (nSizeX)
2617 --nSizeX;
2618 if (nSizeY)
2619 --nSizeY;
2620 ss << aCellPos.getX() << ", " << aCellPos.getY()
2621 << ", " << nSizeX << ", " << nSizeY << ", "
2622 << nX << ", " << nY;
2623 }
2624
2625 return ss.str().c_str();
2626}
2627
2628// Number of cells on a screen
2629SCCOL ScViewData::CellsAtX( SCCOL nPosX, SCCOL nDir, ScHSplitPos eWhichX, sal_uInt16 nScrSizeX ) const
2630{
2631 OSL_ENSURE( nDir==1 || nDir==-1, "wrong CellsAt call" );
2632
2633 if (pView)
2634 const_cast<ScViewData*>(this)->aScrSize.setWidth( pView->GetGridWidth(eWhichX) );
2635
2636 SCCOL nX;
2637 sal_uInt16 nScrPosX = 0;
2638 if (nScrSizeX == SC_SIZE_NONE) nScrSizeX = static_cast<sal_uInt16>(aScrSize.Width());
2639
2640 if (nDir==1)
2641 nX = nPosX; // forwards
2642 else
2643 nX = nPosX-1; // backwards
2644
2645 bool bOut = false;
2646 for ( ; nScrPosX<=nScrSizeX && !bOut; nX = sal::static_int_cast<SCCOL>(nX + nDir) )
2647 {
2648 SCCOL nColNo = nX;
2649 if (nColNo < 0 || nColNo > mrDoc.MaxCol())
2650 bOut = true;
2651 else
2652 {
2653 sal_uInt16 nTSize = mrDoc.GetColWidth(nColNo, nTabNo);
2654 if (nTSize)
2655 {
2656 tools::Long nSizeXPix = ToPixel( nTSize, nPPTX );
2657 nScrPosX = sal::static_int_cast<sal_uInt16>( nScrPosX + static_cast<sal_uInt16>(nSizeXPix) );
2658 }
2659 }
2660 }
2661
2662 if (nDir==1)
2663 nX = sal::static_int_cast<SCCOL>( nX - nPosX );
2664 else
2665 nX = (nPosX-1)-nX;
2666
2667 if (nX>0) --nX;
2668 return nX;
2669}
2670
2671SCROW ScViewData::CellsAtY( SCROW nPosY, SCROW nDir, ScVSplitPos eWhichY, sal_uInt16 nScrSizeY ) const
2672{
2673 OSL_ENSURE( nDir==1 || nDir==-1, "wrong CellsAt call" );
2674
2675 if (pView)
2676 const_cast<ScViewData*>(this)->aScrSize.setHeight( pView->GetGridHeight(eWhichY) );
2677
2678 if (nScrSizeY == SC_SIZE_NONE) nScrSizeY = static_cast<sal_uInt16>(aScrSize.Height());
2679
2680 SCROW nY;
2681
2682 if (nDir==1)
2683 {
2684 // forward
2685 nY = nPosY;
2686 tools::Long nScrPosY = 0;
2687 AddPixelsWhile(nScrPosY, nScrSizeY, nY, mrDoc.MaxRow(), nPPTY, &mrDoc, nTabNo);
2688 // Original loop ended on last evaluated +1 or if that was MaxRow even on MaxRow+2.
2689 nY += (nY == mrDoc.MaxRow() ? 2 : 1);
2690 nY -= nPosY;
2691 }
2692 else
2693 {
2694 // backward
2695 nY = nPosY-1;
2696 tools::Long nScrPosY = 0;
2697 AddPixelsWhileBackward(nScrPosY, nScrSizeY, nY, 0, nPPTY, &mrDoc, nTabNo);
2698 // Original loop ended on last evaluated -1 or if that was 0 even on -2.
2699 nY -= (nY == 0 ? 2 : 1);
2700 nY = (nPosY-1)-nY;
2701 }
2702
2703 if (nY>0) --nY;
2704 return nY;
2705}
2706
2708{
2709 return CellsAtX( GetPosX( eWhichX ), 1, eWhichX );
2710}
2711
2713{
2714 return CellsAtY( GetPosY( eWhichY ), 1, eWhichY );
2715}
2716
2718{
2719 return CellsAtX( GetPosX( eWhichX ), -1, eWhichX );
2720}
2721
2723{
2724 return CellsAtY( GetPosY( eWhichY ), -1, eWhichY );
2725}
2726
2727bool ScViewData::GetMergeSizePixel( SCCOL nX, SCROW nY, tools::Long& rSizeXPix, tools::Long& rSizeYPix ) const
2728{
2729 const ScMergeAttr* pMerge = mrDoc.GetAttr(nX, nY, nTabNo, ATTR_MERGE);
2730 if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
2731 {
2732 tools::Long nOutWidth = 0;
2733 tools::Long nOutHeight = 0;
2734 SCCOL nCountX = pMerge->GetColMerge();
2735 for (SCCOL i=0; i<nCountX; i++)
2736 nOutWidth += ToPixel(mrDoc.GetColWidth(nX + i, nTabNo), nPPTX);
2737 SCROW nCountY = pMerge->GetRowMerge();
2738
2739 for (SCROW nRow = nY; nRow <= nY+nCountY-1; ++nRow)
2740 {
2741 SCROW nLastRow = nRow;
2742 if (mrDoc.RowHidden(nRow, nTabNo, nullptr, &nLastRow))
2743 {
2744 nRow = nLastRow;
2745 continue;
2746 }
2747
2748 sal_uInt16 nHeight = mrDoc.GetRowHeight(nRow, nTabNo);
2749 nOutHeight += ToPixel(nHeight, nPPTY);
2750 }
2751
2752 rSizeXPix = nOutWidth;
2753 rSizeYPix = nOutHeight;
2754 return true;
2755 }
2756 else
2757 {
2758 rSizeXPix = ToPixel(mrDoc.GetColWidth(nX, nTabNo), nPPTX);
2759 rSizeYPix = ToPixel(mrDoc.GetRowHeight(nY, nTabNo), nPPTY);
2760 return false;
2761 }
2762}
2763
2764bool ScViewData::GetMergeSizePrintTwips(SCCOL nX, SCROW nY, tools::Long& rSizeXTwips, tools::Long& rSizeYTwips) const
2765{
2766 const ScMergeAttr* pMerge = mrDoc.GetAttr(nX, nY, nTabNo, ATTR_MERGE);
2767 SCCOL nCountX = pMerge->GetColMerge();
2768 if (!nCountX)
2769 nCountX = 1;
2770 rSizeXTwips = mrDoc.GetColWidth(nX, nX + nCountX - 1, nTabNo);
2771
2772 SCROW nCountY = pMerge->GetRowMerge();
2773 if (!nCountY)
2774 nCountY = 1;
2775 rSizeYTwips = mrDoc.GetRowHeight(nY, nY + nCountY - 1, nTabNo);
2776
2777 return (nCountX > 1 || nCountY > 1);
2778}
2779
2781 SCCOL& rPosX, SCROW& rPosY,
2782 bool bTestMerge, bool bRepair, SCTAB nForTab )
2783{
2784 // special handling of 0 is now in ScViewFunctionSet::SetCursorAtPoint
2785
2786 if (nForTab == -1)
2787 nForTab = nTabNo;
2788 bool bForCurTab = (nForTab == nTabNo);
2789 if (!bForCurTab && (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size()))))
2790 {
2791 SAL_WARN("sc.viewdata", "ScViewData::GetPosFromPixel : invalid nForTab = " << nForTab);
2792 nForTab = nTabNo;
2793 bForCurTab = true;
2794 }
2795
2796 ScHSplitPos eHWhich = WhichH(eWhich);
2797 ScVSplitPos eVWhich = WhichV(eWhich);
2798
2799 if (mrDoc.IsLayoutRTL(nForTab))
2800 {
2802 {
2803 // mirror horizontal position
2804 if (pView)
2805 aScrSize.setWidth( pView->GetGridWidth(eHWhich) );
2806 nClickX = aScrSize.Width() - 1 - nClickX;
2807 }
2808 }
2809
2810 SCCOL nStartPosX = GetPosX(eHWhich, nForTab);
2811 SCROW nStartPosY = GetPosY(eVWhich, nForTab);
2812 rPosX = nStartPosX;
2813 rPosY = nStartPosY;
2814 tools::Long nScrX = 0;
2815 tools::Long nScrY = 0;
2816
2817 if (nClickX > 0)
2818 {
2819 while (rPosX <= mrDoc.MaxCol() && nClickX >= nScrX)
2820 {
2821 nScrX += ToPixel(mrDoc.GetColWidth(rPosX, nForTab), nPPTX);
2822 ++rPosX;
2823 }
2824 --rPosX;
2825 }
2826 else
2827 {
2828 while ( rPosX>0 && nClickX < nScrX )
2829 {
2830 --rPosX;
2831 nScrX -= ToPixel(mrDoc.GetColWidth(rPosX, nForTab), nPPTX);
2832 }
2833 }
2834
2835 if (nClickY > 0)
2836 AddPixelsWhile(nScrY, nClickY, rPosY, mrDoc.MaxRow(), nPPTY, &mrDoc, nForTab);
2837 else
2838 {
2839 /* TODO: could need some "SubPixelsWhileBackward" method */
2840 while ( rPosY>0 && nClickY < nScrY )
2841 {
2842 --rPosY;
2843 nScrY -= ToPixel(mrDoc.GetRowHeight(rPosY, nForTab), nPPTY);
2844 }
2845 }
2846
2847 // cells too big?
2848 if ( rPosX == nStartPosX && nClickX > 0 )
2849 {
2850 if (pView)
2851 aScrSize.setWidth( pView->GetGridWidth(eHWhich) );
2852 if ( nClickX > aScrSize.Width() )
2853 ++rPosX;
2854 }
2855 if ( rPosY == nStartPosY && nClickY > 0 )
2856 {
2857 if (pView)
2859 if ( nClickY > aScrSize.Height() )
2860 ++rPosY;
2861 }
2862
2863 rPosX = std::clamp(rPosX, SCCOL(0), mrDoc.MaxCol());
2864 rPosY = std::clamp(rPosY, SCROW(0), mrDoc.MaxRow());
2865
2866 if (!(bTestMerge && bForCurTab))
2867 return;
2868
2869 // public method to adapt position
2870 SCCOL nOrigX = rPosX;
2871 SCROW nOrigY = rPosY;
2872 mrDoc.SkipOverlapped(rPosX, rPosY, nTabNo);
2873 bool bHOver = (nOrigX != rPosX);
2874 bool bVOver = (nOrigY != rPosY);
2875
2876 if ( !(bRepair && ( bHOver || bVOver )) )
2877 return;
2878
2879 const ScMergeAttr* pMerge = mrDoc.GetAttr(rPosX, rPosY, nTabNo, ATTR_MERGE);
2880 if ( ( bHOver && pMerge->GetColMerge() <= 1 ) ||
2881 ( bVOver && pMerge->GetRowMerge() <= 1 ) )
2882 {
2883 OSL_FAIL("merge error found");
2884
2886 SCCOL nEndCol = mrDoc.MaxCol();
2887 SCROW nEndRow = mrDoc.MaxRow();
2888 mrDoc.ExtendMerge(0, 0, nEndCol, nEndRow, nTabNo, true);
2889 if (pDocShell)
2892 }
2893}
2894
2895void ScViewData::GetMouseQuadrant( const Point& rClickPos, ScSplitPos eWhich,
2896 SCCOL nPosX, SCROW nPosY, bool& rLeft, bool& rTop )
2897{
2898 bool bLayoutRTL = mrDoc.IsLayoutRTL(nTabNo);
2899 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
2900
2901 Point aCellStart = GetScrPos( nPosX, nPosY, eWhich, true );
2902 tools::Long nSizeX;
2903 tools::Long nSizeY;
2904 GetMergeSizePixel( nPosX, nPosY, nSizeX, nSizeY );
2905 rLeft = ( rClickPos.X() - aCellStart.X() ) * nLayoutSign <= nSizeX / 2;
2906 rTop = rClickPos.Y() - aCellStart.Y() <= nSizeY / 2;
2907}
2908
2909void ScViewData::SetPosX( ScHSplitPos eWhich, SCCOL nNewPosX )
2910{
2911 // in the tiled rendering case, nPosX [the leftmost visible column] must be 0
2912 bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
2913 if (nNewPosX != 0 && !bIsTiledRendering)
2914 {
2915 SCCOL nOldPosX = pThisTab->nPosX[eWhich];
2916 tools::Long nTPosX = pThisTab->nTPosX[eWhich];
2917 tools::Long nPixPosX = pThisTab->nPixPosX[eWhich];
2918 SCCOL i;
2919 if ( nNewPosX > nOldPosX )
2920 for ( i=nOldPosX; i<nNewPosX; i++ )
2921 {
2923 nTPosX -= nThis;
2924 nPixPosX -= ToPixel(sal::static_int_cast<sal_uInt16>(nThis), nPPTX);
2925 }
2926 else
2927 for ( i=nNewPosX; i<nOldPosX; i++ )
2928 {
2930 nTPosX += nThis;
2931 nPixPosX += ToPixel(sal::static_int_cast<sal_uInt16>(nThis), nPPTX);
2932 }
2933
2934 pThisTab->nPosX[eWhich] = nNewPosX;
2935 pThisTab->nTPosX[eWhich] = nTPosX;
2937 pThisTab->nPixPosX[eWhich] = nPixPosX;
2938 }
2939 else
2940 {
2941 pThisTab->nPixPosX[eWhich] =
2942 pThisTab->nTPosX[eWhich] =
2943 pThisTab->nMPosX[eWhich] =
2944 pThisTab->nPosX[eWhich] = 0;
2945 }
2946}
2947
2948void ScViewData::SetPosY( ScVSplitPos eWhich, SCROW nNewPosY )
2949{
2950 // in the tiled rendering case, nPosY [the topmost visible row] must be 0
2951 bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
2952 if (nNewPosY != 0 && !bIsTiledRendering)
2953 {
2954 SCROW nOldPosY = pThisTab->nPosY[eWhich];
2955 tools::Long nTPosY = pThisTab->nTPosY[eWhich];
2956 tools::Long nPixPosY = pThisTab->nPixPosY[eWhich];
2957 SCROW i, nHeightEndRow;
2958 if ( nNewPosY > nOldPosY )
2959 for ( i=nOldPosY; i<nNewPosY; i++ )
2960 {
2961 tools::Long nThis = mrDoc.GetRowHeight(i, nTabNo, nullptr, &nHeightEndRow);
2962 SCROW nRows = std::min( nNewPosY, nHeightEndRow + 1) - i;
2963 i = nHeightEndRow;
2964 nTPosY -= nThis * nRows;
2965 nPixPosY -= ToPixel(sal::static_int_cast<sal_uInt16>(nThis), nPPTY) * nRows;
2966 }
2967 else
2968 for ( i=nNewPosY; i<nOldPosY; i++ )
2969 {
2970 tools::Long nThis = mrDoc.GetRowHeight(i, nTabNo, nullptr, &nHeightEndRow);
2971 SCROW nRows = std::min( nOldPosY, nHeightEndRow + 1) - i;
2972 i = nHeightEndRow;
2973 nTPosY += nThis * nRows;
2974 nPixPosY += ToPixel(sal::static_int_cast<sal_uInt16>(nThis), nPPTY) * nRows;
2975 }
2976
2977 pThisTab->nPosY[eWhich] = nNewPosY;
2978 pThisTab->nTPosY[eWhich] = nTPosY;
2980 pThisTab->nPixPosY[eWhich] = nPixPosY;
2981 }
2982 else
2983 {
2984 pThisTab->nPixPosY[eWhich] =
2985 pThisTab->nTPosY[eWhich] =
2986 pThisTab->nMPosY[eWhich] =
2987 pThisTab->nPosY[eWhich] = 0;
2988 }
2989}
2990
2991void ScViewData::RecalcPixPos() // after zoom changes
2992{
2993 for (sal_uInt16 eWhich=0; eWhich<2; eWhich++)
2994 {
2995 tools::Long nPixPosX = 0;
2996 SCCOL nPosX = pThisTab->nPosX[eWhich];
2997 for (SCCOL i=0; i<nPosX; i++)
2998 nPixPosX -= ToPixel(mrDoc.GetColWidth(i, nTabNo), nPPTX);
2999 pThisTab->nPixPosX[eWhich] = nPixPosX;
3000
3001 tools::Long nPixPosY = 0;
3002 SCROW nPosY = pThisTab->nPosY[eWhich];
3003 tools::Long nRowHeight = -1;
3004 SCROW nLastSameHeightRow = -1;
3005 for (SCROW j=0; j<nPosY; j++)
3006 {
3007 if(nLastSameHeightRow < j)
3008 nRowHeight = ToPixel(mrDoc.GetRowHeight(j, nTabNo, nullptr, &nLastSameHeightRow), nPPTY);
3009 nPixPosY -= nRowHeight;
3010 }
3011 pThisTab->nPixPosY[eWhich] = nPixPosY;
3012 }
3013}
3014
3016{
3018 pThisTab->nMPosY[WhichV(eWhich)] ) );
3019 return aLogicMode;
3020}
3021
3023{
3025 return aLogicMode;
3026}
3027
3028void ScViewData::SetScreen( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
3029{
3030 SCCOL nCol;
3031 SCROW nRow;
3032 sal_uInt16 nTSize;
3033 tools::Long nSizePix;
3034 tools::Long nScrPosX = 0;
3035 tools::Long nScrPosY = 0;
3036
3038 SetPosX( SC_SPLIT_LEFT, nCol1 );
3039 SetPosY( SC_SPLIT_BOTTOM, nRow1 );
3040
3041 for (nCol=nCol1; nCol<=nCol2; nCol++)
3042 {
3043 nTSize = mrDoc.GetColWidth(nCol, nTabNo);
3044 if (nTSize)
3045 {
3046 nSizePix = ToPixel( nTSize, nPPTX );
3047 nScrPosX += static_cast<sal_uInt16>(nSizePix);
3048 }
3049 }
3050
3051 for (nRow=nRow1; nRow<=nRow2; nRow++)
3052 {
3053 nTSize = mrDoc.GetRowHeight(nRow, nTabNo);
3054 if (nTSize)
3055 {
3056 nSizePix = ToPixel( nTSize, nPPTY );
3057 nScrPosY += static_cast<sal_uInt16>(nSizePix);
3058 }
3059 }
3060
3061 aScrSize = Size( nScrPosX, nScrPosY );
3062}
3063
3064void ScViewData::SetScreenPos( const Point& rVisAreaStart )
3065{
3066 tools::Long nSize;
3067 tools::Long nTwips;
3068 tools::Long nAdd;
3069 bool bEnd;
3070
3071 nSize = 0;
3072 nTwips = o3tl::convert(rVisAreaStart.X(), o3tl::Length::mm100, o3tl::Length::twip);
3074 nTwips = -nTwips;
3075 SCCOL nX1 = 0;
3076 bEnd = false;
3077 while (!bEnd)
3078 {
3079 nAdd = static_cast<tools::Long>(mrDoc.GetColWidth(nX1, nTabNo));
3080 if (nSize + nAdd <= nTwips + 1 && nX1 < mrDoc.MaxCol())
3081 {
3082 nSize += nAdd;
3083 ++nX1;
3084 }
3085 else
3086 bEnd = true;
3087 }
3088
3089 nSize = 0;
3090 nTwips = o3tl::convert(rVisAreaStart.Y(), o3tl::Length::mm100, o3tl::Length::twip);
3091 SCROW nY1 = 0;
3092 bEnd = false;
3093 while (!bEnd)
3094 {
3095 nAdd = static_cast<tools::Long>(mrDoc.GetRowHeight(nY1, nTabNo));
3096 if (nSize + nAdd <= nTwips + 1 && nY1 < mrDoc.MaxRow())
3097 {
3098 nSize += nAdd;
3099 ++nY1;
3100 }
3101 else
3102 bEnd = true;
3103 }
3104
3106 SetPosX( SC_SPLIT_LEFT, nX1 );
3107 SetPosY( SC_SPLIT_BOTTOM, nY1 );
3108
3109 SetCurX( nX1 );
3110 SetCurY( nY1 );
3111}
3112
3114{
3115 SetScreenPos( rVisArea.TopLeft() );
3116
3117 // here without GetOutputFactor(), since it's for the output into a Metafile
3118
3119 aScrSize = rVisArea.GetSize();
3122}
3123
3125{
3126 return pDocShell->GetDocFunc();
3127}
3128
3130{
3131 assert(pView && "GetBindings() without ViewShell");
3132 return pView->GetViewFrame().GetBindings();
3133}
3134
3136{
3137 assert(pView && "GetDispatcher() without ViewShell");
3138 return *pView->GetViewFrame().GetDispatcher();
3139}
3140
3142{
3143 return maMarkData;
3144}
3145
3147{
3148 return maMarkData;
3149}
3150
3152{
3153 assert(pView && "GetDialogParent() without ViewShell");
3154 return pView->GetDialogParent();
3155}
3156
3158{
3159 assert(pView && "GetActiveWin() without View");
3160 return pView->GetActiveWin();
3161}
3162
3164{
3165 assert(pView && "GetActiveWin() without View");
3166 return pView->GetActiveWin();
3167}
3168
3170{
3171 assert(pView && "GetScDrawView() without View");
3172 return pView->GetScDrawView();
3173}
3174
3176{
3177 assert(pView && "IsMinimized() without View");
3178 return pView->IsMinimized();
3179}
3180
3181void ScViewData::UpdateScreenZoom( const Fraction& rNewX, const Fraction& rNewY )
3182{
3183 Fraction aOldX = GetZoomX();
3184 Fraction aOldY = GetZoomY();
3185
3186 SetZoom( rNewX, rNewY, false );
3187
3188 Fraction aWidth = GetZoomX();
3189 aWidth *= Fraction( aScrSize.Width(),1 );
3190 aWidth /= aOldX;
3191
3192 Fraction aHeight = GetZoomY();
3193 aHeight *= Fraction( aScrSize.Height(),1 );
3194 aHeight /= aOldY;
3195
3196 aScrSize.setWidth( static_cast<tools::Long>(aWidth) );
3197 aScrSize.setHeight( static_cast<tools::Long>(aHeight) );
3198}
3199
3201{
3202 double nOldPPTX = nPPTX;
3203 double nOldPPTY = nPPTY;
3204 nPPTX = ScGlobal::nScreenPPTX * static_cast<double>(GetZoomX());
3205 if (pDocShell)
3206 nPPTX = nPPTX / pDocShell->GetOutputFactor(); // Factor is printer to screen
3207 nPPTY = ScGlobal::nScreenPPTY * static_cast<double>(GetZoomY());
3208
3209 // if detective objects are present,
3210 // try to adjust horizontal scale so the most common column width has minimal rounding errors,
3211 // to avoid differences between cell and drawing layer output
3212
3214 {
3215 SCCOL nEndCol = 0;
3216 SCROW nDummy = 0;
3217 mrDoc.GetTableArea(nTabNo, nEndCol, nDummy);
3218 if (nEndCol<20)
3219 nEndCol = 20; // same end position as when determining draw scale
3220
3221 sal_uInt16 nTwips = mrDoc.GetCommonWidth(nEndCol, nTabNo);
3222 if ( nTwips )
3223 {
3224 double fOriginal = nTwips * nPPTX;
3225 if ( fOriginal < static_cast<double>(nEndCol) )
3226 {
3227 // if one column is smaller than the column count,
3228 // rounding errors are likely to add up to a whole column.
3229
3230 double fRounded = ::rtl::math::approxFloor( fOriginal + 0.5 );
3231 if ( fRounded > 0.0 )
3232 {
3233 double fScale = fRounded / fOriginal + 1E-6;
3234 if ( fScale >= 0.9 && fScale <= 1.1 )
3235 nPPTX *= fScale;
3236 }
3237 }
3238 }
3239 }
3240
3242 return;
3243
3244 SCTAB nTabCount = maTabData.size();
3245 bool bResetWidths = (nPPTX != nOldPPTX);
3246 bool bResetHeights = (nPPTY != nOldPPTY);
3247 for (SCTAB nTabIdx = 0; nTabIdx < nTabCount; ++nTabIdx)
3248 {
3249 if (!maTabData[nTabIdx])
3250 continue;
3251
3252 if (bResetWidths)
3253 if (auto* pWHelper = GetLOKWidthHelper(nTabIdx))
3254 pWHelper->invalidateByPosition(0L);
3255
3256 if (bResetHeights)
3257 if (auto* pHHelper = GetLOKHeightHelper(nTabIdx))
3258 pHHelper->invalidateByPosition(0L);
3259 }
3260}
3261
3262#define SC_OLD_TABSEP '/'
3263#define SC_NEW_TABSEP '+'
3264
3265void ScViewData::WriteUserData(OUString& rData)
3266{
3267 // nZoom (until 364v) or nZoom/nPageZoom/bPageMode (from 364w)
3268 // nTab
3269 // Tab control width
3270 // per sheet:
3271 // CursorX/CursorY/HSplitMode/VSplitMode/HSplitPos/VSplitPos/SplitActive/
3272 // PosX[left]/PosX[right]/PosY[top]/PosY[bottom]
3273 // when rows bigger than 8192, "+" instead of "/"
3274
3275 sal_uInt16 nZoom = static_cast<sal_uInt16>(tools::Long(pThisTab->aZoomY * 100));
3276 rData = OUString::number( nZoom ) + "/";
3277 nZoom = static_cast<sal_uInt16>(tools::Long(pThisTab->aPageZoomY * 100));
3278 rData += OUString::number( nZoom ) + "/";
3279 if (bPagebreak)
3280 rData += "1";
3281 else
3282 rData += "0";
3283
3284 rData += ";" + OUString::number( nTabNo ) + ";" + TAG_TABBARWIDTH +
3285 OUString::number( pView->GetTabBarWidth() );
3286
3287 SCTAB nTabCount = mrDoc.GetTableCount();
3288 for (SCTAB i=0; i<nTabCount; i++)
3289 {
3290 rData += ";"; // Numbering must not get mixed up under any circumstances
3291 if (i < static_cast<SCTAB>(maTabData.size()) && maTabData[i])
3292 {
3293 OUString cTabSep(SC_OLD_TABSEP); // like 3.1
3294 if ( maTabData[i]->nCurY > MAXROW_30 ||
3295 maTabData[i]->nPosY[0] > MAXROW_30 || maTabData[i]->nPosY[1] > MAXROW_30 ||
3296 ( maTabData[i]->eVSplitMode == SC_SPLIT_FIX &&
3297 maTabData[i]->nFixPosY > MAXROW_30 ) )
3298 {
3299 cTabSep = OUStringChar(SC_NEW_TABSEP); // in order to not kill a 3.1-version
3300 }
3301
3302 rData += OUString::number( maTabData[i]->nCurX ) + cTabSep +
3303 OUString::number( maTabData[i]->nCurY ) + cTabSep +
3304 OUString::number( maTabData[i]->eHSplitMode ) + cTabSep +
3305 OUString::number( maTabData[i]->eVSplitMode ) + cTabSep;
3306 if ( maTabData[i]->eHSplitMode == SC_SPLIT_FIX )
3307 rData += OUString::number( maTabData[i]->nFixPosX );
3308 else
3309 rData += OUString::number( maTabData[i]->nHSplitPos );
3310 rData += cTabSep;
3311 if ( maTabData[i]->eVSplitMode == SC_SPLIT_FIX )
3312 rData += OUString::number( maTabData[i]->nFixPosY );
3313 else
3314 rData += OUString::number( maTabData[i]->nVSplitPos );
3315 rData += cTabSep +
3316 OUString::number( maTabData[i]->eWhichActive ) + cTabSep +
3317 OUString::number( maTabData[i]->nPosX[0] ) + cTabSep +
3318 OUString::number( maTabData[i]->nPosX[1] ) + cTabSep +
3319 OUString::number( maTabData[i]->nPosY[0] ) + cTabSep +
3320 OUString::number( maTabData[i]->nPosY[1] );
3321 }
3322 }
3323}
3324
3325void ScViewData::ReadUserData(std::u16string_view rData)
3326{
3327 if (rData.empty()) // empty string on "reload"
3328 return; // then exit without assertion
3329
3330 if ( comphelper::string::getTokenCount(rData, ';') <= 2 )
3331 {
3332 // when reload, in page preview, the preview UserData may have been left intact.
3333 // we don't want the zoom from the page preview here.
3334 OSL_FAIL("ReadUserData: This is not my data");
3335 return;
3336 }
3337
3338 sal_Int32 nMainIdx {0};
3339 sal_Int32 nIdx {0};
3340
3341 std::u16string_view aZoomStr = o3tl::getToken(rData, 0, ';', nMainIdx); // Zoom/PageZoom/Mode
3342 sal_Unicode cMode = o3tl::getToken(aZoomStr, 2, '/', nIdx)[0]; // 0 or "0"/"1"
3343 SetPagebreakMode( cMode == '1' );
3344 // SetPagebreakMode must always be called due to CalcPPT / RecalcPixPos()
3345
3346 // sheet may have become invalid (for instance last version):
3347 SCTAB nNewTab = static_cast<SCTAB>(o3tl::toUInt32(o3tl::getToken(rData, 0, ';', nMainIdx)));
3348 if (mrDoc.HasTable(nNewTab))
3349 SetTabNo(nNewTab);
3350
3351 // if available, get tab bar width:
3352 const sal_Int32 nMainIdxRef {nMainIdx};
3353 std::u16string_view aTabOpt = o3tl::getToken(rData, 0, ';', nMainIdx);
3354
3355 std::u16string_view aRest;
3356 if (o3tl::starts_with(aTabOpt, TAG_TABBARWIDTH, &aRest))
3357 {
3359 }
3360 else
3361 {
3362 // Tab bar width not specified, token to be processed again
3363 nMainIdx = nMainIdxRef;
3364 }
3365
3366 // per sheet
3367 SCTAB nPos = 0;
3368 while ( nMainIdx>0 )
3369 {
3370 aTabOpt = o3tl::getToken(rData, 0, ';', nMainIdx);
3372 if (!maTabData[nPos])
3373 maTabData[nPos].reset(new ScViewDataTable(&mrDoc));
3374
3375 sal_Unicode cTabSep = 0;
3377 cTabSep = SC_OLD_TABSEP;
3378 else if (comphelper::string::getTokenCount(aTabOpt, SC_NEW_TABSEP) >= 11)
3379 cTabSep = SC_NEW_TABSEP;
3380 // '+' is only allowed, if we can deal with rows > 8192
3381
3382 if (cTabSep)
3383 {
3384 nIdx = 0;
3385 maTabData[nPos]->nCurX = mrDoc.SanitizeCol(static_cast<SCCOL>(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx))));
3386 maTabData[nPos]->nCurY = mrDoc.SanitizeRow(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx)));
3387 maTabData[nPos]->eHSplitMode = static_cast<ScSplitMode>(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx)));
3388 maTabData[nPos]->eVSplitMode = static_cast<ScSplitMode>(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx)));
3389
3390 sal_Int32 nTmp = o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx));
3391 if ( maTabData[nPos]->eHSplitMode == SC_SPLIT_FIX )
3392 {
3393 maTabData[nPos]->nFixPosX = mrDoc.SanitizeCol(static_cast<SCCOL>(nTmp));
3395 }
3396 else
3397 maTabData[nPos]->nHSplitPos = nTmp;
3398
3399 nTmp = o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx));
3400 if ( maTabData[nPos]->eVSplitMode == SC_SPLIT_FIX )
3401 {
3402 maTabData[nPos]->nFixPosY = mrDoc.SanitizeRow(nTmp);
3404 }
3405 else
3406 maTabData[nPos]->nVSplitPos = nTmp;
3407
3408 maTabData[nPos]->eWhichActive = static_cast<ScSplitPos>(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx)));
3409 maTabData[nPos]->nPosX[0] = mrDoc.SanitizeCol(static_cast<SCCOL>(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx))));
3410 maTabData[nPos]->nPosX[1] = mrDoc.SanitizeCol(static_cast<SCCOL>(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx))));
3411 maTabData[nPos]->nPosY[0] = mrDoc.SanitizeRow(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx)));
3412 maTabData[nPos]->nPosY[1] = mrDoc.SanitizeRow(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx)));
3413
3414 maTabData[nPos]->eWhichActive = maTabData[nPos]->SanitizeWhichActive();
3415 }
3416 ++nPos;
3417 }
3418
3419 RecalcPixPos();
3420}
3421
3423{
3424 // *** Fill extended document data for export filters ***
3425
3426 // document settings
3427 ScExtDocSettings& rDocSett = rDocOpt.GetDocSettings();
3428
3429 // displayed sheet
3430 rDocSett.mnDisplTab = GetTabNo();
3431
3432 // width of the tabbar, relative to frame window width
3434 if( rDocSett.mfTabBarWidth < 0.0 )
3436
3437 bool bLOKActive = comphelper::LibreOfficeKit::isActive();
3438
3439 // sheet settings
3440 for( SCTAB nTab = 0; nTab < static_cast<SCTAB>(maTabData.size()); ++nTab )
3441 {
3442 if( const ScViewDataTable* pViewTab = maTabData[ nTab ].get() )
3443 {
3444 ScExtTabSettings& rTabSett = rDocOpt.GetOrCreateTabSettings( nTab );
3445
3446 // split mode
3447 ScSplitMode eExHSplit = pViewTab->eHSplitMode;
3448 ScSplitMode eExVSplit = pViewTab->eVSplitMode;
3449 SCCOL nExFixPosX = pViewTab->nFixPosX;
3450 SCROW nExFixPosY = pViewTab->nFixPosY;
3451 tools::Long nExHSplitPos = pViewTab->nHSplitPos;
3452 tools::Long nExVSplitPos = pViewTab->nVSplitPos;
3453
3454 if (bLOKActive)
3455 {
3456 OverrideWithLOKFreeze(eExHSplit, eExVSplit,
3457 nExFixPosX, nExFixPosY,
3458 nExHSplitPos, nExVSplitPos, nTab);
3459 }
3460
3461 bool bHSplit = eExHSplit != SC_SPLIT_NONE;
3462 bool bVSplit = eExVSplit != SC_SPLIT_NONE;
3463 bool bRealSplit = (eExHSplit == SC_SPLIT_NORMAL) || (eExVSplit == SC_SPLIT_NORMAL);
3464 bool bFrozen = (eExHSplit == SC_SPLIT_FIX) || (eExVSplit == SC_SPLIT_FIX);
3465 OSL_ENSURE( !bRealSplit || !bFrozen, "ScViewData::WriteExtOptions - split and freeze in same sheet" );
3466 rTabSett.mbFrozenPanes = !bRealSplit && bFrozen;
3467
3468 // split and freeze position
3469 rTabSett.maSplitPos = Point( 0, 0 );
3470 rTabSett.maFreezePos.Set( 0, 0, nTab );
3471 if( bRealSplit )
3472 {
3473 Point& rSplitPos = rTabSett.maSplitPos;
3474 rSplitPos = Point( bHSplit ? nExHSplitPos : 0, bVSplit ? nExVSplitPos : 0 );
3475 rSplitPos = Application::GetDefaultDevice()->PixelToLogic( rSplitPos, MapMode( MapUnit::MapTwip ) );
3476 if( pDocShell )
3477 rSplitPos.setX( static_cast<tools::Long>(static_cast<double>(rSplitPos.X()) / pDocShell->GetOutputFactor()) );
3478 }
3479 else if( bFrozen )
3480 {
3481 if( bHSplit ) rTabSett.maFreezePos.SetCol( nExFixPosX );
3482 if( bVSplit ) rTabSett.maFreezePos.SetRow( nExFixPosY );
3483 }
3484
3485 // first visible cell in top-left and additional panes
3486 rTabSett.maFirstVis.Set( pViewTab->nPosX[ SC_SPLIT_LEFT ], pViewTab->nPosY[ bVSplit ? SC_SPLIT_TOP : SC_SPLIT_BOTTOM ], nTab );
3487 rTabSett.maSecondVis.Set( pViewTab->nPosX[ SC_SPLIT_RIGHT ], pViewTab->nPosY[ SC_SPLIT_BOTTOM ], nTab );
3488
3489 // active pane
3490 switch( pViewTab->eWhichActive )
3491 {
3492 // no horizontal split -> always use left panes
3493 // no vertical split -> always use top panes
3494 case SC_SPLIT_TOPLEFT:
3496 break;
3497 case SC_SPLIT_TOPRIGHT:
3499 break;
3502 break;
3504 rTabSett.meActivePane = bHSplit ?
3507 break;
3508 }
3509
3510 // cursor position
3511 rTabSett.maCursor.Set( pViewTab->nCurX, pViewTab->nCurY, nTab );
3512
3513 // sheet selection and selected ranges
3514 const ScMarkData& rMarkData = GetMarkData();
3515 rTabSett.mbSelected = rMarkData.GetTableSelect( nTab );
3516 rMarkData.FillRangeListWithMarks( &rTabSett.maSelection, true );
3517
3518 // grid color
3519 rTabSett.maGridColor = COL_AUTO;
3520 const Color& rGridColor = maOptions.GetGridColor();
3521 if (rGridColor != SC_STD_GRIDCOLOR)
3522 rTabSett.maGridColor = rGridColor;
3523 rTabSett.mbShowGrid = pViewTab->bShowGrid;
3524
3525 // view mode and zoom
3526 rTabSett.mbPageMode = bPagebreak;
3527 rTabSett.mnNormalZoom = static_cast< tools::Long >( pViewTab->aZoomY * Fraction( 100.0 ) );
3528 rTabSett.mnPageZoom = static_cast< tools::Long >( pViewTab->aPageZoomY * Fraction( 100.0 ) );
3529 }
3530 }
3531}
3532
3534{
3535 // *** Get extended document data from import filters ***
3536
3537 if( !rDocOpt.IsChanged() ) return;
3538
3539 // document settings
3540 const ScExtDocSettings& rDocSett = rDocOpt.GetDocSettings();
3541
3542 // displayed sheet
3543 SetTabNo( rDocSett.mnDisplTab );
3544
3545 /* Width of the tabbar, relative to frame window width. We do not have the
3546 correct width of the frame window here -> store in ScTabView, which sets
3547 the size in the next resize. */
3549
3550 // sheet settings
3551 SCTAB nLastTab = rDocOpt.GetLastTab();
3552 if (static_cast<SCTAB>(maTabData.size()) <= nLastTab)
3553 maTabData.resize(nLastTab+1);
3554
3555 for( SCTAB nTab = 0; nTab < static_cast<SCTAB>(maTabData.size()); ++nTab )
3556 {
3557 if( const ScExtTabSettings* pTabSett = rDocOpt.GetTabSettings( nTab ) )
3558 {
3559 if( !maTabData[ nTab ] )
3560 maTabData[nTab].reset(new ScViewDataTable(&mrDoc));
3561
3562 const ScExtTabSettings& rTabSett = *pTabSett;
3563 ScViewDataTable& rViewTab = *maTabData[ nTab ];
3564
3565 // split mode initialization
3566 bool bFrozen = rTabSett.mbFrozenPanes;
3567 bool bHSplit = bFrozen ? (rTabSett.maFreezePos.Col() > 0) : (rTabSett.maSplitPos.X() > 0);
3568 bool bVSplit = bFrozen ? (rTabSett.maFreezePos.Row() > 0) : (rTabSett.maSplitPos.Y() > 0);
3569
3570 // first visible cell of top-left pane and additional panes
3571 if (rTabSett.maFirstVis.IsValid())
3572 {
3573 rViewTab.nPosX[ SC_SPLIT_LEFT ] = rTabSett.maFirstVis.Col();
3574 rViewTab.nPosY[ bVSplit ? SC_SPLIT_TOP : SC_SPLIT_BOTTOM ] = rTabSett.maFirstVis.Row();
3575 }
3576
3577 if (rTabSett.maSecondVis.IsValid())
3578 {
3579 if (bHSplit)
3580 rViewTab.nPosX[ SC_SPLIT_RIGHT ] = rTabSett.maSecondVis.Col();
3581 if (bVSplit)
3582 rViewTab.nPosY[ SC_SPLIT_BOTTOM ] = rTabSett.maSecondVis.Row();
3583 }
3584
3585 // split mode, split and freeze position
3586 rViewTab.eHSplitMode = rViewTab.eVSplitMode = SC_SPLIT_NONE;
3587 rViewTab.nHSplitPos = rViewTab.nVSplitPos = 0;
3588 rViewTab.nFixPosX = 0;
3589 rViewTab.nFixPosY = 0;
3590 if( bFrozen )
3591 {
3592 if( bHSplit )
3593 {
3594 rViewTab.eHSplitMode = SC_SPLIT_FIX;
3595 rViewTab.nFixPosX = rTabSett.maFreezePos.Col();
3596 UpdateFixX( nTab );
3597 }
3598 if( bVSplit )
3599 {
3600 rViewTab.eVSplitMode = SC_SPLIT_FIX;
3601 rViewTab.nFixPosY = rTabSett.maFreezePos.Row();
3602 UpdateFixY( nTab );
3603 }
3604 }
3605 else
3606 {
3608 rTabSett.maSplitPos, MapMode( MapUnit::MapTwip ) );
3609 // the test for use of printer metrics for text formatting here
3610 // effectively results in the nFactor = 1.0 regardless of the Option setting.
3611 if( pDocShell && SC_MOD()->GetInputOptions().GetTextWysiwyg())
3612 {
3613 double nFactor = pDocShell->GetOutputFactor();
3614 aPixel.setX( static_cast<tools::Long>( aPixel.X() * nFactor + 0.5 ) );
3615 }
3616
3617 bHSplit = bHSplit && aPixel.X() > 0;
3618 bVSplit = bVSplit && aPixel.Y() > 0;
3619 if( bHSplit )
3620 {
3621 rViewTab.eHSplitMode = SC_SPLIT_NORMAL;
3622 rViewTab.nHSplitPos = aPixel.X();
3623 }
3624 if( bVSplit )
3625 {
3626 rViewTab.eVSplitMode = SC_SPLIT_NORMAL;
3627 rViewTab.nVSplitPos = aPixel.Y();
3628 }
3629 }
3630
3631 // active pane
3633 switch( rTabSett.meActivePane )
3634 {
3635 // no horizontal split -> always use left panes
3636 // no vertical split -> always use *bottom* panes
3637 case SCEXT_PANE_TOPLEFT:
3639 break;
3641 ePos = bHSplit ?
3644 break;
3647 break;
3650 break;
3651 }
3652 rViewTab.eWhichActive = ePos;
3653
3654 // cursor position
3655 const ScAddress& rCursor = rTabSett.maCursor;
3656 if( rCursor.IsValid() )
3657 {
3658 rViewTab.nCurX = rCursor.Col();
3659 rViewTab.nCurY = rCursor.Row();
3660 }
3661
3662 // sheet selection and selected ranges
3663 ScMarkData& rMarkData = GetMarkData();
3664 rMarkData.SelectTable( nTab, rTabSett.mbSelected );
3665
3666 // zoom for each sheet
3667 if( rTabSett.mnNormalZoom )
3668 rViewTab.aZoomX = rViewTab.aZoomY = Fraction( rTabSett.mnNormalZoom, 100 );
3669 if( rTabSett.mnPageZoom )
3670 rViewTab.aPageZoomX = rViewTab.aPageZoomY = Fraction( rTabSett.mnPageZoom, 100 );
3671
3672 rViewTab.bShowGrid = rTabSett.mbShowGrid;
3673
3674 // get some settings from displayed Excel sheet, set at Calc document
3675 if( nTab == GetTabNo() )
3676 {
3677 // grid color -- #i47435# set automatic grid color explicitly
3678 Color aGridColor(rTabSett.maGridColor);
3679 if (aGridColor == COL_AUTO)
3680 aGridColor = SC_STD_GRIDCOLOR;
3681 maOptions.SetGridColor(aGridColor, OUString());
3682
3683 // view mode and default zoom (for new sheets) from current sheet
3684 if( rTabSett.mnNormalZoom )
3685 aDefZoomX = aDefZoomY = Fraction( rTabSett.mnNormalZoom, 100L );
3686 if( rTabSett.mnPageZoom )
3687 aDefPageZoomX = aDefPageZoomY = Fraction( rTabSett.mnPageZoom, 100L );
3688 /* #i46820# set pagebreak mode via SetPagebreakMode(), this will
3689 update map modes that are needed to draw text correctly. */
3690 SetPagebreakMode( rTabSett.mbPageMode );
3691 }
3692 }
3693 }
3694
3697
3698 // RecalcPixPos or so - also nMPos - also for ReadUserData ??!?!
3699}
3700
3701void ScViewData::WriteUserDataSequence(uno::Sequence <beans::PropertyValue>& rSettings) const
3702{
3703 rSettings.realloc(SC_VIEWSETTINGS_COUNT);
3704 // + 1, because we have to put the view id in the sequence
3705 beans::PropertyValue* pSettings = rSettings.getArray();
3706
3707 sal_uInt16 nViewID(pView->GetViewFrame().GetCurViewId());
3708 pSettings[SC_VIEW_ID].Name = SC_VIEWID;
3709 pSettings[SC_VIEW_ID].Value <<= SC_VIEW + OUString::number(nViewID);
3710
3711 uno::Reference<container::XNameContainer> xNameContainer =
3712 document::NamedPropertyValues::create( comphelper::getProcessComponentContext() );
3713 for (SCTAB nTab=0; nTab<static_cast<SCTAB>(maTabData.size()); nTab++)
3714 {
3715 if (maTabData[nTab])
3716 {
3717 uno::Sequence <beans::PropertyValue> aTableViewSettings;
3718 maTabData[nTab]->WriteUserDataSequence(aTableViewSettings, *this, nTab);
3719 OUString sTabName;
3720 GetDocument().GetName( nTab, sTabName );
3721 try
3722 {
3723 xNameContainer->insertByName(sTabName, uno::Any(aTableViewSettings));
3724 }
3725 //#101739#; two tables with the same name are possible
3726 catch ( container::ElementExistException& )
3727 {
3728 OSL_FAIL("seems there are two tables with the same name");
3729 }
3730 catch ( uno::RuntimeException& )
3731 {
3732 OSL_FAIL("something went wrong");
3733 }
3734 }
3735 }
3736 pSettings[SC_TABLE_VIEWSETTINGS].Name = SC_TABLES;
3737 pSettings[SC_TABLE_VIEWSETTINGS].Value <<= xNameContainer;
3738
3739 OUString sName;
3741 pSettings[SC_ACTIVE_TABLE].Name = SC_ACTIVETABLE;
3742 pSettings[SC_ACTIVE_TABLE].Value <<= sName;
3744 pSettings[SC_HORIZONTAL_SCROLL_BAR_WIDTH].Value <<= sal_Int32(pView->GetTabBarWidth());
3745 sal_Int32 nZoomValue = tools::Long(pThisTab->aZoomY * 100);
3746 sal_Int32 nPageZoomValue = tools::Long(pThisTab->aPageZoomY * 100);
3747 pSettings[SC_ZOOM_TYPE].Name = SC_ZOOMTYPE;
3748 pSettings[SC_ZOOM_TYPE].Value <<= sal_Int16(pThisTab->eZoomType);
3749 pSettings[SC_ZOOM_VALUE].Name = SC_ZOOMVALUE;
3750 pSettings[SC_ZOOM_VALUE].Value <<= nZoomValue;
3752 pSettings[SC_PAGE_VIEW_ZOOM_VALUE].Value <<= nPageZoomValue;
3754 pSettings[SC_PAGE_BREAK_PREVIEW].Value <<= bPagebreak;
3755
3756 pSettings[SC_SHOWZERO].Name = SC_UNO_SHOWZERO;
3757 pSettings[SC_SHOWZERO].Value <<= maOptions.GetOption(VOPT_NULLVALS);
3758 pSettings[SC_SHOWNOTES].Name = SC_UNO_SHOWNOTES;
3759 pSettings[SC_SHOWNOTES].Value <<= maOptions.GetOption(VOPT_NOTES);
3762 pSettings[SC_SHOWGRID].Name = SC_UNO_SHOWGRID;
3763 pSettings[SC_SHOWGRID].Value <<= maOptions.GetOption(VOPT_GRID);
3764 pSettings[SC_GRIDCOLOR].Name = SC_UNO_GRIDCOLOR;
3765 OUString aColorName;
3766 Color aColor = maOptions.GetGridColor(&aColorName);
3767 pSettings[SC_GRIDCOLOR].Value <<= aColor;
3768 pSettings[SC_SHOWPAGEBR].Name = SC_UNO_SHOWPAGEBR;
3769 pSettings[SC_SHOWPAGEBR].Value <<= maOptions.GetOption(VOPT_PAGEBREAKS);
3770 pSettings[SC_COLROWHDR].Name = SC_UNO_COLROWHDR;
3771 pSettings[SC_COLROWHDR].Value <<= maOptions.GetOption(VOPT_HEADER);
3772 pSettings[SC_SHEETTABS].Name = SC_UNO_SHEETTABS;
3773 pSettings[SC_SHEETTABS].Value <<= maOptions.GetOption(VOPT_TABCONTROLS);
3774 pSettings[SC_OUTLSYMB].Name = SC_UNO_OUTLSYMB;
3775 pSettings[SC_OUTLSYMB].Value <<= maOptions.GetOption(VOPT_OUTLINER);
3776 pSettings[SC_VALUE_HIGHLIGHTING].Name = SC_UNO_VALUEHIGH;
3779 pSettings[SC_FORMULA_BAR_HEIGHT_VALUE].Value <<= GetFormulaBarLines();;
3780
3781 const ScGridOptions& aGridOpt = maOptions.GetGridOptions();
3782 pSettings[SC_SNAPTORASTER].Name = SC_UNO_SNAPTORASTER;
3783 pSettings[SC_SNAPTORASTER].Value <<= aGridOpt.GetUseGridSnap();
3784 pSettings[SC_RASTERVIS].Name = SC_UNO_RASTERVIS;
3785 pSettings[SC_RASTERVIS].Value <<= aGridOpt.GetGridVisible();
3786 pSettings[SC_RASTERRESX].Name = SC_UNO_RASTERRESX;
3787 pSettings[SC_RASTERRESX].Value <<= static_cast<sal_Int32>(aGridOpt.GetFieldDrawX());
3788 pSettings[SC_RASTERRESY].Name = SC_UNO_RASTERRESY;
3789 pSettings[SC_RASTERRESY].Value <<= static_cast<sal_Int32>(aGridOpt.GetFieldDrawY());
3790 pSettings[SC_RASTERSUBX].Name = SC_UNO_RASTERSUBX;
3791 pSettings[SC_RASTERSUBX].Value <<= static_cast<sal_Int32>(aGridOpt.GetFieldDivisionX());
3792 pSettings[SC_RASTERSUBY].Name = SC_UNO_RASTERSUBY;
3793 pSettings[SC_RASTERSUBY].Value <<= static_cast<sal_Int32>(aGridOpt.GetFieldDivisionY());
3794 pSettings[SC_RASTERSYNC].Name = SC_UNO_RASTERSYNC;
3795 pSettings[SC_RASTERSYNC].Value <<= aGridOpt.GetSynchronize();
3796
3797 // Common SdrModel processing
3799}
3800
3801void ScViewData::ReadUserDataSequence(const uno::Sequence <beans::PropertyValue>& rSettings)
3802{
3803 std::vector<bool> aHasZoomVect( GetDocument().GetTableCount(), false );
3804
3805 sal_Int32 nTemp32(0);
3806 sal_Int16 nTemp16(0);
3807 sal_Int16 nFormulaBarLineCount(0);
3808 bool bPageMode(false);
3809
3810 EnsureTabDataSize(GetDocument().GetTableCount());
3811
3812 for (const auto& rSetting : rSettings)
3813 {
3814 // SC_VIEWID has to parse and use by mba
3815 OUString sName(rSetting.Name);
3816 if (sName == SC_TABLES)
3817 {
3818 uno::Reference<container::XNameContainer> xNameContainer;
3819 if ((rSetting.Value >>= xNameContainer) && xNameContainer->hasElements())
3820 {
3821 const uno::Sequence< OUString > aNames(xNameContainer->getElementNames());
3822 for (const OUString& sTabName : aNames)
3823 {
3824 SCTAB nTab(0);
3825 if (GetDocument().GetTable(sTabName, nTab))
3826 {
3827 uno::Any aAny = xNameContainer->getByName(sTabName);
3828 uno::Sequence<beans::PropertyValue> aTabSettings;
3829 if (aAny >>= aTabSettings)
3830 {
3831 EnsureTabDataSize(nTab + 1);
3832 if (!maTabData[nTab])
3833 maTabData[nTab].reset(new ScViewDataTable(&mrDoc));
3834
3835 bool bHasZoom = false;
3836 maTabData[nTab]->ReadUserDataSequence(aTabSettings, *this, nTab, bHasZoom);
3837 aHasZoomVect[nTab] = bHasZoom;
3838 }
3839 }
3840 }
3841 }
3842 }
3843 else if (sName == SC_ACTIVETABLE)
3844 {
3845 OUString sTabName;
3846 if(rSetting.Value >>= sTabName)
3847 {
3848 SCTAB nTab(0);
3849 if (GetDocument().GetTable(sTabName, nTab))
3850 nTabNo = nTab;
3851 }
3852 }
3854 {
3855 if (rSetting.Value >>= nTemp32)
3856 pView->SetTabBarWidth(nTemp32);
3857 }
3859 {
3860 double fWidth = 0.0;
3861 if (rSetting.Value >>= fWidth)
3863 }
3864 else if (sName == SC_ZOOMTYPE)
3865 {
3866 if (rSetting.Value >>= nTemp16)
3867 eDefZoomType = SvxZoomType(nTemp16);
3868 }
3869 else if (sName == SC_ZOOMVALUE)
3870 {
3871 if (rSetting.Value >>= nTemp32)
3872 {
3873 Fraction aZoom(nTemp32, 100);
3874 aDefZoomX = aDefZoomY = aZoom;
3875 }
3876 }
3877 else if (sName == SC_PAGEVIEWZOOMVALUE)
3878 {
3879 if (rSetting.Value >>= nTemp32)
3880 {
3881 Fraction aZoom(nTemp32, 100);
3882 aDefPageZoomX = aDefPageZoomY = aZoom;
3883 }
3884 }
3885 else if (sName == SC_FORMULABARHEIGHT)
3886 {
3887 if (rSetting.Value >>= nFormulaBarLineCount)
3888 {
3889 SetFormulaBarLines(nFormulaBarLineCount);
3890 // Notify formula bar about changed lines
3891 ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
3892 if (pInputHdl)
3893 {
3894 ScInputWindow* pInputWin = pInputHdl->GetInputWindow();
3895 if (pInputWin)
3896 pInputWin->NumLinesChanged();
3897 }
3898 }
3899 }
3900 else if (sName == SC_SHOWPAGEBREAKPREVIEW)
3901 bPageMode = ScUnoHelpFunctions::GetBoolFromAny( rSetting.Value );
3902 else if ( sName == SC_UNO_SHOWZERO )
3904 else if ( sName == SC_UNO_SHOWNOTES )
3906 else if ( sName == SC_UNO_SHOWFORMULASMARKS )
3908 else if ( sName == SC_UNO_SHOWGRID )
3910 else if ( sName == SC_UNO_GRIDCOLOR )
3911 {
3912 Color aColor;
3913 if (rSetting.Value >>= aColor)
3914 {
3915 // #i47435# set automatic grid color explicitly
3916 if( aColor == COL_AUTO )
3917 aColor = SC_STD_GRIDCOLOR;
3918 maOptions.SetGridColor(aColor, OUString());
3919 }
3920 }
3921 else if ( sName == SC_UNO_SHOWPAGEBR )
3923 else if ( sName == SC_UNO_COLROWHDR )
3925 else if ( sName == SC_UNO_SHEETTABS )
3927 else if ( sName == SC_UNO_OUTLSYMB )
3929 else if ( sName == SC_UNO_SHOWOBJ )
3930 {
3931 // #i80528# placeholders not supported anymore
3932 if ( rSetting.Value >>= nTemp16 )
3934 }
3935 else if ( sName == SC_UNO_SHOWCHARTS )
3936 {
3937 // #i80528# placeholders not supported anymore
3938 if ( rSetting.Value >>= nTemp16 )
3940 }
3941 else if ( sName == SC_UNO_SHOWDRAW )
3942 {
3943 // #i80528# placeholders not supported anymore
3944 if ( rSetting.Value >>= nTemp16 )
3946 }
3947 else if ( sName == SC_UNO_VALUEHIGH )
3949 else
3950 {
3952 if ( sName == SC_UNO_SNAPTORASTER )
3953 aGridOpt.SetUseGridSnap( ScUnoHelpFunctions::GetBoolFromAny( rSetting.Value ) );
3954 else if ( sName == SC_UNO_RASTERVIS )
3955 aGridOpt.SetGridVisible( ScUnoHelpFunctions::GetBoolFromAny( rSetting.Value ) );
3956 else if ( sName == SC_UNO_RASTERRESX )
3957 aGridOpt.SetFieldDrawX( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( rSetting.Value ) ) );
3958 else if ( sName == SC_UNO_RASTERRESY )
3959 aGridOpt.SetFieldDrawY( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( rSetting.Value ) ) );
3960 else if ( sName == SC_UNO_RASTERSUBX )
3961 aGridOpt.SetFieldDivisionX( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( rSetting.Value ) ) );
3962 else if ( sName == SC_UNO_RASTERSUBY )
3963 aGridOpt.SetFieldDivisionY( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( rSetting.Value ) ) );
3964 else if ( sName == SC_UNO_RASTERSYNC )
3965 aGridOpt.SetSynchronize( ScUnoHelpFunctions::GetBoolFromAny( rSetting.Value ) );
3966 // Fallback to common SdrModel processing
3968
3969 maOptions.SetGridOptions(aGridOpt);
3970 }
3971 }
3972
3973 // copy default zoom to sheets where a different one wasn't specified
3974 for (SCTAB nZoomTab=0; nZoomTab< static_cast<SCTAB>(maTabData.size()); ++nZoomTab)
3975 if (maTabData[nZoomTab] && ( nZoomTab >= static_cast<SCTAB>(aHasZoomVect.size()) || !aHasZoomVect[nZoomTab] ))
3976 {
3977 maTabData[nZoomTab]->eZoomType = eDefZoomType;
3978 maTabData[nZoomTab]->aZoomX = aDefZoomX;
3979 maTabData[nZoomTab]->aZoomY = aDefZoomY;
3980 maTabData[nZoomTab]->aPageZoomX = aDefPageZoomX;
3981 maTabData[nZoomTab]->aPageZoomY = aDefPageZoomY;
3982 }
3983
3984 if (rSettings.hasElements())
3985 SetPagebreakMode( bPageMode );
3986
3987 // #i47426# write view options to document, needed e.g. for Excel export
3989
3992}
3993
3995{
3996 // if visibility of horizontal ScrollBar is changed, TabBar may have to be resized...
3997 bool bHScrollChanged = (rOpt.GetOption(VOPT_HSCROLL) != maOptions.GetOption(VOPT_HSCROLL));
3998
3999 // if graphics are turned on or off, animation has to be started or stopped
4000 // graphics are controlled by VOBJ_TYPE_OLE
4001 bool bGraphicsChanged = (maOptions.GetObjMode(VOBJ_TYPE_OLE) !=
4002 rOpt.GetObjMode(VOBJ_TYPE_OLE) );
4003
4004 maOptions = rOpt;
4005 OSL_ENSURE( pView, "No View" );
4006
4007 if( pView )
4008 {
4009 pView->ViewOptionsHasChanged( bHScrollChanged, bGraphicsChanged );
4010 }
4011}
4012
4014{
4015 OSL_ENSURE( pView, "GetMousePosPixel() without View" );
4016 return pView->GetMousePosPixel();
4017}
4018
4020{
4021 if (pView)
4022 pView->UpdateInputHandler(bForce);
4023}
4024
4026{
4027 return pDocShell && pDocShell->IsOle();
4028}
4029
4030bool ScViewData::UpdateFixX( SCTAB nTab ) // true = value changed
4031{
4032 if (!ValidTab(nTab)) // Default
4033 nTab=nTabNo; // current table
4034
4035 if (!pView || maTabData[nTab]->eHSplitMode != SC_SPLIT_FIX)
4036 return false;
4037
4038 ScDocument& rLocalDoc = GetDocument();
4039 if (!rLocalDoc.HasTable(nTab)) // if called from reload, the sheet may not exist
4040 return false;
4041
4042 SCCOL nFix = maTabData[nTab]->nFixPosX;
4043 tools::Long nNewPos = 0;
4044 for (SCCOL nX=maTabData[nTab]->nPosX[SC_SPLIT_LEFT]; nX<nFix; nX++)
4045 {
4046 sal_uInt16 nTSize = rLocalDoc.GetColWidth( nX, nTab );
4047 if (nTSize)
4048 {
4049 tools::Long nPix = ToPixel( nTSize, nPPTX );
4050 nNewPos += nPix;
4051 }
4052 }
4053 nNewPos += pView->GetGridOffset().X();
4054 if (nNewPos != maTabData[nTab]->nHSplitPos)
4055 {
4056 maTabData[nTab]->nHSplitPos = nNewPos;
4057 if (nTab == nTabNo)
4058 RecalcPixPos(); // should not be needed
4059 return true;
4060 }
4061
4062 return false;
4063}
4064
4065bool ScViewData::UpdateFixY( SCTAB nTab ) // true = value changed
4066{
4067 if (!ValidTab(nTab)) // Default
4068 nTab=nTabNo; // current table
4069
4070 if (!pView || maTabData[nTab]->eVSplitMode != SC_SPLIT_FIX)
4071 return false;
4072
4073 ScDocument& rLocalDoc = GetDocument();
4074 if (!rLocalDoc.HasTable(nTab)) // if called from reload, the sheet may not exist
4075 return false;
4076
4077 SCROW nFix = maTabData[nTab]->nFixPosY;
4078 tools::Long nNewPos = 0;
4079 for (SCROW nY=maTabData[nTab]->nPosY[SC_SPLIT_TOP]; nY<nFix; nY++)
4080 {
4081 sal_uInt16 nTSize = rLocalDoc.GetRowHeight( nY, nTab );
4082 if (nTSize)
4083 {
4084 tools::Long nPix = ToPixel( nTSize, nPPTY );
4085 nNewPos += nPix;
4086 }
4087 }
4088 nNewPos += pView->GetGridOffset().Y();
4089 if (nNewPos != maTabData[nTab]->nVSplitPos)
4090 {
4091 maTabData[nTab]->nVSplitPos = nNewPos;
4092 if (nTab == nTabNo)
4093 RecalcPixPos(); // should not be needed
4094 return true;
4095 }
4096
4097 return false;
4098}
4099
4101{
4102 ScDocument& rLocalDoc = GetDocument();
4103 bool bOnlineSpell = rLocalDoc.GetDocOptions().IsAutoSpell();
4104
4105 EEControlBits nCntrl = rOutl.GetControlWord();
4106 nCntrl |= EEControlBits::MARKNONURLFIELDS;
4107 nCntrl &= ~EEControlBits::MARKURLFIELDS; // URLs not shaded for output
4108 nCntrl |= EEControlBits::AUTOCORRECT;
4109 if( bOnlineSpell )
4110 nCntrl |= EEControlBits::ONLINESPELLING;
4111 else
4112 nCntrl &= ~EEControlBits::ONLINESPELLING;
4113 rOutl.SetControlWord(nCntrl);
4114
4115 rOutl.SetCalcFieldValueHdl( LINK( SC_MOD(), ScModule, CalcFieldValueHdl ) );
4116
4117 // don't call GetSpellChecker if online spelling isn't enabled.
4118 // The language for AutoCorrect etc. is taken from the pool defaults
4119 // (set in ScDocument::UpdateDrawLanguages)
4120
4121 if ( bOnlineSpell )
4122 {
4123 css::uno::Reference<css::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() );
4124 rOutl.SetSpeller( xXSpellChecker1 );
4125 }
4126
4128 rLocalDoc.GetEditTextDirection( nTabNo ) );
4129}
4130
4132{
4133 return ScAddress( GetCurX(), GetCurY(), GetTabNo() );
4134}
4135
4136void ScViewData::SetRefStart( SCCOL nNewX, SCROW nNewY, SCTAB nNewZ )
4137{
4138 nRefStartX = nNewX; nRefStartY = nNewY; nRefStartZ = nNewZ;
4139}
4140
4141void ScViewData::SetRefEnd( SCCOL nNewX, SCROW nNewY, SCTAB nNewZ )
4142{
4143 nRefEndX = nNewX; nRefEndY = nNewY; nRefEndZ = nNewZ;
4144}
4145
4146void ScViewData::AddPixelsWhile( tools::Long & rScrY, tools::Long nEndPixels, SCROW & rPosY,
4147 SCROW nEndRow, double nPPTY, const ScDocument * pDoc, SCTAB nTabNo )
4148{
4149 SCROW nRow = rPosY;
4150 while (rScrY <= nEndPixels && nRow <= nEndRow)
4151 {
4152 SCROW nHeightEndRow;
4153 sal_uInt16 nHeight = pDoc->GetRowHeight( nRow, nTabNo, nullptr, &nHeightEndRow);
4154 if (nHeightEndRow > nEndRow)
4155 nHeightEndRow = nEndRow;
4156 if (!nHeight)
4157 {
4158 if (ValidTab(nTabNo) && nTabNo <= pDoc->GetMaxTableNumber())
4159 nRow = nHeightEndRow + 1;
4160 else
4161 break;
4162 }
4163 else
4164 {
4165 SCROW nRows = nHeightEndRow - nRow + 1;
4166 sal_Int64 nPixel = ToPixel( nHeight, nPPTY);
4167 sal_Int64 nAdd = nPixel * nRows;
4168 if (nAdd + rScrY > nEndPixels)
4169 {
4170 sal_Int64 nDiff = rScrY + nAdd - nEndPixels;
4171 nRows -= static_cast<SCROW>(nDiff / nPixel);
4172 nAdd = nPixel * nRows;
4173 // We're looking for a value that satisfies loop condition.
4174 if (nAdd + rScrY <= nEndPixels)
4175 {
4176 ++nRows;
4177 nAdd += nPixel;
4178 }
4179 }
4180 rScrY += static_cast<tools::Long>(nAdd);
4181 nRow += nRows;
4182 }
4183 }
4184 if (nRow > rPosY)
4185 --nRow;
4186 rPosY = nRow;
4187}
4188
4190 SCROW & rPosY, SCROW nStartRow, double nPPTY, const ScDocument * pDoc,
4191 SCTAB nTabNo )
4192{
4193 SCROW nRow = rPosY;
4194 while (rScrY <= nEndPixels && nRow >= nStartRow)
4195 {
4196 SCROW nHeightStartRow;
4197 sal_uInt16 nHeight = pDoc->GetRowHeight( nRow, nTabNo, &nHeightStartRow, nullptr);
4198 if (nHeightStartRow < nStartRow)
4199 nHeightStartRow = nStartRow;
4200 if (!nHeight)
4201 nRow = nHeightStartRow - 1;
4202 else
4203 {
4204 SCROW nRows = nRow - nHeightStartRow + 1;
4205 sal_Int64 nPixel = ToPixel( nHeight, nPPTY);
4206 sal_Int64 nAdd = nPixel * nRows;
4207 if (nAdd + rScrY > nEndPixels)
4208 {
4209 sal_Int64 nDiff = nAdd + rScrY - nEndPixels;
4210 nRows -= static_cast<SCROW>(nDiff / nPixel);
4211 nAdd = nPixel * nRows;
4212 // We're looking for a value that satisfies loop condition.
4213 if (nAdd + rScrY <= nEndPixels)
4214 {
4215 ++nRows;
4216 nAdd += nPixel;
4217 }
4218 }
4219 rScrY += static_cast<tools::Long>(nAdd);
4220 nRow -= nRows;
4221 }
4222 }
4223 if (nRow < rPosY)
4224 ++nRow;
4225 rPosY = nRow;
4226}
4227
4229{
4230 SCCOLROW nFreezeIndex = bIsCol ? mrDoc.GetLOKFreezeCol(nTabNo) : mrDoc.GetLOKFreezeRow(nTabNo);
4231 return nFreezeIndex >= 0 ? nFreezeIndex : 0;
4232}
4233
4234bool ScViewData::SetLOKSheetFreezeIndex(const SCCOLROW nFreezeIndex, bool bIsCol, SCTAB nForTab)
4235{
4236 if (nForTab == -1)
4237 {
4238 nForTab = nTabNo;
4239 }
4240 else if (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size())))
4241 {
4242 SAL_WARN("sc.viewdata", "ScViewData::SetLOKSheetFreezeIndex : invalid nForTab = " << nForTab);
4243 return false;
4244 }
4245
4246 return bIsCol ? mrDoc.SetLOKFreezeCol(static_cast<SCCOL>(nFreezeIndex), nForTab)
4247 : mrDoc.SetLOKFreezeRow(static_cast<SCROW>(nFreezeIndex), nForTab);
4248}
4249
4251{
4252 bool colUnfreezed = SetLOKSheetFreezeIndex(0, true);
4253 bool rowUnfreezed = SetLOKSheetFreezeIndex(0, false);
4254 return colUnfreezed || rowUnfreezed;
4255}
4256
4258{
4259 SCTAB nMaxTab = static_cast<SCTAB>(maTabData.size()) - 1;
4260 for (SCTAB nTab = 0; nTab <= nMaxTab; ++nTab)
4262}
4263
4265{
4266 if (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size())))
4267 {
4268 SAL_WARN("sc.viewdata", "ScViewData::DeriveLOKFreezeIfNeeded : invalid nForTab = " << nForTab);
4269 return;
4270 }
4271
4272 ScViewDataTable* pViewTable = maTabData[nForTab].get();
4273 if (!pViewTable)
4274 return;
4275
4276 bool bConvertToFreezeX = false;
4277 bool bConvertToFreezeY = false;
4278 SCCOL nFreezeCol = mrDoc.GetLOKFreezeCol(nForTab);
4279 SCROW nFreezeRow = mrDoc.GetLOKFreezeRow(nForTab);
4280
4281 if (nFreezeCol == -1)
4282 {
4283 ScSplitMode eSplitMode = pViewTable->eHSplitMode;
4284 if (eSplitMode == SC_SPLIT_FIX)
4285 nFreezeCol = pViewTable->nFixPosX;
4286 else if (eSplitMode == SC_SPLIT_NORMAL)
4287 bConvertToFreezeX = true;
4288 else
4289 nFreezeCol = 0;
4290 }
4291
4292 if (nFreezeRow == -1)
4293 {
4294 ScSplitMode eSplitMode = pViewTable->eVSplitMode;
4295 if (eSplitMode == SC_SPLIT_FIX)
4296 nFreezeRow = pViewTable->nFixPosY;
4297 else if (eSplitMode == SC_SPLIT_NORMAL)
4298 bConvertToFreezeY = true;
4299 else
4300 nFreezeRow = 0;
4301 }
4302
4303 if (bConvertToFreezeX || bConvertToFreezeY)
4304 {
4305 SCCOL nCol;
4306 SCROW nRow;
4307 GetPosFromPixel(bConvertToFreezeX ? pViewTable->nHSplitPos : 0,
4308 bConvertToFreezeY ? pViewTable->nVSplitPos : 0,
4309 SC_SPLIT_BOTTOMLEFT, nCol, nRow,
4310 false /* bTestMerge */, false /* bRepair */,
4311 nForTab);
4312 if (bConvertToFreezeX)
4313 nFreezeCol = nCol;
4314 if (bConvertToFreezeY)
4315 nFreezeRow = nRow;
4316 }
4317
4318 mrDoc.SetLOKFreezeCol(nFreezeCol, nForTab);
4319 mrDoc.SetLOKFreezeRow(nFreezeRow, nForTab);
4320}
4321
4323 SCCOL& nExFixPosX, SCROW& nExFixPosY,
4324 tools::Long& nExHSplitPos, tools::Long& nExVSplitPos, SCTAB nForTab) const
4325{
4326 SCCOL nFreezeCol = mrDoc.GetLOKFreezeCol(nForTab);
4327 SCROW nFreezeRow = mrDoc.GetLOKFreezeRow(nForTab);
4328
4329 bool bConvertToScrPosX = false;
4330 bool bConvertToScrPosY = false;
4331
4332 if (nFreezeCol >= 0)
4333 {
4334 if (eExHSplitMode == SC_SPLIT_NONE)
4335 eExHSplitMode = SC_SPLIT_FIX;
4336
4337 if (eExHSplitMode == SC_SPLIT_FIX)
4338 {
4339 nExFixPosX = nFreezeCol;
4340 pThisTab->nPosX[SC_SPLIT_RIGHT] = nFreezeCol;
4341 }
4342 else
4343 bConvertToScrPosX = true;
4344 }
4345
4346 if (nFreezeRow >= 0)
4347 {
4348 if (eExVSplitMode == SC_SPLIT_NONE)
4349 eExVSplitMode = SC_SPLIT_FIX;
4350
4351 if (eExVSplitMode == SC_SPLIT_FIX)
4352 {
4353 nExFixPosY = nFreezeRow;
4354 pThisTab->nPosY[SC_SPLIT_BOTTOM] = nFreezeRow;
4355 }
4356 else
4357 bConvertToScrPosY = true;
4358 }
4359
4360 if (bConvertToScrPosX || bConvertToScrPosY)
4361 {
4362 Point aExSplitPos = GetScrPos(nFreezeCol, nFreezeRow, SC_SPLIT_BOTTOMLEFT, true, nForTab);
4363 if (bConvertToScrPosX)
4364 nExHSplitPos = aExSplitPos.X();
4365 if (bConvertToScrPosY)
4366 nExVSplitPos = aExSplitPos.Y();
4367 }
4368}
4369
4370/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::chart::ChartAxisLabelPosition ePos
#define SC_HORIZONTAL_SPLIT_POSITION
#define SC_RASTERRESY
#define SC_TABLESELECTED
#define SC_VERTICALSPLITPOSITION_TWIPS
#define SC_SHOWGRID
#define SC_TABLE_VIEWSETTINGS
#define SC_TABLE_ZOOM_VALUE
#define SC_VERTICAL_SPLIT_MODE
#define SC_VIEWSETTINGS_COUNT
#define SC_HORIZONTAL_SPLIT_MODE
#define SC_GRIDCOLOR
#define SC_OUTLSYMB
#define SC_RASTERVIS
#define SC_POSITION_RIGHT
constexpr OUStringLiteral SC_ACTIVESPLITRANGE
constexpr OUStringLiteral SC_SHOWPAGEBREAKPREVIEW
constexpr OUStringLiteral SC_HORIZONTALSCROLLBARWIDTH
constexpr OUStringLiteral SC_TABLES
#define SC_ACTIVE_TABLE
#define SC_VERTICAL_SPLIT_POSITION
constexpr OUStringLiteral SC_POSITIONRIGHT
#define SC_VIEW_ID
#define SC_FORMULA_BAR_HEIGHT_VALUE
#define SC_RELHORIZONTALTABBARWIDTH
constexpr OUStringLiteral SC_ZOOMVALUE
constexpr OUStringLiteral SC_CURSORPOSITIONY
#define SC_RASTERSUBY
#define SC_SHOWNOTES
constexpr OUStringLiteral SC_VERTICALSPLITMODE
#define SC_CURSOR_Y
#define SC_ZOOM_TYPE
#define SC_TABLE_SHOWGRID
#define SC_VALUE_HIGHLIGHTING
constexpr OUStringLiteral SC_POSITIONBOTTOM
constexpr OUStringLiteral SC_VERTICALSPLITPOSITION
constexpr OUStringLiteral SC_POSITIONLEFT
constexpr OUStringLiteral SC_VIEWID
#define SC_SHOWZERO
constexpr OUStringLiteral SC_ZOOMTYPE
constexpr OUStringLiteral SC_HORIZONTALSPLITPOSITION
#define SC_POSITION_TOP
#define SC_RASTERSYNC
#define SC_ACTIVE_SPLIT_RANGE
#define SC_ZOOM_VALUE
#define SC_PAGE_VIEW_ZOOM_VALUE
constexpr OUStringLiteral SC_CURSORPOSITIONX
#define SC_HORIZONTAL_SCROLL_BAR_WIDTH
#define SC_SHOWFORMULASMARKS
#define SC_SNAPTORASTER
#define SC_COLROWHDR
constexpr OUStringLiteral SC_PAGEVIEWZOOMVALUE
constexpr OUStringLiteral SC_FORMULABARHEIGHT
constexpr OUStringLiteral SC_ACTIVETABLE
#define SC_RASTERSUBX
#define SC_CURSOR_X
#define SC_POSITION_LEFT
#define SC_TABLE_PAGE_VIEW_ZOOM_VALUE
#define SC_HORIZONTALSPLITPOSITION_TWIPS
#define SC_TABLE_ZOOM_TYPE
#define SC_TABLE_VIEWSETTINGS_COUNT
#define SC_PAGE_BREAK_PREVIEW
constexpr OUStringLiteral SC_POSITIONTOP
#define SC_SHOWPAGEBR
constexpr OUStringLiteral SC_HORIZONTALSPLITMODE
#define SC_SHEETTABS
#define SC_RASTERRESX
#define SC_POSITION_BOTTOM
bool ValidTab(SCTAB nTab)
Definition: address.hxx:111
const SCROW MAXTILEDROW
Definition: address.hxx:77
const SCTAB MAXTAB
Definition: address.hxx:70
const SCROW MAXROW_30
Definition: address.hxx:97
const SCCOL SC_TABSTART_NONE
Definition: address.hxx:95
const SCTAB SC_TAB_APPEND
Definition: address.hxx:90
static OutputDevice * GetDefaultDevice()
bool IsTransparent() const
OUString GetText(LineEnd eEnd=LINEEND_LF) const
bool SetUpdateLayout(bool bUpdate, bool bRestoring=false)
EEControlBits GetControlWord() const
sal_Int32 GetParagraphCount() const
const Size & GetPaperSize() const
EditView * RemoveView(EditView *pEditView)
sal_uInt32 GetTextHeight() const
bool IsEffectivelyVertical() const
sal_uInt32 CalcTextWidth()
void SetControlWord(EEControlBits nWord)
void SetStatusEventHdl(const Link< EditStatus &, void > &rLink)
void SetPaperSize(const Size &rSize)
void SetLOKSpecialPaperSize(const Size &rSize)
void InsertView(EditView *pEditView, size_t nIndex=EE_APPEND)
const Size & GetLOKSpecialPaperSize() const
void SetLOKSpecialVisArea(const tools::Rectangle &rVisArea)
void SetControlWord(EVControlBits nWord)
void InvalidateOtherViewWindows(const tools::Rectangle &rInvRect)
<