/* -*- 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 .
*/
// The header row must be drawn also when the inner rectangle is not visible, // that is why there is no return value anymore. // When it is far away, then lcl_DrawOneFrame is not even called.
}
staticvoid lcl_DrawOneFrame( vcl::RenderContext* pDev, const tools::Rectangle& rInnerPixel, const OUString& rTitle, const Color& rColor, bool bTextBelow, double nPPTX, double nPPTY, const Fraction& rZoomY, const ScDocument& rDoc, ScViewData& rButtonViewData, bool bLayoutRTL )
{ // rButtonViewData is only used to set the button size,
// use ScPatternAttr::GetFont only for font size
vcl::Font aAttrFont;
rDoc.getCellAttributeHelper().getDefaultCellAttribute().fillFontOnly(aAttrFont, pDev, &rZoomY);
// everything else from application font
vcl::Font aAppFont = pDev->GetSettings().GetStyleSettings().GetAppFont();
aAppFont.SetFontSize( aAttrFont.GetFontSize() );
bool ScGridWindow::NeedLOKCursorInvalidation(const tools::Rectangle& rCursorRect, const Fraction aScaleX, const Fraction aScaleY)
{ // Don't see the need for a map as there will be only a few zoom levels // and as of now X and Y zooms in online are the same. for (auto& rEntry : maLOKLastCursor)
{ if (aScaleX == rEntry.aScaleX && aScaleY == rEntry.aScaleY)
{ if (rCursorRect == rEntry.aRect) returnfalse; // No change
void ScGridWindow::Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect )
{
ScDocument& rDoc = mrViewData.GetDocument(); if ( rDoc.IsInInterpreter() )
{ // Via Reschedule, interpreted cells do not trigger Invalidate again, // otherwise for instance an error box would never appear (bug 36381). // Later, through bNeedsRepaint everything is painted again. if ( bNeedsRepaint )
{ //! Merge Rectangle?
aRepaintPixel = tools::Rectangle(); // multiple -> paint all
} else
{
bNeedsRepaint = true;
aRepaintPixel = LogicToPixel(rRect); // only affected ranges
} return;
}
// #i117893# If GetSizePixel needs to call the resize handler, the resulting nested Paint call // (possibly for a larger rectangle) has to be allowed. Call GetSizePixel before setting bIsInPaint.
GetSizePixel();
// let's ignore the normal Draw() attempts when doing the tiled rendering, // all the rendering should go through PaintTile() in that case. // TODO revisit if we can actually turn this into an assert(), and clean // up the callers if (comphelper::LibreOfficeKit::isActive()) return;
if ( bTextWysiwyg )
{ // use printer for text formatting
OutputDevice* pFmtDev = rDoc.GetPrinter();
pFmtDev->SetMapMode( mrViewData.GetLogicMode(eWhich) );
aOutputData.SetFmtDevice( pFmtDev );
} elseif ( aZoomX != aZoomY && mrViewData.IsOle() )
{ // #i45033# For OLE inplace editing with different zoom factors, // use a virtual device with 1/100th mm as text formatting reference
// If something was inverted during the Paint (selection changed from Basic Macro) // then this is now mixed up and has to be repainted
OSL_ENSURE(nPaintCount, "Wrong nPaintCount");
--nPaintCount; if (!nPaintCount)
CheckNeedsRepaint();
// Flag drawn formula cells "unchanged".
rDoc.ResetChanged(ScRange(nX1, nY1, nTab, nX2, nY2, nTab));
rDoc.PrepareFormulaCalc();
}
namespace {
class SuppressEditViewMessagesGuard
{ public:
SuppressEditViewMessagesGuard(EditView& rEditView) :
mrEditView(rEditView),
mbOrigSuppressFlag(rEditView.IsSuppressLOKMessages())
{ if (!mbOrigSuppressFlag)
mrEditView.SuppressLOKMessages(true);
}
~SuppressEditViewMessagesGuard()
{ if (mrEditView.IsSuppressLOKMessages() != mbOrigSuppressFlag)
mrEditView.SuppressLOKMessages(mbOrigSuppressFlag);
}
/** * Used to store the necessary information about the (combined-)tile * area relevant to coordinate transformations in RTL mode.
*/ class ScLokRTLContext
{ public:
ScLokRTLContext(const ScOutputData& rOutputData, const tools::Long nTileDeviceOriginPixelX):
mrOutputData(rOutputData),
mnTileDevOriginX(nTileDeviceOriginPixelX)
{}
/** * Converts from document x pixel position to the * corresponding pixel position w.r.t the tile device origin.
*/
tools::Long docToTilePos(tools::Long nPosX) const
{
tools::Long nMirrorX = (-2 * mnTileDevOriginX) + mrOutputData.GetScrW(); return nMirrorX - 1 - nPosX;
}
const svtools::ColorConfig& rColorCfg = pScMod->GetColorConfig();
Color aGridColor( rColorCfg.GetColorValue( svtools::CALCGRID ).nColor ); if ( aGridColor == COL_TRANSPARENT )
{ // use view options' grid color only if color config has "automatic" color
aGridColor = rOpts.GetGridColor();
}
// define drawing layer map mode and paint rectangle
MapMode aDrawMode = GetDrawMapMode(); if (bIsTiledRendering)
{ // FIXME this shouldn't be necessary once we change the entire Calc to // work in the logic coordinates (ideally 100ths of mm - so that it is // the same as editeng and drawinglayer), and get rid of all the // SetMapMode's and other unnecessary fun we have with pixels // See also ScGridWindow::GetDrawMapMode() for the rest of this hack
aDrawMode.SetOrigin(PixelToLogic(Point(nScrX, nScrY), aDrawMode));
}
tools::Rectangle aDrawingRectLogic; bool bLayoutRTL = rDoc.IsLayoutRTL( nTab ); bool bLokRTL = bLayoutRTL && bIsTiledRendering;
std::unique_ptr<ScLokRTLContext> pLokRTLCtxt(
bLokRTL ? new ScLokRTLContext(aOutputData, o3tl::convert(aOriginalMode.GetOrigin().X(), o3tl::Length::twip, o3tl::Length::px)) :
nullptr);
{ // get drawing pixel rect
tools::Rectangle aDrawingRectPixel(
bLokRTL ? Point(-(nScrX + aOutputData.GetScrW()), nScrY) : Point(nScrX, nScrY),
Size(aOutputData.GetScrW(), aOutputData.GetScrH()));
// get logic positions
aDrawingRectLogic = PixelToLogic(aDrawingRectPixel, aDrawMode);
}
bool bInPlaceEditing = bEditMode && (mrViewData.GetRefTabNo() == mrViewData.GetTabNo());
vcl::Cursor* pInPlaceCrsr = nullptr; bool bInPlaceVisCursor = false; if (bInPlaceEditing)
{ // toggle the cursor off if it's on to ensure the cursor invert // background logic remains valid after the background is cleared on // the next cursor flash
pInPlaceCrsr = pEditView->GetCursor();
bInPlaceVisCursor = pInPlaceCrsr && pInPlaceCrsr->IsVisible(); if (bInPlaceVisCursor)
pInPlaceCrsr->Hide();
}
OutputDevice* pContentDev = &rDevice; // device for document content, used by overlay manager
SdrPaintWindow* pTargetPaintWindow = nullptr; // #i74769# work with SdrPaintWindow directly
if(pDrawView)
{ // #i74769# Use new BeginDrawLayers() interface
vcl::Region aDrawingRegion(aDrawingRectLogic);
pTargetPaintWindow = pDrawView->BeginDrawLayers(pContentDev, aDrawingRegion);
OSL_ENSURE(pTargetPaintWindow, "BeginDrawLayers: Got no SdrPaintWindow (!)");
if (!bIsTiledRendering)
{ // #i74769# get target device from SdrPaintWindow, this may be the prerender // device now, too.
pContentDev = &(pTargetPaintWindow->GetTargetOutputDevice());
aOutputData.SetContentDevice(pContentDev);
}
}
pContentDev->SetMapMode(aCurrentMapMode);
}
}
// app-background / document edge (area) (Pixel) if ( !bIsTiledRendering && ( nX2 == rDoc.MaxCol() || nY2 == rDoc.MaxRow() ) )
{ // save MapMode and set to pixel
MapMode aCurrentMapMode(pContentDev->GetMapMode());
pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
tools::Rectangle aPixRect( Point(), GetOutputSizePixel() );
pContentDev->SetFillColor( rColorCfg.GetColorValue(svtools::APPBACKGROUND).nColor );
pContentDev->SetLineColor(); if ( nX2==rDoc.MaxCol() )
{
tools::Rectangle aDrawRect( aPixRect ); if ( bLayoutRTL )
aDrawRect.SetRight( nScrX - 1 ); else
aDrawRect.SetLeft( nScrX + aOutputData.GetScrW() ); if (aDrawRect.Right() >= aDrawRect.Left())
pContentDev->DrawRect( aDrawRect );
} if ( nY2==rDoc.MaxRow() )
{
tools::Rectangle aDrawRect( aPixRect );
aDrawRect.SetTop( nScrY + aOutputData.GetScrH() ); if ( nX2==rDoc.MaxCol() )
{ // no double painting of the corner if ( bLayoutRTL )
aDrawRect.SetLeft( nScrX ); else
aDrawRect.SetRight( nScrX + aOutputData.GetScrW() - 1 );
} if (aDrawRect.Bottom() >= aDrawRect.Top())
pContentDev->DrawRect( aDrawRect );
}
if (bGridFirst && (bGrid || bPage))
{ // Draw lines in background color cover over lok client grid lines in merged cell areas if bNoBackgroundAndGrid is set. if (bNoBackgroundAndGrid)
aOutputData.DrawGrid(*pContentDev, false/* bGrid */, false /* bPage */, true /* bMergeCover */); else
aOutputData.DrawGrid(*pContentDev, bGrid, bPage);
}
//tdf#128258 - draw a dotted line before hidden columns/rows
DrawHiddenIndicator(nX1,nY1,nX2,nY2, *pContentDev);
if ( bPageMode )
{ // DrawPagePreview draws complete lines/page numbers, must always be clipped if ( aOutputData.SetChangedClip() )
{
DrawPagePreview(nX1,nY1,nX2,nY2, *pContentDev);
pContentDev->SetClipRegion();
}
}
// Show Note Mark if ( rOpts.GetOption( VOPT_NOTES ) )
aOutputData.DrawNoteMarks(*pContentDev);
if ( rOpts.GetOption( VOPT_FORMULAS_MARKS ) )
aOutputData.DrawFormulaMarks(*pContentDev);
if ( !bLogicText )
aOutputData.DrawStrings(); // in pixel MapMode
// edit cells and printer-metrics text must be before the buttons // (DataPilot buttons contain labels in UI font)
pContentDev->SetMapMode(mrViewData.GetLogicMode(eWhich)); if ( bLogicText )
aOutputData.DrawStrings(true); // in logic MapMode if bLogicText is set
aOutputData.DrawEdit(true);
// the buttons are painted in absolute coordinates if (bIsTiledRendering)
{ // Tiled offset nScrX, nScrY
MapMode aMap( MapUnit::MapPixel );
Point aOrigin(o3tl::convert(aOriginalMode.GetOrigin(), o3tl::Length::twip, o3tl::Length::px));
aOrigin.Move(nScrX, nScrY);
aMap.SetOrigin(aOrigin);
pContentDev->SetMapMode(aMap);
} else
pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
if(pDrawView)
{ // #i74769# work with SdrPaintWindow directly
pDrawView->EndDrawLayers(*pTargetPaintWindow, true);
}
pContentDev->SetMapMode(aCurrentMapMode);
}
}
// in place editing - lok case if (bIsTiledRendering)
{
ScTabViewShell* pThisViewShell = mrViewData.GetViewShell();
ViewShellList aCurrentDocViewList = LOKEditViewHistory::GetSortedViewsForDoc(pThisViewShell->GetDocId());
tools::Rectangle aTileRectPx(Point(nScrX, nScrY), Size(aOutputData.GetScrW(), aOutputData.GetScrH()));
for (SfxViewShell* pVS: aCurrentDocViewList)
{ auto pTabViewShell = dynamic_cast<ScTabViewShell*>(pVS); if (!pTabViewShell) continue;
if (!(bOtherEditMode
&& ( nCol2 >= nX1 && nCol1 <= nX2 && nRow2 >= nY1 && nRow1 <= nY2 )
&& rOtherViewData.GetRefTabNo() == nTab)) continue; // only views where in place editing is occurring need to be rendered
EditView* pOtherEditView = rOtherViewData.GetEditView(eOtherWhich); if (!pOtherEditView) continue;
// edit rectangle / background
Point aStart = mrViewData.GetScrPos( nCol1, nRow1, eOtherWhich );
Point aEnd = mrViewData.GetScrPos( nCol2+1, nRow2+1, eOtherWhich );
tools::Rectangle aEditRectPx(aStart, aEnd); if (bLokRTL)
{ // Transform the cell range X coordinates such that the edit cell area is // horizontally mirrored w.r.t the (combined-)tile.
aStart.setX(pLokRTLCtxt->docToTilePos(aStart.X()));
aEnd.setX(pLokRTLCtxt->docToTilePos(aEnd.X()));
}
tools::Rectangle aBackground(aStart, aEnd); if (bLokRTL)
aBackground.Normalize();
tools::Rectangle aBGAbs(aBackground);
// Need to draw the background in absolute coords.
Point aOriginTw = aOriginalMode.GetOrigin();
Point aOriginAbsTw = aOriginTw + o3tl::toTwips(aTileRectPx.GetPos(), o3tl::Length::px);
Point aOriginAbsPx = o3tl::convert(aOriginAbsTw, o3tl::Length::twip, o3tl::Length::px);
aBackground += aOriginAbsPx;
rDevice.SetMapMode(aDrawMode);
// keep into account the zoom factor
Point aNewOrigin(o3tl::convert(aOriginAbsTw, o3tl::Length::twip, o3tl::Length::mm100));
aNewOrigin = aNewOrigin.scale(
aDrawMode.GetScaleX().GetDenominator(), aDrawMode.GetScaleX().GetNumerator(),
aDrawMode.GetScaleY().GetDenominator(), aDrawMode.GetScaleY().GetNumerator());
// paint text const tools::Rectangle aOrigOutputArea(pOtherEditView->GetOutputArea()); // Not in pixels.
tools::Rectangle aNewOutputArea; // compute output area for view with a different zoom level wrt the view used for painting if (!(mrViewData.GetZoomX() == rOtherViewData.GetZoomX() &&
mrViewData.GetZoomY() == rOtherViewData.GetZoomY()))
{
Point aOtherStart = rOtherViewData.GetScrPos( nCol1, nRow1, eOtherWhich );
Point aOtherEnd = rOtherViewData.GetScrPos( nCol2+1, nRow2+1, eOtherWhich );
tools::Rectangle aOtherEditRect(
o3tl::convert(tools::Rectangle(aOtherStart, aOtherEnd), o3tl::Length::px,
aOrigOutputAreaUnit));
aNewOutputArea = tools::Rectangle(sides[0], sides[1], sides[2], sides[3]);
aNewOutputArea += aOriginAbsPx;
} // compute output area for RTL case if (bLokRTL)
{ if (aNewOutputArea.IsEmpty())
{ // same zoom level as view used for painting
aNewOutputArea = rDevice.LogicToPixel(aOrigOutputArea);
} // a small workaround for getting text position matching cursor position horizontally. const tools::Long nCursorGapPx = 2; // Transform the cell range X coordinates such that the edit cell area is // horizontally mirrored w.r.t the (combined-)tile.
aNewOutputArea = tools::Rectangle(
pLokRTLCtxt->docToTilePos(aNewOutputArea.Left() - aOriginAbsPx.X()) + aOriginAbsPx.X(),
aNewOutputArea.Top(),
pLokRTLCtxt->docToTilePos(aNewOutputArea.Right() - aOriginAbsPx.X()) + aOriginAbsPx.X() + nCursorGapPx,
aNewOutputArea.Bottom());
aNewOutputArea.Normalize();
}
if (aNewOutputArea.IsEmpty())
{ // same zoom level and not RTL: no need to change the output area before painting
pOtherEditView->Paint(rDevice.PixelToLogic(aTileRectPx), &rDevice);
} else
{ // EditView has an 'output area' which is used to clip the 'paint area' we provide below. // So they need to be in the same coordinates/units. This is tied to the mapmode of the gridwin // attached to the EditView, so we have to change its mapmode too (temporarily). We save the // original mapmode and 'output area' and roll them back when we finish painting to rDevice.
rOtherWin.SetMapMode(rDevice.GetMapMode());
// Avoid sending wrong cursor/selection messages by the 'other' view, as the output-area is going // to be tweaked temporarily to match the current view's zoom.
SuppressEditViewMessagesGuard aGuard(*pOtherEditView);
// EditView will do the cursor notifications correctly if we're in // print-twips messaging mode. if (pTabViewShell == pThisViewShell
&& !comphelper::LibreOfficeKit::isCompatFlagSet(
comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
{ // Now we need to get relative cursor position within the editview. // This is for sending the pixel-aligned twips position of the cursor to the specific views with // the same given zoom level.
tools::Rectangle aCursorRect = pEditView->GetEditCursor();
Point aCursPos = o3tl::toTwips(aCursorRect.TopLeft(), o3tl::Length::mm100);
aBGAbs.AdjustLeft(1);
aBGAbs.AdjustTop(1);
aCursorRect = GetOutDev()->PixelToLogic(aBGAbs, aMM);
aCursorRect.setWidth(0);
aCursorRect.Move(aCursPos.getX(), 0); // Sends view cursor position to views of all matching zooms if needed (avoids duplicates).
InvalidateLOKViewCursor(aCursorRect, aMM.GetScaleX(), aMM.GetScaleY());
}
// Rollback the mapmode and 'output area'.
rOtherWin.SetMapMode(aOrigMapMode);
pOtherEditView->SetOutputArea(aOrigOutputArea);
}
rDevice.SetMapMode(MapMode(MapUnit::MapPixel));
}
}
// In-place editing - when the user is typing, we need to paint the text // using the editeng. // It's being done after EndDrawLayers() to get it outside the overlay // buffer and on top of everything. if (bInPlaceEditing && !bIsTiledRendering && bInPlaceVisCursor)
pInPlaceCrsr->Show();
if (mrViewData.HasEditView(eWhich))
{ // set MapMode for text edit
rDevice.SetMapMode(mrViewData.GetLogicMode());
} else
rDevice.SetMapMode(aDrawMode);
if (bPage && bInitialPageBreaks)
SetupInitialPageBreaks(rDoc, nTab);
}
void ScGridWindow::SetupInitialPageBreaks(const ScDocument& rDoc, SCTAB nTab)
{ // tdf#124983, if option LibreOfficeDev Calc/View/Visual Aids/Page breaks // is enabled, breaks should be visible. If the document is opened the first // time, the breaks are not calculated yet, so for this initialization // a timer will be triggered here.
std::set<SCCOL> aColBreaks;
std::set<SCROW> aRowBreaks;
rDoc.GetAllColBreaks(aColBreaks, nTab, true, false);
rDoc.GetAllRowBreaks(aRowBreaks, nTab, true, false); if (aColBreaks.empty() || aRowBreaks.empty())
{
maShowPageBreaksTimer.SetPriority(TaskPriority::DEFAULT_IDLE);
maShowPageBreaksTimer.Start();
}
bInitialPageBreaks = false;
}
void ScGridWindow::resetCachedViewGridOffsets() const
{ if (mpLOKDrawView) if (SdrPageView* pPageView = mpLOKDrawView->GetSdrPageView())
pPageView->resetGridOffsetsOfAllPageWindows();
}
void ScGridWindow::PaintTile( VirtualDevice& rDevice, int nOutputWidth, int nOutputHeight, int nTilePosX, int nTilePosY,
tools::Long nTileWidth, tools::Long nTileHeight,
SCCOL nTiledRenderingAreaEndCol, SCROW nTiledRenderingAreaEndRow )
{
Fraction origZoomX = mrViewData.GetZoomX();
Fraction origZoomY = mrViewData.GetZoomY();
// Output size is in pixels while tile position and size are in logical units (twips).
// Assumption: always paint the whole sheet i.e. "visible" range is always // from (0,0) to last data position.
// Tile geometry is independent of the zoom level, but the output size is // dependent of the zoom level. Determine the correct zoom level before // we start.
// FIXME the painting works using a mixture of drawing with coordinates in // pixels and in logic coordinates; it should be cleaned up to use logic // coords only, and avoid all the SetMapMode()'s. // Similarly to Writer, we should set the mapmode once on the rDevice, and // not care about any zoom settings.
// page break zoom, and aLogicMode in ScViewData // FIXME: there are issues when SetZoom is called conditionally.
mrViewData.SetZoom(aFracX, aFracY, true); if (bChangeZoom)
{ if (ScDrawView* pDrawView = mrViewData.GetScDrawView())
pDrawView->resetGridOffsetsForAllSdrPageViews();
}
// Checkout -> 'rDoc.ExtendMerge' ... if we miss merged cells.
// Origin must be the offset of the first col and row // containing our top-left pixel. const MapMode aOriginalMode = rDevice.GetMapMode();
MapMode aAbsMode = aOriginalMode; const Point aOrigin(-nTopLeftTileColOrigin, -nTopLeftTileRowOrigin);
aAbsMode.SetOrigin(aOrigin);
rDevice.SetMapMode(aAbsMode);
// setup the SdrPage so that drawinglayer works correctly
ScDrawLayer* pModel = rDoc.GetDrawLayer(); if (pModel)
{ bool bPrintTwipsMsgs = comphelper::LibreOfficeKit::isCompatFlagSet(
comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs); if (!mpLOKDrawView)
{
mpLOKDrawView.reset(bPrintTwipsMsgs ? new ScLOKDrawView(
&rDevice,
mrViewData) : new FmFormView(
*pModel,
&rDevice));
}
void ScGridWindow::LogicInvalidatePart(const tools::Rectangle* pRectangle, int nPart)
{
tools::Rectangle aRectangle;
tools::Rectangle* pResultRectangle; if (!pRectangle)
pResultRectangle = nullptr; else
{
aRectangle = *pRectangle; // When dragging shapes the map mode is disabled. if (IsMapModeEnabled())
{ if (GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
{
aRectangle = o3tl::convert(aRectangle, o3tl::Length::mm100, o3tl::Length::twip);
}
} else
aRectangle = PixelToLogic(aRectangle, MapMode(MapUnit::MapTwip));
pResultRectangle = &aRectangle;
}
// Trim invalidation rectangle overlapping negative X region in RTL mode. if (pResultRectangle && pResultRectangle->Left() < 0
&& mrViewData.GetDocument().IsLayoutRTL(mrViewData.GetTabNo()))
{
pResultRectangle->SetLeft(0); if (pResultRectangle->Right() < 0)
pResultRectangle->SetRight(0);
}
void ScGridWindow::SetCellSelectionPixel(int nType, int nPixelX, int nPixelY)
{
ScTabView* pTabView = mrViewData.GetView();
ScTabViewShell* pViewShell = mrViewData.GetViewShell();
ScInputHandler* pInputHandler = ScModule::get()->GetInputHdl(pViewShell);
if (pInputHandler && pInputHandler->IsInputMode())
{ // we need to switch off the editeng
ScTabView::UpdateInputLine();
pViewShell->UpdateInputHandler();
}
if (nType == LOK_SETTEXTSELECTION_RESET)
{
pTabView->DoneBlockMode(); return;
}
// obtain the current selection
ScRangeList aRangeList = mrViewData.GetMarkData().GetMarkedRanges();
// selection function in status bar might also be invalid
SfxBindings& rBindings = mrViewData.GetBindings();
rBindings.Invalidate( SID_STATUS_SUM );
rBindings.Invalidate( SID_ATTR_SIZE );
rBindings.Invalidate( SID_TABLE_CELL );
}
void ScGridWindow::DrawHiddenIndicator( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, vcl::RenderContext& rRenderContext)
{
ScDocument& rDoc = mrViewData.GetDocument();
SCTAB nTab = mrViewData.GetTabNo(); const svtools::ColorConfig& rColorCfg = ScModule::get()->GetColorConfig(); const svtools::ColorConfigValue aColorValue = rColorCfg.GetColorValue(svtools::CALCHIDDENROWCOL); if (aColorValue.bIsVisible) {
rRenderContext.SetLineColor(aColorValue.nColor);
LineInfo aLineInfo(LineStyle::Dash, 2);
aLineInfo.SetDashCount(0);
aLineInfo.SetDotCount(1);
aLineInfo.SetDistance(15); // round caps except when running VCL_PLUGIN=gen due to a performance issue // https://bugs.documentfoundation.org/show_bug.cgi?id=128258#c14 if (mrViewData.GetActiveWin()->GetSystemData()->toolkit != SystemEnvData::Toolkit::Gen)
aLineInfo.SetLineCap(css::drawing::LineCap_ROUND);
aLineInfo.SetDotLen(1); for (int i=nX1; i<nX2; i++) { if (rDoc.ColHidden(i,nTab) && (i<rDoc.MaxCol() ? !rDoc.ColHidden(i+1,nTab) : true)) {
Point aStart = mrViewData.GetScrPos(i, nY1, eWhich, true );
Point aEnd = mrViewData.GetScrPos(i, nY2, eWhich, true );
rRenderContext.DrawLine(aStart,aEnd,aLineInfo);
}
} for (int i=nY1; i<nY2; i++) { if (rDoc.RowHidden(i,nTab) && (i<rDoc.MaxRow() ? !rDoc.RowHidden(i+1,nTab) : true)) {
Point aStart = mrViewData.GetScrPos(nX1, i, eWhich, true );
Point aEnd = mrViewData.GetScrPos(nX2, i, eWhich, true );
rRenderContext.DrawLine(aStart,aEnd,aLineInfo);
}
}
} //visible
}
Point aOldPos = aComboButton.GetPosPixel(); // store state for MouseDown/Up
Size aOldSize = aComboButton.GetSizePixel();
for (nArrY=1; nArrY+1<nArrCount; nArrY++)
{ if ( pRowInfo[nArrY].bAutoFilter && pRowInfo[nArrY].bChanged )
{
RowInfo* pThisRowInfo = &pRowInfo[nArrY];
nRow = pThisRowInfo->nRowNo;
for (nCol=nX1; nCol<=nX2; nCol++)
{
ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nCol); //if several columns merged on a row, there should be only one auto button at the end of the columns. //if several rows merged on a column, the button may be in the middle, so "!pInfo->bVOverlapped" should not be used if ( pInfo->bAutoFilter && !pInfo->bHOverlapped )
{ if (!pQueryParam)
pQueryParam.reset(new ScQueryParam);
bool bNewData = true; if (pDBData)
{
SCCOL nStartCol;
SCROW nStartRow;
SCCOL nEndCol;
SCROW nEndRow;
SCTAB nAreaTab;
pDBData->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow ); if ( nCol >= nStartCol && nCol <= nEndCol &&
nRow >= nStartRow && nRow <= nEndRow )
bNewData = false;
} if (bNewData)
{
pDBData = rDoc.GetDBAtCursor( nCol, nRow, nTab, ScDBDataPortion::AREA ); if (pDBData)
pDBData->GetQueryParam( *pQueryParam ); else
{ // can also be part of DataPilot table
}
}
// pQueryParam can only include MAXQUERY entries
bool bArrowState = false; if (pQueryParam->bInplace)
{
SCSIZE nCount = pQueryParam->GetEntryCount(); for (nQuery = 0; nQuery < nCount; ++nQuery)
{ // Do no restrict to EQUAL here // (Column head should become blue also when ">1") const ScQueryEntry& rEntry = pQueryParam->GetEntry(nQuery); if (rEntry.bDoQuery && rEntry.nField == nCol)
{
bArrowState = true; break;
}
}
}
tools::Long nSizeX;
tools::Long nSizeY;
SCCOL nStartCol= nCol;
SCROW nStartRow = nRow; //if address(nCol,nRow) is not the start pos of the merge area, the value of the nSizeX will be incorrect, it will be the length of the cell. //should first get the start pos of the merge area, then get the nSizeX through the start pos.
rDoc.ExtendOverlapped(nStartCol, nStartRow,nCol, nRow, nTab);//get nStartCol,nStartRow
mrViewData.GetMergeSizePixel( nStartCol, nStartRow, nSizeX, nSizeY );//get nSizeX
nSizeY = ScViewData::ToPixel(rDoc.GetRowHeight(nRow, nTab), mrViewData.GetPPTY());
Point aScrPos = mrViewData.GetScrPos( nCol, nRow, eWhich ); if (pLokRTLContext)
aScrPos.setX(pLokRTLContext->docToTilePos(aScrPos.X()));
aCellBtn.setBoundingBox(aScrPos, Size(nSizeX-1, nSizeY-1), bLayoutRTL);
aCellBtn.setPopupLeft(bLayoutRTL); // #i114944# AutoFilter button is left-aligned in RTL
aCellBtn.setDrawBaseButton(false);
aCellBtn.setDrawPopupButton(true);
aCellBtn.setHasHiddenMember(bArrowState);
aCellBtn.draw();
}
}
}
if ( (pRowInfo[nArrY].bPivotToggle || pRowInfo[nArrY].bPivotButton) && pRowInfo[nArrY].bChanged )
{
RowInfo* pThisRowInfo = &pRowInfo[nArrY];
nRow = pThisRowInfo->nRowNo; for (nCol=nX1; nCol<=nX2; nCol++)
{
ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nCol); if (pInfo->bHOverlapped || pInfo->bVOverlapped) continue;
tools::Long nCellSizeX; // width of this cell, including merged
tools::Long nDummy;
mrViewData.GetMergeSizePixel( nCol, nRow, nCellSizeX, nDummy );
// for height, only the cell's row is used, excluding merged cells
tools::Long nCellSizeY = ScViewData::ToPixel( rDoc.GetRowHeight( nRow, nTab ), mrViewData.GetPPTY() );
tools::Long nAvailable = nCellSizeX;
// left edge of next cell if there is a non-hidden next column
SCCOL nNextCol = nCol + 1; const ScMergeAttr* pMerge = rDoc.GetAttr( nCol,nRow,nTab, ATTR_MERGE ); if ( pMerge->GetColMerge() > 1 )
nNextCol = nCol + pMerge->GetColMerge(); // next cell after the merged area while ( nNextCol <= rDoc.MaxCol() && rDoc.ColHidden(nNextCol, nTab) )
++nNextCol; bool bNextCell = ( nNextCol <= rDoc.MaxCol() ); if ( bNextCell )
nAvailable = ScViewData::ToPixel( rDoc.GetColWidth( nNextCol, nTab ), mrViewData.GetPPTX() );
if ( nAvailable < aBtnSize.Width() )
aBtnSize.setWidth( nAvailable ); if ( nCellSizeY < aBtnSize.Height() )
aBtnSize.setHeight( nCellSizeY );
Point aPos = mrViewData.GetScrPos( nCol, nRow, eWhich, true );
aPos.AdjustX(nCellSizeX * nLayoutSign ); // start of next cell if (!bNextCell)
aPos.AdjustX( -(aBtnSize.Width() * nLayoutSign) ); // right edge of cell if next cell not available
aPos.AdjustY(nCellSizeY - aBtnSize.Height() ); // X remains at the left edge
if ( bLayoutRTL )
aPos.AdjustX( -(aBtnSize.Width()-1) ); // align right edge of button with cell border
SCCOL nPosX = mrViewData.GetPosX( eHWhich );
SCROW nPosY = mrViewData.GetPosY( eVWhich ); // is the selection visible at all? if (nTestX2 < nPosX || nTestY2 < nPosY) return;
SCCOL nRealX1 = nX1; if (nX1 < nPosX)
nX1 = nPosX; if (nY1 < nPosY)
nY1 = nPosY;
if (!comphelper::LibreOfficeKit::isActive())
{ // limit the selection to only what is visible on the screen
SCCOL nXRight = nPosX + mrViewData.VisibleCellsX(eHWhich); if (nXRight > rDoc.MaxCol())
nXRight = rDoc.MaxCol();
if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
(rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
{ if ( eWhich == mrViewData.GetActivePart() ) // only once for the view
{
ScTabView* pView = mrViewData.GetView();
pView->RecalcPPT();
// RepeatResize in case scroll bar sizes have changed
pView->RepeatResize();
pView->UpdateAllOverlays();
// invalidate cell attribs in input handler, in case the // EditEngine BackgroundColor has to be changed if ( mrViewData.IsActive() )
{
ScInputHandler* pHdl = ScModule::get()->GetInputHdl(); if (pHdl)
pHdl->ForgetLastPattern();
}
}
}
const ScViewOptions& rOpts = mrViewData.GetOptions(); constbool bPage = rOpts.GetOption(VOPT_PAGEBREAKS); // tdf#124983, if option LibreOfficeDev Calc/View/Visual Aids/Page // breaks is enabled, breaks should be visible. If the document is // opened the first time or a tab is activated the first time, the // breaks are not calculated yet, so this initialization is done here. if (bPage)
{ const SCTAB nCurrentTab = mrViewData.GetTabNo();
ScDocument& rDoc = mrViewData.GetDocument(); const Size aPageSize = rDoc.GetPageSize(nCurrentTab); // Do not attempt to calculate a page size here if it is empty if // that involves counting pages. // An earlier implementation did // ScPrintFunc(pDocSh, rDocSh.GetPrinter(), nCurrentTab); // rDoc.SetPageSize(nCurrentTab, rDoc.GetPageSize(nCurrentTab)); // which resulted in tremendous waiting times after having loaded // larger documents i.e. imported from CSV, in which UI is entirely // blocked. All time is spent under ScPrintFunc::CountPages() in // ScTable::ExtendPrintArea() in the loop that calls // MaybeAddExtraColumn() to do stuff for each text string content // cell (each row in each column). Maybe that can be optimized, or // obtaining page size without that overhead would be possible, but // as is calling that from here is a no-no so this is a quick // disable things. if (!aPageSize.IsEmpty())
{
ScDocShell& rDocSh = mrViewData.GetDocShell(); constbool bModified = rDocSh.IsModified(); // Even setting the same size sets page size valid, so // UpdatePageBreaks() actually does something.
rDoc.SetPageSize( nCurrentTab, aPageSize);
rDoc.UpdatePageBreaks(nCurrentTab);
rDocSh.PostPaint(0, 0, nCurrentTab, rDoc.MaxCol(), rDoc.MaxRow(), nCurrentTab, PaintPartFlags::Grid);
rDocSh.SetModified(bModified);
}
}
}
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.