From df50b02cd3177570bb26484a03273ba5caa50037 Mon Sep 17 00:00:00 2001 From: Caolán McNamara Date: Sun, 24 May 2020 20:48:03 +0100 Subject: weld ScFilterListBox MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit use the same positioning and sizing logic for DataSelectMenu and ScenarioMenu Change-Id: I34d183f72b6719528ce357b1fd40a1fdd1a4a29a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94774 Tested-by: Jenkins Reviewed-by: Caolán McNamara --- sc/UIConfig_scalc.mk | 1 + sc/source/ui/inc/gridwin.hxx | 2 + sc/source/ui/view/gridwin.cxx | 297 ++++++++++++++++--------------------- sc/uiconfig/scalc/ui/filterlist.ui | 61 ++++++++ 4 files changed, 189 insertions(+), 172 deletions(-) create mode 100644 sc/uiconfig/scalc/ui/filterlist.ui diff --git a/sc/UIConfig_scalc.mk b/sc/UIConfig_scalc.mk index 3035aa28e2bb..8e3de9629a7f 100644 --- a/sc/UIConfig_scalc.mk +++ b/sc/UIConfig_scalc.mk @@ -126,6 +126,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/scalc,\ sc/uiconfig/scalc/ui/externaldata \ sc/uiconfig/scalc/ui/exponentialsmoothingdialog \ sc/uiconfig/scalc/ui/filldlg \ + sc/uiconfig/scalc/ui/filterlist \ sc/uiconfig/scalc/ui/footerdialog \ sc/uiconfig/scalc/ui/formatcellsdialog \ sc/uiconfig/scalc/ui/formulacalculationoptions \ diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx index 5f0844a1547f..e04fc42cbc74 100644 --- a/sc/source/ui/inc/gridwin.hxx +++ b/sc/source/ui/inc/gridwin.hxx @@ -373,6 +373,8 @@ public: void UpdateFormulas(SCCOL nX1 = -1, SCROW nY1 = -1, SCCOL nX2 = -1, SCROW nY2 = -1); + void ShowFilterMenu(const tools::Rectangle& rCellRect, bool bLayoutRTL); + void LaunchDataSelectMenu( SCCOL nCol, SCROW nRow ); void DoScenarioMenu( const ScRange& rScenRange ); diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index 0e2c81780afd..bb55a7433cfb 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -37,11 +37,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -187,29 +187,30 @@ bool ScGridWindow::VisibleRange::set(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCRO return bChanged; } -class ScFilterListBox : public ListBox +class ScFilterListBox final : public InterimItemWindow { private: + std::unique_ptr xTreeView; VclPtr pGridWin; SCCOL nCol; SCROW nRow; bool bInit; bool bCancelled; - bool bInSelect; sal_uLong nSel; ScFilterBoxMode eMode; + ImplSVEvent* nAsyncSelectHdl; -protected: - void SelectHdl(); + DECL_LINK(SelectHdl, weld::TreeView&, bool); + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(AsyncSelectHdl, void*, void); public: - ScFilterListBox( vcl::Window* pParent, ScGridWindow* pGrid, - SCCOL nNewCol, SCROW nNewRow, ScFilterBoxMode eNewMode ); - virtual ~ScFilterListBox() override; + ScFilterListBox( vcl::Window* pParent, ScGridWindow* pGrid, + SCCOL nNewCol, SCROW nNewRow, ScFilterBoxMode eNewMode ); + virtual ~ScFilterListBox() override; virtual void dispose() override; - virtual bool PreNotify( NotifyEvent& rNEvt ) override; - virtual void Select() override; + weld::TreeView& get_widget() { return *xTreeView; } SCCOL GetCol() const { return nCol; } SCROW GetRow() const { return nRow; } @@ -217,22 +218,24 @@ public: void EndInit(); bool IsInInit() const { return bInit; } void SetCancelled() { bCancelled = true; } - bool IsInSelect() const { return bInSelect; } }; // ListBox in a FloatingWindow (pParent) ScFilterListBox::ScFilterListBox( vcl::Window* pParent, ScGridWindow* pGrid, SCCOL nNewCol, SCROW nNewRow, ScFilterBoxMode eNewMode ) : - ListBox( pParent, WB_AUTOHSCROLL | WB_LISTBOX_POPUP ), + InterimItemWindow(pParent, "modules/scalc/ui/filterlist.ui", "FilterList"), + xTreeView(m_xBuilder->weld_tree_view("list")), pGridWin( pGrid ), nCol( nNewCol ), nRow( nNewRow ), bInit( true ), bCancelled( false ), - bInSelect( false ), nSel( 0 ), - eMode( eNewMode ) + eMode( eNewMode ), + nAsyncSelectHdl(nullptr) { + xTreeView->connect_row_activated(LINK(this, ScFilterListBox, SelectHdl)); + xTreeView->connect_key_press(LINK(this, ScFilterListBox, KeyInputHdl)); } ScFilterListBox::~ScFilterListBox() @@ -242,16 +245,20 @@ ScFilterListBox::~ScFilterListBox() void ScFilterListBox::dispose() { - if (IsMouseCaptured()) - ReleaseMouse(); + if (nAsyncSelectHdl) + { + Application::RemoveUserEvent(nAsyncSelectHdl); + nAsyncSelectHdl = nullptr; + } pGridWin.clear(); - ListBox::dispose(); + xTreeView.reset(); + InterimItemWindow::dispose(); } void ScFilterListBox::EndInit() { - sal_Int32 nPos = GetSelectedEntryPos(); - if ( LISTBOX_ENTRY_NOTFOUND == nPos ) + sal_Int32 nPos = xTreeView->get_selected_index(); + if (nPos == -1) nSel = 0; else nSel = nPos; @@ -259,52 +266,41 @@ void ScFilterListBox::EndInit() bInit = false; } -bool ScFilterListBox::PreNotify( NotifyEvent& rNEvt ) +IMPL_LINK(ScFilterListBox, KeyInputHdl, const KeyEvent&, rKeyEvent, bool) { bool bDone = false; - if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT ) + + vcl::KeyCode aCode = rKeyEvent.GetKeyCode(); + // esc with no modifiers + if (!aCode.GetModifier() && aCode.GetCode() == KEY_ESCAPE) { - KeyEvent aKeyEvt = *rNEvt.GetKeyEvent(); - vcl::KeyCode aCode = aKeyEvt.GetKeyCode(); - if ( !aCode.GetModifier() ) // no modifiers - { - sal_uInt16 nKey = aCode.GetCode(); - if ( nKey == KEY_RETURN ) - { - SelectHdl(); // select - bDone = true; - } - else if ( nKey == KEY_ESCAPE ) - { - pGridWin->ClickExtern(); // clears the listbox - bDone = true; - } - } + pGridWin->ClickExtern(); // clears the listbox + bDone = true; } - return bDone || ListBox::PreNotify( rNEvt ); -} - -void ScFilterListBox::Select() -{ - ListBox::Select(); - SelectHdl(); + return bDone; } -void ScFilterListBox::SelectHdl() +IMPL_LINK_NOARG(ScFilterListBox, SelectHdl, weld::TreeView&, bool) { - if ( !IsTravelSelect() && !bInit && !bCancelled ) + if (!bInit && !bCancelled && !nAsyncSelectHdl) { - sal_Int32 nPos = GetSelectedEntryPos(); - if ( LISTBOX_ENTRY_NOTFOUND != nPos ) + int nPos = xTreeView->get_selected_index(); + if (nPos != -1) { nSel = nPos; - // #i81298# set bInSelect flag, so the box isn't deleted from modifications within FilterSelect - bInSelect = true; - pGridWin->FilterSelect( nSel ); - bInSelect = false; + // #i81298# launch async so the box isn't deleted from modifications within FilterSelect + nAsyncSelectHdl = Application::PostUserEvent(LINK(this, ScFilterListBox, AsyncSelectHdl)); } } + return true; +} + +IMPL_LINK_NOARG(ScFilterListBox, AsyncSelectHdl, void*, void) +{ + pGridWin->FilterSelect( nSel ); + nAsyncSelectHdl = nullptr; + pGridWin->ClickExtern(); } namespace { @@ -516,13 +512,9 @@ void ScGridWindow::ClickExtern() { do { - // #i81298# don't delete the filter box when called from its select handler - // (possible through row header size update) // #i84277# when initializing the filter box, a Basic error can deactivate the view - if (mpFilterBox && (mpFilterBox->IsInSelect() || mpFilterBox->IsInInit())) - { + if (mpFilterBox && mpFilterBox->IsInInit()) break; - } mpFilterBox.disposeAndClear(); mpFilterFloat.disposeAndClear(); } @@ -923,6 +915,52 @@ void ScGridWindow::LaunchDPFieldMenu( SCCOL nCol, SCROW nRow ) DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, ScAddress(nCol, nRow, nTab), pDPObj); } +void ScGridWindow::ShowFilterMenu(const tools::Rectangle& rCellRect, bool bLayoutRTL) +{ + auto nSizeX = rCellRect.GetWidth(); + + // minimum width in pixel + if (comphelper::LibreOfficeKit::isActive()) + { + const long nMinLOKWinWidth = static_cast(1.3 * STD_COL_WIDTH / TWIPS_PER_PIXEL); + 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()); + if (aSize.Width() < nSizeX) + aSize.setWidth(nSizeX); + if (aSize.Width() > 300) + aSize.setWidth(300); // do not over do it (Pixel) + + aSize.AdjustWidth(4); // add a little margin + nSizeX += 4; + aSize.AdjustHeight(4); + + tools::Rectangle aCellRect(rCellRect); + aCellRect.AdjustLeft(-2); // offset the little margin above + + if (!bLayoutRTL && aSize.Width() > nSizeX) + { + // move popup position + long nDiff = aSize.Width() - nSizeX; + long nNewX = aCellRect.Left() - nDiff; + if ( nNewX < 0 ) + nNewX = 0; + aCellRect.SetLeft( nNewX ); + } + + mpFilterBox->SetSizePixel(aSize); + mpFilterFloat->SetOutputSizePixel(aSize); + mpFilterFloat->StartPopupMode(aCellRect, FloatWinPopupFlags::Down|FloatWinPopupFlags::GrabFocus); +} + void ScGridWindow::DoScenarioMenu( const ScRange& rScenRange ) { bool bMenuAtTop = true; @@ -945,7 +983,6 @@ void ScGridWindow::DoScenarioMenu( const ScRange& rScenRange ) long nSizeX = 0; long nSizeY = 0; - long nHeight = 0; pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY ); // The button height should not use the merged cell height, should still use single row height nSizeY = ScViewData::ToPixel(pDoc->GetRowHeight(nRow, nTab), pViewData->GetPPTY()); @@ -967,37 +1004,14 @@ void ScGridWindow::DoScenarioMenu( const ScRange& rScenRange ) mpFilterFloat.reset(VclPtr::Create(this, WinBits(WB_BORDER))); mpFilterFloat->SetPopupModeEndHdl( LINK( this, ScGridWindow, PopupModeEndHdl ) ); mpFilterBox.reset(VclPtr::Create(mpFilterFloat.get(), this, nCol, nRow, ScFilterBoxMode::Scenario)); - if (bLayoutRTL) - mpFilterBox->EnableMirroring(); - - nSizeX += 1; - - { - vcl::Font aOldFont = GetFont(); - SetFont(mpFilterBox->GetFont()); - MapMode aOldMode = GetMapMode(); - SetMapMode(MapMode(MapUnit::MapPixel)); - - nHeight = GetTextHeight(); - nHeight *= SC_FILTERLISTBOX_LINES; - - SetMapMode( aOldMode ); - SetFont( aOldFont ); - } - - // SetSize later + weld::TreeView& rFilterBox = mpFilterBox->get_widget(); + rFilterBox.set_direction(bLayoutRTL); // Fix for bug fdo#44925 use sheet direction for widget RTL/LTR - // ParentSize missing check - Size aSize( nSizeX, nHeight ); - mpFilterBox->SetSizePixel( aSize ); mpFilterBox->Show(); // Show has to be before SetUpdateMode !!! - mpFilterBox->SetUpdateMode(false); - // SetOutputSizePixel/StartPopupMode first below, when the size is set // Listbox fill - - long nMaxText = 0; + rFilterBox.freeze(); OUString aCurrent; OUString aTabName; SCTAB nTabCount = pDoc->GetTableCount(); @@ -1007,56 +1021,31 @@ void ScGridWindow::DoScenarioMenu( const ScRange& rScenRange ) if (pDoc->HasScenarioRange( i, rScenRange )) if (pDoc->GetName( i, aTabName )) { - mpFilterBox->InsertEntry(aTabName); + rFilterBox.append_text(aTabName); if (pDoc->IsActiveScenario(i)) aCurrent = aTabName; - long nTextWidth = mpFilterBox->GetTextWidth(aTabName); - if ( nTextWidth > nMaxText ) - nMaxText = nTextWidth; ++nEntryCount; } } - if (nEntryCount > SC_FILTERLISTBOX_LINES) - nMaxText += GetSettings().GetStyleSettings().GetScrollBarSize(); - nMaxText += 4; // for margin - if ( nMaxText > 300 ) - nMaxText = 300; // do not over do it (Pixel) - - if (nMaxText > nSizeX) // Adjust size to what is needed - { - long nDiff = nMaxText - nSizeX; - aSize = Size( nMaxText, nHeight ); - mpFilterBox->SetSizePixel(aSize); - mpFilterFloat->SetOutputSizePixel(aSize); - - if ( !bLayoutRTL ) - { - // also move popup position - long nNewX = aCellRect.Left() - nDiff; - if ( nNewX < 0 ) - nNewX = 0; - aCellRect.SetLeft( nNewX ); - } - } + rFilterBox.thaw(); - mpFilterFloat->SetOutputSizePixel( aSize ); - mpFilterFloat->StartPopupMode( aCellRect, FloatWinPopupFlags::Down|FloatWinPopupFlags::GrabFocus ); + ShowFilterMenu(aCellRect, bLayoutRTL); - mpFilterBox->SetUpdateMode(true); - mpFilterBox->GrabFocus(); + rFilterBox.grab_focus(); - sal_Int32 nPos = LISTBOX_ENTRY_NOTFOUND; + sal_Int32 nPos = -1; if (!aCurrent.isEmpty()) { - nPos = mpFilterBox->GetEntryPos(aCurrent); + nPos = rFilterBox.find_text(aCurrent); } - if (LISTBOX_ENTRY_NOTFOUND == nPos && mpFilterBox->GetEntryCount() > 0 ) + if (nPos == -1 && rFilterBox.n_children() > 0 ) { nPos = 0; } - if (LISTBOX_ENTRY_NOTFOUND != nPos ) + if (nPos != -1) { - mpFilterBox->SelectEntryPos(nPos); + rFilterBox.set_cursor(nPos); + rFilterBox.select(nPos); } mpFilterBox->EndInit(); @@ -1077,7 +1066,6 @@ void ScGridWindow::LaunchDataSelectMenu( SCCOL nCol, SCROW nRow ) long nSizeX = 0; long nSizeY = 0; - long nHeight = 0; pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY ); Point aPos = pViewData->GetScrPos( nCol, nRow, eWhich ); bool bLOKActive = comphelper::LibreOfficeKit::isActive(); @@ -1112,24 +1100,8 @@ void ScGridWindow::LaunchDataSelectMenu( SCCOL nCol, SCROW nRow ) } mpFilterFloat->SetPopupModeEndHdl(LINK( this, ScGridWindow, PopupModeEndHdl)); mpFilterBox.reset(VclPtr::Create(mpFilterFloat.get(), this, nCol, nRow, ScFilterBoxMode::DataSelect)); - // Fix for bug fdo#44925 - if (AllSettings::GetLayoutRTL() != bLayoutRTL) - mpFilterBox->EnableMirroring(); - - nSizeX += 1; - - { - vcl::Font aOldFont = GetFont(); - SetFont(mpFilterBox->GetFont()); - MapMode aOldMode = GetMapMode(); - SetMapMode(MapMode(MapUnit::MapPixel)); - - nHeight = GetTextHeight(); - nHeight *= SC_FILTERLISTBOX_LINES; - - SetMapMode( aOldMode ); - SetFont( aOldFont ); - } + weld::TreeView& rFilterBox = mpFilterBox->get_widget(); + rFilterBox.set_direction(bLayoutRTL); // Fix for bug fdo#44925 use sheet direction for widget RTL/LTR // SetSize later @@ -1142,31 +1114,8 @@ void ScGridWindow::LaunchDataSelectMenu( SCCOL nCol, SCROW nRow ) if (!bEmpty) { - // Adjust position and size to Window - //! Check first if the entries fit (width) - - // minimum width in pixel - const long nMinLOKWinWidth = static_cast(1.3 * STD_COL_WIDTH / TWIPS_PER_PIXEL); - if (bLOKActive && nSizeX < nMinLOKWinWidth) - nSizeX = nMinLOKWinWidth; - - if (bLOKActive && aStrings.size() < SC_FILTERLISTBOX_LINES) - nHeight = nHeight * (aStrings.size() + 1) / SC_FILTERLISTBOX_LINES; - - Size aParentSize = GetParent()->GetOutputSizePixel(); - Size aSize( nSizeX, nHeight ); - - if ( aSize.Height() > aParentSize.Height() ) - aSize.setHeight( aParentSize.Height() ); - if ( aPos.Y() + aSize.Height() > aParentSize.Height() ) - aPos.setY( aParentSize.Height() - aSize.Height() ); - - mpFilterBox->SetSizePixel(aSize); - mpFilterBox->Show(); // Show has to be before SetUpdateMode !!! - mpFilterBox->SetUpdateMode(false); - - mpFilterFloat->SetOutputSizePixel(aSize); - mpFilterFloat->StartPopupMode(aCellRect, FloatWinPopupFlags::Down | FloatWinPopupFlags::GrabFocus); + mpFilterBox->Show(); // Show has to be before freeze !!! + rFilterBox.freeze(); // Fill Listbox bool bWait = aStrings.size() > 100; @@ -1175,15 +1124,17 @@ void ScGridWindow::LaunchDataSelectMenu( SCCOL nCol, SCROW nRow ) EnterWait(); for (const auto& rString : aStrings) - mpFilterBox->InsertEntry(rString.GetString()); + rFilterBox.append_text(rString.GetString()); if (bWait) LeaveWait(); - mpFilterBox->SetUpdateMode(true); + rFilterBox.thaw(); + + ShowFilterMenu(aCellRect, bLayoutRTL); } - sal_Int32 nSelPos = LISTBOX_ENTRY_NOTFOUND; + sal_Int32 nSelPos = -1; sal_uLong nIndex = pDoc->GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA )->GetValue(); if ( nIndex ) @@ -1225,15 +1176,16 @@ void ScGridWindow::LaunchDataSelectMenu( SCCOL nCol, SCROW nRow ) } else { - mpFilterBox->GrabFocus(); + rFilterBox.grab_focus(); // Select only after GrabFocus, so that the focus rectangle gets correct - if ( LISTBOX_ENTRY_NOTFOUND != nSelPos ) - mpFilterBox->SelectEntryPos(nSelPos); - else + if (nSelPos != -1) { - mpFilterBox->SetNoSelection(); + rFilterBox.set_cursor(nSelPos); + rFilterBox.select(nSelPos); } + else + rFilterBox.unselect_all(); mpFilterBox->EndInit(); } @@ -1241,7 +1193,8 @@ void ScGridWindow::LaunchDataSelectMenu( SCCOL nCol, SCROW nRow ) void ScGridWindow::FilterSelect( sal_uLong nSel ) { - OUString aString = mpFilterBox->GetEntry(static_cast(nSel)); + weld::TreeView& rFilterBox = mpFilterBox->get_widget(); + OUString aString = rFilterBox.get_text(static_cast(nSel)); SCCOL nCol = mpFilterBox->GetCol(); SCROW nRow = mpFilterBox->GetRow(); diff --git a/sc/uiconfig/scalc/ui/filterlist.ui b/sc/uiconfig/scalc/ui/filterlist.ui new file mode 100644 index 000000000000..0456fabbe905 --- /dev/null +++ b/sc/uiconfig/scalc/ui/filterlist.ui @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + True + False + True + True + vertical + 6 + + + True + True + True + True + never + + + True + True + True + liststore1 + False + False + 0 + False + True + + + + + + + + + 0 + + + + + + + + + False + True + 0 + + + + -- cgit v1.2.3