[Libreoffice-commits] core.git: sw/source sw/uiconfig

Jakub Trzebiatowski ubap.dev at gmail.com
Fri Mar 25 08:54:22 UTC 2016


 sw/source/ui/misc/bookmark.cxx           |  457 ++++++++++++++++++++++---------
 sw/source/uibase/inc/bookmark.hxx        |   57 ++-
 sw/uiconfig/swriter/ui/insertbookmark.ui |  188 +++++++++---
 3 files changed, 511 insertions(+), 191 deletions(-)

New commits:
commit 08da15cabdcef60191f4ed98ed694eba3e35b5e1
Author: Jakub Trzebiatowski <ubap.dev at gmail.com>
Date:   Fri Mar 11 20:58:34 2016 +0100

    tdf#90855 Improve the 'Insert Bookmark' dialog
    
    implemented:
    - display page number
    - displaying bookmark text
    - goto (button and table doubleclick)
    - help
    - rename
    - selecting multiple bookmarks in TableView or in EditField by ";"
    - sorting by any column
    
    Change-Id: I7523dc066380bc360bd484c88a6f4ba45e867320
    Reviewed-on: https://gerrit.libreoffice.org/23156
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>

diff --git a/sw/source/ui/misc/bookmark.cxx b/sw/source/ui/misc/bookmark.cxx
index c12da8d..a65ddaf 100644
--- a/sw/source/ui/misc/bookmark.cxx
+++ b/sw/source/ui/misc/bookmark.cxx
@@ -22,220 +22,419 @@
 #include <svl/stritem.hxx>
 #include <vcl/msgbox.hxx>
 #include <vcl/builderfactory.hxx>
+#include <svtools/headbar.hxx>
+#include <svtools/treelistentry.hxx>
+#include <com/sun/star/text/XBookmarksSupplier.hpp>
 
+#include "swabstdlg.hxx"
+#include "swuiexp.hxx"
 #include "view.hxx"
 #include "basesh.hxx"
 #include "wrtsh.hxx"
 #include "cmdid.h"
 #include "bookmark.hxx"
-#include "IMark.hxx"
+#include "docsh.hxx"
 #include "globals.hrc"
 
-const OUString BookmarkCombo::aForbiddenChars("/\\@*?\";,#");
+using namespace ::com::sun::star;
 
-IMPL_LINK_TYPED( SwInsertBookmarkDlg, ModifyHdl, Edit&, rEdit, void )
+const OUString BookmarkTable::aForbiddenChars("/\\@*?\",#");
+const char BookmarkTable::cSeparator(';');
+const OUString BookmarkTable::sDefaultBookmarkName("Bookmark");
+
+// callback to modify EditBox
+IMPL_LINK_NOARG_TYPED(SwInsertBookmarkDlg, ModifyHdl, Edit&, void)
 {
-    BookmarkCombo& rBox = static_cast<BookmarkCombo&>(rEdit);
-    bool bSelEntries = rBox.GetSelectEntryCount() != 0;
+    ValidateBookmarks();
+    m_pBookmarksBox->SelectAll(false);
     // if a string has been pasted from the clipboard then
     // there may be illegal characters in the box
-    if(!bSelEntries)
+    // sanitization
+    OUString sTmp = m_pEditBox->GetText();
+    OUString sMsg;
+    const sal_Int32 nLen = sTmp.getLength();
+    for (sal_Int32 i = 0; i < BookmarkTable::aForbiddenChars.getLength(); i++)
     {
-        OUString sTmp = rBox.GetText();
-        const sal_Int32 nLen = sTmp.getLength();
-        OUString sMsg;
-        for(sal_Int32 i = 0; i < BookmarkCombo::aForbiddenChars.getLength(); i++)
-        {
-            const sal_Int32 nTmpLen = sTmp.getLength();
-            sTmp = comphelper::string::remove(sTmp, BookmarkCombo::aForbiddenChars[i]);
-            if(sTmp.getLength() != nTmpLen)
-                sMsg += OUString(BookmarkCombo::aForbiddenChars[i]);
-        }
-        if(sTmp.getLength() != nLen)
+        const sal_Int32 nTmpLen = sTmp.getLength();
+        sTmp = comphelper::string::remove(sTmp, BookmarkTable::aForbiddenChars[i]);
+        if (sTmp.getLength() != nTmpLen)
+           sMsg += OUString(BookmarkTable::aForbiddenChars[i]);
+    }
+    if (sTmp.getLength() != nLen)
+    {
+        m_pEditBox->SetText(sTmp);
+        ScopedVclPtr<InfoBox>::Create(this, sRemoveWarning + sMsg)->Execute();
+    }
+
+    sal_Int32 nSelectedEntries = 0;
+    sal_Int32 nEntries = 0;
+    sal_Int32 nTokenIndex = 0;
+    while (!sTmp.isEmpty() && nTokenIndex >= 0)
+    {
+        OUString aToken = sTmp.getToken(0, BookmarkTable::cSeparator, nTokenIndex);
+        if (m_pBookmarksBox->GetBookmarkByName(aToken))
         {
-            rBox.SetText(sTmp);
-            ScopedVclPtr<InfoBox>::Create(this, sRemoveWarning+sMsg)->Execute();
+            m_pBookmarksBox->SelectByName(aToken);
+            nSelectedEntries++;
         }
-
+        nEntries++;
     }
 
-    m_pOkBtn->Enable(!bSelEntries);    // new text mark
-    m_pDeleteBtn->Enable(bSelEntries); // deletable?
+    // allow to add new bookmark only if one name provided and its not taken
+    m_pInsertBtn->Enable(nEntries == 1 && nSelectedEntries == 0);
+
+    // allow to delete only if all bookmarks are recognized
+    m_pDeleteBtn->Enable(nEntries > 0 && nSelectedEntries == nEntries);
+    m_pGotoBtn->Enable(nEntries == 1 && nSelectedEntries == 1);
+    m_pRenameBtn->Enable(nEntries == 1 && nSelectedEntries == 1);
 }
 
 // callback to delete a text mark
 IMPL_LINK_NOARG_TYPED(SwInsertBookmarkDlg, DeleteHdl, Button*, void)
 {
-    // remove text marks from the ComboBox
+    if (!ValidateBookmarks())
+        return;
+    if (m_pBookmarksBox->GetSelectionCount() == 0)
+        return;
 
-    for (sal_Int32 i = m_pBookmarkBox->GetSelectEntryCount(); i; i-- )
-        m_pBookmarkBox->RemoveEntryAt(m_pBookmarkBox->GetSelectEntryPos(i - 1));
+    SvTreeListEntry* pSelected = m_pBookmarksBox->FirstSelected();
+    for (sal_Int32 i = m_pBookmarksBox->GetSelectionCount(); i; i--)
+    {
+        // remove from model
+        sw::mark::IMark* pBookmark = static_cast<sw::mark::IMark*>(pSelected->GetUserData());
+        OUString sRemoved = pBookmark->GetName();
+        IDocumentMarkAccess* const pMarkAccess = rSh.getIDocumentMarkAccess();
+        pMarkAccess->deleteMark(pMarkAccess->findMark(sRemoved));
+        SfxRequest aReq(rSh.GetView().GetViewFrame(), FN_DELETE_BOOKMARK);
+        aReq.AppendItem(SfxStringItem(FN_DELETE_BOOKMARK, sRemoved));
+        aReq.Done();
+        aTableBookmarks.erase(std::remove(aTableBookmarks.begin(), aTableBookmarks.end(),
+                              std::make_pair(pBookmark, sRemoved)), aTableBookmarks.end());
+        // remove from BookmarkTable
+        SvTreeListEntry* nextSelected = m_pBookmarksBox->NextSelected(pSelected);
+        m_pBookmarksBox->RemoveEntry(pSelected);
+        pSelected = nextSelected;
+    }
+    m_pBookmarksBox->SelectAll(false);
+    m_pEditBox->SetText("");
+    m_pDeleteBtn->Disable();
+    m_pGotoBtn->Disable();
+    m_pRenameBtn->Disable();
+    m_pInsertBtn->Disable();
+}
 
-    m_pBookmarkBox->SetText(OUString());
-    m_pDeleteBtn->Enable(false);   // no further entries there
+// callback to a goto button
+IMPL_LINK_NOARG_TYPED(SwInsertBookmarkDlg, GotoHdl, Button*, void)
+{
+    GotoSelectedBookmark();
+}
 
-    m_pOkBtn->Enable();            // the OK handler deletes
+IMPL_LINK_NOARG_TYPED(SwInsertBookmarkDlg, DoubleClickHdl, SvTreeListBox*, bool)
+{
+    GotoSelectedBookmark();
+    return true;
 }
 
-// callback for OKButton. Inserts a new text mark to the current position.
-// Deleted text marks are also deleted in the model.
-void SwInsertBookmarkDlg::Apply()
+IMPL_LINK_NOARG_TYPED(SwInsertBookmarkDlg, SelectionChangedHdl, SvTreeListBox*, void)
 {
-    //at first remove deleted bookmarks to prevent multiple bookmarks with the same
-    //name
-    for (sal_Int32 nCount = m_pBookmarkBox->GetRemovedCount(); nCount > 0; nCount--)
+    if (!ValidateBookmarks())
+        return;
+    // this event should fired only if we change selection by clicking on BookmarkTable entry
+    if (!m_pBookmarksBox->HasFocus())
+        return;
+
+    OUString sEditBoxText;
+    SvTreeListEntry* pSelected = m_pBookmarksBox->FirstSelected();
+    for (sal_Int32 i = m_pBookmarksBox->GetSelectionCount(); i; i--)
     {
-        OUString sRemoved = m_pBookmarkBox->GetRemovedEntry( nCount -1 ).GetName();
-        IDocumentMarkAccess* const pMarkAccess = rSh.getIDocumentMarkAccess();
-        pMarkAccess->deleteMark( pMarkAccess->findMark(sRemoved) );
-        SfxRequest aReq( rSh.GetView().GetViewFrame(), FN_DELETE_BOOKMARK );
-        aReq.AppendItem( SfxStringItem( FN_DELETE_BOOKMARK, sRemoved ) );
-        aReq.Done();
+        sw::mark::IMark* pBookmark = static_cast<sw::mark::IMark*>(pSelected->GetUserData());
+        OUString sEntryName = pBookmark->GetName();
+        sEditBoxText = sEditBoxText + sEntryName;
+        if (i > 1)
+            sEditBoxText += ";";
+        pSelected = m_pBookmarksBox->NextSelected(pSelected);
     }
-
-    // insert text mark
-    SwBoxEntry  aTmpEntry(m_pBookmarkBox->GetText() );
-
-    if (!m_pBookmarkBox->GetText().isEmpty() &&
-        (m_pBookmarkBox->GetSwEntryPos(aTmpEntry) == COMBOBOX_ENTRY_NOTFOUND))
+    if (m_pBookmarksBox->GetSelectionCount() > 0)
     {
-        OUString sEntry(comphelper::string::remove(m_pBookmarkBox->GetText(),
-            m_pBookmarkBox->GetMultiSelectionSeparator()));
+        m_pInsertBtn->Disable();
+        m_pGotoBtn->Enable(m_pBookmarksBox->GetSelectionCount() == 1);
+        m_pRenameBtn->Enable(m_pBookmarksBox->GetSelectionCount() == 1);
+        m_pDeleteBtn->Enable();
+        m_pEditBox->SetText(sEditBoxText);
+    }
+    else
+    {
+        m_pInsertBtn->Enable();
+        m_pGotoBtn->Disable();
+        m_pRenameBtn->Disable();
+        m_pDeleteBtn->Disable();
+    }
+}
 
-        rSh.SetBookmark( vcl::KeyCode(), sEntry, OUString() );
-        rReq.AppendItem( SfxStringItem( FN_INSERT_BOOKMARK, sEntry ) );
-        rReq.Done();
+IMPL_LINK_NOARG_TYPED(SwInsertBookmarkDlg, RenameHdl, Button*, void)
+{
+    if (!ValidateBookmarks())
+        return;
+    if (m_pBookmarksBox->GetSelectionCount() == 0)
+        return;
+
+    SvTreeListEntry* pSelected = m_pBookmarksBox->FirstSelected();
+    sw::mark::IMark* pBookmark = static_cast<sw::mark::IMark*>(pSelected->GetUserData());
+
+    uno::Reference<frame::XModel> xModel = rSh.GetView().GetDocShell()->GetBaseModel();
+    uno::Reference<text::XBookmarksSupplier> xBkms(xModel, uno::UNO_QUERY);
+    uno::Reference<container::XNameAccess> xNameAccess = xBkms->getBookmarks();
+    uno::Any aObj = xNameAccess->getByName(pBookmark->GetName());
+    uno::Reference<uno::XInterface> xTmp;
+    aObj >>= xTmp;
+    uno::Reference<container::XNamed> xNamed(xTmp, uno::UNO_QUERY);
+    SwAbstractDialogFactory* pFact = swui::GetFactory();
+    OSL_ENSURE(pFact, "SwAbstractDialogFactory fail!");
+    std::unique_ptr<AbstractSwRenameXNamedDlg> pDlg(pFact->CreateSwRenameXNamedDlg(this, xNamed, xNameAccess));
+    OSL_ENSURE(pDlg, "Dialog creation failed!");
+    pDlg->SetForbiddenChars(BookmarkTable::aForbiddenChars + OUStringLiteral1<BookmarkTable::cSeparator>());
+
+    if (pDlg->Execute())
+    {
+        ValidateBookmarks();
+        m_pDeleteBtn->Disable();
+        m_pGotoBtn->Disable();
+        m_pRenameBtn->Disable();
+        m_pInsertBtn->Disable();
     }
+}
 
-    if ( !rReq.IsDone() )
+// callback to a insert button. Inserts a new text mark to the current position.
+IMPL_LINK_NOARG_TYPED(SwInsertBookmarkDlg, InsertHdl, Button*, void)
+{
+    OUString sBookmark = m_pEditBox->GetText();
+    rSh.SetBookmark(vcl::KeyCode(), sBookmark, OUString());
+    rReq.AppendItem(SfxStringItem(FN_INSERT_BOOKMARK, sBookmark));
+    rReq.Done();
+    if (!rReq.IsDone())
         rReq.Ignore();
 
+    Close();
 }
 
-SwInsertBookmarkDlg::SwInsertBookmarkDlg( vcl::Window *pParent, SwWrtShell &rS, SfxRequest& rRequest ) :
-    SvxStandardDialog(pParent, "InsertBookmarkDialog", "modules/swriter/ui/insertbookmark.ui"),
-    rSh( rS ),
-    rReq( rRequest )
+void SwInsertBookmarkDlg::GotoSelectedBookmark()
 {
-    get(m_pBookmarkBox, "bookmarks");
-    get(m_pOkBtn, "ok");
-    get(m_pDeleteBtn, "delete");
+    if (!ValidateBookmarks())
+        return;
+    // if no entries selected we cant jump anywhere
+    // shouldn't be needed as we disable GoTo button when jump is not possible
+    if (m_pBookmarksBox->GetSelectionCount() == 0)
+        return;
 
-    m_pBookmarkBox->SetModifyHdl(LINK(this, SwInsertBookmarkDlg, ModifyHdl));
-    m_pBookmarkBox->EnableMultiSelection(true);
-    m_pBookmarkBox->EnableAutocomplete( true, true );
+    sw::mark::IMark* pBookmark = static_cast<sw::mark::IMark*>(m_pBookmarksBox->FirstSelected()->GetUserData());
 
-    m_pDeleteBtn->SetClickHdl(LINK(this, SwInsertBookmarkDlg, DeleteHdl));
+    rSh.EnterStdMode();
+    rSh.GotoMark(pBookmark);
+}
+
+bool SwInsertBookmarkDlg::ValidateBookmarks()
+{
+    if (HaveBookmarksChanged())
+    {
+        PopulateTable();
+        m_pEditBox->SetText("");
+        return false;
+    }
+    return true;
+}
 
-    // fill Combobox with existing bookmarks
+bool SwInsertBookmarkDlg::HaveBookmarksChanged()
+{
     IDocumentMarkAccess* const pMarkAccess = rSh.getIDocumentMarkAccess();
-    for( IDocumentMarkAccess::const_iterator_t ppBookmark = pMarkAccess->getBookmarksBegin();
-        ppBookmark != pMarkAccess->getBookmarksEnd();
-        ++ppBookmark)
+    if (pMarkAccess->getBookmarksCount() != static_cast<sal_Int32>(aTableBookmarks.size()))
+        return true;
+
+    IDocumentMarkAccess::const_iterator_t ppBookmark = pMarkAccess->getBookmarksBegin();
+    for (sal_Int32 i = 0; i < static_cast<sal_Int32>(aTableBookmarks.size()); i++)
     {
-        if(IDocumentMarkAccess::MarkType::BOOKMARK == IDocumentMarkAccess::GetType(**ppBookmark))
+        if (IDocumentMarkAccess::MarkType::BOOKMARK == IDocumentMarkAccess::GetType(**ppBookmark))
         {
-            m_pBookmarkBox->InsertSwEntry(
-                    SwBoxEntry(ppBookmark->get()->GetName()));
+            if (aTableBookmarks[i].first != ppBookmark->get() ||
+                aTableBookmarks[i].second != ppBookmark->get()->GetName())
+                return true;
         }
+        ++ppBookmark;
     }
-
-    sRemoveWarning = OUString(SW_RES(STR_REMOVE_WARNING));
+    return false;
 }
 
-SwInsertBookmarkDlg::~SwInsertBookmarkDlg()
+void SwInsertBookmarkDlg::PopulateTable()
 {
-    disposeOnce();
+    aTableBookmarks.clear();
+    m_pBookmarksBox->Clear();
+    IDocumentMarkAccess* const pMarkAccess = rSh.getIDocumentMarkAccess();
+    for (IDocumentMarkAccess::const_iterator_t ppBookmark = pMarkAccess->getBookmarksBegin();
+         ppBookmark != pMarkAccess->getBookmarksEnd(); ++ppBookmark)
+    {
+        if (IDocumentMarkAccess::MarkType::BOOKMARK == IDocumentMarkAccess::GetType(**ppBookmark))
+        {
+            m_pBookmarksBox->InsertBookmark(ppBookmark->get());
+            aTableBookmarks.push_back(std::make_pair(ppBookmark->get(), ppBookmark->get()->GetName()));
+        }
+    }
 }
 
-void SwInsertBookmarkDlg::dispose()
+void SwInsertBookmarkDlg::Apply()
 {
-    m_pBookmarkBox.clear();
-    m_pOkBtn.clear();
-    m_pDeleteBtn.clear();
-    SvxStandardDialog::dispose();
 }
 
-BookmarkCombo::BookmarkCombo(vcl::Window* pWin, WinBits nStyle)
-    : SwComboBox(pWin, nStyle)
+SwInsertBookmarkDlg::SwInsertBookmarkDlg(vcl::Window* pParent, SwWrtShell& rS, SfxRequest& rRequest) :
+    SvxStandardDialog(pParent, "InsertBookmarkDialog", "modules/swriter/ui/insertbookmark.ui"),
+    rSh(rS),
+    rReq(rRequest)
 {
+    get(m_pBookmarksContainer, "bookmarks");
+    get(m_pEditBox, "name");
+    get(m_pInsertBtn, "insert");
+    get(m_pDeleteBtn, "delete");
+    get(m_pGotoBtn, "goto");
+    get(m_pRenameBtn, "rename");
+
+    m_pBookmarksBox = VclPtr<BookmarkTable>::Create(*m_pBookmarksContainer);
+
+    m_pBookmarksBox->SetSelectHdl(LINK(this, SwInsertBookmarkDlg, SelectionChangedHdl));
+    m_pBookmarksBox->SetDeselectHdl(LINK(this, SwInsertBookmarkDlg, SelectionChangedHdl));
+    m_pBookmarksBox->SetDoubleClickHdl(LINK(this, SwInsertBookmarkDlg, DoubleClickHdl));
+    m_pEditBox->SetModifyHdl(LINK(this, SwInsertBookmarkDlg, ModifyHdl));
+    m_pInsertBtn->SetClickHdl(LINK(this, SwInsertBookmarkDlg, InsertHdl));
+    m_pDeleteBtn->SetClickHdl(LINK(this, SwInsertBookmarkDlg, DeleteHdl));
+    m_pGotoBtn->SetClickHdl(LINK(this, SwInsertBookmarkDlg, GotoHdl));
+    m_pRenameBtn->SetClickHdl(LINK(this, SwInsertBookmarkDlg, RenameHdl));
+
+    m_pDeleteBtn->Disable();
+    m_pGotoBtn->Disable();
+    m_pRenameBtn->Disable();
+
+    PopulateTable();
+
+    m_pEditBox->SetText(m_pBookmarksBox->GetNameProposal());
+    m_pEditBox->SetCursorAtLast();
+
+    sRemoveWarning = OUString(SW_RES(STR_REMOVE_WARNING));
 }
 
-sal_Int32 BookmarkCombo::GetFirstSelEntryPos() const
+SwInsertBookmarkDlg::~SwInsertBookmarkDlg()
 {
-    return GetSelEntryPos(0);
+    disposeOnce();
 }
 
-sal_Int32 BookmarkCombo::GetNextSelEntryPos(sal_Int32 nPos) const
+void SwInsertBookmarkDlg::dispose()
 {
-    return GetSelEntryPos(nPos + 1);
+    m_pBookmarksBox.disposeAndClear();
+    m_pBookmarksContainer.clear();
+    m_pInsertBtn.clear();
+    m_pDeleteBtn.clear();
+    m_pGotoBtn.clear();
+    m_pEditBox.clear();
+    SvxStandardDialog::dispose();
 }
 
-sal_Int32 BookmarkCombo::GetSelEntryPos(sal_Int32 nPos) const
+BookmarkTable::BookmarkTable(SvSimpleTableContainer& rParent) :
+    SvSimpleTable(rParent, 0)
 {
-    sal_Unicode cSep = GetMultiSelectionSeparator();
+    static long nTabs[] = {3, 0, 30, 150};
 
-    sal_Int32 nCnt = comphelper::string::getTokenCount(GetText(), cSep);
-
-    for (; nPos < nCnt; nPos++)
-    {
-        OUString sEntry(comphelper::string::strip(GetText().getToken(nPos, cSep), ' '));
-        if (GetEntryPos(sEntry) != COMBOBOX_ENTRY_NOTFOUND)
-            return nPos;
-    }
+    SetTabs(nTabs, MAP_PIXEL);
+    SetSelectionMode(MULTIPLE_SELECTION);
+    InsertHeaderEntry("Page");
+    InsertHeaderEntry("Name");
+    InsertHeaderEntry("Text");
 
-    return COMBOBOX_ENTRY_NOTFOUND;
+    rParent.SetTable(this);
 }
 
-sal_Int32 BookmarkCombo::GetSelectEntryCount() const
+void BookmarkTable::InsertBookmark(sw::mark::IMark* pMark)
 {
-    sal_Int32 nCnt = 0;
-
-    sal_Int32 nPos = GetFirstSelEntryPos();
-    while (nPos != COMBOBOX_ENTRY_NOTFOUND)
+    OUString sBookmarkNodeText = pMark->GetMarkStart().nNode.GetNode().GetTextNode()->GetText();
+    sal_Int32 nBookmarkNodeTextPos = pMark->GetMarkStart().nContent.GetIndex();
+    sal_Int32 nBookmarkTextLen = 0;
+    bool bPulledAll = false;
+    bool bPulling = false;
+    static const sal_Int32 nMaxTextLen = 50;
+
+    if (pMark->IsExpanded())
     {
-        nPos = GetNextSelEntryPos(nPos);
-        nCnt++;
+        nBookmarkTextLen = pMark->GetMarkEnd().nContent.GetIndex() - nBookmarkNodeTextPos;
     }
-
-    return nCnt;
+    else
+    {
+        if (nBookmarkNodeTextPos == sBookmarkNodeText.getLength()) // no text after bookmark
+        {
+            nBookmarkNodeTextPos = std::max<sal_Int32>(0, nBookmarkNodeTextPos - nMaxTextLen);
+            bPulling = true;
+            if (nBookmarkNodeTextPos == 0)
+                bPulledAll = true;
+        }
+        nBookmarkTextLen = sBookmarkNodeText.getLength() - nBookmarkNodeTextPos;
+    }
+    bool bExceedsLength = nBookmarkTextLen > nMaxTextLen;
+    nBookmarkTextLen = std::min<sal_Int32>(nMaxTextLen, nBookmarkTextLen);
+    sBookmarkNodeText = sBookmarkNodeText.copy(nBookmarkNodeTextPos, nBookmarkTextLen).trim();
+    if (bExceedsLength)
+        sBookmarkNodeText += "...";
+    else if (bPulling && !bPulledAll)
+        sBookmarkNodeText = "..." + sBookmarkNodeText;
+
+    OUString sPageNum = OUString::number(SwPaM(pMark->GetMarkStart()).GetPageNum());
+    OUString sColumnData = sPageNum + "\t" + pMark->GetName() + "\t" + sBookmarkNodeText;
+    InsertEntryToColumn(sColumnData, TREELIST_APPEND, 0xffff, pMark);
 }
 
-// position inside of the listbox (the ComboBox)
-sal_Int32 BookmarkCombo::GetSelectEntryPos( sal_Int32 nSelIndex ) const
+SvTreeListEntry* BookmarkTable::GetRowByBookmarkName(const OUString& sName)
 {
-    sal_Int32 nCnt = 0;
-    sal_Int32 nPos = GetFirstSelEntryPos();
-    while (nPos != COMBOBOX_ENTRY_NOTFOUND)
+    SvTreeListEntry* pEntry = First();
+    for (sal_Int32 i = GetRowCount(); i; i--)
     {
-        if (nSelIndex == nCnt)
+        sw::mark::IMark* pBookmark = static_cast<sw::mark::IMark*>(pEntry->GetUserData());
+        if (pBookmark->GetName() == sName)
         {
-            sal_Unicode cSep = GetMultiSelectionSeparator();
-            OUString sEntry(comphelper::string::strip(GetText().getToken(nPos, cSep), ' '));
-            return GetEntryPos(sEntry);
+            return pEntry;
         }
-        nPos = GetNextSelEntryPos(nPos);
-        nCnt++;
+        pEntry = Next(pEntry);
     }
+    return nullptr;
+}
+
+sw::mark::IMark* BookmarkTable::GetBookmarkByName(const OUString& sName)
+{
+    SvTreeListEntry* pEntry = GetRowByBookmarkName(sName);
+    if (!pEntry)
+        return nullptr;
 
-    return COMBOBOX_ENTRY_NOTFOUND;
+    return static_cast<sw::mark::IMark*>(pEntry->GetUserData());
 }
 
-bool BookmarkCombo::PreNotify( NotifyEvent& rNEvt )
+void BookmarkTable::SelectByName(const OUString& sName)
 {
-    bool bHandled = false;
-    if( MouseNotifyEvent::KEYINPUT == rNEvt.GetType() &&
-         rNEvt.GetKeyEvent()->GetCharCode() )
+    SvTreeListEntry* pEntry = GetRowByBookmarkName(sName);
+    if (!pEntry)
+        return;
+
+    Select(pEntry);
+}
+
+OUString BookmarkTable::GetNameProposal()
+{
+    sal_Int32 nHighestBookmarkId = 0;
+    SvTreeListEntry* pEntry = First();
+    for (sal_Int32 i = GetRowCount(); i; i--)
     {
-        OUString sKey( rNEvt.GetKeyEvent()->GetCharCode() );
-        if(-1 != aForbiddenChars.indexOf(sKey))
-            bHandled = true;
+        sw::mark::IMark* pBookmark = static_cast<sw::mark::IMark*>(pEntry->GetUserData());
+        OUString sName = pBookmark->GetName();
+        sal_Int32 nIndex = 0;
+        if (sName.getToken(0, ' ', nIndex) == sDefaultBookmarkName)
+        {
+            sal_Int32 nCurrBookmarkId = sName.getToken(0, ' ', nIndex).toInt32();
+            nHighestBookmarkId = std::max<sal_Int32>(nHighestBookmarkId, nCurrBookmarkId);
+        }
+        pEntry = Next(pEntry);
     }
-    if(!bHandled)
-        bHandled = SwComboBox::PreNotify( rNEvt );
-    return bHandled;
+    return sDefaultBookmarkName + " " + OUString::number(nHighestBookmarkId + 1);
 }
 
-VCL_BUILDER_FACTORY_ARGS(BookmarkCombo, 0)
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/inc/bookmark.hxx b/sw/source/uibase/inc/bookmark.hxx
index 7a94dc3..0754f69 100644
--- a/sw/source/uibase/inc/bookmark.hxx
+++ b/sw/source/uibase/inc/bookmark.hxx
@@ -21,47 +21,68 @@
 
 #include <svx/stddlg.hxx>
 #include <vcl/fixed.hxx>
+#include <ndtxt.hxx>
 
 #include <vcl/button.hxx>
+#include <svtools/simptabl.hxx>
+#include <pam.hxx>
 
 #include "swlbox.hxx"
+#include "IMark.hxx"
 
 class SwWrtShell;
 class SfxRequest;
 
-class BookmarkCombo : public SwComboBox
+class BookmarkTable : public SvSimpleTable
 {
-    sal_Int32           GetFirstSelEntryPos() const;
-    sal_Int32           GetNextSelEntryPos(sal_Int32  nPos) const;
-    sal_Int32           GetSelEntryPos(sal_Int32  nPos) const;
-
-    virtual bool    PreNotify(NotifyEvent& rNEvt) override;
+    SvTreeListEntry*    GetRowByBookmarkName(const OUString& sName);
 public:
-    BookmarkCombo(vcl::Window* pWin, WinBits nStyle);
-
-    sal_Int32           GetSelectEntryCount() const;
-    sal_Int32           GetSelectEntryPos( sal_Int32  nSelIndex = 0 ) const;
+    BookmarkTable(SvSimpleTableContainer& rParent);
+    void                InsertBookmark(sw::mark::IMark* pMark);
+    void                SelectByName(const OUString& sName);
+    sw::mark::IMark*    GetBookmarkByName(const OUString& sName);
+    OUString            GetNameProposal();
 
     static const OUString aForbiddenChars;
+    static const OUString sDefaultBookmarkName;
+    static const char     cSeparator;
 };
 
 class SwInsertBookmarkDlg: public SvxStandardDialog
 {
-    VclPtr<BookmarkCombo>  m_pBookmarkBox;
-    VclPtr<OKButton>       m_pOkBtn;
-    VclPtr<PushButton>     m_pDeleteBtn;
-
-    OUString        sRemoveWarning;
-    SwWrtShell      &rSh;
-    SfxRequest&     rReq;
+    VclPtr<SvSimpleTableContainer>      m_pBookmarksContainer;
+    VclPtr<BookmarkTable>               m_pBookmarksBox;
+    VclPtr<Edit>                        m_pEditBox;
+    VclPtr<PushButton>                  m_pInsertBtn;
+    VclPtr<PushButton>                  m_pDeleteBtn;
+    VclPtr<PushButton>                  m_pGotoBtn;
+    VclPtr<PushButton>                  m_pRenameBtn;
+    OUString                            sRemoveWarning;
+    SwWrtShell&                         rSh;
+    SfxRequest&                         rReq;
+    std::vector<std::pair<sw::mark::IMark*, OUString>> aTableBookmarks;
 
     DECL_LINK_TYPED(ModifyHdl, Edit&, void);
+    DECL_LINK_TYPED(InsertHdl, Button*, void);
     DECL_LINK_TYPED(DeleteHdl, Button*, void);
+    DECL_LINK_TYPED(RenameHdl, Button*, void);
+    DECL_LINK_TYPED(GotoHdl, Button*, void);
+    DECL_LINK_TYPED(SelectionChangedHdl, SvTreeListBox*, void);
+    DECL_LINK_TYPED(DoubleClickHdl, SvTreeListBox*, bool);
 
+    // Fill table with bookmarks
+    void PopulateTable();
+    /**
+     * Check if displayed bookmarks are up-to date, if not update them.
+     * @return True if no update was needed.
+     */
+    bool ValidateBookmarks();
+    bool HaveBookmarksChanged();
+    void GotoSelectedBookmark();
     virtual void Apply() override;
 
 public:
-    SwInsertBookmarkDlg(vcl::Window *pParent, SwWrtShell &rSh, SfxRequest& rReq);
+    SwInsertBookmarkDlg(vcl::Window* pParent, SwWrtShell& rSh, SfxRequest& rReq);
     virtual ~SwInsertBookmarkDlg();
     virtual void dispose() override;
 };
diff --git a/sw/uiconfig/swriter/ui/insertbookmark.ui b/sw/uiconfig/swriter/ui/insertbookmark.ui
index 080af59..49cd3eb 100644
--- a/sw/uiconfig/swriter/ui/insertbookmark.ui
+++ b/sw/uiconfig/swriter/ui/insertbookmark.ui
@@ -1,78 +1,76 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.16.0 -->
+<!-- Generated with glade 3.18.3 -->
 <interface>
   <requires lib="gtk+" version="3.0"/>
   <object class="GtkDialog" id="InsertBookmarkDialog">
     <property name="can_focus">False</property>
     <property name="border_width">6</property>
-    <property name="title" translatable="yes">Insert Bookmark</property>
+    <property name="title" translatable="yes">Bookmark</property>
     <property name="type_hint">dialog</property>
     <child internal-child="vbox">
       <object class="GtkBox" id="dialog-vbox1">
         <property name="can_focus">False</property>
         <property name="orientation">vertical</property>
         <property name="spacing">12</property>
-        <child internal-child="action_area">
-          <object class="GtkButtonBox" id="dialog-action_area1">
+        <child>
+          <object class="GtkBox" id="box1">
+            <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="layout_style">end</property>
+            <property name="spacing">6</property>
             <child>
-              <object class="GtkButton" id="ok">
-                <property name="label">gtk-ok</property>
+              <object class="GtkEntry" id="name">
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="has_default">True</property>
-                <property name="receives_default">True</property>
-                <property name="use_stock">True</property>
+                <property name="max_width_chars">0</property>
               </object>
               <packing>
-                <property name="expand">False</property>
+                <property name="expand">True</property>
                 <property name="fill">True</property>
+                <property name="pack_type">start</property>
                 <property name="position">0</property>
               </packing>
             </child>
             <child>
-              <object class="GtkButton" id="cancel">
-                <property name="label">gtk-cancel</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="use_stock">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="delete">
-                <property name="label" translatable="yes">Delete</property>
+              <object class="GtkButtonBox" id="box5">
                 <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
+                <property name="can_focus">False</property>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkButton" id="insert">
+                    <property name="label">Insert</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="can_default">True</property>
+                    <property name="has_default">True</property>
+                    <property name="receives_default">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
               </object>
               <packing>
                 <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">2</property>
+                <property name="fill">False</property>
+                <property name="pack_type">end</property>
+                <property name="position">0</property>
               </packing>
             </child>
           </object>
           <packing>
             <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="pack_type">end</property>
+            <property name="fill">False</property>
             <property name="position">0</property>
           </packing>
         </child>
         <child>
-          <object class="swuilo-BookmarkCombo" id="bookmarks">
-              <property name="width_request">150</property>
-              <property name="height_request">200</property>
-              <property name="visible">True</property>
-              <property name="can_focus">True</property>
+          <object class="svtlo-SvSimpleTableContainer" id="bookmarks">
+            <property name="width_request">350</property>
+            <property name="height_request">250</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
           </object>
           <packing>
             <property name="expand">True</property>
@@ -80,12 +78,114 @@
             <property name="position">1</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkBox" id="box2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkButtonBox" id="box4">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkButton" id="help">
+                    <property name="label">gtk-help</property>
+                    <property name="width_request">75</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_stock">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="pack_type">start</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButtonBox" id="box4">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="homogeneous">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkButton" id="rename">
+                    <property name="label" translatable="yes">Rename</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="delete">
+                    <property name="label" translatable="yes">Delete</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="goto">
+                    <property name="label" translatable="yes">Go to</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="close">
+                    <property name="label">gtk-close</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_stock">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="pack_type">end</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
       </object>
     </child>
-    <action-widgets>
-      <action-widget response="0">ok</action-widget>
-      <action-widget response="0">cancel</action-widget>
-      <action-widget response="0">delete</action-widget>
-    </action-widgets>
   </object>
 </interface>


More information about the Libreoffice-commits mailing list