/* -*- 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 .
*/
//tdf#133971 hold self-ref until we return auto xThis(shared_from_this());
pGridWin->FilterSelect(nSel); if (xThis.use_count() == 1)
{ // tdf#133855 we got disposed by FilterSelect return;
}
pGridWin->ClickExtern();
}
staticbool lcl_IsEditableMatrix( ScDocument& rDoc, const ScRange& rRange )
{ // If it is an editable range and if there is a Matrix cell at the bottom right with an // origin top left then the range will be set to contain the exact matrix. //! Extract the MatrixEdges functions directly from the column ??? if ( !rDoc.IsBlockEditable( rRange.aStart.Tab(), rRange.aStart.Col(),rRange.aStart.Row(),
rRange.aEnd.Col(),rRange.aEnd.Row() ) ) returnfalse;
if (mpSpellCheckCxt)
mpSpellCheckCxt->reset();
mpSpellCheckCxt.reset();
vcl::Window::dispose();
}
void ScGridWindow::ClickExtern()
{ do
{ // #i84277# when initializing the filter box, a Basic error can deactivate the view if (mpFilterBox && mpFilterBox->IsInInit()) break;
mpFilterBox.reset();
} while (false);
if (mpDPFieldPopup)
{
mpDPFieldPopup->close(false);
mpDPFieldPopup.reset();
}
}
IMPL_LINK_NOARG(ScGridWindow, PopupModeEndHdl, weld::Popover&, void)
{ if (mpFilterBox)
{ bool bMouseWasCaptured = mpFilterBox->MouseWasCaptured();
mpFilterBox->SetCancelled(); // cancel select // restore the mouse capture state of the GridWindow to // what it was at initial popup time
SAL_WARN_IF(bMouseWasCaptured, "sc.ui", "Is there a scenario where the mouse was captured before mouse down?"); if (bMouseWasCaptured)
CaptureMouse();
}
GrabFocus();
}
IMPL_LINK( ScGridWindow, PopupSpellingHdl, SpellCallbackInfo&, rInfo, void )
{ if( rInfo.nCommand == SpellCallbackCommand::STARTSPELLDLG )
mrViewData.GetDispatcher().Execute( SID_SPELL_DIALOG, SfxCallMode::ASYNCHRON ); elseif (rInfo.nCommand == SpellCallbackCommand::AUTOCORRECT_OPTIONS)
mrViewData.GetDispatcher().Execute( SID_AUTO_CORRECT_DLG, SfxCallMode::ASYNCHRON ); else//IGNOREWORD, ADDTODICTIONARY, WORDLANGUAGE, PARALANGUAGE
{ // The spelling status of the word has changed. Close the cell to reset the caches
ScInputHandler* pHdl = ScModule::get()->GetInputHdl(mrViewData.GetViewShell()); if (pHdl)
pHdl->EnterHandler();
}
}
class AutoFilterAction : public ScCheckListMenuControl::Action
{ protected:
VclPtr<ScGridWindow> mpWindow;
ScGridWindow::AutoFilterMode meMode; public:
AutoFilterAction(ScGridWindow* p, ScGridWindow::AutoFilterMode eMode) :
mpWindow(p), meMode(eMode) {} virtualbool execute() override
{
mpWindow->UpdateAutoFilterFromMenu(meMode); // UpdateAutoFilterFromMenu manually closes the popup so return // false to not attempt a second close returnfalse;
}
};
class AutoFilterPopupEndAction : public ScCheckListMenuControl::Action
{
VclPtr<ScGridWindow> mpWindow;
ScAddress maPos; public:
AutoFilterPopupEndAction(ScGridWindow* p, const ScAddress& rPos) :
mpWindow(p), maPos(rPos) {} virtualbool execute() override
{
mpWindow->RefreshAutoFilterButton(maPos);
mpWindow->GrabFocus(); returnfalse; // this is called after the popup has been closed
}
};
class AutoFilterSubMenuAction : public AutoFilterAction
{ protected:
ScListSubMenuControl* m_pSubMenu;
// Disable color filter when active color was selected if (bActive)
{
aParam.RemoveAllEntriesByField(rPos.Col());
pEntry = nullptr; // invalidated by RemoveAllEntriesByField call
// Estimate the width (in pixels) of the longest text in the list
ScFilterEntries aFilterEntries;
rDoc.GetFilterEntries(nCol, nRow, nTab, aFilterEntries);
int nMaxTextWidth = 0; if (aFilterEntries.size() <= 10)
{ // do pixel calculation for all elements of short lists for (constauto& rEntry : aFilterEntries)
{ const OUString& aText = rEntry.GetString();
nMaxTextWidth = std::max<int>(nMaxTextWidth, mpAutoFilterPopup->GetTextWidth(aText) + aText.getLength() * 2);
}
} else
{ // find the longest string, probably it will be the longest rendered text, too // (performance optimization for long lists) auto itMax = aFilterEntries.begin(); for (auto it = itMax; it != aFilterEntries.end(); ++it)
{ int nTextWidth = it->GetString().getLength(); if (nMaxTextWidth < nTextWidth)
{
nMaxTextWidth = nTextWidth;
itMax = it;
}
}
nMaxTextWidth = mpAutoFilterPopup->GetTextWidth(itMax->GetString()) + nMaxTextWidth * 2;
}
// window should be at least as wide as the column, or the longest text + checkbox, scrollbar ... (it is estimated with 70 pixel now) // window should be maximum 1024 pixel wide. int nWindowWidth = std::min<int>(1024, nMaxTextWidth + 70);
nWindowWidth = mpAutoFilterPopup->IncreaseWindowWidthToFitText(nWindowWidth);
nMaxTextWidth = std::max<int>(nMaxTextWidth, nWindowWidth - 70);
if (!bQueryByNonEmpty)
{ for (ScQueryEntry* pEntry : aEntries)
{ if (pEntry && pEntry->eOp == SC_EQUAL)
{
ScQueryEntry::QueryItemsType& rItems = pEntry->GetQueryItems();
std::for_each(rItems.begin(), rItems.end(), AddSelectedItemString(aSelectedString, aSelectedValue));
}
}
}
// Populate the check box list.
mpAutoFilterPopup->setMemberSize(aFilterEntries.size()); for (auto it = aFilterEntries.begin(); it != aFilterEntries.end(); ++it)
{ // tdf#140745 show (empty) entry on top of the checkbox list if not hidden by filter if (it->GetString().isEmpty() && !it->IsHiddenByFilter())
{ const OUString& aStringVal = it->GetString(); constdouble aDoubleVal = it->GetValue(); bool bSelected = true; if (!aSelectedValue.empty() || !aSelectedString.empty())
bSelected = aSelectedString.count(aStringVal) > 0; elseif (bQueryByNonEmpty)
bSelected = false; // it->IsHiddenByFilter() is always false here so no need to evaluate it
mpAutoFilterPopup->addMember(aStringVal, aDoubleVal, bSelected, false);
aFilterEntries.maStrData.erase(it); break;
}
} for (constauto& rEntry : aFilterEntries)
{ const OUString& aStringVal = rEntry.GetString(); constdouble aDoubleVal = rEntry.GetValue(); constdouble aRDoubleVal = rEntry.GetRoundedValue(); bool bSelected = !rEntry.IsHiddenByFilter();
void ScGridWindow::UpdateAutoFilterFromMenu(AutoFilterMode eMode)
{ // Terminate autofilter popup now when there is no further user input needed bool bColorMode = eMode == AutoFilterMode::TextColor || eMode == AutoFilterMode::BackgroundColor; if (!bColorMode)
mpAutoFilterPopup->terminateAllPopupMenus();
if (eMode == AutoFilterMode::Normal)
{ // Do not recreate autofilter rules if there are no changes from the user
ScCheckListMenuControl::ResultType aResult;
mpAutoFilterPopup->getResult(aResult);
if (aResult == aSaveAutoFilterResult)
{
SAL_INFO("sc.ui", "Apply autofilter to data when entries are the same");
if (!mpAutoFilterPopup->isAllSelected())
{ // Apply autofilter to data
ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);
pEntry->bDoQuery = true;
pEntry->nField = rPos.Col();
pEntry->eConnect = SC_AND;
pEntry->eOp = SC_EQUAL;
mrViewData.GetView()->Query(aParam, nullptr, true);
}
return;
}
}
// Remove old entries in auto-filter rules if (!bColorMode)
{
aParam.RemoveAllEntriesByField(rPos.Col());
if (eMode != AutoFilterMode::Clear
&& !(eMode == AutoFilterMode::Normal && mpAutoFilterPopup->isAllSelected()))
{ // Try to use the existing entry for the column (if one exists).
ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);
if (!pEntry) // Something went terribly wrong! return;
if (ScTabViewShell::isAnyEditViewInRange(mrViewData.GetViewShell(), /*bColumns*/ false, aParam.nRow1, aParam.nRow2)) return;
void getCellGeometry(Point& rScrPos, Size& rScrSize, const ScViewData& rViewData, SCCOL nCol, SCROW nRow, ScSplitPos eWhich)
{ // Get the screen position of the cell.
rScrPos = rViewData.GetScrPos(nCol, nRow, eWhich);
// Get the screen size of the cell.
tools::Long nSizeX, nSizeY;
rViewData.GetMergeSizePixel(nCol, nRow, nSizeX, nSizeY);
rScrSize = Size(nSizeX-1, nSizeY-1);
}
}
void ScGridWindow::LaunchPageFieldMenu( SCCOL nCol, SCROW nRow )
{ if (nCol == 0) // We assume that the page field button is located in cell to the immediate left. return;
// minimum width in pixel if (comphelper::LibreOfficeKit::isActive())
{ const tools::Long nMinLOKWinWidth = o3tl::convert(STD_COL_WIDTH * 13 / 10, o3tl::Length::twip, o3tl::Length::px); if (nSizeX < nMinLOKWinWidth)
nSizeX = nMinLOKWinWidth;
}
weld::TreeView& rFilterBox = mpFilterBox->get_widget(); int nEntryCount = rFilterBox.n_children(); if (nEntryCount > SC_FILTERLISTBOX_LINES)
nEntryCount = SC_FILTERLISTBOX_LINES; auto nHeight = rFilterBox.get_height_rows(nEntryCount);
rFilterBox.set_size_request(-1, nHeight);
Size aSize(rFilterBox.get_preferred_size()); auto nMaxToExpandTo = std::min(nSizeX, static_cast<decltype(nSizeX)>(300)); // do not over do it (Pixel) if (aSize.Width() < nMaxToExpandTo)
aSize.setWidth(nMaxToExpandTo);
aSize.AdjustWidth(4); // add a little margin
nSizeX += 4;
aSize.AdjustHeight(4);
tools::Rectangle aCellRect(rCellRect);
aCellRect.AdjustLeft(-2); // offset the little margin above
SCCOL nCol = rScenRange.aEnd.Col(); // Cell is below the Buttons
SCROW nRow = rScenRange.aStart.Row(); if (nRow == 0)
{
nRow = rScenRange.aEnd.Row() + 1; // Range at very the top -> Button below if (nRow>rDoc.MaxRow()) nRow = rDoc.MaxRow();
bMenuAtTop = false;
}
if (bLOKActive)
{ // aPos is now view-zoom adjusted and in pixels an more importantly this is pixel aligned to the view-zoom, // but once we use this to set the position of the floating window, it has no information of view-zoom level // so if we don't reverse the zoom now, a simple PixelToLogic(aPos, MapMode(MapUnit::MapTwip)) employed in // FloatingWindow::ImplCalcPos will produce a 'scaled' twips position which will again get zoom scaled in the // client (effective double scaling) causing wrong positioning/size. double fZoomX(mrViewData.GetZoomX()); double fZoomY(mrViewData.GetZoomY());
aPos.setX(aPos.getX() / fZoomX);
aPos.setY(aPos.getY() / fZoomY);
nSizeX = nSizeX / fZoomX;
nSizeY = nSizeY / fZoomY;
}
if (pData->GetListType() == css::sheet::TableValidationVisibility::SORTEDASCENDING)
{ auto it = std::lower_bound(aStrings.begin(), aStrings.end(), *pNew, ScTypedStrData::LessCaseSensitive()); if (it != aStrings.end() && ScTypedStrData::EqualCaseSensitive()(*it, *pNew))
nSelPos = static_cast<sal_Int32>(std::distance(aStrings.begin(), it));
} else
{ auto it = std::find_if(aStrings.begin(), aStrings.end(), FindTypedStrData(*pNew, true)); if (it != aStrings.end())
nSelPos = static_cast<sal_Int32>(std::distance(aStrings.begin(), it));
}
}
}
// Do not show an empty selection List:
if ( bEmpty )
{
mpFilterBox.reset();
} else
{
rFilterBox.grab_focus();
if (rFilterBox.n_children())
{ if (nSelPos != -1)
rFilterBox.set_cursor(nSelPos); else
rFilterBox.set_cursor(0);
} // Select only after GrabFocus, so that the focus rectangle gets correct if (nSelPos != -1)
rFilterBox.select(nSelPos); else
rFilterBox.unselect_all();
bool ScGridWindow::TestMouse( const MouseEvent& rMEvt, bool bAction )
{ // MouseEvent buttons must only be checked if bAction==TRUE // to allow changing the mouse pointer in MouseMove, // but not start AutoFill with right button (#74229#). // with bAction==sal_True, SetFillMode / SetDragMode is called
// The simple selection must also be recognized when dragging, // where the Marking flag is set and MarkToSimple won't work anymore.
mrViewData.GetMarkData().MarkToSimple();
}
bNewPointer = true;
}
}
}
if (bRefMode && pView->GetFunctionSet().CheckRefBounds(nPosX, nPosY)) return;
}
nNestedButtonState = ScNestedButtonState::Down;
MouseEventState aState;
HandleMouseButtonDown(rMEvt, aState); if (aState.mbActivatePart)
mrViewData.GetView()->ActivatePart(eWhich);
if ( nNestedButtonState == ScNestedButtonState::Up )
{ // #i41690# If an object is deactivated from MouseButtonDown, it might reschedule, // so MouseButtonUp comes before the MouseButtonDown call is finished. In this case, // simulate another MouseButtonUp call, so the selection state is consistent.
nButtonDown = rMEvt.GetButtons();
FakeButtonUp();
if ( IsTracking() )
EndTracking(); // normally done in VCL as part of MouseButtonUp handling
}
nNestedButtonState = ScNestedButtonState::NONE;
}
void ScGridWindow::HandleMouseButtonDown( const MouseEvent& rMEvt, MouseEventState& rState )
{ // We have to check if a context menu is shown and we have an UI // active inplace client. In that case we have to ignore the event. // Otherwise we would crash (context menu has been // opened by inplace client and we would deactivate the inplace client, // the context menu is closed by VCL asynchronously which in the end // would work on deleted objects or the context menu has no parent anymore)
SfxViewShell* pViewSh = mrViewData.GetViewShell();
SfxInPlaceClient* pClient = pViewSh->GetIPClient(); if ( pClient &&
pClient->IsObjectInPlaceActive() &&
vcl::IsInPopupMenuExecute() ) return;
aCurMousePos = rMEvt.GetPosPixel();
// Filter popup is ended with its own mouse click, not when clicking into the Grid Window, // so the following query is no longer necessary:
ClickExtern(); // deletes FilterBox when available
HideNoteOverlay();
bEEMouse = false;
ScModule* pScMod = ScModule::get(); if (pScMod->IsModalMode(&mrViewData.GetSfxDocShell())) return;
constbool bWasMouseCaptured = IsMouseCaptured();
SAL_WARN_IF(bWasMouseCaptured, "sc.ui", "Is there a scenario where the mouse is captured before mouse down?");
pScActiveViewShell = mrViewData.GetViewShell(); // if left is clicked
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.27 Sekunden
(vorverarbeitet)
¤
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.