diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sc/source/ui/view/tabview2.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sc/source/ui/view/tabview2.cxx')
-rw-r--r-- | sc/source/ui/view/tabview2.cxx | 1510 |
1 files changed, 1510 insertions, 0 deletions
diff --git a/sc/source/ui/view/tabview2.cxx b/sc/source/ui/view/tabview2.cxx new file mode 100644 index 000000000..400ea89b6 --- /dev/null +++ b/sc/source/ui/view/tabview2.cxx @@ -0,0 +1,1510 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <scitems.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <sfx2/bindings.hxx> +#include <osl/diagnose.h> + +#include <attrib.hxx> +#include <pagedata.hxx> +#include <tabview.hxx> +#include <tabvwsh.hxx> +#include <printfun.hxx> +#include <stlpool.hxx> +#include <docsh.hxx> +#include <gridwin.hxx> +#include <sc.hrc> +#include <viewutil.hxx> +#include <colrowba.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <scmod.hxx> +#include <tabprotection.hxx> +#include <markdata.hxx> +#include <inputopt.hxx> +#include <comphelper/lok.hxx> + +namespace { + +bool isCellQualified(const ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, bool bSelectLocked, bool bSelectUnlocked) +{ + bool bCellProtected = pDoc->HasAttrib( + nCol, nRow, nTab, nCol, nRow, nTab, HasAttrFlags::Protected); + + if (bCellProtected && !bSelectLocked) + return false; + + if (!bCellProtected && !bSelectUnlocked) + return false; + + return true; +} + +void moveCursorByProtRule( + SCCOL& rCol, SCROW& rRow, SCCOL nMovX, SCROW nMovY, SCTAB nTab, const ScDocument* pDoc) +{ + bool bSelectLocked = true; + bool bSelectUnlocked = true; + const ScTableProtection* pTabProtection = pDoc->GetTabProtection(nTab); + if (pTabProtection && pTabProtection->isProtected()) + { + bSelectLocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS); + bSelectUnlocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS); + } + + if (nMovX > 0) + { + for (SCCOL i = 0; i < nMovX && rCol < pDoc->MaxCol(); ++i) + { + SCCOL nNewUnhiddenCol = rCol + 1; + SCCOL nEndCol = 0; + while(pDoc->ColHidden(nNewUnhiddenCol, nTab, nullptr, &nEndCol)) + { + if(nNewUnhiddenCol >= pDoc->MaxCol()) + return; + + i += nEndCol - nNewUnhiddenCol + 1; + nNewUnhiddenCol = nEndCol +1; + } + + if (!isCellQualified(pDoc, nNewUnhiddenCol, rRow, nTab, bSelectLocked, bSelectUnlocked)) + break; + rCol = nNewUnhiddenCol; + } + } + else if (nMovX < 0) + { + for (SCCOL i = 0; i > nMovX && rCol > 0; --i) + { + SCCOL nNewUnhiddenCol = rCol - 1; + SCCOL nStartCol = 0; + while(pDoc->ColHidden(nNewUnhiddenCol, nTab, &nStartCol)) + { + if(nNewUnhiddenCol <= 0) + return; + + i -= nNewUnhiddenCol - nStartCol + 1; + nNewUnhiddenCol = nStartCol - 1; + } + + if (!isCellQualified(pDoc, nNewUnhiddenCol, rRow, nTab, bSelectLocked, bSelectUnlocked)) + break; + rCol = nNewUnhiddenCol; + } + } + + if (nMovY > 0) + { + for (SCROW i = 0; i < nMovY && rRow < pDoc->MaxRow(); ++i) + { + SCROW nNewUnhiddenRow = rRow + 1; + SCROW nEndRow = 0; + while(pDoc->RowHidden(nNewUnhiddenRow, nTab, nullptr, &nEndRow)) + { + if(nNewUnhiddenRow >= pDoc->MaxRow()) + return; + + i += nEndRow - nNewUnhiddenRow + 1; + nNewUnhiddenRow = nEndRow + 1; + } + + if (!isCellQualified(pDoc, rCol, nNewUnhiddenRow, nTab, bSelectLocked, bSelectUnlocked)) + break; + rRow = nNewUnhiddenRow; + } + } + else if (nMovY < 0) + { + for (SCROW i = 0; i > nMovY && rRow > 0; --i) + { + SCROW nNewUnhiddenRow = rRow - 1; + SCROW nStartRow = 0; + while(pDoc->RowHidden(nNewUnhiddenRow, nTab, &nStartRow)) + { + if(nNewUnhiddenRow <= 0) + return; + + i -= nNewUnhiddenRow - nStartRow + 1; + nNewUnhiddenRow = nStartRow - 1; + } + + if (!isCellQualified(pDoc, rCol, nNewUnhiddenRow, nTab, bSelectLocked, bSelectUnlocked)) + break; + rRow = nNewUnhiddenRow; + } + } +} + +bool checkBoundary(const ScDocument* pDoc, SCCOL& rCol, SCROW& rRow) +{ + bool bGood = true; + if (rCol < 0) + { + rCol = 0; + bGood = false; + } + else if (rCol > pDoc->MaxCol()) + { + rCol = pDoc->MaxCol(); + bGood = false; + } + + if (rRow < 0) + { + rRow = 0; + bGood = false; + } + else if (rRow > pDoc->MaxRow()) + { + rRow = pDoc->MaxRow(); + bGood = false; + } + return bGood; +} + +void moveCursorByMergedCell( + SCCOL& rCol, SCROW& rRow, SCCOL nMovX, SCROW nMovY, SCTAB nTab, + const ScDocument* pDoc, const ScViewData& rViewData) +{ + SCCOL nOrigX = rViewData.GetCurX(); + SCROW nOrigY = rViewData.GetCurY(); + + const ScTableProtection* pTabProtection = pDoc->GetTabProtection(nTab); + bool bSelectLocked = true; + bool bSelectUnlocked = true; + if (pTabProtection && pTabProtection->isProtected()) + { + bSelectLocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS); + bSelectUnlocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS); + } + + const ScMergeAttr* pMergeAttr = pDoc->GetAttr(nOrigX, nOrigY, nTab, ATTR_MERGE); + + bool bOriginMerged = false; + SCCOL nColSpan = 1; + SCROW nRowSpan = 1; + if (pMergeAttr && pMergeAttr->IsMerged()) + { + nColSpan = pMergeAttr->GetColMerge(); + nRowSpan = pMergeAttr->GetRowMerge(); + bOriginMerged = true; + } + + if (nMovX > 0) + { + SCCOL nOld = rCol; + if (bOriginMerged) + { + // Original cell is merged. Push the block end outside the merged region. + if (nOrigX < pDoc->MaxCol() && nOrigX < rCol && rCol <= nOrigX + nColSpan - 1) + rCol = nOrigX + nColSpan; + } + else + { + pDoc->SkipOverlapped(rCol, rRow, nTab); + } + + if (nOld < rCol) + { + // The block end has moved. Check the protection setting and move back if needed. + checkBoundary(pDoc, rCol, rRow); + if (!isCellQualified(pDoc, rCol, rRow, nTab, bSelectLocked, bSelectUnlocked)) + --rCol; + } + } + if (nMovX < 0) + { + SCCOL nOld = rCol; + if (bOriginMerged) + { + if (nOrigX > 0 && nOrigX <= rCol && rCol < nOrigX + nColSpan - 1) + // Block end is still within the merged region. Push it outside. + rCol = nOrigX - 1; + } + else + { + pDoc->SkipOverlapped(rCol, rRow, nTab); + } + + if (nOld > rCol) + { + // The block end has moved. Check the protection setting and move back if needed. + checkBoundary(pDoc, rCol, rRow); + if (!isCellQualified(pDoc, rCol, rRow, nTab, bSelectLocked, bSelectUnlocked)) + ++rCol; + } + } + if (nMovY > 0) + { + SCROW nOld = rRow; + if (bOriginMerged) + { + // Original cell is merged. Push the block end outside the merged region. + if (nOrigY < pDoc->MaxRow() && nOrigY < rRow && rRow <= nOrigY + nRowSpan - 1) + rRow = nOrigY + nRowSpan; + } + else + { + pDoc->SkipOverlapped(rCol, rRow, nTab); + } + + if (nOld < rRow) + { + // The block end has moved. Check the protection setting and move back if needed. + checkBoundary(pDoc, rCol, rRow); + if (!isCellQualified(pDoc, rCol, rRow, nTab, bSelectLocked, bSelectUnlocked)) + --rRow; + } + } + if (nMovY >= 0) + return; + + SCROW nOld = rRow; + if (bOriginMerged) + { + if (nOrigY > 0 && nOrigY <= rRow && rRow < nOrigY + nRowSpan - 1) + // Block end is still within the merged region. Push it outside. + rRow = nOrigY - 1; + } + else + { + pDoc->SkipOverlapped(rCol, rRow, nTab); + } + + if (nOld > rRow) + { + // The block end has moved. Check the protection setting and move back if needed. + checkBoundary(pDoc, rCol, rRow); + if (!isCellQualified(pDoc, rCol, rRow, nTab, bSelectLocked, bSelectUnlocked)) + ++rRow; + } +} + +} + +void ScTabView::PaintMarks(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) +{ + auto& rDoc = aViewData.GetDocument(); + if (!rDoc.ValidCol(nStartCol)) nStartCol = rDoc.MaxCol(); + if (!rDoc.ValidRow(nStartRow)) nStartRow = rDoc.MaxRow(); + if (!rDoc.ValidCol(nEndCol)) nEndCol = rDoc.MaxCol(); + if (!rDoc.ValidRow(nEndRow)) nEndRow = rDoc.MaxRow(); + + bool bLeft = (nStartCol==0 && nEndCol==rDoc.MaxCol()); + bool bTop = (nStartRow==0 && nEndRow==rDoc.MaxRow()); + + if (bLeft) + PaintLeftArea( nStartRow, nEndRow ); + if (bTop) + PaintTopArea( nStartCol, nEndCol ); + + aViewData.GetDocument().ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, + aViewData.GetTabNo() ); + PaintArea( nStartCol, nStartRow, nEndCol, nEndRow, ScUpdateMode::Marks ); +} + +bool ScTabView::IsMarking( SCCOL nCol, SCROW nRow, SCTAB nTab ) const +{ + return IsBlockMode() + && nBlockStartX == nCol + && nBlockStartY == nRow + && nBlockStartZ == nTab; +} + +void ScTabView::InitOwnBlockMode( const ScRange& rMarkRange ) +{ + if (IsBlockMode()) + return; + + // when there is no (old) selection anymore, delete anchor in SelectionEngine: + ScMarkData& rMark = aViewData.GetMarkData(); + if (!rMark.IsMarked() && !rMark.IsMultiMarked()) + GetSelEngine()->CursorPosChanging( false, false ); + + meBlockMode = Own; + nBlockStartX = rMarkRange.aStart.Col(); + nBlockStartY = rMarkRange.aStart.Row(); + nBlockStartZ = rMarkRange.aStart.Tab(); + nBlockEndX = rMarkRange.aEnd.Col(); + nBlockEndY = rMarkRange.aEnd.Row(); + nBlockEndZ = rMarkRange.aEnd.Tab(); + + SelectionChanged(); // status is checked with mark set +} + +void ScTabView::InitBlockMode( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ, + bool bTestNeg, bool bCols, bool bRows, bool bForceNeg ) +{ + if (IsBlockMode()) + return; + + auto& rDoc = aViewData.GetDocument(); + if (!rDoc.ValidCol(nCurX)) nCurX = rDoc.MaxCol(); + if (!rDoc.ValidRow(nCurY)) nCurY = rDoc.MaxRow(); + + ScMarkData& rMark = aViewData.GetMarkData(); + SCTAB nTab = aViewData.GetTabNo(); + + // unmark part? + if (bForceNeg) + bBlockNeg = true; + else if (bTestNeg) + { + if ( bCols ) + bBlockNeg = rMark.IsColumnMarked( nCurX ); + else if ( bRows ) + bBlockNeg = rMark.IsRowMarked( nCurY ); + else + bBlockNeg = rMark.IsCellMarked( nCurX, nCurY ); + } + else + bBlockNeg = false; + rMark.SetMarkNegative(bBlockNeg); + + meBlockMode = Normal; + bBlockCols = bCols; + bBlockRows = bRows; + nBlockStartX = nBlockStartXOrig = nCurX; + nBlockStartY = nBlockStartYOrig = nCurY; + nBlockStartZ = nCurZ; + nBlockEndX = nOldCurX = nBlockStartX; + nBlockEndY = nOldCurY = nBlockStartY; + nBlockEndZ = nBlockStartZ; + + if (bBlockCols) + { + nBlockStartY = nBlockStartYOrig = 0; + nBlockEndY = rDoc.MaxRow(); + } + + if (bBlockRows) + { + nBlockStartX = nBlockStartXOrig = 0; + nBlockEndX = rDoc.MaxCol(); + } + + rMark.SetMarkArea( ScRange( nBlockStartX,nBlockStartY, nTab, nBlockEndX,nBlockEndY, nTab ) ); + + UpdateSelectionOverlay(); +} + +void ScTabView::DoneBlockMode( bool bContinue ) +{ + // When switching between sheet and header SelectionEngine DeselectAll may be called, + // because the other engine does not have any anchor. + // bMoveIsShift prevents the selection to be canceled. + + if (!IsBlockMode() || bMoveIsShift) + return; + + ScMarkData& rMark = aViewData.GetMarkData(); + bool bFlag = rMark.GetMarkingFlag(); + rMark.SetMarking(false); + + if (bBlockNeg && !bContinue) + rMark.MarkToMulti(); + + if (bContinue) + rMark.MarkToMulti(); + else + { + // the sheet may be invalid at this point because DoneBlockMode from SetTabNo is + // called (for example, when the current sheet is closed from another View) + SCTAB nTab = aViewData.GetTabNo(); + ScDocument& rDoc = aViewData.GetDocument(); + if ( rDoc.HasTable(nTab) ) + PaintBlock( true ); // true -> delete block + else + rMark.ResetMark(); + } + meBlockMode = None; + + rMark.SetMarking(bFlag); + rMark.SetMarkNegative(false); +} + +bool ScTabView::IsBlockMode() const +{ + return meBlockMode != None; +} + +void ScTabView::MarkCursor( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ, + bool bCols, bool bRows, bool bCellSelection ) +{ + ScDocument& rDocument = aViewData.GetDocument(); + if (!rDocument.ValidCol(nCurX)) nCurX = rDocument.MaxCol(); + if (!rDocument.ValidRow(nCurY)) nCurY = rDocument.MaxRow(); + + if (!IsBlockMode()) + { + OSL_FAIL( "MarkCursor not in BlockMode" ); + InitBlockMode( nCurX, nCurY, nCurZ, false, bCols, bRows ); + } + + if (bCols) + nCurY = rDocument.MaxRow(); + if (bRows) + nCurX = rDocument.MaxCol(); + + ScMarkData& rMark = aViewData.GetMarkData(); + OSL_ENSURE(rMark.IsMarked() || rMark.IsMultiMarked(), "MarkCursor, !IsMarked()"); + const ScRange& aMarkRange = rMark.GetMarkArea(); + if (( aMarkRange.aStart.Col() != nBlockStartX && aMarkRange.aEnd.Col() != nBlockStartX ) || + ( aMarkRange.aStart.Row() != nBlockStartY && aMarkRange.aEnd.Row() != nBlockStartY ) || + ( meBlockMode == Own )) + { + // Mark has been changed + // (Eg MarkToSimple if by negative everything was erased, except for a rectangle) + // or after InitOwnBlockMode is further marked with shift- + bool bOldShift = bMoveIsShift; + bMoveIsShift = false; // really move + DoneBlockMode(); //! Set variables directly? (-> no flicker) + bMoveIsShift = bOldShift; + + InitBlockMode( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), + nBlockStartZ, rMark.IsMarkNegative(), bCols, bRows ); + } + + if ( nCurX != nOldCurX || nCurY != nOldCurY ) + { + // Current cursor has moved + + SCTAB nTab = nCurZ; + + if ( bCellSelection ) + { + // Expand selection area accordingly when the current selection ends + // with a merged cell. + SCCOL nCurXOffset = 0; + SCCOL nBlockStartXOffset = 0; + SCROW nCurYOffset = 0; + SCROW nBlockStartYOffset = 0; + bool bBlockStartMerged = false; + + // The following block checks whether or not the "BlockStart" (anchor) + // cell is merged. If it's merged, it'll then move the position of the + // anchor cell to the corner that's diagonally opposite of the + // direction of a current selection area. For instance, if a current + // selection is moving in the upperleft direction, the anchor cell will + // move to the lower-right corner of the merged anchor cell, and so on. + + const ScMergeAttr* pMergeAttr = + rDocument.GetAttr( nBlockStartXOrig, nBlockStartYOrig, nTab, ATTR_MERGE ); + if ( pMergeAttr->IsMerged() ) + { + SCCOL nColSpan = pMergeAttr->GetColMerge(); + SCROW nRowSpan = pMergeAttr->GetRowMerge(); + + if ( nCurX < nBlockStartXOrig + nColSpan - 1 || nCurY < nBlockStartYOrig + nRowSpan - 1 ) + { + nBlockStartX = nCurX >= nBlockStartXOrig ? nBlockStartXOrig : nBlockStartXOrig + nColSpan - 1; + nBlockStartY = nCurY >= nBlockStartYOrig ? nBlockStartYOrig : nBlockStartYOrig + nRowSpan - 1; + nCurXOffset = (nCurX >= nBlockStartXOrig && nCurX < nBlockStartXOrig + nColSpan - 1) ? + nBlockStartXOrig - nCurX + nColSpan - 1 : 0; + nCurYOffset = (nCurY >= nBlockStartYOrig && nCurY < nBlockStartYOrig + nRowSpan - 1) ? + nBlockStartYOrig - nCurY + nRowSpan - 1 : 0; + bBlockStartMerged = true; + } + } + + // The following block checks whether or not the current cell is + // merged. If it is, it'll then set the appropriate X & Y offset + // values (nCurXOffset & nCurYOffset) such that the selection area will + // grow by those specified offset amounts. Note that the values of + // nCurXOffset/nCurYOffset may also be specified in the previous code + // block, in which case whichever value is greater will take on. + + pMergeAttr = rDocument.GetAttr( nCurX, nCurY, nTab, ATTR_MERGE ); + if ( pMergeAttr->IsMerged() ) + { + SCCOL nColSpan = pMergeAttr->GetColMerge(); + SCROW nRowSpan = pMergeAttr->GetRowMerge(); + + if ( nBlockStartX < nCurX + nColSpan - 1 || nBlockStartY < nCurY + nRowSpan - 1 ) + { + if ( nBlockStartX <= nCurX + nColSpan - 1 ) + { + SCCOL nCurXOffsetTemp = (nCurX < nCurX + nColSpan - 1) ? nColSpan - 1 : 0; + nCurXOffset = std::max(nCurXOffset, nCurXOffsetTemp); + } + if ( nBlockStartY <= nCurY + nRowSpan - 1 ) + { + SCROW nCurYOffsetTemp = (nCurY < nCurY + nRowSpan - 1) ? nRowSpan - 1 : 0; + nCurYOffset = std::max(nCurYOffset, nCurYOffsetTemp); + } + if ( ( nBlockStartX > nCurX || nBlockStartY > nCurY ) && + ( nBlockStartX <= nCurX + nColSpan - 1 || nBlockStartY <= nCurY + nRowSpan - 1 ) ) + { + nBlockStartXOffset = (nBlockStartX > nCurX && nBlockStartX <= nCurX + nColSpan - 1) ? nCurX - nBlockStartX : 0; + nBlockStartYOffset = (nBlockStartY > nCurY && nBlockStartY <= nCurY + nRowSpan - 1) ? nCurY - nBlockStartY : 0; + } + } + } + else + { + // The current cell is not merged. Move the anchor cell to its + // original position. + if ( !bBlockStartMerged ) + { + nBlockStartX = nBlockStartXOrig; + nBlockStartY = nBlockStartYOrig; + } + } + + nBlockStartX = nBlockStartX + nBlockStartXOffset >= 0 ? nBlockStartX + nBlockStartXOffset : 0; + nBlockStartY = nBlockStartY + nBlockStartYOffset >= 0 ? nBlockStartY + nBlockStartYOffset : 0; + nBlockEndX = std::min<SCCOL>(nCurX + nCurXOffset, rDocument.MaxCol()); + nBlockEndY = std::min(nCurY + nCurYOffset, rDocument.MaxRow()); + } + else + { + nBlockEndX = nCurX; + nBlockEndY = nCurY; + } + + // Set new selection area + rMark.SetMarkArea( ScRange( nBlockStartX, nBlockStartY, nTab, nBlockEndX, nBlockEndY, nTab ) ); + + UpdateSelectionOverlay(); + SelectionChanged(); + + nOldCurX = nCurX; + nOldCurY = nCurY; + + aViewData.GetViewShell()->UpdateInputHandler(); + } + + if ( !bCols && !bRows ) + aHdrFunc.SetAnchorFlag( false ); +} + +void ScTabView::GetPageMoveEndPosition(SCCOL nMovX, SCROW nMovY, SCCOL& rPageX, SCROW& rPageY) +{ + SCCOL nCurX; + SCROW nCurY; + if (aViewData.IsRefMode()) + { + nCurX = aViewData.GetRefEndX(); + nCurY = aViewData.GetRefEndY(); + } + else if (IsBlockMode()) + { + // block end position. + nCurX = nBlockEndX; + nCurY = nBlockEndY; + } + else + { + // cursor position + nCurX = aViewData.GetCurX(); + nCurY = aViewData.GetCurY(); + } + + ScSplitPos eWhich = aViewData.GetActivePart(); + ScHSplitPos eWhichX = WhichH( eWhich ); + ScVSplitPos eWhichY = WhichV( eWhich ); + + sal_uInt16 nScrSizeY = SC_SIZE_NONE; + if (comphelper::LibreOfficeKit::isActive() && aViewData.GetPageUpDownOffset() > 0) { + nScrSizeY = ScViewData::ToPixel( aViewData.GetPageUpDownOffset(), aViewData.GetPPTX() ); + } + + SCCOL nPageX; + SCROW nPageY; + if (nMovX >= 0) + nPageX = aViewData.CellsAtX( nCurX, 1, eWhichX ) * nMovX; + else + nPageX = aViewData.CellsAtX( nCurX, -1, eWhichX ) * nMovX; + + if (nMovY >= 0) + nPageY = aViewData.CellsAtY( nCurY, 1, eWhichY, nScrSizeY ) * nMovY; + else + nPageY = aViewData.CellsAtY( nCurY, -1, eWhichY, nScrSizeY ) * nMovY; + + if (nMovX != 0 && nPageX == 0) nPageX = (nMovX>0) ? 1 : -1; + if (nMovY != 0 && nPageY == 0) nPageY = (nMovY>0) ? 1 : -1; + + rPageX = nPageX; + rPageY = nPageY; +} + +void ScTabView::GetAreaMoveEndPosition(SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, + SCCOL& rAreaX, SCROW& rAreaY, ScFollowMode& rMode) +{ + SCCOL nNewX = -1; + SCROW nNewY = -1; + + // current cursor position. + SCCOL nCurX = aViewData.GetCurX(); + SCROW nCurY = aViewData.GetCurY(); + + if (aViewData.IsRefMode()) + { + nNewX = aViewData.GetRefEndX(); + nNewY = aViewData.GetRefEndY(); + nCurX = aViewData.GetRefStartX(); + nCurY = aViewData.GetRefStartY(); + } + else if (IsBlockMode()) + { + // block end position. + nNewX = nBlockEndX; + nNewY = nBlockEndY; + } + else + { + nNewX = nCurX; + nNewY = nCurY; + } + + ScDocument& rDoc = aViewData.GetDocument(); + SCTAB nTab = aViewData.GetTabNo(); + + // FindAreaPos knows only -1 or 1 as direction + ScModule* pScModule = SC_MOD(); + bool bLegacyCellSelection = pScModule->GetInputOptions().GetLegacyCellSelection(); + SCCOL nVirtualX = bLegacyCellSelection ? nNewX : nCurX; + SCROW nVirtualY = bLegacyCellSelection ? nNewY : nCurY; + + SCCOLROW i; + if ( nMovX > 0 ) + for ( i=0; i<nMovX; i++ ) + rDoc.FindAreaPos( nNewX, nVirtualY, nTab, SC_MOVE_RIGHT ); + if ( nMovX < 0 ) + for ( i=0; i<-nMovX; i++ ) + rDoc.FindAreaPos( nNewX, nVirtualY, nTab, SC_MOVE_LEFT ); + if ( nMovY > 0 ) + for ( i=0; i<nMovY; i++ ) + rDoc.FindAreaPos( nVirtualX, nNewY, nTab, SC_MOVE_DOWN ); + if ( nMovY < 0 ) + for ( i=0; i<-nMovY; i++ ) + rDoc.FindAreaPos( nVirtualX, nNewY, nTab, SC_MOVE_UP ); + + if (eMode==SC_FOLLOW_JUMP) // bottom right do not show too much grey + { + if (nMovX != 0 && nNewX == rDoc.MaxCol()) + eMode = SC_FOLLOW_LINE; + if (nMovY != 0 && nNewY == rDoc.MaxRow()) + eMode = SC_FOLLOW_LINE; + } + + if (aViewData.IsRefMode()) + { + rAreaX = nNewX - aViewData.GetRefEndX(); + rAreaY = nNewY - aViewData.GetRefEndY(); + } + else if (IsBlockMode()) + { + rAreaX = nNewX - nBlockEndX; + rAreaY = nNewY - nBlockEndY; + } + else + { + rAreaX = nNewX - nCurX; + rAreaY = nNewY - nCurY; + } + rMode = eMode; +} + +void ScTabView::SkipCursorHorizontal(SCCOL& rCurX, SCROW& rCurY, SCCOL nOldX, SCCOL nMovX) +{ + ScDocument& rDoc = aViewData.GetDocument(); + SCTAB nTab = aViewData.GetTabNo(); + + bool bSkipProtected = false, bSkipUnprotected = false; + const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab); + if (pProtect && pProtect->isProtected()) + { + bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS); + bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS); + } + + bool bSkipCell = false; + bool bHFlip = false; + // If a number of last columns are hidden, search up to and including the first of them, + // because after it nothing changes. + SCCOL nMaxCol; + if(rDoc.ColHidden(rDoc.MaxCol(), nTab, &nMaxCol)) + ++nMaxCol; + else + nMaxCol = rDoc.MaxCol(); + // Search also at least up to and including the first unallocated column (all unallocated columns + // share a set of attrs). + nMaxCol = std::max( nMaxCol, std::min<SCCOL>( rDoc.GetAllocatedColumnsCount(nTab) + 1, rDoc.MaxCol())); + do + { + bSkipCell = rDoc.ColHidden(rCurX, nTab) || rDoc.IsHorOverlapped(rCurX, rCurY, nTab); + if (bSkipProtected && !bSkipCell) + bSkipCell = rDoc.HasAttrib(rCurX, rCurY, nTab, rCurX, rCurY, nTab, HasAttrFlags::Protected); + if (bSkipUnprotected && !bSkipCell) + bSkipCell = !rDoc.HasAttrib(rCurX, rCurY, nTab, rCurX, rCurY, nTab, HasAttrFlags::Protected); + + if (bSkipCell) + { + if (rCurX <= 0 || rCurX >= nMaxCol) + { + if (bHFlip) + { + rCurX = nOldX; + bSkipCell = false; + } + else + { + nMovX = -nMovX; + if (nMovX > 0) + ++rCurX; + else + --rCurX; + bHFlip = true; + } + } + else + if (nMovX > 0) + ++rCurX; + else + --rCurX; + } + } + while (bSkipCell); + + if (rDoc.IsVerOverlapped(rCurX, rCurY, nTab)) + { + aViewData.SetOldCursor(rCurX, rCurY); + while (rDoc.IsVerOverlapped(rCurX, rCurY, nTab)) + --rCurY; + } +} + +void ScTabView::SkipCursorVertical(SCCOL& rCurX, SCROW& rCurY, SCROW nOldY, SCROW nMovY) +{ + ScDocument& rDoc = aViewData.GetDocument(); + SCTAB nTab = aViewData.GetTabNo(); + + bool bSkipProtected = false, bSkipUnprotected = false; + const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab); + if (pProtect && pProtect->isProtected()) + { + bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS); + bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS); + } + + bool bSkipCell = false; + bool bVFlip = false; + // Avoid repeated calls to RowHidden(), IsVerOverlapped() and HasAttrib(). + SCROW nFirstSameHiddenRow = -1; + SCROW nLastSameHiddenRow = -1; + bool bRowHidden = false; + SCROW nFirstSameIsVerOverlapped = -1; + SCROW nLastSameIsVerOverlapped = -1; + bool bIsVerOverlapped = false; + SCROW nFirstSameHasAttribRow = -1; + SCROW nLastSameHasAttribRow = -1; + bool bHasAttribProtected = false; + do + { + if( rCurY < nFirstSameHiddenRow || rCurY > nLastSameHiddenRow ) + bRowHidden = rDoc.RowHidden(rCurY, nTab, &nFirstSameHiddenRow, &nLastSameHiddenRow); + bSkipCell = bRowHidden; + if( !bSkipCell ) + { + if( rCurY < nFirstSameIsVerOverlapped || rCurY > nLastSameIsVerOverlapped ) + bIsVerOverlapped = rDoc.IsVerOverlapped(rCurX, rCurY, nTab, &nFirstSameIsVerOverlapped, &nLastSameIsVerOverlapped); + bSkipCell = bIsVerOverlapped; + } + if (bSkipProtected && !bSkipCell) + { + if( rCurY < nFirstSameHasAttribRow || rCurY > nLastSameHasAttribRow ) + bHasAttribProtected = rDoc.HasAttrib(rCurX, rCurY, nTab, HasAttrFlags::Protected, + &nFirstSameHasAttribRow, &nLastSameHasAttribRow); + bSkipCell = bHasAttribProtected; + } + if (bSkipUnprotected && !bSkipCell) + { + if( rCurY < nFirstSameHasAttribRow || rCurY > nLastSameHasAttribRow ) + bHasAttribProtected = rDoc.HasAttrib(rCurX, rCurY, nTab, HasAttrFlags::Protected, + &nFirstSameHasAttribRow, &nLastSameHasAttribRow); + bSkipCell = !bHasAttribProtected; + } + + if (bSkipCell) + { + if (rCurY <= 0 || rCurY >= rDoc.MaxRow()) + { + if (bVFlip) + { + rCurY = nOldY; + bSkipCell = false; + } + else + { + nMovY = -nMovY; + if (nMovY > 0) + ++rCurY; + else + --rCurY; + bVFlip = true; + } + } + else + if (nMovY > 0) + ++rCurY; + else + --rCurY; + } + } + while (bSkipCell); + + if (rDoc.IsHorOverlapped(rCurX, rCurY, nTab)) + { + aViewData.SetOldCursor(rCurX, rCurY); + while (rDoc.IsHorOverlapped(rCurX, rCurY, nTab)) + --rCurX; + } +} + +void ScTabView::ExpandBlock(SCCOL nMovX, SCROW nMovY, ScFollowMode eMode) +{ + if (!nMovX && !nMovY) + // Nothing to do. Bail out. + return; + + ScTabViewShell* pViewShell = aViewData.GetViewShell(); + bool bRefInputMode = pViewShell && pViewShell->IsRefInputMode(); + if (bRefInputMode && !aViewData.IsRefMode()) + // initialize formula reference mode if it hasn't already. + InitRefMode(aViewData.GetCurX(), aViewData.GetCurY(), aViewData.GetTabNo(), SC_REFTYPE_REF); + + ScDocument& rDoc = aViewData.GetDocument(); + + if (aViewData.IsRefMode()) + { + // formula reference mode + + SCCOL nNewX = aViewData.GetRefEndX(); + SCROW nNewY = aViewData.GetRefEndY(); + SCTAB nRefTab = aViewData.GetRefEndZ(); + + bool bSelectLocked = true; + bool bSelectUnlocked = true; + const ScTableProtection* pTabProtection = rDoc.GetTabProtection(nRefTab); + if (pTabProtection && pTabProtection->isProtected()) + { + bSelectLocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS); + bSelectUnlocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS); + } + + moveCursorByProtRule(nNewX, nNewY, nMovX, nMovY, nRefTab, &rDoc); + checkBoundary(&rDoc, nNewX, nNewY); + + if (nMovX) + { + SCCOL nTempX = nNewX; + while (rDoc.IsHorOverlapped(nTempX, nNewY, nRefTab)) + { + if (nMovX > 0) + ++nTempX; + else + --nTempX; + if (!checkBoundary(&rDoc, nTempX, nNewY)) + break; + } + if (isCellQualified(&rDoc, nTempX, nNewY, nRefTab, bSelectLocked, bSelectUnlocked)) + nNewX = nTempX; + } + + if (nMovY) + { + SCROW nTempY = nNewY; + while (rDoc.IsVerOverlapped(nNewX, nTempY, nRefTab)) + { + if (nMovY > 0) + ++nTempY; + else + --nTempY; + if (!checkBoundary(&rDoc, nNewX, nTempY)) + break; + } + if (isCellQualified(&rDoc, nNewX, nTempY, nRefTab, bSelectLocked, bSelectUnlocked)) + nNewY = nTempY; + } + + rDoc.SkipOverlapped(nNewX, nNewY, nRefTab); + UpdateRef(nNewX, nNewY, nRefTab); + SCCOL nTargetCol = nNewX; + SCROW nTargetRow = nNewY; + if (((aViewData.GetRefStartX() == 0) || (aViewData.GetRefStartY() == 0)) && + ((nNewX != rDoc.MaxCol()) || (nNewY != rDoc.MaxRow()))) + { + // Row selection + if ((aViewData.GetRefStartX() == 0) && (nNewX == rDoc.MaxCol())) + nTargetCol = aViewData.GetCurX(); + // Column selection + if ((aViewData.GetRefStartY() == 0) && (nNewY == rDoc.MaxRow())) + nTargetRow = aViewData.GetCurY(); + } + AlignToCursor(nTargetCol, nTargetRow, eMode); + } + else + { + // normal selection mode + + SCTAB nTab = aViewData.GetTabNo(); + SCCOL nOrigX = aViewData.GetCurX(); + SCROW nOrigY = aViewData.GetCurY(); + + // Note that the origin position *never* moves during selection. + + if (!IsBlockMode()) + InitBlockMode(nOrigX, nOrigY, nTab, true); + + moveCursorByProtRule(nBlockEndX, nBlockEndY, nMovX, nMovY, nTab, &rDoc); + checkBoundary(&rDoc, nBlockEndX, nBlockEndY); + moveCursorByMergedCell(nBlockEndX, nBlockEndY, nMovX, nMovY, nTab, &rDoc, aViewData); + checkBoundary(&rDoc, nBlockEndX, nBlockEndY); + + MarkCursor(nBlockEndX, nBlockEndY, nTab, false, false, true); + + // Check if the entire row(s) or column(s) are selected. + ScSplitPos eActive = aViewData.GetActivePart(); + bool bRowSelected = (nBlockStartX == 0 && nBlockEndX == rDoc.MaxCol()); + bool bColSelected = (nBlockStartY == 0 && nBlockEndY == rDoc.MaxRow()); + SCCOL nAlignX = bRowSelected ? aViewData.GetPosX(WhichH(eActive)) : nBlockEndX; + SCROW nAlignY = bColSelected ? aViewData.GetPosY(WhichV(eActive)) : nBlockEndY; + AlignToCursor(nAlignX, nAlignY, eMode); + + SelectionChanged(); + } +} + +void ScTabView::ExpandBlockPage(SCCOL nMovX, SCROW nMovY) +{ + SCCOL nPageX; + SCROW nPageY; + GetPageMoveEndPosition(nMovX, nMovY, nPageX, nPageY); + ExpandBlock(nPageX, nPageY, SC_FOLLOW_FIX); +} + +void ScTabView::ExpandBlockArea(SCCOL nMovX, SCROW nMovY) +{ + SCCOL nAreaX; + SCROW nAreaY; + ScFollowMode eMode; + GetAreaMoveEndPosition(nMovX, nMovY, SC_FOLLOW_JUMP, nAreaX, nAreaY, eMode); + ExpandBlock(nAreaX, nAreaY, eMode); +} + +void ScTabView::UpdateCopySourceOverlay() +{ + for (VclPtr<ScGridWindow> & pWin : pGridWin) + if (pWin && pWin->IsVisible()) + pWin->UpdateCopySourceOverlay(); +} + +void ScTabView::UpdateSelectionOverlay() +{ + for (VclPtr<ScGridWindow> & pWin : pGridWin) + if ( pWin && pWin->IsVisible() ) + pWin->UpdateSelectionOverlay(); +} + +void ScTabView::UpdateShrinkOverlay() +{ + for (VclPtr<ScGridWindow> & pWin : pGridWin) + if ( pWin && pWin->IsVisible() ) + pWin->UpdateShrinkOverlay(); +} + +void ScTabView::UpdateAllOverlays() +{ + for (VclPtr<ScGridWindow> & pWin : pGridWin) + if ( pWin && pWin->IsVisible() ) + pWin->UpdateAllOverlays(); +} + +//! +//! divide PaintBlock into two methods: RepaintBlock and RemoveBlock or similar +//! + +void ScTabView::PaintBlock( bool bReset ) +{ + ScMarkData& rMark = aViewData.GetMarkData(); + SCTAB nTab = aViewData.GetTabNo(); + bool bMulti = rMark.IsMultiMarked(); + if (!(rMark.IsMarked() || bMulti)) + return; + + ScRange aMarkRange; + HideAllCursors(); + if (bMulti) + { + bool bFlag = rMark.GetMarkingFlag(); + rMark.SetMarking(false); + rMark.MarkToMulti(); + aMarkRange = rMark.GetMultiMarkArea(); + rMark.MarkToSimple(); + rMark.SetMarking(bFlag); + } + else + aMarkRange = rMark.GetMarkArea(); + + nBlockStartX = aMarkRange.aStart.Col(); + nBlockStartY = aMarkRange.aStart.Row(); + nBlockStartZ = aMarkRange.aStart.Tab(); + nBlockEndX = aMarkRange.aEnd.Col(); + nBlockEndY = aMarkRange.aEnd.Row(); + nBlockEndZ = aMarkRange.aEnd.Tab(); + + bool bDidReset = false; + + if ( nTab>=nBlockStartZ && nTab<=nBlockEndZ ) + { + if ( bReset ) + { + // Inverting when deleting only on active View + if ( aViewData.IsActive() ) + { + rMark.ResetMark(); + UpdateSelectionOverlay(); + bDidReset = true; + } + } + else + PaintMarks( nBlockStartX, nBlockStartY, nBlockEndX, nBlockEndY ); + } + + if ( bReset && !bDidReset ) + rMark.ResetMark(); + + ShowAllCursors(); +} + +void ScTabView::SelectAll( bool bContinue ) +{ + ScDocument& rDoc = aViewData.GetDocument(); + ScMarkData& rMark = aViewData.GetMarkData(); + SCTAB nTab = aViewData.GetTabNo(); + + if (rMark.IsMarked()) + { + if ( rMark.GetMarkArea() == ScRange( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab ) ) + return; + } + + DoneBlockMode( bContinue ); + InitBlockMode( 0,0,nTab ); + MarkCursor( rDoc.MaxCol(),rDoc.MaxRow(),nTab ); + + SelectionChanged(); +} + +void ScTabView::SelectAllTables() +{ + ScDocument& rDoc = aViewData.GetDocument(); + ScMarkData& rMark = aViewData.GetMarkData(); + SCTAB nCount = rDoc.GetTableCount(); + + if (nCount>1) + { + for (SCTAB i=0; i<nCount; i++) + rMark.SelectTable( i, true ); + + aViewData.GetDocShell()->PostPaintExtras(); + SfxBindings& rBind = aViewData.GetBindings(); + rBind.Invalidate( FID_FILL_TAB ); + rBind.Invalidate( FID_TAB_DESELECTALL ); + } +} + +void ScTabView::DeselectAllTables() +{ + ScDocument& rDoc = aViewData.GetDocument(); + ScMarkData& rMark = aViewData.GetMarkData(); + SCTAB nTab = aViewData.GetTabNo(); + SCTAB nCount = rDoc.GetTableCount(); + + for (SCTAB i=0; i<nCount; i++) + rMark.SelectTable( i, ( i == nTab ) ); + + aViewData.GetDocShell()->PostPaintExtras(); + SfxBindings& rBind = aViewData.GetBindings(); + rBind.Invalidate( FID_FILL_TAB ); + rBind.Invalidate( FID_TAB_DESELECTALL ); +} + +static bool lcl_FitsInWindow( double fScaleX, double fScaleY, sal_uInt16 nZoom, + tools::Long nWindowX, tools::Long nWindowY, const ScDocument* pDoc, SCTAB nTab, + SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, + SCCOL nFixPosX, SCROW nFixPosY ) +{ + double fZoomFactor = static_cast<double>(Fraction(nZoom,100)); + fScaleX *= fZoomFactor; + fScaleY *= fZoomFactor; + + tools::Long nBlockX = 0; + SCCOL nCol; + for (nCol=0; nCol<nFixPosX; nCol++) + { + // for frozen panes, add both parts + sal_uInt16 nColTwips = pDoc->GetColWidth( nCol, nTab ); + if (nColTwips) + { + nBlockX += static_cast<tools::Long>(nColTwips * fScaleX); + if (nBlockX > nWindowX) + return false; + } + } + for (nCol=nStartCol; nCol<=nEndCol; nCol++) + { + sal_uInt16 nColTwips = pDoc->GetColWidth( nCol, nTab ); + if (nColTwips) + { + nBlockX += static_cast<tools::Long>(nColTwips * fScaleX); + if (nBlockX > nWindowX) + return false; + } + } + + tools::Long nBlockY = 0; + for (SCROW nRow = 0; nRow <= nFixPosY-1; ++nRow) + { + if (pDoc->RowHidden(nRow, nTab)) + continue; + + // for frozen panes, add both parts + sal_uInt16 nRowTwips = pDoc->GetRowHeight(nRow, nTab); + if (nRowTwips) + { + nBlockY += static_cast<tools::Long>(nRowTwips * fScaleY); + if (nBlockY > nWindowY) + return false; + } + } + for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow) + { + sal_uInt16 nRowTwips = pDoc->GetRowHeight(nRow, nTab); + if (nRowTwips) + { + nBlockY += static_cast<tools::Long>(nRowTwips * fScaleY); + if (nBlockY > nWindowY) + return false; + } + } + + return true; +} + +sal_uInt16 ScTabView::CalcZoom( SvxZoomType eType, sal_uInt16 nOldZoom ) +{ + sal_uInt16 nZoom = 100; + + switch ( eType ) + { + case SvxZoomType::PERCENT: // rZoom is no particular percent value + nZoom = nOldZoom; + break; + + case SvxZoomType::OPTIMAL: // nZoom corresponds to the optimal size + { + ScMarkData& rMark = aViewData.GetMarkData(); + ScDocument& rDoc = aViewData.GetDocument(); + + if (!rMark.IsMarked() && !rMark.IsMultiMarked()) + nZoom = 100; // nothing selected + else + { + SCTAB nTab = aViewData.GetTabNo(); + ScRange aMarkRange; + if ( aViewData.GetSimpleArea( aMarkRange ) != SC_MARK_SIMPLE ) + aMarkRange = rMark.GetMultiMarkArea(); + + SCCOL nStartCol = aMarkRange.aStart.Col(); + SCROW nStartRow = aMarkRange.aStart.Row(); + SCTAB nStartTab = aMarkRange.aStart.Tab(); + SCCOL nEndCol = aMarkRange.aEnd.Col(); + SCROW nEndRow = aMarkRange.aEnd.Row(); + SCTAB nEndTab = aMarkRange.aEnd.Tab(); + + if ( nTab < nStartTab && nTab > nEndTab ) + nTab = nStartTab; + + ScSplitPos eUsedPart = aViewData.GetActivePart(); + + SCCOL nFixPosX = 0; + SCROW nFixPosY = 0; + if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX ) + { + // use right part + eUsedPart = (WhichV(eUsedPart)==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT; + nFixPosX = aViewData.GetFixPosX(); + if ( nStartCol < nFixPosX ) + nStartCol = nFixPosX; + } + if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX ) + { + // use bottom part + eUsedPart = (WhichH(eUsedPart)==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT; + nFixPosY = aViewData.GetFixPosY(); + if ( nStartRow < nFixPosY ) + nStartRow = nFixPosY; + } + + if (pGridWin[eUsedPart]) + { + // Because scale is rounded to pixels, the only reliable way to find + // the right scale is to check if a zoom fits + + Size aWinSize = pGridWin[eUsedPart]->GetOutputSizePixel(); + + // for frozen panes, use sum of both parts for calculation + + if ( nFixPosX != 0 ) + aWinSize.AdjustWidth(GetGridWidth( SC_SPLIT_LEFT ) ); + if ( nFixPosY != 0 ) + aWinSize.AdjustHeight(GetGridHeight( SC_SPLIT_TOP ) ); + + ScDocShell* pDocSh = aViewData.GetDocShell(); + double nPPTX = ScGlobal::nScreenPPTX / pDocSh->GetOutputFactor(); + double nPPTY = ScGlobal::nScreenPPTY; + + sal_uInt16 nMin = MINZOOM; + sal_uInt16 nMax = MAXZOOM; + while ( nMax > nMin ) + { + sal_uInt16 nTest = (nMin+nMax+1)/2; + if ( lcl_FitsInWindow( + nPPTX, nPPTY, nTest, aWinSize.Width(), aWinSize.Height(), + &rDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow, + nFixPosX, nFixPosY ) ) + nMin = nTest; + else + nMax = nTest-1; + } + OSL_ENSURE( nMin == nMax, "Nesting is wrong" ); + nZoom = nMin; + + if ( nZoom != nOldZoom ) + { + // scroll to block only in active split part + // (the part for which the size was calculated) + + if ( nStartCol <= nEndCol ) + aViewData.SetPosX( WhichH(eUsedPart), nStartCol ); + if ( nStartRow <= nEndRow ) + aViewData.SetPosY( WhichV(eUsedPart), nStartRow ); + } + } + } + } + break; + + case SvxZoomType::WHOLEPAGE: // nZoom corresponds to the whole page or + case SvxZoomType::PAGEWIDTH: // nZoom corresponds to the page width + { + SCTAB nCurTab = aViewData.GetTabNo(); + ScDocument& rDoc = aViewData.GetDocument(); + ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool(); + SfxStyleSheetBase* pStyleSheet = + pStylePool->Find( rDoc.GetPageStyle( nCurTab ), + SfxStyleFamily::Page ); + + OSL_ENSURE( pStyleSheet, "PageStyle not found :-/" ); + + if ( pStyleSheet ) + { + ScPrintFunc aPrintFunc( aViewData.GetDocShell(), + aViewData.GetViewShell()->GetPrinter(true), + nCurTab ); + + Size aPageSize = aPrintFunc.GetDataSize(); + + // use the size of the largest GridWin for normal split, + // or both combined for frozen panes, with the (document) size + // of the frozen part added to the page size + // (with frozen panes, the size of the individual parts + // depends on the scale that is to be calculated) + + if (!pGridWin[SC_SPLIT_BOTTOMLEFT]) + return nZoom; + + Size aWinSize = pGridWin[SC_SPLIT_BOTTOMLEFT]->GetOutputSizePixel(); + ScSplitMode eHMode = aViewData.GetHSplitMode(); + if ( eHMode != SC_SPLIT_NONE && pGridWin[SC_SPLIT_BOTTOMRIGHT] ) + { + tools::Long nOtherWidth = pGridWin[SC_SPLIT_BOTTOMRIGHT]-> + GetOutputSizePixel().Width(); + if ( eHMode == SC_SPLIT_FIX ) + { + aWinSize.AdjustWidth(nOtherWidth ); + for ( SCCOL nCol = aViewData.GetPosX(SC_SPLIT_LEFT); + nCol < aViewData.GetFixPosX(); nCol++ ) + aPageSize.AdjustWidth(rDoc.GetColWidth( nCol, nCurTab ) ); + } + else if ( nOtherWidth > aWinSize.Width() ) + aWinSize.setWidth( nOtherWidth ); + } + ScSplitMode eVMode = aViewData.GetVSplitMode(); + if ( eVMode != SC_SPLIT_NONE && pGridWin[SC_SPLIT_TOPLEFT] ) + { + tools::Long nOtherHeight = pGridWin[SC_SPLIT_TOPLEFT]-> + GetOutputSizePixel().Height(); + if ( eVMode == SC_SPLIT_FIX ) + { + aWinSize.AdjustHeight(nOtherHeight ); + aPageSize.AdjustHeight(rDoc.GetRowHeight( + aViewData.GetPosY(SC_SPLIT_TOP), + aViewData.GetFixPosY()-1, nCurTab) ); + } + else if ( nOtherHeight > aWinSize.Height() ) + aWinSize.setHeight( nOtherHeight ); + } + + double nPPTX = ScGlobal::nScreenPPTX / aViewData.GetDocShell()->GetOutputFactor(); + double nPPTY = ScGlobal::nScreenPPTY; + + tools::Long nZoomX = static_cast<tools::Long>( aWinSize.Width() * 100 / + ( aPageSize.Width() * nPPTX ) ); + tools::Long nZoomY = static_cast<tools::Long>( aWinSize.Height() * 100 / + ( aPageSize.Height() * nPPTY ) ); + + if (nZoomX > 0) + nZoom = static_cast<sal_uInt16>(nZoomX); + + if (eType == SvxZoomType::WHOLEPAGE && nZoomY > 0 && nZoomY < nZoom) + nZoom = static_cast<sal_uInt16>(nZoomY); + } + } + break; + + default: + OSL_FAIL("Unknown Zoom-Revision"); + } + + return nZoom; +} + +// is called for instance when the view window is shifted: + +void ScTabView::StopMarking() +{ + ScSplitPos eActive = aViewData.GetActivePart(); + if (pGridWin[eActive]) + pGridWin[eActive]->StopMarking(); + + ScHSplitPos eH = WhichH(eActive); + if (pColBar[eH]) + pColBar[eH]->StopMarking(); + + ScVSplitPos eV = WhichV(eActive); + if (pRowBar[eV]) + pRowBar[eV]->StopMarking(); +} + +void ScTabView::HideNoteMarker() +{ + for (VclPtr<ScGridWindow> & pWin : pGridWin) + if (pWin && pWin->IsVisible()) + pWin->HideNoteMarker(); +} + +void ScTabView::MakeDrawLayer() +{ + if (pDrawView) + return; + + aViewData.GetDocShell()->MakeDrawLayer(); + + // pDrawView is set per Notify + OSL_ENSURE(pDrawView,"ScTabView::MakeDrawLayer does not work"); + + for(VclPtr<ScGridWindow> & pWin : pGridWin) + { + if(pWin) + { + pWin->DrawLayerCreated(); + } + } +} + +void ScTabView::ErrorMessage(TranslateId pGlobStrId) +{ + if ( SC_MOD()->IsInExecuteDrop() ) + { + // #i28468# don't show error message when called from Drag&Drop, silently abort instead + return; + } + + StopMarking(); // if called by Focus from MouseButtonDown + + weld::Window* pParent = aViewData.GetDialogParent(); + weld::WaitObject aWaitOff( pParent ); + bool bFocus = pParent && pParent->has_focus(); + + if (pGlobStrId && pGlobStrId == STR_PROTECTIONERR) + { + if (aViewData.GetDocShell()->IsReadOnly()) + { + pGlobStrId = STR_READONLYERR; + } + } + + m_xMessageBox.reset(Application::CreateMessageDialog(pParent, + VclMessageType::Info, VclButtonsType::Ok, + ScResId(pGlobStrId))); + weld::Window* pGrabOnClose = bFocus ? pParent : nullptr; + m_xMessageBox->runAsync(m_xMessageBox, [this, pGrabOnClose](sal_Int32 /*nResult*/) { + m_xMessageBox.reset(); + if (pGrabOnClose) + pGrabOnClose->grab_focus(); + }); +} + +void ScTabView::UpdatePageBreakData( bool bForcePaint ) +{ + std::unique_ptr<ScPageBreakData> pNewData; + + if (aViewData.IsPagebreakMode()) + { + ScDocShell* pDocSh = aViewData.GetDocShell(); + ScDocument& rDoc = pDocSh->GetDocument(); + SCTAB nTab = aViewData.GetTabNo(); + + sal_uInt16 nCount = rDoc.GetPrintRangeCount(nTab); + if (!nCount) + nCount = 1; + pNewData.reset( new ScPageBreakData(nCount) ); + + ScPrintFunc aPrintFunc( pDocSh, pDocSh->GetPrinter(), nTab, 0,0,nullptr, nullptr, pNewData.get() ); + // ScPrintFunc fills the PageBreakData in ctor + if ( nCount > 1 ) + { + aPrintFunc.ResetBreaks(nTab); + pNewData->AddPages(); + } + + // print area changed? + if ( bForcePaint || ( pPageBreakData && !( *pPageBreakData == *pNewData ) ) ) + PaintGrid(); + } + + pPageBreakData = std::move(pNewData); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |