tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / view / tabview2.cxx
blob7f78e9575e83477da7f76ea24500d6f8f729401f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <scitems.hxx>
21 #include <vcl/svapp.hxx>
22 #include <vcl/weld.hxx>
23 #include <sfx2/bindings.hxx>
24 #include <osl/diagnose.h>
26 #include <attrib.hxx>
27 #include <pagedata.hxx>
28 #include <tabview.hxx>
29 #include <tabvwsh.hxx>
30 #include <printfun.hxx>
31 #include <stlpool.hxx>
32 #include <docsh.hxx>
33 #include <gridwin.hxx>
34 #include <sc.hrc>
35 #include <viewutil.hxx>
36 #include <colrowba.hxx>
37 #include <globstr.hrc>
38 #include <scresid.hxx>
39 #include <scmod.hxx>
40 #include <table.hxx>
41 #include <tabprotection.hxx>
42 #include <markdata.hxx>
43 #include <inputopt.hxx>
44 #include <comphelper/lok.hxx>
46 namespace {
48 bool isCellQualified(const ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, bool bSelectLocked, bool bSelectUnlocked)
50 bool bCellProtected = pDoc->HasAttrib(
51 nCol, nRow, nTab, nCol, nRow, nTab, HasAttrFlags::Protected);
53 if (bCellProtected && !bSelectLocked)
54 return false;
56 if (!bCellProtected && !bSelectUnlocked)
57 return false;
59 return true;
62 bool areCellsQualified(const ScDocument* pDoc, SCCOL nColStart, SCROW nRowStart, SCCOL nColEnd,
63 SCROW nRowEnd, SCTAB nTab, bool bSelectLocked, bool bSelectUnlocked)
65 PutInOrder(nColStart, nColEnd);
66 PutInOrder(nRowStart, nRowEnd);
67 for (SCCOL col = nColStart; col <= nColEnd; ++col)
68 for (SCROW row = nRowStart; row <= nRowEnd; ++row)
69 if (!isCellQualified(pDoc, col, row, nTab, bSelectLocked, bSelectUnlocked))
70 return false;
72 return true;
75 void moveCursorByProtRule(
76 SCCOL& rCol, SCROW& rRow, SCCOL nMovX, SCROW nMovY, SCTAB nTab, const ScDocument* pDoc)
78 bool bSelectLocked = true;
79 bool bSelectUnlocked = true;
80 const ScTableProtection* pTabProtection = pDoc->GetTabProtection(nTab);
81 if (pTabProtection && pTabProtection->isProtected())
83 bSelectLocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
84 bSelectUnlocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
87 if (nMovX > 0)
89 for (SCCOL i = 0; i < nMovX && rCol < pDoc->MaxCol(); ++i)
91 SCCOL nNewUnhiddenCol = rCol + 1;
92 SCCOL nEndCol = 0;
93 while(pDoc->ColHidden(nNewUnhiddenCol, nTab, nullptr, &nEndCol))
95 if(nNewUnhiddenCol >= pDoc->MaxCol())
96 return;
98 i += nEndCol - nNewUnhiddenCol + 1;
99 nNewUnhiddenCol = nEndCol +1;
102 if (!isCellQualified(pDoc, nNewUnhiddenCol, rRow, nTab, bSelectLocked, bSelectUnlocked))
103 break;
104 rCol = nNewUnhiddenCol;
107 else if (nMovX < 0)
109 for (SCCOL i = 0; i > nMovX && rCol > 0; --i)
111 SCCOL nNewUnhiddenCol = rCol - 1;
112 SCCOL nStartCol = 0;
113 while(pDoc->ColHidden(nNewUnhiddenCol, nTab, &nStartCol))
115 if(nNewUnhiddenCol <= 0)
116 return;
118 i -= nNewUnhiddenCol - nStartCol + 1;
119 nNewUnhiddenCol = nStartCol - 1;
122 if (!isCellQualified(pDoc, nNewUnhiddenCol, rRow, nTab, bSelectLocked, bSelectUnlocked))
123 break;
124 rCol = nNewUnhiddenCol;
128 if (nMovY > 0)
130 for (SCROW i = 0; i < nMovY && rRow < pDoc->MaxRow(); ++i)
132 SCROW nNewUnhiddenRow = rRow + 1;
133 SCROW nEndRow = 0;
134 while(pDoc->RowHidden(nNewUnhiddenRow, nTab, nullptr, &nEndRow))
136 if(nNewUnhiddenRow >= pDoc->MaxRow())
137 return;
139 i += nEndRow - nNewUnhiddenRow + 1;
140 nNewUnhiddenRow = nEndRow + 1;
143 if (!isCellQualified(pDoc, rCol, nNewUnhiddenRow, nTab, bSelectLocked, bSelectUnlocked))
144 break;
145 rRow = nNewUnhiddenRow;
148 else if (nMovY < 0)
150 for (SCROW i = 0; i > nMovY && rRow > 0; --i)
152 SCROW nNewUnhiddenRow = rRow - 1;
153 SCROW nStartRow = 0;
154 while(pDoc->RowHidden(nNewUnhiddenRow, nTab, &nStartRow))
156 if(nNewUnhiddenRow <= 0)
157 return;
159 i -= nNewUnhiddenRow - nStartRow + 1;
160 nNewUnhiddenRow = nStartRow - 1;
163 if (!isCellQualified(pDoc, rCol, nNewUnhiddenRow, nTab, bSelectLocked, bSelectUnlocked))
164 break;
165 rRow = nNewUnhiddenRow;
170 bool checkBoundary(const ScDocument* pDoc, SCCOL& rCol, SCROW& rRow)
172 bool bGood = true;
173 if (rCol < 0)
175 rCol = 0;
176 bGood = false;
178 else if (rCol > pDoc->MaxCol())
180 rCol = pDoc->MaxCol();
181 bGood = false;
184 if (rRow < 0)
186 rRow = 0;
187 bGood = false;
189 else if (rRow > pDoc->MaxRow())
191 rRow = pDoc->MaxRow();
192 bGood = false;
194 return bGood;
197 void moveRefByCell(SCCOL& rNewX, SCROW& rNewY,
198 SCCOL nMovX, SCROW nMovY, SCTAB nRefTab,
199 const ScDocument& rDoc)
201 SCCOL nOldX = rNewX;
202 SCROW nOldY = rNewY;
203 bool bSelectLocked = true;
204 bool bSelectUnlocked = true;
205 const ScTableProtection* pTabProtection = rDoc.GetTabProtection(nRefTab);
206 if (pTabProtection && pTabProtection->isProtected())
208 bSelectLocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
209 bSelectUnlocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
212 moveCursorByProtRule(rNewX, rNewY, nMovX, nMovY, nRefTab, &rDoc);
213 checkBoundary(&rDoc, rNewX, rNewY);
215 if (nMovX)
217 SCCOL nTempX = rNewX;
218 while (rDoc.IsHorOverlapped(nTempX, rNewY, nRefTab))
220 nTempX = (nMovX > 0) ? nTempX + 1 : nTempX - 1;
221 if (!checkBoundary(&rDoc, nTempX, rNewY))
222 break;
224 if (isCellQualified(&rDoc, nTempX, rNewY, nRefTab, bSelectLocked, bSelectUnlocked))
225 rNewX = nTempX;
227 if (nMovX < 0 && rNewX > 0)
229 const ScMergeAttr* pMergeAttr = rDoc.GetAttr(rNewX, rNewY, nRefTab, ATTR_MERGE);
230 if (pMergeAttr && pMergeAttr->IsMerged() &&
231 nOldX >= rNewX &&
232 nOldX <= rNewX + pMergeAttr->GetRowMerge() - 1)
233 rNewX = rNewX - 1;
237 if (nMovY)
239 SCROW nTempY = rNewY;
240 while (rDoc.IsVerOverlapped(rNewX, nTempY, nRefTab))
242 nTempY = (nMovY > 0) ? nTempY + 1 : nTempY - 1;
243 if (!checkBoundary(&rDoc, rNewX, nTempY))
244 break;
246 if (isCellQualified(&rDoc, rNewX, nTempY, nRefTab, bSelectLocked, bSelectUnlocked))
247 rNewY = nTempY;
249 if (nMovY < 0 && rNewY > 0)
251 const ScMergeAttr* pMergeAttr = rDoc.GetAttr(rNewX, rNewY, nRefTab, ATTR_MERGE);
252 if (pMergeAttr && pMergeAttr->IsMerged() &&
253 nOldY >= rNewY &&
254 nOldY <= rNewY + pMergeAttr->GetRowMerge() - 1)
255 rNewY = rNewY - 1;
259 rDoc.SkipOverlapped(rNewX, rNewY, nRefTab);
262 void moveCursorByMergedCell(SCCOL& rCol, SCROW& rRow, SCCOL nMovX, SCROW nMovY, SCCOL nStartX,
263 SCROW nStartY, SCTAB nTab, const ScDocument* pDoc)
265 const ScTableProtection* pTabProtection = pDoc->GetTabProtection(nTab);
266 bool bSelectLocked = true;
267 bool bSelectUnlocked = true;
268 if (pTabProtection && pTabProtection->isProtected())
270 bSelectLocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
271 bSelectUnlocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
274 if (nMovX > 0)
276 SCROW rowStart = std::min(rRow, nStartY);
277 SCROW rowEnd = std::max(rRow, nStartY);
279 for (SCROW i = rowStart; i <= rowEnd && rCol < nStartX;)
281 SCCOL tmpCol = rCol;
282 while (tmpCol < pDoc->MaxCol() && pDoc->IsHorOverlapped(tmpCol, i, nTab))
283 ++tmpCol;
284 if (tmpCol != rCol)
286 i = rowStart;
287 if (tmpCol > nStartX)
288 --tmpCol;
289 if (!areCellsQualified(pDoc, rCol + 1, rowStart, tmpCol, rowEnd, nTab,
290 bSelectLocked, bSelectUnlocked))
291 break;
292 rCol = tmpCol;
294 else
295 ++i;
298 else if (nMovX < 0)
300 SCROW rowStart = std::min(rRow, nStartY);
301 SCROW rowEnd = std::max(rRow, nStartY);
303 for (SCROW i = rowStart; i <= rowEnd && rCol > nStartX;)
305 SCCOL tmpCol = rCol;
306 while (tmpCol >= 0 && pDoc->IsHorOverlapped(tmpCol + 1, i, nTab))
307 --tmpCol;
308 if (tmpCol != rCol)
310 i = rowStart;
311 if (tmpCol < nStartX)
312 ++tmpCol;
313 if (!areCellsQualified(pDoc, rCol - 1, rowStart, tmpCol, rowEnd, nTab,
314 bSelectLocked, bSelectUnlocked))
315 break;
316 rCol = tmpCol;
318 else
319 ++i;
323 if (nMovY > 0)
325 SCCOL colStart = std::min(rCol, nStartX);
326 SCCOL colEnd = std::max(rCol, nStartX);
328 for (SCCOL i = colStart; i <= colEnd && rRow < nStartY;)
330 SCROW tmpRow = rRow;
331 while (tmpRow < pDoc->MaxRow() && pDoc->IsVerOverlapped(i, tmpRow, nTab))
332 ++tmpRow;
333 if (tmpRow != rRow)
335 i = colStart;
336 if (tmpRow > nStartY)
337 --tmpRow;
338 if (!areCellsQualified(pDoc, colStart, rRow + 1, colEnd, tmpRow, nTab,
339 bSelectLocked, bSelectUnlocked))
340 break;
341 rRow = tmpRow;
343 else
344 ++i;
347 else if (nMovY < 0)
349 SCCOL colStart = std::min(rCol, nStartX);
350 SCCOL colEnd = std::max(rCol, nStartX);
352 for (SCCOL i = colStart; i <= colEnd && rRow > nStartY;)
354 SCROW tmpRow = rRow;
355 while (tmpRow >= 0 && pDoc->IsVerOverlapped(i, tmpRow + 1, nTab))
356 --tmpRow;
357 if (tmpRow != rRow)
359 i = colStart;
360 if (tmpRow < nStartY)
361 ++tmpRow;
362 if (!areCellsQualified(pDoc, colStart, rRow - 1, colEnd, tmpRow, nTab,
363 bSelectLocked, bSelectUnlocked))
364 break;
365 rRow = tmpRow;
367 else
368 ++i;
373 void moveCursorToProperSide(SCCOL& rCol, SCROW& rRow, SCCOL nMovX, SCROW nMovY, SCCOL nStartX,
374 SCROW nStartY, SCTAB nTab, const ScDocument* pDoc)
376 SCCOL tmpCol = rCol;
377 SCROW tmpRow = rRow;
379 if (nMovX > 0 && nStartX < pDoc->MaxCol() && rCol < nStartX)
381 SCROW rowStart = std::min(rRow, nStartY);
382 SCROW rowEnd = std::max(rRow, nStartY);
383 for (SCROW i = rowStart; i <= rowEnd && tmpCol < nStartX;)
385 if (pDoc->IsHorOverlapped(tmpCol + 1, i, nTab))
389 ++tmpCol;
390 } while (pDoc->IsHorOverlapped(tmpCol + 1, i, nTab));
391 i = rowStart;
393 else
394 ++i;
396 if (tmpCol < nStartX)
397 tmpCol = rCol;
399 else if (nMovX < 0 && nStartX > 0 && rCol > nStartX)
401 SCROW rowStart = std::min(rRow, nStartY);
402 SCROW rowEnd = std::max(rRow, nStartY);
403 for (SCROW i = rowStart; i <= rowEnd && tmpCol > nStartX;)
405 if (pDoc->IsHorOverlapped(tmpCol, i, nTab))
409 --tmpCol;
410 } while (pDoc->IsHorOverlapped(tmpCol, i, nTab));
411 i = rowStart;
413 else
414 ++i;
416 if (tmpCol > nStartX)
417 tmpCol = rCol;
420 if (nMovY > 0 && nStartY < pDoc->MaxRow() && rRow < nStartY)
422 SCCOL colStart = std::min(rCol, nStartX);
423 SCCOL colEnd = std::max(rCol, nStartX);
424 for (SCCOL i = colStart; i <= colEnd && tmpRow < nStartY;)
426 if (pDoc->IsVerOverlapped(i, tmpRow + 1, nTab))
430 ++tmpRow;
431 } while (pDoc->IsVerOverlapped(i, tmpRow + 1, nTab));
432 i = colStart;
434 else
435 ++i;
437 if (tmpRow < nStartY)
438 tmpRow = rRow;
440 else if (nMovY < 0 && nStartY > 0 && rRow > nStartY)
442 SCCOL colStart = std::min(rCol, nStartX);
443 SCCOL colEnd = std::max(rCol, nStartX);
444 for (SCCOL i = colStart; i <= colEnd && tmpRow > nStartY;)
446 if (pDoc->IsVerOverlapped(i, tmpRow, nTab))
450 --tmpRow;
451 } while (pDoc->IsVerOverlapped(i, tmpRow, nTab));
452 i = colStart;
454 else
455 ++i;
457 if (tmpRow > nStartY)
458 tmpRow = rRow;
461 if (tmpCol != rCol)
462 rCol = tmpCol;
463 if (tmpRow != rRow)
464 rRow = tmpRow;
468 void ScTabView::PaintMarks(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow )
470 auto& rDoc = aViewData.GetDocument();
471 if (!rDoc.ValidCol(nStartCol)) nStartCol = rDoc.MaxCol();
472 if (!rDoc.ValidRow(nStartRow)) nStartRow = rDoc.MaxRow();
473 if (!rDoc.ValidCol(nEndCol)) nEndCol = rDoc.MaxCol();
474 if (!rDoc.ValidRow(nEndRow)) nEndRow = rDoc.MaxRow();
476 bool bLeft = (nStartCol==0 && nEndCol==rDoc.MaxCol());
477 bool bTop = (nStartRow==0 && nEndRow==rDoc.MaxRow());
479 if (bLeft)
480 PaintLeftArea( nStartRow, nEndRow );
481 if (bTop)
482 PaintTopArea( nStartCol, nEndCol );
484 aViewData.GetDocument().ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow,
485 aViewData.GetTabNo() );
486 PaintArea( nStartCol, nStartRow, nEndCol, nEndRow, ScUpdateMode::Marks );
489 bool ScTabView::IsMarking( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
491 return IsBlockMode()
492 && nBlockStartX == nCol
493 && nBlockStartY == nRow
494 && nBlockStartZ == nTab;
497 void ScTabView::InitOwnBlockMode( const ScRange& rMarkRange )
499 if (IsBlockMode())
500 return;
502 // when there is no (old) selection anymore, delete anchor in SelectionEngine:
503 ScMarkData& rMark = aViewData.GetMarkData();
504 if (!rMark.IsMarked() && !rMark.IsMultiMarked())
505 GetSelEngine()->CursorPosChanging( false, false );
507 meBlockMode = Own;
508 nBlockStartX = rMarkRange.aStart.Col();
509 nBlockStartY = rMarkRange.aStart.Row();
510 nBlockStartZ = rMarkRange.aStart.Tab();
511 nBlockEndX = rMarkRange.aEnd.Col();
512 nBlockEndY = rMarkRange.aEnd.Row();
513 nBlockEndZ = rMarkRange.aEnd.Tab();
515 SelectionChanged(); // status is checked with mark set
518 void ScTabView::InitBlockModeHighlight( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ,
519 bool bCols, bool bRows )
521 if (meHighlightBlockMode != None)
522 return;
524 auto& rDoc = aViewData.GetDocument();
525 if (!rDoc.ValidCol(nCurX)) nCurX = rDoc.MaxCol();
526 if (!rDoc.ValidRow(nCurY)) nCurY = rDoc.MaxRow();
528 ScMarkData& rMark = aViewData.GetHighlightData();
529 meHighlightBlockMode = Normal;
531 SCROW nStartY = nCurY;
532 SCCOL nStartX = nCurX;
533 SCROW nEndY = nCurY;
534 SCCOL nEndX = nCurX;
536 if (bCols)
538 nStartY = 0;
539 nEndY = rDoc.MaxRow();
542 if (bRows)
544 nStartX = 0;
545 nEndX = rDoc.MaxCol();
548 rMark.SetMarkArea( ScRange( nStartX, nStartY, nCurZ, nEndX, nEndY, nCurZ ) );
549 UpdateHighlightOverlay();
552 void ScTabView::InitBlockMode( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ,
553 bool bTestNeg, bool bCols, bool bRows, bool bForceNeg )
555 if (IsBlockMode())
556 return;
558 auto& rDoc = aViewData.GetDocument();
559 if (!rDoc.ValidCol(nCurX)) nCurX = rDoc.MaxCol();
560 if (!rDoc.ValidRow(nCurY)) nCurY = rDoc.MaxRow();
562 ScMarkData& rMark = aViewData.GetMarkData();
563 SCTAB nTab = aViewData.GetTabNo();
565 // unmark part?
566 if (bForceNeg)
567 bBlockNeg = true;
568 else if (bTestNeg)
570 if ( bCols )
571 bBlockNeg = rMark.IsColumnMarked( nCurX );
572 else if ( bRows )
573 bBlockNeg = rMark.IsRowMarked( nCurY );
574 else
575 bBlockNeg = rMark.IsCellMarked( nCurX, nCurY );
577 else
578 bBlockNeg = false;
579 rMark.SetMarkNegative(bBlockNeg);
581 meBlockMode = Normal;
582 bBlockCols = bCols;
583 bBlockRows = bRows;
584 nBlockStartX = nBlockStartXOrig = nCurX;
585 nBlockStartY = nBlockStartYOrig = nCurY;
586 nBlockStartZ = nCurZ;
587 nBlockEndX = nOldCurX = nBlockStartX;
588 nBlockEndY = nOldCurY = nBlockStartY;
589 nBlockEndZ = nBlockStartZ;
591 if (bBlockCols)
593 nBlockStartY = nBlockStartYOrig = 0;
594 nBlockEndY = rDoc.MaxRow();
597 if (bBlockRows)
599 nBlockStartX = nBlockStartXOrig = 0;
600 nBlockEndX = rDoc.MaxCol();
603 rMark.SetMarkArea( ScRange( nBlockStartX,nBlockStartY, nTab, nBlockEndX,nBlockEndY, nTab ) );
605 UpdateSelectionOverlay();
608 void ScTabView::DoneBlockModeHighlight( bool bContinue )
610 if (meHighlightBlockMode == None)
611 return;
613 ScMarkData& rMark = aViewData.GetHighlightData();
614 bool bFlag = rMark.GetMarkingFlag();
615 rMark.SetMarking(false);
617 if (bContinue)
618 rMark.MarkToMulti();
619 else
621 SCTAB nTab = aViewData.GetTabNo();
622 ScDocument& rDoc = aViewData.GetDocument();
623 if ( rDoc.HasTable(nTab) )
624 rMark.ResetMark();
626 meHighlightBlockMode = None;
628 rMark.SetMarking(bFlag);
629 if (bContinue)
630 rMark.SetMarking(false);
633 void ScTabView::DoneBlockMode( bool bContinue )
635 // When switching between sheet and header SelectionEngine DeselectAll may be called,
636 // because the other engine does not have any anchor.
637 // bMoveIsShift prevents the selection to be canceled.
639 if (!IsBlockMode() || bMoveIsShift)
640 return;
642 ScMarkData& rMark = aViewData.GetMarkData();
643 bool bFlag = rMark.GetMarkingFlag();
644 rMark.SetMarking(false);
646 if (bBlockNeg && !bContinue)
647 rMark.MarkToMulti();
649 if (bContinue)
650 rMark.MarkToMulti();
651 else
653 // the sheet may be invalid at this point because DoneBlockMode from SetTabNo is
654 // called (for example, when the current sheet is closed from another View)
655 SCTAB nTab = aViewData.GetTabNo();
656 ScDocument& rDoc = aViewData.GetDocument();
657 if ( rDoc.HasTable(nTab) )
658 PaintBlock( true ); // true -> delete block
659 else
660 rMark.ResetMark();
662 meBlockMode = None;
664 rMark.SetMarking(bFlag);
665 rMark.SetMarkNegative(false);
668 bool ScTabView::IsBlockMode() const
670 return meBlockMode != None;
673 void ScTabView::MarkCursor( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ,
674 bool bCols, bool bRows, bool bCellSelection )
676 ScDocument& rDocument = aViewData.GetDocument();
677 if (!rDocument.ValidCol(nCurX)) nCurX = rDocument.MaxCol();
678 if (!rDocument.ValidRow(nCurY)) nCurY = rDocument.MaxRow();
680 if (!IsBlockMode())
682 OSL_FAIL( "MarkCursor not in BlockMode" );
683 InitBlockMode( nCurX, nCurY, nCurZ, false, bCols, bRows );
686 if (bCols)
687 nCurY = rDocument.MaxRow();
688 if (bRows)
689 nCurX = rDocument.MaxCol();
691 ScMarkData& rMark = aViewData.GetMarkData();
692 OSL_ENSURE(rMark.IsMarked() || rMark.IsMultiMarked(), "MarkCursor, !IsMarked()");
693 const ScRange& aMarkRange = rMark.GetMarkArea();
694 if (( aMarkRange.aStart.Col() != nBlockStartX && aMarkRange.aEnd.Col() != nBlockStartX ) ||
695 ( aMarkRange.aStart.Row() != nBlockStartY && aMarkRange.aEnd.Row() != nBlockStartY ) ||
696 ( meBlockMode == Own ))
698 // Mark has been changed
699 // (Eg MarkToSimple if by negative everything was erased, except for a rectangle)
700 // or after InitOwnBlockMode is further marked with shift-
701 bool bOldShift = bMoveIsShift;
702 bMoveIsShift = false; // really move
703 DoneBlockMode(); //! Set variables directly? (-> no flicker)
704 bMoveIsShift = bOldShift;
706 InitBlockMode( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
707 nBlockStartZ, rMark.IsMarkNegative(), bCols, bRows );
710 if ( nCurX != nOldCurX || nCurY != nOldCurY )
712 // Current cursor has moved
714 SCTAB nTab = nCurZ;
716 if ( bCellSelection )
718 // Expand selection area accordingly when the current selection cuts
719 // through a merged cell.
720 ScRange cellSel(nBlockStartXOrig, nBlockStartYOrig, nTab, nCurX, nCurY, nTab);
721 cellSel.PutInOrder();
722 ScRange oldSel;
725 oldSel = cellSel;
726 rDocument.ExtendOverlapped(cellSel);
727 rDocument.ExtendMerge(cellSel);
728 } while (oldSel != cellSel);
730 // Preserve the directionality of the selection
731 if (nCurX >= nBlockStartXOrig)
733 nBlockStartX = cellSel.aStart.Col();
734 nBlockEndX = cellSel.aEnd.Col();
736 else
738 nBlockStartX = cellSel.aEnd.Col();
739 nBlockEndX = cellSel.aStart.Col();
741 if (nCurY >= nBlockStartYOrig)
743 nBlockStartY = cellSel.aStart.Row();
744 nBlockEndY = cellSel.aEnd.Row();
746 else
748 nBlockStartY = cellSel.aEnd.Row();
749 nBlockEndY = cellSel.aStart.Row();
752 else
754 nBlockEndX = nCurX;
755 nBlockEndY = nCurY;
758 // Set new selection area
759 rMark.SetMarkArea( ScRange( nBlockStartX, nBlockStartY, nTab, nBlockEndX, nBlockEndY, nTab ) );
761 UpdateSelectionOverlay();
762 SelectionChanged();
764 nOldCurX = nBlockEndX;
765 nOldCurY = nBlockEndY;
767 aViewData.GetViewShell()->UpdateInputHandler();
770 if ( !bCols && !bRows )
771 aHdrFunc.SetAnchorFlag( false );
774 void ScTabView::GetPageMoveEndPosition(SCCOL nMovX, SCROW nMovY, SCCOL& rPageX, SCROW& rPageY)
776 SCCOL nCurX;
777 SCROW nCurY;
778 if (aViewData.IsRefMode())
780 nCurX = aViewData.GetRefEndX();
781 nCurY = aViewData.GetRefEndY();
783 else if (IsBlockMode())
785 // block end position.
786 nCurX = nBlockEndX;
787 nCurY = nBlockEndY;
789 else
791 // cursor position
792 nCurX = aViewData.GetCurX();
793 nCurY = aViewData.GetCurY();
796 ScSplitPos eWhich = aViewData.GetActivePart();
797 ScHSplitPos eWhichX = WhichH( eWhich );
798 ScVSplitPos eWhichY = WhichV( eWhich );
800 sal_uInt16 nScrSizeY = SC_SIZE_NONE;
801 if (comphelper::LibreOfficeKit::isActive() && aViewData.GetPageUpDownOffset() > 0) {
802 nScrSizeY = ScViewData::ToPixel( aViewData.GetPageUpDownOffset(), aViewData.GetPPTX() );
805 SCCOL nPageX;
806 SCROW nPageY;
807 if (nMovX >= 0)
808 nPageX = aViewData.CellsAtX( nCurX, 1, eWhichX ) * nMovX;
809 else
810 nPageX = aViewData.CellsAtX( nCurX, -1, eWhichX ) * nMovX;
812 if (nMovY >= 0)
813 nPageY = aViewData.CellsAtY( nCurY, 1, eWhichY, nScrSizeY ) * nMovY;
814 else
815 nPageY = aViewData.CellsAtY( nCurY, -1, eWhichY, nScrSizeY ) * nMovY;
817 if (nMovX != 0 && nPageX == 0) nPageX = (nMovX>0) ? 1 : -1;
818 if (nMovY != 0 && nPageY == 0) nPageY = (nMovY>0) ? 1 : -1;
820 rPageX = nPageX;
821 rPageY = nPageY;
824 void ScTabView::GetAreaMoveEndPosition(SCCOL nMovX, SCROW nMovY, ScFollowMode eMode,
825 SCCOL& rAreaX, SCROW& rAreaY, ScFollowMode& rMode,
826 bool bInteractiveByUser)
828 SCCOL nNewX = -1;
829 SCROW nNewY = -1;
831 // current cursor position.
832 SCCOL nCurX = aViewData.GetCurX();
833 SCROW nCurY = aViewData.GetCurY();
835 ScModule* pScModule = ScModule::get();
836 bool bLegacyCellSelection = pScModule->GetInputOptions().GetLegacyCellSelection();
837 bool bIncrementallyExpandToDocLimits(false);
839 if (aViewData.IsRefMode())
841 nNewX = aViewData.GetRefEndX();
842 nNewY = aViewData.GetRefEndY();
843 nCurX = aViewData.GetRefStartX();
844 nCurY = aViewData.GetRefStartY();
846 else if (IsBlockMode())
848 // block end position.
849 nNewX = nBlockEndX;
850 nNewY = nBlockEndY;
852 else
854 nNewX = nCurX;
855 nNewY = nCurY;
856 // cool#6931 on ctrl+[right/down] don't immediately leap to the far limits of the document when no more data,
857 // instead jump a generous block of emptiness. Limit to direct interaction by user and the simple
858 // case.
859 bIncrementallyExpandToDocLimits = bInteractiveByUser && (nMovX == 1 || nMovY == 1) &&
860 !bLegacyCellSelection && comphelper::LibreOfficeKit::isActive();
863 ScDocument& rDoc = aViewData.GetDocument();
864 SCTAB nTab = aViewData.GetTabNo();
866 // FindAreaPos knows only -1 or 1 as direction
867 SCCOL nVirtualX = bLegacyCellSelection ? nNewX : nCurX;
868 SCROW nVirtualY = bLegacyCellSelection ? nNewY : nCurY;
870 SCCOLROW i;
871 if ( nMovX > 0 )
872 for ( i=0; i<nMovX; i++ )
873 rDoc.FindAreaPos( nNewX, nVirtualY, nTab, SC_MOVE_RIGHT );
874 if ( nMovX < 0 )
875 for ( i=0; i<-nMovX; i++ )
876 rDoc.FindAreaPos( nNewX, nVirtualY, nTab, SC_MOVE_LEFT );
877 if ( nMovY > 0 )
878 for ( i=0; i<nMovY; i++ )
879 rDoc.FindAreaPos( nVirtualX, nNewY, nTab, SC_MOVE_DOWN );
880 if ( nMovY < 0 )
881 for ( i=0; i<-nMovY; i++ )
882 rDoc.FindAreaPos( nVirtualX, nNewY, nTab, SC_MOVE_UP );
884 if (eMode==SC_FOLLOW_JUMP) // bottom right do not show too much grey
886 if (nMovX != 0 && nNewX == rDoc.MaxCol())
888 eMode = SC_FOLLOW_LINE;
889 if (bIncrementallyExpandToDocLimits)
891 if (const ScTable* pTab = rDoc.FetchTable(nTab))
893 if (!pTab->HasData(nNewX, nCurY))
895 SCCOL nLastUsedCol(0);
896 SCROW nLastUsedRow(0);
897 rDoc.GetPrintArea(nTab, nLastUsedCol, nLastUsedRow);
898 SCCOL nJumpFrom = std::max(nCurX, nLastUsedCol);
899 nNewX = ((nJumpFrom / 13) + 2) * 13 - 1;
904 if (nMovY != 0 && nNewY == rDoc.MaxRow())
906 eMode = SC_FOLLOW_LINE;
907 if (bIncrementallyExpandToDocLimits)
909 if (const ScTable* pTab = rDoc.FetchTable(nTab))
911 if (!pTab->HasData(nCurX, nNewY))
913 SCCOL nLastUsedCol(0);
914 SCROW nLastUsedRow(0);
915 rDoc.GetPrintArea(nTab, nLastUsedCol, nLastUsedRow);
916 SCROW nJumpFrom = std::max(nCurY, nLastUsedRow);
917 nNewY = ((nJumpFrom / 500) + 2) * 500 - 1;
924 if (aViewData.IsRefMode())
926 rAreaX = nNewX - aViewData.GetRefEndX();
927 rAreaY = nNewY - aViewData.GetRefEndY();
929 else if (IsBlockMode())
931 rAreaX = nNewX - nBlockEndX;
932 rAreaY = nNewY - nBlockEndY;
934 else
936 rAreaX = nNewX - nCurX;
937 rAreaY = nNewY - nCurY;
939 rMode = eMode;
942 void ScTabView::SkipCursorHorizontal(SCCOL& rCurX, SCROW& rCurY, SCCOL nOldX, SCCOL nMovX)
944 ScDocument& rDoc = aViewData.GetDocument();
945 SCTAB nTab = aViewData.GetTabNo();
947 bool bSkipProtected = false, bSkipUnprotected = false;
948 const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
949 if (pProtect && pProtect->isProtected())
951 bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
952 bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
955 bool bSkipCell = false;
956 bool bHFlip = false;
957 // If a number of last columns are hidden, search up to and including the first of them,
958 // because after it nothing changes.
959 SCCOL nMaxCol;
960 if(rDoc.ColHidden(rDoc.MaxCol(), nTab, &nMaxCol))
961 ++nMaxCol;
962 else
963 nMaxCol = rDoc.MaxCol();
964 // Search also at least up to and including the first unallocated column (all unallocated columns
965 // share a set of attrs).
966 nMaxCol = std::max( nMaxCol, std::min<SCCOL>( rDoc.GetAllocatedColumnsCount(nTab) + 1, rDoc.MaxCol()));
969 bSkipCell = rDoc.ColHidden(rCurX, nTab) || rDoc.IsHorOverlapped(rCurX, rCurY, nTab);
970 if (bSkipProtected && !bSkipCell)
971 bSkipCell = rDoc.HasAttrib(rCurX, rCurY, nTab, rCurX, rCurY, nTab, HasAttrFlags::Protected);
972 if (bSkipUnprotected && !bSkipCell)
973 bSkipCell = !rDoc.HasAttrib(rCurX, rCurY, nTab, rCurX, rCurY, nTab, HasAttrFlags::Protected);
975 if (bSkipCell)
977 if (rCurX <= 0 || rCurX >= nMaxCol)
979 if (bHFlip)
981 rCurX = nOldX;
982 bSkipCell = false;
984 else
986 nMovX = -nMovX;
987 if (nMovX > 0)
988 ++rCurX;
989 else
990 --rCurX;
991 bHFlip = true;
994 else
995 if (nMovX > 0)
996 ++rCurX;
997 else
998 --rCurX;
1001 while (bSkipCell);
1003 if (rDoc.IsVerOverlapped(rCurX, rCurY, nTab))
1005 aViewData.SetOldCursor(rCurX, rCurY);
1006 while (rDoc.IsVerOverlapped(rCurX, rCurY, nTab))
1007 --rCurY;
1011 void ScTabView::SkipCursorVertical(SCCOL& rCurX, SCROW& rCurY, SCROW nOldY, SCROW nMovY)
1013 ScDocument& rDoc = aViewData.GetDocument();
1014 SCTAB nTab = aViewData.GetTabNo();
1016 bool bSkipProtected = false, bSkipUnprotected = false;
1017 const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
1018 if (pProtect && pProtect->isProtected())
1020 bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
1021 bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
1024 bool bSkipCell = false;
1025 bool bVFlip = false;
1026 // Avoid repeated calls to RowHidden(), IsVerOverlapped() and HasAttrib().
1027 SCROW nFirstSameHiddenRow = -1;
1028 SCROW nLastSameHiddenRow = -1;
1029 bool bRowHidden = false;
1030 SCROW nFirstSameIsVerOverlapped = -1;
1031 SCROW nLastSameIsVerOverlapped = -1;
1032 bool bIsVerOverlapped = false;
1033 SCROW nFirstSameHasAttribRow = -1;
1034 SCROW nLastSameHasAttribRow = -1;
1035 bool bHasAttribProtected = false;
1038 if( rCurY < nFirstSameHiddenRow || rCurY > nLastSameHiddenRow )
1039 bRowHidden = rDoc.RowHidden(rCurY, nTab, &nFirstSameHiddenRow, &nLastSameHiddenRow);
1040 bSkipCell = bRowHidden;
1041 if( !bSkipCell )
1043 if( rCurY < nFirstSameIsVerOverlapped || rCurY > nLastSameIsVerOverlapped )
1044 bIsVerOverlapped = rDoc.IsVerOverlapped(rCurX, rCurY, nTab, &nFirstSameIsVerOverlapped, &nLastSameIsVerOverlapped);
1045 bSkipCell = bIsVerOverlapped;
1047 if (bSkipProtected && !bSkipCell)
1049 if( rCurY < nFirstSameHasAttribRow || rCurY > nLastSameHasAttribRow )
1050 bHasAttribProtected = rDoc.HasAttrib(rCurX, rCurY, nTab, HasAttrFlags::Protected,
1051 &nFirstSameHasAttribRow, &nLastSameHasAttribRow);
1052 bSkipCell = bHasAttribProtected;
1054 if (bSkipUnprotected && !bSkipCell)
1056 if( rCurY < nFirstSameHasAttribRow || rCurY > nLastSameHasAttribRow )
1057 bHasAttribProtected = rDoc.HasAttrib(rCurX, rCurY, nTab, HasAttrFlags::Protected,
1058 &nFirstSameHasAttribRow, &nLastSameHasAttribRow);
1059 bSkipCell = !bHasAttribProtected;
1062 if (bSkipCell)
1064 if (rCurY <= 0 || rCurY >= rDoc.MaxRow())
1066 if (bVFlip)
1068 rCurY = nOldY;
1069 bSkipCell = false;
1071 else
1073 nMovY = -nMovY;
1074 if (nMovY > 0)
1075 ++rCurY;
1076 else
1077 --rCurY;
1078 bVFlip = true;
1081 else
1082 if (nMovY > 0)
1083 ++rCurY;
1084 else
1085 --rCurY;
1088 while (bSkipCell);
1090 if (rDoc.IsHorOverlapped(rCurX, rCurY, nTab))
1092 aViewData.SetOldCursor(rCurX, rCurY);
1093 while (rDoc.IsHorOverlapped(rCurX, rCurY, nTab))
1094 --rCurX;
1098 void ScTabView::ExpandBlock(SCCOL nMovX, SCROW nMovY, ScFollowMode eMode)
1100 if (!nMovX && !nMovY)
1101 // Nothing to do. Bail out.
1102 return;
1104 ScTabViewShell* pViewShell = aViewData.GetViewShell();
1105 bool bRefInputMode = pViewShell && pViewShell->IsRefInputMode();
1106 if (bRefInputMode && !aViewData.IsRefMode())
1107 // initialize formula reference mode if it hasn't already.
1108 InitRefMode(aViewData.GetCurX(), aViewData.GetCurY(), aViewData.GetTabNo(), SC_REFTYPE_REF);
1110 ScDocument& rDoc = aViewData.GetDocument();
1112 if (aViewData.IsRefMode())
1114 // formula reference mode
1116 SCCOL nNewX = aViewData.GetRefEndX();
1117 SCROW nNewY = aViewData.GetRefEndY();
1118 SCTAB nRefTab = aViewData.GetRefEndZ();
1120 moveRefByCell(nNewX, nNewY, nMovX, nMovY, nRefTab, rDoc);
1122 UpdateRef(nNewX, nNewY, nRefTab);
1123 SCCOL nTargetCol = nNewX;
1124 SCROW nTargetRow = nNewY;
1125 if (((aViewData.GetRefStartX() == 0) || (aViewData.GetRefStartY() == 0)) &&
1126 ((nNewX != rDoc.MaxCol()) || (nNewY != rDoc.MaxRow())))
1128 // Row selection
1129 if ((aViewData.GetRefStartX() == 0) && (nNewX == rDoc.MaxCol()))
1130 nTargetCol = aViewData.GetCurX();
1131 // Column selection
1132 if ((aViewData.GetRefStartY() == 0) && (nNewY == rDoc.MaxRow()))
1133 nTargetRow = aViewData.GetCurY();
1135 AlignToCursor(nTargetCol, nTargetRow, eMode);
1137 else
1139 // normal selection mode
1141 SCTAB nTab = aViewData.GetTabNo();
1142 SCCOL nOrigX = aViewData.GetCurX();
1143 SCROW nOrigY = aViewData.GetCurY();
1145 // Note that the origin position *never* moves during selection.
1147 if (!IsBlockMode())
1149 InitBlockMode(nOrigX, nOrigY, nTab, true);
1150 const ScMergeAttr* pMergeAttr = rDoc.GetAttr(nOrigX, nOrigY, nTab, ATTR_MERGE);
1151 if (pMergeAttr && pMergeAttr->IsMerged())
1153 nBlockEndX = nOrigX + pMergeAttr->GetColMerge() - 1;
1154 nBlockEndY = nOrigY + pMergeAttr->GetRowMerge() - 1;
1158 moveCursorToProperSide(nBlockEndX, nBlockEndY, nMovX, nMovY, nBlockStartX, nBlockStartY,
1159 nTab, &rDoc);
1160 moveCursorByProtRule(nBlockEndX, nBlockEndY, nMovX, nMovY, nTab, &rDoc);
1161 checkBoundary(&rDoc, nBlockEndX, nBlockEndY);
1162 moveCursorByMergedCell(nBlockEndX, nBlockEndY, nMovX, nMovY, nBlockStartX, nBlockStartY,
1163 nTab, &rDoc);
1164 checkBoundary(&rDoc, nBlockEndX, nBlockEndY);
1166 MarkCursor(nBlockEndX, nBlockEndY, nTab, false, false, true);
1168 // Check if the entire row(s) or column(s) are selected.
1169 ScSplitPos eActive = aViewData.GetActivePart();
1170 bool bRowSelected = (nBlockStartX == 0 && nBlockEndX == rDoc.MaxCol());
1171 bool bColSelected = (nBlockStartY == 0 && nBlockEndY == rDoc.MaxRow());
1172 SCCOL nAlignX = bRowSelected ? aViewData.GetPosX(WhichH(eActive)) : nBlockEndX;
1173 SCROW nAlignY = bColSelected ? aViewData.GetPosY(WhichV(eActive)) : nBlockEndY;
1174 AlignToCursor(nAlignX, nAlignY, eMode);
1176 SelectionChanged();
1180 void ScTabView::ExpandBlockPage(SCCOL nMovX, SCROW nMovY)
1182 SCCOL nPageX;
1183 SCROW nPageY;
1184 GetPageMoveEndPosition(nMovX, nMovY, nPageX, nPageY);
1185 ExpandBlock(nPageX, nPageY, SC_FOLLOW_FIX);
1188 void ScTabView::ExpandBlockArea(SCCOL nMovX, SCROW nMovY)
1190 SCCOL nAreaX;
1191 SCROW nAreaY;
1192 ScFollowMode eMode;
1193 GetAreaMoveEndPosition(nMovX, nMovY, SC_FOLLOW_JUMP, nAreaX, nAreaY, eMode);
1194 ExpandBlock(nAreaX, nAreaY, eMode);
1197 void ScTabView::UpdateCopySourceOverlay()
1199 for (VclPtr<ScGridWindow> & pWin : pGridWin)
1200 if (pWin && pWin->IsVisible())
1201 pWin->UpdateCopySourceOverlay();
1204 void ScTabView::UpdateSelectionOverlay()
1206 for (VclPtr<ScGridWindow> & pWin : pGridWin)
1207 if ( pWin && pWin->IsVisible() )
1208 pWin->UpdateSelectionOverlay();
1211 void ScTabView::UpdateHighlightOverlay()
1213 for (VclPtr<ScGridWindow> & pWin : pGridWin)
1214 if ( pWin && pWin->IsVisible() )
1215 pWin->UpdateHighlightOverlay();
1218 void ScTabView::UpdateShrinkOverlay()
1220 for (VclPtr<ScGridWindow> & pWin : pGridWin)
1221 if ( pWin && pWin->IsVisible() )
1222 pWin->UpdateShrinkOverlay();
1225 void ScTabView::UpdateAllOverlays()
1227 for (VclPtr<ScGridWindow> & pWin : pGridWin)
1228 if ( pWin && pWin->IsVisible() )
1229 pWin->UpdateAllOverlays();
1233 //! divide PaintBlock into two methods: RepaintBlock and RemoveBlock or similar
1236 void ScTabView::PaintBlock( bool bReset )
1238 ScMarkData& rMark = aViewData.GetMarkData();
1239 SCTAB nTab = aViewData.GetTabNo();
1240 bool bMulti = rMark.IsMultiMarked();
1241 if (!(rMark.IsMarked() || bMulti))
1242 return;
1244 ScRange aMarkRange;
1245 HideAllCursors();
1246 if (bMulti)
1248 bool bFlag = rMark.GetMarkingFlag();
1249 rMark.SetMarking(false);
1250 rMark.MarkToMulti();
1251 aMarkRange = rMark.GetMultiMarkArea();
1252 rMark.MarkToSimple();
1253 rMark.SetMarking(bFlag);
1255 else
1256 aMarkRange = rMark.GetMarkArea();
1258 nBlockStartX = aMarkRange.aStart.Col();
1259 nBlockStartY = aMarkRange.aStart.Row();
1260 nBlockStartZ = aMarkRange.aStart.Tab();
1261 nBlockEndX = aMarkRange.aEnd.Col();
1262 nBlockEndY = aMarkRange.aEnd.Row();
1263 nBlockEndZ = aMarkRange.aEnd.Tab();
1265 bool bDidReset = false;
1267 if ( nTab>=nBlockStartZ && nTab<=nBlockEndZ )
1269 if ( bReset )
1271 // Inverting when deleting only on active View
1272 if ( aViewData.IsActive() )
1274 rMark.ResetMark();
1275 UpdateSelectionOverlay();
1276 bDidReset = true;
1279 else
1280 PaintMarks( nBlockStartX, nBlockStartY, nBlockEndX, nBlockEndY );
1283 if ( bReset && !bDidReset )
1284 rMark.ResetMark();
1286 ShowAllCursors();
1289 void ScTabView::SelectAll( bool bContinue )
1291 ScDocument& rDoc = aViewData.GetDocument();
1292 ScMarkData& rMark = aViewData.GetMarkData();
1293 SCTAB nTab = aViewData.GetTabNo();
1295 if (rMark.IsMarked())
1297 if ( rMark.GetMarkArea() == ScRange( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab ) )
1298 return;
1301 DoneBlockMode( bContinue );
1302 InitBlockMode( 0,0,nTab );
1303 MarkCursor( rDoc.MaxCol(),rDoc.MaxRow(),nTab );
1305 SelectionChanged();
1308 void ScTabView::SelectAllTables()
1310 ScDocument& rDoc = aViewData.GetDocument();
1311 ScMarkData& rMark = aViewData.GetMarkData();
1312 SCTAB nCount = rDoc.GetTableCount();
1314 if (nCount>1)
1316 for (SCTAB i=0; i<nCount; i++)
1317 rMark.SelectTable( i, true );
1319 aViewData.GetDocShell()->PostPaintExtras();
1320 SfxBindings& rBind = aViewData.GetBindings();
1321 rBind.Invalidate( FID_FILL_TAB );
1322 rBind.Invalidate( FID_TAB_DESELECTALL );
1326 void ScTabView::DeselectAllTables()
1328 ScDocument& rDoc = aViewData.GetDocument();
1329 ScMarkData& rMark = aViewData.GetMarkData();
1330 SCTAB nTab = aViewData.GetTabNo();
1331 SCTAB nCount = rDoc.GetTableCount();
1333 for (SCTAB i=0; i<nCount; i++)
1334 rMark.SelectTable( i, ( i == nTab ) );
1336 aViewData.GetDocShell()->PostPaintExtras();
1337 SfxBindings& rBind = aViewData.GetBindings();
1338 rBind.Invalidate( FID_FILL_TAB );
1339 rBind.Invalidate( FID_TAB_DESELECTALL );
1342 static bool lcl_FitsInWindow( double fScaleX, double fScaleY, sal_uInt16 nZoom,
1343 tools::Long nWindowX, tools::Long nWindowY, const ScDocument* pDoc, SCTAB nTab,
1344 SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1345 SCCOL nFixPosX, SCROW nFixPosY )
1347 double fZoomFactor = static_cast<double>(Fraction(nZoom,100));
1348 fScaleX *= fZoomFactor;
1349 fScaleY *= fZoomFactor;
1351 tools::Long nBlockX = 0;
1352 SCCOL nCol;
1353 for (nCol=0; nCol<nFixPosX; nCol++)
1355 // for frozen panes, add both parts
1356 sal_uInt16 nColTwips = pDoc->GetColWidth( nCol, nTab );
1357 if (nColTwips)
1359 nBlockX += static_cast<tools::Long>(nColTwips * fScaleX);
1360 if (nBlockX > nWindowX)
1361 return false;
1364 for (nCol=nStartCol; nCol<=nEndCol; nCol++)
1366 sal_uInt16 nColTwips = pDoc->GetColWidth( nCol, nTab );
1367 if (nColTwips)
1369 nBlockX += static_cast<tools::Long>(nColTwips * fScaleX);
1370 if (nBlockX > nWindowX)
1371 return false;
1375 tools::Long nBlockY = 0;
1376 for (SCROW nRow = 0; nRow <= nFixPosY-1; ++nRow)
1378 if (pDoc->RowHidden(nRow, nTab))
1379 continue;
1381 // for frozen panes, add both parts
1382 sal_uInt16 nRowTwips = pDoc->GetRowHeight(nRow, nTab);
1383 if (nRowTwips)
1385 nBlockY += static_cast<tools::Long>(nRowTwips * fScaleY);
1386 if (nBlockY > nWindowY)
1387 return false;
1390 for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
1392 sal_uInt16 nRowTwips = pDoc->GetRowHeight(nRow, nTab);
1393 if (nRowTwips)
1395 nBlockY += static_cast<tools::Long>(nRowTwips * fScaleY);
1396 if (nBlockY > nWindowY)
1397 return false;
1401 return true;
1404 sal_uInt16 ScTabView::CalcZoom( SvxZoomType eType, sal_uInt16 nOldZoom )
1406 sal_uInt16 nZoom = 100;
1408 switch ( eType )
1410 case SvxZoomType::PERCENT: // rZoom is no particular percent value
1411 nZoom = nOldZoom;
1412 break;
1414 case SvxZoomType::OPTIMAL: // nZoom corresponds to the optimal size
1416 ScMarkData& rMark = aViewData.GetMarkData();
1417 ScDocument& rDoc = aViewData.GetDocument();
1419 if (!rMark.IsMarked() && !rMark.IsMultiMarked())
1420 nZoom = 100; // nothing selected
1421 else
1423 SCTAB nTab = aViewData.GetTabNo();
1424 ScRange aMarkRange;
1425 if ( aViewData.GetSimpleArea( aMarkRange ) != SC_MARK_SIMPLE )
1426 aMarkRange = rMark.GetMultiMarkArea();
1428 SCCOL nStartCol = aMarkRange.aStart.Col();
1429 SCROW nStartRow = aMarkRange.aStart.Row();
1430 SCTAB nStartTab = aMarkRange.aStart.Tab();
1431 SCCOL nEndCol = aMarkRange.aEnd.Col();
1432 SCROW nEndRow = aMarkRange.aEnd.Row();
1433 SCTAB nEndTab = aMarkRange.aEnd.Tab();
1435 if ( nTab < nStartTab && nTab > nEndTab )
1436 nTab = nStartTab;
1438 ScSplitPos eUsedPart = aViewData.GetActivePart();
1440 SCCOL nFixPosX = 0;
1441 SCROW nFixPosY = 0;
1442 if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
1444 // use right part
1445 eUsedPart = (WhichV(eUsedPart)==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT;
1446 nFixPosX = aViewData.GetFixPosX();
1447 if ( nStartCol < nFixPosX )
1448 nStartCol = nFixPosX;
1450 if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
1452 // use bottom part
1453 eUsedPart = (WhichH(eUsedPart)==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT;
1454 nFixPosY = aViewData.GetFixPosY();
1455 if ( nStartRow < nFixPosY )
1456 nStartRow = nFixPosY;
1459 if (pGridWin[eUsedPart])
1461 // Because scale is rounded to pixels, the only reliable way to find
1462 // the right scale is to check if a zoom fits
1464 Size aWinSize = pGridWin[eUsedPart]->GetOutputSizePixel();
1466 // for frozen panes, use sum of both parts for calculation
1468 if ( nFixPosX != 0 )
1469 aWinSize.AdjustWidth(GetGridWidth( SC_SPLIT_LEFT ) );
1470 if ( nFixPosY != 0 )
1471 aWinSize.AdjustHeight(GetGridHeight( SC_SPLIT_TOP ) );
1473 ScDocShell* pDocSh = aViewData.GetDocShell();
1474 double nPPTX = ScGlobal::nScreenPPTX / pDocSh->GetOutputFactor();
1475 double nPPTY = ScGlobal::nScreenPPTY;
1477 sal_uInt16 nMin = MINZOOM;
1478 sal_uInt16 nMax = MAXZOOM;
1479 while ( nMax > nMin )
1481 sal_uInt16 nTest = (nMin+nMax+1)/2;
1482 if ( lcl_FitsInWindow(
1483 nPPTX, nPPTY, nTest, aWinSize.Width(), aWinSize.Height(),
1484 &rDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow,
1485 nFixPosX, nFixPosY ) )
1486 nMin = nTest;
1487 else
1488 nMax = nTest-1;
1490 OSL_ENSURE( nMin == nMax, "Nesting is wrong" );
1491 nZoom = nMin;
1493 if ( nZoom != nOldZoom )
1495 // scroll to block only in active split part
1496 // (the part for which the size was calculated)
1498 if ( nStartCol <= nEndCol )
1499 aViewData.SetPosX( WhichH(eUsedPart), nStartCol );
1500 if ( nStartRow <= nEndRow )
1501 aViewData.SetPosY( WhichV(eUsedPart), nStartRow );
1506 break;
1508 case SvxZoomType::WHOLEPAGE: // nZoom corresponds to the whole page or
1509 case SvxZoomType::PAGEWIDTH: // nZoom corresponds to the page width
1511 SCTAB nCurTab = aViewData.GetTabNo();
1512 ScDocument& rDoc = aViewData.GetDocument();
1513 ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
1514 SfxStyleSheetBase* pStyleSheet =
1515 pStylePool->Find( rDoc.GetPageStyle( nCurTab ),
1516 SfxStyleFamily::Page );
1518 OSL_ENSURE( pStyleSheet, "PageStyle not found :-/" );
1520 if ( pStyleSheet )
1522 ScPrintFunc aPrintFunc( aViewData.GetDocShell(),
1523 aViewData.GetViewShell()->GetPrinter(true),
1524 nCurTab );
1526 Size aPageSize = aPrintFunc.GetDataSize();
1528 // use the size of the largest GridWin for normal split,
1529 // or both combined for frozen panes, with the (document) size
1530 // of the frozen part added to the page size
1531 // (with frozen panes, the size of the individual parts
1532 // depends on the scale that is to be calculated)
1534 if (!pGridWin[SC_SPLIT_BOTTOMLEFT])
1535 return nZoom;
1537 Size aWinSize = pGridWin[SC_SPLIT_BOTTOMLEFT]->GetOutputSizePixel();
1538 ScSplitMode eHMode = aViewData.GetHSplitMode();
1539 if ( eHMode != SC_SPLIT_NONE && pGridWin[SC_SPLIT_BOTTOMRIGHT] )
1541 tools::Long nOtherWidth = pGridWin[SC_SPLIT_BOTTOMRIGHT]->
1542 GetOutputSizePixel().Width();
1543 if ( eHMode == SC_SPLIT_FIX )
1545 aWinSize.AdjustWidth(nOtherWidth );
1546 for ( SCCOL nCol = aViewData.GetPosX(SC_SPLIT_LEFT);
1547 nCol < aViewData.GetFixPosX(); nCol++ )
1548 aPageSize.AdjustWidth(rDoc.GetColWidth( nCol, nCurTab ) );
1550 else if ( nOtherWidth > aWinSize.Width() )
1551 aWinSize.setWidth( nOtherWidth );
1553 ScSplitMode eVMode = aViewData.GetVSplitMode();
1554 if ( eVMode != SC_SPLIT_NONE && pGridWin[SC_SPLIT_TOPLEFT] )
1556 tools::Long nOtherHeight = pGridWin[SC_SPLIT_TOPLEFT]->
1557 GetOutputSizePixel().Height();
1558 if ( eVMode == SC_SPLIT_FIX )
1560 aWinSize.AdjustHeight(nOtherHeight );
1561 aPageSize.AdjustHeight(rDoc.GetRowHeight(
1562 aViewData.GetPosY(SC_SPLIT_TOP),
1563 aViewData.GetFixPosY()-1, nCurTab) );
1565 else if ( nOtherHeight > aWinSize.Height() )
1566 aWinSize.setHeight( nOtherHeight );
1569 double nPPTX = ScGlobal::nScreenPPTX / aViewData.GetDocShell()->GetOutputFactor();
1570 double nPPTY = ScGlobal::nScreenPPTY;
1572 tools::Long nZoomX = static_cast<tools::Long>( aWinSize.Width() * 100 /
1573 ( aPageSize.Width() * nPPTX ) );
1574 tools::Long nZoomY = static_cast<tools::Long>( aWinSize.Height() * 100 /
1575 ( aPageSize.Height() * nPPTY ) );
1577 if (nZoomX > 0)
1578 nZoom = static_cast<sal_uInt16>(nZoomX);
1580 if (eType == SvxZoomType::WHOLEPAGE && nZoomY > 0 && nZoomY < nZoom)
1581 nZoom = static_cast<sal_uInt16>(nZoomY);
1584 break;
1586 default:
1587 OSL_FAIL("Unknown Zoom-Revision");
1590 return nZoom;
1593 // is called for instance when the view window is shifted:
1595 void ScTabView::StopMarking()
1597 ScSplitPos eActive = aViewData.GetActivePart();
1598 if (pGridWin[eActive])
1599 pGridWin[eActive]->StopMarking();
1601 ScHSplitPos eH = WhichH(eActive);
1602 if (pColBar[eH])
1603 pColBar[eH]->StopMarking();
1605 ScVSplitPos eV = WhichV(eActive);
1606 if (pRowBar[eV])
1607 pRowBar[eV]->StopMarking();
1610 void ScTabView::HideNoteMarker()
1612 for (VclPtr<ScGridWindow> & pWin : pGridWin)
1613 if (pWin && pWin->IsVisible())
1614 pWin->HideNoteMarker();
1617 void ScTabView::MakeDrawLayer()
1619 if (pDrawView)
1620 return;
1622 aViewData.GetDocShell()->MakeDrawLayer();
1624 // pDrawView is set per Notify
1625 OSL_ENSURE(pDrawView,"ScTabView::MakeDrawLayer does not work");
1627 for(VclPtr<ScGridWindow> & pWin : pGridWin)
1629 if(pWin)
1631 pWin->DrawLayerCreated();
1636 IMPL_STATIC_LINK_NOARG(ScTabView, InstallLOKNotifierHdl, void*, vcl::ILibreOfficeKitNotifier*)
1638 return GetpApp();
1641 void ScTabView::ErrorMessage(TranslateId pGlobStrId)
1643 if (ScModule::get()->IsInExecuteDrop())
1645 // #i28468# don't show error message when called from Drag&Drop, silently abort instead
1646 return;
1649 StopMarking(); // if called by Focus from MouseButtonDown
1651 weld::Window* pParent = aViewData.GetDialogParent();
1652 weld::WaitObject aWaitOff( pParent );
1653 bool bFocus = pParent && pParent->has_focus();
1655 if (pGlobStrId && pGlobStrId == STR_PROTECTIONERR)
1657 if (aViewData.GetDocShell()->IsReadOnly())
1659 pGlobStrId = STR_READONLYERR;
1663 m_xMessageBox.reset(Application::CreateMessageDialog(pParent,
1664 VclMessageType::Info, VclButtonsType::Ok,
1665 ScResId(pGlobStrId)));
1667 if (comphelper::LibreOfficeKit::isActive())
1668 m_xMessageBox->SetInstallLOKNotifierHdl(LINK(this, ScTabView, InstallLOKNotifierHdl));
1670 weld::Window* pGrabOnClose = bFocus ? pParent : nullptr;
1671 m_xMessageBox->runAsync(m_xMessageBox, [this, pGrabOnClose](sal_Int32 /*nResult*/) {
1672 m_xMessageBox.reset();
1673 if (pGrabOnClose)
1674 pGrabOnClose->grab_focus();
1678 void ScTabView::UpdatePageBreakData( bool bForcePaint )
1680 std::unique_ptr<ScPageBreakData> pNewData;
1682 if (aViewData.IsPagebreakMode())
1684 ScDocShell* pDocSh = aViewData.GetDocShell();
1685 ScDocument& rDoc = pDocSh->GetDocument();
1686 SCTAB nTab = aViewData.GetTabNo();
1688 sal_uInt16 nCount = rDoc.GetPrintRangeCount(nTab);
1689 if (!nCount)
1690 nCount = 1;
1691 pNewData.reset( new ScPageBreakData(nCount) );
1693 ScPrintFunc aPrintFunc( pDocSh, pDocSh->GetPrinter(), nTab, 0,0,nullptr, nullptr, pNewData.get() );
1694 // ScPrintFunc fills the PageBreakData in ctor
1695 if ( nCount > 1 )
1697 aPrintFunc.ResetBreaks(nTab);
1698 pNewData->AddPages();
1701 // print area changed?
1702 if ( bForcePaint || ( pPageBreakData && !( *pPageBreakData == *pNewData ) ) )
1703 PaintGrid();
1706 pPageBreakData = std::move(pNewData);
1709 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */