[Libreoffice-commits] core.git: include/svtools include/vcl sc/inc sc/source sc/uiconfig starmath/source svtools/source vcl/source vcl/unx

Caolán McNamara caolanm at redhat.com
Sat Apr 7 15:47:01 UTC 2018


 include/svtools/inettbc.hxx          |   61 +
 include/vcl/combobox.hxx             |    1 
 include/vcl/edit.hxx                 |    3 
 include/vcl/weld.hxx                 |   11 
 sc/inc/scabstdlg.hxx                 |    2 
 sc/source/ui/attrdlg/scdlgfact.cxx   |   21 
 sc/source/ui/attrdlg/scdlgfact.hxx   |   10 
 sc/source/ui/docshell/arealink.cxx   |    5 
 sc/source/ui/inc/linkarea.hxx        |   47 -
 sc/source/ui/miscdlgs/linkarea.cxx   |  181 ++---
 sc/source/ui/view/cellsh1.cxx        |    2 
 sc/uiconfig/scalc/ui/externaldata.ui |   51 +
 starmath/source/dialog.cxx           |    4 
 svtools/source/control/inettbc.cxx   | 1145 ++++++++++++++++++++++++++++++++---
 vcl/source/app/salvtables.cxx        |   34 -
 vcl/source/control/combobox.cxx      |    3 
 vcl/source/control/edit.cxx          |    8 
 vcl/unx/gtk3/gtk3gtkinst.cxx         |  159 ++++
 18 files changed, 1464 insertions(+), 284 deletions(-)

New commits:
commit c4764345e0d326c7a9d443f5af06f06854806bdc
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Apr 4 14:33:16 2018 +0100

    weld ScLinkedAreaDlg
    
    Change-Id: I427e5abd76f6edfa891c9186d5822173d3fa7f7e
    Reviewed-on: https://gerrit.libreoffice.org/52513
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/include/svtools/inettbc.hxx b/include/svtools/inettbc.hxx
index d2b6707c0a5f..133978045054 100644
--- a/include/svtools/inettbc.hxx
+++ b/include/svtools/inettbc.hxx
@@ -26,7 +26,10 @@
 #include <tools/urlobj.hxx>
 
 #include <vcl/combobox.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/weld.hxx>
 
+class MatchContext_Impl;
 class SvtMatchContext_Impl;
 class SvtURLBox_Impl;
 class SVT_DLLPUBLIC SvtURLBox : public ComboBox
@@ -88,6 +91,64 @@ public:
                                         { return ( !aPlaceHolder.isEmpty() ) && ( aPlaceHolder == sToMatch ); }
 };
 
+class SVT_DLLPUBLIC URLBox
+{
+    friend class MatchContext_Impl;
+    friend class SvtURLBox_Impl;
+
+    Idle                            aChangedIdle;
+    OUString                        aBaseURL;
+    OUString                        aPlaceHolder;
+    rtl::Reference< MatchContext_Impl > pCtx;
+    std::unique_ptr<SvtURLBox_Impl> pImpl;
+    INetProtocol                    eSmartProtocol;
+    bool                            bAutoCompleteMode   : 1;
+    bool                            bOnlyDirectories    : 1;
+    bool                            bHistoryDisabled    : 1;
+
+    std::unique_ptr<weld::ComboBoxText> m_xWidget;
+
+    SVT_DLLPRIVATE bool             ProcessKey( const vcl::KeyCode& rCode );
+    DECL_DLLPRIVATE_LINK(           TryAutoComplete, Timer*, void);
+    SVT_DLLPRIVATE void             UpdatePicklistForSmartProtocol_Impl();
+    DECL_DLLPRIVATE_LINK(           ChangedHdl, weld::ComboBoxText&, void);
+    DECL_DLLPRIVATE_LINK(           FocusInHdl, weld::Widget&, void);
+    DECL_DLLPRIVATE_LINK(           FocusOutHdl, weld::Widget&, void);
+    SVT_DLLPRIVATE void             Init();
+
+public:
+    URLBox(weld::ComboBoxText* pWidget);
+    ~URLBox();
+
+    void                            SetText(const OUString& rStr) { m_xWidget->set_entry_text(rStr); }
+    void                            Clear() { m_xWidget->clear(); }
+    void connect_entry_activate(const Link<weld::ComboBoxText&, void>& rLink) { m_xWidget->connect_entry_activate(rLink); }
+    void                            append_text(const OUString& rStr) { m_xWidget->append_text(rStr); }
+    OUString                        get_text(int nIndex) { return m_xWidget->get_text(nIndex); }
+    void select_entry_region(int nStartPos, int nEndPos) { m_xWidget->select_entry_region(nStartPos, nEndPos); }
+    void                            EnableAutocomplete() { m_xWidget->set_entry_completion(true); }
+
+    void                            SetBaseURL( const OUString& rURL );
+    const OUString&                 GetBaseURL() const { return aBaseURL; }
+    void                            SetOnlyDirectories( bool bDir );
+    INetProtocol                    GetSmartProtocol() const { return eSmartProtocol; }
+    void                            SetSmartProtocol( INetProtocol eProt );
+    OUString                        GetURL();
+    void                            DisableHistory();
+
+    void                            UpdatePickList( );
+
+    static OUString                 ParseSmart( const OUString& aText, const OUString& aBaseURL );
+
+    void                            SetFilter(const OUString& _sFilter);
+
+    void                            SetPlaceHolder( const OUString& sPlaceHolder )
+                                        { aPlaceHolder = sPlaceHolder; }
+    const OUString&                 GetPlaceHolder() { return aPlaceHolder; }
+    bool                            MatchesPlaceHolder( const OUString& sToMatch ) const
+                                        { return ( !aPlaceHolder.isEmpty() ) && ( aPlaceHolder == sToMatch ); }
+};
+
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/vcl/combobox.hxx b/include/vcl/combobox.hxx
index ddfe65186a18..2f7efd3e006e 100644
--- a/include/vcl/combobox.hxx
+++ b/include/vcl/combobox.hxx
@@ -121,6 +121,7 @@ public:
     const Link<ComboBox&,void>&   GetSelectHdl() const;
     void            SetDoubleClickHdl(const Link<ComboBox&,void>& rLink);
     const Link<ComboBox&,void>&   GetDoubleClickHdl() const;
+    void            SetEntryActivateHdl(const Link<Edit&,void>& rLink);
 
     Size            CalcMinimumSize() const override;
     virtual Size    GetOptimalSize() const override;
diff --git a/include/vcl/edit.hxx b/include/vcl/edit.hxx
index d4a9b418c7ab..c55a19eb02c0 100644
--- a/include/vcl/edit.hxx
+++ b/include/vcl/edit.hxx
@@ -97,6 +97,7 @@ private:
     Link<Edit&,void>    maModifyHdl;
     Link<Edit&,void>    maUpdateDataHdl;
     Link<Edit&,void>    maAutocompleteHdl;
+    Link<Edit&,void>    maActivateHdl;
     std::unique_ptr<VclBuilder> mpUIBuilder;
 
     css::uno::Reference<css::i18n::XExtendedInputSequenceChecker> mxISC;
@@ -237,6 +238,8 @@ public:
     virtual const Link<Edit&,void>& GetModifyHdl() const { return maModifyHdl; }
     virtual void        SetUpdateDataHdl( const Link<Edit&,void>& rLink ) { maUpdateDataHdl = rLink; }
 
+    void                SetActivateHdl(const Link<Edit&,void>& rLink) { maActivateHdl = rLink; }
+
     void                SetSubEdit( Edit* pEdit );
     Edit*               GetSubEdit() const { return mpSubEdit; }
 
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 52f247921289..33efcd3e0e41 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -197,6 +197,7 @@ private:
 
 protected:
     Link<ComboBoxText&, void> m_aChangeHdl;
+    Link<ComboBoxText&, void> m_aEntryActivateHdl;
 
     void signal_changed() { m_aChangeHdl.Call(*this); }
 
@@ -227,8 +228,12 @@ public:
     virtual void set_entry_text(const OUString& rStr) = 0;
     virtual void select_entry_region(int nStartPos, int nEndPos) = 0;
     virtual bool get_entry_selection_bounds(int& rStartPos, int& rEndPos) = 0;
+    virtual void set_entry_completion(bool bEnable) = 0;
 
-    virtual void unset_entry_completion() = 0;
+    void connect_entry_activate(const Link<ComboBoxText&, void>& rLink)
+    {
+        m_aEntryActivateHdl = rLink;
+    }
 
     void save_value() { m_sSavedValue = get_active_text(); }
 
@@ -262,6 +267,7 @@ public:
     virtual void set_top_entry(int pos) = 0;
     virtual void clear() = 0;
     virtual OUString get_selected() const = 0;
+    virtual std::vector<OUString> get_selected_rows() const = 0;
     OUString get_selected_id() const { return get_id(get_selected_index()); }
     virtual int get_selected_index() const = 0;
     virtual OUString get(int pos) const = 0;
@@ -271,6 +277,9 @@ public:
     virtual void freeze() = 0;
     virtual void thaw() = 0;
 
+    virtual void set_selection_mode(bool bMultiple) = 0;
+    virtual int count_selected_rows() const = 0;
+
     void connect_changed(const Link<TreeView&, void>& rLink) { m_aChangeHdl = rLink; }
 
     void connect_row_activated(const Link<TreeView&, void>& rLink) { m_aRowActivatedHdl = rLink; }
diff --git a/sc/inc/scabstdlg.hxx b/sc/inc/scabstdlg.hxx
index d90cc4ed9810..ccdd419f2a69 100644
--- a/sc/inc/scabstdlg.hxx
+++ b/sc/inc/scabstdlg.hxx
@@ -454,7 +454,7 @@ public:
 
     virtual VclPtr<AbstractScSelEntryDlg > CreateScSelEntryDlg ( vcl::Window* pParent,
                                                           const std::vector<OUString> &rEntryList ) = 0;
-    virtual VclPtr<AbstractScLinkedAreaDlg> CreateScLinkedAreaDlg(vcl::Window* pParent) = 0;
+    virtual VclPtr<AbstractScLinkedAreaDlg> CreateScLinkedAreaDlg(weld::Window* pParent) = 0;
 
     virtual VclPtr<AbstractScMetricInputDlg> CreateScMetricInputDlg ( vcl::Window*        pParent,
                                                                 const OString&  sDialogName,
diff --git a/sc/source/ui/attrdlg/scdlgfact.cxx b/sc/source/ui/attrdlg/scdlgfact.cxx
index b263ca09cc94..101ad4c56d96 100644
--- a/sc/source/ui/attrdlg/scdlgfact.cxx
+++ b/sc/source/ui/attrdlg/scdlgfact.cxx
@@ -115,7 +115,7 @@ AbstractScLinkedAreaDlg_Impl::~AbstractScLinkedAreaDlg_Impl()
 }
 short AbstractScLinkedAreaDlg_Impl::Execute()
 {
-    return pDlg->Execute();
+    return m_xDlg->run();
 }
 
 void ScAbstractTabDialog_Impl::SetCurPageId( sal_uInt16 nId )
@@ -393,32 +393,32 @@ void AbstractScLinkedAreaDlg_Impl::InitFromOldLink( const OUString& rFile, const
                                         const OUString& rOptions, const OUString& rSource,
                                         sal_uLong nRefresh )
 {
-    pDlg->InitFromOldLink( rFile, rFilter, rOptions, rSource, nRefresh);
+    m_xDlg->InitFromOldLink( rFile, rFilter, rOptions, rSource, nRefresh);
 }
 
 OUString  AbstractScLinkedAreaDlg_Impl::GetURL()
 {
-    return pDlg->GetURL();
+    return m_xDlg->GetURL();
 }
 
 OUString  AbstractScLinkedAreaDlg_Impl::GetFilter()
 {
-    return pDlg->GetFilter();
+    return m_xDlg->GetFilter();
 }
 
 OUString  AbstractScLinkedAreaDlg_Impl::GetOptions()
 {
-    return pDlg->GetOptions();
+    return m_xDlg->GetOptions();
 }
 
 OUString  AbstractScLinkedAreaDlg_Impl::GetSource()
 {
-    return pDlg->GetSource();
+    return m_xDlg->GetSource();
 }
 
-sal_uLong   AbstractScLinkedAreaDlg_Impl::GetRefresh()
+sal_uLong AbstractScLinkedAreaDlg_Impl::GetRefresh()
 {
-    return pDlg->GetRefresh();
+    return m_xDlg->GetRefresh();
 }
 
 ScConditionalFormatList* AbstractScCondFormatManagerDlg_Impl::GetConditionalFormatList()
@@ -742,10 +742,9 @@ VclPtr<AbstractScSelEntryDlg> ScAbstractDialogFactory_Impl::CreateScSelEntryDlg
     return VclPtr<AbstractScSelEntryDlg_Impl>::Create( pDlg );
 }
 
-VclPtr<AbstractScLinkedAreaDlg> ScAbstractDialogFactory_Impl::CreateScLinkedAreaDlg(vcl::Window* pParent)
+VclPtr<AbstractScLinkedAreaDlg> ScAbstractDialogFactory_Impl::CreateScLinkedAreaDlg(weld::Window* pParent)
 {
-    VclPtr<ScLinkedAreaDlg> pDlg = VclPtr<ScLinkedAreaDlg>::Create( pParent );
-    return VclPtr<AbstractScLinkedAreaDlg_Impl>::Create( pDlg );
+    return VclPtr<AbstractScLinkedAreaDlg_Impl>::Create(new ScLinkedAreaDlg(pParent));
 }
 
 VclPtr<AbstractScMetricInputDlg> ScAbstractDialogFactory_Impl::CreateScMetricInputDlg (  vcl::Window*      pParent,
diff --git a/sc/source/ui/attrdlg/scdlgfact.hxx b/sc/source/ui/attrdlg/scdlgfact.hxx
index 33d471fec7af..86cf786de353 100644
--- a/sc/source/ui/attrdlg/scdlgfact.hxx
+++ b/sc/source/ui/attrdlg/scdlgfact.hxx
@@ -240,10 +240,12 @@ class AbstractScSelEntryDlg_Impl : public AbstractScSelEntryDlg
 
 class AbstractScLinkedAreaDlg_Impl : public AbstractScLinkedAreaDlg
 {
-    ScopedVclPtr<ScLinkedAreaDlg> pDlg;
+    std::unique_ptr<ScLinkedAreaDlg> m_xDlg;
 public:
-    explicit                AbstractScLinkedAreaDlg_Impl( ScLinkedAreaDlg* p)
-                              : pDlg(p) {}
+    explicit AbstractScLinkedAreaDlg_Impl(ScLinkedAreaDlg* p)
+        : m_xDlg(p)
+    {
+    }
     virtual                 ~AbstractScLinkedAreaDlg_Impl() override;
     virtual short           Execute() override;
     virtual void            InitFromOldLink( const OUString& rFile, const OUString& rFilter,
@@ -459,7 +461,7 @@ public:
     virtual VclPtr<AbstractScSelEntryDlg> CreateScSelEntryDlg ( vcl::Window* pParent,
                                                           const std::vector<OUString> &rEntryList ) override;
 
-    virtual VclPtr<AbstractScLinkedAreaDlg> CreateScLinkedAreaDlg(vcl::Window* pParent) override;
+    virtual VclPtr<AbstractScLinkedAreaDlg> CreateScLinkedAreaDlg(weld::Window* pParent) override;
 
     virtual VclPtr<AbstractScMetricInputDlg> CreateScMetricInputDlg (  vcl::Window*        pParent,
                                                                 const OString&  sDialogName,
diff --git a/sc/source/ui/docshell/arealink.cxx b/sc/source/ui/docshell/arealink.cxx
index 8a75234cc686..c1def55db4d3 100644
--- a/sc/source/ui/docshell/arealink.cxx
+++ b/sc/source/ui/docshell/arealink.cxx
@@ -73,14 +73,13 @@ ScAreaLink::~ScAreaLink()
     StopRefreshTimer();
 }
 
-void ScAreaLink::Edit(weld::Window*, const Link<SvBaseLink&,void>& /* rEndEditHdl */ )
+void ScAreaLink::Edit(weld::Window* pParent, const Link<SvBaseLink&,void>& /* rEndEditHdl */ )
 {
     //  use own dialog instead of SvBaseLink::Edit...
     ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
     OSL_ENSURE(pFact, "ScAbstractFactory create fail!");
 
-//TODO    ScopedVclPtr<AbstractScLinkedAreaDlg> pDlg(pFact->CreateScLinkedAreaDlg(pParent));
-    ScopedVclPtr<AbstractScLinkedAreaDlg> pDlg(pFact->CreateScLinkedAreaDlg(nullptr));
+    ScopedVclPtr<AbstractScLinkedAreaDlg> pDlg(pFact->CreateScLinkedAreaDlg(pParent));
     OSL_ENSURE(pDlg, "Dialog create fail!");
     pDlg->InitFromOldLink( aFileName, aFilterName, aOptions, aSourceArea, GetRefreshDelay() );
     if ( pDlg->Execute() == RET_OK )
diff --git a/sc/source/ui/inc/linkarea.hxx b/sc/source/ui/inc/linkarea.hxx
index e0fef1f20f9e..564568419d30 100644
--- a/sc/source/ui/inc/linkarea.hxx
+++ b/sc/source/ui/inc/linkarea.hxx
@@ -20,12 +20,7 @@
 #ifndef INCLUDED_SC_SOURCE_UI_INC_LINKAREA_HXX
 #define INCLUDED_SC_SOURCE_UI_INC_LINKAREA_HXX
 
-#include <vcl/dialog.hxx>
-
-#include <vcl/button.hxx>
-#include <vcl/field.hxx>
-#include <vcl/fixed.hxx>
-#include <vcl/lstbox.hxx>
+#include <vcl/weld.hxx>
 #include <sfx2/objsh.hxx>
 #include <svtools/inettbc.hxx>
 
@@ -34,27 +29,26 @@ namespace sfx2 { class FileDialogHelper; }
 
 class ScDocShell;
 
-class ScLinkedAreaDlg : public ModalDialog
+class ScLinkedAreaDlg : public weld::GenericDialogController
 {
 private:
-    VclPtr<SvtURLBox>    m_pCbUrl;
-    VclPtr<PushButton>   m_pBtnBrowse;
-    VclPtr<ListBox>      m_pLbRanges;
-    VclPtr<CheckBox>     m_pBtnReload;
-    VclPtr<NumericField> m_pNfDelay;
-    VclPtr<FixedText>    m_pFtSeconds;
-    VclPtr<OKButton>     m_pBtnOk;
-
-    ScDocShell*             pSourceShell;
-    std::unique_ptr<sfx2::DocumentInserter> pDocInserter;
-
+    ScDocShell*             m_pSourceShell;
+    std::unique_ptr<sfx2::DocumentInserter> m_xDocInserter;
     SfxObjectShellRef   aSourceRef;
 
-    DECL_LINK(FileHdl, ComboBox&, void);
-    DECL_LINK(BrowseHdl, Button*, void);
-    DECL_LINK(RangeHdl, ListBox&, void);
-    DECL_LINK(ReloadHdl, Button*, void);
-    DECL_LINK( DialogClosedHdl, sfx2::FileDialogHelper*, void );
+    std::unique_ptr<URLBox> m_xCbUrl;
+    std::unique_ptr<weld::Button> m_xBtnBrowse;
+    std::unique_ptr<weld::TreeView> m_xLbRanges;
+    std::unique_ptr<weld::CheckButton> m_xBtnReload;
+    std::unique_ptr<weld::SpinButton> m_xNfDelay;
+    std::unique_ptr<weld::Label> m_xFtSeconds;
+    std::unique_ptr<weld::Button> m_xBtnOk;
+
+    DECL_LINK(FileHdl, weld::ComboBoxText&, void);
+    DECL_LINK(BrowseHdl, weld::Button&, void);
+    DECL_LINK(RangeHdl, weld::TreeView&, void);
+    DECL_LINK(ReloadHdl, weld::Button&, void);
+    DECL_LINK(DialogClosedHdl, sfx2::FileDialogHelper*, void);
 
     void                UpdateSourceRanges();
     void                UpdateEnable();
@@ -62,9 +56,8 @@ private:
                                         const OUString& rOptions );
 
 public:
-            ScLinkedAreaDlg( vcl::Window* pParent );
-            virtual ~ScLinkedAreaDlg() override;
-    virtual void dispose() override;
+    ScLinkedAreaDlg(weld::Window* pParent);
+    virtual ~ScLinkedAreaDlg() override;
 
     void            InitFromOldLink( const OUString& rFile, const OUString& rFilter,
                                         const OUString& rOptions, const OUString& rSource,
@@ -74,7 +67,7 @@ public:
     OUString       GetFilter();        // may be empty
     OUString       GetOptions();       // filter options
     OUString       GetSource();        // separated by ";"
-    sal_uLong           GetRefresh();       // 0 if disabled
+    sal_uLong      GetRefresh();       // 0 if disabled
 };
 
 #endif
diff --git a/sc/source/ui/miscdlgs/linkarea.cxx b/sc/source/ui/miscdlgs/linkarea.cxx
index 257f07f24747..96cfee9ab2dc 100644
--- a/sc/source/ui/miscdlgs/linkarea.cxx
+++ b/sc/source/ui/miscdlgs/linkarea.cxx
@@ -37,62 +37,47 @@
 #include <docsh.hxx>
 #include <tablink.hxx>
 
-ScLinkedAreaDlg::ScLinkedAreaDlg(vcl::Window* pParent)
-    : ModalDialog(pParent, "ExternalDataDialog", "modules/scalc/ui/externaldata.ui")
-    , pSourceShell(nullptr)
-    , pDocInserter(nullptr)
-
+ScLinkedAreaDlg::ScLinkedAreaDlg(weld::Window* pParent)
+    : GenericDialogController(pParent, "modules/scalc/ui/externaldata.ui", "ExternalDataDialog")
+    , m_pSourceShell(nullptr)
+    , m_xCbUrl(new URLBox(m_xBuilder->weld_combo_box_text("url")))
+    , m_xBtnBrowse(m_xBuilder->weld_button("browse"))
+    , m_xLbRanges(m_xBuilder->weld_tree_view("ranges"))
+    , m_xBtnReload(m_xBuilder->weld_check_button("reload"))
+    , m_xNfDelay(m_xBuilder->weld_spin_button("delay"))
+    , m_xFtSeconds(m_xBuilder->weld_label("secondsft"))
+    , m_xBtnOk(m_xBuilder->weld_button("ok"))
 {
-    get(m_pCbUrl, "url");
-    get(m_pLbRanges, "ranges");
-    m_pLbRanges->EnableMultiSelection(true);
-    m_pLbRanges->SetDropDownLineCount(8);
-    get(m_pBtnBrowse, "browse");
-    get(m_pBtnReload, "reload");
-    get(m_pNfDelay, "delay");
-    get(m_pFtSeconds, "secondsft");
-    get(m_pBtnOk, "ok");
-
-    m_pCbUrl->SetSelectHdl( LINK( this, ScLinkedAreaDlg, FileHdl ) );
-    m_pBtnBrowse->SetClickHdl( LINK( this, ScLinkedAreaDlg, BrowseHdl ) );
-    m_pLbRanges->SetSelectHdl( LINK( this, ScLinkedAreaDlg, RangeHdl ) );
-    m_pBtnReload->SetClickHdl( LINK( this, ScLinkedAreaDlg, ReloadHdl ) );
+    m_xLbRanges->set_selection_mode(true);
+
+    m_xCbUrl->connect_entry_activate(LINK( this, ScLinkedAreaDlg, FileHdl));
+    m_xBtnBrowse->connect_clicked(LINK( this, ScLinkedAreaDlg, BrowseHdl));
+    m_xLbRanges->connect_changed(LINK( this, ScLinkedAreaDlg, RangeHdl));
+    m_xLbRanges->set_size_request(m_xLbRanges->get_approximate_digit_width() * 54,
+                                  m_xLbRanges->get_height_rows(5));
+    m_xBtnReload->connect_clicked(LINK( this, ScLinkedAreaDlg, ReloadHdl));
     UpdateEnable();
 }
 
 ScLinkedAreaDlg::~ScLinkedAreaDlg()
 {
-    disposeOnce();
-}
-
-void ScLinkedAreaDlg::dispose()
-{
-    // pSourceShell is deleted by aSourceRef
-    m_pCbUrl.clear();
-    m_pBtnBrowse.clear();
-    m_pLbRanges.clear();
-    m_pBtnReload.clear();
-    m_pNfDelay.clear();
-    m_pFtSeconds.clear();
-    m_pBtnOk.clear();
-    ModalDialog::dispose();
 }
 
 #define FILTERNAME_HTML  "HTML (StarCalc)"
 #define FILTERNAME_QUERY "calc_HTML_WebQuery"
 
-IMPL_LINK_NOARG(ScLinkedAreaDlg, BrowseHdl, Button*, void)
+IMPL_LINK_NOARG(ScLinkedAreaDlg, BrowseHdl, weld::Button&, void)
 {
-    pDocInserter.reset( new sfx2::DocumentInserter(GetFrameWeld(), ScDocShell::Factory().GetFactoryName()) );
-    pDocInserter->StartExecuteModal( LINK( this, ScLinkedAreaDlg, DialogClosedHdl ) );
+    m_xDocInserter.reset( new sfx2::DocumentInserter(m_xDialog.get(), ScDocShell::Factory().GetFactoryName()) );
+    m_xDocInserter->StartExecuteModal( LINK( this, ScLinkedAreaDlg, DialogClosedHdl ) );
 }
 
-IMPL_LINK_NOARG(ScLinkedAreaDlg, FileHdl, ComboBox&, void)
+IMPL_LINK_NOARG(ScLinkedAreaDlg, FileHdl, weld::ComboBoxText&, void)
 {
-    OUString aEntered = m_pCbUrl->GetURL();
-    if (pSourceShell)
+    OUString aEntered = m_xCbUrl->GetURL();
+    if (m_pSourceShell)
     {
-        SfxMedium* pMed = pSourceShell->GetMedium();
+        SfxMedium* pMed = m_pSourceShell->GetMedium();
         if ( aEntered == pMed->GetName() )
         {
             //  already loaded - nothing to do
@@ -104,7 +89,7 @@ IMPL_LINK_NOARG(ScLinkedAreaDlg, FileHdl, ComboBox&, void)
     OUString aOptions;
     //  get filter name by looking at the file content (bWithContent = true)
     // Break operation if any error occurred inside.
-    if (!ScDocumentLoader::GetFilterName( aEntered, aFilter, aOptions, true, true ))
+    if (!ScDocumentLoader::GetFilterName( aEntered, aFilter, aOptions, true, false ))
         return;
 
     // #i53241# replace HTML filter with DataQuery filter
@@ -119,32 +104,32 @@ IMPL_LINK_NOARG(ScLinkedAreaDlg, FileHdl, ComboBox&, void)
 
 void ScLinkedAreaDlg::LoadDocument( const OUString& rFile, const OUString& rFilter, const OUString& rOptions )
 {
-    if ( pSourceShell )
+    if (m_pSourceShell)
     {
         //  unload old document
-        pSourceShell->DoClose();
-        pSourceShell = nullptr;
+        m_pSourceShell->DoClose();
+        m_pSourceShell = nullptr;
         aSourceRef.clear();
     }
 
     if ( !rFile.isEmpty() )
     {
-        WaitObject aWait( this );
+        weld::WaitObject aWait(m_xDialog.get());
 
         OUString aNewFilter = rFilter;
         OUString aNewOptions = rOptions;
 
         SfxErrorContext aEc( ERRCTX_SFX_OPENDOC, rFile );
 
-        ScDocumentLoader aLoader( rFile, aNewFilter, aNewOptions, 0, GetFrameWeld() );    // with interaction
-        pSourceShell = aLoader.GetDocShell();
-        if ( pSourceShell )
+        ScDocumentLoader aLoader( rFile, aNewFilter, aNewOptions, 0, m_xDialog.get() );    // with interaction
+        m_pSourceShell = aLoader.GetDocShell();
+        if (m_pSourceShell)
         {
-            ErrCode nErr = pSourceShell->GetErrorCode();
+            ErrCode nErr = m_pSourceShell->GetErrorCode();
             if (nErr)
                 ErrorHandler::HandleError( nErr );      // including warnings
 
-            aSourceRef = pSourceShell;
+            aSourceRef = m_pSourceShell;
             aLoader.ReleaseDocRef();    // don't call DoClose in DocLoader dtor
         }
     }
@@ -155,13 +140,13 @@ void ScLinkedAreaDlg::InitFromOldLink( const OUString& rFile, const OUString& rF
                                         sal_uLong nRefresh )
 {
     LoadDocument( rFile, rFilter, rOptions );
-    if (pSourceShell)
+    if (m_pSourceShell)
     {
-        SfxMedium* pMed = pSourceShell->GetMedium();
-        m_pCbUrl->SetText( pMed->GetName() );
+        SfxMedium* pMed = m_pSourceShell->GetMedium();
+        m_xCbUrl->SetText(pMed->GetName());
     }
     else
-        m_pCbUrl->SetText( EMPTY_OUSTRING );
+        m_xCbUrl->SetText(EMPTY_OUSTRING);
 
     UpdateSourceRanges();
 
@@ -169,23 +154,23 @@ void ScLinkedAreaDlg::InitFromOldLink( const OUString& rFile, const OUString& rF
     for ( sal_Int32 i=0; i<nRangeCount; i++ )
     {
         OUString aRange = rSource.getToken(i,';');
-        m_pLbRanges->SelectEntry( aRange );
+        m_xLbRanges->select(aRange);
     }
 
     bool bDoRefresh = (nRefresh != 0);
-    m_pBtnReload->Check( bDoRefresh );
+    m_xBtnReload->set_active(bDoRefresh);
     if (bDoRefresh)
-        m_pNfDelay->SetValue( nRefresh );
+        m_xNfDelay->set_value(nRefresh);
 
     UpdateEnable();
 }
 
-IMPL_LINK_NOARG(ScLinkedAreaDlg, RangeHdl, ListBox&, void)
+IMPL_LINK_NOARG(ScLinkedAreaDlg, RangeHdl, weld::TreeView&, void)
 {
     UpdateEnable();
 }
 
-IMPL_LINK_NOARG(ScLinkedAreaDlg, ReloadHdl, Button*, void)
+IMPL_LINK_NOARG(ScLinkedAreaDlg, ReloadHdl, weld::Button&, void)
 {
     UpdateEnable();
 }
@@ -195,10 +180,10 @@ IMPL_LINK( ScLinkedAreaDlg, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg,
     if ( _pFileDlg->GetError() != ERRCODE_NONE )
         return;
 
-    SfxMedium* pMed = pDocInserter->CreateMedium();
+    SfxMedium* pMed = m_xDocInserter->CreateMedium();
     if ( pMed )
     {
-        WaitObject aWait( this );
+        weld::WaitObject aWait(m_xDialog.get());
 
         // replace HTML filter with DataQuery filter
         const OUString aHTMLFilterName( FILTERNAME_HTML );
@@ -216,30 +201,30 @@ IMPL_LINK( ScLinkedAreaDlg, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg,
         //  ERRCTX_SFX_OPENDOC -> "Error loading document"
         SfxErrorContext aEc( ERRCTX_SFX_OPENDOC, pMed->GetName() );
 
-        if (pSourceShell)
-            pSourceShell->DoClose();        // deleted when assigning aSourceRef
+        if (m_pSourceShell)
+            m_pSourceShell->DoClose();        // deleted when assigning aSourceRef
 
         pMed->UseInteractionHandler( true );    // to enable the filter options dialog
 
-        pSourceShell = new ScDocShell;
-        aSourceRef = pSourceShell;
-        pSourceShell->DoLoad( pMed );
+        m_pSourceShell = new ScDocShell;
+        aSourceRef = m_pSourceShell;
+        m_pSourceShell->DoLoad( pMed );
 
-        ErrCode nErr = pSourceShell->GetErrorCode();
+        ErrCode nErr = m_pSourceShell->GetErrorCode();
         if (nErr)
             ErrorHandler::HandleError( nErr );              // including warnings
 
-        if ( !pSourceShell->GetError() )                    // only errors
+        if (!m_pSourceShell->GetError())                    // only errors
         {
-            m_pCbUrl->SetText( pMed->GetName() );
+            m_xCbUrl->SetText(pMed->GetName());
         }
         else
         {
-            pSourceShell->DoClose();
-            pSourceShell = nullptr;
+            m_pSourceShell->DoClose();
+            m_pSourceShell = nullptr;
             aSourceRef.clear();
 
-            m_pCbUrl->SetText( EMPTY_OUSTRING );
+            m_xCbUrl->SetText(EMPTY_OUSTRING);
         }
     }
 
@@ -252,46 +237,46 @@ IMPL_LINK( ScLinkedAreaDlg, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg,
 
 void ScLinkedAreaDlg::UpdateSourceRanges()
 {
-    m_pLbRanges->SetUpdateMode(false);
+    m_xLbRanges->freeze();
 
-    m_pLbRanges->Clear();
-    if ( pSourceShell )
+    m_xLbRanges->clear();
+    if ( m_pSourceShell )
     {
-        std::shared_ptr<const SfxFilter> pFilter = pSourceShell->GetMedium()->GetFilter();
+        std::shared_ptr<const SfxFilter> pFilter = m_pSourceShell->GetMedium()->GetFilter();
         if (pFilter && pFilter->GetFilterName() == SC_TEXT_CSV_FILTER_NAME)
         {
             // Insert dummy All range to have something selectable.
-            m_pLbRanges->InsertEntry("CSV_all");
+            m_xLbRanges->append_text("CSV_all");
         }
 
-        ScAreaNameIterator aIter( &pSourceShell->GetDocument() );
+        ScAreaNameIterator aIter(&m_pSourceShell->GetDocument());
         ScRange aDummy;
         OUString aName;
         while ( aIter.Next( aName, aDummy ) )
-            m_pLbRanges->InsertEntry( aName );
+            m_xLbRanges->append_text(aName);
     }
 
-    m_pLbRanges->SetUpdateMode(true);
+    m_xLbRanges->thaw();
 
-    if ( m_pLbRanges->GetEntryCount() == 1 )
-        m_pLbRanges->SelectEntryPos(0);
+    if (m_xLbRanges->n_children() == 1)
+        m_xLbRanges->select(0);
 }
 
 void ScLinkedAreaDlg::UpdateEnable()
 {
-    bool bEnable = ( pSourceShell && m_pLbRanges->GetSelectedEntryCount() );
-    m_pBtnOk->Enable( bEnable );
+    bool bEnable = ( m_pSourceShell && m_xLbRanges->count_selected_rows() );
+    m_xBtnOk->set_sensitive(bEnable);
 
-    bool bReload = m_pBtnReload->IsChecked();
-    m_pNfDelay->Enable( bReload );
-    m_pFtSeconds->Enable( bReload );
+    bool bReload = m_xBtnReload->get_active();
+    m_xNfDelay->set_sensitive(bReload);
+    m_xFtSeconds->set_sensitive(bReload);
 }
 
 OUString ScLinkedAreaDlg::GetURL()
 {
-    if (pSourceShell)
+    if (m_pSourceShell)
     {
-        SfxMedium* pMed = pSourceShell->GetMedium();
+        SfxMedium* pMed = m_pSourceShell->GetMedium();
         return pMed->GetName();
     }
     return EMPTY_OUSTRING;
@@ -299,9 +284,9 @@ OUString ScLinkedAreaDlg::GetURL()
 
 OUString ScLinkedAreaDlg::GetFilter()
 {
-    if (pSourceShell)
+    if (m_pSourceShell)
     {
-        SfxMedium* pMed = pSourceShell->GetMedium();
+        SfxMedium* pMed = m_pSourceShell->GetMedium();
         return pMed->GetFilter()->GetFilterName();
     }
     return OUString();
@@ -309,9 +294,9 @@ OUString ScLinkedAreaDlg::GetFilter()
 
 OUString ScLinkedAreaDlg::GetOptions()
 {
-    if (pSourceShell)
+    if (m_pSourceShell)
     {
-        SfxMedium* pMed = pSourceShell->GetMedium();
+        SfxMedium* pMed = m_pSourceShell->GetMedium();
         return ScDocumentLoader::GetOptions( *pMed );
     }
     return OUString();
@@ -320,20 +305,20 @@ OUString ScLinkedAreaDlg::GetOptions()
 OUString ScLinkedAreaDlg::GetSource()
 {
     OUStringBuffer aBuf;
-    const sal_Int32 nCount = m_pLbRanges->GetSelectedEntryCount();
-    for (sal_Int32 i=0; i<nCount; ++i)
+    std::vector<OUString> aSelection = m_xLbRanges->get_selected_rows();
+    for (size_t i = 0; i < aSelection.size(); ++i)
     {
         if (i > 0)
             aBuf.append(';');
-        aBuf.append(m_pLbRanges->GetSelectedEntry(i));
+        aBuf.append(aSelection[i]);
     }
     return aBuf.makeStringAndClear();
 }
 
 sal_uLong ScLinkedAreaDlg::GetRefresh()
 {
-    if ( m_pBtnReload->IsChecked() )
-        return sal::static_int_cast<sal_uLong>( m_pNfDelay->GetValue() );
+    if (m_xBtnReload->get_active())
+        return sal::static_int_cast<sal_uLong>(m_xNfDelay->get_value());
     else
         return 0;   // disabled
 }
diff --git a/sc/source/ui/view/cellsh1.cxx b/sc/source/ui/view/cellsh1.cxx
index 80b3ccf6d888..97892de03912 100644
--- a/sc/source/ui/view/cellsh1.cxx
+++ b/sc/source/ui/view/cellsh1.cxx
@@ -2626,7 +2626,7 @@ void ScCellShell::ExecuteEdit( SfxRequest& rReq )
 
                     pImpl->m_pLinkedDlg.disposeAndClear();
                     pImpl->m_pLinkedDlg =
-                        pFact->CreateScLinkedAreaDlg(pTabViewShell->GetDialogParent());
+                        pFact->CreateScLinkedAreaDlg(pTabViewShell->GetFrameWeld());
                     OSL_ENSURE(pImpl->m_pLinkedDlg, "Dialog create fail!");
                     delete pImpl->m_pRequest;
                     pImpl->m_pRequest = new SfxRequest( rReq );
diff --git a/sc/uiconfig/scalc/ui/externaldata.ui b/sc/uiconfig/scalc/ui/externaldata.ui
index 040213842c3a..449cce77cd7e 100644
--- a/sc/uiconfig/scalc/ui/externaldata.ui
+++ b/sc/uiconfig/scalc/ui/externaldata.ui
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.18.3 -->
+<!-- Generated with glade 3.20.4 -->
 <interface domain="sc">
   <requires lib="gtk+" version="3.18"/>
-  <requires lib="LibreOffice" version="1.0"/>
   <object class="GtkAdjustment" id="adjustment1">
     <property name="lower">1</property>
     <property name="upper">99999</property>
@@ -10,10 +9,21 @@
     <property name="step_increment">1</property>
     <property name="page_increment">10</property>
   </object>
+  <object class="GtkListStore" id="liststore1">
+    <columns>
+      <!-- column-name text -->
+      <column type="gchararray"/>
+      <!-- column-name id -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
   <object class="GtkDialog" id="ExternalDataDialog">
     <property name="can_focus">False</property>
     <property name="border_width">6</property>
     <property name="title" translatable="yes" context="externaldata|ExternalDataDialog">External Data</property>
+    <property name="modal">True</property>
+    <property name="default_width">0</property>
+    <property name="default_height">0</property>
     <property name="type_hint">dialog</property>
     <child internal-child="vbox">
       <object class="GtkBox" id="dialog-vbox1">
@@ -82,6 +92,7 @@
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
             <property name="orientation">vertical</property>
             <property name="spacing">12</property>
             <child>
@@ -112,21 +123,20 @@
                             <property name="hexpand">True</property>
                             <property name="spacing">12</property>
                             <child>
-                              <object class="svtlo-SvtURLBox" id="url">
+                              <object class="GtkComboBoxText" id="url">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
                                 <property name="tooltip_text" translatable="yes" context="externaldata|url|tooltip_text">Enter the URL of the source document in the local file system or Internet here.</property>
-                                <property name="hexpand">True</property>
                                 <property name="has_entry">True</property>
-                                <property name="max_width_chars">48</property>
                                 <child internal-child="entry">
-                                  <object class="GtkEntry" id="URLBox-entry2">
-                                    <property name="can_focus">False</property>
+                                  <object class="GtkEntry">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
                                   </object>
                                 </child>
                               </object>
                               <packing>
-                                <property name="expand">False</property>
+                                <property name="expand">True</property>
                                 <property name="fill">True</property>
                                 <property name="position">0</property>
                               </packing>
@@ -199,21 +209,35 @@
                         <property name="orientation">vertical</property>
                         <property name="spacing">6</property>
                         <child>
-                          <object class="GtkScrolledWindow" id="scrolledwindow1">
+                          <object class="GtkScrolledWindow">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
                             <property name="hexpand">True</property>
                             <property name="vexpand">True</property>
                             <property name="shadow_type">in</property>
                             <child>
-                              <object class="GtkTreeView" id="ranges:border">
+                              <object class="GtkTreeView" id="ranges">
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
-                                <property name="hexpand">True</property>
                                 <property name="vexpand">True</property>
+                                <property name="model">liststore1</property>
+                                <property name="headers_visible">False</property>
+                                <property name="headers_clickable">False</property>
+                                <property name="search_column">0</property>
+                                <property name="show_expanders">False</property>
                                 <child internal-child="selection">
                                   <object class="GtkTreeSelection" id="treeview-selection1"/>
                                 </child>
+                                <child>
+                                  <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+                                    <child>
+                                      <object class="GtkCellRendererText" id="cellrenderertext1"/>
+                                      <attributes>
+                                        <attribute name="text">0</attribute>
+                                      </attributes>
+                                    </child>
+                                  </object>
+                                </child>
                               </object>
                             </child>
                           </object>
@@ -302,9 +326,9 @@
                   <object class="GtkLabel" id="label2">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="xalign">0.47999998927116394</property>
                     <property name="label" translatable="yes" context="externaldata|label2">_Available Tables/Ranges</property>
                     <property name="use_underline">True</property>
+                    <property name="xalign">0.47999998927116394</property>
                     <attributes>
                       <attribute name="weight" value="bold"/>
                     </attributes>
@@ -331,5 +355,8 @@
       <action-widget response="-6">cancel</action-widget>
       <action-widget response="-11">help</action-widget>
     </action-widgets>
+    <child>
+      <placeholder/>
+    </child>
   </object>
 </interface>
diff --git a/starmath/source/dialog.cxx b/starmath/source/dialog.cxx
index 38a4415b652d..176ad2352804 100644
--- a/starmath/source/dialog.cxx
+++ b/starmath/source/dialog.cxx
@@ -1981,8 +1981,8 @@ SmSymDefineDialog::SmSymDefineDialog(weld::Window* pParent, OutputDevice *pFntLi
 {
     // auto completion is troublesome since that symbols character also gets automatically selected in the
     // display and if the user previously selected a character to define/redefine that one this is bad
-    m_xOldSymbols->unset_entry_completion();
-    m_xSymbols->unset_entry_completion();
+    m_xOldSymbols->set_entry_completion(false);
+    m_xSymbols->set_entry_completion(false);
 
     FillFonts();
     if (m_xFonts->get_count() > 0)
diff --git a/svtools/source/control/inettbc.cxx b/svtools/source/control/inettbc.cxx
index 8dab51f2ba1f..a1b3d744748d 100644
--- a/svtools/source/control/inettbc.cxx
+++ b/svtools/source/control/inettbc.cxx
@@ -120,6 +120,39 @@ public:
     void                            Stop();
 };
 
+class MatchContext_Impl: public salhelper::Thread
+{
+    static ::osl::Mutex*            pDirMutex;
+
+    std::vector<OUString>           aPickList;
+    std::vector<OUString>           aCompletions;
+    std::vector<OUString>           aURLs;
+    svtools::AsynchronLink          aLink;
+    OUString                        aBaseURL;
+    OUString                        aText;
+    URLBox*                         pBox;
+    bool                            bOnlyDirectories;
+
+    osl::Mutex mutex_;
+    bool stopped_;
+    css::uno::Reference< css::ucb::XCommandProcessor > processor_;
+    sal_Int32 commandId_;
+
+    DECL_LINK(                Select_Impl, void*, void );
+
+    virtual                         ~MatchContext_Impl() override;
+    virtual void                    execute() override;
+    void                            doExecute();
+    void                            Insert( const OUString& rCompletion, const OUString& rURL, bool bForce = false);
+    void                            ReadFolder( const OUString& rURL, const OUString& rMatch, bool bSmart );
+    static void                     FillPicklist(std::vector<OUString>& rPickList);
+
+public:
+                                    MatchContext_Impl( URLBox* pBoxP, const OUString& rText );
+    void                            Stop();
+};
+
+
 namespace
 {
     struct theSvtMatchContextMutex
@@ -456,126 +489,439 @@ void SvtMatchContext_Impl::ReadFolder( const OUString& rURL,
     }
 }
 
-OUString SvtURLBox::ParseSmart( const OUString& _aText, const OUString& _aBaseURL )
+MatchContext_Impl::MatchContext_Impl(URLBox* pBoxP, const OUString& rText)
+    : Thread( "MatchContext_Impl" )
+    , aLink( LINK( this, MatchContext_Impl, Select_Impl ) )
+    , aBaseURL( pBoxP->aBaseURL )
+    , aText( rText )
+    , pBox( pBoxP )
+    , bOnlyDirectories( pBoxP->bOnlyDirectories )
+    , stopped_(false)
+    , commandId_(0)
 {
-    OUString aMatch;
-    OUString aText = _aText;
-    OUString aBaseURL = _aBaseURL;
+    aLink.CreateMutex();
 
-    // parse ~ for Unix systems
-    // does nothing for Windows
-    if( !SvtURLBox_Impl::TildeParsing( aText, aBaseURL ) )
-        return OUString();
+    FillPicklist( aPickList );
+}
 
-    if( !aBaseURL.isEmpty() )
-    {
-        INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL );
+MatchContext_Impl::~MatchContext_Impl()
+{
+    aLink.ClearPendingCall();
+}
 
-        // if a base URL is set the string may be parsed relative
-        if( aText.startsWith( "/" ) )
-        {
-            // text starting with slashes means absolute file URLs
-            OUString aTemp = INetURLObject::GetScheme( eBaseProt );
+void MatchContext_Impl::FillPicklist(std::vector<OUString>& rPickList)
+{
+    // Read the history of picks
+    Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( ePICKLIST );
+    sal_uInt32 nCount = seqPicklist.getLength();
 
-            // file URL must be correctly encoded!
-            OUString aTextURL = INetURLObject::encode( aText, INetURLObject::PART_FPATH,
-                                                     INetURLObject::EncodeMechanism::All );
-            aTemp += aTextURL;
+    for( sal_uInt32 nItem=0; nItem < nCount; nItem++ )
+    {
+        Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
 
-            INetURLObject aTmp( aTemp );
-            if ( !aTmp.HasError() && aTmp.GetProtocol() != INetProtocol::NotValid )
-                aMatch = aTmp.GetMainURL( INetURLObject::DecodeMechanism::NONE );
-        }
-        else
-        {
-            OUString aSmart( aText );
-            INetURLObject aObj( aBaseURL );
+        OUString sTitle;
+        INetURLObject aURL;
 
-            // HRO: I suppose this hack should only be done for Windows !!!???
-#ifdef _WIN32
-            // HRO: INetURLObject::smatRel2Abs does not recognize '\\' as a relative path
-            //      but in case of "\\\\" INetURLObject is right - this is an absolute path !
+        sal_uInt32 nPropertyCount = seqPropertySet.getLength();
 
-            if( aText.startsWith("\\") && (aText.getLength() < 2 || aText[ 1 ] != '\\') )
+        for( sal_uInt32 nProperty=0; nProperty < nPropertyCount; nProperty++ )
+        {
+            if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_TITLE )
             {
-                // cut to first segment
-                OUString aTmp = INetURLObject::GetScheme( eBaseProt );
-                aTmp += "/";
-                aTmp += aObj.getName( 0, true, INetURLObject::DecodeMechanism::WithCharset );
-                aObj.SetURL( aTmp );
-
-                aSmart = aSmart.copy(1);
+                seqPropertySet[nProperty].Value >>= sTitle;
+                aURL.SetURL( sTitle );
+                rPickList.insert(rPickList.begin() + nItem, aURL.GetMainURL(INetURLObject::DecodeMechanism::WithCharset));
+                break;
             }
-#endif
-            // base URL must be a directory !
-            aObj.setFinalSlash();
-
-            // take base URL and append current input
-            bool bWasAbsolute = false;
-#ifdef UNX
-            // encode file URL correctly
-            aSmart = INetURLObject::encode( aSmart, INetURLObject::PART_FPATH, INetURLObject::EncodeMechanism::All );
-#endif
-            INetURLObject aTmp( aObj.smartRel2Abs( aSmart, bWasAbsolute ) );
-
-            if ( aText.endsWith(".") )
-                // INetURLObject appends a final slash for the directories "." and "..", this is a bug!
-                // Remove it as a workaround
-                aTmp.removeFinalSlash();
-            if ( !aTmp.HasError() && aTmp.GetProtocol() != INetProtocol::NotValid )
-                aMatch = aTmp.GetMainURL( INetURLObject::DecodeMechanism::NONE );
         }
     }
-    else
+}
+
+void MatchContext_Impl::Stop()
+{
+    css::uno::Reference< css::ucb::XCommandProcessor > proc;
+    sal_Int32 id(0);
     {
-        OUString aTmpMatch;
-        osl::FileBase::getFileURLFromSystemPath( aText, aTmpMatch );
-        aMatch = aTmpMatch;
+        osl::MutexGuard g(mutex_);
+        if (!stopped_) {
+            stopped_ = true;
+            proc = processor_;
+            id = commandId_;
+        }
+    }
+    if (proc.is()) {
+        proc->abort(id);
     }
+    terminate();
+}
 
-    return aMatch;
+void MatchContext_Impl::execute( )
+{
+    doExecute();
+    aLink.Call( this );
 }
 
-void SvtMatchContext_Impl::doExecute()
+
+// This method is called via AsynchronLink, so it has the SolarMutex and
+// calling solar code ( VCL ... ) is safe. It is called when the thread is
+// terminated ( finished work or stopped ). Cancelling the thread via
+// Cancellable does not discard the information gained so far, it
+// inserts all collected completions into the listbox.
+
+IMPL_LINK_NOARG( MatchContext_Impl, Select_Impl, void*, void )
 {
-    ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
+    // avoid recursion through cancel button
     {
-        // have we been stopped while we were waiting for the mutex?
         osl::MutexGuard g(mutex_);
         if (stopped_) {
+            // Completion was stopped, no display:
             return;
         }
     }
 
-    // Reset match lists
-    aCompletions.clear();
+    pBox->bAutoCompleteMode = true;
+
+    // insert all completed strings into the listbox
+    pBox->Clear();
+
+    for (auto const& completion : aCompletions)
+    {
+        // convert the file into an URL
+        OUString sURL;
+        osl::FileBase::getFileURLFromSystemPath(completion, sURL);
+            // note: if this doesn't work, we're not interested in: we're checking the
+            // untouched sCompletion then
+
+        if ( !sURL.isEmpty() && !sURL.endsWith("/") )
+        {
+            OUString sUpperURL( sURL.toAsciiUpperCase() );
+
+            if ( ::std::none_of( pBox->pImpl->m_aFilters.begin(),
+                                 pBox->pImpl->m_aFilters.end(),
+                                 FilterMatch( sUpperURL ) ) )
+            {   // this URL is not allowed
+                continue;
+            }
+        }
+
+        pBox->append_text(completion);
+    }
+
+    pBox->EnableAutocomplete();
+
+    // transfer string lists to listbox and forget them
+    pBox->pImpl->aURLs = aURLs;
+    pBox->pImpl->aCompletions = aCompletions;
     aURLs.clear();
+    aCompletions.clear();
 
-    // check for input
-    if ( aText.isEmpty() )
+    // the box has this control as a member so we have to set that member
+    // to zero before deleting ourself.
+    pBox->pCtx.clear();
+}
+
+void MatchContext_Impl::Insert( const OUString& rCompletion,
+                                   const OUString& rURL,
+                                   bool bForce )
+{
+    if( !bForce )
+    {
+        // avoid doubles
+        if(find(aCompletions.begin(), aCompletions.end(), rCompletion) != aCompletions.end())
+            return;
+    }
+
+    aCompletions.push_back(rCompletion);
+    aURLs.push_back(rURL);
+}
+
+
+void MatchContext_Impl::ReadFolder( const OUString& rURL,
+                                       const OUString& rMatch,
+                                       bool bSmart )
+{
+    // check folder to scan
+    if( !UCBContentHelper::IsFolder( rURL ) )
         return;
 
-    if( aText.indexOf( '*' ) != -1 || aText.indexOf( '?' ) != -1 )
-        // no autocompletion for wildcards
+    bool bPureHomePath = false;
+#ifdef UNX
+    bPureHomePath = aText.startsWith( "~" ) && aText.indexOf( '/' ) == -1;
+#endif
+
+    bool bExectMatch = bPureHomePath
+                || aText == "."
+                || aText.endsWith("/.")
+                || aText.endsWith("/..");
+
+    // for pure home paths ( ~username ) the '.' at the end of rMatch
+    // means that it points to root catalog
+    // this is done only for file contents since home paths parsing is useful only for them
+    if ( bPureHomePath && rMatch == "file:///." )
+    {
+        // a home that refers to /
+
+        OUString aNewText( aText );
+        aNewText += "/";
+        Insert( aNewText, rURL, true );
+
         return;
+    }
 
-    OUString aMatch;
-    INetProtocol eProt = INetURLObject::CompareProtocolScheme( aText );
-    INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL );
-    if ( aBaseURL.isEmpty() )
-        eBaseProt = INetURLObject::CompareProtocolScheme( SvtPathOptions().GetWorkPath() );
-    INetProtocol eSmartProt = pBox->GetSmartProtocol();
+    // string to match with
+    INetURLObject aMatchObj( rMatch );
+    OUString aMatchName;
 
-    // if the user input is a valid URL, go on with it
-    // otherwise it could be parsed smart with a predefined smart protocol
-    // ( or if this is not set with the protocol of a predefined base URL )
-    if( eProt == INetProtocol::NotValid || eProt == eSmartProt || (eSmartProt == INetProtocol::NotValid && eProt == eBaseProt) )
+    if ( rURL != aMatchObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) )
     {
-        // not stopped yet ?
-        if( schedule() )
-        {
-            if ( eProt == INetProtocol::NotValid )
-                aMatch = SvtURLBox::ParseSmart( aText, aBaseURL );
+        aMatchName = aMatchObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
+
+        // matching is always done case insensitive, but completion will be case sensitive and case preserving
+        aMatchName = aMatchName.toAsciiLowerCase();
+
+        // if the matchstring ends with a slash, we must search for this also
+        if ( rMatch.endsWith("/") )
+            aMatchName += "/";
+    }
+
+    sal_Int32 nMatchLen = aMatchName.getLength();
+
+    INetURLObject aFolderObj( rURL );
+    DBG_ASSERT( aFolderObj.GetProtocol() != INetProtocol::NotValid, "Invalid URL!" );
+
+    try
+    {
+        Content aCnt( aFolderObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+                      new ::ucbhelper::CommandEnvironment( uno::Reference< XInteractionHandler >(),
+                                                     uno::Reference< XProgressHandler >() ),
+                      comphelper::getProcessComponentContext() );
+        uno::Reference< XResultSet > xResultSet;
+        Sequence< OUString > aProps(2);
+        OUString* pProps = aProps.getArray();
+        pProps[0] = "Title";
+        pProps[1] = "IsFolder";
+
+        try
+        {
+            uno::Reference< XDynamicResultSet > xDynResultSet;
+            ResultSetInclude eInclude = INCLUDE_FOLDERS_AND_DOCUMENTS;
+            if ( bOnlyDirectories )
+                eInclude = INCLUDE_FOLDERS_ONLY;
+
+            xDynResultSet = aCnt.createDynamicCursor( aProps, eInclude );
+
+            uno::Reference < XAnyCompareFactory > xCompare;
+            uno::Reference < XSortedDynamicResultSetFactory > xSRSFac =
+                SortedDynamicResultSetFactory::create( ::comphelper::getProcessComponentContext() );
+
+            Sequence< NumberedSortingInfo > aSortInfo( 2 );
+            NumberedSortingInfo* pInfo = aSortInfo.getArray();
+            pInfo[ 0 ].ColumnIndex = 2;
+            pInfo[ 0 ].Ascending   = false;
+            pInfo[ 1 ].ColumnIndex = 1;
+            pInfo[ 1 ].Ascending   = true;
+
+            uno::Reference< XDynamicResultSet > xDynamicResultSet;
+            xDynamicResultSet =
+                xSRSFac->createSortedDynamicResultSet( xDynResultSet, aSortInfo, xCompare );
+
+            if ( xDynamicResultSet.is() )
+            {
+                xResultSet = xDynamicResultSet->getStaticResultSet();
+            }
+        }
+        catch( css::uno::Exception& ) {}
+
+        if ( xResultSet.is() )
+        {
+            uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
+            uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
+
+            try
+            {
+                while ( schedule() && xResultSet->next() )
+                {
+                    OUString   aURL      = xContentAccess->queryContentIdentifierString();
+                    OUString   aTitle    = xRow->getString(1);
+                    bool   bIsFolder = xRow->getBoolean(2);
+
+                    // matching is always done case insensitive, but completion will be case sensitive and case preserving
+                    aTitle = aTitle.toAsciiLowerCase();
+
+                    if (
+                        !nMatchLen ||
+                        (bExectMatch && aMatchName == aTitle) ||
+                        (!bExectMatch && aTitle.startsWith(aMatchName))
+                       )
+                    {
+                        // all names fit if matchstring is empty
+                        INetURLObject aObj( aURL );
+                        sal_Unicode aDelimiter = '/';
+                        if ( bSmart )
+                            // when parsing is done "smart", the delimiter must be "guessed"
+                            aObj.getFSysPath( static_cast<FSysStyle>(FSysStyle::Detect & ~FSysStyle::Vos), &aDelimiter );
+
+                        if ( bIsFolder )
+                            aObj.setFinalSlash();
+
+                        // get the last name of the URL
+                        OUString aMatch = aObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
+                        OUString aInput( aText );
+                        if ( nMatchLen )
+                        {
+                            if (aText.endsWith(".") || bPureHomePath)
+                            {
+                                // if a "special folder" URL was typed, don't touch the user input
+                                aMatch = aMatch.copy( nMatchLen );
+                            }
+                            else
+                            {
+                                // make the user input case preserving
+                                DBG_ASSERT( aInput.getLength() >= nMatchLen, "Suspicious Matching!" );
+                                aInput = aInput.copy( 0, aInput.getLength() - nMatchLen );
+                            }
+                        }
+
+                        aInput += aMatch;
+
+                        // folders should get a final slash automatically
+                        if ( bIsFolder )
+                            aInput += OUStringLiteral1(aDelimiter);
+
+                        Insert( aInput, aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), true );
+                    }
+                }
+            }
+            catch( css::uno::Exception& )
+            {
+            }
+        }
+    }
+    catch( css::uno::Exception& )
+    {
+    }
+}
+
+OUString SvtURLBox::ParseSmart( const OUString& _aText, const OUString& _aBaseURL )
+{
+    OUString aMatch;
+    OUString aText = _aText;
+    OUString aBaseURL = _aBaseURL;
+
+    // parse ~ for Unix systems
+    // does nothing for Windows
+    if( !SvtURLBox_Impl::TildeParsing( aText, aBaseURL ) )
+        return OUString();
+
+    if( !aBaseURL.isEmpty() )
+    {
+        INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL );
+
+        // if a base URL is set the string may be parsed relative
+        if( aText.startsWith( "/" ) )
+        {
+            // text starting with slashes means absolute file URLs
+            OUString aTemp = INetURLObject::GetScheme( eBaseProt );
+
+            // file URL must be correctly encoded!
+            OUString aTextURL = INetURLObject::encode( aText, INetURLObject::PART_FPATH,
+                                                     INetURLObject::EncodeMechanism::All );
+            aTemp += aTextURL;
+
+            INetURLObject aTmp( aTemp );
+            if ( !aTmp.HasError() && aTmp.GetProtocol() != INetProtocol::NotValid )
+                aMatch = aTmp.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+        }
+        else
+        {
+            OUString aSmart( aText );
+            INetURLObject aObj( aBaseURL );
+
+            // HRO: I suppose this hack should only be done for Windows !!!???
+#ifdef _WIN32
+            // HRO: INetURLObject::smatRel2Abs does not recognize '\\' as a relative path
+            //      but in case of "\\\\" INetURLObject is right - this is an absolute path !
+
+            if( aText.startsWith("\\") && (aText.getLength() < 2 || aText[ 1 ] != '\\') )
+            {
+                // cut to first segment
+                OUString aTmp = INetURLObject::GetScheme( eBaseProt );
+                aTmp += "/";
+                aTmp += aObj.getName( 0, true, INetURLObject::DecodeMechanism::WithCharset );
+                aObj.SetURL( aTmp );
+
+                aSmart = aSmart.copy(1);
+            }
+#endif
+            // base URL must be a directory !
+            aObj.setFinalSlash();
+
+            // take base URL and append current input
+            bool bWasAbsolute = false;
+#ifdef UNX
+            // encode file URL correctly
+            aSmart = INetURLObject::encode( aSmart, INetURLObject::PART_FPATH, INetURLObject::EncodeMechanism::All );
+#endif
+            INetURLObject aTmp( aObj.smartRel2Abs( aSmart, bWasAbsolute ) );
+
+            if ( aText.endsWith(".") )
+                // INetURLObject appends a final slash for the directories "." and "..", this is a bug!
+                // Remove it as a workaround
+                aTmp.removeFinalSlash();
+            if ( !aTmp.HasError() && aTmp.GetProtocol() != INetProtocol::NotValid )
+                aMatch = aTmp.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+        }
+    }
+    else
+    {
+        OUString aTmpMatch;
+        osl::FileBase::getFileURLFromSystemPath( aText, aTmpMatch );
+        aMatch = aTmpMatch;
+    }
+
+    return aMatch;
+}
+
+void SvtMatchContext_Impl::doExecute()
+{
+    ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
+    {
+        // have we been stopped while we were waiting for the mutex?
+        osl::MutexGuard g(mutex_);
+        if (stopped_) {
+            return;
+        }
+    }
+
+    // Reset match lists
+    aCompletions.clear();
+    aURLs.clear();
+
+    // check for input
+    if ( aText.isEmpty() )
+        return;
+
+    if( aText.indexOf( '*' ) != -1 || aText.indexOf( '?' ) != -1 )
+        // no autocompletion for wildcards
+        return;
+
+    OUString aMatch;
+    INetProtocol eProt = INetURLObject::CompareProtocolScheme( aText );
+    INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL );
+    if ( aBaseURL.isEmpty() )
+        eBaseProt = INetURLObject::CompareProtocolScheme( SvtPathOptions().GetWorkPath() );
+    INetProtocol eSmartProt = pBox->GetSmartProtocol();
+
+    // if the user input is a valid URL, go on with it
+    // otherwise it could be parsed smart with a predefined smart protocol
+    // ( or if this is not set with the protocol of a predefined base URL )
+    if( eProt == INetProtocol::NotValid || eProt == eSmartProt || (eSmartProt == INetProtocol::NotValid && eProt == eBaseProt) )
+    {
+        // not stopped yet ?
+        if( schedule() )
+        {
+            if ( eProt == INetProtocol::NotValid )
+                aMatch = SvtURLBox::ParseSmart( aText, aBaseURL );
             else
                 aMatch = aText;
             if ( !aMatch.isEmpty() )
@@ -584,9 +930,9 @@ void SvtMatchContext_Impl::doExecute()
                 OUString aMainURL( aURLObject.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
                 // Disable autocompletion for anything but the (local) file
                 // system (for which access is hopefully fast), as the logic of
-                // how SvtMatchContext_Impl is used requires this code to run to
+                // how MatchContext_Impl is used requires this code to run to
                 // completion before further user input is processed, and even
-                // SvtMatchContext_Impl::Stop does not guarantee a speedy
+                // MatchContext_Impl::Stop does not guarantee a speedy
                 // return:
                 if ( !aMainURL.isEmpty()
                      && aURLObject.GetProtocol() == INetProtocol::File )
@@ -661,7 +1007,7 @@ void SvtMatchContext_Impl::doExecute()
                         }
                     }
                     if ( folder )
-                            Insert( aText, aMatch );
+                        Insert( aText, aMatch );
                     else
                         // otherwise the parent folder will be taken
                         aURLObject.removeSegment();
@@ -781,15 +1127,260 @@ void SvtMatchContext_Impl::doExecute()
     }
 }
 
-void SvtURLBox::TryAutoComplete()
+void MatchContext_Impl::doExecute()
 {
-    if( Application::AnyInput( VclInputFlags::KEYBOARD ) ) return;
-
-    OUString aCurText = GetText();
-    Selection aSelection( GetSelection() );
-    if( aSelection.Max() != aCurText.getLength() )
-        return;
-    sal_uInt16 nLen = static_cast<sal_uInt16>(aSelection.Min());
+    ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
+    {
+        // have we been stopped while we were waiting for the mutex?
+        osl::MutexGuard g(mutex_);
+        if (stopped_) {
+            return;
+        }
+    }
+
+    // Reset match lists
+    aCompletions.clear();
+    aURLs.clear();
+
+    // check for input
+    if ( aText.isEmpty() )
+        return;
+
+    if( aText.indexOf( '*' ) != -1 || aText.indexOf( '?' ) != -1 )
+        // no autocompletion for wildcards
+        return;
+
+    OUString aMatch;
+    INetProtocol eProt = INetURLObject::CompareProtocolScheme( aText );
+    INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL );
+    if ( aBaseURL.isEmpty() )
+        eBaseProt = INetURLObject::CompareProtocolScheme( SvtPathOptions().GetWorkPath() );
+    INetProtocol eSmartProt = pBox->GetSmartProtocol();
+
+    // if the user input is a valid URL, go on with it
+    // otherwise it could be parsed smart with a predefined smart protocol
+    // ( or if this is not set with the protocol of a predefined base URL )
+    if( eProt == INetProtocol::NotValid || eProt == eSmartProt || (eSmartProt == INetProtocol::NotValid && eProt == eBaseProt) )
+    {
+        // not stopped yet ?
+        if( schedule() )
+        {
+            if ( eProt == INetProtocol::NotValid )
+                aMatch = SvtURLBox::ParseSmart( aText, aBaseURL );
+            else
+                aMatch = aText;
+            if ( !aMatch.isEmpty() )
+            {
+                INetURLObject aURLObject( aMatch );
+                OUString aMainURL( aURLObject.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+                // Disable autocompletion for anything but the (local) file
+                // system (for which access is hopefully fast), as the logic of
+                // how MatchContext_Impl is used requires this code to run to
+                // completion before further user input is processed, and even
+                // MatchContext_Impl::Stop does not guarantee a speedy
+                // return:
+                if ( !aMainURL.isEmpty()
+                     && aURLObject.GetProtocol() == INetProtocol::File )
+                {
+                    // if text input is a directory, it must be part of the match list! Until then it is scanned
+                    bool folder = false;
+                    if (aURLObject.hasFinalSlash()) {
+                        try {
+                            css::uno::Reference< css::uno::XComponentContext >
+                                ctx(comphelper::getProcessComponentContext());
+                            css::uno::Reference<
+                                css::ucb::XUniversalContentBroker > ucb(
+                                    css::ucb::UniversalContentBroker::create(
+                                        ctx));
+                            css::uno::Sequence< css::beans::Property > prop(1);
+                            prop[0].Name = "IsFolder";
+                            prop[0].Handle = -1;
+                            prop[0].Type = cppu::UnoType< bool >::get();
+                            css::uno::Any res;
+                            css::uno::Reference< css::ucb::XCommandProcessor >
+                                proc(
+                                    ucb->queryContent(
+                                        ucb->createContentIdentifier(aMainURL)),
+                                    css::uno::UNO_QUERY_THROW);
+                            css::uno::Reference< css::ucb::XCommandProcessor2 >
+                                proc2(proc, css::uno::UNO_QUERY);
+                            sal_Int32 id = proc->createCommandIdentifier();
+                            try {
+                                {
+                                    osl::MutexGuard g(mutex_);
+                                    processor_ = proc;
+                                    commandId_ = id;
+                                }
+                                res = proc->execute(
+                                    css::ucb::Command(
+                                        "getPropertyValues", -1,
+                                        css::uno::makeAny(prop)),
+                                    id,
+                                    css::uno::Reference<
+                                        css::ucb::XCommandEnvironment >());
+                            } catch (...) {
+                                if (proc2.is()) {
+                                    try {
+                                        proc2->releaseCommandIdentifier(id);
+                                    } catch (css::uno::RuntimeException & e) {
+                                        SAL_WARN("svtools.control", "ignoring " << e);
+                                    }
+                                }
+                                throw;
+                            }
+                            if (proc2.is()) {
+                                proc2->releaseCommandIdentifier(id);
+                            }
+                            {
+                                osl::MutexGuard g(mutex_);
+                                processor_.clear();
+                                // At least the neon-based WebDAV UCP does not
+                                // properly support aborting commands, so return
+                                // anyway now if an abort request had been
+                                // ignored and the command execution only
+                                // returned "successfully" after some timeout:
+                                if (stopped_) {
+                                    return;
+                                }
+                            }
+                            css::uno::Reference< css::sdbc::XRow > row(
+                                res, css::uno::UNO_QUERY_THROW);
+                            folder = row->getBoolean(1) && !row->wasNull();
+                        } catch (css::uno::Exception & e) {
+                            SAL_WARN("svtools.control", "ignoring " << e);
+                            return;
+                        }
+                    }
+                    if (folder)
+                        Insert( aText, aMatch );
+                    else
+                        // otherwise the parent folder will be taken
+                        aURLObject.removeSegment();
+
+                    // scan directory and insert all matches
+                    ReadFolder( aURLObject.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aMatch, eProt == INetProtocol::NotValid );
+                }
+            }
+        }
+    }
+
+    if ( bOnlyDirectories )
+        // don't scan history picklist if only directories are allowed, picklist contains only files
+        return;
+
+    bool bFull = false;
+
+    INetURLObject aCurObj;
+    OUString aCurString, aCurMainURL;
+    INetURLObject aObj;
+    aObj.SetSmartProtocol( eSmartProt == INetProtocol::NotValid ? INetProtocol::Http : eSmartProt );
+    for( ;; )
+    {
+        for(std::vector<OUString>::iterator i = aPickList.begin(); schedule() && i != aPickList.end(); ++i)
+        {
+            aCurObj.SetURL(*i);
+            aCurObj.SetSmartURL( aCurObj.GetURLNoPass());
+            aCurMainURL = aCurObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+            if( eProt != INetProtocol::NotValid && aCurObj.GetProtocol() != eProt )
+                continue;
+
+            if( eSmartProt != INetProtocol::NotValid && aCurObj.GetProtocol() != eSmartProt )
+                continue;
+
+            switch( aCurObj.GetProtocol() )
+            {
+                case INetProtocol::Http:
+                case INetProtocol::Https:
+                case INetProtocol::Ftp:
+                {
+                    if( eProt == INetProtocol::NotValid && !bFull )
+                    {
+                        aObj.SetSmartURL( aText );
+                        if( aObj.GetURLPath().getLength() > 1 )
+                            continue;
+                    }
+
+                    aCurString = aCurMainURL;
+                    if( eProt == INetProtocol::NotValid )
+                    {
+                        // try if text matches the scheme
+                        OUString aScheme( INetURLObject::GetScheme( aCurObj.GetProtocol() ) );
+                        if ( aScheme.startsWithIgnoreAsciiCase( aText ) && aText.getLength() < aScheme.getLength() )
+                        {
+                            if( bFull )
+                                aMatch = aCurObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+                            else
+                            {
+                                aCurObj.SetMark( "" );
+                                aCurObj.SetParam( "" );
+                                aCurObj.SetURLPath( "" );
+                                aMatch = aCurObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+                            }
+
+                            Insert( aMatch, aMatch );
+                        }
+
+                        // now try smart matching
+                        aCurString = aCurString.copy( aScheme.getLength() );
+                    }
+
+                    if( aCurString.startsWithIgnoreAsciiCase( aText ) )
+                    {
+                        if( bFull )
+                            aMatch = aCurObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+                        else
+                        {
+                            aCurObj.SetMark( "" );
+                            aCurObj.SetParam( "" );
+                            aCurObj.SetURLPath( "" );
+                            aMatch = aCurObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+                        }
+
+                        OUString aURL( aMatch );
+                        if( eProt == INetProtocol::NotValid )
+                            aMatch = aMatch.copy( INetURLObject::GetScheme( aCurObj.GetProtocol() ).getLength() );
+
+                        if( aText.getLength() < aMatch.getLength() )
+                            Insert( aMatch, aURL );
+
+                        continue;
+                    }
+                    break;
+                }
+                default:
+                {
+                    if( bFull )
+                        continue;
+
+                    if( aCurMainURL.startsWith(aText) )
+                    {
+                        if( aText.getLength() < aCurMainURL.getLength() )
+                            Insert( aCurMainURL, aCurMainURL );
+
+                        continue;
+                    }
+                    break;
+                }
+            }
+        }
+
+        if( !bFull )
+            bFull = true;
+        else
+            break;
+    }
+}
+
+void SvtURLBox::TryAutoComplete()
+{
+    if( Application::AnyInput( VclInputFlags::KEYBOARD ) ) return;
+
+    OUString aCurText = GetText();
+    Selection aSelection( GetSelection() );
+    if( aSelection.Max() != aCurText.getLength() )
+        return;
+    sal_uInt16 nLen = static_cast<sal_uInt16>(aSelection.Min());
     aCurText = aCurText.copy( 0, nLen );
     if( !aCurText.isEmpty() && bIsAutoCompleteEnabled )
     {
@@ -1325,4 +1916,362 @@ void SvtURLBox::SetFilter(const OUString& _sFilter)
     FilterMatch::createWildCardFilterList(_sFilter,pImpl->m_aFilters);
 }
 
+//--
+
+OUString URLBox::ParseSmart( const OUString& _aText, const OUString& _aBaseURL )
+{
+    OUString aMatch;
+    OUString aText = _aText;
+    OUString aBaseURL = _aBaseURL;
+
+    // parse ~ for Unix systems
+    // does nothing for Windows
+    if( !SvtURLBox_Impl::TildeParsing( aText, aBaseURL ) )
+        return OUString();
+
+    if( !aBaseURL.isEmpty() )
+    {
+        INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL );
+
+        // if a base URL is set the string may be parsed relative
+        if( aText.startsWith( "/" ) )
+        {
+            // text starting with slashes means absolute file URLs
+            OUString aTemp = INetURLObject::GetScheme( eBaseProt );
+
+            // file URL must be correctly encoded!
+            OUString aTextURL = INetURLObject::encode( aText, INetURLObject::PART_FPATH,
+                                                     INetURLObject::EncodeMechanism::All );
+            aTemp += aTextURL;
+
+            INetURLObject aTmp( aTemp );
+            if ( !aTmp.HasError() && aTmp.GetProtocol() != INetProtocol::NotValid )
+                aMatch = aTmp.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+        }
+        else
+        {
+            OUString aSmart( aText );
+            INetURLObject aObj( aBaseURL );
+
+            // HRO: I suppose this hack should only be done for Windows !!!???
+#ifdef _WIN32
+            // HRO: INetURLObject::smatRel2Abs does not recognize '\\' as a relative path
+            //      but in case of "\\\\" INetURLObject is right - this is an absolute path !
+
+            if( aText.startsWith("\\") && (aText.getLength() < 2 || aText[ 1 ] != '\\') )
+            {
+                // cut to first segment
+                OUString aTmp = INetURLObject::GetScheme( eBaseProt );
+                aTmp += "/";
+                aTmp += aObj.getName( 0, true, INetURLObject::DecodeMechanism::WithCharset );
+                aObj.SetURL( aTmp );
+
+                aSmart = aSmart.copy(1);
+            }
+#endif
+            // base URL must be a directory !
+            aObj.setFinalSlash();
+
+            // take base URL and append current input
+            bool bWasAbsolute = false;
+#ifdef UNX
+            // encode file URL correctly
+            aSmart = INetURLObject::encode( aSmart, INetURLObject::PART_FPATH, INetURLObject::EncodeMechanism::All );
+#endif
+            INetURLObject aTmp( aObj.smartRel2Abs( aSmart, bWasAbsolute ) );
+
+            if ( aText.endsWith(".") )
+                // INetURLObject appends a final slash for the directories "." and "..", this is a bug!
+                // Remove it as a workaround
+                aTmp.removeFinalSlash();
+            if ( !aTmp.HasError() && aTmp.GetProtocol() != INetProtocol::NotValid )
+                aMatch = aTmp.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+        }
+    }
+    else
+    {
+        OUString aTmpMatch;
+        osl::FileBase::getFileURLFromSystemPath( aText, aTmpMatch );
+        aMatch = aTmpMatch;
+    }
+
+    return aMatch;
+}
+
+IMPL_LINK_NOARG(URLBox, TryAutoComplete, Timer *, void)
+{
+    OUString aCurText = m_xWidget->get_active_text();
+    int nStartPos, nEndPos;
+    m_xWidget->get_entry_selection_bounds(nStartPos, nEndPos);
+    if (nEndPos != aCurText.getLength())
+        return;
+    aCurText = aCurText.copy(0, nStartPos);
+    if (!aCurText.isEmpty())
+    {
+        if (pCtx.is())
+        {
+            pCtx->Stop();
+            pCtx->join();
+            pCtx.clear();
+        }
+        pCtx = new MatchContext_Impl(this, aCurText);
+        pCtx->launch();
+    }
+    else
+        m_xWidget->clear();
+}
+
+URLBox::URLBox(weld::ComboBoxText* pWidget)
+    : eSmartProtocol(INetProtocol::NotValid)
+    , bAutoCompleteMode(false)
+    , bOnlyDirectories(false)
+    , bHistoryDisabled(false)
+    , m_xWidget(pWidget)
+{
+    Init();
+
+    m_xWidget->connect_focus_in(LINK(this, URLBox, FocusInHdl));
+    m_xWidget->connect_focus_out(LINK(this, URLBox, FocusOutHdl));
+    m_xWidget->connect_changed(LINK(this, URLBox, ChangedHdl));
+
+    aChangedIdle.SetInvokeHandler(LINK(this, URLBox, TryAutoComplete));
+    aChangedIdle.SetDebugName("svtools::URLBox aChangedIdle");
+}
+
+void URLBox::Init()
+{
+    pImpl.reset( new SvtURLBox_Impl );
+
+    m_xWidget->set_entry_completion(false);
+
+    UpdatePicklistForSmartProtocol_Impl();
+}
+
+URLBox::~URLBox()
+{
+    if (pCtx.is())
+    {
+        pCtx->Stop();
+        pCtx->join();
+    }
+}
+
+void URLBox::UpdatePickList( )
+{
+    if (pCtx.is())
+    {
+        pCtx->Stop();
+        pCtx->join();
+        pCtx.clear();
+    }
+    OUString sText = m_xWidget->get_active_text();
+    if (!sText.isEmpty())
+    {
+        pCtx = new MatchContext_Impl( this, sText );
+        pCtx->launch();
+    }
+}
+
+void URLBox::SetSmartProtocol( INetProtocol eProt )
+{
+    if ( eSmartProtocol != eProt )
+    {
+        eSmartProtocol = eProt;
+        UpdatePicklistForSmartProtocol_Impl();
+    }
+}
+
+void URLBox::UpdatePicklistForSmartProtocol_Impl()
+{
+    m_xWidget->clear();
+    if ( bHistoryDisabled )
+        return;
+
+    // read history pick list
+    Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( ePICKLIST );
+    sal_uInt32 nCount = seqPicklist.getLength();
+    INetURLObject aCurObj;
+
+    for( sal_uInt32 nItem=0; nItem < nCount; nItem++ )
+    {
+        Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
+
+        OUString sURL;
+
+        sal_uInt32 nPropertyCount = seqPropertySet.getLength();
+
+        for( sal_uInt32 nProperty=0; nProperty < nPropertyCount; nProperty++ )
+        {
+            if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_URL )
+            {
+                seqPropertySet[nProperty].Value >>= sURL;
+                aCurObj.SetURL( sURL );
+
+                if ( !sURL.isEmpty() && ( eSmartProtocol != INetProtocol::NotValid ) )
+                {
+                    if( aCurObj.GetProtocol() != eSmartProtocol )
+                        break;
+                }
+
+                OUString aURL( aCurObj.GetMainURL( INetURLObject::DecodeMechanism::WithCharset ) );
+
+                if ( !aURL.isEmpty() )
+                {
+                    bool bFound = aURL.endsWith("/");
+                    if ( !bFound )
+                    {
+                        OUString aUpperURL( aURL );
+                        aUpperURL = aUpperURL.toAsciiUpperCase();
+
+                        bFound = ::std::any_of(pImpl->m_aFilters.begin(),
+                                               pImpl->m_aFilters.end(),
+                                               FilterMatch( aUpperURL ) );
+                    }
+                    if ( bFound )
+                    {
+                        OUString aFile;
+                        if (osl::FileBase::getSystemPathFromFileURL(aURL, aFile) == osl::FileBase::E_None)
+                            m_xWidget->append_text(aFile);
+                        else
+                            m_xWidget->append_text(aURL);
+                    }
+                }
+                break;
+            }
+        }
+    }
+}
+
+IMPL_LINK_NOARG(URLBox, ChangedHdl, weld::ComboBoxText&, void)
+{
+    aChangedIdle.Start(); //launch this to happen on idle after cursor position will have been set
+}
+
+IMPL_LINK_NOARG(URLBox, FocusInHdl, weld::Widget&, void)
+{
+#ifndef UNX
+    // pb: don't select automatically on unix #93251#
+    m_xWidget->select_entry_region(0, -1);
+#endif
+}
+
+IMPL_LINK_NOARG(URLBox, FocusOutHdl, weld::Widget&, void)
+{
+    if (pCtx.is())
+    {
+        pCtx->Stop();
+        pCtx->join();
+        pCtx.clear();
+    }
+}
+
+void URLBox::SetOnlyDirectories( bool bDir )
+{
+    bOnlyDirectories = bDir;
+    if (bOnlyDirectories)
+        m_xWidget->clear();
+}
+
+OUString URLBox::GetURL()
+{
+    // wait for end of autocompletion
+    ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
+
+    OUString aText(m_xWidget->get_active_text());
+    if ( MatchesPlaceHolder( aText ) )
+        return aPlaceHolder;
+
+    // try to get the right case preserving URL from the list of URLs
+    for(std::vector<OUString>::iterator i = pImpl->aCompletions.begin(), j = pImpl->aURLs.begin(); i != pImpl->aCompletions.end() && j != pImpl->aURLs.end(); ++i, ++j)
+    {
+        if((*i) == aText)
+            return *j;
+    }
+
+#ifdef _WIN32
+    // erase trailing spaces on Windows since thay are invalid on this OS and
+    // most of the time they are inserted by accident via copy / paste
+    aText = comphelper::string::stripEnd(aText, ' ');
+    if ( aText.isEmpty() )
+        return aText;
+    // #i9739#
+#endif
+
+    INetURLObject aObj( aText );
+    if( aText.indexOf( '*' ) != -1 || aText.indexOf( '?' ) != -1 )
+    {
+        // no autocompletion for wildcards
+        INetURLObject aTempObj;
+        if ( eSmartProtocol != INetProtocol::NotValid )
+            aTempObj.SetSmartProtocol( eSmartProtocol );
+        if ( aTempObj.SetSmartURL( aText ) )
+            return aTempObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+        else
+            return aText;
+    }
+
+    if ( aObj.GetProtocol() == INetProtocol::NotValid )
+    {
+        OUString aName = ParseSmart( aText, aBaseURL );
+        aObj.SetURL(aName);
+        OUString aURL( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+        if ( aURL.isEmpty() )
+            // aText itself is invalid, and even together with aBaseURL, it could not
+            // made valid -> no chance
+            return aText;
+
+        bool bSlash = aObj.hasFinalSlash();
+        {
+            const OUString aPropName("CasePreservingURL");
+
+            OUString aFileURL;
+
+            Any aAny = UCBContentHelper::GetProperty(aURL, aPropName);
+            bool success = (aAny >>= aFileURL);
+            OUString aTitle;
+            if(success)
+                aTitle = INetURLObject(aFileURL).getName(
+                             INetURLObject::LAST_SEGMENT,
+                             true,
+                             INetURLObject::DecodeMechanism::WithCharset );
+            else
+                success =
+                    UCBContentHelper::GetTitle(aURL,&aTitle);
+
+            if( success && aTitle != "/" && aTitle != "." )
+            {
+                    aObj.SetName( aTitle );
+                    if ( bSlash )
+                        aObj.setFinalSlash();
+            }
+        }
+    }
+
+    return aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+}
+
+void URLBox::DisableHistory()
+{
+    bHistoryDisabled = true;
+    UpdatePicklistForSmartProtocol_Impl();
+}
+
+void URLBox::SetBaseURL( const OUString& rURL )
+{
+    ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
+
+    // Reset match lists
+    pImpl->aCompletions.clear();
+    pImpl->aURLs.clear();
+
+    aBaseURL = rURL;
+}
+
+void URLBox::SetFilter(const OUString& _sFilter)
+{
+    pImpl->m_aFilters.clear();
+    FilterMatch::createWildCardFilterList(_sFilter,pImpl->m_aFilters);
+}
+
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 905e29f5b33d..637f5651d66b 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -1091,6 +1091,16 @@ public:
         return m_xTreeView->GetSelectedEntry();
     }
 
+    virtual std::vector<OUString> get_selected_rows() const override
+    {
+        std::vector<OUString> aRows;
+
+        for (sal_Int32 i = 0; i < m_xTreeView->GetSelectedEntryCount(); ++i)
+            aRows.push_back(m_xTreeView->GetSelectedEntry(i));
+
+        return aRows;
+    }
+
     virtual OUString get(int pos) const override
     {
         return m_xTreeView->GetEntry(pos);
@@ -1127,6 +1137,16 @@ public:
         m_xTreeView->SetUpdateMode(true);
     }
 
+    virtual void set_selection_mode(bool bMultiple) override
+    {
+        m_xTreeView->EnableMultiSelection(bMultiple);
+    }
+
+    virtual int count_selected_rows() const override
+    {
+        return m_xTreeView->GetSelectedEntryCount();
+    }
+
     virtual int get_height_rows(int nRows) const override
     {
         return m_xTreeView->CalcWindowSizePixel(nRows);
@@ -1597,7 +1617,7 @@ public:
         return false;
     }
 
-    virtual void unset_entry_completion() override
+    virtual void set_entry_completion(bool) override
     {
         assert(false);
     }
@@ -1617,11 +1637,13 @@ class SalInstanceComboBoxTextWithEdit : public SalInstanceComboBoxText<ComboBox>
 {
 private:
     DECL_LINK(ChangeHdl, Edit&, void);
+    DECL_LINK(EntryActivateHdl, Edit&, void);
 public:
     SalInstanceComboBoxTextWithEdit(ComboBox* pComboBoxText, bool bTakeOwnership)
         : SalInstanceComboBoxText<ComboBox>(pComboBoxText, bTakeOwnership)
     {
         m_xComboBoxText->SetModifyHdl(LINK(this, SalInstanceComboBoxTextWithEdit, ChangeHdl));
+        m_xComboBoxText->SetEntryActivateHdl(LINK(this, SalInstanceComboBoxTextWithEdit, EntryActivateHdl));
     }
 
     virtual void set_entry_error(bool bError) override
@@ -1642,9 +1664,9 @@ public:
         m_xComboBoxText->SetText(rText);
     }
 
-    virtual void unset_entry_completion() override
+    virtual void set_entry_completion(bool bEnable) override
     {
-        m_xComboBoxText->EnableAutocomplete(false);
+        m_xComboBoxText->EnableAutocomplete(bEnable);
     }
 
     virtual void select_entry_region(int nStartPos, int nEndPos) override
@@ -1662,6 +1684,7 @@ public:
 
     virtual ~SalInstanceComboBoxTextWithEdit() override
     {
+        m_xComboBoxText->SetEntryActivateHdl(Link<Edit&, void>());
         m_xComboBoxText->SetModifyHdl(Link<Edit&, void>());
     }
 };
@@ -1671,6 +1694,11 @@ IMPL_LINK_NOARG(SalInstanceComboBoxTextWithEdit, ChangeHdl, Edit&, void)
     signal_changed();
 }
 
+IMPL_LINK_NOARG(SalInstanceComboBoxTextWithEdit, EntryActivateHdl, Edit&, void)
+{
+    m_aEntryActivateHdl.Call(*this);
+}
+
 class SalInstanceBuilder : public weld::Builder
 {
 private:
diff --git a/vcl/source/control/combobox.cxx b/vcl/source/control/combobox.cxx
index 7b14c8da64c2..1cb790dada78 100644
--- a/vcl/source/control/combobox.cxx
+++ b/vcl/source/control/combobox.cxx
@@ -58,6 +58,7 @@ struct ComboBox::Impl
     sal_Int32           m_nMaxWidthChars;
     Link<ComboBox&,void>               m_SelectHdl;
     Link<ComboBox&,void>               m_DoubleClickHdl;
+    Link<ComboBox&,void>               m_EntryActivateHdl;
 
     explicit Impl(ComboBox & rThis)
         : m_rThis(rThis)
@@ -986,6 +987,8 @@ void ComboBox::SetDoubleClickHdl(const Link<ComboBox&,void>& rLink) { m_pImpl->m
 
 const Link<ComboBox&,void>& ComboBox::GetDoubleClickHdl() const { return m_pImpl->m_DoubleClickHdl; }
 
+void ComboBox::SetEntryActivateHdl(const Link<Edit&,void>& rLink) { m_pImpl->m_pSubEdit->SetActivateHdl(rLink); }
+
 long ComboBox::CalcWindowSizePixel(sal_uInt16 nLines) const
 {
     return m_pImpl->m_pImplLB->GetEntryHeight() * nLines;
diff --git a/vcl/source/control/edit.cxx b/vcl/source/control/edit.cxx
index 42dd22296585..8d3bfa665596 100644
--- a/vcl/source/control/edit.cxx
+++ b/vcl/source/control/edit.cxx
@@ -1677,6 +1677,14 @@ bool Edit::ImplHandleKeyEvent( const KeyEvent& rKEvt )
             }
             break;
 
+            case KEY_RETURN:
+                if (maActivateHdl.IsSet())
+                {
+                    maActivateHdl.Call(*this);
+                    bDone = true;
+                }
+            break;
+
             default:
             {
                 if ( IsCharInput( rKEvt ) )
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 133406925d79..269a0741973f 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -1184,12 +1184,14 @@ private:
     static void signalFocusIn(GtkWidget*, GdkEvent*, gpointer widget)
     {
         GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_focus_in();
     }
 
     static void signalFocusOut(GtkWidget*, GdkEvent*, gpointer widget)
     {
         GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_focus_out();
     }
 
@@ -1446,6 +1448,7 @@ private:
     static void signalActivate(GtkMenuItem* pItem, gpointer widget)
     {
         GtkInstanceMenu* pThis = static_cast<GtkInstanceMenu*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_activate(pItem);
     }
 
@@ -2077,6 +2080,7 @@ private:
     static void signalVAdjustValueChanged(GtkAdjustment*, gpointer widget)
     {
         GtkInstanceScrolledWindow* pThis = static_cast<GtkInstanceScrolledWindow*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_vadjustment_changed();
     }
 
@@ -2181,6 +2185,7 @@ private:
     static void signalSwitchPage(GtkNotebook*, GtkWidget*, guint nNewPage, gpointer widget)
     {
         GtkInstanceNotebook* pThis = static_cast<GtkInstanceNotebook*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_switch_page(nNewPage);
     }
 
@@ -2278,6 +2283,7 @@ private:
     static void signalClicked(GtkButton*, gpointer widget)
     {
         GtkInstanceButton* pThis = static_cast<GtkInstanceButton*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_clicked();
     }
 
@@ -2360,6 +2366,7 @@ private:
     static void signalToggled(GtkToggleButton*, gpointer widget)
     {
         GtkInstanceToggleButton* pThis = static_cast<GtkInstanceToggleButton*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_toggled();
     }
 public:
@@ -2438,6 +2445,7 @@ private:
     static void signalChanged(GtkEntry*, gpointer widget)
     {
         GtkInstanceEntry* pThis = static_cast<GtkInstanceEntry*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_changed();
     }
 
@@ -2445,6 +2453,7 @@ private:
                                  gint* position, gpointer widget)
     {
         GtkInstanceEntry* pThis = static_cast<GtkInstanceEntry*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_insert_text(pEntry, pNewText, nNewTextLength, position);
     }
 
@@ -2580,12 +2589,14 @@ private:
     static void signalChanged(GtkTreeView*, gpointer widget)
     {
         GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_changed();
     }
 
     static void signalRowActivated(GtkTreeView*, GtkTreePath*, GtkTreeViewColumn*, gpointer widget)
     {
         GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_row_activated();
     }
 
@@ -2721,6 +2732,8 @@ public:
 
     virtual OUString get_selected() const override
     {
+        assert(gtk_tree_selection_get_mode(gtk_tree_view_get_selection(m_pTreeView)) == GTK_SELECTION_SINGLE);
+
         OUString sRet;
         GtkTreeIter iter;
         GtkTreeModel* pModel;
@@ -2734,6 +2747,23 @@ public:
         return sRet;
     }
 
+    virtual std::vector<OUString> get_selected_rows() const override
+    {
+        std::vector<OUString> aRows;
+
+        GtkTreeModel* pModel;
+        GList* pList = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(m_pTreeView), &pModel);
+        for (GList* pItem = g_list_first(pList); pItem; pItem = g_list_next(pItem))
+        {
+            GtkTreePath* path = static_cast<GtkTreePath*>(pItem->data);
+            int nRow = gtk_tree_path_get_indices(path)[0];
+            aRows.push_back(get(nRow));
+        }
+        g_list_free_full(pList, reinterpret_cast<GDestroyNotify>(gtk_tree_path_free));
+
+        return aRows;
+    }
+
     virtual OUString get(int pos) const override
     {
         return get(pos, 0);
@@ -2808,6 +2838,16 @@ public:
             gtk_widget_set_size_request(m_pWidget, nWidth, nHeight);
     }
 
+    virtual void set_selection_mode(bool bMultiple) override
+    {
+        gtk_tree_selection_set_mode(gtk_tree_view_get_selection(m_pTreeView), bMultiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE);
+    }
+
+    virtual int count_selected_rows() const override
+    {
+        return gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(m_pTreeView));
+    }
+
     virtual void disable_notify_events() override
     {
         g_signal_handler_block(gtk_tree_view_get_selection(m_pTreeView), m_nChangedSignalId);
@@ -2840,12 +2880,14 @@ private:
     static void signalValueChanged(GtkSpinButton*, gpointer widget)
     {
         GtkInstanceSpinButton* pThis = static_cast<GtkInstanceSpinButton*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_value_changed();
     }
 
     static gboolean signalOutput(GtkSpinButton*, gpointer widget)
     {
         GtkInstanceSpinButton* pThis = static_cast<GtkInstanceSpinButton*>(widget);
+        SolarMutexGuard aGuard;
         return pThis->signal_output();
     }
 
@@ -3078,6 +3120,7 @@ private:
     static gboolean signalDraw(GtkWidget*, cairo_t* cr, gpointer widget)
     {
         GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_draw(cr);
         return false;
     }
@@ -3097,6 +3140,7 @@ private:
     static void signalSizeAllocate(GtkWidget*, GdkRectangle* allocation, gpointer widget)
     {
         GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_size_allocate(allocation->width, allocation->height);
     }
     void signal_size_allocate(guint nWidth, guint nHeight)
@@ -3119,6 +3163,7 @@ private:
     static gboolean signalButton(GtkWidget*, GdkEventButton* pEvent, gpointer widget)
     {
         GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget);
+        SolarMutexGuard aGuard;
         return pThis->signal_button(pEvent);
     }
     bool signal_button(GdkEventButton* pEvent)
@@ -3187,6 +3232,7 @@ private:
     static gboolean signalMotion(GtkWidget*, GdkEventMotion* pEvent, gpointer widget)
     {
         GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget);
+        SolarMutexGuard aGuard;
         return pThis->signal_motion(pEvent);
     }
     bool signal_motion(GdkEventMotion* pEvent)
@@ -3202,6 +3248,7 @@ private:
     static gboolean signalKey(GtkWidget*, GdkEventKey* pEvent, gpointer widget)
     {
         GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget);
+        SolarMutexGuard aGuard;
         return pThis->signal_key(pEvent);
     }
     gboolean signal_key(GdkEventKey* pEvent)
@@ -3312,14 +3359,53 @@ class GtkInstanceComboBoxText : public GtkInstanceContainer, public virtual weld
 private:
     GtkComboBoxText* m_pComboBoxText;
     std::unique_ptr<comphelper::string::NaturalStringSorter> m_xSorter;
-    gulong m_nSignalId;
+    gboolean m_bPopupActive;
+    gulong m_nChangedSignalId;
+    gulong m_nPopupShownSignalId;
+    gulong m_nEntryActivateSignalId;
 
     static void signalChanged(GtkComboBox*, gpointer widget)
     {
         GtkInstanceComboBoxText* pThis = static_cast<GtkInstanceComboBoxText*>(widget);
+        SolarMutexGuard aGuard;
         pThis->signal_changed();
     }
 
+    static void signalPopupShown(GtkComboBox*, GParamSpec*, gpointer widget)
+    {
+        GtkInstanceComboBoxText* pThis = static_cast<GtkInstanceComboBoxText*>(widget);
+        pThis->signal_popup_shown();
+    }
+
+    void signal_popup_shown()
+    {
+        gboolean bIsShown(false);
+        g_object_get(m_pComboBoxText, "popup-shown", &bIsShown, nullptr);
+        if (m_bPopupActive != bIsShown)
+        {
+            m_bPopupActive = bIsShown;
+            //restore focus to the entry wieh the popup is gone, which
+            //is what the vcl case does, to ease the transition a little
+            gtk_widget_grab_focus(m_pWidget);
+        }
+    }
+
+    static void signalEntryActivate(GtkComboBox*, gpointer widget)
+    {
+        GtkInstanceComboBoxText* pThis = static_cast<GtkInstanceComboBoxText*>(widget);
+        pThis->signal_entry_activate();
+    }
+
+    void signal_entry_activate()
+    {
+        if (m_aEntryActivateHdl.IsSet())
+        {
+            SolarMutexGuard aGuard;
+            m_aEntryActivateHdl.Call(*this);
+            g_signal_stop_emission_by_name(get_entry(), "activate");
+        }
+    }
+
     OUString get(int pos, int col) const
     {
         OUString sRet;
@@ -3358,28 +3444,43 @@ private:
         return -1;
     }
 
-    void setup_completion()
+    GtkEntry* get_entry()
     {
         GtkWidget* pChild = gtk_bin_get_child(GTK_BIN(m_pComboBoxText));
-        if (GTK_IS_ENTRY(pChild))
-        {
-            GtkEntry* pEntry = GTK_ENTRY(pChild);
-            GtkEntryCompletion* pCompletion = gtk_entry_completion_new();
-            gtk_entry_completion_set_model(pCompletion, gtk_combo_box_get_model(GTK_COMBO_BOX(m_pComboBoxText)));
-            gtk_entry_completion_set_text_column(pCompletion, 0);
-            gtk_entry_completion_set_inline_selection(pCompletion, true);
-            gtk_entry_set_completion(pEntry, pCompletion);
-            g_object_unref(pCompletion);
-        }
+        if (!GTK_IS_ENTRY(pChild))
+            return nullptr;
+        return GTK_ENTRY(pChild);
+    }
+
+    void setup_completion(GtkEntry* pEntry)
+    {
+        if (gtk_entry_get_completion(pEntry))
+            return;
+        GtkEntryCompletion* pCompletion = gtk_entry_completion_new();
+        gtk_entry_completion_set_model(pCompletion, gtk_combo_box_get_model(GTK_COMBO_BOX(m_pComboBoxText)));
+        gtk_entry_completion_set_text_column(pCompletion, 0);
+        gtk_entry_completion_set_inline_selection(pCompletion, true);
+        gtk_entry_completion_set_inline_completion(pCompletion, true);
+        gtk_entry_completion_set_popup_completion(pCompletion, false);
+        gtk_entry_set_completion(pEntry, pCompletion);
+        g_object_unref(pCompletion);
     }
 
 public:
     GtkInstanceComboBoxText(GtkComboBoxText* pComboBoxText, bool bTakeOwnership)
         : GtkInstanceContainer(GTK_CONTAINER(pComboBoxText), bTakeOwnership)
         , m_pComboBoxText(pComboBoxText)
-        , m_nSignalId(g_signal_connect(m_pComboBoxText, "changed", G_CALLBACK(signalChanged), this))
+        , m_bPopupActive(false)
+        , m_nChangedSignalId(g_signal_connect(m_pComboBoxText, "changed", G_CALLBACK(signalChanged), this))
+        , m_nPopupShownSignalId(g_signal_connect(m_pComboBoxText, "notify::popup-shown", G_CALLBACK(signalPopupShown), this))
     {
-        setup_completion();
+        if (GtkEntry* pEntry = get_entry())
+        {
+            setup_completion(pEntry);
+            m_nEntryActivateSignalId = g_signal_connect(pEntry, "activate", G_CALLBACK(signalEntryActivate), this);
+        }
+        else
+            m_nEntryActivateSignalId = 0;
     }
 
     virtual int get_active() const override
@@ -3517,29 +3618,40 @@ public:
         return gtk_editable_get_selection_bounds(GTK_EDITABLE(pEntry), &rStartPos, &rEndPos);
     }
 
-    virtual void unset_entry_completion() override
+    virtual void set_entry_completion(bool bEnable) override

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list