diff options
Diffstat (limited to 'sw/source/ui/misc')
-rw-r--r-- | sw/source/ui/misc/bookmark.cxx | 516 | ||||
-rw-r--r-- | sw/source/ui/misc/contentcontroldlg.cxx | 414 | ||||
-rw-r--r-- | sw/source/ui/misc/contentcontrollistitemdlg.cxx | 48 | ||||
-rw-r--r-- | sw/source/ui/misc/docfnote.cxx | 394 | ||||
-rw-r--r-- | sw/source/ui/misc/glosbib.cxx | 405 | ||||
-rw-r--r-- | sw/source/ui/misc/glossary.cxx | 1086 | ||||
-rw-r--r-- | sw/source/ui/misc/impfnote.hxx | 83 | ||||
-rw-r--r-- | sw/source/ui/misc/insfnote.cxx | 249 | ||||
-rw-r--r-- | sw/source/ui/misc/linenum.cxx | 260 | ||||
-rw-r--r-- | sw/source/ui/misc/num.cxx | 957 | ||||
-rw-r--r-- | sw/source/ui/misc/outline.cxx | 1078 | ||||
-rw-r--r-- | sw/source/ui/misc/pgfnote.cxx | 313 | ||||
-rw-r--r-- | sw/source/ui/misc/pggrid.cxx | 551 | ||||
-rw-r--r-- | sw/source/ui/misc/srtdlg.cxx | 428 | ||||
-rw-r--r-- | sw/source/ui/misc/swmodalredlineacceptdlg.cxx | 79 | ||||
-rw-r--r-- | sw/source/ui/misc/titlepage.cxx | 334 |
16 files changed, 7195 insertions, 0 deletions
diff --git a/sw/source/ui/misc/bookmark.cxx b/sw/source/ui/misc/bookmark.cxx new file mode 100644 index 000000000..a25e85164 --- /dev/null +++ b/sw/source/ui/misc/bookmark.cxx @@ -0,0 +1,516 @@ +/* -*- 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 <rtl/ustrbuf.hxx> +#include <sfx2/request.hxx> +#include <svl/stritem.hxx> +#include <unotools/viewoptions.hxx> +#include <vcl/weld.hxx> +#include <o3tl/string_view.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/text/XBookmarksSupplier.hpp> +#include <officecfg/Office/Common.hxx> + +#include <swabstdlg.hxx> +#include <swuiexp.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <cmdid.h> +#include <bookmark.hxx> +#include <docsh.hxx> +#include <ndtxt.hxx> +#include <strings.hrc> +#include <IDocumentSettingAccess.hxx> + +using namespace ::com::sun::star; + +const char BookmarkTable::cSeparator(';'); + +// callback to modify EditBox +IMPL_LINK_NOARG(SwInsertBookmarkDlg, ModifyHdl, weld::Entry&, void) +{ + ValidateBookmarks(); + m_xBookmarksBox->unselect_all(); + // if a string has been pasted from the clipboard then + // there may be illegal characters in the box + // sanitization + OUString sTmp = m_xEditBox->get_text(); + 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(OUStringChar(BookmarkTable::aForbiddenChars.getStr()[i]), ""); + if (sTmp.getLength() != nTmpLen) + sMsg += OUStringChar(BookmarkTable::aForbiddenChars.getStr()[i]); + } + const bool bHasForbiddenChars = sTmp.getLength() != nLen; + m_xForbiddenChars->set_visible(bHasForbiddenChars); + if (bHasForbiddenChars) + m_xEditBox->set_message_type(weld::EntryMessageType::Error); + else + m_xEditBox->set_message_type(weld::EntryMessageType::Normal); + + 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_xBookmarksBox->GetBookmarkByName(aToken)) + { + m_xBookmarksBox->SelectByName(aToken); + nSelectedEntries++; + } + nEntries++; + } + + // allow to add new bookmark only if one name provided and it's not taken + m_xInsertBtn->set_sensitive(nEntries == 1 && nSelectedEntries == 0 && !bHasForbiddenChars + && !m_bAreProtected); + + // allow to delete only if all bookmarks are recognized + m_xDeleteBtn->set_sensitive(nEntries > 0 && nSelectedEntries == nEntries && !m_bAreProtected); + m_xGotoBtn->set_sensitive(nEntries == 1 && nSelectedEntries == 1); + m_xRenameBtn->set_sensitive(nEntries == 1 && nSelectedEntries == 1 && !m_bAreProtected); +} + +// callback to delete a text mark +IMPL_LINK_NOARG(SwInsertBookmarkDlg, DeleteHdl, weld::Button&, void) +{ + if (!ValidateBookmarks()) + return; + + int nSelectedRows(0); + + m_xBookmarksBox->selected_foreach([this, &nSelectedRows](weld::TreeIter& rEntry) { + // remove from model + sw::mark::IMark* pBookmark + = weld::fromId<sw::mark::IMark*>(m_xBookmarksBox->get_id(rEntry)); + OUString sRemoved = pBookmark->GetName(); + IDocumentMarkAccess* const pMarkAccess = rSh.getIDocumentMarkAccess(); + pMarkAccess->deleteMark(pMarkAccess->findMark(sRemoved), false); + 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()); + + ++nSelectedRows; + + return false; + }); + + if (!nSelectedRows) + return; + + // remove from BookmarkTable + m_xBookmarksBox->remove_selection(); + + ValidateBookmarks(); + + m_xDeleteBtn->set_sensitive(false); + m_xGotoBtn->set_sensitive(false); + m_xRenameBtn->set_sensitive(false); + m_xInsertBtn->set_sensitive(false); +} + +// callback to a goto button +IMPL_LINK_NOARG(SwInsertBookmarkDlg, GotoHdl, weld::Button&, void) { GotoSelectedBookmark(); } + +IMPL_LINK_NOARG(SwInsertBookmarkDlg, DoubleClickHdl, weld::TreeView&, bool) +{ + GotoSelectedBookmark(); + return true; +} + +IMPL_LINK_NOARG(SwInsertBookmarkDlg, SelectionChangedHdl, weld::TreeView&, void) +{ + if (!ValidateBookmarks()) + return; + // this event should fired only if we change selection by clicking on BookmarkTable entry + if (!m_xBookmarksBox->has_focus()) + return; + + OUStringBuffer sEditBoxText; + int nSelectedRows = 0; + m_xBookmarksBox->selected_foreach( + [this, &sEditBoxText, &nSelectedRows](weld::TreeIter& rEntry) { + sw::mark::IMark* pBookmark + = weld::fromId<sw::mark::IMark*>(m_xBookmarksBox->get_id(rEntry)); + const OUString& sEntryName = pBookmark->GetName(); + if (!sEditBoxText.isEmpty()) + sEditBoxText.append(";"); + sEditBoxText.append(sEntryName); + ++nSelectedRows; + return false; + }); + if (nSelectedRows) + { + m_xInsertBtn->set_sensitive(false); + m_xGotoBtn->set_sensitive(nSelectedRows == 1); + m_xRenameBtn->set_sensitive(nSelectedRows == 1 && !m_bAreProtected); + m_xDeleteBtn->set_sensitive(!m_bAreProtected); + m_xEditBox->set_text(sEditBoxText.makeStringAndClear()); + } + else + { + m_xInsertBtn->set_sensitive(!m_bAreProtected); + m_xGotoBtn->set_sensitive(false); + m_xRenameBtn->set_sensitive(false); + m_xDeleteBtn->set_sensitive(false); + } +} + +IMPL_LINK_NOARG(SwInsertBookmarkDlg, RenameHdl, weld::Button&, void) +{ + if (!ValidateBookmarks()) + return; + auto xSelected = m_xBookmarksBox->get_selected(); + if (!xSelected) + return; + + sw::mark::IMark* pBookmark + = weld::fromId<sw::mark::IMark*>(m_xBookmarksBox->get_id(*xSelected)); + 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& rFact = swui::GetFactory(); + ScopedVclPtr<AbstractSwRenameXNamedDlg> pDlg( + rFact.CreateSwRenameXNamedDlg(m_xDialog.get(), xNamed, xNameAccess)); + pDlg->SetForbiddenChars(BookmarkTable::aForbiddenChars + + OUStringChar(BookmarkTable::cSeparator)); + + if (pDlg->Execute()) + { + ValidateBookmarks(); + m_xDeleteBtn->set_sensitive(false); + m_xGotoBtn->set_sensitive(false); + m_xRenameBtn->set_sensitive(false); + m_xInsertBtn->set_sensitive(false); + } +} + +// callback to an insert button. Inserts a new text mark to the current position. +IMPL_LINK_NOARG(SwInsertBookmarkDlg, InsertHdl, weld::Button&, void) +{ + OUString sBookmark = m_xEditBox->get_text(); + rSh.SetBookmark2(vcl::KeyCode(), sBookmark, m_xHideCB->get_active(), + m_xConditionED->get_text()); + + m_xDialog->response(RET_OK); +} + +IMPL_LINK(SwInsertBookmarkDlg, ChangeHideHdl, weld::Toggleable&, rBox, void) +{ + bool bHide = rBox.get_active(); + m_xConditionED->set_sensitive(bHide); + m_xConditionFT->set_sensitive(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 + auto xSelected = m_xBookmarksBox->get_selected(); + if (!xSelected) + return; + + sw::mark::IMark* pBookmark + = weld::fromId<sw::mark::IMark*>(m_xBookmarksBox->get_id(*xSelected)); + + rSh.EnterStdMode(); + rSh.GotoMark(pBookmark); +} + +bool SwInsertBookmarkDlg::ValidateBookmarks() +{ + if (HaveBookmarksChanged()) + { + PopulateTable(); + m_xEditBox->set_text(""); + 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 || aListIter->second != (*ppBookmark)->GetName()) + return true; + ++aListIter; + } + } + // less bookmarks then expected + return aListIter != aTableBookmarks.end(); +} + +void SwInsertBookmarkDlg::PopulateTable() +{ + aTableBookmarks.clear(); + m_xBookmarksBox->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_xBookmarksBox->InsertBookmark(*ppBookmark); + aTableBookmarks.emplace_back(*ppBookmark, (*ppBookmark)->GetName()); + } + } + m_nLastBookmarksCount = pMarkAccess->getBookmarksCount(); +} + +SwInsertBookmarkDlg::SwInsertBookmarkDlg(weld::Window* pParent, SwWrtShell& rS) + : SfxDialogController(pParent, "modules/swriter/ui/insertbookmark.ui", "InsertBookmarkDialog") + , rSh(rS) + , m_nLastBookmarksCount(0) + , m_bSorted(false) + , m_xEditBox(m_xBuilder->weld_entry("name")) + , m_xInsertBtn(m_xBuilder->weld_button("insert")) + , m_xDeleteBtn(m_xBuilder->weld_button("delete")) + , m_xGotoBtn(m_xBuilder->weld_button("goto")) + , m_xRenameBtn(m_xBuilder->weld_button("rename")) + , m_xHideCB(m_xBuilder->weld_check_button("hide")) + , m_xConditionFT(m_xBuilder->weld_label("condlabel")) + , m_xConditionED(new ConditionEdit(m_xBuilder->weld_entry("withcond"))) + , m_xBookmarksBox(new BookmarkTable(m_xBuilder->weld_tree_view("bookmarks"))) + , m_xForbiddenChars(m_xBuilder->weld_label("lbForbiddenChars")) +{ + m_xBookmarksBox->connect_changed(LINK(this, SwInsertBookmarkDlg, SelectionChangedHdl)); + m_xBookmarksBox->connect_row_activated(LINK(this, SwInsertBookmarkDlg, DoubleClickHdl)); + m_xBookmarksBox->connect_column_clicked(LINK(this, SwInsertBookmarkDlg, HeaderBarClick)); + m_xEditBox->connect_changed(LINK(this, SwInsertBookmarkDlg, ModifyHdl)); + m_xInsertBtn->connect_clicked(LINK(this, SwInsertBookmarkDlg, InsertHdl)); + m_xDeleteBtn->connect_clicked(LINK(this, SwInsertBookmarkDlg, DeleteHdl)); + m_xGotoBtn->connect_clicked(LINK(this, SwInsertBookmarkDlg, GotoHdl)); + m_xRenameBtn->connect_clicked(LINK(this, SwInsertBookmarkDlg, RenameHdl)); + m_xHideCB->connect_toggled(LINK(this, SwInsertBookmarkDlg, ChangeHideHdl)); + + m_xDeleteBtn->set_sensitive(false); + m_xGotoBtn->set_sensitive(false); + m_xRenameBtn->set_sensitive(false); + + PopulateTable(); + + m_xEditBox->set_text(m_xBookmarksBox->GetNameProposal()); + m_xEditBox->set_position(-1); + + m_xForbiddenChars->set_label(SwResId(STR_BOOKMARK_FORBIDDENCHARS) + " " + + BookmarkTable::aForbiddenChars); + m_xForbiddenChars->set_visible(false); + + if (!officecfg::Office::Common::Misc::ExperimentalMode::get()) + { + m_xHideCB->set_visible(false); + m_xConditionFT->set_visible(false); + m_xConditionED->set_visible(false); + } + + m_bAreProtected = rSh.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS); + + // disabled until "Hide" flag is not checked + m_xConditionED->set_sensitive(false); + m_xConditionFT->set_sensitive(false); + + // restore dialog size + SvtViewOptions aDlgOpt(EViewType::Dialog, "BookmarkDialog"); + if (aDlgOpt.Exists()) + m_xDialog->set_window_state(aDlgOpt.GetWindowState().toUtf8()); +} + +SwInsertBookmarkDlg::~SwInsertBookmarkDlg() +{ + // tdf#146261 - Remember size of bookmark dialog + SvtViewOptions aDlgOpt(EViewType::Dialog, "BookmarkDialog"); + OString sWindowState + = m_xDialog->get_window_state(WindowStateMask::Pos | WindowStateMask::Size); + aDlgOpt.SetWindowState(OUString::fromUtf8(sWindowState)); +} + +IMPL_LINK(SwInsertBookmarkDlg, HeaderBarClick, int, nColumn, void) +{ + if (!m_bSorted) + { + m_xBookmarksBox->make_sorted(); + m_bSorted = true; + } + + bool bSortAtoZ = m_xBookmarksBox->get_sort_order(); + + //set new arrow positions in headerbar + if (nColumn == m_xBookmarksBox->get_sort_column()) + { + bSortAtoZ = !bSortAtoZ; + m_xBookmarksBox->set_sort_order(bSortAtoZ); + } + else + { + int nOldSortColumn = m_xBookmarksBox->get_sort_column(); + if (nOldSortColumn != -1) + m_xBookmarksBox->set_sort_indicator(TRISTATE_INDET, nOldSortColumn); + m_xBookmarksBox->set_sort_column(nColumn); + } + + if (nColumn != -1) + { + //sort lists + m_xBookmarksBox->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn); + } +} + +BookmarkTable::BookmarkTable(std::unique_ptr<weld::TreeView> xControl) + : m_xControl(std::move(xControl)) +{ + m_xControl->set_size_request(-1, m_xControl->get_height_rows(8)); + m_xControl->set_column_fixed_widths({ 40, 110, 150, 160 }); + m_xControl->set_selection_mode(SelectionMode::Multiple); +} + +std::unique_ptr<weld::TreeIter> BookmarkTable::get_selected() const +{ + std::unique_ptr<weld::TreeIter> xIter(m_xControl->make_iterator()); + if (!m_xControl->get_selected(xIter.get())) + xIter.reset(); + return xIter; +} + +void BookmarkTable::InsertBookmark(sw::mark::IMark* pMark) +{ + sw::mark::IBookmark* pBookmark = dynamic_cast<sw::mark::IBookmark*>(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<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 + = o3tl::trim(sBookmarkNodeText.subView(nBookmarkNodeTextPos, nBookmarkTextLen)); + if (bExceedsLength) + sBookmarkNodeText += "..."; + else if (bPulling && !bPulledAll) + sBookmarkNodeText = "..." + sBookmarkNodeText; + + const OUString& sHideCondition = pBookmark->GetHideCondition(); + OUString sHidden = SwResId(STR_BOOKMARK_NO); + if (pBookmark->IsHidden() || !sHideCondition.isEmpty()) + sHidden = SwResId(STR_BOOKMARK_YES); + OUString sPageNum = OUString::number(SwPaM(pMark->GetMarkStart()).GetPageNum()); + int nRow = m_xControl->n_children(); + m_xControl->append(weld::toId(pMark), sPageNum); + m_xControl->set_text(nRow, pBookmark->GetName(), 1); + m_xControl->set_text(nRow, sBookmarkNodeText, 2); + m_xControl->set_text(nRow, sHidden, 3); + m_xControl->set_text(nRow, sHideCondition, 4); +} + +std::unique_ptr<weld::TreeIter> BookmarkTable::GetRowByBookmarkName(const OUString& sName) +{ + std::unique_ptr<weld::TreeIter> xRet; + m_xControl->all_foreach([this, &sName, &xRet](weld::TreeIter& rEntry) { + sw::mark::IMark* pBookmark = weld::fromId<sw::mark::IMark*>(m_xControl->get_id(rEntry)); + if (pBookmark->GetName() == sName) + { + xRet = m_xControl->make_iterator(&rEntry); + return true; + } + return false; + }); + return xRet; +} + +sw::mark::IMark* BookmarkTable::GetBookmarkByName(const OUString& sName) +{ + auto xEntry = GetRowByBookmarkName(sName); + if (!xEntry) + return nullptr; + + return weld::fromId<sw::mark::IMark*>(m_xControl->get_id(*xEntry)); +} + +void BookmarkTable::SelectByName(const OUString& sName) +{ + auto xEntry = GetRowByBookmarkName(sName); + if (!xEntry) + return; + select(*xEntry); +} + +OUString BookmarkTable::GetNameProposal() const +{ + OUString sDefaultBookmarkName = SwResId(STR_BOOKMARK_DEF_NAME); + sal_Int32 nHighestBookmarkId = 0; + for (int i = 0, nCount = m_xControl->n_children(); i < nCount; ++i) + { + sw::mark::IMark* pBookmark = weld::fromId<sw::mark::IMark*>(m_xControl->get_id(i)); + const OUString& sName = pBookmark->GetName(); + sal_Int32 nIndex = 0; + if (o3tl::getToken(sName, 0, ' ', nIndex) == sDefaultBookmarkName) + { + sal_Int32 nCurrBookmarkId = o3tl::toInt32(o3tl::getToken(sName, 0, ' ', nIndex)); + nHighestBookmarkId = std::max<sal_Int32>(nHighestBookmarkId, nCurrBookmarkId); + } + } + return sDefaultBookmarkName + " " + OUString::number(nHighestBookmarkId + 1); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/contentcontroldlg.cxx b/sw/source/ui/misc/contentcontroldlg.cxx new file mode 100644 index 000000000..95c86120e --- /dev/null +++ b/sw/source/ui/misc/contentcontroldlg.cxx @@ -0,0 +1,414 @@ +/* -*- 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 <contentcontroldlg.hxx> + +#include <vcl/weld.hxx> +#include <cui/cuicharmap.hxx> +#include <svl/numformat.hxx> +#include <svl/zformat.hxx> + +#include <wrtsh.hxx> +#include <ndtxt.hxx> +#include <textcontentcontrol.hxx> +#include <IDocumentState.hxx> +#include <swuiexp.hxx> +#include <numfmtlb.hxx> + +using namespace com::sun::star; + +SwContentControlDlg::SwContentControlDlg(weld::Window* pParent, SwWrtShell& rWrtShell) + : SfxDialogController(pParent, "modules/swriter/ui/contentcontroldlg.ui", + "ContentControlDialog") + , m_rWrtShell(rWrtShell) + , m_xShowingPlaceHolderCB(m_xBuilder->weld_check_button("showing_place_holder")) + , m_xCheckboxFrame(m_xBuilder->weld_frame("checkboxframe")) + , m_xCheckedState(m_xBuilder->weld_entry("checkboxcheckedentry")) + , m_xCheckedStateBtn(m_xBuilder->weld_button("btncheckboxchecked")) + , m_xUncheckedState(m_xBuilder->weld_entry("checkboxuncheckedentry")) + , m_xUncheckedStateBtn(m_xBuilder->weld_button("btncheckboxunchecked")) + , m_xListItemsFrame(m_xBuilder->weld_frame("listitemsframe")) + , m_xListItems(m_xBuilder->weld_tree_view("listitems")) + , m_xListItemButtons(m_xBuilder->weld_box("listitembuttons")) + , m_xInsertBtn(m_xBuilder->weld_button("add")) + , m_xRenameBtn(m_xBuilder->weld_button("modify")) + , m_xDeleteBtn(m_xBuilder->weld_button("remove")) + , m_xMoveUpBtn(m_xBuilder->weld_button("moveup")) + , m_xMoveDownBtn(m_xBuilder->weld_button("movedown")) + , m_xDateFrame(m_xBuilder->weld_frame("dateframe")) + , m_xDateFormat(new SwNumFormatTreeView(m_xBuilder->weld_tree_view("date_formats_treeview"))) + , m_xOk(m_xBuilder->weld_button("ok")) +{ + m_xCheckedStateBtn->connect_clicked(LINK(this, SwContentControlDlg, SelectCharHdl)); + m_xUncheckedStateBtn->connect_clicked(LINK(this, SwContentControlDlg, SelectCharHdl)); + m_xListItems->connect_changed(LINK(this, SwContentControlDlg, SelectionChangedHdl)); + m_xOk->connect_clicked(LINK(this, SwContentControlDlg, OkHdl)); + + // Only 2 items would be visible by default. + m_xListItems->set_size_request(-1, m_xListItems->get_height_rows(8)); + // Only the first column would have a non-zero size by default in the SvHeaderTabListBox case. + m_xListItems->set_column_fixed_widths({ 100, 100 }); + + m_xInsertBtn->connect_clicked(LINK(this, SwContentControlDlg, InsertHdl)); + m_xRenameBtn->connect_clicked(LINK(this, SwContentControlDlg, RenameHdl)); + m_xDeleteBtn->connect_clicked(LINK(this, SwContentControlDlg, DeleteHdl)); + m_xMoveUpBtn->connect_clicked(LINK(this, SwContentControlDlg, MoveUpHdl)); + m_xMoveDownBtn->connect_clicked(LINK(this, SwContentControlDlg, MoveDownHdl)); + + const SwPosition* pStart = rWrtShell.GetCursor()->Start(); + SwTextNode* pTextNode = pStart->nNode.GetNode().GetTextNode(); + if (!pTextNode) + { + return; + } + + SwTextAttr* pAttr = pTextNode->GetTextAttrAt(pStart->nContent.GetIndex(), + RES_TXTATR_CONTENTCONTROL, SwTextNode::PARENT); + if (!pAttr) + { + return; + } + + SwTextContentControl* pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr); + const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl(); + m_pContentControl = rFormatContentControl.GetContentControl(); + + bool bShowingPlaceHolder = m_pContentControl->GetShowingPlaceHolder(); + TriState eShowingPlaceHolder = bShowingPlaceHolder ? TRISTATE_TRUE : TRISTATE_FALSE; + m_xShowingPlaceHolderCB->set_state(eShowingPlaceHolder); + m_xShowingPlaceHolderCB->save_state(); + + if (m_pContentControl->GetCheckbox()) + { + m_xCheckedState->set_text(m_pContentControl->GetCheckedState()); + m_xCheckedState->save_value(); + m_xUncheckedState->set_text(m_pContentControl->GetUncheckedState()); + m_xUncheckedState->save_value(); + } + else + { + m_xCheckboxFrame->set_visible(false); + } + + if (m_pContentControl->HasListItems()) + { + for (const auto& rListItem : m_pContentControl->GetListItems()) + { + int nRow = m_xListItems->n_children(); + m_xListItems->append_text(rListItem.m_aDisplayText); + m_xListItems->set_text(nRow, rListItem.m_aValue, 1); + } + m_aSavedListItems = m_pContentControl->GetListItems(); + } + else + { + m_xListItemsFrame->set_visible(false); + m_xListItemButtons->set_visible(false); + } + + if (m_pContentControl->GetDate()) + { + m_xDateFormat->SetFormatType(SvNumFormatType::DATE); + m_xDateFormat->SetShowLanguageControl(true); + + // Set height to double of the default. + weld::TreeView& rTreeView = dynamic_cast<weld::TreeView&>(m_xDateFormat->get_widget()); + rTreeView.set_size_request(rTreeView.get_preferred_size().Width(), + rTreeView.get_height_rows(10)); + + OUString sFormatString = m_pContentControl->GetDateFormat(); + OUString sLang = m_pContentControl->GetDateLanguage(); + if (!sFormatString.isEmpty() && !sLang.isEmpty()) + { + SvNumberFormatter* pNumberFormatter = m_rWrtShell.GetNumberFormatter(); + LanguageType aLangType = LanguageTag(sLang).getLanguageType(); + sal_uInt32 nFormat = pNumberFormatter->GetEntryKey(sFormatString, aLangType); + if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + { + sal_Int32 nCheckPos = 0; + SvNumFormatType nType; + pNumberFormatter->PutEntry(sFormatString, nCheckPos, nType, nFormat, + LanguageTag(sLang).getLanguageType()); + } + + if (aLangType != LANGUAGE_DONTKNOW && nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND) + { + m_xDateFormat->SetDefFormat(nFormat); + } + } + } + else + { + m_xDateFrame->set_visible(false); + } +} + +SwContentControlDlg::~SwContentControlDlg() {} + +IMPL_LINK_NOARG(SwContentControlDlg, OkHdl, weld::Button&, void) +{ + if (!m_pContentControl) + { + return; + } + + bool bChanged = false; + if (m_xShowingPlaceHolderCB->get_state_changed_from_saved()) + { + bool bShowingPlaceHolder = m_xShowingPlaceHolderCB->get_state() == TRISTATE_TRUE; + m_pContentControl->SetShowingPlaceHolder(bShowingPlaceHolder); + bChanged = true; + } + + if (m_xCheckedState->get_value_changed_from_saved()) + { + m_pContentControl->SetCheckedState(m_xCheckedState->get_text()); + } + + if (m_xUncheckedState->get_value_changed_from_saved()) + { + m_pContentControl->SetUncheckedState(m_xUncheckedState->get_text()); + } + + std::vector<SwContentControlListItem> aItems; + for (int i = 0; i < m_xListItems->n_children(); ++i) + { + SwContentControlListItem aItem; + aItem.m_aDisplayText = m_xListItems->get_text(i, 0); + aItem.m_aValue = m_xListItems->get_text(i, 1); + aItems.push_back(aItem); + } + if (aItems != m_aSavedListItems) + { + m_pContentControl->SetListItems(aItems); + bChanged = true; + } + + if (m_pContentControl->GetDate()) + { + SvNumberFormatter* pNumberFormatter = m_rWrtShell.GetNumberFormatter(); + const SvNumberformat* pFormat = pNumberFormatter->GetEntry(m_xDateFormat->GetFormat()); + if (pFormat) + { + if (pFormat->GetFormatstring() != m_pContentControl->GetDateFormat()) + { + m_pContentControl->SetDateFormat(pFormat->GetFormatstring()); + bChanged = true; + } + + OUString aLanguage = LanguageTag(pFormat->GetLanguage()).getBcp47(); + if (aLanguage != m_pContentControl->GetDateLanguage()) + { + m_pContentControl->SetDateLanguage(aLanguage); + bChanged = true; + } + } + } + + if (bChanged) + { + m_rWrtShell.GetDoc()->getIDocumentState().SetModified(); + + // Make sure that the cursor gets updated with the new list items. + m_rWrtShell.HideCursor(); + m_rWrtShell.ShowCursor(); + } + + m_xDialog->response(RET_OK); +} + +IMPL_LINK(SwContentControlDlg, SelectCharHdl, weld::Button&, rButton, void) +{ + SvxCharacterMap aMap(m_xDialog.get(), nullptr, nullptr); + sal_UCS4 cBullet = 0; + sal_Int32 nIndex = 0; + if (&rButton == m_xCheckedStateBtn.get()) + { + cBullet = m_pContentControl->GetCheckedState().iterateCodePoints(&nIndex); + } + else if (&rButton == m_xUncheckedStateBtn.get()) + { + cBullet = m_pContentControl->GetUncheckedState().iterateCodePoints(&nIndex); + } + aMap.SetChar(cBullet); + if (aMap.run() != RET_OK) + { + return; + } + + cBullet = aMap.GetChar(); + if (&rButton == m_xCheckedStateBtn.get()) + { + m_xCheckedState->set_text(OUString(&cBullet, 1)); + } + else if (&rButton == m_xUncheckedStateBtn.get()) + { + m_xUncheckedState->set_text(OUString(&cBullet, 1)); + } +} + +IMPL_LINK_NOARG(SwContentControlDlg, InsertHdl, weld::Button&, void) +{ + SwContentControlListItem aItem; + SwAbstractDialogFactory& rFact = swui::GetFactory(); + ScopedVclPtr<VclAbstractDialog> pDlg( + rFact.CreateSwContentControlListItemDlg(m_xDialog.get(), aItem)); + if (!pDlg->Execute()) + { + return; + } + + if (aItem.m_aDisplayText.isEmpty() && aItem.m_aValue.isEmpty()) + { + // Maintain the invariant that value can't be empty. + return; + } + + if (aItem.m_aValue.isEmpty()) + { + aItem.m_aValue = aItem.m_aDisplayText; + } + + int nRow = m_xListItems->n_children(); + m_xListItems->append_text(aItem.m_aDisplayText); + m_xListItems->set_text(nRow, aItem.m_aValue, 1); +} + +IMPL_LINK_NOARG(SwContentControlDlg, RenameHdl, weld::Button&, void) +{ + int nRow = m_xListItems->get_selected_index(); + if (nRow < 0) + { + return; + } + + SwContentControlListItem aItem; + aItem.m_aDisplayText = m_xListItems->get_text(nRow, 0); + aItem.m_aValue = m_xListItems->get_text(nRow, 1); + SwAbstractDialogFactory& rFact = swui::GetFactory(); + ScopedVclPtr<VclAbstractDialog> pDlg( + rFact.CreateSwContentControlListItemDlg(m_xDialog.get(), aItem)); + if (!pDlg->Execute()) + { + return; + } + + if (aItem.m_aDisplayText.isEmpty() && aItem.m_aValue.isEmpty()) + { + // Maintain the invariant that value can't be empty. + return; + } + + if (aItem.m_aValue.isEmpty()) + { + aItem.m_aValue = aItem.m_aDisplayText; + } + + m_xListItems->set_text(nRow, aItem.m_aDisplayText, 0); + m_xListItems->set_text(nRow, aItem.m_aValue, 1); +} + +IMPL_LINK_NOARG(SwContentControlDlg, DeleteHdl, weld::Button&, void) +{ + int nRow = m_xListItems->get_selected_index(); + if (nRow < 0) + { + return; + } + + m_xListItems->remove(nRow); +} + +IMPL_LINK_NOARG(SwContentControlDlg, MoveUpHdl, weld::Button&, void) +{ + int nRow = m_xListItems->get_selected_index(); + if (nRow <= 0) + { + return; + } + + SwContentControlListItem aItem; + aItem.m_aDisplayText = m_xListItems->get_text(nRow, 0); + aItem.m_aValue = m_xListItems->get_text(nRow, 1); + m_xListItems->remove(nRow); + --nRow; + m_xListItems->insert_text(nRow, aItem.m_aDisplayText); + m_xListItems->set_text(nRow, aItem.m_aValue, 1); + m_xListItems->select(nRow); +} + +IMPL_LINK_NOARG(SwContentControlDlg, MoveDownHdl, weld::Button&, void) +{ + int nRow = m_xListItems->get_selected_index(); + int nEndPos = m_xListItems->n_children() - 1; + if (nRow < 0 || nRow >= nEndPos) + { + return; + } + + SwContentControlListItem aItem; + aItem.m_aDisplayText = m_xListItems->get_text(nRow, 0); + aItem.m_aValue = m_xListItems->get_text(nRow, 1); + m_xListItems->remove(nRow); + ++nRow; + m_xListItems->insert_text(nRow, aItem.m_aDisplayText); + m_xListItems->set_text(nRow, aItem.m_aValue, 1); + m_xListItems->select(nRow); +} + +IMPL_LINK_NOARG(SwContentControlDlg, SelectionChangedHdl, weld::TreeView&, void) +{ + if (!m_xListItems->has_focus()) + { + return; + } + + int nRow = m_xListItems->get_selected_index(); + if (nRow < 0) + { + m_xRenameBtn->set_sensitive(false); + m_xDeleteBtn->set_sensitive(false); + } + else + { + m_xRenameBtn->set_sensitive(true); + m_xDeleteBtn->set_sensitive(true); + } + + if (nRow <= 0) + { + m_xMoveUpBtn->set_sensitive(false); + } + else + { + m_xMoveUpBtn->set_sensitive(true); + } + + int nEndPos = m_xListItems->n_children() - 1; + if (nRow < 0 || nRow >= nEndPos) + { + m_xMoveDownBtn->set_sensitive(false); + } + else + { + m_xMoveDownBtn->set_sensitive(true); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/contentcontrollistitemdlg.cxx b/sw/source/ui/misc/contentcontrollistitemdlg.cxx new file mode 100644 index 000000000..6ac160aeb --- /dev/null +++ b/sw/source/ui/misc/contentcontrollistitemdlg.cxx @@ -0,0 +1,48 @@ +/* -*- 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 <contentcontrollistitemdlg.hxx> + +#include <formatcontentcontrol.hxx> + +using namespace com::sun::star; + +SwContentControlListItemDlg::SwContentControlListItemDlg(weld::Widget* pParent, + SwContentControlListItem& rItem) + : GenericDialogController(pParent, "modules/swriter/ui/contentcontrollistitemdlg.ui", + "ContentControlListItemDialog") + , m_rItem(rItem) + , m_xDisplayNameED(m_xBuilder->weld_entry("displayname")) + , m_xValueED(m_xBuilder->weld_entry("value")) + , m_xOk(m_xBuilder->weld_button("ok")) +{ + m_xOk->connect_clicked(LINK(this, SwContentControlListItemDlg, OkHdl)); + m_xDisplayNameED->set_text(rItem.m_aDisplayText); + m_xValueED->set_text(rItem.m_aValue); +} + +IMPL_LINK_NOARG(SwContentControlListItemDlg, OkHdl, weld::Button&, void) +{ + m_rItem.m_aDisplayText = m_xDisplayNameED->get_text(); + m_rItem.m_aValue = m_xValueED->get_text(); + + m_xDialog->response(RET_OK); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/docfnote.cxx b/sw/source/ui/misc/docfnote.cxx new file mode 100644 index 000000000..e065a272e --- /dev/null +++ b/sw/source/ui/misc/docfnote.cxx @@ -0,0 +1,394 @@ +/* -*- 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 <svl/style.hxx> +#include <osl/diagnose.h> +#include <wrtsh.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <docfnote.hxx> +#include "impfnote.hxx" +#include <ftninfo.hxx> +#include <fmtcol.hxx> +#include <pagedesc.hxx> +#include <charfmt.hxx> +#include <docstyle.hxx> +#include <wdocsh.hxx> +#include <uitool.hxx> +#include <poolfmt.hxx> +#include <SwStyleNameMapper.hxx> +#include <memory> + +SwFootNoteOptionDlg::SwFootNoteOptionDlg(weld::Window *pParent, SwWrtShell &rS) + : SfxTabDialogController(pParent, "modules/swriter/ui/footendnotedialog.ui", "FootEndnoteDialog") + , rSh( rS ) +{ + RemoveResetButton(); + + GetOKButton().connect_clicked(LINK(this, SwFootNoteOptionDlg, OkHdl)); + + AddTabPage("footnotes", SwFootNoteOptionPage::Create, nullptr); + AddTabPage("endnotes", SwEndNoteOptionPage::Create, nullptr); +} + +void SwFootNoteOptionDlg::PageCreated(const OString& /*rId*/, SfxTabPage &rPage) +{ + static_cast<SwEndNoteOptionPage&>(rPage).SetShell(rSh); +} + +IMPL_LINK(SwFootNoteOptionDlg, OkHdl, weld::Button&, rBtn, void) +{ + SfxItemSetFixed<1, 1> aDummySet(rSh.GetAttrPool()); + SfxTabPage *pPage = GetTabPage("footnotes"); + if ( pPage ) + pPage->FillItemSet( &aDummySet ); + pPage = GetTabPage("endnotes"); + if ( pPage ) + pPage->FillItemSet( &aDummySet ); + SfxTabDialogController::OkHdl(rBtn); +} + +SwEndNoteOptionPage::SwEndNoteOptionPage(weld::Container* pPage, weld::DialogController* pController, bool bEN, + const SfxItemSet &rSet) + : SfxTabPage(pPage, pController, + bEN ? OUString("modules/swriter/ui/endnotepage.ui") : OUString("modules/swriter/ui/footnotepage.ui"), + bEN ? OString("EndnotePage") : OString("FootnotePage"), + &rSet) + , pSh(nullptr) + , bPosDoc(false) + , bEndNote(bEN) + , m_xNumViewBox(new SwNumberingTypeListBox(m_xBuilder->weld_combo_box("numberinglb"))) + , m_xOffsetLbl(m_xBuilder->weld_label("offset")) + , m_xOffsetField(m_xBuilder->weld_spin_button("offsetnf")) + , m_xNumCountBox(m_xBuilder->weld_combo_box("countinglb")) + , m_xPrefixED(m_xBuilder->weld_entry("prefix")) + , m_xSuffixED(m_xBuilder->weld_entry("suffix")) + , m_xPosFT(m_xBuilder->weld_label("pos")) + , m_xPosPageBox(m_xBuilder->weld_radio_button("pospagecb")) + , m_xPosChapterBox(m_xBuilder->weld_radio_button("posdoccb")) + , m_xStylesContainer(m_xBuilder->weld_widget("allstyles")) + , m_xParaTemplBox(m_xBuilder->weld_combo_box("parastylelb")) + , m_xPageTemplLbl(m_xBuilder->weld_label("pagestyleft")) + , m_xPageTemplBox(m_xBuilder->weld_combo_box("pagestylelb")) + , m_xFootnoteCharAnchorTemplBox(m_xBuilder->weld_combo_box("charanchorstylelb")) + , m_xFootnoteCharTextTemplBox(m_xBuilder->weld_combo_box("charstylelb")) + , m_xContEdit(m_xBuilder->weld_entry("conted")) + , m_xContFromEdit(m_xBuilder->weld_entry("contfromed")) +{ + m_xNumViewBox->Reload(SwInsertNumTypes::Extended); + if (!bEndNote) + { + m_xNumCountBox->connect_changed(LINK(this, SwEndNoteOptionPage, NumCountHdl)); + aNumDoc = m_xNumCountBox->get_text(FTNNUM_DOC); + aNumPage = m_xNumCountBox->get_text(FTNNUM_PAGE); + aNumChapter = m_xNumCountBox->get_text(FTNNUM_CHAPTER); + m_xPosPageBox->connect_toggled(LINK(this, SwEndNoteOptionPage, ToggleHdl)); + m_xPosChapterBox->connect_toggled(LINK(this, SwEndNoteOptionPage, ToggleHdl)); + } + m_xParaTemplBox->make_sorted(); +} + +SwEndNoteOptionPage::~SwEndNoteOptionPage() +{ +} + +void SwEndNoteOptionPage::Reset( const SfxItemSet* ) +{ + std::unique_ptr<SwEndNoteInfo> pInf(bEndNote ? new SwEndNoteInfo( pSh->GetEndNoteInfo() ) + : new SwFootnoteInfo( pSh->GetFootnoteInfo() )); + SfxObjectShell * pDocSh = SfxObjectShell::Current(); + + if (dynamic_cast<SwWebDocShell*>( pDocSh) ) + m_xStylesContainer->hide(); + + if ( bEndNote ) + { + bPosDoc = true; + } + else + { + const SwFootnoteInfo &rInf = pSh->GetFootnoteInfo(); + // set position (page, chapter) + if ( rInf.m_ePos == FTNPOS_PAGE ) + { + m_xPosPageBox->set_active(true); + m_xPageTemplLbl->set_sensitive(false); + m_xPageTemplBox->set_sensitive(false); + } + else + { + m_xPosChapterBox->set_active(true); + m_xNumCountBox->remove_text(aNumPage); + m_xNumCountBox->remove_text(aNumChapter); + bPosDoc = true; + } + // reference tests + m_xContEdit->set_text(rInf.m_aQuoVadis); + m_xContFromEdit->set_text(rInf.m_aErgoSum); + + // collected + SelectNumbering(rInf.m_eNum); + } + + // numbering + // art + m_xNumViewBox->SelectNumberingType( pInf->m_aFormat.GetNumberingType()); + m_xOffsetField->set_value(pInf->m_nFootnoteOffset + 1); + m_xPrefixED->set_text(pInf->GetPrefix().replaceAll("\t", "\\t")); // fdo#65666 + m_xSuffixED->set_text(pInf->GetSuffix().replaceAll("\t", "\\t")); + + const SwCharFormat* pCharFormat = pInf->GetCharFormat( + *pSh->GetView().GetDocShell()->GetDoc()); + m_xFootnoteCharTextTemplBox->set_active_text(pCharFormat->GetName()); + m_xFootnoteCharTextTemplBox->save_value(); + + pCharFormat = pInf->GetAnchorCharFormat( *pSh->GetDoc() ); + m_xFootnoteCharAnchorTemplBox->set_active_text( pCharFormat->GetName() ); + m_xFootnoteCharAnchorTemplBox->save_value(); + + // styles special regions + // paragraph + SfxStyleSheetBasePool* pStyleSheetPool = pSh->GetView().GetDocShell()->GetStyleSheetPool(); + SfxStyleSheetBase *pStyle = pStyleSheetPool->First(SfxStyleFamily::Para, SfxStyleSearchBits::SwExtra); + while(pStyle) + { + m_xParaTemplBox->append_text(pStyle->GetName()); + pStyle = pStyleSheetPool->Next(); + } + + OUString sStr; + SwStyleNameMapper::FillUIName( static_cast< sal_uInt16 >(bEndNote ? RES_POOLCOLL_ENDNOTE + : RES_POOLCOLL_FOOTNOTE), sStr ); + if (m_xParaTemplBox->find_text(sStr) == -1) + m_xParaTemplBox->append_text(sStr); + + SwTextFormatColl* pColl = pInf->GetFootnoteTextColl(); + if( !pColl ) + m_xParaTemplBox->set_active_text(sStr); // Default + else + { + OSL_ENSURE(!pColl->IsDefault(), "default style for footnotes is wrong"); + const int nPos = m_xParaTemplBox->find_text(pColl->GetName()); + if (nPos != -1) + m_xParaTemplBox->set_active( nPos ); + else + { + m_xParaTemplBox->append_text(pColl->GetName()); + m_xParaTemplBox->set_active_text(pColl->GetName()); + } + } + + // page + for (sal_uInt16 i = RES_POOLPAGE_BEGIN; i < RES_POOLPAGE_END; ++i) + m_xPageTemplBox->append_text(SwStyleNameMapper::GetUIName(i, OUString())); + + const size_t nCount = pSh->GetPageDescCnt(); + for(size_t i = 0; i < nCount; ++i) + { + const SwPageDesc &rPageDesc = pSh->GetPageDesc(i); + if (m_xPageTemplBox->find_text(rPageDesc.GetName()) == -1) + m_xPageTemplBox->append_text(rPageDesc.GetName()); + } + m_xPageTemplBox->make_sorted(); + + m_xPageTemplBox->set_active_text(pInf->GetPageDesc(*pSh->GetDoc())->GetName()); +} + +std::unique_ptr<SfxTabPage> SwEndNoteOptionPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet ) +{ + return std::make_unique<SwEndNoteOptionPage>(pPage, pController, true, *rSet); +} + +// Different kinds of numbering; because the Listbox has varying numbers of +// entries, here are functions to set and query the intended kind of numbering. +void SwEndNoteOptionPage::SelectNumbering(SwFootnoteNum const eNum) +{ + OUString sSelect; + switch(eNum) + { + case FTNNUM_DOC: + sSelect = aNumDoc; + break; + case FTNNUM_PAGE: + sSelect = aNumPage; + break; + case FTNNUM_CHAPTER: + sSelect = aNumChapter; + break; + default: + assert(false); + } + m_xNumCountBox->set_active_text(sSelect); + NumCountHdl(*m_xNumCountBox); +} + +SwFootnoteNum SwEndNoteOptionPage::GetNumbering() const +{ + const int nPos = m_xNumCountBox->get_active(); + return static_cast<SwFootnoteNum>(bPosDoc ? nPos + 2 : nPos); +} + +void SwEndNoteOptionPage::SetShell( SwWrtShell &rShell ) +{ + pSh = &rShell; + // collect character templates + m_xFootnoteCharTextTemplBox->clear(); + m_xFootnoteCharAnchorTemplBox->clear(); + ::FillCharStyleListBox(*m_xFootnoteCharTextTemplBox, + pSh->GetView().GetDocShell(), true); + + ::FillCharStyleListBox(*m_xFootnoteCharAnchorTemplBox, + pSh->GetView().GetDocShell(), true); +} + +IMPL_LINK(SwEndNoteOptionPage, ToggleHdl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + + if (m_xPosPageBox->get_active()) + { + // Handler behind the button to collect the footnote at the page. In this case + // all kinds of numbering can be used. + + const SwFootnoteNum eNum = GetNumbering(); + bPosDoc = false; + if (m_xNumCountBox->find_text(aNumPage) == -1) + { + m_xNumCountBox->insert_text(FTNNUM_PAGE, aNumPage); + m_xNumCountBox->insert_text(FTNNUM_CHAPTER, aNumChapter); + SelectNumbering(eNum); + } + m_xPageTemplLbl->set_sensitive(false); + m_xPageTemplBox->set_sensitive(false); + } + else if (m_xPosChapterBox->get_active()) + { + // Handler behind the button to collect the footnote at the chapter or end of + // the document. In this case no pagewise numbering can be used. + + if ( !bPosDoc ) + SelectNumbering(FTNNUM_DOC); + + bPosDoc = true; + m_xNumCountBox->remove_text(aNumPage); + m_xNumCountBox->remove_text(aNumChapter); + m_xPageTemplLbl->set_sensitive(true); + m_xPageTemplBox->set_sensitive(true); + } +} + +IMPL_LINK_NOARG(SwEndNoteOptionPage, NumCountHdl, weld::ComboBox&, void) +{ + bool bEnable = true; + if (m_xNumCountBox->get_count() - 1 != m_xNumCountBox->get_active()) + { + bEnable = false; + m_xOffsetField->set_value(1); + } + m_xOffsetLbl->set_sensitive(bEnable); + m_xOffsetField->set_sensitive(bEnable); +} + +static SwCharFormat* lcl_GetCharFormat( SwWrtShell* pSh, const OUString& rCharFormatName ) +{ + SwCharFormat* pFormat = nullptr; + const sal_uInt16 nChCount = pSh->GetCharFormatCount(); + for(sal_uInt16 i = 0; i< nChCount; i++) + { + SwCharFormat& rChFormat = pSh->GetCharFormat(i); + if(rChFormat.GetName() == rCharFormatName ) + { + pFormat = &rChFormat; + break; + } + } + if(!pFormat) + { + SfxStyleSheetBasePool* pPool = pSh->GetView().GetDocShell()->GetStyleSheetPool(); + SfxStyleSheetBase* pBase; + pBase = pPool->Find(rCharFormatName, SfxStyleFamily::Char); + if(!pBase) + pBase = &pPool->Make(rCharFormatName, SfxStyleFamily::Char); + pFormat = static_cast<SwDocStyleSheet*>(pBase)->GetCharFormat(); + } + return pFormat; +} + +bool SwEndNoteOptionPage::FillItemSet( SfxItemSet * ) +{ + std::unique_ptr<SwEndNoteInfo> pInf(bEndNote ? new SwEndNoteInfo() : new SwFootnoteInfo()); + + pInf->m_nFootnoteOffset = m_xOffsetField->get_value() - 1; + pInf->m_aFormat.SetNumberingType(m_xNumViewBox->GetSelectedNumberingType() ); + pInf->SetPrefix(m_xPrefixED->get_text().replaceAll("\\t", "\t")); + pInf->SetSuffix(m_xSuffixED->get_text().replaceAll("\\t", "\t")); + + pInf->SetCharFormat( lcl_GetCharFormat( pSh, + m_xFootnoteCharTextTemplBox->get_active_text() ) ); + pInf->SetAnchorCharFormat( lcl_GetCharFormat( pSh, + m_xFootnoteCharAnchorTemplBox->get_active_text() ) ); + + // paragraph template + int nPos = m_xParaTemplBox->get_active(); + if (nPos != -1) + { + const OUString aFormatName( m_xParaTemplBox->get_active_text() ); + SwTextFormatColl *pColl = pSh->GetParaStyle(aFormatName, SwWrtShell::GETSTYLE_CREATEANY); + OSL_ENSURE(pColl, "paragraph style not found"); + pInf->SetFootnoteTextColl(*pColl); + } + + // page template + pInf->ChgPageDesc( pSh->FindPageDescByName( + m_xPageTemplBox->get_active_text(), true ) ); + + if ( bEndNote ) + { + if ( !(*pInf == pSh->GetEndNoteInfo()) ) + pSh->SetEndNoteInfo( *pInf ); + } + else + { + SwFootnoteInfo *pI = static_cast<SwFootnoteInfo*>(pInf.get()); + pI->m_ePos = m_xPosPageBox->get_active() ? FTNPOS_PAGE : FTNPOS_CHAPTER; + pI->m_eNum = GetNumbering(); + pI->m_aQuoVadis = m_xContEdit->get_text(); + pI->m_aErgoSum = m_xContFromEdit->get_text(); + if ( !(*pI == pSh->GetFootnoteInfo()) ) + pSh->SetFootnoteInfo( *pI ); + } + return true; +} + +SwFootNoteOptionPage::SwFootNoteOptionPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet) + : SwEndNoteOptionPage(pPage, pController, false, rSet) +{ +} + +SwFootNoteOptionPage::~SwFootNoteOptionPage() +{ +} + +std::unique_ptr<SfxTabPage> SwFootNoteOptionPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet ) +{ + return std::make_unique<SwFootNoteOptionPage>(pPage, pController, *rSet); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/glosbib.cxx b/sw/source/ui/misc/glosbib.cxx new file mode 100644 index 000000000..934cd47fb --- /dev/null +++ b/sw/source/ui/misc/glosbib.cxx @@ -0,0 +1,405 @@ +/* -*- 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 <tools/urlobj.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <unotools/transliterationwrapper.hxx> +#include <unotools/tempfile.hxx> +#include <unotools/pathoptions.hxx> +#include <osl/diagnose.h> +#include <o3tl/string_view.hxx> + +#include <swtypes.hxx> +#include <glosbib.hxx> +#include <gloshdl.hxx> +#include <glossary.hxx> +#include <glosdoc.hxx> +#include <swunohelper.hxx> + +#include <strings.hrc> + +#define PATH_CASE_SENSITIVE 0x01 +#define PATH_READONLY 0x02 + +#define RENAME_TOKEN_DELIM u'\x0001' + +SwGlossaryGroupDlg::SwGlossaryGroupDlg(weld::Window * pParent, + std::vector<OUString> const& rPathArr, SwGlossaryHdl *pHdl) + : SfxDialogController(pParent, "modules/swriter/ui/editcategories.ui", + "EditCategoriesDialog") + , m_pParent(pParent) + , pGlosHdl(pHdl) + , m_xNameED(m_xBuilder->weld_entry("name")) + , m_xPathLB(m_xBuilder->weld_combo_box("pathlb")) + , m_xGroupTLB(m_xBuilder->weld_tree_view("group")) + , m_xNewPB(m_xBuilder->weld_button("new")) + , m_xDelPB(m_xBuilder->weld_button("delete")) + , m_xRenamePB(m_xBuilder->weld_button("rename")) +{ + int nWidth = m_xGroupTLB->get_approximate_digit_width() * 34; + m_xPathLB->set_size_request(nWidth, -1); + //just has to be something small, real size will be available space + m_xGroupTLB->set_size_request(nWidth, m_xGroupTLB->get_height_rows(10)); + + m_xGroupTLB->set_column_fixed_widths( { nWidth } ); + m_xGroupTLB->connect_changed(LINK(this, SwGlossaryGroupDlg, SelectHdl)); + + m_xNewPB->connect_clicked(LINK(this, SwGlossaryGroupDlg, NewHdl)); + m_xDelPB->connect_clicked(LINK(this, SwGlossaryGroupDlg, DeleteHdl)); + m_xNameED->connect_changed(LINK(this, SwGlossaryGroupDlg, ModifyHdl)); + m_xNameED->connect_insert_text(LINK(this, SwGlossaryGroupDlg, EditInsertTextHdl)); + m_xPathLB->connect_changed(LINK(this, SwGlossaryGroupDlg, ModifyListBoxHdl)); + m_xRenamePB->connect_clicked(LINK(this, SwGlossaryGroupDlg, RenameHdl)); + + m_xNameED->connect_size_allocate(LINK(this, SwGlossaryGroupDlg, EntrySizeAllocHdl)); + m_xPathLB->connect_size_allocate(LINK(this, SwGlossaryGroupDlg, EntrySizeAllocHdl)); + + for (size_t i = 0; i < rPathArr.size(); ++i) + { + INetURLObject aTempURL(rPathArr[i]); + const OUString sPath = aTempURL.GetMainURL(INetURLObject::DecodeMechanism::WithCharset ); + sal_uInt32 nCaseReadonly = 0; + utl::TempFile aTempFile(&sPath); + aTempFile.EnableKillingFile(); + if(!aTempFile.IsValid()) + nCaseReadonly |= PATH_READONLY; + else if( SWUnoHelper::UCB_IsCaseSensitiveFileName( aTempFile.GetURL())) + nCaseReadonly |= PATH_CASE_SENSITIVE; + m_xPathLB->append(OUString::number(nCaseReadonly), sPath); + } + m_xPathLB->set_active(0); + m_xPathLB->set_sensitive(true); + + const size_t nCount = pHdl->GetGroupCnt(); + /* tdf#111870 "My AutoText" comes from mytexts.bau but should be translated + here as well, see also SwGlossaryDlg::Init */ + static const OUStringLiteral sMyAutoTextEnglish(u"My AutoText"); + for( size_t i = 0; i < nCount; ++i) + { + OUString sTitle; + OUString sGroup = pHdl->GetGroupName(i, &sTitle); + if(sGroup.isEmpty()) + continue; + GlosBibUserData* pData = new GlosBibUserData; + pData->sGroupName = sGroup; + if ( sTitle == sMyAutoTextEnglish ) + pData->sGroupTitle = SwResId(STR_MY_AUTOTEXT); + else + pData->sGroupTitle = sTitle; + pData->sPath = m_xPathLB->get_text(o3tl::toInt32(o3tl::getToken(sGroup, 1, GLOS_DELIM))); + const OUString sId(weld::toId(pData)); + m_xGroupTLB->append(sId, pData->sGroupTitle); + int nEntry = m_xGroupTLB->find_id(sId); + m_xGroupTLB->set_text(nEntry, pData->sPath, 1); + + } + m_xGroupTLB->make_sorted(); +} + +SwGlossaryGroupDlg::~SwGlossaryGroupDlg() +{ + int nCount = m_xGroupTLB->n_children(); + for (int i = 0; i < nCount; ++i) + { + GlosBibUserData* pUserData = weld::fromId<GlosBibUserData*>(m_xGroupTLB->get_id(i)); + delete pUserData; + } +} + +short SwGlossaryGroupDlg::run() +{ + short nRet = SfxDialogController::run(); + if (nRet == RET_OK) + Apply(); + return nRet; +} + +void SwGlossaryGroupDlg::Apply() +{ + if (m_xNewPB->get_sensitive()) + NewHdl(*m_xNewPB); + + const OUString aActGroup = SwGlossaryDlg::GetCurrGroup(); + + for (const auto& removedStr : m_RemovedArr) + { + sal_Int32 nIdx{ 0 }; + const OUString sDelGroup = removedStr.getToken(0, '\t', nIdx); + if( sDelGroup == aActGroup ) + { + //when the current group is deleted, the current group has to be relocated + if (m_xGroupTLB->n_children()) + { + GlosBibUserData* pUserData = weld::fromId<GlosBibUserData*>(m_xGroupTLB->get_id(0)); + pGlosHdl->SetCurGroup(pUserData->sGroupName); + } + } + const OUString sMsg(SwResId(STR_QUERY_DELETE_GROUP1) + + o3tl::getToken(removedStr, 0, '\t', nIdx) + + SwResId(STR_QUERY_DELETE_GROUP2)); + + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_pParent, + VclMessageType::Question, VclButtonsType::YesNo, sMsg)); + xQueryBox->set_default_response(RET_NO); + if (RET_YES == xQueryBox->run()) + pGlosHdl->DelGroup( sDelGroup ); + } + + //don't rename before there was one + for (auto it(m_RenamedArr.cbegin()); it != m_RenamedArr.cend(); ++it) + { + sal_Int32 nIdx{ 0 }; + OUString const sOld(it->getToken(0, RENAME_TOKEN_DELIM, nIdx)); + OUString sNew(it->getToken(0, RENAME_TOKEN_DELIM, nIdx)); + OUString const sTitle(it->getToken(0, RENAME_TOKEN_DELIM, nIdx)); + pGlosHdl->RenameGroup(sOld, sNew, sTitle); + if (it == m_RenamedArr.begin()) + { + sCreatedGroup = sNew; + } + } + for (auto& sNewGroup : m_InsertedArr) + { + OUString sNewTitle = sNewGroup.getToken(0, GLOS_DELIM); + if( sNewGroup != aActGroup ) + { + pGlosHdl->NewGroup(sNewGroup, sNewTitle); + if(sCreatedGroup.isEmpty()) + sCreatedGroup = sNewGroup; + } + } +} + +IMPL_LINK_NOARG( SwGlossaryGroupDlg, SelectHdl, weld::TreeView&, void ) +{ + m_xNewPB->set_sensitive(false); + int nFirstEntry = m_xGroupTLB->get_selected_index(); + if (nFirstEntry == -1) + return; + + GlosBibUserData* pUserData = weld::fromId<GlosBibUserData*>(m_xGroupTLB->get_id(nFirstEntry)); + const OUString sEntry(pUserData->sGroupName); + const OUString sName(m_xNameED->get_text()); + bool bExists = false; + int nPos = m_xGroupTLB->find_text(sName); + if (nPos != -1) + { + GlosBibUserData* pFoundData = weld::fromId<GlosBibUserData*>(m_xGroupTLB->get_id(nPos)); + bExists = pFoundData->sGroupName == sEntry; + } + + m_xRenamePB->set_sensitive(!bExists && !sName.isEmpty()); + m_xDelPB->set_sensitive(IsDeleteAllowed(sEntry)); +} + +IMPL_LINK_NOARG(SwGlossaryGroupDlg, NewHdl, weld::Button&, void) +{ + OUString sGroup = m_xNameED->get_text() + + OUStringChar(GLOS_DELIM) + + OUString::number(m_xPathLB->get_active()); + OSL_ENSURE(!pGlosHdl->FindGroupName(sGroup), "group already available!"); + m_InsertedArr.push_back(sGroup); + GlosBibUserData* pData = new GlosBibUserData; + pData->sPath = m_xPathLB->get_active_text(); + pData->sGroupName = sGroup; + pData->sGroupTitle = m_xNameED->get_text(); + OUString sId(weld::toId(pData)); + m_xGroupTLB->append(sId, m_xNameED->get_text()); + int nEntry = m_xGroupTLB->find_id(sId); + m_xGroupTLB->set_text(nEntry, pData->sPath, 1); + m_xGroupTLB->select(nEntry); + SelectHdl(*m_xGroupTLB); + m_xGroupTLB->scroll_to_row(nEntry); +} + +IMPL_LINK_NOARG(SwGlossaryGroupDlg, EntrySizeAllocHdl, const Size&, void) +{ + std::vector<int> aWidths; + int x, y, width, height; + if (m_xPathLB->get_extents_relative_to(*m_xGroupTLB, x, y, width, height)) + { + aWidths.push_back(x); + m_xGroupTLB->set_column_fixed_widths(aWidths); + } +} + +IMPL_LINK( SwGlossaryGroupDlg, DeleteHdl, weld::Button&, rButton, void ) +{ + int nEntry = m_xGroupTLB->get_selected_index(); + if (nEntry == -1) + { + rButton.set_sensitive(false); + return; + } + GlosBibUserData* pUserData = weld::fromId<GlosBibUserData*>(m_xGroupTLB->get_id(nEntry)); + OUString const sEntry(pUserData->sGroupName); + // if the name to be deleted is among the new ones - get rid of it + bool bDelete = true; + auto it = std::find(m_InsertedArr.begin(), m_InsertedArr.end(), sEntry); + if (it != m_InsertedArr.end()) + { + m_InsertedArr.erase(it); + bDelete = false; + } + // it should probably be renamed? + if(bDelete) + { + it = std::find_if(m_RenamedArr.begin(), m_RenamedArr.end(), + [&sEntry](OUString& s) { return o3tl::getToken(s, 0, RENAME_TOKEN_DELIM) == sEntry; }); + if (it != m_RenamedArr.end()) + { + m_RenamedArr.erase(it); + bDelete = false; + } + } + if(bDelete) + { + m_RemovedArr.emplace_back(pUserData->sGroupName + "\t" + pUserData->sGroupTitle); + } + delete pUserData; + m_xGroupTLB->remove(nEntry); + if (!m_xGroupTLB->n_children()) + rButton.set_sensitive(false); + //the content must be deleted - otherwise the new handler would be called in Apply() + m_xNameED->set_text(OUString()); + ModifyHdl(*m_xNameED); +} + +IMPL_LINK_NOARG(SwGlossaryGroupDlg, RenameHdl, weld::Button&, void) +{ + int nEntry = m_xGroupTLB->get_selected_index(); + GlosBibUserData* pUserData = weld::fromId<GlosBibUserData*>(m_xGroupTLB->get_id(nEntry)); + OUString sEntry(pUserData->sGroupName); + + const OUString sNewTitle(m_xNameED->get_text()); + OUString sNewName = sNewTitle + + OUStringChar(GLOS_DELIM) + + OUString::number(m_xPathLB->get_active()); + OSL_ENSURE(!pGlosHdl->FindGroupName(sNewName), "group already available!"); + + // if the name to be renamed is among the new ones - replace + bool bDone = false; + auto it = std::find(m_InsertedArr.begin(), m_InsertedArr.end(), sEntry); + if (it != m_InsertedArr.end()) + { + m_InsertedArr.erase(it); + m_InsertedArr.push_back(sNewName); + bDone = true; + } + if(!bDone) + { + sEntry += OUStringChar(RENAME_TOKEN_DELIM) + sNewName + + OUStringChar(RENAME_TOKEN_DELIM) + sNewTitle; + m_RenamedArr.push_back(sEntry); + } + delete pUserData; + m_xGroupTLB->remove(nEntry); + + GlosBibUserData* pData = new GlosBibUserData; + pData->sPath = m_xPathLB->get_active_text(); + pData->sGroupName = sNewName; + pData->sGroupTitle = sNewTitle; + + OUString sId(weld::toId(pData)); + m_xGroupTLB->append(sId, m_xNameED->get_text()); + nEntry = m_xGroupTLB->find_id(sId); + m_xGroupTLB->set_text(nEntry, m_xPathLB->get_active_text(), 1); + m_xGroupTLB->select(nEntry); + SelectHdl(*m_xGroupTLB); + m_xGroupTLB->scroll_to_row(nEntry); +} + +IMPL_LINK_NOARG(SwGlossaryGroupDlg, ModifyListBoxHdl, weld::ComboBox&, void) +{ + ModifyHdl(*m_xNameED); +} + +IMPL_LINK_NOARG(SwGlossaryGroupDlg, ModifyHdl, weld::Entry&, void) +{ + const OUString sEntry(m_xNameED->get_text()); + bool bEnableNew = true; + bool bEnableDel = false; + sal_uInt32 nCaseReadonly = m_xPathLB->get_active_id().toUInt32(); + bool bDirReadonly = 0 != (nCaseReadonly&PATH_READONLY); + + if (sEntry.isEmpty() || bDirReadonly) + bEnableNew = false; + else if(!sEntry.isEmpty()) + { + int nPos = m_xGroupTLB->find_text(sEntry); + //if it's not case sensitive you have to search for yourself + if (nPos == -1) + { + const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore(); + for (int i = 0, nEntryCount = m_xGroupTLB->n_children(); i < nEntryCount; ++i) + { + const OUString sTemp = m_xGroupTLB->get_text(i, 0); + nCaseReadonly = m_xPathLB->get_id(m_xPathLB->find_text(m_xGroupTLB->get_text(i,1))).toUInt32(); + bool bCase = 0 != (nCaseReadonly & PATH_CASE_SENSITIVE); + + if( !bCase && rSCmp.isEqual( sTemp, sEntry )) + { + nPos = i; + break; + } + } + } + if (nPos != -1) + { + bEnableNew = false; + m_xGroupTLB->select(nPos); + m_xGroupTLB->scroll_to_row(nPos); + SelectHdl(*m_xGroupTLB); + } + } + int nEntry = m_xGroupTLB->get_selected_index(); + if (nEntry != -1) + { + GlosBibUserData* pUserData = weld::fromId<GlosBibUserData*>(m_xGroupTLB->get_id(nEntry)); + bEnableDel = IsDeleteAllowed(pUserData->sGroupName); + } + + m_xDelPB->set_sensitive(bEnableDel); + m_xNewPB->set_sensitive(bEnableNew); + m_xRenamePB->set_sensitive(bEnableNew && nEntry != -1); +} + +bool SwGlossaryGroupDlg::IsDeleteAllowed(const OUString &rGroup) +{ + bool bDel = !pGlosHdl->IsReadOnly(&rGroup); + + // OM: if the name is among the new region name, it is deletable + // as well! Because for non existing region names ReadOnly issues + // true. + + auto it = std::find(m_InsertedArr.cbegin(), m_InsertedArr.cend(), rGroup); + if (it != m_InsertedArr.cend()) + bDel = true; + + return bDel; +} + +IMPL_STATIC_LINK(SwGlossaryGroupDlg, EditInsertTextHdl, OUString&, rText, bool) +{ + rText = rText.replaceAll(OUStringChar(SVT_SEARCHPATH_DELIMITER), ""); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/glossary.cxx b/sw/source/ui/misc/glossary.cxx new file mode 100644 index 000000000..8fe493f93 --- /dev/null +++ b/sw/source/ui/misc/glossary.cxx @@ -0,0 +1,1086 @@ +/* -*- 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 <hintids.hxx> + +#include <o3tl/any.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/transfer.hxx> +#include <vcl/weld.hxx> +#include <svl/stritem.hxx> +#include <svl/macitem.hxx> +#include <unotools/pathoptions.hxx> +#include <sfx2/request.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/docfilt.hxx> +#include <osl/diagnose.h> + +#include <svx/svxdlg.hxx> +#include <editeng/acorrcfg.hxx> +#include <sfx2/viewfrm.hxx> +#include <unotools.hxx> +#include <comphelper/processfactory.hxx> +#include <ucbhelper/content.hxx> +#include <com/sun/star/text/AutoTextContainer.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <svl/urihelper.hxx> +#include <unotools/charclass.hxx> +#include <swtypes.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <glossary.hxx> +#include <gloshdl.hxx> +#include <glosbib.hxx> +#include <initui.hxx> +#include <glosdoc.hxx> +#include <macassgn.hxx> +#include <docsh.hxx> +#include <shellio.hxx> + +#include <cmdid.h> +#include <sfx2/filedlghelper.hxx> + +#include <memory> + +#include <strings.hrc> +#include <iodetect.hxx> + +#include <officecfg/Office/Writer.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::ucbhelper; +using namespace ::sfx2; + +static OUString lcl_GetValidShortCut( const OUString& rName ) +{ + const sal_Int32 nSz = rName.getLength(); + + if ( 0 == nSz ) + return rName; + + sal_Int32 nStart = 1; + while( rName[nStart-1]==' ' && nStart < nSz ) + nStart++; + + OUStringBuffer aBuf; + aBuf.append(rName[nStart-1]); + + for( ; nStart < nSz; ++nStart ) + { + if( rName[nStart-1]==' ' && rName[nStart]!=' ') + aBuf.append(rName[nStart]); + } + return aBuf.makeStringAndClear(); +} + +struct GroupUserData +{ + OUString sGroupName; + sal_uInt16 nPathIdx; + bool bReadonly; + + GroupUserData() + : nPathIdx(0), + bReadonly(false) {} +}; + +// dialog for new block name +class SwNewGlosNameDlg : public weld::GenericDialogController +{ + TextFilter m_aNoSpaceFilter; + SwGlossaryDlg* m_pParent; + + std::unique_ptr<weld::Entry> m_xNewName; + std::unique_ptr<weld::Entry> m_xNewShort; + std::unique_ptr<weld::Button> m_xOk; + std::unique_ptr<weld::Entry> m_xOldName; + std::unique_ptr<weld::Entry> m_xOldShort; + +protected: + DECL_LINK(Modify, weld::Entry&, void); + DECL_LINK(Rename, weld::Button&, void); + DECL_LINK(TextFilterHdl, OUString&, bool); + +public: + SwNewGlosNameDlg(SwGlossaryDlg* pParent, + const OUString& rOldName, + const OUString& rOldShort); + + OUString GetNewName() const { return m_xNewName->get_text(); } + OUString GetNewShort() const { return m_xNewShort->get_text(); } +}; + +IMPL_LINK(SwNewGlosNameDlg, TextFilterHdl, OUString&, rTest, bool) +{ + rTest = m_aNoSpaceFilter.filter(rTest); + return true; +} + +SwNewGlosNameDlg::SwNewGlosNameDlg(SwGlossaryDlg* pParent, const OUString& rOldName, const OUString& rOldShort) + : GenericDialogController(pParent->getDialog(), "modules/swriter/ui/renameautotextdialog.ui", "RenameAutoTextDialog") + , m_pParent(pParent) + , m_xNewName(m_xBuilder->weld_entry("newname")) + , m_xNewShort(m_xBuilder->weld_entry("newsc")) + , m_xOk(m_xBuilder->weld_button("ok")) + , m_xOldName(m_xBuilder->weld_entry("oldname")) + , m_xOldShort(m_xBuilder->weld_entry("oldsc")) +{ + m_xNewShort->connect_insert_text(LINK(this, SwNewGlosNameDlg, TextFilterHdl)); + + m_xOldName->set_text(rOldName); + m_xOldShort->set_text(rOldShort); + m_xNewName->connect_changed(LINK(this, SwNewGlosNameDlg, Modify )); + m_xNewShort->connect_changed(LINK(this, SwNewGlosNameDlg, Modify )); + m_xOk->connect_clicked(LINK(this, SwNewGlosNameDlg, Rename )); + m_xNewName->grab_focus(); +} + +// query / set currently set group +OUString SwGlossaryDlg::GetCurrGroup() +{ + if( !::GetCurrGlosGroup().isEmpty() ) + return ::GetCurrGlosGroup(); + return SwGlossaries::GetDefName(); +} + +void SwGlossaryDlg::SetActGroup(const OUString &rGrp) +{ + ::SetCurrGlosGroup(rGrp); +} + +IMPL_LINK(SwGlossaryDlg, TextFilterHdl, OUString&, rTest, bool) +{ + rTest = m_aNoSpaceFilter.filter(rTest); + return true; +} + +class SwGlossaryDropTarget : public DropTargetHelper +{ +private: + weld::TreeView& m_rTreeView; + SwGlossaryHdl* m_pGlosHdl; + + virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override + { + weld::TreeView* pSource = m_rTreeView.get_drag_source(); + if (!pSource || pSource != &m_rTreeView) + return DND_ACTION_NONE; + + std::unique_ptr<weld::TreeIter> xSelected(pSource->make_iterator()); + bool bSelected = pSource->get_selected(xSelected.get()); + if (!bSelected) + return DND_ACTION_NONE; + + while (pSource->get_iter_depth(*xSelected)) + (void)pSource->iter_parent(*xSelected); + + GroupUserData* pSrcRootData = weld::fromId<GroupUserData*>(pSource->get_id(*xSelected)); + GroupUserData* pDestRootData = nullptr; + + std::unique_ptr<weld::TreeIter> xDestEntry(m_rTreeView.make_iterator()); + bool bEntry = m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xDestEntry.get(), true); + if (bEntry) + { + while (m_rTreeView.get_iter_depth(*xDestEntry)) + (void)m_rTreeView.iter_parent(*xDestEntry); + pDestRootData = weld::fromId<GroupUserData*>(m_rTreeView.get_id(*xDestEntry)); + } + if (pDestRootData == pSrcRootData) + return DND_ACTION_NONE; + sal_uInt8 nRet = DND_ACTION_COPY; + const bool bCheckForMove = rEvt.mnAction & DND_ACTION_MOVE; + if (bCheckForMove && !pSrcRootData->bReadonly) + nRet |= DND_ACTION_MOVE; + return nRet; + } + + virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override + { + weld::TreeView* pSource = m_rTreeView.get_drag_source(); + if (!pSource) + return DND_ACTION_NONE; + + std::unique_ptr<weld::TreeIter> xDestEntry(m_rTreeView.make_iterator()); + bool bEntry = m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xDestEntry.get(), true); + if (!bEntry) + return DND_ACTION_NONE; + + std::unique_ptr<weld::TreeIter> xSelected(pSource->make_iterator()); + bool bSelected = pSource->get_selected(xSelected.get()); + if (!bSelected) + return DND_ACTION_NONE; + + std::unique_ptr<weld::TreeIter> xSrcParent(pSource->make_iterator(xSelected.get())); + while (pSource->get_iter_depth(*xSrcParent)) + (void)pSource->iter_parent(*xSrcParent); + + std::unique_ptr<weld::TreeIter> xDestParent(pSource->make_iterator(xDestEntry.get())); + while (pSource->get_iter_depth(*xDestParent)) + (void)pSource->iter_parent(*xDestParent); + + GroupUserData* pSrcParent = weld::fromId<GroupUserData*>(pSource->get_id(*xSrcParent)); + GroupUserData* pDestParent = weld::fromId<GroupUserData*>(m_rTreeView.get_id(*xDestParent)); + + if (pDestParent != pSrcParent) + { + weld::WaitObject aBusy(&m_rTreeView); + + OUString sSourceGroup = pSrcParent->sGroupName + + OUStringChar(GLOS_DELIM) + + OUString::number(pSrcParent->nPathIdx); + + m_pGlosHdl->SetCurGroup(sSourceGroup); + OUString sTitle(pSource->get_text(*xSelected)); + OUString sShortName(pSource->get_id(*xSelected)); + + OUString sDestName = pDestParent->sGroupName + + OUStringChar(GLOS_DELIM) + + OUString::number(pDestParent->nPathIdx); + + bool bIsMove = rEvt.mnAction & DND_ACTION_MOVE; + + const bool bRet = m_pGlosHdl->CopyOrMove(sSourceGroup, sShortName, + sDestName, sTitle, bIsMove); + + if(bRet) + { + m_rTreeView.insert(xDestParent.get(), -1, &sTitle, &sShortName, + nullptr, nullptr, false, nullptr); + if (bIsMove) + { + pSource->remove(*xSelected); + } + } + } + + return DND_ACTION_NONE; + } + +public: + SwGlossaryDropTarget(weld::TreeView& rTreeView, SwGlossaryHdl* pGlosHdl) + : DropTargetHelper(rTreeView.get_drop_target()) + , m_rTreeView(rTreeView) + , m_pGlosHdl(pGlosHdl) + { + } +}; + +SwGlossaryDlg::SwGlossaryDlg(SfxViewFrame const * pViewFrame, + SwGlossaryHdl * pGlosHdl, SwWrtShell *pWrtShell) + : SfxDialogController(pViewFrame->GetFrameWeld(), "modules/swriter/ui/autotext.ui", "AutoTextDialog") + , m_sReadonlyPath(SwResId(STR_READONLY_PATH)) + , m_pGlossaryHdl(pGlosHdl) + , m_bResume(false) + , m_bSelection(pWrtShell->IsSelection()) + , m_bReadOnly(false) + , m_bIsOld(false) + , m_bIsDocReadOnly(false) + , m_pShell(pWrtShell) + , m_xInsertTipCB(m_xBuilder->weld_check_button("inserttip")) + , m_xNameED(m_xBuilder->weld_entry("name")) + , m_xShortNameLbl(m_xBuilder->weld_label("shortnameft")) + , m_xShortNameEdit(m_xBuilder->weld_entry("shortname")) + , m_xCategoryBox(m_xBuilder->weld_tree_view("category")) + , m_xFileRelCB(m_xBuilder->weld_check_button("relfile")) + , m_xNetRelCB(m_xBuilder->weld_check_button("relnet")) + , m_xInsertBtn(m_xBuilder->weld_button("ok")) + , m_xEditBtn(m_xBuilder->weld_menu_button("autotext")) + , m_xBibBtn(m_xBuilder->weld_button("categories")) + , m_xPathBtn(m_xBuilder->weld_button("path")) +{ + m_xCategoryBox->set_size_request(m_xCategoryBox->get_approximate_digit_width() * 52, + m_xCategoryBox->get_height_rows(12)); + + Link<SwOneExampleFrame&,void> aLink(LINK(this, SwGlossaryDlg, PreviewLoadedHdl)); + m_xExampleFrame.reset(new SwOneExampleFrame(EX_SHOW_ONLINE_LAYOUT, &aLink)); + m_xExampleFrameWin.reset(new weld::CustomWeld(*m_xBuilder, "example", *m_xExampleFrame)); + Size aSize = m_xExampleFrame->GetDrawingArea()->get_ref_device().LogicToPixel( + Size(82, 124), MapMode(MapUnit::MapAppFont)); + m_xExampleFrame->set_size_request(aSize.Width(), aSize.Height()); + + m_xShortNameEdit->connect_insert_text(LINK(this, SwGlossaryDlg, TextFilterHdl)); + + m_xEditBtn->connect_toggled(LINK(this, SwGlossaryDlg, EnableHdl)); + m_xEditBtn->connect_selected(LINK(this, SwGlossaryDlg, MenuHdl)); + m_xPathBtn->connect_clicked(LINK(this, SwGlossaryDlg, PathHdl)); + + m_xNameED->connect_changed(LINK(this,SwGlossaryDlg,NameModify)); + m_xShortNameEdit->connect_changed(LINK(this,SwGlossaryDlg,NameModify)); + + m_xCategoryBox->connect_row_activated(LINK(this, SwGlossaryDlg, NameDoubleClick)); + m_xCategoryBox->connect_changed(LINK(this, SwGlossaryDlg, GrpSelect)); + m_xCategoryBox->connect_key_press(LINK(this, SwGlossaryDlg, KeyInputHdl)); + + m_xDropTarget.reset(new SwGlossaryDropTarget(*m_xCategoryBox, pGlosHdl)); + rtl::Reference<TransferDataContainer> xHelper(new TransferDataContainer); + m_xCategoryBox->enable_drag_source(xHelper, DND_ACTION_COPYMOVE); + + m_xBibBtn->connect_clicked(LINK(this,SwGlossaryDlg,BibHdl)); + + m_xInsertBtn->connect_clicked(LINK(this,SwGlossaryDlg,InsertHdl)); + + ShowPreview(); + + m_bIsDocReadOnly = m_pShell->GetView().GetDocShell()->IsReadOnly() || + m_pShell->HasReadonlySel(); + if( m_bIsDocReadOnly ) + m_xInsertBtn->set_sensitive(false); + m_xNameED->grab_focus(); + m_xCategoryBox->make_sorted(); + m_xCategoryBox->set_sort_order(true); + + Init(); +} + +SwGlossaryDlg::~SwGlossaryDlg() +{ +} + +namespace +{ + +OUString getCurrentGlossary() +{ + const OUString sTemp{ ::GetCurrGlosGroup() }; + + // the zeroth path is not being recorded! + if (o3tl::starts_with(o3tl::getToken(sTemp, 1, GLOS_DELIM), u"0")) + return sTemp.getToken(0, GLOS_DELIM); + + return sTemp; +} + +} + +// select new group +IMPL_LINK(SwGlossaryDlg, GrpSelect, weld::TreeView&, rBox, void) +{ + std::unique_ptr<weld::TreeIter> xEntry = rBox.make_iterator(); + if (!rBox.get_selected(xEntry.get())) + return; + + std::unique_ptr<weld::TreeIter> xParent = rBox.make_iterator(xEntry.get()); + weld::TreeIter* pParent; + if (rBox.get_iter_depth(*xParent)) + { + rBox.iter_parent(*xParent); + pParent = xParent.get(); + } + else + pParent = xEntry.get(); + GroupUserData* pGroupData = weld::fromId<GroupUserData*>(rBox.get_id(*pParent)); + ::SetCurrGlosGroup(pGroupData->sGroupName + + OUStringChar(GLOS_DELIM) + + OUString::number(pGroupData->nPathIdx)); + m_pGlossaryHdl->SetCurGroup(::GetCurrGlosGroup()); + // set current text block + m_bReadOnly = m_pGlossaryHdl->IsReadOnly(); + EnableShortName( !m_bReadOnly ); + m_xEditBtn->set_sensitive(!m_bReadOnly); + m_bIsOld = m_pGlossaryHdl->IsOld(); + if( pParent != xEntry.get()) + { + OUString aName(rBox.get_text(*xEntry)); + m_xNameED->set_text(aName); + m_xShortNameEdit->set_text(rBox.get_id(*xEntry)); + m_xInsertBtn->set_sensitive( !m_bIsDocReadOnly); + ShowAutoText(::GetCurrGlosGroup(), m_xShortNameEdit->get_text()); + } + else + { + m_xNameED->set_text(""); + m_xShortNameEdit->set_text(""); + m_xShortNameEdit->set_sensitive(false); + ShowAutoText("", ""); + } + // update controls + NameModify(*m_xShortNameEdit); + if( SfxRequest::HasMacroRecorder( m_pShell->GetView().GetViewFrame() ) ) + { + SfxRequest aReq( m_pShell->GetView().GetViewFrame(), FN_SET_ACT_GLOSSARY ); + aReq.AppendItem(SfxStringItem(FN_SET_ACT_GLOSSARY, getCurrentGlossary())); + aReq.Done(); + } +} + +short SwGlossaryDlg::run() +{ + short nRet = SfxDialogController::run(); + if (nRet == RET_OK) + Apply(); + return nRet; +} + +void SwGlossaryDlg::Apply() +{ + const OUString aGlosName(m_xShortNameEdit->get_text()); + if (!aGlosName.isEmpty()) + { + m_pGlossaryHdl->InsertGlossary(aGlosName); + } + if( SfxRequest::HasMacroRecorder( m_pShell->GetView().GetViewFrame() ) ) + { + SfxRequest aReq( m_pShell->GetView().GetViewFrame(), FN_INSERT_GLOSSARY ); + aReq.AppendItem(SfxStringItem(FN_INSERT_GLOSSARY, getCurrentGlossary())); + aReq.AppendItem(SfxStringItem(FN_PARAM_1, aGlosName)); + aReq.Done(); + } +} + +void SwGlossaryDlg::EnableShortName(bool bOn) +{ + m_xShortNameLbl->set_sensitive(bOn); + m_xShortNameEdit->set_sensitive(bOn); +} + +// does the title exist in the selected group? +std::unique_ptr<weld::TreeIter> SwGlossaryDlg::DoesBlockExist(std::u16string_view rBlock, + std::u16string_view rShort) +{ + // look for possible entry in TreeListBox + std::unique_ptr<weld::TreeIter> xEntry = m_xCategoryBox->make_iterator(); + if (m_xCategoryBox->get_selected(xEntry.get())) + { + if (m_xCategoryBox->get_iter_depth(*xEntry)) + m_xCategoryBox->iter_parent(*xEntry); + if (!m_xCategoryBox->iter_children(*xEntry)) + return nullptr; + do + { + if (rBlock == m_xCategoryBox->get_text(*xEntry) && + (rShort.empty() || + rShort == m_xCategoryBox->get_id(*xEntry)) + ) + { + return xEntry; + } + } + while (m_xCategoryBox->iter_next_sibling(*xEntry)); + } + return nullptr; +} + +IMPL_LINK(SwGlossaryDlg, NameModify, weld::Entry&, rEdit, void) +{ + const OUString aName(m_xNameED->get_text()); + bool bNameED = &rEdit == m_xNameED.get(); + if( aName.isEmpty() ) + { + if(bNameED) + m_xShortNameEdit->set_text(aName); + m_xInsertBtn->set_sensitive(false); + return; + } + const bool bNotFound = !DoesBlockExist(aName, bNameED ? OUString() : rEdit.get_text()); + if(bNameED) + { + // did the text get in to the Listbox in the Edit with a click? + if(bNotFound) + { + m_xShortNameEdit->set_text( lcl_GetValidShortCut( aName ) ); + EnableShortName(); + } + else + { + m_xShortNameEdit->set_text(m_pGlossaryHdl->GetGlossaryShortName(aName)); + EnableShortName(!m_bReadOnly); + } + m_xInsertBtn->set_sensitive(!bNotFound && !m_bIsDocReadOnly); + } + else + { + //ShortNameEdit + if(!bNotFound) + { + m_xInsertBtn->set_sensitive(!m_bIsDocReadOnly); + } + } +} + +IMPL_LINK( SwGlossaryDlg, NameDoubleClick, weld::TreeView&, rBox, bool ) +{ + std::unique_ptr<weld::TreeIter> xEntry = rBox.make_iterator(); + if (rBox.get_selected(xEntry.get()) && rBox.get_iter_depth(*xEntry) && !m_bIsDocReadOnly) + m_xDialog->response(RET_OK); + return true; +} + +IMPL_LINK_NOARG( SwGlossaryDlg, EnableHdl, weld::Toggleable&, void ) +{ + std::unique_ptr<weld::TreeIter> xEntry = m_xCategoryBox->make_iterator(); + bool bEntry = m_xCategoryBox->get_selected(xEntry.get()); + + const OUString aEditText(m_xNameED->get_text()); + const bool bHasEntry = !aEditText.isEmpty() && !m_xShortNameEdit->get_text().isEmpty(); + const bool bExists = nullptr != DoesBlockExist(aEditText, m_xShortNameEdit->get_text()); + const bool bIsGroup = bEntry && !m_xCategoryBox->get_iter_depth(*xEntry); + m_xEditBtn->set_item_visible("new", m_bSelection && bHasEntry && !bExists); + m_xEditBtn->set_item_visible("newtext", m_bSelection && bHasEntry && !bExists); + m_xEditBtn->set_item_visible("copy", bExists && !bIsGroup); + m_xEditBtn->set_item_visible("replace", m_bSelection && bExists && !bIsGroup && !m_bIsOld ); + m_xEditBtn->set_item_visible("replacetext", m_bSelection && bExists && !bIsGroup && !m_bIsOld ); + m_xEditBtn->set_item_visible("edit", bExists && !bIsGroup ); + m_xEditBtn->set_item_visible("rename", bExists && !bIsGroup ); + m_xEditBtn->set_item_visible("delete", bExists && !bIsGroup ); + m_xEditBtn->set_item_visible("macro", bExists && !bIsGroup && !m_bIsOld && + !m_pGlossaryHdl->IsReadOnly() ); + m_xEditBtn->set_item_visible("import", bIsGroup && !m_bIsOld && !m_pGlossaryHdl->IsReadOnly() ); +} + +IMPL_LINK(SwGlossaryDlg, MenuHdl, const OString&, rItemIdent, void) +{ + if (rItemIdent == "edit") + { + std::unique_ptr<SwTextBlocks> pGroup = ::GetGlossaries()->GetGroupDoc ( GetCurrGrpName () ); + pGroup.reset(); + m_xDialog->response(RET_EDIT); + } + else if (rItemIdent == "replace") + { + m_pGlossaryHdl->NewGlossary(m_xNameED->get_text(), + m_xShortNameEdit->get_text()); + } + else if (rItemIdent == "replacetext") + { + m_pGlossaryHdl->NewGlossary(m_xNameED->get_text(), + m_xShortNameEdit->get_text(), + false, true); + } + else if (rItemIdent == "new" || rItemIdent == "newtext") + { + bool bNoAttr = rItemIdent == "newtext"; + + const OUString aStr(m_xNameED->get_text()); + const OUString aShortName(m_xShortNameEdit->get_text()); + if(m_pGlossaryHdl->HasShortName(aShortName)) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_DOUBLE_SHORTNAME))); + xInfoBox->run(); + m_xShortNameEdit->select_region(0, -1); + m_xShortNameEdit->grab_focus(); + } + if(m_pGlossaryHdl->NewGlossary(aStr, aShortName, false, bNoAttr )) + { + std::unique_ptr<weld::TreeIter> xEntry = m_xCategoryBox->make_iterator(); + if (!m_xCategoryBox->get_selected(xEntry.get())) + xEntry.reset(); + else if (m_xCategoryBox->get_iter_depth(*xEntry)) + m_xCategoryBox->iter_parent(*xEntry); + m_xCategoryBox->insert(xEntry.get(), -1, &aStr, &aShortName, + nullptr, nullptr, false, nullptr); + + m_xNameED->set_text(aStr); + m_xShortNameEdit->set_text(aShortName); + NameModify(*m_xNameED); // for toggling the buttons + + if( SfxRequest::HasMacroRecorder( m_pShell->GetView().GetViewFrame() ) ) + { + SfxRequest aReq(m_pShell->GetView().GetViewFrame(), FN_NEW_GLOSSARY); + aReq.AppendItem(SfxStringItem(FN_NEW_GLOSSARY, getCurrentGlossary())); + aReq.AppendItem(SfxStringItem(FN_PARAM_1, aShortName)); + aReq.AppendItem(SfxStringItem(FN_PARAM_2, aStr)); + aReq.Done(); + } + } + } + else if (rItemIdent == "copy") + { + m_pGlossaryHdl->CopyToClipboard(*m_pShell, m_xShortNameEdit->get_text()); + } + else if (rItemIdent == "rename") + { + m_xShortNameEdit->set_text(m_pGlossaryHdl->GetGlossaryShortName(m_xNameED->get_text())); + SwNewGlosNameDlg aNewNameDlg(this, m_xNameED->get_text(), m_xShortNameEdit->get_text()); + if (aNewNameDlg.run() == RET_OK && m_pGlossaryHdl->Rename(m_xShortNameEdit->get_text(), + aNewNameDlg.GetNewShort(), + aNewNameDlg.GetNewName())) + { + std::unique_ptr<weld::TreeIter> xEntry = m_xCategoryBox->make_iterator(); + if (m_xCategoryBox->get_selected(xEntry.get())) + { + std::unique_ptr<weld::TreeIter> xOldEntry = m_xCategoryBox->make_iterator(xEntry.get()); + if (m_xCategoryBox->get_iter_depth(*xEntry)) + m_xCategoryBox->iter_parent(*xEntry); + + std::unique_ptr<weld::TreeIter> xNewEntry = m_xCategoryBox->make_iterator(); + OUString sId(aNewNameDlg.GetNewShort()); + OUString sName(aNewNameDlg.GetNewName()); + + m_xCategoryBox->insert(xEntry.get(), -1, &sName, &sId, + nullptr, nullptr, false, xNewEntry.get()); + + m_xCategoryBox->remove(*xOldEntry); + m_xCategoryBox->select(*xNewEntry); + m_xCategoryBox->scroll_to_row(*xNewEntry); + } + } + GrpSelect(*m_xCategoryBox); + } + else if (rItemIdent == "delete") + { + DeleteEntry(); + } + else if (rItemIdent == "macro") + { + SfxItemSetFixed<RES_FRMMACRO, RES_FRMMACRO, SID_EVENTCONFIG, SID_EVENTCONFIG> aSet( m_pShell->GetAttrPool() ); + + SvxMacro aStart(OUString(), OUString(), STARBASIC); + SvxMacro aEnd(OUString(), OUString(), STARBASIC); + m_pGlossaryHdl->GetMacros(m_xShortNameEdit->get_text(), aStart, aEnd ); + + SvxMacroItem aItem(RES_FRMMACRO); + if( aStart.HasMacro() ) + aItem.SetMacro( SvMacroItemId::SwStartInsGlossary, aStart ); + if( aEnd.HasMacro() ) + aItem.SetMacro( SvMacroItemId::SwEndInsGlossary, aEnd ); + + aSet.Put( aItem ); + aSet.Put( SwMacroAssignDlg::AddEvents( MACASSGN_AUTOTEXT ) ); + + const SvxMacroItem* pMacroItem; + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<SfxAbstractDialog> pMacroDlg(pFact->CreateEventConfigDialog(m_xDialog.get(), aSet, + m_pShell->GetView().GetViewFrame()->GetFrame().GetFrameInterface() )); + if ( pMacroDlg && pMacroDlg->Execute() == RET_OK && + (pMacroItem = pMacroDlg->GetOutputItemSet()->GetItemIfSet( RES_FRMMACRO, false )) ) + { + const SvxMacroTableDtor& rTable = pMacroItem->GetMacroTable(); + m_pGlossaryHdl->SetMacros( m_xShortNameEdit->get_text(), + rTable.Get( SvMacroItemId::SwStartInsGlossary ), + rTable.Get( SvMacroItemId::SwEndInsGlossary ) ); + } + } + else if (rItemIdent == "import") + { + // call the FileOpenDialog do find WinWord - Files with templates + FileDialogHelper aDlgHelper(TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, m_xDialog.get()); + aDlgHelper.SetContext(FileDialogHelper::WriterImportAutotext); + uno::Reference < XFilePicker3 > xFP = aDlgHelper.GetFilePicker(); + + SfxFilterMatcher aMatcher( SwDocShell::Factory().GetFactoryName() ); + SfxFilterMatcherIter aIter( aMatcher ); + std::shared_ptr<const SfxFilter> pFilter = aIter.First(); + while ( pFilter ) + { + if( pFilter->GetUserData() == FILTER_WW8 ) + { + xFP->appendFilter( pFilter->GetUIName(), + pFilter->GetWildcard().getGlob() ); + xFP->setCurrentFilter( pFilter->GetUIName() ) ; + } + else if( pFilter->GetUserData() == FILTER_DOCX ) + { + xFP->appendFilter( pFilter->GetUIName(), + pFilter->GetWildcard().getGlob() ); + xFP->setCurrentFilter( pFilter->GetUIName() ) ; + } + + pFilter = aIter.Next(); + } + + if( aDlgHelper.Execute() == ERRCODE_NONE ) + { + if( m_pGlossaryHdl->ImportGlossaries( xFP->getSelectedFiles().getConstArray()[0] )) + Init(); + else + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_NO_GLOSSARIES))); + xInfoBox->run(); + } + } + } +} + +// dialog manage regions +IMPL_LINK_NOARG(SwGlossaryDlg, BibHdl, weld::Button&, void) +{ + SwGlossaries* pGloss = ::GetGlossaries(); + if( pGloss->IsGlosPathErr() ) + pGloss->ShowError(); + else + { + //check if at least one glossary path is write enabled + SvtPathOptions aPathOpt; + const OUString& sGlosPath( aPathOpt.GetAutoTextPath() ); + bool bIsWritable = false; + sal_Int32 nIdx {sGlosPath.isEmpty() ? -1 : 0}; + while (nIdx>=0) + { + const OUString sPath = URIHelper::SmartRel2Abs( + INetURLObject(), sGlosPath.getToken(0, ';', nIdx), + URIHelper::GetMaybeFileHdl()); + try + { + Content aTestContent( sPath, + uno::Reference< XCommandEnvironment >(), + comphelper::getProcessComponentContext() ); + Any aAny = aTestContent.getPropertyValue( "IsReadOnly" ); + if(aAny.hasValue()) + { + bIsWritable = !*o3tl::doAccess<bool>(aAny); + } + } + catch (const Exception&) + { + } + if(bIsWritable) + break; + } + if(bIsWritable) + { + + SwGlossaryGroupDlg aDlg(m_xDialog.get(), pGloss->GetPathArray(), m_pGlossaryHdl); + if (aDlg.run() == RET_OK) + { + Init(); + //if new groups were created - select one of them + const OUString sNewGroup = aDlg.GetCreatedGroupName(); + + std::unique_ptr<weld::TreeIter> xEntry = m_xCategoryBox->make_iterator(); + bool bEntry = m_xCategoryBox->get_iter_first(*xEntry); + + while (!sNewGroup.isEmpty() && bEntry) + { + if (!m_xCategoryBox->get_iter_depth(*xEntry)) + { + GroupUserData* pGroupData = weld::fromId<GroupUserData*>(m_xCategoryBox->get_id(*xEntry)); + const OUString sGroup = pGroupData->sGroupName + + OUStringChar(GLOS_DELIM) + + OUString::number(pGroupData->nPathIdx); + if(sGroup == sNewGroup) + { + m_xCategoryBox->select(*xEntry); + m_xCategoryBox->scroll_to_row(*xEntry); + GrpSelect(*m_xCategoryBox); + break; + } + } + bEntry = m_xCategoryBox->iter_next(*xEntry); + } + + } + } + else + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Question, VclButtonsType::YesNo, + m_sReadonlyPath)); + if (RET_YES == xBox->run()) + PathHdl(*m_xPathBtn); + } + } +} + +// initialisation; from Ctor and after editing regions +void SwGlossaryDlg::Init() +{ + m_xCategoryBox->freeze(); + m_xCategoryBox->clear(); + m_xGroupData.clear(); + m_xCategoryBox->make_unsorted(); + + // display text block regions + const size_t nCnt = m_pGlossaryHdl->GetGroupCnt(); + std::unique_ptr<weld::TreeIter> xSelEntry; + const OUString sSelStr(::GetCurrGlosGroup().getToken(0, GLOS_DELIM)); + const sal_Int32 nSelPath = o3tl::toInt32(o3tl::getToken(::GetCurrGlosGroup(), 1, GLOS_DELIM)); + // #i66304# - "My AutoText" comes from mytexts.bau, but should be translated + static const OUStringLiteral sMyAutoTextEnglish(u"My AutoText"); + const OUString sMyAutoTextTranslated(SwResId(STR_MY_AUTOTEXT)); + for(size_t nId = 0; nId < nCnt; ++nId ) + { + OUString sTitle; + OUString sGroupName(m_pGlossaryHdl->GetGroupName(nId, &sTitle)); + if(sGroupName.isEmpty()) + continue; + sal_Int32 nIdx{ 0 }; + const OUString sName{ sGroupName.getToken( 0, GLOS_DELIM, nIdx ) }; + if(sTitle.isEmpty()) + sTitle = sName; + if(sTitle == sMyAutoTextEnglish) + sTitle = sMyAutoTextTranslated; + + std::unique_ptr<weld::TreeIter> xEntry = m_xCategoryBox->make_iterator(); + m_xCategoryBox->append(xEntry.get()); + m_xCategoryBox->set_text(*xEntry, sTitle, 0); + const sal_Int32 nPath = o3tl::toInt32(o3tl::getToken(sGroupName, 0, GLOS_DELIM, nIdx )); + + GroupUserData* pData = new GroupUserData; + pData->sGroupName = sName; + pData->nPathIdx = static_cast< sal_uInt16 >(nPath); + pData->bReadonly = m_pGlossaryHdl->IsReadOnly(&sGroupName); + m_xGroupData.emplace_back(pData); + + m_xCategoryBox->set_id(*xEntry, weld::toId(pData)); + if (sSelStr == pData->sGroupName && nSelPath == nPath) + xSelEntry = m_xCategoryBox->make_iterator(xEntry.get()); + + // fill entries for the groups + { + m_pGlossaryHdl->SetCurGroup(sGroupName, false, true); + const sal_uInt16 nCount = m_pGlossaryHdl->GetGlossaryCnt(); + for(sal_uInt16 i = 0; i < nCount; ++i) + { + OUString sEntryName = m_pGlossaryHdl->GetGlossaryName(i); + OUString sId = m_pGlossaryHdl->GetGlossaryShortName(i); + m_xCategoryBox->insert(xEntry.get(), -1, &sEntryName, &sId, + nullptr, nullptr, false, nullptr); + } + } + } + // set current group and display text blocks + if (!xSelEntry) + { + //find a non-readonly group + std::unique_ptr<weld::TreeIter> xSearch = m_xCategoryBox->make_iterator(); + if (m_xCategoryBox->get_iter_first(*xSearch)) + { + do + { + if (!m_xCategoryBox->get_iter_depth(*xSearch)) + { + GroupUserData* pData = weld::fromId<GroupUserData*>(m_xCategoryBox->get_id(*xSearch)); + if (!pData->bReadonly) + { + xSelEntry = std::move(xSearch); + break; + } + } + } + while (m_xCategoryBox->iter_next(*xSearch)); + } + if (!xSelEntry) + { + xSelEntry = std::move(xSearch); + if (!m_xCategoryBox->get_iter_first(*xSelEntry)) + xSelEntry.reset(); + } + } + + m_xCategoryBox->thaw(); + m_xCategoryBox->make_sorted(); + + if (xSelEntry) + { + m_xCategoryBox->expand_row(*xSelEntry); + m_xCategoryBox->select(*xSelEntry); + m_xCategoryBox->scroll_to_row(*xSelEntry); + GrpSelect(*m_xCategoryBox); + } + + const SvxAutoCorrCfg& rCfg = SvxAutoCorrCfg::Get(); + m_xFileRelCB->set_active( rCfg.IsSaveRelFile() ); + m_xFileRelCB->connect_toggled(LINK(this, SwGlossaryDlg, CheckBoxHdl)); + m_xNetRelCB->set_active( rCfg.IsSaveRelNet() ); + m_xNetRelCB->connect_toggled(LINK(this, SwGlossaryDlg, CheckBoxHdl)); + m_xInsertTipCB->set_active( rCfg.IsAutoTextTip() ); + m_xInsertTipCB->set_sensitive(!officecfg::Office::Writer::AutoFunction::Text::ShowToolTip::isReadOnly()); + m_xInsertTipCB->connect_toggled(LINK(this, SwGlossaryDlg, CheckBoxHdl)); +} + +// KeyInput for ShortName - Edits without Spaces +IMPL_LINK( SwNewGlosNameDlg, Modify, weld::Entry&, rBox, void ) +{ + OUString aName(m_xNewName->get_text()); + SwGlossaryDlg* pDlg = m_pParent; + if (&rBox == m_xNewName.get()) + m_xNewShort->set_text(lcl_GetValidShortCut(aName)); + + bool bEnable = !aName.isEmpty() && !m_xNewShort->get_text().isEmpty() && + (!pDlg->DoesBlockExist(aName, m_xNewShort->get_text()) + || aName == m_xOldName->get_text()); + m_xOk->set_sensitive(bEnable); +} + +IMPL_LINK_NOARG(SwNewGlosNameDlg, Rename, weld::Button&, void) +{ + SwGlossaryDlg* pDlg = m_pParent; + OUString sNew = GetAppCharClass().uppercase(m_xNewShort->get_text()); + if (pDlg->m_pGlossaryHdl->HasShortName(m_xNewShort->get_text()) + && sNew != m_xOldShort->get_text()) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_DOUBLE_SHORTNAME))); + xBox->run(); + m_xNewShort->grab_focus(); + } + else + m_xDialog->response(RET_OK); +} + +IMPL_LINK(SwGlossaryDlg, CheckBoxHdl, weld::Toggleable&, rBox, void) +{ + SvxAutoCorrCfg& rCfg = SvxAutoCorrCfg::Get(); + bool bCheck = rBox.get_active(); + if (&rBox == m_xInsertTipCB.get()) + rCfg.SetAutoTextTip(bCheck); + else if (&rBox == m_xFileRelCB.get()) + rCfg.SetSaveRelFile(bCheck); + else + rCfg.SetSaveRelNet(bCheck); + rCfg.Commit(); +} + +IMPL_LINK(SwGlossaryDlg, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + if (rKEvt.GetKeyCode().GetCode() == KEY_DELETE) + { + DeleteEntry(); + return true; + } + return false; +} + +OUString SwGlossaryDlg::GetCurrGrpName() const +{ + std::unique_ptr<weld::TreeIter> xEntry = m_xCategoryBox->make_iterator(); + if (m_xCategoryBox->get_selected(xEntry.get())) + { + if (m_xCategoryBox->get_iter_depth(*xEntry)) + m_xCategoryBox->iter_parent(*xEntry); + GroupUserData* pGroupData = weld::fromId<GroupUserData*>(m_xCategoryBox->get_id(*xEntry)); + return pGroupData->sGroupName + OUStringChar(GLOS_DELIM) + OUString::number(pGroupData->nPathIdx); + } + return OUString(); +} + +IMPL_LINK_NOARG( SwGlossaryDlg, PathHdl, weld::Button&, void ) +{ + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractSvxMultiPathDialog> pDlg(pFact->CreateSvxPathSelectDialog(m_xDialog.get())); + SvtPathOptions aPathOpt; + const OUString sGlosPath( aPathOpt.GetAutoTextPath() ); + pDlg->SetPath(sGlosPath); + if(RET_OK == pDlg->Execute()) + { + const OUString sTmp(pDlg->GetPath()); + if(sTmp != sGlosPath) + { + aPathOpt.SetAutoTextPath( sTmp ); + ::GetGlossaries()->UpdateGlosPath( true ); + Init(); + } + } +} + +IMPL_LINK_NOARG(SwGlossaryDlg, InsertHdl, weld::Button&, void) +{ + m_xDialog->response(RET_OK); +} + +void SwGlossaryDlg::ShowPreview() +{ + ShowAutoText(::GetCurrGlosGroup(), m_xShortNameEdit->get_text()); +}; + +IMPL_LINK_NOARG(SwGlossaryDlg, PreviewLoadedHdl, SwOneExampleFrame&, void) +{ + ResumeShowAutoText(); +} + +void SwGlossaryDlg::ShowAutoText(const OUString& rGroup, const OUString& rShortName) +{ + if (m_xExampleFrameWin->get_visible()) + { + SetResumeData(rGroup, rShortName); + //try to make an Undo() + m_xExampleFrame->ClearDocument(); + } +} + +void SwGlossaryDlg::ResumeShowAutoText() +{ + OUString sGroup; + OUString sShortName; + if(GetResumeData(sGroup, sShortName) && m_xExampleFrameWin->get_visible()) + { + if(!m_xAutoText.is()) + { + //now the AutoText ListBoxes have to be filled + m_xAutoText = text::AutoTextContainer::create( comphelper::getProcessComponentContext() ); + } + + uno::Reference< XTextCursor > & xCursor = m_xExampleFrame->GetTextCursor(); + if(xCursor.is()) + { + if (!sShortName.isEmpty()) + { + uno::Any aGroup = m_xAutoText->getByName(sGroup); + uno::Reference< XAutoTextGroup > xGroup; + if((aGroup >>= xGroup) && xGroup->hasByName(sShortName)) + { + uno::Any aEntry(xGroup->getByName(sShortName)); + uno::Reference< XAutoTextEntry > xEntry; + aEntry >>= xEntry; + xEntry->applyTo(xCursor); + } + } + } + } + m_bResume = false; +} + +void SwGlossaryDlg::DeleteEntry() +{ + bool bEntry = m_xCategoryBox->get_selected(nullptr); + + const OUString aTitle(m_xNameED->get_text()); + const OUString aShortName(m_xShortNameEdit->get_text()); + + std::unique_ptr<weld::TreeIter> xParent; + std::unique_ptr<weld::TreeIter> xChild = DoesBlockExist(aTitle, aShortName); + if (xChild && m_xCategoryBox->get_iter_depth(*xChild)) + { + xParent = m_xCategoryBox->make_iterator(xChild.get()); + m_xCategoryBox->iter_parent(*xParent); + } + + const bool bExists = nullptr != xChild; + const bool bIsGroup = bEntry && !xParent; + + std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Question, VclButtonsType::YesNo, + SwResId(STR_QUERY_DELETE))); + if (bExists && !bIsGroup && RET_YES == xQuery->run()) + { + if (!aTitle.isEmpty() && m_pGlossaryHdl->DelGlossary(aShortName)) + { + OSL_ENSURE(xChild, "entry not found!"); + m_xCategoryBox->select(*xParent); + m_xCategoryBox->remove(*xChild); + m_xNameED->set_text(OUString()); + NameModify(*m_xNameED); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/impfnote.hxx b/sw/source/ui/misc/impfnote.hxx new file mode 100644 index 000000000..9119ff148 --- /dev/null +++ b/sw/source/ui/misc/impfnote.hxx @@ -0,0 +1,83 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_SW_SOURCE_UI_MISC_IMPFNOTE_HXX +#define INCLUDED_SW_SOURCE_UI_MISC_IMPFNOTE_HXX + +#include <sfx2/tabdlg.hxx> +#include <vcl/weld.hxx> +#include <numberingtypelistbox.hxx> + +enum SwFootnoteNum : unsigned; +class SwWrtShell; + +class SwEndNoteOptionPage : public SfxTabPage +{ + OUString aNumDoc; + OUString aNumPage; + OUString aNumChapter; + SwWrtShell *pSh; + bool bPosDoc; + bool bEndNote; + + std::unique_ptr<SwNumberingTypeListBox> m_xNumViewBox; + std::unique_ptr<weld::Label> m_xOffsetLbl; + std::unique_ptr<weld::SpinButton> m_xOffsetField; + std::unique_ptr<weld::ComboBox> m_xNumCountBox; + std::unique_ptr<weld::Entry> m_xPrefixED; + std::unique_ptr<weld::Entry> m_xSuffixED; + std::unique_ptr<weld::Label> m_xPosFT; + std::unique_ptr<weld::RadioButton> m_xPosPageBox; + std::unique_ptr<weld::RadioButton> m_xPosChapterBox; + std::unique_ptr<weld::Widget> m_xStylesContainer; + std::unique_ptr<weld::ComboBox> m_xParaTemplBox; + std::unique_ptr<weld::Label> m_xPageTemplLbl; + std::unique_ptr<weld::ComboBox> m_xPageTemplBox; + std::unique_ptr<weld::ComboBox> m_xFootnoteCharAnchorTemplBox; + std::unique_ptr<weld::ComboBox> m_xFootnoteCharTextTemplBox; + std::unique_ptr<weld::Entry> m_xContEdit; + std::unique_ptr<weld::Entry> m_xContFromEdit; + + inline void SelectNumbering(SwFootnoteNum eNum); + SwFootnoteNum GetNumbering() const; + + DECL_LINK(ToggleHdl, weld::Toggleable&, void); + DECL_LINK(NumCountHdl, weld::ComboBox&, void); + +public: + SwEndNoteOptionPage(weld::Container* pPage, weld::DialogController* pController, bool bEndNote, const SfxItemSet &rSet); + virtual ~SwEndNoteOptionPage() override; + + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet); + virtual bool FillItemSet(SfxItemSet *rSet) override; + virtual void Reset( const SfxItemSet* ) override; + + void SetShell( SwWrtShell &rShell ); +}; + +class SwFootNoteOptionPage : public SwEndNoteOptionPage +{ +public: + SwFootNoteOptionPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet ); + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet); + virtual ~SwFootNoteOptionPage() override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/insfnote.cxx b/sw/source/ui/misc/insfnote.cxx new file mode 100644 index 000000000..5cdad12d3 --- /dev/null +++ b/sw/source/ui/misc/insfnote.cxx @@ -0,0 +1,249 @@ +/* -*- 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 <hintids.hxx> +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <editeng/fontitem.hxx> +#include <fmtftn.hxx> +#include <swundo.hxx> +#include <cmdid.h> +#include <wrtsh.hxx> +#include <insfnote.hxx> +#include <svx/svxdlg.hxx> + +#include <memory> + +static bool bFootnote = true; + +// inserting a footnote with OK +void SwInsFootNoteDlg::Apply() +{ + OUString aStr; + if ( m_xNumberCharBtn->get_active() ) + aStr = m_xNumberCharEdit->get_text(); + + if (m_bEdit) + { + m_rSh.StartAction(); + m_rSh.Left(CRSR_SKIP_CHARS, false, 1, false ); + m_rSh.StartUndo( SwUndoId::START ); + SwFormatFootnote aNote( m_xEndNoteBtn->get_active() ); + aNote.SetNumStr( aStr ); + + if (m_rSh.SetCurFootnote( aNote ) && m_bExtCharAvailable) + { + m_rSh.Right(CRSR_SKIP_CHARS, true, 1, false ); + SfxItemSetFixed<RES_CHRATR_FONT, RES_CHRATR_FONT> aSet(m_rSh.GetAttrPool()); + m_rSh.GetCurAttr(aSet); + const SvxFontItem &rFont = aSet.Get( RES_CHRATR_FONT ); + SvxFontItem aFont( rFont.GetFamily(), m_aFontName, + rFont.GetStyleName(), rFont.GetPitch(), + m_eCharSet, RES_CHRATR_FONT ); + aSet.Put( aFont ); + m_rSh.SetAttrSet( aSet, SetAttrMode::DONTEXPAND ); + m_rSh.ResetSelect(nullptr, false); + m_rSh.Left(CRSR_SKIP_CHARS, false, 1, false ); + } + m_rSh.EndUndo( SwUndoId::END ); + m_rSh.EndAction(); + } + + bFootnote = m_xFootnoteBtn->get_active(); +} + +IMPL_LINK_NOARG(SwInsFootNoteDlg, NumberEditHdl, weld::Entry&, void) +{ + m_xNumberCharBtn->set_active(true); + m_xOkBtn->set_sensitive( !m_xNumberCharEdit->get_text().isEmpty() ); +} + +IMPL_LINK(SwInsFootNoteDlg, NumberToggleHdl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + + if (m_xNumberAutoBtn->get_active()) + m_xOkBtn->set_sensitive(true); + else if (m_xNumberCharBtn->get_active()) + { + m_xNumberCharEdit->grab_focus(); + m_xOkBtn->set_sensitive( !m_xNumberCharEdit->get_text().isEmpty() || m_bExtCharAvailable ); + } +} + +IMPL_LINK_NOARG(SwInsFootNoteDlg, NumberExtCharHdl, weld::Button&, void) +{ + m_xNumberCharBtn->set_active(true); + + SfxItemSetFixed<RES_CHRATR_FONT, RES_CHRATR_FONT> aSet(m_rSh.GetAttrPool()); + m_rSh.GetCurAttr( aSet ); + const SvxFontItem &rFont = aSet.Get( RES_CHRATR_FONT ); + + SfxAllItemSet aAllSet(m_rSh.GetAttrPool()); + aAllSet.Put( SfxBoolItem( FN_PARAM_1, false ) ); + aAllSet.Put( rFont ); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<SfxAbstractDialog> pDlg(pFact->CreateCharMapDialog(m_xDialog.get(), aAllSet, nullptr)); + if (RET_OK != pDlg->Execute()) + return; + + const SfxStringItem* pItem = SfxItemSet::GetItem<SfxStringItem>(pDlg->GetOutputItemSet(), SID_CHARMAP, false); + const SvxFontItem* pFontItem = SfxItemSet::GetItem<SvxFontItem>(pDlg->GetOutputItemSet(), SID_ATTR_CHAR_FONT, false); + if ( !pItem ) + return; + + m_xNumberCharEdit->set_text(pItem->GetValue()); + + if ( pFontItem ) + { + m_aFontName = pFontItem->GetFamilyName(); + m_eCharSet = pFontItem->GetCharSet(); + vcl::Font aFont(m_aFontName, pFontItem->GetStyleName(), m_xNumberCharEdit->get_font().GetFontSize()); + aFont.SetCharSet( pFontItem->GetCharSet() ); + aFont.SetPitch( pFontItem->GetPitch() ); + m_xNumberCharEdit->set_font(aFont); + } + + m_bExtCharAvailable = true; + m_xOkBtn->set_sensitive(!m_xNumberCharEdit->get_text().isEmpty()); +} + +IMPL_LINK( SwInsFootNoteDlg, NextPrevHdl, weld::Button&, rBtn, void ) +{ + Apply(); + + // go to the next foot/endnote here + m_rSh.ResetSelect(nullptr, false); + if (&rBtn == m_xNextBT.get()) + m_rSh.GotoNextFootnoteAnchor(); + else + m_rSh.GotoPrevFootnoteAnchor(); + + Init(); +} + +SwInsFootNoteDlg::SwInsFootNoteDlg(weld::Window *pParent, SwWrtShell &rShell, bool bEd) + : GenericDialogController(pParent, "modules/swriter/ui/insertfootnote.ui", "InsertFootnoteDialog") + , m_rSh(rShell) + , m_eCharSet(RTL_TEXTENCODING_DONTKNOW) + , m_bExtCharAvailable(false) + , m_bEdit(bEd) + , m_xNumberFrame(m_xBuilder->weld_widget("numberingframe")) + , m_xNumberAutoBtn(m_xBuilder->weld_radio_button("automatic")) + , m_xNumberCharBtn(m_xBuilder->weld_radio_button("character")) + , m_xNumberCharEdit(m_xBuilder->weld_entry("characterentry")) + , m_xNumberExtChar(m_xBuilder->weld_button("choosecharacter")) + , m_xFootnoteBtn(m_xBuilder->weld_radio_button("footnote")) + , m_xEndNoteBtn(m_xBuilder->weld_radio_button("endnote")) + , m_xOkBtn(m_xBuilder->weld_button("ok")) + , m_xPrevBT(m_xBuilder->weld_button("prev")) + , m_xNextBT(m_xBuilder->weld_button("next")) +{ + m_xNumberAutoBtn->connect_toggled(LINK(this,SwInsFootNoteDlg,NumberToggleHdl)); + m_xNumberCharBtn->connect_toggled(LINK(this,SwInsFootNoteDlg,NumberToggleHdl)); + m_xNumberExtChar->connect_clicked(LINK(this,SwInsFootNoteDlg,NumberExtCharHdl)); + m_xNumberCharEdit->connect_changed(LINK(this,SwInsFootNoteDlg,NumberEditHdl)); + + m_xPrevBT->connect_clicked(LINK(this, SwInsFootNoteDlg, NextPrevHdl)); + m_xNextBT->connect_clicked(LINK(this, SwInsFootNoteDlg, NextPrevHdl)); + + SwViewShell::SetCareDialog(m_xDialog); + + if (m_bEdit) + { + Init(); + + m_xPrevBT->show(); + m_xNextBT->show(); + } +} + +SwInsFootNoteDlg::~SwInsFootNoteDlg() COVERITY_NOEXCEPT_FALSE +{ + SwViewShell::SetCareDialog(nullptr); + + if (m_bEdit) + m_rSh.ResetSelect(nullptr, false); +} + +void SwInsFootNoteDlg::Init() +{ + SwFormatFootnote aFootnoteNote; + OUString sNumStr; + vcl::Font aFont; + m_bExtCharAvailable = false; + + m_rSh.StartAction(); + + if (m_rSh.GetCurFootnote(&aFootnoteNote)) + { + if (!aFootnoteNote.GetNumStr().isEmpty()) + { + sNumStr = aFootnoteNote.GetNumStr(); + + m_rSh.Right(CRSR_SKIP_CHARS, true, 1, false ); + SfxItemSetFixed<RES_CHRATR_FONT, RES_CHRATR_FONT> aSet(m_rSh.GetAttrPool()); + m_rSh.GetCurAttr(aSet); + const SvxFontItem &rFont = aSet.Get( RES_CHRATR_FONT ); + aFont = m_xNumberCharEdit->get_font(); + m_aFontName = rFont.GetFamilyName(); + m_eCharSet = rFont.GetCharSet(); + aFont.SetFamilyName(m_aFontName); + aFont.SetCharSet(m_eCharSet); + m_bExtCharAvailable = true; + m_rSh.Left( CRSR_SKIP_CHARS, false, 1, false ); + } + bFootnote = !aFootnoteNote.IsEndNote(); + } + m_xNumberCharEdit->set_font(aFont); + + const bool bNumChar = !sNumStr.isEmpty(); + + m_xNumberCharEdit->set_text(sNumStr); + m_xNumberCharBtn->set_active(bNumChar); + m_xNumberAutoBtn->set_active(!bNumChar); + if (bNumChar) + m_xNumberCharEdit->grab_focus(); + + if (bFootnote) + m_xFootnoteBtn->set_active(true); + else + m_xEndNoteBtn->set_active(true); + + bool bNext = m_rSh.GotoNextFootnoteAnchor(); + + if (bNext) + m_rSh.GotoPrevFootnoteAnchor(); + + bool bPrev = m_rSh.GotoPrevFootnoteAnchor(); + + if (bPrev) + m_rSh.GotoNextFootnoteAnchor(); + + m_xPrevBT->set_sensitive(bPrev); + m_xNextBT->set_sensitive(bNext); + + m_rSh.Right(CRSR_SKIP_CHARS, true, 1, false ); + + m_rSh.EndAction(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/linenum.cxx b/sw/source/ui/misc/linenum.cxx new file mode 100644 index 000000000..72adb140b --- /dev/null +++ b/sw/source/ui/misc/linenum.cxx @@ -0,0 +1,260 @@ +/* -*- 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 <sfx2/viewfrm.hxx> +#include <svl/style.hxx> +#include <svtools/unitconv.hxx> +#include <sal/log.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <docsh.hxx> +#include <charfmt.hxx> + +#include <docstyle.hxx> + +#include <lineinfo.hxx> +#include <linenum.hxx> +#include <swmodule.hxx> +#include <uitool.hxx> +#include <usrpref.hxx> +#include <wdocsh.hxx> +#include <fmtline.hxx> +#include <strings.hrc> + +#include <IDocumentStylePoolAccess.hxx> + +static rtl::Reference<SwDocStyleSheet> lcl_getDocStyleSheet(const OUString& rName, SwWrtShell *pSh) +{ + SfxStyleSheetBasePool* pBase = pSh->GetView().GetDocShell()->GetStyleSheetPool(); + SfxStyleSheetBase* pStyle = pBase->Find(rName, SfxStyleFamily::Para); + SAL_WARN_IF( !pStyle, "sw.ui", "Style not found" ); + if(!pStyle) + return nullptr; + return new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pStyle)); +} + +static void lcl_setLineNumbering(const OUString& rName, SwWrtShell* pSh, bool bLineNumber) +{ + rtl::Reference<SwDocStyleSheet> xStyleSheet = lcl_getDocStyleSheet(rName, pSh); + if(!xStyleSheet.is()) + return; + SfxItemSet& rSet = xStyleSheet->GetItemSet(); + SwFormatLineNumber aFormat; + aFormat.SetCountLines(bLineNumber); + rSet.Put(aFormat); + xStyleSheet->MergeIndentAttrsOfListStyle( rSet ); + xStyleSheet->SetItemSet(rSet); +} + +SwLineNumberingDlg::SwLineNumberingDlg(const SwView& rVw) + : SfxDialogController(rVw.GetViewFrame()->GetFrameWeld(), + "modules/swriter/ui/linenumbering.ui", "LineNumberingDialog") + , m_pSh(rVw.GetWrtShellPtr()) + , m_xBodyContent(m_xBuilder->weld_widget("content")) + , m_xDivIntervalFT(m_xBuilder->weld_widget("every")) + , m_xDivIntervalNF(m_xBuilder->weld_spin_button("linesspin")) + , m_xDivRowsFT(m_xBuilder->weld_widget("lines")) + , m_xNumIntervalNF(m_xBuilder->weld_spin_button("intervalspin")) + , m_xCharStyleLB(m_xBuilder->weld_combo_box("styledropdown")) + , m_xFormatLB(new SwNumberingTypeListBox(m_xBuilder->weld_combo_box("formatdropdown"))) + , m_xPosLB(m_xBuilder->weld_combo_box("positiondropdown")) + , m_xOffsetMF(m_xBuilder->weld_metric_spin_button("spacingspin", FieldUnit::CM)) + , m_xDivisorED(m_xBuilder->weld_entry("textentry")) + , m_xCountEmptyLinesCB(m_xBuilder->weld_check_button("blanklines")) + , m_xCountFrameLinesCB(m_xBuilder->weld_check_button("linesintextframes")) + , m_xRestartEachPageCB(m_xBuilder->weld_check_button("restarteverynewpage")) + , m_xNumberingOnCB(m_xBuilder->weld_check_button("shownumbering")) + , m_xNumberingOnFooterHeader(m_xBuilder->weld_check_button("showfooterheadernumbering")) + , m_xOKButton(m_xBuilder->weld_button("ok")) + , m_xNumIntervalFT(m_xBuilder->weld_widget("interval")) + , m_xNumRowsFT(m_xBuilder->weld_widget("intervallines")) +{ + m_xFormatLB->Reload(SwInsertNumTypes::Extended); + + OUString sIntervalName = m_xDivIntervalFT->get_accessible_name() + + "(" + + m_xDivRowsFT->get_accessible_name() + + ")"; + m_xDivIntervalNF->set_accessible_name(sIntervalName); + + sIntervalName = m_xNumIntervalFT->get_accessible_name() + + "(" + + m_xNumRowsFT->get_accessible_name() + + ")"; + m_xNumIntervalNF->set_accessible_name(sIntervalName); + + // char styles + ::FillCharStyleListBox(*m_xCharStyleLB, m_pSh->GetView().GetDocShell()); + + const SwLineNumberInfo &rInf = m_pSh->GetLineNumberInfo(); + IDocumentStylePoolAccess& rIDSPA = m_pSh->getIDocumentStylePoolAccess(); + + OUString sStyleName(rInf.GetCharFormat( rIDSPA )->GetName()); + const int nPos = m_xCharStyleLB->find_text(sStyleName); + + if (nPos != -1) + m_xCharStyleLB->set_active(nPos); + else + { + if (!sStyleName.isEmpty()) + { + m_xCharStyleLB->append_text(sStyleName); + m_xCharStyleLB->set_active_text(sStyleName); + } + } + + // format + SvxNumType nSelFormat = rInf.GetNumType().GetNumberingType(); + + m_xFormatLB->SelectNumberingType(nSelFormat); + + // position + m_xPosLB->set_active(rInf.GetPos()); + + // offset + sal_uInt16 nOffset = rInf.GetPosFromLeft(); + if (nOffset == USHRT_MAX) + nOffset = 0; + + FieldUnit eFieldUnit = SW_MOD()->GetUsrPref(dynamic_cast< const SwWebDocShell*>( + rVw.GetDocShell()) != nullptr)->GetMetric(); + ::SetFieldUnit(*m_xOffsetMF, eFieldUnit); + m_xOffsetMF->set_value(m_xOffsetMF->normalize(nOffset), FieldUnit::TWIP); + + // numbering offset + m_xNumIntervalNF->set_value(rInf.GetCountBy()); + + // divider + m_xDivisorED->set_text(rInf.GetDivider()); + + // divider offset + m_xDivIntervalNF->set_value(rInf.GetDividerCountBy()); + + // count + m_xCountEmptyLinesCB->set_active(rInf.IsCountBlankLines()); + m_xCountFrameLinesCB->set_active(rInf.IsCountInFlys()); + m_xRestartEachPageCB->set_active(rInf.IsRestartEachPage()); + + m_xNumberingOnCB->set_active(rInf.IsPaintLineNumbers()); + + // Header/Footer Line Numbering + rtl::Reference< SwDocStyleSheet > xStyleSheet = lcl_getDocStyleSheet(SwResId(STR_POOLCOLL_FOOTER), m_pSh); + if(xStyleSheet.is()) + { + SfxItemSet& rSet = xStyleSheet->GetItemSet(); + const SwFormatLineNumber &aFormat = rSet.Get(RES_LINENUMBER); + if (aFormat.IsCount()) + m_xNumberingOnFooterHeader->set_state(TRISTATE_TRUE); + else + m_xNumberingOnFooterHeader->set_state(TRISTATE_FALSE); + } + + // Line Numbering + m_xNumberingOnCB->connect_toggled(LINK(this, SwLineNumberingDlg, LineOnOffHdl)); + m_xDivisorED->connect_changed(LINK(this, SwLineNumberingDlg, ModifyHdl)); + ModifyHdl(*m_xDivisorED); + LineOnOffHdl(*m_xNumberingOnCB); + + m_xOKButton->connect_clicked(LINK(this, SwLineNumberingDlg, OKHdl)); +} + +SwLineNumberingDlg::~SwLineNumberingDlg() +{ +} + +IMPL_LINK_NOARG(SwLineNumberingDlg, OKHdl, weld::Button&, void) +{ + SwLineNumberInfo aInf(m_pSh->GetLineNumberInfo()); + + // char styles + OUString sCharFormatName(m_xCharStyleLB->get_active_text()); + SwCharFormat *pCharFormat = m_pSh->FindCharFormatByName(sCharFormatName); + + if (!pCharFormat) + { + SfxStyleSheetBasePool* pPool = m_pSh->GetView().GetDocShell()->GetStyleSheetPool(); + SfxStyleSheetBase* pBase; + pBase = pPool->Find(sCharFormatName, SfxStyleFamily::Char); + if(!pBase) + pBase = &pPool->Make(sCharFormatName, SfxStyleFamily::Char); + pCharFormat = static_cast<SwDocStyleSheet*>(pBase)->GetCharFormat(); + } + + if (pCharFormat) + aInf.SetCharFormat(pCharFormat); + + // format + SvxNumberType aType; + aType.SetNumberingType(m_xFormatLB->GetSelectedNumberingType()); + aInf.SetNumType(aType); + + // position + aInf.SetPos(static_cast<LineNumberPosition>(m_xPosLB->get_active())); + + // offset + aInf.SetPosFromLeft(o3tl::narrowing<sal_uInt16>(m_xOffsetMF->denormalize(m_xOffsetMF->get_value(FieldUnit::TWIP)))); + + // numbering offset + aInf.SetCountBy(o3tl::narrowing<sal_uInt16>(m_xNumIntervalNF->get_value())); + + // divider + aInf.SetDivider(m_xDivisorED->get_text()); + + // divider offset + aInf.SetDividerCountBy(o3tl::narrowing<sal_uInt16>(m_xDivIntervalNF->get_value())); + + // count + aInf.SetCountBlankLines(m_xCountEmptyLinesCB->get_active()); + aInf.SetCountInFlys(m_xCountFrameLinesCB->get_active()); + aInf.SetRestartEachPage(m_xRestartEachPageCB->get_active()); + + aInf.SetPaintLineNumbers(m_xNumberingOnCB->get_active()); + + m_pSh->SetLineNumberInfo(aInf); + + // Set LineNumber explicitly for Header and Footer + lcl_setLineNumbering(SwResId(STR_POOLCOLL_FOOTER), m_pSh, m_xNumberingOnFooterHeader->get_active()); + lcl_setLineNumbering(SwResId(STR_POOLCOLL_HEADER), m_pSh, m_xNumberingOnFooterHeader->get_active()); + if( m_xNumberingOnFooterHeader->get_active()) + m_xNumberingOnFooterHeader->set_state(TRISTATE_TRUE); + else + m_xNumberingOnFooterHeader->set_state(TRISTATE_FALSE); + + m_xDialog->response(RET_OK); +} + +// modify +IMPL_LINK_NOARG(SwLineNumberingDlg, ModifyHdl, weld::Entry&, void) +{ + bool bEnable = m_xNumberingOnCB->get_active() && !m_xDivisorED->get_text().isEmpty(); + + m_xDivIntervalFT->set_sensitive(bEnable); + m_xDivIntervalNF->set_sensitive(bEnable); + m_xDivRowsFT->set_sensitive(bEnable); +} + +// On/Off +IMPL_LINK_NOARG(SwLineNumberingDlg, LineOnOffHdl, weld::Toggleable&, void) +{ + bool bEnable = m_xNumberingOnCB->get_active(); + m_xBodyContent->set_sensitive(bEnable); + ModifyHdl(*m_xDivisorED); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/num.cxx b/sw/source/ui/misc/num.cxx new file mode 100644 index 000000000..b41e15b15 --- /dev/null +++ b/sw/source/ui/misc/num.cxx @@ -0,0 +1,957 @@ +/* -*- 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 <editeng/numitem.hxx> +#include <cmdid.h> +#include <wrtsh.hxx> +#include <docsh.hxx> +#include <wview.hxx> +#include <uitool.hxx> +#include <wdocsh.hxx> +#include <uiitems.hxx> +#include <poolfmt.hxx> +#include <shellres.hxx> +#include <outline.hxx> +#include <num.hxx> + +#include <SwStyleNameMapper.hxx> +#include <svx/dialogs.hrc> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <svl/slstitm.hxx> +#include <svl/intitem.hxx> +#include <comphelper/lok.hxx> +#include <osl/diagnose.h> + +static bool bLastRelative = false; + +//See cui/uiconfig/ui/numberingpositionpage.ui for effectively a duplicate +//dialog to this one, except with a different preview window impl. +//TODO, determine if SwNumPositionTabPage and SvxNumPositionTabPage can be +//merged +SwNumPositionTabPage::SwNumPositionTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/outlinepositionpage.ui", "OutlinePositionPage", &rSet) + , pSaveNum(nullptr) + , pWrtSh(nullptr) + , pOutlineDlg(nullptr) + , nActNumLvl(0) + , bModified(false) + , bPreset(false) + , bInInintControl(false) + , bLabelAlignmentPosAndSpaceModeActive(false) + , m_xLevelLB(m_xBuilder->weld_tree_view("levellb")) + , m_xPositionFrame(m_xBuilder->weld_widget("numberingframe")) + , m_xDistBorderFT(m_xBuilder->weld_label("indent")) + , m_xDistBorderMF(m_xBuilder->weld_metric_spin_button("indentmf", FieldUnit::CM)) + , m_xRelativeCB(m_xBuilder->weld_check_button("relative")) + , m_xIndentFT(m_xBuilder->weld_label("numberingwidth")) + , m_xIndentMF(m_xBuilder->weld_metric_spin_button("numberingwidthmf", FieldUnit::CM)) + , m_xDistNumFT(m_xBuilder->weld_label("numdist")) + , m_xDistNumMF(m_xBuilder->weld_metric_spin_button("numdistmf", FieldUnit::CM)) + , m_xAlignFT(m_xBuilder->weld_label("numalign")) + , m_xAlignLB(m_xBuilder->weld_combo_box("numalignlb")) + , m_xLabelFollowedByFT(m_xBuilder->weld_label("numfollowedby")) + , m_xLabelFollowedByLB(m_xBuilder->weld_combo_box("numfollowedbylb")) + , m_xListtabFT(m_xBuilder->weld_label("at")) + , m_xListtabMF(m_xBuilder->weld_metric_spin_button("atmf", FieldUnit::CM)) + , m_xAlign2FT(m_xBuilder->weld_label("num2align")) + , m_xAlign2LB(m_xBuilder->weld_combo_box("num2alignlb")) + , m_xAlignedAtFT(m_xBuilder->weld_label("alignedat")) + , m_xAlignedAtMF(m_xBuilder->weld_metric_spin_button("alignedatmf", FieldUnit::CM)) + , m_xIndentAtFT(m_xBuilder->weld_label("indentat")) + , m_xIndentAtMF(m_xBuilder->weld_metric_spin_button("indentatmf", FieldUnit::CM)) + , m_xStandardPB(m_xBuilder->weld_button("standard")) + , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "preview", m_aPreviewWIN)) +{ + SetExchangeSupport(); + + m_xLevelLB->set_selection_mode(SelectionMode::Multiple); + + m_xRelativeCB->set_active(true); + m_xAlignLB->connect_changed(LINK(this, SwNumPositionTabPage, EditModifyHdl)); + m_xAlign2LB->connect_changed(LINK(this, SwNumPositionTabPage, EditModifyHdl)); + for (int i = 0; i < m_xAlignLB->get_count(); ++i) + { + m_xAlign2LB->append_text(m_xAlignLB->get_text(i)); + } + m_xAlign2FT->set_label(m_xAlignFT->get_label()); + + Link<weld::MetricSpinButton&, void> aLk = LINK(this, SwNumPositionTabPage, DistanceHdl); + m_xDistBorderMF->connect_value_changed(aLk); + m_xDistNumMF->connect_value_changed(aLk); + m_xIndentMF->connect_value_changed(aLk); + + m_xLabelFollowedByLB->connect_changed( LINK(this, SwNumPositionTabPage, LabelFollowedByHdl_Impl) ); + + aLk = LINK(this, SwNumPositionTabPage, ListtabPosHdl_Impl); + m_xListtabMF->connect_value_changed(aLk); + + aLk = LINK(this, SwNumPositionTabPage, AlignAtHdl_Impl); + m_xAlignedAtMF->connect_value_changed(aLk); + + aLk = LINK(this, SwNumPositionTabPage, IndentAtHdl_Impl); + m_xIndentAtMF->connect_value_changed(aLk); + + m_xLevelLB->connect_changed(LINK(this, SwNumPositionTabPage, LevelHdl)); + m_xRelativeCB->connect_toggled(LINK(this, SwNumPositionTabPage, RelativeHdl)); + m_xStandardPB->connect_clicked(LINK(this, SwNumPositionTabPage, StandardHdl)); + + // insert levels + for(sal_uInt16 i = 1; i <= MAXLEVEL; i++) + m_xLevelLB->append_text(OUString::number(i)); + OUString sEntry = "1 - " + OUString::number(MAXLEVEL); + m_xLevelLB->append_text(sEntry); + m_xLevelLB->select_text(sEntry); + + m_xRelativeCB->set_active(bLastRelative); + m_aPreviewWIN.SetPositionMode(); +} + +SwNumPositionTabPage::~SwNumPositionTabPage() +{ + pActNum.reset(); + pOutlineDlg = nullptr; +} + +void SwNumPositionTabPage::InitControls() +{ + bInInintControl = true; + const bool bRelative = !bLabelAlignmentPosAndSpaceModeActive && + m_xRelativeCB->get_sensitive() && m_xRelativeCB->get_active(); + const bool bSingleSelection = m_xLevelLB->count_selected_rows() == 1 && + USHRT_MAX != nActNumLvl; + + m_xDistBorderMF->set_sensitive( !bLabelAlignmentPosAndSpaceModeActive && + ( bSingleSelection || bRelative || pOutlineDlg != nullptr ) ); + m_xDistBorderFT->set_sensitive( !bLabelAlignmentPosAndSpaceModeActive && + ( bSingleSelection || bRelative || pOutlineDlg != nullptr ) ); + + bool bSetDistEmpty = false; + bool bSameDistBorderNum = !bLabelAlignmentPosAndSpaceModeActive; + bool bSameDist = !bLabelAlignmentPosAndSpaceModeActive; + bool bSameIndent = !bLabelAlignmentPosAndSpaceModeActive; + bool bSameAdjust = true; + + bool bSameLabelFollowedBy = bLabelAlignmentPosAndSpaceModeActive; + bool bSameListtab = bLabelAlignmentPosAndSpaceModeActive; + bool bSameAlignAt = bLabelAlignmentPosAndSpaceModeActive; + bool bSameIndentAt = bLabelAlignmentPosAndSpaceModeActive; + + const SwNumFormat* aNumFormatArr[MAXLEVEL]; + sal_uInt16 nMask = 1; + sal_uInt16 nLvl = USHRT_MAX; + tools::Long nFirstBorderTextRelative = -1; + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + aNumFormatArr[i] = &pActNum->Get(i); + if(nActNumLvl & nMask) + { + if(USHRT_MAX == nLvl) + { + nLvl = i; + } + + if( i > nLvl) + { + bSameAdjust &= aNumFormatArr[i]->GetNumAdjust() == aNumFormatArr[nLvl]->GetNumAdjust(); + if ( !bLabelAlignmentPosAndSpaceModeActive ) + { + if(bRelative) + { + const tools::Long nBorderTextRelative = + aNumFormatArr[i]->GetAbsLSpace() + aNumFormatArr[i]->GetFirstLineOffset() - + aNumFormatArr[i - 1]->GetAbsLSpace() + aNumFormatArr[i - 1]->GetFirstLineOffset(); + if (nFirstBorderTextRelative == -1) + nFirstBorderTextRelative = nBorderTextRelative; + else + bSameDistBorderNum &= nFirstBorderTextRelative == nBorderTextRelative; + } + else + { + bSameDistBorderNum &= + aNumFormatArr[i]->GetAbsLSpace() - aNumFormatArr[i]->GetFirstLineOffset() == + aNumFormatArr[i - 1]->GetAbsLSpace() - aNumFormatArr[i - 1]->GetFirstLineOffset(); + } + + bSameDist &= aNumFormatArr[i]->GetCharTextDistance() == aNumFormatArr[nLvl]->GetCharTextDistance(); + bSameIndent &= aNumFormatArr[i]->GetFirstLineOffset() == aNumFormatArr[nLvl]->GetFirstLineOffset(); + } + else + { + bSameLabelFollowedBy &= + aNumFormatArr[i]->GetLabelFollowedBy() == aNumFormatArr[nLvl]->GetLabelFollowedBy(); + bSameListtab &= + aNumFormatArr[i]->GetListtabPos() == aNumFormatArr[nLvl]->GetListtabPos(); + bSameAlignAt &= + ( ( aNumFormatArr[i]->GetIndentAt() + aNumFormatArr[i]->GetFirstLineIndent() ) + == ( aNumFormatArr[nLvl]->GetIndentAt() + aNumFormatArr[nLvl]->GetFirstLineIndent() ) ); + bSameIndentAt &= + aNumFormatArr[i]->GetIndentAt() == aNumFormatArr[nLvl]->GetIndentAt(); + } + } + } + nMask <<= 1; + + } + if (MAXLEVEL <= nLvl) + { + OSL_ENSURE(false, "cannot happen."); + return; + } + if(bSameDistBorderNum) + { + tools::Long nDistBorderNum; + if(bRelative) + { + nDistBorderNum = static_cast<tools::Long>(aNumFormatArr[nLvl]->GetAbsLSpace())+ aNumFormatArr[nLvl]->GetFirstLineOffset(); + if(nLvl) + nDistBorderNum -= static_cast<tools::Long>(aNumFormatArr[nLvl - 1]->GetAbsLSpace())+ aNumFormatArr[nLvl - 1]->GetFirstLineOffset(); + } + else + { + nDistBorderNum = static_cast<tools::Long>(aNumFormatArr[nLvl]->GetAbsLSpace())+ aNumFormatArr[nLvl]->GetFirstLineOffset(); + } + m_xDistBorderMF->set_value(m_xDistBorderMF->normalize(nDistBorderNum),FieldUnit::TWIP); + } + else + bSetDistEmpty = true; + + if(bSameDist) + m_xDistNumMF->set_value(m_xDistNumMF->normalize(aNumFormatArr[nLvl]->GetCharTextDistance()), FieldUnit::TWIP); + else + m_xDistNumMF->set_text(OUString()); + if(bSameIndent) + m_xIndentMF->set_value(m_xIndentMF->normalize(-aNumFormatArr[nLvl]->GetFirstLineOffset()), FieldUnit::TWIP); + else + m_xIndentMF->set_text(OUString()); + + if(bSameAdjust) + { + sal_Int32 nPos = 1; // centered + if(aNumFormatArr[nLvl]->GetNumAdjust() == SvxAdjust::Left) + nPos = 0; + else if(aNumFormatArr[nLvl]->GetNumAdjust() == SvxAdjust::Right) + nPos = 2; + m_xAlignLB->set_active(nPos); + m_xAlign2LB->set_active( nPos ); + } + else + { + m_xAlignLB->set_active(-1); + m_xAlign2LB->set_active(-1); + } + + if ( bSameLabelFollowedBy ) + { + sal_Int32 nPos = 0; // LISTTAB + if ( aNumFormatArr[nLvl]->GetLabelFollowedBy() == SvxNumberFormat::SPACE ) + { + nPos = 1; + } + else if ( aNumFormatArr[nLvl]->GetLabelFollowedBy() == SvxNumberFormat::NOTHING ) + { + nPos = 2; + } + else if ( aNumFormatArr[nLvl]->GetLabelFollowedBy() == SvxNumberFormat::NEWLINE ) + { + nPos = 3; + } + m_xLabelFollowedByLB->set_active(nPos); + } + else + { + m_xLabelFollowedByLB->set_active(-1); + } + + if ( aNumFormatArr[nLvl]->GetLabelFollowedBy() == SvxNumberFormat::LISTTAB ) + { + m_xListtabFT->set_sensitive(true); + m_xListtabMF->set_sensitive(true); + if ( bSameListtab ) + { + m_xListtabMF->set_value(m_xListtabMF->normalize(aNumFormatArr[nLvl]->GetListtabPos()),FieldUnit::TWIP); + } + else + { + m_xListtabMF->set_text(OUString()); + } + } + else + { + m_xListtabFT->set_sensitive( false ); + m_xListtabMF->set_sensitive( false ); + m_xListtabMF->set_text(OUString()); + } + + if ( bSameAlignAt ) + { + m_xAlignedAtMF->set_value( + m_xAlignedAtMF->normalize( aNumFormatArr[nLvl]->GetIndentAt() + + aNumFormatArr[nLvl]->GetFirstLineIndent()), + FieldUnit::TWIP ); + } + else + { + m_xAlignedAtMF->set_text(OUString()); + } + + if ( bSameIndentAt ) + { + m_xIndentAtMF->set_value( + m_xIndentAtMF->normalize( aNumFormatArr[nLvl]->GetIndentAt()), FieldUnit::TWIP ); + } + else + { + m_xIndentAtMF->set_text(OUString()); + } + + if (bSetDistEmpty) + m_xDistBorderMF->set_text(OUString()); + + bInInintControl = false; +} + +void SwNumPositionTabPage::ActivatePage(const SfxItemSet& ) +{ + const SfxPoolItem* pItem; + sal_uInt16 nTmpNumLvl = + pOutlineDlg ? SwOutlineTabDialog::GetActNumLevel() : 0; + const SfxItemSet* pExampleSet = GetDialogExampleSet(); + if(pExampleSet && pExampleSet->GetItemState(FN_PARAM_NUM_PRESET, false, &pItem) != SfxItemState::UNKNOWN) + { + bPreset = static_cast<const SfxBoolItem*>(pItem)->GetValue(); + } + bModified = (!pActNum->GetNumFormat( 0 ) || bPreset); + if(*pActNum != *pSaveNum || + nActNumLvl != nTmpNumLvl ) + { + *pActNum = *pSaveNum; + nActNumLvl = nTmpNumLvl; + sal_uInt16 nMask = 1; + m_xLevelLB->unselect_all(); + if (nActNumLvl == USHRT_MAX) + m_xLevelLB->select(MAXLEVEL); + else + { + for (sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + if (nActNumLvl & nMask) + m_xLevelLB->select(i); + nMask <<= 1 ; + } + } + + InitPosAndSpaceMode(); + ShowControlsDependingOnPosAndSpaceMode(); + + InitControls(); + } + m_xRelativeCB->set_sensitive(1 != nActNumLvl); + m_aPreviewWIN.Invalidate(); +} + +DeactivateRC SwNumPositionTabPage::DeactivatePage(SfxItemSet *_pSet) +{ + SwOutlineTabDialog::SetActNumLevel(nActNumLvl); + if(_pSet) + FillItemSet(_pSet); + return DeactivateRC::LeavePage; + +} + +bool SwNumPositionTabPage::FillItemSet( SfxItemSet* rSet ) +{ + if(pOutlineDlg) + *pOutlineDlg->GetNumRule() = *pActNum; + else if(bModified && pActNum) + { + *pSaveNum = *pActNum; + rSet->Put(SwUINumRuleItem( *pSaveNum )); + rSet->Put(SfxBoolItem(FN_PARAM_NUM_PRESET, false)); + } + return bModified; +} + +void SwNumPositionTabPage::Reset( const SfxItemSet* rSet ) +{ + if (pOutlineDlg) + { + pSaveNum = pOutlineDlg->GetNumRule(); + m_xLevelLB->set_selection_mode(SelectionMode::Single); + } + else if(const SwUINumRuleItem* pNumberItem = rSet->GetItemIfSet(FN_PARAM_ACT_NUMBER, false)) + pSaveNum = const_cast<SwUINumRuleItem*>(pNumberItem)->GetNumRule(); + + nActNumLvl = SwOutlineTabDialog::GetActNumLevel(); + sal_uInt16 nMask = 1; + m_xLevelLB->unselect_all(); + if(nActNumLvl == USHRT_MAX) + { + m_xLevelLB->select(MAXLEVEL); + } + else + { + for (sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + if (nActNumLvl & nMask) + m_xLevelLB->select(i); + nMask <<= 1; + } + } + + if(!pActNum) + pActNum.reset(new SwNumRule(*pSaveNum)); + else if(*pSaveNum != *pActNum) + *pActNum = *pSaveNum; + m_aPreviewWIN.SetNumRule(pActNum.get()); + InitPosAndSpaceMode(); + ShowControlsDependingOnPosAndSpaceMode(); + InitControls(); + bModified = false; +} + +void SwNumPositionTabPage::InitPosAndSpaceMode() +{ + if ( pActNum == nullptr ) + { + OSL_FAIL( "<SwNumPositionTabPage::InitPosAndSpaceMode()> - misusage of method -> <pAktNum> has to be already set!" ); + return; + } + + SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode = + SvxNumberFormat::LABEL_ALIGNMENT; + sal_uInt16 nMask = 1; + for( sal_uInt16 i = 0; i < MAXLEVEL; ++i ) + { + if(nActNumLvl & nMask) + { + SvxNumberFormat aNumFormat( pActNum->Get(i) ); + ePosAndSpaceMode = aNumFormat.GetPositionAndSpaceMode(); + if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + break; + } + } + nMask <<= 1; + } + + bLabelAlignmentPosAndSpaceModeActive = + ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT; +} + +void SwNumPositionTabPage::ShowControlsDependingOnPosAndSpaceMode() +{ + m_xDistBorderFT->set_visible( !bLabelAlignmentPosAndSpaceModeActive ); + m_xDistBorderMF->set_visible( !bLabelAlignmentPosAndSpaceModeActive ); + m_xRelativeCB->set_visible( !bLabelAlignmentPosAndSpaceModeActive ); + m_xIndentFT->set_visible( !bLabelAlignmentPosAndSpaceModeActive ); + m_xIndentMF->set_visible( !bLabelAlignmentPosAndSpaceModeActive ); + m_xDistNumFT->set_visible( !bLabelAlignmentPosAndSpaceModeActive ); + m_xDistNumMF->set_visible( !bLabelAlignmentPosAndSpaceModeActive ); + m_xAlignFT->set_visible( !bLabelAlignmentPosAndSpaceModeActive ); + m_xAlignLB->set_visible( !bLabelAlignmentPosAndSpaceModeActive ); + + m_xLabelFollowedByFT->set_visible( bLabelAlignmentPosAndSpaceModeActive ); + m_xLabelFollowedByLB->set_visible( bLabelAlignmentPosAndSpaceModeActive ); + m_xListtabFT->set_visible( bLabelAlignmentPosAndSpaceModeActive ); + m_xListtabMF->set_visible( bLabelAlignmentPosAndSpaceModeActive ); + m_xAlign2FT->set_visible( bLabelAlignmentPosAndSpaceModeActive ); + m_xAlign2LB->set_visible( bLabelAlignmentPosAndSpaceModeActive ); + m_xAlignedAtFT->set_visible( bLabelAlignmentPosAndSpaceModeActive ); + m_xAlignedAtMF->set_visible( bLabelAlignmentPosAndSpaceModeActive ); + m_xIndentAtFT->set_visible( bLabelAlignmentPosAndSpaceModeActive ); + m_xIndentAtMF->set_visible( bLabelAlignmentPosAndSpaceModeActive ); +} + +std::unique_ptr<SfxTabPage> SwNumPositionTabPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwNumPositionTabPage>(pPage, pController, *rAttrSet); +} + +void SwNumPositionTabPage::SetWrtShell(SwWrtShell* pSh) +{ + pWrtSh = pSh; + + const SwTwips nWidth = pWrtSh->GetAnyCurRect(CurRectType::Frame).Width(); + + m_xDistBorderMF->set_max(m_xDistBorderMF->normalize( nWidth ), FieldUnit::TWIP ); + m_xDistNumMF->set_max(m_xDistNumMF->normalize( nWidth ), FieldUnit::TWIP); + m_xIndentMF->set_max(m_xIndentMF->normalize( nWidth ), FieldUnit::TWIP ); + m_xListtabMF->set_max(m_xListtabMF->normalize( nWidth ), FieldUnit::TWIP ); + m_xAlignedAtMF->set_max(m_xAlignedAtMF->normalize( nWidth ), FieldUnit::TWIP ); + m_xIndentAtMF->set_max(m_xIndentAtMF->normalize( nWidth ), FieldUnit::TWIP ); + + const SwRect& rPrtRect = pWrtSh->GetAnyCurRect(CurRectType::Page); + m_aPreviewWIN.SetPageWidth(rPrtRect.Width()); + FieldUnit eMetric = ::GetDfltMetric( dynamic_cast<SwWebView*>( &pWrtSh->GetView()) != nullptr ); + if(eMetric == FieldUnit::MM) + { + m_xDistBorderMF->set_digits(1); + m_xDistNumMF->set_digits(1); + m_xIndentMF->set_digits(1); + m_xListtabMF->set_digits(1); + m_xAlignedAtMF->set_digits(1); + m_xIndentAtMF->set_digits(1); + } + m_xDistBorderMF->set_unit( eMetric ); + m_xDistNumMF->set_unit( eMetric ); + m_xIndentMF->set_unit( eMetric ); + m_xListtabMF->set_unit( eMetric ); + m_xAlignedAtMF->set_unit( eMetric ); + m_xIndentAtMF->set_unit( eMetric ); +} + +IMPL_LINK_NOARG(SwNumPositionTabPage, EditModifyHdl, weld::ComboBox&, void) +{ + sal_uInt16 nMask = 1; + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + if(nActNumLvl & nMask) + { + SwNumFormat aNumFormat(pActNum->Get(i)); + + const int nPos = m_xAlignLB->get_visible() + ? m_xAlignLB->get_active() + : m_xAlign2LB->get_active(); + SvxAdjust eAdjust = SvxAdjust::Center; + if(nPos == 0) + eAdjust = SvxAdjust::Left; + else if(nPos == 2) + eAdjust = SvxAdjust::Right; + aNumFormat.SetNumAdjust( eAdjust ); + pActNum->Set(i, aNumFormat); + } + nMask <<= 1; + } + SetModified(); +} + +IMPL_LINK( SwNumPositionTabPage, LevelHdl, weld::TreeView&, rBox, void ) +{ + sal_uInt16 nSaveNumLvl = nActNumLvl; + nActNumLvl = 0; + auto aRows = rBox.get_selected_rows(); + if ((std::find(aRows.begin(), aRows.end(), MAXLEVEL) != aRows.end()) && + (aRows.size() == 1 || nSaveNumLvl != 0xffff)) + { + nActNumLvl = 0xFFFF; + for (sal_uInt16 i = 0; i < MAXLEVEL; ++i) + rBox.unselect(i); + } + else if (!aRows.empty()) + { + sal_uInt16 nMask = 1; + for (sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + if (std::find(aRows.begin(), aRows.end(), i) != aRows.end()) + nActNumLvl |= nMask; + nMask <<= 1; + } + rBox.unselect(MAXLEVEL); + } + else + { + nActNumLvl = nSaveNumLvl; + sal_uInt16 nMask = 1; + for (sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + if(nActNumLvl & nMask) + { + rBox.select(i); + break; + } + nMask <<=1; + } + } + m_xRelativeCB->set_sensitive(1 != nActNumLvl); + SetModified(); + InitPosAndSpaceMode(); + ShowControlsDependingOnPosAndSpaceMode(); + InitControls(); +} + +IMPL_LINK(SwNumPositionTabPage, DistanceHdl, weld::MetricSpinButton&, rField, void) +{ + if(bInInintControl) + return; + tools::Long nValue = static_cast< tools::Long >(rField.denormalize(rField.get_value(FieldUnit::TWIP))); + sal_uInt16 nMask = 1; + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + if(nActNumLvl & nMask) + { + SwNumFormat aNumFormat( pActNum->Get( i ) ); + if (&rField == m_xDistBorderMF.get()) + { + + if (m_xRelativeCB->get_active() && m_xRelativeCB->get_sensitive()) + { + if(0 == i) + { + auto const nTmp = aNumFormat.GetFirstLineOffset(); + aNumFormat.SetAbsLSpace( nValue - nTmp ); + } + else + { + tools::Long nTmp = pActNum->Get( i - 1 ).GetAbsLSpace() + + pActNum->Get( i - 1 ).GetFirstLineOffset() - + pActNum->Get( i ).GetFirstLineOffset(); + + aNumFormat.SetAbsLSpace( nValue + nTmp ); + } + } + else + { + aNumFormat.SetAbsLSpace( nValue - aNumFormat.GetFirstLineOffset()); + } + } + else if (&rField == m_xDistNumMF.get()) + { + aNumFormat.SetCharTextDistance( nValue ); + } + else if (&rField == m_xIndentMF.get()) + { + // now AbsLSpace also has to be modified by FirstLineOffset + tools::Long nDiff = nValue + aNumFormat.GetFirstLineOffset(); + auto const nAbsLSpace = aNumFormat.GetAbsLSpace(); + aNumFormat.SetAbsLSpace( nAbsLSpace + nDiff ); + aNumFormat.SetFirstLineOffset( -nValue ); + } + + pActNum->Set( i, aNumFormat ); + } + nMask <<= 1; + } + + SetModified(); + if(!m_xDistBorderMF->get_sensitive()) + m_xDistBorderMF->set_text(OUString()); +} + +IMPL_LINK( SwNumPositionTabPage, RelativeHdl, weld::Toggleable&, rBox, void ) +{ + bool bOn = rBox.get_active(); + bool bSingleSelection = m_xLevelLB->n_children() == 1 && USHRT_MAX != nActNumLvl; + bool bSetValue = false; + tools::Long nValue = 0; + if(bOn || bSingleSelection) + { + sal_uInt16 nMask = 1; + bool bFirst = true; + bSetValue = true; + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + if(nActNumLvl & nMask) + { + const SwNumFormat &rNumFormat = pActNum->Get(i); + if(bFirst) + { + nValue = rNumFormat.GetAbsLSpace(); + if(bOn && i) + nValue -= pActNum->Get(i - 1).GetAbsLSpace(); + } + else + bSetValue = nValue == rNumFormat.GetAbsLSpace() - pActNum->Get(i - 1).GetAbsLSpace(); + bFirst = false; + } + nMask <<= 1; + } + + } + if(bSetValue) + m_xDistBorderMF->set_value(m_xDistBorderMF->normalize(nValue), FieldUnit::TWIP); + else + m_xDistBorderMF->set_text(OUString()); + m_xDistBorderMF->set_sensitive(bOn || bSingleSelection || pOutlineDlg); + bLastRelative = bOn; +} + +IMPL_LINK_NOARG(SwNumPositionTabPage, LabelFollowedByHdl_Impl, weld::ComboBox&, void) +{ + // determine value to be set at the chosen list levels + SvxNumberFormat::LabelFollowedBy eLabelFollowedBy = SvxNumberFormat::LISTTAB; + { + const int nPos = m_xLabelFollowedByLB->get_active(); + if ( nPos == 1 ) + { + eLabelFollowedBy = SvxNumberFormat::SPACE; + } + else if ( nPos == 2 ) + { + eLabelFollowedBy = SvxNumberFormat::NOTHING; + } + else if ( nPos == 3 ) + { + eLabelFollowedBy = SvxNumberFormat::NEWLINE; + } + } + + // set value at the chosen list levels + bool bSameListtabPos = true; + sal_uInt16 nFirstLvl = USHRT_MAX; + sal_uInt16 nMask = 1; + for( sal_uInt16 i = 0; i < MAXLEVEL; ++i ) + { + if ( nActNumLvl & nMask ) + { + SwNumFormat aNumFormat( pActNum->Get(i) ); + aNumFormat.SetLabelFollowedBy( eLabelFollowedBy ); + pActNum->Set( i, aNumFormat ); + + if ( nFirstLvl == USHRT_MAX ) + { + nFirstLvl = i; + } + else + { + bSameListtabPos &= aNumFormat.GetListtabPos() == + pActNum->Get( nFirstLvl ).GetListtabPos(); + } + } + nMask <<= 1; + } + + // enable/disable metric field for list tab stop position depending on + // selected item following the list label. + m_xListtabFT->set_sensitive( eLabelFollowedBy == SvxNumberFormat::LISTTAB ); + m_xListtabMF->set_sensitive( eLabelFollowedBy == SvxNumberFormat::LISTTAB ); + if ( bSameListtabPos && eLabelFollowedBy == SvxNumberFormat::LISTTAB ) + { + m_xListtabMF->set_value( + m_xListtabMF->normalize( pActNum->Get( nFirstLvl ).GetListtabPos() ), + FieldUnit::TWIP ); + } + else + { + m_xListtabMF->set_text(OUString()); + } + + SetModified(); +} + +IMPL_LINK( SwNumPositionTabPage, ListtabPosHdl_Impl, weld::MetricSpinButton&, rField, void ) +{ + // determine value to be set at the chosen list levels + const tools::Long nValue = static_cast< tools::Long >(rField.denormalize(rField.get_value(FieldUnit::TWIP))); + + // set value at the chosen list levels + sal_uInt16 nMask = 1; + for( sal_uInt16 i = 0; i < MAXLEVEL; ++i ) + { + if ( nActNumLvl & nMask ) + { + SwNumFormat aNumFormat( pActNum->Get(i) ); + aNumFormat.SetListtabPos( nValue ); + pActNum->Set( i, aNumFormat ); + } + nMask <<= 1; + } + + SetModified(); +} + +IMPL_LINK( SwNumPositionTabPage, AlignAtHdl_Impl, weld::MetricSpinButton&, rField, void ) +{ + // determine value to be set at the chosen list levels + const tools::Long nValue = static_cast< tools::Long >(rField.denormalize(rField.get_value(FieldUnit::TWIP))); + + // set value at the chosen list levels + sal_uInt16 nMask = 1; + for( sal_uInt16 i = 0; i < MAXLEVEL; ++i ) + { + if ( nActNumLvl & nMask ) + { + SwNumFormat aNumFormat( pActNum->Get(i) ); + const tools::Long nFirstLineIndent = nValue - aNumFormat.GetIndentAt(); + aNumFormat.SetFirstLineIndent( nFirstLineIndent ); + pActNum->Set( i, aNumFormat ); + } + nMask <<= 1; + } + + SetModified(); +} + +IMPL_LINK( SwNumPositionTabPage, IndentAtHdl_Impl, weld::MetricSpinButton&, rField, void ) +{ + // determine value to be set at the chosen list levels + const tools::Long nValue = static_cast< tools::Long >(rField.denormalize(rField.get_value(FieldUnit::TWIP))); + + // set value at the chosen list levels + sal_uInt16 nMask = 1; + for( sal_uInt16 i = 0; i < MAXLEVEL; ++i ) + { + if ( nActNumLvl & nMask ) + { + SwNumFormat aNumFormat( pActNum->Get(i) ); + const tools::Long nAlignedAt = aNumFormat.GetIndentAt() + + aNumFormat.GetFirstLineIndent(); + aNumFormat.SetIndentAt( nValue ); + const tools::Long nNewFirstLineIndent = nAlignedAt - nValue; + aNumFormat.SetFirstLineIndent( nNewFirstLineIndent ); + pActNum->Set( i, aNumFormat ); + } + nMask <<= 1; + } + + SetModified(); +} + +IMPL_LINK_NOARG(SwNumPositionTabPage, StandardHdl, weld::Button&, void) +{ + sal_uInt16 nMask = 1; + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + if(nActNumLvl & nMask) + { + SwNumFormat aNumFormat( pActNum->Get( i ) ); + SwNumRule aTmpNumRule( pWrtSh->GetUniqueNumRuleName(), + aNumFormat.GetPositionAndSpaceMode(), + pOutlineDlg ? OUTLINE_RULE : NUM_RULE ); + const SwNumFormat& aTempFormat(aTmpNumRule.Get( i )); + aNumFormat.SetPositionAndSpaceMode( aTempFormat.GetPositionAndSpaceMode() ); + if ( aTempFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aNumFormat.SetAbsLSpace( aTempFormat.GetAbsLSpace()); + aNumFormat.SetCharTextDistance( aTempFormat.GetCharTextDistance() ); + aNumFormat.SetFirstLineOffset( aTempFormat.GetFirstLineOffset() ); + } + else if ( aTempFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aNumFormat.SetNumAdjust( aTempFormat.GetNumAdjust() ); + aNumFormat.SetLabelFollowedBy( aTempFormat.GetLabelFollowedBy() ); + aNumFormat.SetListtabPos( aTempFormat.GetListtabPos() ); + aNumFormat.SetFirstLineIndent( aTempFormat.GetFirstLineIndent() ); + aNumFormat.SetIndentAt( aTempFormat.GetIndentAt() ); + } + pActNum->Set( i, aNumFormat ); + } + nMask <<= 1; + } + + InitControls(); + SetModified(); +} + +#ifdef DBG_UTIL +void SwNumPositionTabPage::SetModified() +{ + bModified = true; + m_aPreviewWIN.SetLevel(nActNumLvl); + m_aPreviewWIN.Invalidate(); +} +#endif + +SwSvxNumBulletTabDialog::SwSvxNumBulletTabDialog(weld::Window* pParent, + const SfxItemSet* pSwItemSet, SwWrtShell & rSh) + : SfxTabDialogController(pParent, "modules/swriter/ui/bulletsandnumbering.ui", "BulletsAndNumberingDialog", + pSwItemSet) + , rWrtSh(rSh) + , m_xDummyCombo(m_xBuilder->weld_combo_box("dummycombo")) +{ + weld::Button* pButton = GetUserButton(); + pButton->connect_clicked(LINK(this, SwSvxNumBulletTabDialog, RemoveNumberingHdl)); + pButton->set_sensitive(rWrtSh.GetNumRuleAtCurrCursorPos() != nullptr); + AddTabPage("singlenum", RID_SVXPAGE_PICK_SINGLE_NUM ); + AddTabPage("bullets", RID_SVXPAGE_PICK_BULLET ); + AddTabPage("outlinenum", RID_SVXPAGE_PICK_NUM ); + AddTabPage("graphics", RID_SVXPAGE_PICK_BMP ); + + if (comphelper::LibreOfficeKit::isActive()) + { + RemoveTabPage("customize"); + } + else + { + AddTabPage("customize", RID_SVXPAGE_NUM_OPTIONS ); + } + + AddTabPage("position", RID_SVXPAGE_NUM_POSITION ); +} + +SwSvxNumBulletTabDialog::~SwSvxNumBulletTabDialog() +{ +} + +void SwSvxNumBulletTabDialog::PageCreated(const OString& rPageId, SfxTabPage& rPage) +{ + // set styles' names and metric + OUString sNumCharFormat, sBulletCharFormat; + SwStyleNameMapper::FillUIName( RES_POOLCHR_NUM_LEVEL, sNumCharFormat ); + SwStyleNameMapper::FillUIName( RES_POOLCHR_BULLET_LEVEL, sBulletCharFormat ); + + if (rPageId == "singlenum") + { + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + aSet.Put (SfxStringItem(SID_NUM_CHAR_FMT,sNumCharFormat)); + aSet.Put (SfxStringItem(SID_BULLET_CHAR_FMT,sBulletCharFormat)); + rPage.PageCreated(aSet); + } + else if (rPageId == "bullets") + { + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + aSet.Put (SfxStringItem(SID_BULLET_CHAR_FMT,sBulletCharFormat)); + rPage.PageCreated(aSet); + } + else if (rPageId == "customize") + { + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + aSet.Put (SfxStringItem(SID_NUM_CHAR_FMT,sNumCharFormat)); + aSet.Put (SfxStringItem(SID_BULLET_CHAR_FMT,sBulletCharFormat)); + // collect char styles + m_xDummyCombo->clear(); + m_xDummyCombo->append_text(SwViewShell::GetShellRes()->aStrNone); + SwDocShell* pDocShell = rWrtSh.GetView().GetDocShell(); + ::FillCharStyleListBox(*m_xDummyCombo, pDocShell); + + std::vector<OUString> aList; + aList.reserve(m_xDummyCombo->get_count()); + for (sal_Int32 j = 0; j < m_xDummyCombo->get_count(); j++) + aList.push_back(m_xDummyCombo->get_text(j)); + + aSet.Put( SfxStringListItem( SID_CHAR_FMT_LIST_BOX,&aList ) ) ; + + FieldUnit eMetric = ::GetDfltMetric(dynamic_cast< const SwWebDocShell *>( pDocShell ) != nullptr); + aSet.Put ( SfxUInt16Item(SID_METRIC_ITEM, static_cast< sal_uInt16 >(eMetric) ) ); + rPage.PageCreated(aSet); + } + else if (rPageId == "position") + { + SwDocShell* pDocShell = rWrtSh.GetView().GetDocShell(); + FieldUnit eMetric = ::GetDfltMetric(dynamic_cast< const SwWebDocShell *>( pDocShell ) != nullptr); + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + aSet.Put ( SfxUInt16Item(SID_METRIC_ITEM, static_cast< sal_uInt16 >(eMetric)) ); + rPage.PageCreated(aSet); + } +} + +short SwSvxNumBulletTabDialog::Ok() +{ + short nRet = SfxTabDialogController::Ok(); + m_xExampleSet->ClearItem(SID_PARAM_NUM_PRESET); + return nRet; +} + +IMPL_LINK_NOARG(SwSvxNumBulletTabDialog, RemoveNumberingHdl, weld::Button&, void) +{ + m_xDialog->response(RET_USER); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/outline.cxx b/sw/source/ui/misc/outline.cxx new file mode 100644 index 000000000..533028ebe --- /dev/null +++ b/sw/source/ui/misc/outline.cxx @@ -0,0 +1,1078 @@ +/* -*- 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 <hintids.hxx> +#include <vcl/settings.hxx> +#include <vcl/virdev.hxx> +#include <sfx2/tabdlg.hxx> +#include <editeng/brushitem.hxx> +#include <unotools/configmgr.hxx> +#include <SwStyleNameMapper.hxx> +#include <num.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <uitool.hxx> +#include <wrtsh.hxx> +#include <swmodule.hxx> +#include <fmtcol.hxx> +#include <outline.hxx> +#include <uinums.hxx> +#include <poolfmt.hxx> +#include <shellres.hxx> +#include <svl/style.hxx> +#include <charfmt.hxx> +#include <docstyle.hxx> +#include <viewopt.hxx> +#include <outline.hrc> +#include <strings.hrc> +#include <paratr.hxx> +#include <svtools/colorcfg.hxx> + +#include <IDocumentOutlineNodes.hxx> + +using namespace ::com::sun::star; + +namespace { + +class SwNumNamesDlg : public weld::GenericDialogController +{ + std::unique_ptr<weld::Entry> m_xFormEdit; + std::unique_ptr<weld::TreeView> m_xFormBox; + std::unique_ptr<weld::Button> m_xOKBtn; + + DECL_LINK( ModifyHdl, weld::Entry&, void ); + DECL_LINK( SelectHdl, weld::TreeView&, void ); + DECL_LINK( DoubleClickHdl, weld::TreeView&, bool ); + +public: + explicit SwNumNamesDlg(weld::Window *pParent); + void SetUserNames(const OUString *pList[]); + OUString GetName() const { return m_xFormEdit->get_text(); } + int GetCurEntryPos() const { return m_xFormBox->get_selected_index(); } +}; + +} + +// remember selected entry +IMPL_LINK( SwNumNamesDlg, SelectHdl, weld::TreeView&, rBox, void ) +{ + m_xFormEdit->set_text(rBox.get_selected_text()); + m_xFormEdit->select_region(0, -1); +} + +/** set user defined names + * + * @param pList list of user defined names; unknown positions for the user are 0. + */ +void SwNumNamesDlg::SetUserNames(const OUString *pList[]) +{ + sal_uInt16 nSelect = 0; + for (sal_uInt16 i = 0; i < SwChapterNumRules::nMaxRules; ++i) + { + if(pList[i]) + { + m_xFormBox->remove(i); + m_xFormBox->insert_text(i, *pList[i]); + if (i == nSelect) + nSelect++; + } + } + m_xFormBox->select(std::min(nSelect, o3tl::narrowing<sal_uInt16>(m_xFormBox->n_children() - 1))); + SelectHdl(*m_xFormBox); +} + +// unlock OK-Button when text is in Edit +IMPL_LINK( SwNumNamesDlg, ModifyHdl, weld::Entry&, rBox, void ) +{ + m_xOKBtn->set_sensitive(!rBox.get_text().isEmpty()); +} + +// DoubleClickHdl +IMPL_LINK_NOARG(SwNumNamesDlg, DoubleClickHdl, weld::TreeView&, bool) +{ + m_xDialog->response(RET_OK); + return true; +} + +SwNumNamesDlg::SwNumNamesDlg(weld::Window *pParent) + : GenericDialogController(pParent, + "modules/swriter/ui/numberingnamedialog.ui", + "NumberingNameDialog") + , m_xFormEdit(m_xBuilder->weld_entry("entry")) + , m_xFormBox(m_xBuilder->weld_tree_view("form")) + , m_xOKBtn(m_xBuilder->weld_button("ok")) +{ + for (size_t i = 0; i < SAL_N_ELEMENTS(OUTLINE_STYLE); ++i) + m_xFormBox->append_text(SwResId(OUTLINE_STYLE[i])); + + m_xFormEdit->connect_changed(LINK(this, SwNumNamesDlg, ModifyHdl)); + m_xFormBox->connect_changed(LINK(this, SwNumNamesDlg, SelectHdl)); + m_xFormBox->connect_row_activated(LINK(this, SwNumNamesDlg, DoubleClickHdl)); + m_xFormBox->set_size_request(-1, m_xFormBox->get_height_rows(9)); +} + +static sal_uInt16 lcl_BitToLevel(sal_uInt16 nActLevel) +{ + sal_uInt16 nTmp = nActLevel; + sal_uInt16 nTmpLevel = 0; + while( 0 != (nTmp >>= 1) ) + nTmpLevel++; + return nTmpLevel; +} + +sal_uInt16 SwOutlineTabDialog::nNumLevel = 1; + +SwOutlineTabDialog::SwOutlineTabDialog(weld::Window* pParent, const SfxItemSet* pSwItemSet, + SwWrtShell &rSh) + : SfxTabDialogController(pParent, "modules/swriter/ui/outlinenumbering.ui", "OutlineNumberingDialog", pSwItemSet) + , rWrtSh(rSh) + , pChapterNumRules(SW_MOD()->GetChapterNumRules()) + , bModified(rWrtSh.IsModified()) + , m_xMenuButton(m_xBuilder->weld_menu_button("format")) +{ + m_xMenuButton->connect_toggled(LINK(this, SwOutlineTabDialog, FormHdl)); + m_xMenuButton->connect_selected(LINK(this, SwOutlineTabDialog, MenuSelectHdl)); + + xNumRule.reset(new SwNumRule(*rSh.GetOutlineNumRule())); + GetCancelButton().connect_clicked(LINK(this, SwOutlineTabDialog, CancelHdl)); + + AddTabPage("position", &SwNumPositionTabPage::Create, nullptr); + AddTabPage("numbering", &SwOutlineSettingsTabPage::Create, nullptr); + + OUString sHeadline; + sal_uInt16 i; + + for( i = 0; i < MAXLEVEL; ++i ) + { + // if the style wasn't created yet, it's still at this position + if( !rWrtSh.GetParaStyle( sHeadline = + SwStyleNameMapper::GetUIName( static_cast< sal_uInt16 >(RES_POOLCOLL_HEADLINE1 + i), + sHeadline )) ) + aCollNames[i] = sHeadline; + } + + // query the text templates' outlining levels + const sal_uInt16 nCount = rWrtSh.GetTextFormatCollCount(); + for(i = 0; i < nCount; ++i ) + { + SwTextFormatColl &rTextColl = rWrtSh.GetTextFormatColl(i); + if(!rTextColl.IsDefault()) + { + if(rTextColl.IsAssignedToListLevelOfOutlineStyle()) + { + int nOutLevel = rTextColl.GetAssignedOutlineStyleLevel(); + aCollNames[ nOutLevel ] = rTextColl.GetName(); + } + } + } +} + +SwOutlineTabDialog::~SwOutlineTabDialog() +{ +} + +void SwOutlineTabDialog::PageCreated(const OString& rPageId, SfxTabPage& rPage) +{ + if (rPageId == "position") + { + static_cast<SwNumPositionTabPage&>(rPage).SetWrtShell(&rWrtSh); + static_cast<SwNumPositionTabPage&>(rPage).SetOutlineTabDialog(this); + } + else if (rPageId == "numbering") + { + static_cast<SwOutlineSettingsTabPage&>(rPage).SetWrtShell(&rWrtSh); + } +} + +IMPL_LINK_NOARG(SwOutlineTabDialog, CancelHdl, weld::Button&, void) +{ + if (!bModified) + rWrtSh.ResetModified(); + m_xDialog->response(RET_CANCEL); +} + +IMPL_LINK_NOARG(SwOutlineTabDialog, FormHdl, weld::Toggleable&, void) +{ + if (!m_xMenuButton->get_active()) + return; + + // fill PopupMenu + for(sal_uInt16 i = 0; i < SwChapterNumRules::nMaxRules; ++i) + { + const SwNumRulesWithName *pRules = pChapterNumRules->GetRules(i); + if (!pRules) + continue; + m_xMenuButton->set_item_label("form" + OString::number(i + 1), pRules->GetName()); + } +} + +IMPL_LINK(SwOutlineTabDialog, MenuSelectHdl, const OString&, rIdent, void) +{ + sal_uInt8 nLevelNo = 0; + + if (rIdent == "form1") + nLevelNo = 1; + else if (rIdent == "form2") + nLevelNo = 2; + else if (rIdent == "form3") + nLevelNo = 3; + else if (rIdent == "form4") + nLevelNo = 4; + else if (rIdent == "form5") + nLevelNo = 5; + else if (rIdent == "form6") + nLevelNo = 6; + else if (rIdent == "form7") + nLevelNo = 7; + else if (rIdent == "form8") + nLevelNo = 8; + else if (rIdent == "form9") + nLevelNo = 9; + else if (rIdent == "saveas") + { + SwNumNamesDlg aDlg(m_xDialog.get()); + const OUString *aStrArr[SwChapterNumRules::nMaxRules]; + for(sal_uInt16 i = 0; i < SwChapterNumRules::nMaxRules; ++i) + { + const SwNumRulesWithName *pRules = pChapterNumRules->GetRules(i); + if(pRules) + aStrArr[i] = &pRules->GetName(); + else + aStrArr[i] = nullptr; + } + aDlg.SetUserNames(aStrArr); + if (aDlg.run() == RET_OK) + { + const OUString aName(aDlg.GetName()); + pChapterNumRules->ApplyNumRules( SwNumRulesWithName( + *xNumRule, aName ), aDlg.GetCurEntryPos() ); + m_xMenuButton->set_item_label("form" + OString::number(aDlg.GetCurEntryPos() + 1), aName); + } + return; + } + + if( nLevelNo-- ) + { + const SwNumRulesWithName *pRules = pChapterNumRules->GetRules( nLevelNo ); + if( pRules ) + { + pRules->ResetNumRule(rWrtSh, *xNumRule); + xNumRule->SetRuleType( OUTLINE_RULE ); + SfxTabPage* pOutlinePage = GetTabPage("numbering"); + assert(pOutlinePage); + static_cast<SwOutlineSettingsTabPage*>(pOutlinePage)->SetNumRule(xNumRule.get()); + } + else + *xNumRule = *rWrtSh.GetOutlineNumRule(); + } + + SfxTabPage* pPage = GetCurTabPage(); + pPage->Reset(GetOutputItemSet()); +} + +sal_uInt16 SwOutlineTabDialog::GetLevel(std::u16string_view rFormatName) const +{ + for(sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + if(aCollNames[i] == rFormatName) + return i; + } + return MAXLEVEL; +} + +short SwOutlineTabDialog::Ok() +{ + SfxTabDialogController::Ok(); + // set levels for all created templates; has to be done in order to + // delete possibly cancelled assignments again. + + // encapsulate changes into an action to avoid effects on the current cursor + // position during the changes. + rWrtSh.StartAction(); + + const SwNumRule * pOutlineRule = rWrtSh.GetOutlineNumRule(); + + sal_uInt16 i, nCount = rWrtSh.GetTextFormatCollCount(); + for( i = 0; i < nCount; ++i ) + { + SwTextFormatColl &rTextColl = rWrtSh.GetTextFormatColl(i); + if( !rTextColl.IsDefault() ) + { + const SfxPoolItem & rItem = + rTextColl.GetFormatAttr(RES_PARATR_NUMRULE, false); + + if (static_cast<sal_uInt8>(GetLevel(rTextColl.GetName())) == MAXLEVEL) + { + if(rTextColl.IsAssignedToListLevelOfOutlineStyle()) + { + rTextColl.DeleteAssignmentToListLevelOfOutlineStyle(); + } + if (static_cast<const SwNumRuleItem &>(rItem).GetValue() == + pOutlineRule->GetName()) + { + rTextColl.ResetFormatAttr(RES_PARATR_NUMRULE); + } + } + else + { + rTextColl.AssignToListLevelOfOutlineStyle(GetLevel(rTextColl.GetName())); + + if (static_cast<const SwNumRuleItem &>(rItem).GetValue() != + pOutlineRule->GetName()) + { + SwNumRuleItem aItem(pOutlineRule->GetName()); + rTextColl.SetFormatAttr(aItem); + } + } + } + } + + for(i = 0; i < MAXLEVEL; ++i ) + { + OUString sHeadline; + ::SwStyleNameMapper::FillUIName( static_cast< sal_uInt16 >(RES_POOLCOLL_HEADLINE1 + i), + sHeadline ); + SwTextFormatColl* pColl = rWrtSh.FindTextFormatCollByName( sHeadline ); + if( !pColl && aCollNames[i] != sHeadline) + { + SwTextFormatColl* pTextColl = rWrtSh.GetTextCollFromPool( + static_cast< sal_uInt16 >(RES_POOLCOLL_HEADLINE1 + i) ); + pTextColl->DeleteAssignmentToListLevelOfOutlineStyle(); + pTextColl->ResetFormatAttr(RES_PARATR_NUMRULE); + + if( !aCollNames[i].isEmpty() ) + { + pTextColl = rWrtSh.GetParaStyle( + aCollNames[i], SwWrtShell::GETSTYLE_CREATESOME); + if(pTextColl) + { + pTextColl->AssignToListLevelOfOutlineStyle(i); + SwNumRuleItem aItem(pOutlineRule->GetName()); + pTextColl->SetFormatAttr(aItem); + } + } + } + } + + rWrtSh.SetOutlineNumRule(*xNumRule); + + // #i30443# + rWrtSh.EndAction(); + + return RET_OK; +} + +SwOutlineSettingsTabPage::SwOutlineSettingsTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/outlinenumberingpage.ui", "OutlineNumberingPage", &rSet) + , aNoFormatName(SwResId(SW_STR_NONE)) + , pSh(nullptr) + , pNumRule(nullptr) + , pCollNames(nullptr) + , nActLevel(1) + , m_xLevelLB(m_xBuilder->weld_tree_view("level")) + , m_xCollBox(m_xBuilder->weld_combo_box("style")) + , m_xNumberBox(new SwNumberingTypeListBox(m_xBuilder->weld_combo_box("numbering"))) + , m_xCharFormatLB(m_xBuilder->weld_combo_box("charstyle")) + , m_xAllLevelFT(m_xBuilder->weld_label("sublevelsft")) + , m_xAllLevelNF(m_xBuilder->weld_spin_button("sublevelsnf")) + , m_xPrefixED(m_xBuilder->weld_entry("prefix")) + , m_xSuffixED(m_xBuilder->weld_entry("suffix")) + , m_xStartEdit(m_xBuilder->weld_spin_button("startat")) + , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "preview", m_aPreviewWIN)) +{ + SetExchangeSupport(); + + m_xNumberBox->Reload(SwInsertNumTypes::NoNumbering | SwInsertNumTypes::Extended); + m_xCollBox->make_sorted(); + m_xCollBox->append_text(aNoFormatName); + m_xLevelLB->connect_changed(LINK(this, SwOutlineSettingsTabPage, LevelHdl)); + m_xAllLevelNF->connect_value_changed(LINK(this, SwOutlineSettingsTabPage, ToggleComplete)); + m_xCollBox->connect_changed(LINK(this, SwOutlineSettingsTabPage, CollSelect)); + m_xNumberBox->connect_changed(LINK(this, SwOutlineSettingsTabPage, NumberSelect)); + m_xPrefixED->connect_changed(LINK(this, SwOutlineSettingsTabPage, DelimModify)); + m_xSuffixED->connect_changed(LINK(this, SwOutlineSettingsTabPage, DelimModify)); + m_xStartEdit->connect_value_changed(LINK(this, SwOutlineSettingsTabPage, StartModified)); + m_xCharFormatLB->make_sorted(); + m_xCharFormatLB->connect_changed(LINK(this, SwOutlineSettingsTabPage, CharFormatHdl)); +} + +void SwOutlineSettingsTabPage::Update() +{ + // if a template was already selected for this level, select it in the ListBox + m_xCollBox->set_sensitive(USHRT_MAX != nActLevel); + if(USHRT_MAX == nActLevel) + { + bool bSamePrefix = true; + bool bSameSuffix = true; + bool bSameType = true; + bool bSameComplete = true; + bool bSameStart = true; + bool bSameCharFormat = true; + + const SwNumFormat* aNumFormatArr[MAXLEVEL]; + const SwCharFormat* pFirstFormat = nullptr; + + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + + aNumFormatArr[ i ] = &pNumRule->Get(i); + if(i == 0) + pFirstFormat = aNumFormatArr[i]->GetCharFormat(); + else + { + bSameType &= aNumFormatArr[i]->GetNumberingType() == aNumFormatArr[0]->GetNumberingType(); + bSameStart &= aNumFormatArr[i]->GetStart() == aNumFormatArr[0]->GetStart(); + bSamePrefix &= aNumFormatArr[i]->GetPrefix() == aNumFormatArr[0]->GetPrefix(); + bSameSuffix &= aNumFormatArr[i]->GetSuffix() == aNumFormatArr[0]->GetSuffix(); + bSameComplete &= aNumFormatArr[i]->GetIncludeUpperLevels() == aNumFormatArr[0]->GetIncludeUpperLevels(); + const SwCharFormat* pFormat = aNumFormatArr[i]->GetCharFormat(); + bSameCharFormat &= (!pFirstFormat && !pFormat) + || (pFirstFormat && pFormat && pFormat->GetName() == pFirstFormat->GetName()); + } + } + CheckForStartValue_Impl(aNumFormatArr[0]->GetNumberingType()); + if (bSameType) + m_xNumberBox->SelectNumberingType( aNumFormatArr[0]->GetNumberingType() ); + else + m_xNumberBox->SetNoSelection(); + if(bSameStart) + m_xStartEdit->set_value(aNumFormatArr[0]->GetStart()); + else + m_xStartEdit->set_text(OUString()); + if(bSamePrefix) + m_xPrefixED->set_text(aNumFormatArr[0]->GetPrefix()); + else + m_xPrefixED->set_text(OUString()); + if(bSameSuffix) + m_xSuffixED->set_text(aNumFormatArr[0]->GetSuffix()); + else + m_xSuffixED->set_text(OUString()); + + if (bSameCharFormat) + { + if (pFirstFormat) + m_xCharFormatLB->set_active_text(pFirstFormat->GetName()); + else + m_xCharFormatLB->set_active_text(SwViewShell::GetShellRes()->aStrNone); + } + else + m_xCharFormatLB->set_active(-1); + + m_xAllLevelFT->set_sensitive(true); + m_xAllLevelNF->set_sensitive(true); + m_xAllLevelNF->set_max(MAXLEVEL); + if (bSameComplete) + { + m_xAllLevelNF->set_value(aNumFormatArr[0]->GetIncludeUpperLevels()); + } + else + { + m_xAllLevelNF->set_text(OUString()); + } + } + else + { + sal_uInt16 nTmpLevel = lcl_BitToLevel(nActLevel); + OUString aColl(pCollNames[nTmpLevel]); + if(!aColl.isEmpty()) + m_xCollBox->set_active_text(aColl); + else + m_xCollBox->set_active_text(aNoFormatName); + const SwNumFormat &rFormat = pNumRule->Get(nTmpLevel); + + m_xNumberBox->SelectNumberingType( rFormat.GetNumberingType() ); + m_xPrefixED->set_text(rFormat.GetPrefix()); + m_xSuffixED->set_text(rFormat.GetSuffix()); + const SwCharFormat* pFormat = rFormat.GetCharFormat(); + if(pFormat) + m_xCharFormatLB->set_active_text(pFormat->GetName()); + else + m_xCharFormatLB->set_active_text(SwViewShell::GetShellRes()->aStrNone); + + if (nTmpLevel || rFormat.HasListFormat()) + { + m_xAllLevelFT->set_sensitive(true); + m_xAllLevelNF->set_sensitive(true); + m_xAllLevelNF->set_max(nTmpLevel + 1); + m_xAllLevelNF->set_min(rFormat.HasListFormat() ? 0 : 1); + m_xAllLevelNF->set_value(rFormat.GetIncludeUpperLevels()); + } + else + { + m_xAllLevelNF->set_text(OUString()); + m_xAllLevelNF->set_sensitive(false); + m_xAllLevelFT->set_sensitive(false); + } + CheckForStartValue_Impl(rFormat.GetNumberingType()); + m_xStartEdit->set_value( rFormat.GetStart() ); + } + SetModified(); +} + +IMPL_LINK( SwOutlineSettingsTabPage, LevelHdl, weld::TreeView&, rBox, void ) +{ + nActLevel = 0; + auto aRows = rBox.get_selected_rows(); + if (std::find(aRows.begin(), aRows.end(), MAXLEVEL) != aRows.end()) + { + nActLevel = 0xFFFF; + } + else + { + sal_uInt16 nMask = 1; + for( sal_uInt16 i = 0; i < MAXLEVEL; i++ ) + { + if (std::find(aRows.begin(), aRows.end(), i) != aRows.end()) + nActLevel |= nMask; + nMask <<= 1; + } + } + Update(); +} + +IMPL_LINK(SwOutlineSettingsTabPage, ToggleComplete, weld::SpinButton&, rEdit, void) +{ + sal_uInt16 nMask = 1; + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + if(nActLevel & nMask) + { + SwNumFormat aNumFormat(pNumRule->Get(i)); + aNumFormat.SetIncludeUpperLevels( std::min( static_cast<sal_uInt8>(rEdit.get_value()), + static_cast<sal_uInt8>(i + 1)) ); + // Set the same prefix/suffix to generate list format with changed IncludedUpperLevels + aNumFormat.SetListFormat(aNumFormat.GetPrefix(), aNumFormat.GetSuffix(), i); + pNumRule->Set(i, aNumFormat); + } + nMask <<= 1; + } + SetModified(); +} + +IMPL_LINK( SwOutlineSettingsTabPage, CollSelect, weld::ComboBox&, rBox, void ) +{ + sal_uInt8 i; + + const OUString aCollName(rBox.get_active_text()); + //0xFFFF not allowed here (disable) + sal_uInt16 nTmpLevel = lcl_BitToLevel(nActLevel); + OUString sOldName( pCollNames[nTmpLevel] ); + + for( i = 0; i < MAXLEVEL; ++i) + pCollNames[i] = aSaveCollNames[i]; + + if(aCollName == aNoFormatName) + pCollNames[nTmpLevel].clear(); + else + { + pCollNames[nTmpLevel] = aCollName; + // template already in use? + for( i = 0; i < MAXLEVEL; ++i) + if(i != nTmpLevel && pCollNames[i] == aCollName ) + pCollNames[i].clear(); + } + + // search the oldname and put it into the current entries + if( !sOldName.isEmpty() ) + for( i = 0; i < MAXLEVEL; ++i) + if( aSaveCollNames[ i ] == sOldName && i != nTmpLevel && + pCollNames[ i ].isEmpty() ) + { + sal_uInt8 n; + for( n = 0; n < MAXLEVEL; ++n ) + if( pCollNames[ n ] == sOldName ) + break; + + if( MAXLEVEL == n ) + // it was an outline level name and the current entries is zero. + pCollNames[ i ] = sOldName; + } + + SetModified(); + CollSave(); +} + +void SwOutlineSettingsTabPage::CollSave() +{ + for (sal_uInt8 i = 0; i < MAXLEVEL; ++i) + aSaveCollNames[i] = pCollNames[i]; +} + +IMPL_LINK_NOARG(SwOutlineSettingsTabPage, NumberSelect, weld::ComboBox&, void) +{ + sal_uInt16 nMask = 1; + SvxNumType nNumberType = m_xNumberBox->GetSelectedNumberingType(); + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + if(nActLevel & nMask) + { + SwNumFormat aNumFormat(pNumRule->Get(i)); + aNumFormat.SetNumberingType(nNumberType); + pNumRule->Set(i, aNumFormat); + CheckForStartValue_Impl(nNumberType); + } + nMask <<= 1; + } + SetModified(); +} + +IMPL_LINK_NOARG(SwOutlineSettingsTabPage, DelimModify, weld::Entry&, void) +{ + sal_uInt16 nMask = 1; + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + if(nActLevel & nMask) + { + SwNumFormat aNumFormat(pNumRule->Get(i)); + aNumFormat.SetListFormat( m_xPrefixED->get_text(), m_xSuffixED->get_text(), i ); + pNumRule->Set(i, aNumFormat); + } + nMask <<= 1; + } + SetModified(); +} + +IMPL_LINK( SwOutlineSettingsTabPage, StartModified, weld::SpinButton&, rEdit, void ) +{ + sal_uInt16 nMask = 1; + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + if(nActLevel & nMask) + { + SwNumFormat aNumFormat(pNumRule->Get(i)); + aNumFormat.SetStart(o3tl::narrowing<sal_uInt16>(rEdit.get_value())); + pNumRule->Set(i, aNumFormat); + } + nMask <<= 1; + } + SetModified(); +} + +IMPL_LINK_NOARG(SwOutlineSettingsTabPage, CharFormatHdl, weld::ComboBox&, void) +{ + OUString sEntry = m_xCharFormatLB->get_active_text(); + sal_uInt16 nMask = 1; + bool bFormatNone = sEntry == SwViewShell::GetShellRes()->aStrNone; + SwCharFormat* pFormat = nullptr; + if(!bFormatNone) + { + sal_uInt16 nChCount = pSh->GetCharFormatCount(); + for(sal_uInt16 i = 0; i < nChCount; i++) + { + SwCharFormat& rChFormat = pSh->GetCharFormat(i); + if(rChFormat.GetName() == sEntry) + { + pFormat = &rChFormat; + break; + } + } + if(!pFormat) + { + SfxStyleSheetBasePool* pPool = pSh->GetView().GetDocShell()->GetStyleSheetPool(); + SfxStyleSheetBase* pBase; + pBase = pPool->Find(sEntry, SfxStyleFamily::Char); + if(!pBase) + pBase = &pPool->Make(sEntry, SfxStyleFamily::Page); + pFormat = static_cast<SwDocStyleSheet*>(pBase)->GetCharFormat(); + + } + } + + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + if(nActLevel & nMask) + { + SwNumFormat aNumFormat(pNumRule->Get(i)); + if(bFormatNone) + aNumFormat.SetCharFormat(nullptr); + else + aNumFormat.SetCharFormat(pFormat); + pNumRule->Set(i, aNumFormat); + } + nMask <<= 1; + } +} + +SwOutlineSettingsTabPage::~SwOutlineSettingsTabPage() +{ +} + +void SwOutlineSettingsTabPage::SetWrtShell(SwWrtShell* pShell) +{ + pSh = pShell; + // query this document's NumRules + pNumRule = static_cast<SwOutlineTabDialog*>(GetDialogController())->GetNumRule(); + pCollNames = static_cast<SwOutlineTabDialog*>(GetDialogController())->GetCollNames(); + + CollSave(); + + m_aPreviewWIN.SetNumRule(pNumRule); + m_aPreviewWIN.SetOutlineNames(pCollNames); + // set start value - nActLevel must be 1 here + sal_uInt16 nTmpLevel = lcl_BitToLevel(nActLevel); + const SwNumFormat& rNumFormat = pNumRule->Get( nTmpLevel ); + m_xStartEdit->set_value( rNumFormat.GetStart() ); + + // create pool formats for headlines + for (sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + m_xCollBox->append_text( SwStyleNameMapper::GetUIName( + static_cast< sal_uInt16 >(RES_POOLCOLL_HEADLINE1 + i), OUString())); + m_xLevelLB->append_text( OUString::number(i + 1) ); + } + OUString sStr = "1 - " + OUString::number(MAXLEVEL); + m_xLevelLB->append_text(sStr); + + // query the texttemplates' outlining levels + const sal_uInt16 nCount = pSh->GetTextFormatCollCount(); + for (sal_uInt16 i = 0; i < nCount; ++i) + { + SwTextFormatColl &rTextColl = pSh->GetTextFormatColl(i); + if(!rTextColl.IsDefault()) + { + sStr = rTextColl.GetName(); + if (m_xCollBox->find_text(sStr) == -1) + m_xCollBox->append_text(sStr); + } + } + + m_xNumberBox->SelectNumberingType(rNumFormat.GetNumberingType()); + SwOutlineNodes::size_type nOutlinePos = pSh->GetOutlinePos(MAXLEVEL); + int nTmp = 0; + if(nOutlinePos != SwOutlineNodes::npos) + { + nTmp = o3tl::narrowing<sal_uInt16>(pSh->getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos)); + } + m_xLevelLB->select(nTmp-1); + + // collect char styles + m_xCharFormatLB->clear(); + m_xCharFormatLB->append_text(SwViewShell::GetShellRes()->aStrNone); + + // char styles + ::FillCharStyleListBox(*m_xCharFormatLB, + pSh->GetView().GetDocShell()); + Update(); +} + +void SwOutlineSettingsTabPage::ActivatePage(const SfxItemSet& ) +{ + nActLevel = SwOutlineTabDialog::GetActNumLevel(); + if(nActLevel != USHRT_MAX) + m_xLevelLB->select(lcl_BitToLevel(nActLevel)); + else + m_xLevelLB->select(MAXLEVEL); + LevelHdl(*m_xLevelLB); +} + +DeactivateRC SwOutlineSettingsTabPage::DeactivatePage(SfxItemSet*) +{ + SwOutlineTabDialog::SetActNumLevel(nActLevel); + return DeactivateRC::LeavePage; +} + +bool SwOutlineSettingsTabPage::FillItemSet( SfxItemSet* ) +{ + return true; +} + +void SwOutlineSettingsTabPage::Reset( const SfxItemSet* rSet ) +{ + ActivatePage(*rSet); +} + +std::unique_ptr<SfxTabPage> SwOutlineSettingsTabPage::Create(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwOutlineSettingsTabPage>(pPage, pController, *rAttrSet); +} + +void SwOutlineSettingsTabPage::CheckForStartValue_Impl(sal_uInt16 nNumberingType) +{ + bool bIsNull = m_xStartEdit->get_value() == 0; + bool bNoZeroAllowed = nNumberingType < SVX_NUM_ARABIC || + SVX_NUM_CHARS_UPPER_LETTER_N == nNumberingType || + SVX_NUM_CHARS_LOWER_LETTER_N == nNumberingType; + m_xStartEdit->set_min(bNoZeroAllowed ? 1 : 0); + if (bIsNull && bNoZeroAllowed) + StartModified(*m_xStartEdit); +} + +static tools::Long lcl_DrawBullet(vcl::RenderContext* pVDev, const SwNumFormat& rFormat, tools::Long nXStart, tools::Long nYStart, const Size& rSize) +{ + vcl::Font aTmpFont(pVDev->GetFont()); + + // via Uno it's possible that no font has been set! + vcl::Font aFont(rFormat.GetBulletFont() ? *rFormat.GetBulletFont() : aTmpFont); + Size aTmpSize(rSize); + aTmpSize.setWidth( aTmpSize.Width() * ( rFormat.GetBulletRelSize()) ); + aTmpSize.setWidth( aTmpSize.Width() / 100 ) ; + aTmpSize.setHeight( aTmpSize.Height() * ( rFormat.GetBulletRelSize()) ); + aTmpSize.setHeight( aTmpSize.Height() / 100 ) ; + // in case of a height of zero it is drawn in original height + if(!aTmpSize.Height()) + aTmpSize.setHeight( 1 ); + aFont.SetFontSize(aTmpSize); + aFont.SetTransparent(true); + Color aBulletColor = rFormat.GetBulletColor(); + if(aBulletColor == COL_AUTO) + aBulletColor = pVDev->GetFillColor().IsDark() ? COL_WHITE : COL_BLACK; + else if(aBulletColor == pVDev->GetFillColor()) + aBulletColor.Invert(); + aFont.SetColor(aBulletColor); + pVDev->SetFont( aFont ); + sal_UCS4 cBullet = rFormat.GetBulletChar(); + OUString aText(&cBullet, 1); + tools::Long nY = nYStart; + nY -= ((aTmpSize.Height() - rSize.Height())/ 2); + pVDev->DrawText( Point(nXStart, nY), aText ); + tools::Long nRet = pVDev->GetTextWidth(aText); + + pVDev->SetFont(aTmpFont); + return nRet; +} + +static tools::Long lcl_DrawGraphic(vcl::RenderContext& rVDev, const SwNumFormat &rFormat, tools::Long nXStart, tools::Long nYStart, tools::Long nDivision) +{ + const SvxBrushItem* pBrushItem = rFormat.GetBrush(); + tools::Long nRet = 0; + if (pBrushItem) + { + const Graphic* pGraphic = pBrushItem->GetGraphic(); + if (pGraphic) + { + Size aGSize( rFormat.GetGraphicSize()); + aGSize.setWidth( aGSize.Width() / nDivision ); + nRet = aGSize.Width(); + aGSize.setHeight( aGSize.Height() / nDivision ); + pGraphic->Draw(rVDev, Point(nXStart, nYStart), rVDev.PixelToLogic(aGSize)); + } + } + return nRet; +} + +void NumberingPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + const Size aSize(rRenderContext.PixelToLogic(GetOutputSizePixel())); + + ScopedVclPtrInstance<VirtualDevice> pVDev(rRenderContext); + pVDev->SetMapMode(rRenderContext.GetMapMode()); + pVDev->SetOutputSize(aSize); + + // #101524# OJ + pVDev->SetFillColor(SwViewOption::GetDocColor()); + pVDev->SetLineColor(SwViewOption::GetDocBoundariesColor()); + pVDev->DrawRect(tools::Rectangle(Point(0,0), aSize)); + + if (pActNum) + { + tools::Long nWidthRelation = 30; // chapter dialog + if(nPageWidth) + { + nWidthRelation = nPageWidth / aSize.Width(); + if(bPosition) + nWidthRelation = nWidthRelation * 2 / 3; + else + nWidthRelation = nWidthRelation / 4; + } + + // height per level + const tools::Long nXStep = aSize.Width() / (3 * MAXLEVEL * ((MAXLEVEL < 10) ? 2 : 1)); + const tools::Long nYStep = (aSize.Height() - 6)/ MAXLEVEL; + tools::Long nYStart = 4; + aStdFont = OutputDevice::GetDefaultFont(DefaultFontType::UI_SANS, GetAppLanguage(), + GetDefaultFontFlags::OnlyOne, &rRenderContext); + + if (svtools::ColorConfig().GetColorValue(svtools::FONTCOLOR, false).nColor == COL_AUTO) + aStdFont.SetColor( SwViewOption::GetDocColor().IsDark() ? COL_WHITE : COL_BLACK ); + else + aStdFont.SetColor( SwViewOption::GetFontColor() ); + + const tools::Long nFontHeight = nYStep * ( bPosition ? 15 : 6 ) / 10; + aStdFont.SetFontSize(Size( 0, nFontHeight )); + + tools::Long nPreNum = pActNum->Get(0).GetStart(); + + if (bPosition) + { + const tools::Long nLineHeight = nFontHeight * 8 / 7; + sal_uInt8 nStart = 0; + while (!(nActLevel & (1 << nStart))) + { + nStart++; + } + if(nStart) // so that possible predecessors and successors are showed + nStart--; + + SwNumberTree::tNumberVector aNumVector; + sal_uInt8 nEnd = std::min(sal_uInt8(nStart + 3), MAXLEVEL); + for (sal_uInt8 nLevel = nStart; nLevel < nEnd; ++nLevel) + { + const SwNumFormat &rFormat = pActNum->Get(nLevel); + aNumVector.push_back(rFormat.GetStart()); + + tools::Long nXStart( 0 ); + tools::Long nTextOffset( 0 ); + tools::Long nNumberXPos( 0 ); + if (rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION) + { + nXStart = rFormat.GetAbsLSpace() / nWidthRelation; + nTextOffset = rFormat.GetCharTextDistance() / nWidthRelation; + nNumberXPos = nXStart; + const tools::Long nFirstLineOffset = (-rFormat.GetFirstLineOffset()) / nWidthRelation; + + if(nFirstLineOffset <= nNumberXPos) + nNumberXPos -= nFirstLineOffset; + else + nNumberXPos = 0; + } + else if (rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT) + { + const tools::Long nTmpNumberXPos((rFormat.GetIndentAt() + rFormat.GetFirstLineIndent()) / nWidthRelation); + nNumberXPos = (nTmpNumberXPos < 0) ? 0 : nTmpNumberXPos; + } + + tools::Long nBulletWidth = 0; + if (SVX_NUM_BITMAP == rFormat.GetNumberingType()) + { + nBulletWidth = lcl_DrawGraphic(*pVDev, rFormat, nNumberXPos, + nYStart, nWidthRelation); + } + else if (SVX_NUM_CHAR_SPECIAL == rFormat.GetNumberingType()) + { + nBulletWidth = lcl_DrawBullet(pVDev.get(), rFormat, nNumberXPos, + nYStart, aStdFont.GetFontSize()); + } + else + { + pVDev->SetFont(aStdFont); + if(pActNum->IsContinusNum()) + aNumVector[nLevel] = nPreNum; + OUString aText(pActNum->MakeNumString( aNumVector )); + pVDev->DrawText( Point(nNumberXPos, nYStart), aText ); + nBulletWidth = pVDev->GetTextWidth(aText); + nPreNum++; + } + if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT && + rFormat.GetLabelFollowedBy() == SvxNumberFormat::SPACE ) + { + pVDev->SetFont(aStdFont); + OUString aText(' '); + pVDev->DrawText( Point(nNumberXPos, nYStart), aText ); + nBulletWidth += pVDev->GetTextWidth(aText); + } + + tools::Long nTextXPos(0); + if (rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION) + { + nTextXPos = nXStart; + if (nTextOffset < 0) + nTextXPos = nTextXPos + nTextOffset; + if (nNumberXPos + nBulletWidth + nTextOffset > nTextXPos) + nTextXPos = nNumberXPos + nBulletWidth + nTextOffset; + } + else if (rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT) + { + switch (rFormat.GetLabelFollowedBy()) + { + case SvxNumberFormat::LISTTAB: + { + nTextXPos = rFormat.GetListtabPos() / nWidthRelation; + if (nTextXPos < nNumberXPos + nBulletWidth) + { + nTextXPos = nNumberXPos + nBulletWidth; + } + } + break; + case SvxNumberFormat::SPACE: + case SvxNumberFormat::NOTHING: + case SvxNumberFormat::NEWLINE: + { + nTextXPos = nNumberXPos + nBulletWidth; + } + break; + } + + nXStart = rFormat.GetIndentAt() / nWidthRelation; + } + + tools::Rectangle aRect1(Point(nTextXPos, nYStart + nFontHeight / 2), Size(aSize.Width() / 2, 2)); + pVDev->SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetWindowColor()); // COL_BLACK ); + pVDev->DrawRect(aRect1); + + tools::Rectangle aRect2(Point(nXStart, nYStart + nLineHeight + nFontHeight / 2), Size(aSize.Width() / 2, 2)); + pVDev->DrawRect(aRect2); + nYStart += 2 * nLineHeight; + } + } + else + { + SwNumberTree::tNumberVector aNumVector; + const tools::Long nLineHeight = nFontHeight * 3 / 2; + for (sal_uInt8 nLevel = 0; nLevel < MAXLEVEL; ++nLevel, nYStart = nYStart + nYStep) + { + const SwNumFormat &rFormat = pActNum->Get(nLevel); + aNumVector.push_back(rFormat.GetStart()); + tools::Long nXStart(0); + if (rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION) + { + nXStart = rFormat.GetAbsLSpace() / nWidthRelation; + } + else if (rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT) + { + const tools::Long nTmpXStart((rFormat.GetIndentAt() + rFormat.GetFirstLineIndent() ) / nWidthRelation); + nXStart = (nTmpXStart < 0) ? 0 : nTmpXStart; + } + nXStart /= 2; + nXStart += 2; + tools::Long nTextOffset; + if (SVX_NUM_BITMAP == rFormat.GetNumberingType()) + { + lcl_DrawGraphic(*pVDev, rFormat, nXStart, nYStart, nWidthRelation); + nTextOffset = nLineHeight + nXStep; + } + else if (SVX_NUM_CHAR_SPECIAL == rFormat.GetNumberingType()) + { + nTextOffset = lcl_DrawBullet(pVDev.get(), rFormat, nXStart, nYStart, aStdFont.GetFontSize()); + nTextOffset += nXStep; + } + else + { + pVDev->SetFont(aStdFont); + if (pActNum->IsContinusNum()) + aNumVector[nLevel] = nPreNum; + OUString aText(pActNum->MakeNumString( aNumVector )); + pVDev->DrawText( Point(nXStart, nYStart), aText ); + nTextOffset = pVDev->GetTextWidth(aText) + nXStep; + nPreNum++; + } + pVDev->SetFont(aStdFont); + pVDev->DrawText( + Point(nXStart + nTextOffset, nYStart), + (pOutlineNames == nullptr + ? utl::ConfigManager::getProductName() + : pOutlineNames[nLevel])); + } + } + } + rRenderContext.DrawOutDev(Point(0,0), aSize, Point(0,0), aSize, *pVDev); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/pgfnote.cxx b/sw/source/ui/misc/pgfnote.cxx new file mode 100644 index 000000000..fa94ea19e --- /dev/null +++ b/sw/source/ui/misc/pgfnote.cxx @@ -0,0 +1,313 @@ +/* -*- 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 <cmdid.h> +#include <fmtfsize.hxx> +#include <hintids.hxx> +#include <svtools/unitconv.hxx> +#include <vcl/fieldvalues.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/syslocale.hxx> +#include <editeng/borderline.hxx> +#include <editeng/sizeitem.hxx> +#include <svx/pageitem.hxx> +#include <svl/eitem.hxx> +#include <editeng/ulspitem.hxx> +#include <uitool.hxx> +#include <pagedesc.hxx> +#include <pgfnote.hxx> +#include <uiitems.hxx> + +#include <memory> + +using namespace ::com::sun::star; + +const WhichRangesContainer SwFootNotePage::aPageRg(svl::Items<FN_PARAM_FTN_INFO, FN_PARAM_FTN_INFO>); + +// handler to switch between the different possibilities how the footnote +// region's height can be set. +IMPL_LINK_NOARG(SwFootNotePage, HeightPage, weld::Toggleable&, void) +{ + if (m_xMaxHeightPageBtn->get_active()) + m_xMaxHeightEdit->set_sensitive(false); +} + +IMPL_LINK_NOARG(SwFootNotePage, HeightMetric, weld::Toggleable&, void) +{ + if (m_xMaxHeightBtn->get_active()) + { + m_xMaxHeightEdit->set_sensitive(true); + m_xMaxHeightEdit->grab_focus(); + } +} + +// handler limit values +IMPL_LINK_NOARG(SwFootNotePage, HeightModify, weld::MetricSpinButton&, void) +{ + m_xMaxHeightEdit->set_max(m_xMaxHeightEdit->normalize(lMaxHeight - + (m_xDistEdit->denormalize(m_xDistEdit->get_value(FieldUnit::TWIP)) + + m_xLineDistEdit->denormalize(m_xLineDistEdit->get_value(FieldUnit::TWIP)))), + FieldUnit::TWIP); + if (m_xMaxHeightEdit->get_value(FieldUnit::NONE) < 0) + m_xMaxHeightEdit->set_value(0, FieldUnit::NONE); + m_xDistEdit->set_max(m_xDistEdit->normalize(lMaxHeight - + (m_xMaxHeightEdit->denormalize(m_xMaxHeightEdit->get_value(FieldUnit::TWIP)) + + m_xLineDistEdit->denormalize(m_xLineDistEdit->get_value(FieldUnit::TWIP)))), + FieldUnit::TWIP); + if (m_xDistEdit->get_value(FieldUnit::NONE) < 0) + m_xDistEdit->set_value(0, FieldUnit::NONE); + m_xLineDistEdit->set_max(m_xLineDistEdit->normalize(lMaxHeight - + (m_xMaxHeightEdit->denormalize(m_xMaxHeightEdit->get_value(FieldUnit::TWIP)) + + m_xDistEdit->denormalize(m_xDistEdit->get_value(FieldUnit::TWIP)))), + FieldUnit::TWIP); +} + +IMPL_LINK_NOARG(SwFootNotePage, LineWidthChanged_Impl, weld::MetricSpinButton&, void) +{ + sal_Int64 nVal = m_xLineWidthEdit->get_value(FieldUnit::NONE); + nVal = static_cast<sal_Int64>(vcl::ConvertDoubleValue( + nVal, + m_xLineWidthEdit->get_digits(), + m_xLineWidthEdit->get_unit(), MapUnit::MapTwip )); + m_xLineTypeBox->SetWidth(nVal); +} + +IMPL_LINK(SwFootNotePage, LineColorSelected_Impl, ColorListBox&, rColorBox, void) +{ + m_xLineTypeBox->SetColor(rColorBox.GetSelectEntryColor()); +} + +SwFootNotePage::SwFootNotePage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/footnoteareapage.ui", "FootnoteAreaPage", &rSet) + , lMaxHeight(0) + , m_xMaxHeightPageBtn(m_xBuilder->weld_radio_button("maxheightpage")) + , m_xMaxHeightBtn(m_xBuilder->weld_radio_button("maxheight")) + , m_xMaxHeightEdit(m_xBuilder->weld_metric_spin_button("maxheightsb", FieldUnit::CM)) + , m_xDistEdit(m_xBuilder->weld_metric_spin_button("spacetotext", FieldUnit::CM)) + , m_xLinePosBox(m_xBuilder->weld_combo_box("position")) + , m_xLineTypeBox(new SvtLineListBox(m_xBuilder->weld_menu_button("style"))) + , m_xLineWidthEdit(m_xBuilder->weld_metric_spin_button("thickness", FieldUnit::POINT)) + , m_xLineColorBox(new ColorListBox(m_xBuilder->weld_menu_button("color"), + [this]{ return GetDialogController()->getDialog(); })) + , m_xLineLengthEdit(m_xBuilder->weld_metric_spin_button("length", FieldUnit::PERCENT)) + , m_xLineDistEdit(m_xBuilder->weld_metric_spin_button("spacingtocontents", FieldUnit::CM)) +{ + SetExchangeSupport(); + FieldUnit aMetric = ::GetDfltMetric(false); + ::SetFieldUnit(*m_xMaxHeightEdit, aMetric); + ::SetFieldUnit(*m_xDistEdit, aMetric); + ::SetFieldUnit(*m_xLineDistEdit, aMetric); + MeasurementSystem eSys = SvtSysLocale().GetLocaleData().getMeasurementSystemEnum(); + tools::Long nHeightValue = MeasurementSystem::Metric != eSys ? 1440 : 1134; + m_xMaxHeightEdit->set_value(m_xMaxHeightEdit->normalize(nHeightValue),FieldUnit::TWIP); +} + +SwFootNotePage::~SwFootNotePage() +{ + m_xLineColorBox.reset(); + m_xLineTypeBox.reset(); +} + +std::unique_ptr<SfxTabPage> SwFootNotePage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet) +{ + return std::make_unique<SwFootNotePage>(pPage, pController, *rSet); +} + +void SwFootNotePage::Reset(const SfxItemSet *rSet) +{ + // if no example exists, otherwise Init here in Activate + std::optional<SwPageFootnoteInfo> pDefFootnoteInfo; + const SwPageFootnoteInfo* pFootnoteInfo; + const SfxPoolItem* pItem = SfxTabPage::GetItem(*rSet, FN_PARAM_FTN_INFO); + if( pItem ) + { + pFootnoteInfo = &static_cast<const SwPageFootnoteInfoItem*>(pItem)->GetPageFootnoteInfo(); + } + else + { + // when "standard" is being activated the footnote item is deleted, + // that's why a footnote structure has to be created here + pDefFootnoteInfo.emplace(); + pFootnoteInfo = &*pDefFootnoteInfo; + } + // footnote area's height + SwTwips lHeight = pFootnoteInfo->GetHeight(); + if(lHeight) + { + m_xMaxHeightEdit->set_value(m_xMaxHeightEdit->normalize(lHeight),FieldUnit::TWIP); + m_xMaxHeightBtn->set_active(true); + } + else + { + m_xMaxHeightPageBtn->set_active(true); + m_xMaxHeightEdit->set_sensitive(false); + } + m_xMaxHeightPageBtn->connect_toggled(LINK(this,SwFootNotePage,HeightPage)); + m_xMaxHeightBtn->connect_toggled(LINK(this,SwFootNotePage,HeightMetric)); + Link<weld::MetricSpinButton&,void> aLk = LINK(this, SwFootNotePage, HeightModify); + m_xMaxHeightEdit->connect_value_changed(aLk); + m_xDistEdit->connect_value_changed(aLk); + m_xLineDistEdit->connect_value_changed(aLk); + + // Separator width + m_xLineWidthEdit->connect_value_changed(LINK(this, SwFootNotePage, LineWidthChanged_Impl)); + + sal_Int64 nWidthPt = static_cast<sal_Int64>(vcl::ConvertDoubleValue( + sal_Int64( pFootnoteInfo->GetLineWidth() ), m_xLineWidthEdit->get_digits(), + MapUnit::MapTwip, m_xLineWidthEdit->get_unit( ) )); + m_xLineWidthEdit->set_value(nWidthPt, FieldUnit::NONE); + + // Separator style + m_xLineTypeBox->SetSourceUnit( FieldUnit::TWIP ); + + m_xLineTypeBox->InsertEntry( + ::editeng::SvxBorderLine::getWidthImpl(SvxBorderLineStyle::SOLID), + SvxBorderLineStyle::SOLID ); + m_xLineTypeBox->InsertEntry( + ::editeng::SvxBorderLine::getWidthImpl(SvxBorderLineStyle::DOTTED), + SvxBorderLineStyle::DOTTED ); + m_xLineTypeBox->InsertEntry( + ::editeng::SvxBorderLine::getWidthImpl(SvxBorderLineStyle::DASHED), + SvxBorderLineStyle::DASHED ); + m_xLineTypeBox->SetWidth( pFootnoteInfo->GetLineWidth( ) ); + m_xLineTypeBox->SelectEntry( pFootnoteInfo->GetLineStyle() ); + + // Separator Color + m_xLineColorBox->SelectEntry(pFootnoteInfo->GetLineColor()); + m_xLineColorBox->SetSelectHdl(LINK(this, SwFootNotePage, LineColorSelected_Impl)); + m_xLineTypeBox->SetColor(pFootnoteInfo->GetLineColor()); + + // position + m_xLinePosBox->set_active(static_cast<sal_Int32>(pFootnoteInfo->GetAdj())); + + // width + Fraction aTmp( 100, 1 ); + aTmp *= pFootnoteInfo->GetWidth(); + m_xLineLengthEdit->set_value(static_cast<tools::Long>(aTmp), FieldUnit::PERCENT); + + // gap footnote area + m_xDistEdit->set_value(m_xDistEdit->normalize(pFootnoteInfo->GetTopDist()), FieldUnit::TWIP); + m_xLineDistEdit->set_value( + m_xLineDistEdit->normalize(pFootnoteInfo->GetBottomDist()), FieldUnit::TWIP); + ActivatePage( *rSet ); +} + +// stuff attributes into the set, when OK +bool SwFootNotePage::FillItemSet(SfxItemSet *rSet) +{ + SwPageFootnoteInfoItem aItem(GetItemSet().Get(FN_PARAM_FTN_INFO)); + + // that's the original + SwPageFootnoteInfo &rFootnoteInfo = aItem.GetPageFootnoteInfo(); + + // footnote area's height + if (m_xMaxHeightBtn->get_active()) + rFootnoteInfo.SetHeight( static_cast< SwTwips >( + m_xMaxHeightEdit->denormalize(m_xMaxHeightEdit->get_value(FieldUnit::TWIP)))); + else + rFootnoteInfo.SetHeight(0); + + // gap footnote area + rFootnoteInfo.SetTopDist( static_cast< SwTwips >( + m_xDistEdit->denormalize(m_xDistEdit->get_value(FieldUnit::TWIP)))); + rFootnoteInfo.SetBottomDist( static_cast< SwTwips >( + m_xLineDistEdit->denormalize(m_xLineDistEdit->get_value(FieldUnit::TWIP)))); + + // Separator style + rFootnoteInfo.SetLineStyle(m_xLineTypeBox->GetSelectEntryStyle()); + + // Separator width + sal_Int64 nWidth = m_xLineWidthEdit->get_value(FieldUnit::NONE); + nWidth = static_cast<tools::Long>(vcl::ConvertDoubleValue( + nWidth, + m_xLineWidthEdit->get_digits(), + m_xLineWidthEdit->get_unit(), MapUnit::MapTwip )); + rFootnoteInfo.SetLineWidth( nWidth ); + + // Separator color + rFootnoteInfo.SetLineColor(m_xLineColorBox->GetSelectEntryColor()); + + // Position + rFootnoteInfo.SetAdj(static_cast<css::text::HorizontalAdjust>(m_xLinePosBox->get_active())); + + // Width + rFootnoteInfo.SetWidth(Fraction(m_xLineLengthEdit->get_value(FieldUnit::PERCENT), 100)); + + const SfxPoolItem* pOldItem; + if(nullptr == (pOldItem = GetOldItem( *rSet, FN_PARAM_FTN_INFO )) || + aItem != *pOldItem ) + rSet->Put(aItem); + + return true; +} + +void SwFootNotePage::ActivatePage(const SfxItemSet& rSet) +{ + auto const & rSize = rSet.Get( RES_FRM_SIZE ); + lMaxHeight = rSize.GetHeight(); + + if( const SvxSetItem* pHeaderSetItem = rSet.GetItemIfSet( rSet.GetPool()->GetWhich( SID_ATTR_PAGE_HEADERSET), false ) ) + { + const SfxItemSet& rHeaderSet = pHeaderSetItem->GetItemSet(); + const SfxBoolItem& rHeaderOn = + rHeaderSet.Get( rSet.GetPool()->GetWhich( SID_ATTR_PAGE_ON ) ); + + if ( rHeaderOn.GetValue() ) + { + const SvxSizeItem& rSizeItem = + rHeaderSet.Get(rSet.GetPool()->GetWhich(SID_ATTR_PAGE_SIZE)); + lMaxHeight -= rSizeItem.GetSize().Height(); + } + } + + if( const SvxSetItem* pFooterSetItem = rSet.GetItemIfSet( rSet.GetPool()->GetWhich( SID_ATTR_PAGE_FOOTERSET), + false ) ) + { + const SfxItemSet& rFooterSet = pFooterSetItem->GetItemSet(); + const SfxBoolItem& rFooterOn = rFooterSet.Get( SID_ATTR_PAGE_ON ); + + if ( rFooterOn.GetValue() ) + { + const SvxSizeItem& rSizeItem = + rFooterSet.Get( rSet.GetPool()->GetWhich( SID_ATTR_PAGE_SIZE ) ); + lMaxHeight -= rSizeItem.GetSize().Height(); + } + } + + if ( const SvxULSpaceItem* pSpaceItem = rSet.GetItemIfSet( RES_UL_SPACE , false ) ) + { + lMaxHeight -= pSpaceItem->GetUpper() + pSpaceItem->GetLower(); + } + + lMaxHeight *= 8; + lMaxHeight /= 10; + + // set maximum values + HeightModify(*m_xMaxHeightEdit); +} + +DeactivateRC SwFootNotePage::DeactivatePage( SfxItemSet* _pSet) +{ + if(_pSet) + FillItemSet(_pSet); + + return DeactivateRC::LeavePage; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/pggrid.cxx b/sw/source/ui/misc/pggrid.cxx new file mode 100644 index 000000000..c483c4f47 --- /dev/null +++ b/sw/source/ui/misc/pggrid.cxx @@ -0,0 +1,551 @@ +/* -*- 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 <cmdid.h> +#include <hintids.hxx> +#include <svx/colorbox.hxx> +#include <editeng/sizeitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <svx/ruler.hxx> +#include <pggrid.hxx> +#include <tgrditem.hxx> +#include <svx/pageitem.hxx> + +#include <wrtsh.hxx> +#include <doc.hxx> +#include <swmodule.hxx> +#include <view.hxx> + +constexpr tools::Long constTwips_5mm = o3tl::toTwips(5, o3tl::Length::mm); + +SwTextGridPage::SwTextGridPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/textgridpage.ui", "TextGridPage", &rSet) + , m_nRubyUserValue(0) + , m_bRubyUserValue(false) + , m_aPageSize(constTwips_5mm, constTwips_5mm) + , m_bVertical(false) + , m_bSquaredMode(false) + , m_bHRulerChanged(false) + , m_bVRulerChanged(false) + , m_xNoGridRB(m_xBuilder->weld_radio_button("radioRB_NOGRID")) + , m_xLinesGridRB(m_xBuilder->weld_radio_button("radioRB_LINESGRID")) + , m_xCharsGridRB(m_xBuilder->weld_radio_button("radioRB_CHARSGRID")) + , m_xSnapToCharsCB(m_xBuilder->weld_check_button("checkCB_SNAPTOCHARS")) + , m_xExampleWN(new weld::CustomWeld(*m_xBuilder, "drawingareaWN_EXAMPLE", m_aExampleWN)) + , m_xLayoutFL(m_xBuilder->weld_widget("frameFL_LAYOUT")) + , m_xLinesPerPageNF(m_xBuilder->weld_spin_button("spinNF_LINESPERPAGE")) + , m_xLinesRangeFT(m_xBuilder->weld_label("labelFT_LINERANGE")) + , m_xTextSizeMF(m_xBuilder->weld_metric_spin_button("spinMF_TEXTSIZE", FieldUnit::POINT)) + , m_xCharsPerLineFT(m_xBuilder->weld_label("labelFT_CHARSPERLINE")) + , m_xCharsPerLineNF(m_xBuilder->weld_spin_button("spinNF_CHARSPERLINE")) + , m_xCharsRangeFT(m_xBuilder->weld_label("labelFT_CHARRANGE")) + , m_xCharWidthFT(m_xBuilder->weld_label("labelFT_CHARWIDTH")) + , m_xCharWidthMF(m_xBuilder->weld_metric_spin_button("spinMF_CHARWIDTH", FieldUnit::POINT)) + , m_xRubySizeFT(m_xBuilder->weld_label("labelFT_RUBYSIZE")) + , m_xRubySizeMF(m_xBuilder->weld_metric_spin_button("spinMF_RUBYSIZE", FieldUnit::POINT)) + , m_xRubyBelowCB(m_xBuilder->weld_check_button("checkCB_RUBYBELOW")) + , m_xDisplayFL(m_xBuilder->weld_widget("frameFL_DISPLAY")) + , m_xDisplayCB(m_xBuilder->weld_check_button("checkCB_DISPLAY")) + , m_xPrintCB(m_xBuilder->weld_check_button("checkCB_PRINT")) + , m_xColorLB(new ColorListBox(m_xBuilder->weld_menu_button("listLB_COLOR"), + [this]{ return GetDialogController()->getDialog(); })) +{ + Link<weld::SpinButton&,void> aLink = LINK(this, SwTextGridPage, CharorLineChangedHdl); + m_xCharsPerLineNF->connect_value_changed(aLink); + m_xLinesPerPageNF->connect_value_changed(aLink); + + Link<weld::MetricSpinButton&,void> aSizeLink = LINK(this, SwTextGridPage, TextSizeChangedHdl); + m_xTextSizeMF->connect_value_changed(aSizeLink); + m_xRubySizeMF->connect_value_changed(aSizeLink); + m_xCharWidthMF->connect_value_changed(aSizeLink); + + Link<weld::Toggleable&,void> aGridTypeHdl = LINK(this, SwTextGridPage, GridTypeHdl); + m_xNoGridRB->connect_toggled(aGridTypeHdl); + m_xLinesGridRB->connect_toggled(aGridTypeHdl); + m_xCharsGridRB->connect_toggled(aGridTypeHdl); + + m_xColorLB->SetSelectHdl(LINK(this, SwTextGridPage, ColorModifyHdl)); + m_xPrintCB->connect_toggled(LINK(this, SwTextGridPage, GridModifyClickHdl)); + m_xRubyBelowCB->connect_toggled(LINK(this, SwTextGridPage, GridModifyClickHdl)); + + m_xDisplayCB->connect_toggled(LINK(this, SwTextGridPage, DisplayGridHdl)); + + //Get the default paper mode + if (SwView *pView = GetActiveView()) + { + SwWrtShell* pSh = pView->GetWrtShellPtr(); + if( pSh ) + { + m_bSquaredMode = pSh->GetDoc()->IsSquaredPageMode(); + } + } + if( m_bSquaredMode ) + { + + m_xRubySizeFT->show(); + m_xRubySizeMF->show(); + m_xRubyBelowCB->show(); + m_xSnapToCharsCB->hide(); + m_xCharWidthFT->hide(); + m_xCharWidthMF->hide(); + } + else + { + m_xRubySizeFT->hide(); + m_xRubySizeMF->hide(); + m_xRubyBelowCB->hide(); + m_xSnapToCharsCB->show(); + m_xCharWidthFT->show(); + m_xCharWidthMF->show(); + } +} + +SwTextGridPage::~SwTextGridPage() +{ + m_xColorLB.reset(); +} + +std::unique_ptr<SfxTabPage> SwTextGridPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet) +{ + return std::make_unique<SwTextGridPage>(pPage, pController, *rSet); +} + +bool SwTextGridPage::FillItemSet(SfxItemSet *rSet) +{ + bool bRet = false; + if (m_xNoGridRB->get_state_changed_from_saved() || + m_xLinesGridRB->get_state_changed_from_saved() || + m_xLinesPerPageNF->get_value_changed_from_saved() || + m_xTextSizeMF->get_value_changed_from_saved() || + m_xCharsPerLineNF->get_value_changed_from_saved() || + m_xSnapToCharsCB->get_state_changed_from_saved() || + m_xRubySizeMF->get_value_changed_from_saved() || + m_xCharWidthMF->get_value_changed_from_saved() || + m_xRubyBelowCB->get_state_changed_from_saved() || + m_xDisplayCB->get_state_changed_from_saved() || + m_xPrintCB->get_state_changed_from_saved() || + m_xColorLB->IsValueChangedFromSaved()) + { + PutGridItem(*rSet); + bRet = true; + } + + // draw ticks of ruler + if (SwView * pView = GetActiveView()) + { + if ( m_bHRulerChanged ) + pView->GetHRuler().DrawTicks(); + if ( m_bVRulerChanged ) + pView->GetVRuler().DrawTicks(); + } + return bRet; +} + +void SwTextGridPage::Reset(const SfxItemSet *rSet) +{ + sal_Int32 nLinesPerPage = 0; + + if(SfxItemState::DEFAULT <= rSet->GetItemState(RES_TEXTGRID)) + { + const SwTextGridItem& rGridItem = rSet->Get(RES_TEXTGRID); + weld::RadioButton* pButton = nullptr; + switch(rGridItem.GetGridType()) + { + case GRID_NONE : pButton = m_xNoGridRB.get(); break; + case GRID_LINES_ONLY : pButton = m_xLinesGridRB.get(); break; + default: pButton = m_xCharsGridRB.get(); + } + pButton->set_active(true); + m_xDisplayCB->set_active(rGridItem.IsDisplayGrid()); + GridTypeHdl(*pButton); + m_xSnapToCharsCB->set_active(rGridItem.IsSnapToChars()); + nLinesPerPage = rGridItem.GetLines(); + + SetLinesOrCharsRanges(*m_xLinesRangeFT , m_xLinesPerPageNF->get_max()); + m_nRubyUserValue = rGridItem.GetBaseHeight(); + m_bRubyUserValue = true; + m_xTextSizeMF->set_value(m_xTextSizeMF->normalize(m_nRubyUserValue), FieldUnit::TWIP); + m_xRubySizeMF->set_value(m_xRubySizeMF->normalize(rGridItem.GetRubyHeight()), FieldUnit::TWIP); + m_xCharWidthMF->set_value(m_xCharWidthMF->normalize(rGridItem.GetBaseWidth()), FieldUnit::TWIP); + m_xRubyBelowCB->set_active(rGridItem.IsRubyTextBelow()); + m_xPrintCB->set_active(rGridItem.IsPrintGrid()); + m_xColorLB->SelectEntry(rGridItem.GetColor()); + } + UpdatePageSize(*rSet); + + if (nLinesPerPage > 0) + m_xLinesPerPageNF->set_value(nLinesPerPage); + + m_xNoGridRB->save_state(); + m_xLinesGridRB->save_state(); + m_xSnapToCharsCB->save_state(); + m_xLinesPerPageNF->save_value(); + m_xTextSizeMF->save_value(); + m_xCharsPerLineNF->save_value(); + m_xRubySizeMF->save_value(); + m_xCharWidthMF->save_value(); + m_xRubyBelowCB->save_state(); + m_xDisplayCB->save_state(); + m_xPrintCB->save_state(); + m_xColorLB->SaveValue(); +} + +void SwTextGridPage::ActivatePage( const SfxItemSet& rSet ) +{ + m_aExampleWN.Hide(); + m_aExampleWN.UpdateExample(rSet); + UpdatePageSize(rSet); + m_aExampleWN.Show(); + m_aExampleWN.Invalidate(); +} + +DeactivateRC SwTextGridPage::DeactivatePage( SfxItemSet* ) +{ + return DeactivateRC::LeavePage; +} + +void SwTextGridPage::PutGridItem(SfxItemSet& rSet) +{ + SwTextGridItem aGridItem; + aGridItem.SetGridType(m_xNoGridRB->get_active() ? GRID_NONE : + m_xLinesGridRB->get_active() ? GRID_LINES_ONLY : GRID_LINES_CHARS ); + aGridItem.SetSnapToChars(m_xSnapToCharsCB->get_active()); + aGridItem.SetLines( static_cast< sal_uInt16 >(m_xLinesPerPageNF->get_value()) ); + aGridItem.SetBaseHeight( static_cast< sal_uInt16 >( + m_bRubyUserValue ? m_nRubyUserValue : + m_xTextSizeMF->denormalize(m_xTextSizeMF->get_value(FieldUnit::TWIP))) ); + // Tdf#151544: set ruby height from the value get from UI only when in square page mode. + // When in normal mode, the ruby height should be zero. + if (m_bSquaredMode) + aGridItem.SetRubyHeight(static_cast<sal_uInt16>(m_xRubySizeMF->denormalize(m_xRubySizeMF->get_value(FieldUnit::TWIP)))); + else + aGridItem.SetRubyHeight(0); + aGridItem.SetBaseWidth( static_cast< sal_uInt16 >(m_xCharWidthMF->denormalize(m_xCharWidthMF->get_value(FieldUnit::TWIP))) ); + aGridItem.SetRubyTextBelow(m_xRubyBelowCB->get_active()); + aGridItem.SetSquaredMode(m_bSquaredMode); + aGridItem.SetDisplayGrid(m_xDisplayCB->get_active()); + aGridItem.SetPrintGrid(m_xPrintCB->get_active()); + aGridItem.SetColor(m_xColorLB->GetSelectEntryColor()); + rSet.Put(aGridItem); + + SwView * pView = ::GetActiveView(); + if (pView && aGridItem.GetGridType() != GRID_NONE) + { + if ( aGridItem.GetGridType() == GRID_LINES_CHARS ) + { + m_bHRulerChanged = true; + } + m_bVRulerChanged = true; + pView->GetHRuler().SetCharWidth(static_cast<tools::Long>(m_xCharWidthMF->get_value(FieldUnit::TWIP)/56.7)); + pView->GetVRuler().SetLineHeight(static_cast<tools::Long>(m_xTextSizeMF->get_value(FieldUnit::TWIP)/56.7)); + } +} + +void SwTextGridPage::UpdatePageSize(const SfxItemSet& rSet) +{ + if( SfxItemState::UNKNOWN != rSet.GetItemState( RES_FRAMEDIR )) + { + const SvxFrameDirectionItem& rDirItem = + rSet.Get(RES_FRAMEDIR); + m_bVertical = rDirItem.GetValue() == SvxFrameDirection::Vertical_RL_TB|| + rDirItem.GetValue() == SvxFrameDirection::Vertical_LR_TB; + } + + if( SfxItemState::SET != rSet.GetItemState( SID_ATTR_PAGE_SIZE )) + return; + + const SvxSizeItem& rSize = rSet.Get(SID_ATTR_PAGE_SIZE); + const SvxLRSpaceItem& rLRSpace = rSet.Get( RES_LR_SPACE ); + const SvxULSpaceItem& rULSpace = rSet.Get( RES_UL_SPACE ); + const SvxBoxItem& rBox = rSet.Get(RES_BOX); + sal_Int32 nDistanceLR = rLRSpace.GetLeft() + rLRSpace.GetRight(); + sal_Int32 nDistanceUL = rULSpace.GetUpper() + rULSpace.GetLower(); + + for( const TypedWhichId<SvxSetItem> & nId : { SID_ATTR_PAGE_HEADERSET, SID_ATTR_PAGE_FOOTERSET }) + { + if( const SvxSetItem* pItem = rSet.GetItemIfSet( nId, false ) ) + { + const SfxItemSet& rExtraSet = pItem->GetItemSet(); + const SfxBoolItem& rOn = + rExtraSet.Get( rSet.GetPool()->GetWhich( SID_ATTR_PAGE_ON ) ); + + if ( rOn.GetValue() ) + { + const SvxSizeItem& rSizeItem = + rExtraSet.Get(rSet.GetPool()->GetWhich(SID_ATTR_PAGE_SIZE)); + nDistanceUL += rSizeItem.GetSize().Height(); + } + } + } + + sal_Int32 nValue1 = rSize.GetSize().Height() - nDistanceUL - + rBox.GetDistance(SvxBoxItemLine::TOP) - + rBox.GetDistance(SvxBoxItemLine::BOTTOM); + sal_Int32 nValue2 = rSize.GetSize().Width() - nDistanceLR - + rBox.GetDistance(SvxBoxItemLine::LEFT) - + rBox.GetDistance(SvxBoxItemLine::RIGHT); + if(m_bVertical) + { + m_aPageSize.setWidth( nValue1 ); + m_aPageSize.setHeight( nValue2 ); + } + else + { + m_aPageSize.setWidth( nValue2 ); + m_aPageSize.setHeight( nValue1 ); + } + + sal_Int32 nTextSize = static_cast< sal_Int32 >(m_bRubyUserValue ? + m_nRubyUserValue : + m_xTextSizeMF->denormalize(m_xTextSizeMF->get_value(FieldUnit::TWIP))); + + if ( m_bSquaredMode ) + { + sal_Int32 nCharsPerLine = m_aPageSize.Width() / nTextSize; + m_xCharsPerLineNF->set_max(nCharsPerLine); + m_xCharsPerLineNF->set_sensitive(nCharsPerLine != 0); + m_xCharsPerLineNF->set_value(nCharsPerLine); + sal_Int32 nMaxLines = m_aPageSize.Height() / + ( m_xTextSizeMF->denormalize(m_xTextSizeMF->get_value(FieldUnit::TWIP)) + + m_xRubySizeMF->denormalize(m_xRubySizeMF->get_value(FieldUnit::TWIP))); + m_xLinesPerPageNF->set_max(nMaxLines); + m_xLinesPerPageNF->set_sensitive(nMaxLines != 0); + SetLinesOrCharsRanges( *m_xCharsRangeFT , m_xCharsPerLineNF->get_max() ); + SetLinesOrCharsRanges( *m_xLinesRangeFT , m_xLinesPerPageNF->get_max() ); + } + else + { + sal_Int32 nTextWidth = static_cast< sal_Int32 >(m_xCharWidthMF->denormalize(m_xCharWidthMF->get_value(FieldUnit::TWIP))); + m_xLinesPerPageNF->set_value(m_aPageSize.Height() / nTextSize); + if (nTextWidth) + m_xCharsPerLineNF->set_value(m_aPageSize.Width() / nTextWidth); + else + m_xCharsPerLineNF->set_value(45); + SetLinesOrCharsRanges( *m_xCharsRangeFT , m_xCharsPerLineNF->get_max() ); + SetLinesOrCharsRanges( *m_xLinesRangeFT , m_xLinesPerPageNF->get_max() ); + } +} + +void SwTextGridPage::SetLinesOrCharsRanges(weld::Label& rField, const sal_Int32 nValue ) +{ + OUString aFieldStr = "( 1 -" + OUString::number(nValue) + " )"; + rField.set_label(aFieldStr); +} + +WhichRangesContainer SwTextGridPage::GetRanges() +{ + return WhichRangesContainer(svl::Items<RES_TEXTGRID, RES_TEXTGRID>); +} + +IMPL_LINK(SwTextGridPage, CharorLineChangedHdl, weld::SpinButton&, rField, void) +{ + //if in squared mode + if ( m_bSquaredMode ) + { + if (m_xCharsPerLineNF.get() == &rField) + { + auto nValue = m_xCharsPerLineNF->get_value(); + assert(nValue && "div-by-zero"); + auto nWidth = m_aPageSize.Width() / nValue; + m_xTextSizeMF->set_value(m_xTextSizeMF->normalize(nWidth), FieldUnit::TWIP); + //prevent rounding errors in the MetricField by saving the used value + m_nRubyUserValue = nWidth; + m_bRubyUserValue = true; + + } + //set maximum line per page + { + sal_Int32 nMaxLines = static_cast< sal_Int32 >(m_aPageSize.Height() / + ( m_xTextSizeMF->denormalize(m_xTextSizeMF->get_value(FieldUnit::TWIP)) + + m_xRubySizeMF->denormalize(m_xRubySizeMF->get_value(FieldUnit::TWIP)))); + m_xLinesPerPageNF->set_max(nMaxLines); + m_xLinesPerPageNF->set_sensitive(nMaxLines != 0); + } + SetLinesOrCharsRanges( *m_xLinesRangeFT , m_xLinesPerPageNF->get_max() ); + SetLinesOrCharsRanges( *m_xCharsRangeFT , m_xCharsPerLineNF->get_max() ); + } + else//in normal mode + { + if (m_xLinesPerPageNF.get() == &rField) + { + auto nValue = m_xLinesPerPageNF->get_value(); + assert(nValue && "div-by-zero"); + auto nHeight = m_aPageSize.Height() / nValue; + m_xTextSizeMF->set_value(m_xTextSizeMF->normalize(nHeight), FieldUnit::TWIP); + SetLinesOrCharsRanges( *m_xLinesRangeFT , m_xLinesPerPageNF->get_max() ); + + m_nRubyUserValue = nHeight; + m_bRubyUserValue = true; + } + else if (m_xCharsPerLineNF.get() == &rField) + { + auto nValue = m_xCharsPerLineNF->get_value(); + assert(nValue && "div-by-zero"); + auto nWidth = m_aPageSize.Width() / nValue; + m_xCharWidthMF->set_value(m_xCharWidthMF->normalize(nWidth), FieldUnit::TWIP); + SetLinesOrCharsRanges( *m_xCharsRangeFT , m_xCharsPerLineNF->get_max() ); + } + } + GridModifyHdl(); +} + +IMPL_LINK(SwTextGridPage, TextSizeChangedHdl, weld::MetricSpinButton&, rField, void) +{ + //if in squared mode + if( m_bSquaredMode ) + { + if (m_xTextSizeMF.get() == &rField) + { + m_bRubyUserValue = false; + + // fdo#50941: set maximum characters per line + sal_Int32 nTextSize = static_cast< sal_Int32 >(m_xTextSizeMF->denormalize(m_xTextSizeMF->get_value(FieldUnit::TWIP))); + if (nTextSize > 0) + { + sal_Int32 nMaxChars = m_aPageSize.Width() / nTextSize; + m_xCharsPerLineNF->set_value(nMaxChars); + m_xCharsPerLineNF->set_max(nMaxChars); + m_xCharsPerLineNF->set_sensitive(nMaxChars != 0); + SetLinesOrCharsRanges( *m_xCharsRangeFT , m_xCharsPerLineNF->get_max() ); + } + } + //set maximum line per page + { + sal_Int32 nMaxLines = static_cast< sal_Int32 >(m_aPageSize.Height() / + ( m_xTextSizeMF->denormalize(m_xTextSizeMF->get_value(FieldUnit::TWIP)) + + m_xRubySizeMF->denormalize(m_xRubySizeMF->get_value(FieldUnit::TWIP)))); + m_xLinesPerPageNF->set_max(nMaxLines); + m_xLinesPerPageNF->set_sensitive(nMaxLines != 0); + SetLinesOrCharsRanges( *m_xLinesRangeFT , m_xLinesPerPageNF->get_max() ); + } + } + else + { + if (m_xTextSizeMF.get() == &rField) + { + sal_Int32 nTextSize = static_cast< sal_Int32 >(m_xTextSizeMF->denormalize(m_xTextSizeMF->get_value(FieldUnit::TWIP))); + m_xLinesPerPageNF->set_value(m_aPageSize.Height() / nTextSize); + m_bRubyUserValue = false; + SetLinesOrCharsRanges( *m_xLinesRangeFT , m_xLinesPerPageNF->get_max() ); + } + else if (m_xCharWidthMF.get() == &rField) + { + sal_Int32 nTextWidth = static_cast< sal_Int32 >(m_xCharWidthMF->denormalize(m_xCharWidthMF->get_value(FieldUnit::TWIP))); + sal_Int32 nMaxChar = 45 ; + if (nTextWidth) + nMaxChar = m_aPageSize.Width() / nTextWidth; + m_xCharsPerLineNF->set_value( nMaxChar ); + SetLinesOrCharsRanges( *m_xCharsRangeFT , m_xCharsPerLineNF->get_max() ); + } + //rubySize is disabled + } + GridModifyHdl(); +} + +IMPL_LINK(SwTextGridPage, GridTypeHdl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + + if (m_xNoGridRB.get() == &rButton) + { + // GRID_NONE mode: + // "Layout" and "Display" sections should all be disabled. + m_xLayoutFL->set_sensitive(false); + m_xDisplayFL->set_sensitive(false); + } + else + { + // GRID_LINES_ONLY or GRID_LINES_CHARS mode: + // "Layout" and "Display" sections should all be enabled; + // DisplayGridHdl should be executed; + m_xLayoutFL->set_sensitive(true); + m_xDisplayFL->set_sensitive(true); + DisplayGridHdl(*m_xDisplayCB); + } + + if (m_xCharsGridRB.get() == &rButton) + { + // GRID_LINES_CHARS mode: + // "Snap to character" should be enabled; + // "Characters per line" should be enabled; + // "Characters range" should be enabled; + m_xSnapToCharsCB->set_sensitive(true); + m_xCharsPerLineFT->set_sensitive(true); + m_xCharsPerLineNF->set_sensitive(true); + m_xCharsRangeFT->set_sensitive(true); + m_xCharWidthFT->set_sensitive(true); + m_xCharWidthMF->set_sensitive(true); + } + else + { + // GRID_NONE or GRID_LINES_ONLY mode: + // "Snap to character" should be disabled; + // "Characters per line" should be disabled; + // "Characters range" should be disabled; + m_xSnapToCharsCB->set_sensitive(false); + m_xCharsPerLineFT->set_sensitive(false); + m_xCharsPerLineNF->set_sensitive(false); + m_xCharsRangeFT->set_sensitive(false); + m_xCharWidthFT->set_sensitive(false); + m_xCharWidthMF->set_sensitive(false); + } + + if (m_xNoGridRB.get() != &rButton) + { + // GRID_LINES_ONLY or GRID_LINES_CHARS mode: (additionally) + // TextSizeChangedHdl should be executed to recalculate which dependencies are sensitive. + TextSizeChangedHdl(*m_xTextSizeMF); + } + + GridModifyHdl(); +} + +IMPL_LINK_NOARG(SwTextGridPage, DisplayGridHdl, weld::Toggleable&, void) +{ + bool bChecked = m_xDisplayCB->get_active(); + m_xPrintCB->set_sensitive(bChecked); + m_xPrintCB->set_active(bChecked); +} + +IMPL_LINK_NOARG(SwTextGridPage, GridModifyClickHdl, weld::Toggleable&, void) +{ + GridModifyHdl(); +} + +IMPL_LINK_NOARG(SwTextGridPage, ColorModifyHdl, ColorListBox&, void) +{ + GridModifyHdl(); +} + +void SwTextGridPage::GridModifyHdl() +{ + const SfxItemSet& rOldSet = GetItemSet(); + SfxItemSet aSet(rOldSet); + const SfxItemSet* pExSet = GetDialogExampleSet(); + if(pExSet) + aSet.Put(*pExSet); + PutGridItem(aSet); + m_aExampleWN.UpdateExample(aSet); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/srtdlg.cxx b/sw/source/ui/misc/srtdlg.cxx new file mode 100644 index 000000000..52ca7ba66 --- /dev/null +++ b/sw/source/ui/misc/srtdlg.cxx @@ -0,0 +1,428 @@ +/* -*- 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 <srtdlg.hxx> + +#include <editeng/editids.hrc> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <svl/intitem.hxx> +#include <svx/svxdlg.hxx> +#include <unotools/collatorwrapper.hxx> +#include <svtools/collatorres.hxx> +#include <swwait.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <strings.hrc> +#include <swtable.hxx> +#include <sortopt.hxx> +#include <node.hxx> +#include <tblsel.hxx> +#include <memory> + +static bool bCheck1 = true; +static bool bCheck2 = false; +static bool bCheck3 = false; + +static sal_uInt16 nCol1 = 1; +static sal_uInt16 nCol2 = 1; +static sal_uInt16 nCol3 = 1; + +static sal_uInt16 nType1 = 0; +static sal_uInt16 nType2 = 0; +static sal_uInt16 nType3 = 0; + +static LanguageType nLang = LANGUAGE_NONE; + +static bool bAsc1 = true; +static bool bAsc2 = true; +static bool bAsc3 = true; +static bool bCol = false; +static bool bCsSens= false; + +static sal_Unicode cDeli = '\t'; + +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +// determine lines and columns for table selection +static bool lcl_GetSelTable( SwWrtShell const &rSh, sal_uInt16& rX, sal_uInt16& rY ) +{ + const SwTableNode* pTableNd = rSh.IsCursorInTable(); + if( !pTableNd ) + return false; + + FndBox_ aFndBox( nullptr, nullptr ); + + // look for all boxes / lines + { + SwSelBoxes aSelBoxes; + ::GetTableSel( rSh, aSelBoxes ); + FndPara aPara( aSelBoxes, &aFndBox ); + const SwTable& rTable = pTableNd->GetTable(); + ForEach_FndLineCopyCol( const_cast<SwTableLines&>(rTable.GetTabLines()), &aPara ); + } + rX = aFndBox.GetLines().size(); + if( !rX ) + return false; + + rY = aFndBox.GetLines().front()->GetBoxes().size(); + return true; +} + +// init list +SwSortDlg::SwSortDlg(weld::Window* pParent, SwWrtShell &rShell) + : GenericDialogController(pParent, "modules/swriter/ui/sortdialog.ui", "SortDialog") + , m_pParent(pParent) + , m_xColLbl(m_xBuilder->weld_label("column")) + , m_xKeyCB1(m_xBuilder->weld_check_button("key1")) + , m_xColEdt1(m_xBuilder->weld_spin_button("colsb1")) + , m_xTypDLB1(m_xBuilder->weld_combo_box("typelb1")) + , m_xSortUp1RB(m_xBuilder->weld_radio_button("up1")) + , m_xSortDn1RB(m_xBuilder->weld_radio_button("down1")) + , m_xKeyCB2(m_xBuilder->weld_check_button("key2")) + , m_xColEdt2(m_xBuilder->weld_spin_button("colsb2")) + , m_xTypDLB2(m_xBuilder->weld_combo_box("typelb2")) + , m_xSortUp2RB(m_xBuilder->weld_radio_button("up2")) + , m_xSortDn2RB(m_xBuilder->weld_radio_button("down2")) + , m_xKeyCB3(m_xBuilder->weld_check_button("key3")) + , m_xColEdt3(m_xBuilder->weld_spin_button("colsb3")) + , m_xTypDLB3(m_xBuilder->weld_combo_box("typelb3")) + , m_xSortUp3RB(m_xBuilder->weld_radio_button("up3")) + , m_xSortDn3RB(m_xBuilder->weld_radio_button("down3")) + , m_xColumnRB(m_xBuilder->weld_radio_button("columns")) + , m_xRowRB(m_xBuilder->weld_radio_button("rows")) + , m_xDelimTabRB(m_xBuilder->weld_radio_button("tabs")) + , m_xDelimFreeRB(m_xBuilder->weld_radio_button("character")) + , m_xDelimEdt(m_xBuilder->weld_entry("separator")) + , m_xDelimPB(m_xBuilder->weld_button("delimpb")) + , m_xLangLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("langlb"))) + , m_xCaseCB(m_xBuilder->weld_check_button("matchcase")) + , aColText(SwResId(STR_COL)) + , aRowText(SwResId(STR_ROW)) + , aNumericText(SwResId(STR_NUMERIC)) + , rSh(rShell) + , nX(99) + , nY(99) +{ + if(rSh.GetSelectionType() & + (SelectionType::Table|SelectionType::TableCell) ) + { + m_xColumnRB->set_active(bCol); + m_xColLbl->set_label(bCol ? aRowText : aColText); + m_xRowRB->set_active(!bCol); + m_xDelimTabRB->set_sensitive(false); + m_xDelimFreeRB->set_sensitive(false); + m_xDelimEdt->set_sensitive(false); + } + else + { + m_xColumnRB->set_sensitive(false); + m_xRowRB->set_active(true); + m_xColLbl->set_label(aColText); + } + + // Set accessible names here because text of m_xColLbl may be changed + // by the if-else block above + m_xColEdt1->set_accessible_name(m_xColLbl->get_label()); + m_xColEdt2->set_accessible_name(m_xColLbl->get_label()); + m_xColEdt3->set_accessible_name(m_xColLbl->get_label()); + + // initialise + Link<weld::Toggleable&,void> aLk = LINK(this, SwSortDlg, CheckHdl); + m_xKeyCB1->connect_toggled( aLk ); + m_xKeyCB2->connect_toggled( aLk ); + m_xKeyCB3->connect_toggled( aLk ); + m_xColumnRB->connect_toggled( aLk ); + m_xRowRB->connect_toggled( aLk ); + + aLk = LINK(this, SwSortDlg, DelimHdl); + m_xDelimFreeRB->connect_toggled(aLk); + m_xDelimTabRB->connect_toggled(aLk); + + m_xDelimPB->connect_clicked( LINK( this, SwSortDlg, DelimCharHdl )); + + m_xKeyCB1->set_active(bCheck1); + m_xKeyCB2->set_active(bCheck2); + m_xKeyCB3->set_active(bCheck3); + + m_xColEdt1->set_value(nCol1); + m_xColEdt2->set_value(nCol2); + m_xColEdt3->set_value(nCol3); + + // first initialise the language, then select the + if( LANGUAGE_NONE == nLang || LANGUAGE_DONTKNOW == nLang ) + nLang = GetAppLanguage(); + + m_xLangLB->SetLanguageList( SvxLanguageListFlags::ALL | SvxLanguageListFlags::ONLY_KNOWN, true ); + m_xLangLB->set_active_id(nLang); + + LanguageHdl( nullptr ); + m_xLangLB->connect_changed( LINK( this, SwSortDlg, LanguageListBoxHdl )); + + m_xSortUp1RB->set_active(bAsc1); + m_xSortDn1RB->set_active(!bAsc1); + m_xSortUp2RB->set_active(bAsc2); + m_xSortDn2RB->set_active(!bAsc2); + m_xSortUp3RB->set_active(bAsc3); + m_xSortDn3RB->set_active(!bAsc3); + + m_xCaseCB->set_active( bCsSens ); + + m_xDelimTabRB->set_active(cDeli == '\t'); + if(!m_xDelimTabRB->get_active()) + { + m_xDelimEdt->set_text(OUString(cDeli)); + m_xDelimFreeRB->set_active(true); + DelimHdl(*m_xDelimFreeRB); + } + else + DelimHdl(*m_xDelimTabRB); + + if( ::lcl_GetSelTable( rSh, nX, nY) ) + { + sal_uInt16 nMax = m_xRowRB->get_active()? nY : nX; + m_xColEdt1->set_max(nMax); + m_xColEdt2->set_max(nMax); + m_xColEdt3->set_max(nMax); + } +} + +sal_Unicode SwSortDlg::GetDelimChar() const +{ + sal_Unicode cRet = '\t'; + if( !m_xDelimTabRB->get_active() ) + { + OUString aTmp(m_xDelimEdt->get_text()); + if( !aTmp.isEmpty() ) + cRet = aTmp[0]; + } + return cRet; +} + +short SwSortDlg::run() +{ + short nRet = GenericDialogController::run(); + if (nRet == RET_OK) + Apply(); + return nRet; +} + +// pass on to the Core +void SwSortDlg::Apply() +{ + // save all settings + bCheck1 = m_xKeyCB1->get_active(); + bCheck2 = m_xKeyCB2->get_active(); + bCheck3 = m_xKeyCB3->get_active(); + + nCol1 = m_xColEdt1->get_value(); + nCol2 = m_xColEdt2->get_value(); + nCol3 = m_xColEdt3->get_value(); + + nType1 = m_xTypDLB1->get_active(); + nType2 = m_xTypDLB2->get_active(); + nType3 = m_xTypDLB3->get_active(); + + bAsc1 = m_xSortUp1RB->get_active(); + bAsc2 = m_xSortUp2RB->get_active(); + bAsc3 = m_xSortUp3RB->get_active(); + bCol = m_xColumnRB->get_active(); + nLang = m_xLangLB->get_active_id(); + cDeli = GetDelimChar(); + bCsSens = m_xCaseCB->get_active(); + + SwSortOptions aOptions; + if( bCheck1 ) + { + OUString sEntry( m_xTypDLB1->get_active_text() ); + if( sEntry == aNumericText ) + sEntry.clear(); + else if (!m_xTypDLB1->get_active_id().isEmpty()) + sEntry = m_xTypDLB1->get_active_id(); + + aOptions.aKeys.push_back( + SwSortKey( nCol1, sEntry, + bAsc1 ? SwSortOrder::Ascending : SwSortOrder::Descending )); + } + + if( bCheck2 ) + { + OUString sEntry( m_xTypDLB2->get_active_text() ); + if( sEntry == aNumericText ) + sEntry.clear(); + else if (!m_xTypDLB2->get_active_id().isEmpty()) + sEntry = m_xTypDLB2->get_active_id(); + + aOptions.aKeys.push_back( + SwSortKey( nCol2, sEntry, + bAsc2 ? SwSortOrder::Ascending : SwSortOrder::Descending )); + } + + if( bCheck3 ) + { + OUString sEntry( m_xTypDLB3->get_active_text() ); + if( sEntry == aNumericText ) + sEntry.clear(); + else if (!m_xTypDLB3->get_active_id().isEmpty()) + sEntry = m_xTypDLB3->get_active_id(); + + aOptions.aKeys.push_back( + SwSortKey( nCol3, sEntry, + bAsc3 ? SwSortOrder::Ascending : SwSortOrder::Descending )); + } + + aOptions.eDirection = bCol ? SwSortDirection::Columns : SwSortDirection::Rows; + aOptions.cDeli = cDeli; + aOptions.nLanguage = nLang; + aOptions.bTable = rSh.IsTableMode(); + aOptions.bIgnoreCase = !bCsSens; + + bool bRet; + { + SwWait aWait( *rSh.GetView().GetDocShell(), true ); + rSh.StartAllAction(); + bRet = rSh.Sort( aOptions ); + if( bRet ) + rSh.SetModified(); + rSh.EndAllAction(); + } + + if (!bRet) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_pParent, + VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_SRTERR))); + xInfoBox->run(); + } +} + +IMPL_LINK( SwSortDlg, DelimHdl, weld::Toggleable&, rButton, void ) +{ + bool bEnable = &rButton == m_xDelimFreeRB.get() && m_xDelimFreeRB->get_sensitive(); + m_xDelimEdt->set_sensitive( bEnable ); + m_xDelimPB->set_sensitive( bEnable ); +} + +IMPL_LINK_NOARG(SwSortDlg, DelimCharHdl, weld::Button&, void) +{ + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + SfxAllItemSet aSet( rSh.GetAttrPool() ); + aSet.Put( SfxInt32Item( SID_ATTR_CHAR, GetDelimChar() ) ); + ScopedVclPtr<SfxAbstractDialog> pMap(pFact->CreateCharMapDialog(m_xDialog.get(), aSet, nullptr)); + if( RET_OK == pMap->Execute() ) + { + const SfxInt32Item* pItem = SfxItemSet::GetItem<SfxInt32Item>(pMap->GetOutputItemSet(), SID_ATTR_CHAR, false); + if ( pItem ) + m_xDelimEdt->set_text(OUString(sal_Unicode(pItem->GetValue()))); + } +} + +IMPL_LINK( SwSortDlg, CheckHdl, weld::Toggleable&, rControl, void ) +{ + if (&rControl == m_xRowRB.get()) + { + m_xColLbl->set_label(aColText); + m_xColEdt1->set_max(nY); + m_xColEdt2->set_max(nY); + m_xColEdt3->set_max(nY); + + m_xColEdt1->set_accessible_name(aColText); + m_xColEdt2->set_accessible_name(aColText); + m_xColEdt3->set_accessible_name(aColText); + } + else if (&rControl == m_xColumnRB.get()) + { + m_xColLbl->set_label(aRowText); + m_xColEdt1->set_max(nX); + m_xColEdt2->set_max(nX); + m_xColEdt3->set_max(nX); + + m_xColEdt1->set_accessible_name(aRowText); + m_xColEdt2->set_accessible_name(aRowText); + m_xColEdt3->set_accessible_name(aRowText); + } + else if(!m_xKeyCB1->get_active() && + !m_xKeyCB2->get_active() && + !m_xKeyCB3->get_active()) + { + rControl.set_active(true); + } +} + +IMPL_LINK( SwSortDlg, LanguageListBoxHdl, weld::ComboBox&, rLBox, void ) +{ + LanguageHdl(&rLBox); +} + +void SwSortDlg::LanguageHdl(weld::ComboBox const* pLBox) +{ + Sequence < OUString > aSeq( GetAppCollator().listCollatorAlgorithms( + LanguageTag( m_xLangLB->get_active_id()).getLocale() )); + + if (!m_xColRes) + m_xColRes.reset(new CollatorResource); + + const int nLstBoxCnt = 3; + weld::ComboBox* aLstArr[ nLstBoxCnt ] = { m_xTypDLB1.get(), m_xTypDLB2.get(), m_xTypDLB3.get() }; + sal_uInt16* const aTypeArr[ nLstBoxCnt ] = { &nType1, &nType2, &nType3 }; + OUString aOldStrArr[ nLstBoxCnt ]; + + for( int n = 0; n < nLstBoxCnt; ++n ) + { + weld::ComboBox* pL = aLstArr[ n ]; + OUString sUserData = pL->get_active_id(); + if (!sUserData.isEmpty()) + aOldStrArr[ n ] = sUserData; + pL->clear(); + } + + OUString sAlg, sUINm; + const sal_Int32 nEnd = aSeq.getLength(); + for( sal_Int32 nCnt = 0; nCnt <= nEnd; ++nCnt ) + { + if( nCnt < nEnd ) + { + sAlg = aSeq[ nCnt ]; + sUINm = m_xColRes->GetTranslation( sAlg ); + } + else + sUINm = sAlg = aNumericText; + + for( int n = 0; n < nLstBoxCnt; ++n ) + { + weld::ComboBox* pL = aLstArr[ n ]; + pL->append(sAlg, sUINm); + if (pLBox && sAlg == aOldStrArr[n]) + pL->set_active_id(sAlg); + } + } + + for( int n = 0; n < nLstBoxCnt; ++n ) + { + weld::ComboBox* pL = aLstArr[ n ]; + if( !pLBox ) + pL->set_active(*aTypeArr[n]); + else if (pL->get_active() == -1) + pL->set_active(0); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/swmodalredlineacceptdlg.cxx b/sw/source/ui/misc/swmodalredlineacceptdlg.cxx new file mode 100644 index 000000000..0d2f2672b --- /dev/null +++ b/sw/source/ui/misc/swmodalredlineacceptdlg.cxx @@ -0,0 +1,79 @@ +/* -*- 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 <svx/ctredlin.hxx> +#include <unotools/viewoptions.hxx> + +#include <redlndlg.hxx> +#include <swmodalredlineacceptdlg.hxx> + +SwModalRedlineAcceptDlg::SwModalRedlineAcceptDlg(weld::Window *pParent) + : SfxDialogController(pParent, "svx/ui/acceptrejectchangesdialog.ui", + "AcceptRejectChangesDialog") + , m_xContentArea(m_xDialog->weld_content_area()) +{ + m_xDialog->set_modal(true); + + m_xImplDlg.reset(new SwRedlineAcceptDlg(m_xDialog, m_xBuilder.get(), m_xContentArea.get(), true)); + + SvtViewOptions aDlgOpt(EViewType::Dialog, OStringToOUString(m_xDialog->get_help_id(), RTL_TEXTENCODING_UTF8)); + if (aDlgOpt.Exists()) + { + css::uno::Any aUserItem = aDlgOpt.GetUserItem("UserItem"); + OUString sExtraData; + aUserItem >>= sExtraData; + m_xImplDlg->Initialize(sExtraData); + } + m_xImplDlg->Activate(); // for data's initialisation +} + +SwModalRedlineAcceptDlg::~SwModalRedlineAcceptDlg() +{ + AcceptAll(false); // refuse everything remaining + + OUString sExtraData; + m_xImplDlg->FillInfo(sExtraData); + SvtViewOptions aDlgOpt(EViewType::Dialog, OStringToOUString(m_xDialog->get_help_id(), RTL_TEXTENCODING_UTF8)); + aDlgOpt.SetUserItem("UserItem", css::uno::Any(sExtraData)); + + m_xDialog->set_modal(false); +} + +void SwModalRedlineAcceptDlg::Activate() +{ +} + +void SwModalRedlineAcceptDlg::AcceptAll( bool bAccept ) +{ + SvxTPFilter* pFilterTP = m_xImplDlg->GetChgCtrl().GetFilterPage(); + + if (pFilterTP->IsDate() || pFilterTP->IsAuthor() || + pFilterTP->IsRange() || pFilterTP->IsAction()) + { + pFilterTP->CheckDate(false); // turn off all filters + pFilterTP->CheckAuthor(false); + pFilterTP->CheckRange(false); + pFilterTP->CheckAction(false); + m_xImplDlg->FilterChangedHdl(nullptr); + } + + m_xImplDlg->CallAcceptReject( false, bAccept ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/titlepage.cxx b/sw/source/ui/misc/titlepage.cxx new file mode 100644 index 000000000..4308c8db2 --- /dev/null +++ b/sw/source/ui/misc/titlepage.cxx @@ -0,0 +1,334 @@ +/* -*- 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/. + */ + +#include <view.hxx> +#include <swmodule.hxx> +#include <wrtsh.hxx> +#include <poolfmt.hxx> +#include <docsh.hxx> + +#include <titlepage.hxx> +#include <fmtpdsc.hxx> +#include <pagedesc.hxx> + +namespace +{ + bool lcl_GetPageDesc(SwWrtShell& rSh, sal_uInt16 &rPageNo, std::unique_ptr<const SwFormatPageDesc>* ppPageFormatDesc) + { + bool bRet = false; + SfxItemSetFixed<RES_PAGEDESC, RES_PAGEDESC> aSet(rSh.GetAttrPool()); + if (rSh.GetCurAttr(aSet)) + { + if (const SwFormatPageDesc* pDescItem = aSet.GetItemIfSet( RES_PAGEDESC )) + { + ::std::optional<sal_uInt16> oNumOffset = pDescItem->GetNumOffset(); + if (oNumOffset) + rPageNo = *oNumOffset; + if (ppPageFormatDesc) + ppPageFormatDesc->reset(static_cast<const SwFormatPageDesc *>(pDescItem->Clone())); + bRet = true; + } + } + return bRet; + } + + void lcl_ChangePage(SwWrtShell& rSh, sal_uInt16 nNewNumber, const SwPageDesc *pNewDesc) + { + const size_t nCurIdx = rSh.GetCurPageDesc(); + const SwPageDesc &rCurrentDesc = rSh.GetPageDesc(nCurIdx); + + std::unique_ptr<const SwFormatPageDesc> pPageFormatDesc; + sal_uInt16 nDontCare; + lcl_GetPageDesc(rSh, nDontCare, &pPageFormatDesc); + + // If we want a new number then set it, otherwise reuse the existing one + sal_uInt16 nPgNo = 0; + if (nNewNumber) + { + // -1: Allow special case to prevent inheriting re-numbering from the existing page. + nPgNo = nNewNumber == SAL_MAX_UINT16 ? 0 : nNewNumber; + } + else if (pPageFormatDesc) + { + ::std::optional<sal_uInt16> oNumOffset = pPageFormatDesc->GetNumOffset(); + if (oNumOffset) + nPgNo = *oNumOffset; + } + + // If we want a new descriptor then set it, otherwise reuse the existing one + if (pNewDesc || nPgNo) + { + SwFormatPageDesc aPageFormatDesc(pNewDesc ? pNewDesc : &rCurrentDesc); + if (nPgNo) aPageFormatDesc.SetNumOffset(nPgNo); + rSh.SetAttrItem(aPageFormatDesc); + } + } + + void lcl_PushCursor(SwWrtShell& rSh) + { + rSh.LockView(true); + rSh.StartAllAction(); + rSh.SwCursorShell::Push(); + } + + void lcl_PopCursor(SwWrtShell& rSh) + { + rSh.SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent); + rSh.EndAllAction(); + rSh.LockView(false); + } + + sal_uInt16 lcl_GetCurrentPage(const SwWrtShell& rSh) + { + OUString sDummy; + sal_uInt16 nPhyNum=1, nVirtNum=1; + rSh.GetPageNumber(0, true, nPhyNum, nVirtNum, sDummy); + return nPhyNum; + } + +bool lcl_GotoPage(SwWrtShell& rSh, const sal_uInt16 nStartingPage, sal_uInt16 nOffset = 0) +{ + rSh.GotoPage(nStartingPage, /*bRecord=*/false); + + sal_uInt16 nCurrentPage = lcl_GetCurrentPage(rSh); + // return false if at document end (unless that was the requested destination) + if (nCurrentPage == rSh.GetPageCnt()) + return nCurrentPage == nStartingPage + nOffset; + + if (nCurrentPage != nStartingPage) + { + assert(nStartingPage != 1 && "Physical page 1 couldn't be found/moved to?"); + // Probably there is an auto-inserted blank page to handle odd/even, which Goto doesn't understand. + rSh.GotoPage(nStartingPage + 1, /*bRecord=*/false); + + nCurrentPage = lcl_GetCurrentPage(rSh); + assert(nCurrentPage == nStartingPage + 1 && "Impossible, since unknown goes to last page"); + if (nCurrentPage != nStartingPage + 1) + return false; + } + // Now that we have the correct starting point, move to the correct offset. + while (nOffset--) + rSh.SttNxtPg(); + return true; +} +} // namespace + +/* + * Only include the Index page in the list if the page count implies one + * to reduce confusing things + */ +void SwTitlePageDlg::FillList() +{ + sal_uInt16 nTitlePages = m_xPageCountNF->get_value(); + m_xPagePropertiesLB->clear(); + if (mpTitleDesc) + m_xPagePropertiesLB->append_text(mpTitleDesc->GetName()); + if (nTitlePages > 1 && mpIndexDesc) + m_xPagePropertiesLB->append_text(mpIndexDesc->GetName()); + if (mpNormalDesc) + m_xPagePropertiesLB->append_text(mpNormalDesc->GetName()); + m_xPagePropertiesLB->set_active(0); +} + +sal_uInt16 SwTitlePageDlg::GetInsertPosition() const +{ + sal_uInt16 nPage = 1; + if (m_xPageStartNF->get_sensitive()) + nPage = m_xPageStartNF->get_value(); + return nPage; +} + +SwTitlePageDlg::SwTitlePageDlg(weld::Window *pParent) + : SfxDialogController(pParent, "modules/swriter/ui/titlepage.ui", "DLG_TITLEPAGE") + , mpTitleDesc(nullptr) + , mpIndexDesc(nullptr) + , mpNormalDesc(nullptr) + , m_xUseExistingPagesRB(m_xBuilder->weld_radio_button("RB_USE_EXISTING_PAGES")) + , m_xPageCountNF(m_xBuilder->weld_spin_button("NF_PAGE_COUNT")) + , m_xDocumentStartRB(m_xBuilder->weld_radio_button("RB_DOCUMENT_START")) + , m_xPageStartRB(m_xBuilder->weld_radio_button("RB_PAGE_START")) + , m_xPageStartNF(m_xBuilder->weld_spin_button("NF_PAGE_START")) + , m_xRestartNumberingCB(m_xBuilder->weld_check_button("CB_RESTART_NUMBERING")) + , m_xRestartNumberingNF(m_xBuilder->weld_spin_button("NF_RESTART_NUMBERING")) + , m_xSetPageNumberCB(m_xBuilder->weld_check_button("CB_SET_PAGE_NUMBER")) + , m_xSetPageNumberNF(m_xBuilder->weld_spin_button("NF_SET_PAGE_NUMBER")) + , m_xPagePropertiesLB(m_xBuilder->weld_combo_box("LB_PAGE_PROPERTIES")) + , m_xPagePropertiesPB(m_xBuilder->weld_button("PB_PAGE_PROPERTIES")) + , m_xOkPB(m_xBuilder->weld_button("ok")) +{ + SwView* pView = GetActiveView(); + if (!pView) + return; + SwWrtShell& rWrtShell = pView->GetWrtShell(); + + m_xOkPB->connect_clicked(LINK(this, SwTitlePageDlg, OKHdl)); + m_xRestartNumberingCB->connect_toggled(LINK(this, SwTitlePageDlg, RestartNumberingHdl)); + m_xSetPageNumberCB->connect_toggled(LINK(this, SwTitlePageDlg, SetPageNumberHdl)); + m_xPageStartNF->set_max(rWrtShell.GetPageCnt() + 1); + + sal_uInt16 nSetPage = 1; + sal_uInt16 nResetPage = 1; + sal_uInt16 nTitlePages = 1; + lcl_PushCursor(rWrtShell); + + SwView& rView = rWrtShell.GetView(); + rView.InvalidateRulerPos(); + + bool bMaybeResetNumbering = false; + + mpTitleDesc = rWrtShell.GetPageDescFromPool(RES_POOLPAGE_FIRST); + mpIndexDesc = rWrtShell.GetPageDescFromPool(RES_POOLPAGE_REGISTER); + mpNormalDesc = rWrtShell.GetPageDescFromPool(RES_POOLPAGE_STANDARD); + + rWrtShell.StartOfSection(); + if (lcl_GetPageDesc(rWrtShell, nSetPage, &mpPageFormatDesc)) + { + if (mpPageFormatDesc->GetPageDesc() == mpTitleDesc) + { + while (rWrtShell.SttNxtPg()) + { + const size_t nCurIdx = rWrtShell.GetCurPageDesc(); + const SwPageDesc& rPageDesc = rWrtShell.GetPageDesc(nCurIdx); + + if (mpIndexDesc != &rPageDesc) + { + mpNormalDesc = &rPageDesc; + bMaybeResetNumbering = lcl_GetPageDesc(rWrtShell, nResetPage, nullptr); + break; + } + ++nTitlePages; + } + } + } + lcl_PopCursor(rWrtShell); + + m_xUseExistingPagesRB->set_active(true); + m_xPageCountNF->set_value(nTitlePages); + m_xPageCountNF->connect_value_changed(LINK(this, SwTitlePageDlg, ValueChangeHdl)); + + m_xDocumentStartRB->set_active(true); + m_xPageStartNF->set_sensitive(false); + m_xPageStartNF->set_value(lcl_GetCurrentPage(rWrtShell)); + Link<weld::Toggleable&,void> aStartPageHdl = LINK(this, SwTitlePageDlg, StartPageHdl); + m_xDocumentStartRB->connect_toggled(aStartPageHdl); + m_xPageStartRB->connect_toggled(aStartPageHdl); + + m_xRestartNumberingNF->set_value(nResetPage); + if (bMaybeResetNumbering && nResetPage > 0) + { + m_xRestartNumberingCB->set_active(true); + } + m_xRestartNumberingNF->set_sensitive(m_xRestartNumberingCB->get_active()); + + m_xSetPageNumberNF->set_value(nSetPage); + if (nSetPage > 1) + m_xSetPageNumberCB->set_active(true); + m_xSetPageNumberNF->set_sensitive(m_xSetPageNumberCB->get_active()); + + FillList(); + m_xPagePropertiesPB->connect_clicked(LINK(this, SwTitlePageDlg, EditHdl)); +} + +IMPL_LINK_NOARG(SwTitlePageDlg, ValueChangeHdl, weld::SpinButton&, void) +{ + if (m_xPageCountNF->get_value() == 1 || m_xPageCountNF->get_value() == 2) + FillList(); +} + +IMPL_LINK_NOARG(SwTitlePageDlg, RestartNumberingHdl, weld::Toggleable&, void) +{ + m_xRestartNumberingNF->set_sensitive(m_xRestartNumberingCB->get_active()); +} + +IMPL_LINK_NOARG(SwTitlePageDlg, SetPageNumberHdl, weld::Toggleable&, void) +{ + m_xSetPageNumberNF->set_sensitive(m_xSetPageNumberCB->get_active()); +} + +IMPL_LINK_NOARG(SwTitlePageDlg, StartPageHdl, weld::Toggleable&, void) +{ + m_xPageStartNF->set_sensitive(m_xPageStartRB->get_active()); +} + +SwTitlePageDlg::~SwTitlePageDlg() +{ +} + +IMPL_LINK_NOARG(SwTitlePageDlg, EditHdl, weld::Button&, void) +{ + SwView* pView = GetActiveView(); + if (!pView) + return; + SwWrtShell& rWrtShell = pView->GetWrtShell(); + SwView& rView = rWrtShell.GetView(); + rView.GetDocShell()->FormatPage(getDialog(), m_xPagePropertiesLB->get_active_text(), "page", rWrtShell); + rView.InvalidateRulerPos(); +} + +IMPL_LINK_NOARG(SwTitlePageDlg, OKHdl, weld::Button&, void) +{ + SwView* pView = GetActiveView(); + if (!pView) + return; + SwWrtShell& rWrtShell = pView->GetWrtShell(); + lcl_PushCursor(rWrtShell); + + rWrtShell.StartUndo(); + + SwFormatPageDesc aTitleDesc(mpTitleDesc); + + if (m_xSetPageNumberCB->get_active()) + aTitleDesc.SetNumOffset(m_xSetPageNumberNF->get_value()); + else if (mpPageFormatDesc) + aTitleDesc.SetNumOffset(mpPageFormatDesc->GetNumOffset()); + + sal_uInt16 nNumTitlePages = m_xPageCountNF->get_value(); + if (!m_xUseExistingPagesRB->get_active()) + { + // Assuming that a failure to GotoPage means the end of the document, + // insert new pages after the last page. + if (!lcl_GotoPage(rWrtShell, GetInsertPosition())) + { + rWrtShell.EndPg(); + // Add one more page as a content page to follow the new title pages. + rWrtShell.InsertPageBreak(); + } + for (sal_uInt16 nI = 0; nI < nNumTitlePages; ++nI) + rWrtShell.InsertPageBreak(); + // In order to be able to access these new pages, the layout needs to be recalculated first. + rWrtShell.CalcLayout(); + } + + if (lcl_GotoPage(rWrtShell, GetInsertPosition())) + { + rWrtShell.SetAttrItem(aTitleDesc); + for (sal_uInt16 nI = 1; nI < nNumTitlePages; ++nI) + { + if (rWrtShell.SttNxtPg()) + lcl_ChangePage(rWrtShell, SAL_MAX_UINT16, mpIndexDesc); + } + } + + if ((m_xRestartNumberingCB->get_active() || nNumTitlePages > 1) + && lcl_GotoPage(rWrtShell, GetInsertPosition(), nNumTitlePages)) + { + sal_uInt16 nPgNo + = m_xRestartNumberingCB->get_active() ? m_xRestartNumberingNF->get_value() : 0; + const SwPageDesc* pNewDesc = nNumTitlePages > 1 ? mpNormalDesc : nullptr; + lcl_ChangePage(rWrtShell, nPgNo, pNewDesc); + } + + rWrtShell.EndUndo(); + lcl_PopCursor(rWrtShell); + if (!m_xUseExistingPagesRB->get_active()) + lcl_GotoPage(rWrtShell, GetInsertPosition()); + m_xDialog->response(RET_OK); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |