/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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); std::unique_ptr xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), VclMessageType::Info, VclButtonsType::Ok, sRemoveWarning + sMsg)); xInfoBox->run(); } 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(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; OUStringBuffer sEditBoxText; SvTreeListEntry* pSelected = m_pBookmarksBox->FirstSelected(); for (sal_Int32 i = m_pBookmarksBox->GetSelectionCount(); i; i--) { sw::mark::IMark* pBookmark = static_cast(pSelected->GetUserData()); const OUString& sEntryName = pBookmark->GetName(); sEditBoxText.append(sEntryName); if (i > 1) sEditBoxText.append(";"); 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.makeStringAndClear()); } 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(pSelected->GetUserData()); uno::Reference xModel = rSh.GetView().GetDocShell()->GetBaseModel(); uno::Reference xBkms(xModel, uno::UNO_QUERY); uno::Reference xNameAccess = xBkms->getBookmarks(); uno::Any aObj = xNameAccess->getByName(pBookmark->GetName()); uno::Reference xTmp; aObj >>= xTmp; uno::Reference xNamed(xTmp, uno::UNO_QUERY); SwAbstractDialogFactory& rFact = swui::GetFactory(); ScopedVclPtr pDlg(rFact.CreateSwRenameXNamedDlg(GetFrameWeld(), xNamed, xNameAccess)); 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.SetBookmark2(vcl::KeyCode(), sBookmark, m_pHideCB->IsChecked(), m_pConditionED->GetText()); rReq.AppendItem(SfxStringItem(FN_INSERT_BOOKMARK, sBookmark)); rReq.Done(); if (!rReq.IsDone()) rReq.Ignore(); EndDialog(RET_OK); } IMPL_LINK(SwInsertBookmarkDlg, ChangeHideHdl, Button *, pBox, void) { bool bHide = static_cast(pBox)->IsChecked(); m_pConditionED->Enable(bHide); m_pConditionFT->Enable(bHide); } 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(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>::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"); get(m_pHideCB, "hide"); get(m_pConditionFT, "condlabel"); get(m_pConditionED, "withcond"); m_pBookmarksBox = VclPtr::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_pHideCB->SetClickHdl(LINK(this, SwInsertBookmarkDlg, ChangeHideHdl)); 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(); m_pHideCB.clear(); m_pConditionFT.clear(); m_pConditionED.clear(); SvxStandardDialog::dispose(); } BookmarkTable::BookmarkTable(SvSimpleTableContainer& rParent) : SvSimpleTable(rParent, 0) { static long nTabs[] = { 0, 40, 150, 300, 340 }; SetTabs(SAL_N_ELEMENTS(nTabs), nTabs, MapUnit::MapPixel); SetSelectionMode(SelectionMode::Multiple); InsertHeaderEntry(SwResId(STR_PAGE)); InsertHeaderEntry(SwResId(STR_BOOKMARK_NAME)); InsertHeaderEntry(SwResId(STR_BOOKMARK_TEXT)); InsertHeaderEntry(SwResId(STR_BOOKMARK_HIDDEN)); InsertHeaderEntry(SwResId(STR_BOOKMARK_CONDITION)); rParent.SetTable(this); } void BookmarkTable::InsertBookmark(sw::mark::IMark* pMark) { sw::mark::IBookmark* pBookmark = dynamic_cast(pMark); assert(pBookmark); OUString sBookmarkNodeText = pBookmark->GetMarkStart().nNode.GetNode().GetTextNode()->GetText(); sal_Int32 nBookmarkNodeTextPos = pBookmark->GetMarkStart().nContent.GetIndex(); sal_Int32 nBookmarkTextLen = 0; bool bPulledAll = false; bool bPulling = false; static const sal_Int32 nMaxTextLen = 50; if (pBookmark->IsExpanded()) { nBookmarkTextLen = pBookmark->GetMarkEnd().nContent.GetIndex() - nBookmarkNodeTextPos; } else { if (nBookmarkNodeTextPos == sBookmarkNodeText.getLength()) // no text after bookmark { nBookmarkNodeTextPos = std::max(0, nBookmarkNodeTextPos - nMaxTextLen); bPulling = true; if (nBookmarkNodeTextPos == 0) bPulledAll = true; } nBookmarkTextLen = sBookmarkNodeText.getLength() - nBookmarkNodeTextPos; } bool bExceedsLength = nBookmarkTextLen > nMaxTextLen; nBookmarkTextLen = std::min(nMaxTextLen, nBookmarkTextLen); sBookmarkNodeText = sBookmarkNodeText.copy(nBookmarkNodeTextPos, nBookmarkTextLen).trim(); if (bExceedsLength) sBookmarkNodeText += "..."; else if (bPulling && !bPulledAll) sBookmarkNodeText = "..." + sBookmarkNodeText; OUString sHidden = "No"; if (pBookmark->IsHidden()) sHidden = "Yes"; const OUString& sHideCondition = pBookmark->GetHideCondition(); OUString sPageNum = OUString::number(SwPaM(pMark->GetMarkStart()).GetPageNum()); OUString sColumnData = sPageNum + "\t" + pBookmark->GetName() + "\t" + sBookmarkNodeText + "\t" + sHidden + "\t" + sHideCondition; InsertEntryToColumn(sColumnData, TREELIST_APPEND, 0xffff, pMark); } SvTreeListEntry* BookmarkTable::GetRowByBookmarkName(const OUString& sName) { SvTreeListEntry* pEntry = First(); while (pEntry) { sw::mark::IMark* pBookmark = static_cast(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(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(pEntry->GetUserData()); const 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(nHighestBookmarkId, nCurrBookmarkId); } pEntry = Next(pEntry); } return sDefaultBookmarkName + " " + OUString::number(nHighestBookmarkId + 1); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */