451 lines
15 KiB
C++
451 lines
15 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <comphelper/string.hxx>
|
|
#include <sfx2/request.hxx>
|
|
#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 <docsh.hxx>
|
|
#include <globals.hrc>
|
|
#include <strings.hrc>
|
|
|
|
using namespace ::com::sun::star;
|
|
|
|
const OUString BookmarkTable::aForbiddenChars("/\\@*?\",#");
|
|
const char BookmarkTable::cSeparator(';');
|
|
|
|
// callback to modify EditBox
|
|
IMPL_LINK_NOARG(SwInsertBookmarkDlg, ModifyHdl, Edit&, void)
|
|
{
|
|
ValidateBookmarks();
|
|
m_pBookmarksBox->SelectAll(false);
|
|
// if a string has been pasted from the clipboard then
|
|
// there may be illegal characters in the box
|
|
// sanitization
|
|
OUString sTmp = m_pEditBox->GetText();
|
|
OUString sMsg;
|
|
const sal_Int32 nLen = sTmp.getLength();
|
|
for (sal_Int32 i = 0; i < BookmarkTable::aForbiddenChars.getLength(); i++)
|
|
{
|
|
const sal_Int32 nTmpLen = sTmp.getLength();
|
|
sTmp = sTmp.replaceAll(OUStringLiteral1(BookmarkTable::aForbiddenChars[i]), "");
|
|
if (sTmp.getLength() != nTmpLen)
|
|
sMsg += OUStringLiteral1(BookmarkTable::aForbiddenChars[i]);
|
|
}
|
|
if (sTmp.getLength() != nLen)
|
|
{
|
|
m_pEditBox->SetText(sTmp);
|
|
ScopedVclPtrInstance<InfoBox>(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))
|
|
{
|
|
m_pBookmarksBox->SelectByName(aToken);
|
|
nSelectedEntries++;
|
|
}
|
|
nEntries++;
|
|
}
|
|
|
|
// allow to add new bookmark only if one name provided and it's 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(SwInsertBookmarkDlg, DeleteHdl, Button*, void)
|
|
{
|
|
if (!ValidateBookmarks())
|
|
return;
|
|
if (m_pBookmarksBox->GetSelectionCount() == 0)
|
|
return;
|
|
|
|
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();
|
|
}
|
|
|
|
// callback to a goto button
|
|
IMPL_LINK_NOARG(SwInsertBookmarkDlg, GotoHdl, Button*, void)
|
|
{
|
|
GotoSelectedBookmark();
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SwInsertBookmarkDlg, DoubleClickHdl, SvTreeListBox*, bool)
|
|
{
|
|
GotoSelectedBookmark();
|
|
return true;
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SwInsertBookmarkDlg, SelectionChangedHdl, SvTreeListBox*, void)
|
|
{
|
|
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--)
|
|
{
|
|
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);
|
|
}
|
|
if (m_pBookmarksBox->GetSelectionCount() > 0)
|
|
{
|
|
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();
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_NOARG(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!");
|
|
ScopedVclPtr<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();
|
|
}
|
|
}
|
|
|
|
// callback to a insert button. Inserts a new text mark to the current position.
|
|
IMPL_LINK_NOARG(SwInsertBookmarkDlg, InsertHdl, Button*, void)
|
|
{
|
|
OUString sBookmark = m_pEditBox->GetText();
|
|
rSh.SetBookmark(vcl::KeyCode(), sBookmark);
|
|
rReq.AppendItem(SfxStringItem(FN_INSERT_BOOKMARK, sBookmark));
|
|
rReq.Done();
|
|
if (!rReq.IsDone())
|
|
rReq.Ignore();
|
|
|
|
EndDialog(RET_OK);
|
|
}
|
|
|
|
void SwInsertBookmarkDlg::GotoSelectedBookmark()
|
|
{
|
|
if (!ValidateBookmarks())
|
|
return;
|
|
// if no entries selected we can't jump anywhere
|
|
// shouldn't be needed as we disable GoTo button when jump is not possible
|
|
if (m_pBookmarksBox->GetSelectionCount() == 0)
|
|
return;
|
|
|
|
sw::mark::IMark* pBookmark = static_cast<sw::mark::IMark*>(m_pBookmarksBox->FirstSelected()->GetUserData());
|
|
|
|
rSh.EnterStdMode();
|
|
rSh.GotoMark(pBookmark);
|
|
}
|
|
|
|
bool SwInsertBookmarkDlg::ValidateBookmarks()
|
|
{
|
|
if (HaveBookmarksChanged())
|
|
{
|
|
PopulateTable();
|
|
m_pEditBox->SetText("");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SwInsertBookmarkDlg::HaveBookmarksChanged()
|
|
{
|
|
IDocumentMarkAccess* const pMarkAccess = rSh.getIDocumentMarkAccess();
|
|
if (pMarkAccess->getBookmarksCount() != m_nLastBookmarksCount)
|
|
return true;
|
|
|
|
std::vector<std::pair<sw::mark::IMark*, OUString>>::const_iterator aListIter = aTableBookmarks.begin();
|
|
for (IDocumentMarkAccess::const_iterator_t ppBookmark = pMarkAccess->getBookmarksBegin();
|
|
ppBookmark != pMarkAccess->getBookmarksEnd(); ++ppBookmark)
|
|
{
|
|
if (IDocumentMarkAccess::MarkType::BOOKMARK == IDocumentMarkAccess::GetType(**ppBookmark))
|
|
{
|
|
// more bookmarks then expected
|
|
if (aListIter == aTableBookmarks.end())
|
|
return true;
|
|
if (aListIter->first != ppBookmark->get() ||
|
|
aListIter->second != ppBookmark->get()->GetName())
|
|
return true;
|
|
++aListIter;
|
|
}
|
|
}
|
|
// less bookmarks then expected
|
|
return aListIter != aTableBookmarks.end();
|
|
}
|
|
|
|
void SwInsertBookmarkDlg::PopulateTable()
|
|
{
|
|
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.emplace_back(ppBookmark->get(), ppBookmark->get()->GetName());
|
|
}
|
|
}
|
|
m_nLastBookmarksCount = pMarkAccess->getBookmarksCount();
|
|
}
|
|
|
|
void SwInsertBookmarkDlg::Apply()
|
|
{
|
|
}
|
|
|
|
SwInsertBookmarkDlg::SwInsertBookmarkDlg(vcl::Window* pParent, SwWrtShell& rS, SfxRequest& rRequest)
|
|
: SvxStandardDialog(pParent, "InsertBookmarkDialog", "modules/swriter/ui/insertbookmark.ui")
|
|
, rSh(rS)
|
|
, rReq(rRequest)
|
|
, m_nLastBookmarksCount(0)
|
|
{
|
|
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 = SwResId(STR_REMOVE_WARNING);
|
|
}
|
|
|
|
SwInsertBookmarkDlg::~SwInsertBookmarkDlg()
|
|
{
|
|
disposeOnce();
|
|
}
|
|
|
|
void SwInsertBookmarkDlg::dispose()
|
|
{
|
|
m_pBookmarksBox.disposeAndClear();
|
|
m_pBookmarksContainer.clear();
|
|
m_pInsertBtn.clear();
|
|
m_pDeleteBtn.clear();
|
|
m_pGotoBtn.clear();
|
|
m_pEditBox.clear();
|
|
m_pRenameBtn.clear();
|
|
SvxStandardDialog::dispose();
|
|
}
|
|
|
|
BookmarkTable::BookmarkTable(SvSimpleTableContainer& rParent) :
|
|
SvSimpleTable(rParent, 0)
|
|
{
|
|
static long nTabs[] = {3, 0, 40, 150};
|
|
|
|
SetTabs(nTabs, MapUnit::MapPixel);
|
|
SetSelectionMode(SelectionMode::Multiple);
|
|
InsertHeaderEntry(SwResId(STR_PAGE));
|
|
InsertHeaderEntry(SwResId(STR_BOOKMARK_NAME));
|
|
InsertHeaderEntry(SwResId(STR_BOOKMARK_TEXT));
|
|
|
|
rParent.SetTable(this);
|
|
}
|
|
|
|
void BookmarkTable::InsertBookmark(sw::mark::IMark* pMark)
|
|
{
|
|
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())
|
|
{
|
|
nBookmarkTextLen = pMark->GetMarkEnd().nContent.GetIndex() - nBookmarkNodeTextPos;
|
|
}
|
|
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);
|
|
}
|
|
|
|
SvTreeListEntry* BookmarkTable::GetRowByBookmarkName(const OUString& sName)
|
|
{
|
|
SvTreeListEntry* pEntry = First();
|
|
while (pEntry)
|
|
{
|
|
sw::mark::IMark* pBookmark = static_cast<sw::mark::IMark*>(pEntry->GetUserData());
|
|
if (pBookmark->GetName() == sName)
|
|
{
|
|
return pEntry;
|
|
}
|
|
pEntry = Next(pEntry);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
sw::mark::IMark* BookmarkTable::GetBookmarkByName(const OUString& sName)
|
|
{
|
|
SvTreeListEntry* pEntry = GetRowByBookmarkName(sName);
|
|
if (!pEntry)
|
|
return nullptr;
|
|
|
|
return static_cast<sw::mark::IMark*>(pEntry->GetUserData());
|
|
}
|
|
|
|
void BookmarkTable::SelectByName(const OUString& sName)
|
|
{
|
|
SvTreeListEntry* pEntry = GetRowByBookmarkName(sName);
|
|
if (!pEntry)
|
|
return;
|
|
|
|
Select(pEntry);
|
|
}
|
|
|
|
OUString BookmarkTable::GetNameProposal()
|
|
{
|
|
OUString sDefaultBookmarkName = SwResId(STR_BOOKMARK_DEF_NAME);
|
|
sal_Int32 nHighestBookmarkId = 0;
|
|
SvTreeListEntry* pEntry = First();
|
|
while (pEntry)
|
|
{
|
|
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);
|
|
}
|
|
return sDefaultBookmarkName + " " + OUString::number(nHighestBookmarkId + 1);
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|