summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Trzebiatowski <ubap.dev@gmail.com>2016-03-11 20:58:34 +0100
committerMiklos Vajna <vmiklos@collabora.co.uk>2016-03-25 08:53:50 +0000
commit08da15cabdcef60191f4ed98ed694eba3e35b5e1 (patch)
tree50ca7ad892cbbfa171f948d831032f5ea4604dcc
parentd1b8dcd5d3fa545df4f4ed2714d4424b32286173 (diff)
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@libreoffice.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
-rw-r--r--sw/source/ui/misc/bookmark.cxx457
-rw-r--r--sw/source/uibase/inc/bookmark.hxx57
-rw-r--r--sw/uiconfig/swriter/ui/insertbookmark.ui188
3 files changed, 511 insertions, 191 deletions
diff --git a/sw/source/ui/misc/bookmark.cxx b/sw/source/ui/misc/bookmark.cxx
index c12da8dcbdce..a65ddaf545cb 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 7a94dc3473eb..0754f6988bac 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 080af59d5f3a..49cd3eb5322e 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>