diff options
author | Caolán McNamara <caolanm@redhat.com> | 2019-02-05 15:35:35 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2019-02-05 22:43:05 +0100 |
commit | 29a66fe8cde3e18bf4d1c3d7a1f2077ea54548be (patch) | |
tree | efa032d617b6771bac09a5d5867634a0e605ab6e | |
parent | 2877657777926dbc66f4844cc94e37e74fd546cd (diff) |
weld WebConnectionInfoDialog
Change-Id: Idff8a0589075c8b7c774f187f5082fd954251d77
Reviewed-on: https://gerrit.libreoffice.org/67420
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r-- | cui/source/options/optinet2.cxx | 4 | ||||
-rw-r--r-- | cui/source/options/webconninfo.cxx | 189 | ||||
-rw-r--r-- | cui/source/options/webconninfo.hxx | 44 | ||||
-rw-r--r-- | cui/uiconfig/ui/storedwebconnectiondialog.ui | 100 | ||||
-rw-r--r-- | include/vcl/weld.hxx | 5 | ||||
-rw-r--r-- | vcl/source/app/salvtables.cxx | 42 | ||||
-rw-r--r-- | vcl/source/window/builder.cxx | 32 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 85 |
8 files changed, 270 insertions, 231 deletions
diff --git a/cui/source/options/optinet2.cxx b/cui/source/options/optinet2.cxx index c269d87fdda5..bee5e2d64d14 100644 --- a/cui/source/options/optinet2.cxx +++ b/cui/source/options/optinet2.cxx @@ -784,8 +784,8 @@ IMPL_LINK_NOARG(SvxSecurityTabPage, ShowPasswordsHdl, Button*, void) if ( xMasterPasswd->isPersistentStoringAllowed() && xMasterPasswd->authorizateWithMasterPassword(xTmpHandler) ) { - ScopedVclPtrInstance< svx::WebConnectionInfoDialog > aDlg(this); - aDlg->Execute(); + svx::WebConnectionInfoDialog aDlg(GetDialogFrameWeld()); + aDlg.run(); } } catch (const Exception&) diff --git a/cui/source/options/webconninfo.cxx b/cui/source/options/webconninfo.cxx index 18a2cd7fbca9..5bb56294cfc3 100644 --- a/cui/source/options/webconninfo.cxx +++ b/cui/source/options/webconninfo.cxx @@ -35,125 +35,49 @@ using namespace ::com::sun::star; namespace svx { - -// class PasswordTable --------------------------------------------------- - -PasswordTable::PasswordTable(SvSimpleTableContainer& rParent, WinBits nBits) - : SvSimpleTable(rParent, nBits | WB_NOINITIALSELECTION) -{ -} - -void PasswordTable::InsertHeaderItem(sal_uInt16 nColumn, const OUString& rText, HeaderBarItemBits nBits) -{ - GetTheHeaderBar().InsertItem( nColumn, rText, 0, nBits ); -} - -void PasswordTable::Resort( bool bForced ) -{ - sal_uInt16 nColumn = GetSelectedCol(); - if ( 0 == nColumn || bForced ) // only the first column is sorted - { - HeaderBarItemBits nBits = GetTheHeaderBar().GetItemBits(1); - bool bUp = ( ( nBits & HeaderBarItemBits::UPARROW ) == HeaderBarItemBits::UPARROW ); - SvSortMode eMode = SortAscending; - - if ( bUp ) - { - nBits &= ~HeaderBarItemBits::UPARROW; - nBits |= HeaderBarItemBits::DOWNARROW; - eMode = SortDescending; - } - else - { - nBits &= ~HeaderBarItemBits::DOWNARROW; - nBits |= HeaderBarItemBits::UPARROW; - } - GetTheHeaderBar().SetItemBits( 1, nBits ); - SvTreeList* pListModel = GetModel(); - pListModel->SetSortMode( eMode ); - pListModel->Resort(); - } -} - -void PasswordTable::Resize() -{ - SvSimpleTable::Resize(); - if (isInitialLayout(this)) - setColWidths(); -} - -void PasswordTable::setColWidths() -{ - HeaderBar &rBar = GetTheHeaderBar(); - if (rBar.GetItemCount() < 2) - return; - long nUserNameWidth = 12 + - std::max(rBar.GetTextWidth(rBar.GetItemText(2)), - GetTextWidth("XXXXXXXXXXXX")); - long nWebSiteWidth = std::max( - 12 + rBar.GetTextWidth(rBar.GetItemText(1)), - GetSizePixel().Width() - nUserNameWidth); - long aStaticTabs[]= { 0, nWebSiteWidth }; - SvSimpleTable::SetTabs(SAL_N_ELEMENTS(aStaticTabs), aStaticTabs, MapUnit::MapPixel); -} - // class WebConnectionInfoDialog ----------------------------------------- - -WebConnectionInfoDialog::WebConnectionInfoDialog(vcl::Window* pParent) - : ModalDialog(pParent, "StoredWebConnectionDialog", "cui/ui/storedwebconnectiondialog.ui") +WebConnectionInfoDialog::WebConnectionInfoDialog(weld::Window* pParent) + : GenericDialogController(pParent, "cui/ui/storedwebconnectiondialog.ui", "StoredWebConnectionDialog") , m_nPos( -1 ) + , m_xRemoveBtn(m_xBuilder->weld_button("remove")) + , m_xRemoveAllBtn(m_xBuilder->weld_button("removeall")) + , m_xChangeBtn(m_xBuilder->weld_button("change")) + , m_xPasswordsLB(m_xBuilder->weld_tree_view("logins")) { - get(m_pRemoveBtn, "remove"); - get(m_pRemoveAllBtn, "removeall"); - get(m_pChangeBtn, "change"); - - SvSimpleTableContainer *pPasswordsLBContainer = get<SvSimpleTableContainer>("logins"); - m_pPasswordsLB = VclPtr<PasswordTable>::Create(*pPasswordsLBContainer, 0); - - long const aStaticTabs[]= { 0, 0 }; - m_pPasswordsLB->SetTabs( SAL_N_ELEMENTS(aStaticTabs), aStaticTabs ); - m_pPasswordsLB->InsertHeaderItem( 1, get<FixedText>("website")->GetText(), - HeaderBarItemBits::LEFT | HeaderBarItemBits::FIXEDPOS | HeaderBarItemBits::CLICKABLE | HeaderBarItemBits::UPARROW ); - m_pPasswordsLB->InsertHeaderItem( 2, get<FixedText>("username")->GetText(), - HeaderBarItemBits::LEFT | HeaderBarItemBits::FIXEDPOS ); - pPasswordsLBContainer->set_height_request(m_pPasswordsLB->GetTextHeight()*8); + std::vector<int> aWidths; + aWidths.push_back(m_xPasswordsLB->get_approximate_digit_width() * 50); + m_xPasswordsLB->set_column_fixed_widths(aWidths); + m_xPasswordsLB->set_size_request(m_xPasswordsLB->get_approximate_digit_width() * 70, + m_xPasswordsLB->get_height_rows(8)); - m_pPasswordsLB->SetHeaderBarClickHdl( LINK( this, WebConnectionInfoDialog, HeaderBarClickedHdl ) ); + m_xPasswordsLB->connect_column_clicked(LINK(this, WebConnectionInfoDialog, HeaderBarClickedHdl)); FillPasswordList(); - m_pRemoveBtn->SetClickHdl( LINK( this, WebConnectionInfoDialog, RemovePasswordHdl ) ); - m_pRemoveAllBtn->SetClickHdl( LINK( this, WebConnectionInfoDialog, RemoveAllPasswordsHdl ) ); - m_pChangeBtn->SetClickHdl( LINK( this, WebConnectionInfoDialog, ChangePasswordHdl ) ); - m_pPasswordsLB->SetSelectHdl( LINK( this, WebConnectionInfoDialog, EntrySelectedHdl ) ); + m_xRemoveBtn->connect_clicked( LINK( this, WebConnectionInfoDialog, RemovePasswordHdl ) ); + m_xRemoveAllBtn->connect_clicked( LINK( this, WebConnectionInfoDialog, RemoveAllPasswordsHdl ) ); + m_xChangeBtn->connect_clicked( LINK( this, WebConnectionInfoDialog, ChangePasswordHdl ) ); + m_xPasswordsLB->connect_changed( LINK( this, WebConnectionInfoDialog, EntrySelectedHdl ) ); - m_pRemoveBtn->Enable( false ); - m_pChangeBtn->Enable( false ); + m_xRemoveBtn->set_sensitive( false ); + m_xChangeBtn->set_sensitive( false ); - HeaderBarClickedHdl( nullptr ); + m_xPasswordsLB->make_sorted(); } WebConnectionInfoDialog::~WebConnectionInfoDialog() { - disposeOnce(); } -void WebConnectionInfoDialog::dispose() +IMPL_LINK(WebConnectionInfoDialog, HeaderBarClickedHdl, int, nColumn, void) { - m_pPasswordsLB.disposeAndClear(); - m_pRemoveBtn.clear(); - m_pRemoveAllBtn.clear(); - m_pChangeBtn.clear(); - ModalDialog::dispose(); -} - -IMPL_LINK( WebConnectionInfoDialog, HeaderBarClickedHdl, SvSimpleTable*, pTable, void ) -{ - m_pPasswordsLB->Resort( nullptr == pTable ); + if (nColumn == 0) // only the first column is sorted + { + m_xPasswordsLB->set_sort_order(!m_xPasswordsLB->get_sort_order()); + } } - void WebConnectionInfoDialog::FillPasswordList() { try @@ -173,10 +97,9 @@ void WebConnectionInfoDialog::FillPasswordList() { for ( sal_Int32 nUserInd = 0; nUserInd < aURLEntries[nURLInd].UserList.getLength(); nUserInd++ ) { - SvTreeListEntry* pEntry = m_pPasswordsLB->InsertEntry( - aURLEntries[nURLInd].Url + "\t" + - aURLEntries[nURLInd].UserList[nUserInd].UserName); - pEntry->SetUserData( reinterpret_cast<void*>(nCount++) ); + m_xPasswordsLB->append(OUString::number(nCount), aURLEntries[nURLInd].Url); + m_xPasswordsLB->set_text(nCount, aURLEntries[nURLInd].UserList[nUserInd].UserName, 1); + ++nCount; } } @@ -188,9 +111,9 @@ void WebConnectionInfoDialog::FillPasswordList() for ( sal_Int32 nURLIdx = 0; nURLIdx < aUrls.getLength(); nURLIdx++ ) { - SvTreeListEntry* pEntry = m_pPasswordsLB->InsertEntry( - aUrls[nURLIdx] + "\t*"); - pEntry->SetUserData( reinterpret_cast<void*>(nCount++) ); + m_xPasswordsLB->append(OUString::number(nCount), aUrls[nURLIdx]); + m_xPasswordsLB->set_text(nCount, "*"); + ++nCount; } } } @@ -199,20 +122,20 @@ void WebConnectionInfoDialog::FillPasswordList() } -IMPL_LINK_NOARG(WebConnectionInfoDialog, RemovePasswordHdl, Button*, void) +IMPL_LINK_NOARG(WebConnectionInfoDialog, RemovePasswordHdl, weld::Button&, void) { try { - SvTreeListEntry* pEntry = m_pPasswordsLB->GetCurEntry(); - if ( pEntry ) + int nEntry = m_xPasswordsLB->get_selected_index(); + if (nEntry != -1) { - OUString aURL = SvTabListBox::GetEntryText( pEntry, 0 ); - OUString aUserName = SvTabListBox::GetEntryText( pEntry, 1 ); + OUString aURL = m_xPasswordsLB->get_text(nEntry, 0); + OUString aUserName = m_xPasswordsLB->get_text(nEntry, 1); uno::Reference< task::XPasswordContainer2 > xPasswdContainer( task::PasswordContainer::create(comphelper::getProcessComponentContext())); - sal_Int32 nPos = static_cast<sal_Int32>(reinterpret_cast<sal_IntPtr>(pEntry->GetUserData())); + int nPos = m_xPasswordsLB->get_id(nEntry).toInt32(); if ( nPos < m_nPos ) { xPasswdContainer->removePersistent( aURL, aUserName ); @@ -221,15 +144,15 @@ IMPL_LINK_NOARG(WebConnectionInfoDialog, RemovePasswordHdl, Button*, void) { xPasswdContainer->removeUrl( aURL ); } - m_pPasswordsLB->RemoveEntry( pEntry ); + + m_xPasswordsLB->remove(nEntry); } } catch( uno::Exception& ) {} } - -IMPL_LINK_NOARG(WebConnectionInfoDialog, RemoveAllPasswordsHdl, Button*, void) +IMPL_LINK_NOARG(WebConnectionInfoDialog, RemoveAllPasswordsHdl, weld::Button&, void) { try { @@ -244,30 +167,28 @@ IMPL_LINK_NOARG(WebConnectionInfoDialog, RemoveAllPasswordsHdl, Button*, void) for ( sal_Int32 nURLIdx = 0; nURLIdx < aUrls.getLength(); nURLIdx++ ) xPasswdContainer->removeUrl( aUrls[ nURLIdx ] ); - m_pPasswordsLB->Clear(); + m_xPasswordsLB->clear(); } catch( uno::Exception& ) {} } - -IMPL_LINK_NOARG(WebConnectionInfoDialog, ChangePasswordHdl, Button*, void) +IMPL_LINK_NOARG(WebConnectionInfoDialog, ChangePasswordHdl, weld::Button&, void) { try { - SvTreeListEntry* pEntry = m_pPasswordsLB->GetCurEntry(); - if ( pEntry ) + int nEntry = m_xPasswordsLB->get_selected_index(); + if (nEntry != -1) { - OUString aURL = SvTabListBox::GetEntryText( pEntry, 0 ); - OUString aUserName = SvTabListBox::GetEntryText( pEntry, 1 ); + OUString aURL = m_xPasswordsLB->get_text(nEntry, 0); + OUString aUserName = m_xPasswordsLB->get_text(nEntry, 1); ::comphelper::SimplePasswordRequest* pPasswordRequest = new ::comphelper::SimplePasswordRequest; uno::Reference< task::XInteractionRequest > rRequest( pPasswordRequest ); - auto xWindow = VCLUnoHelper::GetInterface(this); uno::Reference< task::XInteractionHandler > xInteractionHandler( - task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), xWindow), + task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), m_xDialog->GetXWindow()), uno::UNO_QUERY ); xInteractionHandler->handle( rRequest ); @@ -288,27 +209,25 @@ IMPL_LINK_NOARG(WebConnectionInfoDialog, ChangePasswordHdl, Button*, void) } -IMPL_LINK_NOARG(WebConnectionInfoDialog, EntrySelectedHdl, SvTreeListBox*, void) +IMPL_LINK_NOARG(WebConnectionInfoDialog, EntrySelectedHdl, weld::TreeView&, void) { - SvTreeListEntry* pEntry = m_pPasswordsLB->GetCurEntry(); - if ( !pEntry ) + int nEntry = m_xPasswordsLB->get_selected_index(); + if (nEntry == -1) { - m_pRemoveBtn->Enable( false ); - m_pChangeBtn->Enable( false ); + m_xRemoveBtn->set_sensitive(false); + m_xChangeBtn->set_sensitive(false); } else { - m_pRemoveBtn->Enable(); + m_xRemoveBtn->set_sensitive(true); // url container entries (-> use system credentials) have // no password - sal_Int32 nPos = static_cast<sal_Int32>(reinterpret_cast<sal_IntPtr>(pEntry->GetUserData())); - m_pChangeBtn->Enable( nPos < m_nPos ); + int nPos = m_xPasswordsLB->get_id(nEntry).toInt32(); + m_xChangeBtn->set_sensitive(nPos < m_nPos); } } - } - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/options/webconninfo.hxx b/cui/source/options/webconninfo.hxx index 792d66cb2a1c..95d524c8a3bc 100644 --- a/cui/source/options/webconninfo.hxx +++ b/cui/source/options/webconninfo.hxx @@ -18,47 +18,31 @@ #ifndef INCLUDED_CUI_SOURCE_OPTIONS_WEBCONNINFO_HXX #define INCLUDED_CUI_SOURCE_OPTIONS_WEBCONNINFO_HXX -#include <vcl/button.hxx> -#include <vcl/dialog.hxx> -#include <vcl/fixed.hxx> -#include <svtools/simptabl.hxx> +#include <vcl/weld.hxx> namespace svx { - - - class PasswordTable : public SvSimpleTable - { - public: - PasswordTable(SvSimpleTableContainer& rParent, WinBits nBits); - - void InsertHeaderItem(sal_uInt16 nColumn, const OUString& rText, HeaderBarItemBits nBits); - void setColWidths(); - void Resort( bool bForced ); - virtual void Resize() override; - }; - - class WebConnectionInfoDialog : public ModalDialog + class WebConnectionInfoDialog : public weld::GenericDialogController { private: - VclPtr<PasswordTable> m_pPasswordsLB; - VclPtr<PushButton> m_pRemoveBtn; - VclPtr<PushButton> m_pRemoveAllBtn; - VclPtr<PushButton> m_pChangeBtn; - sal_Int32 m_nPos; + sal_Int32 m_nPos; + + std::unique_ptr<weld::Button> m_xRemoveBtn; + std::unique_ptr<weld::Button> m_xRemoveAllBtn; + std::unique_ptr<weld::Button> m_xChangeBtn; + std::unique_ptr<weld::TreeView> m_xPasswordsLB; - DECL_LINK( HeaderBarClickedHdl, SvSimpleTable*, void ); - DECL_LINK( RemovePasswordHdl, Button*, void ); - DECL_LINK( RemoveAllPasswordsHdl, Button*, void ); - DECL_LINK( ChangePasswordHdl, Button*, void ); - DECL_LINK( EntrySelectedHdl, SvTreeListBox*, void ); + DECL_LINK( HeaderBarClickedHdl, int, void ); + DECL_LINK( RemovePasswordHdl, weld::Button&, void ); + DECL_LINK( RemoveAllPasswordsHdl, weld::Button&, void ); + DECL_LINK( ChangePasswordHdl, weld::Button&, void ); + DECL_LINK( EntrySelectedHdl, weld::TreeView&, void ); void FillPasswordList(); public: - explicit WebConnectionInfoDialog( vcl::Window* pParent ); + explicit WebConnectionInfoDialog(weld::Window* pParent); virtual ~WebConnectionInfoDialog() override; - virtual void dispose() override; }; diff --git a/cui/uiconfig/ui/storedwebconnectiondialog.ui b/cui/uiconfig/ui/storedwebconnectiondialog.ui index 685df0e160a4..69f2c30b9b79 100644 --- a/cui/uiconfig/ui/storedwebconnectiondialog.ui +++ b/cui/uiconfig/ui/storedwebconnectiondialog.ui @@ -1,14 +1,26 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.18.3 --> +<!-- Generated with glade 3.22.1 --> <interface domain="cui"> <requires lib="gtk+" version="3.18"/> - <requires lib="LibreOffice" version="1.0"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name text2 --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> <object class="GtkDialog" id="StoredWebConnectionDialog"> <property name="can_focus">False</property> <property name="border_width">6</property> <property name="title" translatable="yes" context="storedwebconnectiondialog|StoredWebConnectionDialog">Stored Web Connection Information</property> <property name="resizable">False</property> <property name="type_hint">dialog</property> + <child> + <placeholder/> + </child> <child internal-child="vbox"> <object class="GtkBox" id="dialog-vbox1"> <property name="can_focus">False</property> @@ -66,8 +78,8 @@ <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="xalign">0</property> <property name="label" translatable="yes" context="storedwebconnectiondialog|label1">Web login information (passwords are never shown)</property> + <property name="xalign">0</property> </object> <packing> <property name="left_attach">0</property> @@ -75,32 +87,53 @@ </packing> </child> <child> - <object class="GtkGrid" id="grid3"> - <property name="can_focus">False</property> - <property name="no_show_all">True</property> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> <property name="hexpand">True</property> - <property name="column_spacing">12</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> <child> - <object class="GtkLabel" id="website"> + <object class="GtkTreeView" id="logins"> <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes" context="storedwebconnectiondialog|website">Website</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="search_column">0</property> + <property name="show_expanders">False</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="Macro Library List-selection2"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn5"> + <property name="resizable">True</property> + <property name="spacing">6</property> + <property name="title" translatable="yes" context="storedwebconnectiondialog|website">Website</property> + <property name="clickable">True</property> + <property name="sort_indicator">True</property> + <child> + <object class="GtkCellRendererText" id="cellrenderer4"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn1"> + <property name="resizable">True</property> + <property name="spacing">6</property> + <property name="title" translatable="yes" context="storedwebconnectiondialog|username">User name</property> + <child> + <object class="GtkCellRendererText" id="cellrenderer1"/> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="username"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes" context="storedwebconnectiondialog|username">User name</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">0</property> - </packing> </child> </object> <packing> @@ -109,21 +142,6 @@ </packing> </child> <child> - <object class="svtlo-SvSimpleTableContainer" id="logins"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="hexpand">True</property> - <property name="vexpand">True</property> - <child internal-child="selection"> - <object class="GtkTreeSelection" id="Simple Table Container-selection1"/> - </child> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">2</property> - </packing> - </child> - <child> <object class="GtkButtonBox" id="buttonbox1"> <property name="visible">True</property> <property name="can_focus">False</property> @@ -175,7 +193,7 @@ </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">3</property> + <property name="top_attach">2</property> </packing> </child> </object> diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index 2649e551921a..bcb6a898105a 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -455,6 +455,7 @@ class VCL_DLLPUBLIC TreeView : virtual public Container protected: Link<TreeView&, void> m_aChangeHdl; Link<TreeView&, void> m_aRowActivatedHdl; + Link<int, void> m_aColumnClickedHdl; Link<const std::pair<int, int>&, void> m_aRadioToggleHdl; // if handler returns false, the expansion of the row is refused Link<TreeIter&, bool> m_aExpandingHdl; @@ -463,6 +464,7 @@ protected: void signal_changed() { m_aChangeHdl.Call(*this); } void signal_row_activated() { m_aRowActivatedHdl.Call(*this); } + void signal_column_clicked(int nColumn) { m_aColumnClickedHdl.Call(nColumn); } bool signal_expanding(TreeIter& rIter) { return !m_aExpandingHdl.IsSet() || m_aExpandingHdl.Call(rIter); @@ -515,6 +517,7 @@ public: { m_aRadioToggleHdl = rLink; } + void connect_column_clicked(const Link<int, void>& rLink) { m_aColumnClickedHdl = rLink; } //by index virtual int get_selected_index() const = 0; @@ -599,6 +602,8 @@ public: virtual int n_children() const = 0; virtual void make_sorted() = 0; + virtual bool get_sort_order() const = 0; + virtual void set_sort_order(bool bAscending) = 0; virtual void clear() = 0; virtual int get_height_rows(int nRows) const = 0; diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 823c4bb2a666..f55c6fc3b43d 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -1936,6 +1936,7 @@ private: DECL_LINK(DoubleClickHdl, SvTreeListBox*, bool); DECL_LINK(ExpandingHdl, SvTreeListBox*, bool); DECL_LINK(EndDragHdl, HeaderBar*, void); + DECL_LINK(HeaderBarClickedHdl, HeaderBar*, void); DECL_LINK(ToggleHdl, SvLBoxButtonData*, void); public: SalInstanceTreeView(SvTabListBox* pTreeView, bool bTakeOwnership) @@ -1956,6 +1957,7 @@ public: //make the last entry fill available space pHeaderBar->SetItemSize(pHeaderBar->GetItemId(pHeaderBar->GetItemCount() - 1 ), HEADERBAR_FULLSIZE); pHeaderBar->SetEndDragHdl(LINK(this, SalInstanceTreeView, EndDragHdl)); + pHeaderBar->SetSelectHdl(LINK(this, SalInstanceTreeView, HeaderBarClickedHdl)); } m_aCheckButtonData.SetLink(LINK(this, SalInstanceTreeView, ToggleHdl)); m_aRadioButtonData.SetLink(LINK(this, SalInstanceTreeView, ToggleHdl)); @@ -2487,7 +2489,36 @@ public: virtual void make_sorted() override { m_xTreeView->SetStyle(m_xTreeView->GetStyle() | WB_SORT); - m_xTreeView->GetModel()->Resort(); + set_sort_order(true); + } + + virtual void set_sort_order(bool bAscending) override + { + SvHeaderTabListBox* pHeaderBox = dynamic_cast<SvHeaderTabListBox*>(m_xTreeView.get()); + if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr) + { + sal_uInt16 nTextId = pHeaderBar->GetItemId(0); + HeaderBarItemBits nBits = pHeaderBar->GetItemBits(nTextId); + if (nBits & HeaderBarItemBits::CLICKABLE) + { + nBits &= ~HeaderBarItemBits::UPARROW; + nBits &= ~HeaderBarItemBits::DOWNARROW; + if (bAscending) + nBits |= HeaderBarItemBits::DOWNARROW; + else + nBits |= HeaderBarItemBits::UPARROW; + pHeaderBar->SetItemBits(nTextId, nBits); + } + } + + SvTreeList* pListModel = m_xTreeView->GetModel(); + pListModel->SetSortMode(bAscending ? SortAscending : SortDescending); + pListModel->Resort(); + } + + virtual bool get_sort_order() const override + { + return m_xTreeView->GetModel()->GetSortMode() == SortAscending; } SvTabListBox& getTreeView() @@ -2500,6 +2531,7 @@ public: SvHeaderTabListBox* pHeaderBox = dynamic_cast<SvHeaderTabListBox*>(m_xTreeView.get()); if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr) { + pHeaderBar->SetSelectHdl(Link<HeaderBar*, void>()); pHeaderBar->SetEndDragHdl(Link<HeaderBar*, void>()); } m_xTreeView->SetExpandingHdl(Link<SvTreeListBox*, bool>()); @@ -2554,6 +2586,14 @@ IMPL_LINK(SalInstanceTreeView, EndDragHdl, HeaderBar*, pHeaderBar, void) m_xTreeView->SetTabs(aTabPositions.size(), aTabPositions.data(), MapUnit::MapPixel); } +IMPL_LINK(SalInstanceTreeView, HeaderBarClickedHdl, HeaderBar*, pHeaderBar, void) +{ + sal_uInt16 nId = pHeaderBar->GetCurItemId(); + if (!(pHeaderBar->GetItemBits(nId) & HeaderBarItemBits::CLICKABLE)) + return; + signal_column_clicked(pHeaderBar->GetItemPos(nId)); +} + IMPL_LINK_NOARG(SalInstanceTreeView, ExpandingHdl, SvTreeListBox*, bool) { SvTreeListEntry* pEntry = m_xTreeView->GetHdlEntry(); diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx index fe406ed94b6f..c95ed2800193 100644 --- a/vcl/source/window/builder.cxx +++ b/vcl/source/window/builder.cxx @@ -1123,6 +1123,30 @@ namespace return bHeadersVisible; } + bool extractSortIndicator(VclBuilder::stringmap &rMap) + { + bool bSortIndicator = false; + VclBuilder::stringmap::iterator aFind = rMap.find(OString("sort-indicator")); + if (aFind != rMap.end()) + { + bSortIndicator = toBool(aFind->second); + rMap.erase(aFind); + } + return bSortIndicator; + } + + bool extractClickable(VclBuilder::stringmap &rMap) + { + bool bClickable = false; + VclBuilder::stringmap::iterator aFind = rMap.find(OString("clickable")); + if (aFind != rMap.end()) + { + bClickable = toBool(aFind->second); + rMap.erase(aFind); + } + return bClickable; + } + void setupFromActionName(Button *pButton, VclBuilder::stringmap &rMap, const css::uno::Reference<css::frame::XFrame>& rFrame) { if (!rFrame.is()) @@ -1950,8 +1974,11 @@ VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OString & SvHeaderTabListBox* pTreeView = dynamic_cast<SvHeaderTabListBox*>(pParent); if (HeaderBar* pHeaderBar = pTreeView ? pTreeView->GetHeaderBar() : nullptr) { - OUString sTitle(extractTitle(rMap)); - HeaderBarItemBits nBits = HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::CLICKABLE; + HeaderBarItemBits nBits = HeaderBarItemBits::LEFTIMAGE; + if (extractClickable(rMap)) + nBits |= HeaderBarItemBits::CLICKABLE; + if (extractSortIndicator(rMap)) + nBits |= HeaderBarItemBits::DOWNARROW; float fAlign = extractAlignment(rMap); if (fAlign == 0.0) nBits |= HeaderBarItemBits::LEFT; @@ -1960,6 +1987,7 @@ VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OString & else if (fAlign == 0.5) nBits |= HeaderBarItemBits::CENTER; auto nItemId = pHeaderBar->GetItemCount() + 1; + OUString sTitle(extractTitle(rMap)); pHeaderBar->InsertItem(nItemId, sTitle, 100, nBits); } } diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index b64cb1933a73..ca35d447fbb1 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -4956,15 +4956,19 @@ private: GtkTreeView* m_pTreeView; GtkTreeStore* m_pTreeStore; std::unique_ptr<comphelper::string::NaturalStringSorter> m_xSorter; + GList *m_pColumns; + std::vector<gulong> m_aColumnSignalIds; // map from toggle column to toggle visibility column std::map<int, int> m_aToggleVisMap; gint m_nTextCol; + gint m_nTextColHeader; gint m_nImageCol; gint m_nExpanderImageCol; gint m_nIdCol; gulong m_nChangedSignalId; gulong m_nRowActivatedSignalId; gulong m_nTestExpandRowSignalId; + GtkSortType m_eSortType; DECL_LINK(async_signal_changed, void*, void); @@ -5142,30 +5146,57 @@ private: gtk_tree_path_free(tree_path); } + void signal_column_clicked(GtkTreeViewColumn* pClickedColumn) + { + int nIndex(0); + for (GList* pEntry = g_list_first(m_pColumns); pEntry; pEntry = g_list_next(pEntry)) + { + GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data); + if (pColumn == pClickedColumn) + { + TreeView::signal_column_clicked(nIndex); + break; + } + ++nIndex; + } + } + + static void signalColumnClicked(GtkTreeViewColumn* pColumn, gpointer widget) + { + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + pThis->signal_column_clicked(pColumn); + } + public: GtkInstanceTreeView(GtkTreeView* pTreeView, bool bTakeOwnership) : GtkInstanceContainer(GTK_CONTAINER(pTreeView), bTakeOwnership) , m_pTreeView(pTreeView) , m_pTreeStore(GTK_TREE_STORE(gtk_tree_view_get_model(m_pTreeView))) , m_nTextCol(-1) + , m_nTextColHeader(-1) , m_nImageCol(-1) , m_nExpanderImageCol(-1) , m_nChangedSignalId(g_signal_connect(gtk_tree_view_get_selection(pTreeView), "changed", G_CALLBACK(signalChanged), this)) , m_nRowActivatedSignalId(g_signal_connect(pTreeView, "row-activated", G_CALLBACK(signalRowActivated), this)) , m_nTestExpandRowSignalId(g_signal_connect(pTreeView, "test-expand-row", G_CALLBACK(signalTestExpandRow), this)) + , m_eSortType(GTK_SORT_ASCENDING) { - GList *pColumns = gtk_tree_view_get_columns(m_pTreeView); - int nIndex(0); - for (GList* pEntry = g_list_first(pColumns); pEntry; pEntry = g_list_next(pEntry)) + m_pColumns = gtk_tree_view_get_columns(m_pTreeView); + int nIndex(0), nHeader(0); + for (GList* pEntry = g_list_first(m_pColumns); pEntry; pEntry = g_list_next(pEntry)) { GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data); + m_aColumnSignalIds.push_back(g_signal_connect(pColumn, "clicked", G_CALLBACK(signalColumnClicked), this)); GList *pRenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(pColumn)); for (GList* pRenderer = g_list_first(pRenderers); pRenderer; pRenderer = g_list_next(pRenderer)) { GtkCellRenderer* pCellRenderer = GTK_CELL_RENDERER(pRenderer->data); if (m_nTextCol == -1 && GTK_IS_CELL_RENDERER_TEXT(pCellRenderer)) + { m_nTextCol = nIndex; + m_nTextColHeader = nHeader; + } else if (GTK_IS_CELL_RENDERER_TOGGLE(pCellRenderer)) { g_object_set_data(G_OBJECT(pCellRenderer), "g-lo-CellIndex", reinterpret_cast<gpointer>(nIndex)); @@ -5183,8 +5214,8 @@ public: ++nIndex; } g_list_free(pRenderers); + ++nHeader; } - g_list_free(pColumns); m_nIdCol = nIndex++; for (auto& a : m_aToggleVisMap) { @@ -5194,8 +5225,7 @@ public: virtual void set_column_fixed_widths(const std::vector<int>& rWidths) override { - GList *pColumns = gtk_tree_view_get_columns(m_pTreeView); - GList* pEntry = g_list_first(pColumns); + GList* pEntry = g_list_first(m_pColumns); for (auto nWidth : rWidths) { assert(pEntry && "wrong count"); @@ -5203,27 +5233,22 @@ public: gtk_tree_view_column_set_fixed_width(pColumn, nWidth); pEntry = g_list_next(pEntry); } - g_list_free(pColumns); } virtual OUString get_column_title(int nColumn) const override { - GList *pColumns = gtk_tree_view_get_columns(m_pTreeView); - GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(pColumns, nColumn)); + GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(m_pColumns, nColumn)); assert(pColumn && "wrong count"); const gchar* pTitle = gtk_tree_view_column_get_title(pColumn); OUString sRet = OUString(pTitle, pTitle ? strlen(pTitle) : 0, RTL_TEXTENCODING_UTF8); - g_list_free(pColumns); return sRet; } virtual void set_column_title(int nColumn, const OUString& rTitle) override { - GList *pColumns = gtk_tree_view_get_columns(m_pTreeView); - GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(pColumns, nColumn)); + GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(m_pColumns, nColumn)); assert(pColumn && "wrong count"); gtk_tree_view_column_set_title(pColumn, OUStringToOString(rTitle, RTL_TEXTENCODING_UTF8).getStr()); - g_list_free(pColumns); } virtual void insert(weld::TreeIter* pParent, int pos, const OUString* pText, const OUString* pId, const OUString* pIconName, @@ -5310,9 +5335,23 @@ public: m_xSorter.reset(new comphelper::string::NaturalStringSorter( ::comphelper::getProcessComponentContext(), Application::GetSettings().GetUILanguageTag().getLocale())); + set_sort_order(true); + } + + virtual void set_sort_order(bool bAscending) override + { + m_eSortType = bAscending ? GTK_SORT_ASCENDING : GTK_SORT_DESCENDING; GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeStore); - gtk_tree_sortable_set_sort_column_id(pSortable, m_nTextCol, GTK_SORT_ASCENDING); - gtk_tree_sortable_set_sort_func(pSortable, m_nTextCol, sort_func, m_xSorter.get(), nullptr); + gtk_tree_sortable_set_sort_column_id(pSortable, m_nTextCol, m_eSortType); + GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(m_pColumns, m_nTextColHeader)); + assert(pColumn && "wrong count"); + if (gtk_tree_view_column_get_sort_indicator(pColumn)) + gtk_tree_view_column_set_sort_order(pColumn, m_eSortType); + } + + virtual bool get_sort_order() const override + { + return m_eSortType == GTK_SORT_ASCENDING; } virtual int n_children() const override @@ -5681,7 +5720,7 @@ public: if (m_xSorter) { GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeStore); - gtk_tree_sortable_set_sort_column_id(pSortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING); + gtk_tree_sortable_set_sort_column_id(pSortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, m_eSortType); } enable_notify_events(); } @@ -5692,7 +5731,7 @@ public: if (m_xSorter) { GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeStore); - gtk_tree_sortable_set_sort_column_id(pSortable, m_nTextCol, GTK_SORT_ASCENDING); + gtk_tree_sortable_set_sort_column_id(pSortable, m_nTextCol, m_eSortType); } gtk_tree_view_set_model(m_pTreeView, GTK_TREE_MODEL(m_pTreeStore)); GtkInstanceContainer::thaw(); @@ -5703,8 +5742,7 @@ public: virtual int get_height_rows(int nRows) const override { gint nMaxRowHeight = 0; - GList *pColumns = gtk_tree_view_get_columns(m_pTreeView); - for (GList* pEntry = g_list_first(pColumns); pEntry; pEntry = g_list_next(pEntry)) + for (GList* pEntry = g_list_first(m_pColumns); pEntry; pEntry = g_list_next(pEntry)) { GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data); GList *pRenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(pColumn)); @@ -5714,7 +5752,6 @@ public: nMaxRowHeight = std::max(nMaxRowHeight, nRowHeight); g_list_free(pRenderers); } - g_list_free(pColumns); gint nVerticalSeparator; gtk_widget_style_get(GTK_WIDGET(m_pTreeView), "vertical-separator", &nVerticalSeparator, nullptr); @@ -5807,6 +5844,14 @@ public: g_signal_handler_disconnect(m_pTreeView, m_nTestExpandRowSignalId); g_signal_handler_disconnect(m_pTreeView, m_nRowActivatedSignalId); g_signal_handler_disconnect(gtk_tree_view_get_selection(m_pTreeView), m_nChangedSignalId); + + for (GList* pEntry = g_list_last(m_pColumns); pEntry; pEntry = g_list_previous(pEntry)) + { + GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data); + g_signal_handler_disconnect(pColumn, m_aColumnSignalIds.back()); + m_aColumnSignalIds.pop_back(); + } + g_list_free(m_pColumns); } }; |