[Libreoffice-commits] core.git: cui/source cui/uiconfig include/vcl vcl/source vcl/unx

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Tue Feb 5 21:43:26 UTC 2019


 cui/source/options/optinet2.cxx              |    4 
 cui/source/options/webconninfo.cxx           |  189 +++++++--------------------
 cui/source/options/webconninfo.hxx           |   44 ++----
 cui/uiconfig/ui/storedwebconnectiondialog.ui |  100 ++++++++------
 include/vcl/weld.hxx                         |    5 
 vcl/source/app/salvtables.cxx                |   42 +++++-
 vcl/source/window/builder.cxx                |   32 ++++
 vcl/unx/gtk3/gtk3gtkinst.cxx                 |   85 +++++++++---
 8 files changed, 270 insertions(+), 231 deletions(-)

New commits:
commit 29a66fe8cde3e18bf4d1c3d7a1f2077ea54548be
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Tue Feb 5 15:35:35 2019 +0000
Commit:     Caolán McNamara <caolanm at redhat.com>
CommitDate: Tue Feb 5 22:43:05 2019 +0100

    weld WebConnectionInfoDialog
    
    Change-Id: Idff8a0589075c8b7c774f187f5082fd954251d77
    Reviewed-on: https://gerrit.libreoffice.org/67420
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

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);
     }
 };
 


More information about the Libreoffice-commits mailing list