1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <scitems.hxx>
21 #include <vcl/svapp.hxx>
22 #include <vcl/weld.hxx>
23 #include <sfx2/bindings.hxx>
24 #include <osl/diagnose.h>
27 #include <pagedata.hxx>
28 #include <tabview.hxx>
29 #include <tabvwsh.hxx>
30 #include <printfun.hxx>
31 #include <stlpool.hxx>
33 #include <gridwin.hxx>
35 #include <viewutil.hxx>
36 #include <colrowba.hxx>
37 #include <globstr.hrc>
38 #include <scresid.hxx>
41 #include <tabprotection.hxx>
42 #include <markdata.hxx>
43 #include <inputopt.hxx>
44 #include <comphelper/lok.hxx>
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
)
56 if (!bCellProtected
&& !bSelectUnlocked
)
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
))
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
);
89 for (SCCOL i
= 0; i
< nMovX
&& rCol
< pDoc
->MaxCol(); ++i
)
91 SCCOL nNewUnhiddenCol
= rCol
+ 1;
93 while(pDoc
->ColHidden(nNewUnhiddenCol
, nTab
, nullptr, &nEndCol
))
95 if(nNewUnhiddenCol
>= pDoc
->MaxCol())
98 i
+= nEndCol
- nNewUnhiddenCol
+ 1;
99 nNewUnhiddenCol
= nEndCol
+1;
102 if (!isCellQualified(pDoc
, nNewUnhiddenCol
, rRow
, nTab
, bSelectLocked
, bSelectUnlocked
))
104 rCol
= nNewUnhiddenCol
;
109 for (SCCOL i
= 0; i
> nMovX
&& rCol
> 0; --i
)
111 SCCOL nNewUnhiddenCol
= rCol
- 1;
113 while(pDoc
->ColHidden(nNewUnhiddenCol
, nTab
, &nStartCol
))
115 if(nNewUnhiddenCol
<= 0)
118 i
-= nNewUnhiddenCol
- nStartCol
+ 1;
119 nNewUnhiddenCol
= nStartCol
- 1;
122 if (!isCellQualified(pDoc
, nNewUnhiddenCol
, rRow
, nTab
, bSelectLocked
, bSelectUnlocked
))
124 rCol
= nNewUnhiddenCol
;
130 for (SCROW i
= 0; i
< nMovY
&& rRow
< pDoc
->MaxRow(); ++i
)
132 SCROW nNewUnhiddenRow
= rRow
+ 1;
134 while(pDoc
->RowHidden(nNewUnhiddenRow
, nTab
, nullptr, &nEndRow
))
136 if(nNewUnhiddenRow
>= pDoc
->MaxRow())
139 i
+= nEndRow
- nNewUnhiddenRow
+ 1;
140 nNewUnhiddenRow
= nEndRow
+ 1;
143 if (!isCellQualified(pDoc
, rCol
, nNewUnhiddenRow
, nTab
, bSelectLocked
, bSelectUnlocked
))
145 rRow
= nNewUnhiddenRow
;
150 for (SCROW i
= 0; i
> nMovY
&& rRow
> 0; --i
)
152 SCROW nNewUnhiddenRow
= rRow
- 1;
154 while(pDoc
->RowHidden(nNewUnhiddenRow
, nTab
, &nStartRow
))
156 if(nNewUnhiddenRow
<= 0)
159 i
-= nNewUnhiddenRow
- nStartRow
+ 1;
160 nNewUnhiddenRow
= nStartRow
- 1;
163 if (!isCellQualified(pDoc
, rCol
, nNewUnhiddenRow
, nTab
, bSelectLocked
, bSelectUnlocked
))
165 rRow
= nNewUnhiddenRow
;
170 bool checkBoundary(const ScDocument
* pDoc
, SCCOL
& rCol
, SCROW
& rRow
)
178 else if (rCol
> pDoc
->MaxCol())
180 rCol
= pDoc
->MaxCol();
189 else if (rRow
> pDoc
->MaxRow())
191 rRow
= pDoc
->MaxRow();
197 void moveRefByCell(SCCOL
& rNewX
, SCROW
& rNewY
,
198 SCCOL nMovX
, SCROW nMovY
, SCTAB nRefTab
,
199 const ScDocument
& rDoc
)
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
);
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
))
224 if (isCellQualified(&rDoc
, nTempX
, rNewY
, nRefTab
, bSelectLocked
, bSelectUnlocked
))
227 if (nMovX
< 0 && rNewX
> 0)
229 const ScMergeAttr
* pMergeAttr
= rDoc
.GetAttr(rNewX
, rNewY
, nRefTab
, ATTR_MERGE
);
230 if (pMergeAttr
&& pMergeAttr
->IsMerged() &&
232 nOldX
<= rNewX
+ pMergeAttr
->GetRowMerge() - 1)
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
))
246 if (isCellQualified(&rDoc
, rNewX
, nTempY
, nRefTab
, bSelectLocked
, bSelectUnlocked
))
249 if (nMovY
< 0 && rNewY
> 0)
251 const ScMergeAttr
* pMergeAttr
= rDoc
.GetAttr(rNewX
, rNewY
, nRefTab
, ATTR_MERGE
);
252 if (pMergeAttr
&& pMergeAttr
->IsMerged() &&
254 nOldY
<= rNewY
+ pMergeAttr
->GetRowMerge() - 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
);
276 SCROW rowStart
= std::min(rRow
, nStartY
);
277 SCROW rowEnd
= std::max(rRow
, nStartY
);
279 for (SCROW i
= rowStart
; i
<= rowEnd
&& rCol
< nStartX
;)
282 while (tmpCol
< pDoc
->MaxCol() && pDoc
->IsHorOverlapped(tmpCol
, i
, nTab
))
287 if (tmpCol
> nStartX
)
289 if (!areCellsQualified(pDoc
, rCol
+ 1, rowStart
, tmpCol
, rowEnd
, nTab
,
290 bSelectLocked
, bSelectUnlocked
))
300 SCROW rowStart
= std::min(rRow
, nStartY
);
301 SCROW rowEnd
= std::max(rRow
, nStartY
);
303 for (SCROW i
= rowStart
; i
<= rowEnd
&& rCol
> nStartX
;)
306 while (tmpCol
>= 0 && pDoc
->IsHorOverlapped(tmpCol
+ 1, i
, nTab
))
311 if (tmpCol
< nStartX
)
313 if (!areCellsQualified(pDoc
, rCol
- 1, rowStart
, tmpCol
, rowEnd
, nTab
,
314 bSelectLocked
, bSelectUnlocked
))
325 SCCOL colStart
= std::min(rCol
, nStartX
);
326 SCCOL colEnd
= std::max(rCol
, nStartX
);
328 for (SCCOL i
= colStart
; i
<= colEnd
&& rRow
< nStartY
;)
331 while (tmpRow
< pDoc
->MaxRow() && pDoc
->IsVerOverlapped(i
, tmpRow
, nTab
))
336 if (tmpRow
> nStartY
)
338 if (!areCellsQualified(pDoc
, colStart
, rRow
+ 1, colEnd
, tmpRow
, nTab
,
339 bSelectLocked
, bSelectUnlocked
))
349 SCCOL colStart
= std::min(rCol
, nStartX
);
350 SCCOL colEnd
= std::max(rCol
, nStartX
);
352 for (SCCOL i
= colStart
; i
<= colEnd
&& rRow
> nStartY
;)
355 while (tmpRow
>= 0 && pDoc
->IsVerOverlapped(i
, tmpRow
+ 1, nTab
))
360 if (tmpRow
< nStartY
)
362 if (!areCellsQualified(pDoc
, colStart
, rRow
- 1, colEnd
, tmpRow
, nTab
,
363 bSelectLocked
, bSelectUnlocked
))
373 void moveCursorToProperSide(SCCOL
& rCol
, SCROW
& rRow
, SCCOL nMovX
, SCROW nMovY
, SCCOL nStartX
,
374 SCROW nStartY
, SCTAB nTab
, const ScDocument
* pDoc
)
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
))
390 } while (pDoc
->IsHorOverlapped(tmpCol
+ 1, i
, nTab
));
396 if (tmpCol
< nStartX
)
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
))
410 } while (pDoc
->IsHorOverlapped(tmpCol
, i
, nTab
));
416 if (tmpCol
> nStartX
)
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
))
431 } while (pDoc
->IsVerOverlapped(i
, tmpRow
+ 1, nTab
));
437 if (tmpRow
< nStartY
)
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
))
451 } while (pDoc
->IsVerOverlapped(i
, tmpRow
, nTab
));
457 if (tmpRow
> nStartY
)
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());
480 PaintLeftArea( nStartRow
, nEndRow
);
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
492 && nBlockStartX
== nCol
493 && nBlockStartY
== nRow
494 && nBlockStartZ
== nTab
;
497 void ScTabView::InitOwnBlockMode( const ScRange
& rMarkRange
)
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 );
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
)
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
;
539 nEndY
= rDoc
.MaxRow();
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
)
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();
571 bBlockNeg
= rMark
.IsColumnMarked( nCurX
);
573 bBlockNeg
= rMark
.IsRowMarked( nCurY
);
575 bBlockNeg
= rMark
.IsCellMarked( nCurX
, nCurY
);
579 rMark
.SetMarkNegative(bBlockNeg
);
581 meBlockMode
= Normal
;
584 nBlockStartX
= nBlockStartXOrig
= nCurX
;
585 nBlockStartY
= nBlockStartYOrig
= nCurY
;
586 nBlockStartZ
= nCurZ
;
587 nBlockEndX
= nOldCurX
= nBlockStartX
;
588 nBlockEndY
= nOldCurY
= nBlockStartY
;
589 nBlockEndZ
= nBlockStartZ
;
593 nBlockStartY
= nBlockStartYOrig
= 0;
594 nBlockEndY
= rDoc
.MaxRow();
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
)
613 ScMarkData
& rMark
= aViewData
.GetHighlightData();
614 bool bFlag
= rMark
.GetMarkingFlag();
615 rMark
.SetMarking(false);
621 SCTAB nTab
= aViewData
.GetTabNo();
622 ScDocument
& rDoc
= aViewData
.GetDocument();
623 if ( rDoc
.HasTable(nTab
) )
626 meHighlightBlockMode
= None
;
628 rMark
.SetMarking(bFlag
);
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
)
642 ScMarkData
& rMark
= aViewData
.GetMarkData();
643 bool bFlag
= rMark
.GetMarkingFlag();
644 rMark
.SetMarking(false);
646 if (bBlockNeg
&& !bContinue
)
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
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();
682 OSL_FAIL( "MarkCursor not in BlockMode" );
683 InitBlockMode( nCurX
, nCurY
, nCurZ
, false, bCols
, bRows
);
687 nCurY
= rDocument
.MaxRow();
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
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();
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();
738 nBlockStartX
= cellSel
.aEnd
.Col();
739 nBlockEndX
= cellSel
.aStart
.Col();
741 if (nCurY
>= nBlockStartYOrig
)
743 nBlockStartY
= cellSel
.aStart
.Row();
744 nBlockEndY
= cellSel
.aEnd
.Row();
748 nBlockStartY
= cellSel
.aEnd
.Row();
749 nBlockEndY
= cellSel
.aStart
.Row();
758 // Set new selection area
759 rMark
.SetMarkArea( ScRange( nBlockStartX
, nBlockStartY
, nTab
, nBlockEndX
, nBlockEndY
, nTab
) );
761 UpdateSelectionOverlay();
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
)
778 if (aViewData
.IsRefMode())
780 nCurX
= aViewData
.GetRefEndX();
781 nCurY
= aViewData
.GetRefEndY();
783 else if (IsBlockMode())
785 // block end 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() );
808 nPageX
= aViewData
.CellsAtX( nCurX
, 1, eWhichX
) * nMovX
;
810 nPageX
= aViewData
.CellsAtX( nCurX
, -1, eWhichX
) * nMovX
;
813 nPageY
= aViewData
.CellsAtY( nCurY
, 1, eWhichY
, nScrSizeY
) * nMovY
;
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;
824 void ScTabView::GetAreaMoveEndPosition(SCCOL nMovX
, SCROW nMovY
, ScFollowMode eMode
,
825 SCCOL
& rAreaX
, SCROW
& rAreaY
, ScFollowMode
& rMode
,
826 bool bInteractiveByUser
)
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.
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
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
;
872 for ( i
=0; i
<nMovX
; i
++ )
873 rDoc
.FindAreaPos( nNewX
, nVirtualY
, nTab
, SC_MOVE_RIGHT
);
875 for ( i
=0; i
<-nMovX
; i
++ )
876 rDoc
.FindAreaPos( nNewX
, nVirtualY
, nTab
, SC_MOVE_LEFT
);
878 for ( i
=0; i
<nMovY
; i
++ )
879 rDoc
.FindAreaPos( nVirtualX
, nNewY
, nTab
, SC_MOVE_DOWN
);
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
;
936 rAreaX
= nNewX
- nCurX
;
937 rAreaY
= nNewY
- nCurY
;
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;
957 // If a number of last columns are hidden, search up to and including the first of them,
958 // because after it nothing changes.
960 if(rDoc
.ColHidden(rDoc
.MaxCol(), nTab
, &nMaxCol
))
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
);
977 if (rCurX
<= 0 || rCurX
>= nMaxCol
)
1003 if (rDoc
.IsVerOverlapped(rCurX
, rCurY
, nTab
))
1005 aViewData
.SetOldCursor(rCurX
, rCurY
);
1006 while (rDoc
.IsVerOverlapped(rCurX
, rCurY
, nTab
))
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
;
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
;
1064 if (rCurY
<= 0 || rCurY
>= rDoc
.MaxRow())
1090 if (rDoc
.IsHorOverlapped(rCurX
, rCurY
, nTab
))
1092 aViewData
.SetOldCursor(rCurX
, rCurY
);
1093 while (rDoc
.IsHorOverlapped(rCurX
, rCurY
, nTab
))
1098 void ScTabView::ExpandBlock(SCCOL nMovX
, SCROW nMovY
, ScFollowMode eMode
)
1100 if (!nMovX
&& !nMovY
)
1101 // Nothing to do. Bail out.
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())))
1129 if ((aViewData
.GetRefStartX() == 0) && (nNewX
== rDoc
.MaxCol()))
1130 nTargetCol
= aViewData
.GetCurX();
1132 if ((aViewData
.GetRefStartY() == 0) && (nNewY
== rDoc
.MaxRow()))
1133 nTargetRow
= aViewData
.GetCurY();
1135 AlignToCursor(nTargetCol
, nTargetRow
, eMode
);
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.
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
,
1160 moveCursorByProtRule(nBlockEndX
, nBlockEndY
, nMovX
, nMovY
, nTab
, &rDoc
);
1161 checkBoundary(&rDoc
, nBlockEndX
, nBlockEndY
);
1162 moveCursorByMergedCell(nBlockEndX
, nBlockEndY
, nMovX
, nMovY
, nBlockStartX
, nBlockStartY
,
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
);
1180 void ScTabView::ExpandBlockPage(SCCOL nMovX
, SCROW nMovY
)
1184 GetPageMoveEndPosition(nMovX
, nMovY
, nPageX
, nPageY
);
1185 ExpandBlock(nPageX
, nPageY
, SC_FOLLOW_FIX
);
1188 void ScTabView::ExpandBlockArea(SCCOL nMovX
, SCROW nMovY
)
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
))
1248 bool bFlag
= rMark
.GetMarkingFlag();
1249 rMark
.SetMarking(false);
1250 rMark
.MarkToMulti();
1251 aMarkRange
= rMark
.GetMultiMarkArea();
1252 rMark
.MarkToSimple();
1253 rMark
.SetMarking(bFlag
);
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
)
1271 // Inverting when deleting only on active View
1272 if ( aViewData
.IsActive() )
1275 UpdateSelectionOverlay();
1280 PaintMarks( nBlockStartX
, nBlockStartY
, nBlockEndX
, nBlockEndY
);
1283 if ( bReset
&& !bDidReset
)
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
) )
1301 DoneBlockMode( bContinue
);
1302 InitBlockMode( 0,0,nTab
);
1303 MarkCursor( rDoc
.MaxCol(),rDoc
.MaxRow(),nTab
);
1308 void ScTabView::SelectAllTables()
1310 ScDocument
& rDoc
= aViewData
.GetDocument();
1311 ScMarkData
& rMark
= aViewData
.GetMarkData();
1312 SCTAB nCount
= rDoc
.GetTableCount();
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;
1353 for (nCol
=0; nCol
<nFixPosX
; nCol
++)
1355 // for frozen panes, add both parts
1356 sal_uInt16 nColTwips
= pDoc
->GetColWidth( nCol
, nTab
);
1359 nBlockX
+= static_cast<tools::Long
>(nColTwips
* fScaleX
);
1360 if (nBlockX
> nWindowX
)
1364 for (nCol
=nStartCol
; nCol
<=nEndCol
; nCol
++)
1366 sal_uInt16 nColTwips
= pDoc
->GetColWidth( nCol
, nTab
);
1369 nBlockX
+= static_cast<tools::Long
>(nColTwips
* fScaleX
);
1370 if (nBlockX
> nWindowX
)
1375 tools::Long nBlockY
= 0;
1376 for (SCROW nRow
= 0; nRow
<= nFixPosY
-1; ++nRow
)
1378 if (pDoc
->RowHidden(nRow
, nTab
))
1381 // for frozen panes, add both parts
1382 sal_uInt16 nRowTwips
= pDoc
->GetRowHeight(nRow
, nTab
);
1385 nBlockY
+= static_cast<tools::Long
>(nRowTwips
* fScaleY
);
1386 if (nBlockY
> nWindowY
)
1390 for (SCROW nRow
= nStartRow
; nRow
<= nEndRow
; ++nRow
)
1392 sal_uInt16 nRowTwips
= pDoc
->GetRowHeight(nRow
, nTab
);
1395 nBlockY
+= static_cast<tools::Long
>(nRowTwips
* fScaleY
);
1396 if (nBlockY
> nWindowY
)
1404 sal_uInt16
ScTabView::CalcZoom( SvxZoomType eType
, sal_uInt16 nOldZoom
)
1406 sal_uInt16 nZoom
= 100;
1410 case SvxZoomType::PERCENT
: // rZoom is no particular percent value
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
1423 SCTAB nTab
= aViewData
.GetTabNo();
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
)
1438 ScSplitPos eUsedPart
= aViewData
.GetActivePart();
1442 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
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
)
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
) )
1490 OSL_ENSURE( nMin
== nMax
, "Nesting is wrong" );
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
);
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 :-/" );
1522 ScPrintFunc
aPrintFunc( aViewData
.GetDocShell(),
1523 aViewData
.GetViewShell()->GetPrinter(true),
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
])
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
) );
1578 nZoom
= static_cast<sal_uInt16
>(nZoomX
);
1580 if (eType
== SvxZoomType::WHOLEPAGE
&& nZoomY
> 0 && nZoomY
< nZoom
)
1581 nZoom
= static_cast<sal_uInt16
>(nZoomY
);
1587 OSL_FAIL("Unknown Zoom-Revision");
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
);
1603 pColBar
[eH
]->StopMarking();
1605 ScVSplitPos eV
= WhichV(eActive
);
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()
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
)
1631 pWin
->DrawLayerCreated();
1636 IMPL_STATIC_LINK_NOARG(ScTabView
, InstallLOKNotifierHdl
, void*, vcl::ILibreOfficeKitNotifier
*)
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
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();
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
);
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
1697 aPrintFunc
.ResetBreaks(nTab
);
1698 pNewData
->AddPages();
1701 // print area changed?
1702 if ( bForcePaint
|| ( pPageBreakData
&& !( *pPageBreakData
== *pNewData
) ) )
1706 pPageBreakData
= std::move(pNewData
);
1709 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */