/* -*- 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 .
*/
ScExtraEditViewManager::~ScExtraEditViewManager()
{
DBG_ASSERT(nTotalWindows == 0, "ScExtraEditViewManager dtor: some out window has not yet been removed!");
}
mpOtherEditView = pOtherViewShell->GetViewData().GetEditView(eWhich); if (mpOtherEditView != nullptr)
{ for (int i = 0; i < 4; ++i)
{
ScGridWindow* pWin = mpGridWin[i].get(); if (pWin != nullptr)
{
Modifier<ModifierTag>(pWin);
}
}
}
}
template<ScExtraEditViewManager::ModifierTagType ModifierTag> void ScExtraEditViewManager::Modifier(ScGridWindow* /*pWin*/)
{
(void)this;
SAL_WARN("sc", "ScExtraEditViewManager::Modifier: non-specialized version should not be invoked.");
}
template<> void ScExtraEditViewManager::Modifier<ScExtraEditViewManager::Adder>(ScGridWindow* pWin)
{ if (mpOtherEditView->AddOtherViewWindow(pWin))
++nTotalWindows;
}
template<> void ScExtraEditViewManager::Modifier<ScExtraEditViewManager::Remover>(ScGridWindow* pWin)
{ if (mpOtherEditView->RemoveOtherViewWindow(pWin))
--nTotalWindows;
}
for (sal_uInt16 i = 0; i < 4; i++)
{ if (pGridWin[i] && pGridWin[i]->IsVisible())
pGridWin[i]->UpdateAutoFillMark( bMarked, aMarkRange );
}
for (sal_uInt16 i = 0; i < 2; i++)
{ if (pColBar[i] && pColBar[i]->IsVisible())
pColBar[i]->SetMark( bMarked, aMarkRange.aStart.Col(), aMarkRange.aEnd.Col() ); if (pRowBar[i] && pRowBar[i]->IsVisible())
pRowBar[i]->SetMark( bMarked, aMarkRange.aStart.Row(), aMarkRange.aEnd.Row() );
}
// selection transfer object is checked together with AutoFill marks, // because it has the same requirement of a single continuous block. if (!bFromPaste)
CheckSelectionTransfer(); // update selection transfer object
}
void ScTabView::FakeButtonUp( ScSplitPos eWhich )
{ if (pGridWin[eWhich])
pGridWin[eWhich]->FakeButtonUp();
}
void ScTabView::HideAllCursors()
{ for (VclPtr<ScGridWindow> & pWin : pGridWin)
{ if (pWin && pWin->IsVisible())
{
vcl::Cursor* pCur = pWin->GetCursor(); if (pCur && pCur->IsVisible())
pCur->Hide();
pWin->HideCursor();
}
}
}
void ScTabView::ShowAllCursors()
{ for (VclPtr<ScGridWindow> & pWin : pGridWin)
{ if (pWin && pWin->IsVisible())
{
pWin->ShowCursor();
pWin->CursorChanged();
}
}
}
// FIXME: this is to limit the number of rows handled in the Online // to 1000; this will be removed again when the performance // bottlenecks are sorted out if (comphelper::LibreOfficeKit::isActive())
nPosY = std::min(nPosY, MAXTILEDROW);
Size aNewSize(0, 0); if (pModelObj)
aNewSize = pModelObj->getDocumentSize();
if (pModelObj)
{
ScGridWindow* pGridWindow = aViewData.GetActiveWin(); if (pGridWindow)
{
Size aNewSizePx(aNewSize.Width() * aViewData.GetPPTX(), aNewSize.Height() * aViewData.GetPPTY()); if (aNewSizePx != pGridWindow->GetOutputSizePixel())
pGridWindow->SetOutputSizePixel(aNewSizePx);
}
}
if (aOldSize == aNewSize) return;
// New area extended to the right of the sheet after last column // including overlapping area with aNewRowArea
tools::Rectangle aNewColArea(aOldSize.getWidth(), 0, aNewSize.getWidth(), aNewSize.getHeight()); // New area extended to the bottom of the sheet after last row // excluding overlapping area with aNewColArea
tools::Rectangle aNewRowArea(0, aOldSize.getHeight(), aOldSize.getWidth(), aNewSize.getHeight());
// Only invalidate if spreadsheet extended to the right if (aNewColArea.getOpenWidth())
{
SfxLokHelper::notifyInvalidation(aViewData.GetViewShell(), &aNewColArea);
}
// Only invalidate if spreadsheet extended to the bottom if (aNewRowArea.getOpenHeight())
{
SfxLokHelper::notifyInvalidation(aViewData.GetViewShell(), &aNewRowArea);
}
// Provide size in the payload, so clients don't have to // call lok::Document::getDocumentSize().
std::stringstream ss;
ss << aNewSize.Width() << ", " << aNewSize.Height();
OString sSize( ss.str() );
ScModelObj* pModel = comphelper::getFromUnoTunnel<ScModelObj>(aViewData.GetViewShell()->GetCurrentDocument());
SfxLokHelper::notifyDocumentSizeChanged(aViewData.GetViewShell(), sSize, pModel, false);
}
void ScTabView::CheckSelectionTransfer()
{ if ( !aViewData.IsActive() ) // only for active view return;
ScModule* pScMod = ScModule::get();
ScSelectionTransferObj* pOld = pScMod->GetSelectionTransfer();
rtl::Reference<ScSelectionTransferObj> pNew = ScSelectionTransferObj::CreateFromView( this ); if ( !pNew ) return;
// create new selection
if (pOld)
pOld->ForgetView();
pScMod->SetSelectionTransfer( pNew.get() );
// tdf#124975/tdf#136242 changing the calc selection can trigger removal of the // selection of an open RefDlg dialog, so don't inform the // desktop clipboard of the changed selection if that dialog is open if (!lcl_IsRefDlgActive(aViewData.GetViewShell()->GetViewFrame()))
pNew->CopyToPrimarySelection(); // may delete pOld
// First, see if we can fit the entire hint window in the visible region.
if (nMRight - nMargin >= rHintWndSize.Width())
{ // Right margin is wide enough. if (rFrameWndSize.Height() >= rHintWndSize.Height())
{ // The frame has enough height. Take it.
Point aPos = rCellPos;
aPos.AdjustX(rCellSize.Width() + nMargin ); if (aPos.Y() + rHintWndSize.Height() > rFrameWndSize.Height())
{ // Push the hint window up a bit to make it fit.
aPos.setY( rFrameWndSize.Height() - rHintWndSize.Height() );
} return aPos;
}
}
if (nMBottom - nMargin >= rHintWndSize.Height())
{ // Bottom margin is high enough. if (rFrameWndSize.Width() >= rHintWndSize.Width())
{ // The frame has enough width. Take it.
Point aPos = rCellPos;
aPos.AdjustY(rCellSize.Height() + nMargin ); if (aPos.X() + rHintWndSize.Width() > rFrameWndSize.Width())
{ // Move the hint window to the left to make it fit.
aPos.setX( rFrameWndSize.Width() - rHintWndSize.Width() );
} return aPos;
}
}
if (nMLeft - nMargin >= rHintWndSize.Width())
{ // Left margin is wide enough. if (rFrameWndSize.Height() >= rHintWndSize.Height())
{ // The frame is high enough. Take it.
Point aPos = rCellPos;
aPos.AdjustX( -(rHintWndSize.Width() + nMargin) ); if (aPos.Y() + rHintWndSize.Height() > rFrameWndSize.Height())
{ // Push the hint window up a bit to make it fit.
aPos.setY( rFrameWndSize.Height() - rHintWndSize.Height() );
} return aPos;
}
}
if (nMTop - nMargin >= rHintWndSize.Height())
{ // Top margin is high enough. if (rFrameWndSize.Width() >= rHintWndSize.Width())
{ // The frame is wide enough. Take it.
Point aPos = rCellPos;
aPos.AdjustY( -(rHintWndSize.Height() + nMargin) ); if (aPos.X() + rHintWndSize.Width() > rFrameWndSize.Width())
{ // Move the hint window to the left to make it fit.
aPos.setX( rFrameWndSize.Width() - rHintWndSize.Width() );
} return aPos;
}
}
// The popup doesn't fit in any direction in its entirety. Do our best.
if (nMRight - nMargin >= rHintWndSize.Width())
{ // Right margin is good enough.
Point aPos = rCellPos;
aPos.AdjustX(nMargin + rCellSize.Width() );
aPos.setY( 0 ); return aPos;
}
if (nMBottom - nMargin >= rHintWndSize.Height())
{ // Bottom margin is good enough.
Point aPos = rCellPos;
aPos.AdjustY(nMargin + rCellSize.Height() );
aPos.setX( 0 ); return aPos;
}
if (nMLeft - nMargin >= rHintWndSize.Width())
{ // Left margin is good enough.
Point aPos = rCellPos;
aPos.AdjustX( -(rHintWndSize.Width() + nMargin) );
aPos.setY( 0 ); return aPos;
}
if (nMTop - nMargin >= rHintWndSize.Height())
{ // Top margin is good enough.
Point aPos = rCellPos;
aPos.AdjustY( -(rHintWndSize.Height() + nMargin) );
aPos.setX( 0 ); return aPos;
}
// None of the above. Hopeless. At least try not to cover the current // cell.
Point aPos = rCellPos;
aPos.AdjustX(rCellSize.Width() ); return aPos;
}
}
void ScTabView::TestHintWindow()
{ // show input help window and list drop-down button for validity
Point aHintPos = calcHintWindowPosition(
aPos, Size(nCellSizeX,nCellSizeY), aWinSize, aHintWndSize);
pOverlay->SetPos(pWin->PixelToLogic(aHintPos, pWin->GetDrawMapMode()), pWin->GetDrawMapMode()); for (VclPtr<ScGridWindow> & pWindow : pGridWin)
{ if (!pWindow) continue; if (!pWindow->IsVisible()) continue;
rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = pWindow->getOverlayManager(); if (!xOverlayManager.is()) continue; if (pWindow == pWin)
{
xOverlayManager->add(*pOverlay);
pWindow->updateLOKInputHelp(aTitle, aMessage);
} else
{ //tdf#92530 if the help tip doesn't fit into its allocated area in a split window //scenario, then because here we place it into the other split windows as well the //missing portions will be displayed in the other split windows to form an apparent //single tip, albeit "under" the split lines
Point aOtherPos(pWindow->ScreenToOutputPixel(pWin->OutputToScreenPixel(aHintPos)));
std::unique_ptr<ScOverlayHint> pOtherOverlay(new ScOverlayHint(aTitle, aMessage,
aCommentBack,
aCommentText,
pFrameWin->GetFont()));
Point aFooPos(pWindow->PixelToLogic(aOtherPos, pWindow->GetDrawMapMode()));
pOtherOverlay->SetPos(aFooPos, pWindow->GetDrawMapMode());
xOverlayManager->add(*pOtherOverlay);
mxInputHintOO->append(std::move(pOtherOverlay));
}
}
}
}
// find window that should not be over the cursor static weld::Window* lcl_GetCareWin(SfxViewFrame& rViewFrm)
{ //! also spelling ??? (then set the member variables when calling)
// search & replace if (rViewFrm.HasChildWindow(SID_SEARCH_DLG))
{
SfxChildWindow* pChild = rViewFrm.GetChildWindow(SID_SEARCH_DLG); if (pChild)
{ auto xDlgController = pChild->GetController(); if (xDlgController && xDlgController->getDialog()->get_visible()) return xDlgController->getDialog();
}
}
// apply changes if ( rViewFrm.HasChildWindow(FID_CHG_ACCEPT) )
{
SfxChildWindow* pChild = rViewFrm.GetChildWindow(FID_CHG_ACCEPT); if (pChild)
{ auto xDlgController = pChild->GetController(); if (xDlgController && xDlgController->getDialog()->get_visible()) return xDlgController->getDialog();
}
}
return nullptr;
}
// adjust screen with respect to cursor position
void ScTabView::AlignToCursor( SCCOL nCurX, SCROW nCurY, ScFollowMode eMode, const ScSplitPos* pWhich )
{ // now switch active part here
tools::Long nDenom; if ( eMode == SC_FOLLOW_JUMP_END && nCurX > aViewData.GetRefStartX()
&& nCurY > aViewData.GetRefStartY() )
nDenom = 1; // tdf#154271 Selected cell will be at the bottom corner // to maximize the visible/usable area else
nDenom = 2; // Selected cell will be at the center of the screen, so that // it will be visible. This is useful for search results, etc.
tools::Long nSpaceX = ( aScrSize.Width() - nCellSizeX ) / nDenom;
tools::Long nSpaceY = ( aScrSize.Height() - nCellSizeY ) / nDenom; // nSpaceY: desired start position of cell for FOLLOW_JUMP, modified if dialog interferes
bool bForceNew = false; // force new calculation of JUMP position (vertical only)
// when for instance a search dialog is open, don't put the cursor behind the dialog // if possible, put the row with the cursor above or below the dialog //! not if already completely visible
if ( eMode == SC_FOLLOW_JUMP || eMode == SC_FOLLOW_JUMP_END )
{
weld::Window* pCare = lcl_GetCareWin( aViewData.GetViewShell()->GetViewFrame() ); if (pCare)
{ bool bLimit = false;
tools::Rectangle aDlgPixel;
Size aWinSize;
vcl::Window* pWin = GetActiveWin();
weld::Window* pFrame = pWin ? pWin->GetFrameWeld() : nullptr; int x, y, width, height; if (pFrame && pCare->get_extents_relative_to(*pFrame, x, y, width, height))
{
aDlgPixel = tools::Rectangle(Point(x, y), Size(width, height));
aWinSize = pWin->GetOutputSizePixel(); // dos the dialog cover the GridWin? if ( aDlgPixel.Right() >= 0 && aDlgPixel.Left() < aWinSize.Width() )
{ if ( nCurX < nDeltaX || nCurX >= nDeltaX+nSizeX ||
nCurY < nDeltaY || nCurY >= nDeltaY+nSizeY )
bLimit = true; // scroll anyway else
{ // cursor is on the screen
Point aStart = aViewData.GetScrPos( nCurX, nCurY, eAlign );
tools::Long nCSX, nCSY;
aViewData.GetMergeSizePixel( nCurX, nCurY, nCSX, nCSY );
tools::Rectangle aCursor( aStart, Size( nCSX, nCSY ) ); if ( aCursor.Overlaps( aDlgPixel ) )
bLimit = true; // cell is covered by the dialog
}
}
}
if (nCurX < 0) nCurX = 0; if (nCurY < 0) nCurY = 0; if (nCurX > rDoc.MaxCol()) nCurX = rDoc.MaxCol(); if (nCurY > rDoc.MaxRow()) nCurY = rDoc.MaxRow();
// FIXME: this is to limit the number of rows handled in the Online // to 1000; this will be removed again when the performance // bottlenecks are sorted out if (comphelper::LibreOfficeKit::isActive())
nCurY = std::min(nCurY, MAXTILEDROW);
HideAllCursors();
// switch of active now in AlignToCursor
AlignToCursor( nCurX, nCurY, eMode );
if (bKeepSel)
{
SetCursor( nCurX, nCurY ); // keep selection
// If the cursor is in existing selection, it's a cursor movement by // ENTER or TAB. If not, then it's a new selection during ADD // selection mode.
const ScMarkData& rMark = aViewData.GetMarkData();
ScRangeList aSelList;
rMark.FillRangeListWithMarks(&aSelList, false); if (!aSelList.Contains(ScRange(nCurX, nCurY, aViewData.GetTabNo()))) // Cursor not in existing selection. Start a new selection.
DoneBlockMode(true);
} else
{ if (!bShift)
{ // Remove all marked data on cursor movement unless the Shift is // locked or while editing a formula. It is cheaper to check for // marks first and then formula mode.
ScMarkData& rMark = aViewData.GetMarkData(); bool bMarked = rMark.IsMarked() || rMark.IsMultiMarked(); if (bMarked && !ScModule::get()->IsFormulaMode())
{
rMark.ResetMark();
DoneBlockMode();
InitOwnBlockMode( ScRange( nCurX, nCurY, aViewData.GetTabNo()));
MarkDataChanged();
}
}
// If the cursor has not been moved, the SelectionChanged for canceling the // selection has to happen here individually: if (bSame)
SelectionChanged();
}
if (nMovX < 0 && nOldX == 0)
{ // trying to go left from 1st column if (nMovY == 0) // done, because no vertical move is requested return;
} if (nMovY < 0 && nOldY == 0)
{ // trying to go up from 1st row if (nMovX == 0) // done, because no horizontal move is requested return;
}
aViewData.ResetOldCursor();
if (nMovX != 0 && rDoc.ValidColRow(nCurX,nCurY))
SkipCursorHorizontal(nCurX, nCurY, nOldX, nMovX);
if (nMovY != 0 && rDoc.ValidColRow(nCurX,nCurY))
SkipCursorVertical(nCurX, nCurY, nOldY, nMovY);
// update input line even if cursor was not moved if ( nNewX == nCurX && nNewY == nCurY )
aViewData.UpdateInputHandler(true);
} else
{ // After Tab and Enter back to the starting column again. const SCCOL nTabStartCol = ((nMoveY != 0 && !nMoveX) ? aViewData.GetTabStartCol() : SC_TABSTART_NONE);
rDoc.GetNextPos( nNewX, nNewY, nTab, nMoveX, nMoveY, false, true, rMark, nTabStartCol );
if (!bNew && nTab == aViewData.GetTabNo()) return;
// FormShell would like to be informed before the switch
FmFormShell* pFormSh = aViewData.GetViewShell()->GetFormShell(); if (pFormSh)
{ bool bAllowed = pFormSh->PrepareClose(); if (!bAllowed)
{ //! error message? or does FormShell do it? //! return error flag and cancel actions
return; // FormShell says that it can not be switched
}
}
// not InputEnterHandler due to reference input
ScDocument& rDoc = aViewData.GetDocument();
rDoc.MakeTable( nTab );
// Update pending row heights before switching the sheet, so Reschedule from the progress bar // doesn't paint the new sheet with old heights
aViewData.GetDocShell().UpdatePendingRowHeights( nTab );
SCTAB nTabCount = rDoc.GetTableCount();
SCTAB nOldPos = nTab; while (!rDoc.IsVisible(nTab)) // search for next visible
{ bool bUp = (nTab>=nOldPos); if (bUp)
{
++nTab; if (nTab>=nTabCount)
{
nTab = nOldPos;
bUp = false;
}
}
if (!bUp)
{ if (nTab != 0)
--nTab; else
--> --------------------
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.