diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/ui | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/ui')
290 files changed, 82521 insertions, 0 deletions
diff --git a/sw/source/ui/chrdlg/break.cxx b/sw/source/ui/chrdlg/break.cxx new file mode 100644 index 0000000000..34048c2564 --- /dev/null +++ b/sw/source/ui/chrdlg/break.cxx @@ -0,0 +1,213 @@ +/* -*- 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 <vcl/svapp.hxx> +#include <osl/diagnose.h> + +#include <uitool.hxx> +#include <swtypes.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <viewopt.hxx> +#include <break.hxx> +#include <pagedesc.hxx> +#include <poolfmt.hxx> + +#include <strings.hrc> +#include <SwStyleNameMapper.hxx> + +void SwBreakDlg::rememberResult() +{ + m_nKind = 0; + if (m_xLineBtn->get_active()) + { + m_nKind = 1; + m_eClear = static_cast<SwLineBreakClear>(m_xLineClearBox->get_active()); + } + else if(m_xColumnBtn->get_active()) + m_nKind = 2; + else if(m_xPageBtn->get_active()) + { + m_nKind = 3; + const int nPos = m_xPageCollBox->get_active(); + if (nPos != 0 && nPos != -1) + { + m_aTemplate = m_xPageCollBox->get_active_text(); + m_oPgNum.reset(); + if (m_xPageNumBox->get_active()) + { + m_oPgNum = o3tl::narrowing<sal_uInt16>(m_xPageNumEdit->get_value()); + } + } + } +} + +IMPL_LINK_NOARG(SwBreakDlg, ToggleHdl, weld::Toggleable&, void) +{ + CheckEnable(); +} + +IMPL_LINK_NOARG(SwBreakDlg, ChangeHdl, weld::ComboBox&, void) +{ + CheckEnable(); +} + +// Handler for Change Page Number +IMPL_LINK(SwBreakDlg, PageNumHdl, weld::Toggleable&, rBox, void) +{ + if (rBox.get_active()) + m_xPageNumEdit->set_value(1); + else + m_xPageNumEdit->set_text(OUString()); +} + +// By changing the Page number the checkbox is checked. +IMPL_LINK_NOARG(SwBreakDlg, PageNumModifyHdl, weld::SpinButton&, void) +{ + m_xPageNumBox->set_active(true); +} + +/* + * Ok-Handler; + * checks whether pagenumber nPage is a legal pagenumber (left pages with even + * numbers etc. for a page template with alternating pages) + */ +IMPL_LINK_NOARG(SwBreakDlg, OkHdl, weld::Button&, void) +{ + if (m_xPageNumBox->get_active()) + { + // In case of differing page descriptions, test validity + const int nPos = m_xPageCollBox->get_active(); + // position 0 says 'Without'. + const SwPageDesc *pPageDesc; + if (nPos != 0 && nPos != -1) + pPageDesc = m_rSh.FindPageDescByName(m_xPageCollBox->get_active_text(), true); + else + pPageDesc = &m_rSh.GetPageDesc(m_rSh.GetCurPageDesc()); + + OSL_ENSURE(pPageDesc, "Page description not found."); + const sal_uInt16 nUserPage = sal_uInt16(m_xPageNumEdit->get_value()); + bool bOk = true; + switch(pPageDesc->GetUseOn()) + { + case UseOnPage::Mirror: + case UseOnPage::All: break; + case UseOnPage::Left: bOk = 0 == nUserPage % 2; break; + case UseOnPage::Right: bOk = 1 == nUserPage % 2; break; + default:; //prevent warning + } + if(!bOk) + { + std::unique_ptr<weld::Dialog> xDialog(Application::CreateMessageDialog(m_xPageNumEdit.get(), VclMessageType::Info, + VclButtonsType::Ok, SwResId(STR_ILLEGAL_PAGENUM))); + xDialog->run(); + m_xPageNumEdit->grab_focus(); + return; + } + } + rememberResult(); + m_xDialog->response(RET_OK); +} + +SwBreakDlg::SwBreakDlg(weld::Window *pParent, SwWrtShell &rS) + : GenericDialogController(pParent, "modules/swriter/ui/insertbreak.ui", "BreakDialog") + , m_xLineBtn(m_xBuilder->weld_radio_button("linerb")) + , m_xLineClearText(m_xBuilder->weld_label("clearft")) + , m_xLineClearBox(m_xBuilder->weld_combo_box("clearlb")) + , m_xColumnBtn(m_xBuilder->weld_radio_button("columnrb")) + , m_xPageBtn(m_xBuilder->weld_radio_button("pagerb")) + , m_xPageCollText(m_xBuilder->weld_label("styleft")) + , m_xPageCollBox(m_xBuilder->weld_combo_box("stylelb")) + , m_xPageNumBox(m_xBuilder->weld_check_button("pagenumcb")) + , m_xPageNumEdit(m_xBuilder->weld_spin_button("pagenumsb")) + , m_xOkBtn(m_xBuilder->weld_button("ok")) + , m_rSh(rS) + , m_nKind(0) + , m_bHtmlMode(0 != ::GetHtmlMode(rS.GetView().GetDocShell())) +{ + Link<weld::Toggleable&,void> aLk = LINK(this, SwBreakDlg, ToggleHdl); + m_xPageBtn->connect_toggled(aLk); + m_xLineBtn->connect_toggled(aLk); + m_xColumnBtn->connect_toggled(aLk); + m_xPageCollBox->connect_changed(LINK(this, SwBreakDlg, ChangeHdl)); + + m_xOkBtn->connect_clicked(LINK(this, SwBreakDlg, OkHdl)); + m_xPageNumBox->connect_toggled(LINK(this, SwBreakDlg, PageNumHdl)); + m_xPageNumEdit->connect_value_changed(LINK(this, SwBreakDlg, PageNumModifyHdl)); + + // Insert page description to Listbox + const size_t nCount = m_rSh.GetPageDescCnt(); + for (size_t i = 0; i < nCount; ++i) + { + const SwPageDesc &rPageDesc = m_rSh.GetPageDesc(i); + ::InsertStringSorted("", rPageDesc.GetName(), *m_xPageCollBox, 1 ); + } + + OUString aFormatName; + for (sal_uInt16 i = RES_POOLPAGE_BEGIN; i < RES_POOLPAGE_END; ++i) + { + aFormatName = SwStyleNameMapper::GetUIName( i, aFormatName ); + if (m_xPageCollBox->find_text(aFormatName) == -1) + ::InsertStringSorted("", aFormatName, *m_xPageCollBox, 1 ); + } + //add landscape page + aFormatName = SwStyleNameMapper::GetUIName( RES_POOLPAGE_LANDSCAPE, aFormatName ); + if (m_xPageCollBox->find_text(aFormatName) == -1) + ::InsertStringSorted("", aFormatName, *m_xPageCollBox, 1); + CheckEnable(); + m_xPageNumEdit->set_text(OUString()); +} + +void SwBreakDlg::CheckEnable() +{ + bool bEnable = true; + if ( m_bHtmlMode ) + { + m_xColumnBtn->set_sensitive(false); + m_xPageCollBox->set_sensitive(false); + bEnable = false; + } + else if(m_rSh.GetFrameType(nullptr,true) + & (FrameTypeFlags::FLY_ANY | FrameTypeFlags::HEADER | FrameTypeFlags::FOOTER | FrameTypeFlags::FOOTNOTE)) + { + m_xPageBtn->set_sensitive(false); + if (m_xPageBtn->get_active()) + m_xLineBtn->set_active(true); + bEnable = false; + } + const bool bPage = m_xPageBtn->get_active(); + m_xPageCollText->set_sensitive(bPage); + m_xPageCollBox->set_sensitive(bPage); + bool bLine = m_xLineBtn->get_active(); + m_xLineClearText->set_sensitive(bLine); + m_xLineClearBox->set_sensitive(bLine); + + bEnable &= bPage; + if ( bEnable ) + { + // position 0 says 'Without' page template. + const int nPos = m_xPageCollBox->get_active(); + if (nPos == 0 || nPos == -1) + bEnable = false; + } + m_xPageNumBox->set_sensitive(bEnable); + m_xPageNumEdit->set_sensitive(bEnable); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/chrdlg/chardlg.cxx b/sw/source/ui/chrdlg/chardlg.cxx new file mode 100644 index 0000000000..ece33852d7 --- /dev/null +++ b/sw/source/ui/chrdlg/chardlg.cxx @@ -0,0 +1,316 @@ +/* -*- 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 <memory> +#include <hintids.hxx> + +#include <comphelper/fileurl.hxx> +#include <svl/urihelper.hxx> +#include <svl/stritem.hxx> +#include <editeng/flstitem.hxx> +#include <sfx2/htmlmode.hxx> +#include <svl/cjkoptions.hxx> +#include <svl/macitem.hxx> +#include <osl/diagnose.h> + +#include <cmdid.h> +#include <swtypes.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <uitool.hxx> +#include <fmtinfmt.hxx> +#include <macassgn.hxx> +#include <chrdlg.hxx> +#include <swmodule.hxx> +#include <poolfmt.hxx> + +#include <strings.hrc> +#include <chrdlgmodes.hxx> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <SwStyleNameMapper.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/frame.hxx> +#include <comphelper/lok.hxx> + +#include <svx/svxdlg.hxx> +#include <svx/flagsdef.hxx> +#include <svx/dialogs.hrc> + +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::sfx2; + +SwCharDlg::SwCharDlg(weld::Window* pParent, SwView& rVw, const SfxItemSet& rCoreSet, + SwCharDlgMode nDialogMode, const OUString* pStr) + : SfxTabDialogController(pParent, "modules/swriter/ui/characterproperties.ui", + "CharacterPropertiesDialog", &rCoreSet, pStr != nullptr) + , m_rView(rVw) + , m_nDialogMode(nDialogMode) +{ + if (pStr) + { + m_xDialog->set_title(m_xDialog->get_title() + SwResId(STR_TEXTCOLL_HEADER) + *pStr + ")"); + } + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + AddTabPage("font", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_CHAR_NAME), nullptr); + AddTabPage("fonteffects", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_CHAR_EFFECTS), nullptr); + AddTabPage("position", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_POSITION ), nullptr ); + AddTabPage("asianlayout", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_TWOLINES ), nullptr ); + AddTabPage("hyperlink", SwCharURLPage::Create, nullptr); + AddTabPage("background", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BKG ), nullptr ); + AddTabPage("borders", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BORDER ), nullptr ); + + if (m_nDialogMode == SwCharDlgMode::Draw || m_nDialogMode == SwCharDlgMode::Ann) + { + RemoveTabPage("hyperlink"); + RemoveTabPage("asianlayout"); + } + else + { + if (!SvtCJKOptions::IsDoubleLinesEnabled()) + RemoveTabPage("asianlayout"); + } + + if (m_nDialogMode != SwCharDlgMode::Std) + RemoveTabPage("borders"); +} + +SwCharDlg::~SwCharDlg() +{ +} + +// set FontList +void SwCharDlg::PageCreated(const OUString& rId, SfxTabPage &rPage) +{ + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + if (rId == "font") + { + SvxFontListItem aFontListItem( *static_cast<const SvxFontListItem*>( + ( m_rView.GetDocShell()->GetItem( SID_ATTR_CHAR_FONTLIST ) ) ) ); + aSet.Put (SvxFontListItem( aFontListItem.GetFontList(), SID_ATTR_CHAR_FONTLIST)); + if(m_nDialogMode != SwCharDlgMode::Draw && m_nDialogMode != SwCharDlgMode::Ann) + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE,SVX_PREVIEW_CHARACTER)); + rPage.PageCreated(aSet); + } + else if (rId == "fonteffects") + { + aSet.Put( + SfxUInt32Item(SID_FLAG_TYPE, SVX_PREVIEW_CHARACTER | SVX_ENABLE_CHAR_TRANSPARENCY)); + rPage.PageCreated(aSet); + } + else if (rId == "position") + { + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE,SVX_PREVIEW_CHARACTER)); + rPage.PageCreated(aSet); + } + else if (rId == "asianlayout") + { + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE,SVX_PREVIEW_CHARACTER)); + rPage.PageCreated(aSet); + } + else if (rId == "background") + { + SvxBackgroundTabFlags eFlags(SvxBackgroundTabFlags::SHOW_HIGHLIGHTING); + if (m_nDialogMode == SwCharDlgMode::Draw || m_nDialogMode == SwCharDlgMode::Ann) + eFlags = SvxBackgroundTabFlags::SHOW_CHAR_BKGCOLOR; + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE,static_cast<sal_uInt32>(eFlags))); + rPage.PageCreated(aSet); + } +} + +SwCharURLPage::SwCharURLPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/charurlpage.ui", "CharURLPage", &rCoreSet) + , m_bModified(false) + , m_xURLED(m_xBuilder->weld_entry("urled")) + , m_xTextFT(m_xBuilder->weld_label("textft")) + , m_xTextED(m_xBuilder->weld_entry("texted")) + , m_xNameED(m_xBuilder->weld_entry("nameed")) + , m_xTargetFrameLB(m_xBuilder->weld_combo_box("targetfrmlb")) + , m_xURLPB(m_xBuilder->weld_button("urlpb")) + , m_xEventPB(m_xBuilder->weld_button("eventpb")) + , m_xVisitedLB(m_xBuilder->weld_combo_box("visitedlb")) + , m_xNotVisitedLB(m_xBuilder->weld_combo_box("unvisitedlb")) + , m_xCharStyleContainer(m_xBuilder->weld_widget("charstyle")) +{ + // tdf#120188 like SfxManageStyleSheetPage limit the width of the style combos + const int nMaxWidth(m_xVisitedLB->get_approximate_digit_width() * 50); + m_xVisitedLB->set_size_request(nMaxWidth , -1); + m_xNotVisitedLB->set_size_request(nMaxWidth , -1); + + const SfxUInt16Item* pItem = rCoreSet.GetItemIfSet(SID_HTML_MODE, false); + if (!pItem) + { + if (SfxObjectShell* pShell = SfxObjectShell::Current()) + pItem = pShell->GetItem(SID_HTML_MODE); + } + if (pItem) + { + sal_uInt16 nHtmlMode = pItem->GetValue(); + if (HTMLMODE_ON & nHtmlMode) + m_xCharStyleContainer->hide(); + } + + if(comphelper::LibreOfficeKit::isActive()) + m_xURLPB->hide(); // Hide browse button in online (not supported yet) + else + m_xURLPB->connect_clicked(LINK( this, SwCharURLPage, InsertFileHdl)); + m_xEventPB->connect_clicked(LINK( this, SwCharURLPage, EventHdl)); + + if (SwView* pView = GetActiveView()) + { + ::FillCharStyleListBox(*m_xVisitedLB, pView->GetDocShell()); + ::FillCharStyleListBox(*m_xNotVisitedLB, pView->GetDocShell()); + } + m_xVisitedLB->set_active_id(OUString::number(RES_POOLCHR_INET_VISIT)); + m_xVisitedLB->save_value(); + m_xNotVisitedLB->set_active_id(OUString::number(RES_POOLCHR_INET_NORMAL)); + m_xNotVisitedLB->save_value(); + + TargetList aList; + SfxFrame::GetDefaultTargetList(aList); + + m_xTargetFrameLB->freeze(); + size_t nCount = aList.size(); + for (size_t i = 0; i < nCount; ++i) + { + m_xTargetFrameLB->append_text(aList.at(i)); + } + m_xTargetFrameLB->thaw(); +} + +SwCharURLPage::~SwCharURLPage() +{ +} + +void SwCharURLPage::Reset(const SfxItemSet* rSet) +{ + if (const SwFormatINetFormat* pINetFormat = rSet->GetItemIfSet(RES_TXTATR_INETFMT, false)) + { + m_xURLED->set_text(INetURLObject::decode(pINetFormat->GetValue(), + INetURLObject::DecodeMechanism::Unambiguous)); + m_xURLED->save_value(); + m_xNameED->set_text(pINetFormat->GetName()); + m_xNameED->save_value(); + + OUString sEntry = pINetFormat->GetVisitedFormat(); + if (sEntry.isEmpty()) + { + OSL_ENSURE( false, "<SwCharURLPage::Reset(..)> - missing visited character format at hyperlink attribute" ); + SwStyleNameMapper::FillUIName(RES_POOLCHR_INET_VISIT, sEntry); + } + m_xVisitedLB->set_active_text(sEntry); + + sEntry = pINetFormat->GetINetFormat(); + if (sEntry.isEmpty()) + { + OSL_ENSURE( false, "<SwCharURLPage::Reset(..)> - missing unvisited character format at hyperlink attribute" ); + SwStyleNameMapper::FillUIName(RES_POOLCHR_INET_NORMAL, sEntry); + } + m_xNotVisitedLB->set_active_text(sEntry); + + m_xTargetFrameLB->set_entry_text(pINetFormat->GetTargetFrame()); + m_xVisitedLB->save_value(); + m_xNotVisitedLB->save_value(); + m_xTargetFrameLB->save_value(); + m_oINetMacroTable.emplace(); + + if( pINetFormat->GetMacroTable() ) + m_oINetMacroTable = *pINetFormat->GetMacroTable(); + } + if (const SfxStringItem* pItem = rSet->GetItemIfSet(FN_PARAM_SELECTION, false)) + { + m_xTextED->set_text(pItem->GetValue()); + m_xTextFT->set_sensitive(false); + m_xTextED->set_sensitive(false); + } +} + +bool SwCharURLPage::FillItemSet(SfxItemSet* rSet) +{ + OUString sURL = m_xURLED->get_text(); + if (!sURL.isEmpty()) + { + sURL = URIHelper::SmartRel2Abs(INetURLObject(), sURL, Link<OUString *, bool>(), false ); + // #i100683# file URLs should be normalized in the UI + if ( comphelper::isFileUrl(sURL) ) + sURL = URIHelper::simpleNormalizedMakeRelative(OUString(), sURL); + } + + SwFormatINetFormat aINetFormat(sURL, m_xTargetFrameLB->get_active_text()); + aINetFormat.SetName(m_xNameED->get_text()); + bool bURLModified = m_xURLED->get_value_changed_from_saved(); + bool bNameModified = m_xNameED->get_value_changed_from_saved(); + bool bTargetModified = m_xTargetFrameLB->get_value_changed_from_saved(); + m_bModified = bURLModified || bNameModified || bTargetModified; + + // set valid settings first + OUString sEntry = m_xVisitedLB->get_active_text(); + sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( sEntry, SwGetPoolIdFromName::ChrFmt); + aINetFormat.SetVisitedFormatAndId( sEntry, nId ); + + sEntry = m_xNotVisitedLB->get_active_text(); + nId = SwStyleNameMapper::GetPoolIdFromUIName( sEntry, SwGetPoolIdFromName::ChrFmt); + aINetFormat.SetINetFormatAndId( sEntry, nId ); + + if (m_oINetMacroTable && !m_oINetMacroTable->empty()) + aINetFormat.SetMacroTable(&*m_oINetMacroTable); + + if (m_xVisitedLB->get_value_changed_from_saved()) + m_bModified = true; + + if (m_xNotVisitedLB->get_value_changed_from_saved()) + m_bModified = true; + + if (bNameModified) + { + m_bModified = true; + rSet->Put(SfxStringItem(FN_PARAM_SELECTION, m_xTextED->get_text())); + } + if(m_bModified) + rSet->Put(aINetFormat); + return m_bModified; +} + +std::unique_ptr<SfxTabPage> SwCharURLPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwCharURLPage>(pPage, pController, *rAttrSet); +} + +IMPL_LINK_NOARG(SwCharURLPage, InsertFileHdl, weld::Button&, void) +{ + FileDialogHelper aDlgHelper(TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, GetFrameWeld()); + aDlgHelper.SetContext(FileDialogHelper::WriterInsertHyperlink); + if( aDlgHelper.Execute() == ERRCODE_NONE ) + { + const Reference<XFilePicker3>& xFP = aDlgHelper.GetFilePicker(); + m_xURLED->set_text(xFP->getSelectedFiles().getConstArray()[0]); + } +} + +IMPL_LINK_NOARG(SwCharURLPage, EventHdl, weld::Button&, void) +{ + if (SwView* pView = GetActiveView()) + m_bModified |= SwMacroAssignDlg::INetFormatDlg(GetFrameWeld(), + pView->GetWrtShell(), m_oINetMacroTable); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/chrdlg/drpcps.cxx b/sw/source/ui/chrdlg/drpcps.cxx new file mode 100644 index 0000000000..15bdd270a0 --- /dev/null +++ b/sw/source/ui/chrdlg/drpcps.cxx @@ -0,0 +1,760 @@ +/* -*- 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 <cmdid.h> +#include <docsh.hxx> +#include <swmodule.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <strings.hrc> + +#include <vcl/metric.hxx> +#include <vcl/settings.hxx> + +#include <rtl/ustrbuf.hxx> +#include <svl/stritem.hxx> +#include <editeng/fontitem.hxx> +#include <sfx2/dialoghelper.hxx> +#include <sfx2/htmlmode.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/printer.hxx> +#include <svtools/unitconv.hxx> +#include <vcl/print.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/i18n/BreakIterator.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <comphelper/processfactory.hxx> +#include <osl/diagnose.h> + +#include <charatr.hxx> +#include <viewopt.hxx> +#include <drpcps.hxx> +#include <paratr.hxx> +#include <uitool.hxx> +#include <charfmt.hxx> + +using namespace css; +using namespace css::uno; +using namespace css::lang; + +const WhichRangesContainer SwDropCapsPage::s_aPageRg(svl::Items<RES_PARATR_DROP, RES_PARATR_DROP>); + +void SwDropCapsPict::SetText( const OUString& rT ) +{ + maText = rT; + UpdatePaintSettings(); +} + +void SwDropCapsPict::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + CustomWidgetController::SetDrawingArea(pDrawingArea); + Size aPrefSize(getParagraphPreviewOptimalSize(pDrawingArea->get_ref_device())); + pDrawingArea->set_size_request(aPrefSize.Width(), aPrefSize.Height()); +} + +void SwDropCapsPict::Resize() +{ + CustomWidgetController::Resize(); + UpdatePaintSettings(); +} + +void SwDropCapsPict::SetLines( sal_uInt8 nL ) +{ + mnLines = nL; + UpdatePaintSettings(); +} + +void SwDropCapsPict::SetDistance( sal_uInt16 nD ) +{ + mnDistance = nD; + UpdatePaintSettings(); +} + +void SwDropCapsPict::SetValues( const OUString& rText, sal_uInt8 nLines, sal_uInt16 nDistance ) +{ + maText = rText; + mnLines = nLines; + mnDistance = nDistance; + + UpdatePaintSettings(); +} + +void SwDropCapsPict::InitPrinter() +{ + if( !mpPrinter ) + InitPrinter_(); +} + +// Create Default-String from character-count (A, AB, ABC, ...) +static OUString GetDefaultString(sal_Int32 nChars) +{ + OUStringBuffer aStr(nChars); + for (sal_Int32 i = 0; i < nChars; i++) + aStr.append(static_cast<sal_Unicode>(i + 65)); + return aStr.makeStringAndClear(); +} + +static void calcFontHeightAnyAscent(vcl::RenderContext& rWin, vcl::Font const & _rFont, tools::Long& _nHeight, tools::Long& _nAscent) +{ + if ( !_nHeight ) + { + rWin.Push(vcl::PushFlags::FONT); + rWin.SetFont(_rFont); + FontMetric aMetric(rWin.GetFontMetric()); + _nHeight = aMetric.GetLineHeight(); + _nAscent = aMetric.GetAscent(); + rWin.Pop(); + } +} + +SwDropCapsPict::~SwDropCapsPict() +{ + if (mbDelPrinter) + mpPrinter.disposeAndClear(); +} + +/// Get the details of the first script change. +/// @param[out] start The character position of the start of the segment. +/// @param[out] end The character position of the end of the segment. +/// @param[out] scriptType The script type (Latin, Asian, Complex etc.) +void SwDropCapsPict::GetFirstScriptSegment(sal_Int32 &start, sal_Int32 &end, sal_uInt16 &scriptType) +{ + start = 0; + if( maScriptChanges.empty() ) + { + end = maText.getLength(); + scriptType = css::i18n::ScriptType::LATIN; + } + else + { + end = maScriptChanges[ 0 ].changePos; + scriptType = maScriptChanges[ 0 ].scriptType; + } +} + +/// Get the details of the first script change. +/// @param[in,out] nIdx Index of the current script change. +/// @param[out] start The character position of the start of the segment. +/// @param[in,out] end The character position of the end of the segment. +/// @param[out] scriptType The script type (Latin, Asian, Complex etc.) +/// @returns True if there was a next segment, false if not. +bool SwDropCapsPict::GetNextScriptSegment(size_t &nIdx, sal_Int32 &start, sal_Int32 &end, sal_uInt16 &scriptType) +{ + if (maScriptChanges.empty() || nIdx >= maScriptChanges.size() - 1 || end >= maText.getLength()) + return false; + start = maScriptChanges[nIdx++].changePos; + end = maScriptChanges[ nIdx ].changePos; + scriptType = maScriptChanges[ nIdx ].scriptType; + return true; +} + +#define LINES 10 +#define BORDER 2 + +void SwDropCapsPict::GetFontSettings( vcl::Font& _rFont, sal_uInt16 _nWhich ) +{ + SwView* pView = GetActiveView(); + if (!pView) + return; + SwWrtShell& rWrtShell = pView->GetWrtShell(); + + SfxItemSet aSet( rWrtShell.GetAttrPool(), _nWhich, _nWhich); + rWrtShell.GetCurAttr(aSet); + SvxFontItem aFormatFont(static_cast<const SvxFontItem &>( aSet.Get(_nWhich))); + + _rFont.SetFamily(aFormatFont.GetFamily()); + _rFont.SetFamilyName(aFormatFont.GetFamilyName()); + _rFont.SetPitch(aFormatFont.GetPitch()); + _rFont.SetCharSet(aFormatFont.GetCharSet()); +} + +void SwDropCapsPict::UpdatePaintSettings() +{ + SwView* pView = GetActiveView(); + if (!pView) + return; + SwWrtShell& rWrtShell = pView->GetWrtShell(); + + maBackColor = Application::GetSettings().GetStyleSettings().GetWindowColor(); + maTextLineColor = COL_LIGHTGRAY; + + // gray lines + mnTotLineH = (GetOutputSizePixel().Height() - 2 * BORDER) / LINES; + mnLineH = mnTotLineH - 2; + + vcl::Font aFont; + if (mpPage) + { + // tdf#135244: preview generation should not jump document view + auto aLock(rWrtShell.GetView().GetDocShell()->LockAllViews()); + + if (!mpPage->m_xTemplateBox->get_active()) + { + // query the Font at paragraph's beginning + rWrtShell.Push(); + rWrtShell.SttCursorMove(); + rWrtShell.ClearMark(); + SwWhichPara pSwuifnParaCurr = GoCurrPara; + SwMoveFnCollection const & pSwuifnParaStart = fnParaStart; + rWrtShell.MovePara(pSwuifnParaCurr,pSwuifnParaStart); + // normal + GetFontSettings( aFont, RES_CHRATR_FONT ); + + // CJK + GetFontSettings( maCJKFont, RES_CHRATR_CJK_FONT ); + + // CTL + GetFontSettings( maCTLFont, RES_CHRATR_CTL_FONT ); + + rWrtShell.EndCursorMove(); + rWrtShell.Pop(SwCursorShell::PopMode::DeleteCurrent); + } + else + { + // query Font at character template + SwCharFormat *pFormat = rWrtShell.GetCharStyle( + mpPage->m_xTemplateBox->get_active_text(), + SwWrtShell::GETSTYLE_CREATEANY ); + OSL_ENSURE(pFormat, "character style doesn't exist!"); + const SvxFontItem &rFormatFont = pFormat->GetFont(); + + aFont.SetFamily(rFormatFont.GetFamily()); + aFont.SetFamilyName(rFormatFont.GetFamilyName()); + aFont.SetPitch(rFormatFont.GetPitch()); + aFont.SetCharSet(rFormatFont.GetCharSet()); + } + + const Color& rFontColor = rWrtShell.GetViewOptions()->GetFontColor(); + aFont.SetColor( rFontColor ); + maCJKFont.SetColor( rFontColor ); + maCTLFont.SetColor( rFontColor ); + } + + mnTextH = mnLines * mnTotLineH; + aFont.SetFontSize(Size(0, mnTextH)); + maCJKFont.SetFontSize(Size(0, mnTextH)); + maCTLFont.SetFontSize(Size(0, mnTextH)); + + aFont.SetTransparent(true); + maCJKFont.SetTransparent(true); + maCTLFont.SetTransparent(true); + + aFont.SetFillColor(Application::GetSettings().GetStyleSettings().GetWindowColor()); + maCJKFont.SetFillColor(Application::GetSettings().GetStyleSettings().GetWindowColor()); + maCTLFont.SetFillColor(Application::GetSettings().GetStyleSettings().GetWindowColor()); + + maCJKFont.SetFontSize(Size(0, maCJKFont.GetFontSize().Height())); + maCTLFont.SetFontSize(Size(0, maCTLFont.GetFontSize().Height())); + + aFont.SetFontSize(Size(0, aFont.GetFontSize().Height())); + maFont = aFont; + + CheckScript(); + + maTextSize = CalcTextSize(); + + Invalidate(); +} + +void SwDropCapsPict::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/) +{ + if (!IsVisible()) + return; + + rRenderContext.SetMapMode(MapMode(MapUnit::MapPixel)); + rRenderContext.SetLineColor(); + + rRenderContext.SetFillColor(maBackColor); + + Size aOutputSizePixel(GetOutputSizePixel()); + + rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), aOutputSizePixel)); + rRenderContext.SetClipRegion(vcl::Region(tools::Rectangle(Point(BORDER, BORDER), + Size(aOutputSizePixel.Width () - 2 * BORDER, + aOutputSizePixel.Height() - 2 * BORDER)))); + + OSL_ENSURE(mnLineH > 0, "We cannot make it that small"); + tools::Long nY0 = (aOutputSizePixel.Height() - (LINES * mnTotLineH)) / 2; + + rRenderContext.SetFillColor(maTextLineColor); + + for (int i = 0; i < LINES; ++i) + { + rRenderContext.DrawRect(tools::Rectangle(Point(BORDER, nY0 + i * mnTotLineH), + Size(aOutputSizePixel.Width() - 2 * BORDER, mnLineH))); + } + + // Text background with gap (240 twips ~ 1 line height) + const tools::Long nDistW = (((static_cast<tools::Long>(mnDistance) * 100) / 240) * mnTotLineH) / 100; + rRenderContext.SetFillColor(maBackColor); + if (mpPage && mpPage->m_xDropCapsBox->get_active()) + { + const Size aTextSize(maTextSize.Width() + nDistW, maTextSize.Height()); + rRenderContext.DrawRect(tools::Rectangle(Point(BORDER, nY0), aTextSize)); + + // draw Text + DrawPrev(rRenderContext, Point(BORDER, nY0)); + } + rRenderContext.SetClipRegion(); +} + +void SwDropCapsPict::DrawPrev(vcl::RenderContext& rRenderContext, const Point& rPt) +{ + Point aPt(rPt); + InitPrinter(); + + vcl::Font aOldFont = mpPrinter->GetFont(); + sal_uInt16 nScript; + size_t nIdx = 0; + sal_Int32 nStart; + sal_Int32 nEnd; + + GetFirstScriptSegment(nStart, nEnd, nScript); + + do + { + SvxFont& rFnt = (nScript == css::i18n::ScriptType::ASIAN) + ? maCJKFont + : ((nScript == css::i18n::ScriptType::COMPLEX) + ? maCTLFont + : maFont); + mpPrinter->SetFont(rFnt); + + rFnt.DrawPrev(&rRenderContext, mpPrinter, aPt, maText, nStart, nEnd - nStart); + + if (!maScriptChanges.empty()) + aPt.AdjustX(maScriptChanges[nIdx].textWidth ); + + if (!GetNextScriptSegment(nIdx, nStart, nEnd, nScript)) + break; + } + while(true); + + mpPrinter->SetFont(aOldFont); +} + +void SwDropCapsPict::CheckScript() +{ + if( maScriptText == maText ) + return; + + maScriptText = maText; + maScriptChanges.clear(); + if( !m_xBreak.is() ) + { + Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext(); + m_xBreak = css::i18n::BreakIterator::create(xContext); + } + sal_Int16 nScript = m_xBreak->getScriptType( maText, 0 ); + sal_Int32 nChg = 0; + if( css::i18n::ScriptType::WEAK == nScript ) + { + nChg = m_xBreak->endOfScript( maText, nChg, nScript ); + if( nChg < maText.getLength() ) + nScript = m_xBreak->getScriptType( maText, nChg ); + else + nScript = css::i18n::ScriptType::LATIN; + } + + for(;;) + { + nChg = m_xBreak->endOfScript( maText, nChg, nScript ); + maScriptChanges.emplace_back(nScript, nChg ); + if( nChg >= maText.getLength() || nChg < 0 ) + break; + nScript = m_xBreak->getScriptType( maText, nChg ); + } +} + +Size SwDropCapsPict::CalcTextSize() +{ + InitPrinter(); + + sal_uInt16 nScript; + size_t nIdx = 0; + sal_Int32 nStart; + sal_Int32 nEnd; + GetFirstScriptSegment(nStart, nEnd, nScript); + tools::Long nTextWidth = 0; + tools::Long nCJKHeight = 0; + tools::Long nCTLHeight = 0; + tools::Long nHeight = 0; + tools::Long nAscent = 0; + tools::Long nCJKAscent = 0; + tools::Long nCTLAscent = 0; + do + { + SvxFont& rFnt = (nScript == css::i18n::ScriptType::ASIAN) + ? maCJKFont + : ((nScript == css::i18n::ScriptType::COMPLEX) + ? maCTLFont + : maFont); + + sal_uLong nWidth = rFnt.GetTextSize(*mpPrinter, maText, nStart, nEnd-nStart ).Width(); + + if (nIdx < maScriptChanges.size()) + maScriptChanges[nIdx].textWidth = nWidth; + nTextWidth += nWidth; + switch(nScript) + { + case css::i18n::ScriptType::ASIAN: + calcFontHeightAnyAscent(GetDrawingArea()->get_ref_device(), maCJKFont, nCJKHeight, nCJKAscent); + break; + case css::i18n::ScriptType::COMPLEX: + calcFontHeightAnyAscent(GetDrawingArea()->get_ref_device(), maCTLFont, nCTLHeight, nCTLAscent); + break; + default: + calcFontHeightAnyAscent(GetDrawingArea()->get_ref_device(), maFont, nHeight, nAscent); + } + + if (!GetNextScriptSegment(nIdx, nStart, nEnd, nScript)) + break; + } + while(true); + + nHeight -= nAscent; + nCJKHeight -= nCJKAscent; + nCTLHeight -= nCTLAscent; + if (nHeight < nCJKHeight) + nHeight = nCJKHeight; + if (nAscent < nCJKAscent) + nAscent = nCJKAscent; + if (nHeight < nCTLHeight) + nHeight = nCTLHeight; + if (nAscent < nCTLAscent) + nAscent = nCTLAscent; + nHeight += nAscent; + + Size aTextSize(nTextWidth, nHeight); + return aTextSize; +} + +void SwDropCapsPict::InitPrinter_() +{ + SfxViewShell* pSh = SfxViewShell::Current(); + + if (pSh) + mpPrinter = pSh->GetPrinter(); + + if (!mpPrinter) + { + mpPrinter = VclPtr<Printer>::Create(); + mbDelPrinter = true; + } +} + +SwDropCapsDlg::SwDropCapsDlg(weld::Window *pParent, const SfxItemSet &rSet) + : SfxSingleTabDialogController(pParent, &rSet) +{ + auto xNewPage(SwDropCapsPage::Create(get_content_area(), this, &rSet)); + static_cast<SwDropCapsPage*>(xNewPage.get())->SetFormat(false); + SetTabPage(std::move(xNewPage)); +} + +SwDropCapsPage::SwDropCapsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/dropcapspage.ui", "DropCapPage", &rSet) + , m_bModified(false) + , m_bFormat(true) + , m_xDropCapsBox(m_xBuilder->weld_check_button("checkCB_SWITCH")) + , m_xWholeWordCB(m_xBuilder->weld_check_button("checkCB_WORD")) + , m_xSwitchText(m_xBuilder->weld_label("labelFT_DROPCAPS")) + , m_xDropCapsField(m_xBuilder->weld_spin_button("spinFLD_DROPCAPS")) + , m_xLinesText(m_xBuilder->weld_label("labelTXT_LINES")) + , m_xLinesField(m_xBuilder->weld_spin_button("spinFLD_LINES")) + , m_xDistanceText(m_xBuilder->weld_label("labelTXT_DISTANCE")) + , m_xDistanceField(m_xBuilder->weld_metric_spin_button("spinFLD_DISTANCE", FieldUnit::CM)) + , m_xTextText(m_xBuilder->weld_label("labelTXT_TEXT")) + , m_xTextEdit(m_xBuilder->weld_entry("entryEDT_TEXT")) + , m_xTemplateText(m_xBuilder->weld_label("labelTXT_TEMPLATE")) + , m_xTemplateBox(m_xBuilder->weld_combo_box("comboBOX_TEMPLATE")) + , m_xPict(new weld::CustomWeld(*m_xBuilder, "drawingareaWN_EXAMPLE", m_aPict)) +{ + m_aPict.SetDropCapsPage(this); + + SetExchangeSupport(); + + const sal_uInt16 nHtmlMode = ::GetHtmlMode(static_cast<const SwDocShell*>(SfxObjectShell::Current())); + m_bHtmlMode = (nHtmlMode & HTMLMODE_ON) != 0; + + // tdf#92154 limit comboBOX_TEMPLATE length + const int nMaxWidth(m_xTemplateBox->get_approximate_digit_width() * 50); + m_xTemplateBox->set_size_request(nMaxWidth , -1); + + // In the template dialog the text is not influenceable + m_xTextText->set_sensitive(!m_bFormat); + m_xTextEdit->set_sensitive(!m_bFormat); + + // Metrics + SetFieldUnit(*m_xDistanceField, GetDfltMetric(m_bHtmlMode)); + + // Install handler + Link<weld::SpinButton&,void> aValueChangedLk = LINK(this, SwDropCapsPage, ValueChangedHdl); + m_xDropCapsField->connect_value_changed(aValueChangedLk); + m_xLinesField->connect_value_changed(aValueChangedLk); + Link<weld::MetricSpinButton&,void> aMetricValueChangedLk = LINK(this, SwDropCapsPage, MetricValueChangedHdl); + m_xDistanceField->connect_value_changed(aMetricValueChangedLk); + m_xTextEdit->connect_changed(LINK(this, SwDropCapsPage, ModifyHdl)); + m_xDropCapsBox->connect_toggled(LINK(this, SwDropCapsPage, ClickHdl)); + m_xTemplateBox->connect_changed(LINK(this, SwDropCapsPage, SelectHdl)); + m_xWholeWordCB->connect_toggled(LINK(this, SwDropCapsPage, WholeWordHdl)); +} + +SwDropCapsPage::~SwDropCapsPage() +{ +} + +DeactivateRC SwDropCapsPage::DeactivatePage(SfxItemSet * _pSet) +{ + if (_pSet) + FillSet(*_pSet); + + return DeactivateRC::LeavePage; +} + +std::unique_ptr<SfxTabPage> SwDropCapsPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet) +{ + return std::make_unique<SwDropCapsPage>(pPage, pController, *rSet); +} + +bool SwDropCapsPage::FillItemSet(SfxItemSet *rSet) +{ + if (m_bModified) + FillSet(*rSet); + return m_bModified; +} + +void SwDropCapsPage::Reset(const SfxItemSet *rSet) +{ + // Characters, lines, gap and text + SwFormatDrop aFormatDrop( rSet->Get(RES_PARATR_DROP) ); + if (aFormatDrop.GetLines() > 1) + { + m_xDropCapsField->set_value(aFormatDrop.GetChars()); + m_xLinesField->set_value(aFormatDrop.GetLines()); + m_xDistanceField->set_value(m_xDistanceField->normalize(aFormatDrop.GetDistance()), FieldUnit::TWIP); + m_xWholeWordCB->set_active(aFormatDrop.GetWholeWord()); + } + else + { + m_xDropCapsField->set_value(1); + m_xLinesField->set_value(3); + m_xDistanceField->set_value(0, FieldUnit::TWIP); + } + + SwView* pView = GetActiveView(); + if (pView) + ::FillCharStyleListBox(*m_xTemplateBox, pView->GetWrtShell().GetView().GetDocShell(), true); + + m_xTemplateBox->insert_text(0, SwResId(SW_STR_NONE)); + + // Reset format + int nSelect = 0; + if (aFormatDrop.GetCharFormat()) + { + int nPos = m_xTemplateBox->find_text(aFormatDrop.GetCharFormat()->GetName()); + if (nPos != -1) + nSelect = nPos; + } + m_xTemplateBox->set_active(nSelect); + + // Enable controls + m_xDropCapsBox->set_active(aFormatDrop.GetLines() > 1); + const sal_Int32 nVal = m_xDropCapsField->get_value(); + if (m_bFormat) + m_xTextEdit->set_text(GetDefaultString(nVal)); + else + { + if (pView) + m_xTextEdit->set_text(pView->GetWrtShell().GetDropText(nVal)); + m_xTextEdit->set_sensitive(true); + m_xTextText->set_sensitive(true); + } + + // Preview + m_aPict.SetValues(m_xTextEdit->get_text(), + sal_uInt8(m_xLinesField->get_value()), + sal_uInt16(m_xDistanceField->denormalize(m_xDistanceField->get_value(FieldUnit::TWIP)))); + + ClickHdl(*m_xDropCapsBox); + m_bModified = false; +} + +IMPL_LINK_NOARG(SwDropCapsPage, ClickHdl, weld::Toggleable&, void) +{ + bool bChecked = m_xDropCapsBox->get_active(); + + m_xWholeWordCB->set_sensitive(bChecked && !m_bHtmlMode); + + m_xSwitchText->set_sensitive(bChecked && !m_xWholeWordCB->get_active()); + m_xDropCapsField->set_sensitive(bChecked && !m_xWholeWordCB->get_active()); + m_xLinesText->set_sensitive( bChecked ); + m_xLinesField->set_sensitive( bChecked ); + m_xDistanceText->set_sensitive( bChecked ); + m_xDistanceField->set_sensitive( bChecked ); + m_xTemplateText->set_sensitive( bChecked ); + m_xTemplateBox->set_sensitive( bChecked ); + m_xTextEdit->set_sensitive( bChecked && !m_bFormat ); + m_xTextText->set_sensitive( bChecked && !m_bFormat ); + + if ( bChecked ) + { + ValueChangedHdl(*m_xDropCapsField); + m_xDropCapsField->grab_focus(); + } + else + m_aPict.SetText(""); + + m_bModified = true; +} + +IMPL_LINK_NOARG(SwDropCapsPage, WholeWordHdl, weld::Toggleable&, void) +{ + m_xDropCapsField->set_sensitive(!m_xWholeWordCB->get_active()); + m_xSwitchText->set_sensitive(!m_xWholeWordCB->get_active()); + + ValueChangedHdl(*m_xDropCapsField); + + m_bModified = true; +} + +void SwDropCapsPage::ModifyEntry(const weld::Entry& rEdit) +{ + OUString sPreview; + + // set text if applicable + if (&rEdit == m_xDropCapsField.get()) + { + const sal_Int32 nVal = !m_xWholeWordCB->get_active() + ? static_cast<sal_Int32>(m_xDropCapsField->get_value()) + : 0; + bool bSetText = false; + + if (SwView* pView = GetActiveView()) + { + if (m_bFormat || pView->GetWrtShell().GetDropText(1).isEmpty()) + sPreview = GetDefaultString(nVal); + else + { + bSetText = true; + sPreview = pView->GetWrtShell().GetDropText(nVal); + } + } + + OUString sEdit(m_xTextEdit->get_text()); + + if (!sEdit.isEmpty() && !sPreview.startsWith(sEdit)) + { + sPreview = sEdit.copy(0, std::min(sEdit.getLength(), sPreview.getLength())); + bSetText = false; + } + + if (bSetText) + m_xTextEdit->set_text(sPreview); + } + else if (&rEdit == m_xTextEdit.get()) // set quantity if applicable + { + const sal_Int32 nTmp = m_xTextEdit->get_text().getLength(); + m_xDropCapsField->set_value(std::max<sal_Int32>(1, nTmp)); + sPreview = m_xTextEdit->get_text(); + } + + // adjust image + if (&rEdit == m_xDropCapsField.get() || &rEdit == m_xTextEdit.get()) + m_aPict.SetText(sPreview); + else if (&rEdit == m_xLinesField.get()) + m_aPict.SetLines(static_cast<sal_uInt8>(m_xLinesField->get_value())); + else + m_aPict.SetDistance(o3tl::narrowing<sal_uInt16>(m_xDistanceField->denormalize(m_xDistanceField->get_value(FieldUnit::TWIP)))); + + m_bModified = true; +} + +IMPL_LINK(SwDropCapsPage, ModifyHdl, weld::Entry&, rEdit, void) +{ + ModifyEntry(rEdit); +} + +IMPL_LINK(SwDropCapsPage, ValueChangedHdl, weld::SpinButton&, rEdit, void) +{ + ModifyEntry(rEdit); +} + +IMPL_LINK(SwDropCapsPage, MetricValueChangedHdl, weld::MetricSpinButton&, rEdit, void) +{ + ModifyEntry(rEdit.get_widget()); +} + +IMPL_LINK_NOARG(SwDropCapsPage, SelectHdl, weld::ComboBox&, void) +{ + m_aPict.UpdatePaintSettings(); + m_bModified = true; +} + +void SwDropCapsPage::FillSet( SfxItemSet &rSet ) +{ + if(!m_bModified) + return; + + SwFormatDrop aFormat; + + bool bOn = m_xDropCapsBox->get_active(); + if (bOn) + { + // quantity, lines, gap + aFormat.GetChars() = static_cast<sal_uInt8>(m_xDropCapsField->get_value()); + aFormat.GetLines() = static_cast<sal_uInt8>(m_xLinesField->get_value()); + aFormat.GetDistance() = o3tl::narrowing<sal_uInt16>(m_xDistanceField->denormalize(m_xDistanceField->get_value(FieldUnit::TWIP))); + aFormat.GetWholeWord() = m_xWholeWordCB->get_active(); + + // template + if (SwView* pView = GetActiveView()) + if (m_xTemplateBox->get_active()) + aFormat.SetCharFormat(pView->GetWrtShell().GetCharStyle(m_xTemplateBox->get_active_text())); + } + else + { + aFormat.GetChars() = 1; + aFormat.GetLines() = 1; + aFormat.GetDistance() = 0; + } + + // set attributes + const SfxPoolItem* pOldItem; + if (nullptr == (pOldItem = GetOldItem(rSet, FN_FORMAT_DROPCAPS)) || aFormat != *pOldItem) + rSet.Put(aFormat); + + // hard text formatting + // Bug 24974: in designer/template catalog this doesn't make sense!! + if (!m_bFormat && m_xDropCapsBox->get_active()) + { + OUString sText(m_xTextEdit->get_text()); + + if (!m_xWholeWordCB->get_active()) + { + sText = sText.copy(0, std::min<sal_Int32>(sText.getLength(), m_xDropCapsField->get_value())); + } + + SfxStringItem aStr(FN_PARAM_1, sText); + rSet.Put(aStr); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/chrdlg/numpara.cxx b/sw/source/ui/chrdlg/numpara.cxx new file mode 100644 index 0000000000..65875eb79c --- /dev/null +++ b/sw/source/ui/chrdlg/numpara.cxx @@ -0,0 +1,418 @@ +/* -*- 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 <swtypes.hxx> +#include <hintids.hxx> +#include <strings.hrc> +#include <sfx2/objsh.hxx> +#include <sfx2/htmlmode.hxx> +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <fmtline.hxx> +#include <numpara.hxx> + +#include <officecfg/Office/Common.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/frame.hxx> +#include <sfx2/viewsh.hxx> + +// tdf#115871 - reset outline and list options to parent settings +const WhichRangesContainer SwParagraphNumTabPage::s_aPageRg( + svl::Items<RES_LINENUMBER, RES_LINENUMBER, SID_ATTR_PARA_NUMRULE, SID_ATTR_PARA_NUMRULE, + SID_ATTR_PARA_OUTLINE_LEVEL, SID_ATTR_PARA_OUTLINE_LEVEL, FN_NUMBER_NEWSTART, + FN_NUMBER_NEWSTART_AT>); + +SwParagraphNumTabPage::SwParagraphNumTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttr) + : SfxTabPage(pPage, pController, "modules/swriter/ui/numparapage.ui", "NumParaPage", &rAttr) + , msOutlineNumbering(SwResId(STR_OUTLINE_NUMBERING )) + , m_bModified(false) + , m_bCurNumrule(false) + , m_xOutlineStartBX(m_xBuilder->weld_widget("boxOUTLINE")) + , m_xOutlineLvLB(m_xBuilder->weld_combo_box("comboLB_OUTLINE_LEVEL")) + , m_xNumberStyleBX(m_xBuilder->weld_widget("boxNUMBER_STYLE")) + , m_xNumberStyleLB(m_xBuilder->weld_combo_box("comboLB_NUMBER_STYLE")) + , m_xEditNumStyleBtn(m_xBuilder->weld_button("editnumstyle")) + , m_xListLvBX(m_xBuilder->weld_widget("boxLIST_LEVEL")) + , m_xListLvLB(m_xBuilder->weld_combo_box("comboLB_LIST_LEVEL")) + , m_xNewStartCB(m_xBuilder->weld_check_button("checkCB_NEW_START")) + , m_xNewStartBX(m_xBuilder->weld_widget("boxNEW_START")) + , m_xNewStartNumberCB(m_xBuilder->weld_check_button("checkCB_NUMBER_NEW_START")) + , m_xNewStartNF(m_xBuilder->weld_spin_button("spinNF_NEW_START")) + , m_xCountParaFram(m_xBuilder->weld_widget("frameFL_COUNT_PARA")) + , m_xCountParaCB(m_xBuilder->weld_check_button("checkCB_COUNT_PARA")) + , m_xRestartParaCountCB(m_xBuilder->weld_check_button("checkCB_RESTART_PARACOUNT")) + , m_xRestartBX(m_xBuilder->weld_widget("boxRESTART_NO")) + , m_xRestartNF(m_xBuilder->weld_spin_button("spinNF_RESTART_PARA")) +{ + m_xNewStartCB->set_state(TRISTATE_FALSE); + m_xNewStartNumberCB->set_state(TRISTATE_FALSE); + m_xCountParaCB->set_state(TRISTATE_FALSE); + m_xRestartParaCountCB->set_state(TRISTATE_FALSE); + m_xEditNumStyleBtn->set_sensitive(false); + + const SfxUInt16Item* pItem = rAttr.GetItemIfSet(SID_HTML_MODE, false); + if (!pItem) + { + if (SfxObjectShell* pObjSh = SfxObjectShell::Current()) + pItem = pObjSh->GetItem(SID_HTML_MODE); + } + if(pItem) + { + const sal_uInt16 nHtmlMode = pItem->GetValue(); + + if (HTMLMODE_ON & nHtmlMode) + m_xCountParaFram->hide(); + } + + m_xNewStartCB->connect_toggled(LINK(this, SwParagraphNumTabPage, NewStartHdl_Impl)); + m_xNewStartNumberCB->connect_toggled(LINK(this, SwParagraphNumTabPage, NewStartHdl_Impl)); + m_xNumberStyleLB->connect_changed(LINK(this, SwParagraphNumTabPage, StyleHdl_Impl)); + m_xCountParaCB->connect_toggled(LINK(this, SwParagraphNumTabPage, LineCountHdl_Impl)); + m_xRestartParaCountCB->connect_toggled(LINK(this, SwParagraphNumTabPage, LineCountHdl_Impl)); + m_xNumberStyleLB->connect_changed(LINK(this, SwParagraphNumTabPage, EditNumStyleSelectHdl_Impl)); + m_xEditNumStyleBtn->connect_clicked(LINK(this, SwParagraphNumTabPage, EditNumStyleHdl_Impl)); + + if (officecfg::Office::Common::Misc::ExperimentalMode::get()) + m_xListLvBX->show(); + else + m_xListLvBX->hide(); +} + +SwParagraphNumTabPage::~SwParagraphNumTabPage() +{ +} + +std::unique_ptr<SfxTabPage> SwParagraphNumTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet) +{ + return std::make_unique<SwParagraphNumTabPage>(pPage, pController, *rSet); +} + +bool SwParagraphNumTabPage::FillItemSet( SfxItemSet* rSet ) +{ + if (m_xOutlineLvLB->get_value_changed_from_saved()) + { + const sal_uInt16 aOutlineLv = m_xOutlineLvLB->get_active(); + const SfxUInt16Item* pOldOutlineLv = GetOldItem( *rSet, SID_ATTR_PARA_OUTLINE_LEVEL); + if (pOldOutlineLv) + { + std::unique_ptr<SfxUInt16Item> pOutlineLv(pOldOutlineLv->Clone()); + pOutlineLv->SetValue( aOutlineLv ); + rSet->Put(std::move(pOutlineLv)); + m_bModified = true; + + // Does List Level need to be set to be the same as Outline Level? + if (!m_xListLvLB->get_active() && m_xListLvBX->get_visible() + && !m_xListLvLB->get_value_changed_from_saved()) + { + sal_Int16 nListLevel = std::max<sal_Int16>(1, aOutlineLv); + --nListLevel; // Outline Level is 1 based. List Level is zero based. + rSet->Put(SfxInt16Item(RES_PARATR_LIST_LEVEL, nListLevel)); + } + } + } + + if (m_xListLvLB->get_value_changed_from_saved()) + { + if (m_xListLvBX->get_visible()) + { + sal_Int16 nListLevel = m_xListLvLB->get_active(); + // Does List Level need to be set to be the same as Outline Level? + if (!nListLevel) + { + nListLevel = std::max<sal_Int16>(1, m_xOutlineLvLB->get_active()); + } + --nListLevel; // List Level is zero based, but both listboxes are 1-based. + + rSet->Put(SfxInt16Item(RES_PARATR_LIST_LEVEL, nListLevel)); + m_bModified = true; + } + } + + if (m_xNumberStyleLB->get_value_changed_from_saved()) + { + OUString aStyle; + if (m_xNumberStyleLB->get_active()) + aStyle = m_xNumberStyleLB->get_active_text(); + const SfxStringItem* pOldRule = static_cast<const SfxStringItem*>(GetOldItem( *rSet, SID_ATTR_PARA_NUMRULE)); + if (pOldRule) + { + std::unique_ptr<SfxStringItem> pRule(pOldRule->Clone()); + pRule->SetValue(aStyle); + rSet->Put(std::move(pRule)); + m_bModified = true; + } + } + if (m_xNewStartCB->get_state_changed_from_saved() || + m_xNewStartNumberCB->get_state_changed_from_saved()|| + m_xNewStartNF->get_value_changed_from_saved()) + { + m_bModified = true; + bool bNewStartChecked = TRISTATE_TRUE == m_xNewStartCB->get_state(); + bool bNumberNewStartChecked = TRISTATE_TRUE == m_xNewStartNumberCB->get_state(); + rSet->Put(SfxBoolItem(FN_NUMBER_NEWSTART, bNewStartChecked)); + rSet->Put(SfxUInt16Item(FN_NUMBER_NEWSTART_AT, + bNumberNewStartChecked && bNewStartChecked ? o3tl::narrowing<sal_uInt16>(m_xNewStartNF->get_value()) : USHRT_MAX)); + } + + if (m_xCountParaCB->get_state_changed_from_saved()|| + m_xRestartParaCountCB->get_state_changed_from_saved() || + m_xRestartNF->get_value_changed_from_saved()) + { + SwFormatLineNumber aFormat; + aFormat.SetStartValue( static_cast< sal_uLong >(m_xRestartParaCountCB->get_state() == TRISTATE_TRUE ? + m_xRestartNF->get_value() : 0 )); + aFormat.SetCountLines(m_xCountParaCB->get_active()); + rSet->Put(aFormat); + m_bModified = true; + } + return m_bModified; +} + +void SwParagraphNumTabPage::ChangesApplied() +{ + m_xOutlineLvLB->save_value(); + m_xNumberStyleLB->save_value(); + m_xListLvLB->save_value(); + m_xNewStartCB->save_state(); + m_xNewStartNumberCB->save_state(); + m_xCountParaCB->save_state(); + m_xRestartParaCountCB->save_state(); + m_xRestartNF->save_value(); +} + +void SwParagraphNumTabPage::Reset(const SfxItemSet* rSet) +{ + bool bHasNumberStyle = false; + + SfxItemState eItemState = rSet->GetItemState( GetWhich(SID_ATTR_PARA_OUTLINE_LEVEL) ); + + sal_Int16 nOutlineLv = 1; // 0 is Text Body, 1 is level 1 + if( eItemState >= SfxItemState::DEFAULT ) + { + nOutlineLv = rSet->Get( GetWhich(SID_ATTR_PARA_OUTLINE_LEVEL) ).GetValue(); + m_xOutlineLvLB->set_active(nOutlineLv) ; + } + else + { + m_xOutlineLvLB->set_active(-1); + } + m_xOutlineLvLB->save_value(); + + eItemState = rSet->GetItemState(RES_PARATR_LIST_LEVEL); + if (eItemState >= SfxItemState::DEFAULT) + { + sal_Int16 nListLevel = rSet->Get(RES_PARATR_LIST_LEVEL).GetValue(); // 0 is level 1 + // Although listLevel doesn't have outline's "Text Body" level, treat it the same as level 1 + // so that if the outline level is either 0 or 1, it is considered equal to list level 1. + // This is a rather crucial discrepancy - otherwise the user will rarely see + // list level using the special "Same as outline level, + // and the highly desirable state of keeping the two in sync will rarely be achieved. + if ((!nOutlineLv && !nListLevel) || nListLevel == nOutlineLv - 1) + m_xListLvLB->set_active(0); // highly encourage using "Same as outline level" + else + m_xListLvLB->set_active(nListLevel + 1); + } + else + { + m_xListLvBX->hide(); + } + m_xListLvLB->save_value(); + + eItemState = rSet->GetItemState( GetWhich(SID_ATTR_PARA_NUMRULE) ); + + if( eItemState >= SfxItemState::DEFAULT ) + { + OUString aStyle = static_cast<const SfxStringItem &>(rSet->Get( GetWhich(SID_ATTR_PARA_NUMRULE) )).GetValue(); + if(aStyle.isEmpty()) + aStyle = m_xNumberStyleLB->get_text(0); + + if( aStyle == "Outline") + { + if (m_xNumberStyleLB->find_id("pseudo") == -1) + { + // tdf#145804 show "Chapter Numbering" + m_xNumberStyleLB->append("pseudo", msOutlineNumbering); + } + m_xNumberStyleLB->set_active_id("pseudo"); + m_xNumberStyleLB->save_value(); + } + else + m_xNumberStyleLB->set_active_text(aStyle); + + bHasNumberStyle = true; + } + else + { + m_xNumberStyleLB->set_active(-1); + } + + if (m_xNumberStyleBX->get_sensitive()) + EditNumStyleSelectHdl_Impl(*m_xNumberStyleLB); + + m_xNumberStyleLB->save_value(); + + eItemState = rSet->GetItemState( FN_NUMBER_NEWSTART ); + if(eItemState > SfxItemState::DEFAULT ) + { + m_bCurNumrule = true; + const SfxBoolItem& rStart = static_cast<const SfxBoolItem&>(rSet->Get(FN_NUMBER_NEWSTART)); + + m_xNewStartCB->set_state(rStart.GetValue() ? TRISTATE_TRUE : TRISTATE_FALSE ); + } + else + m_xNewStartCB->set_state(bHasNumberStyle ? TRISTATE_FALSE : TRISTATE_INDET); + + m_xNewStartCB->save_state(); + + eItemState = rSet->GetItemState( FN_NUMBER_NEWSTART_AT); + if( eItemState > SfxItemState::DEFAULT ) + { + const sal_uInt16 nNewStart = rSet->Get(FN_NUMBER_NEWSTART_AT).GetValue(); + const bool bNotMax = USHRT_MAX != nNewStart; + m_xNewStartNumberCB->set_active(bNotMax); + m_xNewStartNF->set_value(bNotMax ? nNewStart : 1); + } + else + m_xNewStartCB->set_state(TRISTATE_INDET); + NewStartHdl_Impl(*m_xNewStartCB); + m_xNewStartNF->save_value(); + m_xNewStartNumberCB->save_state(); + StyleHdl_Impl(*m_xNumberStyleLB); + if( SfxItemState::DEFAULT <= rSet->GetItemState(RES_LINENUMBER)) + { + const SwFormatLineNumber& rNum = rSet->Get(RES_LINENUMBER); + sal_uLong nStartValue = rNum.GetStartValue(); + bool bCount = rNum.IsCount(); + m_xCountParaCB->set_state(bCount ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xRestartParaCountCB->set_state(0 != nStartValue ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xRestartNF->set_value(nStartValue == 0 ? 1 : nStartValue); + LineCountHdl_Impl(*m_xCountParaCB); + } + else + { + m_xCountParaCB->set_state(TRISTATE_INDET); + m_xRestartParaCountCB->set_state(TRISTATE_INDET); + } + m_xCountParaCB->save_state(); + m_xRestartParaCountCB->save_state(); + m_xRestartNF->save_value(); + + m_bModified = false; +} + +void SwParagraphNumTabPage::DisableOutline() +{ + m_xOutlineStartBX->set_sensitive(false); + m_xOutlineStartBX->set_tooltip_text( SwResId(STR_OUTLINENUMBERING_DISABLED) ); +} + +void SwParagraphNumTabPage::DisableNumbering() +{ + m_xNumberStyleBX->set_sensitive(false); + m_xNumberStyleBX->set_tooltip_text( SwResId(STR_OUTLINENUMBERING_DISABLED) ); + m_xListLvBX->set_sensitive(false); +} + +void SwParagraphNumTabPage::EnableNewStart() +{ + m_xNewStartCB->show(); + m_xNewStartBX->show(); +} + +IMPL_LINK_NOARG(SwParagraphNumTabPage, NewStartHdl_Impl, weld::Toggleable&, void) +{ + bool bEnable = m_xNewStartCB->get_active(); + m_xNewStartNumberCB->set_sensitive(bEnable); + m_xNewStartNF->set_sensitive(bEnable && m_xNewStartNumberCB->get_active()); +} + +IMPL_LINK_NOARG(SwParagraphNumTabPage, LineCountHdl_Impl, weld::Toggleable&, void) +{ + m_xRestartParaCountCB->set_sensitive(m_xCountParaCB->get_active()); + + bool bEnableRestartValue = m_xRestartParaCountCB->get_sensitive() && + m_xRestartParaCountCB->get_active(); + m_xRestartBX->set_sensitive(bEnableRestartValue); +} + +IMPL_LINK_NOARG(SwParagraphNumTabPage, EditNumStyleSelectHdl_Impl, weld::ComboBox&, void) +{ + int numSelectPos = m_xNumberStyleLB->get_active(); + // 0 is "None" and -1 is unselected state and a "pseudo" is uneditable "Chapter Numbering" + if (numSelectPos == 0 || numSelectPos == -1 || m_xNumberStyleLB->get_active_id() == "pseudo") + { + m_xEditNumStyleBtn->set_sensitive(false); + m_xListLvBX->set_sensitive(false); + } + else + { + m_xEditNumStyleBtn->set_sensitive(true); + m_xListLvBX->set_sensitive(true); + } +} + +IMPL_LINK_NOARG(SwParagraphNumTabPage, EditNumStyleHdl_Impl, weld::Button&, void) +{ + OUString aTemplName(m_xNumberStyleLB->get_active_text()); + ExecuteEditNumStyle_Impl( SID_STYLE_EDIT, aTemplName, SfxStyleFamily::Pseudo ); +} + +// Internal: Perform functions through the Dispatcher +void SwParagraphNumTabPage::ExecuteEditNumStyle_Impl( + sal_uInt16 nId, const OUString &rStr, SfxStyleFamily nFamily) +{ + SfxViewShell* pViewShell = SfxViewShell::Current(); + + if( !pViewShell) + return; + + SfxDispatcher* pDispatcher = pViewShell->GetDispatcher(); + SfxStringItem aItem(nId, rStr); + SfxUInt16Item aFamily(SID_STYLE_FAMILY, static_cast<sal_uInt16>(nFamily)); + const SfxPoolItem* pItems[ 3 ]; + sal_uInt16 nCount = 0; + if( !rStr.isEmpty() ) + pItems[ nCount++ ] = &aItem; + pItems[ nCount++ ] = &aFamily; + + pItems[ nCount++ ] = nullptr; + + // tdf#145363 we want the current dialog to be the parent of the new dialog + weld::Window* pDialogParent = GetFrameWeld(); + css::uno::Any aAny(pDialogParent->GetXWindow()); + SfxUnoAnyItem aDialogParent(SID_DIALOG_PARENT, aAny); + const SfxPoolItem* pInternalItems[ 2 ]; + pInternalItems[ 0 ] = &aDialogParent; + pInternalItems[ 1 ] = nullptr; + + pDispatcher->Execute( + nId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD, + pItems, 0, pInternalItems); +} + +IMPL_LINK(SwParagraphNumTabPage, StyleHdl_Impl, weld::ComboBox&, rBox, void) +{ + bool bEnable = m_bCurNumrule || rBox.get_active() > 0; + m_xNewStartCB->set_sensitive(bEnable); + NewStartHdl_Impl(*m_xNewStartCB); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/chrdlg/pardlg.cxx b/sw/source/ui/chrdlg/pardlg.cxx new file mode 100644 index 0000000000..379ee335ca --- /dev/null +++ b/sw/source/ui/chrdlg/pardlg.cxx @@ -0,0 +1,245 @@ +/* -*- 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/htmlmode.hxx> +#include <sfx2/tabdlg.hxx> +#include <svl/style.hxx> +#include <svl/cjkoptions.hxx> +#include <docsh.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <swuipardlg.hxx> +#include <pardlg.hxx> +#include <drpcps.hxx> +#include <viewopt.hxx> +#include <numpara.hxx> +#include <strings.hrc> +#include <svx/svxids.hrc> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svx/svxdlg.hxx> +#include <svx/dialogs.hrc> +#include <svx/flagsdef.hxx> +#include <osl/diagnose.h> +#include <officecfg/Office/Common.hxx> + +SwParaDlg::SwParaDlg(weld::Window *pParent, + SwView& rVw, + const SfxItemSet& rCoreSet, + sal_uInt8 nDialogMode, + const OUString *pTitle, + bool bDraw, + const OUString& sDefPage) + : SfxTabDialogController(pParent, + "modules/swriter/ui/paradialog.ui", + "ParagraphPropertiesDialog", + &rCoreSet, nullptr != pTitle) + , m_rView(rVw) + , m_bDrawParaDlg(bDraw) +{ + sal_uInt16 nHtmlMode = ::GetHtmlMode(rVw.GetDocShell()); + bool bHtmlMode = (nHtmlMode & HTMLMODE_ON) == HTMLMODE_ON; + if(pTitle) + { + // Update title + m_xDialog->set_title(m_xDialog->get_title() + SwResId(STR_TEXTCOLL_HEADER) + *pTitle + ")"); + } + // tabs common to paragraph and draw paragraphs (paragraphs inside a text box) + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + + OSL_ENSURE(pFact->GetTabPageCreatorFunc(RID_SVXPAGE_STD_PARAGRAPH), "GetTabPageCreatorFunc fail!"); + OSL_ENSURE(pFact->GetTabPageRangesFunc(RID_SVXPAGE_STD_PARAGRAPH), "GetTabPageRangesFunc fail!"); + AddTabPage("labelTP_PARA_STD", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_STD_PARAGRAPH), + pFact->GetTabPageRangesFunc(RID_SVXPAGE_STD_PARAGRAPH) ); + + OSL_ENSURE(pFact->GetTabPageCreatorFunc(RID_SVXPAGE_ALIGN_PARAGRAPH), "GetTabPageCreatorFunc fail!"); + OSL_ENSURE(pFact->GetTabPageRangesFunc(RID_SVXPAGE_ALIGN_PARAGRAPH), "GetTabPageRangesFunc fail!"); + AddTabPage("labelTP_PARA_ALIGN", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_ALIGN_PARAGRAPH), + pFact->GetTabPageRangesFunc(RID_SVXPAGE_ALIGN_PARAGRAPH)); + + if (!m_bDrawParaDlg && (!bHtmlMode || officecfg::Office::Common::Filter::HTML::Export::PrintLayout::get())) + { + OSL_ENSURE(pFact->GetTabPageCreatorFunc(RID_SVXPAGE_EXT_PARAGRAPH), "GetTabPageCreatorFunc fail!"); + OSL_ENSURE(pFact->GetTabPageRangesFunc(RID_SVXPAGE_EXT_PARAGRAPH), "GetTabPageRangesFunc fail!"); + AddTabPage("textflow", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_EXT_PARAGRAPH), + pFact->GetTabPageRangesFunc(RID_SVXPAGE_EXT_PARAGRAPH)); + + } + else + RemoveTabPage("textflow"); + + if(!bHtmlMode && SvtCJKOptions::IsAsianTypographyEnabled()) + { + OSL_ENSURE(pFact->GetTabPageCreatorFunc(RID_SVXPAGE_PARA_ASIAN), "GetTabPageCreatorFunc fail!"); + OSL_ENSURE(pFact->GetTabPageRangesFunc(RID_SVXPAGE_PARA_ASIAN), "GetTabPageRangesFunc fail!"); + AddTabPage( "labelTP_PARA_ASIAN", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_PARA_ASIAN), + pFact->GetTabPageRangesFunc(RID_SVXPAGE_PARA_ASIAN) ); + } + else + RemoveTabPage("labelTP_PARA_ASIAN"); + + if(bHtmlMode) + RemoveTabPage("labelTP_TABULATOR"); + else + { + OSL_ENSURE(pFact->GetTabPageCreatorFunc(RID_SVXPAGE_TABULATOR), "GetTabPageCreatorFunc fail!"); + OSL_ENSURE(pFact->GetTabPageRangesFunc(RID_SVXPAGE_TABULATOR), "GetTabPageRangesFunc fail!"); + AddTabPage( "labelTP_TABULATOR", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_TABULATOR), pFact->GetTabPageRangesFunc(RID_SVXPAGE_TABULATOR) ); + } + + // remove unwanted tabs for draw text box paragraph properties + if (m_bDrawParaDlg) + { + RemoveTabPage("labelTP_NUMPARA"); + RemoveTabPage("labelTP_DROPCAPS"); + RemoveTabPage("labelTP_BORDER"); + RemoveTabPage("area"); + RemoveTabPage("transparence"); + } + else + { + if(!(nDialogMode & DLG_ENVELOP)) + AddTabPage("labelTP_NUMPARA", SwParagraphNumTabPage::Create, SwParagraphNumTabPage::GetRanges); + else + RemoveTabPage("labelTP_NUMPARA"); + + AddTabPage("labelTP_DROPCAPS", SwDropCapsPage::Create, SwDropCapsPage::GetRanges); + + if(!bHtmlMode || (nHtmlMode & (HTMLMODE_SOME_STYLES|HTMLMODE_FULL_STYLES))) + { + // add Area and Transparence TabPages + AddTabPage("area", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_AREA ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_AREA )); + AddTabPage("transparence", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_TRANSPARENCE ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_TRANSPARENCE ) ); + } + else + { + RemoveTabPage("area"); + RemoveTabPage("transparence"); + } + + OSL_ENSURE(pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BORDER ), "GetTabPageCreatorFunc fail!"); + OSL_ENSURE(pFact->GetTabPageRangesFunc( RID_SVXPAGE_BORDER ), "GetTabPageRangesFunc fail!"); + AddTabPage("labelTP_BORDER", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BORDER ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_BORDER ) ); + } + + if (!sDefPage.isEmpty()) + SetCurPageId(sDefPage); +} + +SwParaDlg::~SwParaDlg() +{ +} + +void SwParaDlg::PageCreated(const OUString& rId, SfxTabPage& rPage) +{ + SwWrtShell& rSh = m_rView.GetWrtShell(); + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + + // Table borders cannot get any shade in Writer + if (rId == "labelTP_BORDER") + { + aSet.Put (SfxUInt16Item(SID_SWMODE_TYPE,static_cast<sal_uInt16>(SwBorderModes::PARA))); + rPage.PageCreated(aSet); + } + else if (rId == "labelTP_PARA_STD") + { + aSet.Put(SfxUInt16Item(SID_SVXSTDPARAGRAPHTABPAGE_PAGEWIDTH, + static_cast< sal_uInt16 >(rSh.GetAnyCurRect(CurRectType::PagePrt).Width()) )); + + if (!m_bDrawParaDlg) + { + // See SvxStdParagraphTabPage::PageCreated: enable RegisterMode, AutoFirstLine, NegativeMode, ContextualMode + constexpr tools::Long constTwips_0_5mm = o3tl::toTwips(5, o3tl::Length::mm10); + aSet.Put(SfxUInt32Item(SID_SVXSTDPARAGRAPHTABPAGE_FLAGSET,0x0002|0x0004|0x0008|0x0010)); + aSet.Put(SfxUInt32Item(SID_SVXSTDPARAGRAPHTABPAGE_ABSLINEDIST, constTwips_0_5mm)); + + } + rPage.PageCreated(aSet); + } + else if (rId == "labelTP_PARA_ALIGN") + { + if (!m_bDrawParaDlg) + { + aSet.Put(SfxBoolItem(SID_SVXPARAALIGNTABPAGE_ENABLEJUSTIFYEXT,true)); + rPage.PageCreated(aSet); + } + } + else if (rId == "textflow") + { + // pagebreak only when the cursor is in the body-area and not in a table + const FrameTypeFlags eType = rSh.GetFrameType(nullptr,true); + if( !(FrameTypeFlags::BODY & eType) || + rSh.GetSelectionType() & SelectionType::Table ) + { + aSet.Put(SfxBoolItem(SID_DISABLE_SVXEXTPARAGRAPHTABPAGE_PAGEBREAK,true)); + rPage.PageCreated(aSet); + } + } + else if (rId == "labelTP_DROPCAPS") + { + static_cast<SwDropCapsPage&>(rPage).SetFormat(false); + } + else if (rId == "labelTP_NUMPARA") + { + SwTextFormatColl* pTmpColl = rSh.GetCurTextFormatColl(); + if( pTmpColl && pTmpColl->IsAssignedToListLevelOfOutlineStyle() ) + { + static_cast<SwParagraphNumTabPage&>(rPage).DisableOutline() ; + } + + static_cast<SwParagraphNumTabPage&>(rPage).EnableNewStart(); + weld::ComboBox& rBox = static_cast<SwParagraphNumTabPage&>(rPage).GetStyleBox(); + SfxStyleSheetBasePool* pPool = m_rView.GetDocShell()->GetStyleSheetPool(); + const SfxStyleSheetBase* pBase = pPool->First(SfxStyleFamily::Pseudo); + std::set<OUString> aNames; + while(pBase) + { + aNames.insert(pBase->GetName()); + pBase = pPool->Next(); + } + aNames.erase(SwResId(STR_POOLNUMRULE_NOLIST)); + for (const auto& rName : aNames) + rBox.append_text(rName); + } + // inits for Area and Transparency TabPages + // The selection attribute lists (XPropertyList derivates, e.g. XColorList for + // the color table) need to be added as items (e.g. SvxColorTableItem) to make + // these pages find the needed attributes for fill style suggestions. + // These are added in SwDocStyleSheet::GetItemSet() for the SfxStyleFamily::Para on + // demand, but could also be directly added from the DrawModel. + else if (rId == "area") + { + SfxItemSetFixed + <SID_COLOR_TABLE, SID_PATTERN_LIST, + SID_OFFER_IMPORT, SID_OFFER_IMPORT> aNew(*aSet.GetPool()); + + aNew.Put(*GetInputSetImpl()); + + // add flag for direct graphic content selection + aNew.Put(SfxBoolItem(SID_OFFER_IMPORT, true)); + + rPage.PageCreated(aNew); + } + else if (rId == "transparence") + { + rPage.PageCreated(*GetInputSetImpl()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/chrdlg/swuiccoll.cxx b/sw/source/ui/chrdlg/swuiccoll.cxx new file mode 100644 index 0000000000..8dddc8a410 --- /dev/null +++ b/sw/source/ui/chrdlg/swuiccoll.cxx @@ -0,0 +1,247 @@ +/* -*- 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 <memory> +#include <cmdid.h> +#include <o3tl/safeint.hxx> +#include <swmodule.hxx> +#include <view.hxx> +#include <wrtsh.hxx> + +#include <sfx2/styfitem.hxx> + +#include <ccoll.hxx> +#include <fmtcol.hxx> +#include <hintids.hxx> +#include <docsh.hxx> + +#include <swuiccoll.hxx> + +const WhichRangesContainer SwCondCollPage::s_aPageRg(svl::Items<FN_COND_COLL, FN_COND_COLL>); + +SwCondCollPage::SwCondCollPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/conditionpage.ui", "ConditionPage", &rSet) + , m_pCmds(SwCondCollItem::GetCmds()) + , m_pFormat(nullptr) + , m_xTbLinks(m_xBuilder->weld_tree_view("links")) + , m_xStyleLB(m_xBuilder->weld_tree_view("styles")) + , m_xFilterLB(m_xBuilder->weld_combo_box("filter")) + , m_xRemovePB(m_xBuilder->weld_button("remove")) + , m_xAssignPB(m_xBuilder->weld_button("apply")) +{ + m_xStyleLB->make_sorted(); + const auto nHeightRequest = m_xStyleLB->get_height_rows(12); + m_xStyleLB->set_size_request(-1, nHeightRequest); + m_xTbLinks->set_size_request(-1, nHeightRequest); + std::vector<int> aWidths + { + o3tl::narrowing<int>(m_xTbLinks->get_approximate_digit_width() * 40) + }; + m_xTbLinks->set_column_fixed_widths(aWidths); + + const sal_Int32 nStrCount = m_xFilterLB->get_count(); + for (sal_Int32 i = 0; i < nStrCount; ++i) + m_aStrArr.push_back(m_xFilterLB->get_text(i)); + m_xFilterLB->clear(); + + SetExchangeSupport(); + + // Install handlers + m_xTbLinks->connect_row_activated(LINK(this, SwCondCollPage, AssignRemoveTreeListBoxHdl)); + m_xStyleLB->connect_row_activated(LINK(this, SwCondCollPage, AssignRemoveTreeListBoxHdl)); + m_xRemovePB->connect_clicked(LINK(this, SwCondCollPage, AssignRemoveClickHdl)); + m_xAssignPB->connect_clicked(LINK(this, SwCondCollPage, AssignRemoveClickHdl)); + m_xTbLinks->connect_changed(LINK(this, SwCondCollPage, SelectTreeListBoxHdl)); + m_xStyleLB->connect_changed(LINK(this, SwCondCollPage, SelectTreeListBoxHdl)); + m_xFilterLB->connect_changed(LINK(this, SwCondCollPage, SelectListBoxHdl)); + + std::optional<SfxStyleFamilies> xFamilies(SW_MOD()->CreateStyleFamilies()); + size_t nCount = xFamilies->size(); + for (size_t j = 0; j < nCount; ++j) + { + const SfxStyleFamilyItem &rFamilyItem = xFamilies->at(j); + if (SfxStyleFamily::Para == rFamilyItem.GetFamily()) + { + const SfxStyleFilter& rFilterList = rFamilyItem.GetFilterList(); + for (size_t i = 0; i < rFilterList.size(); ++i) + m_xFilterLB->append(OUString::number(int(rFilterList[i].nFlags)), rFilterList[i].aName); + break; + } + } + + m_xFilterLB->set_active(0); + m_xTbLinks->show(); +} + +SwCondCollPage::~SwCondCollPage() +{ +} + +DeactivateRC SwCondCollPage::DeactivatePage(SfxItemSet * _pSet) +{ + if( _pSet ) + FillItemSet(_pSet); + + return DeactivateRC::LeavePage; +} + +std::unique_ptr<SfxTabPage> SwCondCollPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet) +{ + return std::make_unique<SwCondCollPage>(pPage, pController, *rSet); +} + +bool SwCondCollPage::FillItemSet(SfxItemSet *rSet) +{ + SwCondCollItem aCondItem; + for (size_t i = 0; i < m_aStrArr.size(); ++i) + { + const OUString sEntry = m_xTbLinks->get_text(i, 1); + aCondItem.SetStyle( &sEntry, i); + } + rSet->Put(aCondItem); + return true; +} + +void SwCondCollPage::Reset(const SfxItemSet *) +{ + m_xTbLinks->clear(); + m_xStyleLB->clear(); + + SwView* pView = GetActiveView(); + if (!pView) + return; + + SfxStyleSheetBasePool* pPool = pView->GetWrtShell().GetView().GetDocShell()->GetStyleSheetPool(); + const SfxStyleSheetBase* pBase = pPool->First(SfxStyleFamily::Para); + while (pBase) + { + if (!m_pFormat || pBase->GetName() != m_pFormat->GetName()) + m_xStyleLB->append_text(pBase->GetName()); + pBase = pPool->Next(); + } + m_xStyleLB->select(0); + + for (size_t n = 0; n < m_aStrArr.size(); ++n) + { + m_xTbLinks->append_text(m_aStrArr[n]); + + const SwCollCondition* pCond = nullptr; + if( m_pFormat && RES_CONDTXTFMTCOLL == m_pFormat->Which() && + nullptr != ( pCond = static_cast<SwConditionTextFormatColl*>(m_pFormat)-> + HasCondition( SwCollCondition( nullptr, m_pCmds[n].nCnd, m_pCmds[n].nSubCond ) ) ) + && pCond->GetTextFormatColl() ) + { + m_xTbLinks->set_text(n, pCond->GetTextFormatColl()->GetName(), 1); + } + + if (0 == n) + { + m_xTbLinks->select(0); + SelectTreeListBoxHdl(*m_xTbLinks); + } + } +} + +IMPL_LINK(SwCondCollPage, AssignRemoveClickHdl, weld::Button&, rBtn, void) +{ + AssignRemove(&rBtn); +} + +IMPL_LINK(SwCondCollPage, AssignRemoveTreeListBoxHdl, weld::TreeView&, rBtn, bool) +{ + AssignRemove(&rBtn); + return true; +} + +void SwCondCollPage::AssignRemove(const weld::Widget* pBtn) +{ + int nPos = m_xTbLinks->get_selected_index(); + if (nPos == -1) + { + return; + } + + const bool bAssEnabled = pBtn != m_xRemovePB.get() && m_xAssignPB->get_sensitive(); + m_xAssignPB->set_sensitive(!bAssEnabled); + m_xRemovePB->set_sensitive(bAssEnabled); + if (bAssEnabled) + m_xTbLinks->set_text(nPos, m_xStyleLB->get_selected_text(), 1); + else + m_xTbLinks->set_text(nPos, "", 1); +} + +IMPL_LINK(SwCondCollPage, SelectTreeListBoxHdl, weld::TreeView&, rBox, void) +{ + SelectHdl(&rBox); +} + +IMPL_LINK(SwCondCollPage, SelectListBoxHdl, weld::ComboBox&, rBox, void) +{ + SelectHdl(&rBox); +} + +void SwCondCollPage::SelectHdl(const weld::Widget* pBox) +{ + if (pBox == m_xFilterLB.get()) + { + m_xStyleLB->clear(); + + SwView* pView = GetActiveView(); + if (!pView) + return; + + const sal_Int32 nSelPos = m_xFilterLB->get_active(); + const SfxStyleSearchBits nSearchFlags = static_cast<SfxStyleSearchBits>(m_xFilterLB->get_id(nSelPos).toInt32()); + SfxStyleSheetBasePool* pPool = pView->GetWrtShell().GetView().GetDocShell()->GetStyleSheetPool(); + const SfxStyleSheetBase* pBase = pPool->First(SfxStyleFamily::Para, nSearchFlags); + + bool bEmpty = true; + while (pBase) + { + if (!m_pFormat || pBase->GetName() != m_pFormat->GetName()) + { + m_xStyleLB->append_text(pBase->GetName()); + bEmpty = false; + } + pBase = pPool->Next(); + } + m_xStyleLB->select(bEmpty ? -1 : 0); + SelectHdl(m_xStyleLB.get()); + } + else + { + int nSelected = m_xTbLinks->get_selected_index(); + const OUString sTbEntry = nSelected != -1 + ? m_xTbLinks->get_text(nSelected, 1) + : OUString(); + const OUString sStyle = m_xStyleLB->get_selected_text(); + + m_xAssignPB->set_sensitive(sStyle != sTbEntry); + + if (pBox != m_xStyleLB.get()) + m_xRemovePB->set_sensitive(!sTbEntry.isEmpty()); + } +} + +void SwCondCollPage::SetCollection(SwFormat* pFormat) +{ + m_pFormat = pFormat; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/chrdlg/tblnumfm.cxx b/sw/source/ui/chrdlg/tblnumfm.cxx new file mode 100644 index 0000000000..dd3f575e2b --- /dev/null +++ b/sw/source/ui/chrdlg/tblnumfm.cxx @@ -0,0 +1,46 @@ +/* -*- 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/svxids.hrc> +#include <svx/numinf.hxx> +#include <tblnumfm.hxx> + +#include <svx/dialogs.hrc> +#include <svl/itemset.hxx> +#include <sfx2/sfxdlg.hxx> +#include <sfx2/tabdlg.hxx> + +SwNumFormatDlg::SwNumFormatDlg(weld::Widget* pParent, const SfxItemSet& rSet) + : SfxSingleTabDialogController(pParent, &rSet, "cui/ui/formatnumberdialog.ui", "FormatNumberDialog") + , m_xContent( m_xBuilder->weld_container("content") ) +{ + // Create TabPage + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + ::CreateTabPage fnCreatePage = pFact->GetTabPageCreatorFunc(RID_SVXPAGE_NUMBERFORMAT); + if ( fnCreatePage ) + { + std::unique_ptr<SfxTabPage> xNewPage = (*fnCreatePage)(m_xContent.get(), this, &rSet); + SfxAllItemSet aSet(*(rSet.GetPool())); + aSet.Put(xNewPage->GetItemSet().Get( SID_ATTR_NUMBERFORMAT_INFO)); + xNewPage->PageCreated(aSet); + SetTabPage(std::move(xNewPage)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/config/mailconfigpage.cxx b/sw/source/ui/config/mailconfigpage.cxx new file mode 100644 index 0000000000..0bf9633abd --- /dev/null +++ b/sw/source/ui/config/mailconfigpage.cxx @@ -0,0 +1,578 @@ +/* -*- 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 <swtypes.hxx> +#include <mailconfigpage.hxx> +#include <mmconfigitem.hxx> +#include <mailmergehelper.hxx> +#include <officecfg/Office/Writer.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/mail/MailServiceType.hpp> +#include <com/sun/star/mail/XMailService.hpp> +#include <com/sun/star/mail/MailServiceProvider.hpp> +#include <strings.hrc> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::mail; +using namespace ::com::sun::star::beans; + +class SwTestAccountSettingsDialog : public SfxDialogController +{ + ImplSVEvent* m_pPostedEvent; + OUString m_sCompleted; + OUString m_sFailed; + OUString m_sErrorServer; + bool m_bStop; + + SwMailConfigPage* m_pParent; + + std::unique_ptr<weld::Button> m_xStopPB; + std::unique_ptr<weld::TextView> m_xErrorsED; + std::unique_ptr<weld::Label> m_xResult1; + std::unique_ptr<weld::Label> m_xResult2; + std::unique_ptr<weld::Image> m_xImage1; + std::unique_ptr<weld::Image> m_xImage2; + std::unique_ptr<weld::Image> m_xImage3; + std::unique_ptr<weld::Image> m_xImage4; + + void Test(); + DECL_LINK(StopHdl, weld::Button&, void); + DECL_LINK(TestHdl, void*, void); +public: + explicit SwTestAccountSettingsDialog(SwMailConfigPage* pParent); + virtual ~SwTestAccountSettingsDialog() override; +}; + +namespace { + +class SwAuthenticationSettingsDialog : public SfxDialogController +{ + SwMailMergeConfigItem& m_rConfigItem; + + std::unique_ptr<weld::CheckButton> m_xAuthenticationCB; + std::unique_ptr<weld::Widget> m_xAuthenticationImg; + std::unique_ptr<weld::RadioButton> m_xSeparateAuthenticationRB; + std::unique_ptr<weld::Widget> m_xSeparateAuthenticationImg; + std::unique_ptr<weld::RadioButton> m_xSMTPAfterPOPRB; + std::unique_ptr<weld::Widget> m_xSMTPAfterPOPImg; + std::unique_ptr<weld::Label> m_xOutgoingServerFT; + std::unique_ptr<weld::Label> m_xUserNameFT; + std::unique_ptr<weld::Entry> m_xUserNameED; + std::unique_ptr<weld::Widget> m_xUserNameImg; + std::unique_ptr<weld::Label> m_xOutPasswordFT; + std::unique_ptr<weld::Entry> m_xOutPasswordED; + std::unique_ptr<weld::Label> m_xIncomingServerFT; + std::unique_ptr<weld::Label> m_xServerFT; + std::unique_ptr<weld::Entry> m_xServerED; + std::unique_ptr<weld::Widget> m_xServerImg; + std::unique_ptr<weld::Label> m_xPortFT; + std::unique_ptr<weld::SpinButton> m_xPortNF; + std::unique_ptr<weld::Widget> m_xPortImg; + std::unique_ptr<weld::Label> m_xProtocolFT; + std::unique_ptr<weld::RadioButton> m_xPOP3RB; + std::unique_ptr<weld::Widget> m_xPOP3Img; + std::unique_ptr<weld::RadioButton> m_xIMAPRB; + std::unique_ptr<weld::Label> m_xInUsernameFT; + std::unique_ptr<weld::Entry> m_xInUsernameED; + std::unique_ptr<weld::Widget> m_xInUsernameImg; + std::unique_ptr<weld::Label> m_xInPasswordFT; + std::unique_ptr<weld::Entry> m_xInPasswordED; + std::unique_ptr<weld::Button> m_xOKPB; + + DECL_LINK(OKHdl_Impl, weld::Button&, void); + DECL_LINK(CheckBoxHdl_Impl, weld::Toggleable&, void); + DECL_LINK(RadioButtonHdl_Impl, weld::Toggleable&, void); + DECL_LINK(InServerHdl_Impl, weld::Toggleable&, void); + +public: + SwAuthenticationSettingsDialog(weld::Window* pParent, SwMailMergeConfigItem& rItem); +}; + +} + +SwMailConfigPage::SwMailConfigPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/mailconfigpage.ui", "MailConfigPage", &rSet) + , m_pConfigItem(new SwMailMergeConfigItem) + , m_xDisplayNameED(m_xBuilder->weld_entry("displayname")) + , m_xDisplayNameImg(m_xBuilder->weld_widget("lockdisplayname")) + , m_xAddressED(m_xBuilder->weld_entry("address")) + , m_xAddressImg(m_xBuilder->weld_widget("lockaddress")) + , m_xReplyToCB(m_xBuilder->weld_check_button("replytocb")) + , m_xReplyToCBImg(m_xBuilder->weld_widget("lockreplytocb")) + , m_xReplyToFT(m_xBuilder->weld_label("replyto_label")) + , m_xReplyToED(m_xBuilder->weld_entry("replyto")) + , m_xReplyToImg(m_xBuilder->weld_widget("lockreplyto")) + , m_xServerED(m_xBuilder->weld_entry("server")) + , m_xServerImg(m_xBuilder->weld_widget("lockserver")) + , m_xPortNF(m_xBuilder->weld_spin_button("port")) + , m_xPortImg(m_xBuilder->weld_widget("lockport")) + , m_xSecureCB(m_xBuilder->weld_check_button("secure")) + , m_xSecureImg(m_xBuilder->weld_widget("locksecure")) + , m_xServerAuthenticationPB(m_xBuilder->weld_button("serverauthentication")) + , m_xTestPB(m_xBuilder->weld_button("test")) +{ + m_xReplyToCB->connect_toggled(LINK(this, SwMailConfigPage, ReplyToHdl)); + m_xServerAuthenticationPB->connect_clicked(LINK(this, SwMailConfigPage, AuthenticationHdl)); + m_xTestPB->connect_clicked(LINK(this, SwMailConfigPage, TestHdl)); + m_xSecureCB->connect_toggled(LINK(this, SwMailConfigPage, SecureHdl)); +} + +SwMailConfigPage::~SwMailConfigPage() +{ + m_pConfigItem.reset(); +} + +std::unique_ptr<SfxTabPage> SwMailConfigPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwMailConfigPage>(pPage, pController, *rAttrSet); +} + +OUString SwMailConfigPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "displayname_label", "address_label", "replyto_label", + "label2", "server_label", "port_label" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "replytocb", "secure" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + OUString buttons[] = { "serverauthentication", "test" }; + + for (const auto& btn : buttons) + { + if (const auto& pString = m_xBuilder->weld_button(btn)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SwMailConfigPage::FillItemSet( SfxItemSet* /*rSet*/ ) +{ + if (m_xDisplayNameED->get_value_changed_from_saved()) + m_pConfigItem->SetMailDisplayName(m_xDisplayNameED->get_text()); + if (m_xAddressED->get_value_changed_from_saved()) + m_pConfigItem->SetMailAddress(m_xAddressED->get_text()); + if (m_xReplyToCB->get_state_changed_from_saved() ) + m_pConfigItem->SetMailReplyTo(m_xReplyToCB->get_active()); + if (m_xReplyToED->get_value_changed_from_saved()) + m_pConfigItem->SetMailReplyTo(m_xReplyToED->get_text()); + if (m_xServerED->get_value_changed_from_saved()) + m_pConfigItem->SetMailServer(m_xServerED->get_text()); + + m_pConfigItem->SetMailPort(m_xPortNF->get_value()); + m_pConfigItem->SetSecureConnection(m_xSecureCB->get_active()); + + m_pConfigItem->Commit(); + return true; +} + +void SwMailConfigPage::Reset( const SfxItemSet* /*rSet*/ ) +{ + m_xDisplayNameED->set_text(m_pConfigItem->GetMailDisplayName()); + m_xDisplayNameED->set_sensitive(!officecfg::Office::Writer::MailMergeWizard::MailDisplayName::isReadOnly()); + m_xDisplayNameImg->set_visible(officecfg::Office::Writer::MailMergeWizard::MailDisplayName::isReadOnly()); + + m_xAddressED->set_text(m_pConfigItem->GetMailAddress()); + m_xAddressED->set_sensitive(!officecfg::Office::Writer::MailMergeWizard::MailAddress::isReadOnly()); + m_xAddressImg->set_visible(officecfg::Office::Writer::MailMergeWizard::MailAddress::isReadOnly()); + + m_xReplyToED->set_text(m_pConfigItem->GetMailReplyTo()); + m_xReplyToED->set_sensitive(!officecfg::Office::Writer::MailMergeWizard::MailReplyTo::isReadOnly()); + m_xReplyToImg->set_visible(officecfg::Office::Writer::MailMergeWizard::MailReplyTo::isReadOnly()); + + m_xReplyToCB->set_active(m_pConfigItem->IsMailReplyTo()); + m_xReplyToCB->set_sensitive(!officecfg::Office::Writer::MailMergeWizard::IsMailReplyTo::isReadOnly()); + m_xReplyToCBImg->set_visible(officecfg::Office::Writer::MailMergeWizard::IsMailReplyTo::isReadOnly()); + + ReplyToHdl(*m_xReplyToCB); + + m_xServerED->set_text(m_pConfigItem->GetMailServer()); + m_xServerED->set_sensitive(!officecfg::Office::Writer::MailMergeWizard::MailServer::isReadOnly()); + m_xServerImg->set_visible(officecfg::Office::Writer::MailMergeWizard::MailServer::isReadOnly()); + + m_xPortNF->set_value(m_pConfigItem->GetMailPort()); + m_xPortNF->set_sensitive(!officecfg::Office::Writer::MailMergeWizard::MailPort::isReadOnly()); + m_xPortImg->set_visible(officecfg::Office::Writer::MailMergeWizard::MailPort::isReadOnly()); + + m_xSecureCB->set_active(m_pConfigItem->IsSecureConnection()); + m_xSecureCB->set_sensitive(!officecfg::Office::Writer::MailMergeWizard::IsSecureConnection::isReadOnly()); + m_xSecureImg->set_visible(officecfg::Office::Writer::MailMergeWizard::IsSecureConnection::isReadOnly()); + + m_xDisplayNameED->save_value(); + m_xAddressED->save_value(); + m_xReplyToCB->save_state(); + m_xReplyToED->save_value(); + m_xServerED->save_value(); + m_xPortNF->save_value(); + m_xSecureCB->save_state(); +} + +IMPL_LINK(SwMailConfigPage, ReplyToHdl, weld::Toggleable&, rBox, void) +{ + bool bEnable = rBox.get_active() && !m_xReplyToImg->get_visible(); + m_xReplyToFT->set_sensitive(bEnable); + m_xReplyToED->set_sensitive(bEnable); +} + +IMPL_LINK_NOARG(SwMailConfigPage, AuthenticationHdl, weld::Button&, void) +{ + m_pConfigItem->SetMailAddress(m_xAddressED->get_text()); + + SwAuthenticationSettingsDialog aDlg(GetFrameWeld(), *m_pConfigItem); + aDlg.run(); +} + +IMPL_LINK_NOARG(SwMailConfigPage, TestHdl, weld::Button&, void) +{ + SwTestAccountSettingsDialog aDlg(this); + aDlg.run(); +} + +IMPL_LINK(SwMailConfigPage, SecureHdl, weld::Toggleable&, rBox, void) +{ + bool bEnable = rBox.get_active(); + m_pConfigItem->SetSecureConnection(bEnable); + m_pConfigItem->SetMailPort(m_xPortNF->get_value()); + m_xPortNF->set_value(m_pConfigItem->GetMailPort()); +} + +SwTestAccountSettingsDialog::SwTestAccountSettingsDialog(SwMailConfigPage* pParent) + : SfxDialogController(pParent->GetFrameWeld(), "modules/swriter/ui/testmailsettings.ui", "TestMailSettings") + , m_bStop(false) + , m_pParent(pParent) + , m_xStopPB(m_xBuilder->weld_button("stop")) + , m_xErrorsED(m_xBuilder->weld_text_view("errors")) + , m_xResult1(m_xBuilder->weld_label("result1")) + , m_xResult2(m_xBuilder->weld_label("result2")) + , m_xImage1(m_xBuilder->weld_image("image1")) + , m_xImage2(m_xBuilder->weld_image("image2")) + , m_xImage3(m_xBuilder->weld_image("image3")) + , m_xImage4(m_xBuilder->weld_image("image4")) +{ + m_xErrorsED->set_size_request(m_xErrorsED->get_approximate_digit_width() * 72, + m_xErrorsED->get_height_rows(8)); + m_sErrorServer = m_xErrorsED->get_text(); + m_xErrorsED->set_text(""); + m_sCompleted = m_xResult1->get_label(); + m_sFailed = m_xResult2->get_label(); + + m_xStopPB->connect_clicked(LINK(this, SwTestAccountSettingsDialog, StopHdl)); + + m_pPostedEvent = Application::PostUserEvent(LINK(this, SwTestAccountSettingsDialog, TestHdl)); +} + +SwTestAccountSettingsDialog::~SwTestAccountSettingsDialog() +{ + if (m_pPostedEvent) + { + Application::RemoveUserEvent(m_pPostedEvent); + } +} + +IMPL_LINK_NOARG(SwTestAccountSettingsDialog, StopHdl, weld::Button&, void) +{ + m_bStop = true; +} + +IMPL_LINK_NOARG(SwTestAccountSettingsDialog, TestHdl, void*, void) +{ + m_pPostedEvent = nullptr; + weld::WaitObject aWait(m_xDialog.get()); + Test(); +} + +void SwTestAccountSettingsDialog::Test() +{ + uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext(); + + OUString sException; + + bool bIsLoggedIn = false; + bool bIsServer = false; + try + { + uno::Reference< mail::XMailService > xInMailService; + uno::Reference< mail::XMailServiceProvider > xMailServiceProvider( + mail::MailServiceProvider::create(xContext) ); + uno::Reference< mail::XMailService > xMailService = + xMailServiceProvider->create( + mail::MailServiceType_SMTP); + if(m_bStop) + return; + uno::Reference<XConnectionListener> xConnectionListener(new SwConnectionListener); + + if(m_pParent->m_pConfigItem->IsAuthentication() && + m_pParent->m_pConfigItem->IsSMTPAfterPOP()) + { + xInMailService = xMailServiceProvider->create( + m_pParent->m_pConfigItem->IsInServerPOP() ? + mail::MailServiceType_POP3 : mail::MailServiceType_IMAP); + if(m_bStop) + return; + //authenticate at the POP or IMAP server first + uno::Reference<XAuthenticator> xAuthenticator = + new SwAuthenticator( + m_pParent->m_pConfigItem->GetInServerUserName(), + m_pParent->m_pConfigItem->GetInServerPassword(), + m_xDialog.get()); + + xInMailService->addConnectionListener(xConnectionListener); + //check connection + uno::Reference< uno::XCurrentContext> xConnectionContext = + new SwConnectionContext( + m_pParent->m_pConfigItem->GetInServerName(), + m_pParent->m_pConfigItem->GetInServerPort(), + "Insecure"); + xInMailService->connect(xConnectionContext, xAuthenticator); + } + if(m_bStop) + return; + uno::Reference<XAuthenticator> xAuthenticator; + if(m_pParent->m_pConfigItem->IsAuthentication() && + !m_pParent->m_pConfigItem->IsSMTPAfterPOP() && + !m_pParent->m_pConfigItem->GetMailUserName().isEmpty()) + xAuthenticator = + new SwAuthenticator( + m_pParent->m_pConfigItem->GetMailUserName(), + m_pParent->m_pConfigItem->GetMailPassword(), + m_xDialog.get()); + else + xAuthenticator = new SwAuthenticator(); + + xMailService->addConnectionListener(xConnectionListener); + if(m_bStop) + return; + //just to check if the server exists + xMailService->getSupportedConnectionTypes(); + if(m_bStop) + return; + bIsServer = true; + //check connection + uno::Reference< uno::XCurrentContext> xConnectionContext = + new SwConnectionContext( + m_pParent->m_xServerED->get_text(), + m_pParent->m_xPortNF->get_value(), + m_pParent->m_xSecureCB->get_active() ? OUString("Ssl") : OUString("Insecure")); + xMailService->connect(xConnectionContext, xAuthenticator); + bIsLoggedIn = xMailService->isConnected(); + if( xInMailService.is() ) + xInMailService->disconnect(); + if( xMailService->isConnected()) + xMailService->disconnect(); + } + catch (const uno::Exception& e) + { + sException = e.Message; + } + + m_xResult1->set_label(bIsServer ? m_sCompleted : m_sFailed); + m_xImage1->set_visible(!bIsServer); + m_xImage3->set_visible(bIsServer); + + m_xResult2->set_label(bIsLoggedIn ? m_sCompleted : m_sFailed); + m_xImage2->set_visible(!bIsLoggedIn); + m_xImage4->set_visible(bIsLoggedIn); + + if (!bIsServer || !bIsLoggedIn) + { + OUString aErrorMessage(m_sErrorServer); + if (!sException.isEmpty()) + aErrorMessage += "\n--\n" + sException; + m_xErrorsED->set_text(aErrorMessage); + } +} + +SwMailConfigDlg::SwMailConfigDlg(weld::Window* pParent, const SfxItemSet& rSet) + : SfxSingleTabDialogController(pParent, &rSet) +{ + // create TabPage + SetTabPage(SwMailConfigPage::Create(get_content_area(), this, &rSet)); + m_xDialog->set_title(SwResId(STR_MAILCONFIG_DLG_TITLE)); +} + +SwAuthenticationSettingsDialog::SwAuthenticationSettingsDialog( + weld::Window* pParent, SwMailMergeConfigItem& rItem) + : SfxDialogController(pParent, "modules/swriter/ui/authenticationsettingsdialog.ui", "AuthenticationSettingsDialog") + , m_rConfigItem(rItem) + , m_xAuthenticationCB(m_xBuilder->weld_check_button("authentication")) + , m_xAuthenticationImg(m_xBuilder->weld_widget("lockauthentication")) + , m_xSeparateAuthenticationRB(m_xBuilder->weld_radio_button("separateauthentication")) + , m_xSeparateAuthenticationImg(m_xBuilder->weld_widget("lockseparaauth")) + , m_xSMTPAfterPOPRB(m_xBuilder->weld_radio_button("smtpafterpop")) + , m_xSMTPAfterPOPImg(m_xBuilder->weld_widget("locksmtpafterpop")) + , m_xOutgoingServerFT(m_xBuilder->weld_label("label1")) + , m_xUserNameFT(m_xBuilder->weld_label("username_label")) + , m_xUserNameED(m_xBuilder->weld_entry("username")) + , m_xUserNameImg(m_xBuilder->weld_widget("lockusername")) + , m_xOutPasswordFT(m_xBuilder->weld_label("outpassword_label")) + , m_xOutPasswordED(m_xBuilder->weld_entry("outpassword")) + , m_xIncomingServerFT(m_xBuilder->weld_label("label2")) + , m_xServerFT(m_xBuilder->weld_label("server_label")) + , m_xServerED(m_xBuilder->weld_entry("server")) + , m_xServerImg(m_xBuilder->weld_widget("lockserver")) + , m_xPortFT(m_xBuilder->weld_label("port_label")) + , m_xPortNF(m_xBuilder->weld_spin_button("port")) + , m_xPortImg(m_xBuilder->weld_widget("lockport")) + , m_xProtocolFT(m_xBuilder->weld_label("label3")) + , m_xPOP3RB(m_xBuilder->weld_radio_button("pop3")) + , m_xPOP3Img(m_xBuilder->weld_widget("lockpop3")) + , m_xIMAPRB(m_xBuilder->weld_radio_button("imap")) + , m_xInUsernameFT(m_xBuilder->weld_label("inusername_label")) + , m_xInUsernameED(m_xBuilder->weld_entry("inusername")) + , m_xInUsernameImg(m_xBuilder->weld_widget("lockinusername")) + , m_xInPasswordFT(m_xBuilder->weld_label("inpassword_label")) + , m_xInPasswordED(m_xBuilder->weld_entry("inpassword")) + , m_xOKPB(m_xBuilder->weld_button("ok")) +{ + m_xAuthenticationCB->connect_toggled( LINK( this, SwAuthenticationSettingsDialog, CheckBoxHdl_Impl)); + Link<weld::Toggleable&,void> aRBLink = LINK( this, SwAuthenticationSettingsDialog, RadioButtonHdl_Impl ); + m_xSeparateAuthenticationRB->connect_toggled( aRBLink ); + m_xSMTPAfterPOPRB->connect_toggled( aRBLink ); + m_xOKPB->connect_clicked( LINK( this, SwAuthenticationSettingsDialog, OKHdl_Impl)); + m_xPOP3RB->connect_toggled(LINK(this, SwAuthenticationSettingsDialog, InServerHdl_Impl)); + + m_xAuthenticationCB->set_active(m_rConfigItem.IsAuthentication()); + m_xAuthenticationCB->set_sensitive(!officecfg::Office::Writer::MailMergeWizard::IsAuthentication::isReadOnly()); + m_xAuthenticationImg->set_visible(officecfg::Office::Writer::MailMergeWizard::IsAuthentication::isReadOnly()); + if (m_rConfigItem.IsSMTPAfterPOP()) + m_xSMTPAfterPOPRB->set_active(true); + else + m_xSeparateAuthenticationRB->set_active(true); + m_xUserNameED->set_text(m_rConfigItem.GetMailUserName()); + m_xOutPasswordED->set_text(m_rConfigItem.GetMailPassword()); + + m_xServerED->set_text(m_rConfigItem.GetInServerName()); + m_xPortNF->set_value(m_rConfigItem.GetInServerPort()); + if (m_rConfigItem.IsInServerPOP()) + m_xPOP3RB->set_active(true); + else + m_xIMAPRB->set_active(true); + m_xInUsernameED->set_text(m_rConfigItem.GetInServerUserName()); + m_xInPasswordED->set_text(m_rConfigItem.GetInServerPassword()); + + CheckBoxHdl_Impl(*m_xAuthenticationCB); +} + +IMPL_LINK_NOARG(SwAuthenticationSettingsDialog, OKHdl_Impl, weld::Button&, void) +{ + m_rConfigItem.SetAuthentication( m_xAuthenticationCB->get_active() ); + m_rConfigItem.SetSMTPAfterPOP(m_xSMTPAfterPOPRB->get_active()); + m_rConfigItem.SetMailUserName(m_xUserNameED->get_text()); + m_rConfigItem.SetMailPassword(m_xOutPasswordED->get_text()); + m_rConfigItem.SetInServerName(m_xServerED->get_text()); + m_rConfigItem.SetInServerPort(m_xPortNF->get_value()); + m_rConfigItem.SetInServerPOP(m_xPOP3RB->get_active()); + m_rConfigItem.SetInServerUserName(m_xInUsernameED->get_text()); + m_rConfigItem.SetInServerPassword(m_xInPasswordED->get_text()); + m_xDialog->response(RET_OK); +} + +IMPL_LINK( SwAuthenticationSettingsDialog, CheckBoxHdl_Impl, weld::Toggleable&, rBox, void) +{ + bool bChecked = rBox.get_active(); + m_xSeparateAuthenticationRB->set_sensitive(bChecked); + m_xSMTPAfterPOPRB->set_sensitive(bChecked); + RadioButtonHdl_Impl(*m_xSeparateAuthenticationRB); +} + +IMPL_LINK_NOARG(SwAuthenticationSettingsDialog, RadioButtonHdl_Impl, weld::Toggleable&, void) +{ + bool bSeparate = m_xSeparateAuthenticationRB->get_active(); + bool bIsEnabled = m_xSeparateAuthenticationRB->get_sensitive(); + bool bNotSeparate = !bSeparate && bIsEnabled; + bSeparate &= bIsEnabled; + + bool bReadOnly = officecfg::Office::Writer::MailMergeWizard::IsSMPTAfterPOP::isReadOnly(); + if (bSeparate || bNotSeparate) + { + m_xSeparateAuthenticationRB->set_sensitive(!bReadOnly); + m_xSeparateAuthenticationImg->set_visible(bReadOnly); + m_xSMTPAfterPOPRB->set_sensitive(!bReadOnly); + m_xSMTPAfterPOPImg->set_visible(bReadOnly); + } + if (bSeparate && m_xUserNameED->get_text().isEmpty()) + m_xUserNameED->set_text(m_rConfigItem.GetMailAddress()); + else if (!bSeparate && m_xUserNameED->get_text() == m_rConfigItem.GetMailAddress()) + m_xUserNameED->set_text(""); + + if (bNotSeparate && m_xInUsernameED->get_text().isEmpty()) + m_xInUsernameED->set_text(m_rConfigItem.GetMailAddress()); + else if (!bNotSeparate && m_xInUsernameED->get_text() == m_rConfigItem.GetMailAddress()) + m_xInUsernameED->set_text(""); + + m_xOutgoingServerFT->set_sensitive(bSeparate); + m_xUserNameFT->set_sensitive(bSeparate); + + bReadOnly = officecfg::Office::Writer::MailMergeWizard::MailUserName::isReadOnly(); + m_xUserNameED->set_sensitive(bSeparate && !bReadOnly); + m_xUserNameImg->set_visible(bReadOnly); + + m_xOutPasswordFT->set_sensitive(bSeparate); + m_xOutPasswordED->set_sensitive(bSeparate); + + m_xIncomingServerFT->set_sensitive(bNotSeparate); + m_xServerFT->set_sensitive(bNotSeparate); + + bReadOnly = officecfg::Office::Writer::MailMergeWizard::InServerName::isReadOnly(); + m_xServerED->set_sensitive(bNotSeparate && !bReadOnly); + m_xServerImg->set_visible(bReadOnly); + + m_xPortFT->set_sensitive(bNotSeparate); + bReadOnly = officecfg::Office::Writer::MailMergeWizard::InServerPort::isReadOnly(); + m_xPortNF->set_sensitive(bNotSeparate && !bReadOnly); + m_xPortImg->set_visible(bReadOnly); + + m_xInUsernameFT->set_sensitive(bNotSeparate); + bReadOnly = officecfg::Office::Writer::MailMergeWizard::InServerUserName::isReadOnly(); + m_xInUsernameED->set_sensitive(bNotSeparate && !bReadOnly); + m_xInUsernameImg->set_visible(bReadOnly); + m_xProtocolFT->set_sensitive(bNotSeparate); + + bReadOnly = officecfg::Office::Writer::MailMergeWizard::InServerIsPOP::isReadOnly(); + m_xPOP3RB->set_sensitive(bNotSeparate && !bReadOnly); + m_xIMAPRB->set_sensitive(bNotSeparate && !bReadOnly); + m_xPOP3Img->set_visible(bReadOnly); + + m_xInPasswordFT->set_sensitive(bNotSeparate); + m_xInPasswordED->set_sensitive(bNotSeparate); +} + +IMPL_LINK_NOARG( SwAuthenticationSettingsDialog, InServerHdl_Impl, weld::Toggleable&, void) +{ + bool bPOP = m_xPOP3RB->get_active(); + m_rConfigItem.SetInServerPOP(bPOP); + m_xPortNF->set_value(m_rConfigItem.GetInServerPort()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/config/optcomp.cxx b/sw/source/ui/config/optcomp.cxx new file mode 100644 index 0000000000..1393b2864d --- /dev/null +++ b/sw/source/ui/config/optcomp.cxx @@ -0,0 +1,481 @@ +/* -*- 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 <optcomp.hxx> + +#include <cmdid.h> +#include <docsh.hxx> +#include <uiitems.hxx> +#include <view.hxx> +#include <wrtsh.hxx> + +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/fcontnr.hxx> +#include <IDocumentSettingAccess.hxx> +#include <vector> +#include <svtools/restartdialog.hxx> +#include <comphelper/processfactory.hxx> +#include <officecfg/Office/Compatibility.hxx> +#include <osl/diagnose.h> + +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::uno; + +struct SwCompatibilityOptPage_Impl +{ + std::vector< SvtCompatibilityEntry > m_aList; +}; + +SwCompatibilityOptPage::SwCompatibilityOptPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/optcompatpage.ui", "OptCompatPage", &rSet) + , m_pWrtShell(nullptr) + , m_pImpl(new SwCompatibilityOptPage_Impl) + , m_nSavedOptions(0) + , m_xMain(m_xBuilder->weld_frame("compatframe")) + , m_xFormattingLB(m_xBuilder->weld_combo_box("format")) + , m_xOptionsLB(m_xBuilder->weld_tree_view("options")) + , m_xDefaultPB(m_xBuilder->weld_button("default")) +{ + m_xOptionsLB->enable_toggle_buttons(weld::ColumnToggleType::Check); + + int nPos = 0; + for (int i = static_cast<int>(SvtCompatibilityEntry::Index::Module) + 1; + i < static_cast<int>(SvtCompatibilityEntry::Index::INVALID) - 1; // omit AddTableLineSpacing + ++i) + { + int nCoptIdx = i - 2; /* Do not consider "Name" & "Module" indexes */ + + const OUString sEntry = m_xFormattingLB->get_text(nCoptIdx); + m_xOptionsLB->append(); + m_xOptionsLB->set_toggle(nPos, TRISTATE_FALSE); + m_xOptionsLB->set_text(nPos, sEntry, 0); + ++nPos; + } + + m_sUserEntry = m_xFormattingLB->get_text(m_xFormattingLB->get_count() - 1); + + m_xFormattingLB->clear(); + + InitControls( rSet ); + + // set handler + m_xFormattingLB->connect_changed( LINK( this, SwCompatibilityOptPage, SelectHdl ) ); + m_xDefaultPB->connect_clicked( LINK( this, SwCompatibilityOptPage, UseAsDefaultHdl ) ); +} + +SwCompatibilityOptPage::~SwCompatibilityOptPage() +{ +} + +static sal_uInt32 convertBools2Ulong_Impl +( + bool _bAddSpacing, + bool _bAddSpacingAtPages, + bool _bUseOurTabStops, + bool _bNoExtLeading, + bool _bUseLineSpacing, + bool _bAddTableSpacing, + bool _bAddTableLineSpacing, + bool _bUseObjPos, + bool _bUseOurTextWrapping, + bool _bConsiderWrappingStyle, + bool _bExpandWordSpace, + bool _bProtectForm, + bool _bMsWordCompTrailingBlanks, + bool bSubtractFlysAnchoredAtFlys, + bool bEmptyDbFieldHidesPara, + bool bUseVariableWidthNBSP +) +{ + sal_uInt32 nRet = 0; + sal_uInt32 nSetBit = 1; + + if ( _bAddSpacing ) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if ( _bAddSpacingAtPages ) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if ( _bUseOurTabStops ) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if ( _bNoExtLeading ) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if ( _bUseLineSpacing ) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if ( _bAddTableSpacing ) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if (_bAddTableLineSpacing) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if ( _bUseObjPos ) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if ( _bUseOurTextWrapping ) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if ( _bConsiderWrappingStyle ) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if ( _bExpandWordSpace ) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if ( _bProtectForm ) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if ( _bMsWordCompTrailingBlanks ) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if (bSubtractFlysAnchoredAtFlys) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if (bEmptyDbFieldHidesPara) + nRet |= nSetBit; + nSetBit = nSetBit << 1; + if (bUseVariableWidthNBSP) + nRet |= nSetBit; + + return nRet; +} + +void SwCompatibilityOptPage::InitControls( const SfxItemSet& rSet ) +{ + // init objectshell and detect document name + OUString sDocTitle; + SfxObjectShell* pObjShell = nullptr; + if ( const SwPtrItem* pItem = rSet.GetItemIfSet( FN_PARAM_WRTSHELL, false ) ) + m_pWrtShell = static_cast<SwWrtShell*>(pItem->GetValue()); + if ( m_pWrtShell ) + { + pObjShell = m_pWrtShell->GetView().GetDocShell(); + if ( pObjShell ) + sDocTitle = pObjShell->GetTitle(); + } + else + { + m_xMain->set_sensitive(false); + } + const OUString& rText = m_xMain->get_label(); + m_xMain->set_label(rText.replaceAll("%DOCNAME", sDocTitle)); + + // loading file formats + const std::vector< SvtCompatibilityEntry > aList = m_aConfigItem.GetList(); + + for ( const SvtCompatibilityEntry& rEntry : aList ) + { + const OUString sEntryName = rEntry.getValue<OUString>( SvtCompatibilityEntry::Index::Name ); + const bool bIsUserEntry = ( sEntryName == SvtCompatibilityEntry::USER_ENTRY_NAME ); + const bool bIsDefaultEntry = ( sEntryName == SvtCompatibilityEntry::DEFAULT_ENTRY_NAME ); + + m_pImpl->m_aList.push_back( rEntry ); + + if ( bIsDefaultEntry ) + continue; + + OUString sNewEntry; + if ( bIsUserEntry ) + sNewEntry = m_sUserEntry; + + else if ( pObjShell && !sEntryName.isEmpty() ) + { + SfxFilterContainer* pFacCont = pObjShell->GetFactory().GetFilterContainer(); + std::shared_ptr<const SfxFilter> pFilter = pFacCont->GetFilter4FilterName( sEntryName ); + if ( pFilter ) + sNewEntry = pFilter->GetUIName(); + } + + if ( sNewEntry.isEmpty() ) + sNewEntry = sEntryName; + + sal_uInt32 nOptions = convertBools2Ulong_Impl( + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::AddSpacing ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::AddSpacingAtPages ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::UseOurTabStops ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::NoExtLeading ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::UseLineSpacing ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::AddTableSpacing ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::AddTableLineSpacing), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::UseObjectPositioning ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::UseOurTextWrapping ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::ConsiderWrappingStyle ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::ExpandWordSpace ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::ProtectForm ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::MsWordTrailingBlanks ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::SubtractFlysAnchoredAtFlys ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::EmptyDbFieldHidesPara ), + rEntry.getValue<bool>( SvtCompatibilityEntry::Index::UseVariableWidthNBSP ) ); + m_xFormattingLB->append(OUString::number(nOptions), sNewEntry); + } +} + +IMPL_LINK_NOARG(SwCompatibilityOptPage, SelectHdl, weld::ComboBox&, void) +{ + sal_uInt32 nOptions = m_xFormattingLB->get_active_id().toUInt32(); + SetCurrentOptions(nOptions); +} + +IMPL_LINK_NOARG(SwCompatibilityOptPage, UseAsDefaultHdl, weld::Button&, void) +{ + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "modules/swriter/ui/querydefaultcompatdialog.ui")); + std::unique_ptr<weld::MessageDialog> xQueryBox(xBuilder->weld_message_dialog("QueryDefaultCompatDialog")); + if (xQueryBox->run() != RET_YES) + return; + + auto pItem = std::find_if(m_pImpl->m_aList.begin(), m_pImpl->m_aList.end(), + [](const SvtCompatibilityEntry& rItem) + { + const OUString sEntryName = rItem.getValue<OUString>( SvtCompatibilityEntry::Index::Name ); + const bool bIsDefaultEntry = ( sEntryName == SvtCompatibilityEntry::DEFAULT_ENTRY_NAME ); + return bIsDefaultEntry; + }); + if (pItem != m_pImpl->m_aList.end()) + { + const sal_Int32 nCount = m_xOptionsLB->n_children(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + bool bChecked = m_xOptionsLB->get_toggle(i); + + int nCoptIdx = i + 2; /* Consider "Name" & "Module" indexes */ + pItem->setValue<bool>( SvtCompatibilityEntry::Index(nCoptIdx), bChecked ); + if (nCoptIdx == int(SvtCompatibilityEntry::Index::AddTableSpacing)) + { + bool const isLineSpacing = m_xOptionsLB->get_toggle(i) == TRISTATE_TRUE; + pItem->setValue<bool>(SvtCompatibilityEntry::Index::AddTableLineSpacing, isLineSpacing); + } + else + { + assert(m_xOptionsLB->get_toggle(i) != TRISTATE_INDET); + } + } + } + + WriteOptions(); +} + +void SwCompatibilityOptPage::SetCurrentOptions( sal_uInt32 nOptions ) +{ + const int nCount = m_xOptionsLB->n_children(); + const OUString aOptionsName = m_xFormattingLB->get_active_text(); + OSL_ENSURE( nCount <= 32, "SwCompatibilityOptPage::Reset(): entry overflow" ); + for (int i = 0; i < nCount; ++i) + { + bool bReadOnly = false; + bool bChecked = ( ( nOptions & 0x00000001 ) == 0x00000001 ); + TriState value = bChecked ? TRISTATE_TRUE : TRISTATE_FALSE; + if (i == int(SvtCompatibilityEntry::Index::AddTableSpacing) - 2) + { // hack: map 2 bools to 1 tristate + nOptions = nOptions >> 1; + if (value == TRISTATE_TRUE + && (nOptions & 0x00000001) != 0x00000001) // ADD_PARA_LINE_SPACING_TO_TABLE_CELLS + { + value = TRISTATE_INDET; // 3 values possible here + } + } + m_xOptionsLB->set_toggle(i, value); + + int nCoptIdx = i + 2; /* Consider "Name" & "Module" indexes */ + if (aOptionsName.isEmpty() || aOptionsName == SvtCompatibilityEntry::DEFAULT_ENTRY_NAME) + { + bReadOnly = m_aConfigItem.GetDefaultPropertyReadOnly(SvtCompatibilityEntry::Index(nCoptIdx)); + } + else + { + bReadOnly = m_aConfigItem.GetPropertyReadOnly(SvtCompatibilityEntry::Index(nCoptIdx)); + } + m_xOptionsLB->set_sensitive(i, !bReadOnly); + + nOptions = nOptions >> 1; + } + + m_xDefaultPB->set_sensitive(!m_aConfigItem.HaveDefaultReadOnlyProperty()); +} + +sal_uInt32 SwCompatibilityOptPage::GetDocumentOptions() const +{ + sal_uInt32 nRet = 0; + if ( m_pWrtShell ) + { + const IDocumentSettingAccess& rIDocumentSettingAccess = m_pWrtShell->getIDocumentSettingAccess(); + nRet = convertBools2Ulong_Impl( + rIDocumentSettingAccess.get( DocumentSettingId::PARA_SPACE_MAX ), + rIDocumentSettingAccess.get( DocumentSettingId::PARA_SPACE_MAX_AT_PAGES ), + !rIDocumentSettingAccess.get( DocumentSettingId::TAB_COMPAT ), + !rIDocumentSettingAccess.get( DocumentSettingId::ADD_EXT_LEADING ), + rIDocumentSettingAccess.get( DocumentSettingId::OLD_LINE_SPACING ), + rIDocumentSettingAccess.get( DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS ), + rIDocumentSettingAccess.get( DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS ), + rIDocumentSettingAccess.get( DocumentSettingId::USE_FORMER_OBJECT_POS ), + rIDocumentSettingAccess.get( DocumentSettingId::USE_FORMER_TEXT_WRAPPING ), + rIDocumentSettingAccess.get( DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION ), + !rIDocumentSettingAccess.get( DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK ), + rIDocumentSettingAccess.get( DocumentSettingId::PROTECT_FORM ), + rIDocumentSettingAccess.get( DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS ), + rIDocumentSettingAccess.get( DocumentSettingId::SUBTRACT_FLYS ), + rIDocumentSettingAccess.get( DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA ), + rIDocumentSettingAccess.get( DocumentSettingId::USE_VARIABLE_WIDTH_NBSP ) ); + } + return nRet; +} + +void SwCompatibilityOptPage::WriteOptions() +{ + m_aConfigItem.Clear(); + for ( const auto& rItem : m_pImpl->m_aList ) + m_aConfigItem.AppendItem(rItem); +} + +std::unique_ptr<SfxTabPage> SwCompatibilityOptPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwCompatibilityOptPage>(pPage, pController, *rAttrSet); +} + +OUString SwCompatibilityOptPage::GetAllStrings() +{ + OUString sAllStrings; + + if (const auto& pString = m_xBuilder->weld_label(u"label11"_ustr)) + sAllStrings += pString->get_label() + " "; + + sAllStrings += m_xDefaultPB->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool SwCompatibilityOptPage::FillItemSet( SfxItemSet* ) +{ + bool bModified = false; + if ( m_pWrtShell ) + { + sal_uInt32 nSavedOptions = m_nSavedOptions; + const int nCount = m_xOptionsLB->n_children(); + OSL_ENSURE( nCount <= 32, "SwCompatibilityOptPage::Reset(): entry overflow" ); + + for (int i = 0; i < nCount; ++i) + { + TriState const current = m_xOptionsLB->get_toggle(i); + TriState saved = ((nSavedOptions & 0x00000001) == 0x00000001) ? TRISTATE_TRUE : TRISTATE_FALSE; + if (i == int(SvtCompatibilityEntry::Index::AddTableSpacing) - 2) + { // hack: map 2 bools to 1 tristate + nSavedOptions = nSavedOptions >> 1; + if (saved == TRISTATE_TRUE + && ((nSavedOptions & 0x00000001) != 0x00000001)) + { + saved = TRISTATE_INDET; + } + } + if (current != saved) + { + bool const bChecked(current != TRISTATE_FALSE); + assert(current != TRISTATE_INDET); // can't *change* it to that + int nCoptIdx = i + 2; /* Consider "Name" & "Module" indexes */ + switch ( SvtCompatibilityEntry::Index(nCoptIdx) ) + { + case SvtCompatibilityEntry::Index::AddSpacing: + m_pWrtShell->SetParaSpaceMax( bChecked ); + break; + + case SvtCompatibilityEntry::Index::AddSpacingAtPages: + m_pWrtShell->SetParaSpaceMaxAtPages( bChecked ); + break; + + case SvtCompatibilityEntry::Index::UseOurTabStops: + m_pWrtShell->SetTabCompat( !bChecked ); + break; + + case SvtCompatibilityEntry::Index::NoExtLeading: + m_pWrtShell->SetAddExtLeading( !bChecked ); + break; + + case SvtCompatibilityEntry::Index::UseLineSpacing: + m_pWrtShell->SetUseFormerLineSpacing( bChecked ); + break; + + case SvtCompatibilityEntry::Index::AddTableSpacing: + m_pWrtShell->SetAddParaSpacingToTableCells( bChecked ); + break; + + case SvtCompatibilityEntry::Index::UseObjectPositioning: + m_pWrtShell->SetUseFormerObjectPositioning( bChecked ); + break; + + case SvtCompatibilityEntry::Index::UseOurTextWrapping: + m_pWrtShell->SetUseFormerTextWrapping( bChecked ); + break; + + case SvtCompatibilityEntry::Index::ConsiderWrappingStyle: + m_pWrtShell->SetConsiderWrapOnObjPos( bChecked ); + break; + + case SvtCompatibilityEntry::Index::ExpandWordSpace: + m_pWrtShell->SetDoNotJustifyLinesWithManualBreak( !bChecked ); + break; + + case SvtCompatibilityEntry::Index::ProtectForm: + m_pWrtShell->SetProtectForm( bChecked ); + break; + + case SvtCompatibilityEntry::Index::MsWordTrailingBlanks: + m_pWrtShell->SetMsWordCompTrailingBlanks( bChecked ); + break; + + case SvtCompatibilityEntry::Index::SubtractFlysAnchoredAtFlys: + m_pWrtShell->SetSubtractFlysAnchoredAtFlys(bChecked); + break; + + case SvtCompatibilityEntry::Index::EmptyDbFieldHidesPara: + m_pWrtShell->SetEmptyDbFieldHidesPara(bChecked); + break; + + case SvtCompatibilityEntry::Index::UseVariableWidthNBSP: + m_pWrtShell->GetDoc()->getIDocumentSettingAccess() + .set(DocumentSettingId::USE_VARIABLE_WIDTH_NBSP, bChecked); + break; + + default: + break; + } + bModified = true; + } + + nSavedOptions = nSavedOptions >> 1; + } + } + + if ( bModified ) + WriteOptions(); + + return bModified; +} + +void SwCompatibilityOptPage::Reset( const SfxItemSet* ) +{ + m_xOptionsLB->select(0); + + sal_uInt32 nOptions = GetDocumentOptions(); + SetCurrentOptions( nOptions ); + m_nSavedOptions = nOptions; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/config/optload.cxx b/sw/source/ui/config/optload.cxx new file mode 100644 index 0000000000..3adf4dce4e --- /dev/null +++ b/sw/source/ui/config/optload.cxx @@ -0,0 +1,1508 @@ +/* -*- 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 <officecfg/Office/Writer.hxx> +#include <comphelper/string.hxx> +#include <swtypes.hxx> +#include <uiitems.hxx> +#include <modcfg.hxx> +#include <swmodule.hxx> +#include <usrpref.hxx> +#include <wrtsh.hxx> +#include <linkenum.hxx> +#include <uitool.hxx> +#include <view.hxx> + +#include <strings.hrc> +#include <optload.hrc> +#include <cmdid.h> + +#include <optload.hxx> +#include <sfx2/htmlmode.hxx> +#include <fldmgr.hxx> +#include <poolfmt.hxx> +#include <expfld.hxx> + +#include <svtools/insdlg.hxx> +#include <svtools/unitconv.hxx> +#include <tools/resary.hxx> +#include <vcl/settings.hxx> + +#include <comphelper/classids.hxx> +#include <unotools/configmgr.hxx> +#include <SwStyleNameMapper.hxx> +#include <numrule.hxx> + +#include <doc.hxx> +#include <svl/cjkoptions.hxx> +#include <svl/eitem.hxx> + +using namespace ::com::sun::star; + +static bool lcl_isPropertyReadOnly(const SwCapObjType eType, const CapConfigProp ePropType, const SvGlobalName& rOleId) +{ + bool bReadOnly = false; + + switch (ePropType) + { + case PROP_CAP_OBJECT_ENABLE: + { + switch (eType) + { + case TABLE_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Table::Enable::isReadOnly(); + break; + case FRAME_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Frame::Enable::isReadOnly(); + break; + case GRAPHIC_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Graphic::Enable::isReadOnly(); + break; + case OLE_CAP: + { + if (rOleId == SvGlobalName(SO3_SC_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Calc::Enable::isReadOnly(); + } else if (rOleId == SvGlobalName(SO3_SIMPRESS_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Impress::Enable::isReadOnly(); + } else if (rOleId == SvGlobalName(SO3_SCH_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Chart::Enable::isReadOnly(); + } else if (rOleId == SvGlobalName(SO3_SM_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Formula::Enable::isReadOnly(); + } else if (rOleId == SvGlobalName(SO3_SDRAW_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Draw::Enable::isReadOnly(); + } else if (rOleId == SvGlobalName(SO3_OUT_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::OLEMisc::Enable::isReadOnly(); + } else { + // Should not reach it. + } + } + break; + default: + break; + } + } + break; + case PROP_CAP_OBJECT_CATEGORY: + { + switch (eType) + { + case TABLE_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Table::Settings::Category::isReadOnly(); + break; + case FRAME_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Frame::Settings::Category::isReadOnly(); + break; + case GRAPHIC_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Graphic::Settings::Category::isReadOnly(); + break; + case OLE_CAP: + { + if (rOleId == SvGlobalName(SO3_SC_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Calc::Settings::Category::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SIMPRESS_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Impress::Settings::Category::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SCH_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Chart::Settings::Category::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SM_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Formula::Settings::Category::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SDRAW_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Draw::Settings::Category::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_OUT_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::OLEMisc::Settings::Category::isReadOnly(); + } + else { + // Should not reach it. + } + } + break; + default: + break; + } + } + break; + case PROP_CAP_OBJECT_NUMBERING: + { + switch (eType) + { + case TABLE_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Table::Settings::Numbering::isReadOnly(); + break; + case FRAME_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Frame::Settings::Numbering::isReadOnly(); + break; + case GRAPHIC_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Graphic::Settings::Numbering::isReadOnly(); + break; + case OLE_CAP: + { + if (rOleId == SvGlobalName(SO3_SC_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Calc::Settings::Numbering::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SIMPRESS_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Impress::Settings::Numbering::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SCH_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Chart::Settings::Numbering::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SM_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Formula::Settings::Numbering::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SDRAW_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Draw::Settings::Numbering::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_OUT_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::OLEMisc::Settings::Numbering::isReadOnly(); + } + else { + // Should not reach it. + } + } + break; + default: + break; + } + } + break; + case PROP_CAP_OBJECT_NUMBERINGSEPARATOR: + { + switch (eType) + { + case TABLE_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Table::Settings::NumberingSeparator::isReadOnly(); + break; + case FRAME_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Frame::Settings::NumberingSeparator::isReadOnly(); + break; + case GRAPHIC_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Graphic::Settings::NumberingSeparator::isReadOnly(); + break; + case OLE_CAP: + { + if (rOleId == SvGlobalName(SO3_SC_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Calc::Settings::NumberingSeparator::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SIMPRESS_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Impress::Settings::NumberingSeparator::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SCH_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Chart::Settings::NumberingSeparator::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SM_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Formula::Settings::NumberingSeparator::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SDRAW_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Draw::Settings::NumberingSeparator::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_OUT_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::OLEMisc::Settings::NumberingSeparator::isReadOnly(); + } + else { + // Should not reach it. + } + } + break; + default: + break; + } + } + break; + case PROP_CAP_OBJECT_CAPTIONTEXT: + { + switch (eType) + { + case TABLE_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Table::Settings::CaptionText::isReadOnly(); + break; + case FRAME_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Frame::Settings::CaptionText::isReadOnly(); + break; + case GRAPHIC_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Graphic::Settings::CaptionText::isReadOnly(); + break; + case OLE_CAP: + { + if (rOleId == SvGlobalName(SO3_SC_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Calc::Settings::CaptionText::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SIMPRESS_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Impress::Settings::CaptionText::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SCH_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Chart::Settings::CaptionText::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SM_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Formula::Settings::CaptionText::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SDRAW_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Draw::Settings::CaptionText::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_OUT_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::OLEMisc::Settings::CaptionText::isReadOnly(); + } + else { + // Should not reach it. + } + } + break; + default: + break; + } + } + break; + case PROP_CAP_OBJECT_DELIMITER: + { + switch (eType) + { + case TABLE_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Table::Settings::Delimiter::isReadOnly(); + break; + case FRAME_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Frame::Settings::Delimiter::isReadOnly(); + break; + case GRAPHIC_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Graphic::Settings::Delimiter::isReadOnly(); + break; + case OLE_CAP: + { + if (rOleId == SvGlobalName(SO3_SC_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Calc::Settings::Delimiter::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SIMPRESS_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Impress::Settings::Delimiter::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SCH_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Chart::Settings::Delimiter::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SM_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Formula::Settings::Delimiter::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SDRAW_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Draw::Settings::Delimiter::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_OUT_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::OLEMisc::Settings::Delimiter::isReadOnly(); + } + else { + // Should not reach it. + } + } + break; + default: + break; + } + } + break; + case PROP_CAP_OBJECT_LEVEL: + { + switch (eType) + { + case TABLE_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Table::Settings::Level::isReadOnly(); + break; + case FRAME_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Frame::Settings::Level::isReadOnly(); + break; + case GRAPHIC_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Graphic::Settings::Level::isReadOnly(); + break; + case OLE_CAP: + { + if (rOleId == SvGlobalName(SO3_SC_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Calc::Settings::Level::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SIMPRESS_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Impress::Settings::Level::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SCH_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Chart::Settings::Level::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SM_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Formula::Settings::Level::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SDRAW_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Draw::Settings::Level::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_OUT_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::OLEMisc::Settings::Level::isReadOnly(); + } + else { + // Should not reach it. + } + } + break; + default: + break; + } + } + break; + case PROP_CAP_OBJECT_POSITION: + { + switch (eType) + { + case TABLE_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Table::Settings::Position::isReadOnly(); + break; + case FRAME_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Frame::Settings::Position::isReadOnly(); + break; + case GRAPHIC_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Graphic::Settings::Position::isReadOnly(); + break; + case OLE_CAP: + { + if (rOleId == SvGlobalName(SO3_SC_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Calc::Settings::Position::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SIMPRESS_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Impress::Settings::Position::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SCH_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Chart::Settings::Position::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SM_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Formula::Settings::Position::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SDRAW_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Draw::Settings::Position::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_OUT_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::OLEMisc::Settings::Position::isReadOnly(); + } + else { + // Should not reach it. + } + } + break; + default: + break; + } + } + break; + case PROP_CAP_OBJECT_CHARACTERSTYLE: + { + switch (eType) + { + case TABLE_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Table::Settings::CharacterStyle::isReadOnly(); + break; + case FRAME_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Frame::Settings::CharacterStyle::isReadOnly(); + break; + case GRAPHIC_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Graphic::Settings::CharacterStyle::isReadOnly(); + break; + case OLE_CAP: + { + if (rOleId == SvGlobalName(SO3_SC_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Calc::Settings::CharacterStyle::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SIMPRESS_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Impress::Settings::CharacterStyle::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SCH_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Chart::Settings::CharacterStyle::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SM_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Formula::Settings::CharacterStyle::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SDRAW_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Draw::Settings::CharacterStyle::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_OUT_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::OLEMisc::Settings::CharacterStyle::isReadOnly(); + } + else { + // Should not reach it. + } + } + break; + default: + break; + } + } + break; + case PROP_CAP_OBJECT_APPLYATTRIBUTES: + { + switch (eType) + { + case GRAPHIC_CAP: + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Graphic::Settings::ApplyAttributes::isReadOnly(); + break; + case OLE_CAP: + { + if (rOleId == SvGlobalName(SO3_SC_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Calc::Settings::ApplyAttributes::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SIMPRESS_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Impress::Settings::ApplyAttributes::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SCH_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Chart::Settings::ApplyAttributes::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SM_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Formula::Settings::ApplyAttributes::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_SDRAW_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Draw::Settings::ApplyAttributes::isReadOnly(); + } + else if (rOleId == SvGlobalName(SO3_OUT_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::OLEMisc::Settings::ApplyAttributes::isReadOnly(); + } + else { + // Should not reach it. + } + } + break; + default: + break; + } + } + break; + default: + break; + } + + return bReadOnly; +} + +sal_uInt32 SwFieldUnitTable::Count() +{ + return SAL_N_ELEMENTS(STR_ARR_METRIC); +} + +OUString SwFieldUnitTable::GetString(sal_uInt32 nPos) +{ + if (RESARRAY_INDEX_NOTFOUND != nPos && nPos < Count()) + return SwResId(STR_ARR_METRIC[nPos].first); + return OUString(); +} + +FieldUnit SwFieldUnitTable::GetValue(sal_uInt32 nPos) +{ + if (RESARRAY_INDEX_NOTFOUND != nPos && nPos < Count()) + return STR_ARR_METRIC[nPos].second; + return FieldUnit::NONE; +} + +SwLoadOptPage::SwLoadOptPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/optgeneralpage.ui", "OptGeneralPage", &rSet) + , m_pWrtShell(nullptr) + , m_nLastTab(0) + , m_nOldLinkMode(MANUAL) + , m_xAlwaysRB(m_xBuilder->weld_radio_button("always")) + , m_xRequestRB(m_xBuilder->weld_radio_button("onrequest")) + , m_xNeverRB(m_xBuilder->weld_radio_button("never")) + , m_xGridupdatelink(m_xBuilder->weld_widget("gridupdatelink")) + , m_xUpdateLinkImg(m_xBuilder->weld_widget("lockupdatelink")) + , m_xAutoUpdateFields(m_xBuilder->weld_check_button("updatefields")) + , m_xAutoUpdateFieldsImg(m_xBuilder->weld_widget("lockupdatefields")) + , m_xAutoUpdateCharts(m_xBuilder->weld_check_button("updatecharts")) + , m_xAutoUpdateChartsImg(m_xBuilder->weld_widget("lockupdatecharts")) + , m_xMetricLB(m_xBuilder->weld_combo_box("metric")) + , m_xMetricImg(m_xBuilder->weld_widget("lockmetric")) + , m_xTabFT(m_xBuilder->weld_label("tablabel")) + , m_xTabMF(m_xBuilder->weld_metric_spin_button("tab", FieldUnit::CM)) + , m_xTabImg(m_xBuilder->weld_widget("locktab")) + , m_xUseSquaredPageMode(m_xBuilder->weld_check_button("squaremode")) + , m_xUseSquaredPageModeImg(m_xBuilder->weld_widget("locksquaremode")) + , m_xUseCharUnit(m_xBuilder->weld_check_button("usecharunit")) + , m_xUseCharUnitImg(m_xBuilder->weld_widget("lockusecharunit")) + , m_xWordCountED(m_xBuilder->weld_entry("wordcount")) + , m_xWordCountImg(m_xBuilder->weld_widget("lockwordcount")) + , m_xShowStandardizedPageCount(m_xBuilder->weld_check_button("standardizedpageshow")) + , m_xShowStandardizedPageCountImg(m_xBuilder->weld_widget("lockstandardizedpageshow")) + , m_xStandardizedPageSizeNF(m_xBuilder->weld_spin_button("standardpagesize")) + , m_xStandardizedPageSizeImg(m_xBuilder->weld_widget("lockstandardpagesize")) +{ + for (sal_uInt32 i = 0; i < SwFieldUnitTable::Count(); ++i) + { + const OUString sMetric = SwFieldUnitTable::GetString(i); + FieldUnit eFUnit = SwFieldUnitTable::GetValue(i); + + switch ( eFUnit ) + { + case FieldUnit::MM: + case FieldUnit::CM: + case FieldUnit::POINT: + case FieldUnit::PICA: + case FieldUnit::INCH: + { + // use only these metrics + m_xMetricLB->append(OUString::number(static_cast<sal_uInt32>(eFUnit)), sMetric); + break; + } + default:; //prevent warning + } + } + m_xMetricLB->connect_changed(LINK(this, SwLoadOptPage, MetricHdl)); + + const SfxUInt16Item* pItem = rSet.GetItemIfSet(SID_HTML_MODE, false); + if (pItem && pItem->GetValue() & HTMLMODE_ON) + { + m_xTabFT->hide(); + m_xTabMF->hide(); + } + + if(!SvtCJKOptions::IsAsianTypographyEnabled()) + { + m_xUseSquaredPageMode->hide(); + m_xUseCharUnit->hide(); + } + + m_xShowStandardizedPageCount->connect_toggled(LINK(this, SwLoadOptPage, StandardizedPageCountCheckHdl)); +} + +SwLoadOptPage::~SwLoadOptPage() +{ +} + +std::unique_ptr<SfxTabPage> SwLoadOptPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SwLoadOptPage>(pPage, pController, *rAttrSet ); +} + +IMPL_LINK_NOARG(SwLoadOptPage, StandardizedPageCountCheckHdl, weld::Toggleable&, void) +{ + m_xStandardizedPageSizeNF->set_sensitive(m_xShowStandardizedPageCount->get_active()); +} + +OUString SwLoadOptPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label2", "label1", "label3", "label5", + "tablabel", "label4", "label7", "labelstandardpages" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] + = { "updatefields", "updatecharts", "usecharunit", "squaremode", "standardizedpageshow" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + OUString radioButton[] = { "always", "onrequest", "never" }; + + for (const auto& radio : radioButton) + { + if (const auto& pString = m_xBuilder->weld_radio_button(radio)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SwLoadOptPage::FillItemSet( SfxItemSet* rSet ) +{ + bool bRet = false; + SwModule* pMod = SW_MOD(); + + sal_Int32 nNewLinkMode = AUTOMATIC; + if (m_xNeverRB->get_active()) + nNewLinkMode = NEVER; + else if (m_xRequestRB->get_active()) + nNewLinkMode = MANUAL; + + SwFieldUpdateFlags eFieldFlags = m_xAutoUpdateFields->get_active() ? + m_xAutoUpdateCharts->get_active() ? AUTOUPD_FIELD_AND_CHARTS : AUTOUPD_FIELD_ONLY : AUTOUPD_OFF; + + if (m_xAutoUpdateFields->get_state_changed_from_saved() || + m_xAutoUpdateCharts->get_state_changed_from_saved()) + { + pMod->ApplyFieldUpdateFlags(eFieldFlags); + if(m_pWrtShell) + { + m_pWrtShell->SetFieldUpdateFlags(eFieldFlags); + m_pWrtShell->SetModified(); + } + } + + if (nNewLinkMode != m_nOldLinkMode) + { + pMod->ApplyLinkMode(nNewLinkMode); + if (m_pWrtShell) + { + m_pWrtShell->SetLinkUpdMode( nNewLinkMode ); + m_pWrtShell->SetModified(); + } + + bRet = true; + } + + const sal_Int32 nMPos = m_xMetricLB->get_active(); + if (m_xMetricLB->get_value_changed_from_saved()) + { + // Double-Cast for VA3.0 + const sal_uInt16 nFieldUnit = m_xMetricLB->get_id(nMPos).toUInt32(); + rSet->Put( SfxUInt16Item( SID_ATTR_METRIC, nFieldUnit ) ); + bRet = true; + } + + if (m_xTabMF->get_visible() && m_xTabMF->get_value_changed_from_saved()) + { + rSet->Put(SfxUInt16Item(SID_ATTR_DEFTABSTOP, + o3tl::narrowing<sal_uInt16>(m_xTabMF->denormalize(m_xTabMF->get_value(FieldUnit::TWIP))))); + bRet = true; + } + + bool bIsUseCharUnitFlag = m_xUseCharUnit->get_active(); + bIsUseCharUnitFlag = bIsUseCharUnitFlag && SvtCJKOptions::IsAsianTypographyEnabled(); + if( (bIsUseCharUnitFlag ? 1 : 0) != m_xUseCharUnit->get_saved_state()) + { + rSet->Put(SfxBoolItem(SID_ATTR_APPLYCHARUNIT, bIsUseCharUnitFlag )); + bRet = true; + } + + if (m_xWordCountED->get_value_changed_from_saved()) + { + std::shared_ptr< comphelper::ConfigurationChanges > batch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Writer::WordCount::AdditionalSeparators::set(m_xWordCountED->get_text(), batch); + batch->commit(); + bRet = true; + } + + if (m_xShowStandardizedPageCount->get_state_changed_from_saved()) + { + std::shared_ptr< comphelper::ConfigurationChanges > batch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Writer::WordCount::ShowStandardizedPageCount::set( + m_xShowStandardizedPageCount->get_active(), + batch); + batch->commit(); + bRet = true; + } + + if (m_xStandardizedPageSizeNF->get_value_changed_from_saved()) + { + std::shared_ptr< comphelper::ConfigurationChanges > batch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Writer::WordCount::StandardizedPageSize::set( + m_xStandardizedPageSizeNF->get_value(), + batch); + batch->commit(); + bRet = true; + } + + if (m_xUseSquaredPageMode->get_state_changed_from_saved()) + { + bool bIsSquaredPageModeFlag = m_xUseSquaredPageMode->get_active(); + pMod->ApplyDefaultPageMode( bIsSquaredPageModeFlag ); + if ( m_pWrtShell ) + { + SwDoc* pDoc = m_pWrtShell->GetDoc(); + pDoc->SetDefaultPageMode( bIsSquaredPageModeFlag ); + m_pWrtShell->SetModified(); + } + bRet = true; + } + + return bRet; +} + +void SwLoadOptPage::Reset( const SfxItemSet* rSet) +{ + const SwMasterUsrPref* pUsrPref = SW_MOD()->GetUsrPref(false); + const SwPtrItem* pShellItem = rSet->GetItemIfSet(FN_PARAM_WRTSHELL, false); + + if(pShellItem) + m_pWrtShell = static_cast<SwWrtShell*>(pShellItem->GetValue()); + + SwFieldUpdateFlags eFieldFlags = AUTOUPD_GLOBALSETTING; + m_nOldLinkMode = GLOBALSETTING; + if (m_pWrtShell) + { + eFieldFlags = m_pWrtShell->GetFieldUpdateFlags(); + m_nOldLinkMode = m_pWrtShell->GetLinkUpdMode(); + } + if(GLOBALSETTING == m_nOldLinkMode) + m_nOldLinkMode = pUsrPref->GetUpdateLinkMode(); + if(AUTOUPD_GLOBALSETTING == eFieldFlags) + eFieldFlags = pUsrPref->GetFieldUpdateFlags(); + + m_xAutoUpdateFields->set_active(eFieldFlags != AUTOUPD_OFF); + m_xAutoUpdateCharts->set_active(eFieldFlags == AUTOUPD_FIELD_AND_CHARTS); + + switch (m_nOldLinkMode) + { + case NEVER: m_xNeverRB->set_active(true); break; + case MANUAL: m_xRequestRB->set_active(true); break; + case AUTOMATIC: m_xAlwaysRB->set_active(true); break; + } + + m_xAutoUpdateFields->save_state(); + m_xAutoUpdateCharts->save_state(); + m_xMetricLB->set_active(-1); + if ( rSet->GetItemState( SID_ATTR_METRIC ) >= SfxItemState::DEFAULT ) + { + const SfxUInt16Item& rItem = rSet->Get( SID_ATTR_METRIC ); + FieldUnit eFieldUnit = static_cast<FieldUnit>(rItem.GetValue()); + + for (sal_Int32 i = 0, nEntryCount = m_xMetricLB->get_count(); i < nEntryCount; ++i) + { + if (m_xMetricLB->get_id(i).toUInt32() == static_cast<sal_uInt32>(eFieldUnit)) + { + m_xMetricLB->set_active(i); + break; + } + } + ::SetFieldUnit(*m_xTabMF, eFieldUnit); + } + m_xMetricLB->save_value(); + if(const SfxUInt16Item* pItem = rSet->GetItemIfSet(SID_ATTR_DEFTABSTOP, false)) + { + m_nLastTab = pItem->GetValue(); + m_xTabMF->set_value(m_xTabMF->normalize(m_nLastTab), FieldUnit::TWIP); + } + m_xTabMF->save_value(); + + //default page mode loading + if(m_pWrtShell) + { + bool bSquaredPageMode = m_pWrtShell->GetDoc()->IsSquaredPageMode(); + m_xUseSquaredPageMode->set_active( bSquaredPageMode ); + m_xUseSquaredPageMode->save_state(); + } + + if(const SfxBoolItem* pItem = rSet->GetItemIfSet(SID_ATTR_APPLYCHARUNIT, false)) + { + bool bUseCharUnit = pItem->GetValue(); + m_xUseCharUnit->set_active(bUseCharUnit); + } + else + { + m_xUseCharUnit->set_active(pUsrPref->IsApplyCharUnit()); + } + m_xUseCharUnit->save_state(); + + bool bReadOnly = officecfg::Office::Writer::Content::Update::Link::isReadOnly(); + m_xGridupdatelink->set_sensitive(!bReadOnly); + m_xUpdateLinkImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Content::Update::Field::isReadOnly(); + m_xAutoUpdateFields->set_sensitive(!bReadOnly); + m_xAutoUpdateFieldsImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Content::Update::Chart::isReadOnly(); + m_xAutoUpdateCharts->set_sensitive(!bReadOnly); + m_xAutoUpdateChartsImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Layout::Other::MeasureUnit::isReadOnly(); + m_xMetricLB->set_sensitive(!bReadOnly); + m_xMetricImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Layout::Other::TabStop::isReadOnly(); + m_xTabMF->set_sensitive(!bReadOnly); + m_xTabImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Layout::Other::ApplyCharUnit::isReadOnly(); + m_xUseCharUnit->set_sensitive(!bReadOnly); + m_xUseCharUnitImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Layout::Other::IsSquaredPageMode::isReadOnly(); + m_xUseSquaredPageMode->set_sensitive(!bReadOnly); + m_xUseSquaredPageModeImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::WordCount::AdditionalSeparators::isReadOnly(); + m_xWordCountED->set_text(officecfg::Office::Writer::WordCount::AdditionalSeparators::get()); + m_xWordCountED->set_sensitive(!bReadOnly); + m_xWordCountImg->set_visible(bReadOnly); + m_xWordCountED->save_value(); + + bReadOnly = officecfg::Office::Writer::WordCount::ShowStandardizedPageCount::isReadOnly(); + m_xShowStandardizedPageCount->set_active(officecfg::Office::Writer::WordCount::ShowStandardizedPageCount::get()); + m_xShowStandardizedPageCount->set_sensitive(!bReadOnly); + m_xShowStandardizedPageCountImg->set_visible(bReadOnly); + m_xShowStandardizedPageCount->save_state(); + + bReadOnly = officecfg::Office::Writer::WordCount::StandardizedPageSize::isReadOnly(); + m_xStandardizedPageSizeNF->set_value(officecfg::Office::Writer::WordCount::StandardizedPageSize::get()); + m_xStandardizedPageSizeNF->set_sensitive(!bReadOnly && m_xShowStandardizedPageCount->get_active()); + m_xStandardizedPageSizeImg->set_visible(bReadOnly); + m_xStandardizedPageSizeNF->save_value(); +} + +IMPL_LINK_NOARG(SwLoadOptPage, MetricHdl, weld::ComboBox&, void) +{ + const sal_Int32 nMPos = m_xMetricLB->get_active(); + if(nMPos == -1) + return; + + // Double-Cast for VA3.0 + FieldUnit eFieldUnit = static_cast<FieldUnit>(m_xMetricLB->get_id(nMPos).toUInt32()); + bool bModified = m_xTabMF->get_value_changed_from_saved(); + tools::Long nVal = bModified ? + sal::static_int_cast<sal_Int32, sal_Int64 >( m_xTabMF->denormalize( m_xTabMF->get_value( FieldUnit::TWIP ) )) : + m_nLastTab; + ::SetFieldUnit( *m_xTabMF, eFieldUnit ); + m_xTabMF->set_value( m_xTabMF->normalize( nVal ), FieldUnit::TWIP ); + if (!bModified) + m_xTabMF->save_value(); +} + +SwCaptionOptDlg::SwCaptionOptDlg(weld::Window* pParent, const SfxItemSet& rSet) + : SfxSingleTabDialogController(pParent, &rSet, "modules/swriter/ui/captiondialog.ui", + "CaptionDialog") +{ + // create TabPage + SetTabPage(SwCaptionOptPage::Create(get_content_area(), this, &rSet)); +} + +SwCaptionPreview::SwCaptionPreview() + : mbFontInitialized(false) +{ +} + +void SwCaptionPreview::ApplySettings(vcl::RenderContext& rRenderContext) +{ + const StyleSettings& rSettings = rRenderContext.GetSettings().GetStyleSettings(); + Wallpaper aBack(rSettings.GetWindowColor()); + rRenderContext.SetBackground(aBack); + rRenderContext.SetFillColor(aBack.GetColor()); + rRenderContext.SetLineColor(aBack.GetColor()); + rRenderContext.SetTextColor(rSettings.GetWindowTextColor()); + + if (!mbFontInitialized) + { + maFont = rRenderContext.GetFont(); + maFont.SetFontHeight(maFont.GetFontHeight() * 120 / 100); + mbFontInitialized = true; + } + rRenderContext.SetFont(maFont); +} + +void SwCaptionPreview::SetPreviewText(const OUString& rText) +{ + if (rText != maText) + { + maText = rText; + Invalidate(); + } +} + +void SwCaptionPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + CustomWidgetController::SetDrawingArea(pDrawingArea); + Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(106 , 20), MapMode(MapUnit::MapAppFont))); + pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); +} + +void SwCaptionPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + ApplySettings(rRenderContext); + + rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), GetOutputSizePixel())); + rRenderContext.DrawText(Point(4, 6), maText); +} + +IMPL_LINK(SwCaptionOptPage, TextFilterHdl, OUString&, rTest, bool) +{ + rTest = m_aTextFilter.filter(rTest); + return true; +} + +SwCaptionOptPage::SwCaptionOptPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/optcaptionpage.ui", "OptCaptionPage", &rSet) + , m_sSWTable(SwResId(STR_CAPTION_TABLE)) + , m_sSWFrame(SwResId(STR_CAPTION_FRAME)) + , m_sSWGraphic(SwResId(STR_CAPTION_GRAPHIC)) + , m_sOLE(SwResId(STR_CAPTION_OLE)) + , m_sBegin(SwResId(STR_CAPTION_BEGINNING)) + , m_sEnd(SwResId(STR_CAPTION_END)) + , m_sAbove(SwResId(STR_CAPTION_ABOVE)) + , m_sBelow(SwResId(STR_CAPTION_BELOW)) + , m_sNone(SwResId(SW_STR_NONE)) + , m_nPrevSelectedEntry(-1) + , m_pMgr(new SwFieldMgr) + , m_bHTMLMode(false) + , m_aTextFilter(m_sNone) + , m_xCheckLB(m_xBuilder->weld_tree_view("objects")) + , m_xLbCaptionOrder(m_xBuilder->weld_combo_box("captionorder")) + , m_xLbCaptionOrderImg(m_xBuilder->weld_widget("lockcaptionorder")) + , m_xSettingsGroup(m_xBuilder->weld_widget("settings")) + , m_xCategoryBox(m_xBuilder->weld_combo_box("category")) + , m_xCategoryBoxImg(m_xBuilder->weld_widget("lockcategory")) + , m_xFormatText(m_xBuilder->weld_label("numberingft")) + , m_xFormatBox(m_xBuilder->weld_combo_box("numbering")) + , m_xFormatBoxImg(m_xBuilder->weld_widget("locknumbering")) + , m_xNumberingSeparatorFT(m_xBuilder->weld_label("numseparatorft")) + , m_xNumberingSeparatorED(m_xBuilder->weld_entry("numseparator")) + , m_xNumberingSeparatorImg(m_xBuilder->weld_widget("locknumseparator")) + , m_xTextText(m_xBuilder->weld_label("separatorft")) + , m_xTextEdit(m_xBuilder->weld_entry("separator")) + , m_xTextEditImg(m_xBuilder->weld_widget("lockseparator")) + , m_xPosBox(m_xBuilder->weld_combo_box("position")) + , m_xPosBoxImg(m_xBuilder->weld_widget("lockposition")) + , m_xNumCapt(m_xBuilder->weld_widget("numcaption")) + , m_xLbLevel(m_xBuilder->weld_combo_box("level")) + , m_xLbLevelImg(m_xBuilder->weld_widget("locklevel")) + , m_xEdDelim(m_xBuilder->weld_entry("chapseparator")) + , m_xEdDelimImg(m_xBuilder->weld_widget("lockchapseparator")) + , m_xCategory(m_xBuilder->weld_widget("categoryformat")) + , m_xCharStyleLB(m_xBuilder->weld_combo_box("charstyle")) + , m_xCharStyleImg(m_xBuilder->weld_widget("lockcharstyle")) + , m_xApplyBorderCB(m_xBuilder->weld_check_button("applyborder")) + , m_xApplyBorderImg(m_xBuilder->weld_widget("lockapplyborder")) + , m_xPreview(new weld::CustomWeld(*m_xBuilder, "preview", m_aPreview)) +{ + m_xCategoryBox->connect_entry_insert_text(LINK(this, SwCaptionOptPage, TextFilterHdl)); + + m_xCheckLB->enable_toggle_buttons(weld::ColumnToggleType::Check); + + SwStyleNameMapper::FillUIName(RES_POOLCOLL_LABEL_ABB, m_sIllustration); + SwStyleNameMapper::FillUIName(RES_POOLCOLL_LABEL_TABLE, m_sTable); + SwStyleNameMapper::FillUIName(RES_POOLCOLL_LABEL_FRAME, m_sText); + SwStyleNameMapper::FillUIName(RES_POOLCOLL_LABEL_DRAWING, m_sDrawing); + + + // m_xFormatBox + sal_uInt16 nSelFormat = SVX_NUM_ARABIC; + SwWrtShell* pSh = ::GetActiveWrtShell(); + + if (pSh) + { + for ( auto i = m_pMgr->GetFieldTypeCount(); i; ) + { + SwFieldType* pFieldType = m_pMgr->GetFieldType(SwFieldIds::Unknown, --i); + if (!pFieldType->GetName().isEmpty() + && pFieldType->GetName() == m_xCategoryBox->get_active_text()) + { + nSelFormat = o3tl::narrowing<sal_uInt16>(static_cast<SwSetExpFieldType*>(pFieldType)->GetSeqFormat()); + break; + } + } + + ::FillCharStyleListBox( *m_xCharStyleLB, pSh->GetView().GetDocShell(), true, true ); + } + + const sal_uInt16 nCount = m_pMgr->GetFormatCount(SwFieldTypesEnum::Sequence, false); + for ( sal_uInt16 i = 0; i < nCount; ++i ) + { + const sal_uInt16 nFormatId = m_pMgr->GetFormatId(SwFieldTypesEnum::Sequence, i); + m_xFormatBox->append(OUString::number(nFormatId), m_pMgr->GetFormatStr(SwFieldTypesEnum::Sequence, i)); + if (nFormatId == nSelFormat) + m_xFormatBox->set_active(i); + } + + for (int i = 0; i < MAXLEVEL; ++i) + m_xLbLevel->append_text(OUString::number(i + 1)); + + sal_Unicode nLvl = MAXLEVEL; + OUString sDelim(": "); + + if (pSh) + { + SwSetExpFieldType* pFieldType = static_cast<SwSetExpFieldType*>(m_pMgr->GetFieldType( + SwFieldIds::SetExp, m_xCategoryBox->get_active_text() )); + if( pFieldType ) + { + sDelim = pFieldType->GetDelimiter(); + nLvl = pFieldType->GetOutlineLvl(); + } + } + + m_xLbLevel->set_active(nLvl < MAXLEVEL ? nLvl + 1 : 0); + m_xEdDelim->set_text(sDelim); + + m_xCategoryBox->connect_changed(LINK(this, SwCaptionOptPage, ModifyComboHdl)); + Link<weld::Entry&,void> aLk = LINK(this, SwCaptionOptPage, ModifyEntryHdl); + m_xNumberingSeparatorED->connect_changed(aLk); + m_xTextEdit->connect_changed(aLk); + + m_xCategoryBox->connect_changed(LINK(this, SwCaptionOptPage, SelectHdl)); + m_xFormatBox->connect_changed(LINK(this, SwCaptionOptPage, SelectListBoxHdl)); + + m_xLbCaptionOrder->connect_changed(LINK(this, SwCaptionOptPage, OrderHdl)); + + m_xCheckLB->connect_changed(LINK(this, SwCaptionOptPage, ShowEntryHdl)); + m_xCheckLB->connect_toggled(LINK(this, SwCaptionOptPage, ToggleEntryHdl)); +} + +SwCaptionOptPage::~SwCaptionOptPage() +{ + DelUserData(); + m_pMgr.reset(); + m_xPreview.reset(); +} + +std::unique_ptr<SfxTabPage> SwCaptionOptPage::Create(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwCaptionOptPage>(pPage, pController, *rAttrSet); +} + +OUString SwCaptionOptPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "label13", "label2", "label7", "numberingft", + "numseparatorft", "separatorft", "label18", "label11", "label4", + "label6", "label10", "label3" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + if (const auto& pString = m_xBuilder->weld_check_button("applyborder")) + sAllStrings += pString->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool SwCaptionOptPage::FillItemSet( SfxItemSet* ) +{ + bool bRet = false; + SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig(); + + SaveEntry(m_xCheckLB->get_selected_index()); // apply current entry + + int nCheckCount = 0; + for (int i = 0, nCount = m_xCheckLB->n_children(); i < nCount; ++i) + { + if (m_xCheckLB->get_toggle(i) == TRISTATE_TRUE) + ++nCheckCount; + InsCaptionOpt* pData = weld::fromId<InsCaptionOpt*>(m_xCheckLB->get_id(i)); + bRet |= pModOpt->SetCapOption(m_bHTMLMode, pData); + } + + pModOpt->SetInsWithCaption(m_bHTMLMode, nCheckCount > 0); + + int nPos = m_xLbCaptionOrder->get_active(); + pModOpt->SetCaptionOrderNumberingFirst(nPos == 1); + + return bRet; +} + +void SwCaptionOptPage::Reset( const SfxItemSet* rSet) +{ + if(const SfxUInt16Item* pItem = rSet->GetItemIfSet(SID_HTML_MODE, false)) + { + m_bHTMLMode = 0 != (pItem->GetValue() & HTMLMODE_ON); + } + + DelUserData(); + m_xCheckLB->clear(); // remove all entries + + // Writer objects + int nPos = 0; + bool bReadOnly = false; + m_xCheckLB->append(); + m_xCheckLB->set_toggle(nPos, TRISTATE_FALSE); + m_xCheckLB->set_text(nPos, m_sSWTable, 0); + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Table::Enable::isReadOnly(); + m_xCheckLB->set_sensitive(nPos, !bReadOnly); + SetOptions(nPos++, TABLE_CAP); + m_xCheckLB->append(); + m_xCheckLB->set_toggle(nPos, TRISTATE_FALSE); + m_xCheckLB->set_text(nPos, m_sSWFrame, 0); + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Frame::Enable::isReadOnly(); + m_xCheckLB->set_sensitive(nPos, !bReadOnly); + SetOptions(nPos++, FRAME_CAP); + m_xCheckLB->append(); + m_xCheckLB->set_toggle(nPos, TRISTATE_FALSE); + m_xCheckLB->set_text(nPos, m_sSWGraphic, 0); + bReadOnly = officecfg::Office::Writer::Insert::Caption::WriterObject::Graphic::Enable::isReadOnly(); + m_xCheckLB->set_sensitive(nPos, !bReadOnly); + SetOptions(nPos++, GRAPHIC_CAP); + + // get Productname and -version + const OUString sWithoutVersion( utl::ConfigManager::getProductName() ); + const OUString sComplete( + sWithoutVersion + " " + + utl::ConfigManager::getProductVersion() ); + + SvObjectServerList aObjS; + aObjS.FillInsertObjects(); + aObjS.Remove( SvGlobalName( SO3_SW_CLASSID ) ); // remove Writer-ID + + for ( sal_uLong i = 0; i < aObjS.Count(); ++i ) + { + const SvGlobalName &rOleId = aObjS[i].GetClassName(); + OUString sClass; + if (rOleId == SvGlobalName(SO3_OUT_CLASSID)) + sClass = m_sOLE; + else + sClass = aObjS[i].GetHumanName(); + // don't show product version + sClass = sClass.replaceFirst( sComplete, sWithoutVersion ); + m_xCheckLB->append(); + m_xCheckLB->set_toggle(nPos, TRISTATE_FALSE); + m_xCheckLB->set_text(nPos, sClass, 0); + if (rOleId == SvGlobalName(SO3_SC_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Calc::Enable::isReadOnly(); + } else if (rOleId == SvGlobalName(SO3_SDRAW_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Draw::Enable::isReadOnly(); + } else if (rOleId == SvGlobalName(SO3_SM_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Formula::Enable::isReadOnly(); + } else if (rOleId == SvGlobalName(SO3_SCH_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Chart::Enable::isReadOnly(); + } else if (rOleId == SvGlobalName(SO3_SIMPRESS_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::Impress::Enable::isReadOnly(); + } else if (rOleId == SvGlobalName(SO3_OUT_CLASSID)) { + bReadOnly = officecfg::Office::Writer::Insert::Caption::OfficeObject::OLEMisc::Enable::isReadOnly(); + } + else { + // + } + m_xCheckLB->set_sensitive(nPos, !bReadOnly); + SetOptions( nPos++, OLE_CAP, &rOleId ); + } + m_xLbCaptionOrder->set_active( + SW_MOD()->GetModuleConfig()->IsCaptionOrderNumberingFirst() ? 1 : 0); + m_xLbCaptionOrder->set_sensitive(!officecfg::Office::Writer::Insert::Caption::CaptionOrderNumberingFirst::isReadOnly()); + m_xLbCaptionOrderImg->set_visible(officecfg::Office::Writer::Insert::Caption::CaptionOrderNumberingFirst::isReadOnly()); + m_xCheckLB->select(0); + ShowEntryHdl(*m_xCheckLB); +} + +void SwCaptionOptPage::SetOptions(const sal_uLong nPos, + const SwCapObjType eObjType, const SvGlobalName *pOleId) +{ + SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig(); + const InsCaptionOpt* pOpt = pModOpt->GetCapOption(m_bHTMLMode, eObjType, pOleId); + + if (pOpt) + { + InsCaptionOpt* pIns = new InsCaptionOpt(*pOpt); + m_xCheckLB->set_id(nPos, weld::toId(pIns)); + m_xCheckLB->set_toggle(nPos, pOpt->UseCaption() ? TRISTATE_TRUE : TRISTATE_FALSE); + } + else + { + InsCaptionOpt* pIns = new InsCaptionOpt(eObjType, pOleId); + m_xCheckLB->set_id(nPos, weld::toId(pIns)); + } +} + +void SwCaptionOptPage::DelUserData() +{ + for (int i = 0, nCount = m_xCheckLB->n_children(); i < nCount; ++i) + { + delete weld::fromId<InsCaptionOpt*>(m_xCheckLB->get_id(i)); + m_xCheckLB->set_id(i, "0"); + } +} + +void SwCaptionOptPage::UpdateEntry(int nSelEntry) +{ + if (nSelEntry != -1) + { + bool bChecked = m_xCheckLB->get_toggle(nSelEntry) == TRISTATE_TRUE; + + m_xSettingsGroup->set_sensitive(bChecked); + bool bNumSep = bChecked && m_xLbCaptionOrder->get_active() == 1; + m_xNumberingSeparatorED->set_sensitive( bNumSep ); + m_xNumberingSeparatorFT->set_sensitive( bNumSep ); + + m_xNumCapt->set_sensitive(bChecked); + m_xCategory->set_sensitive(bChecked); + m_xPreview->set_sensitive(bChecked); + + + InsCaptionOpt* pOpt = weld::fromId<InsCaptionOpt*>(m_xCheckLB->get_id(nSelEntry)); + + m_xCategoryBox->clear(); + m_xCategoryBox->append_text(m_sNone); + if (::GetActiveWrtShell()) + { + const size_t nCount = m_pMgr->GetFieldTypeCount(); + + for (size_t i = 0; i < nCount; ++i) + { + SwFieldType *pType = m_pMgr->GetFieldType( SwFieldIds::Unknown, i ); + if( pType->Which() == SwFieldIds::SetExp && + static_cast<SwSetExpFieldType *>( pType)->GetType() & nsSwGetSetExpType::GSE_SEQ ) + { + m_xCategoryBox->append_text(pType->GetName()); + } + } + } + else + { + m_xCategoryBox->append_text(m_sIllustration); + m_xCategoryBox->append_text(m_sTable); + m_xCategoryBox->append_text(m_sText); + m_xCategoryBox->append_text(m_sDrawing); + } + + if (!pOpt->GetCategory().isEmpty()) + { + if (m_xCategoryBox->find_text(pOpt->GetCategory()) == -1) + m_xCategoryBox->insert_text(0, pOpt->GetCategory()); + m_xCategoryBox->set_active_text(pOpt->GetCategory()); + } + else + m_xCategoryBox->set_active_text(m_sNone); + + if (m_xCategoryBox->get_active_text().isEmpty()) + { + sal_Int32 nPos = 0; + switch(pOpt->GetObjType()) + { + case OLE_CAP: + case GRAPHIC_CAP: nPos = 1; break; + case TABLE_CAP: nPos = 2; break; + case FRAME_CAP: nPos = 3; break; + } + m_xCategoryBox->set_active(nPos); + } + + bool bReadOnly = lcl_isPropertyReadOnly(pOpt->GetObjType(), PROP_CAP_OBJECT_CATEGORY, pOpt->GetOleId()); + m_xCategoryBox->set_sensitive(bChecked && !bReadOnly); + m_xCategoryBoxImg->set_visible(bReadOnly); + + bReadOnly = lcl_isPropertyReadOnly(pOpt->GetObjType(), PROP_CAP_OBJECT_NUMBERING, pOpt->GetOleId()); + m_xFormatBox->set_sensitive(bChecked && !bReadOnly); + m_xFormatBoxImg->set_visible(bReadOnly); + + bReadOnly = lcl_isPropertyReadOnly(pOpt->GetObjType(), PROP_CAP_OBJECT_NUMBERINGSEPARATOR, pOpt->GetOleId()); + m_xNumberingSeparatorED->set_sensitive(bNumSep && !bReadOnly); + m_xNumberingSeparatorImg->set_visible(bReadOnly); + + bReadOnly = lcl_isPropertyReadOnly(pOpt->GetObjType(), PROP_CAP_OBJECT_CAPTIONTEXT, pOpt->GetOleId()); + m_xTextEdit->set_sensitive(bChecked && !bReadOnly); + m_xTextEditImg->set_visible(bReadOnly); + + bReadOnly = lcl_isPropertyReadOnly(pOpt->GetObjType(), PROP_CAP_OBJECT_DELIMITER, pOpt->GetOleId()); + m_xPosBox->set_sensitive(bChecked && !bReadOnly); + m_xPosBoxImg->set_visible(bReadOnly); + + bReadOnly = lcl_isPropertyReadOnly(pOpt->GetObjType(), PROP_CAP_OBJECT_LEVEL, pOpt->GetOleId()); + m_xLbLevel->set_sensitive(bChecked && !bReadOnly); + m_xLbLevelImg->set_visible(bReadOnly); + + bReadOnly = lcl_isPropertyReadOnly(pOpt->GetObjType(), PROP_CAP_OBJECT_POSITION, pOpt->GetOleId()); + m_xEdDelim->set_sensitive(bChecked && !bReadOnly); + m_xEdDelimImg->set_visible(bReadOnly); + + bReadOnly = lcl_isPropertyReadOnly(pOpt->GetObjType(), PROP_CAP_OBJECT_CHARACTERSTYLE, pOpt->GetOleId()); + m_xCharStyleLB->set_sensitive(bChecked && !bReadOnly); + m_xCharStyleImg->set_visible(bReadOnly); + + for (sal_Int32 i = 0; i < m_xFormatBox->get_count(); i++) + { + if (pOpt->GetNumType() == m_xFormatBox->get_id(i).toUInt32()) + { + m_xFormatBox->set_active(i); + break; + } + } + m_xTextEdit->set_text(pOpt->GetCaption()); + + m_xPosBox->clear(); + switch (pOpt->GetObjType()) + { + case GRAPHIC_CAP: + case TABLE_CAP: + case OLE_CAP: + m_xPosBox->append_text(m_sAbove); + m_xPosBox->append_text(m_sBelow); + break; + case FRAME_CAP: + m_xPosBox->append_text(m_sBegin); + m_xPosBox->append_text(m_sEnd); + break; + } + m_xPosBox->set_active(pOpt->GetPos()); + + sal_Int32 nLevelPos = ( pOpt->GetLevel() < MAXLEVEL ) ? pOpt->GetLevel() + 1 : 0; + m_xLbLevel->set_active(nLevelPos); + m_xEdDelim->set_text(pOpt->GetSeparator()); + m_xNumberingSeparatorED->set_text(pOpt->GetNumSeparator()); + if (!pOpt->GetCharacterStyle().isEmpty()) + m_xCharStyleLB->set_active_text(pOpt->GetCharacterStyle()); + else + m_xCharStyleLB->set_active(0); + + bReadOnly = lcl_isPropertyReadOnly(pOpt->GetObjType(), PROP_CAP_OBJECT_APPLYATTRIBUTES, pOpt->GetOleId()); + m_xApplyBorderCB->set_sensitive(m_xCategoryBox->get_sensitive() && !bReadOnly && + pOpt->GetObjType() != TABLE_CAP && pOpt->GetObjType() != FRAME_CAP ); + m_xApplyBorderImg->set_visible(bReadOnly); + m_xApplyBorderCB->set_active(pOpt->CopyAttributes()); + } + + ModifyHdl(); +} + +IMPL_LINK_NOARG(SwCaptionOptPage, ShowEntryHdl, weld::TreeView&, void) +{ + if (m_nPrevSelectedEntry != -1) + SaveEntry(m_nPrevSelectedEntry); + UpdateEntry(m_xCheckLB->get_selected_index()); + m_nPrevSelectedEntry = m_xCheckLB->get_selected_index(); +} + +IMPL_LINK(SwCaptionOptPage, ToggleEntryHdl, const weld::TreeView::iter_col&, rRowCol, void) +{ + UpdateEntry(m_xCheckLB->get_iter_index_in_parent(rRowCol.first)); +} + +void SwCaptionOptPage::SaveEntry(int nEntry) +{ + if (nEntry == -1) + return; + + InsCaptionOpt* pOpt = weld::fromId<InsCaptionOpt*>(m_xCheckLB->get_id(nEntry)); + + pOpt->UseCaption() = m_xCheckLB->get_toggle(nEntry) == TRISTATE_TRUE; + const OUString aName(m_xCategoryBox->get_active_text()); + if (aName == m_sNone) + pOpt->SetCategory(""); + else + pOpt->SetCategory(comphelper::string::strip(aName, ' ')); + pOpt->SetNumType(m_xFormatBox->get_active_id().toUInt32()); + pOpt->SetCaption(m_xTextEdit->get_sensitive() ? m_xTextEdit->get_text() : OUString() ); + pOpt->SetPos(m_xPosBox->get_active()); + int nPos = m_xLbLevel->get_active(); + sal_Int32 nLevel = (nPos > 0) ? nPos - 1 : MAXLEVEL; + pOpt->SetLevel(nLevel); + pOpt->SetSeparator(m_xEdDelim->get_text()); + pOpt->SetNumSeparator(m_xNumberingSeparatorED->get_text()); + if (m_xCharStyleLB->get_active() == -1) + pOpt->SetCharacterStyle(""); + else + pOpt->SetCharacterStyle(m_xCharStyleLB->get_active_text()); + pOpt->CopyAttributes() = m_xApplyBorderCB->get_active(); +} + +void SwCaptionOptPage::ModifyHdl() +{ + const OUString sFieldTypeName = m_xCategoryBox->get_active_text(); + + if (SfxSingleTabDialogController* pDlg = dynamic_cast<SfxSingleTabDialogController*>(GetDialogController())) + pDlg->GetOKButton().set_sensitive(!sFieldTypeName.isEmpty()); + bool bEnable = m_xCategoryBox->get_sensitive() && sFieldTypeName != m_sNone; + + m_xFormatText->set_sensitive(bEnable); + m_xFormatBox->set_sensitive(bEnable); + m_xTextText->set_sensitive(bEnable); + m_xTextEdit->set_sensitive(bEnable); + + InvalidatePreview(); +} + +IMPL_LINK_NOARG(SwCaptionOptPage, ModifyEntryHdl, weld::Entry&, void) +{ + ModifyHdl(); +} + +IMPL_LINK_NOARG(SwCaptionOptPage, ModifyComboHdl, weld::ComboBox&, void) +{ + ModifyHdl(); +} + +IMPL_LINK_NOARG(SwCaptionOptPage, SelectHdl, weld::ComboBox&, void) +{ + InvalidatePreview(); +} + +IMPL_LINK_NOARG(SwCaptionOptPage, SelectListBoxHdl, weld::ComboBox&, void) +{ + InvalidatePreview(); +} + +IMPL_LINK(SwCaptionOptPage, OrderHdl, weld::ComboBox&, rBox, void) +{ + InvalidatePreview(); + + int nSelEntry = m_xCheckLB->get_selected_index(); + bool bChecked = false; + if (nSelEntry != -1) + { + bChecked = m_xCheckLB->get_toggle(nSelEntry) == TRISTATE_TRUE; + } + + int nPos = rBox.get_active(); + m_xNumberingSeparatorFT->set_sensitive(bChecked && nPos == 1); + m_xNumberingSeparatorED->set_sensitive(bChecked && nPos == 1); +} + +void SwCaptionOptPage::InvalidatePreview() +{ + OUString aStr; + + if (m_xCategoryBox->get_active_text() != m_sNone) + { + //#i61007# order of captions + bool bOrderNumberingFirst = m_xLbCaptionOrder->get_active() == 1; + // number + const sal_uInt16 nNumFormat = m_xFormatBox->get_active_id().toUInt32(); + if (SVX_NUM_NUMBER_NONE != nNumFormat) + { + //#i61007# order of captions + if( !bOrderNumberingFirst ) + { + // category + aStr += m_xCategoryBox->get_active_text() + " "; + } + + if (SwWrtShell *pSh = ::GetActiveWrtShell()) + { + SwSetExpFieldType* pFieldType = static_cast<SwSetExpFieldType*>(m_pMgr->GetFieldType( + SwFieldIds::SetExp, m_xCategoryBox->get_active_text() )); + if( pFieldType && pFieldType->GetOutlineLvl() < MAXLEVEL ) + { + sal_uInt8 nLvl = pFieldType->GetOutlineLvl(); + SwNumberTree::tNumberVector aNumVector; + for( sal_uInt8 i = 0; i <= nLvl; ++i ) + aNumVector.push_back(1); + + const OUString sNumber( pSh->GetOutlineNumRule()->MakeNumString( + aNumVector, false )); + if( !sNumber.isEmpty() ) + aStr += sNumber + pFieldType->GetDelimiter(); + } + } + + switch( nNumFormat ) + { + case SVX_NUM_CHARS_UPPER_LETTER: aStr += "A"; break; + case SVX_NUM_CHARS_UPPER_LETTER_N: aStr += "A"; break; + case SVX_NUM_CHARS_LOWER_LETTER: aStr += "a"; break; + case SVX_NUM_CHARS_LOWER_LETTER_N: aStr += "a"; break; + case SVX_NUM_ROMAN_UPPER: aStr += "I"; break; + case SVX_NUM_ROMAN_LOWER: aStr += "i"; break; + //case ARABIC: + default: aStr += "1"; break; + } + } + //#i61007# order of captions + if( bOrderNumberingFirst ) + { + aStr += m_xNumberingSeparatorED->get_text() + m_xCategoryBox->get_active_text(); + } + aStr += m_xTextEdit->get_text(); + } + m_aPreview.SetPreviewText(aStr); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/config/optpage.cxx b/sw/source/ui/config/optpage.cxx new file mode 100644 index 0000000000..a2af6912b7 --- /dev/null +++ b/sw/source/ui/config/optpage.cxx @@ -0,0 +1,2848 @@ +/* -*- 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 <sal/config.h> + +#include <utility> + +#include <optpage.hxx> +#include <doc.hxx> +#include <hintids.hxx> +#include <cmdid.h> +#include <fmtcol.hxx> +#include <charatr.hxx> +#include <swtypes.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <IDocumentDeviceAccess.hxx> +#include <IDocumentSettingAccess.hxx> + +#include <swmodule.hxx> +#include <wrtsh.hxx> +#include <cfgitems.hxx> +#include <poolfmt.hxx> +#include <uiitems.hxx> +#include <printdata.hxx> +#include <modcfg.hxx> +#include <crstate.hxx> +#include <viewopt.hxx> +#include <globals.hrc> +#include <strings.hrc> +#include <swwrtshitem.hxx> + +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/svxenum.hxx> +#include <officecfg/Office/Common.hxx> +#include <officecfg/Office/Writer.hxx> +#include <officecfg/Office/WriterWeb.hxx> +#include <sal/macros.h> +#include <sfx2/dialoghelper.hxx> +#include <sfx2/printer.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/ctloptions.hxx> +#include <svl/eitem.hxx> +#include <svl/cjkoptions.hxx> +#include <svtools/ctrltool.hxx> +#include <svtools/unitconv.hxx> +#include <sfx2/htmlmode.hxx> + +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> + +#include <optload.hxx> + +using namespace ::com::sun::star; + +namespace { + +void drawRect(vcl::RenderContext& rRenderContext, const tools::Rectangle &rRect, const Color &rFillColor, const Color &rLineColor) +{ + rRenderContext.SetFillColor(rFillColor); + rRenderContext.SetLineColor(rLineColor); + rRenderContext.DrawRect(rRect); +} + +} + +// Tools->Options->Writer->View +// Tools->Options->Writer/Web->View +SwContentOptPage::SwContentOptPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/viewoptionspage.ui", "ViewOptionsPage", &rCoreSet) + , m_xCrossCB(m_xBuilder->weld_check_button("helplines")) + , m_xCrossImg(m_xBuilder->weld_widget("lockhelplines")) + , m_xHMetric(m_xBuilder->weld_combo_box("hrulercombobox")) + , m_xHMetricImg(m_xBuilder->weld_widget("lockhruler")) + , m_xVRulerCBox(m_xBuilder->weld_check_button("vruler")) + , m_xVRulerImg(m_xBuilder->weld_widget("lockvruler")) + , m_xVRulerRightCBox(m_xBuilder->weld_check_button("vrulerright")) + , m_xVRulerRightImg(m_xBuilder->weld_widget("lockvrulerright")) + , m_xVMetric(m_xBuilder->weld_combo_box("vrulercombobox")) + , m_xSmoothCBox(m_xBuilder->weld_check_button("smoothscroll")) + , m_xSmoothImg(m_xBuilder->weld_widget("locksmoothscroll")) + , m_xGrfCB(m_xBuilder->weld_check_button("graphics")) + , m_xGrfImg(m_xBuilder->weld_widget("lockgraphics")) + , m_xTableCB(m_xBuilder->weld_check_button("tables")) + , m_xTableImg(m_xBuilder->weld_widget("locktables")) + , m_xDrwCB(m_xBuilder->weld_check_button("drawings")) + , m_xDrwImg(m_xBuilder->weld_widget("lockdrawings")) + , m_xPostItCB(m_xBuilder->weld_check_button("comments")) + , m_xSettingsFrame(m_xBuilder->weld_frame("settingsframe")) + , m_xSettingsLabel(m_xBuilder->weld_label("settingslabel")) + , m_xMetricLabel(m_xBuilder->weld_label("measureunitlabel")) + , m_xMetricLB(m_xBuilder->weld_combo_box("measureunit")) + , m_xMetricImg(m_xBuilder->weld_widget("lockmeasureunit")) + , m_xShowInlineTooltips(m_xBuilder->weld_check_button("changestooltip")) + , m_xShowInlineTooltipsImg(m_xBuilder->weld_widget("lockchangestooltip")) + , m_xShowOutlineContentVisibilityButton(m_xBuilder->weld_check_button("outlinecontentvisibilitybutton")) + , m_xShowOutlineContentVImg(m_xBuilder->weld_widget("lockoutlinecontentvisibility")) + , m_xTreatSubOutlineLevelsAsContent(m_xBuilder->weld_check_button("suboutlinelevelsascontent")) + , m_xTreatSubOutlineLevelsImg(m_xBuilder->weld_widget("locksuboutlinelevels")) + , m_xShowChangesInMargin(m_xBuilder->weld_check_button("changesinmargin")) + , m_xShowChangesInMarginImg(m_xBuilder->weld_widget("lockchangesinmargin")) + , m_xFieldHiddenCB(m_xBuilder->weld_check_button("hiddentextfield")) + , m_xFieldHiddenImg(m_xBuilder->weld_widget("lockhiddentextfield")) + , m_xFieldHiddenParaCB(m_xBuilder->weld_check_button("hiddenparafield")) + , m_xFieldHiddenParaImg(m_xBuilder->weld_widget("lockhiddenparafield")) +{ + m_xShowOutlineContentVisibilityButton->connect_toggled(LINK(this, SwContentOptPage, ShowOutlineContentVisibilityButtonHdl)); + + /* This part is visible only with Writer/Web->View dialogue. */ + const SfxUInt16Item* pItem = rCoreSet.GetItemIfSet(SID_HTML_MODE, false ); + if (!pItem || !(pItem->GetValue() & HTMLMODE_ON)) + { + m_xSettingsFrame->hide(); + m_xSettingsLabel->hide(); + m_xMetricLabel->hide(); + m_xMetricLB->hide(); + } + + if(!SvtCJKOptions::IsVerticalTextEnabled() ) + m_xVRulerRightCBox->hide(); + m_xVRulerCBox->connect_toggled(LINK(this, SwContentOptPage, VertRulerHdl )); + + for (size_t i = 0; i < SwFieldUnitTable::Count(); ++i) + { + const OUString sMetric = SwFieldUnitTable::GetString(i); + FieldUnit eFUnit = SwFieldUnitTable::GetValue(i); + + switch ( eFUnit ) + { + case FieldUnit::MM: + case FieldUnit::CM: + case FieldUnit::POINT: + case FieldUnit::PICA: + case FieldUnit::INCH: + case FieldUnit::CHAR: // add two units , 'character' and 'line' , their ticks are not fixed + case FieldUnit::LINE: + { + // only use these metrics + // a horizontal ruler has not the 'line' unit + // there isn't 'line' unit in HTML format + if (eFUnit != FieldUnit::LINE) + { + m_xMetricLB->append(OUString::number(static_cast<sal_uInt32>(eFUnit)), sMetric); + m_xHMetric->append(OUString::number(static_cast<sal_uInt32>(eFUnit)), sMetric); + } + // a vertical ruler has not the 'character' unit + if (eFUnit != FieldUnit::CHAR) + { + m_xVMetric->append(OUString::number(static_cast<sal_uInt32>(eFUnit)), sMetric); + } + break; + } + default:;//prevent warning + } + } +} + +SwContentOptPage::~SwContentOptPage() +{ +} + +std::unique_ptr<SfxTabPage> SwContentOptPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwContentOptPage>(pPage, pController, *rAttrSet); +} + +static void lcl_SelectMetricLB(weld::ComboBox& rMetric, TypedWhichId<SfxUInt16Item> nSID, const SfxItemSet& rSet) +{ + const SfxPoolItem* pItem; + if( rSet.GetItemState( nSID, false, &pItem ) >= SfxItemState::DEFAULT ) + { + FieldUnit eFieldUnit = static_cast<FieldUnit>(static_cast<const SfxUInt16Item*>(pItem)->GetValue()); + for (sal_Int32 i = 0, nEntryCount = rMetric.get_count(); i < nEntryCount; ++i) + { + if (rMetric.get_id(i).toUInt32() == static_cast<sal_uInt32>(eFieldUnit)) + { + rMetric.set_active(i); + break; + } + } + } + rMetric.save_value(); +} + +void SwContentOptPage::Reset(const SfxItemSet* rSet) +{ + bool bReadOnly = false; + bool bWebOptionsPage = m_xSettingsFrame->is_visible(); + const SwElemItem* pElemAttr = rSet->GetItemIfSet( FN_PARAM_ELEM , false ); + if(pElemAttr) + { + bReadOnly = !bWebOptionsPage ? officecfg::Office::Writer::Content::Display::Table::isReadOnly() : + officecfg::Office::WriterWeb::Content::Display::Table::isReadOnly(); + m_xTableCB->set_active(pElemAttr->m_bTable); + m_xTableCB->set_sensitive(!bReadOnly); + m_xTableImg->set_visible(bReadOnly); + + bReadOnly = !bWebOptionsPage ? officecfg::Office::Writer::Content::Display::GraphicObject::isReadOnly() : + officecfg::Office::WriterWeb::Content::Display::GraphicObject::isReadOnly(); + m_xGrfCB->set_active(pElemAttr->m_bGraphic); + m_xGrfCB->set_sensitive(!bReadOnly); + m_xGrfImg->set_visible(bReadOnly); + + bReadOnly = !bWebOptionsPage ? officecfg::Office::Writer::Content::Display::DrawingControl::isReadOnly() : + officecfg::Office::WriterWeb::Content::Display::DrawingControl::isReadOnly(); + m_xDrwCB->set_active(pElemAttr->m_bDrawing); + m_xDrwCB->set_sensitive(!bReadOnly); + m_xDrwImg->set_visible(bReadOnly); + + bReadOnly = !bWebOptionsPage ? officecfg::Office::Writer::Content::Display::Note::isReadOnly() : + officecfg::Office::WriterWeb::Content::Display::Note::isReadOnly(); + m_xPostItCB->set_active(pElemAttr->m_bNotes); + m_xPostItCB->set_sensitive(!bReadOnly); + m_xPostItCB->set_visible(pElemAttr->m_bNotes); + + bReadOnly = !bWebOptionsPage ? officecfg::Office::Writer::Layout::Line::Guide::isReadOnly() : + officecfg::Office::WriterWeb::Layout::Line::Guide::isReadOnly(); + m_xCrossCB->set_active(pElemAttr->m_bCrosshair); + m_xCrossCB->set_sensitive(!bReadOnly); + m_xCrossImg->set_visible(bReadOnly); + + bReadOnly = !bWebOptionsPage ? officecfg::Office::Writer::Layout::Window::VerticalRuler::isReadOnly() : + officecfg::Office::WriterWeb::Layout::Window::VerticalRuler::isReadOnly(); + m_xVRulerCBox->set_active(pElemAttr->m_bVertRuler); + m_xVRulerCBox->set_sensitive(!bReadOnly); + m_xVRulerImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Layout::Window::IsVerticalRulerRight::isReadOnly(); + m_xVRulerRightCBox->set_active(pElemAttr->m_bVertRulerRight); + m_xVRulerRightCBox->set_sensitive(!bReadOnly); + m_xVRulerRightImg->set_visible(bReadOnly); + + bReadOnly = !bWebOptionsPage ? officecfg::Office::Writer::Layout::Window::SmoothScroll::isReadOnly() : + officecfg::Office::WriterWeb::Layout::Window::SmoothScroll::isReadOnly(); + m_xSmoothCBox->set_active(pElemAttr->m_bSmoothScroll); + m_xSmoothCBox->set_sensitive(!bReadOnly); + m_xSmoothImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Content::Display::ShowInlineTooltips::isReadOnly(); + m_xShowInlineTooltips->set_active(pElemAttr->m_bShowInlineTooltips); + m_xShowInlineTooltips->set_sensitive(!bReadOnly); + m_xShowInlineTooltipsImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Content::Display::ShowOutlineContentVisibilityButton::isReadOnly(); + m_xShowOutlineContentVisibilityButton->set_active(pElemAttr->m_bShowOutlineContentVisibilityButton); + m_xShowOutlineContentVisibilityButton->set_sensitive(!bReadOnly); + m_xShowOutlineContentVImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Content::Display::TreatSubOutlineLevelsAsContent::isReadOnly(); + m_xTreatSubOutlineLevelsAsContent->set_active(pElemAttr->m_bTreatSubOutlineLevelsAsContent); + m_xTreatSubOutlineLevelsAsContent->set_sensitive(pElemAttr->m_bShowOutlineContentVisibilityButton && !bReadOnly); + m_xTreatSubOutlineLevelsImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Content::Display::ShowChangesInMargin::isReadOnly(); + m_xShowChangesInMargin->set_active(pElemAttr->m_bShowChangesInMargin); + m_xShowChangesInMargin->set_sensitive(!bReadOnly); + m_xShowChangesInMarginImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Content::NonprintingCharacter::HiddenText::isReadOnly(); + m_xFieldHiddenCB->set_active( pElemAttr->m_bFieldHiddenText ); + m_xFieldHiddenCB->set_sensitive(!bReadOnly); + m_xFieldHiddenImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Content::NonprintingCharacter::HiddenParagraph::isReadOnly(); + m_xFieldHiddenParaCB->set_active( pElemAttr->m_bShowHiddenPara ); + m_xFieldHiddenParaCB->set_sensitive(!bReadOnly); + m_xFieldHiddenParaImg->set_visible(bReadOnly); + } + + bReadOnly = !bWebOptionsPage ? officecfg::Office::Writer::Layout::Window::HorizontalRulerUnit::isReadOnly() : + officecfg::Office::WriterWeb::Layout::Window::HorizontalRulerUnit::isReadOnly(); + m_xHMetric->set_sensitive(!bReadOnly); + m_xHMetricImg->set_visible(bReadOnly); + + bReadOnly = !bWebOptionsPage ? officecfg::Office::Writer::Layout::Window::VerticalRulerUnit::isReadOnly() : + officecfg::Office::WriterWeb::Layout::Window::VerticalRulerUnit::isReadOnly(); + m_xVMetric->set_sensitive(!bReadOnly); + + m_xMetricLB->set_active(-1); + if (bWebOptionsPage) + { + bReadOnly = officecfg::Office::WriterWeb::Layout::Other::MeasureUnit::isReadOnly(); + m_xMetricLB->set_sensitive(!bReadOnly); + m_xMetricImg->set_visible(bReadOnly); + } + lcl_SelectMetricLB(*m_xMetricLB, SID_ATTR_METRIC, *rSet); + lcl_SelectMetricLB(*m_xHMetric, FN_HSCROLL_METRIC, *rSet); + lcl_SelectMetricLB(*m_xVMetric, FN_VSCROLL_METRIC, *rSet); +} + +OUString SwContentOptPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] + = { "guideslabel", "displaylabel", "displayfl1", "changeslabel", "label3", + "hruler", "settingslabel", "measureunitlabel", "outlinelabel" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "helplines", + "graphics", + "tables", + "drawings", + "comments", + "resolvedcomments", + "hiddentextfield", + "hiddenparafield", + "changesinmargin", + "changestooltip", + "vruler", + "vrulerright", + "smoothscroll", + "outlinecontentvisibilitybutton", + "suboutlinelevelsascontent" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SwContentOptPage::FillItemSet(SfxItemSet* rSet) +{ + const SwElemItem* pOldAttr = GetOldItem(GetItemSet(), FN_PARAM_ELEM); + + SwElemItem aElem; + aElem.m_bTable = m_xTableCB->get_active(); + aElem.m_bGraphic = m_xGrfCB->get_active(); + aElem.m_bDrawing = m_xDrwCB->get_active(); + aElem.m_bNotes = m_xPostItCB->get_active(); + aElem.m_bCrosshair = m_xCrossCB->get_active(); + aElem.m_bVertRuler = m_xVRulerCBox->get_active(); + aElem.m_bVertRulerRight = m_xVRulerRightCBox->get_active(); + aElem.m_bSmoothScroll = m_xSmoothCBox->get_active(); + aElem.m_bShowInlineTooltips = m_xShowInlineTooltips->get_active(); + aElem.m_bShowOutlineContentVisibilityButton = m_xShowOutlineContentVisibilityButton->get_active(); + aElem.m_bTreatSubOutlineLevelsAsContent = m_xTreatSubOutlineLevelsAsContent->get_active(); + aElem.m_bShowChangesInMargin = m_xShowChangesInMargin->get_active(); + aElem.m_bFieldHiddenText = m_xFieldHiddenCB->get_active(); + aElem.m_bShowHiddenPara = m_xFieldHiddenParaCB->get_active(); + + bool bRet = !pOldAttr || aElem != *pOldAttr; + if(bRet) + bRet = nullptr != rSet->Put(aElem); + + sal_Int32 nMPos = m_xMetricLB->get_active(); + sal_Int32 nGlobalMetricPos = nMPos; + if ( m_xMetricLB->get_value_changed_from_saved() ) + { + const sal_uInt16 nFieldUnit = m_xMetricLB->get_id(nMPos).toUInt32(); + rSet->Put( SfxUInt16Item( SID_ATTR_METRIC, nFieldUnit ) ); + bRet = true; + } + + nMPos = m_xHMetric->get_active(); + if ( m_xHMetric->get_value_changed_from_saved() || nMPos != nGlobalMetricPos ) + { + const sal_uInt16 nFieldUnit = m_xHMetric->get_id(nMPos).toUInt32(); + rSet->Put( SfxUInt16Item( FN_HSCROLL_METRIC, nFieldUnit ) ); + bRet = true; + } + nMPos = m_xVMetric->get_active(); + if ( m_xVMetric->get_value_changed_from_saved() || nMPos != nGlobalMetricPos ) + { + const sal_uInt16 nFieldUnit = m_xVMetric->get_id(nMPos).toUInt32(); + rSet->Put( SfxUInt16Item( FN_VSCROLL_METRIC, nFieldUnit ) ); + bRet = true; + } + + return bRet; +} + +IMPL_LINK(SwContentOptPage, VertRulerHdl, weld::Toggleable&, rBox, void) +{ + m_xVRulerRightCBox->set_sensitive(rBox.get_sensitive() && rBox.get_active() && + !officecfg::Office::Writer::Layout::Window::IsVerticalRulerRight::isReadOnly()); +} + +IMPL_LINK(SwContentOptPage, ShowOutlineContentVisibilityButtonHdl, weld::Toggleable&, rBox, void) +{ + m_xTreatSubOutlineLevelsAsContent->set_sensitive(rBox.get_active()); +} + +// TabPage Printer additional settings +SwAddPrinterTabPage::SwAddPrinterTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/printoptionspage.ui", "PrintOptionsPage", &rCoreSet) + , m_sNone(SwResId(SW_STR_NONE)) + , m_bAttrModified(false) + , m_bPreview(false) + , m_bHTMLMode(false) + , m_xGrfCB(m_xBuilder->weld_check_button("graphics")) + , m_xGrfImg(m_xBuilder->weld_widget("lockgraphics")) + , m_xCtrlFieldCB(m_xBuilder->weld_check_button("formcontrols")) + , m_xCtrlFieldImg(m_xBuilder->weld_widget("lockformcontrols")) + , m_xBackgroundCB(m_xBuilder->weld_check_button("background")) + , m_xBackgroundImg(m_xBuilder->weld_widget("lockbackground")) + , m_xBlackFontCB(m_xBuilder->weld_check_button("inblack")) + , m_xBlackFontImg(m_xBuilder->weld_widget("lockinblack")) + , m_xPrintHiddenTextCB(m_xBuilder->weld_check_button("hiddentext")) + , m_xPrintHiddenTextImg(m_xBuilder->weld_widget("lockhiddentext")) + , m_xPrintTextPlaceholderCB(m_xBuilder->weld_check_button("textplaceholder")) + , m_xPrintTextPlaceholderImg(m_xBuilder->weld_widget("locktextplaceholder")) + , m_xPagesFrame(m_xBuilder->weld_widget("pagesframe")) + , m_xLeftPageCB(m_xBuilder->weld_check_button("leftpages")) + , m_xLeftPageImg(m_xBuilder->weld_widget("lockleftpages")) + , m_xRightPageCB(m_xBuilder->weld_check_button("rightpages")) + , m_xRightPageImg(m_xBuilder->weld_widget("lockrightpages")) + , m_xProspectCB(m_xBuilder->weld_check_button("brochure")) + , m_xProspectImg(m_xBuilder->weld_widget("lockbrochure")) + , m_xProspectCB_RTL(m_xBuilder->weld_check_button("rtl")) + , m_xProspectImg_RTL(m_xBuilder->weld_widget("lockrtl")) + , m_xCommentsFrame(m_xBuilder->weld_widget("commentsframe")) + , m_xNoRB(m_xBuilder->weld_radio_button("none")) + , m_xOnlyRB(m_xBuilder->weld_radio_button("only")) + , m_xEndRB(m_xBuilder->weld_radio_button("end")) + , m_xEndPageRB(m_xBuilder->weld_radio_button("endpage")) + , m_xInMarginsRB(m_xBuilder->weld_radio_button("inmargins")) + , m_xMarginsImg(m_xBuilder->weld_widget("lockcomments")) + , m_xPrintEmptyPagesCB(m_xBuilder->weld_check_button("blankpages")) + , m_xPrintEmptyPagesImg(m_xBuilder->weld_widget("lockblankpages")) + , m_xPaperFromSetupCB(m_xBuilder->weld_check_button("papertray")) + , m_xPaperFromSetupImg(m_xBuilder->weld_widget("lockpapertray")) + , m_xFaxLB(m_xBuilder->weld_combo_box("fax")) + , m_xFaxImg(m_xBuilder->weld_widget("lockfax")) +{ + Link<weld::Toggleable&,void> aLk = LINK( this, SwAddPrinterTabPage, AutoClickHdl); + m_xGrfCB->connect_toggled( aLk ); + m_xRightPageCB->connect_toggled( aLk ); + m_xLeftPageCB->connect_toggled( aLk ); + m_xCtrlFieldCB->connect_toggled( aLk ); + m_xBackgroundCB->connect_toggled( aLk ); + m_xBlackFontCB->connect_toggled( aLk ); + m_xPrintHiddenTextCB->connect_toggled( aLk ); + m_xPrintTextPlaceholderCB->connect_toggled( aLk ); + m_xProspectCB->connect_toggled( aLk ); + m_xProspectCB_RTL->connect_toggled( aLk ); + m_xPaperFromSetupCB->connect_toggled( aLk ); + m_xPrintEmptyPagesCB->connect_toggled( aLk ); + m_xEndPageRB->connect_toggled( aLk ); + m_xInMarginsRB->connect_toggled( aLk ); + m_xEndRB->connect_toggled( aLk ); + m_xOnlyRB->connect_toggled( aLk ); + m_xNoRB->connect_toggled( aLk ); + m_xFaxLB->connect_changed( LINK( this, SwAddPrinterTabPage, SelectHdl ) ); + + const SfxUInt16Item* pItem = rCoreSet.GetItemIfSet(SID_HTML_MODE, false ); + if(pItem && pItem->GetValue() & HTMLMODE_ON) + { + m_bHTMLMode = true; + m_xLeftPageCB->hide(); + m_xRightPageCB->hide(); + m_xPrintHiddenTextCB->hide(); + m_xPrintTextPlaceholderCB->hide(); + m_xPrintEmptyPagesCB->hide(); + } + m_xProspectCB_RTL->set_sensitive(false); + SvtCTLOptions aCTLOptions; + m_xProspectCB_RTL->set_visible(SvtCTLOptions::IsCTLFontEnabled()); +} + +SwAddPrinterTabPage::~SwAddPrinterTabPage() +{ +} + +void SwAddPrinterTabPage::SetPreview(bool bPrev) +{ + m_bPreview = bPrev; + m_xCommentsFrame->set_sensitive(!m_bPreview); + m_xPagesFrame->set_sensitive(!m_bPreview); +} + +std::unique_ptr<SfxTabPage> SwAddPrinterTabPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SwAddPrinterTabPage>(pPage, pController, *rAttrSet); +} + +OUString SwAddPrinterTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label2", "label10", "label1", "label5", "4" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] + = { "graphics", "formcontrols", "background", "inblack", "hiddentext", "textplaceholder", + "leftpages", "rightpages", "brochure", "rtl", "blankpages", "papertray" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + OUString radioButton[] = { "none", "only", "end", "endpage", "inmargins" }; + + for (const auto& radio : radioButton) + { + if (const auto& pString = m_xBuilder->weld_radio_button(radio)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SwAddPrinterTabPage::FillItemSet( SfxItemSet* rCoreSet ) +{ + if ( m_bAttrModified ) + { + SwAddPrinterItem aAddPrinterAttr; + aAddPrinterAttr.m_bPrintGraphic = m_xGrfCB->get_active(); + aAddPrinterAttr.m_bPrintTable = true; // always enabled since CWS printerpullgpages /*m_xTabCB->get_active();*/ + aAddPrinterAttr.m_bPrintDraw = m_xGrfCB->get_active(); // UI merged with m_xGrfCB in CWS printerpullgpages + aAddPrinterAttr.m_bPrintControl = m_xCtrlFieldCB->get_active(); + aAddPrinterAttr.m_bPrintPageBackground = m_xBackgroundCB->get_active(); + aAddPrinterAttr.m_bPrintBlackFont = m_xBlackFontCB->get_active(); + aAddPrinterAttr.m_bPrintHiddenText = m_xPrintHiddenTextCB->get_active(); + aAddPrinterAttr.m_bPrintTextPlaceholder = m_xPrintTextPlaceholderCB->get_active(); + + aAddPrinterAttr.m_bPrintLeftPages = m_xLeftPageCB->get_active(); + aAddPrinterAttr.m_bPrintRightPages = m_xRightPageCB->get_active(); + aAddPrinterAttr.m_bPrintReverse = false; // handled by vcl itself since CWS printerpullpages /*m_xReverseCB->get_active()*/; + aAddPrinterAttr.m_bPrintProspect = m_xProspectCB->get_active(); + aAddPrinterAttr.m_bPrintProspectRTL = m_xProspectCB_RTL->get_active(); + aAddPrinterAttr.m_bPaperFromSetup = m_xPaperFromSetupCB->get_active(); + aAddPrinterAttr.m_bPrintEmptyPages = m_xPrintEmptyPagesCB->get_active(); + aAddPrinterAttr.m_bPrintSingleJobs = true; // handled by vcl in new print dialog since CWS printerpullpages /*m_xSingleJobsCB->get_active()*/; + + if (m_xNoRB->get_active()) aAddPrinterAttr.m_nPrintPostIts = + SwPostItMode::NONE; + if (m_xOnlyRB->get_active()) aAddPrinterAttr.m_nPrintPostIts = + SwPostItMode::Only; + if (m_xEndRB->get_active()) aAddPrinterAttr.m_nPrintPostIts = + SwPostItMode::EndDoc; + if (m_xEndPageRB->get_active()) aAddPrinterAttr.m_nPrintPostIts = + SwPostItMode::EndPage; + if (m_xInMarginsRB->get_active()) aAddPrinterAttr.m_nPrintPostIts = + SwPostItMode::InMargins; + + const OUString sFax = m_xFaxLB->get_active_text(); + aAddPrinterAttr.m_sFaxName = m_sNone == sFax ? OUString() : sFax; + rCoreSet->Put(aAddPrinterAttr); + } + return m_bAttrModified; +} + +void SwAddPrinterTabPage::Reset( const SfxItemSet* ) +{ + const SfxItemSet& rSet = GetItemSet(); + bool bReadOnly = false; + + if( const SwAddPrinterItem* pAddPrinterAttr = rSet.GetItemIfSet( FN_PARAM_ADDPRINTER , false ) ) + { + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Print::Content::Graphic::isReadOnly() : + officecfg::Office::WriterWeb::Print::Content::Graphic::isReadOnly(); + m_xGrfCB->set_active(pAddPrinterAttr->m_bPrintGraphic || pAddPrinterAttr->m_bPrintDraw); + m_xGrfCB->set_sensitive(!bReadOnly); + m_xGrfImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Print::Content::Control::isReadOnly() : + officecfg::Office::WriterWeb::Print::Content::Control::isReadOnly(); + m_xCtrlFieldCB->set_active( pAddPrinterAttr->m_bPrintControl); + m_xCtrlFieldCB->set_sensitive(!bReadOnly); + m_xCtrlFieldImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Print::Content::Background::isReadOnly() : + officecfg::Office::WriterWeb::Print::Content::Background::isReadOnly(); + m_xBackgroundCB->set_active( pAddPrinterAttr->m_bPrintPageBackground); + m_xBackgroundCB->set_sensitive(!bReadOnly); + m_xBackgroundImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Print::Content::PrintBlack::isReadOnly() : + officecfg::Office::WriterWeb::Print::Content::PrintBlack::isReadOnly(); + m_xBlackFontCB->set_active( pAddPrinterAttr->m_bPrintBlackFont); + m_xBlackFontCB->set_sensitive(!bReadOnly); + m_xBlackFontImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Print::Content::PrintHiddenText::isReadOnly(); + m_xPrintHiddenTextCB->set_active( pAddPrinterAttr->m_bPrintHiddenText); + m_xPrintHiddenTextCB->set_sensitive(!bReadOnly); + m_xPrintHiddenTextImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Print::Content::PrintPlaceholders::isReadOnly(); + m_xPrintTextPlaceholderCB->set_active(pAddPrinterAttr->m_bPrintTextPlaceholder); + m_xPrintTextPlaceholderCB->set_sensitive(!bReadOnly); + m_xPrintTextPlaceholderImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Print::Page::LeftPage::isReadOnly(); + m_xLeftPageCB->set_active( pAddPrinterAttr->m_bPrintLeftPages); + m_xLeftPageCB->set_sensitive(!bReadOnly); + m_xLeftPageImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Print::Page::RightPage::isReadOnly(); + m_xRightPageCB->set_active( pAddPrinterAttr->m_bPrintRightPages); + m_xRightPageCB->set_sensitive(!bReadOnly); + m_xRightPageImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Print::Papertray::FromPrinterSetup::isReadOnly() : + officecfg::Office::WriterWeb::Print::Papertray::FromPrinterSetup::isReadOnly(); + m_xPaperFromSetupCB->set_active(pAddPrinterAttr->m_bPaperFromSetup); + m_xPaperFromSetupCB->set_sensitive(!bReadOnly); + m_xPaperFromSetupImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Print::EmptyPages::isReadOnly(); + m_xPrintEmptyPagesCB->set_active(pAddPrinterAttr->m_bPrintEmptyPages); + m_xPrintEmptyPagesCB->set_sensitive(!bReadOnly); + m_xPrintEmptyPagesImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Print::Page::Brochure::isReadOnly() : + officecfg::Office::WriterWeb::Print::Page::Brochure::isReadOnly(); + m_xProspectCB->set_active( pAddPrinterAttr->m_bPrintProspect); + m_xProspectCB->set_sensitive(!bReadOnly); + m_xProspectImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Print::Page::BrochureRightToLeft::isReadOnly() : + officecfg::Office::WriterWeb::Print::Page::BrochureRightToLeft::isReadOnly(); + m_xProspectCB_RTL->set_active( pAddPrinterAttr->m_bPrintProspectRTL); + m_xProspectCB_RTL->set_sensitive(!bReadOnly); + m_xProspectImg_RTL->set_visible(bReadOnly); + + m_xNoRB->set_active(pAddPrinterAttr->m_nPrintPostIts== SwPostItMode::NONE ) ; + m_xOnlyRB->set_active(pAddPrinterAttr->m_nPrintPostIts== SwPostItMode::Only ) ; + m_xEndRB->set_active(pAddPrinterAttr->m_nPrintPostIts== SwPostItMode::EndDoc ) ; + m_xEndPageRB->set_active(pAddPrinterAttr->m_nPrintPostIts== SwPostItMode::EndPage ) ; + m_xInMarginsRB->set_active(pAddPrinterAttr->m_nPrintPostIts== SwPostItMode::InMargins ) ; + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Print::Content::Note::isReadOnly() : + officecfg::Office::WriterWeb::Print::Content::Note::isReadOnly(); + m_xNoRB->set_sensitive(!bReadOnly); + m_xOnlyRB->set_sensitive(!bReadOnly); + m_xEndRB->set_sensitive(!bReadOnly); + m_xEndPageRB->set_sensitive(!bReadOnly); + m_xInMarginsRB->set_sensitive(!bReadOnly); + m_xMarginsImg->set_visible(bReadOnly); + + auto nFound = m_xFaxLB->find_text(pAddPrinterAttr->m_sFaxName); + if (nFound != -1) + m_xFaxLB->set_active(nFound); + else if (m_xFaxLB->get_count()) + m_xFaxLB->set_active(0); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Print::Output::Fax::isReadOnly() : + officecfg::Office::WriterWeb::Print::Output::Fax::isReadOnly(); + m_xFaxLB->set_sensitive(!bReadOnly); + m_xFaxImg->set_visible(bReadOnly); + } + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Print::Page::BrochureRightToLeft::isReadOnly() : + officecfg::Office::WriterWeb::Print::Page::BrochureRightToLeft::isReadOnly(); + if (m_xProspectCB->get_active()) + { + m_xProspectCB_RTL->set_sensitive(!bReadOnly); + m_xNoRB->set_sensitive( false ); + m_xOnlyRB->set_sensitive( false ); + m_xEndRB->set_sensitive( false ); + m_xEndPageRB->set_sensitive( false ); + } + else + m_xProspectCB_RTL->set_sensitive( false ); + + m_xProspectImg_RTL->set_visible(bReadOnly); +} + +IMPL_LINK_NOARG(SwAddPrinterTabPage, AutoClickHdl, weld::Toggleable&, void) +{ + m_bAttrModified = true; + bool bIsProspect = m_xProspectCB->get_active(); + if (!bIsProspect) + m_xProspectCB_RTL->set_active( false ); + m_xProspectCB_RTL->set_sensitive( bIsProspect ); + m_xNoRB->set_sensitive( !bIsProspect ); + m_xOnlyRB->set_sensitive( !bIsProspect ); + m_xEndRB->set_sensitive( !bIsProspect ); + m_xEndPageRB->set_sensitive( !bIsProspect ); + m_xInMarginsRB->set_sensitive( !bIsProspect ); +} + +void SwAddPrinterTabPage::SetFax( const std::vector<OUString>& rFaxLst ) +{ + m_xFaxLB->append_text(m_sNone); + for(const auto & i : rFaxLst) + { + m_xFaxLB->append_text(i); + } + m_xFaxLB->set_active(0); +} + +IMPL_LINK_NOARG(SwAddPrinterTabPage, SelectHdl, weld::ComboBox&, void) +{ + m_bAttrModified=true; +} + +void SwAddPrinterTabPage::PageCreated( const SfxAllItemSet& aSet) +{ + const SfxBoolItem* pListItem = aSet.GetItem<SfxBoolItem>(SID_FAX_LIST, false); + const SfxBoolItem* pPreviewItem = aSet.GetItem<SfxBoolItem>(SID_PREVIEWFLAG_TYPE, false); + if (pPreviewItem) + { + SetPreview(pPreviewItem->GetValue()); + Reset(&aSet); + } + if (pListItem && pListItem->GetValue()) + { + std::vector<OUString> aFaxList; + const std::vector<OUString>& rPrinters = Printer::GetPrinterQueues(); + for (const auto & rPrinter : rPrinters) + aFaxList.insert(aFaxList.begin(), rPrinter); + SetFax( aFaxList ); + } +} + +// Tabpage Standardfonts +SwStdFontTabPage::SwStdFontTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/optfonttabpage.ui", "OptFontTabPage", &rSet) + , m_pPrt(nullptr) + , m_pFontConfig(nullptr) + , m_pWrtShell(nullptr) + , m_eLanguage( GetAppLanguage() ) + , m_bListDefault(false) + , m_bSetListDefault(true) + , m_bLabelDefault(false) + , m_bSetLabelDefault(true) + , m_bIdxDefault(false) + , m_bSetIdxDefault(true) + , m_bDisposePrinter(false) + , m_nFontGroup(FONT_GROUP_DEFAULT) + , m_sScriptWestern(SwResId(ST_SCRIPT_WESTERN)) + , m_sScriptAsian(SwResId(ST_SCRIPT_ASIAN)) + , m_sScriptComplex(SwResId(ST_SCRIPT_CTL)) + , m_xLabelFT(m_xBuilder->weld_label("label1")) + , m_xStandardBox(m_xBuilder->weld_combo_box("standardbox")) + , m_xStandardBoxImg(m_xBuilder->weld_widget("lockstandardbox")) + , m_xStandardHeightLB(new FontSizeBox(m_xBuilder->weld_combo_box("standardheight"))) + , m_xStandardHeightImg(m_xBuilder->weld_widget("lockstandardheight")) + , m_xTitleBox(m_xBuilder->weld_combo_box("titlebox")) + , m_xTitleBoxImg(m_xBuilder->weld_widget("locktitlebox")) + , m_xTitleHeightLB(new FontSizeBox(m_xBuilder->weld_combo_box("titleheight"))) + , m_xTitleHeightImg(m_xBuilder->weld_widget("locktitleheight")) + , m_xListBox(m_xBuilder->weld_combo_box("listbox")) + , m_xListBoxImg(m_xBuilder->weld_widget("locklistbox")) + , m_xListHeightLB(new FontSizeBox(m_xBuilder->weld_combo_box("listheight"))) + , m_xListHeightImg(m_xBuilder->weld_widget("locklistheight")) + , m_xLabelBox(m_xBuilder->weld_combo_box("labelbox")) + , m_xLabelBoxImg(m_xBuilder->weld_widget("locklabelbox")) + , m_xLabelHeightLB(new FontSizeBox(m_xBuilder->weld_combo_box("labelheight"))) + , m_xLabelHeightImg(m_xBuilder->weld_widget("locklabelheight")) + , m_xIdxBox(m_xBuilder->weld_combo_box("idxbox")) + , m_xIdxBoxImg(m_xBuilder->weld_widget("lockidxbox")) + , m_xIndexHeightLB(new FontSizeBox(m_xBuilder->weld_combo_box("indexheight"))) + , m_xIndexHeightImg(m_xBuilder->weld_widget("lockindexheight")) + , m_xStandardPB(m_xBuilder->weld_button("standard")) +{ + m_xStandardBox->make_sorted(); + m_xTitleBox->make_sorted(); + m_xListBox->make_sorted(); + m_xLabelBox->make_sorted(); + m_xIdxBox->make_sorted(); + + m_xStandardPB->connect_clicked(LINK(this, SwStdFontTabPage, StandardHdl)); + m_xStandardBox->connect_changed( LINK(this, SwStdFontTabPage, ModifyHdl)); + m_xListBox->connect_changed( LINK(this, SwStdFontTabPage, ModifyHdl)); + m_xLabelBox->connect_changed( LINK(this, SwStdFontTabPage, ModifyHdl)); + m_xIdxBox->connect_changed( LINK(this, SwStdFontTabPage, ModifyHdl)); + Link<weld::Widget&,void> aFocusLink = LINK( this, SwStdFontTabPage, LoseFocusHdl); + m_xStandardBox->connect_focus_out( aFocusLink ); + m_xTitleBox->connect_focus_out( aFocusLink ); + m_xListBox->connect_focus_out( aFocusLink ); + m_xLabelBox->connect_focus_out( aFocusLink ); + m_xIdxBox->connect_focus_out( aFocusLink ); +} + +SwStdFontTabPage::~SwStdFontTabPage() +{ + m_xIndexHeightLB.reset(); + m_xLabelHeightLB.reset(); + m_xListHeightLB.reset(); + m_xTitleHeightLB.reset(); + m_xStandardHeightLB.reset(); + m_pFontList.reset(); + if (m_bDisposePrinter) + m_pPrt.disposeAndClear(); + else + m_pPrt.clear(); +} + +std::unique_ptr<SfxTabPage> SwStdFontTabPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SwStdFontTabPage>(pPage, pController, *rAttrSet); +} + +static void lcl_SetColl(SwWrtShell* pWrtShell, sal_uInt16 nType, + SfxPrinter const * pPrt, const OUString& rStyle, + sal_uInt16 nFontWhich) +{ + vcl::Font aFont( rStyle, Size( 0, 10 ) ); + if( pPrt ) + aFont = pPrt->GetFontMetric( aFont ); + SwTextFormatColl *pColl = pWrtShell->GetTextCollFromPool(nType); + pColl->SetFormatAttr(SvxFontItem(aFont.GetFamilyType(), aFont.GetFamilyName(), + OUString(), aFont.GetPitch(), aFont.GetCharSet(), nFontWhich)); +} + +static void lcl_SetColl(SwWrtShell* pWrtShell, sal_uInt16 nType, + sal_Int32 nHeight, sal_uInt16 nFontHeightWhich) +{ + float fSize = static_cast<float>(nHeight) / 10; + nHeight = CalcToUnit( fSize, MapUnit::MapTwip ); + SwTextFormatColl *pColl = pWrtShell->GetTextCollFromPool(nType); + pColl->SetFormatAttr(SvxFontHeightItem(nHeight, 100, nFontHeightWhich)); +} + +OUString SwStdFontTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "font_label", "size_label", "default_label", + "heading_label", "list_label", "caption_label", "index_label" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + sAllStrings += m_xStandardPB->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool SwStdFontTabPage::FillItemSet( SfxItemSet* ) +{ + SW_MOD()->GetModuleConfig()->SetDefaultFontInCurrDocOnly(false); + + const OUString sStandard = m_xStandardBox->get_active_text(); + const OUString sTitle = m_xTitleBox->get_active_text(); + const OUString sList = m_xListBox->get_active_text(); + const OUString sLabel = m_xLabelBox->get_active_text(); + const OUString sIdx = m_xIdxBox->get_active_text(); + + bool bStandardHeightChanged = m_xStandardHeightLB->get_value_changed_from_saved(); + bool bTitleHeightChanged = m_xTitleHeightLB->get_value_changed_from_saved(); + bool bListHeightChanged = m_xListHeightLB->get_value_changed_from_saved(); + bool bLabelHeightChanged = m_xLabelHeightLB->get_value_changed_from_saved(); + bool bIndexHeightChanged = m_xIndexHeightLB->get_value_changed_from_saved(); + + m_pFontConfig->SetFontStandard(sStandard, m_nFontGroup); + m_pFontConfig->SetFontOutline(sTitle, m_nFontGroup); + m_pFontConfig->SetFontList(sList, m_nFontGroup); + m_pFontConfig->SetFontCaption(sLabel, m_nFontGroup); + m_pFontConfig->SetFontIndex(sIdx, m_nFontGroup); + if(bStandardHeightChanged) + { + float fSize = static_cast<float>(m_xStandardHeightLB->get_value()) / 10; + m_pFontConfig->SetFontHeight( CalcToUnit( fSize, MapUnit::MapTwip ), FONT_STANDARD, m_nFontGroup ); + } + if(bTitleHeightChanged) + { + float fSize = static_cast<float>(m_xTitleHeightLB->get_value()) / 10; + m_pFontConfig->SetFontHeight( CalcToUnit( fSize, MapUnit::MapTwip ), FONT_OUTLINE, m_nFontGroup ); + } + if(bListHeightChanged) + { + float fSize = static_cast<float>(m_xListHeightLB->get_value()) / 10; + m_pFontConfig->SetFontHeight( CalcToUnit( fSize, MapUnit::MapTwip ), FONT_LIST, m_nFontGroup ); + } + if(bLabelHeightChanged) + { + float fSize = static_cast<float>(m_xLabelHeightLB->get_value()) / 10; + m_pFontConfig->SetFontHeight( CalcToUnit( fSize, MapUnit::MapTwip ), FONT_CAPTION, m_nFontGroup ); + } + if(bIndexHeightChanged) + { + float fSize = static_cast<float>(m_xIndexHeightLB->get_value()) / 10; + m_pFontConfig->SetFontHeight( CalcToUnit( fSize, MapUnit::MapTwip ), FONT_INDEX, m_nFontGroup ); + } + + if(m_pWrtShell) + { + m_pWrtShell->StartAllAction(); + SfxPrinter* pPrinter = m_pWrtShell->getIDocumentDeviceAccess().getPrinter( false ); + bool bMod = false; + const sal_uInt16 nFontWhich = + m_nFontGroup == FONT_GROUP_DEFAULT ? RES_CHRATR_FONT : + FONT_GROUP_CJK == m_nFontGroup ? RES_CHRATR_CJK_FONT : RES_CHRATR_CTL_FONT; + const sal_uInt16 nFontHeightWhich = + m_nFontGroup == FONT_GROUP_DEFAULT ? RES_CHRATR_FONTSIZE : + FONT_GROUP_CJK == m_nFontGroup ? RES_CHRATR_CJK_FONTSIZE : RES_CHRATR_CTL_FONTSIZE; + if(sStandard != m_sShellStd) + { + vcl::Font aFont( sStandard, Size( 0, 10 ) ); + if( pPrinter ) + aFont = pPrinter->GetFontMetric( aFont ); + m_pWrtShell->SetDefault(SvxFontItem(aFont.GetFamilyType(), aFont.GetFamilyName(), + OUString(), aFont.GetPitch(), aFont.GetCharSet(), nFontWhich)); + SwTextFormatColl *pColl = m_pWrtShell->GetTextCollFromPool(RES_POOLCOLL_STANDARD); + pColl->ResetFormatAttr(nFontWhich); + bMod = true; + } + if(bStandardHeightChanged) + { + float fSize = static_cast<float>(m_xStandardHeightLB->get_value()) / 10; + m_pWrtShell->SetDefault(SvxFontHeightItem( CalcToUnit( fSize, MapUnit::MapTwip ), 100, nFontHeightWhich ) ); + SwTextFormatColl *pColl = m_pWrtShell->GetTextCollFromPool(RES_POOLCOLL_STANDARD); + pColl->ResetFormatAttr(nFontHeightWhich); + bMod = true; + } + + if(sTitle != m_sShellTitle ) + { + lcl_SetColl(m_pWrtShell, RES_POOLCOLL_HEADLINE_BASE, pPrinter, sTitle, nFontWhich); + bMod = true; + } + if(bTitleHeightChanged) + { + lcl_SetColl(m_pWrtShell, RES_POOLCOLL_HEADLINE_BASE, + sal::static_int_cast< sal_uInt16, sal_Int64 >(m_xTitleHeightLB->get_value()), nFontHeightWhich); + bMod = true; + } + if(sList != m_sShellList && (!m_bListDefault || !m_bSetListDefault )) + { + lcl_SetColl(m_pWrtShell, RES_POOLCOLL_NUMBER_BULLET_BASE, pPrinter, sList, nFontWhich); + bMod = true; + } + if(bListHeightChanged) + { + lcl_SetColl(m_pWrtShell, RES_POOLCOLL_NUMBER_BULLET_BASE, + sal::static_int_cast< sal_uInt16, sal_Int64 >(m_xListHeightLB->get_value()), nFontHeightWhich); + bMod = true; + } + if(sLabel != m_sShellLabel && (!m_bLabelDefault || !m_bSetLabelDefault)) + { + lcl_SetColl(m_pWrtShell, RES_POOLCOLL_LABEL, pPrinter, sLabel, nFontWhich); + bMod = true; + } + if(bLabelHeightChanged) + { + lcl_SetColl(m_pWrtShell, RES_POOLCOLL_LABEL, + sal::static_int_cast< sal_uInt16, sal_Int64 >(m_xLabelHeightLB->get_value()), nFontHeightWhich); + bMod = true; + } + if(sIdx != m_sShellIndex && (!m_bIdxDefault || !m_bSetIdxDefault)) + { + lcl_SetColl(m_pWrtShell, RES_POOLCOLL_REGISTER_BASE, pPrinter, sIdx, nFontWhich); + bMod = true; + } + if(bIndexHeightChanged) + { + lcl_SetColl(m_pWrtShell, RES_POOLCOLL_REGISTER_BASE, + sal::static_int_cast< sal_uInt16, sal_Int64 >(m_xIndexHeightLB->get_value()), nFontHeightWhich); + bMod = true; + } + if ( bMod ) + m_pWrtShell->SetModified(); + m_pWrtShell->EndAllAction(); + } + return false; +} + +void SwStdFontTabPage::Reset( const SfxItemSet* rSet) +{ + const TypedWhichId<SvxLanguageItem> nLangSlot = m_nFontGroup == FONT_GROUP_DEFAULT ? SID_ATTR_LANGUAGE : + FONT_GROUP_CJK == m_nFontGroup ? SID_ATTR_CHAR_CJK_LANGUAGE : SID_ATTR_CHAR_CTL_LANGUAGE; + + if( const SvxLanguageItem* pLang = rSet->GetItemIfSet(nLangSlot, false) ) + m_eLanguage = pLang->GetValue(); + + OUString sToReplace = m_sScriptWestern; + if(FONT_GROUP_CJK == m_nFontGroup ) + sToReplace = m_sScriptAsian; + else if(FONT_GROUP_CTL == m_nFontGroup ) + sToReplace = m_sScriptComplex; + m_xLabelFT->set_label(m_xLabelFT->get_label().replaceFirst("%1", sToReplace)); + + if (m_bDisposePrinter) + { + m_pPrt.disposeAndClear(); + m_bDisposePrinter = false; + } + + if(const SwPtrItem* pItem = rSet->GetItemIfSet(FN_PARAM_PRINTER, false)) + { + m_pPrt = static_cast<SfxPrinter*>(pItem->GetValue()); + } + else + { + auto pPrinterSet = std::make_unique<SfxItemSetFixed + <SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN, + SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC>>( *rSet->GetPool() ); + m_pPrt = VclPtr<SfxPrinter>::Create(std::move(pPrinterSet)); + m_bDisposePrinter = true; + } + m_pFontList.reset(new FontList( m_pPrt )); + // #i94536# prevent duplication of font entries when 'reset' button is pressed + if( !m_xStandardBox->get_count() ) + { + // get the set of distinct available family names + std::set< OUString > aFontNames; + int nFontNames = m_pPrt->GetFontFaceCollectionCount(); + for( int i = 0; i < nFontNames; i++ ) + { + FontMetric aFontMetric( m_pPrt->GetFontMetricFromCollection( i ) ); + aFontNames.insert( aFontMetric.GetFamilyName() ); + } + + // insert to listboxes + for( const auto& rFontName : aFontNames ) + { + m_xStandardBox->append_text( rFontName ); + m_xTitleBox->append_text( rFontName ); + m_xListBox->append_text( rFontName ); + m_xLabelBox->append_text( rFontName ); + m_xIdxBox->append_text( rFontName ); + } + } + if(const SwPtrItem* pItem = rSet->GetItemIfSet(FN_PARAM_STDFONTS, false)) + { + m_pFontConfig = static_cast<SwStdFontConfig*>(pItem->GetValue()); + } + + if(const SwPtrItem* pItem = rSet->GetItemIfSet(FN_PARAM_WRTSHELL, false)) + { + m_pWrtShell = static_cast<SwWrtShell*>(pItem->GetValue()); + } + OUString sStdBackup; + OUString sOutBackup; + OUString sListBackup; + OUString sCapBackup; + OUString sIdxBackup; + sal_Int32 nStandardHeight = -1; + sal_Int32 nTitleHeight = -1; + sal_Int32 nListHeight = -1; + sal_Int32 nLabelHeight = -1; + sal_Int32 nIndexHeight = -1; + + if(!m_pWrtShell) + { + sStdBackup = m_pFontConfig->GetFontStandard(m_nFontGroup); + sOutBackup = m_pFontConfig->GetFontOutline(m_nFontGroup); + sListBackup= m_pFontConfig->GetFontList(m_nFontGroup); + sCapBackup = m_pFontConfig->GetFontCaption(m_nFontGroup); + sIdxBackup = m_pFontConfig->GetFontIndex(m_nFontGroup); + nStandardHeight = m_pFontConfig->GetFontHeight( FONT_STANDARD, m_nFontGroup, m_eLanguage ); + nTitleHeight = m_pFontConfig->GetFontHeight( FONT_OUTLINE , m_nFontGroup, m_eLanguage ); + nListHeight = m_pFontConfig->GetFontHeight( FONT_LIST , m_nFontGroup, m_eLanguage ); + nLabelHeight = m_pFontConfig->GetFontHeight( FONT_CAPTION , m_nFontGroup, m_eLanguage ); + nIndexHeight = m_pFontConfig->GetFontHeight( FONT_INDEX , m_nFontGroup, m_eLanguage ); + if( nStandardHeight <= 0) + nStandardHeight = SwStdFontConfig::GetDefaultHeightFor( FONT_STANDARD + m_nFontGroup * FONT_PER_GROUP, m_eLanguage); + if( nTitleHeight <= 0) + nTitleHeight = SwStdFontConfig::GetDefaultHeightFor( FONT_OUTLINE + m_nFontGroup * FONT_PER_GROUP, m_eLanguage); + if( nListHeight <= 0) + nListHeight = SwStdFontConfig::GetDefaultHeightFor( FONT_LIST + m_nFontGroup * FONT_PER_GROUP, m_eLanguage); + if( nLabelHeight <= 0) + nLabelHeight = SwStdFontConfig::GetDefaultHeightFor( FONT_CAPTION + m_nFontGroup * FONT_PER_GROUP, m_eLanguage); + if( nIndexHeight <= 0) + nIndexHeight = SwStdFontConfig::GetDefaultHeightFor( FONT_INDEX + m_nFontGroup * FONT_PER_GROUP, m_eLanguage); + } + else + { + SwTextFormatColl *pColl = m_pWrtShell->GetTextCollFromPool(RES_POOLCOLL_STANDARD); + const SvxFontItem& rFont = !m_nFontGroup ? pColl->GetFont() : + FONT_GROUP_CJK == m_nFontGroup ? pColl->GetCJKFont() : pColl->GetCTLFont(); + m_sShellStd = sStdBackup = rFont.GetFamilyName(); + + const TypedWhichId<SvxFontHeightItem> nFontHeightWhich = + m_nFontGroup == FONT_GROUP_DEFAULT ? RES_CHRATR_FONTSIZE : + FONT_GROUP_CJK == m_nFontGroup ? RES_CHRATR_CJK_FONTSIZE : RES_CHRATR_CTL_FONTSIZE; + const SvxFontHeightItem& rFontHeightStandard = pColl->GetFormatAttr(nFontHeightWhich); + nStandardHeight = static_cast<sal_Int32>(rFontHeightStandard.GetHeight()); + + pColl = m_pWrtShell->GetTextCollFromPool(RES_POOLCOLL_HEADLINE_BASE); + const SvxFontItem& rFontHL = !m_nFontGroup ? pColl->GetFont() : + FONT_GROUP_CJK == m_nFontGroup ? pColl->GetCJKFont() : pColl->GetCTLFont(); + m_sShellTitle = sOutBackup = rFontHL.GetFamilyName(); + + const SvxFontHeightItem& rFontHeightTitle = pColl->GetFormatAttr( nFontHeightWhich ); + nTitleHeight = static_cast<sal_Int32>(rFontHeightTitle.GetHeight()); + + const sal_uInt16 nFontWhich = + m_nFontGroup == FONT_GROUP_DEFAULT ? RES_CHRATR_FONT : + FONT_GROUP_CJK == m_nFontGroup ? RES_CHRATR_CJK_FONT : RES_CHRATR_CTL_FONT; + pColl = m_pWrtShell->GetTextCollFromPool(RES_POOLCOLL_NUMBER_BULLET_BASE); + const SvxFontItem& rFontLS = !m_nFontGroup ? pColl->GetFont() : + FONT_GROUP_CJK == m_nFontGroup ? pColl->GetCJKFont() : pColl->GetCTLFont(); + m_bListDefault = SfxItemState::DEFAULT == pColl->GetAttrSet().GetItemState(nFontWhich, false); + m_sShellList = sListBackup = rFontLS.GetFamilyName(); + + const SvxFontHeightItem& rFontHeightList = pColl->GetFormatAttr(nFontHeightWhich); + nListHeight = static_cast<sal_Int32>(rFontHeightList.GetHeight()); + + pColl = m_pWrtShell->GetTextCollFromPool(RES_POOLCOLL_LABEL); + m_bLabelDefault = SfxItemState::DEFAULT == pColl->GetAttrSet().GetItemState(nFontWhich, false); + const SvxFontItem& rFontCP = !m_nFontGroup ? pColl->GetFont() : + FONT_GROUP_CJK == m_nFontGroup ? pColl->GetCJKFont() : pColl->GetCTLFont(); + m_sShellLabel = sCapBackup = rFontCP.GetFamilyName(); + const SvxFontHeightItem& rFontHeightLabel = pColl->GetFormatAttr(nFontHeightWhich); + nLabelHeight = static_cast<sal_Int32>(rFontHeightLabel.GetHeight()); + + pColl = m_pWrtShell->GetTextCollFromPool(RES_POOLCOLL_REGISTER_BASE); + m_bIdxDefault = SfxItemState::DEFAULT == pColl->GetAttrSet().GetItemState(nFontWhich, false); + const SvxFontItem& rFontIDX = !m_nFontGroup ? pColl->GetFont() : + FONT_GROUP_CJK == m_nFontGroup ? pColl->GetCJKFont() : pColl->GetCTLFont(); + m_sShellIndex = sIdxBackup = rFontIDX.GetFamilyName(); + const SvxFontHeightItem& rFontHeightIndex = pColl->GetFormatAttr(nFontHeightWhich); + nIndexHeight = static_cast<sal_Int32>(rFontHeightIndex.GetHeight()); + } + m_xStandardBox->set_entry_text(sStdBackup ); + m_xTitleBox->set_entry_text(sOutBackup ); + m_xListBox->set_entry_text(sListBackup); + m_xLabelBox->set_entry_text(sCapBackup ); + m_xIdxBox->set_entry_text(sIdxBackup ); + + m_xStandardHeightLB->Fill( m_pFontList.get() ); + m_xTitleHeightLB->Fill( m_pFontList.get() ); + m_xListHeightLB->Fill( m_pFontList.get() ); + m_xLabelHeightLB->Fill( m_pFontList.get() ); + m_xIndexHeightLB->Fill( m_pFontList.get() ); + + m_xStandardHeightLB->set_value( CalcToPoint( nStandardHeight, MapUnit::MapTwip, 10 ) ); + m_xTitleHeightLB->set_value( CalcToPoint( nTitleHeight , MapUnit::MapTwip, 10 ) ); + m_xListHeightLB->set_value( CalcToPoint( nListHeight , MapUnit::MapTwip, 10 ) ); + m_xLabelHeightLB->set_value( CalcToPoint( nLabelHeight , MapUnit::MapTwip, 10 )); + m_xIndexHeightLB->set_value( CalcToPoint( nIndexHeight , MapUnit::MapTwip, 10 )); + + + if (m_nFontGroup == FONT_GROUP_DEFAULT) + { + bool bReadonly = officecfg::Office::Writer::DefaultFont::Standard::isReadOnly(); + m_xStandardBox->set_sensitive(!bReadonly); + m_xStandardBoxImg->set_visible(bReadonly); + bReadonly = officecfg::Office::Writer::DefaultFont::StandardHeight::isReadOnly(); + m_xStandardHeightLB->set_sensitive(!bReadonly); + m_xStandardHeightImg->set_visible(bReadonly); + + bReadonly = officecfg::Office::Writer::DefaultFont::Heading::isReadOnly(); + m_xTitleBox->set_sensitive(!bReadonly); + m_xTitleBoxImg->set_visible(bReadonly); + bReadonly = officecfg::Office::Writer::DefaultFont::HeadingHeight::isReadOnly(); + m_xTitleHeightLB->set_sensitive(!bReadonly); + m_xTitleHeightImg->set_visible(bReadonly); + + bReadonly = officecfg::Office::Writer::DefaultFont::List::isReadOnly(); + m_xListBox->set_sensitive(!bReadonly); + m_xListBoxImg->set_visible(bReadonly); + bReadonly = officecfg::Office::Writer::DefaultFont::ListHeight::isReadOnly(); + m_xListHeightLB->set_sensitive(!bReadonly); + m_xListHeightImg->set_visible(bReadonly); + + bReadonly = officecfg::Office::Writer::DefaultFont::Caption::isReadOnly(); + m_xLabelBox->set_sensitive(!bReadonly); + m_xLabelBoxImg->set_visible(bReadonly); + bReadonly = officecfg::Office::Writer::DefaultFont::CaptionHeight::isReadOnly(); + m_xLabelHeightLB->set_sensitive(!bReadonly); + m_xLabelHeightImg->set_visible(bReadonly); + + bReadonly = officecfg::Office::Writer::DefaultFont::Index::isReadOnly(); + m_xIdxBox->set_sensitive(!bReadonly); + m_xIdxBoxImg->set_visible(bReadonly); + bReadonly = officecfg::Office::Writer::DefaultFont::IndexHeight::isReadOnly(); + m_xIndexHeightLB->set_sensitive(!bReadonly); + m_xIndexHeightImg->set_visible(bReadonly); + } + + m_xStandardBox->save_value(); + m_xTitleBox->save_value(); + m_xListBox->save_value(); + m_xLabelBox->save_value(); + m_xIdxBox->save_value(); + + m_xStandardHeightLB->save_value(); + m_xTitleHeightLB->save_value(); + m_xListHeightLB->save_value(); + m_xLabelHeightLB->save_value(); + m_xIndexHeightLB->save_value(); +} + +IMPL_LINK_NOARG(SwStdFontTabPage, StandardHdl, weld::Button&, void) +{ + sal_uInt8 nFontOffset = m_nFontGroup * FONT_PER_GROUP; + m_xStandardBox->set_entry_text(SwStdFontConfig::GetDefaultFor(FONT_STANDARD + nFontOffset, m_eLanguage)); + m_xTitleBox->set_entry_text(SwStdFontConfig::GetDefaultFor(FONT_OUTLINE + nFontOffset, m_eLanguage)); + m_xListBox->set_entry_text(SwStdFontConfig::GetDefaultFor(FONT_LIST + nFontOffset, m_eLanguage)); + m_xLabelBox->set_entry_text(SwStdFontConfig::GetDefaultFor(FONT_CAPTION + nFontOffset, m_eLanguage)); + m_xIdxBox->set_entry_text(SwStdFontConfig::GetDefaultFor(FONT_INDEX + nFontOffset, m_eLanguage)); + + m_xStandardBox->save_value(); + m_xTitleBox->save_value(); + m_xListBox->save_value(); + m_xLabelBox->save_value(); + m_xIdxBox->save_value(); + + m_xStandardHeightLB->set_value( CalcToPoint( + SwStdFontConfig::GetDefaultHeightFor(FONT_STANDARD + nFontOffset, m_eLanguage), + MapUnit::MapTwip, 10 )); + m_xTitleHeightLB->set_value(CalcToPoint( + SwStdFontConfig::GetDefaultHeightFor(FONT_OUTLINE + + nFontOffset, m_eLanguage), MapUnit::MapTwip, 10 )); + m_xListHeightLB->set_value(CalcToPoint( + SwStdFontConfig::GetDefaultHeightFor(FONT_LIST + nFontOffset, m_eLanguage), + MapUnit::MapTwip, 10 )); + m_xLabelHeightLB->set_value(CalcToPoint( + SwStdFontConfig::GetDefaultHeightFor(FONT_CAPTION + nFontOffset, m_eLanguage), + MapUnit::MapTwip, 10 )); + m_xIndexHeightLB->set_value(CalcToPoint( + SwStdFontConfig::GetDefaultHeightFor(FONT_INDEX + nFontOffset, m_eLanguage), + MapUnit::MapTwip, 10 )); +} + +IMPL_LINK( SwStdFontTabPage, ModifyHdl, weld::ComboBox&, rBox, void ) +{ + if (&rBox == m_xStandardBox.get()) + { + const OUString sEntry = rBox.get_active_text(); + if(m_bSetListDefault && m_bListDefault) + m_xListBox->set_entry_text(sEntry); + if(m_bSetLabelDefault && m_bLabelDefault) + m_xLabelBox->set_entry_text(sEntry); + if(m_bSetIdxDefault && m_bIdxDefault) + m_xIdxBox->set_entry_text(sEntry); + } + else if (&rBox == m_xListBox.get()) + { + m_bSetListDefault = false; + } + else if (&rBox == m_xLabelBox.get()) + { + m_bSetLabelDefault = false; + } + else if (&rBox == m_xIdxBox.get()) + { + m_bSetIdxDefault = false; + } +} + +IMPL_LINK( SwStdFontTabPage, LoseFocusHdl, weld::Widget&, rControl, void ) +{ + weld::ComboBox& rBox = dynamic_cast<weld::ComboBox&>(rControl); + FontSizeBox* pHeightLB = nullptr; + + if (&rBox == m_xStandardBox.get()) + { + pHeightLB = m_xStandardHeightLB.get(); + } + else if (&rBox == m_xTitleBox.get()) + { + pHeightLB = m_xTitleHeightLB.get(); + } + else if (&rBox == m_xListBox.get()) + { + pHeightLB = m_xListHeightLB.get(); + } + else if (&rBox == m_xLabelBox.get()) + { + pHeightLB = m_xLabelHeightLB.get(); + } + else /*if (&rBox == m_xIndexHeightLB.get())*/ + { + pHeightLB = m_xIndexHeightLB.get(); + } + + pHeightLB->Fill( m_pFontList.get() ); +} + +void SwStdFontTabPage::PageCreated( const SfxAllItemSet& aSet) +{ + const SfxUInt16Item* pFlagItem = aSet.GetItem<SfxUInt16Item>(SID_FONTMODE_TYPE, false); + if (pFlagItem) + m_nFontGroup = sal::static_int_cast< sal_uInt8, sal_uInt16>( pFlagItem->GetValue() ); +} + +SwTableOptionsTabPage::SwTableOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/opttablepage.ui", "OptTablePage", &rSet) + , m_pWrtShell(nullptr) + , m_bHTMLMode(false) + , m_xHeaderCB(m_xBuilder->weld_check_button("header")) + , m_xHeaderImg(m_xBuilder->weld_widget("lockheader")) + , m_xRepeatHeaderCB(m_xBuilder->weld_check_button("repeatheader")) + , m_xRepeatHeaderImg(m_xBuilder->weld_widget("lockrepeatheader")) + , m_xDontSplitCB(m_xBuilder->weld_check_button("dontsplit")) + , m_xDontSplitImg(m_xBuilder->weld_widget("lockdontsplit")) + , m_xBorderCB(m_xBuilder->weld_check_button("border")) + , m_xBorderImg(m_xBuilder->weld_widget("lockborder")) + , m_xNumFormattingCB(m_xBuilder->weld_check_button("numformatting")) + , m_xNumFormattingImg(m_xBuilder->weld_widget("locknumformatting")) + , m_xNumFormatFormattingCB(m_xBuilder->weld_check_button("numfmtformatting")) + , m_xNumFormatFormattingImg(m_xBuilder->weld_widget("locknumfmtformatting")) + , m_xNumAlignmentCB(m_xBuilder->weld_check_button("numalignment")) + , m_xNumAlignmentImg(m_xBuilder->weld_widget("locknumalignment")) + , m_xRowMoveMF(m_xBuilder->weld_metric_spin_button("rowmove", FieldUnit::CM)) + , m_xRowMoveImg(m_xBuilder->weld_widget("lockrowmove")) + , m_xColMoveMF(m_xBuilder->weld_metric_spin_button("colmove", FieldUnit::CM)) + , m_xColMoveImg(m_xBuilder->weld_widget("lockcolmove")) + , m_xRowInsertMF(m_xBuilder->weld_metric_spin_button("rowinsert", FieldUnit::CM)) + , m_xRowInsertImg(m_xBuilder->weld_widget("lockrowinsert")) + , m_xColInsertMF(m_xBuilder->weld_metric_spin_button("colinsert", FieldUnit::CM)) + , m_xColInsertImg(m_xBuilder->weld_widget("lockcolinsert")) + , m_xFixRB(m_xBuilder->weld_radio_button("fix")) + , m_xFixPropRB(m_xBuilder->weld_radio_button("fixprop")) + , m_xVarRB(m_xBuilder->weld_radio_button("var")) + , m_xBehaviorOfImg(m_xBuilder->weld_widget("lockbehaviorof")) +{ + Link<weld::Toggleable&,void> aLnk(LINK(this, SwTableOptionsTabPage, CheckBoxHdl)); + m_xNumFormattingCB->connect_toggled(aLnk); + m_xNumFormatFormattingCB->connect_toggled(aLnk); + m_xHeaderCB->connect_toggled(aLnk); +} + +SwTableOptionsTabPage::~SwTableOptionsTabPage() +{ +} + +std::unique_ptr<SfxTabPage> SwTableOptionsTabPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SwTableOptionsTabPage>(pPage, pController, *rAttrSet); +} + +OUString SwTableOptionsTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] + = { "label1", "label3", "label4", "label5", "label6", "label10", "label2", + "label14", "label15", "label16", "label11", "label12", "label13" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "header", "repeatheader", "dontsplit", "border", + "numformatting", "numfmtformatting", "numalignment" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + OUString radioButton[] = { "fix", "fixprop", "var" }; + + for (const auto& radio : radioButton) + { + if (const auto& pString = m_xBuilder->weld_radio_button(radio)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SwTableOptionsTabPage::FillItemSet( SfxItemSet* ) +{ + bool bRet = false; + SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig(); + + if (m_xRowMoveMF->get_value_changed_from_saved()) + pModOpt->SetTableHMove( o3tl::narrowing<sal_uInt16>(m_xRowMoveMF->denormalize( m_xRowMoveMF->get_value(FieldUnit::TWIP)))); + + if (m_xColMoveMF->get_value_changed_from_saved()) + pModOpt->SetTableVMove( o3tl::narrowing<sal_uInt16>(m_xColMoveMF->denormalize( m_xColMoveMF->get_value(FieldUnit::TWIP)))); + + if (m_xRowInsertMF->get_value_changed_from_saved()) + pModOpt->SetTableHInsert(o3tl::narrowing<sal_uInt16>(m_xRowInsertMF->denormalize( m_xRowInsertMF->get_value(FieldUnit::TWIP)))); + + if (m_xColInsertMF->get_value_changed_from_saved()) + pModOpt->SetTableVInsert(o3tl::narrowing<sal_uInt16>(m_xColInsertMF->denormalize( m_xColInsertMF->get_value(FieldUnit::TWIP)))); + + TableChgMode eMode; + if (m_xFixRB->get_active()) + eMode = TableChgMode::FixedWidthChangeAbs; + else if(m_xFixPropRB->get_active()) + eMode = TableChgMode::FixedWidthChangeProp; + else + eMode = TableChgMode::VarWidthChangeAbs; + if(eMode != pModOpt->GetTableMode()) + { + pModOpt->SetTableMode(eMode); + // the table-keyboard-mode has changed, now the current + // table should know about that too. + if(m_pWrtShell && SelectionType::Table & m_pWrtShell->GetSelectionType()) + { + m_pWrtShell->SetTableChgMode(eMode); + static sal_uInt16 aInva[] = + { FN_TABLE_MODE_FIX, + FN_TABLE_MODE_FIX_PROP, + FN_TABLE_MODE_VARIABLE, + 0 + }; + m_pWrtShell->GetView().GetViewFrame().GetBindings().Invalidate( aInva ); + } + + bRet = true; + } + + SwInsertTableOptions aInsOpts( SwInsertTableFlags::NONE, 0 ); + + if (m_xHeaderCB->get_active()) + aInsOpts.mnInsMode |= SwInsertTableFlags::Headline; + + if (m_xRepeatHeaderCB->get_sensitive()) + aInsOpts.mnRowsToRepeat = m_xRepeatHeaderCB->get_active() ? 1 : 0; + + if (!m_xDontSplitCB->get_active()) + aInsOpts.mnInsMode |= SwInsertTableFlags::SplitLayout; + + if (m_xBorderCB->get_active()) + aInsOpts.mnInsMode |= SwInsertTableFlags::DefaultBorder; + + if (m_xHeaderCB->get_state_changed_from_saved() || + m_xRepeatHeaderCB->get_state_changed_from_saved() || + m_xDontSplitCB->get_state_changed_from_saved() || + m_xBorderCB->get_state_changed_from_saved()) + { + pModOpt->SetInsTableFlags(m_bHTMLMode, aInsOpts); + } + + if (m_xNumFormattingCB->get_state_changed_from_saved()) + { + pModOpt->SetInsTableFormatNum(m_bHTMLMode, m_xNumFormattingCB->get_active()); + bRet = true; + } + + if (m_xNumFormatFormattingCB->get_state_changed_from_saved()) + { + pModOpt->SetInsTableChangeNumFormat(m_bHTMLMode, m_xNumFormatFormattingCB->get_active()); + bRet = true; + } + + if (m_xNumAlignmentCB->get_state_changed_from_saved()) + { + pModOpt->SetInsTableAlignNum(m_bHTMLMode, m_xNumAlignmentCB->get_active()); + bRet = true; + } + + return bRet; +} + +void SwTableOptionsTabPage::Reset( const SfxItemSet* rSet) +{ + if (const SfxUInt16Item* pItem = rSet->GetItemIfSet(SID_HTML_MODE, false)) + { + m_bHTMLMode = 0 != (pItem->GetValue() & HTMLMODE_ON); + } + + const SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig(); + if ( rSet->GetItemState( SID_ATTR_METRIC ) >= SfxItemState::DEFAULT ) + { + const SfxUInt16Item& rItem = rSet->Get( SID_ATTR_METRIC ); + FieldUnit eFieldUnit = static_cast<FieldUnit>(rItem.GetValue()); + ::SetFieldUnit( *m_xRowMoveMF, eFieldUnit ); + ::SetFieldUnit( *m_xColMoveMF, eFieldUnit ); + ::SetFieldUnit( *m_xRowInsertMF, eFieldUnit ); + ::SetFieldUnit( *m_xColInsertMF, eFieldUnit ); + } + + bool bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Table::Shift::Row::isReadOnly() : + officecfg::Office::WriterWeb::Table::Shift::Row::isReadOnly(); + m_xRowMoveMF->set_value(m_xRowMoveMF->normalize(pModOpt->GetTableHMove()), FieldUnit::TWIP); + m_xRowMoveMF->set_sensitive(!bReadOnly); + m_xRowMoveImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Table::Shift::Column::isReadOnly() : + officecfg::Office::WriterWeb::Table::Shift::Column::isReadOnly(); + m_xColMoveMF->set_value(m_xColMoveMF->normalize(pModOpt->GetTableVMove()), FieldUnit::TWIP); + m_xColMoveMF->set_sensitive(!bReadOnly); + m_xColMoveImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Table::Insert::Row::isReadOnly() : + officecfg::Office::WriterWeb::Table::Insert::Row::isReadOnly(); + m_xRowInsertMF->set_value(m_xRowInsertMF->normalize(pModOpt->GetTableHInsert()), FieldUnit::TWIP); + m_xRowInsertMF->set_sensitive(!bReadOnly); + m_xRowInsertImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Table::Insert::Column::isReadOnly() : + officecfg::Office::WriterWeb::Table::Insert::Column::isReadOnly(); + m_xColInsertMF->set_value(m_xColInsertMF->normalize(pModOpt->GetTableVInsert()), FieldUnit::TWIP); + m_xColInsertMF->set_sensitive(!bReadOnly); + m_xColInsertImg->set_visible(bReadOnly); + + switch(pModOpt->GetTableMode()) + { + case TableChgMode::FixedWidthChangeAbs: m_xFixRB->set_active(true); break; + case TableChgMode::FixedWidthChangeProp: m_xFixPropRB->set_active(true); break; + case TableChgMode::VarWidthChangeAbs: m_xVarRB->set_active(true); break; + } + + // hide certain controls for html + if (m_bHTMLMode) + { + m_xRepeatHeaderCB->hide(); + m_xDontSplitCB->hide(); + } + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Table::Change::Effect::isReadOnly() : + officecfg::Office::WriterWeb::Table::Change::Effect::isReadOnly(); + if (bReadOnly) + { + m_xFixRB->set_sensitive(false); + m_xFixPropRB->set_sensitive(false); + m_xVarRB->set_sensitive(false); + m_xBehaviorOfImg->set_visible(true); + } + + SwInsertTableOptions aInsOpts = pModOpt->GetInsTableFlags(m_bHTMLMode); + const SwInsertTableFlags nInsTableFlags = aInsOpts.mnInsMode; + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Insert::Table::Header::isReadOnly() : + officecfg::Office::WriterWeb::Insert::Table::Header::isReadOnly(); + m_xHeaderCB->set_active(bool(nInsTableFlags & SwInsertTableFlags::Headline)); + m_xHeaderCB->set_sensitive(!bReadOnly); + m_xHeaderImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Insert::Table::RepeatHeader::isReadOnly(); + m_xRepeatHeaderCB->set_active((!m_bHTMLMode) && (aInsOpts.mnRowsToRepeat > 0)); + m_xRepeatHeaderCB->set_sensitive(!bReadOnly); + m_xRepeatHeaderImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Insert::Table::Split::isReadOnly(); + m_xDontSplitCB->set_active(!(nInsTableFlags & SwInsertTableFlags::SplitLayout)); + m_xDontSplitCB->set_sensitive(!bReadOnly); + m_xDontSplitImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Insert::Table::Border::isReadOnly() : + officecfg::Office::WriterWeb::Insert::Table::Border::isReadOnly(); + m_xBorderCB->set_active(bool(nInsTableFlags & SwInsertTableFlags::DefaultBorder)); + m_xBorderCB->set_sensitive(!bReadOnly); + m_xBorderImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Table::Input::NumberRecognition::isReadOnly() : + officecfg::Office::WriterWeb::Table::Input::NumberRecognition::isReadOnly(); + m_xNumFormattingCB->set_active(pModOpt->IsInsTableFormatNum(m_bHTMLMode)); + m_xNumFormattingCB->set_sensitive(!bReadOnly); + m_xNumFormattingImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Table::Input::NumberFormatRecognition::isReadOnly() : + officecfg::Office::WriterWeb::Table::Input::NumberFormatRecognition::isReadOnly(); + m_xNumFormatFormattingCB->set_active(pModOpt->IsInsTableChangeNumFormat(m_bHTMLMode)); + m_xNumFormatFormattingCB->set_sensitive(!bReadOnly); + m_xNumFormatFormattingImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Table::Input::Alignment::isReadOnly() : + officecfg::Office::WriterWeb::Table::Input::Alignment::isReadOnly(); + m_xNumAlignmentCB->set_active(pModOpt->IsInsTableAlignNum(m_bHTMLMode)); + m_xNumAlignmentCB->set_sensitive(!bReadOnly); + m_xNumAlignmentImg->set_visible(bReadOnly); + + m_xHeaderCB->save_state(); + m_xRepeatHeaderCB->save_state(); + m_xDontSplitCB->save_state(); + m_xBorderCB->save_state(); + m_xNumFormattingCB->save_state(); + m_xNumFormatFormattingCB->save_state(); + m_xNumAlignmentCB->save_state(); + m_xRowMoveMF->save_value(); + m_xColMoveMF->save_value(); + m_xRowInsertMF->save_value(); + m_xColInsertMF->save_value(); + + CheckBoxHdl(*m_xHeaderCB); +} + +IMPL_LINK_NOARG(SwTableOptionsTabPage, CheckBoxHdl, weld::Toggleable&, void) +{ + bool bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Table::Input::NumberFormatRecognition::isReadOnly() : + officecfg::Office::WriterWeb::Table::Input::NumberFormatRecognition::isReadOnly(); + m_xNumFormatFormattingCB->set_sensitive(m_xNumFormattingCB->get_active() && !bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Table::Input::Alignment::isReadOnly() : + officecfg::Office::WriterWeb::Table::Input::Alignment::isReadOnly(); + m_xNumAlignmentCB->set_sensitive(m_xNumFormattingCB->get_active() && !bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Insert::Table::RepeatHeader::isReadOnly() : false; + m_xRepeatHeaderCB->set_sensitive(m_xHeaderCB->get_active() && !bReadOnly); +} + +void SwTableOptionsTabPage::PageCreated( const SfxAllItemSet& aSet) +{ + const SwWrtShellItem* pWrtSh = aSet.GetItem<SwWrtShellItem>(SID_WRT_SHELL, false); + if (pWrtSh) + m_pWrtShell = pWrtSh->GetValue(); +} + +SwShdwCursorOptionsTabPage::SwShdwCursorOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/optformataidspage.ui", "OptFormatAidsPage", &rSet) + , m_pWrtShell(nullptr) + , m_bHTMLMode(false) + , m_xParaCB(m_xBuilder->weld_check_button("paragraph")) + , m_xParaImg(m_xBuilder->weld_widget("lockparagraph")) + , m_xSHyphCB(m_xBuilder->weld_check_button("hyphens")) + , m_xSHyphImg(m_xBuilder->weld_widget("lockhyphens")) + , m_xSpacesCB(m_xBuilder->weld_check_button("spaces")) + , m_xSpacesImg(m_xBuilder->weld_widget("lockspaces")) + , m_xHSpacesCB(m_xBuilder->weld_check_button("nonbreak")) + , m_xHSpacesImg(m_xBuilder->weld_widget("locknonbreak")) + , m_xTabCB(m_xBuilder->weld_check_button("tabs")) + , m_xTabImg(m_xBuilder->weld_widget("locktabs")) + , m_xTabLabel(m_xBuilder->weld_label("tabs_label")) + , m_xBreakCB(m_xBuilder->weld_check_button("break")) + , m_xBreakImg(m_xBuilder->weld_widget("lockbreak")) + , m_xCharHiddenCB(m_xBuilder->weld_check_button("hiddentext")) + , m_xCharHiddenImg(m_xBuilder->weld_widget("lockhiddentext")) + , m_xBookmarkCB(m_xBuilder->weld_check_button("bookmarks")) + , m_xBookmarkImg(m_xBuilder->weld_widget("lockbookmarks")) + , m_xBookmarkLabel(m_xBuilder->weld_label("bookmarks_label")) + , m_xDirectCursorFrame(m_xBuilder->weld_frame("directcrsrframe")) + , m_xOnOffCB(m_xBuilder->weld_check_button("cursoronoff")) + , m_xOnOffImg(m_xBuilder->weld_widget("lockcursoronoff")) + , m_xDirectCursorFillMode(m_xBuilder->weld_combo_box("cxDirectCursorFillMode")) + , m_xDirectCursorFillModeImg(m_xBuilder->weld_widget("lockfillmode")) + , m_xCursorProtFrame(m_xBuilder->weld_frame("crsrprotframe")) + , m_xImageFrame(m_xBuilder->weld_frame("frmImage")) + , m_xCursorInProtCB(m_xBuilder->weld_check_button("cursorinprot")) + , m_xCursorInProtImg(m_xBuilder->weld_widget("lockcursorinprot")) + , m_xDefaultAnchorType(m_xBuilder->weld_combo_box("cxDefaultAnchor")) + , m_xDefaultAnchorTypeImg(m_xBuilder->weld_widget("lockAnchor")) + , m_xMathBaselineAlignmentCB(m_xBuilder->weld_check_button("mathbaseline")) + , m_xMathBaselineAlignmentImg(m_xBuilder->weld_widget("lockmathbaseline")) +{ + SwFillMode eMode = SwFillMode::Tab; + bool bIsOn = false; + + if( const SwShadowCursorItem* pItem = rSet.GetItemIfSet( FN_PARAM_SHADOWCURSOR, false )) + { + eMode = pItem->GetMode(); + bIsOn = pItem->IsOn(); + } + m_xOnOffCB->set_active( bIsOn ); + + m_xDirectCursorFillMode->set_active( static_cast<int>(eMode) ); + const SfxUInt16Item* pHtmlModeItem = rSet.GetItemIfSet(SID_HTML_MODE, false); + if(!pHtmlModeItem || !(pHtmlModeItem->GetValue() & HTMLMODE_ON)) + return; + + m_bHTMLMode = true; + + m_xTabCB->hide(); + m_xTabLabel->hide(); + m_xCharHiddenCB->hide(); + m_xBookmarkCB->hide(); + m_xBookmarkLabel->hide(); + + m_xDirectCursorFrame->hide(); + m_xOnOffCB->hide(); + m_xDirectCursorFillMode->hide(); + m_xCursorProtFrame->hide(); + m_xCursorInProtCB->hide(); + m_xImageFrame->hide(); +} + +SwShdwCursorOptionsTabPage::~SwShdwCursorOptionsTabPage() +{ +} + +std::unique_ptr<SfxTabPage> SwShdwCursorOptionsTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet ) +{ + return std::make_unique<SwShdwCursorOptionsTabPage>(pPage, pController, *rSet); +} + +void SwShdwCursorOptionsTabPage::PageCreated( const SfxAllItemSet& aSet ) +{ + const SwWrtShellItem* pWrtSh = aSet.GetItem<SwWrtShellItem>(SID_WRT_SHELL, false); + if (pWrtSh) + m_pWrtShell = pWrtSh->GetValue(); +} + +OUString SwShdwCursorOptionsTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "layoutopt", "displayfl", "cursoropt", "cursorlabel", + "fillmode", "lbImage", "lbDefaultAnchor" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] + = { "mathbaseline", "paragraph", "hyphens", "spaces", "nonbreak", "tabs", + "break", "hiddentext", "bookmarks", "cursorinprot", "cursoronoff" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SwShdwCursorOptionsTabPage::FillItemSet( SfxItemSet* rSet ) +{ + SwShadowCursorItem aOpt; + aOpt.SetOn( m_xOnOffCB->get_active() ); + + SwFillMode eMode = static_cast<SwFillMode>(m_xDirectCursorFillMode->get_active()); + aOpt.SetMode( eMode ); + + bool bRet = false; + const SwShadowCursorItem* pShadowCursorItem = rSet->GetItemIfSet( FN_PARAM_SHADOWCURSOR, false ); + if( !pShadowCursorItem || *pShadowCursorItem != aOpt ) + { + rSet->Put( aOpt ); + bRet = true; + } + + if (m_pWrtShell) { + m_pWrtShell->GetDoc()->getIDocumentSettingAccess().set( DocumentSettingId::MATH_BASELINE_ALIGNMENT, + m_xMathBaselineAlignmentCB->get_active() ); + bRet |= m_xMathBaselineAlignmentCB->get_state_changed_from_saved(); + } + + if( m_xCursorInProtCB->get_state_changed_from_saved()) + { + rSet->Put(SfxBoolItem(FN_PARAM_CRSR_IN_PROTECTED, m_xCursorInProtCB->get_active())); + bRet = true; + } + + const SwDocDisplayItem* pOldAttr = GetOldItem(GetItemSet(), FN_PARAM_DOCDISP); + + SwDocDisplayItem aDisp; + + aDisp.m_bParagraphEnd = m_xParaCB->get_active(); + aDisp.m_bTab = m_xTabCB->get_active(); + aDisp.m_bSpace = m_xSpacesCB->get_active(); + aDisp.m_bNonbreakingSpace = m_xHSpacesCB->get_active(); + aDisp.m_bSoftHyphen = m_xSHyphCB->get_active(); + aDisp.m_bCharHiddenText = m_xCharHiddenCB->get_active(); + aDisp.m_bBookmarks = m_xBookmarkCB->get_active(); + aDisp.m_bManualBreak = m_xBreakCB->get_active(); + aDisp.m_xDefaultAnchor = m_xDefaultAnchorType->get_active(); + + bRet |= (!pOldAttr || aDisp != *pOldAttr); + if(bRet) + bRet = nullptr != rSet->Put(aDisp); + + return bRet; +} + +void SwShdwCursorOptionsTabPage::Reset( const SfxItemSet* rSet ) +{ + SwFillMode eMode = SwFillMode::Tab; + bool bIsOn = false; + + if( const SwShadowCursorItem* pItem = rSet->GetItemIfSet( FN_PARAM_SHADOWCURSOR, false )) + { + eMode = pItem->GetMode(); + bIsOn = pItem->IsOn(); + } + + bool bReadOnly = officecfg::Office::Writer::Cursor::DirectCursor::UseDirectCursor::isReadOnly(); + m_xOnOffCB->set_active( bIsOn ); + m_xOnOffCB->set_sensitive(!bReadOnly); + m_xOnOffImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Cursor::DirectCursor::Insert::isReadOnly(); + m_xDirectCursorFillMode->set_active( static_cast<int>(eMode) ); + m_xDirectCursorFillMode->set_sensitive(!bReadOnly); + m_xDirectCursorFillModeImg->set_visible(bReadOnly); + + if (m_pWrtShell) { + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Layout::Other::IsAlignMathObjectsToBaseline::isReadOnly() : + officecfg::Office::WriterWeb::Layout::Other::IsAlignMathObjectsToBaseline::isReadOnly(); + m_xMathBaselineAlignmentCB->set_active( m_pWrtShell->GetDoc()->getIDocumentSettingAccess().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT ) ); + m_xMathBaselineAlignmentCB->set_sensitive(!bReadOnly); + m_xMathBaselineAlignmentImg->set_visible(bReadOnly); + m_xMathBaselineAlignmentCB->save_state(); + } else { + m_xMathBaselineAlignmentCB->hide(); + } + + if( const SfxBoolItem* pItem = rSet->GetItemIfSet( FN_PARAM_CRSR_IN_PROTECTED, false ) ) + m_xCursorInProtCB->set_active(pItem->GetValue()); + bReadOnly = officecfg::Office::Writer::Cursor::Option::ProtectedArea::isReadOnly(); + m_xCursorInProtCB->set_sensitive(!bReadOnly); + m_xCursorInProtImg->set_visible(bReadOnly); + m_xCursorInProtCB->save_state(); + + const SwDocDisplayItem* pDocDisplayAttr = rSet->GetItemIfSet( FN_PARAM_DOCDISP, false ); + if(pDocDisplayAttr) + { + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Content::NonprintingCharacter::ParagraphEnd::isReadOnly() : + officecfg::Office::WriterWeb::Content::NonprintingCharacter::ParagraphEnd::isReadOnly(); + m_xParaCB->set_active( pDocDisplayAttr->m_bParagraphEnd ); + m_xParaCB->set_sensitive(!bReadOnly); + m_xParaImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Content::NonprintingCharacter::Tab::isReadOnly(); + m_xTabCB->set_active( pDocDisplayAttr->m_bTab ); + m_xTabCB->set_sensitive(!bReadOnly); + m_xTabImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Content::NonprintingCharacter::Space::isReadOnly() : + officecfg::Office::WriterWeb::Content::NonprintingCharacter::Space::isReadOnly(); + m_xSpacesCB->set_active( pDocDisplayAttr->m_bSpace ); + m_xSpacesCB->set_sensitive(!bReadOnly); + m_xSpacesImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Content::NonprintingCharacter::ProtectedSpace::isReadOnly() : + officecfg::Office::WriterWeb::Content::NonprintingCharacter::ProtectedSpace::isReadOnly(); + m_xHSpacesCB->set_active( pDocDisplayAttr->m_bNonbreakingSpace ); + m_xHSpacesCB->set_sensitive(!bReadOnly); + m_xHSpacesImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Content::NonprintingCharacter::OptionalHyphen::isReadOnly() : + officecfg::Office::WriterWeb::Content::NonprintingCharacter::OptionalHyphen::isReadOnly(); + m_xSHyphCB->set_active( pDocDisplayAttr->m_bSoftHyphen ); + m_xSHyphCB->set_sensitive(!bReadOnly); + m_xSHyphImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Content::NonprintingCharacter::HiddenCharacter::isReadOnly(); + m_xCharHiddenCB->set_active( pDocDisplayAttr->m_bCharHiddenText ); + m_xCharHiddenCB->set_sensitive(!bReadOnly); + m_xCharHiddenImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Content::NonprintingCharacter::Bookmarks::isReadOnly(); + m_xBookmarkCB->set_active(pDocDisplayAttr->m_bBookmarks); + m_xBookmarkCB->set_sensitive(!bReadOnly); + m_xBookmarkImg->set_visible(bReadOnly); + + bReadOnly = !m_bHTMLMode ? officecfg::Office::Writer::Content::NonprintingCharacter::Break::isReadOnly() : + officecfg::Office::WriterWeb::Content::NonprintingCharacter::Break::isReadOnly(); + m_xBreakCB->set_active( pDocDisplayAttr->m_bManualBreak ); + m_xBreakCB->set_sensitive(!bReadOnly); + m_xBreakImg->set_visible(bReadOnly); + + bReadOnly = officecfg::Office::Writer::Content::Display::DefaultAnchor::isReadOnly(); + m_xDefaultAnchorType->set_active( pDocDisplayAttr->m_xDefaultAnchor ); + m_xDefaultAnchorType->set_sensitive(!bReadOnly); + m_xDefaultAnchorTypeImg->set_visible(bReadOnly); + } +} + +namespace { + +// TabPage for Redlining +struct CharAttr +{ + sal_uInt16 nItemId; + sal_uInt16 nAttr; +}; + +} + +// Edit corresponds to Paste-attributes +CharAttr const aRedlineAttr[] = +{ + { SID_ATTR_CHAR_CASEMAP, sal_uInt16(SvxCaseMap::NotMapped) }, + { SID_ATTR_CHAR_WEIGHT, WEIGHT_BOLD }, + { SID_ATTR_CHAR_POSTURE, ITALIC_NORMAL }, + { SID_ATTR_CHAR_UNDERLINE, LINESTYLE_SINGLE }, + { SID_ATTR_CHAR_UNDERLINE, LINESTYLE_DOUBLE }, + { SID_ATTR_CHAR_STRIKEOUT, STRIKEOUT_SINGLE }, + { SID_ATTR_CHAR_CASEMAP, sal_uInt16(SvxCaseMap::Uppercase) }, + { SID_ATTR_CHAR_CASEMAP, sal_uInt16(SvxCaseMap::Lowercase) }, + { SID_ATTR_CHAR_CASEMAP, sal_uInt16(SvxCaseMap::SmallCaps) }, + { SID_ATTR_CHAR_CASEMAP, sal_uInt16(SvxCaseMap::Capitalize) }, + { SID_ATTR_BRUSH, 0 } +}; +// Items from aRedlineAttr relevant for InsertAttr: strikethrough is +// not used +static sal_uInt16 aInsertAttrMap[] = { 0, 1, 2, 3, 4, 6, 7, 8, 9, 10 }; + +// Items from aRedlineAttr relevant for DeleteAttr: underline and +// double underline is not used +static sal_uInt16 aDeletedAttrMap[] = { 0, 1, 2, 5, 6, 7, 8, 9, 10 }; + +// Items from aRedlineAttr relevant for ChangeAttr: strikethrough is +// not used +static sal_uInt16 aChangedAttrMap[] = { 0, 1, 2, 3, 4, 6, 7, 8, 9, 10 }; + +// Preview of selection +SwMarkPreview::SwMarkPreview() + : m_aTransCol(COL_TRANSPARENT) + , m_aMarkCol(COL_LIGHTRED) + , m_nMarkPos(0) + +{ + InitColors(); +} + +SwMarkPreview::~SwMarkPreview() +{ +} + +void SwMarkPreview::InitColors() +{ + // m_aTransCol and m_aMarkCol are _not_ changed because they are set from outside! + + const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); + m_aBgCol = rSettings.GetWindowColor(); + + bool bHC = rSettings.GetHighContrastMode(); + const Color& rFontColor = SwViewOption::GetCurrentViewOptions().GetFontColor(); + m_aLineCol = bHC? rFontColor : COL_BLACK; + m_aShadowCol = bHC? m_aBgCol : rSettings.GetShadowColor(); + m_aTextCol = bHC? rFontColor : COL_GRAY; + m_aPrintAreaCol = m_aTextCol; +} + +void SwMarkPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle &/*rRect*/) +{ + const Size aSz(GetOutputSizePixel()); + + // Page + m_aPage.SetSize(Size(aSz.Width() - 3, aSz.Height() - 3)); + + const tools::Long nOutWPix = m_aPage.GetWidth(); + const tools::Long nOutHPix = m_aPage.GetHeight(); + + // PrintArea + const tools::Long nLBorder = 8; + const tools::Long nRBorder = 8; + const tools::Long nTBorder = 4; + const tools::Long nBBorder = 4; + + m_aLeftPagePrtArea = tools::Rectangle(Point(nLBorder, nTBorder), Point((nOutWPix - 1) - nRBorder, (nOutHPix - 1) - nBBorder)); + const tools::Long nWidth = m_aLeftPagePrtArea.GetWidth(); + const tools::Long nCorr = (nWidth & 1) != 0 ? 0 : 1; + m_aLeftPagePrtArea.SetSize(Size(nWidth / 2 - (nLBorder + nRBorder) / 2 + nCorr, m_aLeftPagePrtArea.GetHeight())); + + m_aRightPagePrtArea = m_aLeftPagePrtArea; + m_aRightPagePrtArea.Move(m_aLeftPagePrtArea.GetWidth() + nLBorder + nRBorder + 1, 0); + + // draw shadow + tools::Rectangle aShadow(m_aPage); + aShadow += Point(3, 3); + drawRect(rRenderContext, aShadow, m_aShadowCol, m_aTransCol); + + // draw page + drawRect(rRenderContext, m_aPage, m_aBgCol, m_aLineCol); + + // draw separator + tools::Rectangle aPageSeparator(m_aPage); + aPageSeparator.SetSize(Size(2, aPageSeparator.GetHeight())); + aPageSeparator.Move(m_aPage.GetWidth() / 2 - 1, 0); + drawRect(rRenderContext, aPageSeparator, m_aLineCol, m_aTransCol); + + PaintPage(rRenderContext, m_aLeftPagePrtArea); + PaintPage(rRenderContext, m_aRightPagePrtArea); + + tools::Rectangle aLeftMark(Point(m_aPage.Left() + 2, m_aLeftPagePrtArea.Top() + 4), Size(m_aLeftPagePrtArea.Left() - 4, 2)); + tools::Rectangle aRightMark(Point(m_aRightPagePrtArea.Right() + 2, m_aRightPagePrtArea.Bottom() - 6), Size(m_aLeftPagePrtArea.Left() - 4, 2)); + + switch (m_nMarkPos) + { + case 1: // left + aRightMark.SetPos(Point(m_aRightPagePrtArea.Left() - 2 - aRightMark.GetWidth(), aRightMark.Top())); + break; + + case 2: // right + aLeftMark.SetPos(Point(m_aLeftPagePrtArea.Right() + 2, aLeftMark.Top())); + break; + + case 3: // outside + break; + + case 4: // inside + aLeftMark.SetPos(Point(m_aLeftPagePrtArea.Right() + 2, aLeftMark.Top())); + aRightMark.SetPos(Point(m_aRightPagePrtArea.Left() - 2 - aRightMark.GetWidth(), aRightMark.Top())); + break; + + case 0: // none + default: + return; + } + drawRect(rRenderContext, aLeftMark, m_aMarkCol, m_aTransCol); + drawRect(rRenderContext, aRightMark, m_aMarkCol, m_aTransCol); +} + +void SwMarkPreview::PaintPage(vcl::RenderContext& rRenderContext, const tools::Rectangle &rRect) +{ + // draw PrintArea + drawRect(rRenderContext, rRect, m_aTransCol, m_aPrintAreaCol); + + // draw Testparagraph + + tools::Rectangle aTextLine = rRect; + aTextLine.SetSize(Size(aTextLine.GetWidth(), 2)); + aTextLine.AdjustLeft(4 ); + aTextLine.AdjustRight( -4 ); + aTextLine.Move(0, 4); + + const tools::Long nStep = aTextLine.GetHeight() + 2; + const tools::Long nLines = rRect.GetHeight() / (aTextLine.GetHeight() + 2) - 1; + + // simulate text + for (tools::Long i = 0; i < nLines; ++i) + { + if (i == (nLines - 1)) + aTextLine.SetSize(Size(aTextLine.GetWidth() / 2, aTextLine.GetHeight())); + + if (m_aPage.Contains(aTextLine)) + drawRect(rRenderContext, aTextLine, m_aTextCol, m_aTransCol); + + aTextLine.Move(0, nStep); + } + aTextLine.Move(0, -nStep); +} + +void SwMarkPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + Size aInitialSize = getPreviewOptionsSize(pDrawingArea->get_ref_device()); + pDrawingArea->set_size_request(aInitialSize.Width(), aInitialSize.Height()); + weld::CustomWidgetController::SetDrawingArea(pDrawingArea); + SetOutputSizePixel(aInitialSize); +} + +namespace +{ + void lcl_FillRedlineAttrListBox( + weld::ComboBox& rLB, const AuthorCharAttr& rAttrToSelect, + const sal_uInt16* pAttrMap, const size_t nAttrMapSize) + { + for (size_t i = 0; i != nAttrMapSize; ++i) + { + CharAttr const & rAttr(aRedlineAttr[pAttrMap[i]]); + rLB.set_id(i, weld::toId(&rAttr)); + if (rAttr.nItemId == rAttrToSelect.m_nItemId && + rAttr.nAttr == rAttrToSelect.m_nAttr) + rLB.set_active(i); + } + } +} + +SwRedlineOptionsTabPage::SwRedlineOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/optredlinepage.ui", "OptRedLinePage", &rSet) + , m_xInsertLB(m_xBuilder->weld_combo_box("insert")) + , m_xInsertImg(m_xBuilder->weld_widget("lockinsert")) + , m_xInsertColorLB(new ColorListBox(m_xBuilder->weld_menu_button("insertcolor"), + [this]{ return GetDialogController()->getDialog(); })) + , m_xInsertColorImg(m_xBuilder->weld_widget("lockinsertcolor")) + , m_xInsertedPreviewWN(new SvxFontPrevWindow) + , m_xInsertedPreview(new weld::CustomWeld(*m_xBuilder, "insertedpreview", *m_xInsertedPreviewWN)) + , m_xDeletedLB(m_xBuilder->weld_combo_box("deleted")) + , m_xDeletedImg(m_xBuilder->weld_widget("lockdeleted")) + , m_xDeletedColorLB(new ColorListBox(m_xBuilder->weld_menu_button("deletedcolor"), + [this]{ return GetDialogController()->getDialog(); })) + , m_xDeletedColorImg(m_xBuilder->weld_widget("lockdeletedcolor")) + , m_xDeletedPreviewWN(new SvxFontPrevWindow) + , m_xDeletedPreview(new weld::CustomWeld(*m_xBuilder, "deletedpreview", *m_xDeletedPreviewWN)) + , m_xChangedLB(m_xBuilder->weld_combo_box("changed")) + , m_xChangedImg(m_xBuilder->weld_widget("lockchanged")) + , m_xChangedColorLB(new ColorListBox(m_xBuilder->weld_menu_button("changedcolor"), + [this]{ return GetDialogController()->getDialog(); })) + , m_xChangedColorImg(m_xBuilder->weld_widget("lockchangedcolor")) + , m_xChangedPreviewWN(new SvxFontPrevWindow) + , m_xChangedPreview(new weld::CustomWeld(*m_xBuilder, "changedpreview", *m_xChangedPreviewWN)) + , m_xMarkPosLB(m_xBuilder->weld_combo_box("markpos")) + , m_xMarkPosImg(m_xBuilder->weld_widget("lockmarkpos")) + , m_xMarkColorLB(new ColorListBox(m_xBuilder->weld_menu_button("markcolor"), + [this]{ return GetDialogController()->getDialog(); })) + , m_xMarkColorImg(m_xBuilder->weld_widget("lockmarkcolor")) + , m_xMarkPreviewWN(new SwMarkPreview) + , m_xMarkPreview(new weld::CustomWeld(*m_xBuilder, "markpreview", *m_xMarkPreviewWN)) +{ + Size aPreviewSize(getPreviewOptionsSize(m_xMarkPreviewWN->GetDrawingArea()->get_ref_device())); + + m_xInsertColorLB->SetSlotId(SID_AUTHOR_COLOR, true); + m_xDeletedColorLB->SetSlotId(SID_AUTHOR_COLOR, true); + m_xChangedColorLB->SetSlotId(SID_AUTHOR_COLOR, true); + + m_xInsertedPreviewWN->set_size_request(aPreviewSize.Width(), aPreviewSize.Height()); + m_xDeletedPreviewWN->set_size_request(aPreviewSize.Width(), aPreviewSize.Height()); + m_xChangedPreviewWN->set_size_request(aPreviewSize.Width(), aPreviewSize.Height()); + m_xMarkPreviewWN->set_size_request(aPreviewSize.Width(), aPreviewSize.Height()); + + for (sal_Int32 i = 0, nEntryCount = m_xInsertLB->get_count(); i < nEntryCount; ++i) + { + const OUString sEntry(m_xInsertLB->get_text(i)); + m_xDeletedLB->append_text(sEntry); + m_xChangedLB->append_text(sEntry); + }; + + // remove strikethrough from insert and change and underline + double + // underline from delete + m_xInsertLB->remove(5); + m_xChangedLB->remove(5); + m_xDeletedLB->remove(4); + m_xDeletedLB->remove(3); + + Link<weld::ComboBox&,void> aLk = LINK(this, SwRedlineOptionsTabPage, AttribHdl); + m_xInsertLB->connect_changed( aLk ); + m_xDeletedLB->connect_changed( aLk ); + m_xChangedLB->connect_changed( aLk ); + + Link<ColorListBox&,void> aLk2 = LINK(this, SwRedlineOptionsTabPage, ColorHdl); + m_xInsertColorLB->SetSelectHdl( aLk2 ); + m_xDeletedColorLB->SetSelectHdl( aLk2 ); + m_xChangedColorLB->SetSelectHdl( aLk2 ); + + m_xMarkPosLB->connect_changed(LINK(this, SwRedlineOptionsTabPage, ChangedMaskPrevHdl)); + m_xMarkColorLB->SetSelectHdl(LINK(this, SwRedlineOptionsTabPage, ChangedMaskColorPrevHdl)); +} + +SwRedlineOptionsTabPage::~SwRedlineOptionsTabPage() +{ + m_xInsertColorLB.reset(); + m_xInsertedPreview.reset(); + m_xInsertedPreviewWN.reset(); + m_xDeletedColorLB.reset(); + m_xDeletedPreview.reset(); + m_xDeletedPreviewWN.reset(); + m_xChangedColorLB.reset(); + m_xChangedPreview.reset(); + m_xChangedPreviewWN.reset(); + m_xMarkColorLB.reset(); + m_xMarkPreview.reset(); + m_xMarkPreviewWN.reset(); +} + +std::unique_ptr<SfxTabPage> SwRedlineOptionsTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet) +{ + return std::make_unique<SwRedlineOptionsTabPage>(pPage, pController, *rSet); +} + +OUString SwRedlineOptionsTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label2", "insert_label", "insertcolor_label", + "label3", "deleted_label", "deletedcolor_label", + "label4", "changed_label", "changedcolor_label", + "label5", "markpos_label", "markcolor_label" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SwRedlineOptionsTabPage::FillItemSet( SfxItemSet* ) +{ + CharAttr *pAttr; + SwModuleOptions *pOpt = SW_MOD()->GetModuleConfig(); + + AuthorCharAttr aInsertedAttr; + AuthorCharAttr aDeletedAttr; + AuthorCharAttr aChangedAttr; + + AuthorCharAttr aOldInsertAttr(pOpt->GetInsertAuthorAttr()); + AuthorCharAttr aOldDeletedAttr(pOpt->GetDeletedAuthorAttr()); + AuthorCharAttr aOldChangedAttr(pOpt->GetFormatAuthorAttr()); + + Color nOldMarkColor = pOpt->GetMarkAlignColor(); + sal_uInt16 nOldMarkMode = pOpt->GetMarkAlignMode(); + + sal_Int32 nPos = m_xInsertLB->get_active(); + if (nPos != -1) + { + pAttr = weld::fromId<CharAttr*>(m_xInsertLB->get_id(nPos)); + aInsertedAttr.m_nItemId = pAttr->nItemId; + aInsertedAttr.m_nAttr = pAttr->nAttr; + aInsertedAttr.m_nColor = m_xInsertColorLB->GetSelectEntryColor(); + pOpt->SetInsertAuthorAttr(aInsertedAttr); + } + + nPos = m_xDeletedLB->get_active(); + if (nPos != -1) + { + pAttr = weld::fromId<CharAttr*>(m_xDeletedLB->get_id(nPos)); + aDeletedAttr.m_nItemId = pAttr->nItemId; + aDeletedAttr.m_nAttr = pAttr->nAttr; + aDeletedAttr.m_nColor = m_xDeletedColorLB->GetSelectEntryColor(); + pOpt->SetDeletedAuthorAttr(aDeletedAttr); + } + + nPos = m_xChangedLB->get_active(); + if (nPos != -1) + { + pAttr = weld::fromId<CharAttr*>(m_xChangedLB->get_id(nPos)); + aChangedAttr.m_nItemId = pAttr->nItemId; + aChangedAttr.m_nAttr = pAttr->nAttr; + aChangedAttr.m_nColor = m_xChangedColorLB->GetSelectEntryColor(); + pOpt->SetFormatAuthorAttr(aChangedAttr); + } + + nPos = 0; + switch (m_xMarkPosLB->get_active()) + { + case 0: nPos = text::HoriOrientation::NONE; break; + case 1: nPos = text::HoriOrientation::LEFT; break; + case 2: nPos = text::HoriOrientation::RIGHT; break; + case 3: nPos = text::HoriOrientation::OUTSIDE; break; + case 4: nPos = text::HoriOrientation::INSIDE; break; + } + pOpt->SetMarkAlignMode(nPos); + pOpt->SetMarkAlignColor(m_xMarkColorLB->GetSelectEntryColor()); + + if (!(aInsertedAttr == aOldInsertAttr) || + !(aDeletedAttr == aOldDeletedAttr) || + !(aChangedAttr == aOldChangedAttr) || + nOldMarkColor != pOpt->GetMarkAlignColor() || + nOldMarkMode != pOpt->GetMarkAlignMode() ) + { + // update all documents + SwDocShell* pDocShell = static_cast<SwDocShell*>(SfxObjectShell::GetFirst(checkSfxObjectShell<SwDocShell>)); + + while( pDocShell ) + { + pDocShell->GetWrtShell()->UpdateRedlineAttr(); + pDocShell = static_cast<SwDocShell*>(SfxObjectShell::GetNext(*pDocShell, checkSfxObjectShell<SwDocShell>)); + } + } + + return false; +} + +void SwRedlineOptionsTabPage::Reset( const SfxItemSet* ) +{ + const SwModuleOptions *pOpt = SW_MOD()->GetModuleConfig(); + + const AuthorCharAttr &rInsertAttr = pOpt->GetInsertAuthorAttr(); + const AuthorCharAttr &rDeletedAttr = pOpt->GetDeletedAuthorAttr(); + const AuthorCharAttr &rChangedAttr = pOpt->GetFormatAuthorAttr(); + + // initialise preview + InitFontStyle(*m_xInsertedPreviewWN, SwResId(STR_OPT_PREVIEW_INSERTED)); + InitFontStyle(*m_xDeletedPreviewWN, SwResId(STR_OPT_PREVIEW_DELETED)); + InitFontStyle(*m_xChangedPreviewWN, SwResId(STR_OPT_PREVIEW_CHANGED)); + + Color nColor = rInsertAttr.m_nColor; + m_xInsertColorLB->SelectEntry(nColor); + m_xInsertColorLB->set_sensitive(!officecfg::Office::Writer::Revision::TextDisplay::Insert::Attribute::isReadOnly()); + m_xInsertColorImg->set_visible(officecfg::Office::Writer::Revision::TextDisplay::Insert::Attribute::isReadOnly()); + + nColor = rDeletedAttr.m_nColor; + m_xDeletedColorLB->SelectEntry(nColor); + m_xDeletedColorLB->set_sensitive(!officecfg::Office::Writer::Revision::TextDisplay::Delete::Attribute::isReadOnly()); + m_xDeletedColorImg->set_visible(officecfg::Office::Writer::Revision::TextDisplay::Delete::Attribute::isReadOnly()); + + nColor = rChangedAttr.m_nColor; + m_xChangedColorLB->SelectEntry(nColor); + m_xChangedColorLB->set_sensitive(!officecfg::Office::Writer::Revision::TextDisplay::ChangedAttribute::Attribute::isReadOnly()); + m_xChangedColorImg->set_visible(officecfg::Office::Writer::Revision::TextDisplay::ChangedAttribute::Attribute::isReadOnly()); + + m_xMarkColorLB->SelectEntry(pOpt->GetMarkAlignColor()); + m_xMarkColorLB->set_sensitive(!officecfg::Office::Writer::Revision::LinesChanged::Color::isReadOnly()); + m_xMarkColorImg->set_visible(officecfg::Office::Writer::Revision::LinesChanged::Color::isReadOnly()); + + m_xInsertLB->set_active(0); + m_xInsertLB->set_sensitive(!officecfg::Office::Writer::Revision::TextDisplay::Insert::Color::isReadOnly()); + m_xInsertImg->set_visible(officecfg::Office::Writer::Revision::TextDisplay::Insert::Color::isReadOnly()); + m_xDeletedLB->set_active(0); + m_xDeletedLB->set_sensitive(!officecfg::Office::Writer::Revision::TextDisplay::Delete::Color::isReadOnly()); + m_xDeletedImg->set_visible(officecfg::Office::Writer::Revision::TextDisplay::Delete::Color::isReadOnly()); + m_xChangedLB->set_active(0); + m_xChangedLB->set_sensitive(!officecfg::Office::Writer::Revision::TextDisplay::ChangedAttribute::Color::isReadOnly()); + m_xChangedImg->set_visible(officecfg::Office::Writer::Revision::TextDisplay::ChangedAttribute::Color::isReadOnly()); + + lcl_FillRedlineAttrListBox(*m_xInsertLB, rInsertAttr, aInsertAttrMap, SAL_N_ELEMENTS(aInsertAttrMap)); + lcl_FillRedlineAttrListBox(*m_xDeletedLB, rDeletedAttr, aDeletedAttrMap, SAL_N_ELEMENTS(aDeletedAttrMap)); + lcl_FillRedlineAttrListBox(*m_xChangedLB, rChangedAttr, aChangedAttrMap, SAL_N_ELEMENTS(aChangedAttrMap)); + + sal_Int32 nPos = 0; + switch (pOpt->GetMarkAlignMode()) + { + case text::HoriOrientation::NONE: nPos = 0; break; + case text::HoriOrientation::LEFT: nPos = 1; break; + case text::HoriOrientation::RIGHT: nPos = 2; break; + case text::HoriOrientation::OUTSIDE: nPos = 3; break; + case text::HoriOrientation::INSIDE: nPos = 4; break; + } + m_xMarkPosLB->set_active(nPos); + m_xMarkPosLB->set_sensitive(!officecfg::Office::Writer::Revision::LinesChanged::Mark::isReadOnly()); + m_xMarkPosImg->set_visible(officecfg::Office::Writer::Revision::LinesChanged::Mark::isReadOnly()); + + // show settings in preview + AttribHdl(*m_xInsertLB); + ColorHdl(*m_xInsertColorLB); + AttribHdl(*m_xDeletedLB); + ColorHdl(*m_xInsertColorLB); + AttribHdl(*m_xChangedLB); + ColorHdl(*m_xChangedColorLB); + + ChangedMaskPrev(); +} + +IMPL_LINK( SwRedlineOptionsTabPage, AttribHdl, weld::ComboBox&, rLB, void ) +{ + SvxFontPrevWindow *pPrev = nullptr; + ColorListBox *pColorLB; + + if (&rLB == m_xInsertLB.get()) + { + pColorLB = m_xInsertColorLB.get(); + pPrev = m_xInsertedPreviewWN.get(); + } + else if (&rLB == m_xDeletedLB.get()) + { + pColorLB = m_xDeletedColorLB.get(); + pPrev = m_xDeletedPreviewWN.get(); + } + else + { + pColorLB = m_xChangedColorLB.get(); + pPrev = m_xChangedPreviewWN.get(); + } + + SvxFont& rFont = pPrev->GetFont(); + SvxFont& rCJKFont = pPrev->GetCJKFont(); + + rFont.SetWeight(WEIGHT_NORMAL); + rCJKFont.SetWeight(WEIGHT_NORMAL); + rFont.SetItalic(ITALIC_NONE); + rCJKFont.SetItalic(ITALIC_NONE); + rFont.SetUnderline(LINESTYLE_NONE); + rCJKFont.SetUnderline(LINESTYLE_NONE); + rFont.SetStrikeout(STRIKEOUT_NONE); + rCJKFont.SetStrikeout(STRIKEOUT_NONE); + rFont.SetCaseMap(SvxCaseMap::NotMapped); + rCJKFont.SetCaseMap(SvxCaseMap::NotMapped); + + Color aColor = pColorLB->GetSelectEntryColor(); + + if (aColor == COL_NONE_COLOR) + { + rFont.SetColor( COL_BLACK ); + rCJKFont.SetColor( COL_BLACK ); + } + else if (aColor == COL_TRANSPARENT) + { + rFont.SetColor( COL_RED ); + rCJKFont.SetColor( COL_RED ); + } + else + { + rFont.SetColor(aColor); + rCJKFont.SetColor(aColor); + } + + sal_Int32 nPos = rLB.get_active(); + if( nPos == -1) + nPos = 0; + + CharAttr* pAttr = weld::fromId<CharAttr*>(rLB.get_id(nPos)); + //switch off preview background color + pPrev->ResetColor(); + switch (pAttr->nItemId) + { + case SID_ATTR_CHAR_WEIGHT: + rFont.SetWeight( static_cast<FontWeight>(pAttr->nAttr) ); + rCJKFont.SetWeight( static_cast<FontWeight>(pAttr->nAttr) ); + break; + + case SID_ATTR_CHAR_POSTURE: + rFont.SetItalic( static_cast<FontItalic>(pAttr->nAttr) ); + rCJKFont.SetItalic( static_cast<FontItalic>(pAttr->nAttr) ); + break; + + case SID_ATTR_CHAR_UNDERLINE: + rFont.SetUnderline( static_cast<FontLineStyle>(pAttr->nAttr) ); + rCJKFont.SetUnderline( static_cast<FontLineStyle>(pAttr->nAttr) ); + break; + + case SID_ATTR_CHAR_STRIKEOUT: + rFont.SetStrikeout( static_cast<FontStrikeout>(pAttr->nAttr) ); + rCJKFont.SetStrikeout( static_cast<FontStrikeout>(pAttr->nAttr) ); + break; + + case SID_ATTR_CHAR_CASEMAP: + rFont.SetCaseMap( static_cast<SvxCaseMap>(pAttr->nAttr) ); + rCJKFont.SetCaseMap( static_cast<SvxCaseMap>(pAttr->nAttr) ); + break; + + case SID_ATTR_BRUSH: + { + Color aBgColor = pColorLB->GetSelectEntryColor(); + if (aBgColor != COL_NONE_COLOR) + pPrev->SetColor(aBgColor); + else + pPrev->SetColor(COL_LIGHTGRAY); + rFont.SetColor( COL_BLACK ); + rCJKFont.SetColor( COL_BLACK ); + } + break; + } + + pPrev->Invalidate(); +} + +IMPL_LINK(SwRedlineOptionsTabPage, ColorHdl, ColorListBox&, rListBox, void) +{ + ColorListBox* pColorLB = &rListBox; + SvxFontPrevWindow *pPrev = nullptr; + weld::ComboBox* pLB; + + if (pColorLB == m_xInsertColorLB.get()) + { + pLB = m_xInsertLB.get(); + pPrev = m_xInsertedPreviewWN.get(); + } + else if (pColorLB == m_xDeletedColorLB.get()) + { + pLB = m_xDeletedLB.get(); + pPrev = m_xDeletedPreviewWN.get(); + } + else + { + pLB = m_xChangedLB.get(); + pPrev = m_xChangedPreviewWN.get(); + } + + SvxFont& rFont = pPrev->GetFont(); + SvxFont& rCJKFont = pPrev->GetCJKFont(); + sal_Int32 nPos = pLB->get_active(); + if( nPos == -1) + nPos = 0; + + CharAttr* pAttr = weld::fromId<CharAttr*>(pLB->get_id(nPos)); + + if( pAttr->nItemId == SID_ATTR_BRUSH ) + { + rFont.SetColor( COL_BLACK ); + rCJKFont.SetColor( COL_BLACK ); + + Color aBgColor = pColorLB->GetSelectEntryColor(); + if (aBgColor != COL_NONE_COLOR) + pPrev->SetColor(aBgColor); + else + pPrev->SetColor(COL_LIGHTGRAY); + } + else + { + Color aColor = pColorLB->GetSelectEntryColor(); + + if (aColor == COL_NONE_COLOR) + { + rFont.SetColor( COL_BLACK ); + rCJKFont.SetColor( COL_BLACK ); + } + else if (aColor == COL_TRANSPARENT) + { + rFont.SetColor( COL_RED ); + rCJKFont.SetColor( COL_RED ); + } + else + { + rFont.SetColor(aColor); + rCJKFont.SetColor(aColor); + } + } + + pPrev->Invalidate(); +} + +void SwRedlineOptionsTabPage::ChangedMaskPrev() +{ + m_xMarkPreviewWN->SetMarkPos(m_xMarkPosLB->get_active()); + m_xMarkPreviewWN->SetColor(m_xMarkColorLB->GetSelectEntryColor()); + + m_xMarkPreviewWN->Invalidate(); +} + +IMPL_LINK_NOARG(SwRedlineOptionsTabPage, ChangedMaskPrevHdl, weld::ComboBox&, void) +{ + ChangedMaskPrev(); +} + +IMPL_LINK_NOARG(SwRedlineOptionsTabPage, ChangedMaskColorPrevHdl, ColorListBox&, void) +{ + ChangedMaskPrev(); +} + +void SwRedlineOptionsTabPage::InitFontStyle(SvxFontPrevWindow& rExampleWin, const OUString& rText) +{ + const AllSettings& rAllSettings = Application::GetSettings(); + LanguageType eLangType = rAllSettings.GetUILanguageTag().getLanguageType(); + Color aBackCol( rAllSettings.GetStyleSettings().GetWindowColor() ); + SvxFont& rFont = rExampleWin.GetFont(); + SvxFont& rCJKFont = rExampleWin.GetCJKFont(); + SvxFont& rCTLFont = rExampleWin.GetCTLFont(); + + OutputDevice& rDevice = rExampleWin.GetDrawingArea()->get_ref_device(); + + vcl::Font aFont( OutputDevice::GetDefaultFont( DefaultFontType::SERIF, eLangType, + GetDefaultFontFlags::OnlyOne, &rDevice ) ); + vcl::Font aCJKFont( OutputDevice::GetDefaultFont( DefaultFontType::CJK_TEXT, eLangType, + GetDefaultFontFlags::OnlyOne, &rDevice ) ); + vcl::Font aCTLFont( OutputDevice::GetDefaultFont( DefaultFontType::CTL_TEXT, eLangType, + GetDefaultFontFlags::OnlyOne, &rDevice ) ); + const Size aDefSize( 0, 12 ); + aFont.SetFontSize( aDefSize ); + aCJKFont.SetFontSize( aDefSize ); + aCTLFont.SetFontSize( aDefSize ); + + aFont.SetFillColor( aBackCol ); + aCJKFont.SetFillColor( aBackCol ); + aCTLFont.SetFillColor( aBackCol ); + + aFont.SetWeight( WEIGHT_NORMAL ); + aCJKFont.SetWeight( WEIGHT_NORMAL ); + aCTLFont.SetWeight( WEIGHT_NORMAL ); + + rFont = aFont; + rCJKFont = aCJKFont; + rCTLFont = aCTLFont; + + const Size aNewSize( 0, rExampleWin.GetOutputSizePixel().Height() * 2 / 3 ); + rFont.SetFontSize( aNewSize ); + rCJKFont.SetFontSize( aNewSize ); + + rExampleWin.SetFont( rFont, rCJKFont,rCTLFont ); + rExampleWin.SetPreviewText(rText); +} + +SwCompareOptionsTabPage::SwCompareOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/optcomparison.ui", "OptComparison", &rSet) + , m_xAutoRB(m_xBuilder->weld_radio_button("auto")) + , m_xWordRB(m_xBuilder->weld_radio_button("byword")) + , m_xCharRB(m_xBuilder->weld_radio_button("bycharacter")) + , m_xCompareModeImg(m_xBuilder->weld_widget("lockcomparemode")) + , m_xRsidCB(m_xBuilder->weld_check_button("useRSID")) + , m_xRsidImg(m_xBuilder->weld_widget("lockuseRSID")) + , m_xIgnoreCB(m_xBuilder->weld_check_button("ignore")) + , m_xIgnoreImg(m_xBuilder->weld_widget("lockignore")) + , m_xLenNF(m_xBuilder->weld_spin_button("ignorelen")) + , m_xLenImg(m_xBuilder->weld_widget("lockignorelen")) + , m_xStoreRsidCB(m_xBuilder->weld_check_button("storeRSID")) + , m_xStoreRsidImg(m_xBuilder->weld_widget("lockstoreRSID")) +{ + Link<weld::Toggleable&,void> aLnk( LINK( this, SwCompareOptionsTabPage, ComparisonHdl ) ); + m_xAutoRB->connect_toggled( aLnk ); + m_xWordRB->connect_toggled( aLnk ); + m_xCharRB->connect_toggled( aLnk ); + + m_xIgnoreCB->connect_toggled( LINK( this, SwCompareOptionsTabPage, IgnoreHdl) ); +} + +SwCompareOptionsTabPage::~SwCompareOptionsTabPage() +{ +} + +std::unique_ptr<SfxTabPage> SwCompareOptionsTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SwCompareOptionsTabPage>(pPage, pController, *rAttrSet); +} + +OUString SwCompareOptionsTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString labels[] = { "label1", "setting" }; + + for (const auto& label : labels) + { + if (const auto& pString = m_xBuilder->weld_label(label)) + sAllStrings += pString->get_label() + " "; + } + + OUString checkButton[] = { "useRSID", "ignore", "storeRSID" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + OUString radioButton[] = { "auto", "byword", "bycharacter" }; + + for (const auto& radio : radioButton) + { + if (const auto& pString = m_xBuilder->weld_radio_button(radio)) + sAllStrings += pString->get_label() + " "; + } + + return sAllStrings.replaceAll("_", ""); +} + +bool SwCompareOptionsTabPage::FillItemSet( SfxItemSet* ) +{ + bool bRet = false; + SwModuleOptions *pOpt = SW_MOD()->GetModuleConfig(); + + if( m_xAutoRB->get_state_changed_from_saved() || + m_xWordRB->get_state_changed_from_saved() || + m_xCharRB->get_state_changed_from_saved() ) + { + SwCompareMode eCmpMode = SwCompareMode::Auto; + + if ( m_xAutoRB->get_active() ) eCmpMode = SwCompareMode::Auto; + if ( m_xWordRB->get_active() ) eCmpMode = SwCompareMode::ByWord; + if ( m_xCharRB->get_active() ) eCmpMode = SwCompareMode::ByChar; + + pOpt->SetCompareMode( eCmpMode ); + bRet = true; + } + + if( m_xRsidCB->get_state_changed_from_saved() ) + { + pOpt->SetUseRsid( m_xRsidCB->get_active() ); + bRet = true; + } + + if( m_xIgnoreCB->get_state_changed_from_saved() ) + { + pOpt->SetIgnorePieces( m_xIgnoreCB->get_active() ); + bRet = true; + } + + if( m_xLenNF->get_value_changed_from_saved() ) + { + pOpt->SetPieceLen( m_xLenNF->get_value() ); + bRet = true; + } + + if (m_xStoreRsidCB->get_state_changed_from_saved()) + { + pOpt->SetStoreRsid(m_xStoreRsidCB->get_active()); + bRet = true; + } + + return bRet; +} + +void SwCompareOptionsTabPage::Reset( const SfxItemSet* ) +{ + SwModuleOptions *pOpt = SW_MOD()->GetModuleConfig(); + + SwCompareMode eCmpMode = pOpt->GetCompareMode(); + if( eCmpMode == SwCompareMode::Auto ) + { + m_xAutoRB->set_active(true); + m_xRsidCB->set_sensitive(false); + m_xIgnoreCB->set_sensitive(false); + m_xLenNF->set_sensitive(false); + } + else if( eCmpMode == SwCompareMode::ByWord ) + { + m_xWordRB->set_active(true); + m_xRsidCB->set_sensitive(true); + m_xIgnoreCB->set_sensitive(true); + m_xLenNF->set_sensitive(true); + } + else if( eCmpMode == SwCompareMode::ByChar) + { + m_xCharRB->set_active(true); + m_xRsidCB->set_sensitive(true); + m_xIgnoreCB->set_sensitive(true); + m_xLenNF->set_sensitive(true); + } + + if (officecfg::Office::Writer::Comparison::Mode::isReadOnly()) + { + m_xAutoRB->set_sensitive(false); + m_xWordRB->set_sensitive(false); + m_xCharRB->set_sensitive(false); + m_xCompareModeImg->set_visible(true); + } + + m_xAutoRB->save_state(); + m_xWordRB->save_state(); + m_xCharRB->save_state(); + + m_xRsidCB->set_active( pOpt->IsUseRsid() ); + if (officecfg::Office::Writer::Comparison::UseRSID::isReadOnly()) + { + m_xRsidCB->set_sensitive(false); + m_xRsidImg->set_visible(true); + } + m_xRsidCB->save_state(); + + m_xIgnoreCB->set_active( pOpt->IsIgnorePieces() ); + if (officecfg::Office::Writer::Comparison::IgnorePieces::isReadOnly()) + { + m_xIgnoreCB->set_sensitive(false); + m_xIgnoreImg->set_visible(true); + } + m_xIgnoreCB->save_state(); + + m_xLenNF->set_sensitive( m_xIgnoreCB->get_active() && eCmpMode != SwCompareMode::Auto ); + + m_xLenNF->set_value( pOpt->GetPieceLen() ); + if (officecfg::Office::Writer::Comparison::IgnoreLength::isReadOnly()) + { + m_xLenNF->set_sensitive(false); + m_xLenImg->set_visible(true); + } + m_xLenNF->save_value(); + + m_xStoreRsidCB->set_active(pOpt->IsStoreRsid()); + m_xStoreRsidCB->set_sensitive(!officecfg::Office::Writer::Comparison::StoreRSID::isReadOnly()); + m_xStoreRsidImg->set_visible(officecfg::Office::Writer::Comparison::StoreRSID::isReadOnly()); + m_xStoreRsidCB->save_state(); +} + +IMPL_LINK(SwCompareOptionsTabPage, ComparisonHdl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + + bool bChecked = !m_xAutoRB->get_active(); + m_xRsidCB->set_sensitive( bChecked ); + m_xIgnoreCB->set_sensitive( bChecked ); + m_xLenNF->set_sensitive( bChecked && m_xIgnoreCB->get_active() ); +} + +IMPL_LINK_NOARG(SwCompareOptionsTabPage, IgnoreHdl, weld::Toggleable&, void) +{ + m_xLenNF->set_sensitive(m_xIgnoreCB->get_active()); +} + +#ifdef DBG_UTIL + +SwTestTabPage::SwTestTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/opttestpage.ui", "OptTestPage", &rCoreSet) + , m_bAttrModified( false ) + , m_xTest1CBox(m_xBuilder->weld_check_button("unused")) + , m_xTest2CBox(m_xBuilder->weld_check_button("dynamic")) + , m_xTest3CBox(m_xBuilder->weld_check_button("nocalm")) + , m_xTest4CBox(m_xBuilder->weld_check_button("wysiwygdbg")) + , m_xTest5CBox(m_xBuilder->weld_check_button("noidle")) + , m_xTest6CBox(m_xBuilder->weld_check_button("noscreenadj")) + , m_xTest7CBox(m_xBuilder->weld_check_button("winformat")) + , m_xTest8CBox(m_xBuilder->weld_check_button("noscroll")) + , m_xTest9CBox(m_xBuilder->weld_check_button("DrawingLayerNotLoading")) + , m_xTest10CBox(m_xBuilder->weld_check_button("AutoFormatByInput")) +{ + Init(); +} + +SwTestTabPage::~SwTestTabPage() +{ +} + +std::unique_ptr<SfxTabPage> SwTestTabPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet ) +{ + return std::make_unique<SwTestTabPage>(pPage, pController, *rAttrSet); +} + +OUString SwTestTabPage::GetAllStrings() +{ + OUString sAllStrings; + OUString checkButton[] = { "unused", "dynamic", "nocalm", + "wysiwygdbg", "noidle", "noscreenadj", + "winformat", "noscroll", "DrawingLayerNotLoading", + "AutoFormatByInput" }; + + for (const auto& check : checkButton) + { + if (const auto& pString = m_xBuilder->weld_check_button(check)) + sAllStrings += pString->get_label() + " "; + } + + if (const auto& pString = m_xBuilder->weld_label("label1")) + sAllStrings += pString->get_label() + " "; + + return sAllStrings.replaceAll("_", ""); +} + +bool SwTestTabPage::FillItemSet( SfxItemSet* rCoreSet ) +{ + + if ( m_bAttrModified ) + { + SwTestItem aTestItem; + aTestItem.m_bTest1=m_xTest1CBox->get_active(); + aTestItem.m_bTest2=m_xTest2CBox->get_active(); + aTestItem.m_bTest3=m_xTest3CBox->get_active(); + aTestItem.m_bTest4=m_xTest4CBox->get_active(); + aTestItem.m_bTest5=m_xTest5CBox->get_active(); + aTestItem.m_bTest6=m_xTest6CBox->get_active(); + aTestItem.m_bTest7=m_xTest7CBox->get_active(); + aTestItem.m_bTest8=m_xTest8CBox->get_active(); + aTestItem.m_bTest9=m_xTest9CBox->get_active(); + aTestItem.m_bTest10=m_xTest10CBox->get_active(); + rCoreSet->Put(aTestItem); + } + return m_bAttrModified; +} + +void SwTestTabPage::Reset( const SfxItemSet* ) +{ + const SfxItemSet& rSet = GetItemSet(); + const SwTestItem* pTestAttr = rSet.GetItemIfSet( FN_PARAM_SWTEST, false ); + if(!pTestAttr) + return; + + m_xTest1CBox->set_active(pTestAttr->m_bTest1); + m_xTest2CBox->set_active(pTestAttr->m_bTest2); + m_xTest3CBox->set_active(pTestAttr->m_bTest3); + m_xTest4CBox->set_active(pTestAttr->m_bTest4); + m_xTest5CBox->set_active(pTestAttr->m_bTest5); + m_xTest6CBox->set_active(pTestAttr->m_bTest6); + m_xTest7CBox->set_active(pTestAttr->m_bTest7); + m_xTest8CBox->set_active(pTestAttr->m_bTest8); + m_xTest9CBox->set_active(pTestAttr->m_bTest9); + m_xTest10CBox->set_active(pTestAttr->m_bTest10); +} + +void SwTestTabPage::Init() +{ + // handler + Link<weld::Toggleable&,void> aLk = LINK( this, SwTestTabPage, AutoClickHdl ); + m_xTest1CBox->connect_toggled( aLk ); + m_xTest2CBox->connect_toggled( aLk ); + m_xTest3CBox->connect_toggled( aLk ); + m_xTest4CBox->connect_toggled( aLk ); + m_xTest5CBox->connect_toggled( aLk ); + m_xTest6CBox->connect_toggled( aLk ); + m_xTest7CBox->connect_toggled( aLk ); + m_xTest8CBox->connect_toggled( aLk ); + m_xTest9CBox->connect_toggled( aLk ); + m_xTest10CBox->connect_toggled( aLk ); +} + +IMPL_LINK_NOARG(SwTestTabPage, AutoClickHdl, weld::Toggleable&, void) +{ + m_bAttrModified = true; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/addresslistdialog.cxx b/sw/source/ui/dbui/addresslistdialog.cxx new file mode 100644 index 0000000000..9cb433974b --- /dev/null +++ b/sw/source/ui/dbui/addresslistdialog.cxx @@ -0,0 +1,641 @@ +/* -*- 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 <swtypes.hxx> +#include <comphelper/propertyvalue.hxx> +#include "addresslistdialog.hxx" +#include "selectdbtabledialog.hxx" +#include "createaddresslistdialog.hxx" +#include <mailmergewizard.hxx> +#include <mmconfigitem.hxx> +#include "mmaddressblockpage.hxx" +#include <dbmgr.hxx> +#include <dbconfig.hxx> +#include <unotools/tempfile.hxx> +#include <vcl/svapp.hxx> +#include <tools/urlobj.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/types.hxx> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <com/sun/star/sdb/XCompletedConnection.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/FilterDialog.hpp> +#include <com/sun/star/sdb/XDocumentDataSource.hpp> +#include <com/sun/star/sdbc/XRowSet.hpp> +#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <o3tl/safeint.hxx> +#include <swunohelper.hxx> +#include <unotools/pathoptions.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <svl/urihelper.hxx> +#include <strings.hrc> +#include <view.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::ui::dialogs; + +struct AddressUserData_Impl +{ + uno::Reference<XDataSource> xSource; + SharedConnection xConnection; + uno::Reference< XColumnsSupplier> xColumnsSupplier; + uno::Reference< sdbc::XResultSet> xResultSet; + OUString sFilter; + OUString sURL; // data is editable + sal_Int32 nCommandType; + sal_Int32 nTableAndQueryCount; + AddressUserData_Impl() : + nCommandType(0), + nTableAndQueryCount(-1) + {} +}; + +static OUString lcl_getFlatURL( uno::Reference<beans::XPropertySet> const & xSourceProperties ) +{ + if(xSourceProperties.is()) + { + OUString sDBURL; + xSourceProperties->getPropertyValue("URL") >>= sDBURL; + if (sDBURL.startsWith("sdbc:flat:")) + { + uno::Sequence<OUString> aFilters; + xSourceProperties->getPropertyValue("TableFilter") >>= aFilters; + uno::Sequence<PropertyValue> aInfo; + xSourceProperties->getPropertyValue("Info") >>= aInfo; + if(aFilters.getLength() == 1 && aInfo.hasElements() ) + { + OUString sExtension; + OUString sCharSet; + for(const auto& rInfo : std::as_const(aInfo)) + { + if(rInfo.Name == "Extension") + rInfo.Value >>= sExtension; + else if(rInfo.Name == "CharSet") + rInfo.Value >>= sCharSet; + } + if (sCharSet=="UTF-8") + { + //#i97577# at this point the 'URL' can also be a file name! + return URIHelper::SmartRel2Abs( INetURLObject(), sDBURL.copy(10) ) + + "/" + aFilters[0] + "." + sExtension; + } + } + } + } + return OUString(); +} + +SwAddressListDialog::SwAddressListDialog(SwMailMergeAddressBlockPage* pParent) + : SfxDialogController(pParent->GetWizard()->getDialog(), "modules/swriter/ui/selectaddressdialog.ui", "SelectAddressDialog") + , m_bInSelectHdl(false) + , m_pAddressPage(pParent) + , m_xDescriptionFI(m_xBuilder->weld_label("desc")) + , m_xConnecting(m_xBuilder->weld_label("connecting")) + , m_xListLB(m_xBuilder->weld_tree_view("sources")) + , m_xLoadListPB(m_xBuilder->weld_button("add")) + , m_xRemovePB(m_xBuilder->weld_button("remove")) + , m_xCreateListPB(m_xBuilder->weld_button("create")) + , m_xFilterPB(m_xBuilder->weld_button("filter")) + , m_xEditPB(m_xBuilder->weld_button("edit")) + , m_xTablePB(m_xBuilder->weld_button("changetable")) + , m_xOK(m_xBuilder->weld_button("ok")) + , m_xIter(m_xListLB->make_iterator()) +{ + m_sConnecting = m_xConnecting->get_label(); + + const OUString sTemp(m_xDescriptionFI->get_label() + .replaceFirst("%1", m_xLoadListPB->strip_mnemonic(m_xLoadListPB->get_label())) + .replaceFirst("%2", m_xCreateListPB->strip_mnemonic(m_xCreateListPB->get_label()))); + m_xDescriptionFI->set_label(sTemp); + m_xFilterPB->connect_clicked( LINK( this, SwAddressListDialog, FilterHdl_Impl )); + m_xLoadListPB->connect_clicked( LINK( this, SwAddressListDialog, LoadHdl_Impl )); + m_xRemovePB->connect_clicked( LINK(this, SwAddressListDialog, RemoveHdl_Impl )); + m_xCreateListPB->connect_clicked( LINK( this, SwAddressListDialog,CreateHdl_Impl )); + m_xEditPB->connect_clicked(LINK( this, SwAddressListDialog, EditHdl_Impl)); + m_xTablePB->connect_clicked(LINK( this, SwAddressListDialog, TableSelectHdl_Impl)); + + m_xListLB->set_size_request(m_xListLB->get_approximate_digit_width() * 52, + m_xListLB->get_height_rows(9)); + + std::vector<int> aWidths + { + o3tl::narrowing<int>(m_xListLB->get_approximate_digit_width() * 26) + }; + m_xListLB->set_column_fixed_widths(aWidths); + + m_xListLB->make_sorted(); + m_xOK->connect_clicked(LINK(this, SwAddressListDialog, OKHdl_Impl)); + + uno::Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() ); + m_xDBContext = DatabaseContext::create(xContext); + + SwMailMergeConfigItem& rConfigItem = m_pAddressPage->GetWizard()->GetConfigItem(); + const SwDBData& rCurrentData = rConfigItem.GetCurrentDBData(); + + bool bEnableEdit = false; + bool bEnableOK = true; + bool bSelected = false; + m_xListLB->unselect_all(); + + SwDBConfig aDb; + const OUString sBibliography = aDb.GetBibliographySource().sDataSource; + const uno::Sequence< OUString> aNames = m_xDBContext->getElementNames(); + for(const OUString& rName : aNames) + { + if ( rName == sBibliography ) + continue; + m_xListLB->append(m_xIter.get()); + m_xListLB->set_text(*m_xIter, rName, 0); + m_aUserData.emplace_back(new AddressUserData_Impl); + AddressUserData_Impl* pUserData = m_aUserData.back().get(); + m_xListLB->set_id(*m_xIter, weld::toId(pUserData)); + if (rName == rCurrentData.sDataSource) + { + m_xListLB->select(*m_xIter); + bSelected = true; + m_xListLB->set_text(*m_xIter, rCurrentData.sCommand, 1); + pUserData->nCommandType = rCurrentData.nCommandType; + pUserData->xSource = rConfigItem.GetSource(); + pUserData->xConnection = rConfigItem.GetConnection(); + pUserData->xColumnsSupplier = rConfigItem.GetColumnsSupplier(); + pUserData->xResultSet = rConfigItem.GetResultSet(); + pUserData->sFilter = rConfigItem.GetFilter(); + //is the data source editable (csv, Unicode, single table) + uno::Reference<beans::XPropertySet> xSourceProperties; + try + { + m_xDBContext->getByName(rName) >>= xSourceProperties; + pUserData->sURL = lcl_getFlatURL( xSourceProperties ); + bEnableEdit = !pUserData->sURL.isEmpty() && + SWUnoHelper::UCB_IsFile( pUserData->sURL ) && //#i97577# + !SWUnoHelper::UCB_IsReadOnlyFileName( pUserData->sURL ); + } + catch (const uno::Exception&) + { + bEnableOK = false; + } + m_aDBData = rCurrentData; + } + } + + bool bHasChildren = m_xListLB->n_children() > 0; + if (bHasChildren && !bSelected) + m_xListLB->select(0); // select the first entry if nothing else selected + m_xOK->set_sensitive(bHasChildren && bEnableOK); + m_xEditPB->set_sensitive(bEnableEdit); + m_xRemovePB->set_sensitive(m_xListLB->n_children() > 0); + m_xFilterPB->set_sensitive(m_xListLB->n_children() > 0); + m_xTablePB->set_sensitive(m_xListLB->n_children() > 0); + m_xListLB->connect_changed(LINK(this, SwAddressListDialog, ListBoxSelectHdl_Impl)); + TableSelectHdl(nullptr); +} + +SwAddressListDialog::~SwAddressListDialog() +{ +} + +IMPL_LINK_NOARG(SwAddressListDialog, FilterHdl_Impl, weld::Button&, void) +{ + int nSelect = m_xListLB->get_selected_index(); + uno::Reference< XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() ); + if (nSelect == -1) + return; + + const OUString sCommand = m_xListLB->get_text(nSelect, 1); + if (sCommand.isEmpty()) + return; + + AddressUserData_Impl* pUserData = weld::fromId<AddressUserData_Impl*>(m_xListLB->get_id(nSelect)); + if (!pUserData->xConnection.is() ) + return; + + try + { + uno::Reference<lang::XMultiServiceFactory> xConnectFactory(pUserData->xConnection, UNO_QUERY_THROW); + uno::Reference<XSingleSelectQueryComposer> xComposer( + xConnectFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"), UNO_QUERY_THROW); + + uno::Reference<XRowSet> xRowSet( + xMgr->createInstance("com.sun.star.sdb.RowSet"), UNO_QUERY); + uno::Reference<XPropertySet> xRowProperties(xRowSet, UNO_QUERY); + xRowProperties->setPropertyValue("DataSourceName", + Any(m_xListLB->get_text(nSelect, 0))); + xRowProperties->setPropertyValue("Command", Any(sCommand)); + xRowProperties->setPropertyValue("CommandType", Any(pUserData->nCommandType)); + xRowProperties->setPropertyValue("ActiveConnection", Any(pUserData->xConnection.getTyped())); + xRowSet->execute(); + + OUString sQuery; + xRowProperties->getPropertyValue("ActiveCommand")>>= sQuery; + xComposer->setQuery(sQuery); + if(!pUserData->sFilter.isEmpty()) + xComposer->setFilter(pUserData->sFilter); + + uno::Reference< XExecutableDialog> xDialog = sdb::FilterDialog::createWithQuery( comphelper::getComponentContext(xMgr), + xComposer,xRowSet, uno::Reference<awt::XWindow>() ); + + if ( RET_OK == xDialog->execute() ) + { + weld::WaitObject aWait(m_xDialog.get()); + pUserData->sFilter = xComposer->getFilter(); + } + ::comphelper::disposeComponent(xRowSet); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "sw", "exception caught in SwAddressListDialog::FilterHdl_Impl"); + } +} + +IMPL_LINK_NOARG(SwAddressListDialog, LoadHdl_Impl, weld::Button&, void) +{ + SwView* pView = m_pAddressPage->GetWizard()->GetSwView(); + + const OUString sNewSource = SwDBManager::LoadAndRegisterDataSource(m_xDialog.get(), pView ? pView->GetDocShell() : nullptr); + if(!sNewSource.isEmpty()) + { + m_xListLB->append(m_xIter.get()); + m_xListLB->set_text(*m_xIter, sNewSource, 0); + m_aUserData.emplace_back(new AddressUserData_Impl); + AddressUserData_Impl* pUserData = m_aUserData.back().get(); + m_xListLB->set_id(*m_xIter, weld::toId(pUserData)); + m_xListLB->select(*m_xIter); + ListBoxSelectHdl_Impl(*m_xListLB); + m_xRemovePB->set_sensitive(true); + } +} + +IMPL_LINK_NOARG(SwAddressListDialog, RemoveHdl_Impl, weld::Button&, void) +{ + int nEntry = m_xListLB->get_selected_index(); + if (nEntry == -1) + return; + + std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(getDialog(), + VclMessageType::Question, VclButtonsType::YesNo, SwResId(ST_DELETE_CONFIRM))); + if (xQuery->run() != RET_YES) + return; + + // Remove data source connection + SwDBManager::RevokeDataSource(m_xListLB->get_selected_text()); + // Remove item from the list + m_xListLB->remove(nEntry); + // If this was the last item, disable the Remove & Edit buttons and enable Create + if (m_xListLB->n_children() < 1 ) + { + m_xRemovePB->set_sensitive(false); + m_xEditPB->set_sensitive(false); + m_xFilterPB->set_sensitive(false); + m_xCreateListPB->set_sensitive(true); + } + + +} + +IMPL_LINK_NOARG(SwAddressListDialog, CreateHdl_Impl, weld::Button&, void) +{ + SwCreateAddressListDialog aDlg(m_xDialog.get(), /*sInputURL*/OUString(), m_pAddressPage->GetWizard()->GetConfigItem()); + if (RET_OK != aDlg.run()) + return; + + //register the URL a new datasource + const OUString sURL = aDlg.GetURL(); + try + { + uno::Reference<XInterface> xNewInstance = m_xDBContext->createInstance(); + INetURLObject aURL( sURL ); + const OUString sNewName = aURL.getBase(); + //find a unique name if sNewName already exists + OUString sFind(sNewName); + sal_Int32 nIndex = 0; + while(m_xDBContext->hasByName(sFind)) + { + sFind = sNewName + OUString::number(++nIndex); + } + uno::Reference<XPropertySet> xDataProperties(xNewInstance, UNO_QUERY); + + //only the 'path' has to be added + INetURLObject aTempURL(aURL); + aTempURL.removeSegment(); + aTempURL.removeFinalSlash(); + const OUString sDBURL("sdbc:flat:" + aTempURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)); + xDataProperties->setPropertyValue("URL", Any(sDBURL)); + //set the filter to the file name without extension + uno::Sequence<OUString> aFilters { sNewName }; + xDataProperties->setPropertyValue("TableFilter", Any(aFilters)); + + uno::Sequence<PropertyValue> aInfo + { + comphelper::makePropertyValue("FieldDelimiter", OUString('\t')), + comphelper::makePropertyValue("StringDelimiter", OUString('"')), + comphelper::makePropertyValue("Extension", aURL.getExtension()), //"csv + comphelper::makePropertyValue("CharSet", OUString("UTF-8")) + }; + xDataProperties->setPropertyValue("Info", Any(aInfo)); + + uno::Reference<sdb::XDocumentDataSource> xDS(xNewInstance, UNO_QUERY_THROW); + uno::Reference<frame::XStorable> xStore(xDS->getDatabaseDocument(), UNO_QUERY_THROW); + OUString sTmpName; + { + OUString sHomePath(SvtPathOptions().GetWorkPath()); + utl::TempFileNamed aTempFile(sFind, true, u".odb", &sHomePath); + aTempFile.EnableKillingFile(); + sTmpName = aTempFile.GetURL(); + } + xStore->storeAsURL(sTmpName, Sequence< PropertyValue >()); + + m_xDBContext->registerObject( sFind, xNewInstance ); + //now insert the new source into the ListBox + m_xListLB->append(m_xIter.get()); + m_xListLB->set_text(*m_xIter, sFind, 0); + m_xListLB->set_text(*m_xIter, aFilters[0], 1); + m_aUserData.emplace_back(new AddressUserData_Impl); + AddressUserData_Impl* pUserData = m_aUserData.back().get(); + m_xListLB->set_id(*m_xIter, weld::toId(pUserData)); + m_xListLB->select(*m_xIter); + ListBoxSelectHdl_Impl(*m_xListLB); + m_xCreateListPB->set_sensitive(false); + m_xRemovePB->set_sensitive(true); + } + catch (const Exception&) + { + } +} + +IMPL_LINK_NOARG(SwAddressListDialog, EditHdl_Impl, weld::Button&, void) +{ + int nEntry = m_xListLB->get_selected_index(); + AddressUserData_Impl* pUserData = nEntry != -1 ? weld::fromId<AddressUserData_Impl*>(m_xListLB->get_id(nEntry)) : nullptr; + if (!pUserData || pUserData->sURL.isEmpty()) + return; + + if(pUserData->xResultSet.is()) + { + SwMailMergeConfigItem& rConfigItem = m_pAddressPage->GetWizard()->GetConfigItem(); + if(rConfigItem.GetResultSet() != pUserData->xResultSet) + ::comphelper::disposeComponent( pUserData->xResultSet ); + pUserData->xResultSet = nullptr; + + rConfigItem.DisposeResultSet(); + } + pUserData->xSource.clear(); + pUserData->xColumnsSupplier.clear(); + pUserData->xConnection.clear(); + // will automatically close if it was the las reference + SwCreateAddressListDialog aDlg(m_xDialog.get(), pUserData->sURL, + m_pAddressPage->GetWizard()->GetConfigItem()); + aDlg.run(); +}; + +IMPL_LINK_NOARG(SwAddressListDialog, ListBoxSelectHdl_Impl, weld::TreeView&, void) +{ + int nSelect = m_xListLB->get_selected_index(); + Application::PostUserEvent( LINK( this, SwAddressListDialog, + StaticListBoxSelectHdl_Impl ), reinterpret_cast<void*>(nSelect) ); +} + +IMPL_LINK(SwAddressListDialog, StaticListBoxSelectHdl_Impl, void*, p, void) +{ + int nSelect = reinterpret_cast<sal_IntPtr>(p); + //prevent nested calls of the select handler + if (m_bInSelectHdl) + return; + weld::WaitObject aWait(m_xDialog.get()); + m_bInSelectHdl = true; + AddressUserData_Impl* pUserData = nullptr; + if (nSelect != -1) + { + const OUString sTable(m_xListLB->get_text(nSelect, 1)); + if (sTable.isEmpty()) + { + m_xListLB->set_text(nSelect, m_sConnecting, 1); + } + + pUserData = weld::fromId<AddressUserData_Impl*>(m_xListLB->get_id(nSelect)); + if(pUserData->nTableAndQueryCount > 1 || pUserData->nTableAndQueryCount == -1) + { + DetectTablesAndQueries(nSelect, sTable.isEmpty()); + } + else + { + //otherwise set the selected db-data + m_aDBData.sDataSource = m_xListLB->get_text(nSelect, 0); + m_aDBData.sCommand = m_xListLB->get_text(nSelect, 1); + m_aDBData.nCommandType = pUserData->nCommandType; + m_xOK->set_sensitive(true); + } + if (m_xListLB->get_text(nSelect, 1) == m_sConnecting) + m_xListLB->set_text(nSelect, OUString(), 1); + } + m_xEditPB->set_sensitive(pUserData && !pUserData->sURL.isEmpty() && + SWUnoHelper::UCB_IsFile( pUserData->sURL ) && //#i97577# + !SWUnoHelper::UCB_IsReadOnlyFileName( pUserData->sURL ) ); + m_bInSelectHdl = false; +} + +// detect the number of tables for a data source +// if only one is available then set it at the entry +void SwAddressListDialog::DetectTablesAndQueries( + int nSelect, + bool bWidthDialog) +{ + try + { + AddressUserData_Impl* pUserData = weld::fromId<AddressUserData_Impl*>(m_xListLB->get_id(nSelect)); + uno::Reference<XCompletedConnection> xComplConnection; + if(!pUserData->xConnection.is()) + { + m_aDBData.sDataSource = m_xListLB->get_text(nSelect, 0); + m_xDBContext->getByName(m_aDBData.sDataSource) >>= xComplConnection; + pUserData->xSource.set(xComplConnection, UNO_QUERY); + + uno::Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + uno::Reference< XInteractionHandler > xHandler = InteractionHandler::createWithParent(xContext, nullptr); + pUserData->xConnection = SharedConnection( xComplConnection->connectWithCompletion( xHandler ) ); + } + if(pUserData->xConnection.is()) + { + sal_Int32 nTables = 0; + uno::Sequence<OUString> aTables; + uno::Sequence<OUString> aQueries; + uno::Reference<XTablesSupplier> xTSupplier(pUserData->xConnection, UNO_QUERY); + if(xTSupplier.is()) + { + uno::Reference<XNameAccess> xTables = xTSupplier->getTables(); + aTables = xTables->getElementNames(); + nTables += aTables.getLength(); + } + uno::Reference<XQueriesSupplier> xQSupplier(pUserData->xConnection, UNO_QUERY); + if(xQSupplier.is()) + { + uno::Reference<XNameAccess> xQueries = xQSupplier->getQueries(); + aQueries = xQueries->getElementNames(); + nTables += aQueries.getLength(); + } + pUserData->nTableAndQueryCount = nTables; + if(nTables > 1 && bWidthDialog) + { + //now call the table select dialog - if more than one table exists + SwSelectDBTableDialog aDlg(m_xDialog.get(), pUserData->xConnection); + const OUString sTable = m_xListLB->get_text(nSelect, 1); + if(!sTable.isEmpty()) + aDlg.SetSelectedTable(sTable, pUserData->nCommandType == CommandType::TABLE); + if(RET_OK == aDlg.run()) + { + bool bIsTable; + m_aDBData.sCommand = aDlg.GetSelectedTable(bIsTable); + m_aDBData.nCommandType = bIsTable ? CommandType::TABLE : CommandType::QUERY; + pUserData->nCommandType = m_aDBData.nCommandType; + } + } + else if(nTables == 1) + { + if(aTables.hasElements()) + { + m_aDBData.sCommand = aTables[0]; + m_aDBData.nCommandType = CommandType::TABLE; + } + else + { + m_aDBData.sCommand = aQueries[0]; + m_aDBData.nCommandType = CommandType::QUERY; + } + } + } + if ( !m_aDBData.sCommand.isEmpty() ) + { + uno::Reference<beans::XPropertySet> xSourceProperties; + m_xDBContext->getByName(m_aDBData.sDataSource) >>= xSourceProperties; + pUserData->sURL = lcl_getFlatURL( xSourceProperties ); + + pUserData->xColumnsSupplier = SwDBManager::GetColumnSupplier(pUserData->xConnection, + m_aDBData.sCommand, + m_aDBData.nCommandType == CommandType::TABLE ? + SwDBSelect::TABLE : SwDBSelect::QUERY ); + //#i97577# + if( pUserData->xColumnsSupplier.is() ) + m_xListLB->set_text(nSelect, m_aDBData.sCommand, 1); + else + m_xListLB->set_text(nSelect, OUString(), 1); + } + const OUString sCommand = m_xListLB->get_text(nSelect, 1); + m_xOK->set_sensitive(!sCommand.isEmpty()); + m_xFilterPB->set_sensitive( pUserData->xConnection.is() && !sCommand.isEmpty() ); + m_xTablePB->set_sensitive( pUserData->nTableAndQueryCount > 1 ); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "sw", "exception caught in SwAddressListDialog::DetectTablesAndQueries"); + m_xOK->set_sensitive(false); + } +} + +IMPL_LINK(SwAddressListDialog, TableSelectHdl_Impl, weld::Button&, rButton, void) +{ + TableSelectHdl(&rButton); +} + +void SwAddressListDialog::TableSelectHdl(const weld::Button* pButton) +{ + weld::WaitObject aWait(m_xDialog.get()); + + int nSelect = m_xListLB->get_selected_index(); + if (nSelect != -1) + { + AddressUserData_Impl* pUserData = weld::fromId<AddressUserData_Impl*>(m_xListLB->get_id(nSelect)); + //only call the table select dialog if tables have not been searched for or there + //are more than 1 + const OUString sTable = m_xListLB->get_text(nSelect, 1); + if( pUserData->nTableAndQueryCount > 1 || pUserData->nTableAndQueryCount == -1) + { + DetectTablesAndQueries(nSelect, (pButton != nullptr) || sTable.isEmpty()); + } + } +} + +IMPL_LINK_NOARG(SwAddressListDialog, OKHdl_Impl, weld::Button&, void) +{ + m_xDialog->response(RET_OK); +} + +uno::Reference< XDataSource> SwAddressListDialog::GetSource() const +{ + uno::Reference< XDataSource> xRet; + int nSelect = m_xListLB->get_selected_index(); + if (nSelect != -1) + { + AddressUserData_Impl* pUserData = weld::fromId<AddressUserData_Impl*>(m_xListLB->get_id(nSelect)); + xRet = pUserData->xSource; + } + return xRet; + +} + +SharedConnection SwAddressListDialog::GetConnection() const +{ + SharedConnection xRet; + int nSelect = m_xListLB->get_selected_index(); + if (nSelect != -1) + { + AddressUserData_Impl* pUserData = weld::fromId<AddressUserData_Impl*>(m_xListLB->get_id(nSelect)); + xRet = pUserData->xConnection; + } + return xRet; +} + +uno::Reference< XColumnsSupplier> SwAddressListDialog::GetColumnsSupplier() const +{ + uno::Reference< XColumnsSupplier> xRet; + int nSelect = m_xListLB->get_selected_index(); + if (nSelect != -1) + { + AddressUserData_Impl* pUserData = weld::fromId<AddressUserData_Impl*>(m_xListLB->get_id(nSelect)); + xRet = pUserData->xColumnsSupplier; + } + return xRet; +} + +OUString SwAddressListDialog::GetFilter() const +{ + int nSelect = m_xListLB->get_selected_index(); + if (nSelect != -1) + { + AddressUserData_Impl* pUserData = weld::fromId<AddressUserData_Impl*>(m_xListLB->get_id(nSelect)); + return pUserData->sFilter; + } + return OUString(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/addresslistdialog.hxx b/sw/source/ui/dbui/addresslistdialog.hxx new file mode 100644 index 0000000000..dc0873af00 --- /dev/null +++ b/sw/source/ui/dbui/addresslistdialog.hxx @@ -0,0 +1,101 @@ +/* -*- 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_DBUI_ADDRESSLISTDIALOG_HXX +#define INCLUDED_SW_SOURCE_UI_DBUI_ADDRESSLISTDIALOG_HXX + +#include <sfx2/basedlgs.hxx> +#include <swdbdata.hxx> +#include <sharedconnection.hxx> + +namespace com::sun::star{ + namespace container{ + class XNameAccess; + } + namespace sdb{ + class XDatabaseContext; + } + namespace sdbc{ + class XDataSource; + } + namespace sdbcx{ + class XColumnsSupplier; + } +} +class SwMailMergeAddressBlockPage; + +struct AddressUserData_Impl; + +class SwAddressListDialog : public SfxDialogController +{ + OUString m_sConnecting; + + bool m_bInSelectHdl; + + SwMailMergeAddressBlockPage* m_pAddressPage; + + css::uno::Reference< css::sdb::XDatabaseContext> m_xDBContext; + + SwDBData m_aDBData; + + std::vector<std::unique_ptr<AddressUserData_Impl>> m_aUserData; + + std::unique_ptr<weld::Label> m_xDescriptionFI; + std::unique_ptr<weld::Label> m_xConnecting; + std::unique_ptr<weld::TreeView> m_xListLB; + std::unique_ptr<weld::Button> m_xLoadListPB; + std::unique_ptr<weld::Button> m_xRemovePB; + std::unique_ptr<weld::Button> m_xCreateListPB; + std::unique_ptr<weld::Button> m_xFilterPB; + std::unique_ptr<weld::Button> m_xEditPB; + std::unique_ptr<weld::Button> m_xTablePB; + std::unique_ptr<weld::Button> m_xOK; + std::unique_ptr<weld::TreeIter> m_xIter; + + void DetectTablesAndQueries(int Select, bool bWidthDialog); + + DECL_LINK(FilterHdl_Impl, weld::Button&, void); + DECL_LINK(LoadHdl_Impl, weld::Button&, void); + DECL_LINK(CreateHdl_Impl, weld::Button&, void); + DECL_LINK(RemoveHdl_Impl, weld::Button&, void); + DECL_LINK(ListBoxSelectHdl_Impl, weld::TreeView&, void); + DECL_LINK(EditHdl_Impl, weld::Button&, void); + DECL_LINK(TableSelectHdl_Impl, weld::Button&, void); + void TableSelectHdl(const weld::Button* pButton); + DECL_LINK(OKHdl_Impl, weld::Button&, void); + + DECL_LINK(StaticListBoxSelectHdl_Impl, void*, void); + +public: + SwAddressListDialog(SwMailMergeAddressBlockPage* pParent); + virtual ~SwAddressListDialog() override; + + css::uno::Reference< css::sdbc::XDataSource> + GetSource() const; + + SharedConnection GetConnection() const; + + css::uno::Reference< css::sdbcx::XColumnsSupplier> + GetColumnsSupplier() const; + + const SwDBData& GetDBData() const {return m_aDBData;} + OUString GetFilter() const; +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/createaddresslistdialog.cxx b/sw/source/ui/dbui/createaddresslistdialog.cxx new file mode 100644 index 0000000000..e6de5544ce --- /dev/null +++ b/sw/source/ui/dbui/createaddresslistdialog.cxx @@ -0,0 +1,590 @@ +/* -*- 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 <sal/config.h> + +#include <cstddef> + +#include <osl/diagnose.h> +#include <swtypes.hxx> +#include "createaddresslistdialog.hxx" +#include "customizeaddresslistdialog.hxx" +#include <mmconfigitem.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/docfile.hxx> +#include <rtl/textenc.h> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <tools/urlobj.hxx> +#include <o3tl/string_view.hxx> +#include <strings.hrc> +#include <map> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::ui::dialogs; + +namespace { + +struct SwAddressFragment +{ + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Label> m_xLabel; + std::unique_ptr<weld::Entry> m_xEntry; + weld::Container* m_pGrid; + + SwAddressFragment(weld::Container* pGrid, int nLine) + : m_xBuilder(Application::CreateBuilder(pGrid, "modules/swriter/ui/addressfragment.ui")) + , m_xLabel(m_xBuilder->weld_label("label")) + , m_xEntry(m_xBuilder->weld_entry("entry")) + , m_pGrid(pGrid) + { + m_xLabel->set_grid_left_attach(0); + m_xLabel->set_grid_top_attach(nLine); + + m_xEntry->set_grid_left_attach(1); + m_xEntry->set_grid_top_attach(nLine); + } + + ~SwAddressFragment() + { + m_pGrid->move(m_xEntry.get(), nullptr); + m_pGrid->move(m_xLabel.get(), nullptr); + } +}; + +} + +class SwAddressControl_Impl +{ + std::map<weld::Entry*, sal_Int32> m_aEditLines; + + SwCSVData* m_pData; + sal_uInt32 m_nCurrentDataSet; + + bool m_bNoDataSet; + + std::unique_ptr<weld::ScrolledWindow> m_xScrollBar; + std::unique_ptr<weld::Container> m_xWindow; + std::vector<std::unique_ptr<SwAddressFragment>> m_aLines; + + DECL_LINK(GotFocusHdl_Impl, weld::Widget&, void); + DECL_LINK(EditModifyHdl_Impl, weld::Entry&, void); + + void MakeVisible(const tools::Rectangle& aRect); + +public: + SwAddressControl_Impl(weld::Builder& rBuilder); + + void SetData(SwCSVData& rDBData); + + void SetCurrentDataSet(sal_uInt32 nSet); + void CurrentDataSetInvalidated() { m_nCurrentDataSet = std::numeric_limits<sal_uInt32>::max(); } + sal_uInt32 GetCurrentDataSet() const { return m_nCurrentDataSet; } + void SetCursorTo(std::size_t nElement); +}; + +SwAddressControl_Impl::SwAddressControl_Impl(weld::Builder& rBuilder) + : m_pData(nullptr) + , m_nCurrentDataSet(0) + , m_bNoDataSet(true) + , m_xScrollBar(rBuilder.weld_scrolled_window("scrollwin")) + , m_xWindow(rBuilder.weld_container("CONTAINER")) +{ +} + +void SwAddressControl_Impl::SetData(SwCSVData& rDBData) +{ + m_pData = &rDBData; + //when the address data is updated then remove the controls and build again + if (!m_aLines.empty()) + { + m_aLines.clear(); + m_bNoDataSet = true; + } + + Link<weld::Widget&,void> aFocusLink = LINK(this, SwAddressControl_Impl, GotFocusHdl_Impl); + Link<weld::Entry&,void> aEditModifyLink = LINK(this, SwAddressControl_Impl, EditModifyHdl_Impl); + sal_Int32 nLines = 0; + for (const auto& rHeader : m_pData->aDBColumnHeaders) + { + m_aLines.emplace_back(new SwAddressFragment(m_xWindow.get(), nLines)); + + // when we have one line, measure it to get the line height to use as + // the basis for overall size request + if (nLines == 0) + { + auto nLineHeight = m_xWindow->get_preferred_size().Height(); + m_xScrollBar->set_size_request(m_xScrollBar->get_approximate_digit_width() * 65, + nLineHeight * 10); + } + + weld::Label* pNewFT = m_aLines.back()->m_xLabel.get(); + weld::Entry* pNewED = m_aLines.back()->m_xEntry.get(); + //set nLines a position identifier - used in the ModifyHdl + m_aEditLines[pNewED] = nLines; + pNewED->connect_focus_in(aFocusLink); + pNewED->connect_changed(aEditModifyLink); + + pNewFT->set_label(rHeader); + + nLines++; + } +} + +void SwAddressControl_Impl::SetCurrentDataSet(sal_uInt32 nSet) +{ + if(!(m_bNoDataSet || m_nCurrentDataSet != nSet)) + return; + + m_bNoDataSet = false; + m_nCurrentDataSet = nSet; + OSL_ENSURE(m_pData->aDBData.size() > m_nCurrentDataSet, "wrong data set index"); + if(m_pData->aDBData.size() > m_nCurrentDataSet) + { + sal_uInt32 nIndex = 0; + for(auto& rLine : m_aLines) + { + OSL_ENSURE(nIndex < m_pData->aDBData[m_nCurrentDataSet].size(), + "number of columns doesn't match number of Edits"); + rLine->m_xEntry->set_text(m_pData->aDBData[m_nCurrentDataSet][nIndex]); + ++nIndex; + } + } +} + +IMPL_LINK(SwAddressControl_Impl, GotFocusHdl_Impl, weld::Widget&, rEdit, void) +{ + int x, y, width, height; + rEdit.get_extents_relative_to(*m_xWindow, x, y, width, height); + // the container has a border of 3 in the .ui + tools::Rectangle aRect(Point(x - 3, y - 3), Size(width + 6, height + 6)); + MakeVisible(aRect); +} + +void SwAddressControl_Impl::MakeVisible(const tools::Rectangle & rRect) +{ + //determine range of visible positions + auto nMinVisiblePos = m_xScrollBar->vadjustment_get_value(); + auto nMaxVisiblePos = nMinVisiblePos + m_xScrollBar->vadjustment_get_page_size(); + if (rRect.Top() < nMinVisiblePos || rRect.Bottom() > nMaxVisiblePos) + m_xScrollBar->vadjustment_set_value(rRect.Top()); +} + +// copy data changes into database +IMPL_LINK(SwAddressControl_Impl, EditModifyHdl_Impl, weld::Entry&, rEdit, void) +{ + //get the data element number of the current set + sal_Int32 nIndex = m_aEditLines[&rEdit]; + //get the index of the set + OSL_ENSURE(m_pData->aDBData.size() > m_nCurrentDataSet, "wrong data set index" ); + if (m_pData->aDBData.size() > m_nCurrentDataSet) + { + m_pData->aDBData[m_nCurrentDataSet][nIndex] = rEdit.get_text(); + } +} + +void SwAddressControl_Impl::SetCursorTo(std::size_t nElement) +{ + if (nElement < m_aLines.size()) + { + weld::Entry* pEdit = m_aLines[nElement]->m_xEntry.get(); + pEdit->grab_focus(); + } + +} + +SwCreateAddressListDialog::SwCreateAddressListDialog( + weld::Window* pParent, OUString aURL, SwMailMergeConfigItem const & rConfig) + : SfxDialogController(pParent, "modules/swriter/ui/createaddresslist.ui", "CreateAddressList") + , m_sAddressListFilterName(SwResId(ST_FILTERNAME)) + , m_sURL(std::move(aURL)) + , m_pCSVData(new SwCSVData) + , m_xAddressControl(new SwAddressControl_Impl(*m_xBuilder)) + , m_xNewPB(m_xBuilder->weld_button("NEW")) + , m_xDeletePB(m_xBuilder->weld_button("DELETE")) + , m_xFindPB(m_xBuilder->weld_button("FIND")) + , m_xCustomizePB(m_xBuilder->weld_button("CUSTOMIZE")) + , m_xStartPB(m_xBuilder->weld_button("START")) + , m_xPrevPB(m_xBuilder->weld_button("PREV")) + , m_xSetNoED(m_xBuilder->weld_entry("SETNOED")) + , m_xSetNoNF(m_xBuilder->weld_spin_button("SETNOSB")) + , m_xNextPB(m_xBuilder->weld_button("NEXT")) + , m_xEndPB(m_xBuilder->weld_button("END")) + , m_xOK(m_xBuilder->weld_button("ok")) +{ + m_xSetNoNF->set_min(1); + + m_xNewPB->connect_clicked(LINK(this, SwCreateAddressListDialog, NewHdl_Impl)); + m_xDeletePB->connect_clicked(LINK(this, SwCreateAddressListDialog, DeleteHdl_Impl)); + m_xFindPB->connect_clicked(LINK(this, SwCreateAddressListDialog, FindHdl_Impl)); + m_xCustomizePB->connect_clicked(LINK(this, SwCreateAddressListDialog, CustomizeHdl_Impl)); + m_xOK->connect_clicked(LINK(this, SwCreateAddressListDialog, OkHdl_Impl)); + + Link<weld::Button&,void> aLk = LINK(this, SwCreateAddressListDialog, DBCursorHdl_Impl); + m_xStartPB->connect_clicked(aLk); + m_xPrevPB->connect_clicked(aLk); + m_xSetNoED->connect_changed(LINK(this, SwCreateAddressListDialog, DBNumCursorHdl_Impl)); + m_xSetNoED->connect_focus_out(LINK(this, SwCreateAddressListDialog, RefreshNum_Impl)); + m_xNextPB->connect_clicked(aLk); + m_xEndPB->connect_clicked(aLk); + + if (!m_sURL.isEmpty()) + { + //file exists, has to be loaded here + SfxMedium aMedium( m_sURL, StreamMode::READ ); + SvStream* pStream = aMedium.GetInStream(); + if(pStream) + { + pStream->SetLineDelimiter( LINEEND_LF ); + pStream->SetStreamCharSet(RTL_TEXTENCODING_UTF8); + + OUString sLine; + bool bRead = pStream->ReadByteStringLine( sLine, RTL_TEXTENCODING_UTF8 ); + + if(bRead && !sLine.isEmpty()) + { + sal_Int32 nIndex = 0; + do + { + const std::u16string_view sHeader = o3tl::getToken(sLine, 0, '\t', nIndex ); + OSL_ENSURE(sHeader.size() > 2 && + o3tl::starts_with(sHeader, u"\"") && o3tl::ends_with(sHeader, u"\""), + "Wrong format of header"); + if(sHeader.size() > 2) + { + m_pCSVData->aDBColumnHeaders.push_back( OUString(sHeader.substr(1, sHeader.size() -2))); + } + } + while (nIndex > 0); + } + while(pStream->ReadByteStringLine( sLine, RTL_TEXTENCODING_UTF8 )) + { + std::vector<OUString> aNewData; + //analyze data line + sal_Int32 nIndex = { sLine.isEmpty() ? -1 : 0 }; + while (nIndex >= 0) + { + const OUString sData = sLine.getToken( 0, '\t', nIndex ); + OSL_ENSURE( sData.startsWith("\"") && sData.endsWith("\""), + "Wrong format of line"); + if(sData.getLength() >= 2) + aNewData.push_back(sData.copy(1, sData.getLength() - 2)); + else + aNewData.push_back(sData); + } + m_pCSVData->aDBData.push_back( aNewData ); + } + } + } + else + { + //database has to be created + const std::vector<std::pair<OUString, int>>& rAddressHeader = rConfig.GetDefaultAddressHeaders(); + const sal_uInt32 nCount = rAddressHeader.size(); + for(sal_uInt32 nHeader = 0; nHeader < nCount; ++nHeader) + m_pCSVData->aDBColumnHeaders.push_back(rAddressHeader[nHeader].first); + std::vector<OUString> aNewData; + aNewData.insert(aNewData.begin(), nCount, OUString()); + m_pCSVData->aDBData.push_back(aNewData); + } + //now fill the address control + m_xAddressControl->SetData(*m_pCSVData); + m_xAddressControl->SetCurrentDataSet(0); + m_xSetNoNF->set_max(m_pCSVData->aDBData.size()); + + m_xSetNoNF->set_value(1); + RefreshNum_Impl(*m_xSetNoED); + + UpdateButtons(); +} + +SwCreateAddressListDialog::~SwCreateAddressListDialog() +{ +} + +IMPL_LINK_NOARG(SwCreateAddressListDialog, NewHdl_Impl, weld::Button&, void) +{ + sal_uInt32 nCurrent = m_xAddressControl->GetCurrentDataSet(); + std::vector<OUString> aNewData; + aNewData.insert(aNewData.begin(), m_pCSVData->aDBColumnHeaders.size(), OUString()); + m_pCSVData->aDBData.insert(m_pCSVData->aDBData.begin() + ++nCurrent, aNewData); + m_xSetNoNF->set_max(m_pCSVData->aDBData.size()); + //the NumericField start at 1 + m_xSetNoNF->set_value(nCurrent + 1); + RefreshNum_Impl(*m_xSetNoED); + //the address control starts at 0 + m_xAddressControl->SetCurrentDataSet(nCurrent); + UpdateButtons(); +} + +IMPL_LINK_NOARG(SwCreateAddressListDialog, DeleteHdl_Impl, weld::Button&, void) +{ + sal_uInt32 nCurrent = m_xAddressControl->GetCurrentDataSet(); + if (m_pCSVData->aDBData.size() > 1) + { + m_pCSVData->aDBData.erase(m_pCSVData->aDBData.begin() + nCurrent); + if (nCurrent) + --nCurrent; + } + else + { + // if only one set is available then clear the data + m_pCSVData->aDBData[0].assign(m_pCSVData->aDBData[0].size(), OUString()); + m_xDeletePB->set_sensitive(false); + } + m_xAddressControl->CurrentDataSetInvalidated(); + m_xAddressControl->SetCurrentDataSet(nCurrent); + m_xSetNoNF->set_max(m_pCSVData->aDBData.size()); + UpdateButtons(); +} + +IMPL_LINK_NOARG(SwCreateAddressListDialog, FindHdl_Impl, weld::Button&, void) +{ + if (!m_xFindDlg) + { + m_xFindDlg.reset(new SwFindEntryDialog(this)); + weld::ComboBox& rColumnBox = m_xFindDlg->GetFieldsListBox(); + for(const auto& rHeader : m_pCSVData->aDBColumnHeaders) + rColumnBox.append_text(rHeader); + rColumnBox.set_active(0); + m_xFindDlg->show(); + } + else + m_xFindDlg->set_visible(!m_xFindDlg->get_visible()); +} + +IMPL_LINK_NOARG(SwCreateAddressListDialog, CustomizeHdl_Impl, weld::Button&, void) +{ + SwCustomizeAddressListDialog aDlg(m_xDialog.get(), *m_pCSVData); + if (aDlg.run() == RET_OK) + { + m_pCSVData = aDlg.ReleaseNewData(); + m_xAddressControl->SetData(*m_pCSVData); + m_xAddressControl->SetCurrentDataSet(m_xAddressControl->GetCurrentDataSet()); + } + + //update find dialog + if (m_xFindDlg) + { + weld::ComboBox& rColumnBox = m_xFindDlg->GetFieldsListBox(); + rColumnBox.clear(); + for(const auto& rHeader : m_pCSVData->aDBColumnHeaders) + rColumnBox.append_text(rHeader); + } +} + +namespace +{ + +void lcl_WriteValues(const std::vector<OUString> *pFields, SvStream* pStream) +{ + OUStringBuffer sLine; + const std::vector< OUString >::const_iterator aBegin = pFields->begin(); + const std::vector< OUString >::const_iterator aEnd = pFields->end(); + for(std::vector< OUString >::const_iterator aIter = aBegin; aIter != aEnd; ++aIter) + { + if (aIter==aBegin) + { + sLine.append("\"" + *aIter + "\""); + } + else + { + sLine.append("\t\"" + *aIter + "\""); + } + } + pStream->WriteByteStringLine( sLine, RTL_TEXTENCODING_UTF8 ); +} + +} + +IMPL_LINK_NOARG(SwCreateAddressListDialog, OkHdl_Impl, weld::Button&, void) +{ + if(m_sURL.isEmpty()) + { + sfx2::FileDialogHelper aDlgHelper(TemplateDescription::FILESAVE_SIMPLE, + FileDialogFlags::NONE, m_xDialog.get()); + aDlgHelper.SetContext(sfx2::FileDialogHelper::WriterCreateAddressList); + uno::Reference < XFilePicker3 > xFP = aDlgHelper.GetFilePicker(); + xFP->appendFilter( m_sAddressListFilterName, "*.csv" ); + xFP->setCurrentFilter( m_sAddressListFilterName ) ; + + if( ERRCODE_NONE == aDlgHelper.Execute() ) + { + m_sURL = xFP->getSelectedFiles().getConstArray()[0]; + INetURLObject aResult( m_sURL ); + aResult.setExtension(u"csv"); + m_sURL = aResult.GetMainURL(INetURLObject::DecodeMechanism::NONE); + } + } + if(m_sURL.isEmpty()) + return; + + SfxMedium aMedium( m_sURL, StreamMode::READWRITE|StreamMode::TRUNC ); + SvStream* pStream = aMedium.GetOutStream(); + pStream->SetLineDelimiter( LINEEND_LF ); + pStream->SetStreamCharSet(RTL_TEXTENCODING_UTF8); + + lcl_WriteValues(&(m_pCSVData->aDBColumnHeaders), pStream); + + for(const auto& rData : m_pCSVData->aDBData) + { + lcl_WriteValues(&rData, pStream); + } + aMedium.Commit(); + m_xDialog->response(RET_OK); +} + +IMPL_LINK(SwCreateAddressListDialog, DBCursorHdl_Impl, weld::Button&, rButton, void) +{ + int nValue = m_xSetNoNF->get_value(); + + if (&rButton == m_xStartPB.get()) + nValue = 1; + else if (&rButton == m_xPrevPB.get()) + { + if (nValue > 1) + --nValue; + } + else if (&rButton == m_xNextPB.get()) + { + if (nValue < m_xSetNoNF->get_max()) + ++nValue; + } + else //m_aEndPB + nValue = m_xSetNoNF->get_max(); + if (nValue != m_xSetNoNF->get_value()) + { + m_xSetNoNF->set_value(nValue); + RefreshNum_Impl(*m_xSetNoED); + DBNumCursor(); + } +} + +IMPL_LINK_NOARG(SwCreateAddressListDialog, DBNumCursorHdl_Impl, weld::Entry&, void) +{ + m_xSetNoNF->set_text(m_xSetNoED->get_text()); + DBNumCursor(); +} + +IMPL_LINK_NOARG(SwCreateAddressListDialog, RefreshNum_Impl, weld::Widget&, void) +{ + m_xSetNoED->set_text(OUString::number(m_xSetNoNF->get_value())); +} + +void SwCreateAddressListDialog::DBNumCursor() +{ + m_xAddressControl->SetCurrentDataSet(m_xSetNoNF->get_value() - 1); + UpdateButtons(); +} + +void SwCreateAddressListDialog::UpdateButtons() +{ + sal_uInt32 nCurrent = static_cast< sal_uInt32 >(m_xSetNoNF->get_value() ); + sal_uInt32 nSize = static_cast<sal_uInt32>(m_pCSVData->aDBData.size()); + m_xStartPB->set_sensitive(nCurrent != 1); + m_xPrevPB->set_sensitive(nCurrent != 1); + m_xNextPB->set_sensitive(nCurrent != nSize); + m_xEndPB->set_sensitive(nCurrent != nSize); + m_xDeletePB->set_sensitive(nSize > 0); +} + +void SwCreateAddressListDialog::Find(const OUString& rSearch, sal_Int32 nColumn) +{ + const OUString sSearch = rSearch.toAsciiLowerCase(); + sal_uInt32 nCurrent = m_xAddressControl->GetCurrentDataSet(); + //search forward + bool bFound = false; + sal_uInt32 nStart = nCurrent + 1; + sal_uInt32 nEnd = m_pCSVData->aDBData.size(); + std::size_t nElement = 0; + sal_uInt32 nPos = 0; + for(short nTemp = 0; nTemp < 2 && !bFound; nTemp++) + { + for(nPos = nStart; nPos < nEnd; ++nPos) + { + std::vector< OUString> const & aData = m_pCSVData->aDBData[nPos]; + if(nColumn >=0) + bFound = -1 != aData[static_cast<sal_uInt32>(nColumn)].toAsciiLowerCase().indexOf(sSearch); + else + { + for( nElement = 0; nElement < aData.size(); ++nElement) + { + bFound = -1 != aData[nElement].toAsciiLowerCase().indexOf(sSearch); + if(bFound) + { + nColumn = nElement; //TODO: std::size_t -> sal_Int32! + break; + } + } + } + if(bFound) + break; + } + nStart = 0; + nEnd = nCurrent + 1; + } + if(bFound) + { + m_xAddressControl->SetCurrentDataSet(nPos); + m_xSetNoNF->set_value( nPos + 1 ); + RefreshNum_Impl(*m_xSetNoED); + UpdateButtons(); + m_xAddressControl->SetCursorTo(nElement); + } +} + +SwFindEntryDialog::SwFindEntryDialog(SwCreateAddressListDialog* pParent) + : GenericDialogController(pParent->getDialog(), "modules/swriter/ui/findentrydialog.ui", "FindEntryDialog") + , m_pParent(pParent) + , m_xFindED(m_xBuilder->weld_entry("entry")) + , m_xFindOnlyCB(m_xBuilder->weld_check_button("findin")) + , m_xFindOnlyLB(m_xBuilder->weld_combo_box("area")) + , m_xFindPB(m_xBuilder->weld_button("find")) + , m_xCancel(m_xBuilder->weld_button("cancel")) +{ + m_xFindPB->connect_clicked(LINK(this, SwFindEntryDialog, FindHdl_Impl)); + m_xFindED->connect_changed(LINK(this, SwFindEntryDialog, FindEnableHdl_Impl)); + m_xCancel->connect_clicked(LINK(this, SwFindEntryDialog, CloseHdl_Impl)); +} + +SwFindEntryDialog::~SwFindEntryDialog() +{ +} + +IMPL_LINK_NOARG(SwFindEntryDialog, FindHdl_Impl, weld::Button&, void) +{ + sal_Int32 nColumn = -1; + if (m_xFindOnlyCB->get_active()) + nColumn = m_xFindOnlyLB->get_active(); + m_pParent->Find(m_xFindED->get_text(), nColumn); +} + +IMPL_LINK_NOARG(SwFindEntryDialog, FindEnableHdl_Impl, weld::Entry&, void) +{ + m_xFindPB->set_sensitive(!m_xFindED->get_text().isEmpty()); +} + +IMPL_LINK_NOARG(SwFindEntryDialog, CloseHdl_Impl, weld::Button&, void) +{ + m_xDialog->hide(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/createaddresslistdialog.hxx b/sw/source/ui/dbui/createaddresslistdialog.hxx new file mode 100644 index 0000000000..693dffed39 --- /dev/null +++ b/sw/source/ui/dbui/createaddresslistdialog.hxx @@ -0,0 +1,108 @@ +/* -*- 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_DBUI_CREATEADDRESSLISTDIALOG_HXX +#define INCLUDED_SW_SOURCE_UI_DBUI_CREATEADDRESSLISTDIALOG_HXX + +#include <sfx2/basedlgs.hxx> +#include <vcl/weld.hxx> +#include <vector> + +class SwAddressControl_Impl; +class SwMailMergeConfigItem; + +// container of the created database +struct SwCSVData +{ + std::vector< OUString > aDBColumnHeaders; + std::vector< std::vector< OUString> > aDBData; +}; + +class SwFindEntryDialog; +class SwCreateAddressListDialog : public SfxDialogController +{ + OUString m_sAddressListFilterName; + OUString m_sURL; + + std::unique_ptr<SwCSVData> m_pCSVData; + std::unique_ptr<SwFindEntryDialog> m_xFindDlg; + + std::unique_ptr<SwAddressControl_Impl> m_xAddressControl; + std::unique_ptr<weld::Button> m_xNewPB; + std::unique_ptr<weld::Button> m_xDeletePB; + std::unique_ptr<weld::Button> m_xFindPB; + std::unique_ptr<weld::Button> m_xCustomizePB; + std::unique_ptr<weld::Button> m_xStartPB; + std::unique_ptr<weld::Button> m_xPrevPB; + std::unique_ptr<weld::Entry> m_xSetNoED; + std::unique_ptr<weld::SpinButton> m_xSetNoNF; + std::unique_ptr<weld::Button> m_xNextPB; + std::unique_ptr<weld::Button> m_xEndPB; + std::unique_ptr<weld::Button> m_xOK; + + DECL_LINK(NewHdl_Impl, weld::Button&, void); + DECL_LINK(DeleteHdl_Impl, weld::Button&, void); + DECL_LINK(FindHdl_Impl, weld::Button&, void); + DECL_LINK(CustomizeHdl_Impl, weld::Button&, void); + DECL_LINK(OkHdl_Impl, weld::Button&, void); + DECL_LINK(DBCursorHdl_Impl, weld::Button&, void); + DECL_LINK(DBNumCursorHdl_Impl, weld::Entry&, void); + DECL_LINK(RefreshNum_Impl, weld::Widget&, void); + void DBNumCursor(); + + void UpdateButtons(); + +public: + SwCreateAddressListDialog(weld::Window* pParent, OUString aURL, SwMailMergeConfigItem const & rConfig); + virtual ~SwCreateAddressListDialog() override; + + const OUString& GetURL() const { return m_sURL; } + void Find( const OUString& rSearch, sal_Int32 nColumn); +}; + +class SwFindEntryDialog : public weld::GenericDialogController +{ + SwCreateAddressListDialog* m_pParent; + + std::unique_ptr<weld::Entry> m_xFindED; + std::unique_ptr<weld::CheckButton> m_xFindOnlyCB; + std::unique_ptr<weld::ComboBox> m_xFindOnlyLB; + std::unique_ptr<weld::Button> m_xFindPB; + std::unique_ptr<weld::Button> m_xCancel; + + DECL_LINK(FindHdl_Impl, weld::Button&, void); + DECL_LINK(FindEnableHdl_Impl, weld::Entry&, void); + DECL_LINK(CloseHdl_Impl, weld::Button&, void); + +public: + SwFindEntryDialog(SwCreateAddressListDialog* pParent); + virtual ~SwFindEntryDialog() override; + + void show() { m_xDialog->show(); } + void set_visible(bool bVisible) { m_xDialog->set_visible(bVisible); } + bool get_visible() const { return m_xDialog->get_visible(); } + + weld::ComboBox& GetFieldsListBox() + { + return *m_xFindOnlyLB; + } +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/customizeaddresslistdialog.cxx b/sw/source/ui/dbui/customizeaddresslistdialog.cxx new file mode 100644 index 0000000000..e80e75678c --- /dev/null +++ b/sw/source/ui/dbui/customizeaddresslistdialog.cxx @@ -0,0 +1,181 @@ +/* -*- 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 "customizeaddresslistdialog.hxx" +#include "createaddresslistdialog.hxx" + +SwCustomizeAddressListDialog::SwCustomizeAddressListDialog( + weld::Window* pParent, const SwCSVData& rOldData) + : SfxDialogController(pParent, "modules/swriter/ui/customizeaddrlistdialog.ui", + "CustomizeAddrListDialog") + , m_xNewData(new SwCSVData(rOldData)) + , m_xFieldsLB(m_xBuilder->weld_tree_view("treeview")) + , m_xAddPB(m_xBuilder->weld_button("add")) + , m_xDeletePB(m_xBuilder->weld_button("delete")) + , m_xRenamePB(m_xBuilder->weld_button("rename")) + , m_xUpPB(m_xBuilder->weld_button("up")) + , m_xDownPB(m_xBuilder->weld_button("down")) +{ + m_xFieldsLB->set_size_request(-1, m_xFieldsLB->get_height_rows(14)); + + m_xFieldsLB->connect_changed(LINK(this, SwCustomizeAddressListDialog, ListBoxSelectHdl_Impl)); + Link<weld::Button&,void> aAddRenameLk = LINK(this, SwCustomizeAddressListDialog, AddRenameHdl_Impl ); + m_xAddPB->connect_clicked(aAddRenameLk); + m_xRenamePB->connect_clicked(aAddRenameLk); + m_xDeletePB->connect_clicked(LINK(this, SwCustomizeAddressListDialog, DeleteHdl_Impl )); + Link<weld::Button&,void> aUpDownLk = LINK(this, SwCustomizeAddressListDialog, UpDownHdl_Impl); + m_xUpPB->connect_clicked(aUpDownLk); + m_xDownPB->connect_clicked(aUpDownLk); + + for (const auto& rHeader : m_xNewData->aDBColumnHeaders) + m_xFieldsLB->append_text(rHeader); + + m_xFieldsLB->select(0); + UpdateButtons(); +} + +SwCustomizeAddressListDialog::~SwCustomizeAddressListDialog() +{ +} + +IMPL_LINK_NOARG(SwCustomizeAddressListDialog, ListBoxSelectHdl_Impl, weld::TreeView&, void) +{ + UpdateButtons(); +} + +IMPL_LINK(SwCustomizeAddressListDialog, AddRenameHdl_Impl, weld::Button&, rButton, void) +{ + bool bRename = &rButton == m_xRenamePB.get(); + auto nPos = m_xFieldsLB->get_selected_index(); + if (nPos == -1) + nPos = 0; + + std::unique_ptr<SwAddRenameEntryDialog> xDlg; + if (bRename) + xDlg.reset(new SwRenameEntryDialog(m_xDialog.get(), m_xNewData->aDBColumnHeaders)); + else + xDlg.reset(new SwAddEntryDialog(m_xDialog.get(), m_xNewData->aDBColumnHeaders)); + if (bRename) + { + OUString aTemp = m_xFieldsLB->get_text(nPos); + xDlg->SetFieldName(aTemp); + } + if (xDlg->run() == RET_OK) + { + OUString sNew = xDlg->GetFieldName(); + if(bRename) + { + m_xNewData->aDBColumnHeaders[nPos] = sNew; + m_xFieldsLB->remove(nPos); + } + else + { + if (m_xFieldsLB->get_selected_index() != -1) + ++nPos; // append the new entry behind the selected + //add the new column + m_xNewData->aDBColumnHeaders.insert(m_xNewData->aDBColumnHeaders.begin() + nPos, sNew); + //add a new entry into all data arrays + for (auto& rData : m_xNewData->aDBData) + rData.insert(rData.begin() + nPos, OUString()); + + } + + m_xFieldsLB->insert_text(nPos, sNew); + m_xFieldsLB->select(nPos); + } + UpdateButtons(); +} + +IMPL_LINK_NOARG(SwCustomizeAddressListDialog, DeleteHdl_Impl, weld::Button&, void) +{ + auto nPos = m_xFieldsLB->get_selected_index(); + m_xFieldsLB->remove(nPos); + m_xFieldsLB->select(nPos > m_xFieldsLB->n_children() - 1 ? nPos - 1 : nPos); + + //remove the column + m_xNewData->aDBColumnHeaders.erase(m_xNewData->aDBColumnHeaders.begin() + nPos); + //remove the data + for (auto& rData : m_xNewData->aDBData) + rData.erase(rData.begin() + nPos); + + UpdateButtons(); +} + +IMPL_LINK(SwCustomizeAddressListDialog, UpDownHdl_Impl, weld::Button&, rButton, void) +{ + auto nPos = m_xFieldsLB->get_selected_index(); + auto nOldPos = nPos; + OUString aTemp = m_xFieldsLB->get_text(nPos); + m_xFieldsLB->remove(nPos); + if (&rButton == m_xUpPB.get()) + --nPos; + else + ++nPos; + m_xFieldsLB->insert_text(nPos, aTemp); + m_xFieldsLB->select(nPos); + //align m_xNewData + OUString sHeader = m_xNewData->aDBColumnHeaders[nOldPos]; + m_xNewData->aDBColumnHeaders.erase(m_xNewData->aDBColumnHeaders.begin() + nOldPos); + m_xNewData->aDBColumnHeaders.insert(m_xNewData->aDBColumnHeaders.begin() + nPos, sHeader); + for (auto& rData : m_xNewData->aDBData) + { + OUString sData = rData[nOldPos]; + rData.erase(rData.begin() + nOldPos); + rData.insert(rData.begin() + nPos, sData); + } + + UpdateButtons(); +} + +void SwCustomizeAddressListDialog::UpdateButtons() +{ + auto nPos = m_xFieldsLB->get_selected_index(); + auto nEntries = m_xFieldsLB->n_children(); + m_xUpPB->set_sensitive(nPos > 0 && nEntries > 0); + m_xDownPB->set_sensitive(nPos < nEntries -1); + m_xDeletePB->set_sensitive(nEntries > 0); + m_xRenamePB->set_sensitive(nEntries > 0); +} + +SwAddRenameEntryDialog::SwAddRenameEntryDialog( + weld::Window* pParent, const OUString& rUIXMLDescription, const OUString& rID, + const std::vector< OUString >& rCSVHeader) + : SfxDialogController(pParent, rUIXMLDescription, rID) + , m_rCSVHeader(rCSVHeader) + , m_xFieldNameED(m_xBuilder->weld_entry("entry")) + , m_xOK(m_xBuilder->weld_button("ok")) +{ + m_xFieldNameED->connect_changed(LINK(this, SwAddRenameEntryDialog, ModifyHdl_Impl)); + ModifyHdl_Impl(*m_xFieldNameED); +} + +IMPL_LINK(SwAddRenameEntryDialog, ModifyHdl_Impl, weld::Entry&, rEdit, void) +{ + OUString sEntry = rEdit.get_text(); + bool bFound = sEntry.isEmpty(); + + if(!bFound) + { + bFound = std::any_of(m_rCSVHeader.begin(), m_rCSVHeader.end(), + [&sEntry](const OUString& rHeader) { return rHeader == sEntry; }); + } + m_xOK->set_sensitive(!bFound); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/customizeaddresslistdialog.hxx b/sw/source/ui/dbui/customizeaddresslistdialog.hxx new file mode 100644 index 0000000000..a683ccb829 --- /dev/null +++ b/sw/source/ui/dbui/customizeaddresslistdialog.hxx @@ -0,0 +1,91 @@ +/* -*- 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_DBUI_CUSTOMIZEADDRESSLISTDIALOG_HXX +#define INCLUDED_SW_SOURCE_UI_DBUI_CUSTOMIZEADDRESSLISTDIALOG_HXX + +#include <sfx2/basedlgs.hxx> +#include <vcl/weld.hxx> + +#include "createaddresslistdialog.hxx" + +struct SwCSVData; + +class SwCustomizeAddressListDialog : public SfxDialogController +{ + std::unique_ptr<SwCSVData> m_xNewData; + std::unique_ptr<weld::TreeView> m_xFieldsLB; + std::unique_ptr<weld::Button> m_xAddPB; + std::unique_ptr<weld::Button> m_xDeletePB; + std::unique_ptr<weld::Button> m_xRenamePB; + std::unique_ptr<weld::Button> m_xUpPB; + std::unique_ptr<weld::Button> m_xDownPB; + + DECL_LINK(AddRenameHdl_Impl, weld::Button&, void); + DECL_LINK(DeleteHdl_Impl, weld::Button&, void); + DECL_LINK(UpDownHdl_Impl, weld::Button&, void); + DECL_LINK(ListBoxSelectHdl_Impl, weld::TreeView&, void); + + void UpdateButtons(); +public: + SwCustomizeAddressListDialog(weld::Window* pParent, const SwCSVData& rOldData); + virtual ~SwCustomizeAddressListDialog() override; + + std::unique_ptr<SwCSVData> ReleaseNewData() { return std::move(m_xNewData);} +}; + +class SwAddRenameEntryDialog : public SfxDialogController +{ + const std::vector< OUString >& m_rCSVHeader; + std::unique_ptr<weld::Entry> m_xFieldNameED; + std::unique_ptr<weld::Button> m_xOK; + + DECL_LINK(ModifyHdl_Impl, weld::Entry&, void); +protected: + SwAddRenameEntryDialog(weld::Window* pParent, const OUString& rUIXMLDescription, + const OUString& rID, const std::vector< OUString >& rCSVHeader); + +public: + void SetFieldName(const OUString& rName) { m_xFieldNameED->set_text(rName); } + OUString GetFieldName() const { return m_xFieldNameED->get_text(); } + +}; + +class SwAddEntryDialog : public SwAddRenameEntryDialog +{ +public: + SwAddEntryDialog(weld::Window* pParent, const std::vector< OUString >& rCSVHeader) + : SwAddRenameEntryDialog(pParent, "modules/swriter/ui/addentrydialog.ui", + "AddEntryDialog", rCSVHeader) + { + } +}; + +class SwRenameEntryDialog : public SwAddRenameEntryDialog +{ +public: + SwRenameEntryDialog(weld::Window* pParent, const std::vector< OUString >& rCSVHeader) + : SwAddRenameEntryDialog(pParent, "modules/swriter/ui/renameentrydialog.ui", + "RenameEntryDialog", rCSVHeader) + { + } +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/dbinsdlg.cxx b/sw/source/ui/dbui/dbinsdlg.cxx new file mode 100644 index 0000000000..e6dac3049c --- /dev/null +++ b/sw/source/ui/dbui/dbinsdlg.cxx @@ -0,0 +1,1750 @@ +/* -*- 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 <dbinsdlg.hxx> + +#include <float.h> + +#include <hintids.hxx> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdb/XColumn.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/util/NumberFormatter.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/types.hxx> +#include <svl/numuno.hxx> +#include <svl/numformat.hxx> +#include <svl/stritem.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <utility> +#include <vcl/mnemonic.hxx> +#include <svl/style.hxx> +#include <svl/zformat.hxx> +#include <sfx2/htmlmode.hxx> +#include <svl/itemset.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/boxitem.hxx> +#include <unotools/collatorwrapper.hxx> +#include <fmtclds.hxx> +#include <tabcol.hxx> +#include <uiitems.hxx> +#include <viewopt.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <dbmgr.hxx> +#include <tblafmt.hxx> +#include <cellatr.hxx> +#include <swtablerep.hxx> +#include <dbfld.hxx> +#include <fmtcol.hxx> +#include <swwait.hxx> +#include <modcfg.hxx> +#include <swmodule.hxx> +#include <poolfmt.hxx> +#include <connectivity/dbtools.hxx> + +#include <cmdid.h> +#include <SwStyleNameMapper.hxx> +#include <tabsh.hxx> +#include <swabstdlg.hxx> +#include <strings.hrc> +#include <IDocumentMarkAccess.hxx> + +#include <o3tl/any.hxx> + +#include <memory> +#include <string_view> + +#include <swuiexp.hxx> + +using namespace ::dbtools; +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::uno; + +const char cDBFieldStart = '<'; +const char cDBFieldEnd = '>'; + +// Helper structure for adding database rows as fields or text +struct DB_Column +{ + const enum class Type { FILLTEXT, COL_FIELD, COL_TEXT, SPLITPARA } eColType; + + union { + OUString* pText; + SwField* pField; + sal_uInt32 nFormat; + }; + const SwInsDBColumn* pColInfo; + + DB_Column() : eColType(Type::SPLITPARA), + pText(nullptr), + pColInfo(nullptr) + {} + + explicit DB_Column( const OUString& rText ) + : eColType(Type::FILLTEXT), + pText(new OUString(rText)), + pColInfo(nullptr) + {} + + DB_Column( const SwInsDBColumn& rInfo, sal_uInt32 nFormat_ ) + : eColType(Type::COL_TEXT), + nFormat(nFormat_), + pColInfo(&rInfo) + {} + + DB_Column( const SwInsDBColumn& rInfo, SwDBField& rField ) + : eColType(Type::COL_FIELD), + pField(&rField), + pColInfo(&rInfo) + {} + + ~DB_Column() + { + if( Type::COL_FIELD == eColType ) + delete pField; + else if( Type::FILLTEXT == eColType ) + delete pText; + } +}; + +namespace { + +struct DB_ColumnConfigData +{ + SwInsDBColumns aDBColumns; + OUString sEdit; + OUString sTableList; + OUString sTmplNm; + OUString sTAutoFormatNm; + bool bIsTable : 1, + bIsField : 1, + bIsHeadlineOn : 1, + bIsEmptyHeadln : 1; + + DB_ColumnConfigData(DB_ColumnConfigData const&) = delete; + DB_ColumnConfigData& operator=(DB_ColumnConfigData const&) = delete; + + DB_ColumnConfigData() + { + bIsTable = bIsHeadlineOn = true; + bIsField = bIsEmptyHeadln = false; + } +}; + +} + +bool SwInsDBColumn::operator<( const SwInsDBColumn& rCmp ) const +{ + return 0 > GetAppCollator().compareString( sColumn, rCmp.sColumn ); +} + +SwInsertDBColAutoPilot::SwInsertDBColAutoPilot( SwView& rView, + Reference<XDataSource> const & xDataSource, + Reference<sdbcx::XColumnsSupplier> const & xColSupp, + SwDBData aData ) + : SfxDialogController(rView.GetWindow()->GetFrameWeld(), "modules/swriter/ui/insertdbcolumnsdialog.ui", "InsertDbColumnsDialog") + , ConfigItem("Office.Writer/InsertData/DataSet", ConfigItemMode::NONE) + , m_aDBData(std::move(aData)) + , m_sNoTmpl(SwResId(SW_STR_NONE)) + , m_pView(&rView) + , m_xRbAsTable(m_xBuilder->weld_radio_button("astable")) + , m_xRbAsField(m_xBuilder->weld_radio_button("asfields")) + , m_xRbAsText(m_xBuilder->weld_radio_button("astext")) + , m_xHeadFrame(m_xBuilder->weld_frame("dbframe")) + , m_xLbTableDbColumn(m_xBuilder->weld_tree_view("tabledbcols")) + , m_xLbTextDbColumn(m_xBuilder->weld_tree_view("tabletxtcols")) + , m_xFormatFrame(m_xBuilder->weld_frame("formatframe")) + , m_xRbDbFormatFromDb(m_xBuilder->weld_radio_button("fromdatabase")) + , m_xRbDbFormatFromUsr(m_xBuilder->weld_radio_button("userdefined")) + , m_xLbDbFormatFromUsr(new NumFormatListBox(m_xBuilder->weld_combo_box("numformat"))) + , m_xIbDbcolToEdit(m_xBuilder->weld_button("toedit")) + , m_xEdDbText(m_xBuilder->weld_text_view("textview")) + , m_xFtDbParaColl(m_xBuilder->weld_label("parastylelabel")) + , m_xLbDbParaColl(m_xBuilder->weld_combo_box("parastyle")) + , m_xIbDbcolAllTo(m_xBuilder->weld_button("oneright")) + , m_xIbDbcolOneTo(m_xBuilder->weld_button("allright")) + , m_xIbDbcolOneFrom(m_xBuilder->weld_button("oneleft")) + , m_xIbDbcolAllFrom(m_xBuilder->weld_button("allleft")) + , m_xFtTableCol(m_xBuilder->weld_label("tablecolft")) + , m_xLbTableCol(m_xBuilder->weld_tree_view("tablecols")) + , m_xCbTableHeadon(m_xBuilder->weld_check_button("tableheading")) + , m_xRbHeadlColnms(m_xBuilder->weld_radio_button("columnname")) + , m_xRbHeadlEmpty(m_xBuilder->weld_radio_button("rowonly")) + , m_xPbTableFormat(m_xBuilder->weld_button("tableformat")) + , m_xPbTableAutofmt(m_xBuilder->weld_button("autoformat")) +{ + m_xEdDbText->set_size_request(m_xEdDbText->get_approximate_digit_width() * 40, -1); + m_xLbDbParaColl->make_sorted(); + + m_nGBFormatLen = m_xFormatFrame->get_label().getLength(); + + if (xColSupp.is()) + { + SwWrtShell& rSh = m_pView->GetWrtShell(); + SvNumberFormatter* pNumFormatr = rSh.GetNumberFormatter(); + rtl::Reference<SvNumberFormatsSupplierObj> pNumFormat = new SvNumberFormatsSupplierObj( pNumFormatr ); + Reference< util::XNumberFormats > xDocNumberFormats = pNumFormat->getNumberFormats(); + Reference< util::XNumberFormatTypes > xDocNumberFormatTypes(xDocNumberFormats, UNO_QUERY); + + Reference<XPropertySet> xSourceProps(xDataSource, UNO_QUERY); + Reference< util::XNumberFormats > xNumberFormats; + if(xSourceProps.is()) + { + Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier"); + if(aFormats.hasValue()) + { + Reference< util::XNumberFormatsSupplier> xSuppl; + aFormats >>= xSuppl; + if(xSuppl.is()) + { + xNumberFormats = xSuppl->getNumberFormats( ); + } + } + } + Reference <XNameAccess> xCols = xColSupp->getColumns(); + const Sequence<OUString> aColNames = xCols->getElementNames(); + for (const OUString& rColName : aColNames) + { + std::unique_ptr<SwInsDBColumn> pNew(new SwInsDBColumn( rColName )); + Any aCol = xCols->getByName(rColName); + Reference <XPropertySet> xCol; + aCol >>= xCol; + Any aType = xCol->getPropertyValue("Type"); + sal_Int32 eDataType = 0; + aType >>= eDataType; + switch(eDataType) + { + case DataType::BIT: + case DataType::BOOLEAN: + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::BIGINT: + case DataType::FLOAT: + case DataType::REAL: + case DataType::DOUBLE: + case DataType::NUMERIC: + case DataType::DECIMAL: + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + { + pNew->bHasFormat = true; + Any aFormat = xCol->getPropertyValue("FormatKey"); + if(aFormat.hasValue()) + { + sal_Int32 nFormat = 0; + aFormat >>= nFormat; + if(xNumberFormats.is()) + { + try + { + Reference<XPropertySet> xNumProps = xNumberFormats->getByKey( nFormat ); + Any aFormatVal = xNumProps->getPropertyValue("FormatString"); + Any aLocale = xNumProps->getPropertyValue("Locale"); + OUString sFormat; + aFormatVal >>= sFormat; + lang::Locale aLoc; + aLocale >>= aLoc; + sal_Int32 nKey = xDocNumberFormats->queryKey( sFormat, aLoc, true); + if(nKey < 0) + { + nKey = xDocNumberFormats->addNew( sFormat, aLoc ); + } + pNew->nDBNumFormat = nKey; + } + catch (const Exception&) + { + OSL_FAIL("illegal number format key"); + } + } + } + else + { + pNew->nDBNumFormat = getDefaultNumberFormat(xCol, + xDocNumberFormatTypes, LanguageTag( rSh.GetCurLang() ).getLocale()); + } + + } + break; + } + if( !m_aDBColumns.insert( std::move(pNew) ).second ) + { + OSL_ENSURE( false, "Spaltenname mehrfach vergeben?" ); + } + } + } + + // fill paragraph templates-ListBox + { + SfxStyleSheetBasePool* pPool = m_pView->GetDocShell()->GetStyleSheetPool(); + m_xLbDbParaColl->append_text( m_sNoTmpl ); + + const SfxStyleSheetBase* pBase = pPool->First(SfxStyleFamily::Para); + while( pBase ) + { + m_xLbDbParaColl->append_text( pBase->GetName() ); + pBase = pPool->Next(); + } + m_xLbDbParaColl->set_active( 0 ); + } + + // when the cursor is inside of a table, table must NEVER be selectable + if( m_pView->GetWrtShell().GetTableFormat() ) + { + m_xRbAsField->set_active(true); + m_xRbAsTable->set_sensitive(false); + m_xRbDbFormatFromDb->set_active(true); + } + else + { + m_xRbAsTable->set_active(true); + m_xRbDbFormatFromDb->set_active(true); + m_xIbDbcolOneFrom->set_sensitive( false ); + m_xIbDbcolAllFrom->set_sensitive( false ); + } + + // by default, select header button + m_xRbHeadlColnms->set_active(true); + m_xRbHeadlEmpty->set_active(false); + + m_xRbAsTable->connect_toggled( LINK(this, SwInsertDBColAutoPilot, PageHdl )); + m_xRbAsField->connect_toggled( LINK(this, SwInsertDBColAutoPilot, PageHdl )); + m_xRbAsText->connect_toggled( LINK(this, SwInsertDBColAutoPilot, PageHdl )); + + m_xRbDbFormatFromDb->connect_toggled( LINK(this, SwInsertDBColAutoPilot, DBFormatHdl )); + m_xRbDbFormatFromUsr->connect_toggled( LINK(this, SwInsertDBColAutoPilot, DBFormatHdl )); + + m_xPbTableFormat->connect_clicked(LINK(this, SwInsertDBColAutoPilot, TableFormatHdl )); + m_xPbTableAutofmt->connect_clicked(LINK(this, SwInsertDBColAutoPilot, AutoFormatHdl )); + + m_xIbDbcolAllTo->connect_clicked( LINK(this, SwInsertDBColAutoPilot, TableToFromHdl )); + m_xIbDbcolOneTo->connect_clicked( LINK(this, SwInsertDBColAutoPilot, TableToFromHdl )); + m_xIbDbcolOneFrom->connect_clicked( LINK(this, SwInsertDBColAutoPilot, TableToFromHdl )); + m_xIbDbcolAllFrom->connect_clicked( LINK(this, SwInsertDBColAutoPilot, TableToFromHdl )); + m_xIbDbcolToEdit->connect_clicked( LINK(this, SwInsertDBColAutoPilot, TableToFromHdl )); + + m_xCbTableHeadon->connect_toggled( LINK(this, SwInsertDBColAutoPilot, HeaderHdl )); + + m_xLbTextDbColumn->connect_changed( LINK( this, SwInsertDBColAutoPilot, TVSelectHdl )); + m_xLbTableDbColumn->connect_changed( LINK( this, SwInsertDBColAutoPilot, TVSelectHdl )); + m_xLbDbFormatFromUsr->connect_changed( LINK( this, SwInsertDBColAutoPilot, CBSelectHdl )); + m_xLbTableCol->connect_changed( LINK( this, SwInsertDBColAutoPilot, TVSelectHdl )); + + m_xLbTextDbColumn->connect_row_activated( LINK( this, SwInsertDBColAutoPilot, DblClickHdl )); + m_xLbTableDbColumn->connect_row_activated( LINK( this, SwInsertDBColAutoPilot, DblClickHdl )); + m_xLbTableCol->connect_row_activated( LINK( this, SwInsertDBColAutoPilot, DblClickHdl )); + + for( size_t n = 0; n < m_aDBColumns.size(); ++n ) + { + const OUString& rS = m_aDBColumns[ n ]->sColumn; + m_xLbTableDbColumn->append_text(rS); + m_xLbTextDbColumn->append_text(rS); + } + m_xLbTextDbColumn->select(0); + m_xLbTableDbColumn->select(0); + + // read configuration + Load(); + + // lock size to widest config + m_xHeadFrame->set_size_request(m_xHeadFrame->get_preferred_size().Width(), -1); + // initialise Controls: + PageHdl(m_xRbAsTable->get_active() ? *m_xRbAsTable : *m_xRbAsField); +} + +SwInsertDBColAutoPilot::~SwInsertDBColAutoPilot() +{ +} + +IMPL_LINK( SwInsertDBColAutoPilot, PageHdl, weld::Toggleable&, rButton, void ) +{ + if (!rButton.get_active()) + return; + + bool bShowTable = m_xRbAsTable->get_active(); + + weld::RadioButton& rRadio = dynamic_cast<weld::RadioButton&>(rButton); + m_xHeadFrame->set_label(MnemonicGenerator::EraseAllMnemonicChars(rRadio.get_label().replace('_', '~'))); + + m_xLbTextDbColumn->set_visible( !bShowTable ); + m_xIbDbcolToEdit->set_visible( !bShowTable ); + m_xEdDbText->set_visible( !bShowTable ); + m_xFtDbParaColl->set_visible( !bShowTable ); + m_xLbDbParaColl->set_visible( !bShowTable ); + + m_xLbTableDbColumn->set_visible( bShowTable ); + m_xIbDbcolAllTo->set_visible( bShowTable ); + m_xIbDbcolOneTo->set_visible( bShowTable ); + m_xIbDbcolOneFrom->set_visible( bShowTable ); + m_xIbDbcolAllFrom->set_visible( bShowTable ); + m_xFtTableCol->set_visible( bShowTable ); + m_xLbTableCol->set_visible( bShowTable ); + m_xCbTableHeadon->set_visible( bShowTable ); + m_xRbHeadlColnms->set_visible( bShowTable ); + m_xRbHeadlEmpty->set_visible( bShowTable ); + m_xPbTableFormat->set_visible( bShowTable ); + m_xPbTableAutofmt->set_visible( bShowTable ); + + if( bShowTable ) + m_xPbTableFormat->set_sensitive( 0 != m_xLbTableCol->n_children() ); + + TVSelectHdl( bShowTable ? *m_xLbTableDbColumn : *m_xLbTextDbColumn ); +} + +IMPL_LINK( SwInsertDBColAutoPilot, DBFormatHdl, weld::Toggleable&, rButton, void ) +{ + if (!rButton.get_active()) + return; + + weld::TreeView& rBox = m_xRbAsTable->get_active() + ? ( m_xLbTableCol->get_id(0).isEmpty() + ? *m_xLbTableDbColumn + : *m_xLbTableCol ) + : *m_xLbTextDbColumn; + + SwInsDBColumn aSrch(rBox.get_selected_text()); + SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch ); + + bool bFromDB = m_xRbDbFormatFromDb->get_active(); + (*it)->bIsDBFormat = bFromDB; + m_xLbDbFormatFromUsr->set_sensitive( !bFromDB ); +} + +IMPL_LINK( SwInsertDBColAutoPilot, TableToFromHdl, weld::Button&, rButton, void ) +{ + bool bChgEnable = true, bEnableTo = true, bEnableFrom = true; + + if( &rButton == m_xIbDbcolAllTo.get() ) + { + bEnableTo = false; + + sal_Int32 n, nInsPos = m_xLbTableCol->get_selected_index(), + nCnt = m_xLbTableDbColumn->n_children(); + + m_xLbTableDbColumn->unselect_all(); + + m_xLbTableDbColumn->freeze(); + m_xLbTableCol->freeze(); + + if (nInsPos == -1) + for( n = 0; n < nCnt; ++n ) + m_xLbTableCol->append_text(m_xLbTableDbColumn->get_text(n)); + else + for( n = 0; n < nCnt; ++n, ++nInsPos ) + m_xLbTableCol->insert_text(nInsPos, m_xLbTableDbColumn->get_text(n)); + m_xLbTableDbColumn->clear(); + + m_xLbTableDbColumn->thaw(); + m_xLbTableCol->thaw(); + + m_xLbTableCol->select(nInsPos); + } + else if( &rButton == m_xIbDbcolOneTo.get() && + m_xLbTableDbColumn->get_selected_index() != -1 ) + { + sal_Int32 nInsPos = m_xLbTableCol->get_selected_index(), + nDelPos = m_xLbTableDbColumn->get_selected_index(); + m_xLbTableCol->insert_text(nInsPos, m_xLbTableDbColumn->get_text(nDelPos)); + m_xLbTableDbColumn->remove(nDelPos); + + m_xLbTableCol->select(nInsPos); + if (nDelPos >= m_xLbTableDbColumn->n_children()) + nDelPos = m_xLbTableDbColumn->n_children() - 1; + m_xLbTableDbColumn->select(nDelPos); + + bEnableTo = 0 != m_xLbTableDbColumn->n_children(); + } + else if( &rButton == m_xIbDbcolOneFrom.get() ) + { + if (m_xLbTableCol->get_selected_index() != -1) + { + sal_Int32 nInsPos, + nDelPos = m_xLbTableCol->get_selected_index(); + + // look for the right InsertPos!! + SwInsDBColumn aSrch(m_xLbTableCol->get_text(nDelPos)); + SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch ); + if( it == m_aDBColumns.begin() || (it+1) == m_aDBColumns.end() ) + nInsPos = it - m_aDBColumns.begin(); + else + { + nInsPos = -1; + while( ++it != m_aDBColumns.end() && + -1 == (nInsPos = m_xLbTableDbColumn-> + find_text( (*it)->sColumn )) ) + ; + } + + m_xLbTableDbColumn->insert_text(nInsPos, aSrch.sColumn); + m_xLbTableCol->remove( nDelPos ); + + if (nInsPos >= m_xLbTableDbColumn->n_children()) + nInsPos = m_xLbTableDbColumn->n_children() - 1; + m_xLbTableDbColumn->select(nInsPos); + + if (nDelPos >= m_xLbTableCol->n_children()) + nDelPos = m_xLbTableCol->n_children() - 1; + m_xLbTableCol->select(nDelPos); + } + else + bEnableTo = 0 != m_xLbTableDbColumn->n_children(); + + bEnableFrom = 0 != m_xLbTableCol->n_children(); + } + else if( &rButton == m_xIbDbcolAllFrom.get() ) + { + bEnableFrom = false; + + m_xLbTableDbColumn->freeze(); + m_xLbTableCol->freeze(); + + m_xLbTableDbColumn->clear(); + m_xLbTableCol->clear(); + for (size_t n = 0; n < m_aDBColumns.size(); ++n) + m_xLbTableDbColumn->append_text(m_aDBColumns[n]->sColumn); + + m_xLbTableDbColumn->thaw(); + m_xLbTableCol->thaw(); + + m_xLbTableDbColumn->select(0); + } + else if( &rButton == m_xIbDbcolToEdit.get() ) + { + bChgEnable = false; + // move data to Edit: + OUString aField(m_xLbTextDbColumn->get_selected_text()); + if( !aField.isEmpty() ) + { + OUString aStr( m_xEdDbText->get_text() ); + int nStartPos, nEndPos; + m_xEdDbText->get_selection_bounds(nStartPos, nEndPos); + sal_Int32 nPos = std::min(nStartPos, nEndPos); + sal_Int32 nMax = std::max(nStartPos, nEndPos); + const sal_Int32 nSel = nMax - nPos; + if( nSel ) + // first delete the existing selection + aStr = aStr.replaceAt( nPos, nSel, u"" ); + + aField = OUStringChar(cDBFieldStart) + aField + OUStringChar(cDBFieldEnd); + if( !aStr.isEmpty() ) + { + if( nPos ) // one blank in front + { + sal_Unicode c = aStr[ nPos-1 ]; + if( '\n' != c && '\r' != c ) + aField = " " + aField; + } + if( nPos < aStr.getLength() ) // one blank behind + { + sal_Unicode c = aStr[ nPos ]; + if( '\n' != c && '\r' != c ) + aField += " "; + } + } + + m_xEdDbText->set_text( aStr.replaceAt( nPos, 0, aField ) ); + nPos += aField.getLength(); + m_xEdDbText->select_region(nPos, nPos); + } + } + + if( !bChgEnable ) + return; + + m_xIbDbcolOneTo->set_sensitive( bEnableTo ); + m_xIbDbcolAllTo->set_sensitive( bEnableTo ); + m_xIbDbcolOneFrom->set_sensitive( bEnableFrom ); + m_xIbDbcolAllFrom->set_sensitive( bEnableFrom ); + + m_xRbDbFormatFromDb->set_sensitive( false ); + m_xRbDbFormatFromUsr->set_sensitive( false ); + m_xLbDbFormatFromUsr->set_sensitive( false ); + + m_xPbTableFormat->set_sensitive( bEnableFrom ); +} + +IMPL_LINK(SwInsertDBColAutoPilot, DblClickHdl, weld::TreeView&, rBox, bool) +{ + weld::Button* pButton = nullptr; + if( &rBox == m_xLbTextDbColumn.get() ) + pButton = m_xIbDbcolToEdit.get(); + else if( &rBox == m_xLbTableDbColumn.get() && m_xIbDbcolOneTo->get_sensitive() ) + pButton = m_xIbDbcolOneTo.get(); + else if( &rBox == m_xLbTableCol.get() && m_xIbDbcolOneFrom->get_sensitive() ) + pButton = m_xIbDbcolOneFrom.get(); + + if (pButton) + TableToFromHdl(*pButton); + + return true; +} + +IMPL_LINK_NOARG(SwInsertDBColAutoPilot, TableFormatHdl, weld::Button&, void) +{ + SwWrtShell& rSh = m_pView->GetWrtShell(); + bool bNewSet = false; + if( !m_pTableSet ) + { + bNewSet = true; + m_pTableSet.reset(new SfxItemSet( rSh.GetAttrPool(), SwuiGetUITableAttrRange() )); + + // At first acquire the simple attributes + m_pTableSet->Put( SfxStringItem( FN_PARAM_TABLE_NAME, rSh.GetUniqueTableName() )); + m_pTableSet->Put( SfxUInt16Item( FN_PARAM_TABLE_HEADLINE, 1 ) ); + + m_pTableSet->Put( SfxUInt16Item( SID_BACKGRND_DESTINATION, + rSh.GetViewOptions()->GetTableDest() )); + + SvxBrushItem aBrush( RES_BACKGROUND ); + m_pTableSet->Put( aBrush ); + aBrush.SetWhich(SID_ATTR_BRUSH_ROW); + m_pTableSet->Put( aBrush ); + aBrush.SetWhich(SID_ATTR_BRUSH_TABLE); + m_pTableSet->Put( aBrush ); + + SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER ); + // table variant, when multiple table cells are selected + aBoxInfo.SetTable( true ); + // always show gap field + aBoxInfo.SetDist( true); + // set minimum size in tables and paragraphs + aBoxInfo.SetMinDist( false ); + // always set default-gap + aBoxInfo.SetDefDist( MIN_BORDER_DIST ); + // Single lines can have DontCare-status only in tables + aBoxInfo.SetValid( SvxBoxInfoItemValidFlags::DISABLE ); + m_pTableSet->Put( aBoxInfo ); + + SwGetCurColNumPara aPara; + const sal_uInt16 nNum = rSh.GetCurColNum( &aPara ); + tools::Long nWidth; + + if( nNum ) + { + nWidth = aPara.pPrtRect->Width(); + const SwFormatCol& rCol = aPara.pFrameFormat->GetCol(); + const SwColumns& rCols = rCol.GetColumns(); + + // initialise nStart and nEnd for nNum == 0 + tools::Long nWidth1 = 0, + nStart1 = 0, + nEnd1 = nWidth; + for( sal_uInt16 i = 0; i < nNum; ++i ) + { + const SwColumn* pCol = &rCols[i]; + nStart1 = pCol->GetLeft() + nWidth1; + nWidth1 += static_cast<tools::Long>(rCol.CalcColWidth( i, o3tl::narrowing<sal_uInt16>(nWidth) )); + nEnd1 = nWidth1 - pCol->GetRight(); + } + if(nStart1 || nEnd1 != nWidth) + nWidth = nEnd1 - nStart1; + } + else + nWidth = rSh.GetAnyCurRect( + (FrameTypeFlags::FLY_ANY & rSh.GetFrameType( nullptr, true )) + ? CurRectType::FlyEmbeddedPrt + : CurRectType::PagePrt ).Width(); + + SwTabCols aTabCols; + aTabCols.SetRight( nWidth ); + aTabCols.SetRightMax( nWidth ); + m_pRep.reset(new SwTableRep( aTabCols )); + m_pRep->SetAlign( text::HoriOrientation::NONE ); + m_pRep->SetSpace( nWidth ); + m_pRep->SetWidth( nWidth ); + m_pRep->SetWidthPercent( 100 ); + m_pTableSet->Put( SwPtrItem( FN_TABLE_REP, m_pRep.get() )); + + m_pTableSet->Put( SfxUInt16Item( SID_HTML_MODE, + ::GetHtmlMode( m_pView->GetDocShell() ))); + } + + sal_Int32 nCols = m_xLbTableCol->n_children(); + if (nCols != m_pRep->GetAllColCount() && nCols > 0) + { + // Number of columns has changed: then the TabCols have to be adjusted + tools::Long nWidth = m_pRep->GetWidth(); + --nCols; + SwTabCols aTabCols( nCols ); + aTabCols.SetRight( nWidth ); + aTabCols.SetRightMax( nWidth ); + if( nCols ) + { + const sal_Int32 nStep = nWidth / (nCols+1); + for( sal_Int32 n = 0; n < nCols; ++n ) + { + aTabCols.Insert( nStep*(n+1), false, n ); + } + } + m_pRep.reset(new SwTableRep( aTabCols )); + m_pRep->SetAlign( text::HoriOrientation::NONE ); + m_pRep->SetSpace( nWidth ); + m_pRep->SetWidth( nWidth ); + m_pRep->SetWidthPercent( 100 ); + m_pTableSet->Put( SwPtrItem( FN_TABLE_REP, m_pRep.get() )); + } + + SwAbstractDialogFactory& rFact = swui::GetFactory(); + + ScopedVclPtr<SfxAbstractTabDialog> pDlg(rFact.CreateSwTableTabDlg(m_xDialog.get(), m_pTableSet.get(), &rSh)); + if( RET_OK == pDlg->Execute() ) + m_pTableSet->Put( *pDlg->GetOutputItemSet() ); + else if( bNewSet ) + { + m_pTableSet.reset(); + m_pRep.reset(); + } +} + +IMPL_LINK_NOARG(SwInsertDBColAutoPilot, AutoFormatHdl, weld::Button&, void) +{ + SwAbstractDialogFactory& rFact = swui::GetFactory(); + + ScopedVclPtr<AbstractSwAutoFormatDlg> pDlg(rFact.CreateSwAutoFormatDlg(m_xDialog.get(), m_pView->GetWrtShellPtr(), false, m_xTAutoFormat.get())); + if( RET_OK == pDlg->Execute()) + m_xTAutoFormat = pDlg->FillAutoFormatOfIndex(); +} + +IMPL_LINK(SwInsertDBColAutoPilot, TVSelectHdl, weld::TreeView&, rBox, void) +{ + weld::TreeView* pGetBox = &rBox; + + SwInsDBColumn aSrch(pGetBox->get_selected_text()); + SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch ); + + // set the selected FieldName at the FormatGroupBox, so that + // it's clear what field is configured by the format! + OUString sText( m_xFormatFrame->get_label().copy( 0, m_nGBFormatLen )); + if( aSrch.sColumn.isEmpty() ) + { + m_xRbDbFormatFromDb->set_sensitive( false ); + m_xRbDbFormatFromUsr->set_sensitive( false ); + m_xLbDbFormatFromUsr->set_sensitive( false ); + } + else + { + bool bEnableFormat = (*it)->bHasFormat; + m_xRbDbFormatFromDb->set_sensitive( bEnableFormat ); + m_xRbDbFormatFromUsr->set_sensitive( bEnableFormat ); + + if( bEnableFormat ) + { + sText += " (" + aSrch.sColumn + ")"; + } + + bool bIsDBFormat = (*it)->bIsDBFormat; + m_xRbDbFormatFromDb->set_active( bIsDBFormat ); + m_xRbDbFormatFromUsr->set_active( !bIsDBFormat ); + m_xLbDbFormatFromUsr->set_sensitive( !bIsDBFormat ); + if( !bIsDBFormat ) + m_xLbDbFormatFromUsr->SetDefFormat( (*it)->nUsrNumFormat ); + } + + m_xFormatFrame->set_label(sText); + + if (m_xLbTableCol->n_children()) + { + // to know later on, what ListBox was the "active", a Flag + // is remembered in the 1st entry + if (&rBox == m_xLbTableCol.get()) + m_xLbTableCol->set_id(0, "tablecols"); + else + m_xLbTableCol->set_id(0, OUString()); + } +} + +IMPL_LINK_NOARG(SwInsertDBColAutoPilot, CBSelectHdl, weld::ComboBox&, void) +{ + weld::TreeView* pGetBox = m_xRbAsTable->get_active() + ? ( m_xLbTableCol->get_id(0).isEmpty() + ? m_xLbTableDbColumn.get() + : m_xLbTableCol.get() ) + : m_xLbTextDbColumn.get(); + + SwInsDBColumn aSrch(pGetBox->get_selected_text()); + SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch ); + + if( !aSrch.sColumn.isEmpty() ) + { + m_xLbDbFormatFromUsr->CallSelectHdl(); + (*it)->nUsrNumFormat = m_xLbDbFormatFromUsr->GetFormat(); + } +} + +IMPL_LINK_NOARG(SwInsertDBColAutoPilot, HeaderHdl, weld::Toggleable&, void) +{ + bool bEnable = m_xCbTableHeadon->get_active(); + m_xRbHeadlColnms->set_sensitive( bEnable ); + m_xRbHeadlEmpty->set_sensitive( bEnable ); +} + +static void lcl_InsTextInArr( std::u16string_view aText, DB_Columns& rColArr ) +{ + size_t nSttPos = 0; + size_t nFndPos; + while( std::u16string_view::npos != ( nFndPos = aText.find( '\x0A', nSttPos )) ) + { + if( 1 < nFndPos ) + { + rColArr.push_back(std::make_unique<DB_Column>(OUString(aText.substr(nSttPos, nFndPos -1)))); + } + rColArr.push_back(std::make_unique<DB_Column>()); + nSttPos = nFndPos + 1; + } + if( nSttPos < aText.size() ) + { + rColArr.push_back(std::make_unique<DB_Column>(OUString(aText.substr(nSttPos)))); + } +} + +bool SwInsertDBColAutoPilot::SplitTextToColArr( const OUString& rText, + DB_Columns& rColArr, + bool bInsField ) +{ + // create each of the database columns from the text again + // and then save in an array + // database columns are in <> and must be present in the columns' array: + OUString sText( rText ); + sal_Int32 nFndPos, nEndPos, nSttPos = 0; + + while( -1 != ( nFndPos = sText.indexOf( cDBFieldStart, nSttPos ))) + { + nSttPos = nFndPos + 1; + nEndPos = sText.indexOf( cDBFieldEnd, nSttPos+1 ); + if( -1 != nEndPos ) + { + // Text in <> brackets found: what is it: + SwInsDBColumn aSrch( sText.copy( nSttPos, nEndPos - nSttPos )); + SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch ); + if( it != m_aDBColumns.end() ) + { + // that is a valid field + // so surely the text "before": + const SwInsDBColumn& rFndCol = **it; + + DB_Column* pNew; + + if( 1 < nSttPos ) + { + ::lcl_InsTextInArr( sText.subView( 0, nSttPos-1 ), rColArr ); + sText = sText.copy( nSttPos-1 ); + } + + sText = sText.copy( rFndCol.sColumn.getLength() + 2 ); + nSttPos = 0; + + sal_uInt16 nSubType = 0; + sal_uInt32 nFormat; + if( rFndCol.bHasFormat ) + { + if( rFndCol.bIsDBFormat ) + nFormat = static_cast<sal_uInt32>(rFndCol.nDBNumFormat); + else + { + nFormat = rFndCol.nUsrNumFormat; + nSubType = nsSwExtendedSubType::SUB_OWN_FMT; + } + } + else + nFormat = 0; + + if( bInsField ) + { + SwWrtShell& rSh = m_pView->GetWrtShell(); + SwDBFieldType aFieldType( rSh.GetDoc(), aSrch.sColumn, + m_aDBData ); + pNew = new DB_Column( rFndCol, *new SwDBField( + static_cast<SwDBFieldType*>(rSh.InsertFieldType( aFieldType )), + nFormat ) ); + if( nSubType ) + pNew->pField->SetSubType( nSubType ); + } + else + pNew = new DB_Column( rFndCol, nFormat ); + + rColArr.push_back( std::unique_ptr<DB_Column>(pNew) ); + } + } + } + + // don't forget the last text + if( !sText.isEmpty() ) + ::lcl_InsTextInArr( sText, rColArr ); + + return !rColArr.empty(); +} + +void SwInsertDBColAutoPilot::DataToDoc( const Sequence<Any>& rSelection, + Reference< XDataSource> const & xSource, + Reference< XConnection> const & xConnection, + Reference< sdbc::XResultSet > const & xResultSet_in ) +{ + auto xResultSet = xResultSet_in; + + const Any* pSelection = rSelection.hasElements() ? rSelection.getConstArray() : nullptr; + SwWrtShell& rSh = m_pView->GetWrtShell(); + + //with the drag and drop interface no result set is initially available + bool bDisposeResultSet = false; + // we don't have a cursor, so we have to create our own RowSet + if ( !xResultSet.is() ) + { + xResultSet = SwDBManager::createCursor(m_aDBData.sDataSource,m_aDBData.sCommand,m_aDBData.nCommandType,xConnection,m_pView); + bDisposeResultSet = xResultSet.is(); + } + + Reference< sdbc::XRow > xRow(xResultSet, UNO_QUERY); + if ( !xRow.is() ) + return; + + rSh.StartAllAction(); + bool bUndo = rSh.DoesUndo(); + if( bUndo ) + rSh.StartUndo(); + + bool bAsTable = m_xRbAsTable->get_active(); + SvNumberFormatter& rNumFormatr = *rSh.GetNumberFormatter(); + + if( rSh.HasSelection() ) + rSh.DelRight(); + + std::optional<SwWait> oWait; + + Reference< XColumnsSupplier > xColsSupp( xResultSet, UNO_QUERY ); + Reference <XNameAccess> xCols = xColsSupp->getColumns(); + + uno::Reference<sdbcx::XRowLocate> xRowLocate(xResultSet, uno::UNO_QUERY_THROW); + + do{ // middle checked loop!! + if( bAsTable ) // fill in data as table + { + rSh.DoUndo( false ); + + sal_Int32 nCols = m_xLbTableCol->n_children(); + sal_Int32 nRows = 0; + if( m_xCbTableHeadon->get_active() ) + nRows++; + + if( pSelection ) + nRows += rSelection.getLength(); + else + ++nRows; + + // prepare the array for the selected columns + std::vector<SwInsDBColumn*> aColFields; + for( sal_Int32 n = 0; n < nCols; ++n ) + { + SwInsDBColumn aSrch(m_xLbTableCol->get_text(n)); + SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch ); + if (it != m_aDBColumns.end()) + aColFields.push_back(it->get()); + else { + OSL_ENSURE( false, "database column not found" ); + } + } + + if( static_cast<size_t>(nCols) != aColFields.size() ) + { + OSL_ENSURE( false, "not all database columns found" ); + nCols = static_cast<sal_Int32>(aColFields.size()); + } + + if(!nRows || !nCols) + { + OSL_ENSURE( false, "wrong parameters" ); + break; + } + + const SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig(); + + bool bHTML = 0 != (::GetHtmlMode( m_pView->GetDocShell() ) & HTMLMODE_ON); + rSh.InsertTable( + pModOpt->GetInsTableFlags(bHTML), + nRows, nCols, (pSelection ? m_xTAutoFormat.get(): nullptr) ); + rSh.MoveTable( GotoPrevTable, fnTableStart ); + + if( pSelection && m_pTableSet ) + SetTabSet(); + + SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_VALUE> aTableSet( rSh.GetAttrPool() ); + bool bIsAutoUpdateCells = rSh.IsAutoUpdateCells(); + rSh.SetAutoUpdateCells( false ); + + if( m_xCbTableHeadon->get_active() ) + { + for( sal_Int32 n = 0; n < nCols; ++n ) + { + if( m_xRbHeadlColnms->get_active() ) + { + rSh.SwEditShell::Insert2( aColFields[ n ]->sColumn ); + } + rSh.GoNextCell(); + } + } + else + rSh.SetRowsToRepeat( 0 ); + + for( sal_Int32 i = 0 ; ; ++i ) + { + bool bBreak = false; + try + { + if(pSelection) + { + bBreak = !xRowLocate->moveToBookmark(pSelection[i]); + } + else if(!i) + bBreak = !xResultSet->first(); + } + catch (const Exception&) + { + bBreak = true; + } + if(bBreak) + break; + + for( sal_Int32 n = 0; n < nCols; ++n ) + { + // at the very first time, NO GoNextCell, because we're + // already in it. Also no GoNextCell after the Insert, + // because an empty line is added at the end. + if( i || n ) + rSh.GoNextCell(); + + const SwInsDBColumn* pEntry = aColFields[ n ]; + + Reference< XColumn > xColumn; + xCols->getByName(pEntry->sColumn) >>= xColumn; + Reference< XPropertySet > xColumnProps( xColumn, UNO_QUERY ); + sal_Int32 eDataType = 0; + if( xColumnProps.is() ) + { + Any aType = xColumnProps->getPropertyValue("Type"); + aType >>= eDataType; + } + try + { + if( pEntry->bHasFormat ) + { + SwTableBoxNumFormat aNumFormat( + pEntry->bIsDBFormat ? static_cast<sal_uInt32>(pEntry->nDBNumFormat) + : pEntry->nUsrNumFormat ); + aTableSet.Put(aNumFormat); + if( xColumn.is() ) + { + double fVal = xColumn->getDouble(); + if( xColumn->wasNull() ) + aTableSet.ClearItem( RES_BOXATR_VALUE ); + else + { + if(rNumFormatr.GetType(aNumFormat.GetValue()) & SvNumFormatType::DATE) + { + ::Date aStandard(1,1,1900); + if (rNumFormatr.GetNullDate() != aStandard) + fVal += (aStandard - rNumFormatr.GetNullDate()); + } + aTableSet.Put( SwTableBoxValue( fVal )); + } + } + else + aTableSet.ClearItem( RES_BOXATR_VALUE ); + rSh.SetTableBoxFormulaAttrs( aTableSet ); + } + //#i60207# don't insert binary data as string - creates a loop + else if( DataType::BINARY == eDataType || + DataType::VARBINARY == eDataType || + DataType::LONGVARBINARY== eDataType || + DataType::SQLNULL == eDataType || + DataType::OTHER == eDataType || + DataType::OBJECT == eDataType || + DataType::DISTINCT == eDataType || + DataType::STRUCT == eDataType || + DataType::ARRAY == eDataType || + DataType::BLOB == eDataType || + DataType::CLOB == eDataType || + DataType::REF == eDataType + ) + { + // do nothing + } + else + { + const OUString sVal = xColumn->getString(); + if(!xColumn->wasNull()) + { + rSh.SwEditShell::Insert2( sVal ); + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("sw", ""); + } + } + + if( !pSelection ) + { + if ( !xResultSet->next() ) + break; + } + else if( i+1 >= rSelection.getLength() ) + break; + + if( 10 == i ) + oWait.emplace( *m_pView->GetDocShell(), true ); + } + + rSh.MoveTable( GotoCurrTable, fnTableStart ); + if( !pSelection && ( m_pTableSet || m_xTAutoFormat )) + { + if( m_pTableSet ) + SetTabSet(); + + if (m_xTAutoFormat) + rSh.SetTableStyle(*m_xTAutoFormat); + } + rSh.SetAutoUpdateCells( bIsAutoUpdateCells ); + } + else // add data as fields/text + { + DB_Columns aColArr; + if( SplitTextToColArr( m_xEdDbText->get_text(), aColArr, m_xRbAsField->get_active() ) ) + { + // now for each data set, we can iterate over the array + // and add the data + + if( !rSh.IsSttPara() ) + rSh.SwEditShell::SplitNode(); + if( !rSh.IsEndPara() ) + { + rSh.SwEditShell::SplitNode(); + rSh.SwCursorShell::Left(1,SwCursorSkipMode::Chars); + } + + rSh.DoUndo( false ); + + SwTextFormatColl* pColl = nullptr; + { + const OUString sTmplNm(m_xLbDbParaColl->get_active_text()); + if( m_sNoTmpl != sTmplNm ) + { + pColl = rSh.FindTextFormatCollByName( sTmplNm ); + if( !pColl ) + { + const sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( + sTmplNm, SwGetPoolIdFromName::TxtColl ); + if( USHRT_MAX != nId ) + pColl = rSh.GetTextCollFromPool( nId ); + else + pColl = rSh.MakeTextFormatColl( sTmplNm ); + } + rSh.SetTextFormatColl( pColl ); + } + } + + // for adding as fields -> insert a "NextField" after + // every data set + SwDBFormatData aDBFormatData; + Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + aDBFormatData.xFormatter.set(util::NumberFormatter::create(xContext), UNO_QUERY_THROW) ; + + Reference<XPropertySet> xSourceProps(xSource, UNO_QUERY); + if(xSourceProps.is()) + { + Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier"); + if(aFormats.hasValue()) + { + Reference< util::XNumberFormatsSupplier> xSuppl; + aFormats >>= xSuppl; + if(xSuppl.is()) + { + Reference< XPropertySet > xSettings = xSuppl->getNumberFormatSettings(); + Any aNull = xSettings->getPropertyValue("NullDate"); + aNull >>= aDBFormatData.aNullDate; + if(aDBFormatData.xFormatter.is()) + aDBFormatData.xFormatter->attachNumberFormatsSupplier(xSuppl); + } + } + } + aDBFormatData.aLocale = LanguageTag( rSh.GetCurLang() ).getLocale(); + SwDBNextSetField aNxtDBField( static_cast<SwDBNextSetFieldType*>(rSh. + GetFieldType( 0, SwFieldIds::DbNextSet )), + "1", m_aDBData ); + + bool bSetCursor = true; + const size_t nCols = aColArr.size(); + ::sw::mark::IMark* pMark = nullptr; + for( sal_Int32 i = 0 ; ; ++i ) + { + bool bBreak = false; + try + { + if(pSelection) + { + bBreak = !xRowLocate->moveToBookmark(pSelection[i]); + } + else if(!i) + bBreak = !xResultSet->first(); + } + catch (const Exception&) + { + bBreak = true; + } + + if(bBreak) + break; + + for( size_t n = 0; n < nCols; ++n ) + { + DB_Column* pDBCol = aColArr[ n ].get(); + OUString sIns; + switch( pDBCol->eColType ) + { + case DB_Column::Type::FILLTEXT: + sIns = *pDBCol->pText; + break; + + case DB_Column::Type::SPLITPARA: + rSh.SplitNode(); + // when the template is not the same as the follow template, + // the selected has to be set newly + if( pColl && &pColl->GetNextTextFormatColl() != pColl ) + rSh.SetTextFormatColl( pColl ); + break; + + case DB_Column::Type::COL_FIELD: + { + std::unique_ptr<SwDBField> pField(static_cast<SwDBField *>( + pDBCol->pField->CopyField().release())); + double nValue = DBL_MAX; + + Reference< XPropertySet > xColumnProps; + xCols->getByName(pDBCol->pColInfo->sColumn) >>= xColumnProps; + + pField->SetExpansion( SwDBManager::GetDBField( + xColumnProps, + aDBFormatData, + &nValue ) ); + if( DBL_MAX != nValue ) + { + Any aType = xColumnProps->getPropertyValue("Type"); + sal_Int32 eDataType = 0; + aType >>= eDataType; + if( DataType::DATE == eDataType || DataType::TIME == eDataType || + DataType::TIMESTAMP == eDataType) + + { + ::Date aStandard(1,1,1900); + ::Date aCompare(aDBFormatData.aNullDate.Day , + aDBFormatData.aNullDate.Month, + aDBFormatData.aNullDate.Year); + if(aStandard != aCompare) + nValue += (aStandard - aCompare); + } + pField->ChgValue( nValue, true ); + } + pField->SetInitialized(); + + rSh.InsertField2( *pField ); + } + break; + + case DB_Column::Type::COL_TEXT: + { + double nValue = DBL_MAX; + Reference< XPropertySet > xColumnProps; + xCols->getByName(pDBCol->pColInfo->sColumn) >>= xColumnProps; + sIns = SwDBManager::GetDBField( + xColumnProps, + aDBFormatData, + &nValue ); + if( pDBCol->nFormat && + DBL_MAX != nValue ) + { + const Color* pCol; + if(rNumFormatr.GetType(pDBCol->nFormat) & SvNumFormatType::DATE) + { + ::Date aStandard(1,1,1900); + if (rNumFormatr.GetNullDate() != aStandard) + nValue += (aStandard - rNumFormatr.GetNullDate()); + } + rNumFormatr.GetOutputString( nValue, + pDBCol->nFormat, + sIns, &pCol ); + } + } + break; + } + + if( !sIns.isEmpty() ) + { + rSh.Insert( sIns ); + + if( bSetCursor) + { + // to the beginning and set a mark, so that + // the cursor can be set to the initial position + // at the end. + + rSh.SwCursorShell::MovePara( + GoCurrPara, fnParaStart ); + pMark = rSh.SetBookmark( + vcl::KeyCode(), + OUString(), + IDocumentMarkAccess::MarkType::UNO_BOOKMARK ); + rSh.SwCursorShell::MovePara( + GoCurrPara, fnParaEnd ); + bSetCursor = false; + } + } + } + + if( !pSelection ) + { + bool bNext = xResultSet->next(); + if(!bNext) + break; + } + else if( i+1 >= rSelection.getLength() ) + break; + + if( m_xRbAsField->get_active() ) + rSh.InsertField2( aNxtDBField ); + + if( !rSh.IsSttPara() ) + rSh.SwEditShell::SplitNode(); + + if( 10 == i ) + oWait.emplace( *m_pView->GetDocShell(), true ); + } + + if( !bSetCursor && pMark != nullptr) + { + rSh.SetMark(); + rSh.GotoMark( pMark ); + rSh.getIDocumentMarkAccess()->deleteMark( pMark ); + break; + } + } + } + // write configuration + Commit(); + }while( false ); // middle checked loop + + if( bUndo ) + { + rSh.DoUndo(); + rSh.AppendUndoForInsertFromDB( bAsTable ); + rSh.EndUndo(); + } + rSh.ClearMark(); + rSh.EndAllAction(); + + if ( bDisposeResultSet ) + ::comphelper::disposeComponent(xResultSet); +} + +void SwInsertDBColAutoPilot::SetTabSet() +{ + SwWrtShell& rSh = m_pView->GetWrtShell(); + const SfxPoolItem* pItem; + + if (m_xTAutoFormat) + { + if (m_xTAutoFormat->IsFrame()) + { + // border is from AutoFormat + m_pTableSet->ClearItem( RES_BOX ); + m_pTableSet->ClearItem( SID_ATTR_BORDER_INNER ); + } + if (m_xTAutoFormat->IsBackground()) + { + m_pTableSet->ClearItem( RES_BACKGROUND ); + m_pTableSet->ClearItem( SID_ATTR_BRUSH_ROW ); + m_pTableSet->ClearItem( SID_ATTR_BRUSH_TABLE ); + } + } + else + { + // remove the defaults again, it makes no sense to set them + SvxBrushItem aBrush( RES_BACKGROUND ); + static const sal_uInt16 aIds[3] = + { RES_BACKGROUND, SID_ATTR_BRUSH_ROW, SID_ATTR_BRUSH_TABLE }; + for(sal_uInt16 i : aIds) + if( SfxItemState::SET == m_pTableSet->GetItemState( i, + false, &pItem ) && *pItem == aBrush ) + m_pTableSet->ClearItem( i ); + } + + const SfxStringItem* pTableNameItem = m_pTableSet->GetItemIfSet( FN_PARAM_TABLE_NAME, false); + if( pTableNameItem && pTableNameItem->GetValue() == rSh.GetTableFormat()->GetName() ) + m_pTableSet->ClearItem( FN_PARAM_TABLE_NAME ); + + rSh.MoveTable( GotoCurrTable, fnTableStart ); + rSh.SetMark(); + rSh.MoveTable( GotoCurrTable, fnTableEnd ); + + ItemSetToTableParam( *m_pTableSet, rSh ); + + rSh.ClearMark(); + rSh.MoveTable( GotoCurrTable, fnTableStart ); +} + +static Sequence<OUString> lcl_createSourceNames(std::u16string_view rNodeName) +{ + Sequence<OUString> aSourceNames(11); + OUString* pNames = aSourceNames.getArray(); + pNames[0] = OUString::Concat(rNodeName) + "/DataSource"; + pNames[1] = OUString::Concat(rNodeName) + "/Command"; + pNames[2] = OUString::Concat(rNodeName) + "/CommandType"; + pNames[3] = OUString::Concat(rNodeName) + "/ColumnsToText"; + pNames[4] = OUString::Concat(rNodeName) + "/ColumnsToTable"; + pNames[5] = OUString::Concat(rNodeName) + "/ParaStyle"; + pNames[6] = OUString::Concat(rNodeName) + "/TableAutoFormat"; + pNames[7] = OUString::Concat(rNodeName) + "/IsTable"; + pNames[8] = OUString::Concat(rNodeName) + "/IsField"; + pNames[9] = OUString::Concat(rNodeName) + "/IsHeadlineOn"; + pNames[10] = OUString::Concat(rNodeName) + "/IsEmptyHeadline"; + return aSourceNames; +} + +static Sequence<OUString> lcl_CreateSubNames(std::u16string_view rSubNodeName) +{ + return + { + OUString::Concat(rSubNodeName) + "/ColumnName", + OUString::Concat(rSubNodeName) + "/ColumnIndex", + OUString::Concat(rSubNodeName) + "/IsNumberFormat", + OUString::Concat(rSubNodeName) + "/IsNumberFormatFromDataBase", + OUString::Concat(rSubNodeName) + "/NumberFormat", + OUString::Concat(rSubNodeName) + "/NumberFormatLocale" + }; +} + +static OUString lcl_CreateUniqueName(const Sequence<OUString>& aNames) +{ + sal_Int32 nIdx = aNames.getLength(); + while(true) + { + const OUString sRet = "_" + OUString::number(nIdx++); + if ( comphelper::findValue(aNames, sRet) == -1 ) + return sRet; // No match found, return unique name + } +} + +void SwInsertDBColAutoPilot::Notify( const css::uno::Sequence< OUString >& ) {} + +void SwInsertDBColAutoPilot::ImplCommit() +{ + Sequence <OUString> aNames = GetNodeNames(OUString()); + //remove entries that contain this data source + table at first + for(OUString const & nodeName : std::as_const(aNames)) + { + Sequence<Any> aSourceProperties = GetProperties({ nodeName + "/DataSource", nodeName + "/Command" }); + const Any* pSourceProps = aSourceProperties.getArray(); + OUString sSource, sCommand; + pSourceProps[0] >>= sSource; + pSourceProps[1] >>= sCommand; + if(sSource==m_aDBData.sDataSource && sCommand==m_aDBData.sCommand) + { + ClearNodeElements(OUString(), { nodeName }); + } + } + + aNames = GetNodeNames(OUString()); + OUString sNewNode = lcl_CreateUniqueName(aNames); + Sequence<OUString> aNodeNames = lcl_createSourceNames(sNewNode); + Sequence<PropertyValue> aValues(aNodeNames.getLength()); + PropertyValue* pValues = aValues.getArray(); + const OUString* pNodeNames = aNodeNames.getConstArray(); + for(sal_Int32 i = 0; i < aNodeNames.getLength(); i++) + { + pValues[i].Name = "/" + pNodeNames[i]; + } + + pValues[0].Value <<= m_aDBData.sDataSource; + pValues[1].Value <<= m_aDBData.sCommand; + pValues[2].Value <<= m_aDBData.nCommandType; + pValues[3].Value <<= m_xEdDbText->get_text(); + + OUString sTmp; + const sal_Int32 nCnt = m_xLbTableCol->n_children(); + for( sal_Int32 n = 0; n < nCnt; ++n ) + sTmp += m_xLbTableCol->get_text(n) + "\x0a"; + + if (!sTmp.isEmpty()) + pValues[4].Value <<= sTmp; + + if( m_sNoTmpl != (sTmp = m_xLbDbParaColl->get_active_text()) ) + pValues[5].Value <<= sTmp; + + if (m_xTAutoFormat) + pValues[6].Value <<= m_xTAutoFormat->GetName(); + + pValues[7].Value <<= m_xRbAsTable->get_active(); + pValues[8].Value <<= m_xRbAsField->get_active(); + pValues[9].Value <<= m_xCbTableHeadon->get_active(); + pValues[10].Value <<= m_xRbHeadlEmpty->get_active(); + + SetSetProperties(OUString(), aValues); + + sNewNode += "/ColumnSet"; + + LanguageType ePrevLang(0xffff); + + SvNumberFormatter& rNFormatr = *m_pView->GetWrtShell().GetNumberFormatter(); + for(size_t nCol = 0; nCol < m_aDBColumns.size(); nCol++) + { + SwInsDBColumn* pColumn = m_aDBColumns[nCol].get(); + OUString sColumnInsertNode(sNewNode + "/__"); + if( nCol < 10 ) + sColumnInsertNode += "00"; + else if( nCol < 100 ) + sColumnInsertNode += "0"; + sColumnInsertNode += OUString::number( nCol ); + + const Sequence <OUString> aSubNodeNames = lcl_CreateSubNames(sColumnInsertNode); + Sequence<PropertyValue> aSubValues(aSubNodeNames.getLength()); + PropertyValue* pSubValues = aSubValues.getArray(); + sal_Int32 i = 0; + + for( const OUString& rSubNodeName : aSubNodeNames) + pSubValues[i++].Name = rSubNodeName; + pSubValues[0].Value <<= pColumn->sColumn; + pSubValues[1].Value <<= i; + pSubValues[2].Value <<= pColumn->bHasFormat; + pSubValues[3].Value <<= pColumn->bIsDBFormat; + + SwStyleNameMapper::FillUIName( RES_POOLCOLL_STANDARD, sTmp ); + const SvNumberformat* pNF = rNFormatr.GetEntry( pColumn->nUsrNumFormat ); + LanguageType eLang; + if( pNF ) + { + pSubValues[4].Value <<= pNF->GetFormatstring(); + eLang = pNF->GetLanguage(); + } + else + { + pSubValues[4].Value <<= sTmp; + eLang = GetAppLanguage(); + } + + OUString sPrevLang; + if( eLang != ePrevLang ) + { + sPrevLang = LanguageTag::convertToBcp47( eLang ); + ePrevLang = eLang; + } + + pSubValues[5].Value <<= sPrevLang; + SetSetProperties(sNewNode, aSubValues); + } +} + +void SwInsertDBColAutoPilot::Load() +{ + const Sequence<OUString> aNames = GetNodeNames(OUString()); + SvNumberFormatter& rNFormatr = *m_pView->GetWrtShell().GetNumberFormatter(); + for(OUString const & nodeName : aNames) + { + //search for entries with the appropriate data source and table + Sequence<OUString> aSourceNames = lcl_createSourceNames(nodeName); + + Sequence< Any> aDataSourceProps = GetProperties(aSourceNames); + const Any* pDataSourceProps = aDataSourceProps.getConstArray(); + OUString sSource, sCommand; + sal_Int16 nCommandType; + pDataSourceProps[0] >>= sSource; + pDataSourceProps[1] >>= sCommand; + pDataSourceProps[2] >>= nCommandType; + if(sSource == m_aDBData.sDataSource && sCommand == m_aDBData.sCommand) + { + DB_ColumnConfigData aNewData; + + pDataSourceProps[3] >>= aNewData.sEdit; + pDataSourceProps[4] >>= aNewData.sTableList; + pDataSourceProps[5] >>= aNewData.sTmplNm; + pDataSourceProps[6] >>= aNewData.sTAutoFormatNm; + if(pDataSourceProps[7].hasValue()) + aNewData.bIsTable = *o3tl::doAccess<bool>(pDataSourceProps[7]); + if(pDataSourceProps[8].hasValue()) + aNewData.bIsField = *o3tl::doAccess<bool>(pDataSourceProps[8]); + if(pDataSourceProps[9].hasValue()) + aNewData.bIsHeadlineOn = *o3tl::doAccess<bool>(pDataSourceProps[9]); + if(pDataSourceProps[10].hasValue()) + aNewData.bIsEmptyHeadln = *o3tl::doAccess<bool>(pDataSourceProps[10]); + + const OUString sSubNodeName(nodeName + "/ColumnSet/"); + const Sequence <OUString> aSubNames = GetNodeNames(sSubNodeName); + for(const OUString& rSubName : aSubNames) + { + Sequence <OUString> aSubNodeNames = + lcl_CreateSubNames(Concat2View(sSubNodeName + rSubName)); + Sequence< Any> aSubProps = GetProperties(aSubNodeNames); + const Any* pSubProps = aSubProps.getConstArray(); + + OUString sColumn; + pSubProps[0] >>= sColumn; + // check for existence of the loaded column name + bool bFound = false; + for(size_t nRealColumn = 0; nRealColumn < m_aDBColumns.size(); ++nRealColumn) + { + if(m_aDBColumns[nRealColumn]->sColumn == sColumn) + { + bFound = true; + break; + } + } + if(!bFound) + continue; + sal_Int16 nIndex = 0; + pSubProps[1] >>= nIndex; + std::unique_ptr<SwInsDBColumn> pInsDBColumn(new SwInsDBColumn(sColumn)); + if(pSubProps[2].hasValue()) + pInsDBColumn->bHasFormat = *o3tl::doAccess<bool>(pSubProps[2]); + if(pSubProps[3].hasValue()) + pInsDBColumn->bIsDBFormat = *o3tl::doAccess<bool>(pSubProps[3]); + + pSubProps[4] >>= pInsDBColumn->sUsrNumFormat; + OUString sNumberFormatLocale; + pSubProps[5] >>= sNumberFormatLocale; + + /* XXX Earlier versions wrote a Country-Language string in + * SwInsertDBColAutoPilot::Commit() that here was read as + * Language-Country with 2 characters copied to language, + * 1 character separator and unconditionally 2 characters read + * as country. So for 'DE-de' and locales that have similar + * case-insensitive equal language/country combos that may have + * worked, for all others not. FIXME if you need to read old + * data that you were never able to read before. */ + pInsDBColumn->eUsrNumFormatLng = LanguageTag::convertToLanguageType( sNumberFormatLocale ); + + pInsDBColumn->nUsrNumFormat = rNFormatr.GetEntryKey( pInsDBColumn->sUsrNumFormat, + pInsDBColumn->eUsrNumFormatLng ); + + aNewData.aDBColumns.insert(std::move(pInsDBColumn)); + } + OUString sTmp( aNewData.sTableList ); + if( !sTmp.isEmpty() ) + { + sal_Int32 n = 0; + do { + const OUString sEntry( sTmp.getToken( 0, '\x0a', n ) ); + //preselect column - if they still exist! + if (m_xLbTableDbColumn->find_text(sEntry) != -1) + { + m_xLbTableCol->append_text(sEntry); + m_xLbTableDbColumn->remove_text(sEntry); + } + } while( n>=0 ); + + if (!m_xLbTableDbColumn->n_children()) + { + m_xIbDbcolAllTo->set_sensitive( false ); + m_xIbDbcolOneTo->set_sensitive( false ); + } + m_xIbDbcolOneFrom->set_sensitive(true); + m_xIbDbcolAllFrom->set_sensitive(true); + } + m_xEdDbText->set_text( aNewData.sEdit ); + + sTmp = aNewData.sTmplNm; + if( !sTmp.isEmpty() ) + m_xLbDbParaColl->set_active_text(sTmp); + else + m_xLbDbParaColl->set_active(0); + + m_xTAutoFormat.reset(); + sTmp = aNewData.sTAutoFormatNm; + if( !sTmp.isEmpty() ) + { + // then load the AutoFormat file and look for Autoformat first + SwTableAutoFormatTable aAutoFormatTable; + aAutoFormatTable.Load(); + for( size_t nAutoFormat = aAutoFormatTable.size(); nAutoFormat; ) + if( sTmp == aAutoFormatTable[ --nAutoFormat ].GetName() ) + { + m_xTAutoFormat.reset(new SwTableAutoFormat(aAutoFormatTable[nAutoFormat])); + break; + } + } + + m_xRbAsTable->set_active( aNewData.bIsTable ); + m_xRbAsField->set_active( aNewData.bIsField ); + m_xRbAsText->set_active( !aNewData.bIsTable && !aNewData.bIsField ); + + m_xCbTableHeadon->set_active( aNewData.bIsHeadlineOn ); + m_xRbHeadlColnms->set_active( !aNewData.bIsEmptyHeadln ); + m_xRbHeadlEmpty->set_active( aNewData.bIsEmptyHeadln ); + HeaderHdl(*m_xCbTableHeadon); + + // now copy the user defined Numberformat strings to the + // Shell. Then only these are available as ID + for( size_t n = 0; n < m_aDBColumns.size() ; ++n ) + { + SwInsDBColumn& rSet = *m_aDBColumns[ n ]; + for( size_t m = 0; m < aNewData.aDBColumns.size() ; ++m ) + { + SwInsDBColumn& rGet = *aNewData.aDBColumns[ m ]; + if(rGet.sColumn == rSet.sColumn) + { + if( rGet.bHasFormat && !rGet.bIsDBFormat ) + { + rSet.bIsDBFormat = false; + rSet.nUsrNumFormat = rNFormatr.GetEntryKey( rGet.sUsrNumFormat, + rGet.eUsrNumFormatLng ); + if( NUMBERFORMAT_ENTRY_NOT_FOUND == rSet.nUsrNumFormat ) + { + sal_Int32 nCheckPos; + SvNumFormatType nType; + rNFormatr.PutEntry( rGet.sUsrNumFormat, nCheckPos, nType, + rSet.nUsrNumFormat, rGet.eUsrNumFormatLng ); + } + } + break; + } + } + } + + // when the cursor is inside of a table, table must NEVER be selectable + if( !m_xRbAsTable->get_sensitive() && m_xRbAsTable->get_active() ) + m_xRbAsField->set_active(true); + break; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/dbtablepreviewdialog.cxx b/sw/source/ui/dbui/dbtablepreviewdialog.cxx new file mode 100644 index 0000000000..ec530f9e3c --- /dev/null +++ b/sw/source/ui/dbui/dbtablepreviewdialog.cxx @@ -0,0 +1,119 @@ +/* -*- 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 "dbtablepreviewdialog.hxx" +#include <comphelper/processfactory.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/frame/Frame.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <utility> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; + +class DBTablePreviewFrame + : public cppu::WeakImplHelper<lang::XEventListener> +{ +private: + css::uno::Reference<css::frame::XFrame2> m_xFrame; + + virtual void SAL_CALL disposing(const lang::EventObject& /*Source*/) override + { + m_xFrame.clear(); + } + +public: + DBTablePreviewFrame(css::uno::Reference<css::frame::XFrame2> xFrame) + : m_xFrame(std::move(xFrame)) + { + } + + void cleanup() + { + if (m_xFrame.is()) + { + m_xFrame->setComponent(nullptr, nullptr); + m_xFrame->dispose(); + m_xFrame.clear(); + } + } +}; + +SwDBTablePreviewDialog::SwDBTablePreviewDialog(weld::Window* pParent, uno::Sequence< beans::PropertyValue> const & rValues) + : SfxDialogController(pParent, "modules/swriter/ui/tablepreviewdialog.ui", "TablePreviewDialog") + , m_xDescriptionFI(m_xBuilder->weld_label("description")) + , m_xBeamerWIN(m_xBuilder->weld_container("beamer")) +{ + Size aSize(m_xBeamerWIN->get_approximate_digit_width() * 80, + m_xBeamerWIN->get_text_height() * 18); + m_xBeamerWIN->set_size_request(aSize.Width(), aSize.Height()); + + auto pValue = std::find_if(rValues.begin(), rValues.end(), + [](const beans::PropertyValue& rValue) { return rValue.Name == "Command"; }); + if (pValue != rValues.end()) + { + OUString sDescription = m_xDescriptionFI->get_label(); + OUString sTemp; + pValue->Value >>= sTemp; + m_xDescriptionFI->set_label(sDescription.replaceFirst("%1", sTemp)); + } + + css::uno::Reference<css::frame::XFrame2> xFrame; + try + { + // create a frame wrapper for myself + xFrame = frame::Frame::create( comphelper::getProcessComponentContext() ); + xFrame->initialize(m_xBeamerWIN->CreateChildFrame()); + } + catch (uno::Exception const &) + { + xFrame.clear(); + } + if (!xFrame.is()) + return; + + m_xFrameListener.set(new DBTablePreviewFrame(xFrame)); + xFrame->addEventListener(m_xFrameListener); + + util::URL aURL; + aURL.Complete = ".component:DB/DataSourceBrowser"; + uno::Reference<frame::XDispatch> xD = xFrame->queryDispatch(aURL, "", + css::frame::FrameSearchFlag::CHILDREN | css::frame::FrameSearchFlag::CREATE); + if (xD.is()) + { + xD->dispatch(aURL, rValues); + m_xBeamerWIN->show(); + } +} + +SwDBTablePreviewDialog::~SwDBTablePreviewDialog() +{ + if (m_xFrameListener) + { + m_xFrameListener->cleanup(); + m_xFrameListener.clear(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/dbtablepreviewdialog.hxx b/sw/source/ui/dbui/dbtablepreviewdialog.hxx new file mode 100644 index 0000000000..99315fa017 --- /dev/null +++ b/sw/source/ui/dbui/dbtablepreviewdialog.hxx @@ -0,0 +1,46 @@ +/* -*- 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_DBUI_DBTABLEPREVIEWDIALOG_HXX +#define INCLUDED_SW_SOURCE_UI_DBUI_DBTABLEPREVIEWDIALOG_HXX + +#include <sfx2/basedlgs.hxx> +#include <com/sun/star/uno/Sequence.h> + +namespace com::sun::star{ + namespace beans{ struct PropertyValue; } + namespace frame{ class XFrame2; } +} + +class DBTablePreviewFrame; + +class SwDBTablePreviewDialog : public SfxDialogController +{ + std::unique_ptr<weld::Label> m_xDescriptionFI; + std::unique_ptr<weld::Container> m_xBeamerWIN; + + rtl::Reference<DBTablePreviewFrame> m_xFrameListener; +public: + SwDBTablePreviewDialog(weld::Window* pParent, + css::uno::Sequence< css::beans::PropertyValue> const & rValues ); + virtual ~SwDBTablePreviewDialog() override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/mailmergewizard.cxx b/sw/source/ui/dbui/mailmergewizard.cxx new file mode 100644 index 0000000000..7090d5c3e2 --- /dev/null +++ b/sw/source/ui/dbui/mailmergewizard.cxx @@ -0,0 +1,268 @@ +/* -*- 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 <osl/diagnose.h> + +#include <mailmergewizard.hxx> +#include "mmdocselectpage.hxx" +#include "mmoutputtypepage.hxx" +#include "mmaddressblockpage.hxx" +#include "mmgreetingspage.hxx" +#include "mmlayoutpage.hxx" +#include <mmconfigitem.hxx> +#include <swabstdlg.hxx> +#include <strings.hrc> +#include <utility> +#include <view.hxx> + +#include <helpids.h> + +using namespace svt; +using namespace ::com::sun::star; + +SwMailMergeWizard::SwMailMergeWizard(SwView& rView, std::shared_ptr<SwMailMergeConfigItem> xItem) + : RoadmapWizardMachine(rView.GetFrameWeld()) + , m_pSwView(&rView) + , m_bDocumentLoad(false) + , m_xConfigItem(std::move(xItem)) + , m_sStarting(SwResId(ST_STARTING)) + , m_sDocumentType(SwResId(ST_DOCUMENTTYPE)) + , m_sAddressBlock(SwResId(ST_ADDRESSBLOCK)) + , m_sAddressList(SwResId(ST_ADDRESSLIST)) + , m_sGreetingsLine(SwResId(ST_GREETINGSLINE)) + , m_sLayout(SwResId(ST_LAYOUT)) + , m_nRestartPage(MM_DOCUMENTSELECTPAGE) +{ + defaultButton(WizardButtonFlags::NEXT); + enableButtons(WizardButtonFlags::FINISH, false); + + setTitleBase(SwResId(ST_MMWTITLE)); + + m_xFinish->set_label(SwResId( ST_FINISH )); + m_xNextPage->set_help_id(HID_MM_NEXT_PAGE); + m_xPrevPage->set_help_id(HID_MM_PREV_PAGE); + + //#i51949# no output type page visible if e-Mail is not supported + if (m_xConfigItem->IsMailAvailable()) + declarePath( + 0, + {MM_DOCUMENTSELECTPAGE, + MM_OUTPUTTYPETPAGE, + MM_ADDRESSBLOCKPAGE, + MM_GREETINGSPAGE, + MM_LAYOUTPAGE} + ); + else + declarePath( + 0, + {MM_DOCUMENTSELECTPAGE, + MM_ADDRESSBLOCKPAGE, + MM_GREETINGSPAGE, + MM_LAYOUTPAGE} + ); + + ActivatePage(); + m_xAssistant->set_current_page(0); + UpdateRoadmap(); +} + +SwMailMergeWizard::~SwMailMergeWizard() +{ +} + +std::unique_ptr<BuilderPage> SwMailMergeWizard::createPage(WizardState _nState) +{ + OUString sIdent(OUString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + std::unique_ptr<vcl::OWizardPage> xRet; + switch(_nState) + { + case MM_DOCUMENTSELECTPAGE : + xRet = std::make_unique<SwMailMergeDocSelectPage>(pPageContainer, this); + + /* tdf#52986 Set help ID using SetRoadmapHelpId for all pages + so that when by default the focus is on the left side pane of + the wizard the relevant help page is displayed when hitting + the Help / F1 button */ + SetRoadmapHelpId("modules/swriter/ui/mmselectpage/MMSelectPage"); + break; + case MM_OUTPUTTYPETPAGE : + xRet = std::make_unique<SwMailMergeOutputTypePage>(pPageContainer, this); + SetRoadmapHelpId("modules/swriter/ui/mmoutputtypepage/MMOutputTypePage"); + break; + case MM_ADDRESSBLOCKPAGE : + xRet = std::make_unique<SwMailMergeAddressBlockPage>(pPageContainer, this); + SetRoadmapHelpId("modules/swriter/ui/mmaddressblockpage/MMAddressBlockPage"); + break; + case MM_GREETINGSPAGE : + xRet = std::make_unique<SwMailMergeGreetingsPage>(pPageContainer, this); + SetRoadmapHelpId("modules/swriter/ui/mmsalutationpage/MMSalutationPage"); + break; + case MM_LAYOUTPAGE : + xRet = std::make_unique<SwMailMergeLayoutPage>(pPageContainer, this); + SetRoadmapHelpId("modules/swriter/ui/mmlayoutpage/MMLayoutPage"); + break; + } + + m_xAssistant->set_page_title(sIdent, getStateDisplayName(_nState)); + + OSL_ENSURE(xRet, "no page created in ::createPage"); + return xRet; +} + +void SwMailMergeWizard::enterState( WizardState _nState ) +{ + ::vcl::RoadmapWizardMachine::enterState( _nState ); + + if (m_xConfigItem->GetTargetView()) + { + //close the dialog, remove the target view, show the source view + m_nRestartPage = _nState; + //set ResultSet back to start + m_xConfigItem->MoveResultSet(1); + m_xAssistant->response(RET_REMOVE_TARGET); + return; + } + bool bEnablePrev = true; + bool bEnableNext = true; + switch(_nState) + { + case MM_DOCUMENTSELECTPAGE: + { + bEnablePrev = false; // the first page + + OUString sDataSourceName = GetSwView()->GetDataSourceName(); + if(!sDataSourceName.isEmpty() && + !SwView::IsDataSourceAvailable(sDataSourceName)) + { + bEnableNext = false; + } + } + break; + case MM_ADDRESSBLOCKPAGE : + bEnableNext = m_xConfigItem->GetResultSet().is(); + break; + case MM_LAYOUTPAGE: + bEnableNext = false; // the last page + break; + } + enableButtons( WizardButtonFlags::PREVIOUS, bEnablePrev); + enableButtons( WizardButtonFlags::NEXT, bEnableNext); + + UpdateRoadmap(); +} + +OUString SwMailMergeWizard::getStateDisplayName( WizardState _nState ) const +{ + switch(_nState) + { + case MM_DOCUMENTSELECTPAGE: + return m_sStarting; + case MM_OUTPUTTYPETPAGE: + return m_sDocumentType; + case MM_ADDRESSBLOCKPAGE: + return m_xConfigItem->IsOutputToLetter() ? + m_sAddressBlock : m_sAddressList; + case MM_GREETINGSPAGE: + return m_sGreetingsLine; + case MM_LAYOUTPAGE: + return m_sLayout; + } + return OUString(); +} + +// enables/disables pages in the roadmap depending on the current page and state +void SwMailMergeWizard::UpdateRoadmap() +{ +/* + MM_DOCUMENTSELECTPAGE > inactive after the layoutpage + MM_OUTPUTTYPETPAGE : > inactive after the layoutpage + MM_ADDRESSBLOCKPAGE > inactive after the layoutpage + MM_GREETINGSPAGE > inactive after the layoutpage + MM_LAYOUTPAGE > inactive after the layoutpage + inactive if address block and greeting are switched off + or are already inserted into the source document +*/ + + // enableState( <page id>, false ); + const sal_uInt16 nCurPage = m_xAssistant->get_current_page(); + BuilderPage* pCurPage = GetPage( nCurPage ); + if(!pCurPage) + return; + bool bAddressFieldsConfigured = !m_xConfigItem->IsOutputToLetter() || + !m_xConfigItem->IsAddressBlock() || + m_xConfigItem->IsAddressFieldsAssigned(); + bool bGreetingFieldsConfigured = !m_xConfigItem->IsGreetingLine(false) || + !m_xConfigItem->IsIndividualGreeting(false) || + m_xConfigItem->IsGreetingFieldsAssigned(); + + //#i97436# if a document has to be loaded then enable output type page only + m_bDocumentLoad = false; + bool bEnableOutputTypePage = (nCurPage != MM_DOCUMENTSELECTPAGE) || + static_cast<vcl::OWizardPage*>(pCurPage)->commitPage( ::vcl::WizardTypes::eValidate ); + + // handle the Finish button + bool bCanFinish = !m_bDocumentLoad && bEnableOutputTypePage && + m_xConfigItem->GetResultSet().is() && + bAddressFieldsConfigured && + bGreetingFieldsConfigured; + enableButtons(WizardButtonFlags::FINISH, (nCurPage != MM_DOCUMENTSELECTPAGE) && bCanFinish); + + for(sal_uInt16 nPage = MM_DOCUMENTSELECTPAGE; nPage <= MM_LAYOUTPAGE; ++nPage) + { + bool bEnable = true; + switch(nPage) + { + case MM_DOCUMENTSELECTPAGE: + bEnable = true; + break; + case MM_OUTPUTTYPETPAGE: + bEnable = bEnableOutputTypePage; + break; + case MM_ADDRESSBLOCKPAGE: + bEnable = !m_bDocumentLoad && bEnableOutputTypePage; + // update page title for email vs letter + m_xAssistant->set_page_title(OUString::number(MM_ADDRESSBLOCKPAGE), getStateDisplayName(MM_ADDRESSBLOCKPAGE)); + break; + case MM_GREETINGSPAGE: + bEnable = !m_bDocumentLoad && bEnableOutputTypePage && + m_xConfigItem->GetResultSet().is() && + bAddressFieldsConfigured; + break; + case MM_LAYOUTPAGE: + bEnable = bCanFinish && + ((m_xConfigItem->IsAddressBlock() && !m_xConfigItem->IsAddressInserted()) || + (m_xConfigItem->IsGreetingLine(false) && !m_xConfigItem->IsGreetingInserted() )); + break; + } + enableState( nPage, bEnable ); + } +} + +short SwMailMergeWizard::run() +{ + OSL_FAIL("SwMailMergeWizard cannot be executed via Dialog::Execute!\n" + "It creates a thread (MailDispatcher instance) that will call" + "back to VCL apartment => deadlock!\n" + "Use Dialog::StartExecuteAsync to execute the dialog!" ); + return RET_CANCEL; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/mmaddressblockpage.cxx b/sw/source/ui/dbui/mmaddressblockpage.cxx new file mode 100644 index 0000000000..73811cbf3e --- /dev/null +++ b/sw/source/ui/dbui/mmaddressblockpage.cxx @@ -0,0 +1,1582 @@ +/* -*- 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 "mmaddressblockpage.hxx" +#include <mailmergewizard.hxx> +#include <swtypes.hxx> +#include "addresslistdialog.hxx" +#include <editeng/eeitem.hxx> +#include <o3tl/safeint.hxx> +#include <svl/grabbagitem.hxx> +#include <svl/itemset.hxx> +#include <utility> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <vcl/transfer.hxx> +#include <mmconfigitem.hxx> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdb/XColumn.hpp> +#include <comphelper/sequence.hxx> +#include <comphelper/string.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <vector> +#include <strings.hrc> +#include <mmaddressblockpage.hrc> +#include <helpids.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; + +SwMailMergeAddressBlockPage::SwMailMergeAddressBlockPage(weld::Container* pPage, SwMailMergeWizard* pWizard) + : vcl::OWizardPage(pPage, pWizard, "modules/swriter/ui/mmaddressblockpage.ui", "MMAddressBlockPage") + , m_pWizard(pWizard) + , m_xAddressListPB(m_xBuilder->weld_button("addresslist")) + , m_xCurrentAddressFI(m_xBuilder->weld_label("currentaddress")) + , m_xStep2(m_xBuilder->weld_container("step2")) + , m_xStep3(m_xBuilder->weld_container("step3")) + , m_xStep4(m_xBuilder->weld_container("step4")) + , m_xSettingsFI(m_xBuilder->weld_label("settingsft")) + , m_xAddressCB(m_xBuilder->weld_check_button("address")) + , m_xSettingsPB(m_xBuilder->weld_button("settings")) + , m_xHideEmptyParagraphsCB(m_xBuilder->weld_check_button("hideempty")) + , m_xAssignPB(m_xBuilder->weld_button("assign")) + , m_xDocumentIndexFI(m_xBuilder->weld_label("documentindex")) + , m_xPrevSetIB(m_xBuilder->weld_button("prev")) + , m_xNextSetIB(m_xBuilder->weld_button("next")) + , m_xDifferentlist(m_xBuilder->weld_button("differentlist")) + , m_xSettings(new SwAddressPreview(m_xBuilder->weld_scrolled_window("settingspreviewwin", true))) + , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("addresspreviewwin", true))) + , m_xSettingsWIN(new weld::CustomWeld(*m_xBuilder, "settingspreview", *m_xSettings)) + , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "addresspreview", *m_xPreview)) +{ + m_xSettingsWIN->set_size_request(m_xDifferentlist->get_approximate_digit_width() * 40, + m_xDifferentlist->get_text_height() * 6); + m_xPreviewWIN->set_size_request(m_xDifferentlist->get_approximate_digit_width() * 44, + m_xDifferentlist->get_text_height() * 6); + m_sChangeAddress = m_xDifferentlist->get_label(); + m_sDocument = m_xDocumentIndexFI->get_label(); + + m_sCurrentAddress = m_xCurrentAddressFI->get_label(); + m_xAddressListPB->connect_clicked(LINK(this, SwMailMergeAddressBlockPage, AddressListHdl_Impl)); + m_xSettingsPB->connect_clicked(LINK(this, SwMailMergeAddressBlockPage, SettingsHdl_Impl)); + m_xAssignPB->connect_clicked(LINK(this, SwMailMergeAddressBlockPage, AssignHdl_Impl )); + m_xAddressCB->connect_toggled(LINK(this, SwMailMergeAddressBlockPage, AddressBlockHdl_Impl)); + m_xSettings->SetSelectHdl(LINK(this, SwMailMergeAddressBlockPage, AddressBlockSelectHdl_Impl)); + m_xHideEmptyParagraphsCB->connect_toggled(LINK(this, SwMailMergeAddressBlockPage, HideParagraphsHdl_Impl)); + + Link<weld::Button&,void> aLink = LINK(this, SwMailMergeAddressBlockPage, InsertDataHdl_Impl); + m_xPrevSetIB->connect_clicked(aLink); + m_xNextSetIB->connect_clicked(aLink); + + // lock in preferred size including current address line + Size aSize1(m_xContainer->get_preferred_size()); + + OUString sOrigLabel = m_xAddressListPB->get_label(); + m_xAddressListPB->set_label(m_sChangeAddress); + Size aSize2(m_xContainer->get_preferred_size()); + m_xAddressListPB->set_label(sOrigLabel); + + m_xCurrentAddressFI->hide(); + + m_xContainer->set_size_request(std::max(aSize1.Width(), aSize2.Width()), + std::max(aSize1.Height(), aSize2.Height())); +} + +SwMailMergeAddressBlockPage::~SwMailMergeAddressBlockPage() +{ + m_xPreviewWIN.reset(); + m_xSettingsWIN.reset(); + m_xPreview.reset(); + m_xSettings.reset(); +} + +bool SwMailMergeAddressBlockPage::canAdvance() const +{ + return m_pWizard->GetConfigItem().GetResultSet().is(); +} + +void SwMailMergeAddressBlockPage::Activate() +{ + SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); + bool bIsLetter = rConfigItem.IsOutputToLetter(); + + //no address block is created for e-Mail + m_xStep2->set_visible(bIsLetter); + m_xStep3->set_visible(bIsLetter); + m_xStep4->set_visible(bIsLetter); + + if (!bIsLetter) + return; + + m_xHideEmptyParagraphsCB->set_active( rConfigItem.IsHideEmptyParagraphs() ); + m_xDocumentIndexFI->set_label(m_sDocument.replaceFirst("%1", "1")); + + m_xSettings->Clear(); + const uno::Sequence< OUString> aBlocks = + m_pWizard->GetConfigItem().GetAddressBlocks(); + for(const auto& rAddress : aBlocks) + m_xSettings->AddAddress(rAddress); + m_xSettings->SelectAddress(o3tl::narrowing<sal_uInt16>(rConfigItem.GetCurrentAddressBlockIndex())); + m_xAddressCB->set_active(rConfigItem.IsAddressBlock()); + AddressBlockHdl_Impl(*m_xAddressCB); + m_xSettings->SetLayout(1, 2); + InsertDataHdl(nullptr); +} + +bool SwMailMergeAddressBlockPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) +{ + return ::vcl::WizardTypes::eTravelForward != _eReason || m_pWizard->GetConfigItem().GetResultSet().is(); +} + +IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, AddressListHdl_Impl, weld::Button&, void) +{ + try + { + SwAddressListDialog aAddrDialog(this); + if (RET_OK == aAddrDialog.run()) + { + SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); + rConfigItem.SetCurrentConnection( + aAddrDialog.GetSource(), + aAddrDialog.GetConnection(), + aAddrDialog.GetColumnsSupplier(), + aAddrDialog.GetDBData()); + OUString sFilter = aAddrDialog.GetFilter(); + rConfigItem.SetFilter( sFilter ); + InsertDataHdl(nullptr); + GetWizard()->UpdateRoadmap(); + GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE)); + } + } + catch (const uno::Exception& e) + { + TOOLS_WARN_EXCEPTION("sw", ""); + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_pWizard->getDialog(), + VclMessageType::Warning, VclButtonsType::Ok, e.Message)); + xBox->run(); + } +} + +IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, SettingsHdl_Impl, weld::Button&, void) +{ + SwSelectAddressBlockDialog aDlg(m_pWizard->getDialog(), m_pWizard->GetConfigItem()); + SwMailMergeConfigItem& rConfig = m_pWizard->GetConfigItem(); + aDlg.SetAddressBlocks(rConfig.GetAddressBlocks(), m_xSettings->GetSelectedAddress()); + aDlg.SetSettings(rConfig.IsIncludeCountry(), rConfig.GetExcludeCountry()); + if (aDlg.run() == RET_OK) + { + //the dialog provides the selected address at the first position! + const uno::Sequence< OUString> aBlocks = aDlg.GetAddressBlocks(); + rConfig.SetAddressBlocks(aBlocks); + m_xSettings->Clear(); + for(const auto& rAddress : aBlocks) + m_xSettings->AddAddress(rAddress); + m_xSettings->SelectAddress(0); + m_xSettings->Invalidate(); // #i40408 + rConfig.SetCountrySettings(aDlg.IsIncludeCountry(), aDlg.GetCountry()); + InsertDataHdl(nullptr); + } + GetWizard()->UpdateRoadmap(); + GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE)); +} + +IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, AssignHdl_Impl, weld::Button&, void) +{ + SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); + const sal_uInt16 nSel = m_xSettings->GetSelectedAddress(); + const uno::Sequence< OUString> aBlocks = rConfigItem.GetAddressBlocks(); + SwAssignFieldsDialog aDlg(m_pWizard->getDialog(), m_pWizard->GetConfigItem(), aBlocks[nSel], true); + if(RET_OK == aDlg.run()) + { + //preview update + InsertDataHdl(nullptr); + GetWizard()->UpdateRoadmap(); + GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE)); + } +} + +void SwMailMergeAddressBlockPage::EnableAddressBlock(bool bAll, bool bSelective) +{ + m_xSettingsFI->set_sensitive(bAll); + m_xAddressCB->set_sensitive(bAll); + bSelective &= bAll; + m_xHideEmptyParagraphsCB->set_sensitive(bSelective); + m_xSettingsWIN->set_sensitive(bSelective); + m_xSettingsPB->set_sensitive(bSelective); + m_xStep3->set_sensitive(bSelective); + m_xStep4->set_sensitive(bSelective); +} + +IMPL_LINK(SwMailMergeAddressBlockPage, AddressBlockHdl_Impl, weld::Toggleable&, rBox, void) +{ + EnableAddressBlock(rBox.get_sensitive(), rBox.get_active()); + SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); + rConfigItem.SetAddressBlock(m_xAddressCB->get_active()); + m_pWizard->UpdateRoadmap(); + GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE)); +} + +IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, AddressBlockSelectHdl_Impl, LinkParamNone*, void) +{ + const sal_uInt16 nSel = m_xSettings->GetSelectedAddress(); + const uno::Sequence< OUString> aBlocks = + m_pWizard->GetConfigItem().GetAddressBlocks(); + m_xPreview->SetAddress(SwAddressPreview::FillData(aBlocks[nSel], + m_pWizard->GetConfigItem())); + m_pWizard->GetConfigItem().SetCurrentAddressBlockIndex( nSel ); + GetWizard()->UpdateRoadmap(); + GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE)); +} + +IMPL_LINK(SwMailMergeAddressBlockPage, HideParagraphsHdl_Impl, weld::Toggleable&, rBox, void) +{ + SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); + rConfigItem.SetHideEmptyParagraphs(rBox.get_active()); +} + +void SwMailMergeAddressBlockPage::InsertDataHdl(const weld::Button* pButton) +{ + //if no pButton is given, the first set has to be pre-set + SwMailMergeConfigItem& rConfig = m_pWizard->GetConfigItem(); + std::unique_ptr<weld::WaitObject> xWaitObj(new weld::WaitObject(m_pWizard->getDialog())); + if(!pButton) + { + rConfig.GetResultSet(); + } + else + { + bool bNext = pButton == m_xNextSetIB.get(); + sal_Int32 nPos = rConfig.GetResultSetPosition(); + rConfig.MoveResultSet( bNext ? ++nPos : --nPos); + } + xWaitObj.reset(); + sal_Int32 nPos = rConfig.GetResultSetPosition(); + bool bEnable = true; + if(nPos < 1) + { + bEnable = false; + nPos = 1; + } + else + { + //if output type is letter + if (m_xSettings->IsVisible()) + { + //Fill data into preview + const sal_uInt16 nSel = m_xSettings->GetSelectedAddress(); + const uno::Sequence< OUString> aBlocks = + m_pWizard->GetConfigItem().GetAddressBlocks(); + m_xPreview->SetAddress(SwAddressPreview::FillData(aBlocks[nSel], rConfig)); + } + } + m_xPrevSetIB->set_sensitive(bEnable); + m_xDocumentIndexFI->set_label(m_sDocument.replaceFirst("%1", OUString::number(nPos))); + + GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE)); + bool bHasResultSet = rConfig.GetResultSet().is(); + m_xCurrentAddressFI->set_visible(bHasResultSet); + if(bHasResultSet) + { + m_xCurrentAddressFI->set_label(m_sCurrentAddress.replaceFirst("%1", rConfig.GetCurrentDBData().sDataSource)); + m_xAddressListPB->set_label(m_sChangeAddress); + } + EnableAddressBlock(bHasResultSet, m_xAddressCB->get_active()); +} + +IMPL_LINK(SwMailMergeAddressBlockPage, InsertDataHdl_Impl, weld::Button&, rButton, void) +{ + InsertDataHdl(&rButton); +} + +SwSelectAddressBlockDialog::SwSelectAddressBlockDialog(weld::Window* pParent, SwMailMergeConfigItem& rConfig) + : SfxDialogController(pParent, "modules/swriter/ui/selectblockdialog.ui", "SelectBlockDialog") + , m_rConfig(rConfig) + , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin", true))) + , m_xNewPB(m_xBuilder->weld_button("new")) + , m_xCustomizePB(m_xBuilder->weld_button("edit")) + , m_xDeletePB(m_xBuilder->weld_button("delete")) + , m_xNeverRB(m_xBuilder->weld_radio_button("never")) + , m_xAlwaysRB(m_xBuilder->weld_radio_button("always")) + , m_xDependentRB(m_xBuilder->weld_radio_button("dependent")) + , m_xCountryED(m_xBuilder->weld_entry("country")) + , m_xPreviewWin(new weld::CustomWeld(*m_xBuilder, "preview", *m_xPreview)) +{ + m_xPreviewWin->set_size_request(m_xCountryED->get_approximate_digit_width() * 45, + m_xCountryED->get_text_height() * 12); + + Link<weld::Button&,void> aCustomizeHdl = LINK(this, SwSelectAddressBlockDialog, NewCustomizeHdl_Impl); + m_xNewPB->connect_clicked(aCustomizeHdl); + m_xCustomizePB->connect_clicked(aCustomizeHdl); + + m_xDeletePB->connect_clicked(LINK(this, SwSelectAddressBlockDialog, DeleteHdl_Impl)); + + Link<weld::Toggleable&,void> aLk = LINK(this, SwSelectAddressBlockDialog, IncludeHdl_Impl); + m_xNeverRB->connect_toggled(aLk); + m_xAlwaysRB->connect_toggled(aLk); + m_xDependentRB->connect_toggled(aLk); + m_xPreview->SetLayout(2, 2); + m_xPreview->EnableScrollBar(); +} + +SwSelectAddressBlockDialog::~SwSelectAddressBlockDialog() +{ +} + +void SwSelectAddressBlockDialog::SetAddressBlocks(const uno::Sequence< OUString>& rBlocks, + sal_uInt16 nSelectedAddress) +{ + m_aAddressBlocks = rBlocks; + for (const auto& rAddressBlock : std::as_const(m_aAddressBlocks)) + m_xPreview->AddAddress(rAddressBlock); + m_xPreview->SelectAddress(nSelectedAddress); +} + +// return the address blocks and put the selected one to the first position +const uno::Sequence< OUString >& SwSelectAddressBlockDialog::GetAddressBlocks() +{ + //put the selected block to the first position + const sal_Int32 nSelect = static_cast<sal_Int32>(m_xPreview->GetSelectedAddress()); + if(nSelect) + { + uno::Sequence< OUString >aTemp(m_aAddressBlocks.getLength()); + auto it = aTemp.getArray(); + *it = std::as_const(m_aAddressBlocks)[nSelect]; + it = std::copy_n(std::cbegin(m_aAddressBlocks), nSelect - 1, std::next(it)); + std::copy(std::next(std::cbegin(m_aAddressBlocks), nSelect + 1), std::cend(m_aAddressBlocks), it); + m_aAddressBlocks = aTemp; + } + return m_aAddressBlocks; +} + +void SwSelectAddressBlockDialog::SetSettings( + bool bIsCountry, const OUString& rCountry) +{ + weld::RadioButton *pActive = m_xNeverRB.get(); + if(bIsCountry) + { + pActive = !rCountry.isEmpty() ? m_xDependentRB.get() : m_xAlwaysRB.get(); + m_xCountryED->set_text(rCountry); + } + pActive->set_active(true); + IncludeHdl_Impl(*pActive); + m_xDeletePB->set_sensitive(m_aAddressBlocks.getLength() > 1); +} + +OUString SwSelectAddressBlockDialog::GetCountry() const +{ + if (m_xDependentRB->get_active()) + return m_xCountryED->get_text(); + return OUString(); +} + +IMPL_LINK(SwSelectAddressBlockDialog, DeleteHdl_Impl, weld::Button&, rButton, void) +{ + if (m_aAddressBlocks.getLength()) + { + const sal_Int32 nSelected = static_cast<sal_Int32>(m_xPreview->GetSelectedAddress()); + comphelper::removeElementAt(m_aAddressBlocks, nSelected); + if (m_aAddressBlocks.getLength() <= 1) + rButton.set_sensitive(false); + m_xPreview->RemoveSelectedAddress(); + } +} + +IMPL_LINK(SwSelectAddressBlockDialog, NewCustomizeHdl_Impl, weld::Button&, rButton, void) +{ + bool bCustomize = &rButton == m_xCustomizePB.get(); + SwCustomizeAddressBlockDialog::DialogType nType = bCustomize ? + SwCustomizeAddressBlockDialog::ADDRESSBLOCK_EDIT : + SwCustomizeAddressBlockDialog::ADDRESSBLOCK_NEW; + std::unique_ptr<SwCustomizeAddressBlockDialog> xDlg(new SwCustomizeAddressBlockDialog(&rButton, + m_rConfig, nType)); + if(bCustomize) + { + xDlg->SetAddress(m_aAddressBlocks[m_xPreview->GetSelectedAddress()]); + } + if (RET_OK != xDlg->run()) + return; + + const OUString sNew = xDlg->GetAddress(); + if(bCustomize) + { + m_xPreview->ReplaceSelectedAddress(sNew); + m_aAddressBlocks.getArray()[m_xPreview->GetSelectedAddress()] = sNew; + } + else + { + m_xPreview->AddAddress(sNew); + m_aAddressBlocks.realloc(m_aAddressBlocks.getLength() + 1); + const sal_Int32 nSelect = m_aAddressBlocks.getLength() - 1; + m_aAddressBlocks.getArray()[nSelect] = sNew; + m_xPreview->SelectAddress(o3tl::narrowing<sal_uInt16>(nSelect)); + } + m_xDeletePB->set_sensitive(m_aAddressBlocks.getLength() > 1); +} + +IMPL_LINK_NOARG(SwSelectAddressBlockDialog, IncludeHdl_Impl, weld::Toggleable&, void) +{ + m_xCountryED->set_sensitive(m_xDependentRB->get_active()); +} + +#define USER_DATA_SALUTATION -1 +#define USER_DATA_PUNCTUATION -2 +#define USER_DATA_TEXT -3 +#define USER_DATA_NONE -4 + +IMPL_LINK(SwCustomizeAddressBlockDialog, TextFilterHdl, OUString&, rTest, bool) +{ + rTest = m_aTextFilter.filter(rTest); + return true; +} + +SwCustomizeAddressBlockDialog::SwCustomizeAddressBlockDialog( + weld::Widget* pParent, SwMailMergeConfigItem& rConfig, DialogType eType) + : SfxDialogController(pParent, "modules/swriter/ui/addressblockdialog.ui", + "AddressBlockDialog") + , m_aTextFilter("<>") + , m_rConfigItem(rConfig) + , m_eType(eType) + , m_aSelectionChangedIdle("SwCustomizeAddressBlockDialog m_aSelectionChangedIdle") + , m_xAddressElementsFT(m_xBuilder->weld_label("addressesft")) + , m_xAddressElementsLB(m_xBuilder->weld_tree_view("addresses")) + , m_xInsertFieldIB(m_xBuilder->weld_button("toaddr")) + , m_xRemoveFieldIB(m_xBuilder->weld_button("fromaddr")) + , m_xDragFT(m_xBuilder->weld_label("addressdestft")) + , m_xUpIB(m_xBuilder->weld_button("up")) + , m_xLeftIB(m_xBuilder->weld_button("left")) + , m_xRightIB(m_xBuilder->weld_button("right")) + , m_xDownIB(m_xBuilder->weld_button("down")) + , m_xFieldFT(m_xBuilder->weld_label("customft")) + , m_xFieldCB(m_xBuilder->weld_combo_box("custom")) + , m_xOK(m_xBuilder->weld_button("ok")) + , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin", true))) + , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "addrpreview", *m_xPreview)) + , m_xDragED(new AddressMultiLineEdit(this)) + , m_xDragWIN(new weld::CustomWeld(*m_xBuilder, "addressdest", *m_xDragED)) +{ + m_aSelectionChangedIdle.SetInvokeHandler( LINK( this, SwCustomizeAddressBlockDialog, SelectionChangedIdleHdl ) ); + + Size aSize(m_xDragED->GetDrawingArea()->get_size_request()); + m_xPreview->set_size_request(aSize.Width(), aSize.Height()); + + m_xFieldCB->connect_entry_insert_text(LINK(this, SwCustomizeAddressBlockDialog, TextFilterHdl)); + m_xAddressElementsLB->set_size_request(-1, m_xAddressElementsLB->get_height_rows(16)); + + if( eType >= GREETING_FEMALE ) + { + m_xFieldFT->show(); + m_xFieldCB->show(); + m_xAddressElementsLB->append(OUString::number(USER_DATA_SALUTATION), SwResId(ST_SALUTATION)); + m_xAddressElementsLB->append(OUString::number(USER_DATA_PUNCTUATION), SwResId(ST_PUNCTUATION)); + m_xAddressElementsLB->append(OUString::number(USER_DATA_TEXT), SwResId(ST_TEXT)); + for (auto const& aID : RA_SALUTATION) + m_aSalutations.push_back(SwResId(aID)); + for (auto const& aID : RA_PUNCTUATION) + m_aPunctuations.push_back(SwResId(aID)); + m_xDragED->SetText(" "); + m_xDialog->set_title(SwResId(eType == GREETING_MALE ? ST_TITLE_MALE : ST_TITLE_FEMALE)); + m_xAddressElementsFT->set_label(SwResId(ST_SALUTATIONELEMENTS)); + m_xInsertFieldIB->set_tooltip_text(SwResId(ST_INSERTSALUTATIONFIELD)); + m_xRemoveFieldIB->set_tooltip_text(SwResId(ST_REMOVESALUTATIONFIELD)); + m_xDragFT->set_label(SwResId(ST_DRAGSALUTATION)); + } + else + { + if (eType == ADDRESSBLOCK_EDIT) + m_xDialog->set_title(SwResId(ST_TITLE_EDIT)); + m_xDragED->SetText("\n\n\n\n\n"); + /* Set custom HIDs for swriter/01/mm_newaddblo.xhp */ + m_xAddressElementsLB->set_help_id( HID_MM_ADDBLOCK_ELEMENTS ); + m_xInsertFieldIB->set_help_id( HID_MM_ADDBLOCK_INSERT ); + m_xRemoveFieldIB->set_help_id( HID_MM_ADDBLOCK_REMOVE ); + m_xDragWIN->set_help_id( HID_MM_ADDBLOCK_DRAG ); + m_xPreviewWIN->set_help_id( HID_MM_ADDBLOCK_PREVIEW ); + m_xRightIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS ); + m_xLeftIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS ); + m_xDownIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS ); + m_xUpIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS ); + } + + const std::vector<std::pair<OUString, int>>& rHeaders = m_rConfigItem.GetDefaultAddressHeaders(); + for (size_t i = 0; i < rHeaders.size(); ++i) + m_xAddressElementsLB->append(OUString::number(i), rHeaders[i].first); + m_xOK->connect_clicked(LINK(this, SwCustomizeAddressBlockDialog, OKHdl_Impl)); + m_xAddressElementsLB->connect_changed(LINK(this, SwCustomizeAddressBlockDialog, ListBoxSelectHdl_Impl)); + if (m_xAddressElementsLB->n_children()) + m_xAddressElementsLB->select(0); + m_xDragED->SetModifyHdl(LINK(this, SwCustomizeAddressBlockDialog, EditModifyHdl_Impl)); + m_xDragED->SetSelectionChangedHdl( LINK( this, SwCustomizeAddressBlockDialog, SelectionChangedHdl_Impl)); + m_xFieldCB->connect_changed(LINK(this, SwCustomizeAddressBlockDialog, FieldChangeComboBoxHdl_Impl)); + Link<weld::Button&,void> aImgButtonHdl = LINK(this, SwCustomizeAddressBlockDialog, ImageButtonHdl_Impl); + m_xInsertFieldIB->connect_clicked(aImgButtonHdl); + m_xRemoveFieldIB->connect_clicked(aImgButtonHdl); + m_xUpIB->connect_clicked(aImgButtonHdl); + m_xLeftIB->connect_clicked(aImgButtonHdl); + m_xRightIB->connect_clicked(aImgButtonHdl); + m_xDownIB->connect_clicked(aImgButtonHdl); + UpdateImageButtons_Impl(); +} + +bool SwCustomizeAddressBlockDialog::SetCursorLogicPosition(const Point& rPosition) +{ + return m_xDragED->SetCursorLogicPosition(rPosition); +} + +void SwCustomizeAddressBlockDialog::UpdateFields() +{ + m_xDragED->UpdateFields(); +} + +SwCustomizeAddressBlockDialog::~SwCustomizeAddressBlockDialog() +{ + m_xDragED->EndDropTarget(); +} + +IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, OKHdl_Impl, weld::Button&, void) +{ + m_xDialog->response(RET_OK); +} + +IMPL_LINK(SwCustomizeAddressBlockDialog, ListBoxSelectHdl_Impl, weld::TreeView&, rBox, void) +{ + sal_Int32 nUserData = rBox.get_selected_id().toInt32(); + // Check if the selected entry is already in the address and then forbid inserting + m_xInsertFieldIB->set_sensitive(nUserData >= 0 || !HasItem(nUserData)); +} + +IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, EditModifyHdl_Impl, AddressMultiLineEdit&, void) +{ + m_xPreview->SetAddress(SwAddressPreview::FillData(GetAddress(), m_rConfigItem)); + UpdateImageButtons_Impl(); +} + +IMPL_LINK(SwCustomizeAddressBlockDialog, ImageButtonHdl_Impl, weld::Button&, rButton, void) +{ + if (m_xInsertFieldIB.get() == &rButton) + { + int nEntry = m_xAddressElementsLB->get_selected_index(); + if (nEntry != -1) + { + m_xDragED->InsertNewEntry("<" + m_xAddressElementsLB->get_text(nEntry) + ">"); + } + } + else if (m_xRemoveFieldIB.get() == &rButton) + { + m_xDragED->RemoveCurrentEntry(); + } + else + { + MoveItemFlags nMove = MoveItemFlags::Down; + if (m_xUpIB.get() == &rButton) + nMove = MoveItemFlags::Up; + else if (m_xLeftIB.get() == &rButton) + nMove = MoveItemFlags::Left; + else if (m_xRightIB.get() == &rButton) + nMove = MoveItemFlags::Right; + m_xDragED->MoveCurrentItem(nMove); + } + UpdateImageButtons_Impl(); +} + +sal_Int32 SwCustomizeAddressBlockDialog::GetSelectedItem_Impl() const +{ + sal_Int32 nRet = USER_DATA_NONE; + const OUString sSelected = m_xDragED->GetCurrentItem(); + if(!sSelected.isEmpty()) + { + for (int i = 0, nEntryCount = m_xAddressElementsLB->n_children(); i < nEntryCount; ++i) + { + const OUString sEntry = m_xAddressElementsLB->get_text(i); + if( sEntry == sSelected.subView( 1, sSelected.getLength() - 2 ) ) + { + nRet = m_xAddressElementsLB->get_id(i).toInt32(); + break; + } + } + } + return nRet; +} + +bool SwCustomizeAddressBlockDialog::HasItem(sal_Int32 nUserData) +{ + //get the entry from the ListBox + OUString sEntry; + for (int i = 0, nEntryCount = m_xAddressElementsLB->n_children(); i < nEntryCount; ++i) + { + if (m_xAddressElementsLB->get_id(i).toInt32() == nUserData) + { + sEntry = m_xAddressElementsLB->get_text(i); + break; + } + } + //search for this entry in the content + return m_xDragED->GetText().indexOf(Concat2View("<" + sEntry + ">")) >= 0; +} + +IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, SelectionChangedIdleHdl, Timer*, void) +{ + // called in case the selection of the edit field changes. + // determine selection - if it's one of the editable fields then + // enable the related ComboBox and fill it + + // don't trigger outself again + m_xDragED->SetSelectionChangedHdl(Link<bool, void>()); + + sal_Int32 nSelected = GetSelectedItem_Impl(); + if (USER_DATA_NONE != nSelected) + m_xDragED->SelectCurrentItem(); + + if(m_xFieldCB->get_visible() && (USER_DATA_NONE != nSelected) && (nSelected < 0)) + { + //search in ListBox if it's one of the first entries + OUString sSelect; + std::vector<OUString>* pVector = nullptr; + switch(nSelected) { + case USER_DATA_SALUTATION: + sSelect = m_sCurrentSalutation; + pVector = &m_aSalutations; + break; + case USER_DATA_PUNCTUATION: + sSelect = m_sCurrentPunctuation; + pVector = &m_aPunctuations; + break; + case USER_DATA_TEXT: + sSelect = m_sCurrentText; + break; + } + m_xFieldCB->clear(); + if(pVector) { + for (const auto& rItem : *pVector) + m_xFieldCB->append_text(rItem); + } + m_xFieldCB->set_entry_text(sSelect); + m_xFieldCB->set_sensitive(true); + m_xFieldFT->set_sensitive(true); + } + else + { + m_xFieldCB->set_sensitive(false); + m_xFieldFT->set_sensitive(false); + } + + UpdateImageButtons_Impl(); + m_xDragED->SetSelectionChangedHdl( LINK( this, SwCustomizeAddressBlockDialog, SelectionChangedHdl_Impl)); +} + +IMPL_LINK(SwCustomizeAddressBlockDialog, SelectionChangedHdl_Impl, bool, bIdle, void) +{ + if (bIdle) + m_aSelectionChangedIdle.Start(); + else + { + m_aSelectionChangedIdle.Stop(); + SelectionChangedIdleHdl(nullptr); + } +} + +IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, FieldChangeComboBoxHdl_Impl, weld::ComboBox&, void) +{ + //changing the field content changes the related members, too + sal_Int32 nSelected = GetSelectedItem_Impl(); + const OUString sContent = m_xFieldCB->get_active_text(); + switch(nSelected) { + case USER_DATA_SALUTATION: + m_sCurrentSalutation = sContent; + break; + case USER_DATA_PUNCTUATION: + m_sCurrentPunctuation = sContent; + break; + case USER_DATA_TEXT: + m_sCurrentText = sContent; + break; + } + UpdateImageButtons_Impl(); + m_xPreview->SetAddress(GetAddress()); + EditModifyHdl_Impl(*m_xDragED); +} + +void SwCustomizeAddressBlockDialog::UpdateImageButtons_Impl() +{ + MoveItemFlags nMove = m_xDragED->IsCurrentItemMoveable(); + m_xUpIB->set_sensitive( bool(nMove & MoveItemFlags::Up) ); + m_xLeftIB->set_sensitive( bool(nMove & MoveItemFlags::Left) ); + m_xRightIB->set_sensitive( bool(nMove & MoveItemFlags::Right) ); + m_xDownIB->set_sensitive( bool(nMove & MoveItemFlags::Down) ); + m_xRemoveFieldIB->set_sensitive(m_xDragED->HasCurrentItem()); + int nEntry = m_xAddressElementsLB->get_selected_index(); + m_xInsertFieldIB->set_sensitive( nEntry != -1 && + (m_xAddressElementsLB->get_id(nEntry).toInt32() >= 0 || !m_xFieldCB->get_active_text().isEmpty())); +} + +void SwCustomizeAddressBlockDialog::SetAddress(const OUString& rAddress) +{ + m_xDragED->SetText(rAddress); + UpdateImageButtons_Impl(); + EditModifyHdl_Impl(*m_xDragED); +} + +OUString SwCustomizeAddressBlockDialog::GetAddress() const +{ + OUString sAddress(m_xDragED->GetAddress()); + //remove placeholders by the actual content + if (m_xFieldFT->get_visible()) + { + for (int i = 0, nEntryCount = m_xAddressElementsLB->n_children(); i < nEntryCount; ++i) + { + const OUString sEntry = "<" + m_xAddressElementsLB->get_text(i) + ">"; + sal_Int32 nUserData = m_xAddressElementsLB->get_id(i).toInt32(); + switch(nUserData) + { + case USER_DATA_SALUTATION: + sAddress = sAddress.replaceFirst(sEntry, m_sCurrentSalutation); + break; + case USER_DATA_PUNCTUATION: + sAddress = sAddress.replaceFirst(sEntry, m_sCurrentPunctuation); + break; + case USER_DATA_TEXT: + sAddress = sAddress.replaceFirst(sEntry, m_sCurrentText); + break; + } + } + } + return sAddress; +} + +namespace { + +struct SwAssignFragment +{ + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Label> m_xLabel; + std::unique_ptr<weld::ComboBox> m_xComboBox; + std::unique_ptr<weld::Label> m_xPreview; + + SwAssignFragment(weld::Container* pGrid, int nLine) + : m_xBuilder(Application::CreateBuilder(pGrid, "modules/swriter/ui/assignfragment.ui")) + , m_xLabel(m_xBuilder->weld_label("label")) + , m_xComboBox(m_xBuilder->weld_combo_box("combobox")) + , m_xPreview(m_xBuilder->weld_label("preview")) + { + m_xLabel->set_grid_left_attach(0); + m_xLabel->set_grid_top_attach(nLine); + + m_xComboBox->set_grid_left_attach(1); + m_xComboBox->set_grid_top_attach(nLine); + + m_xPreview->set_grid_left_attach(2); + m_xPreview->set_grid_top_attach(nLine); + } +}; + +} + +class SwAssignFieldsControl +{ + friend class SwAssignFieldsDialog; + std::unique_ptr<weld::ScrolledWindow> m_xVScroll; + std::unique_ptr<weld::Container> m_xGrid; + + std::vector<SwAssignFragment> m_aFields; + + SwMailMergeConfigItem* m_rConfigItem; + + Link<LinkParamNone*,void> m_aModifyHdl; + + DECL_LINK(MatchHdl_Impl, weld::ComboBox&, void); + DECL_LINK(GotFocusHdl_Impl, weld::Widget&, void); + + void MakeVisible(const tools::Rectangle & rRect); +public: + SwAssignFieldsControl(std::unique_ptr<weld::ScrolledWindow> xWindow, + std::unique_ptr<weld::Container> xGrid); + + void Init(SwAssignFieldsDialog* pDialog, SwMailMergeConfigItem& rConfigItem); + void SetModifyHdl(const Link<LinkParamNone*,void>& rModifyHdl) + { + m_aModifyHdl = rModifyHdl; + m_aModifyHdl.Call(nullptr); + } +}; + +SwAssignFieldsControl::SwAssignFieldsControl(std::unique_ptr<weld::ScrolledWindow> xWindow, + std::unique_ptr<weld::Container> xGrid) + : m_xVScroll(std::move(xWindow)) + , m_xGrid(std::move(xGrid)) + , m_rConfigItem(nullptr) +{ +} + +void SwAssignFieldsControl::Init(SwAssignFieldsDialog* pDialog, SwMailMergeConfigItem& rConfigItem) +{ + m_rConfigItem = &rConfigItem; + + //get the name of the default headers + const std::vector<std::pair<OUString, int>>& rHeaders = rConfigItem.GetDefaultAddressHeaders(); + //get the actual data + uno::Reference< XColumnsSupplier > xColsSupp( rConfigItem.GetResultSet(), uno::UNO_QUERY); + //get the name of the actual columns + uno::Reference <XNameAccess> xColAccess = xColsSupp.is() ? xColsSupp->getColumns() : nullptr; + uno::Sequence< OUString > aFields; + if(xColAccess.is()) + aFields = xColAccess->getElementNames(); + + //get the current assignment list + //each position in this sequence matches the position in the header array rHeaders + //if no assignment is available an empty sequence will be returned + uno::Sequence< OUString> aAssignments = rConfigItem.GetColumnAssignment( rConfigItem.GetCurrentDBData() ); + Link<weld::ComboBox&,void> aMatchHdl = LINK(this, SwAssignFieldsControl, MatchHdl_Impl); + Link<weld::Widget&,void> aFocusHdl = LINK(this, SwAssignFieldsControl, GotFocusHdl_Impl); + + int nLabelWidth(0), nComboBoxWidth(0), nPreviewWidth(0); + + //fill the controls + for (size_t i = 0; i < rHeaders.size(); ++i) + { + m_aFields.emplace_back(m_xGrid.get(), i); + + const OUString rHeader = rHeaders[i].first; + weld::ComboBox& rNewLB = *m_aFields.back().m_xComboBox; + rNewLB.append_text(SwResId(SW_STR_NONE)); + rNewLB.set_active(0); + + for (const OUString& rField : std::as_const(aFields)) + rNewLB.append_text(rField); + //select the ListBox + //if there is an assignment + if(o3tl::make_unsigned(aAssignments.getLength()) > i && !aAssignments[i].isEmpty()) + rNewLB.set_active_text(aAssignments[i]); + else //otherwise the current column name may match one of the db columns + rNewLB.set_active_text(rHeader); + + weld::Label& rNewText = *m_aFields.back().m_xLabel; + rNewText.set_label("<" + rHeader + ">"); + + weld::Label& rNewPreview = *m_aFields.back().m_xPreview; + //then the preview can be filled accordingly + if (xColAccess.is() && rNewLB.get_active() > 0 && + xColAccess->hasByName(rNewLB.get_active_text())) + { + uno::Any aCol = xColAccess->getByName(rNewLB.get_active_text()); + uno::Reference< XColumn > xColumn; + aCol >>= xColumn; + if(xColumn.is()) + { + try + { + rNewPreview.set_label(xColumn->getString()); + } + catch (const SQLException&) + { + } + } + } + + if (i == 0) + { + auto nLineHeight = m_xGrid->get_preferred_size().Height(); + m_xVScroll->set_size_request(m_xVScroll->get_approximate_digit_width() * 65, + nLineHeight * 6); + nComboBoxWidth = rNewLB.get_preferred_size().Width(); + } + + nLabelWidth = std::max<int>(nLabelWidth, rNewText.get_preferred_size().Width()); + nPreviewWidth = std::max<int>(nPreviewWidth, rNewPreview.get_preferred_size().Width()); + + rNewLB.connect_changed(aMatchHdl); + rNewLB.connect_focus_in(aFocusHdl); + rNewText.show(); + rNewLB.show(); + rNewPreview.show(); + } + pDialog->ConnectSizeGroups(nLabelWidth, nComboBoxWidth, nPreviewWidth); +} + +void SwAssignFieldsControl::MakeVisible(const tools::Rectangle & rRect) +{ + //determine range of visible positions + auto nMinVisiblePos = m_xVScroll->vadjustment_get_value(); + auto nMaxVisiblePos = nMinVisiblePos + m_xVScroll->vadjustment_get_page_size(); + if (rRect.Top() < nMinVisiblePos || rRect.Bottom() > nMaxVisiblePos) + m_xVScroll->vadjustment_set_value(rRect.Top()); +} + +IMPL_LINK(SwAssignFieldsControl, MatchHdl_Impl, weld::ComboBox&, rBox, void) +{ + const OUString sColumn = rBox.get_active_text(); + uno::Reference< XColumnsSupplier > xColsSupp( m_rConfigItem->GetResultSet(), uno::UNO_QUERY); + uno::Reference <XNameAccess> xColAccess = xColsSupp.is() ? xColsSupp->getColumns() : nullptr; + OUString sPreview; + if(xColAccess.is() && xColAccess->hasByName(sColumn)) + { + uno::Any aCol = xColAccess->getByName(sColumn); + uno::Reference< XColumn > xColumn; + aCol >>= xColumn; + if(xColumn.is()) + { + try + { + sPreview = xColumn->getString(); + } + catch (const sdbc::SQLException&) + { + } + } + } + auto aLBIter = std::find_if(m_aFields.begin(), m_aFields.end(), [&rBox](const SwAssignFragment& rFragment){ + return &rBox == rFragment.m_xComboBox.get(); }); + if (aLBIter != m_aFields.end()) + { + auto nIndex = static_cast<sal_Int32>(std::distance(m_aFields.begin(), aLBIter)); + m_aFields[nIndex].m_xPreview->set_label(sPreview); + } + m_aModifyHdl.Call(nullptr); +} + +IMPL_LINK(SwAssignFieldsControl, GotFocusHdl_Impl, weld::Widget&, rBox, void) +{ + int x, y, width, height; + rBox.get_extents_relative_to(*m_xGrid, x, y, width, height); + // the container has a border of 3 in the .ui + tools::Rectangle aRect(Point(x - 3, y - 3), Size(width + 6, height + 6)); + MakeVisible(aRect); +} + +SwAssignFieldsDialog::SwAssignFieldsDialog( + weld::Window* pParent, SwMailMergeConfigItem& rConfigItem, + OUString aPreview, + bool bIsAddressBlock) + : SfxDialogController(pParent, "modules/swriter/ui/assignfieldsdialog.ui", "AssignFieldsDialog") + , m_sNone(SwResId(SW_STR_NONE)) + , m_rPreviewString(std::move(aPreview)) + , m_rConfigItem(rConfigItem) + , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin", true))) + , m_xMatchingFI(m_xBuilder->weld_label("MATCHING_LABEL")) + , m_xAddressTitle(m_xBuilder->weld_label("addresselem")) + , m_xMatchTitle(m_xBuilder->weld_label("matchelem")) + , m_xPreviewTitle(m_xBuilder->weld_label("previewelem")) + , m_xPreviewFI(m_xBuilder->weld_label("PREVIEW_LABEL")) + , m_xOK(m_xBuilder->weld_button("ok")) + , m_xPreviewWin(new weld::CustomWeld(*m_xBuilder, "PREVIEW", *m_xPreview)) + , m_xFieldsControl(new SwAssignFieldsControl(m_xBuilder->weld_scrolled_window("scroll"), + m_xBuilder->weld_container("FIELDS"))) +{ + m_xPreviewWin->set_size_request(m_xMatchingFI->get_approximate_digit_width() * 45, + m_xMatchingFI->get_text_height() * 5); + m_xFieldsControl->Init(this, rConfigItem); + + const OUString sMatchesTo( SwResId(ST_MATCHESTO) ); + if (!bIsAddressBlock) + { + m_xPreviewFI->set_label(SwResId(ST_SALUTATIONPREVIEW)); + m_xMatchingFI->set_label(SwResId(ST_SALUTATIONMATCHING)); + m_xAddressTitle->set_label(SwResId(ST_SALUTATIONELEMENT)); + } + + m_xFieldsControl->SetModifyHdl(LINK(this, SwAssignFieldsDialog, AssignmentModifyHdl_Impl )); + m_xMatchingFI->set_label(m_xMatchingFI->get_label().replaceAll("%1", sMatchesTo)); + m_xOK->connect_clicked(LINK(this, SwAssignFieldsDialog, OkHdl_Impl)); +} + +SwAssignFieldsDialog::~SwAssignFieldsDialog() +{ +} + +uno::Sequence< OUString > SwAssignFieldsDialog::CreateAssignments() +{ + uno::Sequence< OUString > aAssignments( + m_rConfigItem.GetDefaultAddressHeaders().size()); + OUString* pAssignments = aAssignments.getArray(); + sal_Int32 nIndex = 0; + for (const auto& rLBItem : m_xFieldsControl->m_aFields) + { + const OUString sSelect = rLBItem.m_xComboBox->get_active_text(); + pAssignments[nIndex] = (m_sNone != sSelect) ? sSelect : OUString(); + ++nIndex; + } + return aAssignments; +} + +IMPL_LINK_NOARG(SwAssignFieldsDialog, OkHdl_Impl, weld::Button&, void) +{ + m_rConfigItem.SetColumnAssignment( + m_rConfigItem.GetCurrentDBData(), + CreateAssignments() ); + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(SwAssignFieldsDialog, AssignmentModifyHdl_Impl, LinkParamNone*, void) +{ + uno::Sequence< OUString > aAssignments = CreateAssignments(); + const OUString sPreview = SwAddressPreview::FillData( + m_rPreviewString, m_rConfigItem, &aAssignments); + m_xPreview->SetAddress(sPreview); +} + +void SwAssignFieldsDialog::ConnectSizeGroups(int nLabelWidth, int nComboBoxWidth, int nPreviewWidth) +{ + m_xAddressTitle->set_size_request(nLabelWidth, -1); + m_xMatchTitle->set_size_request(nComboBoxWidth, -1); + m_xPreviewTitle->set_size_request(nPreviewWidth, -1); +} + +namespace +{ + const EECharAttrib* FindCharAttrib(int nStartPosition, std::vector<EECharAttrib>& rAttribList) + { + for (auto it = rAttribList.rbegin(); it != rAttribList.rend(); ++it) + { + const auto& rTextAtr = *it; + if (rTextAtr.pAttr->Which() != EE_CHAR_GRABBAG) + continue; + if (rTextAtr.nStart <= nStartPosition && rTextAtr.nEnd >= nStartPosition) + { + return &rTextAtr; + } + } + + return nullptr; + } +} + +AddressMultiLineEdit::AddressMultiLineEdit(SwCustomizeAddressBlockDialog *pParent) + : m_pParentDialog(pParent) +{ +} + +void AddressMultiLineEdit::EndDropTarget() +{ + if (m_xDropTarget.is()) + { + m_xEditEngine->RemoveView(m_xEditView.get()); + auto xRealDropTarget = GetDrawingArea()->get_drop_target(); + uno::Reference<css::datatransfer::dnd::XDropTargetListener> xListener(m_xDropTarget, uno::UNO_QUERY); + xRealDropTarget->removeDropTargetListener(xListener); + m_xDropTarget.clear(); + } +} + +AddressMultiLineEdit::~AddressMultiLineEdit() +{ + assert(!m_xDropTarget.is()); +} + +void AddressMultiLineEdit::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(160, 60), MapMode(MapUnit::MapAppFont))); + pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); + WeldEditView::SetDrawingArea(pDrawingArea); +} + +bool AddressMultiLineEdit::KeyInput(const KeyEvent& rKEvt) +{ + if (rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE) + return false; // we want default esc behaviour + if (rKEvt.GetCharCode()) + return true; // handled + return WeldEditView::KeyInput(rKEvt); +} + +bool AddressMultiLineEdit::Command(const CommandEvent& rCEvt) +{ + if (rCEvt.GetCommand() == CommandEventId::StartExtTextInput || + rCEvt.GetCommand() == CommandEventId::EndExtTextInput || + rCEvt.GetCommand() == CommandEventId::ExtTextInput) + { + return true; + } + return WeldEditView::Command(rCEvt); +} + +bool AddressMultiLineEdit::MouseButtonDown(const MouseEvent& rMEvt) +{ + if (rMEvt.GetClicks() >= 2) + return true; // handled + return WeldEditView::MouseButtonDown(rMEvt); +} + +OUString AddressMultiLineEdit::GetText() const +{ + return m_xEditEngine->GetText(); +} + +void AddressMultiLineEdit::SetText( const OUString& rStr ) +{ + m_xEditEngine->SetText(rStr); + //set attributes to all address tokens + + sal_Int32 nSequence(0); + SfxGrabBagItem aProtectAttr(EE_CHAR_GRABBAG); + const sal_uInt32 nParaCount = m_xEditEngine->GetParagraphCount(); + for(sal_uInt32 nPara = 0; nPara < nParaCount; ++nPara) + { + sal_Int32 nIndex = 0; + const OUString sPara = m_xEditEngine->GetText( nPara ); + if (!sPara.isEmpty() && !sPara.endsWith(" ")) + { + ESelection aPaM(nPara, sPara.getLength(), nPara, sPara.getLength()); + m_xEditEngine->QuickInsertText(" ", aPaM); + } + for(;;) + { + const sal_Int32 nStart = sPara.indexOf( '<', nIndex ); + if (nStart < 0) + break; + const sal_Int32 nEnd = sPara.indexOf( '>', nStart ); + if (nEnd < 0) + break; + nIndex = nEnd; + SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet()); + // make each one different, so they are not collapsed together + // as one attribute + aProtectAttr.GetGrabBag()["Index"] <<= nSequence++; + aSet.Put(aProtectAttr); + m_xEditEngine->QuickSetAttribs(aSet, ESelection(nPara, nStart, nPara, nEnd + 1)); + } + + } + // add two empty paragraphs at the end + if(m_pParentDialog->m_eType == SwCustomizeAddressBlockDialog::ADDRESSBLOCK_NEW || + m_pParentDialog->m_eType == SwCustomizeAddressBlockDialog::ADDRESSBLOCK_EDIT) + { + sal_Int32 nLastLen = m_xEditEngine->GetText(nParaCount - 1).getLength(); + if(nLastLen) + { + int nPara = nParaCount ? nParaCount - 1 : 0; + ESelection aPaM(nPara, nLastLen, nPara, nLastLen); + m_xEditEngine->QuickInsertText("\n \n ", aPaM); + } + } + + m_xEditView->SetSelection(ESelection(0, 0, 0, 0)); +} + +// Insert the new entry in front of the entry at the beginning of the selection +void AddressMultiLineEdit::InsertNewEntry( const OUString& rStr ) +{ + // insert new entry after current selected one. + ESelection aSelection = m_xEditView->GetSelection(); + const sal_uInt32 nPara = aSelection.nStartPara; + + std::vector<EECharAttrib> aAttribList; + m_xEditEngine->GetCharAttribs(nPara, aAttribList); + + sal_Int32 nIndex = aSelection.nEndPara; + const EECharAttrib* pAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); + if(nullptr != pAttrib) + nIndex = pAttrib->nEnd; + InsertNewEntryAtPosition( rStr, nPara, nIndex ); + + // select the new entry + m_xEditEngine->GetCharAttribs(nPara, aAttribList); + pAttrib = FindCharAttrib(nIndex, aAttribList); + const sal_Int32 nEnd = pAttrib ? pAttrib->nEnd : nIndex; + ESelection aEntrySel(nPara, nIndex, nPara, nEnd); + m_xEditView->SetSelection(aEntrySel); + Invalidate(); + m_aModifyLink.Call(*this); +} + +void AddressMultiLineEdit::InsertNewEntryAtPosition( const OUString& rStr, sal_uLong nPara, sal_uInt16 nIndex ) +{ + ESelection aInsertPos(nPara, nIndex, nPara, nIndex); + m_xEditEngine->QuickInsertText(rStr, aInsertPos); + + //restore the attributes + SetText( GetAddress() ); + + //select the newly inserted/moved element + m_xEditView->SetSelection(aInsertPos); + m_aSelectionLink.Call(false); +} + +void AddressMultiLineEdit::RemoveCurrentEntry() +{ + ESelection aSelection = m_xEditView->GetSelection(); + + std::vector<EECharAttrib> aAttribList; + m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); + + const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); + if(pBeginAttrib && + (pBeginAttrib->nStart <= aSelection.nStartPos + && pBeginAttrib->nEnd >= aSelection.nEndPos)) + { + const sal_uInt32 nPara = aSelection.nStartPara; + ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd); + m_xEditEngine->QuickInsertText(OUString(), aEntrySel); + //restore the attributes + SetText( GetAddress() ); + m_aModifyLink.Call(*this); + } +} + +void AddressMultiLineEdit::MoveCurrentItem(MoveItemFlags nMove) +{ + ESelection aSelection = m_xEditView->GetSelection(); + + std::vector<EECharAttrib> aAttribList; + m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); + + const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); + if(!pBeginAttrib || + pBeginAttrib->nStart > aSelection.nStartPos || + pBeginAttrib->nEnd < aSelection.nEndPos) + return; + + //current item has been found + sal_Int32 nPara = aSelection.nStartPara; + sal_Int32 nIndex = pBeginAttrib->nStart; + ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd); + const OUString sCurrentItem = m_xEditEngine->GetText(aEntrySel); + m_xEditEngine->RemoveAttribs(aEntrySel, false, EE_CHAR_GRABBAG); + m_xEditEngine->QuickInsertText(OUString(), aEntrySel); + m_xEditEngine->GetCharAttribs(nPara, aAttribList); + switch (nMove) + { + case MoveItemFlags::Left : + if(nIndex) + { + //go left to find a predecessor or simple text + --nIndex; + const OUString sPara = m_xEditEngine->GetText( nPara ); + sal_Int32 nSearchIndex = sPara.lastIndexOf( '>', nIndex+1 ); + if( nSearchIndex != -1 && nSearchIndex == nIndex ) + { + nSearchIndex = sPara.lastIndexOf( '<', nIndex ); + if( nSearchIndex != -1 ) + nIndex = nSearchIndex; + } + } + break; + case MoveItemFlags::Right: + { + //go right to find a successor or simple text + ++nIndex; + const EECharAttrib* pEndAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); + if(pEndAttrib && pEndAttrib->nEnd >= nIndex) + { + nIndex = pEndAttrib->nEnd; + } + } + break; + case MoveItemFlags::Up : + --nPara; + nIndex = 0; + break; + case MoveItemFlags::Down : + ++nPara; + nIndex = 0; + break; + default: break; + } + //add a new paragraph if there is none yet + if (nPara >= m_xEditEngine->GetParagraphCount()) + { + auto nInsPara = nPara - 1; + auto nInsPos = m_xEditEngine->GetTextLen( nPara - 1 ); + ESelection aTemp(nInsPara, nInsPos, nInsPara, nInsPos); + m_xEditEngine->QuickInsertText("\n", aTemp); + } + InsertNewEntryAtPosition( sCurrentItem, nPara, nIndex ); + + // select the new entry [#i40817] + m_xEditEngine->GetCharAttribs(nPara, aAttribList); + const EECharAttrib* pAttrib = FindCharAttrib(nIndex, aAttribList); + if (pAttrib) + aEntrySel = ESelection(nPara, nIndex, nPara, pAttrib->nEnd); + m_xEditView->SetSelection(aEntrySel); + Invalidate(); + m_aModifyLink.Call(*this); +} + +MoveItemFlags AddressMultiLineEdit::IsCurrentItemMoveable() const +{ + MoveItemFlags nRet = MoveItemFlags::NONE; + ESelection aSelection = m_xEditView->GetSelection(); + + std::vector<EECharAttrib> aAttribList; + m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); + + const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); + if (pBeginAttrib && + (pBeginAttrib->nStart <= aSelection.nStartPos + && pBeginAttrib->nEnd >= aSelection.nEndPos)) + { + if (pBeginAttrib->nStart) + nRet |= MoveItemFlags::Left; + //if there is an entry it can always be move to the right and down + nRet |= MoveItemFlags::Right | MoveItemFlags::Down; + if (aSelection.nStartPara > 0) + nRet |= MoveItemFlags::Up; + } + return nRet; +} + +bool AddressMultiLineEdit::HasCurrentItem() const +{ + ESelection aSelection = m_xEditView->GetSelection(); + + std::vector<EECharAttrib> aAttribList; + m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); + + const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); + return (pBeginAttrib && + (pBeginAttrib->nStart <= aSelection.nStartPos + && pBeginAttrib->nEnd >= aSelection.nEndPos)); +} + +OUString AddressMultiLineEdit::GetCurrentItem() const +{ + ESelection aSelection = m_xEditView->GetSelection(); + + std::vector<EECharAttrib> aAttribList; + m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); + + const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); + if (pBeginAttrib && + (pBeginAttrib->nStart <= aSelection.nStartPos + && pBeginAttrib->nEnd >= aSelection.nEndPos)) + { + const sal_uInt32 nPara = aSelection.nStartPara; + ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd); + return m_xEditEngine->GetText( aEntrySel ); + } + return OUString(); +} + +void AddressMultiLineEdit::SelectCurrentItem() +{ + ESelection aSelection = m_xEditView->GetSelection(); + + std::vector<EECharAttrib> aAttribList; + m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); + + const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); + if (pBeginAttrib && + (pBeginAttrib->nStart <= aSelection.nStartPos + && pBeginAttrib->nEnd >= aSelection.nEndPos)) + { + const sal_uInt32 nPara = aSelection.nStartPara; + ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd); + m_xEditView->SetSelection(aEntrySel); + Invalidate(); + } +} + +OUString AddressMultiLineEdit::GetAddress() const +{ + OUString sRet; + const sal_uInt32 nParaCount = m_xEditEngine->GetParagraphCount(); + for(sal_uInt32 nPara = nParaCount; nPara; --nPara) + { + const OUString sPara = comphelper::string::stripEnd(m_xEditEngine->GetText(nPara - 1), ' '); + //don't add empty trailing paragraphs + if(!sRet.isEmpty() || !sPara.isEmpty()) + { + sRet = sPara + sRet; + //insert the para break + if(nPara > 1) + sRet = "\n" + sRet; + } + } + return sRet; +} + +void AddressMultiLineEdit::UpdateFields() +{ + ESelection aSelection = m_xEditView->GetSelection(); + + //restore the attributes + SetText( GetAddress() ); + + //reselect the element + m_xEditView->SetSelection(aSelection); + m_aSelectionLink.Call(false); +} + +void AddressMultiLineEdit::EditViewSelectionChange() +{ + WeldEditView::EditViewSelectionChange(); + m_aSelectionLink.Call(true); +} + +namespace +{ + // sit between the tree as drag source and the editview as drop target and translate + // the tree dnd data to the simple string the editview wants + class DropTargetListener : public cppu::WeakImplHelper< css::datatransfer::dnd::XDropTargetListener, + css::datatransfer::dnd::XDropTarget > + { + private: + css::uno::Reference<css::datatransfer::dnd::XDropTarget> m_xRealDropTarget; + std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> m_aListeners; + SwCustomizeAddressBlockDialog* m_pParentDialog; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& ) override + { + m_xRealDropTarget.clear(); + m_aListeners.clear(); + } + + // XDropTargetListener + virtual void SAL_CALL drop( const css::datatransfer::dnd::DropTargetDropEvent& dtde ) override + { + SolarMutexGuard aGuard; + + auto aReplacement(dtde); + + Point aMousePos(dtde.LocationX, dtde.LocationY); + bool bAllowed = m_pParentDialog->SetCursorLogicPosition(aMousePos); + if (bAllowed) + { + if (weld::TreeView* pTree = m_pParentDialog->get_drag_source()) + { + int nEntry = pTree->get_selected_index(); + if (nEntry != -1) + { + sal_Int32 nUserData = pTree->get_id(nEntry).toInt32(); + //special entries can only be once in the address / greeting + if (nUserData >= 0 || !m_pParentDialog->HasItem(nUserData)) + { + rtl::Reference<TransferDataContainer> xContainer = new TransferDataContainer; + xContainer->CopyString( "<" + pTree->get_text(nEntry) + ">" ); + + // replace what the treeview is offering with what ImpEditView::drop wants + aReplacement.Transferable = xContainer.get(); + } + } + } + } + + std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners); + for (auto const& listener : aListeners) + listener->drop(aReplacement); + + if (bAllowed) + m_pParentDialog->UpdateFields(); + } + + virtual void SAL_CALL dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) override + { + auto aReplacement(dtdee); + // replace what the treeview is offering with what ImpEditView::dragEnter wants + aReplacement.SupportedDataFlavors.realloc(1); + SotExchange::GetFormatDataFlavor(SotClipboardFormatId::STRING, aReplacement.SupportedDataFlavors.getArray()[0]); + + std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners); + for (auto const& listener : aListeners) + listener->dragEnter(aReplacement); + } + + virtual void SAL_CALL dragExit( const css::datatransfer::dnd::DropTargetEvent& dte ) override + { + std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners); + for (auto const& listener : aListeners) + listener->dragExit( dte ); + } + + virtual void SAL_CALL dragOver( const css::datatransfer::dnd::DropTargetDragEvent& dtde ) override + { + std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners); + for (auto const& listener : aListeners) + listener->dragOver( dtde ); + } + + virtual void SAL_CALL dropActionChanged( const css::datatransfer::dnd::DropTargetDragEvent& dtde ) override + { + std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners); + for (auto const& listener : aListeners) + listener->dropActionChanged( dtde ); + } + + // XDropTarget + virtual void SAL_CALL addDropTargetListener(const css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>& xListener) override + { + m_aListeners.push_back(xListener); + } + + virtual void SAL_CALL removeDropTargetListener(const css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>& xListener) override + { + std::erase(m_aListeners, xListener); + } + + virtual sal_Bool SAL_CALL isActive() override + { + return m_xRealDropTarget->isActive(); + } + + virtual void SAL_CALL setActive(sal_Bool active) override + { + m_xRealDropTarget->setActive(active); + } + + virtual sal_Int8 SAL_CALL getDefaultActions() override + { + return m_xRealDropTarget->getDefaultActions(); + } + + virtual void SAL_CALL setDefaultActions(sal_Int8 actions) override + { + m_xRealDropTarget->setDefaultActions(actions); + } + + public: + DropTargetListener(css::uno::Reference<css::datatransfer::dnd::XDropTarget> xRealDropTarget, + SwCustomizeAddressBlockDialog* pParentDialog) + : m_xRealDropTarget(std::move(xRealDropTarget)) + , m_pParentDialog(pParentDialog) + { + } + }; +} + +css::uno::Reference<css::datatransfer::dnd::XDropTarget> AddressMultiLineEdit::GetDropTarget() +{ + if (!m_xDropTarget.is()) + { + auto xRealDropTarget = GetDrawingArea()->get_drop_target(); + rtl::Reference<DropTargetListener> pProxy = new DropTargetListener(xRealDropTarget, m_pParentDialog); + xRealDropTarget->addDropTargetListener(pProxy); + m_xDropTarget = pProxy; + } + return m_xDropTarget; +} + +bool AddressMultiLineEdit::SetCursorLogicPosition(const Point& rPosition) +{ + Point aMousePos = EditViewOutputDevice().PixelToLogic(rPosition); + m_xEditView->SetCursorLogicPosition(aMousePos, false, true); + + ESelection aSelection = m_xEditView->GetSelection(); + std::vector<EECharAttrib> aAttribList; + m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); + return FindCharAttrib(aSelection.nStartPos, aAttribList) == nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/mmaddressblockpage.hxx b/sw/source/ui/dbui/mmaddressblockpage.hxx new file mode 100644 index 0000000000..f69b446169 --- /dev/null +++ b/sw/source/ui/dbui/mmaddressblockpage.hxx @@ -0,0 +1,280 @@ +/* -*- 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_DBUI_MMADDRESSBLOCKPAGE_HXX +#define INCLUDED_SW_SOURCE_UI_DBUI_MMADDRESSBLOCKPAGE_HXX + +#include <svx/weldeditview.hxx> +#include <vcl/wizardmachine.hxx> +#include <mailmergehelper.hxx> +#include <sfx2/basedlgs.hxx> +#include <vcl/textfilter.hxx> +#include <svl/lstner.hxx> +#include <vcl/idle.hxx> +#include <o3tl/typed_flags_set.hxx> + +class SwMailMergeWizard; +class SwMailMergeConfigItem; + +class SwMailMergeAddressBlockPage : public vcl::OWizardPage +{ + OUString m_sDocument; + OUString m_sCurrentAddress; + OUString m_sChangeAddress; + + SwMailMergeWizard* m_pWizard; + + std::unique_ptr<weld::Button> m_xAddressListPB; + std::unique_ptr<weld::Label> m_xCurrentAddressFI; + + std::unique_ptr<weld::Container> m_xStep2; + std::unique_ptr<weld::Container> m_xStep3; + std::unique_ptr<weld::Container> m_xStep4; + + std::unique_ptr<weld::Label> m_xSettingsFI; + std::unique_ptr<weld::CheckButton> m_xAddressCB; + std::unique_ptr<weld::Button> m_xSettingsPB; + std::unique_ptr<weld::CheckButton> m_xHideEmptyParagraphsCB; + + std::unique_ptr<weld::Button> m_xAssignPB; + + std::unique_ptr<weld::Label> m_xDocumentIndexFI; + std::unique_ptr<weld::Button> m_xPrevSetIB; + std::unique_ptr<weld::Button> m_xNextSetIB; + + std::unique_ptr<weld::Button> m_xDifferentlist; + + std::unique_ptr<SwAddressPreview> m_xSettings; + std::unique_ptr<SwAddressPreview> m_xPreview; + std::unique_ptr<weld::CustomWeld> m_xSettingsWIN; + std::unique_ptr<weld::CustomWeld> m_xPreviewWIN; + + void InsertDataHdl(const weld::Button* pButton); + + DECL_LINK(AddressListHdl_Impl, weld::Button&, void); + DECL_LINK(SettingsHdl_Impl, weld::Button&, void); + DECL_LINK(AssignHdl_Impl, weld::Button&, void); + DECL_LINK(AddressBlockHdl_Impl, weld::Toggleable&, void); + DECL_LINK(InsertDataHdl_Impl, weld::Button&, void); + DECL_LINK(AddressBlockSelectHdl_Impl, LinkParamNone*, void); + DECL_LINK(HideParagraphsHdl_Impl, weld::Toggleable&, void); + + void EnableAddressBlock(bool bAll, bool bSelective); + + virtual void Activate() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + +public: + SwMailMergeAddressBlockPage(weld::Container* pPage, SwMailMergeWizard* pWizard); + virtual ~SwMailMergeAddressBlockPage() override; + SwMailMergeWizard* GetWizard() { return m_pWizard; } +}; + +class SwSelectAddressBlockDialog : public SfxDialogController +{ + css::uno::Sequence< OUString> m_aAddressBlocks; + SwMailMergeConfigItem& m_rConfig; + + std::unique_ptr<SwAddressPreview> m_xPreview; + std::unique_ptr<weld::Button> m_xNewPB; + std::unique_ptr<weld::Button> m_xCustomizePB; + std::unique_ptr<weld::Button> m_xDeletePB; + std::unique_ptr<weld::RadioButton> m_xNeverRB; + std::unique_ptr<weld::RadioButton> m_xAlwaysRB; + std::unique_ptr<weld::RadioButton> m_xDependentRB; + std::unique_ptr<weld::Entry> m_xCountryED; + std::unique_ptr<weld::CustomWeld> m_xPreviewWin; + + DECL_LINK(NewCustomizeHdl_Impl, weld::Button&, void); + DECL_LINK(DeleteHdl_Impl, weld::Button&, void); + DECL_LINK(IncludeHdl_Impl, weld::Toggleable&, void); + +public: + SwSelectAddressBlockDialog(weld::Window* pParent, SwMailMergeConfigItem& rConfig); + virtual ~SwSelectAddressBlockDialog() override; + + void SetAddressBlocks(const css::uno::Sequence< OUString>& rBlocks, + sal_uInt16 nSelected); + const css::uno::Sequence< OUString>& GetAddressBlocks(); + + void SetSettings(bool bIsCountry, const OUString& sCountry); + bool IsIncludeCountry() const {return !m_xNeverRB->get_active();} + OUString GetCountry() const; +}; + +class SwCustomizeAddressBlockDialog; + +enum class MoveItemFlags { + NONE = 0, + Left = 1, + Right = 2, + Up = 4, + Down = 8, +}; +namespace o3tl { + template<> struct typed_flags<MoveItemFlags> : is_typed_flags<MoveItemFlags, 0x0f> {}; +} + +class AddressMultiLineEdit; + +class AddressMultiLineEdit : public WeldEditView + , public SfxListener +{ + Link<bool,void> m_aSelectionLink; + Link<AddressMultiLineEdit&,void> m_aModifyLink; + SwCustomizeAddressBlockDialog* m_pParentDialog; + + virtual void EditViewSelectionChange() override; + virtual css::uno::Reference<css::datatransfer::dnd::XDropTarget> GetDropTarget() override; + + virtual bool KeyInput(const KeyEvent& rKEvt) override; + virtual bool Command(const CommandEvent& rCEvt) override; + virtual bool MouseButtonDown(const MouseEvent& rMEvt) override; + +public: + AddressMultiLineEdit(SwCustomizeAddressBlockDialog *pParent); + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + void EndDropTarget(); + bool SetCursorLogicPosition(const Point& rPosition); + void UpdateFields(); + virtual ~AddressMultiLineEdit() override; + + void SetSelectionChangedHdl( const Link<bool,void>& rLink ) { m_aSelectionLink = rLink; } + void SetModifyHdl( const Link<AddressMultiLineEdit&,void>& rLink ) { m_aModifyLink = rLink; } + + void SetText( const OUString& rStr ); + OUString GetText() const; + OUString GetAddress() const; + + void InsertNewEntry( const OUString& rStr ); + void InsertNewEntryAtPosition( const OUString& rStr, sal_uLong nPara, sal_uInt16 nIndex ); + void RemoveCurrentEntry(); + + void MoveCurrentItem(MoveItemFlags nMove); + MoveItemFlags IsCurrentItemMoveable() const; + bool HasCurrentItem() const; + OUString GetCurrentItem() const; + void SelectCurrentItem(); +}; + +class SwCustomizeAddressBlockDialog : public SfxDialogController +{ + friend class AddressMultiLineEdit; +public: + enum DialogType + { + ADDRESSBLOCK_NEW, + ADDRESSBLOCK_EDIT, + GREETING_FEMALE, + GREETING_MALE + }; +private: + TextFilter m_aTextFilter; + + std::vector<OUString> m_aSalutations; + std::vector<OUString> m_aPunctuations; + + OUString m_sCurrentSalutation; + OUString m_sCurrentPunctuation; + OUString m_sCurrentText; + + SwMailMergeConfigItem& m_rConfigItem; + DialogType m_eType; + + Idle m_aSelectionChangedIdle; + + std::unique_ptr<weld::Label> m_xAddressElementsFT; + std::unique_ptr<weld::TreeView> m_xAddressElementsLB; + std::unique_ptr<weld::Button> m_xInsertFieldIB; + std::unique_ptr<weld::Button> m_xRemoveFieldIB; + std::unique_ptr<weld::Label> m_xDragFT; + std::unique_ptr<weld::Button> m_xUpIB; + std::unique_ptr<weld::Button> m_xLeftIB; + std::unique_ptr<weld::Button> m_xRightIB; + std::unique_ptr<weld::Button> m_xDownIB; + std::unique_ptr<weld::Label> m_xFieldFT; + std::unique_ptr<weld::ComboBox> m_xFieldCB; + std::unique_ptr<weld::Button> m_xOK; + std::unique_ptr<SwAddressPreview> m_xPreview; + std::unique_ptr<weld::CustomWeld> m_xPreviewWIN; + std::unique_ptr<AddressMultiLineEdit> m_xDragED; + std::unique_ptr<weld::CustomWeld> m_xDragWIN; + + DECL_LINK(OKHdl_Impl, weld::Button&, void); + DECL_LINK(ListBoxSelectHdl_Impl, weld::TreeView&, void); + DECL_LINK(EditModifyHdl_Impl, AddressMultiLineEdit&, void); + DECL_LINK(ImageButtonHdl_Impl, weld::Button&, void); + DECL_LINK(SelectionChangedHdl_Impl, bool, void); + DECL_LINK(FieldChangeComboBoxHdl_Impl, weld::ComboBox&, void); + DECL_LINK(TextFilterHdl, OUString&, bool); + DECL_LINK(SelectionChangedIdleHdl, Timer*, void); + + sal_Int32 GetSelectedItem_Impl() const; + void UpdateImageButtons_Impl(); + +public: + SwCustomizeAddressBlockDialog(weld::Widget* pParent, SwMailMergeConfigItem& rConfig, DialogType); + virtual ~SwCustomizeAddressBlockDialog() override; + + bool SetCursorLogicPosition(const Point& rPosition); + void UpdateFields(); + + // for dragging from the TreeViews, return the active source + weld::TreeView* get_drag_source() const { return m_xAddressElementsLB->get_drag_source(); } + bool HasItem(sal_Int32 nUserData); + + void SetAddress(const OUString& rAddress); + OUString GetAddress() const; +}; + +class SwAssignFieldsControl; +class SwAssignFieldsDialog : public SfxDialogController +{ + OUString m_sNone; + OUString m_rPreviewString; + + SwMailMergeConfigItem& m_rConfigItem; + + std::unique_ptr<SwAddressPreview> m_xPreview; + std::unique_ptr<weld::Label> m_xMatchingFI; + std::unique_ptr<weld::Label> m_xAddressTitle; + std::unique_ptr<weld::Label> m_xMatchTitle; + std::unique_ptr<weld::Label> m_xPreviewTitle; + std::unique_ptr<weld::Label> m_xPreviewFI; + std::unique_ptr<weld::Button> m_xOK; + std::unique_ptr<weld::CustomWeld> m_xPreviewWin; + std::unique_ptr<SwAssignFieldsControl> m_xFieldsControl; + + css::uno::Sequence< OUString > CreateAssignments(); + DECL_LINK(OkHdl_Impl, weld::Button&, void); + DECL_LINK(AssignmentModifyHdl_Impl, LinkParamNone*, void); + +public: + SwAssignFieldsDialog(weld::Window* pParent, + SwMailMergeConfigItem& rConfigItem, + OUString aPreview, + bool bIsAddressBlock); + + void ConnectSizeGroups(int nLabelWidth, int nComboBoxWidth, int nPreviewWidth); + + virtual ~SwAssignFieldsDialog() override; +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/mmdocselectpage.cxx b/sw/source/ui/dbui/mmdocselectpage.cxx new file mode 100644 index 0000000000..180a6d0441 --- /dev/null +++ b/sw/source/ui/dbui/mmdocselectpage.cxx @@ -0,0 +1,226 @@ +/* -*- 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/filedlghelper.hxx> +#include <sfx2/new.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/docfac.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include "mmdocselectpage.hxx" +#include <mailmergewizard.hxx> +#include <swabstdlg.hxx> +#include <mmconfigitem.hxx> +#include <swuiexp.hxx> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> + +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace svt; + +SwMailMergeDocSelectPage::SwMailMergeDocSelectPage(weld::Container* pPage, SwMailMergeWizard* pWizard) + : vcl::OWizardPage(pPage, pWizard, "modules/swriter/ui/mmselectpage.ui", "MMSelectPage") + , m_pWizard(pWizard) + , m_xCurrentDocRB(m_xBuilder->weld_radio_button("currentdoc")) + , m_xNewDocRB(m_xBuilder->weld_radio_button("newdoc")) + , m_xLoadDocRB(m_xBuilder->weld_radio_button("loaddoc")) + , m_xLoadTemplateRB(m_xBuilder->weld_radio_button("template")) + , m_xRecentDocRB(m_xBuilder->weld_radio_button("recentdoc")) + , m_xBrowseDocPB(m_xBuilder->weld_button("browsedoc")) + , m_xBrowseTemplatePB(m_xBuilder->weld_button("browsetemplate")) + , m_xRecentDocLB(m_xBuilder->weld_combo_box("recentdoclb")) + , m_xDataSourceWarningFT(m_xBuilder->weld_label("datasourcewarning")) + , m_xExchangeDatabasePB(m_xBuilder->weld_button("exchangedatabase")) +{ + m_xDataSourceWarningFT->set_label_type(weld::LabelType::Warning); + m_xCurrentDocRB->set_active(true); + DocSelectHdl(*m_xNewDocRB); + + Link<weld::Toggleable&,void> aDocSelectLink = LINK(this, SwMailMergeDocSelectPage, DocSelectHdl); + m_xCurrentDocRB->connect_toggled(aDocSelectLink); + m_xNewDocRB->connect_toggled(aDocSelectLink); + m_xLoadDocRB->connect_toggled(aDocSelectLink); + m_xLoadTemplateRB->connect_toggled(aDocSelectLink); + m_xRecentDocRB->connect_toggled(aDocSelectLink); + + Link<weld::Button&,void> aFileSelectHdl = LINK(this, SwMailMergeDocSelectPage, FileSelectHdl); + m_xBrowseDocPB->connect_clicked(aFileSelectHdl); + m_xBrowseTemplatePB->connect_clicked(aFileSelectHdl); + + Link<weld::Button&,void> aExchangeDatabaseHdl = LINK(this, SwMailMergeDocSelectPage, ExchangeDatabaseHdl); + m_xExchangeDatabasePB->connect_clicked(aExchangeDatabaseHdl); + + const uno::Sequence< OUString >& rDocs = + m_pWizard->GetConfigItem().GetSavedDocuments(); + for(const auto& rDoc : rDocs) + { + //insert in reverse order + m_xRecentDocLB->insert_text(0, rDoc); + } + if (!rDocs.hasElements()) + m_xRecentDocRB->set_sensitive(false); + else + m_xRecentDocLB->set_active(0); +} + +SwMailMergeDocSelectPage::~SwMailMergeDocSelectPage() +{ +} + +IMPL_LINK_NOARG(SwMailMergeDocSelectPage, DocSelectHdl, weld::Toggleable&, void) +{ + m_xRecentDocLB->set_sensitive(m_xRecentDocRB->get_active()); + m_pWizard->UpdateRoadmap(); + OUString sDataSourceName = m_pWizard->GetSwView()->GetDataSourceName(); + + if(m_xCurrentDocRB->get_active() && + !sDataSourceName.isEmpty() && + !SwView::IsDataSourceAvailable(sDataSourceName)) + { + m_xDataSourceWarningFT->show(); + m_pWizard->enableButtons(WizardButtonFlags::NEXT, false); + } + else + { + m_xDataSourceWarningFT->hide(); + m_pWizard->enableButtons(WizardButtonFlags::NEXT, m_pWizard->isStateEnabled(MM_OUTPUTTYPETPAGE)); + } + + if(m_xCurrentDocRB->get_active()) + m_xExchangeDatabasePB->set_sensitive(true); + else + m_xExchangeDatabasePB->set_sensitive(false); +} + +IMPL_LINK(SwMailMergeDocSelectPage, FileSelectHdl, weld::Button&, rButton, void) +{ + bool bTemplate = m_xBrowseTemplatePB.get() == &rButton; + + if(bTemplate) + { + m_xLoadTemplateRB->set_active(true); + SfxNewFileDialog aNewFileDlg(m_pWizard->getDialog(), SfxNewFileDialogMode::NONE); + sal_uInt16 nRet = aNewFileDlg.run(); + if(RET_TEMPLATE_LOAD == nRet) + bTemplate = false; + else if(RET_CANCEL != nRet) + m_sLoadTemplateName = aNewFileDlg.GetTemplateFileName(); + } + else + m_xLoadDocRB->set_active(true); + + if(!bTemplate) + { + sfx2::FileDialogHelper aDlgHelper(TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, m_pWizard->getDialog()); + aDlgHelper.SetContext(sfx2::FileDialogHelper::WriterMailMerge); + Reference < XFilePicker3 > xFP = aDlgHelper.GetFilePicker(); + + SfxObjectFactory &rFact = m_pWizard->GetSwView()->GetDocShell()->GetFactory(); + SfxFilterMatcher aMatcher( rFact.GetFactoryName() ); + SfxFilterMatcherIter aIter( aMatcher ); + std::shared_ptr<const SfxFilter> pFlt = aIter.First(); + while( pFlt ) + { + if( pFlt && pFlt->IsAllowedAsTemplate() ) + { + const OUString sWild = pFlt->GetWildcard().getGlob(); + xFP->appendFilter( pFlt->GetUIName(), sWild ); + + // #i40125 + if(pFlt->GetFilterFlags() & SfxFilterFlags::DEFAULT) + xFP->setCurrentFilter( pFlt->GetUIName() ) ; + } + + pFlt = aIter.Next(); + } + + if( ERRCODE_NONE == aDlgHelper.Execute() ) + { + m_sLoadFileName = xFP->getSelectedFiles().getConstArray()[0]; + } + } + m_pWizard->UpdateRoadmap(); + m_pWizard->enableButtons(WizardButtonFlags::NEXT, m_pWizard->isStateEnabled(MM_OUTPUTTYPETPAGE)); +} + +IMPL_LINK_NOARG(SwMailMergeDocSelectPage, ExchangeDatabaseHdl, weld::Button&, void) +{ + + SwAbstractDialogFactory& rFact = ::swui::GetFactory(); + ScopedVclPtr<VclAbstractDialog> pDlg(rFact.CreateSwChangeDBDlg(*m_pWizard->GetSwView())); + pDlg->Execute(); + + OUString sDataSourceName = m_pWizard->GetSwView()->GetDataSourceName(); + + if(m_xCurrentDocRB->get_active() && + !sDataSourceName.isEmpty() && + SwView::IsDataSourceAvailable(sDataSourceName)) + { + m_xDataSourceWarningFT->hide(); + m_pWizard->enableButtons(WizardButtonFlags::NEXT, true); + } +} + +bool SwMailMergeDocSelectPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) +{ + bool bReturn = false; + bool bNext = _eReason == ::vcl::WizardTypes::eTravelForward; + if(bNext || _eReason == ::vcl::WizardTypes::eValidate ) + { + OUString sReloadDocument; + bReturn = m_xCurrentDocRB->get_active() || + m_xNewDocRB->get_active(); + if (!bReturn) + { + sReloadDocument = m_sLoadFileName; + bReturn = !sReloadDocument.isEmpty() && m_xLoadDocRB->get_active(); + } + if (!bReturn) + { + sReloadDocument = m_sLoadTemplateName; + bReturn = !sReloadDocument.isEmpty() && m_xLoadTemplateRB->get_active(); + } + if (!bReturn) + { + bReturn = m_xRecentDocRB->get_active(); + if (bReturn) + { + sReloadDocument = m_xRecentDocLB->get_active_text(); + bReturn = !sReloadDocument.isEmpty(); + } + } + if( _eReason == ::vcl::WizardTypes::eValidate ) + m_pWizard->SetDocumentLoad(!m_xCurrentDocRB->get_active()); + + if(bNext && !m_xCurrentDocRB->get_active()) + { + if(!sReloadDocument.isEmpty()) + m_pWizard->SetReloadDocument( sReloadDocument ); + m_pWizard->SetRestartPage(MM_OUTPUTTYPETPAGE); + m_pWizard->response(RET_LOAD_DOC); + } + } + return bReturn; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/mmdocselectpage.hxx b/sw/source/ui/dbui/mmdocselectpage.hxx new file mode 100644 index 0000000000..d1cdca67d3 --- /dev/null +++ b/sw/source/ui/dbui/mmdocselectpage.hxx @@ -0,0 +1,58 @@ +/* -*- 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_DBUI_MMDOCSELECTPAGE_HXX +#define INCLUDED_SW_SOURCE_UI_DBUI_MMDOCSELECTPAGE_HXX + +#include <vcl/wizardmachine.hxx> +#include <vcl/weld.hxx> + +class SwMailMergeWizard; + +class SwMailMergeDocSelectPage : public vcl::OWizardPage +{ + OUString m_sLoadFileName; + OUString m_sLoadTemplateName; + + SwMailMergeWizard* m_pWizard; + + std::unique_ptr<weld::RadioButton> m_xCurrentDocRB; + std::unique_ptr<weld::RadioButton> m_xNewDocRB; + std::unique_ptr<weld::RadioButton> m_xLoadDocRB; + std::unique_ptr<weld::RadioButton> m_xLoadTemplateRB; + std::unique_ptr<weld::RadioButton> m_xRecentDocRB; + std::unique_ptr<weld::Button> m_xBrowseDocPB; + std::unique_ptr<weld::Button> m_xBrowseTemplatePB; + std::unique_ptr<weld::ComboBox> m_xRecentDocLB; + std::unique_ptr<weld::Label> m_xDataSourceWarningFT; + std::unique_ptr<weld::Button> m_xExchangeDatabasePB; + + DECL_LINK(DocSelectHdl, weld::Toggleable&, void); + DECL_LINK(FileSelectHdl, weld::Button&, void); + DECL_LINK(ExchangeDatabaseHdl, weld::Button&, void); + + virtual bool commitPage(::vcl::WizardTypes::CommitPageReason _eReason) override; + +public: + SwMailMergeDocSelectPage(weld::Container* pPage, SwMailMergeWizard* pWizard); + virtual ~SwMailMergeDocSelectPage() override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/mmgreetingspage.cxx b/sw/source/ui/dbui/mmgreetingspage.cxx new file mode 100644 index 0000000000..c75a01ee8d --- /dev/null +++ b/sw/source/ui/dbui/mmgreetingspage.cxx @@ -0,0 +1,421 @@ +/* -*- 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 "mmgreetingspage.hxx" +#include <mailmergewizard.hxx> +#include <mmconfigitem.hxx> +#include "mmaddressblockpage.hxx" +#include <dbui.hrc> +#include <com/sun/star/sdb/XColumn.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <comphelper/diagnose_ex.hxx> +#include <swmodule.hxx> +#include <view.hxx> + +using namespace svt; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +static void lcl_FillGreetingsBox(weld::ComboBox& rBox, + SwMailMergeConfigItem const & rConfig, + SwMailMergeConfigItem::Gender eType) +{ + const Sequence< OUString> rEntries = rConfig.GetGreetings(eType); + for(const auto& rEntry : rEntries) + rBox.append_text(rEntry); + rBox.set_active(rConfig.GetCurrentGreeting(eType)); +} + +static void lcl_StoreGreetingsBox(const weld::ComboBox& rBox, + SwMailMergeConfigItem& rConfig, + SwMailMergeConfigItem::Gender eType) +{ + Sequence< OUString> aEntries(rBox.get_count()); + OUString* pEntries = aEntries.getArray(); + for(sal_Int32 nEntry = 0; nEntry < rBox.get_count(); ++nEntry) + pEntries[nEntry] = rBox.get_text(nEntry); + rConfig.SetGreetings(eType, aEntries); + rConfig.SetCurrentGreeting(eType, rBox.get_active()); +} + +IMPL_LINK_NOARG(SwGreetingsHandler, IndividualHdl_Impl, weld::Toggleable&, void) +{ + bool bIndividual = m_xPersonalizedCB->get_sensitive() && m_xPersonalizedCB->get_active(); + m_xFemaleFT->set_sensitive(bIndividual); + m_xFemaleLB->set_sensitive(bIndividual); + m_xFemalePB->set_sensitive(bIndividual); + m_xMaleFT->set_sensitive(bIndividual); + m_xMaleLB->set_sensitive(bIndividual); + m_xMalePB->set_sensitive(bIndividual); + m_xFemaleFI->set_sensitive(bIndividual); + m_xFemaleColumnFT->set_sensitive(bIndividual); + m_xFemaleColumnLB->set_sensitive(bIndividual); + m_xFemaleFieldFT->set_sensitive(bIndividual); + m_xFemaleFieldCB->set_sensitive(bIndividual); + + if( m_bIsTabPage ) + { + m_rConfigItem.SetIndividualGreeting(bIndividual, false); + m_pWizard->UpdateRoadmap(); + m_pWizard->enableButtons(WizardButtonFlags::NEXT, m_pWizard->isStateEnabled(MM_LAYOUTPAGE)); + } + UpdatePreview(); +} + +IMPL_LINK(SwGreetingsHandler, GreetingHdl_Impl, weld::Button&, rButton, void) +{ + std::unique_ptr<SwCustomizeAddressBlockDialog> xDlg(new SwCustomizeAddressBlockDialog(&rButton, m_rConfigItem, + &rButton == m_xMalePB.get() ? + SwCustomizeAddressBlockDialog::GREETING_MALE : + SwCustomizeAddressBlockDialog::GREETING_FEMALE )); + if (RET_OK == xDlg->run()) + { + weld::ComboBox* pToInsert = &rButton == m_xMalePB.get() ? m_xMaleLB.get() : m_xFemaleLB.get(); + pToInsert->append_text(xDlg->GetAddress()); + pToInsert->set_active(pToInsert->get_count() - 1); + if(m_bIsTabPage) + { + m_pWizard->UpdateRoadmap(); + m_pWizard->enableButtons(WizardButtonFlags::NEXT, m_pWizard->isStateEnabled(MM_LAYOUTPAGE)); + } + UpdatePreview(); + } +} + +void SwGreetingsHandler::UpdatePreview() +{ + //the base class does nothing +} + +IMPL_LINK_NOARG(SwMailMergeGreetingsPage, AssignHdl_Impl, weld::Button&, void) +{ + const OUString sPreview(m_xFemaleLB->get_active_text() + "\n" + m_xMaleLB->get_active_text()); + SwAssignFieldsDialog aDlg(m_pWizard->getDialog(), m_rConfigItem, sPreview, false); + if (RET_OK == aDlg.run()) + { + UpdatePreview(); + m_pWizard->UpdateRoadmap(); + m_pWizard->enableButtons(WizardButtonFlags::NEXT, m_pWizard->isStateEnabled(MM_LAYOUTPAGE)); + } +} + +IMPL_LINK_NOARG(SwMailMergeGreetingsPage, GreetingSelectListBoxHdl_Impl, weld::ComboBox&, void) +{ + UpdatePreview(); +} + +IMPL_LINK_NOARG(SwMailMergeGreetingsPage, GreetingSelectComboBoxHdl_Impl, weld::ComboBox&, void) +{ + UpdatePreview(); +} + +void SwMailMergeGreetingsPage::UpdatePreview() +{ + //find out which type of greeting should be selected: + bool bFemale = false; + bool bNoValue = !m_xFemaleColumnLB->get_sensitive(); + if( !bNoValue ) + { + const OUString sFemaleValue = m_xFemaleFieldCB->get_active_text(); + const OUString sFemaleColumn = m_xFemaleColumnLB->get_active_text(); + Reference< sdbcx::XColumnsSupplier > xColsSupp( m_rConfigItem.GetResultSet(), UNO_QUERY); + Reference < container::XNameAccess> xColAccess = xColsSupp.is() ? xColsSupp->getColumns() : nullptr; + if(!sFemaleValue.isEmpty() && !sFemaleColumn.isEmpty() && + xColAccess.is() && + xColAccess->hasByName(sFemaleColumn)) + { + //get the content and exchange it in the address string + Any aCol = xColAccess->getByName(sFemaleColumn); + Reference< sdb::XColumn > xColumn; + aCol >>= xColumn; + if(xColumn.is()) + { + try + { + bFemale = xColumn->getString() == sFemaleValue; + + //no last name value marks the greeting also as neutral + const OUString sLastNameColumn = + m_rConfigItem.GetAssignedColumn(MM_PART_LASTNAME); + if ( xColAccess->hasByName(sLastNameColumn) ) + { + aCol = xColAccess->getByName(sLastNameColumn); + aCol >>= xColumn; + bNoValue = xColumn->getString().isEmpty(); + } + } + catch (const sdbc::SQLException&) + { + TOOLS_WARN_EXCEPTION( "sw", ""); + } + } + } + } + + OUString sPreview = bFemale ? m_xFemaleLB->get_active_text() : + bNoValue ? m_xNeutralCB->get_active_text() : m_xMaleLB->get_active_text(); + + sPreview = SwAddressPreview::FillData(sPreview, m_rConfigItem); + m_xPreview->SetAddress(sPreview); +} + +void SwGreetingsHandler::Contains(bool bContainsGreeting) +{ + m_xPersonalizedCB->set_sensitive(bContainsGreeting); + bool bEnablePersonal = bContainsGreeting && m_xPersonalizedCB->get_active(); + m_xFemaleFT->set_sensitive(bEnablePersonal); + m_xFemaleLB->set_sensitive(bEnablePersonal); + m_xFemalePB->set_sensitive(bEnablePersonal); + m_xMaleFT->set_sensitive(bEnablePersonal); + m_xMaleLB->set_sensitive(bEnablePersonal); + m_xMalePB->set_sensitive(bEnablePersonal); + m_xFemaleFI->set_sensitive(bEnablePersonal); + m_xFemaleColumnFT->set_sensitive(bEnablePersonal); + m_xFemaleColumnLB->set_sensitive(bEnablePersonal); + m_xFemaleFieldFT->set_sensitive(bEnablePersonal); + m_xFemaleFieldCB->set_sensitive(bEnablePersonal); + m_xNeutralFT->set_sensitive(bContainsGreeting); + m_xNeutralCB->set_sensitive(bContainsGreeting); +} + +SwMailMergeGreetingsPage::SwMailMergeGreetingsPage(weld::Container* pPage, SwMailMergeWizard* pWizard) + : vcl::OWizardPage(pPage, pWizard, "modules/swriter/ui/mmsalutationpage.ui", "MMSalutationPage") + , SwGreetingsHandler(pWizard->GetConfigItem(), *m_xBuilder) + , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin", true))) + , m_xPreviewFI(m_xBuilder->weld_label("previewft")) + , m_xAssignPB(m_xBuilder->weld_button("assign")) + , m_xDocumentIndexFI(m_xBuilder->weld_label("documentindex")) + , m_xPrevSetIB(m_xBuilder->weld_button("prev")) + , m_xNextSetIB(m_xBuilder->weld_button("next")) + , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "preview", *m_xPreview)) +{ + m_pWizard = pWizard; + + Size aSize(m_xPreview->GetDrawingArea()->get_ref_device().LogicToPixel(Size(186, 21), MapMode(MapUnit::MapAppFont))); + m_xPreviewWIN->set_size_request(aSize.Width(), aSize.Height()); + m_sDocument = m_xDocumentIndexFI->get_label(); + + m_bIsTabPage = true; + + m_xGreetingLineCB->connect_toggled(LINK(this, SwMailMergeGreetingsPage, ContainsHdl_Impl)); + Link<weld::Toggleable&,void> aIndividualLink = LINK(this, SwGreetingsHandler, IndividualHdl_Impl); + m_xPersonalizedCB->connect_toggled(aIndividualLink); + Link<weld::Button&,void> aGreetingLink = LINK(this, SwGreetingsHandler, GreetingHdl_Impl); + m_xFemalePB->connect_clicked(aGreetingLink); + m_xMalePB->connect_clicked(aGreetingLink); + m_xAssignPB->connect_clicked(LINK(this, SwMailMergeGreetingsPage, AssignHdl_Impl)); + Link<weld::ComboBox&,void> aLBoxLink2 = LINK(this, SwMailMergeGreetingsPage, GreetingSelectListBoxHdl_Impl); + m_xFemaleLB->connect_changed(aLBoxLink2); + m_xMaleLB->connect_changed(aLBoxLink2); + m_xFemaleColumnLB->connect_changed(aLBoxLink2); + m_xFemaleFieldCB->connect_changed(LINK(this, SwMailMergeGreetingsPage, GreetingSelectComboBoxHdl_Impl)); + m_xNeutralCB->connect_changed(LINK(this, SwMailMergeGreetingsPage, GreetingSelectComboBoxHdl_Impl)); + + Link<weld::Button&,void> aDataLink = LINK(this, SwMailMergeGreetingsPage, InsertDataHdl_Impl); + m_xPrevSetIB->connect_clicked(aDataLink); + m_xNextSetIB->connect_clicked(aDataLink); + + m_xGreetingLineCB->set_active(m_rConfigItem.IsGreetingLine(false)); + m_xPersonalizedCB->set_active(m_rConfigItem.IsIndividualGreeting(false)); + ContainsHdl_Impl(*m_xGreetingLineCB); + aIndividualLink.Call(*m_xPersonalizedCB); + + lcl_FillGreetingsBox(*m_xFemaleLB, m_rConfigItem, SwMailMergeConfigItem::FEMALE); + lcl_FillGreetingsBox(*m_xMaleLB, m_rConfigItem, SwMailMergeConfigItem::MALE); + lcl_FillGreetingsBox(*m_xNeutralCB, m_rConfigItem, SwMailMergeConfigItem::NEUTRAL); + + m_xDocumentIndexFI->set_label(m_sDocument.replaceFirst("%1", "1")); +} + +SwMailMergeGreetingsPage::~SwMailMergeGreetingsPage() +{ + m_xPreviewWIN.reset(); + m_xPreview.reset(); +} + +void SwMailMergeGreetingsPage::Activate() +{ + //try to find the gender setting + m_xFemaleColumnLB->clear(); + Reference< sdbcx::XColumnsSupplier > xColsSupp = m_rConfigItem.GetColumnsSupplier(); + if(xColsSupp.is()) + { + Reference < container::XNameAccess> xColAccess = xColsSupp->getColumns(); + const Sequence< OUString > aColumns = xColAccess->getElementNames(); + for(const auto& rColumn : aColumns) + m_xFemaleColumnLB->append_text(rColumn); + } + + m_xFemaleColumnLB->set_active_text(m_rConfigItem.GetAssignedColumn(MM_PART_GENDER)); + m_xFemaleColumnLB->save_value(); + + m_xFemaleFieldCB->set_entry_text(m_rConfigItem.GetFemaleGenderValue()); + m_xFemaleFieldCB->save_value(); + + UpdatePreview(); + m_pWizard->enableButtons(WizardButtonFlags::NEXT, m_pWizard->isStateEnabled(MM_LAYOUTPAGE)); +} + +bool SwMailMergeGreetingsPage::commitPage( ::vcl::WizardTypes::CommitPageReason ) +{ + if (m_xFemaleColumnLB->get_value_changed_from_saved()) + { + const SwDBData& rDBData = m_rConfigItem.GetCurrentDBData(); + Sequence< OUString> aAssignment = m_rConfigItem.GetColumnAssignment( rDBData ); + if(aAssignment.getLength() <= MM_PART_GENDER) + aAssignment.realloc(MM_PART_GENDER + 1); + aAssignment.getArray()[MM_PART_GENDER] = m_xFemaleColumnLB->get_active_text(); + m_rConfigItem.SetColumnAssignment( rDBData, aAssignment ); + } + if (m_xFemaleFieldCB->get_value_changed_from_saved()) + m_rConfigItem.SetFemaleGenderValue(m_xFemaleFieldCB->get_active_text()); + + lcl_StoreGreetingsBox(*m_xFemaleLB, m_rConfigItem, SwMailMergeConfigItem::FEMALE); + lcl_StoreGreetingsBox(*m_xMaleLB, m_rConfigItem, SwMailMergeConfigItem::MALE); + + sal_Int32 nCurrentTextPos = m_xNeutralCB->find_text(m_xNeutralCB->get_active_text()); + if (nCurrentTextPos == -1) + { + m_xNeutralCB->append_text(m_xNeutralCB->get_active_text()); + m_xNeutralCB->set_active(m_xNeutralCB->get_count() - 1); + } + lcl_StoreGreetingsBox(*m_xNeutralCB, m_rConfigItem, SwMailMergeConfigItem::NEUTRAL); + m_rConfigItem.SetGreetingLine(m_xGreetingLineCB->get_active(), false); + m_rConfigItem.SetIndividualGreeting(m_xPersonalizedCB->get_active(), false); + return true; +} + +IMPL_LINK(SwMailMergeGreetingsPage, ContainsHdl_Impl, weld::Toggleable&, rBox, void) +{ + bool bContainsGreeting = rBox.get_active(); + SwGreetingsHandler::Contains(bContainsGreeting); + m_xPreviewFI->set_sensitive(bContainsGreeting); + m_xPreviewWIN->set_sensitive(bContainsGreeting); + m_xAssignPB->set_sensitive(bContainsGreeting); + m_xDocumentIndexFI->set_sensitive(bContainsGreeting); + m_xPrevSetIB->set_sensitive(bContainsGreeting); + m_xNextSetIB->set_sensitive(bContainsGreeting); + m_rConfigItem.SetGreetingLine(m_xGreetingLineCB->get_active(), false); + m_pWizard->UpdateRoadmap(); + m_pWizard->enableButtons(WizardButtonFlags::NEXT, m_pWizard->isStateEnabled(MM_LAYOUTPAGE)); +} + +IMPL_LINK(SwMailMergeGreetingsPage, InsertDataHdl_Impl, weld::Button&, rButton, void) +{ + bool bNext = &rButton == m_xNextSetIB.get(); + sal_Int32 nPos = m_rConfigItem.GetResultSetPosition(); + m_rConfigItem.MoveResultSet( bNext ? ++nPos : --nPos); + nPos = m_rConfigItem.GetResultSetPosition(); + bool bEnable = true; + if(nPos < 1) + { + bEnable = false; + nPos = 1; + } + else + UpdatePreview(); + m_xPrevSetIB->set_sensitive(bEnable); + m_xNextSetIB->set_sensitive(bEnable); + m_xDocumentIndexFI->set_sensitive(bEnable); + m_xDocumentIndexFI->set_label(m_sDocument.replaceFirst("%1", OUString::number(nPos))); +} + +SwMailBodyDialog::SwMailBodyDialog(weld::Window* pParent) + : SfxDialogController(pParent, "modules/swriter/ui/mmmailbody.ui", "MailBodyDialog") + , SwGreetingsHandler(*GetActiveView()->GetMailMergeConfigItem(), *m_xBuilder) + , m_xBodyMLE(m_xBuilder->weld_text_view("bodymle")) + , m_xOK(m_xBuilder->weld_button("ok")) +{ + m_bIsTabPage = false; + m_xBodyMLE->set_size_request(m_xBodyMLE->get_approximate_digit_width() * 45, + m_xBodyMLE->get_height_rows(6)); + m_xGreetingLineCB->connect_toggled(LINK(this, SwMailBodyDialog, ContainsHdl_Impl)); + Link<weld::Toggleable&,void> aIndividualLink = LINK(this, SwGreetingsHandler, IndividualHdl_Impl); + m_xPersonalizedCB->connect_toggled(aIndividualLink); + Link<weld::Button&,void> aGreetingLink = LINK(this, SwGreetingsHandler, GreetingHdl_Impl); + m_xFemalePB->connect_clicked(aGreetingLink); + m_xMalePB->connect_clicked(aGreetingLink); + m_xOK->connect_clicked(LINK(this, SwMailBodyDialog, OKHdl)); + + m_xGreetingLineCB->set_active(m_rConfigItem.IsGreetingLine(true)); + m_xPersonalizedCB->set_active(m_rConfigItem.IsIndividualGreeting(true)); + ContainsHdl_Impl(*m_xGreetingLineCB); + aIndividualLink.Call(*m_xPersonalizedCB); + + lcl_FillGreetingsBox(*m_xFemaleLB, m_rConfigItem, SwMailMergeConfigItem::FEMALE); + lcl_FillGreetingsBox(*m_xMaleLB, m_rConfigItem, SwMailMergeConfigItem::MALE); + lcl_FillGreetingsBox(*m_xNeutralCB, m_rConfigItem, SwMailMergeConfigItem::NEUTRAL); + + //try to find the gender setting + m_xFemaleColumnLB->clear(); + Reference< sdbcx::XColumnsSupplier > xColsSupp = m_rConfigItem.GetColumnsSupplier(); + if(xColsSupp.is()) + { + Reference < container::XNameAccess> xColAccess = xColsSupp->getColumns(); + const Sequence< OUString > aColumns = xColAccess->getElementNames(); + for(const auto& rColumn : aColumns) + m_xFemaleColumnLB->append_text(rColumn); + } + + m_xFemaleColumnLB->set_active_text(m_rConfigItem.GetAssignedColumn(MM_PART_GENDER)); + m_xFemaleColumnLB->save_value(); + + m_xFemaleFieldCB->set_entry_text(m_rConfigItem.GetFemaleGenderValue()); + m_xFemaleFieldCB->save_value(); +} + +SwMailBodyDialog::~SwMailBodyDialog() +{ +} + +IMPL_LINK(SwMailBodyDialog, ContainsHdl_Impl, weld::Toggleable&, rBox, void) +{ + SwGreetingsHandler::Contains(rBox.get_active()); + m_rConfigItem.SetGreetingLine(rBox.get_active(), true); +} + +IMPL_LINK_NOARG(SwMailBodyDialog, OKHdl, weld::Button&, void) +{ + m_rConfigItem.SetGreetingLine( + m_xGreetingLineCB->get_active(), false); + m_rConfigItem.SetIndividualGreeting( + m_xPersonalizedCB->get_active(), false); + + if (m_xFemaleColumnLB->get_value_changed_from_saved()) + { + const SwDBData& rDBData = m_rConfigItem.GetCurrentDBData(); + Sequence< OUString> aAssignment = m_rConfigItem.GetColumnAssignment( rDBData ); + sal_Int32 nPos = m_xFemaleColumnLB->get_active(); + if(aAssignment.getLength() < MM_PART_GENDER) + aAssignment.realloc(MM_PART_GENDER); + if( nPos > 0 ) + aAssignment.getArray()[MM_PART_GENDER] = m_xFemaleColumnLB->get_active_text(); + else + aAssignment.getArray()[MM_PART_GENDER].clear(); + m_rConfigItem.SetColumnAssignment( rDBData, aAssignment ); + } + if (m_xFemaleFieldCB->get_value_changed_from_saved()) + m_rConfigItem.SetFemaleGenderValue(m_xFemaleFieldCB->get_active_text()); + + m_xDialog->response(RET_OK); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/mmgreetingspage.hxx b/sw/source/ui/dbui/mmgreetingspage.hxx new file mode 100644 index 0000000000..cce99a0ffb --- /dev/null +++ b/sw/source/ui/dbui/mmgreetingspage.hxx @@ -0,0 +1,130 @@ +/* -*- 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_DBUI_MMGREETINGSPAGE_HXX +#define INCLUDED_SW_SOURCE_UI_DBUI_MMGREETINGSPAGE_HXX + +#include <vcl/wizardmachine.hxx> +#include <sfx2/basedlgs.hxx> +#include <mailmergehelper.hxx> +#include <vcl/weld.hxx> + +#include <mailmergewizard.hxx> + +class SwMailMergeWizard; + +class SwGreetingsHandler +{ +protected: + SwMailMergeWizard* m_pWizard; + /// The mail merge state, available even when m_pWizard is nullptr. + SwMailMergeConfigItem& m_rConfigItem; + bool m_bIsTabPage; + + std::unique_ptr<weld::CheckButton> m_xGreetingLineCB; + std::unique_ptr<weld::CheckButton> m_xPersonalizedCB; + std::unique_ptr<weld::Label> m_xFemaleFT; + std::unique_ptr<weld::ComboBox> m_xFemaleLB; + std::unique_ptr<weld::Button> m_xFemalePB; + std::unique_ptr<weld::Label> m_xMaleFT; + std::unique_ptr<weld::ComboBox> m_xMaleLB; + std::unique_ptr<weld::Button> m_xMalePB; + std::unique_ptr<weld::Label> m_xFemaleFI; + std::unique_ptr<weld::Label> m_xFemaleColumnFT; + std::unique_ptr<weld::ComboBox> m_xFemaleColumnLB; + std::unique_ptr<weld::Label> m_xFemaleFieldFT; + std::unique_ptr<weld::ComboBox> m_xFemaleFieldCB; + std::unique_ptr<weld::Label> m_xNeutralFT; + std::unique_ptr<weld::ComboBox> m_xNeutralCB; + + SwGreetingsHandler(SwMailMergeConfigItem& rConfigItem, weld::Builder& rBuilder) + : m_pWizard(nullptr) + , m_rConfigItem(rConfigItem) + , m_bIsTabPage(false) + , m_xGreetingLineCB(rBuilder.weld_check_button("greeting")) + , m_xPersonalizedCB(rBuilder.weld_check_button("personalized")) + , m_xFemaleFT(rBuilder.weld_label("femaleft")) + , m_xFemaleLB(rBuilder.weld_combo_box("female")) + , m_xFemalePB(rBuilder.weld_button("newfemale")) + , m_xMaleFT(rBuilder.weld_label("maleft")) + , m_xMaleLB(rBuilder.weld_combo_box("male")) + , m_xMalePB(rBuilder.weld_button("newmale")) + , m_xFemaleFI(rBuilder.weld_label("femalefi")) + , m_xFemaleColumnFT(rBuilder.weld_label("femalecolft")) + , m_xFemaleColumnLB(rBuilder.weld_combo_box("femalecol")) + , m_xFemaleFieldFT(rBuilder.weld_label("femalefieldft")) + , m_xFemaleFieldCB(rBuilder.weld_combo_box("femalefield")) + , m_xNeutralFT(rBuilder.weld_label("generalft")) + , m_xNeutralCB(rBuilder.weld_combo_box("general")) + { + } + + ~SwGreetingsHandler() {} + + DECL_LINK(IndividualHdl_Impl, weld::Toggleable&, void); + DECL_LINK(GreetingHdl_Impl, weld::Button&, void); + + void Contains(bool bContainsGreeting); + virtual void UpdatePreview(); +}; + +class SwMailMergeGreetingsPage : public vcl::OWizardPage, public SwGreetingsHandler +{ + std::unique_ptr<SwAddressPreview> m_xPreview; + std::unique_ptr<weld::Label> m_xPreviewFI; + std::unique_ptr<weld::Button> m_xAssignPB; + std::unique_ptr<weld::Label> m_xDocumentIndexFI; + std::unique_ptr<weld::Button> m_xPrevSetIB; + std::unique_ptr<weld::Button> m_xNextSetIB; + std::unique_ptr<weld::CustomWeld> m_xPreviewWIN; + + OUString m_sDocument; + + DECL_LINK(ContainsHdl_Impl, weld::Toggleable&, void); + DECL_LINK(InsertDataHdl_Impl, weld::Button&, void); + DECL_LINK(GreetingSelectComboBoxHdl_Impl, weld::ComboBox&, void); + DECL_LINK(GreetingSelectListBoxHdl_Impl, weld::ComboBox&, void); + DECL_LINK(AssignHdl_Impl, weld::Button&, void); + + virtual void UpdatePreview() override; + virtual void Activate() override; + virtual bool commitPage(::vcl::WizardTypes::CommitPageReason _eReason) override; + +public: + SwMailMergeGreetingsPage(weld::Container* pPage, SwMailMergeWizard* pWizard); + virtual ~SwMailMergeGreetingsPage() override; +}; + +class SwMailBodyDialog : public SfxDialogController, public SwGreetingsHandler +{ + std::unique_ptr<weld::TextView> m_xBodyMLE; + std::unique_ptr<weld::Button> m_xOK; + + DECL_LINK(ContainsHdl_Impl, weld::Toggleable&, void); + DECL_LINK(OKHdl, weld::Button&, void); + +public: + SwMailBodyDialog(weld::Window* pParent); + virtual ~SwMailBodyDialog() override; + + void SetBody(const OUString& rBody) { m_xBodyMLE->set_text(rBody); } + OUString GetBody() const { return m_xBodyMLE->get_text(); } +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/mmlayoutpage.cxx b/sw/source/ui/dbui/mmlayoutpage.cxx new file mode 100644 index 0000000000..2e01e49ec9 --- /dev/null +++ b/sw/source/ui/dbui/mmlayoutpage.cxx @@ -0,0 +1,692 @@ +/* -*- 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 <swtypes.hxx> +#include "mmlayoutpage.hxx" +#include <mailmergewizard.hxx> +#include <mmconfigitem.hxx> +#include <mailmergehelper.hxx> +#include <unotools.hxx> +#include <comphelper/string.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/servicehelper.hxx> +#include <i18nutil/unicode.hxx> +#include <unotools/tempfile.hxx> +#include <uitool.hxx> +#include <view.hxx> +#include <swundo.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/fcontnr.hxx> +#include <svtools/unitconv.hxx> +#include <com/sun/star/view/XViewSettingsSupplier.hpp> +#include <com/sun/star/view/DocumentZoomType.hpp> +#include <fldmgr.hxx> +#include <fldbas.hxx> +#include <unotxdoc.hxx> +#include <docsh.hxx> +#include <doc.hxx> +#include <wrtsh.hxx> +#include <fmtsrnd.hxx> +#include <pagedesc.hxx> +#include <fmtanchr.hxx> +#include <fmtornt.hxx> +#include <fmtfsize.hxx> +#include <editeng/boxitem.hxx> +#include <osl/file.hxx> +#include <vcl/settings.hxx> +#include <unoprnms.hxx> + +#include <dbui.hrc> + +using namespace osl; +using namespace svt; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::view; + +constexpr tools::Long DEFAULT_LEFT_DISTANCE = o3tl::toTwips(25, o3tl::Length::mm); // 2,5 cm +constexpr tools::Long DEFAULT_TOP_DISTANCE = o3tl::toTwips(55, o3tl::Length::mm); // 5,5 cm +constexpr tools::Long GREETING_TOP_DISTANCE = o3tl::toTwips(125, o3tl::Length::mm); //12,5 cm +constexpr tools::Long DEFAULT_ADDRESS_WIDTH = o3tl::toTwips(75, o3tl::Length::mm); // 7,5 cm +constexpr tools::Long DEFAULT_ADDRESS_HEIGHT = o3tl::toTwips(35, o3tl::Length::mm); // 3,5cm + +SwMailMergeLayoutPage::SwMailMergeLayoutPage(weld::Container* pPage, SwMailMergeWizard* pWizard) + : vcl::OWizardPage(pPage, pWizard, "modules/swriter/ui/mmlayoutpage.ui", "MMLayoutPage") + , m_pExampleWrtShell(nullptr) + , m_pAddressBlockFormat(nullptr) + , m_bIsGreetingInserted(false) + , m_pWizard(pWizard) + , m_xPosition(m_xBuilder->weld_container("addresspos")) + , m_xAlignToBodyCB(m_xBuilder->weld_check_button("align")) + , m_xLeftFT(m_xBuilder->weld_label("leftft")) + , m_xLeftMF(m_xBuilder->weld_metric_spin_button("left", FieldUnit::CM)) + , m_xTopMF(m_xBuilder->weld_metric_spin_button("top", FieldUnit::CM)) + , m_xGreetingLine(m_xBuilder->weld_container("greetingspos")) + , m_xUpPB(m_xBuilder->weld_button("up")) + , m_xDownPB(m_xBuilder->weld_button("down")) + , m_xZoomLB(m_xBuilder->weld_combo_box("zoom")) +{ + std::shared_ptr<const SfxFilter> pSfxFlt = + SwDocShell::Factory().GetFilterContainer()-> + GetFilter4FilterName("writer8", SfxFilterFlags::EXPORT); + + //save the current document into a temporary file + { + //temp file needs its own block + //creating with extension is not supported by a static method :-( + OUString const sExt( + comphelper::string::stripStart(pSfxFlt->GetDefaultExtension(),'*')); + utl::TempFileNamed aTempFile( u"", true, sExt ); + aTempFile.EnableKillingFile(); + m_sExampleURL = aTempFile.GetURL(); + } + SwView* pView = m_pWizard->GetSwView(); + // Don't save embedded data set! It would steal it from current document. + uno::Sequence< beans::PropertyValue > aValues = + { + comphelper::makePropertyValue("FilterName", pSfxFlt->GetFilterName()), + comphelper::makePropertyValue("NoEmbDataSet", true) + }; + + uno::Reference< frame::XStorable > xStore( pView->GetDocShell()->GetModel(), uno::UNO_QUERY); + xStore->storeToURL( m_sExampleURL, aValues ); + + Link<SwOneExampleFrame&,void> aLink(LINK(this, SwMailMergeLayoutPage, PreviewLoadedHdl_Impl)); + m_xExampleFrame.reset(new SwOneExampleFrame(EX_SHOW_DEFAULT_PAGE, &aLink, &m_sExampleURL)); + m_xExampleContainerWIN.reset(new weld::CustomWeld(*m_xBuilder, "example", *m_xExampleFrame)); + + Size aSize = m_xExampleFrame->GetDrawingArea()->get_ref_device().LogicToPixel( + Size(124, 159), MapMode(MapUnit::MapAppFont)); + m_xExampleFrame->set_size_request(aSize.Width(), aSize.Height()); + + m_xExampleContainerWIN->hide(); + + m_xLeftMF->set_value(m_xLeftMF->normalize(DEFAULT_LEFT_DISTANCE), FieldUnit::TWIP); + m_xTopMF->set_value(m_xTopMF->normalize(DEFAULT_TOP_DISTANCE), FieldUnit::TWIP); + + const LanguageTag& rLang = Application::GetSettings().GetUILanguageTag(); + m_xZoomLB->append_text(unicode::formatPercent(50, rLang)); + m_xZoomLB->append_text(unicode::formatPercent(75, rLang)); + m_xZoomLB->append_text(unicode::formatPercent(100, rLang)); + m_xZoomLB->set_active(0); //page size + m_xZoomLB->connect_changed(LINK(this, SwMailMergeLayoutPage, ZoomHdl_Impl)); + + Link<weld::MetricSpinButton&,void> aFrameHdl = LINK(this, SwMailMergeLayoutPage, ChangeAddressHdl_Impl); + m_xLeftMF->connect_value_changed(aFrameHdl); + m_xTopMF->connect_value_changed(aFrameHdl); + + FieldUnit eFieldUnit = ::GetDfltMetric(false); + ::SetFieldUnit( *m_xLeftMF, eFieldUnit ); + ::SetFieldUnit( *m_xTopMF, eFieldUnit ); + + Link<weld::Button&,void> aUpDownHdl = LINK(this, SwMailMergeLayoutPage, GreetingsHdl_Impl ); + m_xUpPB->connect_clicked(aUpDownHdl); + m_xDownPB->connect_clicked(aUpDownHdl); + m_xAlignToBodyCB->connect_toggled(LINK(this, SwMailMergeLayoutPage, AlignToTextHdl_Impl)); + m_xAlignToBodyCB->set_active(true); +} + +SwMailMergeLayoutPage::~SwMailMergeLayoutPage() +{ + File::remove( m_sExampleURL ); +} + +void SwMailMergeLayoutPage::Activate() +{ + SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); + bool bGreetingLine = rConfigItem.IsGreetingLine(false) && !rConfigItem.IsGreetingInserted(); + bool bAddressBlock = rConfigItem.IsAddressBlock() && !rConfigItem.IsAddressInserted(); + + m_xPosition->set_sensitive(bAddressBlock); + AlignToTextHdl_Impl(*m_xAlignToBodyCB); + + m_xGreetingLine->set_sensitive(bGreetingLine); + + //check if greeting and/or address frame have to be inserted/removed + if(!m_pExampleWrtShell) // initially there's nothing to check + return; + + if(!rConfigItem.IsGreetingInserted() && + m_bIsGreetingInserted != bGreetingLine ) + { + if( m_bIsGreetingInserted ) + { + m_pExampleWrtShell->DelFullPara(); + m_bIsGreetingInserted = false; + } + else + { + InsertGreeting(*m_pExampleWrtShell, m_pWizard->GetConfigItem(), true); + m_bIsGreetingInserted = true; + } + } + if(!rConfigItem.IsAddressInserted() && + rConfigItem.IsAddressBlock() != ( nullptr != m_pAddressBlockFormat )) + { + if( m_pAddressBlockFormat ) + { + m_pExampleWrtShell->Push(); + m_pExampleWrtShell->GotoFly( m_pAddressBlockFormat->GetName() ); + m_pExampleWrtShell->DelRight(); + m_pAddressBlockFormat = nullptr; + m_pExampleWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent); + } + else + { + tools::Long nLeft = static_cast< tools::Long >(m_xLeftMF->denormalize(m_xLeftMF->get_value(FieldUnit::TWIP))); + tools::Long nTop = static_cast< tools::Long >(m_xTopMF->denormalize(m_xTopMF->get_value(FieldUnit::TWIP))); + m_pAddressBlockFormat = InsertAddressFrame( + *m_pExampleWrtShell, m_pWizard->GetConfigItem(), + Point(nLeft, nTop), + m_xAlignToBodyCB->get_active(), true); + } + } + m_xExampleFrame->Invalidate(); +} + +bool SwMailMergeLayoutPage::commitPage(::vcl::WizardTypes::CommitPageReason eReason) +{ + //now insert the frame and the greeting + SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); + if (eReason == ::vcl::WizardTypes::eTravelForward || eReason == ::vcl::WizardTypes::eFinish) + { + tools::Long nLeft = static_cast< tools::Long >(m_xLeftMF->denormalize(m_xLeftMF->get_value(FieldUnit::TWIP))); + tools::Long nTop = static_cast< tools::Long >(m_xTopMF->denormalize(m_xTopMF->get_value(FieldUnit::TWIP))); + InsertAddressAndGreeting( + m_pWizard->GetSwView(), + rConfigItem, + Point(nLeft, nTop), + m_xAlignToBodyCB->get_active()); + } + return true; +} + +SwFrameFormat* SwMailMergeLayoutPage::InsertAddressAndGreeting(SwView const * pView, + SwMailMergeConfigItem& rConfigItem, + const Point& rAddressPosition, + bool bAlignToBody) +{ + SwFrameFormat* pAddressBlockFormat = nullptr; + pView->GetWrtShell().StartUndo(SwUndoId::INSERT); + if(rConfigItem.IsAddressBlock() && !rConfigItem.IsAddressInserted()) + { + //insert the frame + Point aAddressPosition(DEFAULT_LEFT_DISTANCE, DEFAULT_TOP_DISTANCE); + if(rAddressPosition.X() > 0 && rAddressPosition.Y() > 0) + aAddressPosition = rAddressPosition; + pAddressBlockFormat = InsertAddressFrame( pView->GetWrtShell(), + rConfigItem, + aAddressPosition, bAlignToBody, false); + rConfigItem.SetAddressInserted(); + } + //now the greeting + if(rConfigItem.IsGreetingLine(false) && !rConfigItem.IsGreetingInserted()) + { + InsertGreeting( pView->GetWrtShell(), rConfigItem, false); + rConfigItem.SetGreetingInserted(); + } + pView->GetWrtShell().EndUndo(SwUndoId::INSERT); + return pAddressBlockFormat; +} + +SwFrameFormat* SwMailMergeLayoutPage::InsertAddressFrame( + SwWrtShell& rShell, + SwMailMergeConfigItem const & rConfigItem, + const Point& rDestination, + bool bAlignLeft, + bool bExample) +{ + // insert the address block and the greeting line + SfxItemSetFixed< + RES_FRM_SIZE, RES_FRM_SIZE, + RES_SURROUND, RES_ANCHOR, + RES_BOX, RES_BOX> aSet( rShell.GetAttrPool() ); + aSet.Put(SwFormatAnchor(RndStdIds::FLY_AT_PAGE, 1)); + if(bAlignLeft) + aSet.Put(SwFormatHoriOrient( 0, text::HoriOrientation::NONE, text::RelOrientation::PAGE_PRINT_AREA )); + else + aSet.Put(SwFormatHoriOrient( rDestination.X(), text::HoriOrientation::NONE, text::RelOrientation::PAGE_FRAME )); + aSet.Put(SwFormatVertOrient( rDestination.Y(), text::VertOrientation::NONE, text::RelOrientation::PAGE_FRAME )); + aSet.Put(SwFormatFrameSize( SwFrameSize::Minimum, DEFAULT_ADDRESS_WIDTH, DEFAULT_ADDRESS_HEIGHT )); + // the example gets a border around the frame, the real document doesn't get one + if(!bExample) + aSet.Put(SvxBoxItem( RES_BOX )); + aSet.Put(SwFormatSurround( css::text::WrapTextMode_NONE )); + + rShell.NewFlyFrame(aSet, true ); + SwFrameFormat* pRet = rShell.GetFlyFrameFormat(); + OSL_ENSURE( pRet, "Fly not inserted" ); + + rShell.UnSelectFrame(); + const Sequence< OUString> aBlocks = rConfigItem.GetAddressBlocks(); + if(bExample) + { + rShell.Insert(aBlocks[0]); + } + else + { + //the placeholders should be replaced by the appropriate fields + SwFieldMgr aFieldMgr(&rShell); + //create a database string source.command.commandtype.column + const SwDBData& rData = rConfigItem.GetCurrentDBData(); + OUString sDBName(rData.sDataSource + OUStringChar(DB_DELIM) + + rData.sCommand + OUStringChar(DB_DELIM)); + const OUString sDatabaseConditionPrefix(sDBName.replace(DB_DELIM, '.')); + sDBName += OUString::number(rData.nCommandType) + OUStringChar(DB_DELIM); + + // if only the country is in an address line the + // paragraph has to be hidden depending on the + // IsIncludeCountry()/GetExcludeCountry() settings + + bool bIncludeCountry = rConfigItem.IsIncludeCountry(); + bool bHideEmptyParagraphs = rConfigItem.IsHideEmptyParagraphs(); + const OUString rExcludeCountry = rConfigItem.GetExcludeCountry(); + bool bSpecialReplacementForCountry = (!bIncludeCountry || !rExcludeCountry.isEmpty()); + + const std::vector<std::pair<OUString, int>>& rHeaders = rConfigItem.GetDefaultAddressHeaders(); + Sequence< OUString> aAssignment = + rConfigItem.GetColumnAssignment( rConfigItem.GetCurrentDBData() ); + const OUString* pAssignment = aAssignment.getConstArray(); + const OUString sCountryColumn( + (aAssignment.getLength() > MM_PART_COUNTRY && !aAssignment[MM_PART_COUNTRY].isEmpty()) + ? aAssignment[MM_PART_COUNTRY] + : rHeaders[MM_PART_COUNTRY].first); + + OUString sHideParagraphsExpression; + SwAddressIterator aIter(aBlocks[0]); + while(aIter.HasMore()) + { + SwMergeAddressItem aItem = aIter.Next(); + if(aItem.bIsColumn) + { + OUString sConvertedColumn = aItem.sText; + auto nSize = std::min(static_cast<sal_uInt32>(rHeaders.size()), + static_cast<sal_uInt32>(aAssignment.getLength())); + for(sal_uInt32 nColumn = 0; nColumn < nSize; ++nColumn) + { + if (rHeaders[nColumn].first == aItem.sText && + !pAssignment[nColumn].isEmpty()) + { + sConvertedColumn = pAssignment[nColumn]; + break; + } + } + const OUString sDB(sDBName + sConvertedColumn); + + if(!sHideParagraphsExpression.isEmpty()) + sHideParagraphsExpression += " AND "; + sHideParagraphsExpression += "![" + sDatabaseConditionPrefix + sConvertedColumn + "]"; + + if( bSpecialReplacementForCountry && sCountryColumn == sConvertedColumn ) + { + // now insert a hidden paragraph field + if( !rExcludeCountry.isEmpty() ) + { + const OUString sExpression("[" + sDatabaseConditionPrefix + sCountryColumn + "]"); + SwInsertField_Data aData(SwFieldTypesEnum::ConditionalText, 0, + sExpression + " != \"" + rExcludeCountry + "\"", + sExpression, + 0, &rShell ); + aFieldMgr.InsertField( aData ); + } + else + { + SwInsertField_Data aData(SwFieldTypesEnum::HiddenParagraph, 0, "", "", 0, &rShell ); + aFieldMgr.InsertField( aData ); + } + } + else + { + SwInsertField_Data aData(SwFieldTypesEnum::Database, 0, sDB, OUString(), 0, &rShell); + aFieldMgr.InsertField( aData ); + } + } + else if(!aItem.bIsReturn) + { + rShell.Insert(aItem.sText); + } + else + { + if(bHideEmptyParagraphs) + { + SwInsertField_Data aData(SwFieldTypesEnum::HiddenParagraph, 0, sHideParagraphsExpression, OUString(), 0, &rShell); + aFieldMgr.InsertField( aData ); + } + sHideParagraphsExpression.clear(); + //now add a new paragraph + rShell.SplitNode(); + } + } + if(bHideEmptyParagraphs && !sHideParagraphsExpression.isEmpty()) + { + SwInsertField_Data aData(SwFieldTypesEnum::HiddenParagraph, 0, sHideParagraphsExpression, OUString(), 0, &rShell); + aFieldMgr.InsertField( aData ); + } + } + return pRet; +} + +void SwMailMergeLayoutPage::InsertGreeting(SwWrtShell& rShell, SwMailMergeConfigItem const & rConfigItem, bool bExample) +{ + //set the cursor to the desired position - if no text content is here then + //new paragraphs are inserted + const SwRect& rPageRect = rShell.GetAnyCurRect(CurRectType::Page); + const Point aGreetingPos( DEFAULT_LEFT_DISTANCE + rPageRect.Left(), GREETING_TOP_DISTANCE ); + + const bool bRet = rShell.SetShadowCursorPos( aGreetingPos, SwFillMode::TabSpace ); + + if(!bRet) + { + //there's already text at the desired position + //go to start of the doc, directly! + rShell.SttEndDoc(true); + //and go by paragraph until the position is reached + tools::Long nYPos = rShell.GetCharRect().Top(); + while(nYPos < GREETING_TOP_DISTANCE) + { + if(!rShell.FwdPara()) + break; + nYPos = rShell.GetCharRect().Top(); + } + //text needs to be appended + while(nYPos < GREETING_TOP_DISTANCE) + { + if(!rShell.AppendTextNode()) + break; + nYPos = rShell.GetCharRect().Top(); + } + } + else + { + //we may end up inside of a paragraph if the left margin is not at DEFAULT_LEFT_DISTANCE + rShell.MovePara(GoCurrPara, fnParaStart); + } + bool bSplitNode = !rShell.IsEndPara(); + SwNodeOffset nMoves(rConfigItem.GetGreetingMoves()); + if( !bExample && SwNodeOffset(0) != nMoves ) + { + if(nMoves < SwNodeOffset(0)) + { + rShell.MoveParagraph( nMoves ); + } + else + while(nMoves) + { + bool bMoved = rShell.MoveParagraph(); + if(!bMoved) + { + //insert a new paragraph before the greeting line + rShell.SplitNode(); + } + --nMoves; + } + } + //now insert the greeting text - if we have any? + const bool bIndividual = rConfigItem.IsIndividualGreeting(false); + if(bIndividual) + { + //lock expression fields - prevents hiding of the paragraph to insert into + rShell.LockExpFields(); + if(bExample) + { + for(sal_Int8 eGender = SwMailMergeConfigItem::FEMALE; + eGender <= SwMailMergeConfigItem::NEUTRAL; ++eGender) + { + Sequence< OUString > aEntries = + rConfigItem.GetGreetings(static_cast<SwMailMergeConfigItem::Gender>(eGender)); + sal_Int32 nCurrent = rConfigItem.GetCurrentGreeting(static_cast<SwMailMergeConfigItem::Gender>(eGender)); + if( nCurrent >= 0 && nCurrent < aEntries.getLength()) + { + // Greeting + rShell.Insert(aEntries[nCurrent]); + break; + } + } + } + else + { + SwFieldMgr aFieldMgr(&rShell); + //three paragraphs, each with an appropriate hidden paragraph field + //are to be inserted + + //name of the gender column + const OUString sGenderColumn = rConfigItem.GetAssignedColumn(MM_PART_GENDER); + const OUString sNameColumn = rConfigItem.GetAssignedColumn(MM_PART_LASTNAME); + + const OUString& rFemaleGenderValue = rConfigItem.GetFemaleGenderValue(); + bool bHideEmptyParagraphs = rConfigItem.IsHideEmptyParagraphs(); + const SwDBData& rData = rConfigItem.GetCurrentDBData(); + const OUString sCommonBase(rData.sDataSource + "." + rData.sCommand + "."); + const OUString sConditionBase("[" + sCommonBase + sGenderColumn + "]"); + const OUString sNameColumnBase("[" + sCommonBase + sNameColumn + "]"); + + const OUString sDBName(rData.sDataSource + OUStringChar(DB_DELIM) + + rData.sCommand + OUStringChar(DB_DELIM) + + OUString::number(rData.nCommandType) + OUStringChar(DB_DELIM)); + +// Female: [database.sGenderColumn] != "rFemaleGenderValue" && [database.NameColumn] +// Male: [database.sGenderColumn] == "rFemaleGenderValue" && [database.rGenderColumn] +// Neutral: [database.sNameColumn] + OSL_ENSURE(!sGenderColumn.isEmpty() && !rFemaleGenderValue.isEmpty(), + "gender settings not available - how to form the condition?"); + //column used as lastname + for(sal_Int8 eGender = SwMailMergeConfigItem::FEMALE; + eGender <= SwMailMergeConfigItem::NEUTRAL; ++eGender) + { + Sequence< OUString> aEntries = rConfigItem.GetGreetings(static_cast<SwMailMergeConfigItem::Gender>(eGender)); + sal_Int32 nCurrent = rConfigItem.GetCurrentGreeting(static_cast<SwMailMergeConfigItem::Gender>(eGender)); + if( nCurrent >= 0 && nCurrent < aEntries.getLength()) + { + const OUString sGreeting = aEntries[nCurrent]; + OUString sCondition; + OUString sHideParagraphsExpression; + switch(eGender) + { + case SwMailMergeConfigItem::FEMALE: + sCondition = sConditionBase + " != \"" + rFemaleGenderValue + + "\" OR NOT " + sNameColumnBase; + sHideParagraphsExpression = "!" + sNameColumnBase; + break; + case SwMailMergeConfigItem::MALE: + sCondition = sConditionBase + " == \"" + rFemaleGenderValue + + "\" OR NOT " + sNameColumnBase; + break; + case SwMailMergeConfigItem::NEUTRAL: + sCondition = sNameColumnBase; + break; + } + + if(bHideEmptyParagraphs && !sHideParagraphsExpression.isEmpty()) + { + OUString sComplete = "(" + sCondition + ") OR (" + sHideParagraphsExpression + ")"; + SwInsertField_Data aData(SwFieldTypesEnum::HiddenParagraph, 0, sComplete, OUString(), 0, &rShell); + aFieldMgr.InsertField( aData ); + } + else + { + SwInsertField_Data aData(SwFieldTypesEnum::HiddenParagraph, 0, sCondition, OUString(), 0, &rShell); + aFieldMgr.InsertField( aData ); + } + //now the text has to be inserted + const std::vector<std::pair<OUString, int>>& rHeaders = rConfigItem.GetDefaultAddressHeaders(); + Sequence< OUString> aAssignment = + rConfigItem.GetColumnAssignment( rConfigItem.GetCurrentDBData() ); + const OUString* pAssignment = aAssignment.getConstArray(); + SwAddressIterator aIter(sGreeting); + while(aIter.HasMore()) + { + SwMergeAddressItem aItem = aIter.Next(); + if(aItem.bIsColumn) + { + OUString sConvertedColumn = aItem.sText; + auto nSize = std::min(static_cast<sal_uInt32>(rHeaders.size()), + static_cast<sal_uInt32>(aAssignment.getLength())); + for(sal_uInt32 nColumn = 0; nColumn < nSize; ++nColumn) + { + if (rHeaders[nColumn].first == aItem.sText && + !pAssignment[nColumn].isEmpty()) + { + sConvertedColumn = pAssignment[nColumn]; + break; + } + } + SwInsertField_Data aData(SwFieldTypesEnum::Database, 0, + sDBName + sConvertedColumn, + OUString(), 0, &rShell); + aFieldMgr.InsertField( aData ); + } + else + { + rShell.Insert(aItem.sText); + } + } + //now add a new paragraph + rShell.SplitNode(); + } + } + + } + rShell.UnlockExpFields(); + } + else + { + Sequence< OUString> aEntries = rConfigItem.GetGreetings(SwMailMergeConfigItem::NEUTRAL); + sal_Int32 nCurrent = rConfigItem.GetCurrentGreeting(SwMailMergeConfigItem::NEUTRAL); + // Greeting + rShell.Insert(( nCurrent >= 0 && nCurrent < aEntries.getLength() ) + ? aEntries[nCurrent] : OUString()); + } + // now insert a new paragraph here if necessary + if(bSplitNode) + { + rShell.Push(); + rShell.SplitNode(); + rShell.Pop(SwCursorShell::PopMode::DeleteCurrent); + } + //put the cursor to the start of the paragraph + rShell.SttPara(); + + OSL_ENSURE(nullptr == rShell.GetTableFormat(), "What to do with a table here?"); +} + +IMPL_LINK_NOARG(SwMailMergeLayoutPage, PreviewLoadedHdl_Impl, SwOneExampleFrame&, void) +{ + m_xExampleContainerWIN->show(); + + Reference< XModel > & xModel = m_xExampleFrame->GetModel(); + //now the ViewOptions should be set properly + Reference< XViewSettingsSupplier > xSettings(xModel->getCurrentController(), UNO_QUERY); + m_xViewProperties = xSettings->getViewSettings(); + auto pXDoc = comphelper::getFromUnoTunnel<SwXTextDocument>(xModel); + SwDocShell* pDocShell = pXDoc->GetDocShell(); + m_pExampleWrtShell = pDocShell->GetWrtShell(); + OSL_ENSURE(m_pExampleWrtShell, "No SwWrtShell found!"); + if(!m_pExampleWrtShell) + return; + + SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); + if(rConfigItem.IsAddressBlock()) + { + m_pAddressBlockFormat = InsertAddressFrame( + *m_pExampleWrtShell, rConfigItem, + Point(DEFAULT_LEFT_DISTANCE, DEFAULT_TOP_DISTANCE), + m_xAlignToBodyCB->get_active(), true); + } + if(rConfigItem.IsGreetingLine(false)) + { + InsertGreeting(*m_pExampleWrtShell, rConfigItem, true); + m_bIsGreetingInserted = true; + } + + ZoomHdl_Impl(*m_xZoomLB); + + const SwFormatFrameSize& rPageSize = m_pExampleWrtShell->GetPageDesc( + m_pExampleWrtShell->GetCurPageDesc()).GetMaster().GetFrameSize(); + m_xLeftMF->set_max(rPageSize.GetWidth() - DEFAULT_LEFT_DISTANCE, FieldUnit::NONE); + m_xTopMF->set_max(rPageSize.GetHeight() - DEFAULT_TOP_DISTANCE, FieldUnit::NONE); +} + +IMPL_LINK(SwMailMergeLayoutPage, ZoomHdl_Impl, weld::ComboBox&, rBox, void) +{ + if (!m_pExampleWrtShell) + return; + + sal_Int16 eType = DocumentZoomType::BY_VALUE; + short nZoom = 50; + switch (rBox.get_active()) + { + case 0 : eType = DocumentZoomType::ENTIRE_PAGE; break; + case 1 : nZoom = 50; break; + case 2 : nZoom = 75; break; + case 3 : nZoom = 100; break; + } + Any aZoom; + aZoom <<= eType; + m_xViewProperties->setPropertyValue(UNO_NAME_ZOOM_TYPE, aZoom); + aZoom <<= nZoom; + m_xViewProperties->setPropertyValue(UNO_NAME_ZOOM_VALUE, aZoom); + + m_xExampleFrame->Invalidate(); +} + +IMPL_LINK_NOARG(SwMailMergeLayoutPage, ChangeAddressHdl_Impl, weld::MetricSpinButton&, void) +{ + if(!(m_pExampleWrtShell && m_pAddressBlockFormat)) + return; + + tools::Long nLeft = static_cast< tools::Long >(m_xLeftMF->denormalize(m_xLeftMF->get_value(FieldUnit::TWIP))); + tools::Long nTop = static_cast< tools::Long >(m_xTopMF->denormalize(m_xTopMF->get_value(FieldUnit::TWIP))); + + SfxItemSetFixed<RES_VERT_ORIENT, RES_ANCHOR> aSet( + m_pExampleWrtShell->GetAttrPool()); + if (m_xAlignToBodyCB->get_active()) + aSet.Put(SwFormatHoriOrient( 0, text::HoriOrientation::NONE, text::RelOrientation::PAGE_PRINT_AREA )); + else + aSet.Put(SwFormatHoriOrient( nLeft, text::HoriOrientation::NONE, text::RelOrientation::PAGE_FRAME )); + aSet.Put(SwFormatVertOrient( nTop, text::VertOrientation::NONE, text::RelOrientation::PAGE_FRAME )); + m_pExampleWrtShell->GetDoc()->SetFlyFrameAttr( *m_pAddressBlockFormat, aSet ); + m_xExampleFrame->Invalidate(); +} + +IMPL_LINK(SwMailMergeLayoutPage, GreetingsHdl_Impl, weld::Button&, rButton, void) +{ + bool bDown = &rButton == m_xDownPB.get(); + bool bMoved = m_pExampleWrtShell->MoveParagraph( SwNodeOffset(bDown ? 1 : -1) ); + if (bMoved || bDown) + m_pWizard->GetConfigItem().MoveGreeting(bDown ? 1 : -1 ); + if(!bMoved && bDown) + { + //insert a new paragraph before the greeting line + m_pExampleWrtShell->SplitNode(); + } + m_xExampleFrame->Invalidate(); +} + +IMPL_LINK(SwMailMergeLayoutPage, AlignToTextHdl_Impl, weld::Toggleable&, rBox, void) +{ + bool bCheck = rBox.get_active() && rBox.get_sensitive(); + m_xLeftFT->set_sensitive(!bCheck); + m_xLeftMF->set_sensitive(!bCheck); + ChangeAddressHdl_Impl( *m_xLeftMF ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/mmlayoutpage.hxx b/sw/source/ui/dbui/mmlayoutpage.hxx new file mode 100644 index 0000000000..abec12bb2c --- /dev/null +++ b/sw/source/ui/dbui/mmlayoutpage.hxx @@ -0,0 +1,87 @@ +/* -*- 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_DBUI_MMLAYOUTPAGE_HXX +#define INCLUDED_SW_SOURCE_UI_DBUI_MMLAYOUTPAGE_HXX + +#include <vcl/wizardmachine.hxx> +#include <mailmergehelper.hxx> +#include <com/sun/star/uno/Reference.h> + +class SwMailMergeWizard; +class SwFrameFormat; +class SwOneExampleFrame; +class SwWrtShell; +class SwView; + +namespace com::sun::star::beans{ class XPropertySet;} + +class SwMailMergeLayoutPage : public vcl::OWizardPage +{ + SwWrtShell* m_pExampleWrtShell; + + OUString m_sExampleURL; + SwFrameFormat* m_pAddressBlockFormat; + + bool m_bIsGreetingInserted; + + SwMailMergeWizard* m_pWizard; + + css::uno::Reference< css::beans::XPropertySet > m_xViewProperties; + + std::unique_ptr<weld::Container> m_xPosition; + std::unique_ptr<weld::CheckButton> m_xAlignToBodyCB; + std::unique_ptr<weld::Label> m_xLeftFT; + std::unique_ptr<weld::MetricSpinButton> m_xLeftMF; + std::unique_ptr<weld::MetricSpinButton> m_xTopMF; + std::unique_ptr<weld::Container> m_xGreetingLine; + std::unique_ptr<weld::Button> m_xUpPB; + std::unique_ptr<weld::Button> m_xDownPB; + std::unique_ptr<weld::ComboBox> m_xZoomLB; + std::unique_ptr<SwOneExampleFrame> m_xExampleFrame; + std::unique_ptr<weld::CustomWeld> m_xExampleContainerWIN; + + DECL_LINK(PreviewLoadedHdl_Impl, SwOneExampleFrame&, void); + DECL_LINK(ZoomHdl_Impl, weld::ComboBox&, void); + DECL_LINK(ChangeAddressHdl_Impl, weld::MetricSpinButton&, void); + DECL_LINK(GreetingsHdl_Impl, weld::Button&, void); + DECL_LINK(AlignToTextHdl_Impl, weld::Toggleable&, void); + + static SwFrameFormat* InsertAddressFrame( + SwWrtShell& rShell, + SwMailMergeConfigItem const & rConfigItem, + const Point& rDestination, + bool bAlignToBody, + bool bExample); + static void InsertGreeting(SwWrtShell& rShell, SwMailMergeConfigItem const & rConfigItem, bool bExample); + + virtual void Activate() override; + virtual bool commitPage(::vcl::WizardTypes::CommitPageReason _eReason) override; +public: + SwMailMergeLayoutPage(weld::Container* pPage, SwMailMergeWizard* pWizard); + virtual ~SwMailMergeLayoutPage() override; + + static SwFrameFormat* InsertAddressAndGreeting(SwView const * pView, + SwMailMergeConfigItem& rConfigItem, + const Point& rAddressPos, + bool bAlignToBody); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/mmoutputtypepage.cxx b/sw/source/ui/dbui/mmoutputtypepage.cxx new file mode 100644 index 0000000000..0110c0e5d0 --- /dev/null +++ b/sw/source/ui/dbui/mmoutputtypepage.cxx @@ -0,0 +1,532 @@ +/* -*- 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 "mmoutputtypepage.hxx" +#include <mailmergewizard.hxx> +#include <mmconfigitem.hxx> +#include <strings.hrc> +#include <bitmaps.hlst> +#include <swtypes.hxx> + +#include <osl/diagnose.h> +#include <rtl/ref.hxx> +#include <com/sun/star/mail/XSmtpService.hpp> +#include <vcl/idle.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +#include <swunohelper.hxx> +#include <mmresultdialogs.hxx> +#include <maildispatcher.hxx> +#include <imaildsplistener.hxx> +#include <mutex> + +using namespace ::com::sun::star; + +SwMailMergeOutputTypePage::SwMailMergeOutputTypePage(weld::Container* pPage, SwMailMergeWizard* pWizard) + : vcl::OWizardPage(pPage, pWizard, "modules/swriter/ui/mmoutputtypepage.ui", "MMOutputTypePage") + , m_pWizard(pWizard) + , m_xLetterRB(m_xBuilder->weld_radio_button("letter")) + , m_xMailRB(m_xBuilder->weld_radio_button("email")) + , m_xLetterHint(m_xBuilder->weld_label("letterft")) + , m_xMailHint(m_xBuilder->weld_label("emailft")) +{ + Link<weld::Toggleable&,void> aLink = LINK(this, SwMailMergeOutputTypePage, TypeHdl_Impl); + m_xLetterRB->connect_toggled(aLink); + m_xMailRB->connect_toggled(aLink); + + SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); + if(rConfigItem.IsOutputToLetter()) + m_xLetterRB->set_active(true); + else + m_xMailRB->set_active(true); + TypeHdl_Impl(*m_xLetterRB); +} + +SwMailMergeOutputTypePage::~SwMailMergeOutputTypePage() +{ +} + +IMPL_LINK_NOARG(SwMailMergeOutputTypePage, TypeHdl_Impl, weld::Toggleable&, void) +{ + bool bLetter = m_xLetterRB->get_active(); + m_xLetterHint->set_visible(bLetter); + m_xMailHint->set_visible(!bLetter); + m_pWizard->GetConfigItem().SetOutputToLetter(bLetter); + m_pWizard->UpdateRoadmap(); +} + +struct SwSendMailDialog_Impl +{ + friend class SwSendMailDialog; + // The mutex is locked in SwSendMailDialog_Impl::GetNextDescriptor, which may be called + // both with mutex unlocked (inside SwSendMailDialog::SendMails), and with mutex locked + // (inside SwSendMailDialog::AddDocument). + std::recursive_mutex aDescriptorMutex; + + std::vector< SwMailDescriptor > aDescriptors; + sal_uInt32 nCurrentDescriptor; + ::rtl::Reference< MailDispatcher > xMailDispatcher; + ::rtl::Reference< IMailDispatcherListener> xMailListener; + uno::Reference< mail::XMailService > xConnectedInMailService; + Idle aRemoveIdle; + + SwSendMailDialog_Impl() : + nCurrentDescriptor(0), aRemoveIdle("SwSendMailDialog_Impl aRemoveIdle") + { + aRemoveIdle.SetPriority(TaskPriority::LOWEST); + } + + ~SwSendMailDialog_Impl() + { + // Shutdown must be called when the last reference to the + // mail dispatcher will be released in order to force a + // shutdown of the mail dispatcher thread. + // 'join' with the mail dispatcher thread leads to a + // deadlock (SolarMutex). + if( xMailDispatcher.is() && !xMailDispatcher->isShutdownRequested() ) + xMailDispatcher->shutdown(); + } + const SwMailDescriptor* GetNextDescriptor(); +}; + +const SwMailDescriptor* SwSendMailDialog_Impl::GetNextDescriptor() +{ + std::scoped_lock aGuard(aDescriptorMutex); + if(nCurrentDescriptor < aDescriptors.size()) + { + ++nCurrentDescriptor; + return &aDescriptors[nCurrentDescriptor - 1]; + } + return nullptr; +} + +namespace { + +class SwMailDispatcherListener_Impl : public IMailDispatcherListener +{ + SwSendMailDialog& m_rSendMailDialog; + +public: + explicit SwMailDispatcherListener_Impl(SwSendMailDialog& rParentDlg); + + virtual void idle() override; + virtual void mailDelivered(uno::Reference< mail::XMailMessage> xMailMessage) override; + virtual void mailDeliveryError(::rtl::Reference<MailDispatcher> xMailDispatcher, + uno::Reference< mail::XMailMessage> xMailMessage, const OUString& sErrorMessage) override; + + static void DeleteAttachments( uno::Reference< mail::XMailMessage > const & xMessage ); +}; + +} + +SwMailDispatcherListener_Impl::SwMailDispatcherListener_Impl(SwSendMailDialog& rParentDlg) + : m_rSendMailDialog(rParentDlg) +{ +} + +void SwMailDispatcherListener_Impl::idle() +{ + SolarMutexGuard aGuard; + m_rSendMailDialog.AllMailsSent(); +} + +void SwMailDispatcherListener_Impl::mailDelivered( + uno::Reference< mail::XMailMessage> xMailMessage) +{ + SolarMutexGuard aGuard; + m_rSendMailDialog.DocumentSent( xMailMessage, true, nullptr ); + DeleteAttachments( xMailMessage ); +} + +void SwMailDispatcherListener_Impl::mailDeliveryError( + ::rtl::Reference<MailDispatcher> /*xMailDispatcher*/, + uno::Reference< mail::XMailMessage> xMailMessage, + const OUString& sErrorMessage) +{ + SolarMutexGuard aGuard; + m_rSendMailDialog.DocumentSent( xMailMessage, false, &sErrorMessage ); + DeleteAttachments( xMailMessage ); +} + +void SwMailDispatcherListener_Impl::DeleteAttachments( uno::Reference< mail::XMailMessage > const & xMessage ) +{ + const uno::Sequence< mail::MailAttachment > aAttachments = xMessage->getAttachments(); + + for(const auto& rAttachment : aAttachments) + { + try + { + uno::Reference< beans::XPropertySet > xTransferableProperties( rAttachment.Data, uno::UNO_QUERY_THROW); + OUString sURL; + xTransferableProperties->getPropertyValue("URL") >>= sURL; + if(!sURL.isEmpty()) + SWUnoHelper::UCB_DeleteFile( sURL ); + } + catch (const uno::Exception&) + { + } + } +} + +namespace { + +class SwSendWarningBox_Impl : public weld::MessageDialogController +{ + std::unique_ptr<weld::TextView> m_xDetailED; +public: + SwSendWarningBox_Impl(weld::Window* pParent, const OUString& rDetails) + : MessageDialogController(pParent, "modules/swriter/ui/warnemaildialog.ui", "WarnEmailDialog", "grid") + , m_xDetailED(m_xBuilder->weld_text_view("errors")) + { + m_xDetailED->set_size_request(80 * m_xDetailED->get_approximate_digit_width(), + 8 * m_xDetailED->get_text_height()); + m_xDetailED->set_text(rDetails); + } +}; + +} + +SwSendMailDialog::SwSendMailDialog(weld::Window *pParent, SwMailMergeConfigItem& rConfigItem) + : GenericDialogController(pParent, "modules/swriter/ui/mmsendmails.ui", "SendMailsDialog") + , m_sContinue(SwResId( ST_CONTINUE )) + , m_sClose(SwResId(ST_CLOSE_DIALOG)) + , m_sSendingTo( SwResId(ST_SENDINGTO )) + , m_sCompleted( SwResId(ST_COMPLETED )) + , m_sFailed( SwResId(ST_FAILED )) + , m_sAddressInvalid(SwResId(ST_ADDRESS_INVALID)) + , m_bCancel(false) + , m_bDestructionEnabled(false) + , m_pImpl(new SwSendMailDialog_Impl) + , m_pConfigItem(&rConfigItem) + , m_nExpectedCount(0) + , m_nProcessedCount(0) + , m_nErrorCount(0) + , m_xTransferStatus(m_xBuilder->weld_label("transferstatus")) + , m_xPaused(m_xBuilder->weld_label("paused")) + , m_xProgressBar(m_xBuilder->weld_progress_bar("progress")) + , m_xErrorStatus(m_xBuilder->weld_label("errorstatus")) + , m_xStatus(m_xBuilder->weld_tree_view("container")) + , m_xStop(m_xBuilder->weld_button("stop")) + , m_xCancel(m_xBuilder->weld_button("cancel")) +{ + m_sStop = m_xStop->get_label(); + m_sTransferStatus = m_xTransferStatus->get_label(); + m_sErrorStatus = m_xErrorStatus->get_label(); + + Size aSize(m_xStatus->get_approximate_digit_width() * 28, + m_xStatus->get_height_rows(20)); + m_xStatus->set_size_request(aSize.Width(), aSize.Height()); + + m_xStop->connect_clicked(LINK( this, SwSendMailDialog, StopHdl_Impl)); + m_xCancel->connect_clicked(LINK( this, SwSendMailDialog, CancelHdl_Impl)); + + std::vector<int> aWidths + { + o3tl::narrowing<int>(m_xStatus->get_checkbox_column_width()), + o3tl::narrowing<int>(aSize.Width()/3 * 2) + }; + m_xStatus->set_column_fixed_widths(aWidths); + + m_xPaused->set_visible(false); + UpdateTransferStatus(); +} + +SwSendMailDialog::~SwSendMailDialog() +{ + if(!m_pImpl->xMailDispatcher.is()) + return; + + try + { + if(m_pImpl->xMailDispatcher->isStarted()) + m_pImpl->xMailDispatcher->stop(); + if(m_pImpl->xConnectedInMailService.is() && m_pImpl->xConnectedInMailService->isConnected()) + m_pImpl->xConnectedInMailService->disconnect(); + + uno::Reference<mail::XMailMessage> xMessage = + m_pImpl->xMailDispatcher->dequeueMailMessage(); + while(xMessage.is()) + { + SwMailDispatcherListener_Impl::DeleteAttachments( xMessage ); + xMessage = m_pImpl->xMailDispatcher->dequeueMailMessage(); + } + } + catch (const uno::Exception&) + { + } +} + +void SwSendMailDialog::AddDocument( SwMailDescriptor const & rDesc ) +{ + std::scoped_lock aGuard(m_pImpl->aDescriptorMutex); + m_pImpl->aDescriptors.push_back(rDesc); + // if the dialog is already running then continue sending of documents + if(m_pImpl->xMailDispatcher.is()) + { + IterateMails(); + } +} + +IMPL_LINK( SwSendMailDialog, StopHdl_Impl, weld::Button&, rButton, void ) +{ + m_bCancel = true; + if(!m_pImpl->xMailDispatcher.is()) + return; + + if(m_pImpl->xMailDispatcher->isStarted()) + { + m_pImpl->xMailDispatcher->stop(); + rButton.set_label(m_sContinue); + m_xPaused->show(); + } + else + { + m_pImpl->xMailDispatcher->start(); + rButton.set_label(m_sStop); + m_xPaused->hide(); + } +} + +IMPL_LINK_NOARG(SwSendMailDialog, CancelHdl_Impl, weld::Button&, void) +{ + m_xDialog->hide(); + + if (m_bDestructionEnabled) + m_xDialog->response(RET_CANCEL); + else + { + m_pImpl->aRemoveIdle.SetInvokeHandler( LINK( this, SwSendMailDialog, RemoveThis ) ); + m_pImpl->aRemoveIdle.Start(); + } +} + +IMPL_STATIC_LINK( SwSendMailDialog, StartSendMails, void*, pDialog, void ) +{ + static_cast<SwSendMailDialog*>(pDialog)->SendMails(); +} + +IMPL_LINK( SwSendMailDialog, RemoveThis, Timer*, pTimer, void ) +{ + if( m_pImpl->xMailDispatcher.is() ) + { + if(m_pImpl->xMailDispatcher->isStarted()) + m_pImpl->xMailDispatcher->stop(); + if(!m_pImpl->xMailDispatcher->isShutdownRequested()) + m_pImpl->xMailDispatcher->shutdown(); + } + + if( m_bDestructionEnabled && + (!m_pImpl->xMailDispatcher.is() || + !m_pImpl->xMailDispatcher->isRunning())) + { + m_xDialog->response(RET_CANCEL); + } + else + { + pTimer->Start(); + } +} + +IMPL_STATIC_LINK( SwSendMailDialog, StopSendMails, void*, p, void ) +{ + SwSendMailDialog* pDialog = static_cast<SwSendMailDialog*>(p); + if(pDialog->m_pImpl->xMailDispatcher.is() && + pDialog->m_pImpl->xMailDispatcher->isStarted()) + { + pDialog->m_pImpl->xMailDispatcher->stop(); + pDialog->m_xStop->set_label(pDialog->m_sContinue); + pDialog->m_xPaused->show(); + } +} + +void SwSendMailDialog::SendMails() +{ + if(!m_pConfigItem) + { + OSL_FAIL("config item not set"); + return; + } + auto xWait(std::make_unique<weld::WaitObject>(m_xDialog.get())); + //get a mail server connection + uno::Reference< mail::XSmtpService > xSmtpServer = + SwMailMergeHelper::ConnectToSmtpServer( *m_pConfigItem, + m_pImpl->xConnectedInMailService, + OUString(), OUString(), m_xDialog.get()); + bool bIsLoggedIn = xSmtpServer.is() && xSmtpServer->isConnected(); + xWait.reset(); + if(!bIsLoggedIn) + { + OSL_FAIL("create error message"); + return; + } + m_pImpl->xMailDispatcher.set( new MailDispatcher(xSmtpServer)); + IterateMails(); + m_pImpl->xMailListener = new SwMailDispatcherListener_Impl(*this); + m_pImpl->xMailDispatcher->addListener(m_pImpl->xMailListener); + if(!m_bCancel) + { + m_pImpl->xMailDispatcher->start(); + } +} + +void SwSendMailDialog::IterateMails() +{ + const SwMailDescriptor* pCurrentMailDescriptor = m_pImpl->GetNextDescriptor(); + while( pCurrentMailDescriptor ) + { + if (!SwMailMergeHelper::CheckMailAddress( pCurrentMailDescriptor->sEMail)) + { + OUString sMessage = m_sSendingTo; + m_xStatus->append(); + m_xStatus->set_image(m_nProcessedCount, RID_BMP_FORMULA_CANCEL, 0); + m_xStatus->set_text(m_nProcessedCount, sMessage.replaceFirst("%1", pCurrentMailDescriptor->sEMail), 1); + m_xStatus->set_text(m_nProcessedCount, m_sAddressInvalid, 2); + ++m_nProcessedCount; + ++m_nErrorCount; + UpdateTransferStatus( ); + pCurrentMailDescriptor = m_pImpl->GetNextDescriptor(); + continue; + } + rtl::Reference<SwMailMessage> pMessage = new SwMailMessage; + if(m_pConfigItem->IsMailReplyTo()) + pMessage->setReplyToAddress(m_pConfigItem->GetMailReplyTo()); + pMessage->addRecipient( pCurrentMailDescriptor->sEMail ); + pMessage->SetSenderName( m_pConfigItem->GetMailDisplayName() ); + pMessage->SetSenderAddress( m_pConfigItem->GetMailAddress() ); + if(!pCurrentMailDescriptor->sAttachmentURL.isEmpty()) + { + mail::MailAttachment aAttach; + aAttach.Data = + new SwMailTransferable( + pCurrentMailDescriptor->sAttachmentURL, + pCurrentMailDescriptor->sAttachmentName, + pCurrentMailDescriptor->sMimeType ); + aAttach.ReadableName = pCurrentMailDescriptor->sAttachmentName; + pMessage->addAttachment( aAttach ); + } + pMessage->setSubject( pCurrentMailDescriptor->sSubject ); + uno::Reference< datatransfer::XTransferable> xBody = + new SwMailTransferable( + pCurrentMailDescriptor->sBodyContent, + pCurrentMailDescriptor->sBodyMimeType); + pMessage->setBody( xBody ); + + //CC and BCC are tokenized by ';' + if(!pCurrentMailDescriptor->sCC.isEmpty()) + { + sal_Int32 nPos = 0; + do + { + OUString sTmp = pCurrentMailDescriptor->sCC.getToken( 0, ';', nPos ); + if( !sTmp.isEmpty() ) + pMessage->addCcRecipient( sTmp ); + } + while (nPos >= 0); + } + if(!pCurrentMailDescriptor->sBCC.isEmpty()) + { + sal_Int32 nPos = 0; + do + { + OUString sTmp = pCurrentMailDescriptor->sBCC.getToken( 0, ';', nPos ); + if( !sTmp.isEmpty() ) + pMessage->addBccRecipient( sTmp ); + } + while (nPos >= 0); + } + m_pImpl->xMailDispatcher->enqueueMailMessage( pMessage ); + pCurrentMailDescriptor = m_pImpl->GetNextDescriptor(); + } + UpdateTransferStatus(); +} + +void SwSendMailDialog::StartSend(sal_Int32 nExpectedCount) +{ + Application::PostUserEvent( LINK( this, SwSendMailDialog, + StartSendMails ), this ); + m_nExpectedCount = nExpectedCount > 0 ? nExpectedCount : 1; +} + +void SwSendMailDialog::DocumentSent( uno::Reference< mail::XMailMessage> const & xMessage, + bool bResult, + const OUString* pError ) +{ + //sending should stop on send errors, except after last error - it will stop in AllMailsSent + if (pError && m_nProcessedCount + 1 < m_nExpectedCount && + m_pImpl->xMailDispatcher.is() && m_pImpl->xMailDispatcher->isStarted()) + { + Application::PostUserEvent( LINK( this, SwSendMailDialog, + StopSendMails ), this ); + } + OUString sInsertImg(bResult ? RID_BMP_FORMULA_APPLY : RID_BMP_FORMULA_CANCEL); + + OUString sMessage = m_sSendingTo; + m_xStatus->append(); + m_xStatus->set_image(m_nProcessedCount, sInsertImg, 0); + m_xStatus->set_text(m_nProcessedCount, sMessage.replaceFirst("%1", xMessage->getRecipients()[0]), 1); + m_xStatus->set_text(m_nProcessedCount, bResult ? m_sCompleted : m_sFailed, 2); + ++m_nProcessedCount; + if(!bResult) + ++m_nErrorCount; + + UpdateTransferStatus( ); + + if (pError) + { + SwSendWarningBox_Impl aDlg(m_xDialog.get(), *pError); + aDlg.run(); + } +} + +void SwSendMailDialog::UpdateTransferStatus() +{ + OUString sStatus( m_sTransferStatus ); + sStatus = sStatus.replaceFirst("%1", OUString::number(m_nProcessedCount) ); + sStatus = sStatus.replaceFirst("%2", OUString::number(m_nExpectedCount)); + m_xTransferStatus->set_label(sStatus); + + sStatus = m_sErrorStatus.replaceFirst("%1", OUString::number(m_nErrorCount) ); + m_xErrorStatus->set_label(sStatus); + + if (!m_pImpl->aDescriptors.empty()) + { + assert(m_nExpectedCount && "div-by-zero"); + m_xProgressBar->set_percentage(m_nProcessedCount * 100 / m_nExpectedCount); + } + else + m_xProgressBar->set_percentage(0); +} + +void SwSendMailDialog::AllMailsSent() +{ + if (m_nProcessedCount == m_nExpectedCount) + { + m_xStop->set_sensitive(false); + m_xCancel->set_label(m_sClose); + // Leave open if some kind of error occurred + if (m_nErrorCount == 0) + { + m_xDialog->hide(); + m_xDialog->response(RET_CANCEL); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/mmoutputtypepage.hxx b/sw/source/ui/dbui/mmoutputtypepage.hxx new file mode 100644 index 0000000000..0fa6c00d0f --- /dev/null +++ b/sw/source/ui/dbui/mmoutputtypepage.hxx @@ -0,0 +1,43 @@ +/* -*- 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_DBUI_MMOUTPUTTYPEPAGE_HXX +#define INCLUDED_SW_SOURCE_UI_DBUI_MMOUTPUTTYPEPAGE_HXX + +#include <vcl/wizardmachine.hxx> +#include <vcl/weld.hxx> +class SwMailMergeWizard; + +class SwMailMergeOutputTypePage : public vcl::OWizardPage +{ + SwMailMergeWizard* m_pWizard; + + std::unique_ptr<weld::RadioButton> m_xLetterRB; + std::unique_ptr<weld::RadioButton> m_xMailRB; + std::unique_ptr<weld::Label> m_xLetterHint; + std::unique_ptr<weld::Label> m_xMailHint; + + DECL_LINK(TypeHdl_Impl, weld::Toggleable&, void); + +public: + SwMailMergeOutputTypePage(weld::Container* pPage, SwMailMergeWizard* pWizard); + virtual ~SwMailMergeOutputTypePage() override; +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/mmresultdialogs.cxx b/sw/source/ui/dbui/mmresultdialogs.cxx new file mode 100644 index 0000000000..d53085c912 --- /dev/null +++ b/sw/source/ui/dbui/mmresultdialogs.cxx @@ -0,0 +1,1296 @@ +/* -*- 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 <mmresultdialogs.hxx> +#include <mmconfigitem.hxx> +#include <mailconfigpage.hxx> +#include "mmgreetingspage.hxx" +#include <printdata.hxx> +#include <swmessdialog.hxx> +#include <cmdid.h> +#include <swtypes.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <docsh.hxx> +#include <IDocumentDeviceAccess.hxx> +#include <hintids.hxx> +#include <swmodule.hxx> + +#include <vcl/QueueInfo.hxx> +#include <editeng/langitem.hxx> +#include <o3tl/temporary.hxx> +#include <svl/itemset.hxx> +#include <svl/stritem.hxx> +#include <svtools/ehdl.hxx> +#include <svtools/sfxecode.hxx> +#include <vcl/stdtext.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <vcl/scheduler.hxx> +#include <sfx2/printer.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <tools/urlobj.hxx> +#include <svl/urihelper.hxx> +#include <vcl/print.hxx> +#include <rtl/tencinfo.h> +#include <sal/log.hxx> + +#include <unotools/tempfile.hxx> +#include <osl/file.hxx> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdb/XColumn.hpp> +#include <com/sun/star/task/ErrorCodeIOException.hpp> +#include <dbmgr.hxx> +#include <swunohelper.hxx> +#include <shellio.hxx> +#include <svtools/htmlcfg.hxx> +#include <sfx2/event.hxx> +#include <swevent.hxx> +#include <dbui.hxx> +#include <dbui.hrc> +#include <doc.hxx> +#include <sfx2/app.hxx> +#include <strings.hrc> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/string.hxx> +#include <iodetect.hxx> + +using namespace svt; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +#define MM_DOCTYPE_OOO 1 +#define MM_DOCTYPE_PDF 2 +#define MM_DOCTYPE_WORD 3 +#define MM_DOCTYPE_HTML 4 +#define MM_DOCTYPE_TEXT 5 + +static OUString lcl_GetExtensionForDocType(sal_uLong nDocType) +{ + OUString sExtension; + switch( nDocType ) + { + case MM_DOCTYPE_OOO : sExtension = "odt"; break; + case MM_DOCTYPE_PDF : sExtension = "pdf"; break; + case MM_DOCTYPE_WORD: sExtension = "doc"; break; + case MM_DOCTYPE_HTML: sExtension = "html"; break; + case MM_DOCTYPE_TEXT: sExtension = "txt"; break; + } + return sExtension; +} + +static OUString lcl_GetColumnValueOf(const OUString& rColumn, Reference < container::XNameAccess> const & rxColAccess ) +{ + OUString sRet; + try + { + if (rxColAccess->hasByName(rColumn)) + { + Any aCol = rxColAccess->getByName(rColumn); + Reference< sdb::XColumn > xColumn; + aCol >>= xColumn; + if(xColumn.is()) + sRet = xColumn->getString(); + } + } + catch (const uno::Exception&) + { + } + return sRet; +} + +/** + * Replace email server settings in rConfigItem with those set in Writer's global + * mail merge config settings. + */ +static void lcl_UpdateEmailSettingsFromGlobalConfig(SwMailMergeConfigItem& rConfigItem) +{ + // newly created SwMailMergeConfigItem is initialized with values from (global) config + SwMailMergeConfigItem aConfigItem; + + // take over email-related settings + rConfigItem.SetMailDisplayName(aConfigItem.GetMailDisplayName()); + rConfigItem.SetMailAddress(aConfigItem.GetMailAddress()); + rConfigItem.SetMailReplyTo(aConfigItem.GetMailReplyTo()); + rConfigItem.SetMailReplyTo(aConfigItem.IsMailReplyTo()); + rConfigItem.SetMailServer(aConfigItem.GetMailServer()); + rConfigItem.SetMailPort(aConfigItem.GetMailPort()); + rConfigItem.SetSecureConnection(aConfigItem.IsSecureConnection()); + // authentication settings + rConfigItem.SetAuthentication(aConfigItem.IsAuthentication()); + rConfigItem.SetSMTPAfterPOP(aConfigItem.IsSMTPAfterPOP()); + rConfigItem.SetMailUserName(aConfigItem.GetMailUserName()); + rConfigItem.SetMailPassword(aConfigItem.GetMailPassword()); + rConfigItem.SetInServerName(aConfigItem.GetInServerName()); + rConfigItem.SetInServerPort(aConfigItem.GetInServerPort()); + rConfigItem.SetInServerPOP(aConfigItem.IsInServerPOP()); + rConfigItem.SetInServerUserName(aConfigItem.GetInServerUserName()); + rConfigItem.SetInServerPassword(aConfigItem.GetInServerPassword()); +} + +namespace { + +class SwSaveWarningBox_Impl : public SwMessageAndEditDialog +{ + DECL_LINK( ModifyHdl, weld::Entry&, void); +public: + SwSaveWarningBox_Impl(weld::Window* pParent, const OUString& rFileName); + + OUString GetFileName() const + { + return m_xEdit->get_text(); + } +}; + +class SwSendQueryBox_Impl : public SwMessageAndEditDialog +{ + bool m_bIsEmptyAllowed; + DECL_LINK( ModifyHdl, weld::Entry&, void); +public: + SwSendQueryBox_Impl(weld::Window* pParent, const OUString& rID, + const OUString& rUIXMLDescription); + + void SetValue(const OUString& rSet) + { + m_xEdit->set_text(rSet); + ModifyHdl(*m_xEdit); + } + + OUString GetValue() const + { + return m_xEdit->get_text(); + } + + void SetIsEmptyTextAllowed(bool bSet) + { + m_bIsEmptyAllowed = bSet; + ModifyHdl(*m_xEdit); + } +}; + +} + +SwSaveWarningBox_Impl::SwSaveWarningBox_Impl(weld::Window* pParent, const OUString& rFileName) + : SwMessageAndEditDialog(pParent, "AlreadyExistsDialog", + "modules/swriter/ui/alreadyexistsdialog.ui") +{ + m_xEdit->set_text(rFileName); + m_xEdit->connect_changed(LINK(this, SwSaveWarningBox_Impl, ModifyHdl)); + + INetURLObject aTmp(rFileName); + m_xDialog->set_primary_text(m_xDialog->get_primary_text().replaceAll("%1", aTmp.getName( + INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset))); + + ModifyHdl(*m_xEdit); +} + +IMPL_LINK( SwSaveWarningBox_Impl, ModifyHdl, weld::Entry&, rEdit, void) +{ + m_xOKPB->set_sensitive(!rEdit.get_text().isEmpty()); +} + +SwSendQueryBox_Impl::SwSendQueryBox_Impl(weld::Window* pParent, const OUString& rID, + const OUString& rUIXMLDescription) + : SwMessageAndEditDialog(pParent, rID, rUIXMLDescription) + , m_bIsEmptyAllowed(true) +{ + m_xEdit->connect_changed(LINK(this, SwSendQueryBox_Impl, ModifyHdl)); + ModifyHdl(*m_xEdit); +} + +IMPL_LINK( SwSendQueryBox_Impl, ModifyHdl, weld::Entry&, rEdit, void) +{ + m_xOKPB->set_sensitive(m_bIsEmptyAllowed || !rEdit.get_text().isEmpty()); +} + +namespace { + +class SwCopyToDialog : public SfxDialogController +{ + std::unique_ptr<weld::Entry> m_xCCED; + std::unique_ptr<weld::Entry> m_xBCCED; + +public: + explicit SwCopyToDialog(weld::Window* pParent) + : SfxDialogController(pParent, "modules/swriter/ui/ccdialog.ui", "CCDialog") + , m_xCCED(m_xBuilder->weld_entry("cc")) + , m_xBCCED(m_xBuilder->weld_entry("bcc")) + { + } + + OUString GetCC() const {return m_xCCED->get_text();} + void SetCC(const OUString& rSet) {m_xCCED->set_text(rSet);} + + OUString GetBCC() const {return m_xBCCED->get_text();} + void SetBCC(const OUString& rSet) {m_xBCCED->set_text(rSet);} +}; + +} + +SwMMResultSaveDialog::SwMMResultSaveDialog(weld::Window* pParent) + : SfxDialogController(pParent, "modules/swriter/ui/mmresultsavedialog.ui", "MMResultSaveDialog") + , m_bCancelSaving(false) + , m_xSaveAsOneRB(m_xBuilder->weld_radio_button("singlerb")) + , m_xSaveIndividualRB(m_xBuilder->weld_radio_button("individualrb")) + , m_xFromRB(m_xBuilder->weld_check_button("fromrb")) + , m_xFromNF(m_xBuilder->weld_spin_button("from")) + , m_xToFT(m_xBuilder->weld_label("toft")) + , m_xToNF(m_xBuilder->weld_spin_button("to")) + , m_xOKButton(m_xBuilder->weld_button("ok")) +{ + Link<weld::Toggleable&,void> aLink = LINK(this, SwMMResultSaveDialog, DocumentSelectionHdl_Impl); + m_xSaveAsOneRB->connect_toggled(aLink); + m_xSaveIndividualRB->connect_toggled(aLink); + m_xFromRB->connect_toggled(aLink); + // m_pSaveAsOneRB is the default, so disable m_xFromNF and m_xToNF initially. + aLink.Call(*m_xSaveAsOneRB); + if (SwView* pView = GetActiveView()) + { + const std::shared_ptr<SwMailMergeConfigItem>& xConfigItem = pView->GetMailMergeConfigItem(); + assert(xConfigItem); + sal_Int32 nCount = xConfigItem->GetMergedDocumentCount(); + m_xFromNF->set_max(nCount); + m_xToNF->set_max(nCount); + m_xToNF->set_value(nCount); + } + + m_xOKButton->connect_clicked(LINK(this, SwMMResultSaveDialog, SaveOutputHdl_Impl)); +} + +SwMMResultSaveDialog::~SwMMResultSaveDialog() +{ +} + +SwMMResultPrintDialog::SwMMResultPrintDialog(weld::Window* pParent) + : SfxDialogController(pParent, "modules/swriter/ui/mmresultprintdialog.ui", "MMResultPrintDialog") + , m_xPrinterLB(m_xBuilder->weld_combo_box("printers")) + , m_xPrinterSettingsPB(m_xBuilder->weld_button("printersettings")) + , m_xPrintAllRB(m_xBuilder->weld_radio_button("printallrb")) + , m_xFromRB(m_xBuilder->weld_radio_button("fromrb")) + , m_xFromNF(m_xBuilder->weld_spin_button("from")) + , m_xToFT(m_xBuilder->weld_label("toft")) + , m_xToNF(m_xBuilder->weld_spin_button("to")) + , m_xOKButton(m_xBuilder->weld_button("ok")) +{ + m_xPrinterLB->make_sorted(); + + m_xPrinterLB->connect_changed(LINK(this, SwMMResultPrintDialog, PrinterChangeHdl_Impl)); + m_xPrinterSettingsPB->connect_clicked(LINK(this, SwMMResultPrintDialog, PrinterSetupHdl_Impl)); + + Link<weld::Toggleable&,void> aLink = LINK(this, SwMMResultPrintDialog, DocumentSelectionHdl_Impl); + m_xPrintAllRB->connect_toggled(aLink); + m_xFromRB->connect_toggled(aLink); + // m_pPrintAllRB is the default, so disable m_xFromNF and m_xToNF initially. + aLink.Call(*m_xPrintAllRB); + + m_xOKButton->connect_clicked(LINK(this, SwMMResultPrintDialog, PrintHdl_Impl)); + + FillInPrinterSettings(); +} + +SwMMResultPrintDialog::~SwMMResultPrintDialog() +{ +} + +SwMMResultEmailDialog::SwMMResultEmailDialog(weld::Window* pParent) + : SfxDialogController(pParent, "modules/swriter/ui/mmresultemaildialog.ui", "MMResultEmailDialog") + , m_sConfigureMail(SwResId(ST_CONFIGUREMAIL)) + , m_xMailToLB(m_xBuilder->weld_combo_box("mailto")) + , m_xCopyToPB(m_xBuilder->weld_button("copyto")) + , m_xSubjectED(m_xBuilder->weld_entry("subject")) + , m_xSendAsLB(m_xBuilder->weld_combo_box("sendas")) + , m_xSendAsPB(m_xBuilder->weld_button("sendassettings")) + , m_xAttachmentGroup(m_xBuilder->weld_widget("attachgroup")) + , m_xAttachmentED(m_xBuilder->weld_entry("attach")) + , m_xPasswordFT(m_xBuilder->weld_label("passwordft")) + , m_xPasswordLB(m_xBuilder->weld_combo_box("password")) + , m_xPasswordCB(m_xBuilder->weld_check_button("passwordcb")) + , m_xSendAllRB(m_xBuilder->weld_radio_button("sendallrb")) + , m_xFromRB(m_xBuilder->weld_radio_button("fromrb")) + , m_xFromNF(m_xBuilder->weld_spin_button("from")) + , m_xToFT(m_xBuilder->weld_label("toft")) + , m_xToNF(m_xBuilder->weld_spin_button("to")) + , m_xOKButton(m_xBuilder->weld_button("ok")) +{ + m_xCopyToPB->connect_clicked(LINK(this, SwMMResultEmailDialog, CopyToHdl_Impl)); + m_xSendAsPB->connect_clicked(LINK(this, SwMMResultEmailDialog, SendAsHdl_Impl)); + m_xSendAsLB->connect_changed(LINK(this, SwMMResultEmailDialog, SendTypeHdl_Impl)); + m_xPasswordCB->connect_toggled( LINK( this, SwMMResultEmailDialog, CheckHdl )); + + Link<weld::Toggleable&,void> aLink = LINK(this, SwMMResultEmailDialog, DocumentSelectionHdl_Impl); + m_xSendAllRB->connect_toggled(aLink); + m_xFromRB->connect_toggled(aLink); + // m_xSendAllRB is the default, so disable m_xFromNF and m_xToNF initially. + aLink.Call(*m_xSendAllRB); + + m_xOKButton->connect_clicked(LINK(this, SwMMResultEmailDialog, SendDocumentsHdl_Impl)); + + m_xPasswordCB->set_sensitive(false); + m_xPasswordFT->set_sensitive(false); + m_xPasswordLB->set_sensitive(false); + + FillInEmailSettings(); +} + +SwMMResultEmailDialog::~SwMMResultEmailDialog() +{ +} + +void SwMMResultPrintDialog::FillInPrinterSettings() +{ + //fill printer ListBox + SwView* pView = GetActiveView(); + if (!pView) + return; + const std::shared_ptr<SwMailMergeConfigItem>& xConfigItem = pView->GetMailMergeConfigItem(); + const std::vector<OUString>& rPrinters = Printer::GetPrinterQueues(); + unsigned int nCount = rPrinters.size(); + bool bMergePrinterExists = false; + + for (unsigned int i = 0; i < nCount; ++i) + { + m_xPrinterLB->append_text( rPrinters[i] ); + if( !bMergePrinterExists && rPrinters[i] == xConfigItem->GetSelectedPrinter() ) + bMergePrinterExists = true; + } + + assert(xConfigItem); + if(!bMergePrinterExists) + { + SfxPrinter* pPrinter = pView->GetWrtShell().getIDocumentDeviceAccess().getPrinter( true ); + m_xPrinterLB->set_active_text(pPrinter->GetName()); + } + else + { + m_xPrinterLB->set_active_text(xConfigItem->GetSelectedPrinter()); + } + PrinterChangeHdl_Impl(*m_xPrinterLB); + + sal_Int32 count = xConfigItem->GetMergedDocumentCount(); + m_xFromNF->set_max(count); + m_xToNF->set_value(count); + m_xToNF->set_max(count); +} + +void SwMMResultEmailDialog::FillInEmailSettings() +{ + SwView* pView = GetActiveView(); + if (!pView) + return; + const std::shared_ptr<SwMailMergeConfigItem>& xConfigItem = pView->GetMailMergeConfigItem(); + assert(xConfigItem); + + SwView* pSourceView = xConfigItem->GetSourceView(); + OSL_ENSURE(pSourceView, "no source view exists"); + if (pSourceView) + { + SwDocShell* pDocShell = pSourceView->GetDocShell(); + if (pDocShell->HasName()) + { + INetURLObject aTmp(pDocShell->GetMedium()->GetName()); + m_xAttachmentED->set_text(aTmp.getName( + INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset )); + } + } + + if (m_xAttachmentED->get_text().isEmpty()) + { + OUString sAttach = "." + lcl_GetExtensionForDocType(m_xSendAsLB->get_active_id().toUInt32()); + m_xAttachmentED->set_text(sAttach); + + } + + //select first column + uno::Reference< sdbcx::XColumnsSupplier > xColsSupp(xConfigItem->GetResultSet(), uno::UNO_QUERY); + //get the name of the actual columns + uno::Reference < container::XNameAccess> xColAccess = xColsSupp.is() ? xColsSupp->getColumns() : nullptr; + uno::Sequence< OUString > aFields; + if (xColAccess.is()) + aFields = xColAccess->getElementNames(); + + // fill mail address and password ListBox + assert(m_xMailToLB->get_count() == 0); + assert(m_xPasswordLB->get_count() == 0); + for (const OUString& rField : std::as_const(aFields)) + { + m_xMailToLB->append_text(rField); + m_xPasswordLB->append_text(rField); + } + + m_xMailToLB->set_active(0); + m_xPasswordLB->set_active(0); + + // then select the right one - may not be available + const std::vector<std::pair<OUString, int>>& rHeaders = xConfigItem->GetDefaultAddressHeaders(); + OUString sEMailColumn = rHeaders[MM_PART_E_MAIL].first; + Sequence< OUString> aAssignment = xConfigItem->GetColumnAssignment(xConfigItem->GetCurrentDBData()); + if (aAssignment.getLength() > MM_PART_E_MAIL && !aAssignment[MM_PART_E_MAIL].isEmpty()) + sEMailColumn = aAssignment[MM_PART_E_MAIL]; + if (int pos = m_xMailToLB->find_text(sEMailColumn); pos >= 0) + m_xMailToLB->set_active(pos); + + // HTML format pre-selected + m_xSendAsLB->set_active(3); + SendTypeHdl_Impl(*m_xSendAsLB); + + const sal_Int32 nCount = xConfigItem->GetMergedDocumentCount(); + m_xFromNF->set_max(nCount); + m_xToNF->set_max(nCount); + m_xToNF->set_value(nCount); +} + +IMPL_LINK_NOARG(SwMMResultSaveDialog, DocumentSelectionHdl_Impl, weld::Toggleable&, void) +{ + bool bEnableFromTo = m_xFromRB->get_active(); + m_xFromNF->set_sensitive(bEnableFromTo); + m_xToFT->set_sensitive(bEnableFromTo); + m_xToNF->set_sensitive(bEnableFromTo); +} + +IMPL_LINK_NOARG(SwMMResultEmailDialog, CheckHdl, weld::Toggleable&, void) +{ + bool bEnable = m_xPasswordCB->get_active(); + + m_xPasswordFT->set_sensitive(bEnable); + m_xPasswordLB->set_sensitive(bEnable); +} + +IMPL_LINK_NOARG(SwMMResultPrintDialog, DocumentSelectionHdl_Impl, weld::Toggleable&, void) +{ + bool bEnableFromTo = m_xFromRB->get_active(); + m_xFromNF->set_sensitive(bEnableFromTo); + m_xToFT->set_sensitive(bEnableFromTo); + m_xToNF->set_sensitive(bEnableFromTo); +} + +IMPL_LINK_NOARG(SwMMResultEmailDialog, DocumentSelectionHdl_Impl, weld::Toggleable&, void) +{ + bool bEnableFromTo = m_xFromRB->get_active(); + m_xFromNF->set_sensitive(bEnableFromTo); + m_xToFT->set_sensitive(bEnableFromTo); + m_xToNF->set_sensitive(bEnableFromTo); +} + +IMPL_LINK_NOARG(SwMMResultEmailDialog, CopyToHdl_Impl, weld::Button&, void) +{ + SwCopyToDialog aDlg(m_xDialog.get()); + aDlg.SetCC(m_sCC ); + aDlg.SetBCC(m_sBCC); + if (aDlg.run() == RET_OK) + { + m_sCC = aDlg.GetCC() ; + m_sBCC = aDlg.GetBCC(); + } +} + +namespace { + +int documentStartPageNumber(SwMailMergeConfigItem* pConfigItem, int document, bool bIgnoreEmpty) +{ + SwView* pTargetView = pConfigItem->GetTargetView(); + assert( pTargetView ); + SwCursorShell& shell = pTargetView->GetWrtShell(); + const SwDocMergeInfo& info = pConfigItem->GetDocumentMergeInfo(document); + sal_uInt16 page; + shell.Push(); + shell.GotoMark( info.startPageInTarget ); + if (!bIgnoreEmpty) + shell.GetPageNum(page, o3tl::temporary(sal_uInt16())); + else + page = shell.GetPageNumSeqNonEmpty(); + shell.Pop(SwCursorShell::PopMode::DeleteCurrent); + return page; +} + +int documentEndPageNumber(SwMailMergeConfigItem* pConfigItem, int document, bool bIgnoreEmpty) +{ + SwView* pTargetView = pConfigItem->GetTargetView(); + assert( pTargetView ); + SwWrtShell& shell = pTargetView->GetWrtShell(); + shell.Push(); + if (document < int(pConfigItem->GetMergedDocumentCount()) - 1) + { + // Go to the page before the starting page of the next merged document. + const SwDocMergeInfo& info = pConfigItem->GetDocumentMergeInfo( document + 1 ); + shell.GotoMark( info.startPageInTarget ); + shell.EndPrvPg(); + } + else + { // This is the last merged document, so it ends on the page at which the document ends. + shell.SttEndDoc( false ); // go to doc end + } + sal_uInt16 page; + if (!bIgnoreEmpty) + shell.GetPageNum(page, o3tl::temporary(sal_uInt16())); + else + page = shell.GetPageNumSeqNonEmpty(); + shell.Pop(SwCursorShell::PopMode::DeleteCurrent); + return page; +} + +} // anonymous namespace + +IMPL_LINK_NOARG(SwMMResultSaveDialog, SaveOutputHdl_Impl, weld::Button&, void) +{ + SwView* pView = GetActiveView(); + if (!pView) + return; + std::shared_ptr<SwMailMergeConfigItem> xConfigItem = pView->GetMailMergeConfigItem(); + assert(xConfigItem); + + const sal_uInt32 nDocumentCount = xConfigItem->GetMergedDocumentCount(); + sal_uInt32 nBegin = 0; + sal_uInt32 nEnd = nDocumentCount; + + if (m_xFromRB->get_active()) + { + nBegin = static_cast<sal_Int32>(m_xFromNF->get_value() - 1); + nEnd = static_cast<sal_Int32>(m_xToNF->get_value()); + if (nEnd > nDocumentCount) + nEnd = nDocumentCount; + } + + xConfigItem->SetBeginEnd(nBegin, nEnd); + + if (!xConfigItem->GetTargetView()) + SwDBManager::PerformMailMerge(pView); + + SwView* pTargetView = xConfigItem->GetTargetView(); + assert(pTargetView); + + OUString sFilter; + OUString sPath = SwMailMergeHelper::CallSaveAsDialog(m_xDialog.get(), sFilter); + if (sPath.isEmpty()) + { + // just return back to the dialog + return; + } + + if (m_xSaveAsOneRB->get_active()) + { + uno::Sequence< beans::PropertyValue > aValues { comphelper::makePropertyValue("FilterName", sFilter) }; + + uno::Reference< frame::XStorable > xStore( pTargetView->GetDocShell()->GetModel(), uno::UNO_QUERY); + ErrCode nErrorCode = ERRCODE_NONE; + try + { + xStore->storeToURL( sPath, aValues ); + } + catch (const task::ErrorCodeIOException& rErrorEx) + { + nErrorCode = ErrCode(rErrorEx.ErrCode); + } + catch (const Exception&) + { + nErrorCode = ERRCODE_IO_GENERAL; + } + if( nErrorCode != ERRCODE_NONE ) + { + SfxErrorContext aEc(ERRCTX_SFX_SAVEASDOC, pTargetView->GetDocShell()->GetTitle()); + ErrorHandler::HandleError( nErrorCode ); + } + } + else + { + OUString sTargetTempURL = URIHelper::SmartRel2Abs( + INetURLObject(), utl::CreateTempName(), + URIHelper::GetMaybeFileHdl()); + std::shared_ptr<const SfxFilter> pSfxFlt = SwIoSystem::GetFilterOfFormat( + FILTER_XML, + SwDocShell::Factory().GetFilterContainer() ); + + uno::Sequence< beans::PropertyValue > aValues(1); + beans::PropertyValue* pValues = aValues.getArray(); + pValues[0].Name = "FilterName"; + pValues[0].Value <<= pSfxFlt->GetFilterName(); + + uno::Reference< frame::XStorable > xStore( pTargetView->GetDocShell()->GetModel(), uno::UNO_QUERY); + ErrCode nErrorCode = ERRCODE_NONE; + try + { + xStore->storeToURL( sTargetTempURL, aValues ); + } + catch (const task::ErrorCodeIOException& rErrorEx) + { + nErrorCode = ErrCode(rErrorEx.ErrCode); + } + catch (const Exception&) + { + nErrorCode = ERRCODE_IO_GENERAL; + } + if( nErrorCode != ERRCODE_NONE ) + { + SfxErrorContext aEc(ERRCTX_SFX_SAVEASDOC, pTargetView->GetDocShell()->GetTitle()); + ErrorHandler::HandleError( nErrorCode ); + } + + SwView* pSourceView = xConfigItem->GetSourceView(); + auto xSaveMonitor = std::make_shared<SaveMonitor>(m_xDialog.get()); + xSaveMonitor->m_xDocName->set_label(pSourceView->GetDocShell()->GetTitle(22)); + xSaveMonitor->m_xPrinter->set_label( INetURLObject( sPath ).getFSysPath( FSysStyle::Detect ) ); + m_bCancelSaving = false; + weld::DialogController::runAsync(xSaveMonitor, [this, &xSaveMonitor](sal_Int32 nResult){ + if (nResult == RET_CANCEL) + m_bCancelSaving = true; + xSaveMonitor.reset(); + }); + + for(sal_uInt32 nDoc = 0; nDoc < nEnd - nBegin && !m_bCancelSaving; ++nDoc) + { + INetURLObject aURL(sPath); + OUString sExtension = aURL.getExtension(); + if (sExtension.isEmpty()) + { + sExtension = pSfxFlt->GetWildcard().getGlob().getToken(1, '.'); + sPath += "." + sExtension; + } + OUString sStat = SwResId(STR_STATSTR_LETTER) + " " + OUString::number(nDoc + 1); + xSaveMonitor->m_xPrintInfo->set_label(sStat); + + //now extract a document from the target document + // the shell will be closed at the end, but it is more safe to use SfxObjectShellLock here + SfxObjectShellLock xTempDocShell( new SwDocShell( SfxObjectCreateMode::STANDARD ) ); + xTempDocShell->DoInitNew(); + SfxViewFrame* pTempFrame = SfxViewFrame::LoadHiddenDocument( *xTempDocShell, SFX_INTERFACE_NONE ); + SwView* pTempView = static_cast<SwView*>( pTempFrame->GetViewShell() ); + pTargetView->GetWrtShell().StartAction(); + SwgReaderOption aOpt; + aOpt.SetTextFormats( true ); + aOpt.SetFrameFormats( true ); + aOpt.SetPageDescs( true ); + aOpt.SetNumRules( true ); + aOpt.SetMerge( false ); + pTempView->GetDocShell()->LoadStylesFromFile( + sTargetTempURL, aOpt, true ); + pTempView->GetDocShell()->GetDoc()->ReplaceCompatibilityOptions( *pTargetView->GetDocShell()->GetDoc()); + pTempView->GetDocShell()->GetDoc()->ReplaceDefaults( *pTargetView->GetDocShell()->GetDoc()); + pTempView->GetDocShell()->GetDoc()->ReplaceDocumentProperties( *pTargetView->GetDocShell()->GetDoc(), true ); + + uno::Reference<beans::XPropertySet> const xThisSet( + pTargetView->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertySet> const xRetSet( + pTempView->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW); + uno::Sequence<beans::PropertyValue> aInteropGrabBag; + xThisSet->getPropertyValue("InteropGrabBag") >>= aInteropGrabBag; + xRetSet->setPropertyValue("InteropGrabBag", uno::Any(aInteropGrabBag)); + + pTargetView->GetWrtShell().PastePages( + pTempView->GetWrtShell(), documentStartPageNumber(xConfigItem.get(), nDoc, false), + documentEndPageNumber(xConfigItem.get(), nDoc, false)); + pTargetView->GetWrtShell().EndAction(); + //then save it + OUString sOutPath = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri); + OUString sCounter = "_" + OUString::number(nDoc + 1); + sOutPath = sOutPath.replaceAt( sOutPath.getLength() - sExtension.getLength() - 1, 0, sCounter); + + while(true) + { + //time for other slots is needed + Scheduler::ProcessEventsToIdle(); + + bool bFailed = false; + try + { + pValues[0].Value <<= sFilter; + uno::Reference< frame::XStorable > xTempStore( xTempDocShell->GetModel(), uno::UNO_QUERY); + xTempStore->storeToURL( sOutPath, aValues ); + } + catch (const uno::Exception&) + { + bFailed = true; + } + + if(bFailed) + { + std::unique_ptr<SwSaveWarningBox_Impl> xWarning(new SwSaveWarningBox_Impl(m_xDialog.get(), sOutPath)); + if (RET_OK == xWarning->run()) + sOutPath = xWarning->GetFileName(); + else + { + xTempDocShell->DoClose(); + m_xDialog->response(RET_OK); + return; + } + } + else + { + xTempDocShell->DoClose(); + m_xDialog->response(RET_OK); + break; + } + } + } + if (xSaveMonitor) + xSaveMonitor->response(RET_OK); + ::osl::File::remove( sTargetTempURL ); + } + + m_xDialog->response(RET_OK); +} + +IMPL_LINK(SwMMResultPrintDialog, PrinterChangeHdl_Impl, weld::ComboBox&, rBox, void) +{ + SwView* pView = GetActiveView(); + if (!pView) + return; + const std::shared_ptr<SwMailMergeConfigItem>& xConfigItem = pView->GetMailMergeConfigItem(); + assert(xConfigItem); + if (rBox.get_active() != -1) + { + const QueueInfo* pInfo = Printer::GetQueueInfo( rBox.get_active_text(), false ); + + if( pInfo ) + { + if ( !m_pTempPrinter ) + { + m_pTempPrinter = VclPtr<Printer>::Create( *pInfo ); + } + else + { + if( (m_pTempPrinter->GetName() != pInfo->GetPrinterName()) || + (m_pTempPrinter->GetDriverName() != pInfo->GetDriver()) ) + { + m_pTempPrinter.disposeAndClear(); + m_pTempPrinter = VclPtr<Printer>::Create( *pInfo ); + } + } + } + else if( ! m_pTempPrinter ) + m_pTempPrinter = VclPtr<Printer>::Create(); + + m_xPrinterSettingsPB->set_sensitive(m_pTempPrinter->HasSupport(PrinterSupport::SetupDialog)); + } + else + m_xPrinterSettingsPB->set_sensitive(false); + + xConfigItem->SetSelectedPrinter(rBox.get_active_text()); +} + +IMPL_LINK_NOARG(SwMMResultPrintDialog, PrintHdl_Impl, weld::Button&, void) +{ + SwView* pView = GetActiveView(); + if (!pView) + return; + std::shared_ptr<SwMailMergeConfigItem> xConfigItem = pView->GetMailMergeConfigItem(); + assert(xConfigItem); + + const sal_uInt32 nDocumentCount = xConfigItem->GetMergedDocumentCount(); + sal_uInt32 nBegin = 0; + sal_uInt32 nEnd = nDocumentCount; + + if (m_xFromRB->get_active()) + { + nBegin = static_cast<sal_Int32>(m_xFromNF->get_value() - 1); + nEnd = static_cast<sal_Int32>(m_xToNF->get_value()); + if (nEnd > nDocumentCount) + nEnd = nDocumentCount; + } + + xConfigItem->SetBeginEnd(nBegin, nEnd); + + if(!xConfigItem->GetTargetView()) + SwDBManager::PerformMailMerge(pView); + + SwView* pTargetView = xConfigItem->GetTargetView(); + assert(pTargetView); + + // If we skip autoinserted blanks, then the page numbers used in the print range string + // refer to the non-blank pages as they appear in the document (see tdf#89708). + const bool bIgnoreEmptyPages = + !pTargetView->GetDocShell()->GetDoc()->getIDocumentDeviceAccess().getPrintData().IsPrintEmptyPages(); + const int nStartPage = documentStartPageNumber(xConfigItem.get(), 0, bIgnoreEmptyPages); + const int nEndPage = documentEndPageNumber(xConfigItem.get(), nEnd - nBegin - 1, bIgnoreEmptyPages); + + const OUString sPages(OUString::number(nStartPage) + "-" + OUString::number(nEndPage)); + + pTargetView->SetMailMergeConfigItem(xConfigItem); + if(m_pTempPrinter) + { + SfxPrinter *const pDocumentPrinter = pTargetView->GetWrtShell() + .getIDocumentDeviceAccess().getPrinter(true); + pDocumentPrinter->SetPrinterProps(m_pTempPrinter); + // this should be able to handle setting its own printer + pTargetView->SetPrinter(pDocumentPrinter); + } + + SfxObjectShell* pObjSh = pTargetView->GetViewFrame().GetObjectShell(); + SfxGetpApp()->NotifyEvent(SfxEventHint(SfxEventHintId::SwMailMerge, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE), pObjSh)); + + uno::Sequence aProps{ comphelper::makePropertyValue("MonitorVisible", true), + comphelper::makePropertyValue("Pages", sPages) }; + + pTargetView->ExecPrint( aProps, false, true ); + SfxGetpApp()->NotifyEvent(SfxEventHint(SfxEventHintId::SwMailMergeEnd, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE_END), pObjSh)); + + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(SwMMResultPrintDialog, PrinterSetupHdl_Impl, weld::Button&, void) +{ + if (m_pTempPrinter) + m_pTempPrinter->Setup(m_xDialog.get()); +} + +IMPL_LINK(SwMMResultEmailDialog, SendTypeHdl_Impl, weld::ComboBox&, rBox, void) +{ + auto nDocType = rBox.get_active_id().toUInt32(); + bool bEnable = MM_DOCTYPE_HTML != nDocType && MM_DOCTYPE_TEXT != nDocType; + bool bIsPDF = nDocType == MM_DOCTYPE_PDF; + m_xSendAsPB->set_sensitive(bEnable); + m_xAttachmentGroup->set_sensitive(bEnable); + if(bEnable) + { + //add the correct extension + OUString sAttach(m_xAttachmentED->get_text()); + //do nothing if the user has removed the name - the warning will come early enough + if (!sAttach.isEmpty()) + { + sal_Int32 nTokenCount = comphelper::string::getTokenCount(sAttach, '.'); + if( 2 > nTokenCount) + { + sAttach += "."; + ++nTokenCount; + } + sAttach = comphelper::string::setToken(sAttach, nTokenCount - 1, '.', lcl_GetExtensionForDocType( nDocType )); + m_xAttachmentED->set_text(sAttach); + } + } + + if(bIsPDF) + { + m_xPasswordCB->set_sensitive(true); + m_xPasswordFT->set_sensitive(true); + m_xPasswordLB->set_sensitive(true); + CheckHdl(*m_xPasswordCB); + } + else + { + m_xPasswordCB->set_sensitive(false); + m_xPasswordFT->set_sensitive(false); + m_xPasswordLB->set_sensitive(false); + } +} + +IMPL_LINK_NOARG(SwMMResultEmailDialog, SendAsHdl_Impl, weld::Button&, void) +{ + // work around crash when calling constructor with no active view + if (!GetActiveView()) + { + SAL_WARN("sw", "ignoring SendAs button click, because no active view"); + return; + } + SwMailBodyDialog aDlg(m_xDialog.get()); + aDlg.SetBody(m_sBody); + if (RET_OK == aDlg.run()) + { + m_sBody = aDlg.GetBody(); + } +} + +// Send documents as e-mail +IMPL_LINK_NOARG(SwMMResultEmailDialog, SendDocumentsHdl_Impl, weld::Button&, void) +{ + SwView* pView = GetActiveView(); + if (!pView) + return; + std::shared_ptr<SwMailMergeConfigItem> xConfigItem = pView->GetMailMergeConfigItem(); + assert(xConfigItem); + + const sal_uInt32 nDocumentCount = xConfigItem->GetMergedDocumentCount(); + sal_uInt32 nBegin = 0; + sal_uInt32 nEnd = nDocumentCount; + + if (m_xFromRB->get_active()) + { + nBegin = static_cast<sal_Int32>(m_xFromNF->get_value() - 1); + nEnd = static_cast<sal_Int32>(m_xToNF->get_value()); + if (nEnd > nDocumentCount) + nEnd = nDocumentCount; + } + + xConfigItem->SetBeginEnd(nBegin, nEnd); + + if (!xConfigItem->GetTargetView()) + SwDBManager::PerformMailMerge(pView); + + //get the composed document + SwView* pTargetView = xConfigItem->GetTargetView(); + SAL_WARN_IF(!pTargetView, "sw.ui", "No TargetView in SwMailMergeConfigItem"); + + if (xConfigItem->GetMailServer().isEmpty() || + !SwMailMergeHelper::CheckMailAddress(xConfigItem->GetMailAddress()) ) + { + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Question, VclButtonsType::YesNo, + m_sConfigureMail)); + xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL); + sal_uInt16 nRet = xQueryBox->run(); + if (RET_YES == nRet ) + { + SwView* pConfigView = pTargetView ? pTargetView : pView; + SfxAllItemSet aSet(pConfigView->GetPool()); + SwMailConfigDlg aDlg(m_xDialog.get(), aSet); + nRet = aDlg.run(); + } + + if(nRet != RET_OK && nRet != RET_YES) + return; // back to the dialog + + // SwMailConfigDlg writes mail merge email settings only to (global) config, + // so copy them to the existing config item + lcl_UpdateEmailSettingsFromGlobalConfig(*xConfigItem); + } + //add the documents + bool bAsBody = false; + rtl_TextEncoding eEncoding = ::osl_getThreadTextEncoding(); + SfxFilterContainer* pFilterContainer = SwDocShell::Factory().GetFilterContainer(); + std::shared_ptr<const SfxFilter> pSfxFlt; + auto nDocType = m_xSendAsLB->get_active_id().toUInt32(); + OUString sExtension = lcl_GetExtensionForDocType(nDocType); + switch( nDocType ) + { + case MM_DOCTYPE_OOO: + { + //Make sure we don't pick e.g. the flat xml filter + //for this format + pSfxFlt = pFilterContainer->GetFilter4FilterName( + "writer8", + SfxFilterFlags::EXPORT); + } + break; + case MM_DOCTYPE_PDF: + { + pSfxFlt = pFilterContainer->GetFilter4FilterName( + "writer_pdf_Export", + SfxFilterFlags::EXPORT); + } + break; + case MM_DOCTYPE_WORD: + { + //the method SwIOSystemGetFilterOfFormat( ) returns the template filter + //because it uses the same user data :-( + SfxFilterMatcher aMatcher( pFilterContainer->GetName() ); + SfxFilterMatcherIter aIter( aMatcher ); + std::shared_ptr<const SfxFilter> pFilter = aIter.First(); + while ( pFilter ) + { + if( pFilter->GetUserData() == FILTER_WW8 && pFilter->CanExport() ) + { + pSfxFlt = pFilter; + break; + } + pFilter = aIter.Next(); + } + + } + break; + case MM_DOCTYPE_HTML: + { + bAsBody = true; + eEncoding = RTL_TEXTENCODING_UTF8; + } + break; + case MM_DOCTYPE_TEXT: + { + bAsBody = true; + pSfxFlt = pFilterContainer->GetFilter4FilterName( + "Text (encoded)", SfxFilterFlags::EXPORT); + } + break; + } + if(!pSfxFlt) + pSfxFlt = pFilterContainer->GetFilter4Extension(sExtension, SfxFilterFlags::EXPORT); + + if(!pSfxFlt) + { + m_xDialog->response(RET_OK); + return; + } + OUString sMimeType = pSfxFlt->GetMimeType(); + + if (m_xSubjectED->get_text().isEmpty()) + { + std::unique_ptr<SwSendQueryBox_Impl> xQuery(new SwSendQueryBox_Impl(m_xDialog.get(), "SubjectDialog", + "modules/swriter/ui/subjectdialog.ui")); + xQuery->SetIsEmptyTextAllowed(true); + xQuery->SetValue(""); + if(RET_OK == xQuery->run()) + { + if (!xQuery->GetValue().isEmpty()) + m_xSubjectED->set_text(xQuery->GetValue()); + } + else + return; // back to the dialog + } + if(!bAsBody && m_xAttachmentED->get_text().isEmpty()) + { + std::unique_ptr<SwSendQueryBox_Impl> xQuery(new SwSendQueryBox_Impl(m_xDialog.get(), "AttachNameDialog", + "modules/swriter/ui/attachnamedialog.ui")); + xQuery->SetIsEmptyTextAllowed(false); + if (RET_OK == xQuery->run()) + { + OUString sAttach(xQuery->GetValue()); + sal_Int32 nTokenCount = comphelper::string::getTokenCount(sAttach, '.'); + if (2 > nTokenCount) + { + sAttach += "."; + ++nTokenCount; + } + sAttach = comphelper::string::setToken(sAttach, nTokenCount - 1, '.', lcl_GetExtensionForDocType( + m_xSendAsLB->get_active_id().toUInt32())); + m_xAttachmentED->set_text(sAttach); + } + else + return; // back to the dialog + } + + OUString sEMailColumn = m_xMailToLB->get_active_text(); + OSL_ENSURE( !sEMailColumn.isEmpty(), "No email column selected"); + Reference< sdbcx::XColumnsSupplier > xColsSupp( xConfigItem->GetResultSet(), UNO_QUERY); + Reference < container::XNameAccess> xColAccess = xColsSupp.is() ? xColsSupp->getColumns() : nullptr; + if(sEMailColumn.isEmpty() || !xColAccess.is() || !xColAccess->hasByName(sEMailColumn)) + { + m_xDialog->response(RET_OK); + return; + } + + OUString sPasswordColumn = m_xPasswordLB->get_active_text(); + OSL_ENSURE( !sPasswordColumn.isEmpty(), "No password column selected"); + if(sPasswordColumn.isEmpty() || !xColAccess.is() || !xColAccess->hasByName(sPasswordColumn)) + { + m_xDialog->response(RET_OK); + return; + } + + OUString sFilterOptions; + if(MM_DOCTYPE_TEXT == nDocType) + { + SwAsciiOptions aOpt; + sal_uInt16 nAppScriptType = SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetAppLanguage() ); + TypedWhichId<SvxLanguageItem> nWhich = GetWhichOfScript( RES_CHRATR_LANGUAGE, nAppScriptType); + const SvxLanguageItem& rDefLangItem = pTargetView->GetWrtShell().GetDefault( nWhich ); + aOpt.SetLanguage( rDefLangItem.GetLanguage() ); + aOpt.SetParaFlags( LINEEND_CR ); + aOpt.WriteUserData( sFilterOptions ); + } + else if(MM_DOCTYPE_HTML == nDocType) + { + sFilterOptions = "EmbedImages"; + } + OUString sTargetTempURL = URIHelper::SmartRel2Abs( + INetURLObject(), utl::CreateTempName(), + URIHelper::GetMaybeFileHdl()); + std::shared_ptr<const SfxFilter> pTargetSfxFlt = SwIoSystem::GetFilterOfFormat( + FILTER_XML, + SwDocShell::Factory().GetFilterContainer() ); + + uno::Sequence< beans::PropertyValue > aValues { comphelper::makePropertyValue("FilterName", pTargetSfxFlt->GetFilterName()) }; + + uno::Reference< frame::XStorable > xStore( pTargetView->GetDocShell()->GetModel(), uno::UNO_QUERY); + xStore->storeToURL( sTargetTempURL, aValues ); + + //create the send dialog + std::shared_ptr<SwSendMailDialog> xDlg = std::make_shared<SwSendMailDialog>(Application::GetDefDialogParent(), *xConfigItem); + + xDlg->StartSend(nEnd - nBegin); + weld::DialogController::runAsync(xDlg, [](sal_Int32 /*nResult*/){}); + + //help to force painting the dialog + //TODO/CLEANUP + //predetermined breaking point + Application::Reschedule( true ); + m_xDialog->response(RET_OK); + for(sal_uInt32 nDoc = 0; nDoc < nEnd - nBegin; ++nDoc) + { + SwDocMergeInfo& rInfo = xConfigItem->GetDocumentMergeInfo(nDoc); + + //now extract a document from the target document + // the shell will be closed at the end, but it is more safe to use SfxObjectShellLock here + SfxObjectShellLock xTempDocShell( new SwDocShell( SfxObjectCreateMode::STANDARD ) ); + xTempDocShell->DoInitNew(); + SfxViewFrame* pTempFrame = SfxViewFrame::LoadHiddenDocument( *xTempDocShell, SFX_INTERFACE_NONE ); + SwView* pTempView = static_cast<SwView*>( pTempFrame->GetViewShell() ); + pTargetView->GetWrtShell().StartAction(); + SwgReaderOption aOpt; + aOpt.SetTextFormats( true ); + aOpt.SetFrameFormats( true ); + aOpt.SetPageDescs( true ); + aOpt.SetNumRules( true ); + aOpt.SetMerge( false ); + pTempView->GetDocShell()->LoadStylesFromFile( + sTargetTempURL, aOpt, true ); + pTempView->GetDocShell()->GetDoc()->ReplaceCompatibilityOptions( *pTargetView->GetDocShell()->GetDoc()); + pTempView->GetDocShell()->GetDoc()->ReplaceDefaults( *pTargetView->GetDocShell()->GetDoc()); + pTempView->GetDocShell()->GetDoc()->ReplaceDocumentProperties( *pTargetView->GetDocShell()->GetDoc(), true ); + pTargetView->GetWrtShell().PastePages( + pTempView->GetWrtShell(), documentStartPageNumber(xConfigItem.get(), nDoc, false), + documentEndPageNumber(xConfigItem.get(), nDoc, false)); + pTargetView->GetWrtShell().EndAction(); + + //then save it + SfxStringItem aName(SID_FILE_NAME, + URIHelper::SmartRel2Abs( + INetURLObject(), utl::CreateTempName(), + URIHelper::GetMaybeFileHdl()) ); + + { + bool withFilterOptions = MM_DOCTYPE_TEXT == nDocType || MM_DOCTYPE_HTML == nDocType; + bool withPasswordOptions = m_xPasswordCB->get_active(); + + sal_Int32 nTarget = xConfigItem->MoveResultSet(rInfo.nDBRow); + OSL_ENSURE( nTarget == rInfo.nDBRow, "row of current document could not be selected"); + OUString sPassword = lcl_GetColumnValueOf(sPasswordColumn, xColAccess); + + sal_Int32 nOptionCount = (withFilterOptions && withPasswordOptions) ? 4 : withPasswordOptions ? 3 : withFilterOptions ? 2 : 1; + sal_Int32 nOpt = 0; + uno::Sequence< beans::PropertyValue > aFilterValues(nOptionCount); + beans::PropertyValue* pFilterValues = aFilterValues.getArray(); + + pFilterValues[nOpt].Name = "FilterName"; + pFilterValues[nOpt].Value <<= pSfxFlt->GetFilterName(); + + if(withFilterOptions) + { + nOpt++; + pFilterValues[nOpt].Name = "FilterOptions"; + pFilterValues[nOpt].Value <<= sFilterOptions; + } + + if(withPasswordOptions) + { + nOpt++; + pFilterValues[nOpt].Name = "EncryptFile"; + pFilterValues[nOpt].Value <<= true; + nOpt++; + pFilterValues[nOpt].Name = "DocumentOpenPassword"; + pFilterValues[nOpt].Value <<= sPassword; + } + + uno::Reference< frame::XStorable > xTempStore( pTempView->GetDocShell()->GetModel(), uno::UNO_QUERY); + xTempStore->storeToURL( aName.GetValue(), aFilterValues ); + } + xTempDocShell->DoClose(); + + sal_Int32 nTarget = xConfigItem->MoveResultSet(rInfo.nDBRow); + OSL_ENSURE( nTarget == rInfo.nDBRow, "row of current document could not be selected"); + OSL_ENSURE( !sEMailColumn.isEmpty(), "No email column selected"); + OUString sEMail = lcl_GetColumnValueOf(sEMailColumn, xColAccess); + SwMailDescriptor aDesc; + aDesc.sEMail = sEMail; + OUStringBuffer sBody; + if(bAsBody) + { + { + //read in the temporary file and use it as mail body + SfxMedium aMedium( aName.GetValue(), StreamMode::READ); + SvStream* pInStream = aMedium.GetInStream(); + if(pInStream) + pInStream->SetStreamCharSet( eEncoding ); + else + { + OSL_FAIL("no output file created?"); + continue; + } + OStringBuffer sLine; + bool bDone = pInStream->ReadLine( sLine ); + while ( bDone ) + { + sBody.append( OStringToOUString(sLine, eEncoding) + "\n"); + bDone = pInStream->ReadLine( sLine ); + } + } + //remove the temporary file + SWUnoHelper::UCB_DeleteFile( aName.GetValue() ); + } + else + { + sBody = m_sBody; + aDesc.sAttachmentURL = aName.GetValue(); + OUString sAttachment(m_xAttachmentED->get_text()); + sal_Int32 nTokenCount = comphelper::string::getTokenCount(sAttachment, '.'); + if (2 > nTokenCount) + { + sAttachment += "."; + sAttachment = comphelper::string::setToken(sAttachment, nTokenCount, '.', sExtension); + } + else if (o3tl::getToken(sAttachment, nTokenCount - 1, '.') != sExtension) + sAttachment += sExtension; + aDesc.sAttachmentName = sAttachment; + aDesc.sMimeType = sMimeType; + + if (xConfigItem->IsGreetingLine(true)) + { + OUString sNameColumn = xConfigItem->GetAssignedColumn(MM_PART_LASTNAME); + OUString sName = lcl_GetColumnValueOf(sNameColumn, xColAccess); + OUString sGreeting; + if(!sName.isEmpty() && xConfigItem->IsIndividualGreeting(true)) + { + OUString sGenderColumn = xConfigItem->GetAssignedColumn(MM_PART_GENDER); + const OUString& sFemaleValue = xConfigItem->GetFemaleGenderValue(); + OUString sGenderValue = lcl_GetColumnValueOf(sGenderColumn, xColAccess); + SwMailMergeConfigItem::Gender eGenderType = sGenderValue == sFemaleValue ? + SwMailMergeConfigItem::FEMALE : + SwMailMergeConfigItem::MALE; + + sGreeting = SwAddressPreview::FillData( + xConfigItem->GetGreetings(eGenderType) + [xConfigItem->GetCurrentGreeting(eGenderType)], + *xConfigItem); + } + else + { + sGreeting = + xConfigItem->GetGreetings(SwMailMergeConfigItem::NEUTRAL) + [xConfigItem->GetCurrentGreeting(SwMailMergeConfigItem::NEUTRAL)]; + + } + sGreeting += "\n"; + sBody.insert(0, sGreeting); + } + } + aDesc.sBodyContent = sBody.makeStringAndClear(); + if(MM_DOCTYPE_HTML == nDocType) + { + aDesc.sBodyMimeType = "text/html; charset=" + + OUString::createFromAscii(rtl_getBestMimeCharsetFromTextEncoding( eEncoding )); + } + else + aDesc.sBodyMimeType = "text/plain; charset=UTF-8; format=flowed"; + + aDesc.sSubject = m_xSubjectED->get_text(); + aDesc.sCC = m_sCC; + aDesc.sBCC = m_sBCC; + xDlg->AddDocument( aDesc ); + //help to force painting the dialog + Application::Reschedule( true ); + //stop creating of data when dialog has been closed + if (!xDlg->getDialog()->get_visible()) + { + break; + } + } + xDlg->EnableDestruction(); + ::osl::File::remove( sTargetTempURL ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/selectdbtabledialog.cxx b/sw/source/ui/dbui/selectdbtabledialog.cxx new file mode 100644 index 0000000000..be5faf3ada --- /dev/null +++ b/sw/source/ui/dbui/selectdbtabledialog.cxx @@ -0,0 +1,144 @@ +/* -*- 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 <o3tl/safeint.hxx> +#include <comphelper/propertyvalue.hxx> +#include <swtypes.hxx> +#include "selectdbtabledialog.hxx" +#include "dbtablepreviewdialog.hxx" +#include <osl/diagnose.h> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> + +#include <strings.hrc> +#include <utility> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; + +SwSelectDBTableDialog::SwSelectDBTableDialog(weld::Window* pParent, + uno::Reference<sdbc::XConnection> xConnection) + : SfxDialogController(pParent, "modules/swriter/ui/selecttabledialog.ui", "SelectTableDialog") + , m_xConnection(std::move(xConnection)) + , m_xTable(m_xBuilder->weld_tree_view("table")) + , m_xPreviewPB(m_xBuilder->weld_button("preview")) +{ + m_xTable->set_size_request(m_xTable->get_approximate_digit_width() * 60, + m_xTable->get_height_rows(6)); + + std::vector<int> aWidths{ o3tl::narrowing<int>(m_xTable->get_approximate_digit_width() * 30) }; + m_xTable->set_column_fixed_widths(aWidths); + + m_xPreviewPB->connect_clicked(LINK(this, SwSelectDBTableDialog, PreviewHdl)); + + Reference<XTablesSupplier> xTSupplier(m_xConnection, UNO_QUERY); + if (xTSupplier.is()) + { + Reference<XNameAccess> xTables = xTSupplier->getTables(); + Sequence<OUString> aTables = xTables->getElementNames(); + const OUString* pTables = aTables.getConstArray(); + for (int i = 0; i < aTables.getLength(); i++) + { + OUString sEntry = pTables[i]; + m_xTable->append_text(sEntry); + m_xTable->set_text(i, SwResId(ST_TABLE), 1); + } + } + Reference<XQueriesSupplier> xQSupplier(m_xConnection, UNO_QUERY); + if (!xQSupplier.is()) + return; + + Reference<XNameAccess> xQueries = xQSupplier->getQueries(); + const Sequence<OUString> aQueries = xQueries->getElementNames(); + int nPos = m_xTable->n_children(); + for (const OUString& rQuery : aQueries) + { + m_xTable->append_text(rQuery); + m_xTable->set_text(nPos, SwResId(ST_QUERY), 1); + m_xTable->set_id(nPos, OUString::number(1)); + ++nPos; + } +} + +SwSelectDBTableDialog::~SwSelectDBTableDialog() {} + +IMPL_LINK_NOARG(SwSelectDBTableDialog, PreviewHdl, weld::Button&, void) +{ + int nEntry = m_xTable->get_selected_index(); + if (nEntry == -1) + return; + + OUString sTableOrQuery = m_xTable->get_text(nEntry, 0); + sal_Int32 nCommandType = m_xTable->get_id(nEntry).isEmpty() ? 0 : 1; + + OUString sDataSourceName; + Reference<XChild> xChild(m_xConnection, UNO_QUERY); + if (xChild.is()) + { + Reference<XDataSource> xSource(xChild->getParent(), UNO_QUERY); + Reference<XPropertySet> xPrSet(xSource, UNO_QUERY); + xPrSet->getPropertyValue("Name") >>= sDataSourceName; + } + OSL_ENSURE(!sDataSourceName.isEmpty(), "no data source found"); + Sequence<PropertyValue> aProperties{ + comphelper::makePropertyValue("DataSourceName", sDataSourceName), + comphelper::makePropertyValue("Command", sTableOrQuery), + comphelper::makePropertyValue("CommandType", nCommandType), + comphelper::makePropertyValue("ShowTreeView", false), + comphelper::makePropertyValue("ShowTreeViewButton", false) + }; + + SwDBTablePreviewDialog aDlg(m_xDialog.get(), aProperties); + aDlg.run(); +} + +OUString SwSelectDBTableDialog::GetSelectedTable(bool& bIsTable) +{ + int nEntry = m_xTable->get_selected_index(); + if (nEntry != -1) + { + bIsTable = m_xTable->get_id(nEntry).isEmpty(); + return m_xTable->get_text(nEntry, 0); + } + bIsTable = false; + return OUString(); +} + +void SwSelectDBTableDialog::SetSelectedTable(std::u16string_view rTable, bool bIsTable) +{ + for (int i = 0, nCount = m_xTable->n_children(); i < nCount; ++i) + { + if (m_xTable->get_text(i, 0) == rTable && m_xTable->get_id(i).isEmpty() == bIsTable) + { + m_xTable->select(i); + break; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dbui/selectdbtabledialog.hxx b/sw/source/ui/dbui/selectdbtabledialog.hxx new file mode 100644 index 0000000000..aa0bbddea8 --- /dev/null +++ b/sw/source/ui/dbui/selectdbtabledialog.hxx @@ -0,0 +1,44 @@ +/* -*- 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_DBUI_SELECTDBTABLEDIALOG_HXX +#define INCLUDED_SW_SOURCE_UI_DBUI_SELECTDBTABLEDIALOG_HXX + +#include <sfx2/basedlgs.hxx> + +namespace com::sun::star::sdbc { class XConnection; } + +class SwSelectDBTableDialog : public SfxDialogController +{ + css::uno::Reference<css::sdbc::XConnection> m_xConnection; + + std::unique_ptr<weld::TreeView> m_xTable; + std::unique_ptr<weld::Button> m_xPreviewPB; + + DECL_LINK(PreviewHdl, weld::Button&, void); +public: + SwSelectDBTableDialog(weld::Window* pParent, + css::uno::Reference<css::sdbc::XConnection> xConnection); + virtual ~SwSelectDBTableDialog() override; + + OUString GetSelectedTable(bool& bIsTable); + void SetSelectedTable(std::u16string_view rTable, bool bIsTable); +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dialog/abstract.cxx b/sw/source/ui/dialog/abstract.cxx new file mode 100644 index 0000000000..01e0138955 --- /dev/null +++ b/sw/source/ui/dialog/abstract.cxx @@ -0,0 +1,41 @@ +/* -*- 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 <abstract.hxx> + +SwInsertAbstractDlg::SwInsertAbstractDlg(weld::Window* pParent) + : SfxDialogController(pParent, "modules/swriter/ui/abstractdialog.ui", "AbstractDialog") + , m_xLevelNF(m_xBuilder->weld_spin_button("outlines")) + , m_xParaNF(m_xBuilder->weld_spin_button("paras")) +{ +} + +SwInsertAbstractDlg::~SwInsertAbstractDlg() {} + +sal_uInt8 SwInsertAbstractDlg::GetLevel() const +{ + return static_cast<sal_uInt8>(m_xLevelNF->get_value() - 1); +} + +sal_uInt8 SwInsertAbstractDlg::GetPara() const +{ + return static_cast<sal_uInt8>(m_xParaNF->get_value()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dialog/addrdlg.cxx b/sw/source/ui/dialog/addrdlg.cxx new file mode 100644 index 0000000000..0dde165fc0 --- /dev/null +++ b/sw/source/ui/dialog/addrdlg.cxx @@ -0,0 +1,36 @@ +/* -*- 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 <addrdlg.hxx> +#include <sfx2/pageids.hxx> +#include <sfx2/sfxdlg.hxx> + +SwAddrDlg::SwAddrDlg(weld::Window* pParent, const SfxItemSet& rSet) + : SfxSingleTabDialogController(pParent, &rSet) +{ + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + ::CreateTabPage fnCreatePage = pFact->GetTabPageCreatorFunc(RID_SFXPAGE_GENERAL); + if (fnCreatePage) + { + // create TabPage + SetTabPage(fnCreatePage(get_content_area(), this, &rSet)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dialog/ascfldlg.cxx b/sw/source/ui/dialog/ascfldlg.cxx new file mode 100644 index 0000000000..43a3249823 --- /dev/null +++ b/sw/source/ui/dialog/ascfldlg.cxx @@ -0,0 +1,448 @@ +/* -*- 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 <sal/config.h> + +#include <optional> +#include <utility> + +#include <hintids.hxx> +#include <rtl/textenc.h> +#include <i18nlangtag/mslangid.hxx> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <unotools/lingucfg.hxx> +#include <unotools/viewoptions.hxx> +#include <sfx2/sfxsids.hrc> +#include <sfx2/printer.hxx> +#include <sfx2/docfile.hxx> +#include <svl/languageoptions.hxx> +#include <editeng/langitem.hxx> +#include <swtypes.hxx> +#include <ascfldlg.hxx> +#include <shellio.hxx> +#include <docsh.hxx> +#include <doc.hxx> +#include <IDocumentDeviceAccess.hxx> + +#include <vcl/metric.hxx> + +using namespace ::com::sun::star; + +namespace +{ + +const sal_Unicode cDialogExtraDataClose = '}'; +const char sDialogImpExtraData[] = "EncImpDlg:{"; +const char sDialogExpExtraData[] = "EncExpDlg:{"; +const sal_Int32 nDialogExtraDataLen = 11; // 12345678901 + +} + +SwAsciiFilterDlg::SwAsciiFilterDlg( weld::Window* pParent, SwDocShell& rDocSh, + SvStream* pStream ) + : SfxDialogController(pParent, "modules/swriter/ui/asciifilterdialog.ui", "AsciiFilterDialog") + , m_bSaveLineStatus(true) + , m_xCharSetLB(new SvxTextEncodingBox(m_xBuilder->weld_combo_box("charset"))) + , m_xFontFT(m_xBuilder->weld_label("fontft")) + , m_xFontLB(m_xBuilder->weld_combo_box("font")) + , m_xLanguageFT(m_xBuilder->weld_label("languageft")) + , m_xLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("language"))) + , m_xCRLF_RB(m_xBuilder->weld_radio_button("crlf")) + , m_xCR_RB(m_xBuilder->weld_radio_button("cr")) + , m_xLF_RB(m_xBuilder->weld_radio_button("lf")) + , m_xIncludeBOM_CB(m_xBuilder->weld_check_button("includebom")) +{ + m_xFontLB->make_sorted(); + + SwAsciiOptions aOpt; + { + SvtViewOptions aDlgOpt(EViewType::Dialog, m_xDialog->get_help_id()); + if (aDlgOpt.Exists()) + { + css::uno::Any aUserItem = aDlgOpt.GetUserItem("UserItem"); + aUserItem >>= m_sExtraData; + } + + const SfxStringItem* pItem; + OUString sAsciiOptions; + if( rDocSh.GetMedium() != nullptr && + (pItem = rDocSh.GetMedium()->GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ))) + { + sAsciiOptions = pItem->GetValue(); + } + + const OUString sFindNm = OUString::createFromAscii( + pStream ? sDialogImpExtraData + : sDialogExpExtraData); + sal_Int32 nStt = m_sExtraData.indexOf( sFindNm ); + if( -1 != nStt ) + { + nStt += nDialogExtraDataLen; + sal_Int32 nEnd = m_sExtraData.indexOf( cDialogExtraDataClose, nStt ); + if( -1 != nEnd ) + { + if(sAsciiOptions.isEmpty()) + sAsciiOptions = m_sExtraData.copy(nStt, nEnd - nStt); + nStt -= nDialogExtraDataLen; + m_sExtraData = m_sExtraData.replaceAt(nStt, nEnd - nStt + 1, u""); + } + } + if(!sAsciiOptions.isEmpty()) + aOpt.ReadUserData(sAsciiOptions); + } + + // read the first chars and check the charset, (language - with L&H) + if( pStream ) + { + char aBuffer[ 4098 ]; + const sal_uInt64 nOldPos = pStream->Tell(); + const size_t nBytesRead = pStream->ReadBytes(aBuffer, 4096); + pStream->Seek( nOldPos ); + + if( nBytesRead <= 4096 ) + { + aBuffer[ nBytesRead ] = '0'; + aBuffer[ nBytesRead+1 ] = '0'; + } + + bool bCR = false, bLF = false, bNullChar = false; + for( sal_uInt64 nCnt = 0; nCnt < nBytesRead; ++nCnt ) + switch( aBuffer[ nCnt ] ) + { + case 0x0: bNullChar = true; break; + case 0xA: bLF = true; break; + case 0xD: bCR = true; break; + case 0xC: + case 0x1A: + case 0x9: break; + default: break; + } + + if( !bNullChar ) + { + if( bCR ) + { + if( bLF ) + { + aOpt.SetParaFlags( LINEEND_CRLF ); + } + else + { + aOpt.SetParaFlags( LINEEND_CR ); + } + } + else if( bLF ) + { + aOpt.SetParaFlags( LINEEND_LF ); + } + } + + const sal_uInt16 nAppScriptType = SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetAppLanguage() ); + SwDoc* pDoc = rDocSh.GetDoc(); + + // initialize language + { + if( !aOpt.GetLanguage() ) + { + if(pDoc) + { + const TypedWhichId<SvxLanguageItem> nWhich = GetWhichOfScript( RES_CHRATR_LANGUAGE, nAppScriptType); + const SvxLanguageItem& rLangItem = pDoc->GetDefault( nWhich ); + aOpt.SetLanguage( rLangItem.GetLanguage() ); + } + else + { + SvtLinguOptions aLinguOpt; + SvtLinguConfig().GetOptions( aLinguOpt ); + switch(nAppScriptType) + { + case css::i18n::ScriptType::ASIAN: + aOpt.SetLanguage(MsLangId::resolveSystemLanguageByScriptType(aLinguOpt.nDefaultLanguage_CJK, css::i18n::ScriptType::ASIAN)); + break; + case css::i18n::ScriptType::COMPLEX: + aOpt.SetLanguage(MsLangId::resolveSystemLanguageByScriptType(aLinguOpt.nDefaultLanguage_CTL, css::i18n::ScriptType::COMPLEX)); + break; + //SvtScriptType::LATIN: + default: + aOpt.SetLanguage(MsLangId::resolveSystemLanguageByScriptType(aLinguOpt.nDefaultLanguage, css::i18n::ScriptType::LATIN)); + } + } + } + + m_xLanguageLB->SetLanguageList( SvxLanguageListFlags::ALL, true ); + m_xLanguageLB->set_active_id(aOpt.GetLanguage()); + } + + { + bool bDelPrinter = false; + VclPtr<SfxPrinter> pPrt = pDoc ? pDoc->getIDocumentDeviceAccess().getPrinter(false) : nullptr; + if( !pPrt ) + { + auto pSet = std::make_unique<SfxItemSetFixed + <SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN, + SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC>>( rDocSh.GetPool() ); + pPrt = VclPtr<SfxPrinter>::Create( std::move(pSet) ); + bDelPrinter = true; + } + + // get the set of distinct available family names + std::set< OUString > aFontNames; + int nFontNames = pPrt->GetFontFaceCollectionCount(); + for( int i = 0; i < nFontNames; i++ ) + { + FontMetric aFontMetric( pPrt->GetFontMetricFromCollection( i ) ); + aFontNames.insert( aFontMetric.GetFamilyName() ); + } + + // insert into listbox + for( const auto& rFontName : aFontNames ) + { + m_xFontLB->append_text(rFontName); + } + + if( aOpt.GetFontName().isEmpty() ) + { + LanguageType eLang = aOpt.GetLanguage(); + vcl::Font aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED, eLang, GetDefaultFontFlags::OnlyOne, pPrt)); + aOpt.SetFontName(aTmpFont.GetFamilyName()); + } + + m_xFontLB->set_active_text(aOpt.GetFontName()); + + if( bDelPrinter ) + pPrt.disposeAndClear(); + } + + // hide the unused Controls for Export + m_xIncludeBOM_CB->hide(); + } + else + { + // hide the unused Controls for Export + m_xFontFT->hide(); + m_xFontLB->hide(); + m_xLanguageFT->hide(); + m_xLanguageLB->hide(); + + + SetIncludeBOM(aOpt.GetIncludeBOM()); + m_xIncludeBOM_CB->save_state(); + } + + // initialize character set + m_xCharSetLB->FillFromTextEncodingTable( pStream != nullptr ); + m_xCharSetLB->SelectTextEncoding( aOpt.GetCharSet() ); + + m_xCharSetLB->connect_changed( LINK( this, SwAsciiFilterDlg, CharSetSelHdl )); + m_xCRLF_RB->connect_toggled( LINK( this, SwAsciiFilterDlg, LineEndHdl )); + m_xLF_RB->connect_toggled( LINK( this, SwAsciiFilterDlg, LineEndHdl )); + m_xCR_RB->connect_toggled( LINK( this, SwAsciiFilterDlg, LineEndHdl )); + + SetCRLF( aOpt.GetParaFlags() ); + + m_xCRLF_RB->save_state(); + m_xLF_RB->save_state(); + m_xCR_RB->save_state(); + + UpdateIncludeBOMSensitiveState(); +} + +SwAsciiFilterDlg::~SwAsciiFilterDlg() +{ + SvtViewOptions aDlgOpt(EViewType::Dialog, m_xDialog->get_help_id()); + aDlgOpt.SetUserItem("UserItem", uno::Any(m_sExtraData)); +} + +void SwAsciiFilterDlg::FillOptions( SwAsciiOptions& rOptions ) +{ + sal_uLong nCCode = m_xCharSetLB->GetSelectTextEncoding(); + OUString sFont; + LanguageType nLng = LANGUAGE_SYSTEM; + if (m_xFontLB->get_visible()) + { + sFont = m_xFontLB->get_active_text(); + nLng = m_xLanguageLB->get_active_id(); + } + + rOptions.SetFontName( sFont ); + rOptions.SetCharSet( rtl_TextEncoding( nCCode ) ); + rOptions.SetLanguage( nLng ); + rOptions.SetParaFlags( GetCRLF() ); + rOptions.SetIncludeBOM( GetIncludeBOM() ); + + // save the user settings + OUString sData; + rOptions.WriteUserData( sData ); + if (sData.isEmpty()) + return; + + const OUString sFindNm = OUString::createFromAscii( + m_xFontLB->get_visible() ? sDialogImpExtraData + : sDialogExpExtraData); + sal_Int32 nStt = m_sExtraData.indexOf( sFindNm ); + if( -1 != nStt ) + { + // called twice, so remove "old" settings + sal_Int32 nEnd = m_sExtraData.indexOf( cDialogExtraDataClose, + nStt + nDialogExtraDataLen ); + if( -1 != nEnd ) + m_sExtraData = m_sExtraData.replaceAt( nStt, nEnd - nStt + 1, u"" ); + } + m_sExtraData += sFindNm + sData + OUStringChar(cDialogExtraDataClose); +} + +void SwAsciiFilterDlg::SetCRLF( LineEnd eEnd ) +{ + switch (eEnd) + { + case LINEEND_CR: + m_xCR_RB->set_active(true); + break; + case LINEEND_CRLF: + m_xCRLF_RB->set_active(true); + break; + case LINEEND_LF: + m_xLF_RB->set_active(true); + break; + } +} + +LineEnd SwAsciiFilterDlg::GetCRLF() const +{ + LineEnd eEnd; + if(m_xCR_RB->get_active()) + eEnd = LINEEND_CR; + else if (m_xLF_RB->get_active()) + eEnd = LINEEND_LF; + else + eEnd = LINEEND_CRLF; + return eEnd; +} + +void SwAsciiFilterDlg::SetIncludeBOM( bool bIncludeBOM ) +{ + m_xIncludeBOM_CB->set_state(bIncludeBOM ? TRISTATE_TRUE : TRISTATE_FALSE); +} + +bool SwAsciiFilterDlg::GetIncludeBOM() const +{ + return m_xIncludeBOM_CB->get_state() != TRISTATE_FALSE; +} + +void SwAsciiFilterDlg::UpdateIncludeBOMSensitiveState() +{ + if (!m_xIncludeBOM_CB->get_visible()) + return; + + switch (m_xCharSetLB->GetSelectTextEncoding()) + { + case RTL_TEXTENCODING_UTF8: + case RTL_TEXTENCODING_UCS2: + m_xIncludeBOM_CB->set_sensitive(true); + break; + default: + m_xIncludeBOM_CB->set_sensitive(false); + break; + } +} + +IMPL_LINK_NOARG(SwAsciiFilterDlg, CharSetSelHdl, weld::ComboBox&, void) +{ + LineEnd eOldEnd = GetCRLF(); + std::optional<LineEnd> eEnd; + LanguageType nLng = m_xFontLB->get_visible() + ? m_xLanguageLB->get_active_id() + : LANGUAGE_SYSTEM, + nOldLng = nLng; + + rtl_TextEncoding nChrSet = m_xCharSetLB->GetSelectTextEncoding(); + if( nChrSet == osl_getThreadTextEncoding() ) + eEnd = GetSystemLineEnd(); + else + { + switch( nChrSet ) + { + case RTL_TEXTENCODING_MS_1252: +#ifdef UNX + eEnd = LINEEND_LF; +#else + eEnd = LINEEND_CRLF; // ANSI +#endif + break; + + case RTL_TEXTENCODING_APPLE_ROMAN: // MAC + eEnd = LINEEND_CR; + break; + + case RTL_TEXTENCODING_IBM_850: // DOS + eEnd = LINEEND_CRLF; + break; + + case RTL_TEXTENCODING_APPLE_ARABIC: + case RTL_TEXTENCODING_APPLE_CENTEURO: + case RTL_TEXTENCODING_APPLE_CROATIAN: + case RTL_TEXTENCODING_APPLE_CYRILLIC: + case RTL_TEXTENCODING_APPLE_DEVANAGARI: + case RTL_TEXTENCODING_APPLE_FARSI: + case RTL_TEXTENCODING_APPLE_GREEK: + case RTL_TEXTENCODING_APPLE_GUJARATI: + case RTL_TEXTENCODING_APPLE_GURMUKHI: + case RTL_TEXTENCODING_APPLE_HEBREW: + case RTL_TEXTENCODING_APPLE_ICELAND: + case RTL_TEXTENCODING_APPLE_ROMANIAN: + case RTL_TEXTENCODING_APPLE_THAI: + case RTL_TEXTENCODING_APPLE_TURKISH: + case RTL_TEXTENCODING_APPLE_UKRAINIAN: + case RTL_TEXTENCODING_APPLE_CHINSIMP: + case RTL_TEXTENCODING_APPLE_CHINTRAD: + case RTL_TEXTENCODING_APPLE_JAPANESE: + case RTL_TEXTENCODING_APPLE_KOREAN: + eEnd = LINEEND_CR; + break; + } + } + + m_bSaveLineStatus = false; + if( eEnd ) // changed? + { + if( eOldEnd != *eEnd ) + SetCRLF( *eEnd ); + } + else + { + // restore old user choice (not the automatic!) + m_xCRLF_RB->set_state(m_xCRLF_RB->get_saved_state()); + m_xCR_RB->set_state(m_xCR_RB->get_saved_state()); + m_xLF_RB->set_state(m_xLF_RB->get_saved_state()); + } + m_bSaveLineStatus = true; + + if (nOldLng != nLng && m_xFontLB->get_visible()) + m_xLanguageLB->set_active_id(nLng); + + UpdateIncludeBOMSensitiveState(); +} + +IMPL_LINK(SwAsciiFilterDlg, LineEndHdl, weld::Toggleable&, rBtn, void) +{ + if (m_bSaveLineStatus) + rBtn.save_state(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dialog/docstdlg.cxx b/sw/source/ui/dialog/docstdlg.cxx new file mode 100644 index 0000000000..1b300206fc --- /dev/null +++ b/sw/source/ui/dialog/docstdlg.cxx @@ -0,0 +1,131 @@ +/* -*- 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 <swwait.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <pview.hxx> +#include <doc.hxx> +#include <docstdlg.hxx> +#include <IDocumentStatistics.hxx> + +#include <unotools/localedatawrapper.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <osl/diagnose.h> + +std::unique_ptr<SfxTabPage> SwDocStatPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet) +{ + return std::make_unique<SwDocStatPage>(pPage, pController, *rSet); +} + +SwDocStatPage::SwDocStatPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/statisticsinfopage.ui", "StatisticsInfoPage", &rSet) + , m_xPageNo(m_xBuilder->weld_label("nopages")) + , m_xTableNo(m_xBuilder->weld_label("notables")) + , m_xGrfNo(m_xBuilder->weld_label("nogrfs")) + , m_xOLENo(m_xBuilder->weld_label("nooles")) + , m_xParaNo(m_xBuilder->weld_label("noparas")) + , m_xWordNo(m_xBuilder->weld_label("nowords")) + , m_xCharNo(m_xBuilder->weld_label("nochars")) + , m_xCharExclSpacesNo(m_xBuilder->weld_label("nocharsexspaces")) + , m_xLineLbl(m_xBuilder->weld_label("lineft")) + , m_xLineNo(m_xBuilder->weld_label("nolines")) + , m_xUpdatePB(m_xBuilder->weld_button("update")) +{ + Update(); + m_xUpdatePB->connect_clicked(LINK(this, SwDocStatPage, UpdateHdl)); + //#111684# is the current view a page preview no SwFEShell can be found -> hide the update button + SwDocShell* pDocShell = static_cast<SwDocShell*>( SfxObjectShell::Current() ); + SwFEShell* pFEShell = pDocShell ? pDocShell->GetFEShell() : nullptr; + if(!pFEShell) + { + m_xUpdatePB->hide(); + m_xLineLbl->hide(); + m_xLineNo->hide(); + } +} + +SwDocStatPage::~SwDocStatPage() +{ +} + +// Description: fill ItemSet when changed +bool SwDocStatPage::FillItemSet(SfxItemSet * /*rSet*/) +{ + return false; +} + +void SwDocStatPage::Reset(const SfxItemSet *) +{ +} + +// Description: update / set data +void SwDocStatPage::SetData(const SwDocStat &rStat) +{ + const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetUILocaleDataWrapper(); + m_xTableNo->set_label(rLocaleData.getNum(rStat.nTable, 0)); + m_xGrfNo->set_label(rLocaleData.getNum(rStat.nGrf, 0)); + m_xOLENo->set_label(rLocaleData.getNum(rStat.nOLE, 0)); + m_xPageNo->set_label(rLocaleData.getNum(rStat.nPage, 0)); + m_xParaNo->set_label(rLocaleData.getNum(rStat.nPara, 0)); + m_xWordNo->set_label(rLocaleData.getNum(rStat.nWord, 0)); + m_xCharNo->set_label(rLocaleData.getNum(rStat.nChar, 0)); + m_xCharExclSpacesNo->set_label(rLocaleData.getNum(rStat.nCharExcludingSpaces, 0)); +} + +// Description: update statistics +void SwDocStatPage::Update() +{ + SfxViewShell *pVSh = SfxViewShell::Current(); + SwViewShell *pSh = nullptr; + if ( auto pSwView = dynamic_cast<SwView *>( pVSh ) ) + pSh = pSwView->GetWrtShellPtr(); + else if ( auto pPagePreview = dynamic_cast<SwPagePreview *>( pVSh ) ) + pSh = pPagePreview->GetViewShell(); + + OSL_ENSURE( pSh, "Shell not found" ); + + if (!pSh) + return; + + SwWait aWait( *pSh->GetDoc()->GetDocShell(), true ); + pSh->StartAction(); + m_aDocStat = pSh->GetDoc()->getIDocumentStatistics().GetUpdatedDocStat( false, true ); + pSh->EndAction(); + + SetData(m_aDocStat); +} + +IMPL_LINK_NOARG(SwDocStatPage, UpdateHdl, weld::Button&, void) +{ + Update(); + SwDocShell* pDocShell = static_cast<SwDocShell*>( SfxObjectShell::Current()); + SwFEShell* pFEShell = pDocShell ? pDocShell->GetFEShell() : nullptr; + if (pFEShell) + { + const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetUILocaleDataWrapper(); + OUString sLineCount = rLocaleData.getNum(pFEShell->GetLineCount(), 0); + m_xLineNo->set_label(sLineCount); + m_xLineNo->set_size_request(m_xLineNo->get_approximate_digit_width() * sLineCount.getLength(), -1); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dialog/macassgn.cxx b/sw/source/ui/dialog/macassgn.cxx new file mode 100644 index 0000000000..375b1aca4f --- /dev/null +++ b/sw/source/ui/dialog/macassgn.cxx @@ -0,0 +1,132 @@ +/* -*- 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 <sfx2/htmlmode.hxx> +#include <svx/svxids.hrc> +#include <svl/macitem.hxx> + +#include <swtypes.hxx> +#include <wrtsh.hxx> +#include <viewopt.hxx> +#include <macassgn.hxx> +#include <docsh.hxx> +#include <strings.hrc> +#include <view.hxx> +#include <sfx2/viewfrm.hxx> + +#include <svx/svxdlg.hxx> + + +SfxEventNamesItem SwMacroAssignDlg::AddEvents( DlgEventType eType ) +{ + SfxEventNamesItem aItem(SID_EVENTCONFIG); + + sal_uInt16 nHtmlMode = ::GetHtmlMode(static_cast<const SwDocShell*>(SfxObjectShell::Current())); + bool bHtmlMode = nHtmlMode & HTMLMODE_ON; + + switch( eType ) + { + case MACASSGN_AUTOTEXT: + aItem.AddEvent( SwResId(STR_EVENT_START_INS_GLOSSARY), OUString(), + SvMacroItemId::SwStartInsGlossary ); + aItem.AddEvent( SwResId(STR_EVENT_END_INS_GLOSSARY), OUString(), + SvMacroItemId::SwEndInsGlossary); + // in order for the new handler to become active! + break; + case MACASSGN_ALLFRM: + case MACASSGN_GRAPHIC: // graphics + { + aItem.AddEvent( SwResId(STR_EVENT_IMAGE_ERROR), OUString(), + SvMacroItemId::OnImageLoadError); + aItem.AddEvent( SwResId(STR_EVENT_IMAGE_ABORT), OUString(), + SvMacroItemId::OnImageLoadCancel); + aItem.AddEvent( SwResId(STR_EVENT_IMAGE_LOAD), OUString(), + SvMacroItemId::OnImageLoadDone); + } + [[fallthrough]]; + case MACASSGN_FRMURL: // Frame - URL-Attributes + { + if( !bHtmlMode && + (MACASSGN_FRMURL == eType || MACASSGN_ALLFRM == eType)) + { + aItem.AddEvent( SwResId( STR_EVENT_FRM_KEYINPUT_A ), OUString(), + SvMacroItemId::SwFrmKeyInputAlpha ); + aItem.AddEvent( SwResId( STR_EVENT_FRM_KEYINPUT_NOA ), OUString(), + SvMacroItemId::SwFrmKeyInputNoAlpha ); + aItem.AddEvent( SwResId( STR_EVENT_FRM_RESIZE ), OUString(), + SvMacroItemId::SwFrmResize ); + aItem.AddEvent( SwResId( STR_EVENT_FRM_MOVE ), OUString(), + SvMacroItemId::SwFrmMove ); + } + } + [[fallthrough]]; + case MACASSGN_OLE: // OLE + { + if( !bHtmlMode ) + aItem.AddEvent( SwResId(STR_EVENT_OBJECT_SELECT), OUString(), + SvMacroItemId::SwObjectSelect ); + } + [[fallthrough]]; + case MACASSGN_INETFMT: // INetFormat-Attributes + { + aItem.AddEvent( SwResId(STR_EVENT_MOUSEOVER_OBJECT), OUString(), + SvMacroItemId::OnMouseOver ); + aItem.AddEvent( SwResId(STR_EVENT_MOUSECLICK_OBJECT), OUString(), + SvMacroItemId::OnClick); + aItem.AddEvent( SwResId(STR_EVENT_MOUSEOUT_OBJECT), OUString(), + SvMacroItemId::OnMouseOut); + } + break; + } + + return aItem; +} + +bool SwMacroAssignDlg::INetFormatDlg(weld::Window* pParent, SwWrtShell& rSh, + std::optional<SvxMacroTableDtor>& rpINetItem ) +{ + bool bRet = false; + SfxItemSetFixed<RES_FRMMACRO, RES_FRMMACRO, SID_EVENTCONFIG, SID_EVENTCONFIG> aSet( rSh.GetAttrPool() ); + SvxMacroItem aItem( RES_FRMMACRO ); + if( !rpINetItem ) + rpINetItem.emplace(); + else + aItem.SetMacroTable( *rpINetItem ); + + aSet.Put( aItem ); + aSet.Put( AddEvents( MACASSGN_INETFMT ) ); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<SfxAbstractDialog> pMacroDlg( pFact->CreateEventConfigDialog(pParent, aSet, + rSh.GetView().GetViewFrame().GetFrame().GetFrameInterface() ) ); + if ( pMacroDlg && pMacroDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutSet = pMacroDlg->GetOutputItemSet(); + if( const SvxMacroItem* pItem = pOutSet->GetItemIfSet( RES_FRMMACRO, false )) + { + rpINetItem.emplace(pItem->GetMacroTable()); + bRet = true; + } + } + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dialog/swdlgfact.cxx b/sw/source/ui/dialog/swdlgfact.cxx new file mode 100644 index 0000000000..daf0dd6ff3 --- /dev/null +++ b/sw/source/ui/dialog/swdlgfact.cxx @@ -0,0 +1,1430 @@ +/* -*- 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 <config_features.h> +#include <config_fuzzers.h> +#include <config_wasm_strip.h> + +#include "swdlgfact.hxx" +#include <svl/style.hxx> +#include <globals.hrc> + +#include <wordcountdialog.hxx> +#include <abstract.hxx> +#include <addrdlg.hxx> +#include <ascfldlg.hxx> +#include <bookmark.hxx> +#include <break.hxx> +#include <changedb.hxx> +#include <chrdlg.hxx> +#include <colwd.hxx> +#include <contentcontroldlg.hxx> +#include <contentcontrollistitemdlg.hxx> +#include <pagenumberdlg.hxx> +#include <convert.hxx> +#include <cption.hxx> +#include <dbinsdlg.hxx> +#include <docfnote.hxx> +#include <docstdlg.hxx> +#include <DateFormFieldDialog.hxx> +#include <DropDownFieldDialog.hxx> +#include <DropDownFormFieldDialog.hxx> +#include <envlop.hxx> +#include <label.hxx> +#include <drpcps.hxx> +#include <swuipardlg.hxx> +#include <pattern.hxx> +#include <pardlg.hxx> +#include <rowht.hxx> +#include <selglos.hxx> +#include <splittbl.hxx> +#include <srtdlg.hxx> +#include <tautofmt.hxx> +#include <tblnumfm.hxx> +#include <wrap.hxx> +#include <tabledlg.hxx> +#include <fldtdlg.hxx> +#include <fldedt.hxx> +#include <swrenamexnameddlg.hxx> +#include <swmodalredlineacceptdlg.hxx> +#include <frmdlg.hxx> +#include <tmpdlg.hxx> +#include <glossary.hxx> +#include <inpdlg.hxx> +#include <insfnote.hxx> +#include <instable.hxx> +#include <javaedit.hxx> +#include <linenum.hxx> +#include <titlepage.hxx> +#include <mailmrge.hxx> +#include <mergetbl.hxx> +#include <multmrk.hxx> +#include <num.hxx> +#include <outline.hxx> +#include <column.hxx> +#include <cnttab.hxx> +#include <swuicnttab.hxx> +#include <regionsw.hxx> +#include <optcomp.hxx> +#include <optload.hxx> +#include <optpage.hxx> +#include <swuiidxmrk.hxx> +#include <svx/dialogs.hrc> +#include <mailmergewizard.hxx> +#include <mailconfigpage.hxx> +#include <uiborder.hxx> +#include <mmresultdialogs.hxx> +#include <formatlinebreak.hxx> +#include <translatelangselect.hxx> + +using namespace ::com::sun::star; +using namespace css::frame; +using namespace css::uno; + +short AbstractSwWordCountFloatDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSwInsertAbstractDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short SwAbstractSfxController_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractNumFormatDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +bool AbstractNumFormatDlg_Impl::StartExecuteAsync(AsyncContext &rCtx) +{ + return SfxSingleTabDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn); +} + +short AbstractSwAsciiFilterDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSplitTableDialog_Impl::Execute() +{ + return m_xDlg->run(); +} + +bool AbstractSplitTableDialog_Impl::StartExecuteAsync(AsyncContext &rCtx) +{ + return weld::GenericDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn); +} + +short AbstractSwTableWidthDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSwTableHeightDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSwMergeTableDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSwPageNumberDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +bool AbstractSwPageNumberDlg_Impl::StartExecuteAsync(AsyncContext &rCtx) +{ + return weld::GenericDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn); +} + +short AbstractGenericDialog_Impl::Execute() +{ + return m_xDlg->run(); +} + +bool AbstractGenericDialog_Impl::StartExecuteAsync(AsyncContext &rCtx) +{ + return weld::GenericDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn); +} + +short AbstractSwSortDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractMultiTOXMarkDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractTabController_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractNumBulletDialog_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSwConvertTableDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSwInsertDBColAutoPilot_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractDropDownFieldDialog_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractDropDownFormFieldDialog_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractDateFormFieldDialog_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSwLabDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSwSelGlossaryDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSwAutoFormatDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSwFieldDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSwRenameXNamedDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +bool AbstractSwContentControlListItemDlg_Impl::StartExecuteAsync(VclAbstractDialog::AsyncContext& rCtx) +{ + return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn); +} + +short AbstractSwContentControlListItemDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractSwModalRedlineAcceptDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractGlossaryDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractFieldInputDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractInsFootNoteDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractJavaEditDialog_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractMailMergeDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractMailMergeCreateFromDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractMailMergeFieldConnectionsDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractMultiTOXTabDialog_Impl::Execute() +{ + return m_xDlg->run(); +} + +bool AbstractMultiTOXTabDialog_Impl::StartExecuteAsync(AsyncContext &rCtx) +{ + return SfxTabDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn); +} + +short AbstractEditRegionDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractInsertSectionTabDialog_Impl::Execute() +{ + return m_xDlg->run(); +} + +bool AbstractInsertSectionTabDialog_Impl::StartExecuteAsync(AsyncContext &rCtx) +{ + return SfxTabDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn); +} + +short AbstractIndexMarkFloatDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +short AbstractAuthMarkFloatDlg_Impl::Execute() +{ + return m_xDlg->run(); +} + +void AbstractTabController_Impl::SetCurPageId( const OUString &rName ) +{ + m_xDlg->SetCurPageId( rName ); +} + +const SfxItemSet* AbstractTabController_Impl::GetOutputItemSet() const +{ + return m_xDlg->GetOutputItemSet(); +} + +WhichRangesContainer AbstractTabController_Impl::GetInputRanges(const SfxItemPool& pItem ) +{ + return m_xDlg->GetInputRanges( pItem ); +} + +void AbstractTabController_Impl::SetInputSet( const SfxItemSet* pInSet ) +{ + m_xDlg->SetInputSet( pInSet ); +} + +bool AbstractTabController_Impl::StartExecuteAsync(AsyncContext &rCtx) +{ + return SfxTabDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn); +} + +//From class Window. +void AbstractTabController_Impl::SetText( const OUString& rStr ) +{ + m_xDlg->set_title(rStr); +} + +void AbstractNumBulletDialog_Impl::SetCurPageId( const OUString &rName ) +{ + m_xDlg->SetCurPageId( rName ); +} + +const SfxItemSet* AbstractNumBulletDialog_Impl::GetOutputItemSet() const +{ + return m_xDlg->GetOutputItemSet(); +} + +const SfxItemSet* AbstractNumBulletDialog_Impl::GetInputItemSet() const +{ + return m_xDlg->GetInputItemSet(); +} + +WhichRangesContainer AbstractNumBulletDialog_Impl::GetInputRanges(const SfxItemPool& pItem ) +{ + return m_xDlg->GetInputRanges( pItem ); +} + +void AbstractNumBulletDialog_Impl::SetInputSet( const SfxItemSet* pInSet ) +{ + m_xDlg->SetInputSet( pInSet ); +} + +bool AbstractNumBulletDialog_Impl::StartExecuteAsync(AsyncContext &rCtx) +{ + return SfxTabDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn); +} + +//From class Window. +void AbstractNumBulletDialog_Impl::SetText( const OUString& rStr ) +{ + m_xDlg->set_title(rStr); +} + +IMPL_LINK_NOARG(AbstractApplyTabController_Impl, ApplyHdl, weld::Button&, void) +{ + if (m_xDlg->Apply()) + { + m_aHandler.Call(nullptr); + m_xDlg->Applied(); + } +} + +void AbstractApplyTabController_Impl::SetApplyHdl( const Link<LinkParamNone*,void>& rLink ) +{ + m_aHandler = rLink; + m_xDlg->SetApplyHandler(LINK(this, AbstractApplyTabController_Impl, ApplyHdl)); +} + +sal_uInt8 AbstractSwInsertAbstractDlg_Impl::GetLevel() const +{ + return m_xDlg->GetLevel(); +} + +sal_uInt8 AbstractSwInsertAbstractDlg_Impl::GetPara() const +{ + return m_xDlg->GetPara(); +} + +const SfxItemSet* SwAbstractSfxController_Impl::GetOutputItemSet() const +{ + return m_xDlg->GetOutputItemSet(); +} + +const SfxItemSet* AbstractNumFormatDlg_Impl::GetOutputItemSet() const +{ + return m_xDlg->GetOutputItemSet(); +} + +void SwAbstractSfxController_Impl::SetText(const OUString& rStr) +{ + m_xDlg->set_title(rStr); +} + +void AbstractNumFormatDlg_Impl::SetText(const OUString& rStr) +{ + m_xDlg->set_title(rStr); +} + +void AbstractSwAsciiFilterDlg_Impl::FillOptions( SwAsciiOptions& rOptions ) +{ + m_xDlg->FillOptions(rOptions); +} + +SplitTable_HeadlineOption AbstractSplitTableDialog_Impl::GetSplitMode() +{ + return m_xDlg->GetSplitMode(); +} + +OUString AbstractSwBreakDlg_Impl::GetTemplateName() +{ + SwBreakDlg* pDlg = dynamic_cast<SwBreakDlg*>(m_xDlg.get()); + if (pDlg) + return pDlg->GetTemplateName(); + + return ""; +} + +sal_uInt16 AbstractSwBreakDlg_Impl:: GetKind() +{ + SwBreakDlg* pDlg = dynamic_cast<SwBreakDlg*>(m_xDlg.get()); + if (pDlg) + return pDlg->GetKind(); + + return 0; +} + +::std::optional<sal_uInt16> AbstractSwBreakDlg_Impl:: GetPageNumber() +{ + SwBreakDlg* pDlg = dynamic_cast<SwBreakDlg*>(m_xDlg.get()); + if (pDlg) + return pDlg->GetPageNumber(); + + return 0; +} + +std::optional<SwLineBreakClear> AbstractSwBreakDlg_Impl::GetClear() +{ + SwBreakDlg* pDlg = dynamic_cast<SwBreakDlg*>(m_xDlg.get()); + if (pDlg) + return pDlg->GetClear(); + + return SwLineBreakClear::NONE; +} + +void AbstractSwConvertTableDlg_Impl::GetValues( sal_Unicode& rDelim,SwInsertTableOptions& rInsTableFlags, + SwTableAutoFormat const*& prTAFormat) +{ + m_xDlg->GetValues(rDelim,rInsTableFlags, prTAFormat); +} + +void AbstractSwInsertDBColAutoPilot_Impl::DataToDoc( const uno::Sequence< uno::Any >& rSelection, + uno::Reference< sdbc::XDataSource> rxSource, + uno::Reference< sdbc::XConnection> xConnection, + uno::Reference< sdbc::XResultSet > xResultSet) +{ +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + m_xDlg->DataToDoc(rSelection, rxSource, xConnection, xResultSet); +#else + (void) rSelection; + (void) rxSource; + (void) xConnection; + (void) xResultSet; +#endif +} + +bool AbstractDropDownFieldDialog_Impl::PrevButtonPressed() const +{ + return m_xDlg->PrevButtonPressed(); +} + +bool AbstractDropDownFieldDialog_Impl::NextButtonPressed() const +{ + return m_xDlg->NextButtonPressed(); +} + +void AbstractSwLabDlg_Impl::SetCurPageId( const OUString &rName ) +{ + m_xDlg->SetCurPageId( rName ); +} + +const SfxItemSet* AbstractSwLabDlg_Impl::GetOutputItemSet() const +{ + return m_xDlg->GetOutputItemSet(); +} + +WhichRangesContainer AbstractSwLabDlg_Impl::GetInputRanges(const SfxItemPool& pItem ) +{ + return m_xDlg->GetInputRanges( pItem ); +} + +void AbstractSwLabDlg_Impl::SetInputSet( const SfxItemSet* pInSet ) +{ + m_xDlg->SetInputSet( pInSet ); +} + +void AbstractSwLabDlg_Impl::SetText( const OUString& rStr ) +{ + m_xDlg->set_title(rStr); +} + +const OUString& AbstractSwLabDlg_Impl::GetBusinessCardStr() const +{ + return m_xDlg->GetBusinessCardStr(); +} + +Printer * AbstractSwLabDlg_Impl::GetPrt() +{ + return m_xDlg->GetPrt(); +} + +void AbstractSwSelGlossaryDlg_Impl::InsertGlos(const OUString &rRegion, const OUString &rGlosName) +{ + m_xDlg->InsertGlos( rRegion, rGlosName ); +} + +sal_Int32 AbstractSwSelGlossaryDlg_Impl::GetSelectedIdx() const +{ + return m_xDlg->GetSelectedIdx(); +} + +void AbstractSwSelGlossaryDlg_Impl::SelectEntryPos(sal_Int32 nIdx) +{ + m_xDlg->SelectEntryPos( nIdx ); +} + +std::unique_ptr<SwTableAutoFormat> AbstractSwAutoFormatDlg_Impl::FillAutoFormatOfIndex() const +{ + return m_xDlg->FillAutoFormatOfIndex(); +} + +void AbstractSwFieldDlg_Impl::SetCurPageId( const OUString &rName ) +{ + m_xDlg->SetCurPageId( rName ); +} + +const SfxItemSet* AbstractSwFieldDlg_Impl::GetOutputItemSet() const +{ + return m_xDlg->GetOutputItemSet(); +} + +WhichRangesContainer AbstractSwFieldDlg_Impl::GetInputRanges(const SfxItemPool& pItem ) +{ + return m_xDlg->GetInputRanges( pItem ); +} + +void AbstractSwFieldDlg_Impl::SetInputSet( const SfxItemSet* pInSet ) +{ + m_xDlg->SetInputSet( pInSet ); +} + +void AbstractSwFieldDlg_Impl::SetText( const OUString& rStr ) +{ + m_xDlg->set_title(rStr); +} + +bool AbstractSwFieldDlg_Impl::StartExecuteAsync(AsyncContext &rCtx) +{ + auto xDlg = m_xDlg; + return SfxTabDialogController::runAsync(m_xDlg, [=](sal_Int32 nResult){ + xDlg->Close(); + if (rCtx.isSet()) + rCtx.maEndDialogFn(nResult); + }); +} + +void AbstractSwFieldDlg_Impl::Initialize(SfxChildWinInfo *pInfo) +{ + m_xDlg->Initialize( pInfo ); +} + +void AbstractSwFieldDlg_Impl::ReInitDlg() +{ + m_xDlg->ReInitDlg(); +} + +void AbstractSwFieldDlg_Impl::ActivateDatabasePage() +{ + m_xDlg->ActivateDatabasePage(); +} + +void AbstractSwFieldDlg_Impl::ShowReferencePage() +{ + m_xDlg->ShowReferencePage(); +} + +std::shared_ptr<SfxDialogController> AbstractSwFieldDlg_Impl::GetController() +{ + return m_xDlg; +} + +void AbstractSwRenameXNamedDlg_Impl::SetForbiddenChars( const OUString& rSet ) +{ + m_xDlg->SetForbiddenChars( rSet ); +} + +void AbstractSwRenameXNamedDlg_Impl::SetAlternativeAccess( + css::uno::Reference< css::container::XNameAccess > & xSecond, + css::uno::Reference< css::container::XNameAccess > & xThird ) +{ + m_xDlg->SetAlternativeAccess( xSecond, xThird); +} + +OUString AbstractGlossaryDlg_Impl::GetCurrGrpName() const +{ + return m_xDlg->GetCurrGrpName(); +} + +OUString AbstractGlossaryDlg_Impl::GetCurrShortName() const +{ + return m_xDlg->GetCurrShortName(); +} + +void AbstractFieldInputDlg_Impl::EndDialog(sal_Int32 n) +{ + m_xDlg->response(n); +} + +bool AbstractFieldInputDlg_Impl::PrevButtonPressed() const +{ + return m_xDlg->PrevButtonPressed(); +} + +bool AbstractFieldInputDlg_Impl::NextButtonPressed() const +{ + return m_xDlg->NextButtonPressed(); +} + +OUString AbstractInsFootNoteDlg_Impl::GetFontName() +{ + return m_xDlg->GetFontName(); +} + +int AbstractSwPageNumberDlg_Impl::GetPageNumberPosition() const +{ + return m_xDlg->GetPageNumberPosition(); +} + +int AbstractSwPageNumberDlg_Impl::GetPageNumberAlignment() const +{ + return m_xDlg->GetPageNumberAlignment(); +} + +bool AbstractSwPageNumberDlg_Impl::GetMirrorOnEvenPages() const +{ + return m_xDlg->GetMirrorOnEvenPages(); +} + +bool AbstractSwPageNumberDlg_Impl::GetIncludePageTotal() const +{ + return m_xDlg->GetIncludePageTotal(); +} + +SvxNumType AbstractSwPageNumberDlg_Impl::GetPageNumberType() const +{ + return m_xDlg->GetPageNumberType(); +} + +void AbstractSwPageNumberDlg_Impl::SetPageNumberType(SvxNumType nSet) +{ + m_xDlg->SetPageNumberType(nSet); +} + +bool AbstractInsFootNoteDlg_Impl::IsEndNote() +{ + return m_xDlg->IsEndNote(); +} + +OUString AbstractInsFootNoteDlg_Impl::GetStr() +{ + return m_xDlg->GetStr(); +} + +void AbstractInsFootNoteDlg_Impl::SetHelpId(const OUString& rHelpId) +{ + m_xDlg->set_help_id(rHelpId); +} + +void AbstractInsFootNoteDlg_Impl::SetText( const OUString& rStr ) +{ + m_xDlg->set_title(rStr); +} + +void AbstractInsTableDlg_Impl::GetValues( OUString& rName, sal_uInt16& rRow, sal_uInt16& rCol, + SwInsertTableOptions& rInsTableFlags, OUString& rTableAutoFormatName, + std::unique_ptr<SwTableAutoFormat>& prTAFormat ) +{ + SwInsTableDlg* pDlg = dynamic_cast<SwInsTableDlg*>(m_xDlg.get()); + if (pDlg) + pDlg->GetValues(rName, rRow, rCol, rInsTableFlags, rTableAutoFormatName, prTAFormat); +} + +OUString AbstractJavaEditDialog_Impl::GetScriptText() const +{ + return m_xDlg->GetScriptText(); +} + +OUString AbstractJavaEditDialog_Impl::GetScriptType() const +{ + return m_xDlg->GetScriptType(); +} + +bool AbstractJavaEditDialog_Impl::IsUrl() const +{ + return m_xDlg->IsUrl(); +} + +bool AbstractJavaEditDialog_Impl::IsNew() const +{ + return m_xDlg->IsNew(); +} + +bool AbstractJavaEditDialog_Impl::IsUpdate() const +{ + return m_xDlg->IsUpdate(); +} + +DBManagerOptions AbstractMailMergeDlg_Impl::GetMergeType() +{ + return m_xDlg->GetMergeType(); +} + +const OUString& AbstractMailMergeDlg_Impl::GetSaveFilter() const +{ + return m_xDlg->GetSaveFilter(); +} + +css::uno::Sequence< css::uno::Any > AbstractMailMergeDlg_Impl::GetSelection() const +{ + return m_xDlg->GetSelection(); +} + +uno::Reference< sdbc::XResultSet> AbstractMailMergeDlg_Impl::GetResultSet() const +{ + return m_xDlg->GetResultSet(); +} + +bool AbstractMailMergeDlg_Impl::IsSaveSingleDoc() const +{ + return m_xDlg->IsSaveSingleDoc(); +} + +bool AbstractMailMergeDlg_Impl::IsGenerateFromDataBase() const +{ + return m_xDlg->IsGenerateFromDataBase(); +} + +bool AbstractMailMergeDlg_Impl::IsFileEncryptedFromDataBase() const +{ + return m_xDlg->IsFileEncryptedFromDataBase(); +} + +OUString AbstractMailMergeDlg_Impl::GetColumnName() const +{ + return m_xDlg->GetColumnName(); +} + +OUString AbstractMailMergeDlg_Impl::GetPasswordColumnName() const +{ + return m_xDlg->GetPasswordColumnName(); +} + +OUString AbstractMailMergeDlg_Impl::GetTargetURL() const +{ + return m_xDlg->GetTargetURL(); +} + +bool AbstractMailMergeCreateFromDlg_Impl::IsThisDocument() const +{ + return m_xDlg->IsThisDocument(); +} + +bool AbstractMailMergeFieldConnectionsDlg_Impl::IsUseExistingConnections() const +{ + return m_xDlg->IsUseExistingConnections(); +} + +CurTOXType AbstractMultiTOXTabDialog_Impl::GetCurrentTOXType() const +{ + return m_xDlg->GetCurrentTOXType(); +} + +SwTOXDescription& AbstractMultiTOXTabDialog_Impl::GetTOXDescription(CurTOXType eTOXTypes) +{ + return m_xDlg->GetTOXDescription(eTOXTypes); +} + +const SfxItemSet* AbstractMultiTOXTabDialog_Impl::GetOutputItemSet() const +{ + return m_xDlg->GetOutputItemSet(); +} + +void AbstractEditRegionDlg_Impl::SelectSection(const OUString& rSectionName) +{ + m_xDlg->SelectSection(rSectionName); +} + +void +AbstractInsertSectionTabDialog_Impl::SetSectionData(SwSectionData const& rSect) +{ + m_xDlg->SetSectionData(rSect); +} + +void AbstractIndexMarkFloatDlg_Impl::ReInitDlg(SwWrtShell& rWrtShell) +{ + m_xDlg->ReInitDlg( rWrtShell); +} + +std::shared_ptr<SfxDialogController> AbstractIndexMarkFloatDlg_Impl::GetController() +{ + return m_xDlg; +} + +void AbstractAuthMarkFloatDlg_Impl::ReInitDlg(SwWrtShell& rWrtShell) +{ + m_xDlg->ReInitDlg(rWrtShell); +} + +std::shared_ptr<SfxDialogController> AbstractAuthMarkFloatDlg_Impl::GetController() +{ + return m_xDlg; +} + +std::shared_ptr<SfxDialogController> AbstractSwWordCountFloatDlg_Impl::GetController() +{ + return m_xDlg; +} + +void AbstractSwWordCountFloatDlg_Impl::UpdateCounts() +{ + m_xDlg->UpdateCounts(); +} + +void AbstractSwWordCountFloatDlg_Impl::SetCounts(const SwDocStat &rCurrCnt, const SwDocStat &rDocStat) +{ + m_xDlg->SetCounts(rCurrCnt, rDocStat); +} + +AbstractMailMergeWizard_Impl::~AbstractMailMergeWizard_Impl() +{ +} + +bool AbstractMailMergeWizard_Impl::StartExecuteAsync(AsyncContext &rCtx) +{ + // SwMailMergeWizardExecutor wants to run the lifecycle of this dialog + // so clear mxOwner here and leave it up to SwMailMergeWizardExecutor + rCtx.mxOwner.clear(); + return weld::GenericDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn); +} + +short AbstractMailMergeWizard_Impl::Execute() +{ + return m_xDlg->run(); +} + +OUString AbstractMailMergeWizard_Impl::GetReloadDocument() const +{ + return m_xDlg->GetReloadDocument(); +} + +void AbstractMailMergeWizard_Impl::ShowPage( sal_uInt16 nLevel ) +{ + m_xDlg->skipUntil(nLevel); +} + +sal_uInt16 AbstractMailMergeWizard_Impl::GetRestartPage() const +{ + return m_xDlg->GetRestartPage(); +} + +std::optional<SwLanguageListItem> AbstractSwTranslateLangSelectDlg_Impl::GetSelectedLanguage() +{ +#if HAVE_FEATURE_CURL && !ENABLE_WASM_STRIP_EXTRA + return SwTranslateLangSelectDlg::GetSelectedLanguage(); +#else + return {}; +#endif +} + +VclPtr<AbstractSwInsertAbstractDlg> SwAbstractDialogFactory_Impl::CreateSwInsertAbstractDlg(weld::Window* pParent) +{ + return VclPtr<AbstractSwInsertAbstractDlg_Impl>::Create(std::make_unique<SwInsertAbstractDlg>(pParent)); +} + +VclPtr<SfxAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwAddressAbstractDlg(weld::Window* pParent, + const SfxItemSet& rSet) +{ + return VclPtr<SwAbstractSfxController_Impl>::Create(std::make_unique<SwAddrDlg>(pParent, rSet)); +} + +VclPtr<SfxAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwDropCapsDialog(weld::Window* pParent, + const SfxItemSet& rSet) +{ + return VclPtr<SwAbstractSfxController_Impl>::Create(std::make_unique<SwDropCapsDlg>(pParent, rSet)); +} + +VclPtr<SfxAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwBackgroundDialog(weld::Window* pParent, + const SfxItemSet& rSet) +{ + return VclPtr<SwAbstractSfxController_Impl>::Create(std::make_unique<SwBackgroundDlg>(pParent, rSet)); +} + +VclPtr<SfxAbstractDialog> SwAbstractDialogFactory_Impl::CreateNumFormatDialog(weld::Widget* pParent, const SfxItemSet& rSet) +{ + return VclPtr<AbstractNumFormatDlg_Impl>::Create(std::make_shared<SwNumFormatDlg>(pParent, rSet)); +} + +VclPtr<AbstractSwAsciiFilterDlg> SwAbstractDialogFactory_Impl::CreateSwAsciiFilterDlg(weld::Window* pParent, + SwDocShell& rDocSh, SvStream* pStream) +{ + return VclPtr<AbstractSwAsciiFilterDlg_Impl>::Create(std::make_unique<SwAsciiFilterDlg>(pParent, rDocSh, pStream)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwInsertBookmarkDlg(weld::Window *pParent, + SwWrtShell &rSh, OUString const*const pSelected) +{ + return VclPtr<AbstractGenericDialog_Impl>::Create(std::make_shared<SwInsertBookmarkDlg>(pParent, rSh, pSelected)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwContentControlDlg(weld::Window* pParent, + SwWrtShell &rSh) +{ + return VclPtr<AbstractGenericDialog_Impl>::Create(std::make_shared<SwContentControlDlg>(pParent, rSh)); +} + +VclPtr<AbstractSwContentControlListItemDlg> +SwAbstractDialogFactory_Impl::CreateSwContentControlListItemDlg(weld::Window* pParent, + SwContentControlListItem& rItem) +{ + return VclPtr<AbstractSwContentControlListItemDlg_Impl>::Create( + std::make_shared<SwContentControlListItemDlg>(pParent, rItem)); +} + +std::shared_ptr<AbstractSwBreakDlg> SwAbstractDialogFactory_Impl::CreateSwBreakDlg(weld::Window* pParent, SwWrtShell &rSh) +{ + return std::make_shared<AbstractSwBreakDlg_Impl>(std::make_unique<SwBreakDlg>(pParent, rSh)); +} + +std::shared_ptr<AbstractSwTranslateLangSelectDlg> SwAbstractDialogFactory_Impl::CreateSwTranslateLangSelectDlg(weld::Window* pParent, SwWrtShell &rSh) +{ +#if HAVE_FEATURE_CURL && !ENABLE_WASM_STRIP_EXTRA + return std::make_shared<AbstractSwTranslateLangSelectDlg_Impl>(std::make_unique<SwTranslateLangSelectDlg>(pParent, rSh)); +#else + (void) pParent; + (void) rSh; + return nullptr; +#endif +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwChangeDBDlg(SwView& rVw) +{ +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + return VclPtr<AbstractGenericDialog_Impl>::Create(std::make_shared<SwChangeDBDlg>(rVw)); +#else + (void) rVw; + return nullptr; +#endif +} + +VclPtr<SfxAbstractTabDialog> SwAbstractDialogFactory_Impl::CreateSwCharDlg(weld::Window* pParent, SwView& pVw, + const SfxItemSet& rCoreSet, SwCharDlgMode nDialogMode, const OUString* pFormatStr) +{ + return VclPtr<AbstractTabController_Impl>::Create(std::make_shared<SwCharDlg>(pParent, pVw, rCoreSet, nDialogMode, pFormatStr)); +} + +VclPtr<AbstractSwConvertTableDlg> SwAbstractDialogFactory_Impl::CreateSwConvertTableDlg(SwView& rView, bool bToTable) +{ + return VclPtr<AbstractSwConvertTableDlg_Impl>::Create(std::make_unique<SwConvertTableDlg>(rView, bToTable)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwCaptionDialog(weld::Window *pParent, SwView &rV) +{ + return VclPtr<AbstractGenericDialog_Impl>::Create(std::make_shared<SwCaptionDialog>(pParent, rV)); +} + +VclPtr<AbstractSwInsertDBColAutoPilot> SwAbstractDialogFactory_Impl::CreateSwInsertDBColAutoPilot( SwView& rView, + uno::Reference< sdbc::XDataSource> rxSource, + uno::Reference<sdbcx::XColumnsSupplier> xColSupp, + const SwDBData& rData) +{ +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + return VclPtr<AbstractSwInsertDBColAutoPilot_Impl>::Create(std::make_unique<SwInsertDBColAutoPilot>(rView, rxSource, xColSupp, rData)); +#else + (void) rView; + (void) rxSource; + (void) xColSupp; + (void) rData; + return nullptr; +#endif +} + +VclPtr<SfxAbstractTabDialog> SwAbstractDialogFactory_Impl::CreateSwFootNoteOptionDlg(weld::Window *pParent, SwWrtShell &rSh) +{ + return VclPtr<AbstractTabController_Impl>::Create(std::make_shared<SwFootNoteOptionDlg>(pParent, rSh)); +} + +VclPtr<AbstractDropDownFieldDialog> SwAbstractDialogFactory_Impl::CreateDropDownFieldDialog(weld::Widget *pParent, + SwWrtShell &rSh, SwField* pField, bool bPrevButton, bool bNextButton) +{ + return VclPtr<AbstractDropDownFieldDialog_Impl>::Create(std::make_unique<sw::DropDownFieldDialog>(pParent, rSh, pField, bPrevButton, bNextButton)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateDropDownFormFieldDialog(weld::Widget *pParent, sw::mark::IFieldmark* pDropDownField) +{ + return VclPtr<AbstractDropDownFormFieldDialog_Impl>::Create(std::make_unique<sw::DropDownFormFieldDialog>(pParent, pDropDownField)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateDateFormFieldDialog(weld::Widget *pParent, sw::mark::IDateFieldmark* pDateField, SwDoc& rDoc) +{ + return VclPtr<AbstractDateFormFieldDialog_Impl>::Create(std::make_unique<sw::DateFormFieldDialog>(pParent, pDateField, rDoc)); +} + +VclPtr<SfxAbstractTabDialog> SwAbstractDialogFactory_Impl::CreateSwEnvDlg(weld::Window* pParent, const SfxItemSet& rSet, + SwWrtShell* pWrtSh, Printer* pPrt, + bool bInsert) +{ + return VclPtr<AbstractTabController_Impl>::Create(std::make_shared<SwEnvDlg>(pParent, rSet, pWrtSh,pPrt, bInsert)); +} + +VclPtr<AbstractSwLabDlg> SwAbstractDialogFactory_Impl::CreateSwLabDlg(weld::Window* pParent, const SfxItemSet& rSet, + SwDBManager* pDBManager, bool bLabel) +{ + return VclPtr<AbstractSwLabDlg_Impl>::Create(std::make_unique<SwLabDlg>(pParent, rSet, pDBManager, bLabel)); +} + +SwLabDlgMethod SwAbstractDialogFactory_Impl::GetSwLabDlgStaticMethod () +{ + return SwLabDlg::UpdateFieldInformation; +} + +VclPtr<SfxAbstractTabDialog> SwAbstractDialogFactory_Impl::CreateSwParaDlg(weld::Window *pParent, SwView& rVw, + const SfxItemSet& rCoreSet, + bool bDraw , + const OUString& sDefPage) +{ + return VclPtr<AbstractTabController_Impl>::Create(std::make_shared<SwParaDlg>(pParent, rVw, rCoreSet, DLG_STD, nullptr, bDraw, sDefPage)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwAutoMarkDialog(weld::Window *pParent, SwWrtShell &rSh) +{ + return VclPtr<AbstractGenericDialog_Impl>::Create(std::make_shared<SwAuthMarkModalDlg>(pParent, rSh)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwColumnDialog(weld::Window *pParent, SwWrtShell &rSh) +{ + return VclPtr<AbstractGenericDialog_Impl>::Create(std::make_shared<SwColumnDlg>(pParent, rSh)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwTableHeightDialog(weld::Window *pParent, SwWrtShell &rSh) +{ + return VclPtr<AbstractSwTableHeightDlg_Impl>::Create(std::make_unique<SwTableHeightDlg>(pParent, rSh)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwSortingDialog(weld::Window *pParent, SwWrtShell &rSh) +{ + return VclPtr<AbstractSwSortDlg_Impl>::Create(std::make_unique<SwSortDlg>(pParent, rSh)); +} + +VclPtr<AbstractSplitTableDialog> SwAbstractDialogFactory_Impl::CreateSplitTableDialog(weld::Window *pParent, SwWrtShell &rSh) +{ + return VclPtr<AbstractSplitTableDialog_Impl>::Create(std::make_shared<SwSplitTableDlg>(pParent, rSh)); +} + +VclPtr<AbstractSwSelGlossaryDlg> SwAbstractDialogFactory_Impl::CreateSwSelGlossaryDlg(weld::Window *pParent, const OUString &rShortName) +{ + return VclPtr<AbstractSwSelGlossaryDlg_Impl>::Create(std::make_unique<SwSelGlossaryDlg>(pParent, rShortName)); +} + +VclPtr<AbstractSwAutoFormatDlg> SwAbstractDialogFactory_Impl::CreateSwAutoFormatDlg(weld::Window* pParent, + SwWrtShell* pShell, bool bSetAutoFormat, const SwTableAutoFormat* pSelFormat) +{ + return VclPtr<AbstractSwAutoFormatDlg_Impl>::Create( + std::unique_ptr<SwAutoFormatDlg, o3tl::default_delete<SwAutoFormatDlg>>( + new SwAutoFormatDlg(pParent, pShell, bSetAutoFormat, pSelFormat))); +} + +VclPtr<SfxAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwBorderDlg(weld::Window* pParent, SfxItemSet& rSet, SwBorderModes nType ) +{ + return VclPtr<SwAbstractSfxController_Impl>::Create(std::make_unique<SwBorderDlg>(pParent, rSet, nType)); +} + +VclPtr<SfxAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwWrapDlg(weld::Window* pParent, SfxItemSet& rSet, SwWrtShell* pSh) +{ + return VclPtr<SwAbstractSfxController_Impl>::Create(std::make_unique<SwWrapDlg>(pParent, rSet, pSh, true/*bDrawMode*/)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwTableWidthDlg(weld::Window *pParent, SwTableFUNC &rFnc) +{ + return VclPtr<AbstractSwTableWidthDlg_Impl>::Create(std::make_unique<SwTableWidthDlg>(pParent, rFnc)); +} + +VclPtr<SfxAbstractTabDialog> SwAbstractDialogFactory_Impl::CreateSwTableTabDlg(weld::Window* pParent, + const SfxItemSet* pItemSet, SwWrtShell* pSh) +{ + return VclPtr<AbstractTabController_Impl>::Create(std::make_shared<SwTableTabDlg>(pParent, pItemSet, pSh)); +} + +VclPtr<AbstractSwFieldDlg> SwAbstractDialogFactory_Impl::CreateSwFieldDlg(SfxBindings* pB, SwChildWinWrapper* pCW, weld::Window *pParent) +{ + return VclPtr<AbstractSwFieldDlg_Impl>::Create(std::make_shared<SwFieldDlg>(pB, pCW, pParent)); +} + +VclPtr<SfxAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwFieldEditDlg(SwView& rVw) +{ + return VclPtr<SwAbstractSfxController_Impl>::Create(std::make_unique<SwFieldEditDlg>(rVw)); +} + +VclPtr<AbstractSwRenameXNamedDlg> SwAbstractDialogFactory_Impl::CreateSwRenameXNamedDlg(weld::Widget* pParent, + css::uno::Reference< css::container::XNamed > & xNamed, + css::uno::Reference< css::container::XNameAccess > & xNameAccess) +{ + return VclPtr<AbstractSwRenameXNamedDlg_Impl>::Create(std::make_unique<SwRenameXNamedDlg>(pParent,xNamed, xNameAccess)); +} + +VclPtr<AbstractSwModalRedlineAcceptDlg> SwAbstractDialogFactory_Impl::CreateSwModalRedlineAcceptDlg(weld::Window *pParent) +{ + return VclPtr<AbstractSwModalRedlineAcceptDlg_Impl>::Create(std::make_unique<SwModalRedlineAcceptDlg>(pParent)); +} + +VclPtr<AbstractSwPageNumberDlg> SwAbstractDialogFactory_Impl::CreateSwPageNumberDlg(weld::Window *pParent) +{ + return VclPtr<AbstractSwPageNumberDlg_Impl>::Create(std::make_shared<SwPageNumberDlg>(pParent)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateTableMergeDialog(weld::Window* pParent, bool& rWithPrev) +{ + return VclPtr<AbstractSwMergeTableDlg_Impl>::Create(std::make_unique<SwMergeTableDlg>(pParent, rWithPrev)); +} + +VclPtr<SfxAbstractTabDialog> SwAbstractDialogFactory_Impl::CreateFrameTabDialog(const OUString &rDialogType, + SfxViewFrame& rFrame, weld::Window *pParent, + const SfxItemSet& rCoreSet, + bool bNewFrame, + const OUString& sDefPage ) +{ + return VclPtr<AbstractTabController_Impl>::Create(std::make_shared<SwFrameDlg>(rFrame, pParent, rCoreSet, bNewFrame, rDialogType, false/*bFormat*/, sDefPage, nullptr)); +} + +VclPtr<SfxAbstractApplyTabDialog> SwAbstractDialogFactory_Impl::CreateTemplateDialog( + weld::Window *pParent, + SfxStyleSheetBase& rBase, + SfxStyleFamily nRegion, + const OUString& sPage, + SwWrtShell* pActShell, + bool bNew ) +{ + return VclPtr<AbstractApplyTabController_Impl>::Create(std::make_shared<SwTemplateDlgController>(pParent, rBase, nRegion, + sPage, pActShell, bNew)); +} + +VclPtr<AbstractGlossaryDlg> SwAbstractDialogFactory_Impl::CreateGlossaryDlg(SfxViewFrame& rViewFrame, SwGlossaryHdl* pGlosHdl, + SwWrtShell *pWrtShell) +{ + return VclPtr<AbstractGlossaryDlg_Impl>::Create(std::make_unique<SwGlossaryDlg>(rViewFrame, pGlosHdl, pWrtShell)); +} + +VclPtr<AbstractFieldInputDlg> SwAbstractDialogFactory_Impl::CreateFieldInputDlg(weld::Widget *pParent, + SwWrtShell &rSh, SwField* pField, bool bPrevButton, bool bNextButton) +{ + return VclPtr<AbstractFieldInputDlg_Impl>::Create(std::make_unique<SwFieldInputDlg>(pParent, rSh, pField, bPrevButton, bNextButton)); +} + +VclPtr<AbstractInsFootNoteDlg> SwAbstractDialogFactory_Impl::CreateInsFootNoteDlg( + weld::Window * pParent, SwWrtShell &rSh, bool bEd ) +{ + return VclPtr<AbstractInsFootNoteDlg_Impl>::Create(std::make_unique<SwInsFootNoteDlg>(pParent, rSh, bEd)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateTitlePageDlg(weld::Window *pParent) +{ + return VclPtr<AbstractGenericDialog_Impl>::Create(std::make_shared<SwTitlePageDlg>(pParent)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateVclSwViewDialog(SwView& rView) +{ + return VclPtr<AbstractGenericDialog_Impl>::Create(std::make_shared<SwLineNumberingDlg>(rView)); +} + +std::shared_ptr<AbstractInsTableDlg> SwAbstractDialogFactory_Impl::CreateInsTableDlg(SwView& rView) +{ + return std::make_shared<AbstractInsTableDlg_Impl>(std::make_shared<SwInsTableDlg>(rView)); +} + +VclPtr<AbstractJavaEditDialog> SwAbstractDialogFactory_Impl::CreateJavaEditDialog( + weld::Window* pParent, SwWrtShell* pWrtSh) +{ + return VclPtr<AbstractJavaEditDialog_Impl>::Create(std::make_unique<SwJavaEditDialog>(pParent, pWrtSh)); +} + +VclPtr<AbstractMailMergeDlg> SwAbstractDialogFactory_Impl::CreateMailMergeDlg( + weld::Window* pParent, SwWrtShell& rSh, + const OUString& rSourceName, + const OUString& rTableName, + sal_Int32 nCommandType, + const uno::Reference< sdbc::XConnection>& xConnection ) +{ + return VclPtr<AbstractMailMergeDlg_Impl>::Create(std::make_unique<SwMailMergeDlg>(pParent, rSh, rSourceName, rTableName, nCommandType, xConnection, nullptr)); +} + +VclPtr<AbstractMailMergeCreateFromDlg> SwAbstractDialogFactory_Impl::CreateMailMergeCreateFromDlg(weld::Window* pParent) +{ + return VclPtr<AbstractMailMergeCreateFromDlg_Impl>::Create(std::make_unique<SwMailMergeCreateFromDlg>(pParent)); +} + +VclPtr<AbstractMailMergeFieldConnectionsDlg> SwAbstractDialogFactory_Impl::CreateMailMergeFieldConnectionsDlg(weld::Window* pParent) +{ + return VclPtr<AbstractMailMergeFieldConnectionsDlg_Impl>::Create(std::make_unique<SwMailMergeFieldConnectionsDlg>(pParent)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateMultiTOXMarkDlg(weld::Window* pParent, SwTOXMgr &rTOXMgr) +{ + return VclPtr<AbstractMultiTOXMarkDlg_Impl>::Create(std::make_unique<SwMultiTOXMarkDlg>(pParent, rTOXMgr)); +} + +VclPtr<AbstractNumBulletDialog> SwAbstractDialogFactory_Impl::CreateSvxNumBulletTabDialog(weld::Window* pParent, + const SfxItemSet& rSwItemSet, + SwWrtShell & rWrtSh) +{ + return VclPtr<AbstractNumBulletDialog_Impl>::Create(std::make_shared<SwSvxNumBulletTabDialog>(pParent, rSwItemSet, rWrtSh)); +} + +VclPtr<SfxAbstractTabDialog> SwAbstractDialogFactory_Impl::CreateOutlineTabDialog(weld::Window* pParent, + const SfxItemSet* pSwItemSet, + SwWrtShell & rWrtSh ) +{ + return VclPtr<AbstractTabController_Impl>::Create(std::make_shared<SwOutlineTabDialog>(pParent, pSwItemSet, rWrtSh)); +} + +VclPtr<AbstractMultiTOXTabDialog> SwAbstractDialogFactory_Impl::CreateMultiTOXTabDialog(weld::Widget* pParent, const SfxItemSet& rSet, + SwWrtShell &rShell, SwTOXBase* pCurTOX, bool bGlobal) +{ + return VclPtr<AbstractMultiTOXTabDialog_Impl>::Create(std::make_shared<SwMultiTOXTabDialog>(pParent, rSet, rShell, pCurTOX, USHRT_MAX, bGlobal)); +} + +VclPtr<AbstractEditRegionDlg> SwAbstractDialogFactory_Impl::CreateEditRegionDlg(weld::Window* pParent, SwWrtShell& rWrtSh) +{ + return VclPtr<AbstractEditRegionDlg_Impl>::Create(std::make_shared<SwEditRegionDlg>(pParent, rWrtSh)); +} + +VclPtr<AbstractInsertSectionTabDialog> SwAbstractDialogFactory_Impl::CreateInsertSectionTabDialog(weld::Window* pParent, + const SfxItemSet& rSet, SwWrtShell& rSh) +{ + return VclPtr<AbstractInsertSectionTabDialog_Impl>::Create(std::make_shared<SwInsertSectionTabDialog>(pParent, rSet, rSh)); +} + +VclPtr<AbstractMarkFloatDlg> SwAbstractDialogFactory_Impl::CreateIndexMarkFloatDlg( + SfxBindings* pBindings, + SfxChildWindow* pChild, + weld::Window *pParent, + SfxChildWinInfo* pInfo ) +{ + return VclPtr<AbstractIndexMarkFloatDlg_Impl>::Create(std::make_shared<SwIndexMarkFloatDlg>(pBindings, pChild, pParent, pInfo, true/*bNew*/)); +} + +VclPtr<AbstractMarkFloatDlg> SwAbstractDialogFactory_Impl::CreateAuthMarkFloatDlg( + SfxBindings* pBindings, + SfxChildWindow* pChild, + weld::Window *pParent, + SfxChildWinInfo* pInfo) +{ + return VclPtr<AbstractAuthMarkFloatDlg_Impl>::Create(std::make_shared<SwAuthMarkFloatDlg>(pBindings, pChild, pParent, pInfo, true/*bNew*/)); +} + +VclPtr<AbstractSwWordCountFloatDlg> SwAbstractDialogFactory_Impl::CreateSwWordCountDialog( + SfxBindings* pBindings, + SfxChildWindow* pChild, + weld::Window *pParent, + SfxChildWinInfo* pInfo) +{ + return VclPtr<AbstractSwWordCountFloatDlg_Impl>::Create(std::make_shared<SwWordCountFloatDlg>(pBindings, pChild, pParent, pInfo)); +} + +VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateIndexMarkModalDlg(weld::Window *pParent, SwWrtShell& rSh, SwTOXMark* pCurTOXMark ) +{ + return VclPtr<AbstractGenericDialog_Impl>::Create(std::make_shared<SwIndexMarkModalDlg>(pParent, rSh, pCurTOXMark)); +} + +VclPtr<AbstractMailMergeWizard> SwAbstractDialogFactory_Impl::CreateMailMergeWizard( + SwView& rView, std::shared_ptr<SwMailMergeConfigItem>& rConfigItem) +{ +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + return VclPtr<AbstractMailMergeWizard_Impl>::Create(std::make_shared<SwMailMergeWizard>(rView, rConfigItem)); +#else + (void) rView; + (void) rConfigItem; + return nullptr; +#endif +} + +GlossaryGetCurrGroup SwAbstractDialogFactory_Impl::GetGlossaryCurrGroupFunc() +{ + return SwGlossaryDlg::GetCurrGroup; +} + +GlossarySetActGroup SwAbstractDialogFactory_Impl::SetGlossaryActGroupFunc() +{ + return SwGlossaryDlg::SetActGroup; +} + +// Factories for TabPages +CreateTabPage SwAbstractDialogFactory_Impl::GetTabPageCreatorFunc( sal_uInt16 nId ) +{ + CreateTabPage pRet = nullptr; + switch ( nId ) + { + case RID_SW_TP_OPTCOMPATIBILITY_PAGE : + pRet = SwCompatibilityOptPage::Create; + break; + case RID_SW_TP_OPTLOAD_PAGE : + pRet = SwLoadOptPage::Create; + break; + case RID_SW_TP_OPTCAPTION_PAGE: + return SwCaptionOptPage::Create; + case RID_SW_TP_CONTENT_OPT: + case RID_SW_TP_HTML_CONTENT_OPT: + pRet = SwContentOptPage::Create; + break; + case RID_SW_TP_OPTSHDWCRSR: + case RID_SW_TP_HTML_OPTSHDWCRSR: + pRet = SwShdwCursorOptionsTabPage::Create; + break; + case RID_SW_TP_REDLINE_OPT : + pRet = SwRedlineOptionsTabPage::Create; + break; + case RID_SW_TP_OPTTEST_PAGE : +#ifdef DBG_UTIL + pRet = SwTestTabPage::Create; +#endif + break; + case TP_OPTPRINT_PAGE : + case RID_SW_TP_HTML_OPTPRINT_PAGE: + case RID_SW_TP_OPTPRINT_PAGE: + pRet = SwAddPrinterTabPage::Create; + break; + case RID_SW_TP_STD_FONT: + case RID_SW_TP_STD_FONT_CJK: + case RID_SW_TP_STD_FONT_CTL: + pRet = SwStdFontTabPage::Create; + break; + case RID_SW_TP_HTML_OPTTABLE_PAGE: + case RID_SW_TP_OPTTABLE_PAGE: + pRet = SwTableOptionsTabPage::Create; + break; + case RID_SW_TP_DOC_STAT : + pRet = SwDocStatPage::Create; + break; + case RID_SW_TP_MAILCONFIG: + pRet = SwMailConfigPage::Create; + break; + case RID_SW_TP_COMPARISON_OPT : + pRet = SwCompareOptionsTabPage::Create; + break; + } + + return pRet; +} + +void SwAbstractDialogFactory_Impl::ExecuteMMResultSaveDialog(weld::Window* pParent) +{ +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + SwMMResultSaveDialog aDialog(pParent); + aDialog.run(); +#else + (void) pParent; +#endif +} + +void SwAbstractDialogFactory_Impl::ExecuteMMResultPrintDialog(weld::Window* pParent) +{ +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + SwMMResultPrintDialog aDialog(pParent); + aDialog.run(); +#else + (void) pParent; +#endif +} + +void SwAbstractDialogFactory_Impl::ExecuteMMResultEmailDialog(weld::Window* pParent) +{ +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + SwMMResultEmailDialog aDialog(pParent); + aDialog.run(); +#else + (void) pParent; +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dialog/swdlgfact.hxx b/sw/source/ui/dialog/swdlgfact.hxx new file mode 100644 index 0000000000..d5c1c43806 --- /dev/null +++ b/sw/source/ui/dialog/swdlgfact.hxx @@ -0,0 +1,881 @@ +/* -*- 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_DIALOG_SWDLGFACT_HXX +#define INCLUDED_SW_SOURCE_UI_DIALOG_SWDLGFACT_HXX + +#include <swabstdlg.hxx> + +#include <abstract.hxx> +#include <ascfldlg.hxx> +#include <cnttab.hxx> +#include <colwd.hxx> +#include <contentcontrollistitemdlg.hxx> +#include <convert.hxx> +#include <DateFormFieldDialog.hxx> +#include <dbinsdlg.hxx> +#include <DropDownFieldDialog.hxx> +#include <DropDownFormFieldDialog.hxx> +#include <fldtdlg.hxx> +#include <glossary.hxx> +#include <inpdlg.hxx> +#include <insfnote.hxx> +#include <javaedit.hxx> +#include <label.hxx> +#include <mailmergewizard.hxx> +#include <mailmrge.hxx> +#include <mergetbl.hxx> +#include <multmrk.hxx> +#include <regionsw.hxx> +#include <rowht.hxx> +#include <selglos.hxx> +#include <splittbl.hxx> +#include <srtdlg.hxx> +#include <swmodalredlineacceptdlg.hxx> +#include <swrenamexnameddlg.hxx> +#include <swuicnttab.hxx> +#include <swuiidxmrk.hxx> +#include <tautofmt.hxx> +#include <utility> +#include <wordcountdialog.hxx> +#include <itabenum.hxx> +#include <optional> +#include <o3tl/deleter.hxx> +#include <pagenumberdlg.hxx> + + +class SwInsertAbstractDlg; +class SwAsciiFilterDlg; +class SwBreakDlg; +class SwMultiTOXMarkDlg; +class SwSortDlg; +class SwTableHeightDlg; +class SwTableWidthDlg; +class SwMergeTableDlg; +class SfxTabDialog; +class SwConvertTableDlg; +class SwInsertDBColAutoPilot; +class SwLabDlg; +class SwSelGlossaryDlg; +class SwAutoFormatDlg; +class SwFieldDlg; +class SwRenameXNamedDlg; +class SwModalRedlineAcceptDlg; +class SwTOXMark; +class SwSplitTableDlg; +namespace sw +{ +class DropDownFieldDialog; +class DropDownFormFieldDialog; +class DateFormFieldDialog; +} +class SwWordCountFloatDlg; + + +class AbstractSwWordCountFloatDlg_Impl : public AbstractSwWordCountFloatDlg +{ + std::shared_ptr<SwWordCountFloatDlg> m_xDlg; +public: + explicit AbstractSwWordCountFloatDlg_Impl(std::shared_ptr<SwWordCountFloatDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual void UpdateCounts() override; + virtual void SetCounts(const SwDocStat &rCurrCnt, const SwDocStat &rDocStat) override; + virtual std::shared_ptr<SfxDialogController> GetController() override; +}; + +class AbstractSwInsertAbstractDlg_Impl : public AbstractSwInsertAbstractDlg +{ + std::unique_ptr<SwInsertAbstractDlg> m_xDlg; +public: + explicit AbstractSwInsertAbstractDlg_Impl(std::unique_ptr<SwInsertAbstractDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual sal_uInt8 GetLevel() const override ; + virtual sal_uInt8 GetPara() const override ; +}; + +class SwAbstractSfxController_Impl : public SfxAbstractDialog +{ + std::unique_ptr<SfxSingleTabDialogController> m_xDlg; +public: + explicit SwAbstractSfxController_Impl(std::unique_ptr<SfxSingleTabDialogController> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual const SfxItemSet* GetOutputItemSet() const override; + virtual void SetText(const OUString& rStr) override; +}; + +class AbstractNumFormatDlg_Impl : public SfxAbstractDialog +{ + std::shared_ptr<SfxSingleTabDialogController> m_xDlg; +public: + explicit AbstractNumFormatDlg_Impl(std::shared_ptr<SfxSingleTabDialogController> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual bool StartExecuteAsync(AsyncContext &rCtx) override; + virtual const SfxItemSet* GetOutputItemSet() const override; + virtual void SetText(const OUString& rStr) override; +}; + +class AbstractSwAsciiFilterDlg_Impl : public AbstractSwAsciiFilterDlg +{ + std::unique_ptr<SwAsciiFilterDlg> m_xDlg; +public: + explicit AbstractSwAsciiFilterDlg_Impl(std::unique_ptr<SwAsciiFilterDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual void FillOptions( SwAsciiOptions& rOptions ) override; +}; + +/// Interface implementation for the insert -> fields -> page number wizard dialog +class AbstractSwPageNumberDlg_Impl : public AbstractSwPageNumberDlg +{ + std::shared_ptr<SwPageNumberDlg> m_xDlg; +public: + explicit AbstractSwPageNumberDlg_Impl(std::shared_ptr<SwPageNumberDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual bool StartExecuteAsync(AsyncContext &rCtx) override; + virtual int GetPageNumberPosition() const override; + virtual int GetPageNumberAlignment() const override; + bool GetMirrorOnEvenPages() const override; + bool GetIncludePageTotal() const override; + SvxNumType GetPageNumberType() const override; + void SetPageNumberType(SvxNumType nSet) override; +}; + +class AbstractGenericDialog_Impl : public VclAbstractDialog +{ + std::shared_ptr<weld::GenericDialogController> m_xDlg; +public: + explicit AbstractGenericDialog_Impl(std::shared_ptr<weld::GenericDialogController> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual bool StartExecuteAsync(AsyncContext &rCtx) override; +}; + +class AbstractSwSortDlg_Impl : public VclAbstractDialog +{ + std::unique_ptr<SwSortDlg> m_xDlg; +public: + explicit AbstractSwSortDlg_Impl(std::unique_ptr<SwSortDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; +}; + +class AbstractMultiTOXMarkDlg_Impl : public VclAbstractDialog +{ + std::unique_ptr<SwMultiTOXMarkDlg> m_xDlg; +public: + explicit AbstractMultiTOXMarkDlg_Impl(std::unique_ptr<SwMultiTOXMarkDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; +}; + +class AbstractNumBulletDialog_Impl : public AbstractNumBulletDialog +{ +protected: + std::shared_ptr<SfxTabDialogController> m_xDlg; +public: + explicit AbstractNumBulletDialog_Impl(std::shared_ptr<SfxTabDialogController> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual bool StartExecuteAsync(AsyncContext &rCtx) override; + virtual void SetCurPageId( const OUString &rName ) override; + virtual const SfxItemSet* GetOutputItemSet() const override; + virtual const SfxItemSet* GetInputItemSet() const override; + virtual WhichRangesContainer GetInputRanges( const SfxItemPool& pItem ) override; + virtual void SetInputSet( const SfxItemSet* pInSet ) override; + //From class Window. + virtual void SetText( const OUString& rStr ) override; +}; + +class AbstractSwBreakDlg_Impl : public AbstractSwBreakDlg +{ + std::shared_ptr<weld::DialogController> m_xDlg; +public: + explicit AbstractSwBreakDlg_Impl(std::shared_ptr<weld::DialogController> p) + : m_xDlg(std::move(p)) + { + } + virtual OUString GetTemplateName() override; + virtual sal_uInt16 GetKind() override; + virtual ::std::optional<sal_uInt16> GetPageNumber() override; + std::optional<SwLineBreakClear> GetClear() override; + + virtual std::shared_ptr<weld::DialogController> getDialogController() override { return m_xDlg; } +}; + +class AbstractSwTranslateLangSelectDlg_Impl : public AbstractSwTranslateLangSelectDlg +{ + std::shared_ptr<weld::DialogController> m_xDlg; +public: + explicit AbstractSwTranslateLangSelectDlg_Impl(std::shared_ptr<weld::DialogController> p) + : m_xDlg(std::move(p)) + { + } + + virtual std::shared_ptr<weld::DialogController> getDialogController() override { return m_xDlg; } + virtual std::optional<SwLanguageListItem> GetSelectedLanguage() override; +}; + +class AbstractSwTableWidthDlg_Impl : public VclAbstractDialog +{ + std::unique_ptr<SwTableWidthDlg> m_xDlg; +public: + explicit AbstractSwTableWidthDlg_Impl(std::unique_ptr<SwTableWidthDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; +}; + +class AbstractSwTableHeightDlg_Impl : public VclAbstractDialog +{ + std::unique_ptr<SwTableHeightDlg> m_xDlg; +public: + explicit AbstractSwTableHeightDlg_Impl(std::unique_ptr<SwTableHeightDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; +}; + +class AbstractSwMergeTableDlg_Impl : public VclAbstractDialog +{ + std::unique_ptr<SwMergeTableDlg> m_xDlg; +public: + explicit AbstractSwMergeTableDlg_Impl(std::unique_ptr<SwMergeTableDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; +}; + +class AbstractSplitTableDialog_Impl : public AbstractSplitTableDialog // add for +{ + std::shared_ptr<SwSplitTableDlg> m_xDlg; +public: + explicit AbstractSplitTableDialog_Impl(std::shared_ptr<SwSplitTableDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual bool StartExecuteAsync(AsyncContext &rCtx) override; + virtual SplitTable_HeadlineOption GetSplitMode() override; +}; + +class AbstractTabController_Impl : virtual public SfxAbstractTabDialog +{ +protected: + std::shared_ptr<SfxTabDialogController> m_xDlg; +public: + explicit AbstractTabController_Impl(std::shared_ptr<SfxTabDialogController> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual bool StartExecuteAsync(AsyncContext &rCtx) override; + virtual void SetCurPageId( const OUString &rName ) override; + virtual const SfxItemSet* GetOutputItemSet() const override; + virtual WhichRangesContainer GetInputRanges( const SfxItemPool& pItem ) override; + virtual void SetInputSet( const SfxItemSet* pInSet ) override; + //From class Window. + virtual void SetText( const OUString& rStr ) override; +}; + +class AbstractApplyTabController_Impl : public AbstractTabController_Impl, virtual public SfxAbstractApplyTabDialog +{ +public: + explicit AbstractApplyTabController_Impl(std::shared_ptr<SfxTabDialogController> p) + : AbstractTabController_Impl(std::move(p)) + { + } + DECL_LINK(ApplyHdl, weld::Button&, void); +private: + Link<LinkParamNone*,void> m_aHandler; + virtual void SetApplyHdl( const Link<LinkParamNone*,void>& rLink ) override; +}; + +class AbstractSwConvertTableDlg_Impl : public AbstractSwConvertTableDlg +{ + std::unique_ptr<SwConvertTableDlg> m_xDlg; +public: + explicit AbstractSwConvertTableDlg_Impl(std::unique_ptr<SwConvertTableDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual void GetValues( sal_Unicode& rDelim,SwInsertTableOptions& rInsTableFlags, + SwTableAutoFormat const*& prTAFormat) override; +}; + +class AbstractSwInsertDBColAutoPilot_Impl : public AbstractSwInsertDBColAutoPilot +{ + std::unique_ptr<SwInsertDBColAutoPilot> m_xDlg; +public: + explicit AbstractSwInsertDBColAutoPilot_Impl(std::unique_ptr<SwInsertDBColAutoPilot> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual void DataToDoc( const css::uno::Sequence< css::uno::Any >& rSelection, + css::uno::Reference< css::sdbc::XDataSource> rxSource, + css::uno::Reference< css::sdbc::XConnection> xConnection, + css::uno::Reference< css::sdbc::XResultSet > xResultSet) override; +}; + +class AbstractDropDownFieldDialog_Impl : public AbstractDropDownFieldDialog +{ + std::unique_ptr<sw::DropDownFieldDialog> m_xDlg; +public: + explicit AbstractDropDownFieldDialog_Impl(std::unique_ptr<sw::DropDownFieldDialog> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual bool PrevButtonPressed() const override; + virtual bool NextButtonPressed() const override; +}; + +class AbstractDropDownFormFieldDialog_Impl : public VclAbstractDialog +{ + std::unique_ptr<sw::DropDownFormFieldDialog> m_xDlg; +public: + explicit AbstractDropDownFormFieldDialog_Impl(std::unique_ptr<sw::DropDownFormFieldDialog> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; +}; + +class AbstractDateFormFieldDialog_Impl : public VclAbstractDialog +{ + std::unique_ptr<sw::DateFormFieldDialog> m_xDlg; +public: + explicit AbstractDateFormFieldDialog_Impl(std::unique_ptr<sw::DateFormFieldDialog> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; +}; + +class AbstractSwLabDlg_Impl : public AbstractSwLabDlg +{ + std::unique_ptr<SwLabDlg> m_xDlg; +public: + explicit AbstractSwLabDlg_Impl(std::unique_ptr<SwLabDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual void SetCurPageId( const OUString &rName ) override; + virtual const SfxItemSet* GetOutputItemSet() const override; + virtual WhichRangesContainer GetInputRanges( const SfxItemPool& pItem ) override; + virtual void SetInputSet( const SfxItemSet* pInSet ) override; + //From class Window. + virtual void SetText( const OUString& rStr ) override; + virtual const OUString& GetBusinessCardStr() const override; + virtual Printer *GetPrt() override; +}; + +class AbstractSwSelGlossaryDlg_Impl : public AbstractSwSelGlossaryDlg +{ + std::unique_ptr<SwSelGlossaryDlg> m_xDlg; +public: + explicit AbstractSwSelGlossaryDlg_Impl(std::unique_ptr<SwSelGlossaryDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual void InsertGlos(const OUString &rRegion, const OUString &rGlosName) override; // inline + virtual sal_Int32 GetSelectedIdx() const override; // inline + virtual void SelectEntryPos(sal_Int32 nIdx) override; // inline +}; + +class AbstractSwAutoFormatDlg_Impl : public AbstractSwAutoFormatDlg +{ + std::unique_ptr<SwAutoFormatDlg, o3tl::default_delete<SwAutoFormatDlg>> m_xDlg; +public: + explicit AbstractSwAutoFormatDlg_Impl(std::unique_ptr<SwAutoFormatDlg, o3tl::default_delete<SwAutoFormatDlg>> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual std::unique_ptr<SwTableAutoFormat> FillAutoFormatOfIndex() const override; +}; + +class AbstractSwFieldDlg_Impl : public AbstractSwFieldDlg +{ + std::shared_ptr<SwFieldDlg> m_xDlg; +public: + explicit AbstractSwFieldDlg_Impl(std::shared_ptr<SwFieldDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual bool StartExecuteAsync(AsyncContext &rCtx) override; + virtual void SetCurPageId( const OUString &rName ) override; + virtual const SfxItemSet* GetOutputItemSet() const override; + virtual WhichRangesContainer GetInputRanges( const SfxItemPool& pItem ) override; + virtual void SetInputSet( const SfxItemSet* pInSet ) override; + //From class Window. + virtual void SetText( const OUString& rStr ) override; + virtual void ShowReferencePage() override; + virtual void Initialize(SfxChildWinInfo *pInfo) override; + virtual void ReInitDlg() override; + virtual void ActivateDatabasePage() override; + virtual std::shared_ptr<SfxDialogController> GetController() override; +}; + +class AbstractSwRenameXNamedDlg_Impl : public AbstractSwRenameXNamedDlg +{ + std::unique_ptr<SwRenameXNamedDlg> m_xDlg; +public: + explicit AbstractSwRenameXNamedDlg_Impl(std::unique_ptr<SwRenameXNamedDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual void SetForbiddenChars( const OUString& rSet ) override; + virtual void SetAlternativeAccess( + css::uno::Reference< css::container::XNameAccess > & xSecond, + css::uno::Reference< css::container::XNameAccess > & xThird ) override; +}; + +/** + * Implementation of AbstractSwContentControlListItemDlg, that is only visible to + * SwAbstractDialogFactory_Impl::CreateSwContentControlListItemDlg(). + */ +class AbstractSwContentControlListItemDlg_Impl : public AbstractSwContentControlListItemDlg +{ + std::shared_ptr<SwContentControlListItemDlg> m_xDlg; + +public: + explicit AbstractSwContentControlListItemDlg_Impl( + std::shared_ptr<SwContentControlListItemDlg> xDlg) + : m_xDlg(std::move(xDlg)) + { + } + + short Execute() override; + bool StartExecuteAsync(VclAbstractDialog::AsyncContext &) override; +}; + +class AbstractSwModalRedlineAcceptDlg_Impl : public AbstractSwModalRedlineAcceptDlg +{ + std::unique_ptr<SwModalRedlineAcceptDlg> m_xDlg; +public: + explicit AbstractSwModalRedlineAcceptDlg_Impl(std::unique_ptr<SwModalRedlineAcceptDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; +}; + +class SwGlossaryDlg; +class AbstractGlossaryDlg_Impl : public AbstractGlossaryDlg +{ + std::unique_ptr<SwGlossaryDlg> m_xDlg; +public: + explicit AbstractGlossaryDlg_Impl(std::unique_ptr<SwGlossaryDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual OUString GetCurrGrpName() const override; + virtual OUString GetCurrShortName() const override; +}; + +class SwFieldInputDlg; +class AbstractFieldInputDlg_Impl : public AbstractFieldInputDlg +{ + std::unique_ptr<SwFieldInputDlg> m_xDlg; +public: + explicit AbstractFieldInputDlg_Impl(std::unique_ptr<SwFieldInputDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual void EndDialog(sal_Int32) override; + virtual bool PrevButtonPressed() const override; + virtual bool NextButtonPressed() const override; +}; + +class SwInsFootNoteDlg; +class AbstractInsFootNoteDlg_Impl : public AbstractInsFootNoteDlg +{ + std::unique_ptr<SwInsFootNoteDlg> m_xDlg; +public: + explicit AbstractInsFootNoteDlg_Impl(std::unique_ptr<SwInsFootNoteDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual OUString GetFontName() override; + virtual bool IsEndNote() override; + virtual OUString GetStr() override; + //from class Window + virtual void SetHelpId( const OUString& sHelpId ) override; + virtual void SetText( const OUString& rStr ) override; +}; + +class SwInsTableDlg; +class AbstractInsTableDlg_Impl : public AbstractInsTableDlg +{ + std::shared_ptr<weld::DialogController> m_xDlg; +public: + explicit AbstractInsTableDlg_Impl(std::shared_ptr<weld::DialogController> p) + : m_xDlg(std::move(p)) + { + } + virtual void GetValues( OUString& rName, sal_uInt16& rRow, sal_uInt16& rCol, + SwInsertTableOptions& rInsTableFlags, OUString& rTableAutoFormatName, + std::unique_ptr<SwTableAutoFormat>& prTAFormat ) override; + virtual std::shared_ptr<weld::DialogController> getDialogController() override { return m_xDlg; } +}; + +class SwJavaEditDialog; +class AbstractJavaEditDialog_Impl : public AbstractJavaEditDialog +{ + std::unique_ptr<SwJavaEditDialog> m_xDlg; +public: + explicit AbstractJavaEditDialog_Impl(std::unique_ptr<SwJavaEditDialog> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual OUString GetScriptText() const override; + virtual OUString GetScriptType() const override; + virtual bool IsUrl() const override; + virtual bool IsNew() const override; + virtual bool IsUpdate() const override; +}; + +class SwMailMergeDlg; +class AbstractMailMergeDlg_Impl : public AbstractMailMergeDlg +{ + std::unique_ptr<SwMailMergeDlg> m_xDlg; +public: + explicit AbstractMailMergeDlg_Impl(std::unique_ptr<SwMailMergeDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual DBManagerOptions GetMergeType() override ; + virtual const OUString& GetSaveFilter() const override; + virtual css::uno::Sequence< css::uno::Any > GetSelection() const override ; + virtual css::uno::Reference< css::sdbc::XResultSet> GetResultSet() const override; + virtual bool IsSaveSingleDoc() const override; + virtual bool IsGenerateFromDataBase() const override; + virtual bool IsFileEncryptedFromDataBase() const override; + virtual OUString GetColumnName() const override; + virtual OUString GetPasswordColumnName() const override; + virtual OUString GetTargetURL() const override; +}; + +class SwMailMergeCreateFromDlg; +class AbstractMailMergeCreateFromDlg_Impl : public AbstractMailMergeCreateFromDlg +{ + std::unique_ptr<SwMailMergeCreateFromDlg> m_xDlg; +public: + explicit AbstractMailMergeCreateFromDlg_Impl(std::unique_ptr<SwMailMergeCreateFromDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual bool IsThisDocument() const override ; +}; + +class SwMailMergeFieldConnectionsDlg; +class AbstractMailMergeFieldConnectionsDlg_Impl : public AbstractMailMergeFieldConnectionsDlg +{ + std::unique_ptr<SwMailMergeFieldConnectionsDlg> m_xDlg; +public: + explicit AbstractMailMergeFieldConnectionsDlg_Impl(std::unique_ptr<SwMailMergeFieldConnectionsDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual bool IsUseExistingConnections() const override ; +}; + +class SwMultiTOXTabDialog; +class AbstractMultiTOXTabDialog_Impl : public AbstractMultiTOXTabDialog +{ + std::shared_ptr<SwMultiTOXTabDialog> m_xDlg; +public: + explicit AbstractMultiTOXTabDialog_Impl(std::shared_ptr<SwMultiTOXTabDialog> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual bool StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx) override; + virtual CurTOXType GetCurrentTOXType() const override ; + virtual SwTOXDescription& GetTOXDescription(CurTOXType eTOXTypes) override; + //from SfxTabDialog + virtual const SfxItemSet* GetOutputItemSet() const override; +}; + +class SwEditRegionDlg; +class AbstractEditRegionDlg_Impl : public AbstractEditRegionDlg +{ + std::shared_ptr<SwEditRegionDlg> m_xDlg; +public: + explicit AbstractEditRegionDlg_Impl(std::shared_ptr<SwEditRegionDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual void SelectSection(const OUString& rSectionName) override; +}; + +class SwInsertSectionTabDialog; +class AbstractInsertSectionTabDialog_Impl : public AbstractInsertSectionTabDialog +{ + std::shared_ptr<SwInsertSectionTabDialog> m_xDlg; +public: + explicit AbstractInsertSectionTabDialog_Impl(std::shared_ptr<SwInsertSectionTabDialog> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual bool StartExecuteAsync(AsyncContext &rCtx) override; + virtual void SetSectionData(SwSectionData const& rSect) override; +}; + +class SwIndexMarkFloatDlg; +class AbstractIndexMarkFloatDlg_Impl : public AbstractMarkFloatDlg +{ + std::shared_ptr<SwIndexMarkFloatDlg> m_xDlg; +public: + explicit AbstractIndexMarkFloatDlg_Impl(std::shared_ptr<SwIndexMarkFloatDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual void ReInitDlg(SwWrtShell& rWrtShell) override; + virtual std::shared_ptr<SfxDialogController> GetController() override; +}; + +class SwAuthMarkFloatDlg; +class AbstractAuthMarkFloatDlg_Impl : public AbstractMarkFloatDlg +{ + std::shared_ptr<SwAuthMarkFloatDlg> m_xDlg; +public: + explicit AbstractAuthMarkFloatDlg_Impl(std::shared_ptr<SwAuthMarkFloatDlg> p) + : m_xDlg(std::move(p)) + { + } + virtual short Execute() override; + virtual void ReInitDlg(SwWrtShell& rWrtShell) override; + virtual std::shared_ptr<SfxDialogController> GetController() override; +}; + +class SwMailMergeWizard; +class AbstractMailMergeWizard_Impl : public AbstractMailMergeWizard +{ + std::shared_ptr<SwMailMergeWizard> m_xDlg; + +public: + explicit AbstractMailMergeWizard_Impl(std::shared_ptr<SwMailMergeWizard> p) + : m_xDlg(std::move(p)) + { + } + virtual ~AbstractMailMergeWizard_Impl() override; + virtual bool StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx) override; + virtual short Execute() override; + + virtual OUString GetReloadDocument() const override; + virtual void ShowPage( sal_uInt16 nLevel ) override; + virtual sal_uInt16 GetRestartPage() const override; +}; + +//AbstractDialogFactory_Impl implementations +class SwAbstractDialogFactory_Impl : public SwAbstractDialogFactory +{ + +public: + virtual ~SwAbstractDialogFactory_Impl() {} + + virtual VclPtr<SfxAbstractDialog> CreateNumFormatDialog(weld::Widget* pParent, const SfxItemSet& rAttr) override; + virtual VclPtr<SfxAbstractDialog> CreateSwDropCapsDialog(weld::Window* pParent, const SfxItemSet& rSet) override; + virtual VclPtr<SfxAbstractDialog> CreateSwBackgroundDialog(weld::Window* pParent, const SfxItemSet& rSet) override; + virtual VclPtr<AbstractSwWordCountFloatDlg> CreateSwWordCountDialog(SfxBindings* pBindings, + SfxChildWindow* pChild, weld::Window *pParent, SfxChildWinInfo* pInfo) override; + virtual VclPtr<AbstractSwInsertAbstractDlg> CreateSwInsertAbstractDlg(weld::Window* pParent) override; + virtual VclPtr<SfxAbstractDialog> CreateSwAddressAbstractDlg(weld::Window* pParent, const SfxItemSet& rSet) override; + virtual VclPtr<AbstractSwAsciiFilterDlg> CreateSwAsciiFilterDlg(weld::Window* pParent, SwDocShell& rDocSh, + SvStream* pStream) override; + virtual VclPtr<VclAbstractDialog> CreateSwInsertBookmarkDlg(weld::Window *pParent, SwWrtShell &rSh, OUString const* pSelected) override; + virtual VclPtr<VclAbstractDialog> CreateSwContentControlDlg(weld::Window *pParent, SwWrtShell &rSh) override; + virtual VclPtr<AbstractSwPageNumberDlg> CreateSwPageNumberDlg(weld::Window *pParent) override; + + VclPtr<AbstractSwContentControlListItemDlg> + CreateSwContentControlListItemDlg(weld::Window* pParent, + SwContentControlListItem& rItem) override; + + virtual std::shared_ptr<AbstractSwBreakDlg> CreateSwBreakDlg(weld::Window *pParent, SwWrtShell &rSh) override; + virtual std::shared_ptr<AbstractSwTranslateLangSelectDlg> CreateSwTranslateLangSelectDlg(weld::Window *pParent, SwWrtShell &rSh) override; + virtual VclPtr<VclAbstractDialog> CreateSwChangeDBDlg(SwView& rVw) override; + virtual VclPtr<SfxAbstractTabDialog> CreateSwCharDlg(weld::Window* pParent, SwView& pVw, const SfxItemSet& rCoreSet, + SwCharDlgMode nDialogMode, const OUString* pFormatStr = nullptr) override; + virtual VclPtr<AbstractSwConvertTableDlg> CreateSwConvertTableDlg(SwView& rView, bool bToTable) override; + virtual VclPtr<VclAbstractDialog> CreateSwCaptionDialog(weld::Window *pParent, SwView &rV) override; + virtual VclPtr<AbstractSwInsertDBColAutoPilot> CreateSwInsertDBColAutoPilot(SwView& rView, + css::uno::Reference< css::sdbc::XDataSource> rxSource, + css::uno::Reference<css::sdbcx::XColumnsSupplier> xColSupp, + const SwDBData& rData) override; + virtual VclPtr<SfxAbstractTabDialog> CreateSwFootNoteOptionDlg(weld::Window *pParent, SwWrtShell &rSh) override; + + virtual VclPtr<AbstractDropDownFieldDialog> CreateDropDownFieldDialog(weld::Widget* pParent, SwWrtShell &rSh, + SwField* pField, bool bPrevButton, bool bNextButton) override; + virtual VclPtr<VclAbstractDialog> CreateDropDownFormFieldDialog(weld::Widget* pParent, sw::mark::IFieldmark* pDropDownField) override; + virtual VclPtr<VclAbstractDialog> CreateDateFormFieldDialog(weld::Widget* pParent, sw::mark::IDateFieldmark* pDateField, SwDoc& rDoc) override; + + virtual VclPtr<SfxAbstractTabDialog> CreateSwEnvDlg(weld::Window* pParent, const SfxItemSet& rSet, SwWrtShell* pWrtSh, Printer* pPrt, bool bInsert) override; + virtual VclPtr<AbstractSwLabDlg> CreateSwLabDlg(weld::Window* pParent, const SfxItemSet& rSet, + SwDBManager* pDBManager, bool bLabel) override; + + virtual SwLabDlgMethod GetSwLabDlgStaticMethod () override; + virtual VclPtr<SfxAbstractTabDialog> CreateSwParaDlg(weld::Window *pParent, + SwView& rVw, + const SfxItemSet& rCoreSet, + bool bDraw, + const OUString& sDefPage = {}) override; + + virtual VclPtr<VclAbstractDialog> CreateSwAutoMarkDialog(weld::Window *pParent, SwWrtShell &rSh) override; + virtual VclPtr<AbstractSwSelGlossaryDlg> CreateSwSelGlossaryDlg(weld::Window *pParent, const OUString &rShortName) override; + virtual VclPtr<VclAbstractDialog> CreateSwSortingDialog(weld::Window *pParent, SwWrtShell &rSh) override; + virtual VclPtr<VclAbstractDialog> CreateSwTableHeightDialog(weld::Window *pParent, SwWrtShell &rSh) override; + virtual VclPtr<VclAbstractDialog> CreateSwColumnDialog(weld::Window *pParent, SwWrtShell &rSh) override; + virtual VclPtr<AbstractSplitTableDialog> CreateSplitTableDialog(weld::Window* pParent, SwWrtShell &rSh) override; + + virtual VclPtr<AbstractSwAutoFormatDlg> CreateSwAutoFormatDlg(weld::Window* pParent, SwWrtShell* pShell, + bool bSetAutoFormat = true, + const SwTableAutoFormat* pSelFormat = nullptr) override; + virtual VclPtr<SfxAbstractDialog> CreateSwBorderDlg(weld::Window* pParent, SfxItemSet& rSet, SwBorderModes nType) override; + + virtual VclPtr<SfxAbstractDialog> CreateSwWrapDlg(weld::Window* pParent, SfxItemSet& rSet, SwWrtShell* pSh) override; + virtual VclPtr<VclAbstractDialog> CreateSwTableWidthDlg(weld::Window *pParent, SwTableFUNC &rFnc) override; + virtual VclPtr<SfxAbstractTabDialog> CreateSwTableTabDlg(weld::Window* pParent, + const SfxItemSet* pItemSet, SwWrtShell* pSh) override; + virtual VclPtr<AbstractSwFieldDlg> CreateSwFieldDlg(SfxBindings* pB, SwChildWinWrapper* pCW, weld::Window *pParent) override; + virtual VclPtr<SfxAbstractDialog> CreateSwFieldEditDlg ( SwView& rVw ) override; + virtual VclPtr<AbstractSwRenameXNamedDlg> CreateSwRenameXNamedDlg(weld::Widget* pParent, + css::uno::Reference< css::container::XNamed > & xNamed, + css::uno::Reference< css::container::XNameAccess > & xNameAccess) override; + virtual VclPtr<AbstractSwModalRedlineAcceptDlg> CreateSwModalRedlineAcceptDlg(weld::Window *pParent) override; + + virtual VclPtr<VclAbstractDialog> CreateTableMergeDialog(weld::Window* pParent, bool& rWithPrev) override; + virtual VclPtr<SfxAbstractTabDialog> CreateFrameTabDialog( const OUString &rDialogType, + SfxViewFrame& rFrame, weld::Window *pParent, + const SfxItemSet& rCoreSet, + bool bNewFrame = true, + const OUString& sDefPage = {}) override; + virtual VclPtr<SfxAbstractApplyTabDialog> CreateTemplateDialog( + weld::Window *pParent, + SfxStyleSheetBase& rBase, + SfxStyleFamily nRegion, + const OUString& sPage, + SwWrtShell* pActShell, + bool bNew) override; + virtual VclPtr<AbstractGlossaryDlg> CreateGlossaryDlg(SfxViewFrame& rViewFrame, + SwGlossaryHdl* pGlosHdl, + SwWrtShell *pWrtShell) override; + virtual VclPtr<AbstractFieldInputDlg> CreateFieldInputDlg(weld::Widget *pParent, + SwWrtShell &rSh, SwField* pField, bool bPrevButton, bool bNextButton) override; + virtual VclPtr<AbstractInsFootNoteDlg> CreateInsFootNoteDlg( + weld::Window * pParent, SwWrtShell &rSh, bool bEd = false) override; + virtual VclPtr<VclAbstractDialog> CreateTitlePageDlg(weld::Window* pParent) override; + virtual VclPtr<VclAbstractDialog> CreateVclSwViewDialog(SwView& rView) override; + virtual std::shared_ptr<AbstractInsTableDlg> CreateInsTableDlg(SwView& rView) override; + virtual VclPtr<AbstractJavaEditDialog> CreateJavaEditDialog(weld::Window* pParent, + SwWrtShell* pWrtSh) override; + virtual VclPtr<AbstractMailMergeDlg> CreateMailMergeDlg( + weld::Window* pParent, SwWrtShell& rSh, + const OUString& rSourceName, + const OUString& rTableName, + sal_Int32 nCommandType, + const css::uno::Reference< css::sdbc::XConnection>& xConnection ) override; + virtual VclPtr<AbstractMailMergeCreateFromDlg> CreateMailMergeCreateFromDlg(weld::Window* pParent) override; + virtual VclPtr<AbstractMailMergeFieldConnectionsDlg> CreateMailMergeFieldConnectionsDlg(weld::Window* pParent) override; + virtual VclPtr<VclAbstractDialog> CreateMultiTOXMarkDlg(weld::Window* pParent, SwTOXMgr &rTOXMgr) override; + virtual VclPtr<SfxAbstractTabDialog> CreateOutlineTabDialog(weld::Window* pParent, const SfxItemSet* pSwItemSet, + SwWrtShell &) override; + virtual VclPtr<AbstractNumBulletDialog> CreateSvxNumBulletTabDialog(weld::Window* pParent, + const SfxItemSet& rSwItemSet, + SwWrtShell &) override; + virtual VclPtr<AbstractMultiTOXTabDialog> CreateMultiTOXTabDialog( + weld::Widget* pParent, const SfxItemSet& rSet, + SwWrtShell &rShell, + SwTOXBase* pCurTOX, + bool bGlobal) override; + virtual VclPtr<AbstractEditRegionDlg> CreateEditRegionDlg(weld::Window* pParent, SwWrtShell& rWrtSh) override; + virtual VclPtr<AbstractInsertSectionTabDialog> CreateInsertSectionTabDialog( + weld::Window* pParent, const SfxItemSet& rSet, SwWrtShell& rSh) override; + virtual VclPtr<AbstractMarkFloatDlg> CreateIndexMarkFloatDlg( + SfxBindings* pBindings, + SfxChildWindow* pChild, + weld::Window *pParent, + SfxChildWinInfo* pInfo) override; + virtual VclPtr<AbstractMarkFloatDlg> CreateAuthMarkFloatDlg( + SfxBindings* pBindings, + SfxChildWindow* pChild, + weld::Window *pParent, + SfxChildWinInfo* pInfo) override; + virtual VclPtr<VclAbstractDialog> CreateIndexMarkModalDlg( + weld::Window *pParent, SwWrtShell& rSh, SwTOXMark* pCurTOXMark ) override; + + virtual VclPtr<AbstractMailMergeWizard> CreateMailMergeWizard(SwView& rView, std::shared_ptr<SwMailMergeConfigItem>& rConfigItem) override; + + virtual GlossaryGetCurrGroup GetGlossaryCurrGroupFunc() override; + virtual GlossarySetActGroup SetGlossaryActGroupFunc() override; + + // For TabPage + virtual CreateTabPage GetTabPageCreatorFunc( sal_uInt16 nId ) override; + + virtual void ExecuteMMResultSaveDialog(weld::Window* pParent) override; + virtual void ExecuteMMResultPrintDialog(weld::Window* pParent) override; + virtual void ExecuteMMResultEmailDialog(weld::Window* pParent) override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dialog/swmessdialog.cxx b/sw/source/ui/dialog/swmessdialog.cxx new file mode 100644 index 0000000000..abdf16bf4d --- /dev/null +++ b/sw/source/ui/dialog/swmessdialog.cxx @@ -0,0 +1,20 @@ +/* -*- 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 <swmessdialog.hxx> + +SwMessageAndEditDialog::SwMessageAndEditDialog(weld::Window* pParent, const OUString& rID, + const OUString& rUIXMLDescription) + : MessageDialogController(pParent, rUIXMLDescription, rID, "grid") + , m_xEdit(m_xBuilder->weld_entry("edit")) + , m_xOKPB(m_xBuilder->weld_button("ok")) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dialog/swuiexp.cxx b/sw/source/ui/dialog/swuiexp.cxx new file mode 100644 index 0000000000..e141dab80d --- /dev/null +++ b/sw/source/ui/dialog/swuiexp.cxx @@ -0,0 +1,40 @@ +/* -*- 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 "swdlgfact.hxx" + +#include <swuiexp.hxx> + +namespace swui +{ +SwAbstractDialogFactory& GetFactory() +{ + static SwAbstractDialogFactory_Impl aFactory; + return aFactory; +} +} + +extern "C" { +SAL_DLLPUBLIC_EXPORT SwAbstractDialogFactory* SwCreateDialogFactory() +{ + return &::swui::GetFactory(); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dialog/uiregionsw.cxx b/sw/source/ui/dialog/uiregionsw.cxx new file mode 100644 index 0000000000..f0318a4caf --- /dev/null +++ b/sw/source/ui/dialog/uiregionsw.cxx @@ -0,0 +1,2145 @@ +/* -*- 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 <regionsw.hxx> +#include <svl/urihelper.hxx> +#include <svl/PasswordHelper.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <sfx2/passwd.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/request.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/linkmgr.hxx> +#include <sfx2/docinsert.hxx> +#include <sfx2/filedlghelper.hxx> +#include <editeng/sizeitem.hxx> +#include <svtools/htmlcfg.hxx> +#include <osl/diagnose.h> +#include <o3tl/string_view.hxx> +#include <comphelper/lok.hxx> + +#include <uitool.hxx> +#include <IMark.hxx> +#include <section.hxx> +#include <docary.hxx> +#include <doc.hxx> +#include <wdocsh.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <column.hxx> +#include <fmtclbl.hxx> +#include <fmtfsize.hxx> +#include <frmatr.hxx> +#include <shellio.hxx> + +#include <cmdid.h> +#include <strings.hrc> +#include <bitmaps.hlst> +#include <sfx2/bindings.hxx> +#include <sfx2/sfxdlg.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/dialogs.hrc> +#include <svx/flagsdef.hxx> +#include <memory> +#include <string_view> + +using namespace ::com::sun::star; + +namespace { + +OUString BuildBitmap(bool bProtect, bool bHidden) +{ + if (bProtect) + return bHidden ? RID_BMP_PROT_HIDE : RID_BMP_PROT_NO_HIDE; + return bHidden ? RID_BMP_HIDE : RID_BMP_NO_HIDE; +} + +OUString CollapseWhiteSpaces(std::u16string_view sName) +{ + const sal_Int32 nLen = sName.size(); + const sal_Unicode cRef = ' '; + OUStringBuffer aBuf(nLen); + for (sal_Int32 i = 0; i<nLen; ) + { + const sal_Unicode cCur = sName[i++]; + aBuf.append(cCur); + if (cCur!=cRef) + continue; + while (i<nLen && sName[i]==cRef) + ++i; + } + return aBuf.makeStringAndClear(); +} + +} + +static void lcl_ReadSections( SfxMedium& rMedium, weld::ComboBox& rBox ); + +static void lcl_FillList( SwWrtShell& rSh, weld::ComboBox& rSubRegions, weld::ComboBox* pAvailNames, const SwSectionFormat* pNewFormat ) +{ + if( !pNewFormat ) + { + const size_t nCount = rSh.GetSectionFormatCount(); + for (size_t i = 0; i<nCount; i++) + { + SectionType eTmpType; + const SwSectionFormat* pFormat = &rSh.GetSectionFormat(i); + if( !pFormat->GetParent() && + pFormat->IsInNodesArr() && + (eTmpType = pFormat->GetSection()->GetType()) != SectionType::ToxContent + && SectionType::ToxHeader != eTmpType ) + { + const OUString sString(pFormat->GetSection()->GetSectionName()); + if (pAvailNames) + pAvailNames->append_text(sString); + rSubRegions.append_text(sString); + lcl_FillList( rSh, rSubRegions, pAvailNames, pFormat ); + } + } + } + else + { + SwSections aTmpArr; + pNewFormat->GetChildSections(aTmpArr, SectionSort::Pos); + if( !aTmpArr.empty() ) + { + SectionType eTmpType; + for( const auto pSect : aTmpArr ) + { + const SwSectionFormat* pFormat = pSect->GetFormat(); + if( pFormat->IsInNodesArr()&& + (eTmpType = pFormat->GetSection()->GetType()) != SectionType::ToxContent + && SectionType::ToxHeader != eTmpType ) + { + const OUString sString(pFormat->GetSection()->GetSectionName()); + if (pAvailNames) + pAvailNames->append_text(sString); + rSubRegions.append_text(sString); + lcl_FillList( rSh, rSubRegions, pAvailNames, pFormat ); + } + } + } + } +} + +static void lcl_FillSubRegionList( SwWrtShell& rSh, weld::ComboBox& rSubRegions, weld::ComboBox* pAvailNames ) +{ + rSubRegions.clear(); + lcl_FillList( rSh, rSubRegions, pAvailNames, nullptr ); + IDocumentMarkAccess* const pMarkAccess = rSh.getIDocumentMarkAccess(); + for( IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getBookmarksBegin(); + ppMark != pMarkAccess->getBookmarksEnd(); + ++ppMark) + { + const ::sw::mark::IMark* pBkmk = *ppMark; + if( pBkmk->IsExpanded() ) + rSubRegions.append_text( pBkmk->GetName() ); + } +} + +// user data class for region information +class SectRepr +{ +private: + SwSectionData m_SectionData; + SwFormatCol m_Col; + std::unique_ptr<SvxBrushItem> m_Brush; + SwFormatFootnoteAtTextEnd m_FootnoteNtAtEnd; + SwFormatEndAtTextEnd m_EndNtAtEnd; + SwFormatNoBalancedColumns m_Balance; + std::shared_ptr<SvxFrameDirectionItem> m_FrameDirItem; + std::shared_ptr<SvxLRSpaceItem> m_LRSpaceItem; + const size_t m_nArrPos; + // shows, if maybe textcontent is in the region + bool m_bContent : 1; + // for multiselection, mark at first, then work with TreeListBox! + bool m_bSelected : 1; + uno::Sequence<sal_Int8> m_TempPasswd; + +public: + SectRepr(size_t nPos, SwSection& rSect); + + SwSectionData & GetSectionData() { return m_SectionData; } + SwFormatCol& GetCol() { return m_Col; } + std::unique_ptr<SvxBrushItem>& GetBackground() { return m_Brush; } + SwFormatFootnoteAtTextEnd& GetFootnoteNtAtEnd() { return m_FootnoteNtAtEnd; } + SwFormatEndAtTextEnd& GetEndNtAtEnd() { return m_EndNtAtEnd; } + SwFormatNoBalancedColumns& GetBalance() { return m_Balance; } + std::shared_ptr<SvxFrameDirectionItem>& GetFrameDir() { return m_FrameDirItem; } + std::shared_ptr<SvxLRSpaceItem>& GetLRSpace() { return m_LRSpaceItem; } + + size_t GetArrPos() const { return m_nArrPos; } + OUString GetFile() const; + OUString GetSubRegion() const; + void SetFile(std::u16string_view rFile); + void SetFilter(std::u16string_view rFilter); + void SetSubRegion(std::u16string_view rSubRegion); + + bool IsContent() const { return m_bContent; } + void SetContent(bool const bValue) { m_bContent = bValue; } + + void SetSelected() { m_bSelected = true; } + bool IsSelected() const { return m_bSelected; } + + uno::Sequence<sal_Int8> & GetTempPasswd() { return m_TempPasswd; } + void SetTempPasswd(const uno::Sequence<sal_Int8> & rPasswd) + { m_TempPasswd = rPasswd; } +}; + +SectRepr::SectRepr( size_t nPos, SwSection& rSect ) + : m_SectionData( rSect ) + , m_Brush(std::make_unique<SvxBrushItem>(RES_BACKGROUND)) + , m_FrameDirItem(std::make_shared<SvxFrameDirectionItem>(SvxFrameDirection::Environment, RES_FRAMEDIR)) + , m_LRSpaceItem(std::make_shared<SvxLRSpaceItem>(RES_LR_SPACE)) + , m_nArrPos(nPos) + , m_bContent(m_SectionData.GetLinkFileName().isEmpty()) + , m_bSelected(false) +{ + SwSectionFormat *pFormat = rSect.GetFormat(); + if( pFormat ) + { + m_Col = pFormat->GetCol(); + m_Brush = pFormat->makeBackgroundBrushItem(); + m_FootnoteNtAtEnd = pFormat->GetFootnoteAtTextEnd(); + m_EndNtAtEnd = pFormat->GetEndAtTextEnd(); + m_Balance.SetValue(pFormat->GetBalancedColumns().GetValue()); + m_FrameDirItem.reset(pFormat->GetFrameDir().Clone()); + m_LRSpaceItem.reset(pFormat->GetLRSpace().Clone()); + } +} + +void SectRepr::SetFile( std::u16string_view rFile ) +{ + OUString sNewFile( INetURLObject::decode( rFile, + INetURLObject::DecodeMechanism::Unambiguous )); + const OUString sOldFileName( m_SectionData.GetLinkFileName() ); + const std::u16string_view sSub( o3tl::getToken(sOldFileName, 2, sfx2::cTokenSeparator ) ); + + if( !rFile.empty() || !sSub.empty() ) + { + sNewFile += OUStringChar(sfx2::cTokenSeparator); + if( !rFile.empty() ) // Filter only with FileName + sNewFile += o3tl::getToken(sOldFileName, 1, sfx2::cTokenSeparator ); + + sNewFile += OUStringChar(sfx2::cTokenSeparator) + sSub; + } + + m_SectionData.SetLinkFileName( sNewFile ); + + if( !rFile.empty() || !sSub.empty() ) + { + m_SectionData.SetType( SectionType::FileLink ); + } + else + { + m_SectionData.SetType( SectionType::Content ); + } +} + +void SectRepr::SetFilter( std::u16string_view rFilter ) +{ + OUString sNewFile; + const OUString sOldFileName( m_SectionData.GetLinkFileName() ); + sal_Int32 nIdx{ 0 }; + const std::u16string_view sFile( o3tl::getToken(sOldFileName, 0, sfx2::cTokenSeparator, nIdx ) ); // token 0 + const std::u16string_view sSub( o3tl::getToken(sOldFileName, 1, sfx2::cTokenSeparator, nIdx ) ); // token 2 + + if( !sFile.empty() ) + sNewFile = sFile + OUStringChar(sfx2::cTokenSeparator) + + rFilter + OUStringChar(sfx2::cTokenSeparator) + sSub; + else if( !sSub.empty() ) + sNewFile = OUStringChar(sfx2::cTokenSeparator) + OUStringChar(sfx2::cTokenSeparator) + sSub; + + m_SectionData.SetLinkFileName( sNewFile ); + + if( !sNewFile.isEmpty() ) + { + m_SectionData.SetType( SectionType::FileLink ); + } +} + +void SectRepr::SetSubRegion(std::u16string_view rSubRegion) +{ + OUString sNewFile; + sal_Int32 n(0); + const OUString sLinkFileName(m_SectionData.GetLinkFileName()); + const std::u16string_view sOldFileName( o3tl::getToken(sLinkFileName, 0, sfx2::cTokenSeparator, n ) ); + const std::u16string_view sFilter( o3tl::getToken(sLinkFileName, 0, sfx2::cTokenSeparator, n ) ); + + if( !rSubRegion.empty() || !sOldFileName.empty() ) + sNewFile = sOldFileName + OUStringChar(sfx2::cTokenSeparator) + + sFilter + OUStringChar(sfx2::cTokenSeparator) + rSubRegion; + + m_SectionData.SetLinkFileName( sNewFile ); + + if( !rSubRegion.empty() || !sOldFileName.empty() ) + { + m_SectionData.SetType( SectionType::FileLink ); + } + else + { + m_SectionData.SetType( SectionType::Content ); + } +} + +OUString SectRepr::GetFile() const +{ + const OUString sLinkFile( m_SectionData.GetLinkFileName() ); + + if( sLinkFile.isEmpty() ) + { + return sLinkFile; + } + if (SectionType::DdeLink == m_SectionData.GetType()) + { + sal_Int32 n = 0; + return sLinkFile.replaceFirst( OUStringChar(sfx2::cTokenSeparator), " ", &n ) + .replaceFirst( OUStringChar(sfx2::cTokenSeparator), " ", &n ); + } + return INetURLObject::decode( o3tl::getToken(sLinkFile, 0, sfx2::cTokenSeparator ), + INetURLObject::DecodeMechanism::Unambiguous ); +} + +OUString SectRepr::GetSubRegion() const +{ + const OUString sLinkFile( m_SectionData.GetLinkFileName() ); + if( !sLinkFile.isEmpty() ) + return sLinkFile.getToken( 2, sfx2::cTokenSeparator ); + return sLinkFile; +} + +// dialog edit regions +SwEditRegionDlg::SwEditRegionDlg(weld::Window* pParent, SwWrtShell& rWrtSh) + : SfxDialogController(pParent, "modules/swriter/ui/editsectiondialog.ui", + "EditSectionDialog") + , m_bSubRegionsFilled(false) + , m_rSh(rWrtSh) + , m_bDontCheckPasswd(true) + , m_xCurName(m_xBuilder->weld_entry("curname")) + , m_xTree(m_xBuilder->weld_tree_view("tree")) + , m_xFileCB(m_xBuilder->weld_check_button("link")) + , m_xDDECB(m_xBuilder->weld_check_button("dde")) + , m_xDDEFrame(m_xBuilder->weld_widget("ddedepend")) + , m_xFileNameFT(m_xBuilder->weld_label("filenameft")) + , m_xDDECommandFT(m_xBuilder->weld_label("ddeft")) + , m_xFileNameED(m_xBuilder->weld_entry("filename")) + , m_xFilePB(m_xBuilder->weld_button("file")) + , m_xSubRegionFT(m_xBuilder->weld_label("sectionft")) + , m_xSubRegionED(m_xBuilder->weld_combo_box("section")) + , m_xProtectCB(m_xBuilder->weld_check_button("protect")) + , m_xPasswdCB(m_xBuilder->weld_check_button("withpassword")) + , m_xPasswdPB(m_xBuilder->weld_button("password")) + , m_xHideCB(m_xBuilder->weld_check_button("hide")) + , m_xConditionFT(m_xBuilder->weld_label("conditionft")) + , m_xConditionED(new ConditionEdit(m_xBuilder->weld_entry("condition"))) + , m_xEditInReadonlyCB(m_xBuilder->weld_check_button("editinro")) + , m_xOK(m_xBuilder->weld_button("ok")) + , m_xOptionsPB(m_xBuilder->weld_button("options")) + , m_xDismiss(m_xBuilder->weld_button("remove")) + , m_xHideFrame(m_xBuilder->weld_widget("hideframe")) +{ + m_xTree->set_size_request(-1, m_xTree->get_height_rows(16)); + m_xFileCB->set_state(TRISTATE_FALSE); + m_xSubRegionED->make_sorted(); + m_xProtectCB->set_state(TRISTATE_FALSE); + m_xHideCB->set_state(TRISTATE_FALSE); + // edit in readonly sections + m_xEditInReadonlyCB->set_state(TRISTATE_FALSE); + + bool bWeb = dynamic_cast<SwWebDocShell*>( m_rSh.GetView().GetDocShell() ) != nullptr; + + m_xTree->connect_changed(LINK(this, SwEditRegionDlg, GetFirstEntryHdl)); + m_xCurName->connect_changed(LINK(this, SwEditRegionDlg, NameEditHdl)); + m_xConditionED->connect_changed( LINK( this, SwEditRegionDlg, ConditionEditHdl)); + m_xOK->connect_clicked( LINK( this, SwEditRegionDlg, OkHdl)); + m_xPasswdCB->connect_toggled(LINK(this, SwEditRegionDlg, TogglePasswdHdl)); + m_xPasswdPB->connect_clicked(LINK(this, SwEditRegionDlg, ChangePasswdHdl)); + m_xHideCB->connect_toggled(LINK(this, SwEditRegionDlg, ChangeHideHdl)); + // edit in readonly sections + m_xEditInReadonlyCB->connect_toggled(LINK(this, SwEditRegionDlg, ChangeEditInReadonlyHdl)); + + m_xOptionsPB->connect_clicked(LINK(this, SwEditRegionDlg, OptionsHdl)); + m_xProtectCB->connect_toggled(LINK(this, SwEditRegionDlg, ChangeProtectHdl)); + m_xDismiss->connect_clicked( LINK( this, SwEditRegionDlg, ChangeDismissHdl)); + m_xFileCB->connect_toggled(LINK(this, SwEditRegionDlg, UseFileHdl)); + m_xFilePB->connect_clicked(LINK(this, SwEditRegionDlg, FileSearchHdl)); + m_xFileNameED->connect_changed(LINK(this, SwEditRegionDlg, FileNameEntryHdl)); + m_xSubRegionED->connect_changed(LINK(this, SwEditRegionDlg, FileNameComboBoxHdl)); + m_xSubRegionED->connect_popup_toggled(LINK(this, SwEditRegionDlg, SubRegionEventHdl)); + m_xSubRegionED->set_entry_completion(true, true); + + m_xTree->set_selection_mode(SelectionMode::Multiple); + + if (bWeb) + { + m_xDDECB->hide(); + m_xHideFrame->hide(); + m_xPasswdCB->hide(); + } + + m_xDDECB->connect_toggled(LINK(this, SwEditRegionDlg, DDEHdl)); + + m_pCurrSect = m_rSh.GetCurrSection(); + RecurseList( nullptr, nullptr ); + + // if the cursor is not in a region the first one will always be selected + if (!m_xTree->get_selected(nullptr)) + { + std::unique_ptr<weld::TreeIter> xIter(m_xTree->make_iterator()); + if (m_xTree->get_iter_first(*xIter)) + { + m_xTree->select(*xIter); + GetFirstEntryHdl(*m_xTree); + } + } + + m_xTree->show(); + m_bDontCheckPasswd = false; + + if(comphelper::LibreOfficeKit::isActive()) + { + m_xDDECB->hide(); + m_xDDECommandFT->hide(); + m_xFileNameFT->hide(); + m_xFileNameED->hide(); + m_xFilePB->hide(); + } +} + +bool SwEditRegionDlg::CheckPasswd(weld::Toggleable* pBox) +{ + if (m_bDontCheckPasswd) + return true; + bool bRet = true; + + m_xTree->selected_foreach([this, &bRet](weld::TreeIter& rEntry){ + SectRepr* pRepr = weld::fromId<SectRepr*>(m_xTree->get_id(rEntry)); + if (!pRepr->GetTempPasswd().hasElements() + && pRepr->GetSectionData().GetPassword().hasElements()) + { + SfxPasswordDialog aPasswdDlg(m_xDialog.get()); + bRet = false; + if (aPasswdDlg.run()) + { + const OUString sNewPasswd(aPasswdDlg.GetPassword()); + css::uno::Sequence <sal_Int8 > aNewPasswd; + SvPasswordHelper::GetHashPassword( aNewPasswd, sNewPasswd ); + if (SvPasswordHelper::CompareHashPassword( + pRepr->GetSectionData().GetPassword(), sNewPasswd)) + { + pRepr->SetTempPasswd(aNewPasswd); + bRet = true; + } + else + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_WRONG_PASSWORD))); + xInfoBox->run(); + } + } + } + return false; + }); + if (!bRet && pBox) + { + //reset old button state + if (pBox->get_state() != TRISTATE_INDET) + pBox->set_active(!pBox->get_active()); + } + + return bRet; +} + +// recursively look for child-sections +void SwEditRegionDlg::RecurseList(const SwSectionFormat* pFormat, const weld::TreeIter* pEntry) +{ + std::unique_ptr<weld::TreeIter> xIter(m_xTree->make_iterator()); + if (!pFormat) + { + const size_t nCount=m_rSh.GetSectionFormatCount(); + for ( size_t n = 0; n < nCount; n++ ) + { + SectionType eTmpType; + if( !( pFormat = &m_rSh.GetSectionFormat(n))->GetParent() && + pFormat->IsInNodesArr() && + (eTmpType = pFormat->GetSection()->GetType()) != SectionType::ToxContent + && SectionType::ToxHeader != eTmpType ) + { + SwSection *pSect = pFormat->GetSection(); + SectRepr* pSectRepr = new SectRepr( n, *pSect ); + + OUString sText(pSect->GetSectionName()); + OUString sImage(BuildBitmap(pSect->IsProtect(),pSect->IsHidden())); + OUString sId(weld::toId(pSectRepr)); + m_xTree->insert(nullptr, -1, &sText, &sId, nullptr, nullptr, false, xIter.get()); + m_xTree->set_image(*xIter, sImage); + + RecurseList(pFormat, xIter.get()); + if (m_xTree->iter_has_child(*xIter)) + m_xTree->expand_row(*xIter); + if (m_pCurrSect==pSect) + { + m_xTree->select(*xIter); + m_xTree->scroll_to_row(*xIter); + GetFirstEntryHdl(*m_xTree); + } + } + } + } + else + { + SwSections aTmpArr; + pFormat->GetChildSections(aTmpArr, SectionSort::Pos); + for( const auto pSect : aTmpArr ) + { + SectionType eTmpType; + pFormat = pSect->GetFormat(); + if( pFormat->IsInNodesArr() && + (eTmpType = pFormat->GetSection()->GetType()) != SectionType::ToxContent + && SectionType::ToxHeader != eTmpType ) + { + SectRepr* pSectRepr=new SectRepr( + FindArrPos( pSect->GetFormat() ), *pSect ); + + OUString sText(pSect->GetSectionName()); + OUString sImage = BuildBitmap(pSect->IsProtect(), pSect->IsHidden()); + OUString sId(weld::toId(pSectRepr)); + m_xTree->insert(pEntry, -1, &sText, &sId, nullptr, nullptr, false, xIter.get()); + m_xTree->set_image(*xIter, sImage); + + RecurseList(pSect->GetFormat(), xIter.get()); + if (m_xTree->iter_has_child(*xIter)) + m_xTree->expand_row(*xIter); + if (m_pCurrSect==pSect) + { + m_xTree->select(*xIter); + m_xTree->scroll_to_row(*xIter); + GetFirstEntryHdl(*m_xTree); + } + } + } + } +} + +size_t SwEditRegionDlg::FindArrPos(const SwSectionFormat* pFormat ) +{ + const size_t nCount=m_rSh.GetSectionFormatCount(); + for ( size_t i = 0; i < nCount; i++ ) + if ( pFormat == &m_rSh.GetSectionFormat(i) ) + return i; + + OSL_FAIL("SectionFormat not on the list" ); + return SIZE_MAX; +} + +SwEditRegionDlg::~SwEditRegionDlg( ) +{ + std::unique_ptr<weld::TreeIter> xIter(m_xTree->make_iterator()); + if (m_xTree->get_iter_first(*xIter)) + { + do + { + delete weld::fromId<SectRepr*>(m_xTree->get_id(*xIter)); + } while (m_xTree->iter_next(*xIter)); + } +} + +void SwEditRegionDlg::SelectSection(std::u16string_view rSectionName) +{ + std::unique_ptr<weld::TreeIter> xIter(m_xTree->make_iterator()); + if (!m_xTree->get_iter_first(*xIter)) + return; + + do + { + SectRepr* pRepr = weld::fromId<SectRepr*>(m_xTree->get_id(*xIter)); + if (pRepr->GetSectionData().GetSectionName() == rSectionName) + { + m_xTree->unselect_all(); + m_xTree->select(*xIter); + m_xTree->scroll_to_row(*xIter); + GetFirstEntryHdl(*m_xTree); + break; + } + } while (m_xTree->iter_next(*xIter)); +} + +// selected entry in TreeListBox is showed in Edit window in case of +// multiselection some controls are disabled +IMPL_LINK(SwEditRegionDlg, GetFirstEntryHdl, weld::TreeView&, rBox, void) +{ + m_bDontCheckPasswd = true; + std::unique_ptr<weld::TreeIter> xIter(rBox.make_iterator()); + bool bEntry = rBox.get_selected(xIter.get()); + m_xHideCB->set_sensitive(true); + // edit in readonly sections + m_xEditInReadonlyCB->set_sensitive(true); + + m_xProtectCB->set_sensitive(true); + m_xFileCB->set_sensitive(true); + css::uno::Sequence <sal_Int8> aCurPasswd; + if (1 < rBox.count_selected_rows()) + { + m_xHideCB->set_state(TRISTATE_INDET); + m_xProtectCB->set_state(TRISTATE_INDET); + // edit in readonly sections + m_xEditInReadonlyCB->set_state(TRISTATE_INDET); + m_xFileCB->set_state(TRISTATE_INDET); + + bool bHiddenValid = true; + bool bProtectValid = true; + bool bConditionValid = true; + // edit in readonly sections + bool bEditInReadonlyValid = true; + bool bEditInReadonly = true; + + bool bHidden = true; + bool bProtect = true; + OUString sCondition; + bool bFirst = true; + bool bFileValid = true; + bool bFile = true; + bool bPasswdValid = true; + + m_xTree->selected_foreach([&](weld::TreeIter& rEntry){ + SectRepr* pRepr = weld::fromId<SectRepr*>(m_xTree->get_id(rEntry)); + SwSectionData const& rData( pRepr->GetSectionData() ); + if(bFirst) + { + sCondition = rData.GetCondition(); + bHidden = rData.IsHidden(); + bProtect = rData.IsProtectFlag(); + // edit in readonly sections + bEditInReadonly = rData.IsEditInReadonlyFlag(); + + bFile = (rData.GetType() != SectionType::Content); + aCurPasswd = rData.GetPassword(); + } + else + { + if(sCondition != rData.GetCondition()) + bConditionValid = false; + bHiddenValid = (bHidden == rData.IsHidden()); + bProtectValid = (bProtect == rData.IsProtectFlag()); + // edit in readonly sections + bEditInReadonlyValid = + (bEditInReadonly == rData.IsEditInReadonlyFlag()); + + bFileValid = (bFile == + (rData.GetType() != SectionType::Content)); + bPasswdValid = (aCurPasswd == rData.GetPassword()); + } + bFirst = false; + return false; + }); + + m_xHideCB->set_state(!bHiddenValid ? TRISTATE_INDET : + bHidden ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xProtectCB->set_state(!bProtectValid ? TRISTATE_INDET : + bProtect ? TRISTATE_TRUE : TRISTATE_FALSE); + // edit in readonly sections + m_xEditInReadonlyCB->set_state(!bEditInReadonlyValid ? TRISTATE_INDET : + bEditInReadonly ? TRISTATE_TRUE : TRISTATE_FALSE); + + m_xFileCB->set_state(!bFileValid ? TRISTATE_INDET : + bFile ? TRISTATE_TRUE : TRISTATE_FALSE); + + if (bConditionValid) + m_xConditionED->set_text(sCondition); + else + { + m_xConditionFT->set_sensitive(false); + m_xConditionED->set_sensitive(false); + } + + m_xCurName->set_sensitive(false); + m_xDDECB->set_sensitive(false); + m_xDDEFrame->set_sensitive(false); + m_xOptionsPB->set_sensitive(false); + bool bPasswdEnabled = m_xProtectCB->get_state() == TRISTATE_TRUE; + m_xPasswdCB->set_sensitive(bPasswdEnabled); + m_xPasswdPB->set_sensitive(bPasswdEnabled); + if(!bPasswdValid) + { + rBox.get_selected(xIter.get()); + rBox.unselect_all(); + rBox.select(*xIter); + GetFirstEntryHdl(rBox); + return; + } + else + m_xPasswdCB->set_active(aCurPasswd.hasElements()); + } + else if (bEntry ) + { + m_xCurName->set_sensitive(true); + m_xOptionsPB->set_sensitive(true); + SectRepr* pRepr = weld::fromId<SectRepr*>(m_xTree->get_id(*xIter)); + SwSectionData const& rData( pRepr->GetSectionData() ); + m_xConditionED->set_text(rData.GetCondition()); + m_xHideCB->set_sensitive(true); + m_xHideCB->set_state((rData.IsHidden()) ? TRISTATE_TRUE : TRISTATE_FALSE); + bool bHide = TRISTATE_TRUE == m_xHideCB->get_state(); + m_xConditionED->set_sensitive(bHide); + m_xConditionFT->set_sensitive(bHide); + m_xPasswdCB->set_active(rData.GetPassword().hasElements()); + + m_xOK->set_sensitive(true); + m_xPasswdCB->set_sensitive(true); + m_xCurName->set_text(rBox.get_text(*xIter)); + m_xCurName->set_sensitive(true); + m_xDismiss->set_sensitive(true); + const OUString aFile = pRepr->GetFile(); + const OUString sSub = pRepr->GetSubRegion(); + m_xSubRegionED->clear(); + m_xSubRegionED->append_text(""); // put in a dummy entry, which is replaced when m_bSubRegionsFilled is set + m_bSubRegionsFilled = false; + if( !aFile.isEmpty() || !sSub.isEmpty() ) + { + m_xFileCB->set_active(true); + m_xFileNameED->set_text(aFile); + m_xSubRegionED->set_entry_text(sSub); + m_xDDECB->set_active(rData.GetType() == SectionType::DdeLink); + } + else + { + m_xFileCB->set_active(false); + m_xFileNameED->set_text(aFile); + m_xDDECB->set_sensitive(false); + m_xDDECB->set_active(false); + } + UseFileHdl(*m_xFileCB); + DDEHdl(*m_xDDECB); + m_xProtectCB->set_state((rData.IsProtectFlag()) + ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xProtectCB->set_sensitive(true); + + // edit in readonly sections + m_xEditInReadonlyCB->set_state((rData.IsEditInReadonlyFlag()) + ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xEditInReadonlyCB->set_sensitive(true); + + bool bPasswdEnabled = m_xProtectCB->get_active(); + m_xPasswdCB->set_sensitive(bPasswdEnabled); + m_xPasswdPB->set_sensitive(bPasswdEnabled); + } + m_bDontCheckPasswd = false; +} + +// in OkHdl the modified settings are being applied and reversed regions are deleted +IMPL_LINK_NOARG(SwEditRegionDlg, OkHdl, weld::Button&, void) +{ + // temp. Array because during changing of a region the position + // inside of the "Core-Arrays" can be shifted: + // - at linked regions, when they have more SubRegions or get + // new ones. + // StartUndo must certainly also happen not before the formats + // are copied (ClearRedo!) + + const SwSectionFormats& rDocFormats = m_rSh.GetDoc()->GetSections(); + SwSectionFormats aOrigArray(rDocFormats); + + m_rSh.StartAllAction(); + m_rSh.StartUndo(); + m_rSh.ResetSelect( nullptr,false ); + + std::unique_ptr<weld::TreeIter> xIter(m_xTree->make_iterator()); + if (m_xTree->get_iter_first(*xIter)) + { + do + { + SectRepr* pRepr = weld::fromId<SectRepr*>(m_xTree->get_id(*xIter)); + SwSectionFormat* pFormat = aOrigArray[ pRepr->GetArrPos() ]; + if (!pRepr->GetSectionData().IsProtectFlag()) + { + pRepr->GetSectionData().SetPassword(uno::Sequence<sal_Int8 >()); + } + size_t nNewPos = rDocFormats.GetPos(pFormat); + if ( SIZE_MAX != nNewPos ) + { + SwAttrSet aSet(pFormat->GetAttrSet().CloneAsValue( false )); + if( pFormat->GetCol() != pRepr->GetCol() ) + aSet.Put( pRepr->GetCol() ); + + std::unique_ptr<SvxBrushItem> aBrush(pFormat->makeBackgroundBrushItem(false)); + if( pRepr->GetBackground() && *aBrush != *pRepr->GetBackground() ) + aSet.Put( *pRepr->GetBackground() ); + + if( pFormat->GetFootnoteAtTextEnd(false) != pRepr->GetFootnoteNtAtEnd() ) + aSet.Put( pRepr->GetFootnoteNtAtEnd() ); + + if( pFormat->GetEndAtTextEnd(false) != pRepr->GetEndNtAtEnd() ) + aSet.Put( pRepr->GetEndNtAtEnd() ); + + if( pFormat->GetBalancedColumns() != pRepr->GetBalance() ) + aSet.Put( pRepr->GetBalance() ); + + if( pFormat->GetFrameDir() != *pRepr->GetFrameDir() ) + aSet.Put( *pRepr->GetFrameDir() ); + + if( pFormat->GetLRSpace() != *pRepr->GetLRSpace()) + aSet.Put( *pRepr->GetLRSpace()); + + m_rSh.UpdateSection( nNewPos, pRepr->GetSectionData(), + aSet.Count() ? &aSet : nullptr ); + } + } while (m_xTree->iter_next(*xIter)); + } + + for (SectReprs_t::reverse_iterator it = m_SectReprs.rbegin(), aEnd = m_SectReprs.rend(); it != aEnd; ++it) + { + assert(it->first == it->second->GetArrPos()); + SwSectionFormat* pFormat = aOrigArray[ it->second->GetArrPos() ]; + const size_t nNewPos = rDocFormats.GetPos( pFormat ); + if( SIZE_MAX != nNewPos ) + m_rSh.DelSectionFormat( nNewPos ); + } + + aOrigArray.clear(); + + // response must be called ahead of EndAction's end, + // otherwise ScrollError can occur. + m_xDialog->response(RET_OK); + + m_rSh.EndUndo(); + m_rSh.EndAllAction(); +} + +// Toggle protect +IMPL_LINK(SwEditRegionDlg, ChangeProtectHdl, weld::Toggleable&, rButton, void) +{ + if (!CheckPasswd(&rButton)) + return; + bool bCheck = TRISTATE_TRUE == rButton.get_state(); + m_xTree->selected_foreach([this, bCheck](weld::TreeIter& rEntry){ + SectRepr* pRepr = weld::fromId<SectRepr*>(m_xTree->get_id(rEntry)); + pRepr->GetSectionData().SetProtectFlag(bCheck); + OUString aImage = BuildBitmap(bCheck, TRISTATE_TRUE == m_xHideCB->get_state()); + m_xTree->set_image(rEntry, aImage); + return false; + }); + m_xPasswdCB->set_sensitive(bCheck); + m_xPasswdPB->set_sensitive(bCheck); +} + +// Toggle hide +IMPL_LINK( SwEditRegionDlg, ChangeHideHdl, weld::Toggleable&, rButton, void) +{ + if (!CheckPasswd(&rButton)) + return; + m_xTree->selected_foreach([this, &rButton](weld::TreeIter& rEntry){ + SectRepr* pRepr = weld::fromId<SectRepr*>(m_xTree->get_id(rEntry)); + pRepr->GetSectionData().SetHidden(TRISTATE_TRUE == rButton.get_state()); + OUString aImage = BuildBitmap(TRISTATE_TRUE == m_xProtectCB->get_state(), + TRISTATE_TRUE == rButton.get_state()); + m_xTree->set_image(rEntry, aImage); + return false; + }); + bool bHide = TRISTATE_TRUE == rButton.get_state(); + m_xConditionED->set_sensitive(bHide); + m_xConditionFT->set_sensitive(bHide); +} + +// Toggle edit in readonly +IMPL_LINK(SwEditRegionDlg, ChangeEditInReadonlyHdl, weld::Toggleable&, rButton, void) +{ + if (!CheckPasswd(&rButton)) + return; + m_xTree->selected_foreach([this, &rButton](weld::TreeIter& rEntry){ + SectRepr* pRepr = weld::fromId<SectRepr*>(m_xTree->get_id(rEntry)); + pRepr->GetSectionData().SetEditInReadonlyFlag( + TRISTATE_TRUE == rButton.get_state()); + return false; + }); +} + +// clear selected region +IMPL_LINK_NOARG(SwEditRegionDlg, ChangeDismissHdl, weld::Button&, void) +{ + if(!CheckPasswd()) + return; + // at first mark all selected + m_xTree->selected_foreach([this](weld::TreeIter& rEntry){ + SectRepr* const pSectRepr = weld::fromId<SectRepr*>(m_xTree->get_id(rEntry)); + pSectRepr->SetSelected(); + return false; + }); + + std::unique_ptr<weld::TreeIter> xEntry(m_xTree->make_iterator()); + bool bEntry(m_xTree->get_selected(xEntry.get())); + // then delete + while (bEntry) + { + SectRepr* const pSectRepr = weld::fromId<SectRepr*>(m_xTree->get_id(*xEntry)); + std::unique_ptr<weld::TreeIter> xRemove; + bool bRestart = false; + if (pSectRepr->IsSelected()) + { + m_SectReprs.insert(std::make_pair(pSectRepr->GetArrPos(), + std::unique_ptr<SectRepr>(pSectRepr))); + if (m_xTree->iter_has_child(*xEntry)) + { + std::unique_ptr<weld::TreeIter> xChild(m_xTree->make_iterator(xEntry.get())); + (void)m_xTree->iter_children(*xChild); + std::unique_ptr<weld::TreeIter> xParent(m_xTree->make_iterator(xEntry.get())); + if (!m_xTree->iter_parent(*xParent)) + xParent.reset(); + bool bChild = true; + do + { + // because of the repositioning we have to start at the beginning again + bRestart = true; + std::unique_ptr<weld::TreeIter> xMove(m_xTree->make_iterator(xChild.get())); + bChild = m_xTree->iter_next_sibling(*xChild); + m_xTree->move_subtree(*xMove, xParent.get(), m_xTree->get_iter_index_in_parent(*xEntry)); + } while (bChild); + } + xRemove = m_xTree->make_iterator(xEntry.get()); + } + if (bRestart) + bEntry = m_xTree->get_iter_first(*xEntry); + else + bEntry = m_xTree->iter_next(*xEntry); + if (xRemove) + m_xTree->remove(*xRemove); + } + + if (m_xTree->get_selected(nullptr)) + return; + + m_xConditionFT->set_sensitive(false); + m_xConditionED->set_sensitive(false); + m_xDismiss->set_sensitive(false); + m_xCurName->set_sensitive(false); + m_xProtectCB->set_sensitive(false); + m_xPasswdCB->set_sensitive(false); + m_xHideCB->set_sensitive(false); + // edit in readonly sections + m_xEditInReadonlyCB->set_sensitive(false); + m_xEditInReadonlyCB->set_state(TRISTATE_FALSE); + m_xProtectCB->set_state(TRISTATE_FALSE); + m_xPasswdCB->set_active(false); + m_xHideCB->set_state(TRISTATE_FALSE); + m_xFileCB->set_active(false); + // otherwise the focus would be on HelpButton + m_xOK->grab_focus(); + UseFileHdl(*m_xFileCB); +} + +// link CheckBox to file? +IMPL_LINK(SwEditRegionDlg, UseFileHdl, weld::Toggleable&, rButton, void) +{ + if (!CheckPasswd(&rButton)) + return; + bool bMulti = 1 < m_xTree->count_selected_rows(); + bool bFile = rButton.get_active(); + if (m_xTree->get_selected(nullptr)) + { + m_xTree->selected_foreach([&](weld::TreeIter& rEntry){ + SectRepr* const pSectRepr = weld::fromId<SectRepr*>(m_xTree->get_id(rEntry)); + bool bContent = pSectRepr->IsContent(); + if( rButton.get_active() && bContent && m_rSh.HasSelection() ) + { + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Question, VclButtonsType::YesNo, + SwResId(STR_QUERY_CONNECT))); + if (RET_NO == xQueryBox->run()) + rButton.set_active( false ); + } + if( bFile ) + pSectRepr->SetContent(false); + else + { + pSectRepr->SetFile(u""); + pSectRepr->SetSubRegion(std::u16string_view()); + pSectRepr->GetSectionData().SetLinkFilePassword(OUString()); + } + return false; + }); + m_xDDECB->set_sensitive(bFile && !bMulti); + m_xDDEFrame->set_sensitive(bFile && !bMulti); + if( bFile ) + { + m_xProtectCB->set_state(TRISTATE_TRUE); + m_xFileNameED->grab_focus(); + + } + else + { + m_xDDECB->set_active(false); + m_xSubRegionED->set_entry_text(OUString()); + } + DDEHdl(*m_xDDECB); + } + else + { + rButton.set_active(false); + rButton.set_sensitive(false); + m_xDDECB->set_active(false); + m_xDDECB->set_sensitive(false); + m_xDDEFrame->set_sensitive(false); + } +} + +// call dialog paste file +IMPL_LINK_NOARG(SwEditRegionDlg, FileSearchHdl, weld::Button&, void) +{ + if(!CheckPasswd()) + return; + m_pDocInserter.reset(new ::sfx2::DocumentInserter(m_xDialog.get(), "swriter")); + m_pDocInserter->StartExecuteModal( LINK( this, SwEditRegionDlg, DlgClosedHdl ) ); +} + +IMPL_LINK_NOARG(SwEditRegionDlg, OptionsHdl, weld::Button&, void) +{ + if(!CheckPasswd()) + return; + SectRepr* pSectRepr = weld::fromId<SectRepr*>(m_xTree->get_selected_id()); + if (!pSectRepr) + return; + + SfxItemSetFixed< + RES_FRM_SIZE, RES_FRM_SIZE, + RES_LR_SPACE, RES_LR_SPACE, + RES_BACKGROUND, RES_BACKGROUND, + RES_COL, RES_COL, + RES_FTN_AT_TXTEND, RES_FRAMEDIR, + XATTR_FILL_FIRST, XATTR_FILL_LAST, + SID_ATTR_PAGE_SIZE, SID_ATTR_PAGE_SIZE> aSet( m_rSh.GetView().GetPool() ); + + aSet.Put( pSectRepr->GetCol() ); + aSet.Put( *pSectRepr->GetBackground() ); + aSet.Put( pSectRepr->GetFootnoteNtAtEnd() ); + aSet.Put( pSectRepr->GetEndNtAtEnd() ); + aSet.Put( pSectRepr->GetBalance() ); + aSet.Put( *pSectRepr->GetFrameDir() ); + aSet.Put( *pSectRepr->GetLRSpace() ); + + const SwSectionFormats& rDocFormats = m_rSh.GetDoc()->GetSections(); + SwSectionFormats aOrigArray(rDocFormats); + + SwSectionFormat* pFormat = aOrigArray[pSectRepr->GetArrPos()]; + tools::Long nWidth = m_rSh.GetSectionWidth(*pFormat); + aOrigArray.clear(); + if (!nWidth) + nWidth = USHRT_MAX; + + aSet.Put(SwFormatFrameSize(SwFrameSize::Variable, nWidth)); + aSet.Put(SvxSizeItem(SID_ATTR_PAGE_SIZE, Size(nWidth, nWidth))); + + auto pDlg = std::make_shared<SwSectionPropertyTabDialog>(m_xDialog.get(), aSet, m_rSh); + SfxTabDialogController::runAsync(pDlg, [pDlg, this](sal_Int32 nResult){ + if (nResult == RET_OK) { + const SfxItemSet* pOutSet = pDlg->GetOutputItemSet(); + if( !(pOutSet && pOutSet->Count()) ) + return; + + const SwFormatCol* pColItem = pOutSet->GetItemIfSet( + RES_COL, false ); + const SvxBrushItem* pBrushItem = pOutSet->GetItemIfSet( + RES_BACKGROUND, false ); + const SwFormatFootnoteAtTextEnd* pFootnoteItem = pOutSet->GetItemIfSet( + RES_FTN_AT_TXTEND, false ); + const SwFormatEndAtTextEnd* pEndItem = pOutSet->GetItemIfSet( + RES_END_AT_TXTEND, false ); + const SwFormatNoBalancedColumns* pBalanceItem = pOutSet->GetItemIfSet( + RES_COLUMNBALANCE, false ); + const SvxFrameDirectionItem* pFrameDirItem = pOutSet->GetItemIfSet( + RES_FRAMEDIR, false ); + const SvxLRSpaceItem* pLRSpaceItem = pOutSet->GetItemIfSet( + RES_LR_SPACE, false ); + + if( !(pColItem || + pBrushItem || + pFootnoteItem || + pEndItem || + pBalanceItem || + pFrameDirItem || + pLRSpaceItem) ) + return; + + m_xTree->selected_foreach([&](weld::TreeIter& rEntry) + { + SectRepr* pRepr = weld::fromId<SectRepr*>(m_xTree->get_id(rEntry)); + if (pColItem) + pRepr->GetCol() = *pColItem; + if (pBrushItem) + pRepr->GetBackground().reset(pBrushItem->Clone()); + if (pFootnoteItem) + pRepr->GetFootnoteNtAtEnd() = *pFootnoteItem; + if (pEndItem) + pRepr->GetEndNtAtEnd() = *pEndItem; + if (pBalanceItem) + pRepr->GetBalance().SetValue(pBalanceItem->GetValue()); + if (pFrameDirItem) + pRepr->GetFrameDir()->SetValue(pFrameDirItem->GetValue()); + if (pLRSpaceItem) + pRepr->GetLRSpace().reset(pLRSpaceItem->Clone()); + return false; + }); + } + }); + +} + +IMPL_LINK(SwEditRegionDlg, FileNameComboBoxHdl, weld::ComboBox&, rEdit, void) +{ + int nStartPos, nEndPos; + rEdit.get_entry_selection_bounds(nStartPos, nEndPos); + if (!CheckPasswd()) + return; + rEdit.select_entry_region(nStartPos, nEndPos); + SectRepr* pSectRepr = weld::fromId<SectRepr*>(m_xTree->get_selected_id()); + pSectRepr->SetSubRegion( rEdit.get_active_text() ); +} + +// Applying of the filename or the linked region +IMPL_LINK(SwEditRegionDlg, FileNameEntryHdl, weld::Entry&, rEdit, void) +{ + int nStartPos, nEndPos; + rEdit.get_selection_bounds(nStartPos, nEndPos); + if (!CheckPasswd()) + return; + rEdit.select_region(nStartPos, nEndPos); + SectRepr* pSectRepr = weld::fromId<SectRepr*>(m_xTree->get_selected_id()); + m_xSubRegionED->clear(); + m_xSubRegionED->append_text(""); // put in a dummy entry, which is replaced when m_bSubRegionsFilled is set + m_bSubRegionsFilled = false; + if (m_xDDECB->get_active()) + { + OUString sLink( CollapseWhiteSpaces(rEdit.get_text()) ); + sal_Int32 nPos = 0; + sLink = sLink.replaceFirst( " ", OUStringChar(sfx2::cTokenSeparator), &nPos ); + if (nPos>=0) + { + sLink = sLink.replaceFirst( " ", OUStringChar(sfx2::cTokenSeparator), &nPos ); + } + + pSectRepr->GetSectionData().SetLinkFileName( sLink ); + pSectRepr->GetSectionData().SetType( SectionType::DdeLink ); + } + else + { + OUString sTmp(rEdit.get_text()); + if(!sTmp.isEmpty()) + { + SfxMedium* pMedium = m_rSh.GetView().GetDocShell()->GetMedium(); + INetURLObject aAbs; + if( pMedium ) + aAbs = pMedium->GetURLObject(); + sTmp = URIHelper::SmartRel2Abs( + aAbs, sTmp, URIHelper::GetMaybeFileHdl() ); + } + pSectRepr->SetFile( sTmp ); + pSectRepr->GetSectionData().SetLinkFilePassword(OUString()); + } +} + +IMPL_LINK(SwEditRegionDlg, DDEHdl, weld::Toggleable&, rButton, void) +{ + if (!CheckPasswd(&rButton)) + return; + SectRepr* pSectRepr = weld::fromId<SectRepr*>(m_xTree->get_selected_id()); + if (!pSectRepr) + return; + + bool bFile = m_xFileCB->get_active(); + SwSectionData & rData( pSectRepr->GetSectionData() ); + bool bDDE = rButton.get_active(); + if(bDDE) + { + m_xFileNameFT->hide(); + m_xDDECommandFT->set_sensitive(true); + m_xDDECommandFT->show(); + m_xSubRegionFT->hide(); + m_xSubRegionED->hide(); + if (SectionType::FileLink == rData.GetType()) + { + pSectRepr->SetFile(u""); + m_xFileNameED->set_text(OUString()); + rData.SetLinkFilePassword(OUString()); + } + rData.SetType(SectionType::DdeLink); + } + else + { + m_xDDECommandFT->hide(); + m_xFileNameFT->set_sensitive(bFile); + if(!comphelper::LibreOfficeKit::isActive()) + m_xFileNameFT->show(); + m_xSubRegionED->show(); + m_xSubRegionFT->show(); + m_xSubRegionED->set_sensitive(bFile); + m_xSubRegionFT->set_sensitive(bFile); + m_xSubRegionED->set_sensitive(bFile); + if (SectionType::DdeLink == rData.GetType()) + { + rData.SetType(SectionType::FileLink); + pSectRepr->SetFile(u""); + rData.SetLinkFilePassword(OUString()); + m_xFileNameED->set_text(OUString()); + } + } + m_xFilePB->set_sensitive(bFile && !bDDE); +} + +void SwEditRegionDlg::ChangePasswd(bool bChange) +{ + if (!CheckPasswd()) + { + if (!bChange) + m_xPasswdCB->set_active(!m_xPasswdCB->get_active()); + return; + } + + bool bSet = bChange ? bChange : m_xPasswdCB->get_active(); + + m_xTree->selected_foreach([this, bChange, bSet](weld::TreeIter& rEntry){ + SectRepr* pRepr = weld::fromId<SectRepr*>(m_xTree->get_id(rEntry)); + if(bSet) + { + if(!pRepr->GetTempPasswd().hasElements() || bChange) + { + SfxPasswordDialog aPasswdDlg(m_xDialog.get()); + aPasswdDlg.ShowExtras(SfxShowExtras::CONFIRM); + if (RET_OK == aPasswdDlg.run()) + { + const OUString sNewPasswd(aPasswdDlg.GetPassword()); + if (aPasswdDlg.GetConfirm() == sNewPasswd) + { + SvPasswordHelper::GetHashPassword( pRepr->GetTempPasswd(), sNewPasswd ); + } + else + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_WRONG_PASSWD_REPEAT))); + xInfoBox->run(); + ChangePasswd(bChange); + return true; + } + } + else + { + if(!bChange) + m_xPasswdCB->set_active(false); + return true; + } + } + pRepr->GetSectionData().SetPassword(pRepr->GetTempPasswd()); + } + else + { + pRepr->GetSectionData().SetPassword(uno::Sequence<sal_Int8 >()); + } + return false; + }); +} + +IMPL_LINK_NOARG(SwEditRegionDlg, TogglePasswdHdl, weld::Toggleable&, void) +{ + ChangePasswd(false); +} + +IMPL_LINK_NOARG(SwEditRegionDlg, ChangePasswdHdl, weld::Button&, void) +{ + ChangePasswd(true); +} + +// the current region name is being added to the TreeListBox immediately during +// editing, with empty string no Ok() +IMPL_LINK_NOARG(SwEditRegionDlg, NameEditHdl, weld::Entry&, void) +{ + if(!CheckPasswd()) + return; + std::unique_ptr<weld::TreeIter> xIter(m_xTree->make_iterator()); + if (m_xTree->get_selected(xIter.get())) + { + const OUString aName = m_xCurName->get_text(); + m_xTree->set_text(*xIter, aName); + SectRepr* pRepr = weld::fromId<SectRepr*>(m_xTree->get_id(*xIter)); + pRepr->GetSectionData().SetSectionName(aName); + + m_xOK->set_sensitive(!aName.isEmpty()); + } +} + +IMPL_LINK( SwEditRegionDlg, ConditionEditHdl, weld::Entry&, rEdit, void ) +{ + int nStartPos, nEndPos; + rEdit.get_selection_bounds(nStartPos, nEndPos); + if(!CheckPasswd()) + return; + rEdit.select_region(nStartPos, nEndPos); + + m_xTree->selected_foreach([this, &rEdit](weld::TreeIter& rEntry){ + SectRepr* pRepr = weld::fromId<SectRepr*>(m_xTree->get_id(rEntry)); + pRepr->GetSectionData().SetCondition(rEdit.get_text()); + return false; + }); +} + +IMPL_LINK( SwEditRegionDlg, DlgClosedHdl, sfx2::FileDialogHelper *, _pFileDlg, void ) +{ + OUString sFileName, sFilterName, sPassword; + if ( _pFileDlg->GetError() == ERRCODE_NONE ) + { + std::unique_ptr<SfxMedium> pMedium(m_pDocInserter->CreateMedium("sglobal")); + if ( pMedium ) + { + sFileName = pMedium->GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ); + sFilterName = pMedium->GetFilter()->GetFilterName(); + if ( const SfxStringItem* pItem = pMedium->GetItemSet().GetItemIfSet( SID_PASSWORD, false ) ) + sPassword = pItem->GetValue(); + ::lcl_ReadSections(*pMedium, *m_xSubRegionED); + } + } + + SectRepr* pSectRepr = weld::fromId<SectRepr*>(m_xTree->get_selected_id()); + if (pSectRepr) + { + pSectRepr->SetFile( sFileName ); + pSectRepr->SetFilter( sFilterName ); + pSectRepr->GetSectionData().SetLinkFilePassword(sPassword); + m_xFileNameED->set_text(pSectRepr->GetFile()); + } +} + +IMPL_LINK_NOARG(SwEditRegionDlg, SubRegionEventHdl, weld::ComboBox&, void) +{ + if (m_bSubRegionsFilled) + return; + + //if necessary fill the names bookmarks/sections/tables now + + OUString sFileName = m_xFileNameED->get_text(); + if(!sFileName.isEmpty()) + { + SfxMedium* pMedium = m_rSh.GetView().GetDocShell()->GetMedium(); + INetURLObject aAbs; + if( pMedium ) + aAbs = pMedium->GetURLObject(); + sFileName = URIHelper::SmartRel2Abs( + aAbs, sFileName, URIHelper::GetMaybeFileHdl() ); + + //load file and set the shell + SfxMedium aMedium( sFileName, StreamMode::STD_READ ); + sFileName = aMedium.GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ); + ::lcl_ReadSections(aMedium, *m_xSubRegionED); + } + else + lcl_FillSubRegionList(m_rSh, *m_xSubRegionED, nullptr); + m_bSubRegionsFilled = true; +} + +// helper function - read section names from medium +static void lcl_ReadSections( SfxMedium& rMedium, weld::ComboBox& rBox ) +{ + rBox.clear(); + uno::Reference < embed::XStorage > xStg; + if( !(rMedium.IsStorage() && (xStg = rMedium.GetStorage()).is()) ) + return; + + std::vector<OUString> aArr; + SotClipboardFormatId nFormat = SotStorage::GetFormatID( xStg ); + if ( nFormat == SotClipboardFormatId::STARWRITER_60 || nFormat == SotClipboardFormatId::STARWRITERGLOB_60 || + nFormat == SotClipboardFormatId::STARWRITER_8 || nFormat == SotClipboardFormatId::STARWRITERGLOB_8) + SwGetReaderXML()->GetSectionList( rMedium, aArr ); + + for (auto const& it : aArr) + { + rBox.append_text(it); + } +} + +SwInsertSectionTabDialog::SwInsertSectionTabDialog( + weld::Window* pParent, const SfxItemSet& rSet, SwWrtShell& rSh) + : SfxTabDialogController(pParent, "modules/swriter/ui/insertsectiondialog.ui", + "InsertSectionDialog",&rSet) + , m_rWrtSh(rSh) +{ + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + AddTabPage("section", SwInsertSectionTabPage::Create, nullptr); + AddTabPage("columns", SwColumnPage::Create, nullptr); + AddTabPage("background", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_BKG), nullptr); + AddTabPage("notes", SwSectionFootnoteEndTabPage::Create, nullptr); + AddTabPage("indents", SwSectionIndentTabPage::Create, nullptr); + + tools::Long nHtmlMode = SvxHtmlOptions::GetExportMode(); + + bool bWeb = dynamic_cast<SwWebDocShell*>( rSh.GetView().GetDocShell() ) != nullptr ; + if(bWeb) + { + RemoveTabPage("notes"); + RemoveTabPage("indents"); + if( HTML_CFG_NS40 != nHtmlMode && HTML_CFG_WRITER != nHtmlMode) + RemoveTabPage("columns"); + } + SetCurPageId("section"); +} + +SwInsertSectionTabDialog::~SwInsertSectionTabDialog() +{ +} + +void SwInsertSectionTabDialog::PageCreated(const OUString& rId, SfxTabPage &rPage) +{ + if (rId == "section") + static_cast<SwInsertSectionTabPage&>(rPage).SetWrtShell(m_rWrtSh); + else if (rId == "background") + { + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE, static_cast<sal_uInt32>(SvxBackgroundTabFlags::SHOW_SELECTOR))); + rPage.PageCreated(aSet); + } + else if (rId == "columns") + { + const SwFormatFrameSize& rSize = GetInputSetImpl()->Get(RES_FRM_SIZE); + static_cast<SwColumnPage&>(rPage).SetPageWidth(rSize.GetWidth()); + static_cast<SwColumnPage&>(rPage).ShowBalance(true); + static_cast<SwColumnPage&>(rPage).SetInSection(true); + } + else if (rId == "indents") + static_cast<SwSectionIndentTabPage&>(rPage).SetWrtShell(m_rWrtSh); +} + +void SwInsertSectionTabDialog::SetSectionData(SwSectionData const& rSect) +{ + m_pSectionData.reset( new SwSectionData(rSect) ); +} + +short SwInsertSectionTabDialog::Ok() +{ + short nRet = SfxTabDialogController::Ok(); + OSL_ENSURE(m_pSectionData, "SwInsertSectionTabDialog: no SectionData?"); + const SfxItemSet* pOutputItemSet = GetOutputItemSet(); + m_rWrtSh.InsertSection(*m_pSectionData, pOutputItemSet); + SfxViewFrame& rViewFrame = m_rWrtSh.GetView().GetViewFrame(); + uno::Reference< frame::XDispatchRecorder > xRecorder = + rViewFrame.GetBindings().GetRecorder(); + if ( xRecorder.is() ) + { + SfxRequest aRequest(rViewFrame, FN_INSERT_REGION); + if(const SwFormatCol* pCol = pOutputItemSet->GetItemIfSet(RES_COL, false)) + { + aRequest.AppendItem(SfxUInt16Item(SID_ATTR_COLUMNS, + pCol->GetColumns().size())); + } + aRequest.AppendItem(SfxStringItem( FN_PARAM_REGION_NAME, + m_pSectionData->GetSectionName())); + aRequest.AppendItem(SfxStringItem( FN_PARAM_REGION_CONDITION, + m_pSectionData->GetCondition())); + aRequest.AppendItem(SfxBoolItem( FN_PARAM_REGION_HIDDEN, + m_pSectionData->IsHidden())); + aRequest.AppendItem(SfxBoolItem( FN_PARAM_REGION_PROTECT, + m_pSectionData->IsProtectFlag())); + // edit in readonly sections + aRequest.AppendItem(SfxBoolItem( FN_PARAM_REGION_EDIT_IN_READONLY, + m_pSectionData->IsEditInReadonlyFlag())); + + const OUString sLinkFileName( m_pSectionData->GetLinkFileName() ); + sal_Int32 n = 0; + aRequest.AppendItem(SfxStringItem( FN_PARAM_1, sLinkFileName.getToken( 0, sfx2::cTokenSeparator, n ))); + aRequest.AppendItem(SfxStringItem( FN_PARAM_2, sLinkFileName.getToken( 0, sfx2::cTokenSeparator, n ))); + aRequest.AppendItem(SfxStringItem( FN_PARAM_3, sLinkFileName.getToken( 0, sfx2::cTokenSeparator, n ))); + aRequest.Done(); + } + return nRet; +} + +SwInsertSectionTabPage::SwInsertSectionTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rAttrSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/sectionpage.ui", "SectionPage", &rAttrSet) + , m_pWrtSh(nullptr) + , m_xCurName(m_xBuilder->weld_entry_tree_view("sectionnames", "sectionnames-entry", + "sectionnames-list")) + , m_xFileCB(m_xBuilder->weld_check_button("link")) + , m_xDDECB(m_xBuilder->weld_check_button("dde")) + , m_xDDECommandFT(m_xBuilder->weld_label("ddelabel")) + , m_xFileNameFT(m_xBuilder->weld_label("filelabel")) + , m_xFileNameED(m_xBuilder->weld_entry("filename")) + , m_xFilePB(m_xBuilder->weld_button("selectfile")) + , m_xSubRegionFT(m_xBuilder->weld_label("sectionlabel")) + , m_xSubRegionED(m_xBuilder->weld_combo_box("sectionname")) + , m_xProtectCB(m_xBuilder->weld_check_button("protect")) + , m_xPasswdCB(m_xBuilder->weld_check_button("withpassword")) + , m_xPasswdPB(m_xBuilder->weld_button("selectpassword")) + , m_xHideCB(m_xBuilder->weld_check_button("hide")) + , m_xConditionFT(m_xBuilder->weld_label("condlabel")) + , m_xConditionED(new ConditionEdit(m_xBuilder->weld_entry("withcond"))) + // edit in readonly sections + , m_xEditInReadonlyCB(m_xBuilder->weld_check_button("editable")) +{ + m_xCurName->make_sorted(); + m_xCurName->set_height_request_by_rows(12); + m_xSubRegionED->make_sorted(); + + m_xProtectCB->connect_toggled( LINK( this, SwInsertSectionTabPage, ChangeProtectHdl)); + m_xPasswdCB->connect_toggled( LINK( this, SwInsertSectionTabPage, TogglePasswdHdl)); + m_xPasswdPB->connect_clicked( LINK( this, SwInsertSectionTabPage, ChangePasswdHdl)); + m_xHideCB->connect_toggled( LINK( this, SwInsertSectionTabPage, ChangeHideHdl)); + m_xFileCB->connect_toggled( LINK( this, SwInsertSectionTabPage, UseFileHdl )); + m_xFilePB->connect_clicked( LINK( this, SwInsertSectionTabPage, FileSearchHdl )); + m_xCurName->connect_changed( LINK( this, SwInsertSectionTabPage, NameEditHdl)); + m_xDDECB->connect_toggled( LINK( this, SwInsertSectionTabPage, DDEHdl )); + ChangeProtectHdl(*m_xProtectCB); + m_xSubRegionED->set_entry_completion(true, true); + + // Hide Link section. In general it makes no sense to insert a file from the jail, + // because it does not contain any usable files (documents). + if(comphelper::LibreOfficeKit::isActive()) + { + m_xBuilder->weld_label("label1")->hide(); // Link + m_xFileCB->hide(); + m_xDDECB->hide(); + m_xDDECommandFT->hide(); + m_xFileNameFT->hide(); + m_xFileNameED->hide(); + m_xFilePB->hide(); + m_xSubRegionFT->hide(); + m_xSubRegionED->hide(); + } +} + +SwInsertSectionTabPage::~SwInsertSectionTabPage() +{ +} + +void SwInsertSectionTabPage::SetWrtShell(SwWrtShell& rSh) +{ + m_pWrtSh = &rSh; + + bool bWeb = dynamic_cast<SwWebDocShell*>( m_pWrtSh->GetView().GetDocShell() )!= nullptr; + if(bWeb) + { + m_xHideCB->hide(); + m_xConditionED->hide(); + m_xConditionFT->hide(); + m_xDDECB->hide(); + m_xDDECommandFT->hide(); + } + + lcl_FillSubRegionList(*m_pWrtSh, *m_xSubRegionED, m_xCurName.get()); + + SwSectionData *const pSectionData = + static_cast<SwInsertSectionTabDialog*>(GetDialogController()) + ->GetSectionData(); + if (pSectionData) // something set? + { + const OUString sSectionName(pSectionData->GetSectionName()); + m_xCurName->set_entry_text(rSh.GetUniqueSectionName(&sSectionName)); + m_xProtectCB->set_active( pSectionData->IsProtectFlag() ); + ChangeProtectHdl(*m_xProtectCB); + m_sFileName = pSectionData->GetLinkFileName(); + m_sFilePasswd = pSectionData->GetLinkFilePassword(); + m_xFileCB->set_active( !m_sFileName.isEmpty() ); + m_xFileNameED->set_text( m_sFileName ); + UseFileHdl(*m_xFileCB); + } + else + { + m_xCurName->set_entry_text(rSh.GetUniqueSectionName()); + } +} + +bool SwInsertSectionTabPage::FillItemSet( SfxItemSet* ) +{ + SwSectionData aSection(SectionType::Content, m_xCurName->get_active_text()); + aSection.SetCondition(m_xConditionED->get_text()); + bool bProtected = m_xProtectCB->get_active(); + aSection.SetProtectFlag(bProtected); + aSection.SetHidden(m_xHideCB->get_active()); + // edit in readonly sections + aSection.SetEditInReadonlyFlag(m_xEditInReadonlyCB->get_active()); + + if(bProtected) + { + aSection.SetPassword(m_aNewPasswd); + } + const OUString sFileName = m_xFileNameED->get_text(); + const OUString sSubRegion = m_xSubRegionED->get_active_text(); + bool bDDe = m_xDDECB->get_active(); + if (m_xFileCB->get_active() && (!sFileName.isEmpty() || !sSubRegion.isEmpty() || bDDe)) + { + OUString aLinkFile; + if( bDDe ) + { + aLinkFile = CollapseWhiteSpaces(sFileName); + sal_Int32 nPos = 0; + aLinkFile = aLinkFile.replaceFirst( " ", OUStringChar(sfx2::cTokenSeparator), &nPos ); + if (nPos>=0) + { + aLinkFile = aLinkFile.replaceFirst( " ", OUStringChar(sfx2::cTokenSeparator), &nPos ); + } + } + else + { + if(!sFileName.isEmpty()) + { + SfxMedium* pMedium = m_pWrtSh->GetView().GetDocShell()->GetMedium(); + INetURLObject aAbs; + if( pMedium ) + aAbs = pMedium->GetURLObject(); + aLinkFile = URIHelper::SmartRel2Abs( + aAbs, sFileName, URIHelper::GetMaybeFileHdl() ); + aSection.SetLinkFilePassword( m_sFilePasswd ); + } + + aLinkFile += OUStringChar(sfx2::cTokenSeparator) + m_sFilterName + + OUStringChar(sfx2::cTokenSeparator) + sSubRegion; + } + + aSection.SetLinkFileName(aLinkFile); + if (!aLinkFile.isEmpty()) + { + aSection.SetType( m_xDDECB->get_active() ? + SectionType::DdeLink : + SectionType::FileLink); + } + } + static_cast<SwInsertSectionTabDialog*>(GetDialogController())->SetSectionData(aSection); + return true; +} + +void SwInsertSectionTabPage::Reset( const SfxItemSet* ) +{ +} + +std::unique_ptr<SfxTabPage> SwInsertSectionTabPage::Create(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwInsertSectionTabPage>(pPage, pController, *rAttrSet); +} + +IMPL_LINK(SwInsertSectionTabPage, ChangeHideHdl, weld::Toggleable&, rBox, void) +{ + bool bHide = rBox.get_active(); + m_xConditionED->set_sensitive(bHide); + m_xConditionFT->set_sensitive(bHide); +} + +IMPL_LINK(SwInsertSectionTabPage, ChangeProtectHdl, weld::Toggleable&, rBox, void) +{ + bool bCheck = rBox.get_active(); + m_xPasswdCB->set_sensitive(bCheck); + m_xPasswdPB->set_sensitive(bCheck); +} + +void SwInsertSectionTabPage::ChangePasswd(bool bChange) +{ + bool bSet = bChange ? bChange : m_xPasswdCB->get_active(); + if (bSet) + { + if(!m_aNewPasswd.hasElements() || bChange) + { + SfxPasswordDialog aPasswdDlg(GetFrameWeld()); + aPasswdDlg.ShowExtras(SfxShowExtras::CONFIRM); + if (RET_OK == aPasswdDlg.run()) + { + const OUString sNewPasswd(aPasswdDlg.GetPassword()); + if (aPasswdDlg.GetConfirm() == sNewPasswd) + { + SvPasswordHelper::GetHashPassword( m_aNewPasswd, sNewPasswd ); + } + else + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_WRONG_PASSWD_REPEAT))); + xInfoBox->run(); + } + } + else if(!bChange) + m_xPasswdCB->set_active(false); + } + } + else + m_aNewPasswd.realloc(0); +} + +IMPL_LINK_NOARG(SwInsertSectionTabPage, TogglePasswdHdl, weld::Toggleable&, void) +{ + ChangePasswd(false); +} + +IMPL_LINK_NOARG(SwInsertSectionTabPage, ChangePasswdHdl, weld::Button&, void) +{ + ChangePasswd(true); +} + + +IMPL_LINK_NOARG(SwInsertSectionTabPage, NameEditHdl, weld::ComboBox&, void) +{ + const OUString aName = m_xCurName->get_active_text(); + GetDialogController()->GetOKButton().set_sensitive(!aName.isEmpty() && + m_xCurName->find_text(aName) == -1); +} + +IMPL_LINK(SwInsertSectionTabPage, UseFileHdl, weld::Toggleable&, rButton, void) +{ + if (rButton.get_active()) + { + if (m_pWrtSh->HasSelection()) + { + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + SwResId(STR_QUERY_CONNECT))); + if (RET_NO == xQueryBox->run()) + rButton.set_active(false); + } + } + + bool bFile = rButton.get_active(); + m_xFileNameFT->set_sensitive(bFile); + m_xFileNameED->set_sensitive(bFile); + m_xFilePB->set_sensitive(bFile); + m_xSubRegionFT->set_sensitive(bFile); + m_xSubRegionED->set_sensitive(bFile); + m_xDDECommandFT->set_sensitive(bFile); + m_xDDECB->set_sensitive(bFile); + if (bFile) + { + m_xFileNameED->grab_focus(); + m_xProtectCB->set_active(true); + ChangeProtectHdl(*m_xProtectCB); + } + else + { + m_xDDECB->set_active(false); + DDEHdl(*m_xDDECB); + } +} + +IMPL_LINK_NOARG(SwInsertSectionTabPage, FileSearchHdl, weld::Button&, void) +{ + m_pDocInserter.reset(new ::sfx2::DocumentInserter(GetFrameWeld(), "swriter")); + m_pDocInserter->StartExecuteModal( LINK( this, SwInsertSectionTabPage, DlgClosedHdl ) ); +} + +IMPL_LINK( SwInsertSectionTabPage, DDEHdl, weld::Toggleable&, rButton, void ) +{ + bool bDDE = rButton.get_active(); + bool bFile = m_xFileCB->get_active(); + m_xFilePB->set_sensitive(!bDDE && bFile); + if (bDDE) + { + m_xFileNameFT->hide(); + m_xDDECommandFT->set_sensitive(bDDE); + m_xDDECommandFT->show(); + m_xSubRegionFT->hide(); + m_xSubRegionED->hide(); + m_xFileNameED->set_accessible_name(m_xDDECommandFT->get_label()); + } + else + { + m_xDDECommandFT->hide(); + m_xFileNameFT->set_sensitive(bFile); + if(!comphelper::LibreOfficeKit::isActive()) + m_xFileNameFT->show(); + m_xSubRegionFT->show(); + m_xSubRegionED->show(); + m_xSubRegionED->set_sensitive(bFile); + m_xFileNameED->set_accessible_name(m_xFileNameFT->get_label()); + } +} + +IMPL_LINK( SwInsertSectionTabPage, DlgClosedHdl, sfx2::FileDialogHelper *, _pFileDlg, void ) +{ + if ( _pFileDlg->GetError() == ERRCODE_NONE ) + { + std::unique_ptr<SfxMedium> pMedium(m_pDocInserter->CreateMedium("sglobal")); + if ( pMedium ) + { + m_sFileName = pMedium->GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ); + m_sFilterName = pMedium->GetFilter()->GetFilterName(); + if ( const SfxStringItem* pItem = pMedium->GetItemSet().GetItemIfSet( SID_PASSWORD, false ) ) + m_sFilePasswd = pItem->GetValue(); + m_xFileNameED->set_text( INetURLObject::decode( + m_sFileName, INetURLObject::DecodeMechanism::Unambiguous ) ); + ::lcl_ReadSections(*pMedium, *m_xSubRegionED); + } + } + else + { + m_sFilterName.clear(); + m_sFilePasswd.clear(); + } +} + +SwSectionFootnoteEndTabPage::SwSectionFootnoteEndTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rAttrSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/footnotesendnotestabpage.ui", "FootnotesEndnotesTabPage", &rAttrSet) + , m_xFootnoteNtAtTextEndCB(m_xBuilder->weld_check_button("ftnntattextend")) + , m_xFootnoteNtNumCB(m_xBuilder->weld_check_button("ftnntnum")) + , m_xFootnoteOffsetLbl(m_xBuilder->weld_label("ftnoffset_label")) + , m_xFootnoteOffsetField(m_xBuilder->weld_spin_button("ftnoffset")) + , m_xFootnoteNtNumFormatCB(m_xBuilder->weld_check_button("ftnntnumfmt")) + , m_xFootnotePrefixFT(m_xBuilder->weld_label("ftnprefix_label")) + , m_xFootnotePrefixED(m_xBuilder->weld_entry("ftnprefix")) + , m_xFootnoteNumViewBox(new SwNumberingTypeListBox(m_xBuilder->weld_combo_box("ftnnumviewbox"))) + , m_xFootnoteSuffixFT(m_xBuilder->weld_label("ftnsuffix_label")) + , m_xFootnoteSuffixED(m_xBuilder->weld_entry("ftnsuffix")) + , m_xEndNtAtTextEndCB(m_xBuilder->weld_check_button("endntattextend")) + , m_xEndNtNumCB(m_xBuilder->weld_check_button("endntnum")) + , m_xEndOffsetLbl(m_xBuilder->weld_label("endoffset_label")) + , m_xEndOffsetField(m_xBuilder->weld_spin_button("endoffset")) + , m_xEndNtNumFormatCB(m_xBuilder->weld_check_button("endntnumfmt")) + , m_xEndPrefixFT(m_xBuilder->weld_label("endprefix_label")) + , m_xEndPrefixED(m_xBuilder->weld_entry("endprefix")) + , m_xEndNumViewBox(new SwNumberingTypeListBox(m_xBuilder->weld_combo_box("endnumviewbox"))) + , m_xEndSuffixFT(m_xBuilder->weld_label("endsuffix_label")) + , m_xEndSuffixED(m_xBuilder->weld_entry("endsuffix")) +{ + m_xFootnoteNumViewBox->Reload(SwInsertNumTypes::Extended); + m_xEndNumViewBox->Reload(SwInsertNumTypes::Extended); + + Link<weld::Toggleable&,void> aLk( LINK( this, SwSectionFootnoteEndTabPage, FootEndHdl)); + m_xFootnoteNtAtTextEndCB->connect_toggled( aLk ); + m_xFootnoteNtNumCB->connect_toggled( aLk ); + m_xEndNtAtTextEndCB->connect_toggled( aLk ); + m_xEndNtNumCB->connect_toggled( aLk ); + m_xFootnoteNtNumFormatCB->connect_toggled( aLk ); + m_xEndNtNumFormatCB->connect_toggled( aLk ); +} + +SwSectionFootnoteEndTabPage::~SwSectionFootnoteEndTabPage() +{ +} + +bool SwSectionFootnoteEndTabPage::FillItemSet( SfxItemSet* rSet ) +{ + SwFormatFootnoteAtTextEnd aFootnote( m_xFootnoteNtAtTextEndCB->get_active() + ? ( m_xFootnoteNtNumCB->get_active() + ? ( m_xFootnoteNtNumFormatCB->get_active() + ? FTNEND_ATTXTEND_OWNNUMANDFMT + : FTNEND_ATTXTEND_OWNNUMSEQ ) + : FTNEND_ATTXTEND ) + : FTNEND_ATPGORDOCEND ); + + switch( aFootnote.GetValue() ) + { + case FTNEND_ATTXTEND_OWNNUMANDFMT: + aFootnote.SetNumType( m_xFootnoteNumViewBox->GetSelectedNumberingType() ); + aFootnote.SetPrefix( m_xFootnotePrefixED->get_text().replaceAll("\\t", "\t") ); // fdo#65666 + aFootnote.SetSuffix( m_xFootnoteSuffixED->get_text().replaceAll("\\t", "\t") ); + [[fallthrough]]; + + case FTNEND_ATTXTEND_OWNNUMSEQ: + aFootnote.SetOffset( static_cast< sal_uInt16 >( m_xFootnoteOffsetField->get_value()-1 ) ); + break; + default: break; + } + + SwFormatEndAtTextEnd aEnd( m_xEndNtAtTextEndCB->get_active() + ? ( m_xEndNtNumCB->get_active() + ? ( m_xEndNtNumFormatCB->get_active() + ? FTNEND_ATTXTEND_OWNNUMANDFMT + : FTNEND_ATTXTEND_OWNNUMSEQ ) + : FTNEND_ATTXTEND ) + : FTNEND_ATPGORDOCEND ); + + switch( aEnd.GetValue() ) + { + case FTNEND_ATTXTEND_OWNNUMANDFMT: + aEnd.SetNumType( m_xEndNumViewBox->GetSelectedNumberingType() ); + aEnd.SetPrefix( m_xEndPrefixED->get_text().replaceAll("\\t", "\t") ); + aEnd.SetSuffix( m_xEndSuffixED->get_text().replaceAll("\\t", "\t") ); + [[fallthrough]]; + + case FTNEND_ATTXTEND_OWNNUMSEQ: + aEnd.SetOffset( static_cast< sal_uInt16 >( m_xEndOffsetField->get_value()-1 ) ); + break; + default: break; + } + + rSet->Put( aFootnote ); + rSet->Put( aEnd ); + + return true; +} + +void SwSectionFootnoteEndTabPage::ResetState( bool bFootnote, + const SwFormatFootnoteEndAtTextEnd& rAttr ) +{ + weld::CheckButton *pNtAtTextEndCB, *pNtNumCB, *pNtNumFormatCB; + weld::Label *pPrefixFT, *pSuffixFT; + weld::Entry *pPrefixED, *pSuffixED; + SwNumberingTypeListBox *pNumViewBox; + weld::Label *pOffsetText; + weld::SpinButton *pOffsetField; + + if( bFootnote ) + { + pNtAtTextEndCB = m_xFootnoteNtAtTextEndCB.get(); + pNtNumCB = m_xFootnoteNtNumCB.get(); + pNtNumFormatCB = m_xFootnoteNtNumFormatCB.get(); + pPrefixFT = m_xFootnotePrefixFT.get(); + pPrefixED = m_xFootnotePrefixED.get(); + pSuffixFT = m_xFootnoteSuffixFT.get(); + pSuffixED = m_xFootnoteSuffixED.get(); + pNumViewBox = m_xFootnoteNumViewBox.get(); + pOffsetText = m_xFootnoteOffsetLbl.get(); + pOffsetField = m_xFootnoteOffsetField.get(); + } + else + { + pNtAtTextEndCB = m_xEndNtAtTextEndCB.get(); + pNtNumCB = m_xEndNtNumCB.get(); + pNtNumFormatCB = m_xEndNtNumFormatCB.get(); + pPrefixFT = m_xEndPrefixFT.get(); + pPrefixED = m_xEndPrefixED.get(); + pSuffixFT = m_xEndSuffixFT.get(); + pSuffixED = m_xEndSuffixED.get(); + pNumViewBox = m_xEndNumViewBox.get(); + pOffsetText = m_xEndOffsetLbl.get(); + pOffsetField = m_xEndOffsetField.get(); + } + + const sal_uInt16 eState = rAttr.GetValue(); + switch( eState ) + { + case FTNEND_ATTXTEND_OWNNUMANDFMT: + pNtNumFormatCB->set_state( TRISTATE_TRUE ); + [[fallthrough]]; + + case FTNEND_ATTXTEND_OWNNUMSEQ: + pNtNumCB->set_state( TRISTATE_TRUE ); + [[fallthrough]]; + + case FTNEND_ATTXTEND: + pNtAtTextEndCB->set_state( TRISTATE_TRUE ); + // no break; + } + + pNumViewBox->SelectNumberingType( rAttr.GetNumType() ); + pOffsetField->set_value( rAttr.GetOffset() + 1 ); + pPrefixED->set_text( rAttr.GetPrefix().replaceAll("\t", "\\t") ); + pSuffixED->set_text( rAttr.GetSuffix().replaceAll("\t", "\\t") ); + + switch( eState ) + { + case FTNEND_ATPGORDOCEND: + pNtNumCB->set_sensitive( false ); + [[fallthrough]]; + + case FTNEND_ATTXTEND: + pNtNumFormatCB->set_sensitive( false ); + pOffsetField->set_sensitive( false ); + pOffsetText->set_sensitive( false ); + [[fallthrough]]; + + case FTNEND_ATTXTEND_OWNNUMSEQ: + pNumViewBox->set_sensitive( false ); + pPrefixFT->set_sensitive( false ); + pPrefixED->set_sensitive( false ); + pSuffixFT->set_sensitive( false ); + pSuffixED->set_sensitive( false ); + // no break; + } +} + +void SwSectionFootnoteEndTabPage::Reset( const SfxItemSet* rSet ) +{ + ResetState( true, rSet->Get( RES_FTN_AT_TXTEND, false )); + ResetState( false, rSet->Get( RES_END_AT_TXTEND, false )); +} + +std::unique_ptr<SfxTabPage> SwSectionFootnoteEndTabPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwSectionFootnoteEndTabPage>(pPage, pController, *rAttrSet); +} + +IMPL_LINK( SwSectionFootnoteEndTabPage, FootEndHdl, weld::Toggleable&, rBox, void ) +{ + bool bFoot = m_xFootnoteNtAtTextEndCB.get() == &rBox || m_xFootnoteNtNumCB.get() == &rBox || + m_xFootnoteNtNumFormatCB.get() == &rBox ; + + weld::CheckButton *pNumBox, *pNumFormatBox, *pEndBox; + SwNumberingTypeListBox* pNumViewBox; + weld::Label *pOffsetText; + weld::SpinButton *pOffsetField; + weld::Label *pPrefixFT, *pSuffixFT; + weld::Entry *pPrefixED, *pSuffixED; + + if( bFoot ) + { + pEndBox = m_xFootnoteNtAtTextEndCB.get(); + pNumBox = m_xFootnoteNtNumCB.get(); + pNumFormatBox = m_xFootnoteNtNumFormatCB.get(); + pNumViewBox = m_xFootnoteNumViewBox.get(); + pOffsetText = m_xFootnoteOffsetLbl.get(); + pOffsetField = m_xFootnoteOffsetField.get(); + pPrefixFT = m_xFootnotePrefixFT.get(); + pSuffixFT = m_xFootnoteSuffixFT.get(); + pPrefixED = m_xFootnotePrefixED.get(); + pSuffixED = m_xFootnoteSuffixED.get(); + } + else + { + pEndBox = m_xEndNtAtTextEndCB.get(); + pNumBox = m_xEndNtNumCB.get(); + pNumFormatBox = m_xEndNtNumFormatCB.get(); + pNumViewBox = m_xEndNumViewBox.get(); + pOffsetText = m_xEndOffsetLbl.get(); + pOffsetField = m_xEndOffsetField.get(); + pPrefixFT = m_xEndPrefixFT.get(); + pSuffixFT = m_xEndSuffixFT.get(); + pPrefixED = m_xEndPrefixED.get(); + pSuffixED = m_xEndSuffixED.get(); + } + + bool bEnableAtEnd = TRISTATE_TRUE == pEndBox->get_state(); + bool bEnableNum = bEnableAtEnd && TRISTATE_TRUE == pNumBox->get_state(); + bool bEnableNumFormat = bEnableNum && TRISTATE_TRUE == pNumFormatBox->get_state(); + + pNumBox->set_sensitive( bEnableAtEnd ); + pOffsetText->set_sensitive( bEnableNum ); + pOffsetField->set_sensitive( bEnableNum ); + pNumFormatBox->set_sensitive( bEnableNum ); + pNumViewBox->set_sensitive( bEnableNumFormat ); + pPrefixED->set_sensitive( bEnableNumFormat ); + pSuffixED->set_sensitive( bEnableNumFormat ); + pPrefixFT->set_sensitive( bEnableNumFormat ); + pSuffixFT->set_sensitive( bEnableNumFormat ); +} + +SwSectionPropertyTabDialog::SwSectionPropertyTabDialog( + weld::Window* pParent, const SfxItemSet& rSet, SwWrtShell& rSh) + : SfxTabDialogController(pParent, "modules/swriter/ui/formatsectiondialog.ui", + "FormatSectionDialog", &rSet) + , m_rWrtSh(rSh) +{ + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + AddTabPage("columns", SwColumnPage::Create, nullptr); + AddTabPage("background", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_BKG), nullptr); + AddTabPage("notes", SwSectionFootnoteEndTabPage::Create, nullptr); + AddTabPage("indents", SwSectionIndentTabPage::Create, nullptr); + + tools::Long nHtmlMode = SvxHtmlOptions::GetExportMode(); + bool bWeb = dynamic_cast<SwWebDocShell*>( rSh.GetView().GetDocShell() ) != nullptr ; + if(bWeb) + { + RemoveTabPage("notes"); + RemoveTabPage("indents"); + if( HTML_CFG_NS40 != nHtmlMode && HTML_CFG_WRITER != nHtmlMode) + RemoveTabPage("columns"); + } +} + +SwSectionPropertyTabDialog::~SwSectionPropertyTabDialog() +{ +} + +void SwSectionPropertyTabDialog::PageCreated(const OUString& rId, SfxTabPage &rPage) +{ + if (rId == "background") + { + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE, static_cast<sal_uInt32>(SvxBackgroundTabFlags::SHOW_SELECTOR))); + rPage.PageCreated(aSet); + } + else if (rId == "columns") + { + static_cast<SwColumnPage&>(rPage).ShowBalance(true); + static_cast<SwColumnPage&>(rPage).SetInSection(true); + } + else if (rId == "indents") + static_cast<SwSectionIndentTabPage&>(rPage).SetWrtShell(m_rWrtSh); +} + +SwSectionIndentTabPage::SwSectionIndentTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rAttrSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/indentpage.ui", "IndentPage", &rAttrSet) + , m_xBeforeMF(m_xBuilder->weld_metric_spin_button("before", FieldUnit::CM)) + , m_xAfterMF(m_xBuilder->weld_metric_spin_button("after", FieldUnit::CM)) + , m_xPreviewWin(new weld::CustomWeld(*m_xBuilder, "preview", m_aPreviewWin)) +{ + Link<weld::MetricSpinButton&,void> aLk = LINK(this, SwSectionIndentTabPage, IndentModifyHdl); + m_xBeforeMF->connect_value_changed(aLk); + m_xAfterMF->connect_value_changed(aLk); +} + +SwSectionIndentTabPage::~SwSectionIndentTabPage() +{ +} + +bool SwSectionIndentTabPage::FillItemSet(SfxItemSet* rSet) +{ + if (m_xBeforeMF->get_value_changed_from_saved() || m_xAfterMF->get_value_changed_from_saved()) + { + SvxLRSpaceItem aLRSpace( + m_xBeforeMF->denormalize(m_xBeforeMF->get_value(FieldUnit::TWIP)) , + m_xAfterMF->denormalize(m_xAfterMF->get_value(FieldUnit::TWIP)), 0, RES_LR_SPACE); + rSet->Put(aLRSpace); + } + return true; +} + +void SwSectionIndentTabPage::Reset( const SfxItemSet* rSet) +{ + //this page doesn't show up in HTML mode + FieldUnit aMetric = ::GetDfltMetric(false); + SetFieldUnit(*m_xBeforeMF, aMetric); + SetFieldUnit(*m_xAfterMF , aMetric); + + SfxItemState eItemState = rSet->GetItemState( RES_LR_SPACE ); + if ( eItemState >= SfxItemState::DEFAULT ) + { + const SvxLRSpaceItem& rSpace = + rSet->Get( RES_LR_SPACE ); + + m_xBeforeMF->set_value(m_xBeforeMF->normalize(rSpace.GetLeft()), FieldUnit::TWIP); + m_xAfterMF->set_value(m_xAfterMF->normalize(rSpace.GetRight()), FieldUnit::TWIP); + } + else + { + m_xBeforeMF->set_text(""); + m_xAfterMF->set_text(""); + } + m_xBeforeMF->save_value(); + m_xAfterMF->save_value(); + IndentModifyHdl(*m_xBeforeMF); +} + +std::unique_ptr<SfxTabPage> SwSectionIndentTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwSectionIndentTabPage>(pPage, pController, *rAttrSet); +} + +void SwSectionIndentTabPage::SetWrtShell(SwWrtShell const & rSh) +{ + //set sensible values at the preview + m_aPreviewWin.SetAdjust(SvxAdjust::Block); + m_aPreviewWin.SetLastLine(SvxAdjust::Block); + const SwRect& rPageRect = rSh.GetAnyCurRect( CurRectType::Page ); + Size aPageSize(rPageRect.Width(), rPageRect.Height()); + m_aPreviewWin.SetSize(aPageSize); +} + +IMPL_LINK_NOARG(SwSectionIndentTabPage, IndentModifyHdl, weld::MetricSpinButton&, void) +{ + m_aPreviewWin.SetLeftMargin(m_xBeforeMF->denormalize(m_xBeforeMF->get_value(FieldUnit::TWIP))); + m_aPreviewWin.SetRightMargin(m_xAfterMF->denormalize(m_xAfterMF->get_value(FieldUnit::TWIP))); + m_aPreviewWin.Invalidate(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dialog/wordcountdialog.cxx b/sw/source/ui/dialog/wordcountdialog.cxx new file mode 100644 index 0000000000..1277545c6e --- /dev/null +++ b/sw/source/ui/dialog/wordcountdialog.cxx @@ -0,0 +1,161 @@ +/* -*- 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 <officecfg/Office/Writer.hxx> +#include <wordcountdialog.hxx> +#include <docsh.hxx> +#include <docstat.hxx> +#include <swmodule.hxx> +#include <view.hxx> +#include <swwait.hxx> +#include <wrtsh.hxx> +#include <rtl/math.hxx> +#include <svl/cjkoptions.hxx> +#include <unotools/localedatawrapper.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <comphelper/lok.hxx> +#include <PostItMgr.hxx> + +#define IS_MOBILE_PHONE (comphelper::LibreOfficeKit::isActive() && SfxViewShell::Current() && SfxViewShell::Current()->isLOKMobilePhone()) + +SwWordCountFloatDlg::~SwWordCountFloatDlg() +{ + SwViewShell::SetCareDialog(nullptr); +} + +namespace +{ + void setValue(weld::Label& rWidget, sal_uLong nValue, const LocaleDataWrapper& rLocaleData) + { + rWidget.set_label(rLocaleData.getNum(nValue, 0)); + } + + void setDoubleValue(weld::Label& rWidget, double fValue) + { + OUString sValue(OUString::number(::rtl::math::round(fValue, 1))); + rWidget.set_label(sValue); + } +} + +void SwWordCountFloatDlg::SetValues(const SwDocStat& rCurrent, const SwDocStat& rDoc) +{ + const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetUILocaleDataWrapper(); + setValue(*m_xCurrentWordFT, rCurrent.nWord, rLocaleData); + setValue(*m_xCurrentCharacterFT, rCurrent.nChar, rLocaleData); + setValue(*m_xCurrentCharacterExcludingSpacesFT, rCurrent.nCharExcludingSpaces, rLocaleData); + setValue(*m_xCurrentCjkcharsFT, rCurrent.nAsianWord, rLocaleData); + setValue(*m_xDocWordFT, rDoc.nWord, rLocaleData); + setValue(*m_xDocCharacterFT, rDoc.nChar, rLocaleData); + setValue(*m_xDocCharacterExcludingSpacesFT, rDoc.nCharExcludingSpaces, rLocaleData); + setValue(*m_xDocCjkcharsFT, rDoc.nAsianWord, rLocaleData); + setValue(*m_xDocComments, rCurrent.nComments, rLocaleData); + + const sal_Int64 nCharsPerStandardizedPage = m_xStandardizedPagesLabelFT->get_visible() ? + officecfg::Office::Writer::WordCount::StandardizedPageSize::get() : 0; + if (nCharsPerStandardizedPage) + { + setDoubleValue(*m_xCurrentStandardizedPagesFT, + static_cast<double>(rCurrent.nChar) / nCharsPerStandardizedPage); + setDoubleValue(*m_xDocStandardizedPagesFT, + static_cast<double>(rDoc.nChar) / nCharsPerStandardizedPage); + } + + bool bShowCJK = (SvtCJKOptions::IsAnyEnabled() || rDoc.nAsianWord); + bool bToggleCJK = m_xCurrentCjkcharsFT->get_visible() != bShowCJK; + if (bToggleCJK) + { + showCJK(bShowCJK); + m_xDialog->resize_to_request(); //force resize of dialog + } +} + +void SwWordCountFloatDlg::showCJK(bool bShowCJK) +{ + m_xCurrentCjkcharsFT->set_visible(bShowCJK); + m_xDocCjkcharsFT->set_visible(bShowCJK); + if (IS_MOBILE_PHONE && m_xCjkcharsLabelFT2) + m_xCjkcharsLabelFT2->set_visible(bShowCJK); + m_xCjkcharsLabelFT->set_visible(bShowCJK); +} + +void SwWordCountFloatDlg::showStandardizedPages(bool bShowStandardizedPages) +{ + m_xCurrentStandardizedPagesFT->set_visible(bShowStandardizedPages); + m_xDocStandardizedPagesFT->set_visible(bShowStandardizedPages); + if (IS_MOBILE_PHONE && m_xStandardizedPagesLabelFT2) + m_xStandardizedPagesLabelFT2->set_visible(bShowStandardizedPages); + m_xStandardizedPagesLabelFT->set_visible(bShowStandardizedPages); +} + +SwWordCountFloatDlg::SwWordCountFloatDlg(SfxBindings* _pBindings, + SfxChildWindow* pChild, + weld::Window *pParent, + SfxChildWinInfo const * pInfo) + : SfxModelessDialogController(_pBindings, pChild, pParent, IS_MOBILE_PHONE ? OUString("modules/swriter/ui/wordcount-mobile.ui") : OUString("modules/swriter/ui/wordcount.ui"), "WordCountDialog") + , m_xCurrentWordFT(m_xBuilder->weld_label("selectwords")) + , m_xCurrentCharacterFT(m_xBuilder->weld_label("selectchars")) + , m_xCurrentCharacterExcludingSpacesFT(m_xBuilder->weld_label("selectcharsnospaces")) + , m_xCurrentCjkcharsFT(m_xBuilder->weld_label("selectcjkchars")) + , m_xCurrentStandardizedPagesFT(m_xBuilder->weld_label("selectstandardizedpages")) + , m_xDocWordFT(m_xBuilder->weld_label("docwords")) + , m_xDocCharacterFT(m_xBuilder->weld_label("docchars")) + , m_xDocCharacterExcludingSpacesFT(m_xBuilder->weld_label("doccharsnospaces")) + , m_xDocCjkcharsFT(m_xBuilder->weld_label("doccjkchars")) + , m_xDocStandardizedPagesFT(m_xBuilder->weld_label("docstandardizedpages")) + , m_xCjkcharsLabelFT(m_xBuilder->weld_label("cjkcharsft")) + , m_xCjkcharsLabelFT2(m_xBuilder->weld_label("cjkcharsft2")) + , m_xStandardizedPagesLabelFT(m_xBuilder->weld_label("standardizedpages")) + , m_xStandardizedPagesLabelFT2(m_xBuilder->weld_label("standardizedpages2")) + , m_xDocComments(m_xBuilder->weld_label("docComments")) +{ + showCJK(SvtCJKOptions::IsAnyEnabled()); + showStandardizedPages(officecfg::Office::Writer::WordCount::ShowStandardizedPageCount::get()); + + Initialize(pInfo); +} + +void SwWordCountFloatDlg::UpdateCounts() +{ + if (SwView* pView = GetActiveView()) + { + SwWrtShell &rSh = pView->GetWrtShell(); + SwDocStat aCurrCnt; + SwDocStat aDocStat; + { + auto& rDocShell(*pView->GetDocShell()); + SwWait aWait(rDocShell, true); + auto aLock = rDocShell.LockAllViews(); + rSh.StartAction(); + rSh.CountWords( aCurrCnt ); + aDocStat = rSh.GetUpdatedDocStat(); + rSh.EndAction(); + } + SwPostItMgr* pPostItMgr = rSh.GetPostItMgr(); + aCurrCnt.nComments = pPostItMgr->end() - pPostItMgr->begin(); + SetValues(aCurrCnt, aDocStat); + } +} + +void SwWordCountFloatDlg::SetCounts(const SwDocStat &rCurrCnt, const SwDocStat &rDocStat) +{ + SetValues(rCurrCnt, rDocStat); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dochdl/selglos.cxx b/sw/source/ui/dochdl/selglos.cxx new file mode 100644 index 0000000000..1d2b93f239 --- /dev/null +++ b/sw/source/ui/dochdl/selglos.cxx @@ -0,0 +1,42 @@ +/* -*- 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 <selglos.hxx> + +SwSelGlossaryDlg::SwSelGlossaryDlg(weld::Window * pParent, std::u16string_view rShortName) + : GenericDialogController(pParent, "modules/swriter/ui/insertautotextdialog.ui", "InsertAutoTextDialog") + , m_xFrame(m_xBuilder->weld_frame("frame")) + , m_xGlosBox(m_xBuilder->weld_tree_view("treeview")) +{ + m_xFrame->set_label(m_xFrame->get_label() + rShortName); + m_xGlosBox->set_size_request(-1, m_xGlosBox->get_height_rows(10)); + m_xGlosBox->connect_row_activated(LINK(this, SwSelGlossaryDlg, DoubleClickHdl)); +} + +SwSelGlossaryDlg::~SwSelGlossaryDlg() +{ +} + +IMPL_LINK_NOARG(SwSelGlossaryDlg, DoubleClickHdl, weld::TreeView&, bool) +{ + m_xDialog->response(RET_OK); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/envfmt.cxx b/sw/source/ui/envelp/envfmt.cxx new file mode 100644 index 0000000000..ebf99363cd --- /dev/null +++ b/sw/source/ui/envelp/envfmt.cxx @@ -0,0 +1,425 @@ +/* -*- 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 <editeng/paperinf.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/lrspitem.hxx> +#include <svtools/unitconv.hxx> +#include <svx/drawitem.hxx> +#include <o3tl/string_view.hxx> +#include <osl/diagnose.h> + +#include <cmdid.h> +#include <IDocumentDrawModelAccess.hxx> +#include <drawdoc.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include "envfmt.hxx" +#include <fmtcol.hxx> +#include <swuipardlg.hxx> +#include <chrdlgmodes.hxx> +#include <pardlg.hxx> +#include <poolfmt.hxx> +#include <uitool.hxx> + +#include <vector> +#include <algorithm> + +#include <memory> + +#include <swabstdlg.hxx> +#include <swuiexp.hxx> + +static tools::Long lUserW = 5669; // 10 cm +static tools::Long lUserH = 5669; // 10 cm + +SwEnvFormatPage::SwEnvFormatPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/envformatpage.ui", "EnvFormatPage", &rSet) + , m_pDialog(nullptr) + , m_xAddrLeftField(m_xBuilder->weld_metric_spin_button("leftaddr", FieldUnit::CM)) + , m_xAddrTopField(m_xBuilder->weld_metric_spin_button("topaddr", FieldUnit::CM)) + , m_xAddrEditButton(m_xBuilder->weld_menu_button("addredit")) + , m_xSendLeftField(m_xBuilder->weld_metric_spin_button("leftsender", FieldUnit::CM)) + , m_xSendTopField(m_xBuilder->weld_metric_spin_button("topsender", FieldUnit::CM)) + , m_xSendEditButton(m_xBuilder->weld_menu_button("senderedit")) + , m_xSizeFormatBox(m_xBuilder->weld_combo_box("format")) + , m_xSizeWidthField(m_xBuilder->weld_metric_spin_button("width", FieldUnit::CM)) + , m_xSizeHeightField(m_xBuilder->weld_metric_spin_button("height", FieldUnit::CM)) + , m_xPreview(new weld::CustomWeld(*m_xBuilder, "preview", m_aPreview)) +{ + SetExchangeSupport(); + + // Metrics + FieldUnit aMetric = ::GetDfltMetric(false); + ::SetFieldUnit(*m_xAddrLeftField, aMetric); + ::SetFieldUnit(*m_xAddrTopField, aMetric); + ::SetFieldUnit(*m_xSendLeftField, aMetric); + ::SetFieldUnit(*m_xSendTopField, aMetric); + ::SetFieldUnit(*m_xSizeWidthField, aMetric); + ::SetFieldUnit(*m_xSizeHeightField, aMetric); + + // Install handlers + Link<weld::MetricSpinButton&,void> aLk = LINK(this, SwEnvFormatPage, ModifyHdl); + m_xAddrLeftField->connect_value_changed( aLk ); + m_xAddrTopField->connect_value_changed( aLk ); + m_xSendLeftField->connect_value_changed( aLk ); + m_xSendTopField->connect_value_changed( aLk ); + m_xSizeWidthField->connect_value_changed( aLk ); + m_xSizeHeightField->connect_value_changed( aLk ); + + m_xAddrEditButton->connect_selected(LINK(this, SwEnvFormatPage, AddrEditHdl)); + m_xSendEditButton->connect_selected(LINK(this, SwEnvFormatPage, SendEditHdl)); + + m_xSizeFormatBox->connect_changed(LINK(this, SwEnvFormatPage, FormatHdl)); + + // m_xSizeFormatBox + for (sal_uInt16 i = PAPER_A3; i <= PAPER_KAI32BIG; i++) + { + if (i != PAPER_USER) + { + const OUString aPaperName = SvxPaperInfo::GetName(static_cast<Paper>(i)); + + if (aPaperName.isEmpty()) + continue; + + sal_Int32 nPos = 0; + while (nPos < m_xSizeFormatBox->get_count() && + m_xSizeFormatBox->get_text(nPos) < aPaperName) + { + ++nPos; + } + m_xSizeFormatBox->insert_text(nPos, aPaperName); + m_aIDs.insert( m_aIDs.begin() + nPos, i); + } + } + m_xSizeFormatBox->append_text(SvxPaperInfo::GetName(PAPER_USER)); + m_aIDs.push_back( sal_uInt16(PAPER_USER) ); +} + +void SwEnvFormatPage::Init(SwEnvDlg* pDialog) +{ + m_pDialog = pDialog; + m_aPreview.SetDialog(m_pDialog); +} + +SwEnvFormatPage::~SwEnvFormatPage() +{ +} + +IMPL_LINK( SwEnvFormatPage, ModifyHdl, weld::MetricSpinButton&, rEdit, void ) +{ + int lWVal = getfieldval(*m_xSizeWidthField); + int lHVal = getfieldval(*m_xSizeHeightField); + + int lWidth = std::max(lWVal, lHVal); + int lHeight = std::min(lWVal, lHVal); + + if (&rEdit == m_xSizeWidthField.get() || &rEdit == m_xSizeHeightField.get()) + { + int nRotatedWidth = lHeight; + int nRotatedHeight = lWidth; + Paper ePaper = SvxPaperInfo::GetSvxPaper( + Size(nRotatedWidth, nRotatedHeight), MapUnit::MapTwip); + for (size_t i = 0; i < m_aIDs.size(); ++i) + if (m_aIDs[i] == o3tl::narrowing<sal_uInt16>(ePaper)) + m_xSizeFormatBox->set_active(i); + + // remember user size + if (m_aIDs[m_xSizeFormatBox->get_active()] == sal_uInt16(PAPER_USER)) + { + lUserW = lWidth ; + lUserH = lHeight; + } + + FormatHdl(*m_xSizeFormatBox); + } + else + { + FillItem(GetParentSwEnvDlg()->m_aEnvItem); + SetMinMax(); + m_xPreview->queue_draw(); + } +} + +IMPL_LINK(SwEnvFormatPage, AddrEditHdl, const OUString&, rIdent, void) +{ + Edit(rIdent, false); +} + +IMPL_LINK(SwEnvFormatPage, SendEditHdl, const OUString&, rIdent, void) +{ + Edit(rIdent, true); +} + +void SwEnvFormatPage::Edit(std::u16string_view rIdent, bool bSender) +{ + SwWrtShell* pSh = GetParentSwEnvDlg()->m_pSh; + OSL_ENSURE(pSh, "Shell missing"); + + SwTextFormatColl* pColl = pSh->GetTextCollFromPool( static_cast< sal_uInt16 >( + bSender ? RES_POOLCOLL_SEND_ADDRESS : RES_POOLCOLL_ENVELOPE_ADDRESS)); + OSL_ENSURE(pColl, "Text collection missing"); + + if (o3tl::starts_with(rIdent, u"character")) + { + SfxItemSet *pCollSet = GetCollItemSet(pColl, bSender); + + // In order for the background color not to get ironed over: + SfxAllItemSet aTmpSet(*pCollSet); + ::ConvertAttrCharToGen(aTmpSet); + + SwAbstractDialogFactory& rFact = swui::GetFactory(); + + const OUString sFormatStr = pColl->GetName(); + ScopedVclPtr<SfxAbstractTabDialog> pDlg(rFact.CreateSwCharDlg(GetFrameWeld(), pSh->GetView(), aTmpSet, SwCharDlgMode::Env, &sFormatStr)); + if (pDlg->Execute() == RET_OK) + { + SfxItemSet aOutputSet( *pDlg->GetOutputItemSet() ); + ::ConvertAttrGenToChar(aOutputSet, aTmpSet); + pCollSet->Put(aOutputSet); + } + } + else if (o3tl::starts_with(rIdent, u"paragraph")) + { + SfxItemSet *pCollSet = GetCollItemSet(pColl, bSender); + + // In order for the tabulators not to get ironed over: + SfxAllItemSet aTmpSet(*pCollSet); + + // Insert tabs, default tabs into ItemSet + const SvxTabStopItem& rDefTabs = + pSh->GetView().GetCurShell()->GetPool().GetDefaultItem(RES_PARATR_TABSTOP); + + const sal_uInt16 nDefDist = o3tl::narrowing<sal_uInt16>(::GetTabDist( rDefTabs )); + SfxUInt16Item aDefDistItem( SID_ATTR_TABSTOP_DEFAULTS, nDefDist ); + aTmpSet.Put( aDefDistItem ); + + // Current tab + SfxUInt16Item aTabPos( SID_ATTR_TABSTOP_POS, 0 ); + aTmpSet.Put( aTabPos ); + + // left border as offset + const tools::Long nOff = aTmpSet.Get(RES_MARGIN_TEXTLEFT).GetTextLeft(); + SfxInt32Item aOff( SID_ATTR_TABSTOP_OFFSET, nOff ); + aTmpSet.Put( aOff ); + + // set BoxInfo + ::PrepareBoxInfo( aTmpSet, *pSh ); + + SwDrawModel* pDrawModel = pSh->GetView().GetDocShell()->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel(); + aTmpSet.Put(SvxColorListItem(pDrawModel->GetColorList(), SID_COLOR_TABLE)); + aTmpSet.Put(SvxGradientListItem(pDrawModel->GetGradientList(), SID_GRADIENT_LIST)); + aTmpSet.Put(SvxHatchListItem(pDrawModel->GetHatchList(), SID_HATCH_LIST)); + aTmpSet.Put(SvxBitmapListItem(pDrawModel->GetBitmapList(), SID_BITMAP_LIST)); + aTmpSet.Put(SvxPatternListItem(pDrawModel->GetPatternList(), SID_PATTERN_LIST)); + + const OUString sFormatStr = pColl->GetName(); + SwParaDlg aDlg(GetFrameWeld(), pSh->GetView(), aTmpSet, DLG_ENVELOP, &sFormatStr); + + if (aDlg.run() == RET_OK) + { + // maybe relocate defaults + const SfxUInt16Item* pDefaultsItem = nullptr; + SfxItemSet* pOutputSet = const_cast<SfxItemSet*>(aDlg.GetOutputItemSet()); + sal_uInt16 nNewDist; + + if( (pDefaultsItem = pOutputSet->GetItemIfSet( SID_ATTR_TABSTOP_DEFAULTS, false )) && + nDefDist != (nNewDist = pDefaultsItem->GetValue()) ) + { + SvxTabStopItem aDefTabs( 0, 0, SvxTabAdjust::Default, RES_PARATR_TABSTOP ); + MakeDefTabs( nNewDist, aDefTabs ); + pSh->SetDefault( aDefTabs ); + pOutputSet->ClearItem( SID_ATTR_TABSTOP_DEFAULTS ); + } + if( pOutputSet->Count() ) + { + pCollSet->Put(*pOutputSet); + } + } + } +} + +// A temporary Itemset that gets discarded at abort +SfxItemSet *SwEnvFormatPage::GetCollItemSet(SwTextFormatColl const * pColl, bool bSender) +{ + std::unique_ptr<SfxItemSet>& pAddrSet = bSender ? GetParentSwEnvDlg()->m_pSenderSet : GetParentSwEnvDlg()->m_pAddresseeSet; + if (!pAddrSet) + { + // determine range (merge both Itemsets' ranges) + const WhichRangesContainer& pRanges = pColl->GetAttrSet().GetRanges(); + + static WhichRangesContainer const aRanges(svl::Items< + RES_PARATR_BEGIN, RES_PARATR_ADJUST, + RES_PARATR_TABSTOP, RES_PARATR_END-1, + RES_MARGIN_FIRSTLINE, RES_MARGIN_RIGHT, + RES_UL_SPACE, RES_UL_SPACE, + RES_BACKGROUND, RES_SHADOW, + SID_ATTR_TABSTOP_DEFAULTS, SID_ATTR_TABSTOP_DEFAULTS, + SID_ATTR_TABSTOP_POS, SID_ATTR_TABSTOP_POS, + SID_ATTR_TABSTOP_OFFSET, SID_ATTR_TABSTOP_OFFSET, + SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER + >); + + pAddrSet.reset(new SfxItemSet(GetParentSwEnvDlg()->m_pSh->GetView().GetCurShell()->GetPool(), + pRanges)); + for (const auto& rPair : aRanges) + pAddrSet->MergeRange(rPair.first, rPair.second); + pAddrSet->Put(pColl->GetAttrSet()); + } + + return pAddrSet.get(); +} + +IMPL_LINK_NOARG(SwEnvFormatPage, FormatHdl, weld::ComboBox&, void) +{ + tools::Long lWidth; + tools::Long lHeight; + tools::Long lSendFromLeft; + tools::Long lSendFromTop; + tools::Long lAddrFromLeft; + tools::Long lAddrFromTop; + + const sal_uInt16 nPaper = m_aIDs[m_xSizeFormatBox->get_active()]; + if (nPaper != sal_uInt16(PAPER_USER)) + { + Size aSz = SvxPaperInfo::GetPaperSize(static_cast<Paper>(nPaper)); + lWidth = std::max(aSz.Width(), aSz.Height()); + lHeight = std::min(aSz.Width(), aSz.Height()); + } + else + { + lWidth = lUserW; + lHeight = lUserH; + } + + lSendFromLeft = 566; // 1cm + lSendFromTop = 566; // 1cm + lAddrFromLeft = lWidth / 2; + lAddrFromTop = lHeight / 2; + + setfieldval(*m_xAddrLeftField, lAddrFromLeft); + setfieldval(*m_xAddrTopField , lAddrFromTop ); + setfieldval(*m_xSendLeftField, lSendFromLeft); + setfieldval(*m_xSendTopField , lSendFromTop ); + + setfieldval(*m_xSizeWidthField , lWidth ); + setfieldval(*m_xSizeHeightField, lHeight); + + SetMinMax(); + + FillItem(GetParentSwEnvDlg()->m_aEnvItem); + m_xPreview->queue_draw(); +} + +void SwEnvFormatPage::SetMinMax() +{ + tools::Long lWVal = static_cast< tools::Long >(getfieldval(*m_xSizeWidthField )); + tools::Long lHVal = static_cast< tools::Long >(getfieldval(*m_xSizeHeightField)); + + tools::Long lWidth = std::max(lWVal, lHVal), + lHeight = std::min(lWVal, lHVal); + + // Min and Max + m_xAddrLeftField->set_range(100 * (getfieldval(*m_xSendLeftField) + 566), + 100 * (lWidth - 2 * 566), FieldUnit::TWIP); + m_xAddrTopField->set_range(100 * (getfieldval(*m_xSendTopField ) + 2 * 566), + 100 * (lHeight - 2 * 566), FieldUnit::TWIP); + m_xSendLeftField->set_range(100 * 566, + 100 * (getfieldval(*m_xAddrLeftField) - 566), FieldUnit::TWIP); + m_xSendTopField->set_range(100 * 566, + 100 * (getfieldval(*m_xAddrTopField ) - 2 * 566), FieldUnit::TWIP); +} + +std::unique_ptr<SfxTabPage> SwEnvFormatPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet) +{ + return std::make_unique<SwEnvFormatPage>(pPage, pController, *rSet); +} + +void SwEnvFormatPage::ActivatePage(const SfxItemSet& rSet) +{ + SfxItemSet aSet(rSet); + aSet.Put(GetParentSwEnvDlg()->m_aEnvItem); + Reset(&aSet); +} + +DeactivateRC SwEnvFormatPage::DeactivatePage(SfxItemSet* _pSet) +{ + if( _pSet ) + FillItemSet(_pSet); + return DeactivateRC::LeavePage; +} + +void SwEnvFormatPage::FillItem(SwEnvItem& rItem) +{ + rItem.m_nAddrFromLeft = static_cast< sal_Int32 >(getfieldval(*m_xAddrLeftField)); + rItem.m_nAddrFromTop = static_cast< sal_Int32 >(getfieldval(*m_xAddrTopField )); + rItem.m_nSendFromLeft = static_cast< sal_Int32 >(getfieldval(*m_xSendLeftField)); + rItem.m_nSendFromTop = static_cast< sal_Int32 >(getfieldval(*m_xSendTopField )); + + const sal_uInt16 nPaper = m_aIDs[m_xSizeFormatBox->get_active()]; + if (nPaper == sal_uInt16(PAPER_USER)) + { + tools::Long lWVal = static_cast< tools::Long >(getfieldval(*m_xSizeWidthField )); + tools::Long lHVal = static_cast< tools::Long >(getfieldval(*m_xSizeHeightField)); + rItem.m_nWidth = std::max(lWVal, lHVal); + rItem.m_nHeight = std::min(lWVal, lHVal); + } + else + { + tools::Long lWVal = SvxPaperInfo::GetPaperSize(static_cast<Paper>(nPaper)).Width (); + tools::Long lHVal = SvxPaperInfo::GetPaperSize(static_cast<Paper>(nPaper)).Height(); + rItem.m_nWidth = std::max(lWVal, lHVal); + rItem.m_nHeight = std::min(lWVal, lHVal); + } +} + +bool SwEnvFormatPage::FillItemSet(SfxItemSet* rSet) +{ + FillItem(GetParentSwEnvDlg()->m_aEnvItem); + rSet->Put(GetParentSwEnvDlg()->m_aEnvItem); + return true; +} + +void SwEnvFormatPage::Reset(const SfxItemSet* rSet) +{ + const SwEnvItem& rItem = static_cast<const SwEnvItem&>( rSet->Get(FN_ENVELOP)); + + Paper ePaper = SvxPaperInfo::GetSvxPaper( + Size( std::min(rItem.m_nWidth, rItem.m_nHeight), + std::max(rItem.m_nWidth, rItem.m_nHeight)), MapUnit::MapTwip); + for (size_t i = 0; i < m_aIDs.size(); ++i) + if (m_aIDs[i] == o3tl::narrowing<sal_uInt16>(ePaper)) + m_xSizeFormatBox->set_active(i); + + // Metric fields + setfieldval(*m_xAddrLeftField, rItem.m_nAddrFromLeft); + setfieldval(*m_xAddrTopField, rItem.m_nAddrFromTop ); + setfieldval(*m_xSendLeftField, rItem.m_nSendFromLeft); + setfieldval(*m_xSendTopField, rItem.m_nSendFromTop ); + setfieldval(*m_xSizeWidthField , std::max(rItem.m_nWidth, rItem.m_nHeight)); + setfieldval(*m_xSizeHeightField , std::min(rItem.m_nWidth, rItem.m_nHeight)); + SetMinMax(); + + GetParentSwEnvDlg()->m_pSenderSet.reset(); + GetParentSwEnvDlg()->m_pAddresseeSet.reset(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/envfmt.hxx b/sw/source/ui/envelp/envfmt.hxx new file mode 100644 index 0000000000..8b1405492c --- /dev/null +++ b/sw/source/ui/envelp/envfmt.hxx @@ -0,0 +1,76 @@ +/* -*- 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 . + */ +#pragma once + +#include <sal/config.h> + +#include <string_view> + +#include <vcl/weld.hxx> +#include <envlop.hxx> + +class SwTextFormatColl; + +class SwEnvFormatPage : public SfxTabPage +{ + SwEnvDlg* m_pDialog; + std::vector<sal_uInt16> m_aIDs; + + SwEnvPreview m_aPreview; + std::unique_ptr<weld::MetricSpinButton> m_xAddrLeftField; + std::unique_ptr<weld::MetricSpinButton> m_xAddrTopField; + std::unique_ptr<weld::MenuButton> m_xAddrEditButton; + std::unique_ptr<weld::MetricSpinButton> m_xSendLeftField; + std::unique_ptr<weld::MetricSpinButton> m_xSendTopField; + std::unique_ptr<weld::MenuButton> m_xSendEditButton; + std::unique_ptr<weld::ComboBox> m_xSizeFormatBox; + std::unique_ptr<weld::MetricSpinButton> m_xSizeWidthField; + std::unique_ptr<weld::MetricSpinButton> m_xSizeHeightField; + std::unique_ptr<weld::CustomWeld> m_xPreview; + + DECL_LINK(ModifyHdl, weld::MetricSpinButton&, void); + DECL_LINK(AddrEditHdl, const OUString&, void); + DECL_LINK(SendEditHdl, const OUString&, void); + DECL_LINK(FormatHdl, weld::ComboBox&, void); + + void SetMinMax(); + + SfxItemSet* GetCollItemSet(SwTextFormatColl const* pColl, bool bSender); + + void Edit(std::u16string_view rIdent, bool bSender); + + SwEnvDlg* GetParentSwEnvDlg() { return m_pDialog; } + +public: + SwEnvFormatPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet); + void Init(SwEnvDlg* pDialog); + virtual ~SwEnvFormatPage() override; + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet); + + virtual void ActivatePage(const SfxItemSet& rSet) override; + virtual DeactivateRC DeactivatePage(SfxItemSet* pSet) override; + void FillItem(SwEnvItem& rItem); + virtual bool FillItemSet(SfxItemSet* rSet) override; + virtual void Reset(const SfxItemSet* rSet) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/envlop1.cxx b/sw/source/ui/envelp/envlop1.cxx new file mode 100644 index 0000000000..ddffac09a6 --- /dev/null +++ b/sw/source/ui/envelp/envlop1.cxx @@ -0,0 +1,340 @@ +/* -*- 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 <dbmgr.hxx> +#include <tools/lineend.hxx> +#include <vcl/print.hxx> +#include <vcl/settings.hxx> + +#include <swwait.hxx> +#include <viewopt.hxx> + +#include <wrtsh.hxx> +#include <cmdid.h> +#include "envfmt.hxx" +#include <envlop.hxx> +#include "envprt.hxx" +#include <fmtcol.hxx> +#include <poolfmt.hxx> +#include <view.hxx> + +#include <comphelper/string.hxx> + +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +SwEnvPreview::SwEnvPreview() + : m_pDialog(nullptr) +{ +} + +void SwEnvPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + CustomWidgetController::SetDrawingArea(pDrawingArea); + pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 20, + pDrawingArea->get_text_height() * 8); +} + +void SwEnvPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + const StyleSettings& rSettings = rRenderContext.GetSettings().GetStyleSettings(); + rRenderContext.SetBackground(rRenderContext.GetSettings().GetStyleSettings().GetDialogColor()); + rRenderContext.Erase(); + + const SwEnvItem& rItem = m_pDialog->m_aEnvItem; + + const tools::Long nPageW = std::max(rItem.m_nWidth, rItem.m_nHeight); + const tools::Long nPageH = std::min(rItem.m_nWidth, rItem.m_nHeight); + + Size aSize(GetOutputSizePixel()); + + const double f = 0.8 * std::min( + double(aSize.Width()) / double(nPageW), + double(aSize.Height()) / double(nPageH)); + + Color aBack = rSettings.GetWindowColor(); + const Color& rFront = SwViewOption::GetCurrentViewOptions().GetFontColor(); + Color aMedium((aBack.GetRed() + rFront.GetRed()) / 2, + (aBack.GetGreen() + rFront.GetGreen()) / 2, + (aBack.GetBlue() + rFront.GetBlue()) / 2); + + rRenderContext.SetLineColor(rFront); + + // Envelope + const tools::Long nW = static_cast<tools::Long>(f * nPageW); + const tools::Long nH = static_cast<tools::Long>(f * nPageH); + const tools::Long nX = (aSize.Width () - nW) / 2; + const tools::Long nY = (aSize.Height() - nH) / 2; + rRenderContext.SetFillColor(aBack); + rRenderContext.DrawRect(tools::Rectangle(Point(nX, nY), Size(nW, nH))); + + // Sender + if (rItem.m_bSend) + { + const tools::Long nSendX = nX + static_cast<tools::Long>(f * rItem.m_nSendFromLeft); + const tools::Long nSendY = nY + static_cast<tools::Long>(f * rItem.m_nSendFromTop ); + const tools::Long nSendW = static_cast<tools::Long>(f * (rItem.m_nAddrFromLeft - rItem.m_nSendFromLeft)); + const tools::Long nSendH = static_cast<tools::Long>(f * (rItem.m_nAddrFromTop - rItem.m_nSendFromTop - 566)); + rRenderContext.SetFillColor(aMedium); + + rRenderContext.DrawRect(tools::Rectangle(Point(nSendX, nSendY), Size(nSendW, nSendH))); + } + + // Addressee + const tools::Long nAddrX = nX + static_cast<tools::Long>(f * rItem.m_nAddrFromLeft); + const tools::Long nAddrY = nY + static_cast<tools::Long>(f * rItem.m_nAddrFromTop ); + const tools::Long nAddrW = static_cast<tools::Long>(f * (nPageW - rItem.m_nAddrFromLeft - 566)); + const tools::Long nAddrH = static_cast<tools::Long>(f * (nPageH - rItem.m_nAddrFromTop - 566)); + rRenderContext.SetFillColor(aMedium); + rRenderContext.DrawRect(tools::Rectangle(Point(nAddrX, nAddrY), Size(nAddrW, nAddrH))); + + // Stamp + const tools::Long nStmpW = static_cast<tools::Long>(f * 1417 /* 2,5 cm */); + const tools::Long nStmpH = static_cast<tools::Long>(f * 1701 /* 3,0 cm */); + const tools::Long nStmpX = nX + nW - static_cast<tools::Long>(f * 566) - nStmpW; + const tools::Long nStmpY = nY + static_cast<tools::Long>(f * 566); + + rRenderContext.SetFillColor(aBack); + rRenderContext.DrawRect(tools::Rectangle(Point(nStmpX, nStmpY), Size(nStmpW, nStmpH))); +} + +SwEnvDlg::SwEnvDlg(weld::Window* pParent, const SfxItemSet& rSet, + SwWrtShell* pWrtSh, Printer* pPrt, bool bInsert) + : SfxTabDialogController(pParent, "modules/swriter/ui/envdialog.ui", "EnvDialog", &rSet) + , m_aEnvItem(static_cast<const SwEnvItem&>( rSet.Get(FN_ENVELOP))) + , m_pSh(pWrtSh) + , m_pPrinter(pPrt) + , m_xModify(m_xBuilder->weld_button("modify")) +{ + if (!bInsert) + { + GetUserButton()->set_label(m_xModify->get_label()); + } + + AddTabPage("envelope", SwEnvPage::Create, nullptr); + AddTabPage("format", SwEnvFormatPage::Create, nullptr); + AddTabPage("printer", SwEnvPrtPage::Create, nullptr); +} + +SwEnvDlg::~SwEnvDlg() +{ + m_pAddresseeSet.reset(); + m_pSenderSet.reset(); +} + +void SwEnvDlg::PageCreated(const OUString& rId, SfxTabPage &rPage) +{ + if (rId == "printer") + { + static_cast<SwEnvPrtPage*>(&rPage)->SetPrt(m_pPrinter); + } + else if (rId == "envelope") + { + static_cast<SwEnvPage*>(&rPage)->Init(this); + } + else if (rId == "format") + { + static_cast<SwEnvFormatPage*>(&rPage)->Init(this); + } +} + +short SwEnvDlg::Ok() +{ + short nRet = SfxTabDialogController::Ok(); + + if (nRet == RET_OK || nRet == RET_USER) + { + if (m_pAddresseeSet) + { + SwTextFormatColl* pColl = m_pSh->GetTextCollFromPool(RES_POOLCOLL_ENVELOPE_ADDRESS); + pColl->SetFormatAttr(*m_pAddresseeSet); + } + if (m_pSenderSet) + { + SwTextFormatColl* pColl = m_pSh->GetTextCollFromPool(RES_POOLCOLL_SEND_ADDRESS); + pColl->SetFormatAttr(*m_pSenderSet); + } + } + + return nRet; +} + +SwEnvPage::SwEnvPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/envaddresspage.ui", "EnvAddressPage", &rSet) + , m_pDialog(nullptr) + , m_pSh(nullptr) + , m_xAddrEdit(m_xBuilder->weld_text_view("addredit")) + , m_xDatabaseLB(m_xBuilder->weld_combo_box("database")) + , m_xTableLB(m_xBuilder->weld_combo_box("table")) + , m_xDBFieldLB(m_xBuilder->weld_combo_box("field")) + , m_xInsertBT(m_xBuilder->weld_button("insert")) + , m_xSenderBox(m_xBuilder->weld_check_button("sender")) + , m_xSenderEdit(m_xBuilder->weld_text_view("senderedit")) + , m_xPreview(new weld::CustomWeld(*m_xBuilder, "preview", m_aPreview)) +{ + auto nTextBoxHeight(m_xAddrEdit->get_height_rows(10)); + auto nTextBoxWidth(m_xAddrEdit->get_approximate_digit_width() * 25); + + m_xAddrEdit->set_size_request(nTextBoxWidth, nTextBoxHeight); + m_xSenderEdit->set_size_request(nTextBoxWidth, nTextBoxHeight); + + auto nListBoxWidth = m_xTableLB->get_approximate_digit_width() * 25; + m_xTableLB->set_size_request(nListBoxWidth, -1); + m_xDatabaseLB->set_size_request(nListBoxWidth, -1); + m_xDBFieldLB->set_size_request(nListBoxWidth, -1); + + SetExchangeSupport(); +} + +void SwEnvPage::Init(SwEnvDlg* pDialog) +{ + m_pDialog = pDialog; + m_pSh = m_pDialog->m_pSh; + m_aPreview.SetDialog(pDialog); + + // Install handlers + m_xDatabaseLB->connect_changed(LINK(this, SwEnvPage, DatabaseHdl)); + m_xTableLB->connect_changed(LINK(this, SwEnvPage, DatabaseHdl)); + m_xInsertBT->connect_clicked(LINK(this, SwEnvPage, FieldHdl)); + m_xSenderBox->connect_toggled(LINK(this, SwEnvPage, SenderHdl)); + + SwDBData aData = m_pSh->GetDBData(); + m_sActDBName = aData.sDataSource + OUStringChar(DB_DELIM) + aData.sCommand; + InitDatabaseBox(); +} + +SwEnvPage::~SwEnvPage() +{ +} + +IMPL_LINK( SwEnvPage, DatabaseHdl, weld::ComboBox&, rListBox, void ) +{ + SwWait aWait( *m_pSh->GetView().GetDocShell(), true ); + + if (&rListBox == m_xDatabaseLB.get()) + { + m_sActDBName = rListBox.get_active_text(); + m_pSh->GetDBManager()->GetTableNames(*m_xTableLB, m_sActDBName); + m_sActDBName += OUStringChar(DB_DELIM); + } + else + { + m_sActDBName = comphelper::string::setToken(m_sActDBName, 1, DB_DELIM, m_xTableLB->get_active_text()); + } + m_pSh->GetDBManager()->GetColumnNames(*m_xDBFieldLB, m_xDatabaseLB->get_active_text(), + m_xTableLB->get_active_text()); +} + +IMPL_LINK_NOARG(SwEnvPage, FieldHdl, weld::Button&, void) +{ + OUString aStr("<" + m_xDatabaseLB->get_active_text() + "." + + m_xTableLB->get_active_text() + "." + + m_xTableLB->get_active_id() + "." + + m_xDBFieldLB->get_active_text() + ">"); + m_xAddrEdit->replace_selection(aStr); + int nStartPos, nEndPos; + m_xAddrEdit->get_selection_bounds(nStartPos, nEndPos); + m_xAddrEdit->grab_focus(); + m_xAddrEdit->select_region(nStartPos, nEndPos); +} + +IMPL_LINK_NOARG(SwEnvPage, SenderHdl, weld::Toggleable&, void) +{ + const bool bEnable = m_xSenderBox->get_active(); + GetParentSwEnvDlg()->m_aEnvItem.m_bSend = bEnable; + m_xSenderEdit->set_sensitive(bEnable); + if (bEnable) + { + m_xSenderEdit->grab_focus(); + if (m_xSenderEdit->get_text().isEmpty()) + m_xSenderEdit->set_text(MakeSender()); + } + m_xPreview->queue_draw(); +} + +void SwEnvPage::InitDatabaseBox() +{ + if (!m_pSh->GetDBManager()) + return; + + m_xDatabaseLB->clear(); + const Sequence<OUString> aDataNames = SwDBManager::GetExistingDatabaseNames(); + + for (const OUString& rDataName : aDataNames) + m_xDatabaseLB->append_text(rDataName); + + sal_Int32 nIdx{ 0 }; + OUString sDBName = m_sActDBName.getToken( 0, DB_DELIM, nIdx ); + OUString sTableName = m_sActDBName.getToken( 0, DB_DELIM, nIdx ); + m_xDatabaseLB->set_active_text(sDBName); + if (m_pSh->GetDBManager()->GetTableNames(*m_xTableLB, sDBName)) + { + m_xTableLB->append_text(sTableName); + m_pSh->GetDBManager()->GetColumnNames(*m_xDBFieldLB, sDBName, sTableName); + } + else + m_xDBFieldLB->clear(); +} + +std::unique_ptr<SfxTabPage> SwEnvPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet) +{ + return std::make_unique<SwEnvPage>(pPage, pController, *rSet); +} + +void SwEnvPage::ActivatePage(const SfxItemSet& rSet) +{ + SfxItemSet aSet(rSet); + aSet.Put(GetParentSwEnvDlg()->m_aEnvItem); + Reset(&aSet); +} + +DeactivateRC SwEnvPage::DeactivatePage(SfxItemSet* _pSet) +{ + FillItem(GetParentSwEnvDlg()->m_aEnvItem); + if( _pSet ) + FillItemSet(_pSet); + return DeactivateRC::LeavePage; +} + +void SwEnvPage::FillItem(SwEnvItem& rItem) +{ + rItem.m_aAddrText = m_xAddrEdit->get_text(); + rItem.m_bSend = m_xSenderBox->get_active(); + rItem.m_aSendText = m_xSenderEdit->get_text(); +} + +bool SwEnvPage::FillItemSet(SfxItemSet* rSet) +{ + FillItem(GetParentSwEnvDlg()->m_aEnvItem); + rSet->Put(GetParentSwEnvDlg()->m_aEnvItem); + return true; +} + +void SwEnvPage::Reset(const SfxItemSet* rSet) +{ + SwEnvItem aItem = static_cast<const SwEnvItem&>( rSet->Get(FN_ENVELOP)); + m_xAddrEdit->set_text(convertLineEnd(aItem.m_aAddrText, GetSystemLineEnd())); + m_xSenderEdit->set_text(convertLineEnd(aItem.m_aSendText, GetSystemLineEnd())); + m_xSenderBox->set_active(aItem.m_bSend); + SenderHdl(*m_xSenderBox); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/envprt.cxx b/sw/source/ui/envelp/envprt.cxx new file mode 100644 index 0000000000..d08f718e1f --- /dev/null +++ b/sw/source/ui/envelp/envprt.cxx @@ -0,0 +1,190 @@ +/* -*- 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 <vcl/print.hxx> +#include <svtools/prnsetup.hxx> +#include <svtools/unitconv.hxx> + +#include <cmdid.h> +#include "envprt.hxx" +#include <envlop.hxx> +#include <uitool.hxx> + +SwEnvPrtPage::SwEnvPrtPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/envprinterpage.ui", "EnvPrinterPage", &rSet) + , m_xUpper(m_xBuilder->weld_widget("upper")) + , m_xLower(m_xBuilder->weld_widget("lower")) + , m_xTopButton(m_xBuilder->weld_radio_button("top")) + , m_xBottomButton(m_xBuilder->weld_radio_button("bottom")) + , m_xRightField(m_xBuilder->weld_metric_spin_button("right", FieldUnit::CM)) + , m_xDownField(m_xBuilder->weld_metric_spin_button("down", FieldUnit::CM)) + , m_xPrinterInfo(m_xBuilder->weld_label("printername")) + , m_xPrtSetup(m_xBuilder->weld_button("setup")) + , m_aIdsL { m_xBuilder->weld_radio_button("horileftl"), + m_xBuilder->weld_radio_button("horicenterl"), + m_xBuilder->weld_radio_button("horirightl"), + m_xBuilder->weld_radio_button("vertleftl"), + m_xBuilder->weld_radio_button("vertcenterl"), + m_xBuilder->weld_radio_button("vertrightl") } + , m_aIdsU { m_xBuilder->weld_radio_button("horileftu"), + m_xBuilder->weld_radio_button("horicenteru"), + m_xBuilder->weld_radio_button("horirightu"), + m_xBuilder->weld_radio_button("vertleftu"), + m_xBuilder->weld_radio_button("vertcenteru"), + m_xBuilder->weld_radio_button("vertrightu") } +{ + SetExchangeSupport(); + + // Metrics + FieldUnit eUnit = ::GetDfltMetric(false); + ::SetFieldUnit(*m_xRightField, eUnit); + ::SetFieldUnit(*m_xDownField, eUnit); + + // Install handlers + m_xTopButton->connect_toggled(LINK(this, SwEnvPrtPage, ClickHdl)); + m_xBottomButton->connect_toggled(LINK(this, SwEnvPrtPage, ClickHdl)); + + m_xPrtSetup->connect_clicked(LINK(this, SwEnvPrtPage, ButtonHdl)); + + for (auto& a : m_aIdsL) + a->connect_toggled(LINK(this, SwEnvPrtPage, LowerHdl)); + for (auto& a : m_aIdsU) + a->connect_toggled(LINK(this, SwEnvPrtPage, UpperHdl)); + + // Bitmaps + ClickHdl(*m_xBottomButton); +} + +SwEnvPrtPage::~SwEnvPrtPage() +{ + m_xPrt.clear(); +} + +IMPL_LINK_NOARG(SwEnvPrtPage, ClickHdl, weld::Toggleable&, void) +{ + // Envelope from bottom, otherwise Envelope from top + const bool bLowerActive = m_xBottomButton->get_active(); + m_xUpper->set_visible(!bLowerActive); + m_xLower->set_visible(bLowerActive); +} + +IMPL_LINK(SwEnvPrtPage, LowerHdl, weld::Toggleable&, rButton, void) +{ + for (int i = ENV_HOR_LEFT; i <= ENV_VER_RGHT; ++i) + { + if (&rButton == m_aIdsL[i].get()) + { + m_aIdsU[i]->set_active(m_aIdsL[i]->get_active()); + break; + } + } +} + +IMPL_LINK(SwEnvPrtPage, UpperHdl, weld::Toggleable&, rButton, void) +{ + for (int i = ENV_HOR_LEFT; i <= ENV_VER_RGHT; ++i) + { + if (&rButton == m_aIdsU[i].get()) + { + m_aIdsL[i]->set_active(m_aIdsU[i]->get_active()); + break; + } + } +} + +IMPL_LINK(SwEnvPrtPage, ButtonHdl, weld::Button&, rBtn, void) +{ + if (&rBtn == m_xPrtSetup.get()) + { + // Call printer setup + if (m_xPrt) + { + PrinterSetupDialog aDlg(GetFrameWeld()); + aDlg.SetPrinter(m_xPrt); + aDlg.run(); + rBtn.grab_focus(); + m_xPrinterInfo->set_label(m_xPrt->GetName()); + } + } +} + +std::unique_ptr<SfxTabPage> SwEnvPrtPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet) +{ + return std::make_unique<SwEnvPrtPage>(pPage, pController, *rSet); +} + +void SwEnvPrtPage::ActivatePage(const SfxItemSet&) +{ + if (m_xPrt) + m_xPrinterInfo->set_label(m_xPrt->GetName()); +} + +DeactivateRC SwEnvPrtPage::DeactivatePage(SfxItemSet* _pSet) +{ + if( _pSet ) + FillItemSet(_pSet); + return DeactivateRC::LeavePage; +} + +void SwEnvPrtPage::FillItem(SwEnvItem& rItem) +{ + int nOrient = 0; + for (int i = ENV_HOR_LEFT; i <= ENV_VER_RGHT; ++i) + { + assert(m_aIdsL[i]->get_active() == m_aIdsU[i]->get_active()); + if (m_aIdsL[i]->get_active()) + { + nOrient = i; + break; + } + } + + rItem.m_eAlign = static_cast<SwEnvAlign>(nOrient); + rItem.m_bPrintFromAbove = m_xTopButton->get_active(); + rItem.m_nShiftRight = getfieldval(*m_xRightField); + rItem.m_nShiftDown = getfieldval(*m_xDownField); +} + +bool SwEnvPrtPage::FillItemSet(SfxItemSet* rSet) +{ + FillItem(GetParentSwEnvDlg()->m_aEnvItem); + rSet->Put(GetParentSwEnvDlg()->m_aEnvItem); + return true; +} + +void SwEnvPrtPage::Reset(const SfxItemSet* rSet) +{ + // Read item + const SwEnvItem& rItem = static_cast<const SwEnvItem&>( rSet->Get(FN_ENVELOP) ); + m_aIdsL[rItem.m_eAlign]->set_active(true); + m_aIdsU[rItem.m_eAlign]->set_active(true); + + if (rItem.m_bPrintFromAbove) + m_xTopButton->set_active(true); + else + m_xBottomButton->set_active(true); + + setfieldval(*m_xRightField, rItem.m_nShiftRight); + setfieldval(*m_xDownField , rItem.m_nShiftDown ); + + ActivatePage(*rSet); + ClickHdl(*m_xTopButton); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/envprt.hxx b/sw/source/ui/envelp/envprt.hxx new file mode 100644 index 0000000000..4cc3bf4f78 --- /dev/null +++ b/sw/source/ui/envelp/envprt.hxx @@ -0,0 +1,71 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sfx2/tabdlg.hxx> +#include <vcl/print.hxx> +#include <vcl/weld.hxx> + +#include <envimg.hxx> +#include <envlop.hxx> + +class SwEnvDlg; + +class SwEnvPrtPage : public SfxTabPage +{ + std::unique_ptr<weld::Widget> m_xUpper; + std::unique_ptr<weld::Widget> m_xLower; + std::unique_ptr<weld::RadioButton> m_xTopButton; + std::unique_ptr<weld::RadioButton> m_xBottomButton; + std::unique_ptr<weld::MetricSpinButton> m_xRightField; + std::unique_ptr<weld::MetricSpinButton> m_xDownField; + std::unique_ptr<weld::Label> m_xPrinterInfo; + std::unique_ptr<weld::Button> m_xPrtSetup; + + std::unique_ptr<weld::RadioButton> m_aIdsL[ENV_VER_RGHT - ENV_HOR_LEFT + 1]; + std::unique_ptr<weld::RadioButton> m_aIdsU[ENV_VER_RGHT - ENV_HOR_LEFT + 1]; + + VclPtr<Printer> m_xPrt; + + DECL_LINK(LowerHdl, weld::Toggleable&, void); + DECL_LINK(UpperHdl, weld::Toggleable&, void); + DECL_LINK(ClickHdl, weld::Toggleable&, void); + DECL_LINK(ButtonHdl, weld::Button&, void); + + SwEnvDlg* GetParentSwEnvDlg() { return static_cast<SwEnvDlg*>(GetDialogController()); } + +public: + SwEnvPrtPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet); + virtual ~SwEnvPrtPage() override; + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet); + + virtual void ActivatePage(const SfxItemSet& rSet) override; + virtual DeactivateRC DeactivatePage(SfxItemSet* pSet) override; + void FillItem(SwEnvItem& rItem); + virtual bool FillItemSet(SfxItemSet* rSet) override; + virtual void Reset(const SfxItemSet* rSet) override; + + void SetPrt(Printer* pPrinter) { m_xPrt = pPrinter; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/label1.cxx b/sw/source/ui/envelp/label1.cxx new file mode 100644 index 0000000000..8e9a3c3eff --- /dev/null +++ b/sw/source/ui/envelp/label1.cxx @@ -0,0 +1,717 @@ +/* -*- 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 <memory> +#include <vcl/svapp.hxx> +#include <rtl/ustring.hxx> +#include <tools/lineend.hxx> +#include <svtools/unitconv.hxx> +#include <com/sun/star/uno/Sequence.h> +#include <swtypes.hxx> +#include <labimp.hxx> +#include "swuilabimp.hxx" +#include "labfmt.hxx" +#include "labprt.hxx" +#include <dbmgr.hxx> +#include <uitool.hxx> +#include <cmdid.h> +#include <helpids.h> +#include <strings.hrc> +#include <envimg.hxx> + +void SwLabRec::SetFromItem( const SwLabItem& rItem ) +{ + m_nHDist = rItem.m_lHDist; + m_nVDist = rItem.m_lVDist; + m_nWidth = rItem.m_lWidth; + m_nHeight = rItem.m_lHeight; + m_nLeft = rItem.m_lLeft; + m_nUpper = rItem.m_lUpper; + m_nCols = rItem.m_nCols; + m_nRows = rItem.m_nRows; + m_nPWidth = rItem.m_lPWidth; + m_nPHeight = rItem.m_lPHeight; + m_bCont = rItem.m_bCont; +} + +void SwLabRec::FillItem( SwLabItem& rItem ) const +{ + rItem.m_lHDist = m_nHDist; + rItem.m_lVDist = m_nVDist; + rItem.m_lWidth = m_nWidth; + rItem.m_lHeight = m_nHeight; + rItem.m_lLeft = m_nLeft; + rItem.m_lUpper = m_nUpper; + rItem.m_nCols = m_nCols; + rItem.m_lPWidth = m_nPWidth; + rItem.m_lPHeight = m_nPHeight; + rItem.m_nRows = m_nRows; +} + +void SwLabDlg::ReplaceGroup_( const OUString &rMake ) +{ + // Remove old entries + m_pRecs->erase(m_pRecs->begin() + 1, m_pRecs->end()); + m_aLabelsCfg.FillLabels(rMake, *m_pRecs); + m_aLstGroup = rMake; +} + +void SwLabDlg::PageCreated(const OUString &rId, SfxTabPage &rPage) +{ + if (rId == "labels") + { + static_cast<SwLabPage*>(&rPage)->SetDBManager(m_pDBManager); + static_cast<SwLabPage*>(&rPage)->InitDatabaseBox(); + if (!m_bLabel) + static_cast<SwLabPage*>(&rPage)->SetToBusinessCard(); + } + else if (rId == "options") + m_pPrtPage = static_cast<SwLabPrtPage*>(&rPage); +} + +SwLabDlg::SwLabDlg(weld::Window* pParent, const SfxItemSet& rSet, + SwDBManager* pDBManager_, bool bLabel) + : SfxTabDialogController(pParent, "modules/swriter/ui/labeldialog.ui", "LabelDialog", &rSet) + , m_pDBManager(pDBManager_) + , m_pPrtPage(nullptr) + , m_aTypeIds(50, 10) + , m_pRecs(new SwLabRecs) + , m_bLabel(bLabel) +{ + weld::WaitObject aWait(pParent); + + // Read user label from writer.cfg + SwLabItem aItem(static_cast<const SwLabItem&>(rSet.Get( FN_LABEL ))); + std::unique_ptr<SwLabRec> pRec(new SwLabRec); + pRec->m_aMake = pRec->m_aType = SwResId(STR_CUSTOM_LABEL); + pRec->SetFromItem( aItem ); + + bool bDouble = false; + + for (const std::unique_ptr<SwLabRec> & i : *m_pRecs) + { + if (pRec->m_aMake == i->m_aMake && + pRec->m_aType == i->m_aType) + { + bDouble = true; + break; + } + } + + if (!bDouble) + m_pRecs->insert( m_pRecs->begin(), std::move(pRec)); + + size_t nLstGroup = 0; + const std::vector<OUString>& rMan = m_aLabelsCfg.GetManufacturers(); + for(size_t nMan = 0; nMan < rMan.size(); ++nMan) + { + m_aMakes.push_back(rMan[nMan]); + if ( rMan[nMan] == aItem.m_aLstMake ) + nLstGroup = nMan; + } + + if ( !m_aMakes.empty() ) + ReplaceGroup_( m_aMakes[nLstGroup] ); + + if (m_xExampleSet) + m_xExampleSet->Put(aItem); + + AddTabPage("format", SwLabFormatPage::Create, nullptr); + AddTabPage("options", SwLabPrtPage::Create, nullptr); + AddTabPage("labels", SwLabPage::Create, nullptr); + m_sBusinessCardDlg = SwResId(STR_BUSINESS_CARDS); + + if (m_bLabel) + { + RemoveTabPage("business"); + RemoveTabPage("private"); + } + else + { + AddTabPage("business", SwBusinessDataPage::Create, nullptr ); + AddTabPage("private", SwPrivateDataPage::Create, nullptr); + m_xDialog->set_title(m_sBusinessCardDlg); + } +} + +SwLabDlg::~SwLabDlg() +{ + m_pRecs.reset(); +} + +void SwLabDlg::GetLabItem(SwLabItem &rItem) +{ + const SwLabItem& rActItem = static_cast<const SwLabItem&>(GetExampleSet()->Get(FN_LABEL)); + const SwLabItem& rOldItem = static_cast<const SwLabItem&>(GetInputSetImpl()->Get(FN_LABEL)); + + if (rActItem != rOldItem) + { + // Was already "put" with (hopefully) correct content + rItem = rActItem; + } + else + { + rItem = rOldItem; + + // In rItem there are only settings defined by users. + // Therefore get the real settings directly from Record + SwLabRec* pRec = GetRecord(rItem.m_aType, rItem.m_bCont); + pRec->FillItem( rItem ); + } +} + +SwLabRec* SwLabDlg::GetRecord(std::u16string_view rRecName, bool bCont) +{ + SwLabRec* pRec = nullptr; + bool bFound = false; + const OUString sCustom(SwResId(STR_CUSTOM_LABEL)); + + const size_t nCount = Recs().size(); + for (size_t i = 0; i < nCount; ++i) + { + pRec = Recs()[i].get(); + if (pRec->m_aType != sCustom && + rRecName == pRec->m_aType && bCont == pRec->m_bCont) + { + bFound = true; + break; + } + } + if (!bFound) // User defined + pRec = Recs()[0].get(); + + return pRec; +} + +Printer *SwLabDlg::GetPrt() +{ + if (m_pPrtPage) + return m_pPrtPage->GetPrt(); + else + return nullptr; +} + +SwLabPage::SwLabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/cardmediumpage.ui", "CardMediumPage", &rSet) + , m_pDBManager(nullptr) + , m_aItem(static_cast<const SwLabItem&>(rSet.Get(FN_LABEL))) + , m_xAddressFrame(m_xBuilder->weld_widget("addressframe")) + , m_xAddrBox(m_xBuilder->weld_check_button("address")) + , m_xWritingEdit(m_xBuilder->weld_text_view("textview")) + , m_xDatabaseLB(m_xBuilder->weld_combo_box("database")) + , m_xTableLB(m_xBuilder->weld_combo_box("table")) + , m_xInsertBT(m_xBuilder->weld_button("insert")) + , m_xDBFieldLB(m_xBuilder->weld_combo_box("field")) + , m_xContButton(m_xBuilder->weld_radio_button("continuous")) + , m_xSheetButton(m_xBuilder->weld_radio_button("sheet")) + , m_xMakeBox(m_xBuilder->weld_combo_box("brand")) + , m_xTypeBox(m_xBuilder->weld_combo_box("type")) + , m_xHiddenSortTypeBox(m_xBuilder->weld_combo_box("hiddentype")) + , m_xFormatInfo(m_xBuilder->weld_label("formatinfo")) +{ + weld::WaitObject aWait(GetFrameWeld()); + + m_xWritingEdit->set_size_request(m_xWritingEdit->get_approximate_digit_width() * 30, + m_xWritingEdit->get_height_rows(10)); + m_xHiddenSortTypeBox->make_sorted(); + + tools::Long nListBoxWidth = m_xWritingEdit->get_approximate_digit_width() * 25; + m_xTableLB->set_size_request(nListBoxWidth, -1); + m_xDatabaseLB->set_size_request(nListBoxWidth, -1); + m_xDBFieldLB->set_size_request(nListBoxWidth, -1); + + SetExchangeSupport(); + + // Install handlers + m_xAddrBox->connect_toggled(LINK(this, SwLabPage, AddrHdl)); + m_xDatabaseLB->connect_changed(LINK(this, SwLabPage, DatabaseHdl)); + m_xTableLB->connect_changed(LINK(this, SwLabPage, DatabaseHdl)); + m_xDBFieldLB->connect_changed(LINK(this, SwLabPage, DatabaseHdl)); + m_xInsertBT->connect_clicked(LINK(this, SwLabPage, FieldHdl)); + // Disable insert button first, + // it'll be enabled if m_xDatabaseLB, m_pTableLB and m_pInsertBT are filled + m_xInsertBT->set_sensitive(false); + m_xContButton->connect_toggled(LINK(this, SwLabPage, PageHdl)); + m_xSheetButton->connect_toggled(LINK(this, SwLabPage, PageHdl)); + auto nMaxWidth = m_xMakeBox->get_approximate_digit_width() * 32; + m_xMakeBox->set_size_request(nMaxWidth, -1); + m_xTypeBox->set_size_request(nMaxWidth, -1); + m_xMakeBox->connect_changed(LINK(this, SwLabPage, MakeHdl)); + m_xTypeBox->connect_changed(LINK(this, SwLabPage, TypeHdl)); + + InitDatabaseBox(); +} + +SwLabPage::~SwLabPage() +{ +} + +void SwLabPage::SetToBusinessCard() +{ + m_xContainer->set_help_id(HID_BUSINESS_FMT_PAGE); + m_xContButton->set_help_id(HID_BUSINESS_FMT_PAGE_CONT); + m_xSheetButton->set_help_id(HID_BUSINESS_FMT_PAGE_SHEET); + m_xMakeBox->set_help_id(HID_BUSINESS_FMT_PAGE_BRAND); + m_xTypeBox->set_help_id(HID_BUSINESS_FMT_PAGE_TYPE); +}; + +IMPL_LINK_NOARG(SwLabPage, AddrHdl, weld::Toggleable&, void) +{ + OUString aWriting; + + if (m_xAddrBox->get_active()) + aWriting = convertLineEnd(MakeSender(), GetSystemLineEnd()); + + m_xWritingEdit->set_text(aWriting); + m_xWritingEdit->grab_focus(); +} + +IMPL_LINK( SwLabPage, DatabaseHdl, weld::ComboBox&, rListBox, void ) +{ + m_sActDBName = m_xDatabaseLB->get_active_text(); + + weld::WaitObject aObj(GetParentSwLabDlg()->getDialog()); + + if (&rListBox == m_xDatabaseLB.get()) + GetDBManager()->GetTableNames(*m_xTableLB, m_sActDBName); + + if (&rListBox == m_xDatabaseLB.get() || &rListBox == m_xTableLB.get()) + GetDBManager()->GetColumnNames(*m_xDBFieldLB, m_sActDBName, m_xTableLB->get_active_text()); + + if (!m_xDatabaseLB->get_active_text().isEmpty() && !m_xTableLB->get_active_text().isEmpty() + && !m_xDBFieldLB->get_active_text().isEmpty()) + m_xInsertBT->set_sensitive(true); + else + m_xInsertBT->set_sensitive(false); +} + +IMPL_LINK_NOARG(SwLabPage, FieldHdl, weld::Button&, void) +{ + OUString aStr("<" + m_xDatabaseLB->get_active_text() + "." + + m_xTableLB->get_active_text() + "." + + m_xTableLB->get_active_id() + "." + + m_xDBFieldLB->get_active_text() + ">"); + m_xWritingEdit->replace_selection(aStr); + int nStartPos, nEndPos; + m_xWritingEdit->get_selection_bounds(nStartPos, nEndPos); + m_xWritingEdit->grab_focus(); + m_xWritingEdit->select_region(nStartPos, nEndPos); +} + +IMPL_LINK_NOARG(SwLabPage, PageHdl, weld::Toggleable&, void) +{ + MakeHdl(*m_xMakeBox); +} + +IMPL_LINK_NOARG(SwLabPage, MakeHdl, weld::ComboBox&, void) +{ + weld::WaitObject aWait(GetParentSwLabDlg()->getDialog()); + + m_xTypeBox->clear(); + m_xHiddenSortTypeBox->clear(); + GetParentSwLabDlg()->TypeIds().clear(); + + const OUString aMake = m_xMakeBox->get_active_text(); + GetParentSwLabDlg()->ReplaceGroup( aMake ); + m_aItem.m_aLstMake = aMake; + + const bool bCont = m_xContButton->get_active(); + const size_t nCount = GetParentSwLabDlg()->Recs().size(); + size_t nLstType = 0; + + const OUString sCustom(SwResId(STR_CUSTOM_LABEL)); + //insert the entries into the sorted list box + for ( size_t i = 0; i < nCount; ++i ) + { + const OUString aType(GetParentSwLabDlg()->Recs()[i]->m_aType); + bool bInsert = false; + if (GetParentSwLabDlg()->Recs()[i]->m_aType == sCustom) + { + bInsert = true; + m_xTypeBox->append_text(aType ); + } + else if (GetParentSwLabDlg()->Recs()[i]->m_bCont == bCont) + { + if (m_xHiddenSortTypeBox->find_text(aType) == -1) + { + bInsert = true; + m_xHiddenSortTypeBox->append_text( aType ); + } + } + if(bInsert) + { + GetParentSwLabDlg()->TypeIds().push_back(i); + if ( !nLstType && aType == m_aItem.m_aLstType ) + nLstType = GetParentSwLabDlg()->TypeIds().size(); + } + } + for (int nEntry = 0; nEntry < m_xHiddenSortTypeBox->get_count(); ++nEntry) + { + m_xTypeBox->append_text(m_xHiddenSortTypeBox->get_text(nEntry)); + } + if (nLstType) + m_xTypeBox->set_active_text(m_aItem.m_aLstType); + else + m_xTypeBox->set_active(0); + TypeHdl(*m_xTypeBox); +} + +IMPL_LINK_NOARG(SwLabPage, TypeHdl, weld::ComboBox&, void) +{ + DisplayFormat(); + m_aItem.m_aType = m_xTypeBox->get_active_text(); +} + +void SwLabPage::DisplayFormat() +{ + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "cui/ui/spinbox.ui")); + std::unique_ptr<weld::Dialog> xTopLevel(xBuilder->weld_dialog("SpinDialog")); + std::unique_ptr<weld::MetricSpinButton> xField(xBuilder->weld_metric_spin_button("spin", FieldUnit::CM)); + SetFieldUnit(*xField, ::GetDfltMetric(false)); + xField->set_digits(2); + xField->set_range(0, INT_MAX - 1, FieldUnit::NONE); + + SwLabRec* pRec = GetSelectedEntryPos(); + m_aItem.m_aLstType = pRec->m_aType; + setfldval(*xField, pRec->m_nWidth); + xField->reformat(); + const OUString aWString = xField->get_text(); + + setfldval(*xField, pRec->m_nHeight); + xField->reformat(); + + OUString aText = pRec->m_aType + ": " + aWString + + " x " + xField->get_text() + + " (" + OUString::number( pRec->m_nCols ) + + " x " + OUString::number( pRec->m_nRows ) + ")"; + m_xFormatInfo->set_label(aText); +} + +SwLabRec* SwLabPage::GetSelectedEntryPos() +{ + OUString sSelEntry(m_xTypeBox->get_active_text()); + + return GetParentSwLabDlg()->GetRecord(sSelEntry, m_xContButton->get_active()); +} + +void SwLabPage::InitDatabaseBox() +{ + if( !GetDBManager() ) + return; + + m_xDatabaseLB->clear(); + const css::uno::Sequence<OUString> aDataNames = SwDBManager::GetExistingDatabaseNames(); + for (const OUString& rDataName : aDataNames) + m_xDatabaseLB->append_text(rDataName); + sal_Int32 nIdx{ 0 }; + OUString sDBName = m_sActDBName.getToken( 0, DB_DELIM, nIdx ); + OUString sTableName = m_sActDBName.getToken( 0, DB_DELIM, nIdx ); + m_xDatabaseLB->set_active_text(sDBName); + if( !sDBName.isEmpty() && GetDBManager()->GetTableNames(*m_xTableLB, sDBName)) + { + m_xTableLB->set_active_text(sTableName); + GetDBManager()->GetColumnNames(*m_xDBFieldLB, m_sActDBName, sTableName); + } + else + m_xDBFieldLB->clear(); +} + +std::unique_ptr<SfxTabPage> SwLabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet) +{ + return std::make_unique<SwLabPage>(pPage, pController, *rSet); +} + +void SwLabPage::ActivatePage(const SfxItemSet& rSet) +{ + Reset( &rSet ); +} + +DeactivateRC SwLabPage::DeactivatePage(SfxItemSet* _pSet) +{ + if (_pSet) + FillItemSet(_pSet); + + return DeactivateRC::LeavePage; +} + +void SwLabPage::FillItem(SwLabItem& rItem) +{ + rItem.m_bAddr = m_xAddrBox->get_active(); + rItem.m_aWriting = m_xWritingEdit->get_text(); + rItem.m_bCont = m_xContButton->get_active(); + rItem.m_aMake = m_xMakeBox->get_active_text(); + rItem.m_aType = m_xTypeBox->get_active_text(); + rItem.m_sDBName = m_sActDBName; + + SwLabRec* pRec = GetSelectedEntryPos(); + pRec->FillItem( rItem ); + + rItem.m_aLstMake = m_xMakeBox->get_active_text(); + rItem.m_aLstType = m_xTypeBox->get_active_text(); +} + +bool SwLabPage::FillItemSet(SfxItemSet* rSet) +{ + FillItem( m_aItem ); + rSet->Put( m_aItem ); + + return true; +} + +void SwLabPage::Reset(const SfxItemSet* rSet) +{ + m_xMakeBox->clear(); + + size_t nLstGroup = 0; + + const size_t nCount = GetParentSwLabDlg()->Makes().size(); + for(size_t i = 0; i < nCount; ++i) + { + OUString& rStr = GetParentSwLabDlg()->Makes()[i]; + m_xMakeBox->append_text(rStr); + + if ( rStr == m_aItem.m_aLstMake) + nLstGroup = i; + } + + m_xMakeBox->set_active( nLstGroup ); + MakeHdl(*m_xMakeBox); + + m_aItem = static_cast<const SwLabItem&>( rSet->Get(FN_LABEL)); + OUString sDBName = m_aItem.m_sDBName; + + OUString aWriting(convertLineEnd(m_aItem.m_aWriting, GetSystemLineEnd())); + + m_xAddrBox->set_active( m_aItem.m_bAddr ); + m_xWritingEdit->set_text( aWriting ); + + for(const auto& rMake : GetParentSwLabDlg()->Makes()) + { + if (m_xMakeBox->find_text(rMake) == -1) + m_xMakeBox->append_text(rMake); + } + + m_xMakeBox->set_active_text(m_aItem.m_aMake); + //save the current type + OUString sType(m_aItem.m_aType); + MakeHdl(*m_xMakeBox); + m_aItem.m_aType = sType; + //#102806# a newly added make may not be in the type ListBox already + if (m_xTypeBox->find_text(m_aItem.m_aType) == -1 && !m_aItem.m_aMake.isEmpty()) + GetParentSwLabDlg()->UpdateGroup( m_aItem.m_aMake ); + if (m_xTypeBox->find_text(m_aItem.m_aType) != -1) + { + m_xTypeBox->set_active_text(m_aItem.m_aType); + TypeHdl(*m_xTypeBox); + } + if (m_xDatabaseLB->find_text(sDBName) != -1) + { + m_xDatabaseLB->set_active_text(sDBName); + DatabaseHdl(*m_xDatabaseLB); + } + + if (m_aItem.m_bCont) + m_xContButton->set_active(true); + else + m_xSheetButton->set_active(true); +} + +SwPrivateDataPage::SwPrivateDataPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/privateuserpage.ui", "PrivateUserPage", &rSet) + , m_xFirstNameED(m_xBuilder->weld_entry("firstname")) + , m_xNameED(m_xBuilder->weld_entry("lastname")) + , m_xShortCutED(m_xBuilder->weld_entry("shortname")) + , m_xFirstName2ED(m_xBuilder->weld_entry("firstname2")) + , m_xName2ED(m_xBuilder->weld_entry("lastname2")) + , m_xShortCut2ED(m_xBuilder->weld_entry("shortname2")) + , m_xStreetED(m_xBuilder->weld_entry("street")) + , m_xZipED(m_xBuilder->weld_entry("izip")) + , m_xCityED(m_xBuilder->weld_entry("icity")) + , m_xCountryED(m_xBuilder->weld_entry("country")) + , m_xStateED(m_xBuilder->weld_entry("state")) + , m_xTitleED(m_xBuilder->weld_entry("title")) + , m_xProfessionED(m_xBuilder->weld_entry("job")) + , m_xPhoneED(m_xBuilder->weld_entry("phone")) + , m_xMobilePhoneED(m_xBuilder->weld_entry("mobile")) + , m_xFaxED(m_xBuilder->weld_entry("fax")) + , m_xHomePageED(m_xBuilder->weld_entry("url")) + , m_xMailED(m_xBuilder->weld_entry("email")) +{ + SetExchangeSupport(); +} + +SwPrivateDataPage::~SwPrivateDataPage() +{ +} + +std::unique_ptr<SfxTabPage> SwPrivateDataPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet) +{ + return std::make_unique<SwPrivateDataPage>(pPage, pController, *rSet); +} + +void SwPrivateDataPage::ActivatePage(const SfxItemSet& rSet) +{ + Reset(&rSet); +} + +DeactivateRC SwPrivateDataPage::DeactivatePage(SfxItemSet* _pSet) +{ + if (_pSet) + FillItemSet(_pSet); + return DeactivateRC::LeavePage; +} + +bool SwPrivateDataPage::FillItemSet(SfxItemSet* rSet) +{ + const SfxItemSet* pExampleSet = GetDialogExampleSet(); + assert(pExampleSet); + SwLabItem aItem = static_cast<const SwLabItem&>(pExampleSet->Get(FN_LABEL)); + + aItem.m_aPrivFirstName = m_xFirstNameED->get_text(); + aItem.m_aPrivName = m_xNameED->get_text(); + aItem.m_aPrivShortCut = m_xShortCutED->get_text(); + aItem.m_aPrivFirstName2 = m_xFirstName2ED->get_text(); + aItem.m_aPrivName2 = m_xName2ED->get_text(); + aItem.m_aPrivShortCut2 = m_xShortCut2ED->get_text(); + aItem.m_aPrivStreet = m_xStreetED->get_text(); + aItem.m_aPrivZip = m_xZipED->get_text(); + aItem.m_aPrivCity = m_xCityED->get_text(); + aItem.m_aPrivCountry = m_xCountryED->get_text(); + aItem.m_aPrivState = m_xStateED->get_text(); + aItem.m_aPrivTitle = m_xTitleED->get_text(); + aItem.m_aPrivProfession= m_xProfessionED->get_text(); + aItem.m_aPrivPhone = m_xPhoneED->get_text(); + aItem.m_aPrivMobile = m_xMobilePhoneED->get_text(); + aItem.m_aPrivFax = m_xFaxED->get_text(); + aItem.m_aPrivWWW = m_xHomePageED->get_text(); + aItem.m_aPrivMail = m_xMailED->get_text(); + + rSet->Put(aItem); + return true; +} + +void SwPrivateDataPage::Reset(const SfxItemSet* rSet) +{ + const SwLabItem& aItem = static_cast<const SwLabItem&>( rSet->Get(FN_LABEL) ); + m_xFirstNameED->set_text(aItem.m_aPrivFirstName); + m_xNameED->set_text(aItem.m_aPrivName); + m_xShortCutED->set_text(aItem.m_aPrivShortCut); + m_xFirstName2ED->set_text(aItem.m_aPrivFirstName2); + m_xName2ED->set_text(aItem.m_aPrivName2); + m_xShortCut2ED->set_text(aItem.m_aPrivShortCut2); + m_xStreetED->set_text(aItem.m_aPrivStreet); + m_xZipED->set_text(aItem.m_aPrivZip); + m_xCityED->set_text(aItem.m_aPrivCity); + m_xCountryED->set_text(aItem.m_aPrivCountry); + m_xStateED->set_text(aItem.m_aPrivState); + m_xTitleED->set_text(aItem.m_aPrivTitle); + m_xProfessionED->set_text(aItem.m_aPrivProfession); + m_xPhoneED->set_text(aItem.m_aPrivPhone); + m_xMobilePhoneED->set_text(aItem.m_aPrivMobile); + m_xFaxED->set_text(aItem.m_aPrivFax); + m_xHomePageED->set_text(aItem.m_aPrivWWW); + m_xMailED->set_text(aItem.m_aPrivMail); +} + +SwBusinessDataPage::SwBusinessDataPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/businessdatapage.ui", "BusinessDataPage", &rSet) + , m_xCompanyED(m_xBuilder->weld_entry("company")) + , m_xCompanyExtED(m_xBuilder->weld_entry("company2")) + , m_xSloganED(m_xBuilder->weld_entry("slogan")) + , m_xStreetED(m_xBuilder->weld_entry("street")) + , m_xZipED(m_xBuilder->weld_entry("izip")) + , m_xCityED(m_xBuilder->weld_entry("icity")) + , m_xCountryED(m_xBuilder->weld_entry("country")) + , m_xStateED(m_xBuilder->weld_entry("state")) + , m_xPositionED(m_xBuilder->weld_entry("position")) + , m_xPhoneED(m_xBuilder->weld_entry("phone")) + , m_xMobilePhoneED(m_xBuilder->weld_entry("mobile")) + , m_xFaxED(m_xBuilder->weld_entry("fax")) + , m_xHomePageED(m_xBuilder->weld_entry("url")) + , m_xMailED(m_xBuilder->weld_entry("email")) +{ + SetExchangeSupport(); +} + +SwBusinessDataPage::~SwBusinessDataPage() +{ +} + +std::unique_ptr<SfxTabPage> SwBusinessDataPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet) +{ + return std::make_unique<SwBusinessDataPage>(pPage, pController, *rSet); +} + +void SwBusinessDataPage::ActivatePage(const SfxItemSet& rSet) +{ + Reset(&rSet); +} + +DeactivateRC SwBusinessDataPage::DeactivatePage(SfxItemSet* _pSet) +{ + if (_pSet) + FillItemSet(_pSet); + return DeactivateRC::LeavePage; +} + +bool SwBusinessDataPage::FillItemSet(SfxItemSet* rSet) +{ + const SfxItemSet* pExampleSet = GetDialogExampleSet(); + assert(pExampleSet); + SwLabItem aItem = static_cast<const SwLabItem&>(pExampleSet->Get(FN_LABEL)); + + aItem.m_aCompCompany = m_xCompanyED->get_text(); + aItem.m_aCompCompanyExt= m_xCompanyExtED->get_text(); + aItem.m_aCompSlogan = m_xSloganED->get_text(); + aItem.m_aCompStreet = m_xStreetED->get_text(); + aItem.m_aCompZip = m_xZipED->get_text(); + aItem.m_aCompCity = m_xCityED->get_text(); + aItem.m_aCompCountry = m_xCountryED->get_text(); + aItem.m_aCompState = m_xStateED->get_text(); + aItem.m_aCompPosition = m_xPositionED->get_text(); + aItem.m_aCompPhone = m_xPhoneED->get_text(); + aItem.m_aCompMobile = m_xMobilePhoneED->get_text(); + aItem.m_aCompFax = m_xFaxED->get_text(); + aItem.m_aCompWWW = m_xHomePageED->get_text(); + aItem.m_aCompMail = m_xMailED->get_text(); + + rSet->Put(aItem); + return true; +} + +void SwBusinessDataPage::Reset(const SfxItemSet* rSet) +{ + const SwLabItem& aItem = static_cast<const SwLabItem&>( rSet->Get(FN_LABEL) ); + m_xCompanyED->set_text(aItem.m_aCompCompany); + m_xCompanyExtED->set_text(aItem.m_aCompCompanyExt); + m_xSloganED->set_text(aItem.m_aCompSlogan); + m_xStreetED->set_text(aItem.m_aCompStreet); + m_xZipED->set_text(aItem.m_aCompZip); + m_xCityED->set_text(aItem.m_aCompCity); + m_xCountryED->set_text(aItem.m_aCompCountry); + m_xStateED->set_text(aItem.m_aCompState); + m_xPositionED->set_text(aItem.m_aCompPosition); + m_xPhoneED->set_text(aItem.m_aCompPhone); + m_xMobilePhoneED->set_text(aItem.m_aCompMobile); + m_xFaxED->set_text(aItem.m_aCompFax); + m_xHomePageED->set_text(aItem.m_aCompWWW); + m_xMailED->set_text(aItem.m_aCompMail); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/labelexp.cxx b/sw/source/ui/envelp/labelexp.cxx new file mode 100644 index 0000000000..ba4f37b1e0 --- /dev/null +++ b/sw/source/ui/envelp/labelexp.cxx @@ -0,0 +1,104 @@ +/* -*- 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 <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/text/XTextFieldsSupplier.hpp> +#include <com/sun/star/util/XRefreshable.hpp> +#include <label.hxx> +#include <labimg.hxx> +#include <unoprnms.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; + +void SwLabDlg::UpdateFieldInformation(uno::Reference< frame::XModel > const & xModel, const SwLabItem& rItem) +{ + uno::Reference< text::XTextFieldsSupplier > xFields(xModel, uno::UNO_QUERY); + uno::Reference< container::XNameAccess > xFieldMasters = xFields->getTextFieldMasters(); + + static const struct SwLabItemMap { + const char* pName; + OUString SwLabItem::*pValue; + } aArr[] = { + { "BC_PRIV_FIRSTNAME" , &SwLabItem::m_aPrivFirstName }, + { "BC_PRIV_NAME" , &SwLabItem::m_aPrivName }, + { "BC_PRIV_INITIALS" , &SwLabItem::m_aPrivShortCut }, + { "BC_PRIV_FIRSTNAME_2", &SwLabItem::m_aPrivFirstName2 }, + { "BC_PRIV_NAME_2" , &SwLabItem::m_aPrivName2 }, + { "BC_PRIV_INITIALS_2" , &SwLabItem::m_aPrivShortCut2 }, + { "BC_PRIV_STREET" , &SwLabItem::m_aPrivStreet }, + { "BC_PRIV_ZIP" , &SwLabItem::m_aPrivZip }, + { "BC_PRIV_CITY" , &SwLabItem::m_aPrivCity }, + { "BC_PRIV_COUNTRY" , &SwLabItem::m_aPrivCountry }, + { "BC_PRIV_STATE" , &SwLabItem::m_aPrivState }, + { "BC_PRIV_TITLE" , &SwLabItem::m_aPrivTitle }, + { "BC_PRIV_PROFESSION" , &SwLabItem::m_aPrivProfession }, + { "BC_PRIV_PHONE" , &SwLabItem::m_aPrivPhone }, + { "BC_PRIV_MOBILE" , &SwLabItem::m_aPrivMobile }, + { "BC_PRIV_FAX" , &SwLabItem::m_aPrivFax }, + { "BC_PRIV_WWW" , &SwLabItem::m_aPrivWWW }, + { "BC_PRIV_MAIL" , &SwLabItem::m_aPrivMail }, + { "BC_COMP_COMPANY" , &SwLabItem::m_aCompCompany }, + { "BC_COMP_COMPANYEXT" , &SwLabItem::m_aCompCompanyExt }, + { "BC_COMP_SLOGAN" , &SwLabItem::m_aCompSlogan }, + { "BC_COMP_STREET" , &SwLabItem::m_aCompStreet }, + { "BC_COMP_ZIP" , &SwLabItem::m_aCompZip }, + { "BC_COMP_CITY" , &SwLabItem::m_aCompCity }, + { "BC_COMP_COUNTRY" , &SwLabItem::m_aCompCountry }, + { "BC_COMP_STATE" , &SwLabItem::m_aCompState }, + { "BC_COMP_POSITION" , &SwLabItem::m_aCompPosition }, + { "BC_COMP_PHONE" , &SwLabItem::m_aCompPhone }, + { "BC_COMP_MOBILE" , &SwLabItem::m_aCompMobile }, + { "BC_COMP_FAX" , &SwLabItem::m_aCompFax }, + { "BC_COMP_WWW" , &SwLabItem::m_aCompWWW }, + { "BC_COMP_MAIL" , &SwLabItem::m_aCompMail }, + { nullptr, nullptr } + }; + + try + { + for( const SwLabItemMap* p = aArr; p->pName; ++p ) + { + OUString uFieldName( + "com.sun.star.text.FieldMaster.User." + + OUString::createFromAscii(p->pName)); + if( xFieldMasters->hasByName( uFieldName )) + { + uno::Any aFirstName = xFieldMasters->getByName( uFieldName ); + uno::Reference< beans::XPropertySet > xField; + aFirstName >>= xField; + uno::Any aContent; + aContent <<= rItem.*p->pValue; + xField->setPropertyValue( UNO_NAME_CONTENT, aContent ); + } + } + } + catch (const uno::RuntimeException&) + { + + } + + uno::Reference< container::XEnumerationAccess > xFieldAcc = xFields->getTextFields(); + uno::Reference< util::XRefreshable > xRefresh(xFieldAcc, uno::UNO_QUERY); + xRefresh->refresh(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/labfmt.cxx b/sw/source/ui/envelp/labfmt.cxx new file mode 100644 index 0000000000..b90397ab28 --- /dev/null +++ b/sw/source/ui/envelp/labfmt.cxx @@ -0,0 +1,609 @@ +/* -*- 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 <svtools/unitconv.hxx> +#include <tools/poly.hxx> +#include <vcl/weld.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <sal/log.hxx> + +#include <viewopt.hxx> + +#include <swtypes.hxx> +#include <cmdid.h> +#include <label.hxx> +#include <labimp.hxx> +#include <labimg.hxx> +#include "labfmt.hxx" +#include <uitool.hxx> + +#include <strings.hrc> + +using namespace utl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +#define ROUND(x) static_cast<tools::Long>((x) + .5) + +namespace { + +// Arrow or interval character +void DrawArrow(vcl::RenderContext& rRenderContext, const Point &rP1, const Point &rP2, bool bArrow) +{ + rRenderContext.DrawLine(rP1, rP2); + if (bArrow) + { + Point aArr[3]; + + // Arrow character + if (rP1.Y() == rP2.Y()) + { + // Horizontal + aArr[0].setX( rP2.X() - 5 ); + aArr[0].setY( rP2.Y() - 2 ); + aArr[1].setX( rP2.X() ); + aArr[1].setY( rP2.Y() ); + aArr[2].setX( rP2.X() - 5 ); + aArr[2].setY( rP2.Y() + 2 ); + } + else + { + // Vertical + aArr[0].setX( rP2.X() - 2 ); + aArr[0].setY( rP2.Y() - 5 ); + aArr[1].setX( rP2.X() + 2 ); + aArr[1].setY( rP2.Y() - 5 ); + aArr[2].setX( rP2.X() ); + aArr[2].setY( rP2.Y() ); + } + + const Color& rFieldTextColor = SwViewOption::GetCurrentViewOptions().GetFontColor(); + rRenderContext.SetFillColor(rFieldTextColor); + rRenderContext.DrawPolygon( tools::Polygon(3, aArr)); + } + else + { + // Interval symbol + if (rP1.Y() == rP2.Y()) + { + // Horizontal + rRenderContext.DrawLine(Point(rP1.X(), rP1.Y() - 2), Point(rP1.X(), rP1.Y() + 2)); + rRenderContext.DrawLine(Point(rP2.X(), rP2.Y() - 2), Point(rP2.X(), rP2.Y() + 2)); + } + else + { + // Vertical + rRenderContext.DrawLine(Point(rP1.X() - 2, rP1.Y()), Point(rP1.X() + 2, rP1.Y())); + rRenderContext.DrawLine(Point(rP2.X() - 2, rP2.Y()), Point(rP2.X() + 2, rP2.Y())); + } + } +} + +} + +SwLabPreview::SwLabPreview() + : m_aGrayColor(COL_LIGHTGRAY) + , m_aHDistStr(SwResId(STR_HDIST)) + , m_aVDistStr(SwResId(STR_VDIST)) + , m_aWidthStr(SwResId(STR_WIDTH)) + , m_aHeightStr(SwResId(STR_HEIGHT)) + , m_aLeftStr(SwResId(STR_LEFT)) + , m_aUpperStr(SwResId(STR_UPPER)) + , m_aColsStr(SwResId(STR_COLS)) + , m_aRowsStr(SwResId(STR_ROWS)) + , m_lHDistWidth(0) + , m_lVDistWidth(0) + , m_lHeightWidth(0) + , m_lLeftWidth(0) + , m_lUpperWidth(0) + , m_lColsWidth(0) + , m_lXWidth(0) + , m_lXHeight(0) +{ +} + +void SwLabPreview::SetDrawingArea(weld::DrawingArea* pWidget) +{ + CustomWidgetController::SetDrawingArea(pWidget); + + pWidget->set_size_request(pWidget->get_approximate_digit_width() * 54, + pWidget->get_text_height() * 15); + + m_lHDistWidth = pWidget->get_pixel_size(m_aHDistStr).Width(); + m_lVDistWidth = pWidget->get_pixel_size(m_aVDistStr).Width(); + m_lHeightWidth = pWidget->get_pixel_size(m_aHeightStr).Width(); + m_lLeftWidth = pWidget->get_pixel_size(m_aLeftStr).Width(); + m_lUpperWidth = pWidget->get_pixel_size(m_aUpperStr).Width(); + m_lColsWidth = pWidget->get_pixel_size(m_aColsStr).Width(); + m_lXWidth = pWidget->get_pixel_size(OUString('X')).Width(); + m_lXHeight = pWidget->get_text_height(); +} + +void SwLabPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + const Size aSize(GetOutputSizePixel()); + const tools::Long lOutWPix = aSize.Width(); + const tools::Long lOutHPix = aSize.Height(); + + // Scale factor + const double fxpix = double(lOutWPix - (2 * (m_lLeftWidth + 15))) / double(lOutWPix); + + const tools::Long lOutWPix23 = tools::Long(double(lOutWPix) * fxpix); + const tools::Long lOutHPix23 = tools::Long(double(lOutHPix) * fxpix); + + const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); + const Color& rWinColor = rStyleSettings.GetWindowColor(); + const Color& rFieldTextColor = SwViewOption::GetCurrentViewOptions().GetFontColor(); + + vcl::Font aFont = rRenderContext.GetFont(); + aFont.SetFillColor(rWinColor); + aFont.SetColor(rFieldTextColor); + rRenderContext.SetFont(aFont); + + rRenderContext.SetBackground(Wallpaper(rWinColor)); + rRenderContext.Erase(); + + rRenderContext.SetLineColor(rWinColor); + rRenderContext.SetFillColor(m_aGrayColor); + vcl::Font aPaintFont(rRenderContext.GetFont()); + aPaintFont.SetTransparent(false); + rRenderContext.SetFont(aPaintFont); + + // size of region to be displayed + const tools::Long lDispW = m_aItem.m_lLeft + m_aItem.m_lHDist + ((m_aItem.m_nCols == 1) + ? m_aItem.m_lLeft + : ROUND(m_aItem.m_lHDist / 10.0)); + + const tools::Long lDispH = m_aItem.m_lUpper + m_aItem.m_lVDist + ((m_aItem.m_nRows == 1) + ? m_aItem.m_lUpper + : ROUND(m_aItem.m_lVDist / 10.0)); + + // Scale factor + const float fx = float(lOutWPix23) / std::max(tools::Long(1), lDispW); + const float fy = float(lOutHPix23) / std::max(tools::Long(1), lDispH); + const float f = std::min(fx, fy); + + // zero point + const tools::Long lOutlineW = ROUND(f * lDispW); + const tools::Long lOutlineH = ROUND(f * lDispH); + + const tools::Long lX0 = (lOutWPix - lOutlineW) / 2; + const tools::Long lY0 = (lOutHPix - lOutlineH) / 2; + const tools::Long lX1 = lX0 + ROUND(f * m_aItem.m_lLeft ); + const tools::Long lY1 = lY0 + ROUND(f * m_aItem.m_lUpper); + const tools::Long lX2 = lX0 + ROUND(f * (m_aItem.m_lLeft + m_aItem.m_lWidth )); + const tools::Long lY2 = lY0 + ROUND(f * (m_aItem.m_lUpper + m_aItem.m_lHeight)); + const tools::Long lX3 = lX0 + ROUND(f * (m_aItem.m_lLeft + m_aItem.m_lHDist )); + const tools::Long lY3 = lY0 + ROUND(f * (m_aItem.m_lUpper + m_aItem.m_lVDist )); + + // draw outline (area) + rRenderContext.DrawRect(tools::Rectangle(Point(lX0, lY0), Size(lOutlineW, lOutlineH))); + + // draw outline (border) + rRenderContext.SetLineColor(rFieldTextColor); + rRenderContext.DrawLine(Point(lX0, lY0), Point(lX0 + lOutlineW - 1, lY0)); // Up + rRenderContext.DrawLine(Point(lX0, lY0), Point(lX0, lY0 + lOutlineH - 1)); // Left + if (m_aItem.m_nCols == 1) + rRenderContext.DrawLine(Point(lX0 + lOutlineW - 1, lY0), Point(lX0 + lOutlineW - 1, lY0 + lOutlineH - 1)); // Right + if (m_aItem.m_nRows == 1) + rRenderContext.DrawLine(Point(lX0, lY0 + lOutlineH - 1), Point(lX0 + lOutlineW - 1, lY0 + lOutlineH - 1)); // Down + + // Labels + rRenderContext.SetClipRegion(vcl::Region(tools::Rectangle(Point(lX0, lY0), Size(lOutlineW, lOutlineH)))); + rRenderContext.SetFillColor(COL_LIGHTGRAYBLUE); + const sal_Int32 nRows = std::min<sal_Int32>(2, m_aItem.m_nRows); + const sal_Int32 nCols = std::min<sal_Int32>(2, m_aItem.m_nCols); + for (sal_Int32 nRow = 0; nRow < nRows; ++nRow) + for (sal_Int32 nCol = 0; nCol < nCols; ++nCol) + rRenderContext.DrawRect(tools::Rectangle(Point(lX0 + ROUND(f * (m_aItem.m_lLeft + nCol * m_aItem.m_lHDist)), + lY0 + ROUND(f * (m_aItem.m_lUpper + nRow * m_aItem.m_lVDist))), + Size(ROUND(f * m_aItem.m_lWidth), + ROUND(f * m_aItem.m_lHeight)))); + rRenderContext.SetClipRegion(); + + // annotation: left border + if (m_aItem.m_lLeft) + { + tools::Long lX = (lX0 + lX1) / 2; + DrawArrow(rRenderContext, Point(lX0, lY0 - 5), Point(lX1, lY0 - 5), false); + DrawArrow(rRenderContext, Point(lX, lY0 - 10), Point(lX, lY0 - 5), true); + rRenderContext.DrawText(Point(lX1 - m_lLeftWidth, lY0 - 10 - m_lXHeight), m_aLeftStr); + } + + // annotation: upper border + if (m_aItem.m_lUpper) + { + DrawArrow(rRenderContext, Point(lX0 - 5, lY0), Point(lX0 - 5, lY1), false); + rRenderContext.DrawText(Point(lX0 - 10 - m_lUpperWidth, lY0 + ROUND(f*m_aItem.m_lUpper/2.0 - m_lXHeight/2.0)), m_aUpperStr); + } + + // annotation: width and height + { + tools::Long lX = lX2 - m_lXWidth / 2 - m_lHeightWidth / 2; + tools::Long lY = lY1 + m_lXHeight; + + rRenderContext.DrawLine(Point(lX1, lY), Point(lX2 - 1, lY)); + rRenderContext.DrawLine(Point(lX, lY1), Point(lX, lY2 - 1)); + + rRenderContext.DrawText(Point(lX1 + m_lXWidth / 2, lY - m_lXHeight / 2), m_aWidthStr); + rRenderContext.DrawText(Point(lX - m_lHeightWidth / 2, lY2 - m_lXHeight - m_lXHeight / 2), m_aHeightStr); + } + + // annotation: horizontal gap + if (m_aItem.m_nCols > 1) + { + tools::Long lX = (lX1 + lX3) / 2; + DrawArrow(rRenderContext, Point(lX1, lY0 - 5), Point(lX3, lY0 - 5), false); + DrawArrow(rRenderContext, Point(lX, lY0 - 10), Point(lX, lY0 - 5), true); + rRenderContext.DrawText(Point(lX - m_lHDistWidth / 2, lY0 - 10 - m_lXHeight), m_aHDistStr); + } + + // annotation: vertical gap + if (m_aItem.m_nRows > 1) + { + DrawArrow(rRenderContext, Point(lX0 - 5, lY1), Point(lX0 - 5, lY3), false); + rRenderContext.DrawText(Point(lX0 - 10 - m_lVDistWidth, lY1 + ROUND(f*m_aItem.m_lVDist/2.0 - m_lXHeight/2.0)), m_aVDistStr); + } + + // annotation: columns + { + tools::Long lY = lY0 + lOutlineH + 4; + DrawArrow(rRenderContext, Point(lX0, lY), Point(lX0 + lOutlineW - 1, lY), true); + rRenderContext.DrawText(Point((lX0 + lX0 + lOutlineW - 1) / 2 - m_lColsWidth / 2, lY + 5), m_aColsStr); + } + + // annotation: lines + { + tools::Long lX = lX0 + lOutlineW + 4; + DrawArrow(rRenderContext, Point(lX, lY0), Point(lX, lY0 + lOutlineH - 1), true); + rRenderContext.DrawText(Point(lX + 5, (lY0 + lY0 + lOutlineH - 1 - m_lXHeight / 2) / 2), m_aRowsStr); + } +} + +void SwLabPreview::UpdateItem(const SwLabItem& rItem) +{ + m_aItem = rItem; + Invalidate(); +} + +SwLabFormatPage::SwLabFormatPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/labelformatpage.ui", "LabelFormatPage", &rSet) + , m_aPreviewIdle("SwLabFormatPage Preview") + , m_aItem(static_cast<const SwLabItem&>( rSet.Get(FN_LABEL) )) + , m_bModified(false) + , m_xMakeFI(m_xBuilder->weld_label("make")) + , m_xTypeFI(m_xBuilder->weld_label("type")) + , m_xPreview(new weld::CustomWeld(*m_xBuilder, "preview", m_aPreview)) + , m_xHDistField(m_xBuilder->weld_metric_spin_button("hori", FieldUnit::CM)) + , m_xVDistField(m_xBuilder->weld_metric_spin_button("vert", FieldUnit::CM)) + , m_xWidthField(m_xBuilder->weld_metric_spin_button("width", FieldUnit::CM)) + , m_xHeightField(m_xBuilder->weld_metric_spin_button("height", FieldUnit::CM)) + , m_xLeftField(m_xBuilder->weld_metric_spin_button("left", FieldUnit::CM)) + , m_xUpperField(m_xBuilder->weld_metric_spin_button("top", FieldUnit::CM)) + , m_xColsField(m_xBuilder->weld_spin_button("cols")) + , m_xRowsField(m_xBuilder->weld_spin_button("rows")) + , m_xPWidthField(m_xBuilder->weld_metric_spin_button("pagewidth", FieldUnit::CM)) + , m_xPHeightField(m_xBuilder->weld_metric_spin_button("pageheight", FieldUnit::CM)) + , m_xSavePB(m_xBuilder->weld_button("save")) +{ + SetExchangeSupport(); + + // Metrics + FieldUnit aMetric = ::GetDfltMetric(false); + ::SetFieldUnit(*m_xHDistField, aMetric); + ::SetFieldUnit(*m_xVDistField , aMetric); + ::SetFieldUnit(*m_xWidthField , aMetric); + ::SetFieldUnit(*m_xHeightField, aMetric); + ::SetFieldUnit(*m_xLeftField , aMetric); + ::SetFieldUnit(*m_xUpperField , aMetric); + ::SetFieldUnit(*m_xPWidthField , aMetric); + ::SetFieldUnit(*m_xPHeightField, aMetric); + + // Install handlers + Link<weld::MetricSpinButton&,void> aLk = LINK(this, SwLabFormatPage, MetricModifyHdl); + m_xHDistField->connect_value_changed( aLk ); + m_xVDistField->connect_value_changed( aLk ); + m_xWidthField->connect_value_changed( aLk ); + m_xHeightField->connect_value_changed( aLk ); + m_xLeftField->connect_value_changed( aLk ); + m_xUpperField->connect_value_changed( aLk ); + m_xPWidthField->connect_value_changed( aLk ); + m_xPHeightField->connect_value_changed( aLk ); + + m_xColsField->connect_value_changed(LINK(this, SwLabFormatPage, ModifyHdl)); + m_xRowsField->connect_value_changed(LINK(this, SwLabFormatPage, ModifyHdl)); + + m_xSavePB->connect_clicked( LINK (this, SwLabFormatPage, SaveHdl)); + // Set timer + m_aPreviewIdle.SetPriority(TaskPriority::LOWEST); + m_aPreviewIdle.SetInvokeHandler(LINK(this, SwLabFormatPage, PreviewHdl)); +} + +SwLabFormatPage::~SwLabFormatPage() +{ +} + +// Modify-handler of MetricFields. start preview timer +IMPL_LINK_NOARG(SwLabFormatPage, MetricModifyHdl, weld::MetricSpinButton&, void) +{ + m_bModified = true; + m_aPreviewIdle.Start(); +} + +IMPL_LINK_NOARG(SwLabFormatPage, ModifyHdl, weld::SpinButton&, void) +{ + m_bModified = true; + m_aPreviewIdle.Start(); +} + +// Invalidate preview +IMPL_LINK_NOARG(SwLabFormatPage, PreviewHdl, Timer *, void) +{ + m_aPreviewIdle.Stop(); + ChangeMinMax(); + FillItem( m_aItem ); + m_aPreview.UpdateItem(m_aItem); +} + +void SwLabFormatPage::ChangeMinMax() +{ + tools::Long lMax = 31748; // 56 cm + tools::Long nMinSize = 10; // 0,1cm + + // Min and Max + + int nCols = m_xColsField->get_value(), + nRows = m_xRowsField->get_value(); + tools::Long lLeft = static_cast< tools::Long >(getfldval(*m_xLeftField )), + lUpper = static_cast< tools::Long >(getfldval(*m_xUpperField)), + lHDist = static_cast< tools::Long >(getfldval(*m_xHDistField)), + lVDist = static_cast< tools::Long >(getfldval(*m_xVDistField)), + lWidth = static_cast< tools::Long >(getfldval(*m_xWidthField)), + lHeight = static_cast< tools::Long >(getfldval(*m_xHeightField)), + lMinPWidth = lLeft + (nCols - 1) * lHDist + lWidth, + lMinPHeight = lUpper + (nRows - 1) * lVDist + lHeight; + + m_xHDistField->set_min(nMinSize, FieldUnit::CM); + m_xVDistField->set_min(nMinSize, FieldUnit::CM); + + m_xHDistField->set_max(100 * ((lMax - lLeft ) / std::max(1, nCols)), FieldUnit::TWIP); + m_xVDistField->set_max(100 * ((lMax - lUpper) / std::max(1, nRows)), FieldUnit::TWIP); + + m_xWidthField->set_min(nMinSize, FieldUnit::CM); + m_xHeightField->set_min(nMinSize, FieldUnit::CM); + + m_xWidthField->set_max(tools::Long(100) * lHDist, FieldUnit::TWIP); + m_xHeightField->set_max(tools::Long(100) * lVDist, FieldUnit::TWIP); + + m_xLeftField->set_max(tools::Long(100) * (lMax - nCols * lHDist), FieldUnit::TWIP); + m_xUpperField->set_max(tools::Long(100) * (lMax - nRows * lVDist), FieldUnit::TWIP); + + m_xColsField->set_range(1, (lMax - lLeft ) / std::max(tools::Long(1), lHDist)); + m_xRowsField->set_range(1, (lMax - lUpper) / std::max(tools::Long(1), lVDist)); + + m_xPWidthField->set_range(tools::Long(100) * lMinPWidth, tools::Long(100) * lMax, FieldUnit::TWIP); + m_xPHeightField->set_range(tools::Long(100) * lMinPHeight, tools::Long(100) * lMax, FieldUnit::TWIP); +} + +std::unique_ptr<SfxTabPage> SwLabFormatPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet) +{ + return std::make_unique<SwLabFormatPage>(pPage, pController, *rSet); +} + +void SwLabFormatPage::ActivatePage(const SfxItemSet& rSet) +{ + SfxItemSet aSet(rSet); + Reset(&aSet); +} + +DeactivateRC SwLabFormatPage::DeactivatePage(SfxItemSet* _pSet) +{ + if (_pSet) + FillItemSet(_pSet); + + return DeactivateRC::LeavePage; +} + +void SwLabFormatPage::FillItem(SwLabItem& rItem) +{ + if (!m_bModified) + return; + + rItem.m_aMake = rItem.m_aType = SwResId(STR_CUSTOM_LABEL); + + SwLabRec& rRec = *GetParentSwLabDlg()->Recs()[0]; + rItem.m_lHDist = rRec.m_nHDist = static_cast< tools::Long >(getfldval(*m_xHDistField )); + rItem.m_lVDist = rRec.m_nVDist = static_cast< tools::Long >(getfldval(*m_xVDistField )); + rItem.m_lWidth = rRec.m_nWidth = static_cast< tools::Long >(getfldval(*m_xWidthField )); + rItem.m_lHeight = rRec.m_nHeight = static_cast< tools::Long >(getfldval(*m_xHeightField)); + rItem.m_lLeft = rRec.m_nLeft = static_cast< tools::Long >(getfldval(*m_xLeftField )); + rItem.m_lUpper = rRec.m_nUpper = static_cast< tools::Long >(getfldval(*m_xUpperField )); + rItem.m_nCols = rRec.m_nCols = static_cast< sal_Int32 >(m_xColsField->get_value()); + rItem.m_nRows = rRec.m_nRows = static_cast< sal_Int32 >(m_xRowsField->get_value()); + rItem.m_lPWidth = rRec.m_nPWidth = static_cast< tools::Long >(getfldval(*m_xPWidthField )); + rItem.m_lPHeight = rRec.m_nPHeight = static_cast< tools::Long >(getfldval(*m_xPHeightField)); + +} + +bool SwLabFormatPage::FillItemSet(SfxItemSet* rSet) +{ + FillItem(m_aItem); + rSet->Put(m_aItem); + + return true; +} + +void SwLabFormatPage::Reset(const SfxItemSet* ) +{ + // Initialise fields + GetParentSwLabDlg()->GetLabItem(m_aItem); + + m_xHDistField->set_max(100 * m_aItem.m_lHDist , FieldUnit::TWIP); + m_xVDistField->set_max(100 * m_aItem.m_lVDist , FieldUnit::TWIP); + m_xWidthField->set_max(100 * m_aItem.m_lWidth , FieldUnit::TWIP); + m_xHeightField->set_max(100 * m_aItem.m_lHeight, FieldUnit::TWIP); + m_xLeftField->set_max(100 * m_aItem.m_lLeft , FieldUnit::TWIP); + m_xUpperField->set_max(100 * m_aItem.m_lUpper , FieldUnit::TWIP); + m_xPWidthField->set_max(100 * m_aItem.m_lPWidth , FieldUnit::TWIP); + m_xPHeightField->set_max(100 * m_aItem.m_lPHeight, FieldUnit::TWIP); + + setfldval(*m_xHDistField, m_aItem.m_lHDist ); + setfldval(*m_xVDistField , m_aItem.m_lVDist ); + setfldval(*m_xWidthField , m_aItem.m_lWidth ); + setfldval(*m_xHeightField, m_aItem.m_lHeight); + setfldval(*m_xLeftField , m_aItem.m_lLeft ); + setfldval(*m_xUpperField , m_aItem.m_lUpper ); + setfldval(*m_xPWidthField , m_aItem.m_lPWidth ); + setfldval(*m_xPHeightField, m_aItem.m_lPHeight); + + m_xColsField->set_max(m_aItem.m_nCols); + m_xRowsField->set_max(m_aItem.m_nRows); + + m_xColsField->set_value(m_aItem.m_nCols); + m_xRowsField->set_value(m_aItem.m_nRows); + m_xMakeFI->set_label(m_aItem.m_aMake); + m_xTypeFI->set_label(m_aItem.m_aType); + PreviewHdl(nullptr); +} + +IMPL_LINK_NOARG(SwLabFormatPage, SaveHdl, weld::Button&, void) +{ + SwLabRec aRec; + aRec.m_nHDist = static_cast< tools::Long >(getfldval(*m_xHDistField)); + aRec.m_nVDist = static_cast< tools::Long >(getfldval(*m_xVDistField )); + aRec.m_nWidth = static_cast< tools::Long >(getfldval(*m_xWidthField )); + aRec.m_nHeight = static_cast< tools::Long >(getfldval(*m_xHeightField)); + aRec.m_nLeft = static_cast< tools::Long >(getfldval(*m_xLeftField )); + aRec.m_nUpper = static_cast< tools::Long >(getfldval(*m_xUpperField )); + aRec.m_nCols = static_cast< sal_Int32 >(m_xColsField->get_value()); + aRec.m_nRows = static_cast< sal_Int32 >(m_xRowsField->get_value()); + aRec.m_nPWidth = static_cast< tools::Long >(getfldval(*m_xPWidthField )); + aRec.m_nPHeight = static_cast< tools::Long >(getfldval(*m_xPHeightField)); + aRec.m_bCont = m_aItem.m_bCont; + SwSaveLabelDlg aSaveDlg(GetParentSwLabDlg(), aRec); + aSaveDlg.SetLabel(m_aItem.m_aLstMake, m_aItem.m_aLstType); + aSaveDlg.run(); + if (aSaveDlg.GetLabel(m_aItem)) + { + m_bModified = false; + const std::vector<OUString>& rMan = GetParentSwLabDlg()->GetLabelsConfig().GetManufacturers(); + std::vector<OUString>& rMakes(GetParentSwLabDlg()->Makes()); + if(rMakes.size() < rMan.size()) + { + rMakes = rMan; + } + m_xMakeFI->set_label(m_aItem.m_aMake); + m_xTypeFI->set_label(m_aItem.m_aType); + } +} + +SwSaveLabelDlg::SwSaveLabelDlg(SwLabDlg* pParent, SwLabRec& rRec) + : GenericDialogController(pParent->getDialog(), "modules/swriter/ui/savelabeldialog.ui", "SaveLabelDialog") + , m_bSuccess(false) + , m_pLabDialog(pParent) + , m_rLabRec(rRec) + , m_xMakeCB(m_xBuilder->weld_combo_box("brand")) + , m_xTypeED(m_xBuilder->weld_entry("type")) + , m_xOKPB(m_xBuilder->weld_button("ok")) +{ + m_xOKPB->connect_clicked(LINK(this, SwSaveLabelDlg, OkHdl)); + m_xMakeCB->connect_changed(LINK(this, SwSaveLabelDlg, ModifyComboHdl)); + m_xTypeED->connect_changed(LINK(this, SwSaveLabelDlg, ModifyEntryHdl)); + + SwLabelConfig& rCfg = m_pLabDialog->GetLabelsConfig(); + const std::vector<OUString>& rMan = rCfg.GetManufacturers(); + for (const auto & i : rMan) + { + m_xMakeCB->append_text(i); + } +} + +SwSaveLabelDlg::~SwSaveLabelDlg() +{ +} + +IMPL_LINK_NOARG(SwSaveLabelDlg, OkHdl, weld::Button&, void) +{ + SwLabelConfig& rCfg = m_pLabDialog->GetLabelsConfig(); + OUString sMake(m_xMakeCB->get_active_text()); + OUString sType(m_xTypeED->get_text()); + if(rCfg.HasLabel(sMake, sType)) + { + if ( rCfg.IsPredefinedLabel(sMake, sType) ) + { + SAL_WARN( "sw.envelp", "label is predefined and cannot be overwritten" ); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xDialog.get(), "modules/swriter/ui/cannotsavelabeldialog.ui")); + std::unique_ptr<weld::MessageDialog> xBox(xBuilder->weld_message_dialog("CannotSaveLabelDialog")); + xBox->run(); + return; + } + + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xDialog.get(), "modules/swriter/ui/querysavelabeldialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QuerySaveLabelDialog")); + xQuery->set_primary_text(xQuery->get_primary_text(). + replaceAll("%1", sMake).replaceAll("%2", sType)); + xQuery->set_secondary_text(xQuery->get_secondary_text(). + replaceAll("%1", sMake).replaceAll("%2", sType)); + + if (RET_YES != xQuery->run()) + return; + } + m_rLabRec.m_aType = sType; + rCfg.SaveLabel(sMake, sType, m_rLabRec); + m_bSuccess = true; + m_xDialog->response(RET_OK); +} + +void SwSaveLabelDlg::Modify() +{ + m_xOKPB->set_sensitive(!m_xMakeCB->get_active_text().isEmpty() && !m_xTypeED->get_text().isEmpty()); +} + +IMPL_LINK_NOARG(SwSaveLabelDlg, ModifyComboHdl, weld::ComboBox&, void) +{ + Modify(); +} + +IMPL_LINK_NOARG(SwSaveLabelDlg, ModifyEntryHdl, weld::Entry&, void) +{ + Modify(); +} + +bool SwSaveLabelDlg::GetLabel(SwLabItem& rItem) +{ + if(m_bSuccess) + { + rItem.m_aMake = m_xMakeCB->get_active_text(); + rItem.m_aType = m_xTypeED->get_text(); + rItem.m_lHDist = m_rLabRec.m_nHDist; + rItem.m_lVDist = m_rLabRec.m_nVDist; + rItem.m_lWidth = m_rLabRec.m_nWidth; + rItem.m_lHeight = m_rLabRec.m_nHeight; + rItem.m_lLeft = m_rLabRec.m_nLeft; + rItem.m_lUpper = m_rLabRec.m_nUpper; + rItem.m_nCols = m_rLabRec.m_nCols; + rItem.m_nRows = m_rLabRec.m_nRows; + rItem.m_lPWidth = m_rLabRec.m_nPWidth; + rItem.m_lPHeight = m_rLabRec.m_nPHeight; + } + return m_bSuccess; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/labfmt.hxx b/sw/source/ui/envelp/labfmt.hxx new file mode 100644 index 0000000000..bfb1ef3097 --- /dev/null +++ b/sw/source/ui/envelp/labfmt.hxx @@ -0,0 +1,140 @@ +/* -*- 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 . + */ +#pragma once + +#include <labimg.hxx> +#include <label.hxx> + +#include <sfx2/tabdlg.hxx> +#include <vcl/idle.hxx> +#include <vcl/customweld.hxx> +#include <vcl/weld.hxx> + +class SwLabFormatPage; + +class SwLabPreview : public weld::CustomWidgetController +{ + Color m_aGrayColor; + + OUString m_aHDistStr; + OUString m_aVDistStr; + OUString m_aWidthStr; + OUString m_aHeightStr; + OUString m_aLeftStr; + OUString m_aUpperStr; + OUString m_aColsStr; + OUString m_aRowsStr; + + tools::Long m_lHDistWidth; + tools::Long m_lVDistWidth; + tools::Long m_lHeightWidth; + tools::Long m_lLeftWidth; + tools::Long m_lUpperWidth; + tools::Long m_lColsWidth; + + tools::Long m_lXWidth; + tools::Long m_lXHeight; + + SwLabItem m_aItem; + + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + +public: + SwLabPreview(); + + void UpdateItem(const SwLabItem& rItem); +}; + +class SwLabFormatPage : public SfxTabPage +{ + Idle m_aPreviewIdle; + SwLabItem m_aItem; + bool m_bModified; + + SwLabPreview m_aPreview; + + std::unique_ptr<weld::Label> m_xMakeFI; + std::unique_ptr<weld::Label> m_xTypeFI; + std::unique_ptr<weld::CustomWeld> m_xPreview; + std::unique_ptr<weld::MetricSpinButton> m_xHDistField; + std::unique_ptr<weld::MetricSpinButton> m_xVDistField; + std::unique_ptr<weld::MetricSpinButton> m_xWidthField; + std::unique_ptr<weld::MetricSpinButton> m_xHeightField; + std::unique_ptr<weld::MetricSpinButton> m_xLeftField; + std::unique_ptr<weld::MetricSpinButton> m_xUpperField; + std::unique_ptr<weld::SpinButton> m_xColsField; + std::unique_ptr<weld::SpinButton> m_xRowsField; + std::unique_ptr<weld::MetricSpinButton> m_xPWidthField; + std::unique_ptr<weld::MetricSpinButton> m_xPHeightField; + std::unique_ptr<weld::Button> m_xSavePB; + + DECL_LINK(ModifyHdl, weld::SpinButton&, void); + DECL_LINK(MetricModifyHdl, weld::MetricSpinButton&, void); + DECL_LINK(PreviewHdl, Timer*, void); + DECL_LINK(SaveHdl, weld::Button&, void); + + void ChangeMinMax(); + +public: + SwLabFormatPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet); + virtual ~SwLabFormatPage() override; + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet); + + virtual void ActivatePage(const SfxItemSet& rSet) override; + virtual DeactivateRC DeactivatePage(SfxItemSet* pSet) override; + void FillItem(SwLabItem& rItem); + virtual bool FillItemSet(SfxItemSet* rSet) override; + virtual void Reset(const SfxItemSet* rSet) override; + + SwLabDlg* GetParentSwLabDlg() { return static_cast<SwLabDlg*>(GetDialogController()); } +}; + +class SwSaveLabelDlg : public weld::GenericDialogController +{ + bool m_bSuccess; + SwLabDlg* m_pLabDialog; + SwLabRec& m_rLabRec; + + std::unique_ptr<weld::ComboBox> m_xMakeCB; + std::unique_ptr<weld::Entry> m_xTypeED; + std::unique_ptr<weld::Button> m_xOKPB; + + DECL_LINK(OkHdl, weld::Button&, void); + DECL_LINK(ModifyEntryHdl, weld::Entry&, void); + DECL_LINK(ModifyComboHdl, weld::ComboBox&, void); + + void Modify(); + +public: + SwSaveLabelDlg(SwLabDlg* pParent, SwLabRec& rRec); + virtual ~SwSaveLabelDlg() override; + + void SetLabel(const OUString& rMake, const OUString& rType) + { + m_xMakeCB->set_entry_text(rMake); + m_xTypeED->set_text(rType); + } + bool GetLabel(SwLabItem& rItem); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/labprt.cxx b/sw/source/ui/envelp/labprt.cxx new file mode 100644 index 0000000000..6b1c78f160 --- /dev/null +++ b/sw/source/ui/envelp/labprt.cxx @@ -0,0 +1,155 @@ +/* -*- 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 <svtools/prnsetup.hxx> +#include <unotools/cmdoptions.hxx> +#include <vcl/print.hxx> +#include <label.hxx> +#include "labprt.hxx" +#include <labimg.hxx> + +SwLabPrtPage::SwLabPrtPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/labeloptionspage.ui", "LabelOptionsPage", &rSet) + , m_pPrinter(nullptr) + , m_xPageButton(m_xBuilder->weld_radio_button("entirepage")) + , m_xSingleButton(m_xBuilder->weld_radio_button("singlelabel")) + , m_xSingleGrid(m_xBuilder->weld_widget("singlegrid")) + , m_xPrinterFrame(m_xBuilder->weld_widget("printerframe")) + , m_xColField(m_xBuilder->weld_spin_button("cols")) + , m_xRowField(m_xBuilder->weld_spin_button("rows")) + , m_xSynchronCB(m_xBuilder->weld_check_button("synchronize")) + , m_xPrinterInfo(m_xBuilder->weld_label("printername")) + , m_xPrtSetup(m_xBuilder->weld_button("setup")) +{ + SetExchangeSupport(); + + // Install handlers + Link<weld::Toggleable&,void> aLk = LINK(this, SwLabPrtPage, CountHdl); + m_xPageButton->connect_toggled(aLk); + m_xSingleButton->connect_toggled(aLk); + m_xPrtSetup->connect_clicked(LINK(this, SwLabPrtPage, PrtSetupHdl)); + + SvtCommandOptions aCmdOpts; + if (aCmdOpts.LookupDisabled("Print")) + { + m_xPrinterFrame->hide(); + } +} + +SwLabPrtPage::~SwLabPrtPage() +{ + m_pPrinter.disposeAndClear(); +} + +IMPL_LINK( SwLabPrtPage, PrtSetupHdl, weld::Button&, rButton, void ) +{ + // Call printer setup + if (!m_pPrinter) + m_pPrinter = VclPtr<Printer>::Create(); + + PrinterSetupDialog aDlg(GetFrameWeld()); + aDlg.SetPrinter(m_pPrinter); + aDlg.run(); + rButton.grab_focus(); + m_xPrinterInfo->set_label(m_pPrinter->GetName()); +} + +IMPL_LINK(SwLabPrtPage, CountHdl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + + const bool bEnable = m_xSingleButton->get_active(); + m_xSingleGrid->set_sensitive(bEnable); + m_xSynchronCB->set_sensitive(!bEnable); + + if (bEnable) + m_xColField->grab_focus(); +} + +std::unique_ptr<SfxTabPage> SwLabPrtPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet) +{ + return std::make_unique<SwLabPrtPage>(pPage, pController, *rSet ); +} + +void SwLabPrtPage::ActivatePage( const SfxItemSet& rSet ) +{ + Reset(&rSet); +} + +DeactivateRC SwLabPrtPage::DeactivatePage(SfxItemSet* _pSet) +{ + if ( _pSet ) + FillItemSet(_pSet); + + return DeactivateRC::LeavePage; +} + +void SwLabPrtPage::FillItem(SwLabItem& rItem) +{ + rItem.m_bPage = m_xPageButton->get_active(); + rItem.m_nCol = m_xColField->get_value(); + rItem.m_nRow = m_xRowField->get_value(); + rItem.m_bSynchron = m_xSynchronCB->get_active() && m_xSynchronCB->get_sensitive(); +} + +bool SwLabPrtPage::FillItemSet(SfxItemSet* rSet) +{ + SwLabItem aItem; + GetParentSwLabDlg()->GetLabItem(aItem); + FillItem(aItem); + rSet->Put(aItem); + + return true; +} + +void SwLabPrtPage::Reset(const SfxItemSet* ) +{ + SwLabItem aItem; + GetParentSwLabDlg()->GetLabItem(aItem); + + m_xColField->set_value(aItem.m_nCol); + m_xRowField->set_value(aItem.m_nRow); + + if (aItem.m_bPage) + { + m_xPageButton->set_active(true); + CountHdl(*m_xPageButton); + } + else + { + CountHdl(*m_xSingleButton); + m_xSingleButton->set_active(true); + } + + if (m_pPrinter) + { + // show printer + m_xPrinterInfo->set_label(m_pPrinter->GetName()); + } + else + m_xPrinterInfo->set_label(Printer::GetDefaultPrinterName()); + + m_xColField->set_max(aItem.m_nCols); + m_xRowField->set_max(aItem.m_nRows); + + m_xSynchronCB->set_active(aItem.m_bSynchron); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/labprt.hxx b/sw/source/ui/envelp/labprt.hxx new file mode 100644 index 0000000000..66a4c13657 --- /dev/null +++ b/sw/source/ui/envelp/labprt.hxx @@ -0,0 +1,63 @@ +/* -*- 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 . + */ +#pragma once + +#include <sfx2/tabdlg.hxx> + +#include <label.hxx> + +class SwLabDlg; +class SwLabItem; + +class SwLabPrtPage : public SfxTabPage +{ + VclPtr<Printer> m_pPrinter; // for the shaft setting - unfortunately + + std::unique_ptr<weld::RadioButton> m_xPageButton; + std::unique_ptr<weld::RadioButton> m_xSingleButton; + std::unique_ptr<weld::Widget> m_xSingleGrid; + std::unique_ptr<weld::Widget> m_xPrinterFrame; + std::unique_ptr<weld::SpinButton> m_xColField; + std::unique_ptr<weld::SpinButton> m_xRowField; + std::unique_ptr<weld::CheckButton> m_xSynchronCB; + std::unique_ptr<weld::Label> m_xPrinterInfo; + std::unique_ptr<weld::Button> m_xPrtSetup; + + DECL_LINK(CountHdl, weld::Toggleable&, void); + DECL_LINK(PrtSetupHdl, weld::Button&, void); + + SwLabDlg* GetParentSwLabDlg() { return static_cast<SwLabDlg*>(GetDialogController()); } + +public: + SwLabPrtPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet); + virtual ~SwLabPrtPage() override; + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet); + + virtual void ActivatePage(const SfxItemSet& rSet) override; + virtual DeactivateRC DeactivatePage(SfxItemSet* pSet) override; + void FillItem(SwLabItem& rItem); + virtual bool FillItemSet(SfxItemSet* rSet) override; + virtual void Reset(const SfxItemSet* rSet) override; + Printer* GetPrt() { return m_pPrinter; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/mailmrge.cxx b/sw/source/ui/envelp/mailmrge.cxx new file mode 100644 index 0000000000..8567b11443 --- /dev/null +++ b/sw/source/ui/envelp/mailmrge.cxx @@ -0,0 +1,617 @@ +/* -*- 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 <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <comphelper/propertyvalue.hxx> + +#include <tools/urlobj.hxx> +#include <svl/urihelper.hxx> +#include <unotools/pathoptions.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <IDocumentDeviceAccess.hxx> +#include <printdata.hxx> +#include <wrtsh.hxx> +#include <dbmgr.hxx> +#include <swmodule.hxx> +#include <modcfg.hxx> +#include <mailmergehelper.hxx> +#include <mailmrge.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/filedlghelper.hxx> +#include <comphelper/documentconstants.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <com/sun/star/container/XContainerQuery.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/form/runtime/XFormController.hpp> +#include <com/sun/star/frame/Frame.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/sdb/XResultSetAccess.hpp> +#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/implbase.hxx> +#include <osl/diagnose.h> + +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::view; +using namespace ::com::sun::star::ui::dialogs; + +struct SwMailMergeDlg_Impl { + uno::Reference<runtime::XFormController> xFController; + uno::Reference<XSelectionChangeListener> xChgLstnr; + uno::Reference<XSelectionSupplier> xSelSupp; +}; + +class SwXSelChgLstnr_Impl : public cppu::WeakImplHelper + < + view::XSelectionChangeListener + > +{ + SwMailMergeDlg& m_rParent; +public: + explicit SwXSelChgLstnr_Impl(SwMailMergeDlg& rParentDlg); + + virtual void SAL_CALL selectionChanged( const EventObject& aEvent ) override; + virtual void SAL_CALL disposing( const EventObject& Source ) override; +}; + +SwXSelChgLstnr_Impl::SwXSelChgLstnr_Impl(SwMailMergeDlg& rParentDlg) : + m_rParent(rParentDlg) +{} + +void SwXSelChgLstnr_Impl::selectionChanged( const EventObject& ) +{ + //call the parent to enable selection mode + Sequence <Any> aSelection; + if(m_rParent.m_pImpl->xSelSupp.is()) + m_rParent.m_pImpl->xSelSupp->getSelection() >>= aSelection; + + bool bEnable = aSelection.hasElements(); + m_rParent.m_xMarkedRB->set_sensitive(bEnable); + if(bEnable) + m_rParent.m_xMarkedRB->set_active(true); + else if(m_rParent.m_xMarkedRB->get_active()) { + m_rParent.m_xAllRB->set_active(true); + m_rParent.m_aSelection.realloc(0); + } +} + +void SwXSelChgLstnr_Impl::disposing( const EventObject& ) +{ + OSL_FAIL("disposing"); +} + +SwMailMergeDlg::SwMailMergeDlg(weld::Window* pParent, SwWrtShell& rShell, + const OUString& rSourceName, + const OUString& rTableName, + sal_Int32 nCommandType, + const uno::Reference< XConnection>& _xConnection, + Sequence< Any > const * pSelection) + : SfxDialogController(pParent, "modules/swriter/ui/mailmerge.ui", "MailmergeDialog") + , m_pImpl(new SwMailMergeDlg_Impl) + , m_rSh(rShell) + , m_nMergeType(DBMGR_MERGE_EMAIL) + , m_xBeamerWin(m_xBuilder->weld_container("beamer")) + , m_xAllRB(m_xBuilder->weld_radio_button("all")) + , m_xMarkedRB(m_xBuilder->weld_radio_button("selected")) + , m_xFromRB(m_xBuilder->weld_radio_button("rbfrom")) + , m_xFromNF(m_xBuilder->weld_spin_button("from")) + , m_xToNF(m_xBuilder->weld_spin_button("to")) + , m_xPrinterRB(m_xBuilder->weld_radio_button("printer")) + , m_xMailingRB(m_xBuilder->weld_radio_button("electronic")) + , m_xFileRB(m_xBuilder->weld_radio_button("file")) + , m_xSingleJobsCB(m_xBuilder->weld_check_button("singlejobs")) + , m_xPasswordCB(m_xBuilder->weld_check_button("passwd-check")) + , m_xSaveMergedDocumentFT(m_xBuilder->weld_label("savemergeddoclabel")) + , m_xSaveSingleDocRB(m_xBuilder->weld_radio_button("singledocument")) + , m_xSaveIndividualRB(m_xBuilder->weld_radio_button("individualdocuments")) + , m_xGenerateFromDataBaseCB(m_xBuilder->weld_check_button("generate")) + , m_xColumnFT(m_xBuilder->weld_label("fieldlabel")) + , m_xColumnLB(m_xBuilder->weld_combo_box("field")) + , m_xPasswordFT(m_xBuilder->weld_label("passwd-label")) + , m_xPasswordLB(m_xBuilder->weld_combo_box("passwd-combobox")) + , m_xPathFT(m_xBuilder->weld_label("pathlabel")) + , m_xPathED(m_xBuilder->weld_entry("path")) + , m_xPathPB(m_xBuilder->weld_button("pathpb")) + , m_xFilterFT(m_xBuilder->weld_label("fileformatlabel")) + , m_xFilterLB(m_xBuilder->weld_combo_box("fileformat")) + , m_xAddressFieldLB(m_xBuilder->weld_combo_box("address")) + , m_xSubjectFT(m_xBuilder->weld_label("subjectlabel")) + , m_xSubjectED(m_xBuilder->weld_entry("subject")) + , m_xFormatFT(m_xBuilder->weld_label("mailformatlabel")) + , m_xAttachFT(m_xBuilder->weld_label("attachmentslabel")) + , m_xAttachED(m_xBuilder->weld_entry("attachments")) + , m_xAttachPB(m_xBuilder->weld_button("attach")) + , m_xFormatHtmlCB(m_xBuilder->weld_check_button("html")) + , m_xFormatRtfCB(m_xBuilder->weld_check_button("rtf")) + , m_xFormatSwCB(m_xBuilder->weld_check_button("swriter")) + , m_xOkBTN(m_xBuilder->weld_button("ok")) +{ + m_xSingleJobsCB->hide(); // not supported in since cws printerpullpages anymore + //task #97066# mailing of form letters is currently not supported + m_xMailingRB->hide(); + m_xSubjectFT->hide(); + m_xSubjectED->hide(); + m_xFormatFT->hide(); + m_xFormatSwCB->hide(); + m_xFormatHtmlCB->hide(); + m_xFormatRtfCB->hide(); + m_xAttachFT->hide(); + m_xAttachED->hide(); + m_xAttachPB->hide(); + m_xPasswordCB->hide(); + m_xPasswordFT->hide(); + m_xPasswordLB->hide(); + + uno::Reference< lang::XMultiServiceFactory > xMSF = comphelper::getProcessServiceFactory(); + if(pSelection) { + m_aSelection = *pSelection; + m_xBeamerWin->hide(); + } else { + try { + // create a frame wrapper for myself + m_xFrame = frame::Frame::create( comphelper::getProcessComponentContext() ); + m_xFrame->initialize(m_xBeamerWin->CreateChildFrame()); + } catch (const Exception&) { + m_xFrame.clear(); + } + if(m_xFrame.is()) { + URL aURL; + aURL.Complete = ".component:DB/DataSourceBrowser"; + uno::Reference<XDispatch> xD = m_xFrame->queryDispatch(aURL, + "", + 0x0C); + if(xD.is()) { + Sequence<PropertyValue> aProperties + { + comphelper::makePropertyValue("DataSourceName", rSourceName), + comphelper::makePropertyValue("Command", rTableName), + comphelper::makePropertyValue("CommandType", nCommandType), + }; + xD->dispatch(aURL, aProperties); + m_xBeamerWin->show(); + } + uno::Reference<XController> xController = m_xFrame->getController(); + m_pImpl->xFController.set(xController, UNO_QUERY); + if(m_pImpl->xFController.is()) { + uno::Reference< awt::XControl > xCtrl = m_pImpl->xFController->getCurrentControl( ); + m_pImpl->xSelSupp.set(xCtrl, UNO_QUERY); + if(m_pImpl->xSelSupp.is()) { + m_pImpl->xChgLstnr = new SwXSelChgLstnr_Impl(*this); + m_pImpl->xSelSupp->addSelectionChangeListener( m_pImpl->xChgLstnr ); + } + } + } + } + + m_pModOpt = SW_MOD()->GetModuleConfig(); + + MailTextFormats nMailingMode(m_pModOpt->GetMailingFormats()); + m_xFormatSwCB->set_active(bool(nMailingMode & MailTextFormats::OFFICE)); + m_xFormatHtmlCB->set_active(bool(nMailingMode & MailTextFormats::HTML)); + m_xFormatRtfCB->set_active(bool(nMailingMode & MailTextFormats::RTF)); + + m_xAllRB->set_active(true); + + // Install handlers + m_xOkBTN->connect_clicked(LINK(this, SwMailMergeDlg, ButtonHdl)); + + m_xPathPB->connect_clicked(LINK(this, SwMailMergeDlg, InsertPathHdl)); + + m_xPrinterRB->connect_toggled(LINK(this, SwMailMergeDlg, OutputTypeHdl)); + m_xFileRB->connect_toggled(LINK(this, SwMailMergeDlg, OutputTypeHdl)); + + //#i63267# printing might be disabled + bool bIsPrintable = !Application::GetSettings().GetMiscSettings().GetDisablePrinting(); + m_xPrinterRB->set_sensitive(bIsPrintable); + OutputTypeHdl(bIsPrintable ? *m_xPrinterRB : *m_xFileRB); + + m_xGenerateFromDataBaseCB->connect_toggled(LINK(this, SwMailMergeDlg, FilenameHdl)); + bool bColumn = m_pModOpt->IsNameFromColumn(); + if(bColumn) + m_xGenerateFromDataBaseCB->set_active(true); + + FilenameHdl(*m_xGenerateFromDataBaseCB); + m_xSaveSingleDocRB->set_active(true); + m_xSaveSingleDocRB->connect_toggled(LINK(this, SwMailMergeDlg, SaveTypeHdl)); + m_xSaveIndividualRB->connect_toggled(LINK(this, SwMailMergeDlg, SaveTypeHdl)); + SaveTypeHdl(*m_xSaveSingleDocRB); + + m_xFilterLB->connect_changed(LINK(this, SwMailMergeDlg, FileFormatHdl)); + + Link<weld::SpinButton&,void> aLk2 = LINK(this, SwMailMergeDlg, ModifyHdl); + m_xFromNF->connect_value_changed(aLk2); + m_xToNF->connect_value_changed(aLk2); + m_xFromNF->set_max(SAL_MAX_INT32); + m_xToNF->set_max(SAL_MAX_INT32); + + SwDBManager* pDBManager = m_rSh.GetDBManager(); + if(_xConnection.is()) + SwDBManager::GetColumnNames(*m_xAddressFieldLB, _xConnection, rTableName); + else + pDBManager->GetColumnNames(*m_xAddressFieldLB, rSourceName, rTableName); + for(sal_Int32 nEntry = 0, nEntryCount = m_xAddressFieldLB->get_count(); nEntry < nEntryCount; ++nEntry) + { + m_xColumnLB->append_text(m_xAddressFieldLB->get_text(nEntry)); + m_xPasswordLB->append_text(m_xAddressFieldLB->get_text(nEntry)); + } + + m_xAddressFieldLB->set_active_text("EMAIL"); + + OUString sPath(m_pModOpt->GetMailingPath()); + if(sPath.isEmpty()) { + SvtPathOptions aPathOpt; + sPath = aPathOpt.GetWorkPath(); + } + INetURLObject aURL(sPath); + if(aURL.GetProtocol() == INetProtocol::File) + m_xPathED->set_text(aURL.PathToFileName()); + else + m_xPathED->set_text(aURL.GetFull()); + + if (!bColumn ) + { + m_xColumnLB->set_active_text("NAME"); + m_xPasswordLB->set_active_text("PASSWORD"); + } + else + { + m_xColumnLB->set_active_text(m_pModOpt->GetNameFromColumn()); + m_xPasswordLB->set_active_text(m_pModOpt->GetPasswordFromColumn()); + } + + if (m_xAddressFieldLB->get_active() == -1) + m_xAddressFieldLB->set_active(0); + if (m_xColumnLB->get_active() == -1) + m_xColumnLB->set_active(0); + if (m_xPasswordLB->get_active() == -1) + m_xPasswordLB->set_active(0); + + const bool bEnable = m_aSelection.hasElements(); + m_xMarkedRB->set_sensitive(bEnable); + if (bEnable) + m_xMarkedRB->set_active(true); + else { + m_xAllRB->set_active(true); + m_xMarkedRB->set_sensitive(false); + } + try { + uno::Reference< container::XNameContainer> xFilterFactory( + xMSF->createInstance("com.sun.star.document.FilterFactory"), UNO_QUERY_THROW); + uno::Reference< container::XContainerQuery > xQuery(xFilterFactory, UNO_QUERY_THROW); + const OUString sCommand("matchByDocumentService=com.sun.star.text.TextDocument:iflags=" + + OUString::number(static_cast<sal_Int32>(SfxFilterFlags::EXPORT)) + + ":eflags=" + + OUString::number(static_cast<sal_Int32>(SfxFilterFlags::NOTINFILEDLG)) + + ":default_first"); + uno::Reference< container::XEnumeration > xList = xQuery->createSubSetEnumerationByQuery(sCommand); + static constexpr OUStringLiteral sName(u"Name"); + sal_Int32 nODT = -1; + while(xList->hasMoreElements()) { + comphelper::SequenceAsHashMap aFilter(xList->nextElement()); + const OUString sFilter = aFilter.getUnpackedValueOrDefault(sName, OUString()); + + uno::Any aProps = xFilterFactory->getByName(sFilter); + uno::Sequence< beans::PropertyValue > aFilterProperties; + aProps >>= aFilterProperties; + OUString sUIName2; + auto pProp = std::find_if(std::cbegin(aFilterProperties), std::cend(aFilterProperties), + [](const beans::PropertyValue& rProp) { return rProp.Name == "UIName"; }); + if (pProp != std::cend(aFilterProperties)) + pProp->Value >>= sUIName2; + if( !sUIName2.isEmpty() ) { + if( sFilter == "writer8" ) + nODT = m_xFilterLB->get_count(); + m_xFilterLB->append(sFilter, sUIName2); + } + } + m_xFilterLB->set_active( nODT ); + } catch (const uno::Exception&) { + } +} + +SwMailMergeDlg::~SwMailMergeDlg() +{ + if(m_xFrame.is()) { + m_xFrame->setComponent(nullptr, nullptr); + m_xFrame->dispose(); + } +} + +IMPL_LINK_NOARG(SwMailMergeDlg, ButtonHdl, weld::Button&, void) +{ + if (ExecQryShell()) + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(SwMailMergeDlg, OutputTypeHdl, weld::Toggleable&, void) +{ + bool bPrint = m_xPrinterRB->get_active(); + m_xSingleJobsCB->set_sensitive(bPrint); + + m_xSaveMergedDocumentFT->set_sensitive( !bPrint ); + m_xSaveSingleDocRB->set_sensitive( !bPrint ); + m_xSaveIndividualRB->set_sensitive( !bPrint ); + + if( !bPrint ) { + SaveTypeHdl( m_xSaveSingleDocRB->get_active() ? *m_xSaveSingleDocRB : *m_xSaveIndividualRB ); + } else { + m_xPathFT->set_sensitive(false); + m_xPathED->set_sensitive(false); + m_xPathPB->set_sensitive(false); + m_xColumnFT->set_sensitive(false); + m_xColumnLB->set_sensitive(false); + m_xFilterFT->set_sensitive(false); + m_xFilterLB->set_sensitive(false); + m_xGenerateFromDataBaseCB->set_sensitive(false); + m_xPasswordCB->set_sensitive( false ); + m_xPasswordFT->set_sensitive( false ); + m_xPasswordLB->set_sensitive( false ); + } +} + +IMPL_LINK_NOARG(SwMailMergeDlg, SaveTypeHdl, weld::Toggleable&, void) +{ + bool bIndividual = m_xSaveIndividualRB->get_active(); + + m_xGenerateFromDataBaseCB->set_sensitive( bIndividual ); + if( bIndividual ) + { + FilenameHdl(*m_xGenerateFromDataBaseCB); + } + else + { + m_xColumnFT->set_sensitive(false); + m_xColumnLB->set_sensitive(false); + m_xPathFT->set_sensitive( false ); + m_xPathED->set_sensitive( false ); + m_xPathPB->set_sensitive( false ); + m_xFilterFT->set_sensitive( false ); + m_xFilterLB->set_sensitive( false ); + m_xPasswordCB->set_sensitive( false ); + m_xPasswordFT->set_sensitive( false ); + m_xPasswordLB->set_sensitive( false ); + } +} + +IMPL_LINK( SwMailMergeDlg, FilenameHdl, weld::Toggleable&, rBox, void ) +{ + bool bEnable = rBox.get_active(); + m_xColumnFT->set_sensitive( bEnable ); + m_xColumnLB->set_sensitive(bEnable); + m_xPathFT->set_sensitive( bEnable ); + m_xPathED->set_sensitive(bEnable); + m_xPathPB->set_sensitive( bEnable ); + m_xFilterFT->set_sensitive( bEnable ); + m_xFilterLB->set_sensitive( bEnable ); + + if(m_xFilterLB->get_active_id() == "writer_pdf_Export") + { + m_xPasswordCB->show(); + m_xPasswordFT->show(); + m_xPasswordLB->show(); + + m_xPasswordCB->set_sensitive( bEnable ); + m_xPasswordFT->set_sensitive( bEnable ); + m_xPasswordLB->set_sensitive( bEnable ); + } +} + +IMPL_LINK_NOARG( SwMailMergeDlg, FileFormatHdl, weld::ComboBox&, void ) +{ + if(m_xFilterLB->get_active_id() == "writer_pdf_Export") + { + m_xPasswordCB->show(); + m_xPasswordFT->show(); + m_xPasswordLB->show(); + + m_xPasswordCB->set_sensitive( true ); + m_xPasswordFT->set_sensitive( true ); + m_xPasswordLB->set_sensitive( true ); + } + else + { + m_xPasswordCB->hide(); + m_xPasswordFT->hide(); + m_xPasswordLB->hide(); + } +} + +IMPL_LINK_NOARG(SwMailMergeDlg, ModifyHdl, weld::SpinButton&, void) +{ + m_xFromRB->set_active(true); +} + +bool SwMailMergeDlg::AskUserFilename() const +{ + return (m_xSaveSingleDocRB->get_active() || !m_xGenerateFromDataBaseCB->get_active()); +} + +OUString SwMailMergeDlg::GetURLfromPath() const +{ + SfxMedium* pMedium = m_rSh.GetView().GetDocShell()->GetMedium(); + INetURLObject aAbs; + if( pMedium ) + aAbs = pMedium->GetURLObject(); + if( INetProtocol::NotValid == aAbs.GetProtocol() ) + { + SvtPathOptions aPathOpt; + aAbs.SetURL( aPathOpt.GetWorkPath() ); + } + return URIHelper::SmartRel2Abs( + aAbs, m_xPathED->get_text(), URIHelper::GetMaybeFileHdl()); +} + +bool SwMailMergeDlg::ExecQryShell() +{ + if(m_pImpl->xSelSupp.is()) { + m_pImpl->xSelSupp->removeSelectionChangeListener( m_pImpl->xChgLstnr ); + } + + if (m_xPrinterRB->get_active()) + m_nMergeType = DBMGR_MERGE_PRINTER; + else { + m_nMergeType = DBMGR_MERGE_FILE; + m_pModOpt->SetMailingPath( GetURLfromPath() ); + m_pModOpt->SetIsNameFromColumn(m_xGenerateFromDataBaseCB->get_active()); + m_pModOpt->SetIsFileEncryptedFromColumn(m_xPasswordCB->get_active()); + + if (!AskUserFilename()) + { + m_pModOpt->SetNameFromColumn(m_xColumnLB->get_active_text()); + m_pModOpt->SetPasswordFromColumn(m_xPasswordLB->get_active_text()); + if (m_xFilterLB->get_active() != -1) + m_sSaveFilter = m_xFilterLB->get_active_id(); + m_sFilename = OUString(); + } else { + //#i97667# reset column name - otherwise it's remembered from the last run + m_pModOpt->SetNameFromColumn(OUString()); + m_pModOpt->SetPasswordFromColumn(OUString()); + //start save as dialog + OUString sFilter; + m_sFilename = SwMailMergeHelper::CallSaveAsDialog(m_xDialog.get(), sFilter); + if (m_sFilename.isEmpty()) + return false; + m_sSaveFilter = sFilter; + } + } + + if (m_xFromRB->get_active()) { // Insert list + // Safe: the maximal value of the fields is limited + sal_Int32 nStart = m_xFromNF->get_value(); + sal_Int32 nEnd = m_xToNF->get_value(); + + if (nEnd < nStart) + std::swap(nEnd, nStart); + + m_aSelection.realloc(nEnd - nStart + 1); + Any* pSelection = m_aSelection.getArray(); + for (sal_Int32 i = nStart; i <= nEnd; ++i, ++pSelection) + *pSelection <<= i; + } else if (m_xAllRB->get_active() ) + m_aSelection.realloc(0); // Empty selection = insert all + else { + if(m_pImpl->xSelSupp.is()) { + //update selection + uno::Reference< XRowLocate > xRowLocate(GetResultSet(),UNO_QUERY); + uno::Reference< XResultSet > xRes(xRowLocate,UNO_QUERY); + m_pImpl->xSelSupp->getSelection() >>= m_aSelection; + if ( xRowLocate.is() ) { + for (Any& rRow : asNonConstRange(m_aSelection)) { + if ( xRowLocate->moveToBookmark(rRow) ) + rRow <<= xRes->getRow(); + } + } + } + } + IDocumentDeviceAccess& rIDDA = m_rSh.getIDocumentDeviceAccess(); + SwPrintData aPrtData( rIDDA.getPrintData() ); + aPrtData.SetPrintSingleJobs(m_xSingleJobsCB->get_active()); + rIDDA.setPrintData(aPrtData); + + m_pModOpt->SetSinglePrintJob(m_xSingleJobsCB->get_active()); + + MailTextFormats nMailingMode = MailTextFormats::NONE; + + if (m_xFormatSwCB->get_active()) + nMailingMode |= MailTextFormats::OFFICE; + if (m_xFormatHtmlCB->get_active()) + nMailingMode |= MailTextFormats::HTML; + if (m_xFormatRtfCB->get_active()) + nMailingMode |= MailTextFormats::RTF; + m_pModOpt->SetMailingFormats(nMailingMode); + return true; +} + +OUString SwMailMergeDlg::GetTargetURL() const +{ + if( AskUserFilename() ) + return m_sFilename; + OUString sPath( m_pModOpt->GetMailingPath() ); + if( sPath.isEmpty() ) { + SvtPathOptions aPathOpt; + sPath = aPathOpt.GetWorkPath(); + } + if( !sPath.endsWith("/") ) + sPath += "/"; + return sPath; +} + +IMPL_LINK_NOARG(SwMailMergeDlg, InsertPathHdl, weld::Button&, void) +{ + uno::Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + uno::Reference < XFolderPicker2 > xFP = sfx2::createFolderPicker(xContext, m_xDialog.get()); + xFP->setDisplayDirectory( GetURLfromPath() ); + if( xFP->execute() == RET_OK ) { + INetURLObject aURL(xFP->getDirectory()); + if(aURL.GetProtocol() == INetProtocol::File) + m_xPathED->set_text(aURL.PathToFileName()); + else + m_xPathED->set_text(aURL.GetFull()); + } +} + +uno::Reference<XResultSet> SwMailMergeDlg::GetResultSet() const +{ + uno::Reference< XResultSet > xResSetClone; + if ( m_pImpl->xFController.is() ) { + // we create a clone to do the task + uno::Reference< XResultSetAccess > xResultSetAccess( m_pImpl->xFController->getModel(),UNO_QUERY); + if ( xResultSetAccess.is() ) + xResSetClone = xResultSetAccess->createResultSet(); + } + return xResSetClone; +} + +SwMailMergeCreateFromDlg::SwMailMergeCreateFromDlg(weld::Window* pParent) + : GenericDialogController(pParent, "modules/swriter/ui/mailmergedialog.ui", "MailMergeDialog") + , m_xThisDocRB(m_xBuilder->weld_radio_button("document")) +{ +} + +SwMailMergeCreateFromDlg::~SwMailMergeCreateFromDlg() +{ +} + +SwMailMergeFieldConnectionsDlg::SwMailMergeFieldConnectionsDlg(weld::Window* pParent) + : GenericDialogController(pParent, "modules/swriter/ui/mergeconnectdialog.ui", "MergeConnectDialog") + , m_xUseExistingRB(m_xBuilder->weld_radio_button("existing")) +{ +} + +SwMailMergeFieldConnectionsDlg::~SwMailMergeFieldConnectionsDlg() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/envelp/swuilabimp.hxx b/sw/source/ui/envelp/swuilabimp.hxx new file mode 100644 index 0000000000..222c9fd911 --- /dev/null +++ b/sw/source/ui/envelp/swuilabimp.hxx @@ -0,0 +1,145 @@ +/* -*- 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 . + */ +#pragma once + +#include <label.hxx> +#include <labimg.hxx> +#include <labrec.hxx> +#include <sfx2/tabdlg.hxx> + +class SwLabPage : public SfxTabPage +{ + SwDBManager* m_pDBManager; + OUString m_sActDBName; + SwLabItem m_aItem; + + std::unique_ptr<weld::Widget> m_xAddressFrame; + std::unique_ptr<weld::CheckButton> m_xAddrBox; + std::unique_ptr<weld::TextView> m_xWritingEdit; + std::unique_ptr<weld::ComboBox> m_xDatabaseLB; + std::unique_ptr<weld::ComboBox> m_xTableLB; + std::unique_ptr<weld::Button> m_xInsertBT; + std::unique_ptr<weld::ComboBox> m_xDBFieldLB; + std::unique_ptr<weld::RadioButton> m_xContButton; + std::unique_ptr<weld::RadioButton> m_xSheetButton; + std::unique_ptr<weld::ComboBox> m_xMakeBox; + std::unique_ptr<weld::ComboBox> m_xTypeBox; + std::unique_ptr<weld::ComboBox> m_xHiddenSortTypeBox; + std::unique_ptr<weld::Label> m_xFormatInfo; + + DECL_LINK(AddrHdl, weld::Toggleable&, void); + DECL_LINK(DatabaseHdl, weld::ComboBox&, void); + DECL_LINK(FieldHdl, weld::Button&, void); + DECL_LINK(PageHdl, weld::Toggleable&, void); + DECL_LINK(MakeHdl, weld::ComboBox&, void); + DECL_LINK(TypeHdl, weld::ComboBox&, void); + + void DisplayFormat(); + SwLabRec* GetSelectedEntryPos(); + +public: + SwLabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + + virtual ~SwLabPage() override; + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet); + + virtual void ActivatePage(const SfxItemSet& rSet) override; + virtual DeactivateRC DeactivatePage(SfxItemSet* pSet) override; + void FillItem(SwLabItem& rItem); + virtual bool FillItemSet(SfxItemSet* rSet) override; + virtual void Reset(const SfxItemSet* rSet) override; + + SwLabDlg* GetParentSwLabDlg() { return static_cast<SwLabDlg*>(GetDialogController()); } + + void SetToBusinessCard(); + + void InitDatabaseBox(); + void SetDBManager(SwDBManager* pDBManager_) { m_pDBManager = pDBManager_; } + SwDBManager* GetDBManager() const { return m_pDBManager; } +}; + +class SwPrivateDataPage : public SfxTabPage +{ + std::unique_ptr<weld::Entry> m_xFirstNameED; + std::unique_ptr<weld::Entry> m_xNameED; + std::unique_ptr<weld::Entry> m_xShortCutED; + std::unique_ptr<weld::Entry> m_xFirstName2ED; + std::unique_ptr<weld::Entry> m_xName2ED; + std::unique_ptr<weld::Entry> m_xShortCut2ED; + std::unique_ptr<weld::Entry> m_xStreetED; + std::unique_ptr<weld::Entry> m_xZipED; + std::unique_ptr<weld::Entry> m_xCityED; + std::unique_ptr<weld::Entry> m_xCountryED; + std::unique_ptr<weld::Entry> m_xStateED; + std::unique_ptr<weld::Entry> m_xTitleED; + std::unique_ptr<weld::Entry> m_xProfessionED; + std::unique_ptr<weld::Entry> m_xPhoneED; + std::unique_ptr<weld::Entry> m_xMobilePhoneED; + std::unique_ptr<weld::Entry> m_xFaxED; + std::unique_ptr<weld::Entry> m_xHomePageED; + std::unique_ptr<weld::Entry> m_xMailED; + +public: + SwPrivateDataPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet); + virtual ~SwPrivateDataPage() override; + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet); + + virtual void ActivatePage(const SfxItemSet& rSet) override; + virtual DeactivateRC DeactivatePage(SfxItemSet* pSet) override; + virtual bool FillItemSet(SfxItemSet* rSet) override; + virtual void Reset(const SfxItemSet* rSet) override; +}; + +class SwBusinessDataPage : public SfxTabPage +{ + std::unique_ptr<weld::Entry> m_xCompanyED; + std::unique_ptr<weld::Entry> m_xCompanyExtED; + std::unique_ptr<weld::Entry> m_xSloganED; + std::unique_ptr<weld::Entry> m_xStreetED; + std::unique_ptr<weld::Entry> m_xZipED; + std::unique_ptr<weld::Entry> m_xCityED; + std::unique_ptr<weld::Entry> m_xCountryED; + std::unique_ptr<weld::Entry> m_xStateED; + std::unique_ptr<weld::Entry> m_xPositionED; + std::unique_ptr<weld::Entry> m_xPhoneED; + std::unique_ptr<weld::Entry> m_xMobilePhoneED; + std::unique_ptr<weld::Entry> m_xFaxED; + std::unique_ptr<weld::Entry> m_xHomePageED; + std::unique_ptr<weld::Entry> m_xMailED; + +public: + SwBusinessDataPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet); + virtual ~SwBusinessDataPage() override; + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet); + + virtual void ActivatePage(const SfxItemSet& rSet) override; + virtual DeactivateRC DeactivatePage(SfxItemSet* pSet) override; + virtual bool FillItemSet(SfxItemSet* rSet) override; + virtual void Reset(const SfxItemSet* rSet) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/DateFormFieldDialog.cxx b/sw/source/ui/fldui/DateFormFieldDialog.cxx new file mode 100644 index 0000000000..24461c47d6 --- /dev/null +++ b/sw/source/ui/fldui/DateFormFieldDialog.cxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 <DateFormFieldDialog.hxx> +#include <IMark.hxx> +#include <xmloff/odffields.hxx> +#include <svl/numformat.hxx> +#include <svl/zforlist.hxx> +#include <svl/zformat.hxx> +#include <doc.hxx> + +namespace sw +{ +DateFormFieldDialog::DateFormFieldDialog(weld::Widget* pParent, + sw::mark::IDateFieldmark* pDateField, SwDoc& rDoc) + : GenericDialogController(pParent, "modules/swriter/ui/dateformfielddialog.ui", + "DateFormFieldDialog") + , m_pDateField(pDateField) + , m_pNumberFormatter(rDoc.GetNumberFormatter()) + , m_xFormatLB(new SwNumFormatTreeView(m_xBuilder->weld_tree_view("date_formats_treeview"))) +{ + m_xFormatLB->SetFormatType(SvNumFormatType::DATE); + m_xFormatLB->SetAutomaticLanguage(true); + m_xFormatLB->SetShowLanguageControl(true); + m_xFormatLB->SetOneArea(true); + + // Set a default height + weld::TreeView& rTreeView = dynamic_cast<weld::TreeView&>(m_xFormatLB->get_widget()); + rTreeView.set_size_request(rTreeView.get_preferred_size().Width(), + rTreeView.get_height_rows(10)); + InitControls(); +} + +DateFormFieldDialog::~DateFormFieldDialog() {} + +void DateFormFieldDialog::Apply() +{ + if (m_pDateField == nullptr) + return; + + // Try to find out the current date value and replace the content + // with the right formatted date string + sw::mark::IFieldmark::parameter_map_t* pParameters = m_pDateField->GetParameters(); + const SvNumberformat* pFormat = m_pNumberFormatter->GetEntry(m_xFormatLB->GetFormat()); + + // Get date value first + std::pair<bool, double> aResult = m_pDateField->GetCurrentDate(); + + // Then set the date format + (*pParameters)[ODF_FORMDATE_DATEFORMAT] <<= pFormat->GetFormatstring(); + (*pParameters)[ODF_FORMDATE_DATEFORMAT_LANGUAGE] + <<= LanguageTag(pFormat->GetLanguage()).getBcp47(); + + // Update current date + if (aResult.first) + { + m_pDateField->SetCurrentDate(aResult.second); + } + else + { + (*pParameters)[ODF_FORMDATE_CURRENTDATE] <<= OUString(); + } +} + +void DateFormFieldDialog::InitControls() +{ + if (m_pDateField == nullptr) + return; + + sw::mark::IFieldmark::parameter_map_t* pParameters = m_pDateField->GetParameters(); + + OUString sFormatString; + auto pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT); + if (pResult != pParameters->end()) + { + pResult->second >>= sFormatString; + } + + OUString sLang; + pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT_LANGUAGE); + if (pResult != pParameters->end()) + { + pResult->second >>= sLang; + } + + if (sFormatString.isEmpty() || sLang.isEmpty()) + return; + + LanguageType aLangType = LanguageTag(sLang).getLanguageType(); + sal_uInt32 nFormat = m_pNumberFormatter->GetEntryKey(sFormatString, aLangType); + if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + { + sal_Int32 nCheckPos = 0; + SvNumFormatType nType; + m_pNumberFormatter->PutEntry(sFormatString, nCheckPos, nType, nFormat, + LanguageTag(sLang).getLanguageType()); + } + + if (aLangType == LANGUAGE_DONTKNOW || nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + return; + + if (m_xFormatLB->GetCurLanguage() == aLangType) + { + m_xFormatLB->SetAutomaticLanguage(true); + } + else + { + m_xFormatLB->SetAutomaticLanguage(false); + m_xFormatLB->SetLanguage(aLangType); + + // Change format and change back for regenerating the list + m_xFormatLB->SetFormatType(SvNumFormatType::ALL); + m_xFormatLB->SetFormatType(SvNumFormatType::DATE); + } + m_xFormatLB->SetDefFormat(nFormat); +} + +} // namespace sw + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sw/source/ui/fldui/DropDownFieldDialog.cxx b/sw/source/ui/fldui/DropDownFieldDialog.cxx new file mode 100644 index 0000000000..d85bc5365b --- /dev/null +++ b/sw/source/ui/fldui/DropDownFieldDialog.cxx @@ -0,0 +1,142 @@ +/* -*- 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 <wrtsh.hxx> +#include <fldbas.hxx> +#include <DropDownFieldDialog.hxx> +#include <flddropdown.hxx> + +#include <memory> + +using namespace ::com::sun::star; + +// edit insert-field +sw::DropDownFieldDialog::DropDownFieldDialog(weld::Widget *pParent, SwWrtShell &rS, + SwField* pField, bool bPrevButton, bool bNextButton) + : GenericDialogController(pParent, "modules/swriter/ui/dropdownfielddialog.ui", "DropdownFieldDialog") + , m_rSh( rS ) + , m_pDropField(nullptr) + , m_pPressedButton(nullptr) + , m_xListItemsLB(m_xBuilder->weld_tree_view("list")) + , m_xOKPB(m_xBuilder->weld_button("ok")) + , m_xPrevPB(m_xBuilder->weld_button("prev")) + , m_xNextPB(m_xBuilder->weld_button("next")) + , m_xEditPB(m_xBuilder->weld_button("edit")) +{ + m_xListItemsLB->set_size_request(m_xListItemsLB->get_approximate_digit_width() * 24, + m_xListItemsLB->get_height_rows(12)); + Link<weld::TreeView&, bool> aDoubleLk = LINK(this, DropDownFieldDialog, DoubleClickHdl); + m_xListItemsLB->connect_row_activated( aDoubleLk ); + + Link<weld::Button&, void> aEditButtonLk = LINK(this, DropDownFieldDialog, EditHdl); + Link<weld::Button&,void> aPrevButtonLk = LINK(this, DropDownFieldDialog, PrevHdl); + Link<weld::Button&, void> aNextButtonLk = LINK(this, DropDownFieldDialog, NextHdl); + m_xEditPB->connect_clicked(aEditButtonLk); + if( bPrevButton || bNextButton ) + { + m_xPrevPB->show(); + m_xPrevPB->connect_clicked(aPrevButtonLk); + m_xPrevPB->set_sensitive(bPrevButton); + + m_xNextPB->show(); + m_xNextPB->connect_clicked(aNextButtonLk); + m_xNextPB->set_sensitive(bNextButton); + } + if( SwFieldIds::Dropdown == pField->GetTyp()->Which() ) + { + + m_pDropField = static_cast<SwDropDownField*>(pField); + OUString sTitle = m_xDialog->get_title() + + m_pDropField->GetPar2(); + m_xDialog->set_title(sTitle); + const uno::Sequence< OUString > aItems = m_pDropField->GetItemSequence(); + for (const OUString& rItem : aItems) + m_xListItemsLB->append_text(rItem); + m_xListItemsLB->select_text(m_pDropField->GetSelectedItem()); + } + + bool bEnable = !m_rSh.IsCursorReadonly(); + m_xOKPB->set_sensitive(bEnable); + + m_xListItemsLB->grab_focus(); +} + +sw::DropDownFieldDialog::~DropDownFieldDialog() +{ +} + +void sw::DropDownFieldDialog::Apply() +{ + if (!m_pDropField) + return; + + OUString sSelect = m_xListItemsLB->get_selected_text(); + if (m_pDropField->GetPar1() == sSelect) + return; + + m_rSh.StartAllAction(); + + std::unique_ptr<SwDropDownField> const pCopy( + static_cast<SwDropDownField*>(m_pDropField->CopyField().release())); + + pCopy->SetPar1(sSelect); + m_rSh.SwEditShell::UpdateOneField(*pCopy); + + m_rSh.SetUndoNoResetModified(); + m_rSh.EndAllAction(); +} + +bool sw::DropDownFieldDialog::PrevButtonPressed() const +{ + return m_pPressedButton == m_xPrevPB.get(); +} + +bool sw::DropDownFieldDialog::NextButtonPressed() const +{ + return m_pPressedButton == m_xNextPB.get(); +} + +IMPL_LINK_NOARG(sw::DropDownFieldDialog, EditHdl, weld::Button&, void) +{ + m_pPressedButton = m_xEditPB.get(); + m_xDialog->response(RET_YES); +} + +IMPL_LINK_NOARG(sw::DropDownFieldDialog, PrevHdl, weld::Button&, void) +{ + m_pPressedButton = m_xPrevPB.get(); + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(sw::DropDownFieldDialog, NextHdl, weld::Button&, void) +{ + m_pPressedButton = m_xNextPB.get(); + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(sw::DropDownFieldDialog, DoubleClickHdl, weld::TreeView&, bool) +{ + // tdf#114144, when next is available make double-click accept and go to next field + if (m_xNextPB->get_visible() && m_xNextPB->get_sensitive()) + m_pPressedButton = m_xNextPB.get(); + m_xDialog->response(RET_OK); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/DropDownFormFieldDialog.cxx b/sw/source/ui/fldui/DropDownFormFieldDialog.cxx new file mode 100644 index 0000000000..2115bbda48 --- /dev/null +++ b/sw/source/ui/fldui/DropDownFormFieldDialog.cxx @@ -0,0 +1,200 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 <DropDownFormFieldDialog.hxx> +#include <vcl/event.hxx> +#include <IMark.hxx> +#include <xmloff/odffields.hxx> +#include <vcl/svapp.hxx> +#include <strings.hrc> +#include <swtypes.hxx> + +namespace sw +{ +DropDownFormFieldDialog::DropDownFormFieldDialog(weld::Widget* pParent, + mark::IFieldmark* pDropDownField) + : GenericDialogController(pParent, "modules/swriter/ui/dropdownformfielddialog.ui", + "DropDownFormFieldDialog") + , m_pDropDownField(pDropDownField) + , m_bListHasChanged(false) + , m_xListItemEntry(m_xBuilder->weld_entry("item_entry")) + , m_xListAddButton(m_xBuilder->weld_button("add_button")) + , m_xListItemsTreeView(m_xBuilder->weld_tree_view("items_treeview")) + , m_xListRemoveButton(m_xBuilder->weld_button("remove_button")) + , m_xListUpButton(m_xBuilder->weld_button("up_button")) + , m_xListDownButton(m_xBuilder->weld_button("down_button")) +{ + m_xListItemEntry->connect_key_press(LINK(this, DropDownFormFieldDialog, KeyPressedHdl)); + m_xListItemEntry->connect_changed(LINK(this, DropDownFormFieldDialog, EntryChangedHdl)); + + m_xListItemsTreeView->set_size_request(m_xListItemEntry->get_preferred_size().Width(), + m_xListItemEntry->get_preferred_size().Height() * 5); + m_xListItemsTreeView->connect_changed(LINK(this, DropDownFormFieldDialog, ListChangedHdl)); + + Link<weld::Button&, void> aPushButtonLink(LINK(this, DropDownFormFieldDialog, ButtonPushedHdl)); + m_xListAddButton->connect_clicked(aPushButtonLink); + m_xListRemoveButton->connect_clicked(aPushButtonLink); + m_xListUpButton->connect_clicked(aPushButtonLink); + m_xListDownButton->connect_clicked(aPushButtonLink); + + InitControls(); +} + +DropDownFormFieldDialog::~DropDownFormFieldDialog() {} + +IMPL_LINK_NOARG(DropDownFormFieldDialog, ListChangedHdl, weld::TreeView&, void) { UpdateButtons(); } + +IMPL_LINK(DropDownFormFieldDialog, KeyPressedHdl, const KeyEvent&, rEvent, bool) +{ + if (rEvent.GetKeyCode().GetCode() == KEY_RETURN && !m_xListItemEntry->get_text().isEmpty()) + { + AppendItemToList(); + return true; + } + return false; +} + +IMPL_LINK_NOARG(DropDownFormFieldDialog, EntryChangedHdl, weld::Entry&, void) { UpdateButtons(); } + +IMPL_LINK(DropDownFormFieldDialog, ButtonPushedHdl, weld::Button&, rButton, void) +{ + if (&rButton == m_xListAddButton.get()) + { + AppendItemToList(); + } + else if (m_xListItemsTreeView->get_selected_index() != -1) + { + int nSelPos = m_xListItemsTreeView->get_selected_index(); + if (&rButton == m_xListRemoveButton.get()) + { + m_xListItemsTreeView->remove(nSelPos); + if (m_xListItemsTreeView->n_children() > 0) + m_xListItemsTreeView->select(nSelPos ? nSelPos - 1 : 0); + } + else if (&rButton == m_xListUpButton.get()) + { + const OUString sEntry = m_xListItemsTreeView->get_selected_text(); + m_xListItemsTreeView->remove(nSelPos); + nSelPos--; + m_xListItemsTreeView->insert_text(nSelPos, sEntry); + m_xListItemsTreeView->select(nSelPos); + } + else if (&rButton == m_xListDownButton.get()) + { + const OUString sEntry = m_xListItemsTreeView->get_selected_text(); + m_xListItemsTreeView->remove(nSelPos); + nSelPos++; + m_xListItemsTreeView->insert_text(nSelPos, sEntry); + m_xListItemsTreeView->select(nSelPos); + } + m_bListHasChanged = true; + } + UpdateButtons(); +} + +void DropDownFormFieldDialog::InitControls() +{ + if (m_pDropDownField != nullptr) + { + const mark::IFieldmark::parameter_map_t* const pParameters + = m_pDropDownField->GetParameters(); + + auto pListEntries = pParameters->find(ODF_FORMDROPDOWN_LISTENTRY); + if (pListEntries != pParameters->end()) + { + css::uno::Sequence<OUString> vListEntries; + pListEntries->second >>= vListEntries; + for (const OUString& rItem : std::as_const(vListEntries)) + m_xListItemsTreeView->append_text(rItem); + + // Select the current one + auto pResult = pParameters->find(ODF_FORMDROPDOWN_RESULT); + if (pResult != pParameters->end()) + { + sal_Int32 nSelection = -1; + pResult->second >>= nSelection; + if (nSelection >= 0 && nSelection < vListEntries.getLength()) + m_xListItemsTreeView->select_text(vListEntries[nSelection]); + } + } + } + UpdateButtons(); +} + +void DropDownFormFieldDialog::AppendItemToList() +{ + if (!m_xListAddButton->get_sensitive()) + return; + + if (m_xListItemsTreeView->n_children() >= ODF_FORMDROPDOWN_ENTRY_COUNT_LIMIT) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog( + m_xDialog.get(), VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_DROP_DOWN_FIELD_ITEM_LIMIT))); + xInfoBox->run(); + return; + } + + const OUString sEntry(m_xListItemEntry->get_text()); + if (!sEntry.isEmpty()) + { + m_xListItemsTreeView->append_text(sEntry); + m_xListItemsTreeView->select_text(sEntry); + m_bListHasChanged = true; + + // Clear entry + m_xListItemEntry->set_text(OUString()); + m_xListItemEntry->grab_focus(); + } + UpdateButtons(); +} + +void DropDownFormFieldDialog::UpdateButtons() +{ + m_xListAddButton->set_sensitive(!m_xListItemEntry->get_text().isEmpty() + && m_xListItemsTreeView->find_text(m_xListItemEntry->get_text()) + == -1); + + int nSelPos = m_xListItemsTreeView->get_selected_index(); + m_xListRemoveButton->set_sensitive(nSelPos != -1); + m_xListUpButton->set_sensitive(nSelPos > 0); + m_xListDownButton->set_sensitive(nSelPos != -1 + && nSelPos < m_xListItemsTreeView->n_children() - 1); +} + +void DropDownFormFieldDialog::Apply() +{ + if (!(m_pDropDownField != nullptr && m_bListHasChanged)) + return; + + mark::IFieldmark::parameter_map_t* pParameters = m_pDropDownField->GetParameters(); + + css::uno::Sequence<OUString> vListEntries(m_xListItemsTreeView->n_children()); + auto vListEntriesRange = asNonConstRange(vListEntries); + for (int nIndex = 0; nIndex < m_xListItemsTreeView->n_children(); ++nIndex) + { + vListEntriesRange[nIndex] = m_xListItemsTreeView->get_text(nIndex); + } + + if (m_xListItemsTreeView->n_children() != 0) + { + (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] <<= vListEntries; + } + else + { + pParameters->erase(ODF_FORMDROPDOWN_LISTENTRY); + } + + // After editing the drop down field's list we don't specify the selected item + pParameters->erase(ODF_FORMDROPDOWN_RESULT); +} + +} // namespace sw + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sw/source/ui/fldui/changedb.cxx b/sw/source/ui/fldui/changedb.cxx new file mode 100644 index 0000000000..a1e1803d90 --- /dev/null +++ b/sw/source/ui/fldui/changedb.cxx @@ -0,0 +1,258 @@ +/* -*- 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 <sal/config.h> + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> +#include <sfx2/viewfrm.hxx> +#include <o3tl/string_view.hxx> + +#include <view.hxx> +#include <wrtsh.hxx> +#include <dbmgr.hxx> +#include <changedb.hxx> + +#include <strings.hrc> +#include <bitmaps.hlst> + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::uno; + +// edit insert-field +SwChangeDBDlg::SwChangeDBDlg(SwView const & rVw) + : SfxDialogController(rVw.GetViewFrame().GetFrameWeld(), "modules/swriter/ui/exchangedatabases.ui", + "ExchangeDatabasesDialog") + , m_pSh(rVw.GetWrtShellPtr()) + , m_xUsedDBTLB(m_xBuilder->weld_tree_view("inuselb")) + , m_xAvailDBTLB(new SwDBTreeList(m_xBuilder->weld_tree_view("availablelb"))) + , m_xAddDBPB(m_xBuilder->weld_button("browse")) + , m_xDocDBNameFT(m_xBuilder->weld_label("dbnameft")) + , m_xDefineBT(m_xBuilder->weld_button("ok")) +{ + int nWidth = m_xUsedDBTLB->get_approximate_digit_width() * 25; + int nHeight = m_xUsedDBTLB->get_height_rows(8); + m_xUsedDBTLB->set_size_request(nWidth, nHeight); + m_xAvailDBTLB->set_size_request(nWidth, nHeight); + + m_xAvailDBTLB->SetWrtShell(*m_pSh); + FillDBPopup(); + + ShowDBName(m_pSh->GetDBData()); + m_xDefineBT->connect_clicked(LINK(this, SwChangeDBDlg, ButtonHdl)); + m_xAddDBPB->connect_clicked(LINK(this, SwChangeDBDlg, AddDBHdl)); + + m_xUsedDBTLB->set_selection_mode(SelectionMode::Multiple); + m_xUsedDBTLB->make_sorted(); + + Link<weld::TreeView&,void> aLink = LINK(this, SwChangeDBDlg, TreeSelectHdl); + + m_xUsedDBTLB->connect_changed(aLink); + m_xAvailDBTLB->connect_changed(aLink); + TreeSelect(); +} + +// initialise database listboxes +void SwChangeDBDlg::FillDBPopup() +{ + Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + Reference<XDatabaseContext> xDBContext = DatabaseContext::create(xContext); + const SwDBData& rDBData = m_pSh->GetDBData(); + m_xAvailDBTLB->Select(rDBData.sDataSource, rDBData.sCommand, u""); + TreeSelect(); + + Sequence< OUString > aDBNames = xDBContext->getElementNames(); + auto aAllDBNames = comphelper::sequenceToContainer<std::vector<OUString>>(aDBNames); + + std::vector<OUString> aDBNameList; + m_pSh->GetAllUsedDB( aDBNameList, &aAllDBNames ); + + size_t nCount = aDBNameList.size(); + m_xUsedDBTLB->clear(); + std::unique_ptr<weld::TreeIter> xFirst; + + for(size_t k = 0; k < nCount; k++) + { + std::unique_ptr<weld::TreeIter> xLast = Insert(o3tl::getToken(aDBNameList[k], 0, ';')); + if (!xFirst) + xFirst = std::move(xLast); + } + + if (xFirst) + { + m_xUsedDBTLB->expand_row(*xFirst); + m_xUsedDBTLB->scroll_to_row(*xFirst); + m_xUsedDBTLB->select(*xFirst); + } +} + +std::unique_ptr<weld::TreeIter> SwChangeDBDlg::Insert(std::u16string_view rDBName) +{ + sal_Int32 nIdx{ 0 }; + const OUString sDBName(o3tl::getToken(rDBName, 0, DB_DELIM, nIdx)); + const OUString sTableName(o3tl::getToken(rDBName, 0, DB_DELIM, nIdx)); + OUString sUserData( o3tl::getToken(rDBName, 0, DB_DELIM, nIdx) ); + sal_Int32 nCommandType = sUserData.toInt32(); + + const OUString & rToInsert ( nCommandType ? RID_BMP_DBQUERY : RID_BMP_DBTABLE ); + + std::unique_ptr<weld::TreeIter> xIter(m_xUsedDBTLB->make_iterator()); + if (m_xUsedDBTLB->get_iter_first(*xIter)) + { + do + { + if (sDBName == m_xUsedDBTLB->get_text(*xIter)) + { + if (m_xUsedDBTLB->iter_has_child(*xIter)) + { + std::unique_ptr<weld::TreeIter> xChild(m_xUsedDBTLB->make_iterator(xIter.get())); + if (m_xUsedDBTLB->iter_children(*xChild)) + { + do + { + if (sTableName == m_xUsedDBTLB->get_text(*xChild)) + return xChild; + } while (m_xUsedDBTLB->iter_next_sibling(*xChild)); + } + } + m_xUsedDBTLB->insert(xIter.get(), -1, &sTableName, &sUserData, nullptr, nullptr, + false, xIter.get()); + m_xUsedDBTLB->set_image(*xIter, rToInsert); + return xIter; + } + } while (m_xUsedDBTLB->iter_next_sibling(*xIter)); + } + + m_xUsedDBTLB->insert(nullptr, -1, &sDBName, nullptr, nullptr, nullptr, + false, xIter.get()); + m_xUsedDBTLB->set_image(*xIter, RID_BMP_DB); + m_xUsedDBTLB->insert(xIter.get(), -1, &sTableName, &sUserData, nullptr, nullptr, + false, xIter.get()); + m_xUsedDBTLB->set_image(*xIter, rToInsert); + return xIter; +} + +// destroy dialog +SwChangeDBDlg::~SwChangeDBDlg() +{ +} + +short SwChangeDBDlg::run() +{ + short nRet = SfxDialogController::run(); + if (nRet == RET_OK) + UpdateFields(); + return nRet; +} + +void SwChangeDBDlg::UpdateFields() +{ + std::vector<OUString> aDBNames; + + m_xUsedDBTLB->selected_foreach([this, &aDBNames](weld::TreeIter& rEntry){ + if (m_xUsedDBTLB->get_iter_depth(rEntry)) + { + std::unique_ptr<weld::TreeIter> xIter(m_xUsedDBTLB->make_iterator(&rEntry)); + m_xUsedDBTLB->iter_parent(*xIter); + OUString sTmp(m_xUsedDBTLB->get_text(*xIter) + + OUStringChar(DB_DELIM) + m_xUsedDBTLB->get_text(rEntry) + OUStringChar(DB_DELIM) + + m_xUsedDBTLB->get_id(rEntry)); + aDBNames.push_back(sTmp); + } + return false; + }); + + m_pSh->StartAllAction(); + OUString sTableName; + OUString sColumnName; + sal_Bool bIsTable = false; + const OUString DBName(m_xAvailDBTLB->GetDBName(sTableName, sColumnName, &bIsTable)); + const OUString sTemp = DBName + + OUStringChar(DB_DELIM) + + sTableName + + OUStringChar(DB_DELIM) + + OUString::number(bIsTable + ? CommandType::TABLE + : CommandType::QUERY); + m_pSh->ChangeDBFields( aDBNames, sTemp); + m_pSh->EndAllAction(); +} + +IMPL_LINK_NOARG(SwChangeDBDlg, ButtonHdl, weld::Button&, void) +{ + OUString sTableName; + OUString sColumnName; + SwDBData aData; + sal_Bool bIsTable = false; + aData.sDataSource = m_xAvailDBTLB->GetDBName(sTableName, sColumnName, &bIsTable); + aData.sCommand = sTableName; + aData.nCommandType = bIsTable ? 0 : 1; + m_pSh->ChgDBData(aData); + ShowDBName(m_pSh->GetDBData()); + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(SwChangeDBDlg, TreeSelectHdl, weld::TreeView&, void) +{ + TreeSelect(); +} + +void SwChangeDBDlg::TreeSelect() +{ + bool bEnable = false; + std::unique_ptr<weld::TreeIter> xIter(m_xAvailDBTLB->make_iterator()); + if (m_xAvailDBTLB->get_selected(xIter.get())) + { + if (m_xAvailDBTLB->get_iter_depth(*xIter)) + bEnable = true; + } + m_xDefineBT->set_sensitive(bEnable); +} + + +// convert database name for display +void SwChangeDBDlg::ShowDBName(const SwDBData& rDBData) +{ + if (rDBData.sDataSource.isEmpty() && rDBData.sCommand.isEmpty()) + { + m_xDocDBNameFT->set_label(SwResId(SW_STR_NONE)); + } + else + { + const OUString sName(rDBData.sDataSource + "." + rDBData.sCommand); + m_xDocDBNameFT->set_label(sName.replaceAll("~", "~~")); + } +} + +IMPL_LINK_NOARG(SwChangeDBDlg, AddDBHdl, weld::Button&, void) +{ + const OUString sNewDB = SwDBManager::LoadAndRegisterDataSource(m_xDialog.get()); + if (!sNewDB.isEmpty()) + { + m_xAvailDBTLB->AddDataSource(sNewDB); + TreeSelect(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/flddb.cxx b/sw/source/ui/fldui/flddb.cxx new file mode 100644 index 0000000000..0c0210eeda --- /dev/null +++ b/sw/source/ui/fldui/flddb.cxx @@ -0,0 +1,541 @@ +/* -*- 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 <swmodule.hxx> +#include <wrtsh.hxx> +#include <dbfld.hxx> +#include <doc.hxx> + +#include "flddb.hxx" +#include <dbconfig.hxx> +#include <dbmgr.hxx> +#include <o3tl/string_view.hxx> + +#define USER_DATA_VERSION_1 "1" +#define USER_DATA_VERSION USER_DATA_VERSION_1 + +SwFieldDBPage::SwFieldDBPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *const pCoreSet) + : SwFieldPage(pPage, pController, "modules/swriter/ui/flddbpage.ui", "FieldDbPage", pCoreSet) + , m_nOldFormat(0) + , m_nOldSubType(0) + , m_xTypeLB(m_xBuilder->weld_tree_view("type")) + , m_xDatabaseTLB(new SwDBTreeList(m_xBuilder->weld_tree_view("select"))) + , m_xAddDBPB(m_xBuilder->weld_button("browse")) + , m_xCondition(m_xBuilder->weld_widget("condgroup")) + , m_xConditionED(new ConditionEdit(m_xBuilder->weld_entry("condition"))) + , m_xValue(m_xBuilder->weld_widget("recgroup")) + , m_xValueED(m_xBuilder->weld_entry("recnumber")) + , m_xDBFormatRB(m_xBuilder->weld_radio_button("fromdatabasecb")) + , m_xNewFormatRB(m_xBuilder->weld_radio_button("userdefinedcb")) + , m_xNumFormatLB(new NumFormatListBox(m_xBuilder->weld_combo_box("numformat"))) + , m_xFormatLB(m_xBuilder->weld_combo_box("format")) + , m_xFormat(m_xBuilder->weld_widget("formatframe")) +{ + SetTypeSel(-1); //TODO + + m_xTypeLB->make_sorted(); + m_xFormatLB->make_sorted(); + + auto nWidth = m_xTypeLB->get_approximate_digit_width() * FIELD_COLUMN_WIDTH; + auto nHeight = m_xTypeLB->get_height_rows(10); + m_xTypeLB->set_size_request(nWidth, nHeight); + m_xDatabaseTLB->set_size_request(nWidth*2, nHeight); + + m_xNumFormatLB->connect_changed(LINK(this, SwFieldDBPage, NumSelectHdl)); + m_xDatabaseTLB->connect_changed(LINK(this, SwFieldDBPage, TreeSelectHdl)); + m_xDatabaseTLB->connect_row_activated(LINK(this, SwFieldDBPage, TreeViewInsertHdl)); + + m_xValueED->connect_changed(LINK(this, SwFieldDBPage, ModifyHdl)); + m_xAddDBPB->connect_clicked(LINK(this, SwFieldDBPage, AddDBHdl)); + + // uitests + m_xTypeLB->set_buildable_name(m_xTypeLB->get_buildable_name() + "-db"); + m_xNumFormatLB->set_buildable_name(m_xNumFormatLB->get_buildable_name() + "-db"); + m_xFormatLB->set_buildable_name(m_xFormatLB->get_buildable_name() + "-db"); +} + +SwFieldDBPage::~SwFieldDBPage() +{ + // If we have no stored SwWrtShell, it means we didn't do anything useful - no need to revoke. + if (SwWrtShell* pSh = CheckAndGetWrtShell()) + { + // This would cleanup in the case of cancelled dialog + SwDBManager* pDbManager = pSh->GetDoc()->GetDBManager(); + if (pDbManager) + pDbManager->RevokeLastRegistrations(); + } +} + +// initialise TabPage +void SwFieldDBPage::Reset(const SfxItemSet*) +{ + Init(); // general initialization + + const sal_Int32 nOldPos = m_xTypeLB->get_selected_index(); + m_xTypeLB->freeze(); + m_sOldDBName = m_xDatabaseTLB->GetDBName(m_sOldTableName, m_sOldColumnName); + + m_xTypeLB->clear(); + + if (!IsFieldEdit()) + { + // initialise TypeListBox + const SwFieldGroupRgn& rRg = SwFieldMgr::GetGroupRange(IsFieldDlgHtmlMode(), GetGroup()); + + for(sal_uInt16 i = rRg.nStart; i < rRg.nEnd; ++i) + { + const SwFieldTypesEnum nTypeId = SwFieldMgr::GetTypeId(i); + m_xTypeLB->append(OUString::number(static_cast<sal_uInt16>(nTypeId)), SwFieldMgr::GetTypeStr(i)); + } + } + else + { + const SwFieldTypesEnum nTypeId = GetCurField()->GetTypeId(); + m_xTypeLB->append(OUString::number(static_cast<sal_uInt16>(nTypeId)), + SwFieldMgr::GetTypeStr(SwFieldMgr::GetPos(nTypeId))); + } + + m_xTypeLB->thaw(); + + // select old Pos + if (GetTypeSel() != -1) + m_xTypeLB->select(GetTypeSel()); + + m_xFormatLB->clear(); + + const sal_uInt16 nSize = GetFieldMgr().GetFormatCount(SwFieldTypesEnum::DatabaseSetNumber, IsFieldDlgHtmlMode()); + for( sal_uInt16 i = 0; i < nSize; ++i ) + { + const sal_uInt16 nFormatId = GetFieldMgr().GetFormatId( SwFieldTypesEnum::DatabaseSetNumber, i ); + OUString sId(OUString::number(nFormatId)); + m_xFormatLB->append(sId, GetFieldMgr().GetFormatStr(SwFieldTypesEnum::DatabaseSetNumber, i)); + if (SVX_NUM_ARABIC == nFormatId) + m_xFormatLB->set_active_id(sId); + } + + if (!IsFieldEdit()) + { + if (nOldPos != -1) + m_xTypeLB->select(nOldPos); + + if (!m_sOldDBName.isEmpty()) + { + m_xDatabaseTLB->Select(m_sOldDBName, m_sOldTableName, m_sOldColumnName); + } + else + { + if (SwWrtShell *pSh = CheckAndGetWrtShell()) + { + SwDBData aTmp(pSh->GetDBData()); + m_xDatabaseTLB->Select(aTmp.sDataSource, aTmp.sCommand, u""); + } + } + } + + if( !IsRefresh() ) + { + const OUString sUserData = GetUserData(); + sal_Int32 nIdx{ 0 }; + if (o3tl::equalsIgnoreAsciiCase(o3tl::getToken(sUserData, 0, ';', nIdx), u"" USER_DATA_VERSION_1)) + { + const sal_uInt16 nVal = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(o3tl::getToken(sUserData, 0, ';', nIdx))); + if (nVal != USHRT_MAX) + { + for (sal_Int32 i = 0, nEntryCount = m_xTypeLB->n_children(); i < nEntryCount; ++i) + { + if (nVal == m_xTypeLB->get_id(i).toUInt32()) + { + m_xTypeLB->select(i); + break; + } + } + } + } + } + TypeHdl(nullptr); + + m_xTypeLB->connect_changed(LINK(this, SwFieldDBPage, TypeListBoxHdl)); + m_xTypeLB->connect_row_activated(LINK(this, SwFieldDBPage, TreeViewInsertHdl)); + + if (IsFieldEdit()) + { + m_xConditionED->save_value(); + m_xValueED->save_value(); + m_sOldDBName = m_xDatabaseTLB->GetDBName(m_sOldTableName, m_sOldColumnName); + m_nOldFormat = GetCurField()->GetFormat(); + m_nOldSubType = GetCurField()->GetSubType(); + } +} + +// SwFieldDBPage may ask for password to select current document's data source, +// so only do that when activating the page, not when dialog is creating all pages +bool SwFieldDBPage::DeferResetToFirstActivation() { return true; } + +bool SwFieldDBPage::FillItemSet(SfxItemSet* ) +{ + OUString sTableName; + OUString sColumnName; + SwDBData aData; + sal_Bool bIsTable; + aData.sDataSource = m_xDatabaseTLB->GetDBName(sTableName, sColumnName, &bIsTable); + aData.sCommand = sTableName; + aData.nCommandType = bIsTable ? 0 : 1; + + if (SwWrtShell *pSh = CheckAndGetWrtShell()) + { + SwDBManager* pDbManager = pSh->GetDoc()->GetDBManager(); + if (pDbManager) + pDbManager->CommitLastRegistrations(); + + if (aData.sDataSource.isEmpty()) + aData = pSh->GetDBData(); + } + + if(!aData.sDataSource.isEmpty()) // without database no new field command + { + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + sal_uInt32 nFormat = 0; + sal_uInt16 nSubType = 0; + + OUString sDBName = aData.sDataSource + + OUStringChar(DB_DELIM) + + aData.sCommand + + OUStringChar(DB_DELIM) + + OUString::number(aData.nCommandType) + + OUStringChar(DB_DELIM); + if (!sColumnName.isEmpty()) + { + sDBName += sColumnName + OUStringChar(DB_DELIM); + } + OUString aName = sDBName + m_xConditionED->get_text(); + + switch (nTypeId) + { + case SwFieldTypesEnum::Database: + nFormat = m_xNumFormatLB->GetFormat(); + if (m_xNewFormatRB->get_sensitive() && m_xNewFormatRB->get_active()) + nSubType = nsSwExtendedSubType::SUB_OWN_FMT; + aName = sDBName; + break; + + case SwFieldTypesEnum::DatabaseSetNumber: + nFormat = m_xFormatLB->get_active_id().toUInt32(); + break; + default: break; + } + + const OUString aVal(m_xValueED->get_text()); + OUString sTempTableName; + OUString sTempColumnName; + OUString sTempDBName = m_xDatabaseTLB->GetDBName(sTempTableName, sTempColumnName); + bool bDBListBoxChanged = m_sOldDBName != sTempDBName || + m_sOldTableName != sTempTableName || m_sOldColumnName != sTempColumnName; + if (!IsFieldEdit() || + m_xConditionED->get_value_changed_from_saved() || + m_xValueED->get_saved_value() != aVal || + bDBListBoxChanged || + m_nOldFormat != nFormat || m_nOldSubType != nSubType) + { + InsertField( nTypeId, nSubType, aName, aVal, nFormat); + } + } + + return false; +} + +std::unique_ptr<SfxTabPage> SwFieldDBPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet *const pAttrSet ) +{ + return std::make_unique<SwFieldDBPage>( pPage, pController, pAttrSet ); +} + +sal_uInt16 SwFieldDBPage::GetGroup() +{ + return GRP_DB; +} + +IMPL_LINK( SwFieldDBPage, TypeListBoxHdl, weld::TreeView&, rBox, void ) +{ + TypeHdl(&rBox); +} + +void SwFieldDBPage::TypeHdl(const weld::TreeView* pBox) +{ + // save old ListBoxPos + const sal_Int32 nOld = GetTypeSel(); + + // current ListBoxPos + SetTypeSel(m_xTypeLB->get_selected_index()); + + if (GetTypeSel() == -1) + { + SetTypeSel(0); + m_xTypeLB->select(0); + } + + if (nOld == GetTypeSel()) + return; + + bool bCond = false, bSetNo = false, bFormat = false, bDBFormat = false; + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + m_xDatabaseTLB->ShowColumns(nTypeId == SwFieldTypesEnum::Database); + + if (IsFieldEdit()) + { + SwDBData aData; + OUString sColumnName; + if (nTypeId == SwFieldTypesEnum::Database) + { + if (auto const*const pField = dynamic_cast<SwDBField*>(GetCurField())) + { + aData = pField->GetDBData(); + sColumnName = static_cast<SwDBFieldType*>(GetCurField()->GetTyp())->GetColumnName(); + } + } + else + { + if (auto *const pField = dynamic_cast<SwDBNameInfField*>(GetCurField())) + { + if(SwWrtShell *pSh = CheckAndGetWrtShell()) + aData = pField->GetDBData(pSh->GetDoc()); + } + } + m_xDatabaseTLB->Select(aData.sDataSource, aData.sCommand, sColumnName); + } + + switch (nTypeId) + { + case SwFieldTypesEnum::Database: + { + bFormat = true; + bDBFormat = true; + m_xNumFormatLB->show(); + m_xFormatLB->hide(); + + weld::Widget& rWidget = m_xNumFormatLB->get_widget(); + rWidget.set_accessible_relation_labeled_by(m_xNewFormatRB.get()); + + if (pBox) // type was changed by user + m_xDBFormatRB->set_active(true); + + if (IsFieldEdit()) + { + if (GetCurField()->GetFormat() != 0 && GetCurField()->GetFormat() != SAL_MAX_UINT32) + m_xNumFormatLB->SetDefFormat(GetCurField()->GetFormat()); + + if (GetCurField()->GetSubType() & nsSwExtendedSubType::SUB_OWN_FMT) + m_xNewFormatRB->set_active(true); + else + m_xDBFormatRB->set_active(true); + } + break; + } + case SwFieldTypesEnum::DatabaseNumberSet: + bSetNo = true; + [[fallthrough]]; + case SwFieldTypesEnum::DatabaseNextSet: + bCond = true; + if (IsFieldEdit()) + { + m_xConditionED->set_text(GetCurField()->GetPar1()); + m_xValueED->set_text(GetCurField()->GetPar2()); + } + break; + + case SwFieldTypesEnum::DatabaseName: + break; + + case SwFieldTypesEnum::DatabaseSetNumber: + { + bFormat = true; + m_xNewFormatRB->set_active(true); + m_xNumFormatLB->hide(); + m_xFormatLB->show(); + + m_xFormatLB->set_accessible_relation_labeled_by(m_xNewFormatRB.get()); + + if( IsFieldEdit() ) + { + for (sal_Int32 nI = m_xFormatLB->get_count(); nI;) + { + if (GetCurField()->GetFormat() == m_xFormatLB->get_id(--nI).toUInt32()) + { + m_xFormatLB->set_active( nI ); + break; + } + } + } + break; + } + default: break; + } + + m_xCondition->set_sensitive(bCond); + m_xValue->set_sensitive(bSetNo); + if (nTypeId != SwFieldTypesEnum::Database) + { + m_xDBFormatRB->set_sensitive(bDBFormat); + m_xNewFormatRB->set_sensitive(bDBFormat || bFormat); + m_xNumFormatLB->set_sensitive(bDBFormat); + m_xFormatLB->set_sensitive(bFormat); + } + m_xFormat->set_sensitive(bDBFormat || bFormat); + + if (!IsFieldEdit()) + { + m_xValueED->set_text(OUString()); + if (bCond) + m_xConditionED->set_text("TRUE"); + else + m_xConditionED->set_text(OUString()); + } + + CheckInsert(); +} + +IMPL_LINK_NOARG(SwFieldDBPage, NumSelectHdl, weld::ComboBox&, void) +{ + m_xNewFormatRB->set_active(true); + m_xNumFormatLB->CallSelectHdl(); +} + +void SwFieldDBPage::CheckInsert() +{ + bool bInsert = true; + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + std::unique_ptr<weld::TreeIter> xIter(m_xDatabaseTLB->make_iterator()); + if (m_xDatabaseTLB->get_selected(xIter.get())) + { + bool bEntry = m_xDatabaseTLB->iter_parent(*xIter); + + if (nTypeId == SwFieldTypesEnum::Database && bEntry) + bEntry = m_xDatabaseTLB->iter_parent(*xIter); + + bInsert &= bEntry; + } + else + bInsert = false; + + if (nTypeId == SwFieldTypesEnum::DatabaseNumberSet) + { + bool bHasValue = !m_xValueED->get_text().isEmpty(); + + bInsert &= bHasValue; + } + + EnableInsert(bInsert); +} + +IMPL_LINK(SwFieldDBPage, TreeSelectHdl, weld::TreeView&, rBox, void) +{ + std::unique_ptr<weld::TreeIter> xIter(rBox.make_iterator()); + if (!rBox.get_selected(xIter.get())) + return; + + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + bool bEntry = m_xDatabaseTLB->iter_parent(*xIter); + + if (nTypeId == SwFieldTypesEnum::Database && bEntry) + bEntry = m_xDatabaseTLB->iter_parent(*xIter); + + CheckInsert(); + + if (nTypeId != SwFieldTypesEnum::Database) + return; + + bool bNumFormat = false; + + if (bEntry) + { + OUString sTableName; + OUString sColumnName; + sal_Bool bIsTable; + OUString sDBName = m_xDatabaseTLB->GetDBName(sTableName, sColumnName, &bIsTable); + bNumFormat = GetFieldMgr().IsDBNumeric(sDBName, + sTableName, + bIsTable, + sColumnName); + if (!IsFieldEdit()) + m_xDBFormatRB->set_active(true); + } + + m_xDBFormatRB->set_sensitive(bNumFormat); + m_xNewFormatRB->set_sensitive(bNumFormat); + m_xNumFormatLB->set_sensitive(bNumFormat); + m_xFormat->set_sensitive(bNumFormat); +} + +IMPL_LINK_NOARG(SwFieldDBPage, AddDBHdl, weld::Button&, void) +{ + if (SwWrtShell* pSh = CheckAndGetWrtShell()) + { + OUString sNewDB + = SwDBManager::LoadAndRegisterDataSource(GetFrameWeld(), pSh->GetDoc()->GetDocShell()); + if (!sNewDB.isEmpty()) + { + m_xDatabaseTLB->AddDataSource(sNewDB); + } + } +} + +// Modify +IMPL_LINK_NOARG(SwFieldDBPage, ModifyHdl, weld::Entry&, void) +{ + CheckInsert(); +} + +void SwFieldDBPage::FillUserData() +{ + const sal_Int32 nEntryPos = m_xTypeLB->get_selected_index(); + const sal_uInt16 nTypeSel = ( -1 == nEntryPos ) + ? USHRT_MAX : m_xTypeLB->get_id(nEntryPos).toUInt32(); + SetUserData(USER_DATA_VERSION ";" + OUString::number( nTypeSel )); +} + +void SwFieldDBPage::ActivateMailMergeAddress() +{ + m_xTypeLB->select_id(OUString::number(static_cast<sal_uInt16>(SwFieldTypesEnum::Database))); + TypeListBoxHdl(*m_xTypeLB); + const SwDBData& rData = SW_MOD()->GetDBConfig()->GetAddressSource(); + m_xDatabaseTLB->Select(rData.sDataSource, rData.sCommand, u""); +} + +void SwFieldDBPage::SetWrtShell(SwWrtShell& rSh) +{ + // We need to remember the shell to be able to call correct SwDBManager + SwFieldPage::SetWrtShell(&rSh); + m_xDatabaseTLB->SetWrtShell(rSh); +} + +SwWrtShell* SwFieldDBPage::CheckAndGetWrtShell() +{ + SwWrtShell* pSh = GetWrtShell(); + if (!pSh) + { + pSh = ::GetActiveWrtShell(); + if (pSh) // this is not guaranteed: e.g., activating print preview with dialog active + SetWrtShell(*pSh); + } + return pSh; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/flddb.hxx b/sw/source/ui/fldui/flddb.hxx new file mode 100644 index 0000000000..9fb967b9a5 --- /dev/null +++ b/sw/source/ui/fldui/flddb.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_FLDUI_FLDDB_HXX +#define INCLUDED_SW_SOURCE_UI_FLDUI_FLDDB_HXX + +#include <condedit.hxx> +#include <dbtree.hxx> +#include <numfmtlb.hxx> + +#include "fldpage.hxx" + +class SwFieldDBPage : public SwFieldPage +{ + OUString m_sOldDBName; + OUString m_sOldTableName; + OUString m_sOldColumnName; + sal_uInt32 m_nOldFormat; + sal_uInt16 m_nOldSubType; + + std::unique_ptr<weld::TreeView> m_xTypeLB; + std::unique_ptr<SwDBTreeList> m_xDatabaseTLB; + std::unique_ptr<weld::Button> m_xAddDBPB; + std::unique_ptr<weld::Widget> m_xCondition; + std::unique_ptr<ConditionEdit> m_xConditionED; + std::unique_ptr<weld::Widget> m_xValue; + std::unique_ptr<weld::Entry> m_xValueED; + std::unique_ptr<weld::RadioButton> m_xDBFormatRB; + std::unique_ptr<weld::RadioButton> m_xNewFormatRB; + std::unique_ptr<NumFormatListBox> m_xNumFormatLB; + std::unique_ptr<weld::ComboBox> m_xFormatLB; + std::unique_ptr<weld::Widget> m_xFormat; + + DECL_LINK( TypeListBoxHdl, weld::TreeView&, void ); + DECL_LINK( NumSelectHdl, weld::ComboBox&, void ); + DECL_LINK( TreeSelectHdl, weld::TreeView&, void ); + DECL_LINK( ModifyHdl, weld::Entry&, void ); + DECL_LINK( AddDBHdl, weld::Button&, void ); + void TypeHdl(const weld::TreeView*); + + void CheckInsert(); + + using SwFieldPage::SetWrtShell; + SwWrtShell* CheckAndGetWrtShell(); + +protected: + virtual sal_uInt16 GetGroup() override; + +public: + SwFieldDBPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet); + + virtual ~SwFieldDBPage() override; + + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; + virtual bool DeferResetToFirstActivation() override; + + virtual void FillUserData() override; + void ActivateMailMergeAddress(); + + void SetWrtShell(SwWrtShell& rSh); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/flddinf.cxx b/sw/source/ui/fldui/flddinf.cxx new file mode 100644 index 0000000000..7cb69c1d0e --- /dev/null +++ b/sw/source/ui/fldui/flddinf.cxx @@ -0,0 +1,511 @@ +/* -*- 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/frame.hxx> +#include <svl/numformat.hxx> +#include <svl/zforlist.hxx> +#include <svl/zformat.hxx> +#include <o3tl/string_view.hxx> + +#include <swtypes.hxx> +#include <flddinf.hrc> +#include <strings.hrc> +#include <fldbas.hxx> +#include <docufld.hxx> +#include <wrtsh.hxx> +#include <cmdid.h> + +#include "flddinf.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Date.hpp> + +#define USER_DATA_VERSION_1 "1" +#define USER_DATA_VERSION USER_DATA_VERSION_1 + +using namespace nsSwDocInfoSubType; +using namespace com::sun::star; + +void FillFieldSelect(weld::TreeView& rListBox) +{ + for (auto const& aID : FLD_SELECT) + rListBox.append_text(SwResId(aID)); +} + +SwFieldDokInfPage::SwFieldDokInfPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *const pCoreSet) + : SwFieldPage(pPage, pController, "modules/swriter/ui/flddocinfopage.ui", "FieldDocInfoPage", pCoreSet) + , m_nOldSel(0) + , m_nOldFormat(0) + , m_xTypeList(m_xBuilder->weld_tree_view("type-list")) + , m_xTypeTree(m_xBuilder->weld_tree_view("type-tree")) + // tdf#104278 have two tree views, one with expander and one without, the one with is only used + // when there are custom properties which use the expander, so the common case of no custom + // properties doesn't have an 'unexplained' expander margin + , m_pTypeView(m_xTypeTree.get()) + , m_xSelection(m_xBuilder->weld_widget("selectframe")) + , m_xSelectionLB(m_xBuilder->weld_tree_view("select")) + , m_xFormat(m_xBuilder->weld_widget("formatframe")) + , m_xFormatLB(new SwNumFormatTreeView(m_xBuilder->weld_tree_view("format"))) + , m_xFixedCB(m_xBuilder->weld_check_button("fixed")) +{ + m_xTypeList->make_sorted(); + m_xTypeTree->make_sorted(); + FillFieldSelect(*m_xSelectionLB); + + auto nWidth = m_pTypeView->get_approximate_digit_width() * FIELD_COLUMN_WIDTH; + auto nHeight = m_pTypeView->get_height_rows(10); + m_xTypeTree->set_size_request(nWidth, nHeight); + m_xTypeList->set_size_request(nWidth, nHeight); + m_xFormatLB->get_widget().set_size_request(nWidth * 2, nHeight); + m_xSelectionLB->set_size_request(nWidth, nHeight); + + //enable 'active' language selection + m_xFormatLB->SetShowLanguageControl(true); + + const SfxUnoAnyItem* pItem = pCoreSet + ? pCoreSet->GetItem(FN_FIELD_DIALOG_DOC_PROPS, false) + : nullptr; + if ( pItem ) + pItem->GetValue() >>= m_xCustomPropertySet; + + // uitests + m_pTypeView->set_buildable_name("type-docinf"); + m_xSelectionLB->set_buildable_name(m_xSelectionLB->get_buildable_name() + "-docinf"); + m_xFormatLB->set_buildable_name(m_xFormatLB->get_buildable_name() + "-docinf"); +} + +SwFieldDokInfPage::~SwFieldDokInfPage() +{ +} + +void SwFieldDokInfPage::Reset(const SfxItemSet* ) +{ + Init(); // general initialisation + + uno::Sequence<beans::Property> aCustomProperties; + if (m_xCustomPropertySet.is()) + { + uno::Reference<beans::XPropertySetInfo> xSetInfo = m_xCustomPropertySet->getPropertySetInfo(); + aCustomProperties = xSetInfo->getProperties(); + } + + if (aCustomProperties.hasElements()) + { + m_xTypeList->hide(); + m_xTypeList->set_buildable_name("type-list"); + m_xTypeTree->show(); + m_pTypeView = m_xTypeTree.get(); + } + else + { + m_xTypeTree->hide(); + m_xTypeTree->set_buildable_name("type-tree"); + m_xTypeList->show(); + m_pTypeView = m_xTypeList.get(); + } + + m_pTypeView->set_buildable_name("type-docinf"); + + // initialise TypeListBox + m_pTypeView->freeze(); + m_pTypeView->clear(); + m_xSelEntry.reset(); + + // display SubTypes in TypeLB + sal_uInt16 nSubType = USHRT_MAX; + if (IsFieldEdit()) + { + const SwField* pCurField = GetCurField(); + nSubType = pCurField->GetSubType() & 0xff; + if( nSubType == DI_CUSTOM ) + { + if (auto const pField = dynamic_cast<SwDocInfoField const*>(pCurField)) + { + m_sOldCustomFieldName = pField->GetName(); + } + } + m_xFormatLB->SetAutomaticLanguage(pCurField->IsAutomaticLanguage()); + SwWrtShell *pSh = GetWrtShell(); + if(pSh) + { + const SvNumberformat* pFormat = pSh->GetNumberFormatter()->GetEntry(pCurField->GetFormat()); + if(pFormat) + m_xFormatLB->SetLanguage(pFormat->GetLanguage()); + } + } + + sal_Int32 nSelEntryData = -1; + const OUString sUserData = GetUserData(); + sal_Int32 nIdx{ 0 }; + if (o3tl::equalsIgnoreAsciiCase(o3tl::getToken(sUserData, 0, ';', nIdx), u"" USER_DATA_VERSION_1)) + { + nSelEntryData = o3tl::toInt32(o3tl::getToken(sUserData, 0, ';', nIdx)); + } + + std::vector<OUString> aLst; + GetFieldMgr().GetSubTypes(SwFieldTypesEnum::DocumentInfo, aLst); + std::unique_ptr<weld::TreeIter> xEntry(m_pTypeView->make_iterator()); + std::unique_ptr<weld::TreeIter> xExpandEntry; + for(size_t i = 0; i < aLst.size(); ++i) + { + if (!IsFieldEdit() || nSubType == i) + { + const OUString sId(OUString::number(i)); + if (DI_CUSTOM == i) + { + if(m_xCustomPropertySet.is() ) + { + if (aCustomProperties.hasElements()) + { + std::unique_ptr<weld::TreeIter> xInfo(m_pTypeView->make_iterator()); + + OUString sText(SwResId(STR_CUSTOM_FIELD)); + OUString sEntryId(OUString::number(USHRT_MAX)); + m_pTypeView->insert(nullptr, -1, &sText, &sEntryId, nullptr, + nullptr, false, xInfo.get()); + for (const auto& rProperty : aCustomProperties) + { + const OUString sEntry = rProperty.Name; + + m_pTypeView->insert(xInfo.get(), -1, &sEntry, &sId, + nullptr, nullptr, false, xEntry.get()); + if (m_sOldCustomFieldName == sEntry) + { + m_xSelEntry = m_pTypeView->make_iterator(xEntry.get()); + xExpandEntry = m_pTypeView->make_iterator(xInfo.get()); + } + } + } + } + } + else + { + if (!(IsFieldDlgHtmlMode() && (i == DI_EDIT || i == DI_SUBJECT || i == DI_PRINT))) + { + m_pTypeView->insert(nullptr, -1, &aLst[i], &sId, + nullptr, nullptr, false, xEntry.get()); + } + } + if (static_cast<size_t>(nSelEntryData) == i) + m_xSelEntry = std::move(xEntry); + } + } + + m_pTypeView->thaw(); + + if (xExpandEntry) + m_pTypeView->expand_row(*xExpandEntry); + + // select old Pos + if (m_xSelEntry) + { + m_pTypeView->select(*m_xSelEntry); + nSubType = m_pTypeView->get_id(*m_xSelEntry).toUInt32(); + } + else + { + m_xSelEntry = m_pTypeView->make_iterator(); + if (m_pTypeView->get_iter_first(*m_xSelEntry)) + nSubType = m_pTypeView->get_id(*m_xSelEntry).toUInt32(); + else + m_xSelEntry.reset(); + } + + FillSelectionLB(nSubType); + if (m_xSelEntry) + TypeHdl(*m_pTypeView); + + m_pTypeView->connect_changed(LINK(this, SwFieldDokInfPage, TypeHdl)); + m_pTypeView->connect_row_activated(LINK(this, SwFieldDokInfPage, TreeViewInsertHdl)); + m_xSelectionLB->connect_changed(LINK(this, SwFieldDokInfPage, SubTypeHdl)); + m_xSelectionLB->connect_row_activated(LINK(this, SwFieldDokInfPage, TreeViewInsertHdl)); + m_xFormatLB->connect_row_activated(LINK(this, SwFieldDokInfPage, TreeViewInsertHdl)); + + if (IsFieldEdit()) + { + m_nOldSel = m_xSelectionLB->get_selected_index(); + m_nOldFormat = GetCurField()->GetFormat(); + m_xFixedCB->save_state(); + } +} + +IMPL_LINK_NOARG(SwFieldDokInfPage, TypeHdl, weld::TreeView&, void) +{ + // current ListBoxPos + if (!m_pTypeView->get_selected(m_xSelEntry.get()) && + m_pTypeView->get_iter_first(*m_xSelEntry)) + { + m_pTypeView->select(*m_xSelEntry); + } + FillSelectionLB(m_pTypeView->get_id(*m_xSelEntry).toUInt32()); + SubTypeHdl(*m_xSelectionLB); +} + +IMPL_LINK_NOARG(SwFieldDokInfPage, SubTypeHdl, weld::TreeView&, void) +{ + sal_uInt16 nSubType = m_pTypeView->get_id(*m_xSelEntry).toUInt32(); + sal_Int32 nPos = m_xSelectionLB->get_selected_index(); + sal_uInt16 nExtSubType; + SvNumFormatType nNewType = SvNumFormatType::ALL; + + if (nSubType != DI_EDIT) + { + if (nPos == -1) + { + if (!m_xSelectionLB->n_children()) + { + m_xFormatLB->clear(); + m_xFormat->set_sensitive(false); + if( nSubType == DI_CUSTOM ) + { + //find out which type the custom field has - for a start set to DATE format + const OUString sName = m_pTypeView->get_text(*m_xSelEntry); + try + { + uno::Any aVal = m_xCustomPropertySet->getPropertyValue( sName ); + const uno::Type& rValueType = aVal.getValueType(); + if( rValueType == ::cppu::UnoType<util::DateTime>::get()) + { + nNewType = SvNumFormatType::DATETIME; + } + else if( rValueType == ::cppu::UnoType<util::Date>::get()) + { + nNewType = SvNumFormatType::DATE; + } + else if( rValueType == ::cppu::UnoType<util::Time>::get()) + { + nNewType = SvNumFormatType::TIME; + } + } + catch( const uno::Exception& ) + { + } + } + else + return; + } + nPos = 0; + } + + nExtSubType = m_xSelectionLB->get_id(nPos).toUInt32(); + } + else + nExtSubType = DI_SUB_TIME; + + SvNumFormatType nOldType = SvNumFormatType::ALL; + bool bEnable = false; + bool bOneArea = false; + + if (m_xFormatLB->get_active()) + nOldType = m_xFormatLB->GetFormatType(); + + switch (nExtSubType) + { + case DI_SUB_AUTHOR: + break; + + case DI_SUB_DATE: + nNewType = SvNumFormatType::DATE; + bOneArea = true; + break; + + case DI_SUB_TIME: + nNewType = SvNumFormatType::TIME; + bOneArea = true; + break; + } + if (nNewType == SvNumFormatType::ALL) + { + m_xFormatLB->clear(); + } + else + { + if (nOldType != nNewType) + { + m_xFormatLB->SetFormatType(nNewType); + m_xFormatLB->SetOneArea(bOneArea); + } + bEnable = true; + } + + sal_uInt32 nFormat = 0; + + sal_uInt16 nOldSubType = 0; + + if (IsFieldEdit()) + { + if (auto const pField = dynamic_cast<SwDocInfoField const*>(GetCurField())) + { + nFormat = pField->GetFormat(); + nOldSubType = pField->GetSubType() & 0xff00; + } + nPos = m_xSelectionLB->get_selected_index(); + if (nPos != -1) + { + nSubType = m_xSelectionLB->get_id(nPos).toUInt32(); + + nOldSubType &= ~DI_SUB_FIXED; + if (nOldSubType == nSubType) + { + if (!nFormat && (nNewType == SvNumFormatType::DATE || nNewType == SvNumFormatType::TIME)) + { + SwWrtShell *pSh = GetWrtShell(); + if(pSh) + { + SvNumberFormatter* pFormatter = pSh->GetNumberFormatter(); + LanguageType eLang = m_xFormatLB->GetCurLanguage(); + if (nNewType == SvNumFormatType::DATE) + nFormat = pFormatter->GetFormatIndex( NF_DATE_SYSTEM_SHORT, eLang); + else if (nNewType == SvNumFormatType::TIME) + nFormat = pFormatter->GetFormatIndex( NF_TIME_HHMM, eLang); + } + } + m_xFormatLB->SetDefFormat(nFormat); + } + } + else if( (nSubType == DI_CUSTOM) && (nNewType != SvNumFormatType::ALL) ) + { + m_xFormatLB->SetDefFormat(nFormat); + } + } + + // Always allow Fixed Content to be turned off if it is currently on + m_xFormat->set_sensitive(bEnable || m_xFixedCB->get_active()); + + if (!bEnable) + m_xFormatLB->clear(); + else if (m_xFormatLB->get_selected_index() == -1) + m_xFormatLB->select(0); +} + +sal_Int32 SwFieldDokInfPage::FillSelectionLB(sal_uInt16 nSubType) +{ + // fill Format-Listbox + SwFieldTypesEnum nTypeId = SwFieldTypesEnum::DocumentInfo; + + EnableInsert(nSubType != USHRT_MAX); + + if (nSubType == USHRT_MAX) // Info-Text + nSubType = DI_SUBTYPE_BEGIN; + + m_xSelectionLB->clear(); + + sal_uInt16 nSize = 0; + sal_Int32 nSelPos = -1; + sal_uInt16 nExtSubType = 0; + + if (IsFieldEdit()) + { + if (auto const pField = dynamic_cast<SwDocInfoField const*>(GetCurField())) + { + nExtSubType = pField->GetSubType() & 0xff00; + } + m_xFixedCB->set_active((nExtSubType & DI_SUB_FIXED) != 0); + nExtSubType = ((nExtSubType & ~DI_SUB_FIXED) >> 8) - 1; + } + + if (nSubType < DI_CREATE || nSubType == DI_DOCNO || nSubType == DI_EDIT|| nSubType == DI_CUSTOM ) + { + // Format Box is empty for Title and Time + } + else + { + nSize = GetFieldMgr().GetFormatCount(nTypeId, IsFieldDlgHtmlMode()); + for (sal_uInt16 i = 0; i < nSize; ++i) + { + OUString sId(OUString::number(GetFieldMgr().GetFormatId(nTypeId, i))); + m_xSelectionLB->append(sId, GetFieldMgr().GetFormatStr(nTypeId, i)); + if (IsFieldEdit() && i == nExtSubType) + nSelPos = i; + } + } + + bool bEnable = nSize != 0; + + if (nSize) + { + if (m_xSelectionLB->get_selected_index() == -1) + m_xSelectionLB->select(nSelPos == USHRT_MAX ? 0 : nSelPos); + bEnable = true; + } + + m_xSelection->set_sensitive(bEnable); + + return nSize; +} + +bool SwFieldDokInfPage::FillItemSet(SfxItemSet* ) +{ + if (!m_xSelEntry) + return false; + + sal_uInt16 nSubType = m_pTypeView->get_id(*m_xSelEntry).toUInt32(); + if (nSubType == USHRT_MAX) + return false; + + sal_uInt32 nFormat = 0; + + sal_Int32 nPos = m_xSelectionLB->get_selected_index(); + + OUString aName; + if (DI_CUSTOM == nSubType) + aName = m_pTypeView->get_text(*m_xSelEntry); + + if (nPos != -1) + nSubType |= m_xSelectionLB->get_id(nPos).toUInt32(); + + if (m_xFixedCB->get_active()) + nSubType |= DI_SUB_FIXED; + + nPos = m_xFormatLB->get_selected_index(); + if(nPos != -1) + nFormat = m_xFormatLB->GetFormat(); + + if (!IsFieldEdit() || m_nOldSel != m_xSelectionLB->get_selected_index() || + m_nOldFormat != nFormat || m_xFixedCB->get_state_changed_from_saved() + || (DI_CUSTOM == nSubType && aName != m_sOldCustomFieldName )) + { + InsertField(SwFieldTypesEnum::DocumentInfo, nSubType, aName, OUString(), nFormat, + ' ', m_xFormatLB->IsAutomaticLanguage()); + } + + return false; +} + +std::unique_ptr<SfxTabPage> SwFieldDokInfPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet *const pAttrSet) +{ + return std::make_unique<SwFieldDokInfPage>(pPage, pController, pAttrSet); +} + +sal_uInt16 SwFieldDokInfPage::GetGroup() +{ + return GRP_REG; +} + +void SwFieldDokInfPage::FillUserData() +{ + int nEntry = m_pTypeView->get_selected_index(); + sal_uInt16 nTypeSel = nEntry != -1 ? m_pTypeView->get_id(nEntry).toUInt32() : USHRT_MAX; + SetUserData(USER_DATA_VERSION ";" + OUString::number( nTypeSel )); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/flddinf.hxx b/sw/source/ui/fldui/flddinf.hxx new file mode 100644 index 0000000000..c3773af163 --- /dev/null +++ b/sw/source/ui/fldui/flddinf.hxx @@ -0,0 +1,70 @@ +/* -*- 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_FLDUI_FLDDINF_HXX +#define INCLUDED_SW_SOURCE_UI_FLDUI_FLDDINF_HXX + +#include <sfx2/tabdlg.hxx> +#include <numfmtlb.hxx> +#include "fldpage.hxx" + +namespace com::sun::star::beans { class XPropertySet; } + +class SwFieldDokInfPage : public SwFieldPage +{ + std::unique_ptr<weld::TreeIter> m_xSelEntry; + css::uno::Reference < css::beans::XPropertySet > m_xCustomPropertySet; + + sal_Int32 m_nOldSel; + sal_uInt32 m_nOldFormat; + OUString m_sOldCustomFieldName; + + std::unique_ptr<weld::TreeView> m_xTypeList; + std::unique_ptr<weld::TreeView> m_xTypeTree; + weld::TreeView* m_pTypeView; + std::unique_ptr<weld::Widget> m_xSelection; + std::unique_ptr<weld::TreeView> m_xSelectionLB; + std::unique_ptr<weld::Widget> m_xFormat; + std::unique_ptr<SwNumFormatTreeView> m_xFormatLB; + std::unique_ptr<weld::CheckButton> m_xFixedCB; + + DECL_LINK(TypeHdl, weld::TreeView&, void); + DECL_LINK(SubTypeHdl, weld::TreeView&, void); + + sal_Int32 FillSelectionLB(sal_uInt16 nSubTypeId); + +protected: + virtual sal_uInt16 GetGroup() override; + +public: + SwFieldDokInfPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pSet); + virtual ~SwFieldDokInfPage() override; + + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; + + virtual void FillUserData() override; +}; + +void FillFieldSelect(weld::TreeView& rListBox); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/flddok.cxx b/sw/source/ui/fldui/flddok.cxx new file mode 100644 index 0000000000..1a2857bedb --- /dev/null +++ b/sw/source/ui/fldui/flddok.cxx @@ -0,0 +1,644 @@ +/* -*- 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 <flddat.hxx> +#include <docufld.hxx> +#include <strings.hrc> +#include <chpfld.hxx> +#include "flddok.hxx" +#include <swmodule.hxx> +#include <wrtsh.hxx> +#include <svl/numformat.hxx> +#include <svl/zformat.hxx> +#include <o3tl/string_view.hxx> + +#define USER_DATA_VERSION_1 "1" +#define USER_DATA_VERSION USER_DATA_VERSION_1 + +SwFieldDokPage::SwFieldDokPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *const pCoreSet) + : SwFieldPage(pPage, pController, "modules/swriter/ui/flddocumentpage.ui", + "FieldDocumentPage", pCoreSet) + , m_nOldSel(0) + , m_nOldFormat(0) + , m_xTypeLB(m_xBuilder->weld_tree_view("type")) + , m_xSelection(m_xBuilder->weld_widget("selectframe")) + , m_xSelectionLB(m_xBuilder->weld_tree_view("select")) + , m_xValueFT(m_xBuilder->weld_label("valueft")) + , m_xValueED(m_xBuilder->weld_entry("value")) + , m_xLevelFT(m_xBuilder->weld_label("levelft")) + , m_xLevelED(m_xBuilder->weld_combo_box("level")) + , m_xDateFT(m_xBuilder->weld_label("daysft")) + , m_xTimeFT(m_xBuilder->weld_label("minutesft")) + , m_xDateOffsetED(m_xBuilder->weld_spin_button("offset")) + , m_xFormat(m_xBuilder->weld_widget("formatframe")) + , m_xFormatLB(m_xBuilder->weld_tree_view("format")) + , m_xNumFormatLB(new SwNumFormatTreeView(m_xBuilder->weld_tree_view("numformat"))) + , m_xFixedCB(m_xBuilder->weld_check_button("fixed")) +{ + m_xTypeLB->make_sorted(); + m_xFormatLB->make_sorted(); + + auto nWidth = m_xTypeLB->get_approximate_digit_width() * FIELD_COLUMN_WIDTH; + auto nHeight = m_xTypeLB->get_height_rows(10); + + m_xTypeLB->set_size_request(nWidth, nHeight); + m_xSelectionLB->set_size_request(nWidth, nHeight); + m_xFormatLB->set_size_request(nWidth * 2, nHeight); + + m_xSelectionLB->connect_row_activated(LINK(this, SwFieldDokPage, TreeViewInsertHdl)); + m_xFormatLB->connect_row_activated(LINK(this, SwFieldDokPage, TreeViewInsertHdl)); + m_xNumFormatLB->connect_row_activated(LINK(this, SwFieldDokPage, NumFormatHdl)); + + for (sal_uInt16 i = 1; i <= MAXLEVEL; i++) + m_xLevelED->append_text(OUString::number(i)); + + m_xLevelED->set_active(0); + m_xDateOffsetED->set_range(INT_MIN, INT_MAX); + //enable 'active' language selection + m_xNumFormatLB->SetShowLanguageControl(true); + + // uitests + m_xTypeLB->set_buildable_name(m_xTypeLB->get_buildable_name() + "-doc"); + m_xValueED->set_buildable_name(m_xValueED->get_buildable_name() + "-doc"); + m_xNumFormatLB->set_buildable_name(m_xNumFormatLB->get_buildable_name() + "-doc"); + m_xSelectionLB->set_buildable_name(m_xSelectionLB->get_buildable_name() + "-doc"); + m_xFormatLB->set_buildable_name(m_xFormatLB->get_buildable_name() + "-doc"); +} + +SwFieldDokPage::~SwFieldDokPage() +{ +} + +void SwFieldDokPage::Reset(const SfxItemSet* ) +{ + SavePos(*m_xTypeLB); + Init(); // general initialisation + + // initialise TypeListBox + const SwFieldGroupRgn& rRg = SwFieldMgr::GetGroupRange(IsFieldDlgHtmlMode(), GetGroup()); + + m_xTypeLB->freeze(); + m_xTypeLB->clear(); + + if (!IsFieldEdit()) + { + bool bPage = false; + // fill Type-Listbox + for(sal_uInt16 i = rRg.nStart; i < rRg.nEnd; ++i) + { + const SwFieldTypesEnum nTypeId = SwFieldMgr::GetTypeId(i); + + switch (nTypeId) + { + case SwFieldTypesEnum::PreviousPage: + case SwFieldTypesEnum::NextPage: + case SwFieldTypesEnum::PageNumber: + if (!bPage) + { + m_xTypeLB->append(OUString::number(USHRT_MAX), SwResId(FMT_REF_PAGE)); + bPage = true; + } + break; + + default: + m_xTypeLB->append(OUString::number(static_cast<sal_uInt16>(nTypeId)), SwFieldMgr::GetTypeStr(i)); + break; + } + } + } + else + { + const SwField* pCurField = GetCurField(); + SwFieldTypesEnum nTypeId = pCurField->GetTypeId(); + if (nTypeId == SwFieldTypesEnum::FixedDate) + nTypeId = SwFieldTypesEnum::Date; + if (nTypeId == SwFieldTypesEnum::FixedTime) + nTypeId = SwFieldTypesEnum::Time; + m_xTypeLB->append(OUString::number(static_cast<sal_uInt16>(nTypeId)), SwFieldMgr::GetTypeStr(SwFieldMgr::GetPos(nTypeId))); + m_xNumFormatLB->SetAutomaticLanguage(pCurField->IsAutomaticLanguage()); + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + if(pSh) + { + const SvNumberformat* pFormat = pSh->GetNumberFormatter()->GetEntry(pCurField->GetFormat()); + if(pFormat) + m_xNumFormatLB->SetLanguage(pFormat->GetLanguage()); + } + } + + + m_xTypeLB->thaw(); + + // select old Pos + RestorePos(*m_xTypeLB); + + m_xTypeLB->connect_row_activated(LINK(this, SwFieldDokPage, TreeViewInsertHdl)); + m_xTypeLB->connect_changed(LINK(this, SwFieldDokPage, TypeHdl)); + m_xFormatLB->connect_changed(LINK(this, SwFieldDokPage, FormatHdl)); + + if( !IsRefresh() ) + { + const OUString sUserData = GetUserData(); + sal_Int32 nIdx{ 0 }; + if (o3tl::equalsIgnoreAsciiCase(o3tl::getToken(sUserData, 0, ';', nIdx), u"" USER_DATA_VERSION_1)) + { + const sal_uInt16 nVal = static_cast< sal_uInt16 >(o3tl::toInt32(o3tl::getToken(sUserData, 0, ';', nIdx))); + if(nVal != USHRT_MAX) + { + for (int i = 0, nEntryCount = m_xTypeLB->n_children(); i < nEntryCount; i++) + { + if (nVal == m_xTypeLB->get_id(i).toUInt32()) + { + m_xTypeLB->select(i); + break; + } + } + } + } + } + TypeHdl(*m_xTypeLB); + + if (IsFieldEdit()) + { + m_nOldSel = m_xSelectionLB->get_selected_index(); + m_nOldFormat = GetCurField()->GetFormat(); + m_xFixedCB->save_state(); + m_xValueED->save_value(); + m_xLevelED->save_value(); + m_xDateOffsetED->save_value(); + } +} + +IMPL_LINK_NOARG(SwFieldDokPage, TypeHdl, weld::TreeView&, void) +{ + // save old ListBoxPos + const sal_Int32 nOld = GetTypeSel(); + + // current ListBoxPos + SetTypeSel(m_xTypeLB->get_selected_index()); + + if(GetTypeSel() == -1) + { + SetTypeSel(0); + m_xTypeLB->select(0); + } + + if (nOld == GetTypeSel()) + return; + + size_t nCount; + + m_xDateFT->hide(); + m_xTimeFT->hide(); + + SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + // fill Selection-Listbox + m_xSelectionLB->clear(); + + if (nTypeId != SwFieldTypesEnum::Unknown) + { + std::vector<OUString> aLst; + GetFieldMgr().GetSubTypes(nTypeId, aLst); + + if (nTypeId != SwFieldTypesEnum::Author) + nCount = aLst.size(); + else + nCount = GetFieldMgr().GetFormatCount(nTypeId, IsFieldDlgHtmlMode()); + + for (size_t i = 0; i < nCount; ++i) + { + if (!IsFieldEdit()) + { + OUString sId(OUString::number(i)); + if (nTypeId != SwFieldTypesEnum::Author) + m_xSelectionLB->append(sId, aLst[i]); + else + m_xSelectionLB->append(sId, GetFieldMgr().GetFormatStr(nTypeId, i)); + } + else + { + bool bInsert = false; + + OUString sId(OUString::number(i)); + + switch (nTypeId) + { + case SwFieldTypesEnum::Date: + case SwFieldTypesEnum::Time: + m_xSelectionLB->append(sId, aLst[i]); + if (static_cast<SwDateTimeField*>(GetCurField())->IsFixed() && !i) + m_xSelectionLB->select_id(sId); + if (!static_cast<SwDateTimeField*>(GetCurField())->IsFixed() && i) + m_xSelectionLB->select_id(sId); + break; + case SwFieldTypesEnum::ExtendedUser: + case SwFieldTypesEnum::DocumentStatistics: + m_xSelectionLB->append(sId, aLst[i]); + if (GetCurField()->GetSubType() == i) + m_xSelectionLB->select_id(sId); + break; + + case SwFieldTypesEnum::Author: + { + const OUString sFormat(GetFieldMgr().GetFormatStr(nTypeId, i)); + m_xSelectionLB->append(sId, sFormat); + m_xSelectionLB->select_text(GetFieldMgr().GetFormatStr(nTypeId, GetCurField()->GetFormat())); + break; + } + + default: + if (aLst[i] == GetCurField()->GetPar1()) + bInsert = true; + break; + } + if (bInsert) + { + m_xSelectionLB->append(sId, aLst[i]); + break; + } + } + } + m_xSelectionLB->connect_changed(Link<weld::TreeView&,void>()); + } + else + { + AddSubType(SwFieldTypesEnum::PageNumber); + AddSubType(SwFieldTypesEnum::PreviousPage); + AddSubType(SwFieldTypesEnum::NextPage); + nTypeId = static_cast<SwFieldTypesEnum>(m_xSelectionLB->get_id(0).toUInt32()); + nCount = 3; + m_xSelectionLB->connect_changed(LINK(this, SwFieldDokPage, SubTypeHdl)); + } + + bool bEnable = nCount != 0; + + if (bEnable && m_xSelectionLB->get_selected_index() == -1) + m_xSelectionLB->select(0); + + m_xSelection->set_sensitive( bEnable ); + + // fill Format-Listbox + sal_Int32 nSize = FillFormatLB(nTypeId); + + bool bValue = false, bLevel = false, bNumFormat = false, bOffset = false; + bool bFormat = nSize != 0; + bool bOneArea = false; + bool bFixed = false; + SvNumFormatType nFormatType = SvNumFormatType::ALL; + + switch (nTypeId) + { + case SwFieldTypesEnum::Date: + bFormat = bNumFormat = bOneArea = bOffset = true; + + nFormatType = SvNumFormatType::DATE; + + m_xDateFT->show(); + + m_xDateOffsetED->set_range(INT_MIN, INT_MAX); // no limit + + if (IsFieldEdit()) + m_xDateOffsetED->set_value( static_cast<SwDateTimeField*>(GetCurField())->GetOffset() / 24 / 60); + break; + + case SwFieldTypesEnum::Time: + bFormat = bNumFormat = bOneArea = bOffset = true; + + nFormatType = SvNumFormatType::TIME; + + m_xTimeFT->show(); + + m_xDateOffsetED->set_range(-1440, 1440); // one day + + if (IsFieldEdit()) + m_xDateOffsetED->set_value( static_cast<SwDateTimeField*>(GetCurField())->GetOffset() ); + break; + + case SwFieldTypesEnum::PreviousPage: + case SwFieldTypesEnum::NextPage: + if (IsFieldEdit()) + { + const sal_uInt16 nTmp = m_xFormatLB->get_selected_id().toUInt32(); + + if(SVX_NUM_CHAR_SPECIAL != nTmp) + { + sal_Int32 nOff = GetCurField()->GetPar2().toInt32(); + if( SwFieldTypesEnum::NextPage == nTypeId && 1 != nOff ) + m_xValueED->set_text( + OUString::number(nOff - 1) ); + else if( SwFieldTypesEnum::PreviousPage == nTypeId && -1 != nOff ) + m_xValueED->set_text( + OUString::number(nOff + 1) ); + else + m_xValueED->set_text(OUString()); + } + else + m_xValueED->set_text(static_cast<SwPageNumberField*>(GetCurField())->GetUserString()); + } + bValue = true; + break; + + case SwFieldTypesEnum::Chapter: + m_xValueFT->set_label(SwResId(STR_LEVEL)); + if (IsFieldEdit()) + m_xLevelED->set_active(static_cast<SwChapterField*>(GetCurField())->GetLevel(GetWrtShell()->GetLayout())); + bLevel = true; + break; + + case SwFieldTypesEnum::PageNumber: + m_xValueFT->set_label( SwResId( STR_OFFSET )); + if (IsFieldEdit()) + m_xValueED->set_text(GetCurField()->GetPar2()); + bValue = true; + break; + + case SwFieldTypesEnum::ExtendedUser: + case SwFieldTypesEnum::Author: + case SwFieldTypesEnum::Filename: + bFixed = true; + break; + + default: + break; + } + + if (bNumFormat) + { + if (IsFieldEdit()) + { + m_xNumFormatLB->SetDefFormat(GetCurField()->GetFormat()); + + if (m_xNumFormatLB->GetFormatType() == (SvNumFormatType::DATE|SvNumFormatType::TIME)) + { + // always set Format-Type because otherwise when date/time formats are combined, + // both formats would be displayed at the same time + m_xNumFormatLB->SetFormatType(SvNumFormatType::ALL); + m_xNumFormatLB->SetFormatType(nFormatType); + // set correct format once again + m_xNumFormatLB->SetDefFormat(GetCurField()->GetFormat()); + } + } + else + m_xNumFormatLB->SetFormatType(nFormatType); + + m_xNumFormatLB->SetOneArea(bOneArea); + } + + m_xFormatLB->set_visible(!bNumFormat); + m_xNumFormatLB->set_visible(bNumFormat); + + m_xValueFT->set_visible(bValue); + m_xValueED->set_visible(bValue); + m_xLevelFT->set_visible(bLevel); + m_xLevelED->set_visible(bLevel); + m_xDateOffsetED->set_visible(bOffset); + m_xFixedCB->set_visible(!bValue && !bLevel && !bOffset); + + m_xFormat->set_sensitive(bFormat); + m_xFixedCB->set_sensitive(bFixed); + + if (IsFieldEdit()) + m_xFixedCB->set_active((GetCurField()->GetFormat() & AF_FIXED) != 0 && bFixed); + + if (m_xNumFormatLB->get_selected_index() == -1) + m_xNumFormatLB->select(0); + m_xValueFT->set_sensitive(bValue || bLevel || bOffset); + m_xValueED->set_sensitive(bValue); +} + +void SwFieldDokPage::AddSubType(SwFieldTypesEnum nTypeId) +{ + m_xSelectionLB->append(OUString::number(static_cast<sal_uInt16>(nTypeId)), SwFieldType::GetTypeStr(nTypeId)); +} + +IMPL_LINK_NOARG(SwFieldDokPage, SubTypeHdl, weld::TreeView&, void) +{ + sal_Int32 nPos = m_xSelectionLB->get_selected_index(); + if(nPos == -1) + nPos = 0; + + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xSelectionLB->get_id(nPos).toUInt32()); + FillFormatLB(nTypeId); + + TranslateId pTextRes; + switch (nTypeId) + { + case SwFieldTypesEnum::Chapter: + pTextRes = STR_LEVEL; + break; + + case SwFieldTypesEnum::PreviousPage: + case SwFieldTypesEnum::NextPage: + pTextRes = SVX_NUM_CHAR_SPECIAL == m_xFormatLB->get_selected_id().toUInt32() + ? STR_VALUE : STR_OFFSET; + break; + + case SwFieldTypesEnum::PageNumber: + pTextRes = STR_OFFSET; + break; + default: break; + } + + if (pTextRes) + m_xValueFT->set_label(SwResId(pTextRes)); +} + +sal_Int32 SwFieldDokPage::FillFormatLB(SwFieldTypesEnum nTypeId) +{ + // fill Format-Listbox + m_xFormatLB->clear(); + + if (nTypeId == SwFieldTypesEnum::Author) + return m_xFormatLB->n_children(); + + const sal_uInt16 nSize = GetFieldMgr().GetFormatCount(nTypeId, IsFieldDlgHtmlMode()); + + for( sal_uInt16 i = 0; i < nSize; ++i ) + { + const sal_uInt16 nFormatId = GetFieldMgr().GetFormatId( nTypeId, i ); + OUString sId(OUString::number(nFormatId)); + m_xFormatLB->append(sId, GetFieldMgr().GetFormatStr(nTypeId, i)); + } + + if (IsFieldEdit()) + { + m_xFormatLB->select_id(OUString::number(GetCurField()->GetFormat() & ~AF_FIXED)); + } + else + { + // Select default selected value for "Insert" dialog + switch (nTypeId) + { + case SwFieldTypesEnum::PageNumber: + case SwFieldTypesEnum::DocumentStatistics: + m_xFormatLB->select_text(SwResId(FMT_NUM_PAGEDESC)); + break; + default: + m_xFormatLB->select(0); + } + } + + FormatHdl(*m_xFormatLB); + + return nSize; +} + +IMPL_LINK_NOARG(SwFieldDokPage, FormatHdl, weld::TreeView&, void) +{ + SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + if (nTypeId == SwFieldTypesEnum::Unknown) + { + sal_Int32 nPos = m_xSelectionLB->get_selected_index(); + if(nPos == -1) + nPos = 0; + + nTypeId = static_cast<SwFieldTypesEnum>(m_xSelectionLB->get_id(nPos).toUInt32()); + } + + if (nTypeId != SwFieldTypesEnum::NextPage && nTypeId != SwFieldTypesEnum::PreviousPage) + return; + + // Prev/Next - PageNumFields special treatment: + sal_uInt16 nTmp = m_xFormatLB->get_selected_id().toUInt32(); + const OUString sOldText( m_xValueFT->get_label() ); + const OUString sNewText( SwResId( SVX_NUM_CHAR_SPECIAL == nTmp ? STR_VALUE + : STR_OFFSET )); + + if (sOldText != sNewText) + m_xValueFT->set_label(sNewText); + + if (sOldText != m_xValueFT->get_label()) + m_xValueED->set_text(OUString()); +} + +bool SwFieldDokPage::FillItemSet(SfxItemSet* ) +{ + SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + if (nTypeId == SwFieldTypesEnum::Unknown) + { + sal_Int32 nPos = m_xSelectionLB->get_selected_index(); + if(nPos == -1) + nPos = 0; + nTypeId = static_cast<SwFieldTypesEnum>(m_xSelectionLB->get_id(nPos).toUInt32()); + } + + OUString aVal(m_xValueED->get_text()); + sal_uInt32 nFormat = 0; + sal_uInt16 nSubType = 0; + + if (m_xFormatLB->get_sensitive()) + { + sal_Int32 nPos = m_xFormatLB->get_selected_index(); + if(nPos != -1) + nFormat = m_xFormatLB->get_id(nPos).toUInt32(); + } + + if (m_xSelectionLB->get_sensitive()) + { + sal_Int32 nPos = m_xSelectionLB->get_selected_index(); + if(nPos != -1) + nSubType = m_xSelectionLB->get_id(nPos).toUInt32(); + } + + switch (nTypeId) + { + case SwFieldTypesEnum::Author: + nFormat = nSubType; + nSubType = 0; + [[fallthrough]]; + case SwFieldTypesEnum::ExtendedUser: + nFormat |= m_xFixedCB->get_active() ? AF_FIXED : 0; + break; + + case SwFieldTypesEnum::Filename: + nFormat |= m_xFixedCB->get_active() ? FF_FIXED : 0; + break; + + case SwFieldTypesEnum::Date: + case SwFieldTypesEnum::Time: + { + nFormat = m_xNumFormatLB->GetFormat(); + tools::Long nVal = static_cast< tools::Long >(m_xDateOffsetED->get_value()); + if (nTypeId == SwFieldTypesEnum::Date) + aVal = OUString::number(nVal * 60 * 24); + else + aVal = OUString::number(nVal); + break; + } + + case SwFieldTypesEnum::NextPage: + case SwFieldTypesEnum::PreviousPage: + case SwFieldTypesEnum::PageNumber: + case SwFieldTypesEnum::GetRefPage: + { + if( SVX_NUM_CHAR_SPECIAL != nFormat && + (SwFieldTypesEnum::PreviousPage == nTypeId || SwFieldTypesEnum::NextPage == nTypeId)) + { + sal_Int32 nVal = m_xValueED->get_text().toInt32(); + aVal = OUString::number(nVal); + } + break; + } + + case SwFieldTypesEnum::Chapter: + aVal = OUString::number(m_xLevelED->get_active()); + break; + + default: + break; + } + + if (!IsFieldEdit() || + m_nOldSel != m_xSelectionLB->get_selected_index() || + m_nOldFormat != nFormat || + m_xFixedCB->get_state_changed_from_saved() || + m_xValueED->get_value_changed_from_saved() || + m_xLevelED->get_value_changed_from_saved() || + m_xDateOffsetED->get_value_changed_from_saved()) + { + InsertField(nTypeId, nSubType, OUString(), aVal, nFormat, ' ', m_xNumFormatLB->IsAutomaticLanguage()); + } + + return false; +} + +std::unique_ptr<SfxTabPage> SwFieldDokPage::Create(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet *const pAttrSet) +{ + return std::make_unique<SwFieldDokPage>(pPage, pController, pAttrSet); +} + +sal_uInt16 SwFieldDokPage::GetGroup() +{ + return GRP_DOC; +} + +void SwFieldDokPage::FillUserData() +{ + const sal_Int32 nEntryPos = m_xTypeLB->get_selected_index(); + const sal_uInt16 nTypeSel = ( -1 == nEntryPos ) + ? USHRT_MAX : m_xTypeLB->get_id(nEntryPos).toUInt32(); + SetUserData(USER_DATA_VERSION ";" + OUString::number( nTypeSel )); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/flddok.hxx b/sw/source/ui/fldui/flddok.hxx new file mode 100644 index 0000000000..3192ecc0c6 --- /dev/null +++ b/sw/source/ui/fldui/flddok.hxx @@ -0,0 +1,72 @@ +/* -*- 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_FLDUI_FLDDOK_HXX +#define INCLUDED_SW_SOURCE_UI_FLDUI_FLDDOK_HXX + +#include <sfx2/tabdlg.hxx> + +#include <numfmtlb.hxx> +#include "fldpage.hxx" + +class SwFieldDokPage : public SwFieldPage +{ + sal_Int32 m_nOldSel; + sal_uInt32 m_nOldFormat; + + std::unique_ptr<weld::TreeView> m_xTypeLB; + std::unique_ptr<weld::Widget> m_xSelection; + std::unique_ptr<weld::TreeView> m_xSelectionLB; + std::unique_ptr<weld::Label> m_xValueFT; + std::unique_ptr<weld::Entry> m_xValueED; + std::unique_ptr<weld::Label> m_xLevelFT; + std::unique_ptr<weld::ComboBox> m_xLevelED; + std::unique_ptr<weld::Label> m_xDateFT; + std::unique_ptr<weld::Label> m_xTimeFT; + std::unique_ptr<weld::SpinButton> m_xDateOffsetED; + std::unique_ptr<weld::Widget> m_xFormat; + std::unique_ptr<weld::TreeView> m_xFormatLB; + std::unique_ptr<SwNumFormatTreeView> m_xNumFormatLB; + std::unique_ptr<weld::CheckButton> m_xFixedCB; + + DECL_LINK(TypeHdl, weld::TreeView&, void); + DECL_LINK(FormatHdl, weld::TreeView&, void); + DECL_LINK(SubTypeHdl, weld::TreeView&, void); + + void AddSubType(SwFieldTypesEnum nTypeId); + sal_Int32 FillFormatLB(SwFieldTypesEnum nTypeId); + +protected: + virtual sal_uInt16 GetGroup() override; + +public: + SwFieldDokPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet * pSet); + + virtual ~SwFieldDokPage() override; + + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; + + virtual void FillUserData() override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/fldedt.cxx b/sw/source/ui/fldui/fldedt.cxx new file mode 100644 index 0000000000..306d864fab --- /dev/null +++ b/sw/source/ui/fldui/fldedt.cxx @@ -0,0 +1,336 @@ +/* -*- 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 <config_features.h> +#include <config_fuzzers.h> + +#include <sfx2/basedlgs.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/optgenrl.hxx> +#include <docufld.hxx> +#include <expfld.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include "flddb.hxx" +#include "flddinf.hxx" +#include "fldvar.hxx" +#include "flddok.hxx" +#include "fldfunc.hxx" +#include "fldref.hxx" +#include <fldedt.hxx> + +#include <cmdid.h> +#include <swabstdlg.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <memory> +#include <swuiexp.hxx> + +void SwFieldEditDlg::EnsureSelection(SwField *pCurField, SwFieldMgr &rMgr) +{ + if (m_pSh->CursorInsideInputField()) + { + // move cursor to start of Input Field + SwInputField* pInputField = dynamic_cast<SwInputField*>(pCurField); + if (pInputField && pInputField->GetFormatField()) + { + m_pSh->GotoField( *(pInputField->GetFormatField()) ); + } + else + { + SwSetExpField *const pSetField(dynamic_cast<SwSetExpField*>(pCurField)); + if (pSetField) + { + assert(pSetField->GetFormatField()); + m_pSh->GotoField( *(pSetField->GetFormatField()) ); + } + else + { + assert(!"what input field is this"); + } + } + } + + /* Only create selection if there is none already. + Normalize PaM instead of swapping. */ + if (!m_pSh->HasSelection()) + { + SwShellCursor* pCursor = m_pSh->getShellCursor(true); + SwPosition aOrigPos(*pCursor->GetPoint()); + + //After this attempt it is possible that rMgr.GetCurField() != pCurField if + //the field was in e.g. a zero height portion and so invisible in which + //case it will be skipped over + m_pSh->Right(SwCursorSkipMode::Chars, true, 1, false ); + //So (fdo#50640) if it didn't work then reposition back to the original + //location where the field was + SwField *pRealCurField = rMgr.GetCurField(); + bool bSelectionFailed = pCurField != pRealCurField; + if (bSelectionFailed) + { + pCursor->DeleteMark(); + *pCursor->GetPoint() = aOrigPos; + } + } + + m_pSh->NormalizePam(); + + assert(pCurField == rMgr.GetCurField()); +} + +SwFieldEditDlg::SwFieldEditDlg(SwView const & rVw) + : SfxSingleTabDialogController(rVw.GetViewFrame().GetFrameWeld(), nullptr, + "modules/swriter/ui/editfielddialog.ui", "EditFieldDialog") + , m_pSh(rVw.GetWrtShellPtr()) + , m_xPrevBT(m_xBuilder->weld_button("prev")) + , m_xNextBT(m_xBuilder->weld_button("next")) + , m_xAddressBT(m_xBuilder->weld_button("edit")) +{ + SwFieldMgr aMgr(m_pSh); + + SwField *pCurField = aMgr.GetCurField(); + if (!pCurField) + return; + + SwViewShell::SetCareDialog(m_xDialog); + + EnsureSelection(pCurField, aMgr); + + sal_uInt16 nGroup = SwFieldMgr::GetGroup(pCurField->GetTypeId(), pCurField->GetSubType()); + + CreatePage(nGroup); + + GetOKButton().connect_clicked(LINK(this, SwFieldEditDlg, OKHdl)); + + m_xPrevBT->connect_clicked(LINK(this, SwFieldEditDlg, NextPrevHdl)); + m_xNextBT->connect_clicked(LINK(this, SwFieldEditDlg, NextPrevHdl)); + + m_xAddressBT->connect_clicked(LINK(this, SwFieldEditDlg, AddressHdl)); + + Init(); +} + +// initialise controls +void SwFieldEditDlg::Init() +{ + SwFieldPage* pTabPage = static_cast<SwFieldPage*>(GetTabPage()); + if (pTabPage) + { + SwFieldMgr& rMgr = pTabPage->GetFieldMgr(); + + SwField *pCurField = rMgr.GetCurField(); + + if(!pCurField) + return; + + // Traveling only when more than one field + m_pSh->StartAction(); + m_pSh->ClearMark(); + m_pSh->CreateCursor(); + + bool bMove = rMgr.GoNext(); + if( bMove ) + rMgr.GoPrev(); + m_xNextBT->set_sensitive(bMove); + + bMove = rMgr.GoPrev(); + if( bMove ) + rMgr.GoNext(); + m_xPrevBT->set_sensitive( bMove ); + + if (pCurField->GetTypeId() == SwFieldTypesEnum::ExtendedUser) + m_xAddressBT->set_sensitive(true); + else + m_xAddressBT->set_sensitive(false); + + m_pSh->DestroyCursor(); + m_pSh->EndAction(); + } + + GetOKButton().set_sensitive(!m_pSh->IsReadOnlyAvailable() || + !m_pSh->HasReadonlySel()); +} + +SfxTabPage* SwFieldEditDlg::CreatePage(sal_uInt16 nGroup) +{ + // create TabPage + std::unique_ptr<SfxTabPage> xTabPage; + + switch (nGroup) + { + case GRP_DOC: + xTabPage = SwFieldDokPage::Create(get_content_area(), this, nullptr); + break; + case GRP_FKT: + xTabPage = SwFieldFuncPage::Create(get_content_area(), this, nullptr); + break; + case GRP_REF: + xTabPage = SwFieldRefPage::Create(get_content_area(), this, nullptr); + break; + case GRP_REG: + if (SfxObjectShell* pDocSh = SfxObjectShell::Current()) + { + auto pSet = new SfxItemSetFixed<FN_FIELD_DIALOG_DOC_PROPS, FN_FIELD_DIALOG_DOC_PROPS>( pDocSh->GetPool() ); + using namespace ::com::sun::star; + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + pDocSh->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps + = xDPS->getDocumentProperties(); + uno::Reference< beans::XPropertySet > xUDProps( + xDocProps->getUserDefinedProperties(), + uno::UNO_QUERY_THROW); + pSet->Put( SfxUnoAnyItem( FN_FIELD_DIALOG_DOC_PROPS, uno::Any(xUDProps) ) ); + xTabPage = SwFieldDokInfPage::Create(get_content_area(), this, pSet); + } + break; +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + case GRP_DB: + xTabPage = SwFieldDBPage::Create(get_content_area(), this, nullptr); + static_cast<SwFieldDBPage*>(xTabPage.get())->SetWrtShell(*m_pSh); + break; +#endif + case GRP_VAR: + xTabPage = SwFieldVarPage::Create(get_content_area(), this, nullptr); + break; + + } + + assert(xTabPage); + + static_cast<SwFieldPage*>(xTabPage.get())->SetWrtShell(m_pSh); + SetTabPage(std::move(xTabPage)); + + return GetTabPage(); +} + +SwFieldEditDlg::~SwFieldEditDlg() +{ + SwViewShell::SetCareDialog(nullptr); + m_pSh->EnterStdMode(); +} + +void SwFieldEditDlg::EnableInsert(bool bEnable) +{ + if( bEnable && m_pSh->IsReadOnlyAvailable() && m_pSh->HasReadonlySel() ) + bEnable = false; + GetOKButton().set_sensitive(bEnable); +} + +void SwFieldEditDlg::InsertHdl() +{ + GetOKButton().clicked(); +} + +// kick off changing of the field +IMPL_LINK_NOARG(SwFieldEditDlg, OKHdl, weld::Button&, void) +{ + if (GetOKButton().get_sensitive()) + { + SfxTabPage* pTabPage = GetTabPage(); + if (pTabPage) + pTabPage->FillItemSet(nullptr); + m_xDialog->response(RET_OK); + } +} + +short SwFieldEditDlg::run() +{ + // without TabPage no dialog + return GetTabPage() ? SfxSingleTabDialogController::run() : static_cast<short>(RET_CANCEL); +} + +// Traveling between fields of the same type +IMPL_LINK(SwFieldEditDlg, NextPrevHdl, weld::Button&, rButton, void) +{ + bool bNext = &rButton == m_xNextBT.get(); + + m_pSh->EnterStdMode(); + + SwFieldType *pOldTyp = nullptr; + SwFieldPage* pTabPage = static_cast<SwFieldPage*>(GetTabPage()); + + //#112462# FillItemSet may delete the current field + //that's why it has to be called before accessing the current field + if (GetOKButton().get_sensitive()) + pTabPage->FillItemSet(nullptr); + + SwFieldMgr& rMgr = pTabPage->GetFieldMgr(); + SwField *pCurField = rMgr.GetCurField(); + if (pCurField->GetTypeId() == SwFieldTypesEnum::Database) + pOldTyp = pCurField->GetTyp(); + + rMgr.GoNextPrev( bNext, pOldTyp ); + pCurField = rMgr.GetCurField(); + + sal_uInt16 nGroup = SwFieldMgr::GetGroup(pCurField->GetTypeId(), pCurField->GetSubType()); + + if (nGroup != pTabPage->GetGroup()) + pTabPage = static_cast<SwFieldPage*>(CreatePage(nGroup)); + + pTabPage->EditNewField(); + + Init(); + EnsureSelection(pCurField, rMgr); +} + +IMPL_LINK_NOARG(SwFieldEditDlg, AddressHdl, weld::Button&, void) +{ + SwFieldPage* pTabPage = static_cast<SwFieldPage*>(GetTabPage()); + SwFieldMgr& rMgr = pTabPage->GetFieldMgr(); + SwField *pCurField = rMgr.GetCurField(); + + SfxItemSetFixed<SID_FIELD_GRABFOCUS, SID_FIELD_GRABFOCUS> aSet( m_pSh->GetAttrPool() ); + + EditPosition nEditPos = EditPosition::UNKNOWN; + + switch(pCurField->GetSubType()) + { + case EU_FIRSTNAME: nEditPos = EditPosition::FIRSTNAME; break; + case EU_NAME: nEditPos = EditPosition::LASTNAME; break; + case EU_SHORTCUT: nEditPos = EditPosition::SHORTNAME; break; + case EU_COMPANY: nEditPos = EditPosition::COMPANY; break; + case EU_STREET: nEditPos = EditPosition::STREET; break; + case EU_TITLE: nEditPos = EditPosition::TITLE; break; + case EU_POSITION: nEditPos = EditPosition::POSITION; break; + case EU_PHONE_PRIVATE:nEditPos = EditPosition::TELPRIV; break; + case EU_PHONE_COMPANY:nEditPos = EditPosition::TELCOMPANY; break; + case EU_FAX: nEditPos = EditPosition::FAX; break; + case EU_EMAIL: nEditPos = EditPosition::EMAIL; break; + case EU_COUNTRY: nEditPos = EditPosition::COUNTRY; break; + case EU_ZIP: nEditPos = EditPosition::PLZ; break; + case EU_CITY: nEditPos = EditPosition::CITY; break; + case EU_STATE: nEditPos = EditPosition::STATE; break; + + default: nEditPos = EditPosition::UNKNOWN; break; + + } + aSet.Put(SfxUInt16Item(SID_FIELD_GRABFOCUS, static_cast<sal_uInt16>(nEditPos))); + SwAbstractDialogFactory& rFact = swui::GetFactory(); + + ScopedVclPtr<SfxAbstractDialog> pDlg(rFact.CreateSwAddressAbstractDlg(m_xDialog.get(), aSet)); + if (RET_OK == pDlg->Execute()) + { + m_pSh->UpdateOneField(*pCurField); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/fldfunc.cxx b/sw/source/ui/fldui/fldfunc.cxx new file mode 100644 index 0000000000..6447c375e5 --- /dev/null +++ b/sw/source/ui/fldui/fldfunc.cxx @@ -0,0 +1,611 @@ +/* -*- 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 <swtypes.hxx> +#include <strings.hrc> +#include <fldbas.hxx> +#include <docufld.hxx> +#include <wrtsh.hxx> +#include <swmodule.hxx> +#include "fldfunc.hxx" +#include "flddinf.hxx" +#include <flddropdown.hxx> +#include <o3tl/string_view.hxx> + +#define USER_DATA_VERSION_1 "1" +#define USER_DATA_VERSION USER_DATA_VERSION_1 + +using namespace ::com::sun::star; + +SwFieldFuncPage::SwFieldFuncPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *const pCoreSet) + : SwFieldPage(pPage, pController, "modules/swriter/ui/fldfuncpage.ui", "FieldFuncPage", pCoreSet) + , m_nOldFormat(0) + , m_bDropDownLBChanged(false) + , m_xTypeLB(m_xBuilder->weld_tree_view("type")) + , m_xSelectionLB(m_xBuilder->weld_tree_view("select")) + , m_xFormat(m_xBuilder->weld_widget("formatframe")) + , m_xFormatLB(m_xBuilder->weld_tree_view("format")) + , m_xNameFT(m_xBuilder->weld_label("nameft")) + , m_xNameED(new ConditionEdit(m_xBuilder->weld_entry("condFunction"))) + , m_xValueGroup(m_xBuilder->weld_widget("valuegroup")) + , m_xValueFT(m_xBuilder->weld_label("valueft")) + , m_xValueED(m_xBuilder->weld_entry("value")) + , m_xCond1FT(m_xBuilder->weld_label("cond1ft")) + , m_xCond1ED(new ConditionEdit(m_xBuilder->weld_entry("cond1"))) + , m_xCond2FT(m_xBuilder->weld_label("cond2ft")) + , m_xCond2ED(new ConditionEdit(m_xBuilder->weld_entry("cond2"))) + , m_xMacroBT(m_xBuilder->weld_button("macro")) + , m_xListGroup(m_xBuilder->weld_widget("listgroup")) + , m_xListItemED(m_xBuilder->weld_entry("item")) + , m_xListAddPB(m_xBuilder->weld_button("add")) + , m_xListItemsLB(m_xBuilder->weld_tree_view("listitems")) + , m_xListRemovePB(m_xBuilder->weld_button("remove")) + , m_xListUpPB(m_xBuilder->weld_button("up")) + , m_xListDownPB(m_xBuilder->weld_button("down")) + , m_xListNameED(m_xBuilder->weld_entry("listname")) +{ + FillFieldSelect(*m_xSelectionLB); + FillFieldSelect(*m_xFormatLB); + m_xListItemsLB->set_size_request(m_xListItemED->get_preferred_size().Width(), + m_xListItemsLB->get_height_rows(5)); + + auto nWidth = m_xTypeLB->get_approximate_digit_width() * FIELD_COLUMN_WIDTH; + auto nHeight = m_xTypeLB->get_height_rows(10); + m_xTypeLB->set_size_request(nWidth, nHeight); + m_xFormatLB->set_size_request(nWidth, nHeight); + + m_xNameED->connect_changed(LINK(this, SwFieldFuncPage, ModifyHdl)); + + m_sOldValueFT = m_xValueFT->get_label(); + m_sOldNameFT = m_xNameFT->get_label(); + + m_xCond1ED->ShowBrackets(false); + m_xCond2ED->ShowBrackets(false); + + // uitests + m_xTypeLB->set_buildable_name(m_xTypeLB->get_buildable_name() + "-func"); + m_xValueED->set_buildable_name(m_xValueED->get_buildable_name() + "-func"); + m_xSelectionLB->set_buildable_name(m_xSelectionLB->get_buildable_name() + "-func"); + m_xFormatLB->set_buildable_name(m_xFormatLB->get_buildable_name() + "-func"); +} + +SwFieldFuncPage::~SwFieldFuncPage() +{ +} + +void SwFieldFuncPage::Reset(const SfxItemSet* ) +{ + SavePos(*m_xTypeLB); + Init(); // general initialisation + + m_xTypeLB->freeze(); + m_xTypeLB->clear(); + + if (!IsFieldEdit()) + { + // initialise TypeListBox + const SwFieldGroupRgn& rRg = SwFieldMgr::GetGroupRange(IsFieldDlgHtmlMode(), GetGroup()); + + // fill Typ-Listbox + for(sal_uInt16 i = rRg.nStart; i < rRg.nEnd; ++i) + { + const SwFieldTypesEnum nTypeId = SwFieldMgr::GetTypeId(i); + m_xTypeLB->append(OUString::number(static_cast<sal_uInt16>(nTypeId)), SwFieldMgr::GetTypeStr(i)); + } + } + else + { + const SwFieldTypesEnum nTypeId = GetCurField()->GetTypeId(); + m_xTypeLB->append(OUString::number(static_cast<sal_uInt16>(nTypeId)), SwFieldMgr::GetTypeStr(SwFieldMgr::GetPos(nTypeId))); + + if (nTypeId == SwFieldTypesEnum::Macro) + { + GetFieldMgr().SetMacroPath(GetCurField()->GetPar1()); + } + } + + m_xTypeLB->connect_row_activated(LINK(this, SwFieldFuncPage, TreeViewInsertHdl)); + m_xTypeLB->connect_changed(LINK(this, SwFieldFuncPage, TypeHdl)); + m_xSelectionLB->connect_changed(LINK(this, SwFieldFuncPage, SelectHdl)); + m_xSelectionLB->connect_row_activated(LINK(this, SwFieldFuncPage, InsertMacroHdl)); + m_xFormatLB->connect_row_activated(LINK(this, SwFieldFuncPage, TreeViewInsertHdl)); + m_xMacroBT->connect_clicked(LINK(this, SwFieldFuncPage, MacroHdl)); + Link<weld::Button&,void> aListModifyLk( LINK(this, SwFieldFuncPage, ListModifyButtonHdl)); + m_xListAddPB->connect_clicked(aListModifyLk); + m_xListRemovePB->connect_clicked(aListModifyLk); + m_xListUpPB->connect_clicked(aListModifyLk); + m_xListDownPB->connect_clicked(aListModifyLk); + m_xListItemED->connect_activate(LINK(this, SwFieldFuncPage, ListModifyReturnActionHdl)); + Link<weld::Entry&,void> aListEnableLk = LINK(this, SwFieldFuncPage, ListEnableHdl); + m_xListItemED->connect_changed(aListEnableLk); + m_xListItemsLB->connect_changed(LINK(this, SwFieldFuncPage, ListEnableListBoxHdl)); + + int nSelect = -1; + if( !IsRefresh() ) + { + const OUString sUserData = GetUserData(); + sal_Int32 nIdx{ 0 }; + if(o3tl::equalsIgnoreAsciiCase(o3tl::getToken(sUserData, 0, ';', nIdx), u"" USER_DATA_VERSION_1)) + { + const sal_uInt16 nVal = static_cast< sal_uInt16 >(o3tl::toInt32(o3tl::getToken(sUserData, 0, ';', nIdx))); + if(nVal != USHRT_MAX) + { + for (sal_Int32 i = 0, nEntryCount = m_xTypeLB->n_children(); i < nEntryCount; ++i) + { + if (nVal == m_xTypeLB->get_id(i).toUInt32()) + { + nSelect = i; + break; + } + } + } + } + } + + m_xTypeLB->thaw(); + if (nSelect != -1) + m_xTypeLB->select(nSelect); + else + { + // select old Pos + RestorePos(*m_xTypeLB); + } + TypeHdl(*m_xTypeLB); + + if (IsFieldEdit()) + { + m_xNameED->save_value(); + m_xValueED->save_value(); + m_xCond1ED->save_value(); + m_xCond2ED->save_value(); + m_nOldFormat = GetCurField()->GetFormat(); + } +} + +const TranslateId FMT_MARK_ARY[] = +{ + FMT_MARK_TEXT, + FMT_MARK_TABLE, + FMT_MARK_FRAME, + FMT_MARK_GRAFIC, + FMT_MARK_OLE +}; + +IMPL_LINK_NOARG(SwFieldFuncPage, TypeHdl, weld::TreeView&, void) +{ + // save old ListBoxPos + const sal_Int32 nOld = GetTypeSel(); + + // current ListBoxPos + SetTypeSel(m_xTypeLB->get_selected_index()); + + if(GetTypeSel() == -1) + { + SetTypeSel(0); + m_xTypeLB->select(0); + } + + if (nOld == GetTypeSel()) + return; + + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + // fill Selection-Listbox + UpdateSubType(); + + // fill Format-Listbox + m_xFormatLB->clear(); + + const sal_uInt16 nSize = GetFieldMgr().GetFormatCount(nTypeId, IsFieldDlgHtmlMode()); + + for (sal_uInt16 i = 0; i < nSize; i++) + { + m_xFormatLB->append(OUString::number(GetFieldMgr().GetFormatId(nTypeId, i)), + GetFieldMgr().GetFormatStr(nTypeId, i)); + } + + if (nSize) + { + if (IsFieldEdit() && nTypeId == SwFieldTypesEnum::JumpEdit) + m_xFormatLB->select_text(SwResId(FMT_MARK_ARY[GetCurField()->GetFormat()])); + + if (m_xFormatLB->get_selected_index() == -1) + m_xFormatLB->select(0); + } + + bool bValue = false, bName = false, bMacro = false, bInsert = true; + bool bFormat = nSize != 0; + + // two controls for conditional text + bool bDropDown = SwFieldTypesEnum::Dropdown == nTypeId; + bool bCondTextField = SwFieldTypesEnum::ConditionalText == nTypeId; + + m_xCond1FT->set_visible(!bDropDown && bCondTextField); + m_xCond1ED->set_visible(!bDropDown && bCondTextField); + m_xCond2FT->set_visible(!bDropDown && bCondTextField); + m_xCond2ED->set_visible(!bDropDown && bCondTextField); + m_xValueGroup->set_visible(!bDropDown && !bCondTextField); + m_xMacroBT->set_visible(!bDropDown); + m_xNameED->set_visible(!bDropDown); + m_xNameFT->set_visible(!bDropDown); + + m_xListGroup->set_visible(bDropDown); + + m_xNameED->SetDropEnable(false); + + if (IsFieldEdit()) + { + if(bDropDown) + { + const SwDropDownField* pDrop = static_cast<const SwDropDownField*>(GetCurField()); + const uno::Sequence<OUString> aItems = pDrop->GetItemSequence(); + m_xListItemsLB->clear(); + for (const OUString& rItem : aItems) + m_xListItemsLB->append_text(rItem); + m_xListItemsLB->select_text(pDrop->GetSelectedItem()); + m_xListNameED->set_text(pDrop->GetPar2()); + m_xListNameED->save_value(); + m_bDropDownLBChanged = false; + } + else + { + m_xNameED->set_text(GetCurField()->GetPar1()); + m_xValueED->set_text(GetCurField()->GetPar2()); + } + } + else + { + m_xNameED->set_text(OUString()); + m_xValueED->set_text(OUString()); + } + if(bDropDown) + ListEnableHdl(*m_xListItemED); + + if (m_xNameFT->get_label() != m_sOldNameFT) + m_xNameFT->set_label(m_sOldNameFT); + if (m_xValueFT->get_label() != m_sOldValueFT) + m_xValueFT->set_label(m_sOldValueFT); + + switch (nTypeId) + { + case SwFieldTypesEnum::Macro: + bMacro = true; + if (!GetFieldMgr().GetMacroPath().isEmpty()) + bValue = true; + else + bInsert = false; + + m_xNameFT->set_label(SwResId(STR_MACNAME)); + m_xValueFT->set_label(SwResId(STR_PROMPT)); + m_xNameED->set_text(GetFieldMgr().GetMacroName()); + m_xNameED->set_accessible_name(m_xNameFT->get_label()); + m_xValueED->set_accessible_name(m_xValueFT->get_label()); + break; + + case SwFieldTypesEnum::HiddenParagraph: + m_xNameFT->set_label(SwResId(STR_COND)); + m_xNameED->SetDropEnable(true); + bName = true; + m_xNameED->set_accessible_name(m_xNameFT->get_label()); + m_xValueED->set_accessible_name(m_xValueFT->get_label()); + break; + + case SwFieldTypesEnum::HiddenText: + { + m_xNameFT->set_label(SwResId(STR_COND)); + m_xNameED->SetDropEnable(true); + m_xValueFT->set_label(SwResId(STR_INSTEXT)); + SwWrtShell* pSh = GetActiveWrtShell(); + if (!IsFieldEdit() && pSh) + m_xValueED->set_text(pSh->GetSelText()); + bName = bValue = true; + m_xNameED->set_accessible_name(m_xNameFT->get_label()); + m_xValueED->set_accessible_name(m_xValueFT->get_label()); + } + break; + + case SwFieldTypesEnum::ConditionalText: + m_xNameFT->set_label(SwResId(STR_COND)); + m_xNameED->SetDropEnable(true); + if (IsFieldEdit()) + { + sal_Int32 nIdx{ 0 }; + m_xCond1ED->set_text(GetCurField()->GetPar2().getToken(0, '|', nIdx)); + m_xCond2ED->set_text(GetCurField()->GetPar2().getToken(0, '|', nIdx)); + } + + bName = bValue = true; + m_xNameED->set_accessible_name(m_xNameFT->get_label()); + m_xValueED->set_accessible_name(m_xValueFT->get_label()); + break; + + case SwFieldTypesEnum::JumpEdit: + m_xNameFT->set_label(SwResId(STR_JUMPEDITFLD)); + m_xValueFT->set_label(SwResId(STR_PROMPT)); + bName = bValue = true; + m_xNameED->set_accessible_name(m_xNameFT->get_label()); + m_xValueED->set_accessible_name(m_xValueFT->get_label()); + break; + + case SwFieldTypesEnum::Input: + m_xValueFT->set_label(SwResId(STR_PROMPT)); + bValue = true; + m_xNameED->set_accessible_name(m_xNameFT->get_label()); + m_xValueED->set_accessible_name(m_xValueFT->get_label()); + break; + + case SwFieldTypesEnum::CombinedChars: + { + m_xNameFT->set_label(SwResId(STR_COMBCHRS_FT)); + m_xNameED->SetDropEnable(true); + bName = true; + + const sal_Int32 nLen = m_xNameED->get_text().getLength(); + if( !nLen || nLen > MAX_COMBINED_CHARACTERS ) + bInsert = false; + m_xNameED->set_accessible_name(m_xNameFT->get_label()); + m_xValueED->set_accessible_name(m_xValueFT->get_label()); + } + break; + case SwFieldTypesEnum::Dropdown : + break; + default: + break; + } + + m_xSelectionLB->hide(); + + m_xFormat->set_sensitive(bFormat); + m_xNameFT->set_sensitive(bName); + m_xNameED->set_sensitive(bName); + m_xValueGroup->set_sensitive(bValue); + m_xMacroBT->set_sensitive(bMacro); + + EnableInsert( bInsert ); +} + +IMPL_LINK_NOARG(SwFieldFuncPage, SelectHdl, weld::TreeView&, void) +{ + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + if( SwFieldTypesEnum::Macro == nTypeId ) + m_xNameED->set_text( m_xSelectionLB->get_selected_text() ); +} + +IMPL_LINK_NOARG(SwFieldFuncPage, InsertMacroHdl, weld::TreeView&, bool) +{ + SelectHdl(*m_xSelectionLB); + InsertHdl(nullptr); + return true; +} + +IMPL_LINK(SwFieldFuncPage, ListModifyButtonHdl, weld::Button&, rControl, void) +{ + ListModifyHdl(&rControl); +} + +IMPL_LINK(SwFieldFuncPage, ListModifyReturnActionHdl, weld::Entry&, rControl, bool) +{ + ListModifyHdl(&rControl); + return true; +} + +void SwFieldFuncPage::ListModifyHdl(const weld::Widget* pControl) +{ + if (pControl == m_xListAddPB.get() || + (pControl == m_xListItemED.get() && m_xListAddPB->get_sensitive())) + { + const OUString sEntry(m_xListItemED->get_text()); + m_xListItemsLB->append_text(sEntry); + m_xListItemsLB->select_text(sEntry); + } + else if (m_xListItemsLB->get_selected_index() != -1) + { + sal_Int32 nSelPos = m_xListItemsLB->get_selected_index(); + if (pControl == m_xListRemovePB.get()) + { + m_xListItemsLB->remove(nSelPos); + m_xListItemsLB->select(nSelPos ? nSelPos - 1 : 0); + } + else if (pControl == m_xListUpPB.get()) + { + if(nSelPos) + { + const OUString sEntry = m_xListItemsLB->get_selected_text(); + m_xListItemsLB->remove(nSelPos); + nSelPos--; + m_xListItemsLB->insert_text(nSelPos, sEntry); + m_xListItemsLB->select(nSelPos); + } + } + else if (pControl == m_xListDownPB.get()) + { + if( nSelPos < m_xListItemsLB->n_children() - 1) + { + const OUString sEntry = m_xListItemsLB->get_selected_text(); + m_xListItemsLB->remove(nSelPos); + nSelPos++; + m_xListItemsLB->insert_text(nSelPos, sEntry); + m_xListItemsLB->select(nSelPos); + } + } + } + m_bDropDownLBChanged = true; + ListEnableHdl(*m_xListItemED); +} + +IMPL_LINK_NOARG(SwFieldFuncPage, ListEnableListBoxHdl, weld::TreeView&, void) +{ + ListEnableHdl(*m_xListItemED); +} + +IMPL_LINK_NOARG(SwFieldFuncPage, ListEnableHdl, weld::Entry&, void) +{ + //enable "Add" button when text is in the Edit that's not already member of the box + m_xListAddPB->set_sensitive(!m_xListItemED->get_text().isEmpty() && + -1 == m_xListItemsLB->find_text(m_xListItemED->get_text())); + bool bEnableButtons = m_xListItemsLB->get_selected_index() != -1; + m_xListRemovePB->set_sensitive(bEnableButtons); + m_xListUpPB->set_sensitive(bEnableButtons && (m_xListItemsLB->get_selected_index() > 0)); + m_xListDownPB->set_sensitive(bEnableButtons && + (m_xListItemsLB->get_selected_index() < (m_xListItemsLB->n_children() - 1))); +} + +// renew types in SelectionBox +void SwFieldFuncPage::UpdateSubType() +{ + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + // fill Selection-Listbox + m_xSelectionLB->freeze(); + m_xSelectionLB->clear(); + + std::vector<OUString> aLst; + GetFieldMgr().GetSubTypes(nTypeId, aLst); + const size_t nCount = aLst.size(); + + for (size_t i = 0; i < nCount; ++i) + m_xSelectionLB->append(OUString::number(i), aLst[i]); + m_xSelectionLB->thaw(); + + bool bEnable = nCount != 0; + + m_xSelectionLB->set_sensitive( bEnable ); + + if (bEnable) + m_xSelectionLB->select(0); + + if (nTypeId == SwFieldTypesEnum::Macro) + { + const bool bHasMacro = !GetFieldMgr().GetMacroPath().isEmpty(); + + if (bHasMacro) + { + m_xNameED->set_text(GetFieldMgr().GetMacroName()); + m_xValueGroup->set_sensitive(true); + } + EnableInsert(bHasMacro); + } +} + +// call MacroBrowser, fill Listbox with Macros +IMPL_LINK_NOARG( SwFieldFuncPage, MacroHdl, weld::Button&, void) +{ + if (GetFieldMgr().ChooseMacro(GetFrameWeld())) + UpdateSubType(); +} + +bool SwFieldFuncPage::FillItemSet(SfxItemSet* ) +{ + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + sal_uInt16 nSubType = 0; + + const sal_Int32 nEntryPos = m_xFormatLB->get_selected_index(); + const sal_uInt32 nFormat = (nEntryPos == -1) + ? 0 : m_xFormatLB->get_id(nEntryPos).toUInt32(); + + OUString aVal(m_xValueED->get_text()); + OUString aName(m_xNameED->get_text()); + + switch(nTypeId) + { + case SwFieldTypesEnum::Input: + nSubType = INP_TXT; + // to prevent removal of CR/LF restore old content + if (!m_xNameED->get_value_changed_from_saved() && IsFieldEdit()) + aName = GetCurField()->GetPar1(); + + break; + + case SwFieldTypesEnum::Macro: + // use the full script URL, not the name in the Edit control + aName = GetFieldMgr().GetMacroPath(); + break; + + case SwFieldTypesEnum::ConditionalText: + aVal = m_xCond1ED->get_text() + "|" + m_xCond2ED->get_text(); + break; + case SwFieldTypesEnum::Dropdown : + { + aName = m_xListNameED->get_text(); + for (sal_Int32 i = 0, nEntryCount = m_xListItemsLB->n_children(); i < nEntryCount; ++i) + { + if(i) + aVal += OUStringChar(DB_DELIM); + aVal += m_xListItemsLB->get_text(i); + } + } + break; + default: + break; + } + + if (!IsFieldEdit() || + m_xNameED->get_value_changed_from_saved() || + m_xValueED->get_value_changed_from_saved() || + m_xCond1ED->get_value_changed_from_saved() || + m_xCond2ED->get_value_changed_from_saved() || + m_xListNameED->get_value_changed_from_saved() || + m_bDropDownLBChanged || + m_nOldFormat != nFormat) + { + InsertField( nTypeId, nSubType, aName, aVal, nFormat ); + } + + ModifyHdl(m_xNameED->get_widget()); // enable/disable Insert if applicable + + return false; +} + +std::unique_ptr<SfxTabPage> SwFieldFuncPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet *const pAttrSet) +{ + return std::make_unique<SwFieldFuncPage>(pPage, pController, pAttrSet); +} + +sal_uInt16 SwFieldFuncPage::GetGroup() +{ + return GRP_FKT; +} + +void SwFieldFuncPage::FillUserData() +{ + const sal_Int32 nEntryPos = m_xTypeLB->get_selected_index(); + const sal_uInt16 nTypeSel = ( -1 == nEntryPos ) + ? USHRT_MAX + : m_xTypeLB->get_id(nEntryPos).toUInt32(); + SetUserData(USER_DATA_VERSION ";" + OUString::number( nTypeSel )); +} + +IMPL_LINK_NOARG(SwFieldFuncPage, ModifyHdl, weld::Entry&, void) +{ + const sal_Int32 nLen = m_xNameED->get_text().getLength(); + + bool bEnable = true; + SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + if( SwFieldTypesEnum::CombinedChars == nTypeId && + (!nLen || nLen > MAX_COMBINED_CHARACTERS )) + bEnable = false; + + EnableInsert( bEnable ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/fldfunc.hxx b/sw/source/ui/fldui/fldfunc.hxx new file mode 100644 index 0000000000..9fef98d256 --- /dev/null +++ b/sw/source/ui/fldui/fldfunc.hxx @@ -0,0 +1,92 @@ +/* -*- 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_FLDUI_FLDFUNC_HXX +#define INCLUDED_SW_SOURCE_UI_FLDUI_FLDFUNC_HXX + +#include <sfx2/tabdlg.hxx> + +#include <condedit.hxx> +#include "fldpage.hxx" + +class SwFieldFuncPage : public SwFieldPage +{ + OUString m_sOldValueFT; + OUString m_sOldNameFT; + + sal_uInt32 m_nOldFormat; + bool m_bDropDownLBChanged; + + std::unique_ptr<weld::TreeView> m_xTypeLB; + std::unique_ptr<weld::TreeView> m_xSelectionLB; + std::unique_ptr<weld::Widget> m_xFormat; + std::unique_ptr<weld::TreeView> m_xFormatLB; + std::unique_ptr<weld::Label> m_xNameFT; + std::unique_ptr<ConditionEdit> m_xNameED; + std::unique_ptr<weld::Widget> m_xValueGroup; + std::unique_ptr<weld::Label> m_xValueFT; + std::unique_ptr<weld::Entry> m_xValueED; + std::unique_ptr<weld::Label> m_xCond1FT; + std::unique_ptr<ConditionEdit> m_xCond1ED; + std::unique_ptr<weld::Label> m_xCond2FT; + std::unique_ptr<ConditionEdit> m_xCond2ED; + std::unique_ptr<weld::Button> m_xMacroBT; + + //controls of "Input list" + std::unique_ptr<weld::Widget> m_xListGroup; + std::unique_ptr<weld::Entry> m_xListItemED; + std::unique_ptr<weld::Button> m_xListAddPB; + std::unique_ptr<weld::TreeView> m_xListItemsLB; + std::unique_ptr<weld::Button> m_xListRemovePB; + std::unique_ptr<weld::Button> m_xListUpPB; + std::unique_ptr<weld::Button> m_xListDownPB; + std::unique_ptr<weld::Entry> m_xListNameED; + + DECL_LINK( TypeHdl, weld::TreeView&, void ); + DECL_LINK( SelectHdl, weld::TreeView&, void ); + DECL_LINK( InsertMacroHdl, weld::TreeView&, bool ); + DECL_LINK( ModifyHdl, weld::Entry&, void ); + DECL_LINK( ListModifyReturnActionHdl, weld::Entry&, bool ); + DECL_LINK( ListModifyButtonHdl, weld::Button&, void ); + DECL_LINK( ListEnableHdl, weld::Entry&, void ); + DECL_LINK( ListEnableListBoxHdl, weld::TreeView&, void ); + void ListModifyHdl(const weld::Widget*); + + // select Macro + DECL_LINK( MacroHdl, weld::Button&, void ); + + void UpdateSubType(); + +protected: + virtual sal_uInt16 GetGroup() override; + +public: + SwFieldFuncPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pSet); + virtual ~SwFieldFuncPage() override; + + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; + + virtual void FillUserData() override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/fldpage.cxx b/sw/source/ui/fldui/fldpage.cxx new file mode 100644 index 0000000000..7e7f5ade3b --- /dev/null +++ b/sw/source/ui/fldui/fldpage.cxx @@ -0,0 +1,350 @@ +/* -*- 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/stritem.hxx> +#include <sfx2/request.hxx> +#include <sfx2/htmlmode.hxx> +#include <sfx2/viewfrm.hxx> +#include <dbfld.hxx> +#include <flddat.hxx> +#include <fmtfld.hxx> +#include <viewopt.hxx> +#include <fldedt.hxx> +#include <docsh.hxx> +#include <swmodule.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <expfld.hxx> +#include <fldtdlg.hxx> +#include "fldpage.hxx" +#include <docufld.hxx> +#include <cmdid.h> +#include <sfx2/bindings.hxx> +#include <o3tl/string_view.hxx> + +using namespace ::com::sun::star; + +// note: pAttrSet may be null if the dialog is restored on startup +SwFieldPage::SwFieldPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, + const OUString& rID, const SfxItemSet *pAttrSet) + : SfxTabPage(pPage, pController, rUIXMLDescription, rID, pAttrSet) + , m_pCurField(nullptr) + , m_pWrtShell(nullptr) + , m_nTypeSel(-1) + , m_nSelectionSel(-1) + , m_bFieldEdit(false) + , m_bInsert(true) + , m_bFieldDlgHtmlMode(false) + , m_bRefresh(false) + , m_bFirstHTMLInit(true) +{ +} + +SwFieldPage::~SwFieldPage() +{ +} + +// initialise TabPage +void SwFieldPage::Init() +{ + SwDocShell* pDocSh = static_cast<SwDocShell*>(SfxObjectShell::Current()); + bool bNewMode = 0 != (::GetHtmlMode(pDocSh) & HTMLMODE_ON); + + m_bFieldEdit = nullptr == dynamic_cast<SwFieldDlg*>(GetDialogController()); + + // newly initialise FieldManager. important for + // Dok-Switch (fldtdlg:ReInitTabPage) + m_pCurField = m_aMgr.GetCurField(); + + if( bNewMode == m_bFieldDlgHtmlMode ) + return; + + m_bFieldDlgHtmlMode = bNewMode; + + // initialise Rangelistbox + if( !(m_bFieldDlgHtmlMode && m_bFirstHTMLInit) ) + return; + + m_bFirstHTMLInit = false; + SwWrtShell *pSh = m_pWrtShell; + if(! pSh) + pSh = ::GetActiveWrtShell(); + if(pSh) + { + SwDoc* pDoc = pSh->GetDoc(); + pSh->InsertFieldType( SwSetExpFieldType( pDoc, + "HTML_ON", 1)); + pSh->InsertFieldType( SwSetExpFieldType(pDoc, + "HTML_OFF", 1)); + } +} + +// newly initialise page +void SwFieldPage::Activate() +{ + EnableInsert(m_bInsert); +} + +// complete reset; edit new field +void SwFieldPage::EditNewField( bool bOnlyActivate ) +{ + if (!bOnlyActivate) + m_nTypeSel = -1; + m_nSelectionSel = -1; + m_bRefresh = true; + Reset(nullptr); + m_bRefresh = false; +} + +// insert field +void SwFieldPage::InsertField(SwFieldTypesEnum nTypeId, sal_uInt16 nSubType, const OUString& rPar1, + const OUString& rPar2, sal_uInt32 nFormatId, + sal_Unicode cSeparator, bool bIsAutomaticLanguage) +{ + SwView* pView = GetActiveView(); + if (!pView) + return; + + SwWrtShell *pSh = m_pWrtShell ? m_pWrtShell : pView->GetWrtShellPtr(); + if (!pSh) + return; + + if (!IsFieldEdit()) // insert new field + { + SwInsertField_Data aData(nTypeId, nSubType, rPar1, rPar2, nFormatId, nullptr, cSeparator, bIsAutomaticLanguage ); + //#i26566# provide parent for SwWrtShell::StartInputFieldDlg + aData.m_pParent = &GetDialogController()->GetOKButton(); + m_aMgr.InsertField( aData ); + + uno::Reference< frame::XDispatchRecorder > xRecorder = + pView->GetViewFrame().GetBindings().GetRecorder(); + if ( xRecorder.is() ) + { + bool bRecordDB = SwFieldTypesEnum::Database == nTypeId || + SwFieldTypesEnum::DatabaseSetNumber == nTypeId || + SwFieldTypesEnum::DatabaseNumberSet == nTypeId || + SwFieldTypesEnum::DatabaseNextSet == nTypeId || + SwFieldTypesEnum::DatabaseName == nTypeId ; + + SfxRequest aReq(pView->GetViewFrame(), + bRecordDB ? FN_INSERT_DBFIELD : FN_INSERT_FIELD); + if(bRecordDB) + { + sal_Int32 nIdx{ 0 }; + aReq.AppendItem(SfxStringItem + (FN_INSERT_DBFIELD,rPar1.getToken(0, DB_DELIM, nIdx))); + aReq.AppendItem(SfxStringItem + (FN_PARAM_1,rPar1.getToken(0, DB_DELIM, nIdx))); + aReq.AppendItem(SfxInt32Item + (TypedWhichId<SfxInt32Item>(FN_PARAM_3), o3tl::toInt32(o3tl::getToken(rPar1, 0, DB_DELIM, nIdx)))); + aReq.AppendItem(SfxStringItem + (FN_PARAM_2,rPar1.getToken(0, DB_DELIM, nIdx))); + } + else + { + aReq.AppendItem(SfxStringItem(FN_INSERT_FIELD, rPar1)); + aReq.AppendItem(SfxStringItem + (FN_PARAM_3, OUString(cSeparator))); + aReq.AppendItem(SfxUInt16Item(FN_PARAM_FIELD_SUBTYPE, nSubType)); + } + aReq.AppendItem(SfxUInt16Item(FN_PARAM_FIELD_TYPE , static_cast<sal_uInt16>(nTypeId))); + aReq.AppendItem(SfxStringItem(FN_PARAM_FIELD_CONTENT, rPar2)); + aReq.AppendItem(SfxUInt32Item(FN_PARAM_FIELD_FORMAT , nFormatId)); + aReq.Done(); + } + + } + else // change field + { + std::unique_ptr<SwField> pTmpField = m_pCurField->CopyField(); + + OUString sPar1(rPar1); + OUString sPar2(rPar2); + switch( nTypeId ) + { + case SwFieldTypesEnum::Date: + case SwFieldTypesEnum::Time: + nSubType = static_cast< sal_uInt16 >(((nTypeId == SwFieldTypesEnum::Date) ? DATEFLD : TIMEFLD) | + ((nSubType == DATE_VAR) ? 0 : FIXEDFLD)); + break; + + case SwFieldTypesEnum::DatabaseName: + case SwFieldTypesEnum::DatabaseNextSet: + case SwFieldTypesEnum::DatabaseNumberSet: + case SwFieldTypesEnum::DatabaseSetNumber: + { + sal_Int32 nPos = 0; + SwDBData aData; + + aData.sDataSource = rPar1.getToken(0, DB_DELIM, nPos); + aData.sCommand = rPar1.getToken(0, DB_DELIM, nPos); + aData.nCommandType = o3tl::toInt32(o3tl::getToken(rPar1, 0, DB_DELIM, nPos)); + sPar1 = rPar1.copy(nPos); + + static_cast<SwDBNameInfField*>(pTmpField.get())->SetDBData(aData); + } + break; + + case SwFieldTypesEnum::Database: + { + SwDBData aData; + sal_Int32 nIdx{ 0 }; + aData.sDataSource = rPar1.getToken(0, DB_DELIM, nIdx); + aData.sCommand = rPar1.getToken(0, DB_DELIM, nIdx); + aData.nCommandType = o3tl::toInt32(o3tl::getToken(rPar1, 0, DB_DELIM, nIdx)); + OUString sColumn = rPar1.getToken(0, DB_DELIM, nIdx); + + auto pOldType = static_cast<SwDBFieldType*>(pTmpField->GetTyp()); + auto pType = static_cast<SwDBFieldType*>(pSh->InsertFieldType(SwDBFieldType(pSh->GetDoc(), sColumn, aData))); + if(auto pFormatField = pOldType->FindFormatForField(m_pCurField)) + { + pFormatField->RegisterToFieldType(*pType); + pTmpField->ChgTyp(pType); + } + } + break; + + case SwFieldTypesEnum::Sequence: + { + SwSetExpFieldType* pTyp = static_cast<SwSetExpFieldType*>(pTmpField->GetTyp()); + pTyp->SetOutlineLvl( static_cast< sal_uInt8 >(nSubType & 0xff)); + pTyp->SetDelimiter(OUString(cSeparator)); + + nSubType = nsSwGetSetExpType::GSE_SEQ; + } + break; + + case SwFieldTypesEnum::Input: + { + // User- or SetField ? + if (m_aMgr.GetFieldType(SwFieldIds::User, sPar1) == nullptr && + !(pTmpField->GetSubType() & INP_TXT)) // SETEXPFLD + { + SwSetExpField* pField = static_cast<SwSetExpField*>(pTmpField.get()); + pField->SetPromptText(sPar2); + sPar2 = pField->GetPar2(); + } + } + break; + case SwFieldTypesEnum::DocumentInfo: + { + if( nSubType == nsSwDocInfoSubType::DI_CUSTOM ) + { + SwDocInfoField* pDocInfo = static_cast<SwDocInfoField*>( pTmpField.get() ); + pDocInfo->SetName( rPar1 ); + } + } + break; + default: break; + } + + pSh->StartAllAction(); + + pTmpField->SetSubType(nSubType); + pTmpField->SetAutomaticLanguage(bIsAutomaticLanguage); + + m_aMgr.UpdateCurField( nFormatId, sPar1, sPar2, std::move(pTmpField) ); + + m_pCurField = m_aMgr.GetCurField(); + + switch (nTypeId) + { + case SwFieldTypesEnum::HiddenText: + case SwFieldTypesEnum::HiddenParagraph: + m_aMgr.EvalExpFields(pSh); + break; + default: break; + } + + pSh->SetUndoNoResetModified(); + pSh->EndAllAction(); + } +} + +void SwFieldPage::SavePos( const weld::TreeView& rLst1 ) +{ + if (rLst1.n_children()) + m_aLstStrArr[ 0 ] = rLst1.get_selected_text(); + else + m_aLstStrArr[ 0 ].clear(); + m_aLstStrArr[ 1 ].clear(); + m_aLstStrArr[ 2 ].clear(); +} + +void SwFieldPage::RestorePos(weld::TreeView& rLst1) +{ + sal_Int32 nPos = 0; + if (rLst1.n_children() && !m_aLstStrArr[ 0 ].isEmpty() && + -1 != ( nPos = rLst1.find_text(m_aLstStrArr[ 0 ] ) ) ) + rLst1.select( nPos ); +} + +// Insert new fields +IMPL_LINK( SwFieldPage, TreeViewInsertHdl, weld::TreeView&, rBox, bool ) +{ + InsertHdl(&rBox); + return true; +} + +void SwFieldPage::InsertHdl(weld::Widget* pBtn) +{ + if (SwFieldDlg *pDlg = dynamic_cast<SwFieldDlg*>(GetDialogController())) + { + pDlg->InsertHdl(); + + if (pBtn) + pBtn->grab_focus(); // because of InputField-Dlg + } + else + { + SwFieldEditDlg *pEditDlg = static_cast<SwFieldEditDlg*>(GetDialogController()); + pEditDlg->InsertHdl(); + } +} + +// enable/disable "Insert"-Button +void SwFieldPage::EnableInsert(bool bEnable) +{ + if (SwFieldDlg *pDlg = dynamic_cast<SwFieldDlg*>(GetDialogController())) + { + if (pDlg->GetCurTabPage() == this) + pDlg->EnableInsert(bEnable); + } + else + { + SwFieldEditDlg *pEditDlg = static_cast<SwFieldEditDlg*>(GetDialogController()); + pEditDlg->EnableInsert(bEnable); + } + + m_bInsert = bEnable; +} + +IMPL_LINK_NOARG(SwFieldPage, NumFormatHdl, weld::TreeView&, bool) +{ + InsertHdl(nullptr); + return true; +} + +void SwFieldPage::SetWrtShell( SwWrtShell* pShell ) +{ + m_pWrtShell = pShell; + m_aMgr.SetWrtShell( pShell ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/fldpage.hxx b/sw/source/ui/fldui/fldpage.hxx new file mode 100644 index 0000000000..fbfa8cf2ba --- /dev/null +++ b/sw/source/ui/fldui/fldpage.hxx @@ -0,0 +1,89 @@ +/* -*- 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_FLDUI_FLDPAGE_HXX +#define INCLUDED_SW_SOURCE_UI_FLDUI_FLDPAGE_HXX + +#include <sfx2/tabdlg.hxx> +#include <fldmgr.hxx> + +#define FIELD_COLUMN_WIDTH 19 + +const int coLBCount = 3; + +class SwFieldPage : public SfxTabPage +{ + OUString m_aLstStrArr[ coLBCount ]; + SwFieldMgr m_aMgr; + SwField *m_pCurField; + SwWrtShell* m_pWrtShell; + sal_Int32 m_nTypeSel; + sal_Int32 m_nSelectionSel; + bool m_bFieldEdit; + bool m_bInsert; + bool m_bFieldDlgHtmlMode; + bool m_bRefresh; + bool m_bFirstHTMLInit; + +protected: + + sal_Int32 GetTypeSel() const { return m_nTypeSel;} + void SetTypeSel(sal_Int32 nSet) { m_nTypeSel = nSet;} + sal_Int32 GetSelectionSel() const { return m_nSelectionSel;} + void SetSelectionSel(sal_Int32 nSet){ m_nSelectionSel = nSet;} + bool IsFieldDlgHtmlMode() const { return m_bFieldDlgHtmlMode;} + bool IsRefresh() const { return m_bRefresh;} + SwField* GetCurField() { return m_pCurField;} + SwWrtShell* GetWrtShell() { return m_pWrtShell;} + + DECL_LINK( TreeViewInsertHdl, weld::TreeView&, bool ); + DECL_LINK( NumFormatHdl, weld::TreeView&, bool ); + void InsertHdl(weld::Widget*); + + void Init(); + void SavePos( const weld::TreeView& rLst1); + void RestorePos( weld::TreeView& rLst1 ); + void EnableInsert(bool bEnable); + bool IsFieldEdit() const { return m_bFieldEdit; } + + // insert field + void InsertField(SwFieldTypesEnum nTypeId, + sal_uInt16 nSubType, + const OUString& rPar1, + const OUString& rPar2, + sal_uInt32 nFormatId, + sal_Unicode cDelim = ' ', + bool bIsAutomaticLanguage = true); + +public: + SwFieldPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, + const OUString& rID, const SfxItemSet *pAttrSet); + + virtual ~SwFieldPage() override; + + virtual void Activate() override; + + SwFieldMgr& GetFieldMgr() { return m_aMgr; } + void SetWrtShell( SwWrtShell* m_pWrtShell ); + void EditNewField( bool bOnlyActivate = false ); + virtual sal_uInt16 GetGroup() = 0; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/fldref.cxx b/sw/source/ui/fldui/fldref.cxx new file mode 100644 index 0000000000..a08715c8ca --- /dev/null +++ b/sw/source/ui/fldui/fldref.cxx @@ -0,0 +1,1239 @@ +/* -*- 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 <swtypes.hxx> +#include <IMark.hxx> +#include <expfld.hxx> +#include <swmodule.hxx> +#include "fldref.hxx" +#include <frmatr.hxx> +#include <reffld.hxx> +#include <wrtsh.hxx> + +#include <fldref.hrc> +#include <strings.hrc> +#include <SwNodeNum.hxx> +#include <IDocumentMarkAccess.hxx> +#include <unotools/syslocaleoptions.hxx> +#include <unotools/charclass.hxx> +#include <osl/diagnose.h> + +#include <comphelper/string.hxx> +#include <editeng/frmdiritem.hxx> +#include <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> +#include <vcl/settings.hxx> + + +static sal_uInt16 nFieldDlgFormatSel = 0; + +#define USER_DATA_VERSION_1 "1" +#define USER_DATA_VERSION USER_DATA_VERSION_1 + +namespace { + +enum FMT_REF_IDX +{ + FMT_REF_PAGE_IDX = 0, + FMT_REF_CHAPTER_IDX = 1, + FMT_REF_TEXT_IDX = 2, + FMT_REF_UPDOWN_IDX = 3, + FMT_REF_PAGE_PGDSC_IDX = 4, + FMT_REF_ONLYNUMBER_IDX = 5, + FMT_REF_ONLYCAPTION_IDX = 6, + FMT_REF_ONLYSEQNO_IDX = 7, + FMT_REF_NUMBER_IDX = 8, + FMT_REF_NUMBER_NO_CONTEXT_IDX = 9, + FMT_REF_NUMBER_FULL_CONTEXT_IDX = 10 +}; + +} + +SwFieldRefPage::SwFieldRefPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *const pCoreSet ) + : SwFieldPage(pPage, pController, "modules/swriter/ui/fldrefpage.ui", "FieldRefPage", pCoreSet) + , mpSavedSelectedTextNode(nullptr) + , mnSavedSelectedPos(0) + , m_xTypeLB(m_xBuilder->weld_tree_view("type")) + , m_xSelection(m_xBuilder->weld_widget("selectframe")) + , m_xSelectionLB(m_xBuilder->weld_tree_view("select")) + , m_xSelectionToolTipLB(m_xBuilder->weld_tree_view("selecttip")) + , m_xFormat(m_xBuilder->weld_widget("formatframe")) + , m_xFormatLB(m_xBuilder->weld_tree_view("format")) + , m_xNameFT(m_xBuilder->weld_label("nameft")) + , m_xNameED(m_xBuilder->weld_entry("name")) + , m_xValueED(m_xBuilder->weld_entry("value")) + , m_xFilterED(m_xBuilder->weld_entry("filter")) + , m_xStylerefFlags(m_xBuilder->weld_widget("stylerefflagsframe")) + , m_xStylerefFromBottomCB(m_xBuilder->weld_check_button("stylereffrombottomcheckbox")) + , m_xStylerefHideNonNumericalCB(m_xBuilder->weld_check_button("stylerefhidenonnumericalcheckbox")) +{ + m_xSelectionLB->make_sorted(); + // #i83479# + for (auto const& aID : FLD_REF_PAGE_TYPES) + { + m_xTypeLB->append_text(SwResId(aID)); + m_xFormatLB->append_text(SwResId(aID)); + } + + m_sBookmarkText = m_xTypeLB->get_text(0); + m_sFootnoteText = m_xTypeLB->get_text(1); + m_sEndnoteText = m_xTypeLB->get_text(2); + // #i83479# + m_sHeadingText = m_xTypeLB->get_text(3); + m_sNumItemText = m_xTypeLB->get_text(4); + m_sStyleText = m_xTypeLB->get_text(5); + + auto nHeight = m_xTypeLB->get_height_rows(8); + auto nWidth = m_xTypeLB->get_approximate_digit_width() * FIELD_COLUMN_WIDTH; + m_xTypeLB->set_size_request(nWidth * 1.33, nHeight); + m_xFormatLB->set_size_request(nWidth * 1.33, nHeight); + m_xSelection->set_size_request(nWidth * 2, nHeight); + nHeight = m_xTypeLB->get_height_rows(8); + m_xSelectionToolTipLB->set_size_request(nHeight, nWidth*2); + + m_xTypeLB->clear(); + + m_xNameED->connect_changed(LINK(this, SwFieldRefPage, ModifyHdl)); + m_xFilterED->connect_changed( LINK( this, SwFieldRefPage, ModifyHdl_Impl ) ); + + m_xTypeLB->connect_row_activated(LINK(this, SwFieldRefPage, TreeViewInsertHdl)); + m_xTypeLB->connect_changed(LINK(this, SwFieldRefPage, TypeHdl)); + m_xSelectionLB->connect_changed(LINK(this, SwFieldRefPage, SubTypeListBoxHdl)); + m_xSelectionLB->connect_row_activated(LINK(this, SwFieldRefPage, TreeViewInsertHdl)); + m_xFormatLB->connect_row_activated(LINK(this, SwFieldRefPage, TreeViewInsertHdl)); + m_xFormatLB->connect_changed(LINK(this, SwFieldRefPage, FormatHdl)); + + // #i83479# + m_xSelectionToolTipLB->connect_changed( LINK(this, SwFieldRefPage, SubTypeTreeListBoxHdl) ); + m_xSelectionToolTipLB->connect_row_activated( LINK(this, SwFieldRefPage, TreeViewInsertHdl) ); + m_xFilterED->grab_focus(); + + // uitests + m_xTypeLB->set_buildable_name(m_xTypeLB->get_buildable_name() + "-ref"); + m_xNameED->set_buildable_name(m_xNameED->get_buildable_name() + "-ref"); + m_xValueED->set_buildable_name(m_xValueED->get_buildable_name() + "-ref"); + m_xSelectionLB->set_buildable_name(m_xSelectionLB->get_buildable_name() + "-ref"); + m_xFormatLB->set_buildable_name(m_xFormatLB->get_buildable_name() + "-ref"); +} + +SwFieldRefPage::~SwFieldRefPage() +{ +} + +IMPL_LINK_NOARG(SwFieldRefPage, ModifyHdl_Impl, weld::Entry&, void) +{ + UpdateSubType(comphelper::string::strip(m_xFilterED->get_text(), ' ')); + // tdf#135938 - refresh cross-reference name after filter selection has changed + SubTypeHdl(); +} + +// #i83479# +void SwFieldRefPage::SaveSelectedTextNode() +{ + mpSavedSelectedTextNode = nullptr; + mnSavedSelectedPos = 0; + if ( !m_xSelectionToolTipLB->get_visible() ) + return; + + int nEntry = m_xSelectionToolTipLB->get_selected_index(); + if (nEntry == -1) + return; + + const sal_uInt16 nTypeId = m_xTypeLB->get_id(GetTypeSel()).toUInt32(); + + if ( nTypeId == REFFLDFLAG_HEADING ) + { + mnSavedSelectedPos = m_xSelectionToolTipLB->get_id(nEntry).toUInt32(); + if ( mnSavedSelectedPos < maOutlineNodes.size() ) + { + mpSavedSelectedTextNode = maOutlineNodes[mnSavedSelectedPos]; + } + } + else if ( nTypeId == REFFLDFLAG_NUMITEM ) + { + mnSavedSelectedPos = m_xSelectionToolTipLB->get_id(nEntry).toUInt32(); + if ( mnSavedSelectedPos < maNumItems.size() ) + { + mpSavedSelectedTextNode = maNumItems[mnSavedSelectedPos]->GetTextNode(); + } + } +} + +void SwFieldRefPage::Reset(const SfxItemSet* ) +{ + if (!IsFieldEdit()) + { + SavePos(*m_xTypeLB); + // #i83479# + SaveSelectedTextNode(); + } + SetSelectionSel(-1); + SetTypeSel(-1); + Init(); // general initialisation + + // initialise TypeListBox + m_xTypeLB->freeze(); + m_xTypeLB->clear(); + + // fill Type-Listbox + + // set/insert reference + const SwFieldGroupRgn& rRg = SwFieldMgr::GetGroupRange(IsFieldDlgHtmlMode(), GetGroup()); + + for (short i = rRg.nStart; i < rRg.nEnd; ++i) + { + const SwFieldTypesEnum nTypeId = SwFieldMgr::GetTypeId(i); + + if (!IsFieldEdit() || nTypeId != SwFieldTypesEnum::SetRef) + { + m_xTypeLB->append(OUString::number(static_cast<sal_uInt16>(nTypeId)), SwFieldMgr::GetTypeStr(i)); + } + } + + // #i83479# + // entries for headings and numbered items + m_xTypeLB->append(OUString::number(REFFLDFLAG_HEADING), m_sHeadingText); + m_xTypeLB->append(OUString::number(REFFLDFLAG_NUMITEM), m_sNumItemText); + + // fill up with the sequence types + SwWrtShell *pSh = GetWrtShell(); + if (!pSh) + pSh = ::GetActiveWrtShell(); + if (!pSh) + return; + + // tdf#148432 in LTR UI override the navigator treeview direction based on + // the first page directionality + if (!AllSettings::GetLayoutRTL()) + { + const SwPageDesc& rDesc = pSh->GetPageDesc(0); + const SvxFrameDirectionItem& rFrameDir = rDesc.GetMaster().GetFrameDir(); + m_xSelectionToolTipLB->set_direction(rFrameDir.GetValue() == SvxFrameDirection::Horizontal_RL_TB); + } + + const size_t nFieldTypeCnt = pSh->GetFieldTypeCount(SwFieldIds::SetExp); + + OSL_ENSURE( nFieldTypeCnt < o3tl::make_unsigned(REFFLDFLAG), "<SwFieldRefPage::Reset> - Item index will overlap flags!" ); + + for (size_t n = 0; n < nFieldTypeCnt; ++n) + { + SwSetExpFieldType* pType = static_cast<SwSetExpFieldType*>(pSh->GetFieldType(n, SwFieldIds::SetExp)); + + if ((nsSwGetSetExpType::GSE_SEQ & pType->GetType()) && pType->HasWriterListeners() && pSh->IsUsed(*pType)) + { + m_xTypeLB->append(OUString::number(REFFLDFLAG | n), pType->GetName()); + } + } + + // text marks - now always (because of globaldocuments) + m_xTypeLB->append(OUString::number(REFFLDFLAG_BOOKMARK), m_sBookmarkText); + + // footnotes: + if( pSh->HasFootnotes() ) + { + m_xTypeLB->append(OUString::number(REFFLDFLAG_FOOTNOTE), m_sFootnoteText); + } + + // endnotes: + if ( pSh->HasFootnotes(true) ) + { + m_xTypeLB->append(OUString::number(REFFLDFLAG_ENDNOTE), m_sEndnoteText); + } + + // stylerefs + m_xTypeLB->append(OUString::number(REFFLDFLAG_STYLE), m_sStyleText); + + m_xTypeLB->thaw(); + + // select old Pos + if (!IsFieldEdit()) + RestorePos(*m_xTypeLB); + + nFieldDlgFormatSel = 0; + + sal_uInt16 nFormatBoxPosition = USHRT_MAX; + if( !IsRefresh() ) + { + sal_Int32 nIdx{ 0 }; + const OUString sUserData = GetUserData(); + if(!IsRefresh() && o3tl::equalsIgnoreAsciiCase(o3tl::getToken(sUserData, 0, ';', nIdx), + u"" USER_DATA_VERSION_1)) + { + const sal_uInt16 nVal = static_cast< sal_uInt16 >(o3tl::toInt32(o3tl::getToken(sUserData, 0, ';', nIdx))); + if(nVal != USHRT_MAX) + { + for(sal_Int32 i = 0, nEntryCount = m_xTypeLB->n_children(); i < nEntryCount; ++i) + { + if (nVal == m_xTypeLB->get_id(i).toUInt32()) + { + m_xTypeLB->select(i); + break; + } + } + if (nIdx>=0 && nIdx<sUserData.getLength()) + { + nFormatBoxPosition = static_cast< sal_uInt16 >(o3tl::toInt32(o3tl::getToken(sUserData, 0, ';', nIdx))); + } + } + } + } + TypeHdl(*m_xTypeLB); + if (!IsFieldEdit() && nFormatBoxPosition < m_xFormatLB->n_children()) + { + m_xFormatLB->select(nFormatBoxPosition); + } + if (IsFieldEdit()) + { + m_xTypeLB->save_value(); + m_xSelectionLB->save_value(); + m_xFormatLB->save_value(); + m_xNameED->save_value(); + m_xValueED->save_value(); + m_xFilterED->set_text(OUString()); + m_xStylerefFromBottomCB->save_state(); + m_xStylerefHideNonNumericalCB->save_state(); + } +} + +IMPL_LINK_NOARG(SwFieldRefPage, TypeHdl, weld::TreeView&, void) +{ + // save old ListBoxPos + const sal_Int32 nOld = GetTypeSel(); + + // current ListBoxPos + SetTypeSel(m_xTypeLB->get_selected_index()); + + if(GetTypeSel() == -1) + { + if (IsFieldEdit()) + { + // select positions + OUString sName; + sal_uInt16 nFlag = 0; + + switch( GetCurField()->GetSubType() ) + { + case REF_BOOKMARK: + { + // #i83479# + SwGetRefField* pRefField = dynamic_cast<SwGetRefField*>(GetCurField()); + if ( pRefField && + pRefField->IsRefToHeadingCrossRefBookmark() ) + { + sName = m_sHeadingText; + nFlag = REFFLDFLAG_HEADING; + } + else if ( pRefField && + pRefField->IsRefToNumItemCrossRefBookmark() ) + { + sName = m_sNumItemText; + nFlag = REFFLDFLAG_NUMITEM; + } + else + { + sName = m_sBookmarkText; + nFlag = REFFLDFLAG_BOOKMARK; + } + } + break; + + case REF_FOOTNOTE: + sName = m_sFootnoteText; + nFlag = REFFLDFLAG_FOOTNOTE; + break; + + case REF_ENDNOTE: + sName = m_sEndnoteText; + nFlag = REFFLDFLAG_ENDNOTE; + break; + + case REF_SETREFATTR: + sName = SwResId(STR_GETREFFLD); + nFlag = REF_SETREFATTR; + break; + + case REF_SEQUENCEFLD: + { + SwGetRefField const*const pRefField(dynamic_cast<SwGetRefField*>(GetCurField())); + if (pRefField) + { + sName = pRefField->GetSetRefName(); + } + nFlag = REFFLDFLAG; + break; + } + + case REF_STYLE: + { + SwGetRefField const*const pRefField(dynamic_cast<SwGetRefField*>(GetCurField())); + if (pRefField) + { + sName = pRefField->GetPar1(); + } + nFlag = REFFLDFLAG_STYLE; + break; + } + } + + if (m_xTypeLB->find_text(sName) == -1) // reference to deleted mark + { + m_xTypeLB->append(OUString::number(nFlag), sName); + } + + m_xTypeLB->select_text(sName); + SetTypeSel(m_xTypeLB->get_selected_index()); + } + else + { + SetTypeSel(0); + m_xTypeLB->select(0); + } + } + + if (nOld == GetTypeSel()) + return; + + sal_uInt16 nTypeId = m_xTypeLB->get_id(GetTypeSel()).toUInt32(); + + bool bName = false; + nFieldDlgFormatSel = 0; + + if ( ( !IsFieldEdit() || m_xSelectionLB->n_children() ) && + nOld != -1 ) + { + m_xNameED->set_text(OUString()); + m_xValueED->set_text(OUString()); + m_xFilterED->set_text(OUString()); + } + + // fill selection-ListBox + UpdateSubType(comphelper::string::strip(m_xFilterED->get_text(), ' ')); + + switch (nTypeId) + { + case static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef): + if (nOld != -1 && REFFLDFLAG & m_xTypeLB->get_id(nOld).toUInt32()) + // the old one stays + nFieldDlgFormatSel = m_xFormatLB->get_selected_index(); + bName = true; + break; + + case static_cast<sal_uInt16>(SwFieldTypesEnum::SetRef): + bName = true; + break; + + case REFFLDFLAG_BOOKMARK: + bName = true; + [[fallthrough]]; + default: + if( REFFLDFLAG & nTypeId ) + { + const sal_uInt16 nOldId = nOld != -1 ? m_xTypeLB->get_id(nOld).toUInt32() : 0; + if( nOldId & REFFLDFLAG || nOldId == static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef) ) + // then the old one stays + nFieldDlgFormatSel = m_xFormatLB->get_selected_index(); + } + break; + } + + m_xNameED->set_sensitive(bName); + m_xNameFT->set_sensitive(bName); + + // fill Format-Listbox + sal_Int32 nSize = FillFormatLB(nTypeId); + bool bFormat = nSize != 0; + m_xFormat->set_sensitive(bFormat); + + SubTypeHdl(); + ModifyHdl(*m_xNameED); + ModifyHdl(*m_xFilterED); +} + +IMPL_LINK_NOARG(SwFieldRefPage, SubTypeTreeListBoxHdl, weld::TreeView&, void) +{ + SubTypeHdl(); +} + +IMPL_LINK_NOARG(SwFieldRefPage, SubTypeListBoxHdl, weld::TreeView&, void) +{ + SubTypeHdl(); +} + +IMPL_LINK_NOARG(SwFieldRefPage, FormatHdl, weld::TreeView&, void) +{ + SubTypeHdl(); +} + +void SwFieldRefPage::SubTypeHdl() +{ + sal_uInt16 nTypeId = m_xTypeLB->get_id(GetTypeSel()).toUInt32(); + + sal_uInt16 nFormat = m_xFormatLB->get_selected_id().toUInt32(); + m_xStylerefHideNonNumericalCB->set_visible(nFormat == FMT_REF_NUMBER_IDX + || nFormat == FMT_REF_NUMBER_NO_CONTEXT_IDX + || nFormat == FMT_REF_NUMBER_FULL_CONTEXT_IDX); + m_xStylerefFlags->set_visible(nTypeId == REFFLDFLAG_STYLE); + + switch(nTypeId) + { + case static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef): + if (!IsFieldEdit() || m_xSelectionLB->get_selected_index() != -1) + { + m_xNameED->set_text(m_xSelectionLB->get_selected_text()); + ModifyHdl(*m_xNameED); + } + break; + + case static_cast<sal_uInt16>(SwFieldTypesEnum::SetRef): + { + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + if(pSh) + { + m_xValueED->set_text(pSh->GetSelText()); + } + + } + break; + // #i83479# + case REFFLDFLAG_HEADING: + case REFFLDFLAG_NUMITEM: + { + int nEntry = m_xSelectionToolTipLB->get_selected_index(); + if (nEntry != -1) + m_xNameED->set_text(m_xSelectionToolTipLB->get_text(nEntry)); + } + break; + + default: + if (!IsFieldEdit() || m_xSelectionLB->get_selected_index() != -1) + m_xNameED->set_text(m_xSelectionLB->get_selected_text()); + break; + } +} + +// renew types in SelectionLB after filtering +void SwFieldRefPage::UpdateSubType(const OUString& filterString) +{ + SwWrtShell *pSh = GetWrtShell(); + if (!pSh) + pSh = ::GetActiveWrtShell(); + if (!pSh) + return; + + SwGetRefField const*const pRefField(dynamic_cast<SwGetRefField*>(GetCurField())); + const sal_uInt16 nTypeId = m_xTypeLB->get_id(GetTypeSel()).toUInt32(); + + OUString sOldSel; + // #i83479# + if ( m_xSelectionLB->get_visible() ) + { + const sal_Int32 nSelectionSel = m_xSelectionLB->get_selected_index(); + if (nSelectionSel != -1) + sOldSel = m_xSelectionLB->get_text(nSelectionSel); + } + if (IsFieldEdit() && pRefField && sOldSel.isEmpty()) + sOldSel = OUString::number( pRefField->GetSeqNo() + 1 ); + + m_xSelectionLB->freeze(); + m_xSelectionLB->clear(); + + if (REFFLDFLAG & nTypeId) + { + if (nTypeId == REFFLDFLAG_FOOTNOTE || nTypeId == REFFLDFLAG_ENDNOTE) + { + m_xSelectionLB->thaw(); + m_xSelectionLB->make_unsorted(); + m_xSelectionLB->freeze(); + } + // #i83479# + else if (nTypeId != REFFLDFLAG_HEADING && nTypeId != REFFLDFLAG_NUMITEM) + { + m_xSelectionLB->thaw(); + m_xSelectionLB->make_sorted(); + m_xSelectionLB->freeze(); + } + } + + // #i83479# + m_xSelectionToolTipLB->freeze(); + m_xSelectionToolTipLB->clear(); + OUString m_sSelectionToolTipLBId; + bool bShowSelectionToolTipLB( false ); + + if( REFFLDFLAG & nTypeId ) + { + if (nTypeId == REFFLDFLAG_BOOKMARK) // text marks! + { + // get all text marks + IDocumentMarkAccess* const pMarkAccess = pSh->getIDocumentMarkAccess(); + for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getBookmarksBegin(); + ppMark != pMarkAccess->getBookmarksEnd(); + ++ppMark) + { + const ::sw::mark::IMark* pBkmk = *ppMark; + if(IDocumentMarkAccess::MarkType::BOOKMARK == IDocumentMarkAccess::GetType(*pBkmk)) + { + bool isSubstring = MatchSubstring(pBkmk->GetName(), filterString); + if(isSubstring) + { + m_xSelectionLB->append_text( pBkmk->GetName() ); + } + } + } + if (IsFieldEdit() && pRefField) + sOldSel = pRefField->GetSetRefName(); + } + else if (nTypeId == REFFLDFLAG_FOOTNOTE) + { + SwSeqFieldList aArr; + const size_t nCnt = pSh->GetSeqFootnoteList( aArr ); + + for( size_t n = 0; n < nCnt; ++n ) + { + bool isSubstring = MatchSubstring(aArr[ n ].sDlgEntry, filterString); + if(isSubstring) + { + m_xSelectionLB->append_text( aArr[ n ].sDlgEntry ); + } + if (IsFieldEdit() && pRefField && pRefField->GetSeqNo() == aArr[ n ].nSeqNo) + sOldSel = aArr[n].sDlgEntry; + } + } + else if (nTypeId == REFFLDFLAG_ENDNOTE) + { + SwSeqFieldList aArr; + const size_t nCnt = pSh->GetSeqFootnoteList( aArr, true ); + + for( size_t n = 0; n < nCnt; ++n ) + { + bool isSubstring = MatchSubstring(aArr[ n ].sDlgEntry, filterString); + if(isSubstring) + { + m_xSelectionLB->append_text( aArr[ n ].sDlgEntry ); + } + if (IsFieldEdit() && pRefField && pRefField->GetSeqNo() == aArr[ n ].nSeqNo) + sOldSel = aArr[n].sDlgEntry; + } + } + // #i83479# + else if ( nTypeId == REFFLDFLAG_HEADING ) + { + bShowSelectionToolTipLB = true; + + const IDocumentOutlineNodes* pIDoc( pSh->getIDocumentOutlineNodesAccess() ); + pIDoc->getOutlineNodes( maOutlineNodes ); + bool bCertainTextNodeSelected( false ); + for ( size_t nOutlIdx = 0; nOutlIdx < maOutlineNodes.size(); ++nOutlIdx ) + { + if (!pIDoc->isOutlineInLayout(nOutlIdx, *pSh->GetLayout())) + { + continue; // skip it + } + bool isSubstring = MatchSubstring(pIDoc->getOutlineText(nOutlIdx, pSh->GetLayout(), true, true, false), filterString); + if(isSubstring) + { + OUString sId(OUString::number(nOutlIdx)); + m_xSelectionToolTipLB->append(sId, + pIDoc->getOutlineText(nOutlIdx, pSh->GetLayout(), true, true, false)); + if ((IsFieldEdit() && pRefField + && pRefField->GetReferencedTextNode(nullptr, nullptr) == maOutlineNodes[nOutlIdx]) + || mpSavedSelectedTextNode == maOutlineNodes[nOutlIdx]) + { + m_sSelectionToolTipLBId = sId; + sOldSel.clear(); + bCertainTextNodeSelected = true; + } + else if ( !bCertainTextNodeSelected && mnSavedSelectedPos == nOutlIdx ) + { + m_sSelectionToolTipLBId = sId; + sOldSel.clear(); + } + } + } + } + else if ( nTypeId == REFFLDFLAG_NUMITEM ) + { + bShowSelectionToolTipLB = true; + + const IDocumentListItems* pIDoc( pSh->getIDocumentListItemsAccess() ); + pIDoc->getNumItems( maNumItems ); + bool bCertainTextNodeSelected( false ); + for ( size_t nNumItemIdx = 0; nNumItemIdx < maNumItems.size(); ++nNumItemIdx ) + { + if (!pIDoc->isNumberedInLayout(*maNumItems[nNumItemIdx], *pSh->GetLayout())) + { + continue; // skip it + } + bool isSubstring = MatchSubstring(pIDoc->getListItemText(*maNumItems[nNumItemIdx], *pSh->GetLayout()), filterString); + if(isSubstring) + { + OUString sId(OUString::number(nNumItemIdx)); + m_xSelectionToolTipLB->append(sId, + pIDoc->getListItemText(*maNumItems[nNumItemIdx], *pSh->GetLayout())); + if ((IsFieldEdit() && pRefField + && pRefField->GetReferencedTextNode(nullptr, nullptr) == maNumItems[nNumItemIdx]->GetTextNode()) + || mpSavedSelectedTextNode == maNumItems[nNumItemIdx]->GetTextNode()) + { + m_sSelectionToolTipLBId = sId; + sOldSel.clear(); + bCertainTextNodeSelected = true; + } + else if ( !bCertainTextNodeSelected && mnSavedSelectedPos == nNumItemIdx ) + { + m_sSelectionToolTipLBId = sId; + sOldSel.clear(); + } + } + } + } + else if (nTypeId == REFFLDFLAG_STYLE) + { + const IDocumentOutlineNodes* pIDoc(pSh->getIDocumentOutlineNodesAccess()); + pIDoc->getOutlineNodes(maOutlineNodes); + + SfxStyleSheetBasePool* pStyleSheetPool + = pSh->GetDoc()->GetDocShell()->GetStyleSheetPool(); + auto stylesheetIterator + = pStyleSheetPool->CreateIterator(SfxStyleFamily::Para, SfxStyleSearchBits::Used); + + SfxStyleSheetBase* pStyle = stylesheetIterator->First(); + while (pStyle != nullptr) + { + bool isSubstring = MatchSubstring(pStyle->GetName(), filterString); + + if (isSubstring) + { + m_xSelectionLB->append_text(pStyle->GetName()); + } + + pStyle = stylesheetIterator->Next(); + } + + if (IsFieldEdit() && pRefField) { + sOldSel = pRefField->GetPar1(); + m_xStylerefFromBottomCB->set_active((pRefField->GetFlags() & REFFLDFLAG_STYLE_FROM_BOTTOM) == REFFLDFLAG_STYLE_FROM_BOTTOM); + m_xStylerefHideNonNumericalCB->set_active((pRefField->GetFlags() & REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL) == REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL); + } + } + else + { + // get the fields to Seq-FieldType: + + SwSetExpFieldType* pType = static_cast<SwSetExpFieldType*>(pSh->GetFieldType( + nTypeId & ~REFFLDFLAG, SwFieldIds::SetExp )); + if( pType ) + { + SwSeqFieldList aArr; + // old selection should be kept in non-edit mode + if(IsFieldEdit()) + sOldSel.clear(); + + const size_t nCnt = pType->GetSeqFieldList(aArr, pSh->GetLayout()); + for( size_t n = 0; n < nCnt; ++n ) + { + bool isSubstring = MatchSubstring(aArr[ n ].sDlgEntry, filterString); + if(isSubstring) + { + m_xSelectionLB->append_text( aArr[ n ].sDlgEntry ); + } + if (IsFieldEdit() && pRefField && sOldSel.isEmpty() && + aArr[ n ].nSeqNo == pRefField->GetSeqNo()) + sOldSel = aArr[ n ].sDlgEntry; + } + + if (IsFieldEdit() && pRefField && sOldSel.isEmpty()) + sOldSel = OUString::number( pRefField->GetSeqNo() + 1); + } + } + } + else + { + std::vector<OUString> aLst; + GetFieldMgr().GetSubTypes(static_cast<SwFieldTypesEnum>(nTypeId), aLst); + for(const OUString & i : aLst) + { + bool isSubstring = MatchSubstring( i , filterString ); + if(isSubstring) + { + m_xSelectionLB->append_text(i); + } + } + + if (IsFieldEdit() && pRefField) + sOldSel = pRefField->GetSetRefName(); + } + + // #i83479# + m_xSelectionLB->thaw(); + m_xSelectionToolTipLB->thaw(); + if (!m_sSelectionToolTipLBId.isEmpty()) + m_xSelectionToolTipLB->select_id(m_sSelectionToolTipLBId); + m_xSelectionToolTipLB->set_visible( bShowSelectionToolTipLB ); + m_xSelectionLB->set_visible( !bShowSelectionToolTipLB ); + if ( bShowSelectionToolTipLB ) + { + bool bEnable = m_xSelectionToolTipLB->n_children() != 0; + m_xSelection->set_sensitive( bEnable ); + + int nEntry = m_xSelectionToolTipLB->get_selected_index(); + if (nEntry != -1) + m_xSelectionToolTipLB->scroll_to_row(nEntry); + + if (IsFieldEdit() && nEntry == -1) + { + m_xNameED->set_text(sOldSel); + } + } + else + { + // enable or disable + bool bEnable = m_xSelectionLB->n_children() != 0; + m_xSelection->set_sensitive( bEnable ); + + if ( bEnable ) + { + m_xSelectionLB->select_text(sOldSel); + if (m_xSelectionLB->get_selected_index() == -1 && !IsFieldEdit()) + m_xSelectionLB->select(0); + } + + if (IsFieldEdit() && m_xSelectionLB->get_selected_index() == -1) // in case the reference was already deleted... + m_xNameED->set_text(sOldSel); + } +} + +bool SwFieldRefPage::MatchSubstring( const OUString& rListString, const OUString& rSubstr ) +{ + if(rSubstr.isEmpty()) + return true; + OUString aListString = GetAppCharClass().lowercase(rListString); + OUString aSubstr = GetAppCharClass().lowercase(rSubstr); + return aListString.indexOf(aSubstr) >= 0; +} + +const TranslateId FMT_REF_ARY[] = +{ + FMT_REF_PAGE, + FMT_REF_CHAPTER, + FMT_REF_TEXT, + FMT_REF_UPDOWN, + FMT_REF_PAGE_PGDSC, + FMT_REF_ONLYNUMBER, + FMT_REF_ONLYCAPTION, + FMT_REF_ONLYSEQNO, + FMT_REF_NUMBER, + FMT_REF_NUMBER_NO_CONTEXT, + FMT_REF_NUMBER_FULL_CONTEXT +}; + +sal_Int32 SwFieldRefPage::FillFormatLB(sal_uInt16 nTypeId) +{ + OUString sOldSel; + + sal_Int32 nFormatSel = m_xFormatLB->get_selected_index(); + if (nFormatSel != -1) + sOldSel = m_xFormatLB->get_text(nFormatSel); + + // fill Format-Listbox + m_xFormatLB->clear(); + + // reference has less that the annotation + sal_uInt16 nSize( 0 ); + sal_uInt16 nOffset( 0 ); + bool bAddCrossRefFormats( false ); + switch (nTypeId) + { + // #i83479# + case REFFLDFLAG_HEADING: + case REFFLDFLAG_NUMITEM: + bAddCrossRefFormats = true; + [[fallthrough]]; + + case static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef): + case REFFLDFLAG_BOOKMARK: + case REFFLDFLAG_FOOTNOTE: + case REFFLDFLAG_ENDNOTE: + nSize = FMT_REF_PAGE_PGDSC_IDX + 1; + break; + case REFFLDFLAG_STYLE: + nOffset = FMT_REF_TEXT_IDX; + nSize = FMT_REF_UPDOWN_IDX + 1 - nOffset; + bAddCrossRefFormats = true; + break; + + default: + // #i83479# + + if ( REFFLDFLAG & nTypeId ) + { + nSize = FMT_REF_ONLYSEQNO_IDX + 1; + } + else + { + nSize = GetFieldMgr().GetFormatCount( static_cast<SwFieldTypesEnum>(nTypeId), IsFieldDlgHtmlMode() ); + } + break; + } + + if (REFFLDFLAG & nTypeId) + nTypeId = static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef); + + SwFieldTypesEnum nFieldType = static_cast<SwFieldTypesEnum>(nTypeId); + for (sal_uInt16 i = nOffset; i < nSize + nOffset; i++) + { + OUString sId(OUString::number(GetFieldMgr().GetFormatId( nFieldType, i ))); + m_xFormatLB->append(sId, GetFieldMgr().GetFormatStr(nFieldType, i)); + } + // #i83479# + + sal_uInt16 nExtraSize( 0 ); + if ( bAddCrossRefFormats ) + { + sal_uInt16 nFormat = FMT_REF_NUMBER_IDX; + OUString sId(OUString::number(GetFieldMgr().GetFormatId(nFieldType, nFormat))); + m_xFormatLB->append(sId, GetFieldMgr().GetFormatStr( nFieldType, nFormat )); + nFormat = FMT_REF_NUMBER_NO_CONTEXT_IDX; + sId = OUString::number(GetFieldMgr().GetFormatId(nFieldType, nFormat)); + m_xFormatLB->append(sId, GetFieldMgr().GetFormatStr( nFieldType, nFormat )); + nFormat = FMT_REF_NUMBER_FULL_CONTEXT_IDX; + sId = OUString::number(GetFieldMgr().GetFormatId(nFieldType, nFormat)); + m_xFormatLB->append(sId, GetFieldMgr().GetFormatStr( nFieldType, nFormat )); + nExtraSize = 3; + } + + // extra list items optionally, depending from reference-language + SvtSysLocaleOptions aSysLocaleOptions; + static const LanguageTag& rLang = aSysLocaleOptions.GetRealLanguageTag(); + + if (rLang.getLanguage() == "hu") + { + for (sal_uInt16 i = 0; i < nSize; i++) + { + OUString sId(OUString::number(GetFieldMgr().GetFormatId( nFieldType, i + SAL_N_ELEMENTS(FMT_REF_ARY)))); + m_xFormatLB->append(sId, SwResId(FMT_REF_WITH_LOWERCASE_HU_ARTICLE) + GetFieldMgr().GetFormatStr( nFieldType, i )); + } + nExtraSize += nSize; + + if ( bAddCrossRefFormats ) + { + sal_uInt16 nFormat = FMT_REF_NUMBER_IDX + SAL_N_ELEMENTS(FMT_REF_ARY); + OUString sId(OUString::number(GetFieldMgr().GetFormatId(nFieldType, nFormat))); + m_xFormatLB->append(sId, SwResId(FMT_REF_WITH_LOWERCASE_HU_ARTICLE) + GetFieldMgr().GetFormatStr( nFieldType, nFormat % SAL_N_ELEMENTS(FMT_REF_ARY))); + nFormat = FMT_REF_NUMBER_NO_CONTEXT_IDX + SAL_N_ELEMENTS(FMT_REF_ARY); + sId = OUString::number(GetFieldMgr().GetFormatId(nFieldType, nFormat)); + m_xFormatLB->append(sId, SwResId(FMT_REF_WITH_LOWERCASE_HU_ARTICLE) + GetFieldMgr().GetFormatStr( nFieldType, nFormat % SAL_N_ELEMENTS(FMT_REF_ARY))); + nFormat = FMT_REF_NUMBER_FULL_CONTEXT_IDX + SAL_N_ELEMENTS(FMT_REF_ARY); + sId = OUString::number(GetFieldMgr().GetFormatId(nFieldType, nFormat)); + m_xFormatLB->append(sId, SwResId(FMT_REF_WITH_LOWERCASE_HU_ARTICLE) + GetFieldMgr().GetFormatStr( nFieldType, nFormat % SAL_N_ELEMENTS(FMT_REF_ARY))); + nExtraSize += 3; + } + // uppercase article + for (sal_uInt16 i = 0; i < nSize; i++) + { + OUString sId(OUString::number(GetFieldMgr().GetFormatId( nFieldType, i + 2 * SAL_N_ELEMENTS(FMT_REF_ARY)))); + m_xFormatLB->append(sId, SwResId(FMT_REF_WITH_UPPERCASE_HU_ARTICLE) + GetFieldMgr().GetFormatStr( nFieldType, i )); + } + nExtraSize += nSize; + if ( bAddCrossRefFormats ) + { + sal_uInt16 nFormat = FMT_REF_NUMBER_IDX + 2 * SAL_N_ELEMENTS(FMT_REF_ARY); + OUString sId(OUString::number(GetFieldMgr().GetFormatId(nFieldType, nFormat))); + m_xFormatLB->append(sId, SwResId(FMT_REF_WITH_UPPERCASE_HU_ARTICLE) + GetFieldMgr().GetFormatStr( nFieldType, nFormat % SAL_N_ELEMENTS(FMT_REF_ARY))); + nFormat = FMT_REF_NUMBER_NO_CONTEXT_IDX + 2 * SAL_N_ELEMENTS(FMT_REF_ARY); + sId = OUString::number(GetFieldMgr().GetFormatId(nFieldType, nFormat)); + m_xFormatLB->append(sId, SwResId(FMT_REF_WITH_UPPERCASE_HU_ARTICLE) + GetFieldMgr().GetFormatStr( nFieldType, nFormat % SAL_N_ELEMENTS(FMT_REF_ARY))); + nFormat = FMT_REF_NUMBER_FULL_CONTEXT_IDX + 2 * SAL_N_ELEMENTS(FMT_REF_ARY); + sId = OUString::number(GetFieldMgr().GetFormatId(nFieldType, nFormat)); + m_xFormatLB->append(sId, SwResId(FMT_REF_WITH_UPPERCASE_HU_ARTICLE) + GetFieldMgr().GetFormatStr( nFieldType, nFormat % SAL_N_ELEMENTS(FMT_REF_ARY))); + nExtraSize += 3; + } + } + + nSize += nExtraSize; + + // select a certain entry + if (nSize) + { + if (!IsFieldEdit()) + m_xFormatLB->select_text(sOldSel); + else + m_xFormatLB->select_text(SwResId(FMT_REF_ARY[GetCurField()->GetFormat() % SAL_N_ELEMENTS(FMT_REF_ARY)])); + + if (m_xFormatLB->get_selected_index() == -1) + { + if (nFieldDlgFormatSel < m_xFormatLB->n_children()) + m_xFormatLB->select(nFieldDlgFormatSel); + else + m_xFormatLB->select(0); + } + } + + return nSize; +} + +// Modify +IMPL_LINK_NOARG(SwFieldRefPage, ModifyHdl, weld::Entry&, void) +{ + OUString aName(m_xNameED->get_text()); + const bool bEmptyName = aName.isEmpty(); + + bool bEnable = true; + sal_uInt16 nTypeId = m_xTypeLB->get_id(GetTypeSel()).toUInt32(); + + if ((nTypeId == static_cast<sal_uInt16>(SwFieldTypesEnum::SetRef) && !GetFieldMgr().CanInsertRefMark(aName)) || + (bEmptyName && (nTypeId == static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef) || nTypeId == static_cast<sal_uInt16>(SwFieldTypesEnum::SetRef) || + nTypeId == REFFLDFLAG_BOOKMARK))) + bEnable = false; + + EnableInsert(bEnable); + + m_xSelectionLB->select_text(aName); +} + +bool SwFieldRefPage::FillItemSet(SfxItemSet* ) +{ + bool bModified = false; + sal_uInt16 nTypeId = m_xTypeLB->get_id(GetTypeSel()).toUInt32(); + + sal_uInt16 nSubType = 0; + const sal_Int32 nEntryPos = m_xFormatLB->get_selected_index(); + const sal_uInt32 nFormat = (nEntryPos == -1) + ? 0 : m_xFormatLB->get_id(nEntryPos).toUInt32(); + + OUString aVal(m_xValueED->get_text()); + OUString aName(m_xNameED->get_text()); + + switch(nTypeId) + { + case static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef): + nSubType = REF_SETREFATTR; + break; + + case static_cast<sal_uInt16>(SwFieldTypesEnum::SetRef): + { + SwFieldType* pType = GetFieldMgr().GetFieldType(SwFieldIds::SetExp, aName); + + if(!pType) // Only insert when the name doesn't exist yet + { + m_xSelectionLB->append_text(aName); + m_xSelection->set_sensitive(true); + } + break; + } + } + + SwGetRefField const*const pRefField(dynamic_cast<SwGetRefField*>(GetCurField())); + + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + + if (pSh && REFFLDFLAG & nTypeId) + { + if (nTypeId == REFFLDFLAG_BOOKMARK) // text marks! + { + aName = m_xNameED->get_text(); + nTypeId = static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef); + nSubType = REF_BOOKMARK; + } + else if (REFFLDFLAG_FOOTNOTE == nTypeId) // footnotes + { + SwSeqFieldList aArr; + SeqFieldLstElem aElem( m_xSelectionLB->get_selected_text(), 0 ); + + size_t nPos = 0; + + nTypeId = static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef); + nSubType = REF_FOOTNOTE; + aName.clear(); + + if (pSh->GetSeqFootnoteList(aArr) && aArr.SeekEntry(aElem, &nPos)) + { + aVal = OUString::number( aArr[nPos].nSeqNo ); + + if (IsFieldEdit() && pRefField && aArr[nPos].nSeqNo == pRefField->GetSeqNo()) + bModified = true; // can happen with fields of which the references were deleted + } + else if (IsFieldEdit() && pRefField) + aVal = OUString::number( pRefField->GetSeqNo() ); + } + else if (REFFLDFLAG_ENDNOTE == nTypeId) // endnotes + { + SwSeqFieldList aArr; + SeqFieldLstElem aElem( m_xSelectionLB->get_selected_text(), 0 ); + + size_t nPos = 0; + + nTypeId = static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef); + nSubType = REF_ENDNOTE; + aName.clear(); + + if (pSh->GetSeqFootnoteList(aArr, true) && aArr.SeekEntry(aElem, &nPos)) + { + aVal = OUString::number( aArr[nPos].nSeqNo ); + + if (IsFieldEdit() && pRefField && aArr[nPos].nSeqNo == pRefField->GetSeqNo()) + bModified = true; // can happen with fields of which the reference was deleted + } + else if (IsFieldEdit() && pRefField) + aVal = OUString::number( pRefField->GetSeqNo() ); + } + // #i83479# + else if ( nTypeId == REFFLDFLAG_HEADING ) + { + int nEntry = m_xSelectionToolTipLB->get_selected_index(); + OSL_ENSURE( nEntry != -1, + "<SwFieldRefPage::FillItemSet(..)> - no entry selected in selection tool tip listbox!" ); + if (nEntry != -1) + { + const size_t nOutlIdx(m_xSelectionToolTipLB->get_id(nEntry).toUInt32()); + pSh->getIDocumentOutlineNodesAccess()->getOutlineNodes( maOutlineNodes ); + if ( nOutlIdx < maOutlineNodes.size() ) + { + ::sw::mark::IMark const * const pMark = pSh->getIDocumentMarkAccess()->getMarkForTextNode( + *(maOutlineNodes[nOutlIdx]), + IDocumentMarkAccess::MarkType::CROSSREF_HEADING_BOOKMARK); + aName = pMark->GetName(); + nTypeId = static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef); + nSubType = REF_BOOKMARK; + } + } + } + else if ( nTypeId == REFFLDFLAG_NUMITEM ) + { + int nEntry = m_xSelectionToolTipLB->get_selected_index(); + OSL_ENSURE( nEntry != -1, + "<SwFieldRefPage::FillItemSet(..)> - no entry selected in selection tool tip listbox!" ); + if (nEntry != -1) + { + const size_t nNumItemIdx(m_xSelectionToolTipLB->get_id(nEntry).toUInt32()); + pSh->getIDocumentListItemsAccess()->getNumItems(maNumItems); + if ( nNumItemIdx < maNumItems.size() ) + { + ::sw::mark::IMark const * const pMark = pSh->getIDocumentMarkAccess()->getMarkForTextNode( + *(maNumItems[nNumItemIdx]->GetTextNode()), + IDocumentMarkAccess::MarkType::CROSSREF_NUMITEM_BOOKMARK); + aName = pMark->GetName(); + nTypeId = static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef); + nSubType = REF_BOOKMARK; + } + } + } + else if (nTypeId == REFFLDFLAG_STYLE) + { + int nEntry = m_xSelectionLB->get_selected_index(); + if (nEntry != -1) + { + aName = m_xSelectionLB->get_text(nEntry); + nTypeId = static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef); + nSubType = REF_STYLE; + sal_uInt16 nVal = REFFLDFLAG_STYLE; + + if (m_xStylerefFromBottomCB->get_active()) { + nVal |= REFFLDFLAG_STYLE_FROM_BOTTOM; + } + + if (m_xStylerefHideNonNumericalCB->get_active()) { + nVal |= REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL; + } + + aVal = OUString::number(nVal); + } else { + SAL_WARN("sw.ui", "<SwFieldRefPage::FillItemSet(..)> no entry selected in selection listbox!"); + } + } + else // SequenceFields + { + // get fields for Seq-FieldType: + SwSetExpFieldType* pType = static_cast<SwSetExpFieldType*>(pSh->GetFieldType( + nTypeId & ~REFFLDFLAG, SwFieldIds::SetExp )); + if( pType ) + { + SwSeqFieldList aArr; + SeqFieldLstElem aElem( m_xSelectionLB->get_selected_text(), 0 ); + + size_t nPos = 0; + + nTypeId = static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef); + nSubType = REF_SEQUENCEFLD; + aName = pType->GetName(); + + if (pType->GetSeqFieldList(aArr, pSh->GetLayout()) + && aArr.SeekEntry(aElem, &nPos)) + { + aVal = OUString::number( aArr[nPos].nSeqNo ); + + if (IsFieldEdit() && pRefField && aArr[nPos].nSeqNo == pRefField->GetSeqNo()) + bModified = true; // can happen with fields of which the reference was deleted + } + else if (IsFieldEdit() && pRefField) + aVal = OUString::number( pRefField->GetSeqNo() ); + } + } + } + + if (IsFieldEdit() && nTypeId == static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef)) + { + aVal = OUString::number(nSubType) + "|" + aVal; + } + + if (!IsFieldEdit() || bModified || + m_xNameED->get_value_changed_from_saved() || + m_xValueED->get_value_changed_from_saved() || + m_xTypeLB->get_value_changed_from_saved() || + m_xSelectionLB->get_value_changed_from_saved() || + m_xFormatLB->get_value_changed_from_saved() || + (nSubType == REF_STYLE + && (m_xStylerefFromBottomCB->get_state_changed_from_saved() || m_xStylerefHideNonNumericalCB->get_state_changed_from_saved()))) + { + InsertField( static_cast<SwFieldTypesEnum>(nTypeId), nSubType, aName, aVal, nFormat ); + } + + ModifyHdl(*m_xNameED); // enable/disable insert if applicable + + return false; +} + +std::unique_ptr<SfxTabPage> SwFieldRefPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet *const pAttrSet) +{ + return std::make_unique<SwFieldRefPage>(pPage, pController, pAttrSet); +} + +sal_uInt16 SwFieldRefPage::GetGroup() +{ + return GRP_REF; +} + +void SwFieldRefPage::FillUserData() +{ + const sal_Int32 nEntryPos = m_xTypeLB->get_selected_index(); + const sal_uInt16 nTypeSel = ( -1 == nEntryPos ) + ? USHRT_MAX + : m_xTypeLB->get_id(nEntryPos).toUInt32(); + const sal_Int32 nFormatEntryPos = m_xFormatLB->get_selected_index(); + const sal_uInt32 nFormatSel = -1 == nFormatEntryPos ? USHRT_MAX : nFormatEntryPos; + SetUserData( USER_DATA_VERSION ";" + + OUString::number( nTypeSel ) + ";" + + OUString::number( nFormatSel )); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/fldref.hxx b/sw/source/ui/fldui/fldref.hxx new file mode 100644 index 0000000000..472d26a3c4 --- /dev/null +++ b/sw/source/ui/fldui/fldref.hxx @@ -0,0 +1,99 @@ +/* -*- 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_FLDUI_FLDREF_HXX +#define INCLUDED_SW_SOURCE_UI_FLDUI_FLDREF_HXX + +#include <sfx2/tabdlg.hxx> + +#include "fldpage.hxx" +#include <IDocumentOutlineNodes.hxx> +#include <IDocumentListItems.hxx> +class SwTextNode; + +class SwFieldRefPage : public SwFieldPage +{ + OUString m_sBookmarkText; + OUString m_sFootnoteText; + OUString m_sEndnoteText; + // #i83479# + OUString m_sHeadingText; + OUString m_sNumItemText; + OUString m_sStyleText; + + IDocumentOutlineNodes::tSortedOutlineNodeList maOutlineNodes; + IDocumentListItems::tSortedNodeNumList maNumItems; + + // selected text node in the listbox for headings and numbered items + // in order to restore selection after update of selection listbox + const SwTextNode* mpSavedSelectedTextNode; + // fallback, if previously selected text node doesn't exist anymore + size_t mnSavedSelectedPos; + + std::unique_ptr<weld::TreeView> m_xTypeLB; + std::unique_ptr<weld::Widget> m_xSelection; + std::unique_ptr<weld::TreeView> m_xSelectionLB; + // #i83479# + std::unique_ptr<weld::TreeView> m_xSelectionToolTipLB; + std::unique_ptr<weld::Widget> m_xFormat; + std::unique_ptr<weld::TreeView> m_xFormatLB; + std::unique_ptr<weld::Label> m_xNameFT; + std::unique_ptr<weld::Entry> m_xNameED; + std::unique_ptr<weld::Entry> m_xValueED; + std::unique_ptr<weld::Entry> m_xFilterED; + + std::unique_ptr<weld::Widget> m_xStylerefFlags; + std::unique_ptr<weld::CheckButton> m_xStylerefFromBottomCB; + std::unique_ptr<weld::CheckButton> m_xStylerefHideNonNumericalCB; + + DECL_LINK(TypeHdl, weld::TreeView&, void); + DECL_LINK(SubTypeListBoxHdl, weld::TreeView&, void); + DECL_LINK(SubTypeTreeListBoxHdl, weld::TreeView&, void); + DECL_LINK(ModifyHdl, weld::Entry&, void); + DECL_LINK(ModifyHdl_Impl, weld::Entry&, void); + DECL_LINK(FormatHdl, weld::TreeView&, void); + + void SubTypeHdl(); + + void UpdateSubType(const OUString& filterString); + + static bool MatchSubstring( const OUString& list_string, const OUString& substr ); + + sal_Int32 FillFormatLB(sal_uInt16 nTypeId); + + // #i83479# + void SaveSelectedTextNode(); + +protected: + virtual sal_uInt16 GetGroup() override; + +public: + SwFieldRefPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pSet); + virtual ~SwFieldRefPage() override; + + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; + + virtual void FillUserData() override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/fldtdlg.cxx b/sw/source/ui/fldui/fldtdlg.cxx new file mode 100644 index 0000000000..8c20586167 --- /dev/null +++ b/sw/source/ui/fldui/fldtdlg.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 <config_features.h> +#include <config_fuzzers.h> + +#include <cmdid.h> +#include <unotools/confignode.hxx> +#include <comphelper/processfactory.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/htmlmode.hxx> +#include <sfx2/viewfrm.hxx> +#include <osl/diagnose.h> +#include <viewopt.hxx> +#include <chldwrap.hxx> +#include <docsh.hxx> +#include "flddb.hxx" +#include "flddinf.hxx" +#include "fldvar.hxx" +#include "flddok.hxx" +#include "fldfunc.hxx" +#include "fldref.hxx" +#include <wrtsh.hxx> +#include <view.hxx> +#include <fldtdlg.hxx> +#include <swmodule.hxx> +#include <comphelper/lok.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/frame/XModel.hpp> + +// carrier of the dialog +SwFieldDlg::SwFieldDlg(SfxBindings* pB, SwChildWinWrapper* pCW, weld::Window *pParent) + : SfxTabDialogController(pParent, "modules/swriter/ui/fielddialog.ui", "FieldDialog") + , m_pChildWin(pCW) + , m_pBindings(pB) + , m_bDataBaseMode(false) + , m_bClosing(false) +{ + m_bHtmlMode = (::GetHtmlMode(static_cast<SwDocShell*>(SfxObjectShell::Current())) & HTMLMODE_ON) != 0; + + GetCancelButton().connect_clicked(LINK(this, SwFieldDlg, CancelHdl)); + GetOKButton().connect_clicked(LINK(this, SwFieldDlg, OKHdl)); + + AddTabPage("document", SwFieldDokPage::Create, nullptr); + AddTabPage("variables", SwFieldVarPage::Create, nullptr); + AddTabPage("docinfo", SwFieldDokInfPage::Create, nullptr); + + if (!m_bHtmlMode) + { + AddTabPage("ref", SwFieldRefPage::Create, nullptr); + AddTabPage("functions", SwFieldFuncPage::Create, nullptr); + + utl::OConfigurationTreeRoot aCfgRoot + = utl::OConfigurationTreeRoot::createWithComponentContext( + ::comphelper::getProcessComponentContext(), + "/org.openoffice.Office.DataAccess/Policies/Features/Writer", + -1, + utl::OConfigurationTreeRoot::CM_READONLY); + +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + bool bDatabaseFields = true; + aCfgRoot.getNodeValue( + OUString("DatabaseFields")) >>= bDatabaseFields; + + if (bDatabaseFields) + AddTabPage("database", SwFieldDBPage::Create, nullptr); + else +#endif + RemoveTabPage("database"); + } + else + { + RemoveTabPage("ref"); + RemoveTabPage("functions"); + RemoveTabPage("database"); + } + + if (comphelper::LibreOfficeKit::isActive()) + RemoveTabPage("database"); +} + +SwFieldDlg::~SwFieldDlg() +{ +} + +void SwFieldDlg::EndDialog(int nResponse) +{ + m_bClosing = true; + SfxTabDialogController::EndDialog(nResponse); + m_bClosing = false; +} + +void SwFieldDlg::Close() +{ + if (m_bClosing) + return; + const SfxPoolItemHolder aResult(m_pBindings->GetDispatcher()-> + Execute(m_bDataBaseMode ? FN_INSERT_FIELD_DATA_ONLY : FN_INSERT_FIELD, + SfxCallMode::SYNCHRON|SfxCallMode::RECORD)); + if (nullptr == aResult.getItem()) + { + // If Execute action did fail for whatever reason, this means that request + // to close did fail or wasn't delivered to SwTextShell::ExecField(). + // Just explicitly close dialog in this case. + SfxTabDialogController::EndDialog(RET_CLOSE); + } +} + +void SwFieldDlg::Initialize(SfxChildWinInfo const *pInfo) +{ + OUString aWinState = pInfo->aWinState; + if (aWinState.isEmpty()) + return; + m_xDialog->set_window_state(aWinState); +} + +SfxItemSet* SwFieldDlg::CreateInputItemSet(const OUString& rID) +{ + SwDocShell *const pDocSh(static_cast<SwDocShell*>(SfxObjectShell::Current())); + if (rID == "docinfo" && pDocSh) // might not have a shell if the dialog is restored on startup + { + mxInputItemSet = std::make_unique<SfxItemSetFixed<FN_FIELD_DIALOG_DOC_PROPS, FN_FIELD_DIALOG_DOC_PROPS>>( pDocSh->GetPool() ); + using namespace ::com::sun::star; + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + pDocSh->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps + = xDPS->getDocumentProperties(); + uno::Reference< beans::XPropertySet > xUDProps( + xDocProps->getUserDefinedProperties(), + uno::UNO_QUERY_THROW); + mxInputItemSet->Put( SfxUnoAnyItem( FN_FIELD_DIALOG_DOC_PROPS, uno::Any(xUDProps) ) ); + return mxInputItemSet.get(); + } + else + return nullptr; +} + +// kick off inserting of new fields +IMPL_LINK_NOARG(SwFieldDlg, OKHdl, weld::Button&, void) +{ + if (GetOKButton().get_sensitive()) + { + SfxTabPage* pPage = GetTabPage(GetCurPageId()); + assert(pPage); + pPage->FillItemSet(nullptr); + + GetOKButton().grab_focus(); // because of InputField-Dlg + } +} + +IMPL_LINK_NOARG(SwFieldDlg, CancelHdl, weld::Button&, void) +{ + Close(); +} + +// newly initialise dialog after Doc-Switch +void SwFieldDlg::ReInitDlg() +{ + SwDocShell* pDocSh = static_cast<SwDocShell*>(SfxObjectShell::Current()); + bool bNewMode = (::GetHtmlMode(pDocSh) & HTMLMODE_ON) != 0; + + if (bNewMode != m_bHtmlMode) + { + if (SfxViewFrame* pViewFrm = SfxViewFrame::Current()) + { + pViewFrm->GetDispatcher()-> + Execute(FN_INSERT_FIELD, SfxCallMode::ASYNCHRON|SfxCallMode::RECORD); + } + Close(); + } + + SwView* pActiveView = ::GetActiveView(); + if(!pActiveView) + return; + const SwWrtShell& rSh = pActiveView->GetWrtShell(); + GetOKButton().set_sensitive(( !rSh.IsReadOnlyAvailable() + || !rSh.HasReadonlySel()) + && !SwCursorShell::PosInsideInputField(*rSh.GetCursor()->GetPoint())); + + ReInitTabPage(u"document"); + ReInitTabPage(u"variables"); + ReInitTabPage(u"docinfo"); + + if (!m_bHtmlMode) + { + ReInitTabPage(u"ref"); + ReInitTabPage(u"functions"); + ReInitTabPage(u"database"); + } + + m_pChildWin->SetOldDocShell(pDocSh); +} + +// newly initialise TabPage after Doc-Switch +void SwFieldDlg::ReInitTabPage(std::u16string_view rPageId, bool bOnlyActivate) +{ + SwFieldPage* pPage = static_cast<SwFieldPage*>(GetTabPage(rPageId)); + if (pPage) + pPage->EditNewField( bOnlyActivate ); // newly initialise TabPage +} + +// newly initialise after activation of a few TabPages +void SwFieldDlg::Activate() +{ + SwView* pView = GetActiveView(); + if( !pView ) + return; + + bool bHtmlMode = (::GetHtmlMode(static_cast<SwDocShell*>(SfxObjectShell::Current())) & HTMLMODE_ON) != 0; + const SwWrtShell& rSh = pView->GetWrtShell(); + GetOKButton().set_sensitive(( !rSh.IsReadOnlyAvailable() + || !rSh.HasReadonlySel()) + && !SwCursorShell::PosInsideInputField(*rSh.GetCursor()->GetPoint())); + + + ReInitTabPage(u"variables", true); + + if( !bHtmlMode ) + { + ReInitTabPage(u"ref", true); + ReInitTabPage(u"functions", true); + } +} + +void SwFieldDlg::EnableInsert(bool bEnable) +{ + if( bEnable ) + { + SwView* pView = ::GetActiveView(); + if( !pView || + (pView->GetWrtShell().IsReadOnlyAvailable() && + pView->GetWrtShell().HasReadonlySel()) + || SwCursorShell::PosInsideInputField(*pView->GetWrtShell().GetCursor()->GetPoint())) + { + bEnable = false; + } + } + GetOKButton().set_sensitive(bEnable); +} + +void SwFieldDlg::InsertHdl() +{ + GetOKButton().clicked(); +} + +void SwFieldDlg::ActivateDatabasePage() +{ +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + m_bDataBaseMode = true; + ShowPage("database"); + SfxTabPage* pDBPage = GetTabPage(u"database"); + if( pDBPage ) + { + static_cast<SwFieldDBPage*>(pDBPage)->ActivateMailMergeAddress(); + } + //remove all other pages + RemoveTabPage("document"); + RemoveTabPage("variables"); + RemoveTabPage("docinfo"); + RemoveTabPage("ref"); + RemoveTabPage("functions"); +#endif +} + +void SwFieldDlg::ShowReferencePage() +{ + ShowPage("ref"); +} + +void SwFieldDlg::PageCreated(const OUString& rId, SfxTabPage& rPage) +{ +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + if (rId != "database") + return; + + SfxDispatcher* pDispatch = m_pBindings->GetDispatcher(); + SfxViewFrame* pViewFrame = pDispatch ? pDispatch->GetFrame() : nullptr; + if(pViewFrame) + { + SfxViewShell* pViewShell = SfxViewShell::GetFirst( true, checkSfxViewShell<SwView> ); + while(pViewShell && &pViewShell->GetViewFrame() != pViewFrame) + { + pViewShell = SfxViewShell::GetNext( *pViewShell, true, checkSfxViewShell<SwView> ); + } + if(pViewShell) + static_cast<SwFieldDBPage&>(rPage).SetWrtShell(static_cast<SwView*>(pViewShell)->GetWrtShell()); + } +#else + (void) rId; + (void) rPage; +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/fldvar.cxx b/sw/source/ui/fldui/fldvar.cxx new file mode 100644 index 0000000000..13265523ba --- /dev/null +++ b/sw/source/ui/fldui/fldvar.cxx @@ -0,0 +1,1277 @@ +/* -*- 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 <swtypes.hxx> +#include <sfx2/linkmgr.hxx> +#include <IDocumentFieldsAccess.hxx> +#include <usrfld.hxx> +#include <docufld.hxx> +#include <expfld.hxx> +#include <ddefld.hxx> +#include <wrtsh.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <swmodule.hxx> +#include "fldvar.hxx" +#include "flddinf.hxx" +#include <calc.hxx> +#include <svl/numformat.hxx> +#include <svl/zformat.hxx> +#include <o3tl/string_view.hxx> +#include <strings.hrc> + +#define USER_DATA_VERSION_1 "1" +#define USER_DATA_VERSION USER_DATA_VERSION_1 + +SwFieldVarPage::SwFieldVarPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *const pCoreSet ) + : SwFieldPage(pPage, pController, "modules/swriter/ui/fldvarpage.ui", "FieldVarPage", pCoreSet) + , m_xTypeLB(m_xBuilder->weld_tree_view("type")) + , m_xSelection(m_xBuilder->weld_widget("selectframe")) + , m_xSelectionLB(m_xBuilder->weld_tree_view("select")) + , m_xNameFT(m_xBuilder->weld_label("nameft")) + , m_xNameED(m_xBuilder->weld_entry("name")) + , m_xValueFT(m_xBuilder->weld_label("valueft")) + , m_xValueED(new ConditionEdit(m_xBuilder->weld_entry("value"))) + , m_xFormat(m_xBuilder->weld_widget("formatframe")) + , m_xNumFormatLB(new SwNumFormatTreeView(m_xBuilder->weld_tree_view("numformat"))) + , m_xFormatLB(m_xBuilder->weld_tree_view("format")) + , m_xChapterFrame(m_xBuilder->weld_widget("chapterframe")) + , m_xChapterLevelLB(m_xBuilder->weld_combo_box("level")) + , m_xInvisibleCB(m_xBuilder->weld_check_button("invisible")) + , m_xSeparatorFT(m_xBuilder->weld_label("separatorft")) + , m_xSeparatorED(m_xBuilder->weld_entry("separator")) + , m_xNewPB(m_xBuilder->weld_button("apply")) + , m_xDelPB(m_xBuilder->weld_button("delete")) + , m_nOldFormat(0) + , m_bInit(true) +{ + FillFieldSelect(*m_xTypeLB); + m_xSelectionLB->make_sorted(); + FillFieldSelect(*m_xFormatLB); + + auto nWidth = m_xTypeLB->get_approximate_digit_width() * FIELD_COLUMN_WIDTH; + auto nHeight = m_xTypeLB->get_height_rows(10); + m_xTypeLB->set_size_request(nWidth, nHeight); + m_xSelectionLB->set_size_request(nWidth, nHeight); + m_xFormatLB->set_size_request(nWidth, nHeight/2); + + m_sOldValueFT = m_xValueFT->get_label(); + m_sOldNameFT = m_xNameFT->get_label(); + + for (sal_uInt16 i = 1; i <= MAXLEVEL; i++) + m_xChapterLevelLB->append_text(OUString::number(i)); + + m_xChapterLevelLB->set_active(0); + //enable 'active' language selection + m_xNumFormatLB->SetShowLanguageControl(true); + + // uitests + m_xTypeLB->set_buildable_name(m_xTypeLB->get_buildable_name() + "-var"); + m_xNameED->set_buildable_name(m_xNameED->get_buildable_name() + "-var"); + m_xValueED->set_buildable_name(m_xValueED->get_buildable_name() + "-var"); + m_xNumFormatLB->set_buildable_name(m_xNumFormatLB->get_buildable_name() + "-var"); + m_xSelectionLB->set_buildable_name(m_xSelectionLB->get_buildable_name() + "-var"); + m_xFormatLB->set_buildable_name(m_xFormatLB->get_buildable_name() + "-var"); +} + +SwFieldVarPage::~SwFieldVarPage() +{ +} + +void SwFieldVarPage::Reset(const SfxItemSet* ) +{ + SavePos(*m_xTypeLB); + + Init(); // general initialisation + + m_xTypeLB->freeze(); + m_xTypeLB->clear(); + + SwFieldTypesEnum nTypeId; + + if (!IsFieldEdit()) + { + // initialise TypeListBox + const SwFieldGroupRgn& rRg = SwFieldMgr::GetGroupRange(IsFieldDlgHtmlMode(), GetGroup()); + + for (short i = rRg.nStart; i < rRg.nEnd; ++i) + { + nTypeId = SwFieldMgr::GetTypeId(i); + m_xTypeLB->append(OUString::number(static_cast<sal_uInt16>(nTypeId)), SwFieldMgr::GetTypeStr(i)); + } + } + else + { + const SwField* pCurField = GetCurField(); + assert(pCurField && "<SwFieldVarPage::Reset(..)> - <SwField> instance missing!"); + nTypeId = pCurField->GetTypeId(); + if (nTypeId == SwFieldTypesEnum::SetInput) + nTypeId = SwFieldTypesEnum::Input; + m_xTypeLB->append(OUString::number(static_cast<sal_uInt16>(nTypeId)), SwFieldMgr::GetTypeStr(SwFieldMgr::GetPos(nTypeId))); + m_xNumFormatLB->SetAutomaticLanguage(pCurField->IsAutomaticLanguage()); + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + if(pSh) + { + const SvNumberformat* pFormat = pSh->GetNumberFormatter()->GetEntry(pCurField->GetFormat()); + if(pFormat) + m_xNumFormatLB->SetLanguage(pFormat->GetLanguage()); + } + } + + m_xTypeLB->thaw(); + + // select old Pos + RestorePos(*m_xTypeLB); + + m_xTypeLB->connect_row_activated(LINK(this, SwFieldVarPage, TreeViewInsertHdl)); + m_xTypeLB->connect_changed(LINK(this, SwFieldVarPage, TypeHdl)); + m_xSelectionLB->connect_changed(LINK(this, SwFieldVarPage, SubTypeListBoxHdl)); + m_xSelectionLB->connect_row_activated(LINK(this, SwFieldVarPage, SubTypeInsertHdl)); + m_xFormatLB->connect_row_activated(LINK(this, SwFieldVarPage, TreeViewInsertHdl)); + m_xNumFormatLB->connect_row_activated(LINK(this, SwFieldVarPage, TreeViewInsertHdl)); + m_xNameED->connect_changed(LINK(this, SwFieldVarPage, ModifyHdl)); + m_xValueED->connect_changed(LINK(this, SwFieldVarPage, ModifyHdl)); + m_xNewPB->connect_clicked(LINK(this, SwFieldVarPage, TBClickHdl)); + m_xDelPB->connect_clicked(LINK(this, SwFieldVarPage, TBClickHdl)); + m_xChapterLevelLB->connect_changed(LINK(this, SwFieldVarPage, ChapterHdl)); + m_xSeparatorED->connect_changed(LINK(this, SwFieldVarPage, SeparatorHdl)); + + if( !IsRefresh() ) + { + OUString sUserData = GetUserData(); + sal_Int32 nIdx{ 0 }; + if(!IsRefresh() && o3tl::equalsIgnoreAsciiCase(o3tl::getToken(sUserData, 0, ';', nIdx), u"" USER_DATA_VERSION_1)) + { + std::u16string_view sVal = o3tl::getToken(sUserData, 0, ';', nIdx); + sal_uInt16 nVal = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(sVal)); + if (USHRT_MAX != nVal) + { + for (sal_Int32 i = 0, nEntryCount = m_xTypeLB->n_children(); i < nEntryCount; i++) + { + if (nVal == m_xTypeLB->get_id(i).toUInt32()) + { + m_xTypeLB->select(i); + break; + } + } + } + } + } + TypeHdl(*m_xTypeLB); + + if (IsFieldEdit()) + { + m_xSelectionLB->save_value(); + m_xFormatLB->save_value(); + m_nOldFormat = m_xNumFormatLB->GetFormat(); + m_xNameED->save_value(); + m_xValueED->save_value(); + m_xInvisibleCB->save_state(); + m_xChapterLevelLB->save_value(); + m_xSeparatorED->save_value(); + } +} + +IMPL_LINK_NOARG(SwFieldVarPage, TypeHdl, weld::TreeView&, void) +{ + // save old ListBoxPos + const sal_Int32 nOld = GetTypeSel(); + + // current ListBoxPos + SetTypeSel(m_xTypeLB->get_selected_index()); + + if(GetTypeSel() == -1) + { + SetTypeSel(0); + m_xTypeLB->select(0); + } + + if (nOld != GetTypeSel() || nOld == -1) + { + m_bInit = true; + if (nOld != -1) + { + m_xNameED->set_text(OUString()); + m_xValueED->set_text(OUString()); + } + + m_xValueED->SetDropEnable(false); + UpdateSubType(); // initialise selection-listboxes + } + + m_bInit = false; +} + +IMPL_LINK( SwFieldVarPage, SubTypeListBoxHdl, weld::TreeView&, rBox, void ) +{ + SubTypeHdl(&rBox); +} + +static inline sal_uInt32 lcl_getUsedNumFormat( const SwNumFormatTreeView& rNumFormatLB, bool& rbText ) +{ + sal_uInt32 nNumberFormat = 0; + const sal_Int32 nNumFormatPos = rNumFormatLB.get_selected_index(); + if (nNumFormatPos != -1) + { + nNumberFormat = rNumFormatLB.GetFormat(); + if ((rbText = (nNumFormatPos == 0 && nNumberFormat == SAL_MAX_UINT32))) + nNumberFormat = 0; + } + return nNumberFormat; +} + +void SwFieldVarPage::SubTypeHdl(const weld::TreeView* pBox) +{ + SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + sal_Int32 nSelPos = m_xSelectionLB->get_selected_index(); + size_t nSelData = SIZE_MAX; + + if (nSelPos != -1) + nSelData = m_xSelectionLB->get_id(nSelPos).toUInt32(); + + if (IsFieldEdit() && (!pBox || m_bInit)) + { + if (nTypeId != SwFieldTypesEnum::Formel) + m_xNameED->set_text(GetFieldMgr().GetCurFieldPar1()); + + m_xValueED->set_text(GetFieldMgr().GetCurFieldPar2()); + } + + if (m_xNameFT->get_label() != m_sOldNameFT) + m_xNameFT->set_label(m_sOldNameFT); + if (m_xValueFT->get_label() != m_sOldValueFT) + m_xValueFT->set_label(m_sOldValueFT); + + FillFormatLB(nTypeId); + + sal_Int32 nSize = m_xFormatLB->n_children(); + + bool bValue = false, bName = false, bNumFormat = false, + bInvisible = false, bShowChapterFrame = false; + bool bFormat = nSize != 0; + + switch (nTypeId) + { + case SwFieldTypesEnum::User: + { + // change or create user type + SwUserFieldType* pType = static_cast<SwUserFieldType*>( + GetFieldMgr().GetFieldType(SwFieldIds::User, nSelData)); + + if (pType) + { + if (!IsFieldEdit()) + { + if (pBox || (m_bInit && !IsRefresh())) // only when interacting via mouse + { + m_xNameED->set_text(pType->GetName()); + + if (pType->GetType() == UF_STRING) + { + m_xValueED->set_text(pType->GetContent()); + m_xNumFormatLB->select(0); + } + else + { + bool bText = false; + const sal_uInt32 nNumberFormat = lcl_getUsedNumFormat( *m_xNumFormatLB, bText); + m_xValueED->set_text(pType->GetInputOrDateTime(nNumberFormat)); + } + } + } + else + { + bool bText = false; + const sal_uInt32 nNumberFormat = lcl_getUsedNumFormat( *m_xNumFormatLB, bText); + m_xValueED->set_text(pType->GetInputOrDateTime(nNumberFormat)); + } + } + else + { + if (pBox) // only when interacting via mouse + { + m_xNameED->set_text(OUString()); + m_xValueED->set_text(OUString()); + } + } + bValue = bName = bNumFormat = bInvisible = true; + + m_xValueED->SetDropEnable(true); + break; + } + + case SwFieldTypesEnum::Set: + bValue = true; + + bNumFormat = bInvisible = true; + + if (!IsFieldDlgHtmlMode()) + bName = true; + else + { + m_xNumFormatLB->clear(); + m_xNumFormatLB->append(OUString::number(NUMBERFORMAT_ENTRY_NOT_FOUND), SwResId(FMT_SETVAR_TEXT)); + m_xNumFormatLB->select(0); + } + // is there a corresponding SetField + if (IsFieldEdit() || pBox) // only when interacting via mouse + { + if (nSelPos != -1) + { + OUString sName(m_xSelectionLB->get_selected_text()); + m_xNameED->set_text(sName); + + if (!IsFieldDlgHtmlMode()) + { + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + if(pSh) + { + SwSetExpFieldType* pSetTyp = static_cast<SwSetExpFieldType*>( + pSh->GetFieldType(SwFieldIds::SetExp, sName)); + + if (pSetTyp && pSetTyp->GetType() == nsSwGetSetExpType::GSE_STRING) + m_xNumFormatLB->select(0); // textual + } + } + } + } + if (GetCurField() != nullptr && IsFieldEdit()) + { + m_xValueED->set_text(static_cast<SwSetExpField*>(GetCurField())->GetInputOrDateTime()); + } + m_xValueED->SetDropEnable(true); + break; + + case SwFieldTypesEnum::Formel: + { + bValue = true; + bNumFormat = true; + m_xValueFT->set_label(SwResId(STR_FORMULA)); + m_xValueED->SetDropEnable(true); + } + break; + + case SwFieldTypesEnum::Get: + { + if (!IsFieldEdit()) + { + m_xNameED->set_text(OUString()); + m_xValueED->set_text(OUString()); + } + + if (nSelPos != -1) + { + OUString sName(m_xSelectionLB->get_selected_text()); + if (!IsFieldEdit()) + m_xNameED->set_text(sName); + + // is there a corresponding SetField + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + if(pSh) + { + SwSetExpFieldType* pSetTyp = static_cast<SwSetExpFieldType*>( + pSh->GetFieldType(SwFieldIds::SetExp, sName)); + + if(pSetTyp) + { + if (pSetTyp->GetType() & nsSwGetSetExpType::GSE_STRING) // textual? + bFormat = true; + else // numeric + bNumFormat = true; + } + } + } + else + bFormat = false; + + EnableInsert(bFormat || bNumFormat); + } + break; + + case SwFieldTypesEnum::Input: + m_xValueFT->set_label(SwResId(STR_PROMPT)); + + if (nSelPos != -1) + { + bValue = bNumFormat = true; + + OUString sName = m_xSelectionLB->get_selected_text(); + m_xNameED->set_text( sName ); + + // User- or SetField ? + if (!GetFieldMgr().GetFieldType(SwFieldIds::User, sName)) // SetExp + { + // is there a corresponding SetField + SwSetExpFieldType* pSetTyp = static_cast<SwSetExpFieldType*>( + GetFieldMgr().GetFieldType(SwFieldIds::SetExp, sName)); + + if(pSetTyp) + { + if (pSetTyp->GetType() == nsSwGetSetExpType::GSE_STRING) // textual? + { + m_xNumFormatLB->clear(); + m_xNumFormatLB->append(OUString::number(NUMBERFORMAT_ENTRY_NOT_FOUND), SwResId(FMT_USERVAR_TEXT)); + m_xNumFormatLB->select(0); + } + } + if (GetCurField() && IsFieldEdit() && (!pBox || m_bInit) ) + m_xValueED->set_text(static_cast<SwSetExpField*>(GetCurField())->GetPromptText()); + } + else // USERFLD + bFormat = bNumFormat = false; + } + break; + + case SwFieldTypesEnum::DDE: + m_xValueFT->set_label(SwResId(STR_DDE_CMD)); + + if (IsFieldEdit() || pBox) // only when interacting via mouse + { + if (nSelPos != -1) + { + SwDDEFieldType* pType = + static_cast<SwDDEFieldType*>( GetFieldMgr().GetFieldType(SwFieldIds::Dde, nSelData) ); + + if(pType) + { + m_xNameED->set_text(pType->GetName()); + + //JP 28.08.95: DDE-Topics/-Items can have blanks in their names! + // That's not considered here yet + OUString sCmd( pType->GetCmd() ); + sal_Int32 nTmpPos = 0; + sCmd = sCmd.replaceFirst( OUStringChar(sfx2::cTokenSeparator), " ", &nTmpPos ); + sCmd = sCmd.replaceFirst( OUStringChar(sfx2::cTokenSeparator), " ", &nTmpPos ); + + m_xValueED->set_text( sCmd ); + m_xFormatLB->select(static_cast<int>(pType->GetType())); + } + } + } + bName = bValue = true; + break; + + case SwFieldTypesEnum::Sequence: + { + bName = bValue = bShowChapterFrame = true; + + SwFieldType* pFieldTyp; + if( GetCurField() && IsFieldEdit() ) + pFieldTyp = GetCurField()->GetTyp(); + else + { + OUString sFieldTypeName(m_xSelectionLB->get_text(nSelPos)); + if( !sFieldTypeName.isEmpty() ) + pFieldTyp = GetFieldMgr().GetFieldType( SwFieldIds::SetExp, + sFieldTypeName ); + else + pFieldTyp = nullptr; + } + + if( GetCurField() && IsFieldEdit() ) + m_xValueED->set_text( static_cast<SwSetExpField*>(GetCurField())-> + GetFormula() ); + + if( IsFieldEdit() || pBox ) // only when interacting via mouse + m_xNameED->set_text( m_xSelectionLB->get_selected_text() ); + + if( pFieldTyp ) + { + sal_uInt8 nLevel = static_cast<SwSetExpFieldType*>(pFieldTyp)->GetOutlineLvl(); + if( 0x7f == nLevel ) + m_xChapterLevelLB->set_active(0); + else + m_xChapterLevelLB->set_active(nLevel + 1); + OUString sDelim = static_cast<SwSetExpFieldType*>(pFieldTyp)->GetDelimiter(); + m_xSeparatorED->set_text( sDelim ); + ChapterHdl(*m_xChapterLevelLB); + } + } + break; + + case SwFieldTypesEnum::SetRefPage: + { + bValue = false; + m_xValueFT->set_label( SwResId( STR_OFFSET )); + + if (IsFieldEdit() || pBox) // only when interacting via mouse + m_xNameED->set_text(OUString()); + + if (nSelData != 0 && nSelData != SIZE_MAX) + { + bValue = true; // SubType OFF - knows no Offset + if (GetCurField() && IsFieldEdit()) + m_xValueED->set_text(OUString::number(static_cast<SwRefPageSetField*>(GetCurField())->GetOffset())); + } + } + break; + + case SwFieldTypesEnum::GetRefPage: + m_xNameED->set_text(OUString()); + m_xValueED->set_text(OUString()); + break; + + default: break; + } + + m_xNumFormatLB->set_visible(bNumFormat); + m_xFormatLB->set_visible(!bNumFormat); + + if (IsFieldEdit()) + bName = false; + + m_xFormat->set_sensitive(bFormat || bNumFormat); + m_xNameFT->set_sensitive(bName); + m_xNameED->set_sensitive(bName); + m_xValueFT->set_sensitive(bValue); + m_xValueED->set_sensitive(bValue); + + m_xInvisibleCB->set_visible(!bShowChapterFrame); + m_xChapterFrame->set_visible(bShowChapterFrame); + m_xInvisibleCB->set_sensitive(bInvisible); + + ModifyHdl(*m_xNameED); // apply/insert/delete status update +} + +IMPL_LINK(SwFieldVarPage, SubTypeInsertHdl, weld::TreeView&, rBox, bool) +{ + if (!m_bInit) + { + SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + if (nTypeId == SwFieldTypesEnum::Formel) + { + auto nSelPos = m_xSelectionLB->get_selected_index(); + if (nSelPos != -1) + { + m_xValueED->replace_selection(m_xSelectionLB->get_text(nSelPos)); + ModifyHdl(*m_xNameED); + return true; + } + } + } + TreeViewInsertHdl(rBox); + return true; +} + +// renew types in SelectionBox +void SwFieldVarPage::UpdateSubType() +{ + SetSelectionSel(m_xSelectionLB->get_selected_index()); + + OUString sOldSel; + if (GetSelectionSel() != -1) + sOldSel = m_xSelectionLB->get_text(GetSelectionSel()); + + // fill Selection-Listbox + m_xSelectionLB->freeze(); + m_xSelectionLB->clear(); + + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + std::vector<OUString> aList; + GetFieldMgr().GetSubTypes(nTypeId, aList); + const size_t nCount = aList.size(); + for (size_t i = 0; i < nCount; ++i) + { + if (nTypeId != SwFieldTypesEnum::Input || i) + { + if (!IsFieldEdit()) + { + m_xSelectionLB->append(OUString::number(i), aList[i]); + } + else + { + bool bInsert = false; + + switch (nTypeId) + { + case SwFieldTypesEnum::Input: + if (GetCurField() && aList[i] == GetCurField()->GetPar1()) + bInsert = true; + break; + + case SwFieldTypesEnum::Formel: + bInsert = true; + break; + + case SwFieldTypesEnum::Get: + if (GetCurField() && aList[i] == static_cast<const SwFormulaField*>(GetCurField())->GetFormula()) + bInsert = true; + break; + + case SwFieldTypesEnum::Set: + case SwFieldTypesEnum::User: + if (GetCurField() && aList[i] == GetCurField()->GetTyp()->GetName()) + { + bInsert = true; + if (GetCurField()->GetSubType() & nsSwExtendedSubType::SUB_INVISIBLE) + m_xInvisibleCB->set_active(true); + } + break; + + case SwFieldTypesEnum::SetRefPage: + { + if (GetCurField() != nullptr + && ((static_cast<SwRefPageSetField*>(GetCurField())->IsOn() + && i) || (!static_cast<SwRefPageSetField*>(GetCurField()) + ->IsOn() && !i))) + { + sOldSel = aList[i]; + } + + // allow all entries for selection: + m_xSelectionLB->append(OUString::number(i), aList[i]); + break; + } + default: + if (GetCurField() && aList[i] == GetCurField()->GetPar1()) + bInsert = true; + break; + } + + if (bInsert) + { + m_xSelectionLB->append(OUString::number(i), aList[i]); + if (nTypeId != SwFieldTypesEnum::Formel) + break; + } + } + } + } + + m_xSelectionLB->thaw(); + + const bool bEnable = m_xSelectionLB->n_children() != 0; + weld::TreeView* pLB = nullptr; + + if (bEnable) + { + int nIndex = m_xSelectionLB->find_text(sOldSel); + if (nIndex != -1) + m_xSelectionLB->select(nIndex); + else + { + m_xSelectionLB->select(0); + pLB = m_xSelectionLB.get(); // newly initialise all controls + } + } + + m_xSelection->set_sensitive(bEnable); + + SubTypeHdl(pLB); +} + +void SwFieldVarPage::FillFormatLB(SwFieldTypesEnum nTypeId) +{ + OUString sOldSel; + const sal_Int32 nFormatSel = m_xFormatLB->get_selected_index(); + if (nFormatSel != -1) + sOldSel = m_xFormatLB->get_text(nFormatSel); + + weld::TreeView& rWidget = dynamic_cast<weld::TreeView&>(m_xNumFormatLB->get_widget()); + + OUString sOldNumSel; + sal_uInt32 nOldNumFormat = 0; + sal_Int32 nNumFormatSel = rWidget.get_selected_index(); + if (nNumFormatSel != -1) + { + sOldNumSel = rWidget.get_text(nNumFormatSel); + nOldNumFormat = m_xNumFormatLB->GetFormat(); + } + + // fill Format-Listbox + m_xFormatLB->freeze(); + m_xFormatLB->clear(); + m_xNumFormatLB->clear(); // flags list as dirty and needing refilling with stock entries + bool bSpecialFormat = false; + + if( SwFieldTypesEnum::GetRefPage != nTypeId ) + { + if (GetCurField() != nullptr && IsFieldEdit()) + { + bSpecialFormat = GetCurField()->GetFormat() == NUMBERFORMAT_ENTRY_NOT_FOUND; + + if (!bSpecialFormat) + { + m_xNumFormatLB->SetDefFormat(GetCurField()->GetFormat()); + sOldNumSel.clear(); + } + else if (nTypeId == SwFieldTypesEnum::Get || nTypeId == SwFieldTypesEnum::Formel) + { + m_xNumFormatLB->SetFormatType(SvNumFormatType::NUMBER); + } + } + else + { + if (nOldNumFormat && nOldNumFormat != NUMBERFORMAT_ENTRY_NOT_FOUND) + m_xNumFormatLB->SetDefFormat(nOldNumFormat); + else + m_xNumFormatLB->SetFormatType(SvNumFormatType::NUMBER); + } + } + + switch (nTypeId) + { + case SwFieldTypesEnum::User: + { + if (!IsFieldEdit() || bSpecialFormat) + { + OUString sId(OUString::number(NUMBERFORMAT_ENTRY_NOT_FOUND)); + int nOldIndex = rWidget.get_selected_index(); + rWidget.insert(0, SwResId(FMT_MARK_TEXT), &sId, nullptr, nullptr); + rWidget.insert(1, SwResId(FMT_USERVAR_CMD), &sId, nullptr, nullptr); + if (nOldIndex != -1) + rWidget.select(nOldIndex + 2); + } + } + break; + + case SwFieldTypesEnum::Set: + { + if (!IsFieldEdit() || bSpecialFormat) + { + OUString sId(OUString::number(NUMBERFORMAT_ENTRY_NOT_FOUND)); + int nOldIndex = rWidget.get_selected_index(); + rWidget.insert(0, SwResId(FMT_SETVAR_TEXT), &sId, nullptr, nullptr); + if (nOldIndex != -1) + rWidget.select(nOldIndex + 1); + } + } + break; + + case SwFieldTypesEnum::Formel: + { + OUString sId(OUString::number(NUMBERFORMAT_ENTRY_NOT_FOUND)); + int nOldIndex = rWidget.get_selected_index(); + rWidget.insert(0, SwResId(FMT_GETVAR_NAME), &sId, nullptr, nullptr); + if (nOldIndex != -1) + rWidget.select(nOldIndex + 1); + } + break; + + case SwFieldTypesEnum::Get: + { + OUString sId(OUString::number(NUMBERFORMAT_ENTRY_NOT_FOUND)); + int nOldIndex = rWidget.get_selected_index(); + rWidget.insert(0, SwResId(FMT_GETVAR_NAME), &sId, nullptr, nullptr); + if (nOldIndex != -1) + rWidget.select(nOldIndex + 1); + } + break; + + default: break; + } + + if (IsFieldEdit() && bSpecialFormat) + { + if (nTypeId == SwFieldTypesEnum::User && (GetCurField()->GetSubType() & nsSwExtendedSubType::SUB_CMD)) + rWidget.select(1); + else + rWidget.select(0); + } + else + { + if (!nOldNumFormat && (nNumFormatSel = rWidget.find_text(sOldNumSel)) != -1) + rWidget.select(nNumFormatSel); + else if (nOldNumFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + rWidget.select_text(sOldSel); + } + + const sal_uInt16 nSize = GetFieldMgr().GetFormatCount(nTypeId, IsFieldDlgHtmlMode()); + + OUString sSelectId; + + for (sal_uInt16 i = 0; i < nSize; i++) + { + const sal_uInt16 nFieldId = GetFieldMgr().GetFormatId( nTypeId, i ); + OUString sId(OUString::number(nFieldId)); + m_xFormatLB->append(sId, GetFieldMgr().GetFormatStr(nTypeId, i)); + if (IsFieldEdit() && GetCurField() && nFieldId == GetCurField()->GetFormat()) + sSelectId = sId; + } + + m_xFormatLB->thaw(); + if (!sSelectId.isEmpty()) + m_xFormatLB->select_id(sSelectId); + + if (nSize && (!IsFieldEdit() || m_xFormatLB->get_selected_index() == -1)) + { + int nIndex = m_xFormatLB->find_text(sOldSel); + if (nIndex == -1) + nIndex = m_xFormatLB->find_text(SwResId(FMT_NUM_PAGEDESC)); + if (nIndex == -1) + nIndex = m_xFormatLB->find_text(SwResId(FMT_NUM_ARABIC)); + if (nIndex == -1) + nIndex = 0; + m_xFormatLB->select(nIndex); + } +} + +// Modify +IMPL_LINK_NOARG(SwFieldVarPage, ModifyHdl, weld::Entry&, void) +{ + OUString sValue(m_xValueED->get_text()); + bool bHasValue = !sValue.isEmpty(); + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + bool bInsert = false, bApply = false, bDelete = false; + + OUString sName( m_xNameED->get_text() ); + sal_Int32 nLen = sName.getLength(); + + switch( nTypeId ) + { + case SwFieldTypesEnum::DDE: + case SwFieldTypesEnum::User: + case SwFieldTypesEnum::Set: + case SwFieldTypesEnum::Sequence: + SwCalc::IsValidVarName( sName, &sName ); + if ( sName.getLength() != nLen ) + { + nLen = sName.getLength(); + int nStartPos, nEndPos; + m_xNameED->get_selection_bounds(nStartPos, nEndPos); + m_xNameED->set_text( sName ); + m_xNameED->select_region(nStartPos, nEndPos); // restore Cursorpos + } + break; + default: break; + } + + // check buttons + switch (nTypeId) + { + case SwFieldTypesEnum::DDE: + if( nLen ) + { + // is there already a corresponding type + bInsert = bApply = true; + + SwFieldType* pType = GetFieldMgr().GetFieldType(SwFieldIds::Dde, sName); + + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + if(pSh && pType) + bDelete = !pSh->IsUsed( *pType ); + } + break; + + case SwFieldTypesEnum::User: + if( nLen ) + { + // is there already a corresponding type + SwFieldType* pType = GetFieldMgr().GetFieldType(SwFieldIds::User, sName); + + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + if(pSh && pType) + bDelete = !pSh->IsUsed( *pType ); + + pType = GetFieldMgr().GetFieldType(SwFieldIds::SetExp, sName); + if (!pType) // no name conflict with variables + { + // user fields can also be inserted without content! + // Bug #56845 + bInsert = bApply = true; + } + } + break; + + default: + bInsert = true; + + if (nTypeId == SwFieldTypesEnum::Set || nTypeId == SwFieldTypesEnum::Sequence) + { + SwSetExpFieldType* pFieldType = static_cast<SwSetExpFieldType*>( + GetFieldMgr().GetFieldType(SwFieldIds::SetExp, sName)); + + if (pFieldType) + { + + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + if(pSh) + { + const SwFieldTypes* p = pSh->GetDoc()->getIDocumentFieldsAccess().GetFieldTypes(); + sal_uInt16 i; + + for (i = 0; i < INIT_FLDTYPES; i++) + { + SwFieldType* pType = (*p)[ i ].get(); + if (pType == pFieldType) + break; + } + + if (i >= INIT_FLDTYPES && !pSh->IsUsed(*pFieldType)) + bDelete = true; + + if (nTypeId == SwFieldTypesEnum::Sequence && !(pFieldType->GetType() & nsSwGetSetExpType::GSE_SEQ)) + bInsert = false; + + if (nTypeId == SwFieldTypesEnum::Set && (pFieldType->GetType() & nsSwGetSetExpType::GSE_SEQ)) + bInsert = false; + } + } + if (GetFieldMgr().GetFieldType(SwFieldIds::User, sName)) + bInsert = false; + } + + if (!nLen && (nTypeId == SwFieldTypesEnum::Set || nTypeId == SwFieldTypesEnum::Input || + (!IsFieldEdit() && nTypeId == SwFieldTypesEnum::Get ) ) ) + bInsert = false; + + if( (nTypeId == SwFieldTypesEnum::Set || nTypeId == SwFieldTypesEnum::Formel) && + !bHasValue ) + bInsert = false; + break; + } + + m_xNewPB->set_sensitive(bApply); + m_xDelPB->set_sensitive(bDelete); + EnableInsert(bInsert); +} + +IMPL_LINK(SwFieldVarPage, TBClickHdl, weld::Button&, rBox, void) +{ + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + if (&rBox == m_xDelPB.get()) + { + if( nTypeId == SwFieldTypesEnum::User ) + GetFieldMgr().RemoveFieldType(SwFieldIds::User, m_xSelectionLB->get_selected_text()); + else + { + SwFieldIds nWhich; + + switch(nTypeId) + { + case SwFieldTypesEnum::Set: + case SwFieldTypesEnum::Sequence: + nWhich = SwFieldIds::SetExp; + break; + default: + nWhich = SwFieldIds::Dde; + break; + } + + GetFieldMgr().RemoveFieldType(nWhich, m_xSelectionLB->get_selected_text()); + } + + UpdateSubType(); + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + if(pSh) + { + pSh->SetModified(); + } + } + else if (&rBox == m_xNewPB.get()) + { + OUString sName(m_xNameED->get_text()), sValue(m_xValueED->get_text()); + SwFieldType* pType = nullptr; + SwFieldIds nId = SwFieldIds::Database; + sal_Int32 nNumFormatPos = m_xNumFormatLB->get_selected_index(); + + switch (nTypeId) + { + case SwFieldTypesEnum::User: nId = SwFieldIds::User; break; + case SwFieldTypesEnum::DDE: nId = SwFieldIds::Dde; break; + case SwFieldTypesEnum::Set: nId = SwFieldIds::SetExp;break; + default: break; + } + pType = GetFieldMgr().GetFieldType(nId, sName); + + int nFormat = m_xFormatLB->get_selected_index(); + if (nFormat != -1) + nFormat = m_xFormatLB->get_id(nFormat).toUInt32(); + + if (pType) // change + { + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + if(pSh) + { + pSh->StartAllAction(); + + if (nTypeId == SwFieldTypesEnum::User) + { + if (nNumFormatPos != -1) + { + // The first listbox entry is Text and second is + // Formula and both are SAL_MAX_UINT32 :-/ but only if + // not another yet unlisted of Additional Formats was + // selected that may claim the top position :-/ + bool bText = false; + sal_uInt32 nNumberFormat = lcl_getUsedNumFormat( *m_xNumFormatLB, bText); + if (nNumberFormat && nNumberFormat != SAL_MAX_UINT32) + { // Switch language to office-language because calculator expects + // String in office format and it should be fed into dialog like + // that + nNumberFormat = SwValueField::GetSystemFormat(pSh->GetNumberFormatter(), nNumberFormat); + } + static_cast<SwUserFieldType*>(pType)->SetContent(m_xValueED->get_text(), nNumberFormat); + static_cast<SwUserFieldType*>(pType)->SetType( + bText ? nsSwGetSetExpType::GSE_STRING : nsSwGetSetExpType::GSE_EXPR ); + } + } + else + { + if (nFormat != -1) + { + // DDE-Topics/-Items can have blanks in their names! + // That's not being considered here yet. + sal_Int32 nTmpPos = 0; + sValue = sValue.replaceFirst( " ", OUStringChar(sfx2::cTokenSeparator), &nTmpPos ); + sValue = sValue.replaceFirst( " ", OUStringChar(sfx2::cTokenSeparator), &nTmpPos ); + static_cast<SwDDEFieldType*>(pType)->SetCmd(sValue); + static_cast<SwDDEFieldType*>(pType)->SetType(static_cast<SfxLinkUpdateMode>(nFormat)); + } + } + pType->UpdateFields(); + + pSh->EndAllAction(); + } + } + else // new + { + if(nTypeId == SwFieldTypesEnum::User) + { + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + if(pSh) + { + SwUserFieldType aType( pSh->GetDoc(), sName ); + + if (nNumFormatPos != -1) + { + // The first listbox entry is Text and second is + // Formula and both are SAL_MAX_UINT32 :-/ but only if + // not another yet unlisted of Additional Formats was + // selected that may claim the top position :-/ + bool bText = false; + sal_uInt32 nNumberFormat = lcl_getUsedNumFormat( *m_xNumFormatLB, bText); + aType.SetType(bText ? nsSwGetSetExpType::GSE_STRING : nsSwGetSetExpType::GSE_EXPR); + aType.SetContent( sValue, nNumberFormat ); + m_xSelectionLB->append_text(sName); + m_xSelectionLB->select_text(sName); + GetFieldMgr().InsertFieldType( aType ); // Userfld new + } + } + } + else + { + if (nFormat != -1) + { + // DDE-Topics/-Items can have blanks in their names! + // That's not being considered here yet. + sal_Int32 nTmpPos = 0; + sValue = sValue.replaceFirst( " ", OUStringChar(sfx2::cTokenSeparator), &nTmpPos ); + sValue = sValue.replaceFirst( " ", OUStringChar(sfx2::cTokenSeparator), &nTmpPos ); + + SwDDEFieldType aType(sName, sValue, static_cast<SfxLinkUpdateMode>(nFormat)); + m_xSelectionLB->append_text(sName); + m_xSelectionLB->select_text(sName); + GetFieldMgr().InsertFieldType(aType); // DDE-Field new + } + } + } + if (IsFieldEdit()) + GetFieldMgr().GetCurField(); // update FieldManager + + UpdateSubType(); + } +} + +IMPL_LINK_NOARG(SwFieldVarPage, ChapterHdl, weld::ComboBox&, void) +{ + bool bEnable = m_xChapterLevelLB->get_active() != 0; + + m_xSeparatorED->set_sensitive(bEnable); + m_xSeparatorFT->set_sensitive(bEnable); + SeparatorHdl(*m_xSeparatorED); +} + +IMPL_LINK_NOARG(SwFieldVarPage, SeparatorHdl, weld::Entry&, void) +{ + bool bEnable = !m_xSeparatorED->get_text().isEmpty() || + m_xChapterLevelLB->get_active() == 0; + EnableInsert(bEnable); +} + +bool SwFieldVarPage::FillItemSet(SfxItemSet* ) +{ + const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32()); + + OUString aVal(m_xValueED->get_text()); + OUString aName(m_xNameED->get_text()); + + const sal_Int32 nSubPos = m_xSelectionLB->get_selected_index(); + sal_uInt16 nSubType = (nSubPos == -1) ? 0 : m_xSelectionLB->get_id(nSubPos).toUInt32(); + + sal_uInt32 nFormat; + + if (!m_xNumFormatLB->get_visible()) + { + sal_Int32 nFormatPos = m_xFormatLB->get_selected_index(); + + if(nFormatPos == -1) + nFormat = 0; + else + nFormat = m_xFormatLB->get_id(nFormatPos).toUInt32(); + } + else + { + nFormat = m_xNumFormatLB->GetFormat(); + + if (nFormat && nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND && m_xNumFormatLB->IsAutomaticLanguage()) + { + // Switch language to office language because calculator expects + // String in office format and it should be fed into the dialog + // like that + SwWrtShell *pSh = GetWrtShell(); + if(!pSh) + pSh = ::GetActiveWrtShell(); + if(pSh) + { + nFormat = SwValueField::GetSystemFormat(pSh->GetNumberFormatter(), nFormat); + } + } + } + sal_Unicode cSeparator = ' '; + switch (nTypeId) + { + case SwFieldTypesEnum::User: + { + nSubType = (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) ? nsSwGetSetExpType::GSE_STRING : nsSwGetSetExpType::GSE_EXPR; + + if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND && m_xNumFormatLB->get_selected_text() == SwResId(FMT_USERVAR_CMD)) + nSubType |= nsSwExtendedSubType::SUB_CMD; + + if (m_xInvisibleCB->get_active()) + nSubType |= nsSwExtendedSubType::SUB_INVISIBLE; + break; + } + case SwFieldTypesEnum::Formel: + { + nSubType = nsSwGetSetExpType::GSE_FORMULA; + if (m_xNumFormatLB->get_visible() && nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + nSubType |= nsSwExtendedSubType::SUB_CMD; + break; + } + case SwFieldTypesEnum::Get: + { + nSubType &= 0xff00; + if (m_xNumFormatLB->get_visible() && nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + nSubType |= nsSwExtendedSubType::SUB_CMD; + break; + } + case SwFieldTypesEnum::Input: + { + SwFieldType* pType = GetFieldMgr().GetFieldType(SwFieldIds::User, aName); + nSubType = static_cast< sal_uInt16 >((nSubType & 0xff00) | (pType ? INP_USR : INP_VAR)); + break; + } + + case SwFieldTypesEnum::Set: + { + if (IsFieldDlgHtmlMode()) + { + nSubType = 0x0100; + nSubType = (nSubType & 0xff00) | nsSwGetSetExpType::GSE_STRING; + } + else + nSubType = (nSubType & 0xff00) | ((nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) ? nsSwGetSetExpType::GSE_STRING : nsSwGetSetExpType::GSE_EXPR); + + if (m_xInvisibleCB->get_active()) + nSubType |= nsSwExtendedSubType::SUB_INVISIBLE; + break; + } + case SwFieldTypesEnum::Sequence: + { + nSubType = static_cast< sal_uInt16 >(m_xChapterLevelLB->get_active()); + if (nSubType == 0) + nSubType = 0x7f; + else + { + nSubType--; + OUString sSeparator(m_xSeparatorED->get_text()[0]); + cSeparator = !sSeparator.isEmpty() ? sSeparator[0] : ' '; + } + break; + } + case SwFieldTypesEnum::GetRefPage: + if( SVX_NUM_CHAR_SPECIAL == nFormat ) + aVal = m_xValueED->get_text(); + break; + default: break; + } + + if (!IsFieldEdit() || + m_xNameED->get_value_changed_from_saved() || + m_xValueED->get_value_changed_from_saved() || + m_xSelectionLB->get_value_changed_from_saved() || + m_xFormatLB->get_value_changed_from_saved() || + m_nOldFormat != m_xNumFormatLB->GetFormat() || + m_xInvisibleCB->get_state_changed_from_saved() || + m_xChapterLevelLB->get_value_changed_from_saved() || + m_xSeparatorED->get_value_changed_from_saved()) + { + InsertField( nTypeId, nSubType, aName, aVal, nFormat, + cSeparator, m_xNumFormatLB->IsAutomaticLanguage() ); + } + + UpdateSubType(); + + return false; +} + +std::unique_ptr<SfxTabPage> SwFieldVarPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet *const pAttrSet) +{ + return std::make_unique<SwFieldVarPage>( pPage, pController, pAttrSet ); +} + +sal_uInt16 SwFieldVarPage::GetGroup() +{ + return GRP_VAR; +} + +void SwFieldVarPage::FillUserData() +{ + OUString sData = USER_DATA_VERSION ";"; + sal_Int32 nTypeSel = m_xTypeLB->get_selected_index(); + if( -1 == nTypeSel ) + nTypeSel = USHRT_MAX; + else + nTypeSel = m_xTypeLB->get_id(nTypeSel).toUInt32(); + sData += OUString::number( nTypeSel ); + SetUserData(sData); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/fldvar.hxx b/sw/source/ui/fldui/fldvar.hxx new file mode 100644 index 0000000000..3eedfbf2cc --- /dev/null +++ b/sw/source/ui/fldui/fldvar.hxx @@ -0,0 +1,84 @@ +/* -*- 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_FLDUI_FLDVAR_HXX +#define INCLUDED_SW_SOURCE_UI_FLDUI_FLDVAR_HXX + +#include <sfx2/tabdlg.hxx> + +#include "fldpage.hxx" +#include <condedit.hxx> +#include <numfmtlb.hxx> + +class SwFieldVarPage; + +class SwFieldVarPage : public SwFieldPage +{ + std::unique_ptr<weld::TreeView> m_xTypeLB; + std::unique_ptr<weld::Widget> m_xSelection; + std::unique_ptr<weld::TreeView> m_xSelectionLB; + std::unique_ptr<weld::Label> m_xNameFT; + std::unique_ptr<weld::Entry> m_xNameED; + std::unique_ptr<weld::Label> m_xValueFT; + std::unique_ptr<ConditionEdit> m_xValueED; + std::unique_ptr<weld::Widget> m_xFormat; + std::unique_ptr<SwNumFormatTreeView> m_xNumFormatLB; + std::unique_ptr<weld::TreeView> m_xFormatLB; + std::unique_ptr<weld::Widget> m_xChapterFrame; + std::unique_ptr<weld::ComboBox> m_xChapterLevelLB; + std::unique_ptr<weld::CheckButton> m_xInvisibleCB; + std::unique_ptr<weld::Label> m_xSeparatorFT; + std::unique_ptr<weld::Entry> m_xSeparatorED; + std::unique_ptr<weld::Button> m_xNewPB; + std::unique_ptr<weld::Button> m_xDelPB; + + OUString m_sOldValueFT; + OUString m_sOldNameFT; + + sal_uInt32 m_nOldFormat; + bool m_bInit; + + DECL_LINK( TypeHdl, weld::TreeView&, void ); + DECL_LINK( SubTypeListBoxHdl, weld::TreeView&, void ); + DECL_LINK( ModifyHdl, weld::Entry&, void ); + DECL_LINK( TBClickHdl, weld::Button&, void ); + DECL_LINK( ChapterHdl, weld::ComboBox&, void ); + DECL_LINK( SeparatorHdl, weld::Entry&, void ); + DECL_LINK( SubTypeInsertHdl, weld::TreeView&, bool ); + void SubTypeHdl(const weld::TreeView*); + + void UpdateSubType(); + void FillFormatLB(SwFieldTypesEnum nTypeId); + +protected: + virtual sal_uInt16 GetGroup() override; + +public: + SwFieldVarPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pSet); + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + virtual ~SwFieldVarPage() override; + + virtual bool FillItemSet( SfxItemSet* rSet ) override; + virtual void Reset( const SfxItemSet* rSet ) override; + + virtual void FillUserData() override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/inpdlg.cxx b/sw/source/ui/fldui/inpdlg.cxx new file mode 100644 index 0000000000..f5ed2c33e9 --- /dev/null +++ b/sw/source/ui/fldui/inpdlg.cxx @@ -0,0 +1,176 @@ +/* -*- 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/lineend.hxx> +#include <unotools/charclass.hxx> +#include <wrtsh.hxx> +#include <fldbas.hxx> +#include <expfld.hxx> +#include <usrfld.hxx> +#include <inpdlg.hxx> + +// edit field-insert +SwFieldInputDlg::SwFieldInputDlg(weld::Widget *pParent, SwWrtShell &rS, + SwField* pField, bool bPrevButton, bool bNextButton) + : GenericDialogController(pParent, "modules/swriter/ui/inputfielddialog.ui", "InputFieldDialog") + , m_rSh( rS ) + , m_pInpField(nullptr) + , m_pSetField(nullptr) + , m_pUsrType(nullptr) + , m_pPressedButton(nullptr) + , m_xLabelED(m_xBuilder->weld_entry("name")) + , m_xEditED(m_xBuilder->weld_text_view("text")) + , m_xPrevBT(m_xBuilder->weld_button("prev")) + , m_xNextBT(m_xBuilder->weld_button("next")) + , m_xOKBT(m_xBuilder->weld_button("ok")) +{ + m_xEditED->set_size_request(-1, m_xEditED->get_height_rows(8)); + + if( bPrevButton || bNextButton ) + { + m_xPrevBT->show(); + m_xPrevBT->connect_clicked(LINK(this, SwFieldInputDlg, PrevHdl)); + m_xPrevBT->set_sensitive(bPrevButton); + + m_xNextBT->show(); + m_xNextBT->connect_clicked(LINK(this, SwFieldInputDlg, NextHdl)); + m_xNextBT->set_sensitive(bNextButton); + } + + // evaluation here + OUString aStr; + if( SwFieldIds::Input == pField->GetTyp()->Which() ) + { // it is an input field + + m_pInpField = static_cast<SwInputField*>(pField); + m_xLabelED->set_text(m_pInpField->GetPar2()); + sal_uInt16 nSubType = m_pInpField->GetSubType(); + + switch(nSubType & 0xff) + { + case INP_TXT: + aStr = m_pInpField->GetPar1(); + break; + + case INP_USR: + // user field + m_pUsrType = static_cast<SwUserFieldType*>(m_rSh.GetFieldType( + SwFieldIds::User, m_pInpField->GetPar1() )); + if( nullptr != m_pUsrType ) + aStr = m_pUsrType->GetContent(); + break; + } + } + else + { + // it is a SetExpression + m_pSetField = static_cast<SwSetExpField*>(pField); + OUString sFormula(m_pSetField->GetFormula()); + //values are formatted - formulas are not + CharClass aCC( LanguageTag( m_pSetField->GetLanguage() )); + if( aCC.isNumeric( sFormula )) + { + aStr = m_pSetField->ExpandField(true, rS.GetLayout()); + } + else + aStr = sFormula; + m_xLabelED->set_text(m_pSetField->GetPromptText()); + } + + // JP 31.3.00: Inputfields in readonly regions must be allowed to + // input any content. - 74639 + bool bEnable = !m_rSh.IsCursorReadonly(); + + m_xOKBT->set_sensitive( bEnable ); + m_xEditED->set_editable( bEnable ); + + if( !aStr.isEmpty() ) + m_xEditED->set_text(convertLineEnd(aStr, GetSystemLineEnd())); + m_xEditED->grab_focus(); + + // preselect all text to allow quickly changing the content + if (bEnable) + m_xEditED->select_region(0, -1); +} + +SwFieldInputDlg::~SwFieldInputDlg() +{ +} + +// Close +void SwFieldInputDlg::Apply() +{ + OUString aTmp = m_xEditED->get_text().replaceAll("\r", ""); + m_rSh.StartAllAction(); + bool bModified = false; + if(m_pInpField) + { + if(m_pUsrType) + { + if( aTmp != m_pUsrType->GetContent() ) + { + m_pUsrType->SetContent(aTmp); + m_pUsrType->UpdateFields(); + bModified = true; + } + } + else if( aTmp != m_pInpField->GetPar1() ) + { + m_pInpField->SetPar1(aTmp); + m_rSh.SwEditShell::UpdateOneField(*m_pInpField); + bModified = true; + } + } + else if( aTmp != m_pSetField->GetPar2()) + { + m_pSetField->SetPar2(aTmp); + m_rSh.SwEditShell::UpdateOneField(*m_pSetField); + bModified = true; + } + + if( bModified ) + m_rSh.SetUndoNoResetModified(); + + m_rSh.EndAllAction(); +} + +bool SwFieldInputDlg::PrevButtonPressed() const +{ + return m_pPressedButton == m_xPrevBT.get(); +} + +bool SwFieldInputDlg::NextButtonPressed() const +{ + return m_pPressedButton == m_xNextBT.get(); +} + +IMPL_LINK_NOARG(SwFieldInputDlg, PrevHdl, weld::Button&, void) +{ + m_pPressedButton = m_xPrevBT.get(); + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(SwFieldInputDlg, NextHdl, weld::Button&, void) +{ + m_pPressedButton = m_xNextBT.get(); + m_xDialog->response(RET_OK); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fldui/javaedit.cxx b/sw/source/ui/fldui/javaedit.cxx new file mode 100644 index 0000000000..b13c9828d8 --- /dev/null +++ b/sw/source/ui/fldui/javaedit.cxx @@ -0,0 +1,253 @@ +/* -*- 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 <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <svl/urihelper.hxx> +#include <view.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/filedlghelper.hxx> +#include <docsh.hxx> +#include <wrtsh.hxx> +#include <fldbas.hxx> +#include <fldmgr.hxx> +#include <docufld.hxx> +#include <javaedit.hxx> + +#include <strings.hrc> + +using namespace ::com::sun::star; + +SwJavaEditDialog::SwJavaEditDialog(weld::Window* pParent, SwWrtShell* pWrtSh) + : GenericDialogController(pParent, "modules/swriter/ui/insertscript.ui", "InsertScriptDialog") + , m_bNew(true) + , m_bIsUrl(false) + , m_pSh(pWrtSh) + , m_xTypeED(m_xBuilder->weld_entry("scripttype")) + , m_xUrlRB(m_xBuilder->weld_radio_button("url")) + , m_xEditRB(m_xBuilder->weld_radio_button("text")) + , m_xUrlPB(m_xBuilder->weld_button("browse")) + , m_xUrlED(m_xBuilder->weld_entry("urlentry")) + , m_xEditED(m_xBuilder->weld_text_view("textentry")) + , m_xOKBtn(m_xBuilder->weld_button("ok")) + , m_xPrevBtn(m_xBuilder->weld_button("previous")) + , m_xNextBtn(m_xBuilder->weld_button("next")) +{ + // install handler + m_xPrevBtn->connect_clicked( LINK( this, SwJavaEditDialog, PrevHdl ) ); + m_xNextBtn->connect_clicked( LINK( this, SwJavaEditDialog, NextHdl ) ); + m_xOKBtn->connect_clicked( LINK( this, SwJavaEditDialog, OKHdl ) ); + + Link<weld::Toggleable&,void> aLk = LINK(this, SwJavaEditDialog, RadioButtonHdl); + m_xUrlRB->connect_toggled(aLk); + m_xEditRB->connect_toggled(aLk); + m_xUrlPB->connect_clicked(LINK(this, SwJavaEditDialog, InsertFileHdl)); + + m_pMgr.reset(new SwFieldMgr(m_pSh)); + m_pField = static_cast<SwScriptField*>(m_pMgr->GetCurField()); + + m_bNew = !(m_pField && m_pField->GetTyp()->Which() == SwFieldIds::Script); + + CheckTravel(); + + if (!m_bNew) + m_xDialog->set_title(SwResId(STR_JAVA_EDIT)); + + UpdateFromRadioButtons(); +} + +SwJavaEditDialog::~SwJavaEditDialog() +{ + m_pSh->EnterStdMode(); + m_pMgr.reset(); + m_pFileDlg.reset(); +} + +IMPL_LINK_NOARG(SwJavaEditDialog, PrevHdl, weld::Button&, void) +{ + m_pSh->EnterStdMode(); + + SetField(); + m_pMgr->GoPrev(); + m_pField = static_cast<SwScriptField*>(m_pMgr->GetCurField()); + CheckTravel(); + UpdateFromRadioButtons(); +} + +IMPL_LINK_NOARG(SwJavaEditDialog, NextHdl, weld::Button&, void) +{ + m_pSh->EnterStdMode(); + + SetField(); + m_pMgr->GoNext(); + m_pField = static_cast<SwScriptField*>(m_pMgr->GetCurField()); + CheckTravel(); + UpdateFromRadioButtons(); +} + +IMPL_LINK_NOARG(SwJavaEditDialog, OKHdl, weld::Button&, void) +{ + SetField(); + m_xDialog->response(RET_OK); +} + +void SwJavaEditDialog::CheckTravel() +{ + bool bTravel = false; + bool bNext(false), bPrev(false); + + if (!m_bNew) + { + // Traveling only when more than one field + m_pSh->StartAction(); + m_pSh->CreateCursor(); + + bNext = m_pMgr->GoNext(); + if( bNext ) + m_pMgr->GoPrev(); + + bPrev = m_pMgr->GoPrev(); + if( bPrev ) + m_pMgr->GoNext(); + bTravel |= bNext || bPrev; + + m_pSh->DestroyCursor(); + m_pSh->EndAction(); + + if (m_pField->IsCodeURL()) + { + OUString sURL(m_pField->GetPar2()); + if(!sURL.isEmpty()) + { + INetURLObject aINetURL(sURL); + if(INetProtocol::File == aINetURL.GetProtocol()) + sURL = aINetURL.PathToFileName(); + } + m_xUrlED->set_text(sURL); + m_xEditED->set_text(OUString()); + m_xUrlRB->set_active(true); + } + else + { + m_xEditED->set_text(m_pField->GetPar2()); + m_xUrlED->set_text(OUString()); + m_xEditRB->set_active(true); + } + m_xTypeED->set_text(m_pField->GetPar1()); + } + + if ( !bTravel ) + { + m_xPrevBtn->hide(); + m_xNextBtn->hide(); + } + else + { + m_xPrevBtn->set_sensitive(bPrev); + m_xNextBtn->set_sensitive(bNext); + } +} + +void SwJavaEditDialog::SetField() +{ + if( !m_xOKBtn->get_sensitive() ) + return ; + + m_aType = m_xTypeED->get_text(); + m_bIsUrl = m_xUrlRB->get_active(); + + if (m_bIsUrl) + { + m_aText = m_xUrlED->get_text(); + if (!m_aText.isEmpty()) + { + SfxMedium* pMedium = m_pSh->GetView().GetDocShell()->GetMedium(); + INetURLObject aAbs; + if( pMedium ) + aAbs = pMedium->GetURLObject(); + + m_aText = URIHelper::SmartRel2Abs( + aAbs, m_aText, URIHelper::GetMaybeFileHdl()); + } + } + else + m_aText = m_xEditED->get_text(); + + if (m_aType.isEmpty()) + m_aType = "JavaScript"; +} + +bool SwJavaEditDialog::IsUpdate() const +{ + return m_pField && ( sal_uInt32(m_bIsUrl ? 1 : 0) != m_pField->GetFormat() || m_pField->GetPar2() != m_aType || m_pField->GetPar1() != m_aText ); +} + +IMPL_LINK(SwJavaEditDialog, RadioButtonHdl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + UpdateFromRadioButtons(); +} + +void SwJavaEditDialog::UpdateFromRadioButtons() +{ + bool bEnable = m_xUrlRB->get_active(); + m_xUrlPB->set_sensitive(bEnable); + m_xUrlED->set_sensitive(bEnable); + m_xEditED->set_sensitive(!bEnable); + + if (!m_bNew) + { + bEnable = !m_pSh->IsReadOnlyAvailable() || !m_pSh->HasReadonlySel(); + m_xOKBtn->set_sensitive(bEnable); + m_xUrlED->set_editable(bEnable); + m_xEditED->set_editable(bEnable); + m_xTypeED->set_editable(bEnable); + if( m_xUrlPB->get_sensitive() && !bEnable ) + m_xUrlPB->set_sensitive( false ); + } +} + +IMPL_LINK_NOARG( SwJavaEditDialog, InsertFileHdl, weld::Button&, void ) +{ + if (!m_pFileDlg) + { + m_pFileDlg.reset(new ::sfx2::FileDialogHelper( + ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::Insert, "swriter", SfxFilterFlags::NONE, SfxFilterFlags::NONE, m_xDialog.get())); + } + m_pFileDlg->SetContext(sfx2::FileDialogHelper::WriterInsertScript); + m_pFileDlg->StartExecuteModal( LINK( this, SwJavaEditDialog, DlgClosedHdl ) ); +} + +IMPL_LINK_NOARG(SwJavaEditDialog, DlgClosedHdl, sfx2::FileDialogHelper *, void) +{ + if (m_pFileDlg->GetError() == ERRCODE_NONE) + { + OUString sFileName = m_pFileDlg->GetPath(); + if ( !sFileName.isEmpty() ) + { + INetURLObject aINetURL( sFileName ); + if ( INetProtocol::File == aINetURL.GetProtocol() ) + sFileName = aINetURL.PathToFileName(); + } + m_xUrlED->set_text(sFileName); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/fmtui/tmpdlg.cxx b/sw/source/ui/fmtui/tmpdlg.cxx new file mode 100644 index 0000000000..0a5d6686da --- /dev/null +++ b/sw/source/ui/fmtui/tmpdlg.cxx @@ -0,0 +1,542 @@ +/* -*- 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 <sfx2/viewfrm.hxx> +#include <svx/hdft.hxx> +#include <editeng/flstitem.hxx> +#include <osl/diagnose.h> +#include <sfx2/htmlmode.hxx> +#include <sfx2/sfxdlg.hxx> +#include <svl/cjkoptions.hxx> +#include <vcl/svapp.hxx> +#include <numpara.hxx> +#include <swmodule.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <wdocsh.hxx> +#include <viewopt.hxx> +#include <pgfnote.hxx> +#include <pggrid.hxx> +#include <tmpdlg.hxx> +#include <column.hxx> +#include <drpcps.hxx> +#include <frmpage.hxx> +#include <wrap.hxx> +#include <swuiccoll.hxx> +#include <docstyle.hxx> +#include <fmtcol.hxx> +#include <macassgn.hxx> +#include <poolfmt.hxx> +#include <uitool.hxx> +#include <shellres.hxx> +#include <strings.hrc> + +#include <cmdid.h> +#include <SwStyleNameMapper.hxx> +#include <svl/stritem.hxx> +#include <svl/slstitm.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svx/dialogs.hrc> +#include <svx/flagsdef.hxx> +#include <officecfg/Office/Common.hxx> + +// the dialog's carrier +SwTemplateDlgController::SwTemplateDlgController(weld::Window* pParent, + SfxStyleSheetBase& rBase, + SfxStyleFamily nRegion, + const OUString& sPage, + SwWrtShell* pActShell, + bool bNew) + : SfxStyleDialogController(pParent, + "modules/swriter/ui/templatedialog" + + OUString::number(static_cast<sal_uInt16>(nRegion)) + ".ui", + "TemplateDialog" + OUString::number(static_cast<sal_uInt16>(nRegion)), + rBase) + , m_nType(nRegion) + , m_pWrtShell(pActShell) + , m_bNewStyle(bNew) +{ + m_nHtmlMode = ::GetHtmlMode(m_pWrtShell->GetView().GetDocShell()); + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + + GetStandardButton()->set_label(SwResId(STR_STANDARD_LABEL)); + GetStandardButton()->set_tooltip_text(SwResId(STR_STANDARD_TOOLTIP)); + GetStandardButton()->set_accessible_description(SwResId(STR_STANDARD_EXTENDEDTIP)); + + GetApplyButton()->set_label(SwResId(STR_APPLY_LABEL)); + GetApplyButton()->set_tooltip_text(SwResId(STR_APPLY_TOOLTIP)); + GetApplyButton()->set_accessible_description(SwResId(STR_APPLY_EXTENDEDTIP)); + + GetResetButton()->set_label(SwResId(STR_RESET_LABEL)); + GetResetButton()->set_tooltip_text(SwResId(STR_RESET_TOOLTIP)); + GetResetButton()->set_accessible_description(SwResId(STR_RESET_EXTENDEDTIP)); + + // stitch TabPages together + switch( nRegion ) + { + // character styles + case SfxStyleFamily::Char: + { + AddTabPage("font", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_NAME ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_CHAR_NAME )); + AddTabPage("fonteffect", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_EFFECTS ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_CHAR_EFFECTS )); + AddTabPage("position", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_POSITION ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_CHAR_POSITION )); + AddTabPage("asianlayout", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_TWOLINES ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_CHAR_TWOLINES )); + AddTabPage("background", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BKG ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_BKG )); + AddTabPage("borders", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BORDER ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_BORDER )); + if(m_nHtmlMode & HTMLMODE_ON || !SvtCJKOptions::IsDoubleLinesEnabled()) + RemoveTabPage("asianlayout"); + } + break; + // paragraph styles + case SfxStyleFamily::Para: + { + AddTabPage("indents", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_STD_PARAGRAPH), pFact->GetTabPageRangesFunc(RID_SVXPAGE_STD_PARAGRAPH)); + + AddTabPage("alignment", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_ALIGN_PARAGRAPH), pFact->GetTabPageRangesFunc(RID_SVXPAGE_ALIGN_PARAGRAPH)); + + AddTabPage("textflow", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_EXT_PARAGRAPH), pFact->GetTabPageRangesFunc(RID_SVXPAGE_EXT_PARAGRAPH) ); + + AddTabPage("asiantypo", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_PARA_ASIAN), pFact->GetTabPageRangesFunc(RID_SVXPAGE_PARA_ASIAN) ); + + AddTabPage("font", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_NAME ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_CHAR_NAME ) ); + + AddTabPage("fonteffect", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_EFFECTS ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_CHAR_EFFECTS ) ); + + AddTabPage("position", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_POSITION ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_CHAR_POSITION ) ); + + AddTabPage("asianlayout", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_TWOLINES ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_CHAR_TWOLINES ) ); + + AddTabPage("highlighting", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BKG ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_BKG )); + + AddTabPage("tabs", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_TABULATOR), pFact->GetTabPageRangesFunc(RID_SVXPAGE_TABULATOR) ); + + AddTabPage("outline", SwParagraphNumTabPage::Create, SwParagraphNumTabPage::GetRanges); + AddTabPage("dropcaps", SwDropCapsPage::Create, SwDropCapsPage::GetRanges ); + + // add Area and Transparence TabPages + AddTabPage("area", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_AREA ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_AREA )); + AddTabPage("transparence", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_TRANSPARENCE ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_TRANSPARENCE ) ); + + AddTabPage("borders", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BORDER ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_BORDER ) ); + + AddTabPage("condition", SwCondCollPage::Create, + SwCondCollPage::GetRanges ); + if( (!m_bNewStyle && RES_CONDTXTFMTCOLL != static_cast<SwDocStyleSheet&>(rBase).GetCollection()->Which()) + || m_nHtmlMode & HTMLMODE_ON ) + RemoveTabPage("condition"); + + if(m_nHtmlMode & HTMLMODE_ON) + { + if (!officecfg::Office::Common::Filter::HTML::Export::PrintLayout::get()) + RemoveTabPage("textflow"); + RemoveTabPage("asiantypo"); + RemoveTabPage("tabs"); + RemoveTabPage("outline"); + RemoveTabPage("asianlayout"); + if(!(m_nHtmlMode & HTMLMODE_FULL_STYLES)) + { + RemoveTabPage("background"); + RemoveTabPage("dropcaps"); + } + } + else + { + if(!SvtCJKOptions::IsAsianTypographyEnabled()) + RemoveTabPage("asiantypo"); + if(!SvtCJKOptions::IsDoubleLinesEnabled()) + RemoveTabPage("asianlayout"); + } + } + break; + // page styles + case SfxStyleFamily::Page: + { + // add Area and Transparence TabPages + AddTabPage("area", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_AREA ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_AREA )); + AddTabPage("transparence", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_TRANSPARENCE ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_TRANSPARENCE ) ); + AddTabPage("header", SvxHeaderPage::Create, SvxHeaderPage::GetRanges); + AddTabPage("footer", SvxFooterPage::Create, SvxFooterPage::GetRanges); + AddTabPage("page", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_PAGE), pFact->GetTabPageRangesFunc(RID_SVXPAGE_PAGE)); + if (0 == ::GetHtmlMode(m_pWrtShell->GetView().GetDocShell())) + { + AddTabPage("borders", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BORDER ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_BORDER ) ); + AddTabPage("columns", SwColumnPage::Create, SwColumnPage::GetRanges ); + AddTabPage("footnotes", SwFootNotePage::Create, SwFootNotePage::GetRanges ); + AddTabPage("textgrid", SwTextGridPage::Create, SwTextGridPage::GetRanges ); + if(!SvtCJKOptions::IsAsianTypographyEnabled()) + RemoveTabPage("textgrid"); + } + else + { + RemoveTabPage("borders"); + RemoveTabPage("columns"); + RemoveTabPage("footnotes"); + RemoveTabPage("textgrid"); + } + } + break; + // numbering styles + case SfxStyleFamily::Pseudo: + { + AddTabPage("numbering", RID_SVXPAGE_PICK_SINGLE_NUM); + AddTabPage("bullets", RID_SVXPAGE_PICK_BULLET); + AddTabPage("outline", RID_SVXPAGE_PICK_NUM); + AddTabPage("graphics", RID_SVXPAGE_PICK_BMP); + AddTabPage("customize", RID_SVXPAGE_NUM_OPTIONS ); + AddTabPage("position", RID_SVXPAGE_NUM_POSITION ); + } + break; + case SfxStyleFamily::Frame: + { + AddTabPage("type", SwFramePage::Create, SwFramePage::GetRanges); + AddTabPage("options", SwFrameAddPage::Create, SwFrameAddPage::GetRanges); + AddTabPage("wrap", SwWrapTabPage::Create, SwWrapTabPage::GetRanges); + + // add Area and Transparence TabPages + AddTabPage("area", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_AREA ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_AREA )); + AddTabPage("transparence", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_TRANSPARENCE ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_TRANSPARENCE ) ); + + AddTabPage("borders", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BORDER ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_BORDER ) ); + + AddTabPage("columns", SwColumnPage::Create, SwColumnPage::GetRanges ); + + AddTabPage("macros", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_MACROASSIGN), nullptr); + } + break; + default: + OSL_ENSURE(false, "wrong family"); + } + + if (bNew) + SetCurPageId("organizer"); + else if (!sPage.isEmpty()) + SetCurPageId(sPage); +} + +short SwTemplateDlgController::Ok() +{ + short nRet = SfxTabDialogController::Ok(); + if( RET_OK == nRet ) + { + const SfxPoolItem *pOutItem, *pExItem; + if( SfxItemState::SET == m_xExampleSet->GetItemState( + SID_ATTR_NUMBERING_RULE, false, &pExItem ) && + ( !GetOutputItemSet() || + SfxItemState::SET != GetOutputItemSet()->GetItemState( + SID_ATTR_NUMBERING_RULE, false, &pOutItem ) || + *pExItem != *pOutItem )) + { + if( GetOutputItemSet() ) + const_cast<SfxItemSet*>(GetOutputItemSet())->Put( *pExItem ); + else + nRet = RET_CANCEL; + } + } + else + { + //JP 09.01.98 Bug #46446#: + // that's the Ok-Handler, so OK has to be default! + nRet = RET_OK; + } + return nRet; +} + +void SwTemplateDlgController::RefreshInputSet() +{ + SfxItemSet* pInSet = GetInputSetImpl(); + pInSet->ClearItem(); + pInSet->SetParent( &GetStyleSheet().GetItemSet() ); +} + +void SwTemplateDlgController::PageCreated(const OUString& rId, SfxTabPage &rPage ) +{ + // set style's and metric's names + OUString sNumCharFormat, sBulletCharFormat; + SwStyleNameMapper::FillUIName( RES_POOLCHR_NUM_LEVEL, sNumCharFormat); + SwStyleNameMapper::FillUIName( RES_POOLCHR_BULLET_LEVEL, sBulletCharFormat); + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + + if (rId == "font") + { + if (SwView* pView = GetActiveView()) + { + SvxFontListItem aFontListItem( *static_cast<const SvxFontListItem*>(pView-> + GetDocShell()->GetItem( SID_ATTR_CHAR_FONTLIST ) ) ); + + aSet.Put (SvxFontListItem( aFontListItem.GetFontList(), SID_ATTR_CHAR_FONTLIST)); + sal_uInt32 nFlags = 0; + if(rPage.GetItemSet().GetParent() && 0 == (m_nHtmlMode & HTMLMODE_ON )) + nFlags = SVX_RELATIVE_MODE; + if( SfxStyleFamily::Char == m_nType ) + nFlags = nFlags|SVX_PREVIEW_CHARACTER; + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE, nFlags)); + rPage.PageCreated(aSet); + } + } + else if (rId == "fonteffect") + { + sal_uInt32 nFlags = SVX_ENABLE_CHAR_TRANSPARENCY; + if( SfxStyleFamily::Char == m_nType ) + nFlags = nFlags|SVX_PREVIEW_CHARACTER; + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE, nFlags)); + rPage.PageCreated(aSet); + } + else if (rId == "position") + { + if( SfxStyleFamily::Char == m_nType ) + { + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE, SVX_PREVIEW_CHARACTER)); + rPage.PageCreated(aSet); + } + else if (SfxStyleFamily::Pseudo == m_nType) + { + if (SwWrtShell* pSh = ::GetActiveWrtShell()) + { + SwDocShell* pDocShell = pSh->GetView().GetDocShell(); + FieldUnit eMetric = ::GetDfltMetric(dynamic_cast<SwWebDocShell*>( pDocShell) != nullptr ); + + aSet.Put ( SfxUInt16Item(SID_METRIC_ITEM, static_cast< sal_uInt16 >(eMetric))); + rPage.PageCreated(aSet); + } + } + } + else if (rId == "columns") + { + if( m_nType == SfxStyleFamily::Frame ) + static_cast<SwColumnPage&>(rPage).SetFrameMode(true); + static_cast<SwColumnPage&>(rPage).SetFormatUsed( true ); + } + // do not remove; many other style dialog combinations still use the SfxTabPage + // for the SvxBrushItem (see RID_SVXPAGE_BKG) + else if (rId == "background" || rId == "highlighting") + { + SvxBackgroundTabFlags nFlagType = SvxBackgroundTabFlags::NONE; + if( SfxStyleFamily::Char == m_nType || SfxStyleFamily::Para == m_nType ) + nFlagType |= SvxBackgroundTabFlags::SHOW_HIGHLIGHTING; + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE, static_cast<sal_uInt32>(nFlagType))); + rPage.PageCreated(aSet); + } + else if (rId == "condition") + { + static_cast<SwCondCollPage&>(rPage).SetCollection( + static_cast<SwDocStyleSheet&>(GetStyleSheet()).GetCollection() ); + } + else if (rId == "page") + { + if(0 == (m_nHtmlMode & HTMLMODE_ON )) + { + std::vector<OUString> aList; + OUString aNew; + SwStyleNameMapper::FillUIName( RES_POOLCOLL_TEXT, aNew ); + aList.push_back( aNew ); + if( m_pWrtShell ) + { + SfxStyleSheetBasePool* pStyleSheetPool = m_pWrtShell-> + GetView().GetDocShell()->GetStyleSheetPool(); + SfxStyleSheetBase *pFirstStyle = pStyleSheetPool->First(SfxStyleFamily::Para); + while(pFirstStyle) + { + aList.push_back( pFirstStyle->GetName() ); + pFirstStyle = pStyleSheetPool->Next(); + } + } + // set DrawingLayer FillStyles active + aSet.Put(SfxBoolItem(SID_DRAWINGLAYER_FILLSTYLES, true)); + aSet.Put(SfxStringListItem(SID_COLLECT_LIST, &aList)); + rPage.PageCreated(aSet); + } + } + else if (rId == "header") + { + if(0 == (m_nHtmlMode & HTMLMODE_ON )) + { + static_cast<SvxHeaderPage&>(rPage).EnableDynamicSpacing(); + } + + // set DrawingLayer FillStyles active + aSet.Put(SfxBoolItem(SID_DRAWINGLAYER_FILLSTYLES, true)); + rPage.PageCreated(aSet); + } + else if (rId == "footer") + { + if(0 == (m_nHtmlMode & HTMLMODE_ON )) + { + static_cast<SvxFooterPage&>(rPage).EnableDynamicSpacing(); + } + + // set DrawingLayer FillStyles active + aSet.Put(SfxBoolItem(SID_DRAWINGLAYER_FILLSTYLES, true)); + rPage.PageCreated(aSet); + } + else if (rId == "border") + { + if( SfxStyleFamily::Para == m_nType ) + { + aSet.Put (SfxUInt16Item(SID_SWMODE_TYPE,static_cast<sal_uInt16>(SwBorderModes::PARA))); + } + else if( SfxStyleFamily::Frame == m_nType ) + { + aSet.Put (SfxUInt16Item(SID_SWMODE_TYPE,static_cast<sal_uInt16>(SwBorderModes::FRAME))); + } + rPage.PageCreated(aSet); + } + else if (rId == "borders") + { + if( SfxStyleFamily::Para == m_nType ) + { + aSet.Put (SfxUInt16Item(SID_SWMODE_TYPE,static_cast<sal_uInt16>(SwBorderModes::PARA))); + } + else if( SfxStyleFamily::Frame == m_nType ) + { + aSet.Put (SfxUInt16Item(SID_SWMODE_TYPE,static_cast<sal_uInt16>(SwBorderModes::FRAME))); + } + rPage.PageCreated(aSet); + } + // inits for Area and Transparency TabPages + // The selection attribute lists (XPropertyList derivates, e.g. XColorList for + // the color table) need to be added as items (e.g. SvxColorTableItem) to make + // these pages find the needed attributes for fill style suggestions. + // These are added in SwDocStyleSheet::GetItemSet() for the SfxStyleFamily::Para on + // demand, but could also be directly added from the DrawModel. + else if (rId == "area") + { + aSet.Put(GetStyleSheet().GetItemSet()); + + // add flag for direct graphic content selection + aSet.Put(SfxBoolItem(SID_OFFER_IMPORT, true)); + + rPage.PageCreated(aSet); + } + else if (rId == "transparence") + { + rPage.PageCreated(GetStyleSheet().GetItemSet()); + } + else if (rId == "bullets") + { + aSet.Put (SfxStringItem(SID_BULLET_CHAR_FMT,sBulletCharFormat)); + rPage.PageCreated(aSet); + } + else if (rId == "outline") + { + if (SfxStyleFamily::Pseudo == m_nType) + { + aSet.Put (SfxStringItem(SID_NUM_CHAR_FMT,sNumCharFormat)); + aSet.Put (SfxStringItem(SID_BULLET_CHAR_FMT,sBulletCharFormat)); + rPage.PageCreated(aSet); + } + else if (SfxStyleFamily::Para == m_nType) + { + // handle if the current paragraph style is assigned to a list level of outline style, + SwTextFormatColl* pTmpColl = m_pWrtShell->FindTextFormatCollByName( GetStyleSheet().GetName() ); + if( pTmpColl && pTmpColl->IsAssignedToListLevelOfOutlineStyle() ) + { + static_cast<SwParagraphNumTabPage&>(rPage).DisableOutline() ; + static_cast<SwParagraphNumTabPage&>(rPage).DisableNumbering(); + }//<-end + weld::ComboBox& rBox = static_cast<SwParagraphNumTabPage&>(rPage).GetStyleBox(); + SfxStyleSheetBasePool* pPool = m_pWrtShell->GetView().GetDocShell()->GetStyleSheetPool(); + const SfxStyleSheetBase* pBase = pPool->First(SfxStyleFamily::Pseudo); + std::set<OUString> aNames; + while(pBase) + { + aNames.insert(pBase->GetName()); + pBase = pPool->Next(); + } + aNames.erase(SwResId(STR_POOLNUMRULE_NOLIST)); + for(std::set<OUString>::const_iterator it = aNames.begin(); it != aNames.end(); ++it) + rBox.append_text(*it); + } + } + else if (rId == "customize") + { + aSet.Put (SfxStringItem(SID_NUM_CHAR_FMT,sNumCharFormat)); + aSet.Put (SfxStringItem(SID_BULLET_CHAR_FMT,sBulletCharFormat)); + + // collect character styles + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/swriter/ui/comboboxfragment.ui")); + std::unique_ptr<weld::ComboBox> xCharFormatLB(xBuilder->weld_combo_box("combobox")); + xCharFormatLB->clear(); + xCharFormatLB->append_text(SwViewShell::GetShellRes()->aStrNone); + if (SwWrtShell* pSh = ::GetActiveWrtShell()) + { + SwDocShell* pDocShell = pSh->GetView().GetDocShell(); + ::FillCharStyleListBox(*xCharFormatLB, pDocShell); + + std::vector<OUString> aList; + aList.reserve(xCharFormatLB->get_count()); + for (sal_Int32 j = 0; j < xCharFormatLB->get_count(); j++) + aList.push_back(xCharFormatLB->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 (rId == "indents") + { + if( rPage.GetItemSet().GetParent() ) + { + constexpr tools::Long constTwips_0_5mm = o3tl::toTwips(5, o3tl::Length::mm10); + aSet.Put(SfxUInt32Item(SID_SVXSTDPARAGRAPHTABPAGE_ABSLINEDIST, constTwips_0_5mm)); + aSet.Put(SfxUInt32Item(SID_SVXSTDPARAGRAPHTABPAGE_FLAGSET,0x000F)); + rPage.PageCreated(aSet); + } + } + else if (rId == "alignment") + { + aSet.Put(SfxBoolItem(SID_SVXPARAALIGNTABPAGE_ENABLEJUSTIFYEXT,true)); + rPage.PageCreated(aSet); + } + else if (rId == "asianlayout") + { + if( SfxStyleFamily::Char == m_nType ) + { + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE, SVX_PREVIEW_CHARACTER)); + rPage.PageCreated(aSet); + } + } + else if (rId == "type") + { + static_cast<SwFramePage&>(rPage).SetNewFrame( true ); + static_cast<SwFramePage&>(rPage).SetFormatUsed( true ); + } + else if (rId == "options") + { + static_cast<SwFrameAddPage&>(rPage).SetFormatUsed(true); + static_cast<SwFrameAddPage&>(rPage).SetNewFrame(true); + } + else if (rId == "wrap") + { + static_cast<SwWrapTabPage&>(rPage).SetFormatUsed( true, false ); + } + else if (rId == "macros") + { + SfxAllItemSet aNewSet(*aSet.GetPool()); + aNewSet.Put( SwMacroAssignDlg::AddEvents(MACASSGN_ALLFRM) ); + if ( m_pWrtShell ) + rPage.SetFrame( m_pWrtShell->GetView().GetViewFrame().GetFrame().GetFrameInterface() ); + rPage.PageCreated(aNewSet); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/frmdlg/column.cxx b/sw/source/ui/frmdlg/column.cxx new file mode 100644 index 0000000000..8caa69fade --- /dev/null +++ b/sw/source/ui/frmdlg/column.cxx @@ -0,0 +1,1381 @@ +/* -*- 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 <column.hxx> + +#include <hintids.hxx> +#include <svx/dialmgr.hxx> +#include <svx/strings.hrc> +#include <sfx2/htmlmode.hxx> +#include <svx/colorbox.hxx> +#include <editeng/borderline.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/sizeitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/ulspitem.hxx> +#include <svl/ctloptions.hxx> +#include <svl/itemset.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <vcl/event.hxx> +#include <vcl/fieldvalues.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> + +#include <swmodule.hxx> + +#include <swtypes.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <uitool.hxx> +#include <cmdid.h> +#include <viewopt.hxx> +#include <fmtclbl.hxx> +#include <fmtfsize.hxx> +#include <frmatr.hxx> +#include <colmgr.hxx> +#include <prcntfld.hxx> +#include <strings.hrc> +#include <section.hxx> +#include <pagedesc.hxx> + +//to match associated data in ColumnPage.ui +#define LISTBOX_SELECTION 0 +#define LISTBOX_SECTION 1 +#define LISTBOX_SECTIONS 2 +#define LISTBOX_PAGE 3 +#define LISTBOX_FRAME 4 + +using namespace ::com::sun::star; + +#define FRAME_FORMAT_WIDTH 1000 + +// static data +const sal_uInt16 nVisCols = 3; + +static bool IsMarkInSameSection( SwWrtShell& rWrtSh, const SwSection* pSect ) +{ + rWrtSh.SwapPam(); + bool bRet = pSect == rWrtSh.GetCurrSection(); + rWrtSh.SwapPam(); + return bRet; +} + +SwColumnDlg::SwColumnDlg(weld::Window* pParent, SwWrtShell& rSh) + : SfxDialogController(pParent, "modules/swriter/ui/columndialog.ui", "ColumnDialog") + , m_rWrtShell(rSh) + , m_pFrameSet(nullptr) + , m_nOldSelection(0) + , m_nSelectionWidth(0) + , m_bPageChanged(false) + , m_bSectionChanged(false) + , m_bSelSectionChanged(false) + , m_bFrameChanged(false) + , m_xContentArea(m_xBuilder->weld_container("content")) + , m_xOkButton(m_xBuilder->weld_button("ok")) +{ + SwRect aRect; + m_rWrtShell.CalcBoundRect(aRect, RndStdIds::FLY_AS_CHAR); + + m_nSelectionWidth = aRect.Width(); + + SfxItemSet* pColPgSet = nullptr; + static const auto aSectIds = svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, + RES_COL, RES_COL, + RES_COLUMNBALANCE, RES_FRAMEDIR>; + + const SwSection* pCurrSection = m_rWrtShell.GetCurrSection(); + const sal_uInt16 nFullSectCnt = m_rWrtShell.GetFullSelectedSectionCount(); + if( pCurrSection && ( !m_rWrtShell.HasSelection() || 0 != nFullSectCnt )) + { + m_nSelectionWidth = rSh.GetSectionWidth(*pCurrSection->GetFormat()); + if ( !m_nSelectionWidth ) + m_nSelectionWidth = USHRT_MAX; + m_pSectionSet.reset( new SfxItemSet( m_rWrtShell.GetAttrPool(), aSectIds ) ); + m_pSectionSet->Put( pCurrSection->GetFormat()->GetAttrSet() ); + pColPgSet = m_pSectionSet.get(); + } + + if( m_rWrtShell.HasSelection() && m_rWrtShell.IsInsRegionAvailable() && + ( !pCurrSection || ( 1 != nFullSectCnt && + IsMarkInSameSection( m_rWrtShell, pCurrSection ) ))) + { + m_pSelectionSet.reset( new SfxItemSet( m_rWrtShell.GetAttrPool(), aSectIds ) ); + pColPgSet = m_pSelectionSet.get(); + } + + if( m_rWrtShell.GetFlyFrameFormat() ) + { + const SwFrameFormat* pFormat = rSh.GetFlyFrameFormat() ; + m_pFrameSet = new SfxItemSet(m_rWrtShell.GetAttrPool(), aSectIds ); + m_pFrameSet->Put(pFormat->GetFrameSize()); + m_pFrameSet->Put(pFormat->GetCol()); + pColPgSet = m_pFrameSet; + } + + const SwPageDesc* pPageDesc = m_rWrtShell.GetSelectedPageDescs(); + if( pPageDesc ) + { + m_pPageSet = std::make_unique<SfxItemSetFixed< + RES_FRM_SIZE, RES_FRM_SIZE, + RES_LR_SPACE, RES_LR_SPACE, + RES_COL, RES_COL>>(m_rWrtShell.GetAttrPool()); + + const SwFrameFormat &rFormat = pPageDesc->GetMaster(); + m_nPageWidth = rFormat.GetFrameSize().GetSize().Width(); + + const SvxLRSpaceItem& rLRSpace = rFormat.GetLRSpace(); + const SvxBoxItem& rBox = rFormat.GetBox(); + m_nPageWidth -= rLRSpace.GetLeft() + rLRSpace.GetRight() + rBox.GetSmallestDistance(); + + m_pPageSet->Put(rFormat.GetCol()); + m_pPageSet->Put(rFormat.GetLRSpace()); + pColPgSet = m_pPageSet.get(); + } + + assert(pColPgSet); + + // create TabPage + m_xTabPage = std::make_unique<SwColumnPage>(m_xContentArea.get(), this, *pColPgSet); + m_xTabPage->GetApplyLabel()->show(); + weld::ComboBox* pApplyToLB = m_xTabPage->GetApplyComboBox(); + pApplyToLB->show(); + + if (pCurrSection && (!m_rWrtShell.HasSelection() || 0 != nFullSectCnt)) + { + pApplyToLB->remove_id(1 >= nFullSectCnt ? OUString::number(LISTBOX_SECTIONS) : OUString::number(LISTBOX_SECTION)); + } + else + { + pApplyToLB->remove_id(OUString::number(LISTBOX_SECTION)); + pApplyToLB->remove_id(OUString::number(LISTBOX_SECTIONS)); + } + + if (!( m_rWrtShell.HasSelection() && m_rWrtShell.IsInsRegionAvailable() && + ( !pCurrSection || ( 1 != nFullSectCnt && + IsMarkInSameSection( m_rWrtShell, pCurrSection ) )))) + pApplyToLB->remove_id(OUString::number(LISTBOX_SELECTION)); + + if (!m_rWrtShell.GetFlyFrameFormat()) + pApplyToLB->remove_id(OUString::number(LISTBOX_FRAME)); + + const int nPagePos = pApplyToLB->find_id(OUString::number(LISTBOX_PAGE)); + if (m_pPageSet && pPageDesc) + { + const OUString sPageStr = pApplyToLB->get_text(nPagePos) + pPageDesc->GetName(); + pApplyToLB->remove(nPagePos); + OUString sId(OUString::number(LISTBOX_PAGE)); + pApplyToLB->insert(nPagePos, sPageStr, &sId, nullptr, nullptr); + } + else + pApplyToLB->remove( nPagePos ); + + pApplyToLB->set_active(0); + ObjectHdl(nullptr); + + pApplyToLB->connect_changed(LINK(this, SwColumnDlg, ObjectListBoxHdl)); + m_xOkButton->connect_clicked(LINK(this, SwColumnDlg, OkHdl)); + //#i80458# if no columns can be set then disable OK + if (!pApplyToLB->get_count()) + m_xOkButton->set_sensitive(false); + //#i97810# set focus to the TabPage + m_xTabPage->ActivateColumnControl(); +} + +SwColumnDlg::~SwColumnDlg() +{ + m_xTabPage.reset(); +} + +IMPL_LINK(SwColumnDlg, ObjectListBoxHdl, weld::ComboBox&, rBox, void) +{ + ObjectHdl(&rBox); +} + +void SwColumnDlg::ObjectHdl(const weld::ComboBox* pBox) +{ + SfxItemSet* pSet = EvalCurrentSelection(); + + if (pBox) + { + m_xTabPage->FillItemSet(pSet); + } + weld::ComboBox* pApplyToLB = m_xTabPage->GetApplyComboBox(); + m_nOldSelection = pApplyToLB->get_active_id().toInt32(); + tools::Long nWidth = m_nSelectionWidth; + switch(m_nOldSelection) + { + case LISTBOX_SELECTION : + pSet = m_pSelectionSet.get(); + if( m_pSelectionSet ) + pSet->Put(SwFormatFrameSize(SwFrameSize::Variable, nWidth, nWidth)); + break; + case LISTBOX_SECTION : + case LISTBOX_SECTIONS : + pSet = m_pSectionSet.get(); + pSet->Put(SwFormatFrameSize(SwFrameSize::Variable, nWidth, nWidth)); + break; + case LISTBOX_PAGE : + nWidth = m_nPageWidth; + pSet = m_pPageSet.get(); + pSet->Put(SwFormatFrameSize(SwFrameSize::Variable, nWidth, nWidth)); + break; + case LISTBOX_FRAME: + pSet = m_pFrameSet; + break; + } + + bool bIsSection = pSet == m_pSectionSet.get() || pSet == m_pSelectionSet.get(); + m_xTabPage->ShowBalance(bIsSection); + m_xTabPage->SetInSection(bIsSection); + m_xTabPage->SetFrameMode(true); + m_xTabPage->SetPageWidth(nWidth); + if( pSet ) + m_xTabPage->Reset(pSet); +} + +IMPL_LINK_NOARG(SwColumnDlg, OkHdl, weld::Button&, void) +{ + // evaluate current selection + SfxItemSet* pSet = EvalCurrentSelection(); + m_xTabPage->FillItemSet(pSet); + + if(m_pSelectionSet && SfxItemState::SET == m_pSelectionSet->GetItemState(RES_COL)) + { + //insert region with columns + const SwFormatCol& rColItem = m_pSelectionSet->Get(RES_COL); + //only if there actually are columns! + if(rColItem.GetNumCols() > 1) + m_rWrtShell.GetView().GetViewFrame().GetDispatcher()->Execute( + FN_INSERT_REGION, SfxCallMode::ASYNCHRON, *m_pSelectionSet ); + } + + if(m_pSectionSet && m_pSectionSet->Count() && m_bSectionChanged ) + { + const SwSection* pCurrSection = m_rWrtShell.GetCurrSection(); + const SwSectionFormat* pFormat = pCurrSection->GetFormat(); + const size_t nNewPos = m_rWrtShell.GetSectionFormatPos( *pFormat ); + SwSectionData aData(*pCurrSection); + m_rWrtShell.UpdateSection( nNewPos, aData, m_pSectionSet.get() ); + } + + if(m_pSectionSet && m_pSectionSet->Count() && m_bSelSectionChanged ) + { + m_rWrtShell.SetSectionAttr( *m_pSectionSet ); + } + + if(m_pPageSet && SfxItemState::SET == m_pPageSet->GetItemState(RES_COL) && m_bPageChanged) + { + // determine current PageDescriptor and fill the Set with it + const size_t nCurIdx = m_rWrtShell.GetCurPageDesc(); + SwPageDesc aPageDesc(m_rWrtShell.GetPageDesc(nCurIdx)); + SwFrameFormat &rFormat = aPageDesc.GetMaster(); + rFormat.SetFormatAttr(m_pPageSet->Get(RES_COL)); + m_rWrtShell.ChgPageDesc(nCurIdx, aPageDesc); + } + if(m_pFrameSet && SfxItemState::SET == m_pFrameSet->GetItemState(RES_COL) && m_bFrameChanged) + { + SfxItemSetFixed<RES_COL, RES_COL> aTmp(*m_pFrameSet->GetPool()); + aTmp.Put(*m_pFrameSet); + m_rWrtShell.StartAction(); + m_rWrtShell.Push(); + m_rWrtShell.SetFlyFrameAttr( aTmp ); + // undo the frame selection again + if(m_rWrtShell.IsFrameSelected()) + { + m_rWrtShell.UnSelectFrame(); + m_rWrtShell.LeaveSelFrameMode(); + } + m_rWrtShell.Pop(); + m_rWrtShell.EndAction(); + } + m_xDialog->response(RET_OK); +} + +SfxItemSet* SwColumnDlg::EvalCurrentSelection() +{ + SfxItemSet* pSet = nullptr; + + switch(m_nOldSelection) + { + case LISTBOX_SELECTION : + pSet = m_pSelectionSet.get(); + break; + case LISTBOX_SECTION : + pSet = m_pSectionSet.get(); + m_bSectionChanged = true; + break; + case LISTBOX_SECTIONS : + pSet = m_pSectionSet.get(); + m_bSelSectionChanged = true; + break; + case LISTBOX_PAGE : + pSet = m_pPageSet.get(); + m_bPageChanged = true; + break; + case LISTBOX_FRAME: + pSet = m_pFrameSet; + m_bFrameChanged = true; + break; + } + + return pSet; +} + +static +sal_uInt16 GetMaxWidth( SwColMgr const * pColMgr, sal_uInt16 nCols ) +{ + sal_uInt16 nMax = pColMgr->GetActualSize(); + if( --nCols ) + nMax -= pColMgr->GetGutterWidth() * nCols; + return nMax; +} + +const WhichRangesContainer SwColumnPage::s_aPageRg(svl::Items<RES_COL, RES_COL>); + +void SwColumnPage::ResetColWidth() +{ + if( m_nCols ) + { + const sal_uInt16 nWidth = GetMaxWidth( m_xColMgr.get(), m_nCols ) / m_nCols; + + for(sal_uInt16 i = 0; i < m_nCols; ++i) + m_nColWidth[i] = static_cast<tools::Long>(nWidth); + } + +} + +constexpr sal_uInt16 g_nMinWidth(MINLAY); + +// Now as TabPage +SwColumnPage::SwColumnPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/columnpage.ui", "ColumnPage", &rSet) + , m_nFirstVis(0) + , m_pModifiedField(nullptr) + , m_bFormat(false) + , m_bFrame(false) + , m_bHtmlMode(false) + , m_bLockUpdate(false) + , m_xCLNrEdt(m_xBuilder->weld_spin_button("colsnf")) + , m_xBalanceColsCB(m_xBuilder->weld_check_button("balance")) + , m_xBtnBack(m_xBuilder->weld_button("back")) + , m_xLbl1(m_xBuilder->weld_label("1")) + , m_xLbl2(m_xBuilder->weld_label("2")) + , m_xLbl3(m_xBuilder->weld_label("3")) + , m_xBtnNext(m_xBuilder->weld_button("next")) + , m_xAutoWidthBox(m_xBuilder->weld_check_button("autowidth")) + , m_xLineTypeLbl(m_xBuilder->weld_label("linestyleft")) + , m_xLineWidthLbl(m_xBuilder->weld_label("linewidthft")) + , m_xLineWidthEdit(m_xBuilder->weld_metric_spin_button("linewidthmf", FieldUnit::POINT)) + , m_xLineColorLbl(m_xBuilder->weld_label("linecolorft")) + , m_xLineHeightLbl(m_xBuilder->weld_label("lineheightft")) + , m_xLineHeightEdit(m_xBuilder->weld_metric_spin_button("lineheightmf", FieldUnit::PERCENT)) + , m_xLinePosLbl(m_xBuilder->weld_label("lineposft")) + , m_xLinePosDLB(m_xBuilder->weld_combo_box("lineposlb")) + , m_xTextDirectionFT(m_xBuilder->weld_label("textdirectionft")) + , m_xTextDirectionLB(new svx::FrameDirectionListBox(m_xBuilder->weld_combo_box("textdirectionlb"))) + , m_xLineColorDLB(new ColorListBox(m_xBuilder->weld_menu_button("colorlb"), + [this]{ return GetFrameWeld(); })) + , m_xLineTypeDLB(new SvtLineListBox(m_xBuilder->weld_menu_button("linestylelb"))) + , m_xEd1(new SwPercentField(m_xBuilder->weld_metric_spin_button("width1mf", FieldUnit::CM))) + , m_xEd2(new SwPercentField(m_xBuilder->weld_metric_spin_button("width2mf", FieldUnit::CM))) + , m_xEd3(new SwPercentField(m_xBuilder->weld_metric_spin_button("width3mf", FieldUnit::CM))) + , m_xDistEd1(new SwPercentField(m_xBuilder->weld_metric_spin_button("spacing1mf", FieldUnit::CM))) + , m_xDistEd2(new SwPercentField(m_xBuilder->weld_metric_spin_button("spacing2mf", FieldUnit::CM))) + , m_xDefaultVS(new weld::CustomWeld(*m_xBuilder, "valueset", m_aDefaultVS)) + , m_xPgeExampleWN(new weld::CustomWeld(*m_xBuilder, "pageexample", m_aPgeExampleWN)) + , m_xFrameExampleWN(new weld::CustomWeld(*m_xBuilder, "frameexample", m_aFrameExampleWN)) + , m_xApplyToFT(m_xBuilder->weld_label("applytoft")) + , m_xApplyToLB(m_xBuilder->weld_combo_box("applytolb")) +{ + connectPercentField(*m_xEd1); + connectPercentField(*m_xEd2); + connectPercentField(*m_xEd3); + connectPercentField(*m_xDistEd1); + connectPercentField(*m_xDistEd2); + + m_xTextDirectionLB->append(SvxFrameDirection::Horizontal_LR_TB, SvxResId(RID_SVXSTR_FRAMEDIR_LTR)); + m_xTextDirectionLB->append(SvxFrameDirection::Horizontal_RL_TB, SvxResId(RID_SVXSTR_FRAMEDIR_RTL)); + m_xTextDirectionLB->append(SvxFrameDirection::Environment, SvxResId(RID_SVXSTR_FRAMEDIR_SUPER)); + + SetExchangeSupport(); + + m_aDefaultVS.SetColCount(5); + + for (int i = 0; i < 5; ++i) + //Set accessible name one by one + { + OUString aItemText; + switch( i ) + { + case 0: + aItemText = SwResId( STR_COLUMN_VALUESET_ITEM0 ) ; + break; + case 1: + aItemText = SwResId( STR_COLUMN_VALUESET_ITEM1 ) ; + break; + case 2: + aItemText = SwResId( STR_COLUMN_VALUESET_ITEM2 ) ; + break; + case 3: + aItemText = SwResId( STR_COLUMN_VALUESET_ITEM3 ); + break; + default: + aItemText = SwResId( STR_COLUMN_VALUESET_ITEM4 ); + break; + } + m_aDefaultVS.InsertItem( i + 1, aItemText, i ); + } + + m_aDefaultVS.SetSelectHdl(LINK(this, SwColumnPage, SetDefaultsHdl)); + + Link<weld::SpinButton&,void> aCLNrLk = LINK(this, SwColumnPage, ColModify); + m_xCLNrEdt->connect_value_changed(aCLNrLk); + Link<weld::MetricSpinButton&,void> aLk = LINK(this, SwColumnPage, GapModify); + m_xDistEd1->connect_value_changed(aLk); + m_xDistEd2->connect_value_changed(aLk); + + aLk = LINK(this, SwColumnPage, EdModify); + + m_xEd1->connect_value_changed(aLk); + m_xEd2->connect_value_changed(aLk); + m_xEd3->connect_value_changed(aLk); + + m_xBtnBack->connect_clicked(LINK(this, SwColumnPage, Up)); + m_xBtnNext->connect_clicked(LINK(this, SwColumnPage, Down)); + m_xAutoWidthBox->connect_toggled(LINK(this, SwColumnPage, AutoWidthHdl)); + + Link<weld::MetricSpinButton&,void> aLk2 = LINK( this, SwColumnPage, UpdateColMgr ); + m_xLineTypeDLB->SetSelectHdl(LINK(this, SwColumnPage, UpdateColMgrLineBox)); + m_xLineWidthEdit->connect_value_changed(aLk2); + m_xLineColorDLB->SetSelectHdl(LINK( this, SwColumnPage, UpdateColMgrColorBox)); + m_xLineHeightEdit->connect_value_changed(aLk2); + m_xLinePosDLB->connect_changed(LINK(this, SwColumnPage, UpdateColMgrListBox)); + + // Separator line + m_xLineTypeDLB->SetSourceUnit( FieldUnit::TWIP ); + + // Fill the line styles listbox + m_xLineTypeDLB->InsertEntry( + ::editeng::SvxBorderLine::getWidthImpl(SvxBorderLineStyle::SOLID), + SvxBorderLineStyle::SOLID ); + m_xLineTypeDLB->InsertEntry( + ::editeng::SvxBorderLine::getWidthImpl(SvxBorderLineStyle::DOTTED), + SvxBorderLineStyle::DOTTED ); + m_xLineTypeDLB->InsertEntry( + ::editeng::SvxBorderLine::getWidthImpl(SvxBorderLineStyle::DASHED), + SvxBorderLineStyle::DASHED ); + + sal_Int64 nLineWidth = m_xLineWidthEdit->get_value(FieldUnit::POINT); + nLineWidth = static_cast<tools::Long>(vcl::ConvertDoubleValue( + nLineWidth, + m_xLineWidthEdit->get_digits(), + FieldUnit::POINT, MapUnit::MapTwip )); + m_xLineTypeDLB->SetWidth(nLineWidth); + m_xLineColorDLB->SelectEntry(COL_BLACK); +} + +SwColumnPage::~SwColumnPage() +{ + m_xFrameExampleWN.reset(); + m_xPgeExampleWN.reset(); + m_xDefaultVS.reset(); + m_xDistEd2.reset(); + m_xDistEd1.reset(); + m_xEd3.reset(); + m_xEd2.reset(); + m_xEd1.reset(); + m_xLineTypeDLB.reset(); + m_xLineColorDLB.reset(); + m_xTextDirectionLB.reset(); +} + +void SwColumnPage::SetPageWidth(tools::Long nPageWidth) +{ + tools::Long nNewMaxWidth = static_cast< tools::Long >(m_xEd1->NormalizePercent(nPageWidth)); + + m_xDistEd1->set_max(nNewMaxWidth, FieldUnit::TWIP); + m_xDistEd2->set_max(nNewMaxWidth, FieldUnit::TWIP); + m_xEd1->set_max(nNewMaxWidth, FieldUnit::TWIP); + m_xEd2->set_max(nNewMaxWidth, FieldUnit::TWIP); + m_xEd3->set_max(nNewMaxWidth, FieldUnit::TWIP); +} + +void SwColumnPage::connectPercentField(SwPercentField &rWrap) +{ + weld::MetricSpinButton *pField = rWrap.get(); + assert(pField); + m_aPercentFieldsMap[pField] = &rWrap; +} + +void SwColumnPage::Reset(const SfxItemSet *rSet) +{ + const sal_uInt16 nHtmlMode = + ::GetHtmlMode(static_cast<const SwDocShell*>(SfxObjectShell::Current())); + if(nHtmlMode & HTMLMODE_ON) + { + m_bHtmlMode = true; + m_xAutoWidthBox->set_sensitive(false); + } + FieldUnit aMetric = ::GetDfltMetric(m_bHtmlMode); + m_xEd1->SetMetric(aMetric); + m_xEd2->SetMetric(aMetric); + m_xEd3->SetMetric(aMetric); + m_xDistEd1->SetMetric(aMetric); + m_xDistEd2->SetMetric(aMetric); + //default spacing between cols = 0.5cm + m_xDistEd1->set_value(50, FieldUnit::CM); + m_xDistEd2->set_value(50, FieldUnit::CM); + + m_xColMgr.reset(new SwColMgr(*rSet)); + m_nCols = m_xColMgr->GetCount() ; + m_xCLNrEdt->set_max(std::max(o3tl::narrowing<sal_uInt16>(m_xCLNrEdt->get_max()), m_nCols)); + + if(m_bFrame) + { + if(m_bFormat) // there is no size here + m_xColMgr->SetActualWidth(FRAME_FORMAT_WIDTH); + else + { + const SwFormatFrameSize& rSize = rSet->Get(RES_FRM_SIZE); + const SvxBoxItem& rBox = rSet->Get(RES_BOX); + m_xColMgr->SetActualWidth(o3tl::narrowing<sal_uInt16>(rSize.GetSize().Width()) - rBox.GetSmallestDistance()); + } + } + if (m_xBalanceColsCB->get_visible()) + { + if( const SwFormatNoBalancedColumns* pItem = rSet->GetItemIfSet( RES_COLUMNBALANCE, false ) ) + m_xBalanceColsCB->set_active(!pItem->GetValue()); + else + m_xBalanceColsCB->set_active(true); + } + + //text direction + if( SfxItemState::DEFAULT <= rSet->GetItemState( RES_FRAMEDIR ) ) + { + const SvxFrameDirectionItem& rItem = rSet->Get(RES_FRAMEDIR); + SvxFrameDirection nVal = rItem.GetValue(); + m_xTextDirectionLB->set_active_id(nVal); + m_xTextDirectionLB->save_value(); + } + + Init(); + ActivatePage( *rSet ); +} + +// create TabPage +std::unique_ptr<SfxTabPage> SwColumnPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet) +{ + return std::make_unique<SwColumnPage>(pPage, pController, *rSet); +} + +// stuff attributes into the Set when OK +bool SwColumnPage::FillItemSet(SfxItemSet *rSet) +{ + // set in ItemSet; + // the current settings are already present + + const SfxPoolItem* pOldItem; + const SwFormatCol& rCol = m_xColMgr->GetColumns(); + if(nullptr == (pOldItem = GetOldItem( *rSet, RES_COL )) || + rCol != *pOldItem ) + rSet->Put(rCol); + + if (m_xBalanceColsCB->get_visible()) + { + rSet->Put(SwFormatNoBalancedColumns(!m_xBalanceColsCB->get_active())); + } + if (m_xTextDirectionLB->get_visible()) + { + if (m_xTextDirectionLB->get_value_changed_from_saved()) + { + rSet->Put(SvxFrameDirectionItem(m_xTextDirectionLB->get_active_id(), RES_FRAMEDIR) ); + } + } + return true; +} + +// update ColumnManager +IMPL_LINK_NOARG( SwColumnPage, UpdateColMgrListBox, weld::ComboBox&, void ) +{ + UpdateColMgr(*m_xLineWidthEdit); +} + +IMPL_LINK_NOARG( SwColumnPage, UpdateColMgrLineBox, SvtLineListBox&, void ) +{ + UpdateColMgr(*m_xLineWidthEdit); +} + +IMPL_LINK_NOARG( SwColumnPage, UpdateColMgrColorBox, ColorListBox&, void ) +{ + UpdateColMgr(*m_xLineWidthEdit); +} + +IMPL_LINK_NOARG( SwColumnPage, UpdateColMgr, weld::MetricSpinButton&, void ) +{ + if (!m_xColMgr) + return; + tools::Long nGutterWidth = m_xColMgr->GetGutterWidth(); + if (m_nCols > 1) + { + // Determine whether the most narrow column is too narrow + // for the adjusted column gap + tools::Long nMin = m_nColWidth[0]; + + for( sal_uInt16 i = 1; i < m_nCols; ++i ) + nMin = std::min(nMin, m_nColWidth[i]); + + bool bAutoWidth = m_xAutoWidthBox->get_active(); + if(!bAutoWidth) + { + m_xColMgr->SetAutoWidth(false); + // when the user didn't allocate the whole width, + // add the missing amount to the last column. + tools::Long nSum = 0; + for(sal_uInt16 i = 0; i < m_nCols; ++i) + nSum += m_nColWidth[i]; + nGutterWidth = 0; + for(sal_uInt16 i = 0; i < m_nCols - 1; ++i) + nGutterWidth += m_nColDist[i]; + nSum += nGutterWidth; + + tools::Long nMaxW = m_xColMgr->GetActualSize(); + + if( nSum < nMaxW ) + m_nColWidth[m_nCols - 1] += nMaxW - nSum; + + m_xColMgr->SetColWidth( 0, static_cast< sal_uInt16 >(m_nColWidth[0] + m_nColDist[0]/2) ); + for( sal_uInt16 i = 1; i < m_nCols-1; ++i ) + { + tools::Long nActDist = (m_nColDist[i] + m_nColDist[i - 1]) / 2; + m_xColMgr->SetColWidth( i, static_cast< sal_uInt16 >(m_nColWidth[i] + nActDist )); + } + m_xColMgr->SetColWidth( m_nCols-1, static_cast< sal_uInt16 >(m_nColWidth[m_nCols-1] + m_nColDist[m_nCols -2]/2) ); + + } + + bool bEnable = isLineNotNone(); + m_xLineHeightEdit->set_sensitive(bEnable); + m_xLineHeightLbl->set_sensitive(bEnable); + m_xLineWidthLbl->set_sensitive(bEnable); + m_xLineWidthEdit->set_sensitive(bEnable); + m_xLineColorDLB->set_sensitive(bEnable); + m_xLineColorLbl->set_sensitive(bEnable); + + sal_Int64 nLineWidth = m_xLineWidthEdit->get_value(FieldUnit::PERCENT); + nLineWidth = static_cast<tools::Long>(vcl::ConvertDoubleValue( + nLineWidth, + m_xLineWidthEdit->get_digits(), + m_xLineWidthEdit->get_unit(), MapUnit::MapTwip )); + if( !bEnable ) + m_xColMgr->SetNoLine(); + else + { + m_xColMgr->SetLineWidthAndColor( + m_xLineTypeDLB->GetSelectEntryStyle(), + nLineWidth, + m_xLineColorDLB->GetSelectEntryColor() ); + m_xColMgr->SetAdjust(SwColLineAdj(m_xLinePosDLB->get_active() + 1)); + m_xColMgr->SetLineHeightPercent(static_cast<short>(m_xLineHeightEdit->get_value(FieldUnit::PERCENT))); + bEnable = m_xColMgr->GetLineHeightPercent() != 100; + } + m_xLinePosLbl->set_sensitive(bEnable); + m_xLinePosDLB->set_sensitive(bEnable); + + //fdo#66815 if the values are going to be the same, don't update + //them to avoid the listbox selection resetting + if (nLineWidth != m_xLineTypeDLB->GetWidth()) + m_xLineTypeDLB->SetWidth(nLineWidth); + Color aColor(m_xLineColorDLB->GetSelectEntryColor()); + if (aColor != m_xLineTypeDLB->GetColor()) + m_xLineTypeDLB->SetColor(aColor); + } + else + { + m_xColMgr->NoCols(); + m_nCols = 0; + } + + //set maximum values + m_xCLNrEdt->set_max(std::max(tools::Long(1), + std::min(tools::Long(nMaxCols), tools::Long(m_xColMgr->GetActualSize() / (nGutterWidth + MINLAY)) ))); + + //prompt example window + if(!m_bLockUpdate) + { + if(m_bFrame) + { + m_aFrameExampleWN.SetColumns(m_xColMgr->GetColumns()); + m_aFrameExampleWN.Invalidate(); + } + else + m_aPgeExampleWN.Invalidate(); + } +} + +void SwColumnPage::Init() +{ + m_xCLNrEdt->set_value(m_nCols); + + bool bAutoWidth = m_xColMgr->IsAutoWidth() || m_bHtmlMode; + m_xAutoWidthBox->set_active(bAutoWidth); + + sal_Int32 nColumnWidthSum = 0; + // set the widths + for(sal_uInt16 i = 0; i < m_nCols; ++i) + { + m_nColWidth[i] = m_xColMgr->GetColWidth(i); + nColumnWidthSum += m_nColWidth[i]; + if(i < m_nCols - 1) + m_nColDist[i] = m_xColMgr->GetGutterWidth(i); + } + + if( 1 < m_nCols ) + { + // #97495# make sure that the automatic column width's are always equal + if(bAutoWidth) + { + nColumnWidthSum /= m_nCols; + for(sal_uInt16 i = 0; i < m_nCols; ++i) + m_nColWidth[i] = nColumnWidthSum; + } + SwColLineAdj eAdj = m_xColMgr->GetAdjust(); + if( COLADJ_NONE == eAdj ) // the dialog doesn't know a NONE! + { + eAdj = COLADJ_TOP; + //without Adjust no line type + m_xLineTypeDLB->SelectEntry(SvxBorderLineStyle::NONE); + m_xLineHeightEdit->set_value(100, FieldUnit::PERCENT); + } + else + { + // Need to multiply by 100 because of the 2 decimals + m_xLineWidthEdit->set_value( m_xColMgr->GetLineWidth() * 100, FieldUnit::TWIP); + m_xLineColorDLB->SelectEntry( m_xColMgr->GetLineColor() ); + m_xLineTypeDLB->SelectEntry( m_xColMgr->GetLineStyle() ); + m_xLineTypeDLB->SetWidth( m_xColMgr->GetLineWidth( ) ); + m_xLineHeightEdit->set_value(m_xColMgr->GetLineHeightPercent(), FieldUnit::PERCENT); + + } + m_xLinePosDLB->set_active( static_cast< sal_Int32 >(eAdj - 1) ); + } + else + { + m_xLinePosDLB->set_active(0); + m_xLineTypeDLB->SelectEntry(SvxBorderLineStyle::NONE); + m_xLineHeightEdit->set_value(100, FieldUnit::PERCENT); + } + + UpdateCols(); + Update(nullptr); + + // set maximum number of columns + // values below 1 are not allowed + m_xCLNrEdt->set_max(std::max(tools::Long(1), + std::min(tools::Long(nMaxCols), tools::Long(m_xColMgr->GetActualSize() / g_nMinWidth) ))); +} + +bool SwColumnPage::isLineNotNone() const +{ + // nothing is turned off + return m_xLineTypeDLB->GetSelectEntryStyle() != SvxBorderLineStyle::NONE; +} + +/* + * The number of columns has changed -- here the controls for editing of the + * columns are en- or disabled according to the column number. In case there are + * more than nVisCols (=3) all Edit are being enabled and the buttons for + * scrolling too. Otherwise Edits are being enabled according to the column + * numbers; one column can not be edited. + */ +void SwColumnPage::UpdateCols() +{ + bool bEnableBtns= false; + bool bEnable12 = false; + bool bEnable3 = false; + const bool bEdit = !m_xAutoWidthBox->get_active(); + if ( m_nCols > nVisCols ) + { + bEnableBtns = !m_bHtmlMode; + bEnable12 = bEnable3 = bEdit; + } + else if( bEdit ) + { + // here are purposely hardly any breaks + switch(m_nCols) + { + case 3: bEnable3 = true; + [[fallthrough]]; + case 2: bEnable12= true; break; + default: /* do nothing */; + } + } + m_xEd1->set_sensitive(bEnable12); + bool bEnable = m_nCols > 1; + m_xDistEd1->set_sensitive(bEnable); + m_xAutoWidthBox->set_sensitive(bEnable && !m_bHtmlMode); + m_xEd2->set_sensitive(bEnable12); + m_xDistEd2->set_sensitive(bEnable3); + m_xEd3->set_sensitive(bEnable3); + m_xLbl1->set_sensitive(bEnable12); + m_xLbl2->set_sensitive(bEnable12); + m_xLbl3->set_sensitive(bEnable3); + m_xBtnBack->set_sensitive(bEnableBtns); + m_xBtnNext->set_sensitive(bEnableBtns); + + m_xLineTypeDLB->set_sensitive( bEnable ); + m_xLineTypeLbl->set_sensitive( bEnable ); + + if (bEnable) + { + bEnable = isLineNotNone(); + } + + //all these depend on > 1 column and line style != none + m_xLineHeightEdit->set_sensitive(bEnable); + m_xLineHeightLbl->set_sensitive(bEnable); + m_xLineWidthLbl->set_sensitive(bEnable); + m_xLineWidthEdit->set_sensitive(bEnable); + m_xLineColorDLB->set_sensitive(bEnable); + m_xLineColorLbl->set_sensitive(bEnable); + + if (bEnable) + bEnable = m_xColMgr->GetLineHeightPercent() != 100; + + //and these additionally depend on line height != 100% + m_xLinePosDLB->set_sensitive(bEnable); + m_xLinePosLbl->set_sensitive(bEnable); +} + +void SwColumnPage::SetLabels( sal_uInt16 nVis ) +{ + //insert ~ before the last character, e.g. 1 -> ~1, 10 -> 1~0 + const OUString sLbl( '~' ); + + const OUString sLbl1(OUString::number( nVis + 1 )); + m_xLbl1->set_label(sLbl1.replaceAt(sLbl1.getLength()-1, 0, sLbl)); + + const OUString sLbl2(OUString::number( nVis + 2 )); + m_xLbl2->set_label(sLbl2.replaceAt(sLbl2.getLength()-1, 0, sLbl)); + + const OUString sLbl3(OUString::number( nVis + 3 )); + m_xLbl3->set_label(sLbl3.replaceAt(sLbl3.getLength()-1, 0, sLbl)); + + const OUString sColumnWidth = SwResId( STR_ACCESS_COLUMN_WIDTH ) ; + m_xEd1->set_accessible_name(sColumnWidth.replaceFirst("%1", sLbl1)); + m_xEd2->set_accessible_name(sColumnWidth.replaceFirst("%1", sLbl2)); + m_xEd3->set_accessible_name(sColumnWidth.replaceFirst("%1", sLbl3)); + + const OUString sDist = SwResId( STR_ACCESS_PAGESETUP_SPACING ) ; + m_xDistEd1->set_accessible_name( + sDist.replaceFirst("%1", sLbl1).replaceFirst("%2", sLbl2)); + + m_xDistEd2->set_accessible_name( + sDist.replaceFirst("%1", sLbl2).replaceFirst("%2", sLbl3)); +} + +/* + * Handler that is called at alteration of the column number. An alteration of + * the column number overwrites potential user's width settings; all columns + * are equally wide. + */ +IMPL_LINK_NOARG(SwColumnPage, ColModify, weld::SpinButton&, void) +{ + ColModify(/*bForceColReset=*/false); +} + +void SwColumnPage::ColModify(bool bForceColReset) +{ + m_nCols = o3tl::narrowing<sal_uInt16>(m_xCLNrEdt->get_value()); + //#107890# the handler is also called from LoseFocus() + //then no change has been made and thus no action should be taken + // #i17816# changing the displayed types within the ValueSet + //from two columns to two columns with different settings doesn't invalidate the + // example windows in ::ColModify() + if (!bForceColReset && m_xColMgr->GetCount() == m_nCols) + return; + + if (!bForceColReset) + m_aDefaultVS.SetNoSelection(); + tools::Long nDist = static_cast< tools::Long >(m_xDistEd1->DenormalizePercent(m_xDistEd1->get_value(FieldUnit::TWIP))); + m_xColMgr->SetCount(m_nCols, o3tl::narrowing<sal_uInt16>(nDist)); + for(sal_uInt16 i = 0; i < m_nCols; i++) + m_nColDist[i] = nDist; + m_nFirstVis = 0; + SetLabels( m_nFirstVis ); + UpdateCols(); + ResetColWidth(); + Update(nullptr); +} + +/* + * Modify handler for an alteration of the column width or the column gap. + * These changes take effect time-displaced. With an alteration of the column + * width the automatic calculation of the column width is overruled; only an + * alteration of the column number leads back to that default. + */ +IMPL_LINK(SwColumnPage, GapModify, weld::MetricSpinButton&, rMetricField, void) +{ + if (m_nCols < 2) + return; + SwPercentField *pField = m_aPercentFieldsMap[&rMetricField]; + assert(pField); + tools::Long nActValue = static_cast< tools::Long >(pField->DenormalizePercent(pField->get_value(FieldUnit::TWIP))); + if (m_xAutoWidthBox->get_active()) + { + const tools::Long nMaxGap = static_cast< tools::Long > + ((m_xColMgr->GetActualSize() - m_nCols * MINLAY)/(m_nCols - 1)); + if(nActValue > nMaxGap) + { + nActValue = nMaxGap; + m_xDistEd1->set_value(m_xDistEd1->NormalizePercent(nMaxGap), FieldUnit::TWIP); + } + m_xColMgr->SetGutterWidth(o3tl::narrowing<sal_uInt16>(nActValue)); + for(sal_uInt16 i = 0; i < m_nCols; i++) + m_nColDist[i] = nActValue; + + ResetColWidth(); + UpdateCols(); + } + else + { + const sal_uInt16 nVis = m_nFirstVis + ((pField == m_xDistEd2.get()) ? 1 : 0); + tools::Long nDiff = nActValue - m_nColDist[nVis]; + if(nDiff) + { + tools::Long nLeft = m_nColWidth[nVis]; + tools::Long nRight = m_nColWidth[nVis + 1]; + if(nLeft + nRight + 2 * MINLAY < nDiff) + nDiff = nLeft + nRight - 2 * MINLAY; + if(nDiff < nRight - MINLAY) + { + nRight -= nDiff; + } + else + { + tools::Long nTemp = nDiff - nRight + MINLAY; + nRight = MINLAY; + if(nLeft > nTemp - MINLAY) + { + nLeft -= nTemp; + nTemp = 0; + } + else + { + nTemp -= nLeft + MINLAY; + nLeft = MINLAY; + } + nDiff = nTemp; + } + m_nColWidth[nVis] = nLeft; + m_nColWidth[nVis + 1] = nRight; + m_nColDist[nVis] += nDiff; + + m_xColMgr->SetColWidth( nVis, sal_uInt16(nLeft) ); + m_xColMgr->SetColWidth( nVis + 1, sal_uInt16(nRight) ); + m_xColMgr->SetGutterWidth( sal_uInt16(m_nColDist[nVis]), nVis ); + } + + } + Update(&rMetricField); +} + +IMPL_LINK(SwColumnPage, EdModify, weld::MetricSpinButton&, rEdit, void) +{ + SwPercentField *pField = m_aPercentFieldsMap[&rEdit]; + assert(pField); + m_pModifiedField = pField; + Timeout(); +} + +// Handler behind the Checkbox for automatic width. When the box is checked +// no explicit values for the column width can be entered. +IMPL_LINK(SwColumnPage, AutoWidthHdl, weld::Toggleable&, rBox, void) +{ + tools::Long nDist = static_cast< tools::Long >(m_xDistEd1->DenormalizePercent(m_xDistEd1->get_value(FieldUnit::TWIP))); + m_xColMgr->SetCount(m_nCols, o3tl::narrowing<sal_uInt16>(nDist)); + for(sal_uInt16 i = 0; i < m_nCols; i++) + m_nColDist[i] = nDist; + if (rBox.get_active()) + { + m_xColMgr->SetGutterWidth(sal_uInt16(nDist)); + ResetColWidth(); + } + m_xColMgr->SetAutoWidth(rBox.get_active(), sal_uInt16(nDist)); + UpdateCols(); + Update(nullptr); +} + +// scroll up the contents of the edits +IMPL_LINK_NOARG(SwColumnPage, Up, weld::Button&, void) +{ + if( m_nFirstVis ) + { + --m_nFirstVis; + SetLabels( m_nFirstVis ); + Update(nullptr); + } +} + +// scroll down the contents of the edits. +IMPL_LINK_NOARG(SwColumnPage, Down, weld::Button&, void) +{ + if( m_nFirstVis + nVisCols < m_nCols ) + { + ++m_nFirstVis; + SetLabels( m_nFirstVis ); + Update(nullptr); + } +} + +// relict from ancient times - now directly without time handler; triggered by +// an alteration of the column width or the column gap. +void SwColumnPage::Timeout() +{ + SwPercentField *pField = m_pModifiedField; + if (m_pModifiedField) + { + // find the changed column + sal_uInt16 nChanged = m_nFirstVis; + if (m_pModifiedField == m_xEd2.get()) + ++nChanged; + else if (m_pModifiedField == m_xEd3.get()) + nChanged += 2; + + tools::Long nNewWidth = static_cast< tools::Long > + (m_pModifiedField->DenormalizePercent(m_pModifiedField->get_value(FieldUnit::TWIP))); + tools::Long nDiff = nNewWidth - m_nColWidth[nChanged]; + + // when it's the last column + if(nChanged == m_nCols - 1) + { + m_nColWidth[0] -= nDiff; + if(m_nColWidth[0] < static_cast<tools::Long>(g_nMinWidth)) + { + nNewWidth -= g_nMinWidth - m_nColWidth[0]; + m_nColWidth[0] = g_nMinWidth; + } + + } + else if(nDiff) + { + m_nColWidth[nChanged + 1] -= nDiff; + if(m_nColWidth[nChanged + 1] < static_cast<tools::Long>(g_nMinWidth)) + { + nNewWidth -= g_nMinWidth - m_nColWidth[nChanged + 1]; + m_nColWidth[nChanged + 1] = g_nMinWidth; + } + } + m_nColWidth[nChanged] = nNewWidth; + m_pModifiedField = nullptr; + } + + Update(pField ? pField->get() : nullptr); +} + +// Update the view +void SwColumnPage::Update(const weld::MetricSpinButton* pInteractiveField) +{ + m_xBalanceColsCB->set_sensitive(m_nCols > 1); + if(m_nCols >= 2) + { + sal_Int64 nCurrentValue, nNewValue; + + nCurrentValue = m_xEd1->NormalizePercent(m_xEd1->DenormalizePercent(m_xEd1->get_value(FieldUnit::TWIP))); + nNewValue = m_xEd1->NormalizePercent(m_nColWidth[m_nFirstVis]); + + //fdo#87612 if we're interacting with this widget and the value will be the same + //then leave it alone (i.e. don't change equivalent values of e.g. .8 -> 0.8) + if (nNewValue != nCurrentValue || pInteractiveField != m_xEd1->get()) + m_xEd1->set_value(nNewValue, FieldUnit::TWIP); + + nCurrentValue = m_xDistEd1->NormalizePercent(m_xDistEd1->DenormalizePercent(m_xDistEd1->get_value(FieldUnit::TWIP))); + nNewValue = m_xDistEd1->NormalizePercent(m_nColDist[m_nFirstVis]); + if (nNewValue != nCurrentValue || pInteractiveField != m_xDistEd1->get()) + m_xDistEd1->set_value(nNewValue, FieldUnit::TWIP); + + nCurrentValue = m_xEd2->NormalizePercent(m_xEd2->DenormalizePercent(m_xEd2->get_value(FieldUnit::TWIP))); + nNewValue = m_xEd2->NormalizePercent(m_nColWidth[m_nFirstVis+1]); + if (nNewValue != nCurrentValue || pInteractiveField != m_xEd2->get()) + m_xEd2->set_value(nNewValue, FieldUnit::TWIP); + + if(m_nCols >= 3) + { + nCurrentValue = m_xDistEd2->NormalizePercent(m_xDistEd2->DenormalizePercent(m_xDistEd2->get_value(FieldUnit::TWIP))); + nNewValue = m_xDistEd2->NormalizePercent(m_nColDist[m_nFirstVis+1]); + if (nNewValue != nCurrentValue || pInteractiveField != m_xDistEd2->get()) + m_xDistEd2->set_value(nNewValue, FieldUnit::TWIP); + + nCurrentValue = m_xEd3->NormalizePercent(m_xEd3->DenormalizePercent(m_xEd3->get_value(FieldUnit::TWIP))); + nNewValue = m_xEd3->NormalizePercent(m_nColWidth[m_nFirstVis+2]); + if (nNewValue != nCurrentValue || pInteractiveField != m_xEd3->get()) + m_xEd3->set_value(nNewValue, FieldUnit::TWIP); + } + else + { + m_xEd3->set_text(OUString()); + m_xDistEd2->set_text(OUString()); + } + } + else + { + m_xEd1->set_text(OUString()); + m_xEd2->set_text(OUString()); + m_xEd3->set_text(OUString()); + m_xDistEd1->set_text(OUString()); + m_xDistEd2->set_text(OUString()); + } + UpdateColMgr(*m_xLineWidthEdit); +} + +// Update Bsp +void SwColumnPage::ActivatePage(const SfxItemSet& rSet) +{ + bool bVertical = false; + if (SfxItemState::DEFAULT <= rSet.GetItemState(RES_FRAMEDIR)) + { + const SvxFrameDirectionItem& rDirItem = + rSet.Get(RES_FRAMEDIR); + bVertical = rDirItem.GetValue() == SvxFrameDirection::Vertical_RL_TB|| + rDirItem.GetValue() == SvxFrameDirection::Vertical_LR_TB; + } + + if (!m_bFrame) + { + if( SfxItemState::SET == rSet.GetItemState( SID_ATTR_PAGE_SIZE )) + { + const SvxSizeItem& rSize = rSet.Get(SID_ATTR_PAGE_SIZE); + + sal_uInt16 nActWidth; + + if (!bVertical) + { + const SvxLRSpaceItem& rLRSpace = rSet.Get(RES_LR_SPACE); + const SvxBoxItem& rBox = rSet.Get(RES_BOX); + nActWidth = rSize.GetSize().Width() + - rLRSpace.GetLeft() - rLRSpace.GetRight() - rBox.GetSmallestDistance(); + } + else + { + const SvxULSpaceItem& rULSpace = rSet.Get( RES_UL_SPACE ); + const SvxBoxItem& rBox = rSet.Get(RES_BOX); + nActWidth = rSize.GetSize().Height() + - rULSpace.GetUpper() - rULSpace.GetLower() - rBox.GetSmallestDistance(); + + } + + if( m_xColMgr->GetActualSize() != nActWidth) + { + m_xColMgr->SetActualWidth(nActWidth); + ColModify(/*bForceColReset=*/false); + UpdateColMgr( *m_xLineWidthEdit ); + } + } + m_xFrameExampleWN->hide(); + m_aPgeExampleWN.UpdateExample(rSet, m_xColMgr.get()); + m_xPgeExampleWN->show(); + + } + else + { + m_xPgeExampleWN->hide(); + m_xFrameExampleWN->show(); + + // Size + const SwFormatFrameSize& rSize = rSet.Get(RES_FRM_SIZE); + const SvxBoxItem& rBox = rSet.Get(RES_BOX); + + sal_uInt16 nTotalWish; + if (m_bFormat) + nTotalWish = FRAME_FORMAT_WIDTH; + else + { + tools::Long const nDistance = rBox.GetSmallestDistance(); + nTotalWish = (!bVertical ? rSize.GetWidth() : rSize.GetHeight()) - 2 * nDistance; + } + + // set maximum values of column width + SetPageWidth(nTotalWish); + + if(m_xColMgr->GetActualSize() != nTotalWish) + { + m_xColMgr->SetActualWidth(nTotalWish); + Init(); + } + bool bPercent; + // only relative data in frame format + if ( m_bFormat || (rSize.GetWidthPercent() && rSize.GetWidthPercent() != SwFormatFrameSize::SYNCED) ) + { + // set value for 100% + m_xEd1->SetRefValue(nTotalWish); + m_xEd2->SetRefValue(nTotalWish); + m_xEd3->SetRefValue(nTotalWish); + m_xDistEd1->SetRefValue(nTotalWish); + m_xDistEd2->SetRefValue(nTotalWish); + + // switch to %-view + bPercent = true; + } + else + bPercent = false; + + m_xEd1->ShowPercent(bPercent); + m_xEd2->ShowPercent(bPercent); + m_xEd3->ShowPercent(bPercent); + m_xDistEd1->ShowPercent(bPercent); + m_xDistEd2->ShowPercent(bPercent); + m_xDistEd1->SetMetricFieldMin(0); + m_xDistEd2->SetMetricFieldMin(0); + } + Update(nullptr); +} + +DeactivateRC SwColumnPage::DeactivatePage(SfxItemSet *_pSet) +{ + if(_pSet) + FillItemSet(_pSet); + + return DeactivateRC::LeavePage; +} + +IMPL_LINK(SwColumnPage, SetDefaultsHdl, ValueSet *, pVS, void) +{ + const sal_uInt16 nItem = pVS->GetSelectedItemId(); + if( nItem < 4 ) + { + m_xCLNrEdt->set_value(nItem); + m_xAutoWidthBox->set_active(true); + m_xDistEd1->set_value(50, FieldUnit::CM); + ColModify(/*bForceColReset=*/true); + } + else + { + m_bLockUpdate = true; + m_xCLNrEdt->set_value(2); + m_xAutoWidthBox->set_active(false); + m_xDistEd1->set_value(50, FieldUnit::CM); + ColModify(/*bForceColReset=*/true); + // now set the width ratio to 2 : 1 or 1 : 2 respectively + const tools::Long nSmall = static_cast< tools::Long >(m_xColMgr->GetActualSize() / 3); + if(nItem == 4) + { + m_xEd2->set_value(m_xEd2->NormalizePercent(nSmall), FieldUnit::TWIP); + m_pModifiedField = m_xEd2.get(); + } + else + { + m_xEd1->set_value(m_xEd1->NormalizePercent(nSmall), FieldUnit::TWIP); + m_pModifiedField = m_xEd1.get(); + } + m_bLockUpdate = false; + Timeout(); + + } +} + +void SwColumnPage::SetFrameMode(bool bMod) +{ + m_bFrame = bMod; +} + +void SwColumnPage::SetInSection(bool bSet) +{ + if(!SvtCTLOptions::IsCTLFontEnabled()) + return; + + m_xTextDirectionFT->set_visible(bSet); + m_xTextDirectionLB->set_visible(bSet); +} + +void ColumnValueSet::UserDraw(const UserDrawEvent& rUDEvt) +{ + vcl::RenderContext* pDev = rUDEvt.GetRenderContext(); + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + + tools::Rectangle aRect = rUDEvt.GetRect(); + const sal_uInt16 nItemId = rUDEvt.GetItemId(); + tools::Long nRectWidth = aRect.GetWidth(); + tools::Long nRectHeight = aRect.GetHeight(); + + Point aBLPos = aRect.TopLeft(); + Color aFillColor(pDev->GetFillColor()); + Color aLineColor(pDev->GetLineColor()); + pDev->SetFillColor(rStyleSettings.GetFieldColor()); + pDev->SetLineColor(rStyleSettings.GetFieldTextColor()); + + tools::Long nStep = std::abs(std::abs(nRectHeight * 95 /100) / 11); + tools::Long nTop = (nRectHeight - 11 * nStep ) / 2; + sal_uInt16 nCols = 0; + tools::Long nStarts[3]; + tools::Long nEnds[3]; + nStarts[0] = nRectWidth * 10 / 100; + switch( nItemId ) + { + case 1: + nEnds[0] = nRectWidth * 9 / 10; + nCols = 1; + break; + case 2: nCols = 2; + nEnds[0] = nRectWidth * 45 / 100; + nStarts[1] = nEnds[0] + nStep; + nEnds[1] = nRectWidth * 9 / 10; + break; + case 3: nCols = 3; + nEnds[0] = nRectWidth * 30 / 100; + nStarts[1] = nEnds[0] + nStep; + nEnds[1] = nRectWidth * 63 / 100; + nStarts[2] = nEnds[1] + nStep; + nEnds[2] = nRectWidth * 9 / 10; + break; + case 4: nCols = 2; + nEnds[0] = nRectWidth * 63 / 100; + nStarts[1] = nEnds[0] + nStep; + nEnds[1] = nRectWidth * 9 / 10; + break; + case 5: nCols = 2; + nEnds[0] = nRectWidth * 30 / 100; + nStarts[1] = nEnds[0] + nStep; + nEnds[1] = nRectWidth * 9 / 10; + break; + } + for(sal_uInt16 j = 0; j < nCols; j++ ) + { + Point aStart(aBLPos.X() + nStarts[j], 0); + Point aEnd(aBLPos.X() + nEnds[j], 0); + for( sal_uInt16 i = 0; i < 12; i ++) + { + aStart.setY( aBLPos.Y() + nTop + i * nStep); + aEnd.setY( aStart.Y() ); + pDev->DrawLine(aStart, aEnd); + } + } + pDev->SetFillColor(aFillColor); + pDev->SetLineColor(aLineColor); +} + +void ColumnValueSet::StyleUpdated() +{ + SetFormat(); + Invalidate(); + ValueSet::StyleUpdated(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/frmdlg/cption.cxx b/sw/source/ui/frmdlg/cption.cxx new file mode 100644 index 0000000000..e6b387a429 --- /dev/null +++ b/sw/source/ui/frmdlg/cption.cxx @@ -0,0 +1,537 @@ +/* -*- 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 <utility> +#include <view.hxx> +#include <wrtsh.hxx> +#include <cption.hxx> +#include <fldmgr.hxx> +#include <expfld.hxx> +#include <numrule.hxx> +#include <poolfmt.hxx> +#include <docsh.hxx> +#include <calc.hxx> +#include <uitool.hxx> +#include <doc.hxx> +#include <modcfg.hxx> +#include <swmodule.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp> +#include <com/sun/star/text/XTextTablesSupplier.hpp> +#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp> +#include <com/sun/star/text/XTextFramesSupplier.hpp> +#include <comphelper/string.hxx> +#include <vcl/weld.hxx> +#include <strings.hrc> +#include <SwStyleNameMapper.hxx> + +using namespace ::com::sun::star; + +namespace { + +class SwSequenceOptionDialog : public weld::GenericDialogController +{ + SwView& m_rView; + OUString m_aFieldTypeName; + + std::unique_ptr<weld::ComboBox> m_xLbLevel; + std::unique_ptr<weld::Entry> m_xEdDelim; + + std::unique_ptr<weld::ComboBox> m_xLbCharStyle; + std::unique_ptr<weld::CheckButton> m_xApplyBorderAndShadowCB; + + //#i61007# order of captions + std::unique_ptr<weld::ComboBox> m_xLbCaptionOrder; + +public: + SwSequenceOptionDialog(weld::Window *pParent, SwView &rV, OUString aSeqFieldType); + void Apply(); + + bool IsApplyBorderAndShadow() const { return m_xApplyBorderAndShadowCB->get_active(); } + void SetApplyBorderAndShadow( bool bSet ) { m_xApplyBorderAndShadowCB->set_active(bSet); } + + //#i61007# order of captions + bool IsOrderNumberingFirst() const { return m_xLbCaptionOrder->get_active() == 1; } + void SetOrderNumberingFirst(bool bSet) { m_xLbCaptionOrder->set_active(bSet ? 1 : 0); } + + void SetCharacterStyle(const OUString& rStyle); + OUString GetCharacterStyle() const; +}; + +} + +OUString SwCaptionDialog::s_aSepTextSave(": "); // Caption separator text + +//Resolves: tdf#47427 disallow typing *or* pasting invalid content into the category box +OUString TextFilterAutoConvert::filter(const OUString &rText) +{ + if (!rText.isEmpty() && rText != m_sNone && !SwCalc::IsValidVarName(rText)) + return m_sLastGoodText; + m_sLastGoodText = rText; + return rText; +} + +SwCaptionDialog::SwCaptionDialog(weld::Window *pParent, SwView &rV) + : SfxDialogController(pParent, "modules/swriter/ui/insertcaption.ui", "InsertCaptionDialog") + , m_sNone(SwResId(SW_STR_NONE)) + , m_aTextFilter(m_sNone) + , m_rView(rV) + , m_pMgr(new SwFieldMgr(m_rView.GetWrtShellPtr())) + , m_bCopyAttributes(false) + , m_bOrderNumberingFirst(SW_MOD()->GetModuleConfig()->IsCaptionOrderNumberingFirst()) + , m_xTextEdit(m_xBuilder->weld_entry("caption_edit")) + , m_xCategoryBox(m_xBuilder->weld_combo_box("category")) + , m_xFormatText(m_xBuilder->weld_label("numbering_label")) + , m_xFormatBox(m_xBuilder->weld_combo_box("numbering")) + , m_xNumberingSeparatorFT(m_xBuilder->weld_label("num_separator")) + , m_xNumberingSeparatorED(m_xBuilder->weld_entry("num_separator_edit")) + , m_xSepText(m_xBuilder->weld_label("separator_label")) + , m_xSepEdit(m_xBuilder->weld_entry("separator_edit")) + , m_xPosBox(m_xBuilder->weld_combo_box("position")) + , m_xOKButton(m_xBuilder->weld_button("ok")) + , m_xAutoCaptionButton(m_xBuilder->weld_button("auto")) + , m_xOptionButton(m_xBuilder->weld_button("options")) + , m_xPreview(new weld::CustomWeld(*m_xBuilder, "preview", m_aPreview)) +{ + //#i61007# order of captions + ApplyCaptionOrder(); + SwWrtShell &rSh = m_rView.GetWrtShell(); + uno::Reference< frame::XModel > xModel = m_rView.GetDocShell()->GetBaseModel(); + + SelectionType eType = rSh.GetSelectionType(); + if ( eType & SelectionType::Ole ) + { + eType = SelectionType::Graphic; + uno::Reference< text::XTextEmbeddedObjectsSupplier > xObjs(xModel, uno::UNO_QUERY); + m_xNameAccess = xObjs->getEmbeddedObjects(); + } + + m_xCategoryBox->connect_changed(LINK(this, SwCaptionDialog, ModifyComboHdl)); + Link<weld::Entry&,void> aLk = LINK(this, SwCaptionDialog, ModifyEntryHdl); + m_xTextEdit->connect_changed(aLk); + m_xNumberingSeparatorED->connect_changed(aLk); + m_xSepEdit->connect_changed(aLk); + + m_xFormatBox->connect_changed(LINK(this, SwCaptionDialog, SelectListBoxHdl)); + m_xOKButton->connect_clicked(LINK(this, SwCaptionDialog, OKHdl)); + m_xOptionButton->connect_clicked(LINK(this, SwCaptionDialog, OptionHdl)); + m_xAutoCaptionButton->connect_clicked(LINK(this, SwCaptionDialog, CaptionHdl)); + m_xAutoCaptionButton->set_accessible_description(SwResId(STR_A11Y_DESC_AUTO)); + + m_xCategoryBox->append_text(m_sNone); + size_t nCount = m_pMgr->GetFieldTypeCount(); + for (size_t i = 0; i < nCount; ++i) + { + SwFieldType *pType = m_pMgr->GetFieldType( SwFieldIds::Unknown, i ); + if( pType->Which() == SwFieldIds::SetExp && + static_cast<SwSetExpFieldType *>( pType)->GetType() & nsSwGetSetExpType::GSE_SEQ ) + m_xCategoryBox->append_text(pType->GetName()); + } + + OUString sString; + sal_uInt16 nPoolId = 0; + if (eType & SelectionType::Graphic) + { + nPoolId = RES_POOLCOLL_LABEL_FIGURE; + + SwSetExpFieldType* pTypeIll= static_cast<SwSetExpFieldType*>(rSh.GetFieldType(SwFieldIds::SetExp, SwResId(STR_POOLCOLL_LABEL_ABB))); + if(rSh.IsUsed(*pTypeIll)) //default to illustration for legacy docs + { + nPoolId = RES_POOLCOLL_LABEL_ABB; + + } + + sString = m_rView.GetOldGrfCat(); + m_bCopyAttributes = true; + //if not OLE + if(!m_xNameAccess.is()) + { + uno::Reference< text::XTextGraphicObjectsSupplier > xGraphics(xModel, uno::UNO_QUERY); + m_xNameAccess = xGraphics->getGraphicObjects(); + } + + } + else if( eType & SelectionType::Table ) + { + nPoolId = RES_POOLCOLL_LABEL_TABLE; + sString = m_rView.GetOldTabCat(); + uno::Reference< text::XTextTablesSupplier > xTables(xModel, uno::UNO_QUERY); + m_xNameAccess = xTables->getTextTables(); + } + else if( eType & SelectionType::Frame ) + { + nPoolId = RES_POOLCOLL_LABEL_FRAME; + sString = m_rView.GetOldFrameCat(); + uno::Reference< text::XTextFramesSupplier > xFrames(xModel, uno::UNO_QUERY); + m_xNameAccess = xFrames->getTextFrames(); + } + else if( eType == SelectionType::Text ) + { + nPoolId = RES_POOLCOLL_LABEL_FRAME; + sString = m_rView.GetOldFrameCat(); + } + else if( eType & SelectionType::DrawObject ) + { + nPoolId = RES_POOLCOLL_LABEL_DRAWING; + sString = m_rView.GetOldDrwCat(); + } + if( nPoolId ) + { + if (sString.isEmpty()) + sString = SwStyleNameMapper::GetUIName(nPoolId, OUString()); + auto nIndex = m_xCategoryBox->find_text(sString); + if (nIndex != -1) + m_xCategoryBox->set_active(nIndex); + else + m_xCategoryBox->set_entry_text(sString); + } + + // aFormatBox + sal_uInt16 nSelFormat = SVX_NUM_ARABIC; + nCount = m_pMgr->GetFieldTypeCount(); + for ( size_t i = nCount; i; ) + { + SwFieldType* pFieldType = m_pMgr->GetFieldType(SwFieldIds::Unknown, --i); + if (pFieldType->GetName() == m_xCategoryBox->get_active_text()) + { + nSelFormat = o3tl::narrowing<sal_uInt16>(static_cast<SwSetExpFieldType*>(pFieldType)->GetSeqFormat()); + break; + } + } + + sal_uInt16 nFormatCount = m_pMgr->GetFormatCount(SwFieldTypesEnum::Sequence, false); + for ( sal_uInt16 i = 0; i < nFormatCount; ++i ) + { + const sal_uInt16 nFormatId = m_pMgr->GetFormatId(SwFieldTypesEnum::Sequence, i); + m_xFormatBox->append(OUString::number(nFormatId), m_pMgr->GetFormatStr(SwFieldTypesEnum::Sequence, i)); + if (nFormatId == nSelFormat) + m_xFormatBox->set_active(i); + } + + // aPosBox + if (eType == SelectionType::Graphic + || eType == SelectionType::Table + || eType == (SelectionType::Table | SelectionType::NumberList) + || eType == (SelectionType::Table | SelectionType::Text) + || eType == (SelectionType::Table | SelectionType::NumberList | SelectionType::Text) + || eType == SelectionType::DrawObject + || eType == (SelectionType::DrawObject | SelectionType::Ornament)) + { + m_xPosBox->append_text(SwResId(STR_CAPTION_ABOVE)); + m_xPosBox->append_text(SwResId(STR_CAPTION_BELOW)); + } + else if(eType == SelectionType::Frame + || eType == SelectionType::Text) + { + m_xPosBox->append_text(SwResId(STR_CAPTION_BEGINNING)); + m_xPosBox->append_text(SwResId(STR_CAPTION_END)); + } + + if (eType & SelectionType::Table) + { + m_xPosBox->set_active(0); + } + else + { + m_xPosBox->set_active(1); + } + + ModifyHdl(); + + m_xSepEdit->set_text(s_aSepTextSave); + m_xTextEdit->grab_focus(); + DrawSample(); +} + +IMPL_LINK_NOARG(SwCaptionDialog, OKHdl, weld::Button&, void) +{ + Apply(); + m_xDialog->response(RET_OK); +} + +void SwCaptionDialog::Apply() +{ + InsCaptionOpt aOpt; + aOpt.UseCaption() = true; + OUString aName(m_xCategoryBox->get_active_text()); + if ( aName == m_sNone ) + { + aOpt.SetCategory( OUString() ); + aOpt.SetNumSeparator( OUString() ); + } + else + { + aOpt.SetCategory(comphelper::string::strip(aName, ' ')); + aOpt.SetNumSeparator(m_xNumberingSeparatorED->get_text()); + } + aOpt.SetNumType(m_xFormatBox->get_active_id().toUInt32()); + aOpt.SetSeparator(m_xSepEdit->get_sensitive() ? m_xSepEdit->get_text() : OUString()); + aOpt.SetCaption(m_xTextEdit->get_text()); + aOpt.SetPos(m_xPosBox->get_active()); + aOpt.IgnoreSeqOpts() = true; + aOpt.CopyAttributes() = m_bCopyAttributes; + aOpt.SetCharacterStyle( m_sCharacterStyle ); + m_rView.InsertCaption( &aOpt ); + s_aSepTextSave = m_xSepEdit->get_text(); +} + +short SwCaptionDialog::run() +{ + short nRet = SfxDialogController::run(); + if (nRet == RET_OK) + Apply(); + return nRet; +} + +IMPL_LINK_NOARG(SwCaptionDialog, OptionHdl, weld::Button&, void) +{ + OUString sFieldTypeName = m_xCategoryBox->get_active_text(); + if(sFieldTypeName == m_sNone) + sFieldTypeName.clear(); + auto pDlg = std::make_shared<SwSequenceOptionDialog>(m_xDialog.get(), m_rView, sFieldTypeName); + pDlg->SetApplyBorderAndShadow(m_bCopyAttributes); + pDlg->SetCharacterStyle( m_sCharacterStyle ); + pDlg->SetOrderNumberingFirst( m_bOrderNumberingFirst ); + + GenericDialogController::runAsync(pDlg, [pDlg, this](sal_Int32 nResult){ + if (nResult == RET_OK) { + pDlg->Apply(); + m_bCopyAttributes = pDlg->IsApplyBorderAndShadow(); + m_sCharacterStyle = pDlg->GetCharacterStyle(); + //#i61007# order of captions + if( m_bOrderNumberingFirst != pDlg->IsOrderNumberingFirst() ) + { + m_bOrderNumberingFirst = pDlg->IsOrderNumberingFirst(); + SW_MOD()->GetModuleConfig()->SetCaptionOrderNumberingFirst(m_bOrderNumberingFirst); + ApplyCaptionOrder(); + } + DrawSample(); + } + }); +} + +IMPL_LINK_NOARG(SwCaptionDialog, SelectListBoxHdl, weld::ComboBox&, void) +{ + DrawSample(); +} + +void SwCaptionDialog::ModifyHdl() +{ + SwWrtShell &rSh = m_rView.GetWrtShell(); + OUString sFieldTypeName = m_xCategoryBox->get_active_text(); + bool bCorrectFieldName = !sFieldTypeName.isEmpty(); + bool bNone = sFieldTypeName == m_sNone; + SwFieldType* pType = (bCorrectFieldName && !bNone) + ? rSh.GetFieldType( SwFieldIds::SetExp, sFieldTypeName ) + : nullptr; + m_xOKButton->set_sensitive( bCorrectFieldName && + (!pType || + static_cast<SwSetExpFieldType*>(pType)->GetType() == nsSwGetSetExpType::GSE_SEQ) ); + m_xOptionButton->set_sensitive(m_xOKButton->get_sensitive() && !bNone); + m_xNumberingSeparatorFT->set_sensitive(m_bOrderNumberingFirst && !bNone); + m_xNumberingSeparatorED->set_sensitive(m_bOrderNumberingFirst && !bNone); + m_xFormatText->set_sensitive(!bNone); + m_xFormatBox->set_sensitive(!bNone); + m_xSepText->set_sensitive(!bNone); + m_xSepEdit->set_sensitive(!bNone); + DrawSample(); +} + +IMPL_LINK_NOARG(SwCaptionDialog, ModifyEntryHdl, weld::Entry&, void) +{ + ModifyHdl(); +} + +IMPL_LINK_NOARG(SwCaptionDialog, ModifyComboHdl, weld::ComboBox&, void) +{ + OUString sText = m_xCategoryBox->get_active_text(); + OUString sAllowedText = m_aTextFilter.filter(sText); + if (sText != sAllowedText) + { + m_xCategoryBox->set_entry_text(sAllowedText); + m_xCategoryBox->select_entry_region(sAllowedText.getLength(), sAllowedText.getLength()); + } + ModifyHdl(); +} + +IMPL_LINK_NOARG(SwCaptionDialog, CaptionHdl, weld::Button&, void) +{ + SfxItemSet aSet(m_rView.GetDocShell()->GetDoc()->GetAttrPool()); + SwCaptionOptDlg aDlg(m_xDialog.get(), aSet); + aDlg.run(); +} + +void SwCaptionDialog::DrawSample() +{ + OUString aStr; + OUString sCaption = m_xTextEdit->get_text(); + + // number + OUString sFieldTypeName = m_xCategoryBox->get_active_text(); + bool bNone = sFieldTypeName == m_sNone; + if( !bNone ) + { + const sal_uInt16 nNumFormat = m_xFormatBox->get_active_id().toUInt32(); + if (SVX_NUM_NUMBER_NONE != nNumFormat) + { + // category + //#i61007# order of captions + if( !m_bOrderNumberingFirst ) + { + aStr = sFieldTypeName; + if ( !aStr.isEmpty() ) + aStr += " "; + } + + SwWrtShell &rSh = m_rView.GetWrtShell(); + SwSetExpFieldType* pFieldType = static_cast<SwSetExpFieldType*>(rSh.GetFieldType( + SwFieldIds::SetExp, sFieldTypeName )); + if( pFieldType && pFieldType->GetOutlineLvl() < MAXLEVEL ) + { + SwNumberTree::tNumberVector aNumVector; + aNumVector.insert(aNumVector.end(), pFieldType->GetOutlineLvl() + 1, 1); + + OUString sNumber( rSh.GetOutlineNumRule()-> + MakeNumString(aNumVector, false )); + if( !sNumber.isEmpty() ) + aStr += sNumber + pFieldType->GetDelimiter(); + } + + switch( nNumFormat ) + { + case SVX_NUM_CHARS_UPPER_LETTER: aStr += "A"; break; + case SVX_NUM_CHARS_UPPER_LETTER_N: aStr += "A"; break; + case SVX_NUM_CHARS_LOWER_LETTER: aStr += "a"; break; + case SVX_NUM_CHARS_LOWER_LETTER_N: aStr += "a"; break; + case SVX_NUM_ROMAN_UPPER: aStr += "I"; break; + case SVX_NUM_ROMAN_LOWER: aStr += "i"; break; + default: aStr += "1"; break; + } + //#i61007# order of captions + if( m_bOrderNumberingFirst ) + { + aStr += m_xNumberingSeparatorED->get_text() + sFieldTypeName; + } + + } + if( !sCaption.isEmpty() ) + { + aStr += m_xSepEdit->get_text(); + } + } + aStr += sCaption; + // do preview! + m_aPreview.SetPreviewText(aStr); +} + +SwCaptionDialog::~SwCaptionDialog() +{ +} + +SwSequenceOptionDialog::SwSequenceOptionDialog(weld::Window *pParent, SwView &rV, OUString aSeqFieldType ) + : GenericDialogController(pParent, "modules/swriter/ui/captionoptions.ui", "CaptionOptionsDialog") + , m_rView(rV) + , m_aFieldTypeName(std::move(aSeqFieldType)) + , m_xLbLevel(m_xBuilder->weld_combo_box("level")) + , m_xEdDelim(m_xBuilder->weld_entry("separator")) + , m_xLbCharStyle(m_xBuilder->weld_combo_box("style")) + , m_xApplyBorderAndShadowCB(m_xBuilder->weld_check_button("border_and_shadow")) + , m_xLbCaptionOrder(m_xBuilder->weld_combo_box("caption_order")) +{ + SwWrtShell &rSh = m_rView.GetWrtShell(); + + const OUString sNone(SwResId(SW_STR_NONE)); + + m_xLbLevel->append_text(sNone); + for (sal_uInt16 n = 0; n < MAXLEVEL; ++n) + m_xLbLevel->append_text(OUString::number(n + 1)); + + SwSetExpFieldType* pFieldType = static_cast<SwSetExpFieldType*>(rSh.GetFieldType( + SwFieldIds::SetExp, m_aFieldTypeName )); + + sal_Unicode nLvl = MAXLEVEL; + OUString sDelim(": "); + if( pFieldType ) + { + sDelim = pFieldType->GetDelimiter(); + nLvl = pFieldType->GetOutlineLvl(); + } + + m_xLbLevel->set_active(nLvl < MAXLEVEL ? nLvl + 1 : 0); + m_xEdDelim->set_text(sDelim); + + m_xLbCharStyle->append_text(sNone); + ::FillCharStyleListBox(*m_xLbCharStyle, m_rView.GetDocShell(), true, true); + m_xLbCharStyle->set_active(0); +} + +void SwSequenceOptionDialog::Apply() +{ + SwWrtShell &rSh = m_rView.GetWrtShell(); + SwSetExpFieldType* pFieldType = static_cast<SwSetExpFieldType*>(rSh.GetFieldType( + SwFieldIds::SetExp, m_aFieldTypeName )); + + sal_Int8 nLvl = static_cast<sal_Int8>(m_xLbLevel->get_active() - 1); + sal_Unicode cDelim = m_xEdDelim->get_text()[0]; + + bool bUpdate = true; + if( pFieldType ) + { + pFieldType->SetDelimiter( OUString(cDelim) ); + pFieldType->SetOutlineLvl( nLvl ); + } + else if( !m_aFieldTypeName.isEmpty() && nLvl < MAXLEVEL ) + { + // then we have to insert that + SwSetExpFieldType aFieldType( rSh.GetDoc(), m_aFieldTypeName, nsSwGetSetExpType::GSE_SEQ ); + aFieldType.SetDelimiter( OUString(cDelim) ); + aFieldType.SetOutlineLvl( nLvl ); + rSh.InsertFieldType( aFieldType ); + } + else + bUpdate = false; + + if( bUpdate ) + rSh.UpdateExpFields(); +} + +OUString SwSequenceOptionDialog::GetCharacterStyle() const +{ + if (m_xLbCharStyle->get_active() != -1) + return m_xLbCharStyle->get_active_text(); + return OUString(); +} + +void SwSequenceOptionDialog::SetCharacterStyle(const OUString& rStyle) +{ + const int nPos = m_xLbCharStyle->find_text(rStyle); + if (nPos == -1) + m_xLbCharStyle->set_active(0); + else + m_xLbCharStyle->set_active(nPos); +} + +// #i61007# order of captions +void SwCaptionDialog::ApplyCaptionOrder() +{ + m_xNumberingSeparatorFT->set_sensitive(m_bOrderNumberingFirst); + m_xNumberingSeparatorED->set_sensitive(m_bOrderNumberingFirst); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/frmdlg/frmdlg.cxx b/sw/source/ui/frmdlg/frmdlg.cxx new file mode 100644 index 0000000000..0eaf29dfe6 --- /dev/null +++ b/sw/source/ui/frmdlg/frmdlg.cxx @@ -0,0 +1,201 @@ +/* -*- 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/dialogs.hrc> +#include <hintids.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/sfxdlg.hxx> +#include <sfx2/htmlmode.hxx> +#include <fmtfsize.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <viewopt.hxx> +#include <frmdlg.hxx> +#include <frmpage.hxx> +#include <wrap.hxx> +#include <column.hxx> +#include <macassgn.hxx> +#include <IDocumentSettingAccess.hxx> + +#include <strings.hrc> +#include <svl/eitem.hxx> +#include <svx/svxids.hrc> +#include <svx/flagsdef.hxx> +#include <svx/drawitem.hxx> +#include <comphelper/lok.hxx> + +// the dialog's carrier +SwFrameDlg::SwFrameDlg(const SfxViewFrame& rViewFrame, + weld::Window* pParent, + const SfxItemSet& rCoreSet, + bool bNewFrame, + const OUString& sResType, + bool bFormat, + const OUString& sDefPage, + const OUString* pStr) + + : SfxTabDialogController(pParent, "modules/swriter/ui/" + sResType.toAsciiLowerCase() + ".ui", + sResType, &rCoreSet, pStr != nullptr) + , m_bFormat(bFormat) + , m_bNew(bNewFrame) + , m_rSet(rCoreSet) + , m_sDlgType(sResType) + , m_pWrtShell(static_cast<SwView*>(rViewFrame.GetViewShell())->GetWrtShellPtr()) +{ + sal_uInt16 nHtmlMode = ::GetHtmlMode(m_pWrtShell->GetView().GetDocShell()); + bool bHTMLMode = (nHtmlMode & HTMLMODE_ON) != 0; + + // example font for both example TabPages + + if (pStr) + { + m_xDialog->set_title(m_xDialog->get_title() + SwResId(STR_FRMUI_COLL_HEADER) + *pStr + ")"); + } + + AddTabPage("type", SwFramePage::Create, nullptr); + AddTabPage("options", SwFrameAddPage::Create, nullptr); + AddTabPage("wrap", SwWrapTabPage::Create, nullptr); + AddTabPage("hyperlink", SwFrameURLPage::Create, nullptr); + if (m_sDlgType == "PictureDialog") + { + AddTabPage("picture", SwGrfExtPage::Create, nullptr); + AddTabPage("crop", RID_SVXPAGE_GRFCROP); + } + if (m_sDlgType == "FrameDialog") + { + AddTabPage("columns", SwColumnPage::Create, nullptr); + } + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + + // add Area and Transparence TabPages + AddTabPage("area", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_AREA ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_AREA )); + AddTabPage("transparence", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_TRANSPARENCE ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_TRANSPARENCE ) ); + + AddTabPage("macro", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_MACROASSIGN), nullptr); + AddTabPage("borders", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BORDER ), nullptr); + + if(bHTMLMode) + { + if (m_sDlgType == "FrameDialog" || m_sDlgType == "ObjectDialog") + { + if (m_sDlgType == "FrameDialog") + RemoveTabPage("columns"); + RemoveTabPage("hyperlink"); + RemoveTabPage("macro"); + } + else if (m_sDlgType == "PictureDialog") + RemoveTabPage("crop"); + if( m_sDlgType != "FrameDialog" ) + { + // RemoveTabPage("background"); + RemoveTabPage("area"); + RemoveTabPage("transparence"); + } + } + + if(comphelper::LibreOfficeKit::isActive()) + RemoveTabPage("macro"); + + if (m_bNew) + SetCurPageId("type"); + + if (!sDefPage.isEmpty()) + SetCurPageId(sDefPage); +} + +SwFrameDlg::~SwFrameDlg() +{ +} + +void SwFrameDlg::PageCreated(const OUString& rId, SfxTabPage &rPage) +{ + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + if (rId == "type") + { + static_cast<SwFramePage&>(rPage).SetNewFrame(m_bNew); + static_cast<SwFramePage&>(rPage).SetFormatUsed(m_bFormat); + static_cast<SwFramePage&>(rPage).SetFrameType(m_sDlgType); + } + else if (rId == "options") + { + static_cast<SwFrameAddPage&>(rPage).SetFormatUsed(m_bFormat); + static_cast<SwFrameAddPage&>(rPage).SetFrameType(m_sDlgType); + static_cast<SwFrameAddPage&>(rPage).SetNewFrame(m_bNew); + static_cast<SwFrameAddPage&>(rPage).SetShell(m_pWrtShell); + } + else if (rId == "wrap") + { + static_cast<SwWrapTabPage&>(rPage).SetNewFrame(m_bNew); + static_cast<SwWrapTabPage&>(rPage).SetFormatUsed(m_bFormat, false); + static_cast<SwWrapTabPage&>(rPage).SetShell(m_pWrtShell); + } + else if (rId == "columns") + { + static_cast<SwColumnPage&>(rPage).SetFrameMode(true); + static_cast<SwColumnPage&>(rPage).SetFormatUsed(m_bFormat); + + const SwFormatFrameSize& rSize = m_rSet.Get( RES_FRM_SIZE ); + static_cast<SwColumnPage&>(rPage).SetPageWidth( rSize.GetWidth() ); + } + else if (rId == "macro") + { + SfxAllItemSet aNewSet(*aSet.GetPool()); + aNewSet.Put( SwMacroAssignDlg::AddEvents( + m_sDlgType == "PictureDialog" ? MACASSGN_GRAPHIC : m_sDlgType == "ObjectDialog" ? MACASSGN_OLE : MACASSGN_FRMURL ) ); + if (m_pWrtShell) + rPage.SetFrame( m_pWrtShell->GetView().GetViewFrame().GetFrame().GetFrameInterface() ); + rPage.PageCreated(aNewSet); + } + else if (rId == "borders") + { + aSet.Put (SfxUInt16Item(SID_SWMODE_TYPE,static_cast<sal_uInt16>(SwBorderModes::FRAME))); + rPage.PageCreated(aSet); + } + // inits for Area and Transparency TabPages + // The selection attribute lists (XPropertyList derivates, e.g. XColorList for + // the color table) need to be added as items (e.g. SvxColorListItem) to make + // these pages find the needed attributes for fill style suggestions. + // These are set in preparation to trigger this dialog (FN_FORMAT_FRAME_DLG and + // FN_DRAW_WRAP_DLG), but could also be directly added from the DrawModel. + else if (rId == "area") + { + SfxItemSetFixed<SID_COLOR_TABLE, SID_PATTERN_LIST, + SID_OFFER_IMPORT, SID_OFFER_IMPORT> + aNew(*GetInputSetImpl()->GetPool()); + + aNew.Put(m_rSet); + + // add flag for direct graphic content selection + aNew.Put(SfxBoolItem(SID_OFFER_IMPORT, true)); + + rPage.PageCreated(aNew); + } + else if (rId == "transparence") + { + rPage.PageCreated(m_rSet); + } + else if (rId == "crop") + { + sal_Int32 nPreferredDPI = m_pWrtShell->GetDoc()->getIDocumentSettingAccess().getImagePreferredDPI(); + if (nPreferredDPI) + rPage.getAdditionalProperties().emplace("PreferredDPI", css::uno::Any(nPreferredDPI)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/frmdlg/frmpage.cxx b/sw/source/ui/frmdlg/frmpage.cxx new file mode 100644 index 0000000000..b3e2a873ad --- /dev/null +++ b/sw/source/ui/frmdlg/frmpage.cxx @@ -0,0 +1,3285 @@ +/* -*- 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 <com/sun/star/embed/Aspects.hpp> +#include <com/sun/star/embed/EmbedMisc.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> + +#include <cmdid.h> +#include <hintids.hxx> +#include <bitmaps.hlst> +#include <o3tl/safeint.hxx> +#include <vcl/mnemonic.hxx> +#include <svl/stritem.hxx> +#include <sfx2/htmlmode.hxx> +#include <editeng/opaqitem.hxx> +#include <editeng/protitem.hxx> +#include <editeng/prntitem.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <svx/swframeposstrings.hxx> +#include <svx/swframevalidation.hxx> +#include <svx/sdangitm.hxx> +#include <comphelper/classids.hxx> +#include <tools/globname.hxx> +#include <tools/urlobj.hxx> +#include <fmturl.hxx> +#include <fmteiro.hxx> +#include <fmtcnct.hxx> +#include <fmtsrnd.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <swmodule.hxx> +#include <uitool.hxx> +#include <docsh.hxx> +#include <viewopt.hxx> +#include <frmdlg.hxx> +#include <frmmgr.hxx> +#include <frmpage.hxx> +#include <colmgr.hxx> +#include <grfatr.hxx> +#include <fmtfollowtextflow.hxx> +#include <svx/sdtaitm.hxx> +#include <sal/macros.h> +#include <osl/diagnose.h> + +#include <strings.hrc> +#include <formatflysplit.hxx> +#include <fmtcntnt.hxx> +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> +#include <svx/graphichelper.hxx> +#include <sfx2/filedlghelper.hxx> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#include <vcl/graphicfilter.hxx> +#include <svtools/embedhlp.hxx> +#include <comphelper/lok.hxx> +#include <memory> + +using namespace ::com::sun::star; +using namespace ::sfx2; + +#define SwFPos SvxSwFramePosString + +namespace { + +struct StringIdPair_Impl +{ + SvxSwFramePosString::StringId eHori; + SvxSwFramePosString::StringId eVert; +}; + +} + +#define MAX_PERCENT_WIDTH SAL_CONST_INT64(254) +#define MAX_PERCENT_HEIGHT SAL_CONST_INT64(254) + +namespace { + +enum class LB { + NONE = 0x00000000L, + Frame = 0x00000001L, // text region of the paragraph + PrintArea = 0x00000002L, // text region of the paragraph + indentions + VertFrame = 0x00000004L, // vertical text region of the paragraph + VertPrintArea = 0x00000008L, // vertical text region of the paragraph + indentions + RelFrameLeft = 0x00000010L, // left paragraph edge + RelFrameRight = 0x00000020L, // right paragraph edge + + RelPageLeft = 0x00000040L, // left page edge + RelPageRight = 0x00000080L, // right page edge + RelPageFrame = 0x00000100L, // whole page + RelPagePrintArea = 0x00000200L, // text region of the page + + FlyRelPageLeft = 0x00000400L, // left frame edge + FlyRelPageRight = 0x00000800L, // right frame edge + FlyRelPageFrame = 0x00001000L, // whole frame + FlyRelPagePrintArea = 0x00002000L, // inside of the frame + + RelBase = 0x00010000L, // character alignment Base + RelChar = 0x00020000L, // character alignment Character + RelRow = 0x00040000L, // character alignment Row + + FlyVertFrame = 0x00100000L, // vertical entire frame + FlyVertPrintArea = 0x00200000L, // vertical frame text area + + VertLine = 0x00400000L, // vertical text line +}; + +} + +namespace o3tl { + template<> struct typed_flags<LB> : is_typed_flags<LB, 0x00773fffL> {}; +} + +namespace { + +struct RelationMap +{ + SvxSwFramePosString::StringId eStrId; + SvxSwFramePosString::StringId eMirrorStrId; + LB nLBRelation; + sal_Int16 nRelation; +}; + +} + +struct FrameMap +{ + SvxSwFramePosString::StringId eStrId; + SvxSwFramePosString::StringId eMirrorStrId; + sal_Int16 nAlign; + LB nLBRelations; +}; + + +RelationMap const aRelationMap[] = +{ + {SwFPos::FRAME, SwFPos::FRAME, LB::Frame, text::RelOrientation::FRAME}, + {SwFPos::PRTAREA, SwFPos::PRTAREA, LB::PrintArea, text::RelOrientation::PRINT_AREA}, + {SwFPos::REL_PG_LEFT, SwFPos::MIR_REL_PG_LEFT, LB::RelPageLeft, text::RelOrientation::PAGE_LEFT}, + {SwFPos::REL_PG_RIGHT, SwFPos::MIR_REL_PG_RIGHT, LB::RelPageRight, text::RelOrientation::PAGE_RIGHT}, + {SwFPos::REL_FRM_LEFT, SwFPos::MIR_REL_FRM_LEFT, LB::RelFrameLeft, text::RelOrientation::FRAME_LEFT}, + {SwFPos::REL_FRM_RIGHT, SwFPos::MIR_REL_FRM_RIGHT, LB::RelFrameRight, text::RelOrientation::FRAME_RIGHT}, + {SwFPos::REL_PG_FRAME, SwFPos::REL_PG_FRAME, LB::RelPageFrame, text::RelOrientation::PAGE_FRAME}, + {SwFPos::REL_PG_PRTAREA, SwFPos::REL_PG_PRTAREA, LB::RelPagePrintArea, text::RelOrientation::PAGE_PRINT_AREA}, + {SwFPos::REL_CHAR, SwFPos::REL_CHAR, LB::RelChar, text::RelOrientation::CHAR}, + + {SwFPos::FLY_REL_PG_LEFT, SwFPos::FLY_MIR_REL_PG_LEFT, LB::FlyRelPageLeft, text::RelOrientation::PAGE_LEFT}, + {SwFPos::FLY_REL_PG_RIGHT, SwFPos::FLY_MIR_REL_PG_RIGHT, LB::FlyRelPageRight, text::RelOrientation::PAGE_RIGHT}, + {SwFPos::FLY_REL_PG_FRAME, SwFPos::FLY_REL_PG_FRAME, LB::FlyRelPageFrame, text::RelOrientation::PAGE_FRAME}, + {SwFPos::FLY_REL_PG_PRTAREA, SwFPos::FLY_REL_PG_PRTAREA, LB::FlyRelPagePrintArea, text::RelOrientation::PAGE_PRINT_AREA}, + + {SwFPos::REL_BORDER, SwFPos::REL_BORDER, LB::VertFrame, text::RelOrientation::FRAME}, + {SwFPos::REL_PRTAREA, SwFPos::REL_PRTAREA, LB::VertPrintArea, text::RelOrientation::PRINT_AREA}, + + {SwFPos::FLY_REL_PG_FRAME, SwFPos::FLY_REL_PG_FRAME, LB::FlyVertFrame, text::RelOrientation::FRAME}, + {SwFPos::FLY_REL_PG_PRTAREA, SwFPos::FLY_REL_PG_PRTAREA, LB::FlyVertPrintArea, text::RelOrientation::PRINT_AREA}, + + {SwFPos::REL_LINE, SwFPos::REL_LINE, LB::VertLine, text::RelOrientation::TEXT_LINE} +}; + +RelationMap const aAsCharRelationMap[] = +{ + {SwFPos::REL_BASE, SwFPos::REL_BASE, LB::RelBase, text::RelOrientation::FRAME}, + {SwFPos::REL_CHAR, SwFPos::REL_CHAR, LB::RelChar, text::RelOrientation::FRAME}, + {SwFPos::REL_ROW, SwFPos::REL_ROW, LB::RelRow, text::RelOrientation::FRAME} +}; + +// site anchored +constexpr auto HORI_PAGE_REL = LB::RelPageFrame | LB::RelPagePrintArea | LB::RelPageLeft | + LB::RelPageRight; + +FrameMap const aHPageMap[] = +{ + {SwFPos::LEFT, SwFPos::MIR_LEFT, text::HoriOrientation::LEFT, HORI_PAGE_REL}, + {SwFPos::RIGHT, SwFPos::MIR_RIGHT, text::HoriOrientation::RIGHT, HORI_PAGE_REL}, + {SwFPos::CENTER_HORI, SwFPos::CENTER_HORI, text::HoriOrientation::CENTER, HORI_PAGE_REL}, + {SwFPos::FROMLEFT, SwFPos::MIR_FROMLEFT, text::HoriOrientation::NONE, HORI_PAGE_REL} +}; + +FrameMap const aHPageHtmlMap[] = +{ + {SwFPos::FROMLEFT, SwFPos::MIR_FROMLEFT, text::HoriOrientation::NONE, LB::RelPageFrame} +}; + +#define VERT_PAGE_REL (LB::RelPageFrame|LB::RelPagePrintArea) + +FrameMap const aVPageMap[] = +{ + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::TOP, VERT_PAGE_REL}, + {SwFPos::BOTTOM, SwFPos::BOTTOM, text::VertOrientation::BOTTOM, VERT_PAGE_REL}, + {SwFPos::CENTER_VERT, SwFPos::CENTER_VERT, text::VertOrientation::CENTER, VERT_PAGE_REL}, + {SwFPos::FROMTOP, SwFPos::FROMTOP, text::VertOrientation::NONE, VERT_PAGE_REL} +}; + +FrameMap const aVPageHtmlMap[] = +{ + {SwFPos::FROMTOP, SwFPos::FROMTOP, text::VertOrientation::NONE, LB::RelPageFrame} +}; + +// frame anchored +constexpr auto HORI_FRAME_REL = LB::FlyRelPageFrame | LB::FlyRelPagePrintArea | + LB::FlyRelPageLeft | LB::FlyRelPageRight; + +FrameMap const aHFrameMap[] = +{ + {SwFPos::LEFT, SwFPos::MIR_LEFT, text::HoriOrientation::LEFT, HORI_FRAME_REL}, + {SwFPos::RIGHT, SwFPos::MIR_RIGHT, text::HoriOrientation::RIGHT, HORI_FRAME_REL}, + {SwFPos::CENTER_HORI, SwFPos::CENTER_HORI, text::HoriOrientation::CENTER, HORI_FRAME_REL}, + {SwFPos::FROMLEFT, SwFPos::MIR_FROMLEFT, text::HoriOrientation::NONE, HORI_FRAME_REL} +}; + +FrameMap const aHFlyHtmlMap[] = +{ + {SwFPos::LEFT, SwFPos::MIR_LEFT, text::HoriOrientation::LEFT, LB::FlyRelPageFrame}, + {SwFPos::FROMLEFT, SwFPos::MIR_FROMLEFT, text::HoriOrientation::NONE, LB::FlyRelPageFrame} +}; + +// own vertical alignment map for objects anchored to frame +#define VERT_FRAME_REL (LB::FlyVertFrame|LB::FlyVertPrintArea) + +FrameMap const aVFrameMap[] = +{ + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::TOP, VERT_FRAME_REL}, + {SwFPos::BOTTOM, SwFPos::BOTTOM, text::VertOrientation::BOTTOM, VERT_FRAME_REL}, + {SwFPos::CENTER_VERT, SwFPos::CENTER_VERT, text::VertOrientation::CENTER, VERT_FRAME_REL}, + {SwFPos::FROMTOP, SwFPos::FROMTOP, text::VertOrientation::NONE, VERT_FRAME_REL} +}; + +FrameMap const aVFlyHtmlMap[] = +{ + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::TOP, LB::FlyVertFrame}, + {SwFPos::FROMTOP, SwFPos::FROMTOP, text::VertOrientation::NONE, LB::FlyVertFrame} +}; + +// paragraph anchored +constexpr auto HORI_PARA_REL = LB::Frame | LB::PrintArea | LB::RelPageLeft | LB::RelPageRight | + LB::RelPageFrame | LB::RelPagePrintArea | LB::RelFrameLeft | + LB::RelFrameRight; + +FrameMap const aHParaMap[] = +{ + {SwFPos::LEFT, SwFPos::MIR_LEFT, text::HoriOrientation::LEFT, HORI_PARA_REL}, + {SwFPos::RIGHT, SwFPos::MIR_RIGHT, text::HoriOrientation::RIGHT, HORI_PARA_REL}, + {SwFPos::CENTER_HORI, SwFPos::CENTER_HORI, text::HoriOrientation::CENTER, HORI_PARA_REL}, + {SwFPos::FROMLEFT, SwFPos::MIR_FROMLEFT, text::HoriOrientation::NONE, HORI_PARA_REL} +}; + +#define HTML_HORI_PARA_REL (LB::Frame|LB::PrintArea) + +FrameMap const aHParaHtmlMap[] = +{ + {SwFPos::LEFT, SwFPos::LEFT, text::HoriOrientation::LEFT, HTML_HORI_PARA_REL}, + {SwFPos::RIGHT, SwFPos::RIGHT, text::HoriOrientation::RIGHT, HTML_HORI_PARA_REL} +}; + +FrameMap const aHParaHtmlAbsMap[] = +{ + {SwFPos::LEFT, SwFPos::MIR_LEFT, text::HoriOrientation::LEFT, HTML_HORI_PARA_REL}, + {SwFPos::RIGHT, SwFPos::MIR_RIGHT, text::HoriOrientation::RIGHT, HTML_HORI_PARA_REL} +}; + +// allow vertical alignment at page areas +constexpr auto VERT_PARA_REL = LB::VertFrame | LB::VertPrintArea | + LB::RelPageFrame | LB::RelPagePrintArea; + +FrameMap const aVParaMap[] = +{ + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::TOP, VERT_PARA_REL}, + {SwFPos::BOTTOM, SwFPos::BOTTOM, text::VertOrientation::BOTTOM, VERT_PARA_REL}, + {SwFPos::CENTER_VERT, SwFPos::CENTER_VERT, text::VertOrientation::CENTER, VERT_PARA_REL}, + {SwFPos::FROMTOP, SwFPos::FROMTOP, text::VertOrientation::NONE, VERT_PARA_REL} +}; + +FrameMap const aVParaHtmlMap[] = +{ + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::TOP, LB::VertPrintArea} +}; + +// anchored relative to the character +constexpr auto HORI_CHAR_REL = LB::Frame|LB::PrintArea | LB::RelPageLeft | LB::RelPageRight | + LB::RelPageFrame | LB::RelPagePrintArea | LB::RelFrameLeft | + LB::RelFrameRight | LB::RelChar; + +FrameMap const aHCharMap[] = +{ + {SwFPos::LEFT, SwFPos::MIR_LEFT, text::HoriOrientation::LEFT, HORI_CHAR_REL}, + {SwFPos::RIGHT, SwFPos::MIR_RIGHT, text::HoriOrientation::RIGHT, HORI_CHAR_REL}, + {SwFPos::CENTER_HORI, SwFPos::CENTER_HORI, text::HoriOrientation::CENTER, HORI_CHAR_REL}, + {SwFPos::FROMLEFT, SwFPos::MIR_FROMLEFT, text::HoriOrientation::NONE, HORI_CHAR_REL} +}; + +#define HTML_HORI_CHAR_REL (LB::Frame|LB::PrintArea|LB::RelChar) + +FrameMap const aHCharHtmlMap[] = +{ + {SwFPos::LEFT, SwFPos::LEFT, text::HoriOrientation::LEFT, HTML_HORI_CHAR_REL}, + {SwFPos::RIGHT, SwFPos::RIGHT, text::HoriOrientation::RIGHT, HTML_HORI_CHAR_REL} +}; + +FrameMap const aHCharHtmlAbsMap[] = +{ + {SwFPos::LEFT, SwFPos::MIR_LEFT, text::HoriOrientation::LEFT, LB::PrintArea|LB::RelChar}, + {SwFPos::RIGHT, SwFPos::MIR_RIGHT, text::HoriOrientation::RIGHT, LB::PrintArea}, + {SwFPos::FROMLEFT, SwFPos::MIR_FROMLEFT, text::HoriOrientation::NONE, LB::RelPageFrame} +}; + +// allow vertical alignment at page areas +constexpr auto VERT_CHAR_REL = LB::VertFrame | LB::VertPrintArea | + LB::RelPageFrame | LB::RelPagePrintArea; + +FrameMap const aVCharMap[] = +{ + // introduce mappings for new vertical alignment at top of line <LB::VertLine> + // and correct mapping for vertical alignment at character for position <FROM_BOTTOM> + // Note: Because of these adjustments the map becomes ambiguous in its values + // <eStrId>/<eMirrorStrId> and <nAlign>. These ambiguities are considered + // in the methods <SwFramePage::FillRelLB(..)>, <SwFramePage::GetAlignment(..)> + // and <SwFramePage::FillPosLB(..)> + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::TOP, VERT_CHAR_REL|LB::RelChar}, + {SwFPos::BOTTOM, SwFPos::BOTTOM, text::VertOrientation::BOTTOM, VERT_CHAR_REL|LB::RelChar}, + {SwFPos::BELOW, SwFPos::BELOW, text::VertOrientation::CHAR_BOTTOM, LB::RelChar}, + {SwFPos::CENTER_VERT, SwFPos::CENTER_VERT, text::VertOrientation::CENTER, VERT_CHAR_REL|LB::RelChar}, + {SwFPos::FROMTOP, SwFPos::FROMTOP, text::VertOrientation::NONE, VERT_CHAR_REL}, + {SwFPos::FROMBOTTOM, SwFPos::FROMBOTTOM, text::VertOrientation::NONE, LB::RelChar|LB::VertLine}, + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::LINE_TOP, LB::VertLine}, + {SwFPos::BOTTOM, SwFPos::BOTTOM, text::VertOrientation::LINE_BOTTOM, LB::VertLine}, + {SwFPos::CENTER_VERT, SwFPos::CENTER_VERT, text::VertOrientation::LINE_CENTER, LB::VertLine} +}; + +FrameMap const aVCharHtmlMap[] = +{ + {SwFPos::BELOW, SwFPos::BELOW, text::VertOrientation::CHAR_BOTTOM, LB::RelChar} +}; + +FrameMap const aVCharHtmlAbsMap[] = +{ + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::TOP, LB::RelChar}, + {SwFPos::BELOW, SwFPos::BELOW, text::VertOrientation::CHAR_BOTTOM, LB::RelChar} +}; + +// anchored as character +FrameMap const aVAsCharMap[] = +{ + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::TOP, LB::RelBase}, + {SwFPos::BOTTOM, SwFPos::BOTTOM, text::VertOrientation::BOTTOM, LB::RelBase}, + {SwFPos::CENTER_VERT, SwFPos::CENTER_VERT, text::VertOrientation::CENTER, LB::RelBase}, + + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::CHAR_TOP, LB::RelChar}, + {SwFPos::BOTTOM, SwFPos::BOTTOM, text::VertOrientation::CHAR_BOTTOM, LB::RelChar}, + {SwFPos::CENTER_VERT, SwFPos::CENTER_VERT, text::VertOrientation::CHAR_CENTER, LB::RelChar}, + + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::LINE_TOP, LB::RelRow}, + {SwFPos::BOTTOM, SwFPos::BOTTOM, text::VertOrientation::LINE_BOTTOM, LB::RelRow}, + {SwFPos::CENTER_VERT, SwFPos::CENTER_VERT, text::VertOrientation::LINE_CENTER, LB::RelRow}, + + {SwFPos::FROMBOTTOM, SwFPos::FROMBOTTOM, text::VertOrientation::NONE, LB::RelBase} +}; + +FrameMap const aVAsCharHtmlMap[] = +{ + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::TOP, LB::RelBase}, + {SwFPos::CENTER_VERT, SwFPos::CENTER_VERT, text::VertOrientation::CENTER, LB::RelBase}, + + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::CHAR_TOP, LB::RelChar}, + + {SwFPos::TOP, SwFPos::TOP, text::VertOrientation::LINE_TOP, LB::RelRow}, + {SwFPos::BOTTOM, SwFPos::BOTTOM, text::VertOrientation::LINE_BOTTOM, LB::RelRow}, + {SwFPos::CENTER_VERT, SwFPos::CENTER_VERT, text::VertOrientation::LINE_CENTER, LB::RelRow} +}; + +const WhichRangesContainer SwFramePage::s_aPageRg(svl::Items< + RES_FRM_SIZE, RES_FRM_SIZE, + RES_VERT_ORIENT, RES_ANCHOR, + RES_COL, RES_COL, + RES_FOLLOW_TEXT_FLOW, RES_FOLLOW_TEXT_FLOW +>); +const WhichRangesContainer SwFrameAddPage::s_aAddPgRg(svl::Items< + RES_PRINT, RES_PRINT, + RES_PROTECT, RES_PROTECT, + FN_SET_FRM_NAME, FN_SET_FRM_NAME, + FN_SET_FRM_ALT_NAME, FN_SET_FRM_ALT_NAME, + FN_UNO_DESCRIPTION, FN_UNO_DESCRIPTION +>); + +static size_t lcl_GetFrameMapCount( const FrameMap* pMap) +{ + if ( pMap ) + { + if( pMap == aVParaHtmlMap) + return std::size(aVParaHtmlMap); + if( pMap == aVAsCharHtmlMap) + return std::size(aVAsCharHtmlMap); + if( pMap == aHParaHtmlMap) + return std::size(aHParaHtmlMap); + if( pMap == aHParaHtmlAbsMap) + return std::size(aHParaHtmlAbsMap); + if ( pMap == aVPageMap ) + return std::size(aVPageMap); + if ( pMap == aVPageHtmlMap ) + return std::size(aVPageHtmlMap); + if ( pMap == aVAsCharMap ) + return std::size(aVAsCharMap); + if ( pMap == aVParaMap ) + return std::size(aVParaMap); + if ( pMap == aHParaMap ) + return std::size(aHParaMap); + if ( pMap == aHFrameMap ) + return std::size(aHFrameMap); + if ( pMap == aVFrameMap ) + return std::size(aVFrameMap); + if ( pMap == aHCharMap ) + return std::size(aHCharMap); + if ( pMap == aHCharHtmlMap ) + return std::size(aHCharHtmlMap); + if ( pMap == aHCharHtmlAbsMap ) + return std::size(aHCharHtmlAbsMap); + if ( pMap == aVCharMap ) + return std::size(aVCharMap); + if ( pMap == aVCharHtmlMap ) + return std::size(aVCharHtmlMap); + if ( pMap == aVCharHtmlAbsMap ) + return std::size(aVCharHtmlAbsMap); + if ( pMap == aHPageHtmlMap ) + return std::size(aHPageHtmlMap); + if ( pMap == aHFlyHtmlMap ) + return std::size(aHFlyHtmlMap); + if ( pMap == aVFlyHtmlMap ) + return std::size(aVFlyHtmlMap); + return std::size(aHPageMap); + } + return 0; +} + +static void lcl_InsertVectors(weld::ComboBox& rBox, + const std::vector< OUString >& rPrev, const std::vector< OUString >& rThis, + const std::vector< OUString >& rNext, const std::vector< OUString >& rRemain) +{ + for(const auto& rItem : rPrev) + rBox.append_text(rItem); + for(const auto& rItem : rThis) + rBox.append_text(rItem); + for(const auto& rItem : rNext) + rBox.append_text(rItem); + rBox.append_separator(""); + //now insert all strings sorted + const auto nStartPos = rBox.get_count(); + + for(const auto& rItem : rPrev) + ::InsertStringSorted("", rItem, rBox, nStartPos ); + for(const auto& rItem : rThis) + ::InsertStringSorted("", rItem, rBox, nStartPos ); + for(const auto& rItem : rNext) + ::InsertStringSorted("", rItem, rBox, nStartPos ); + for(const auto& rItem : rRemain) + ::InsertStringSorted("", rItem, rBox, nStartPos ); +} + +// --> OD 2009-08-31 #mongolianlayout# +// add input parameter +static SvxSwFramePosString::StringId lcl_ChangeResIdToVerticalOrRTL(SvxSwFramePosString::StringId eStringId, bool bVertical, bool bVerticalL2R, bool bRTL) +{ + //special handling of STR_FROMLEFT + if ( SwFPos::FROMLEFT == eStringId ) + { + eStringId = bVertical + ? ( bRTL + ? SwFPos::FROMBOTTOM + : SwFPos::FROMTOP ) + : ( bRTL + ? SwFPos::FROMRIGHT + : SwFPos::FROMLEFT ); + return eStringId; + } + // --> OD 2009-08-31 #mongolianlayout# + // special handling of STR_FROMTOP in case of mongolianlayout (vertical left-to-right) + if ( SwFPos::FROMTOP == eStringId && + bVertical && bVerticalL2R ) + { + eStringId = SwFPos::FROMLEFT; + return eStringId; + } + if ( bVertical ) + { + //exchange horizontal strings with vertical strings and vice versa + static const StringIdPair_Impl aHoriIds[] = + { + {SwFPos::LEFT, SwFPos::TOP}, + {SwFPos::RIGHT, SwFPos::BOTTOM}, + {SwFPos::CENTER_HORI, SwFPos::CENTER_VERT}, + {SwFPos::FROMTOP, SwFPos::FROMRIGHT}, + {SwFPos::REL_PG_LEFT, SwFPos::REL_PG_TOP}, + {SwFPos::REL_PG_RIGHT, SwFPos::REL_PG_BOTTOM} , + {SwFPos::REL_FRM_LEFT, SwFPos::REL_FRM_TOP}, + {SwFPos::REL_FRM_RIGHT, SwFPos::REL_FRM_BOTTOM} + }; + static const StringIdPair_Impl aVertIds[] = + { + {SwFPos::TOP, SwFPos::RIGHT}, + {SwFPos::BOTTOM, SwFPos::LEFT }, + {SwFPos::CENTER_VERT, SwFPos::CENTER_HORI}, + {SwFPos::FROMTOP, SwFPos::FROMRIGHT }, + {SwFPos::REL_PG_TOP, SwFPos::REL_PG_LEFT }, + {SwFPos::REL_PG_BOTTOM, SwFPos::REL_PG_RIGHT } , + {SwFPos::REL_FRM_TOP, SwFPos::REL_FRM_LEFT }, + {SwFPos::REL_FRM_BOTTOM, SwFPos::REL_FRM_RIGHT } + }; + // --> OD 2009-08-31 #monglianlayout# + static const StringIdPair_Impl aVertL2RIds[] = + { + {SwFPos::TOP, SwFPos::LEFT }, + {SwFPos::BOTTOM, SwFPos::RIGHT }, + {SwFPos::CENTER_VERT, SwFPos::CENTER_HORI }, + {SwFPos::FROMTOP, SwFPos::FROMLEFT }, + {SwFPos::REL_PG_TOP, SwFPos::REL_PG_LEFT }, + {SwFPos::REL_PG_BOTTOM, SwFPos::REL_PG_RIGHT } , + {SwFPos::REL_FRM_TOP, SwFPos::REL_FRM_LEFT }, + {SwFPos::REL_FRM_BOTTOM, SwFPos::REL_FRM_RIGHT } + }; + for(const StringIdPair_Impl & rHoriId : aHoriIds) + { + if(rHoriId.eHori == eStringId) + { + eStringId = rHoriId.eVert; + return eStringId; + } + } + for(size_t nIndex = 0; nIndex < SAL_N_ELEMENTS(aVertIds); ++nIndex) + { + // --> OD 2009-08-31 #mongolianlayout# + if ( !bVerticalL2R ) + { + if(aVertIds[nIndex].eHori == eStringId) + { + eStringId = aVertIds[nIndex].eVert; + break; + } + } + else + { + if(aVertL2RIds[nIndex].eHori == eStringId) + { + eStringId = aVertL2RIds[nIndex].eVert; + break; + } + } + } + } + return eStringId; +} + +// helper method in order to determine all possible +// listbox relations in a relation map for a given relation +static LB lcl_GetLBRelationsForRelations( const sal_Int16 _nRel ) +{ + LB nLBRelations = LB::NONE; + + for (RelationMap const & i : aRelationMap) + { + if ( i.nRelation == _nRel ) + { + nLBRelations |= i.nLBRelation; + } + } + + return nLBRelations; +} + +// helper method on order to determine all possible +// listbox relations in a relation map for a given string ID +static LB lcl_GetLBRelationsForStrID( const FrameMap* _pMap, + const SvxSwFramePosString::StringId _eStrId, + const bool _bUseMirrorStr ) +{ + LB nLBRelations = LB::NONE; + + size_t nRelMapSize = lcl_GetFrameMapCount( _pMap ); + for ( size_t nRelMapPos = 0; nRelMapPos < nRelMapSize; ++nRelMapPos ) + { + if ( ( !_bUseMirrorStr && _pMap[nRelMapPos].eStrId == _eStrId ) || + ( _bUseMirrorStr && _pMap[nRelMapPos].eMirrorStrId == _eStrId ) ) + { + nLBRelations |= _pMap[nRelMapPos].nLBRelations; + } + } + + return nLBRelations; +} + +// standard frame TabPage +namespace +{ + void HandleAutoCB(bool _bChecked, weld::Label& _rFT_man, weld::Label& _rFT_auto, weld::MetricSpinButton& _rPF_Edit) + { + _rFT_man.set_visible( !_bChecked ); + _rFT_auto.set_visible( _bChecked ); + OUString accName = _bChecked ? _rFT_auto.get_label() : _rFT_man.get_label(); + _rPF_Edit.set_accessible_name(accName); + } +} + +SwFramePage::SwFramePage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/frmtypepage.ui", "FrameTypePage", &rSet) + , m_bAtHorzPosModified(false) + , m_bAtVertPosModified(false) + , m_bFormat(false) + , m_bNew(true) + , m_bNoModifyHdl(true) + , m_bIsVerticalFrame(false) + , m_bIsVerticalL2R(false) + , m_bIsInRightToLeft(false) + , m_bHtmlMode(false) + , m_nHtmlMode(0) + , m_nUpperBorder(0) + , m_nLowerBorder(0) + , m_fWidthHeightRatio(1.0) + , mpToCharContentPos(nullptr) + , m_nOldH(text::HoriOrientation::CENTER) + , m_nOldHRel(text::RelOrientation::FRAME) + , m_nOldV(text::VertOrientation::TOP) + , m_nOldVRel(text::RelOrientation::PRINT_AREA) + , m_pVMap(nullptr) + , m_pHMap(nullptr) + , m_bAllowVertPositioning( true ) + , m_bIsMathOLE(false) + , m_bIsMathBaselineAlignment(true) + , m_xWidthFT(m_xBuilder->weld_label("widthft")) + , m_xWidthAutoFT(m_xBuilder->weld_label("autowidthft")) + , m_xRelWidthCB(m_xBuilder->weld_check_button("relwidth")) + , m_xRelWidthRelationLB(m_xBuilder->weld_combo_box("relwidthrelation")) + , m_xAutoWidthCB(m_xBuilder->weld_check_button("autowidth")) + , m_xHeightFT(m_xBuilder->weld_label("heightft")) + , m_xHeightAutoFT(m_xBuilder->weld_label("autoheightft")) + , m_xRelHeightCB(m_xBuilder->weld_check_button("relheight")) + , m_xRelHeightRelationLB(m_xBuilder->weld_combo_box("relheightrelation")) + , m_xAutoHeightCB(m_xBuilder->weld_check_button("autoheight")) + , m_xFixedRatioCB(m_xBuilder->weld_check_button("ratio")) + , m_xRealSizeBT(m_xBuilder->weld_button("origsize")) + , m_xAnchorFrame(m_xBuilder->weld_widget("anchorframe")) + , m_xAnchorAtPageRB(m_xBuilder->weld_radio_button("topage")) + , m_xAnchorAtParaRB(m_xBuilder->weld_radio_button("topara")) + , m_xAnchorAtCharRB(m_xBuilder->weld_radio_button("tochar")) + , m_xAnchorAsCharRB(m_xBuilder->weld_radio_button("aschar")) + , m_xAnchorAtFrameRB(m_xBuilder->weld_radio_button("toframe")) + , m_xHorizontalFT(m_xBuilder->weld_label("horiposft")) + , m_xHorizontalDLB(m_xBuilder->weld_combo_box("horipos")) + , m_xAtHorzPosFT(m_xBuilder->weld_label("horibyft")) + , m_xAtHorzPosED(m_xBuilder->weld_metric_spin_button("byhori", FieldUnit::CM)) + , m_xHoriRelationFT(m_xBuilder->weld_label("horitoft")) + , m_xHoriRelationLB(m_xBuilder->weld_combo_box("horianchor")) + , m_xMirrorPagesCB(m_xBuilder->weld_check_button("mirror")) + , m_xVerticalFT(m_xBuilder->weld_label("vertposft")) + , m_xVerticalDLB(m_xBuilder->weld_combo_box("vertpos")) + , m_xAtVertPosFT(m_xBuilder->weld_label("vertbyft")) + , m_xAtVertPosED(m_xBuilder->weld_metric_spin_button("byvert", FieldUnit::CM)) + , m_xVertRelationFT(m_xBuilder->weld_label("verttoft")) + , m_xVertRelationLB(m_xBuilder->weld_combo_box("vertanchor")) + , m_xFollowTextFlowCB(m_xBuilder->weld_check_button("followtextflow")) + , m_xFlySplitCB(m_xBuilder->weld_check_button("flysplit")) + , m_xExampleWN(new weld::CustomWeld(*m_xBuilder, "preview", m_aExampleWN)) + , m_xWidthED(new SwPercentField(m_xBuilder->weld_metric_spin_button("width", FieldUnit::CM))) + , m_xHeightED(new SwPercentField(m_xBuilder->weld_metric_spin_button("height", FieldUnit::CM))) +{ + const auto nWidthRequest = m_xAtHorzPosED->get_preferred_size().Width(); + m_xAtHorzPosED->set_size_request(nWidthRequest, -1); + m_xAtVertPosED->set_size_request(nWidthRequest, -1); + + setOptimalFrameWidth(); + setOptimalRelWidth(); + + SetExchangeSupport(); + + Link<weld::MetricSpinButton&,void> aLk3 = LINK(this, SwFramePage, ModifyHdl); + m_xWidthED->connect_value_changed( aLk3 ); + m_xHeightED->connect_value_changed( aLk3 ); + m_xAtHorzPosED->connect_value_changed( aLk3 ); + m_xAtVertPosED->connect_value_changed( aLk3 ); + m_xFollowTextFlowCB->connect_toggled(LINK(this, SwFramePage, RangeModifyClickHdl)); + + Link<weld::Toggleable&,void> aLk2 = LINK(this, SwFramePage, AnchorTypeHdl); + m_xAnchorAtPageRB->connect_toggled( aLk2 ); + m_xAnchorAtParaRB->connect_toggled( aLk2 ); + m_xAnchorAtCharRB->connect_toggled( aLk2 ); + m_xAnchorAsCharRB->connect_toggled( aLk2 ); + m_xAnchorAtFrameRB->connect_toggled( aLk2 ); + + m_xHorizontalDLB->connect_changed(LINK(this, SwFramePage, PosHdl)); + m_xVerticalDLB->connect_changed(LINK(this, SwFramePage, PosHdl)); + + m_xHoriRelationLB->connect_changed(LINK(this, SwFramePage, RelHdl)); + m_xVertRelationLB->connect_changed(LINK(this, SwFramePage, RelHdl)); + + m_xMirrorPagesCB->connect_toggled(LINK(this, SwFramePage, MirrorHdl)); + + aLk2 = LINK(this, SwFramePage, RelSizeClickHdl); + m_xRelWidthCB->connect_toggled(aLk2); + m_xRelHeightCB->connect_toggled(aLk2); + + m_xAutoWidthCB->connect_toggled(LINK(this, SwFramePage, AutoWidthClickHdl)); + m_xAutoHeightCB->connect_toggled(LINK(this, SwFramePage, AutoHeightClickHdl)); + + if (comphelper::LibreOfficeKit::isActive()) + { + m_xAnchorAtPageRB->hide(); + m_xAnchorAtFrameRB->hide(); + } +} + +SwFramePage::~SwFramePage() +{ +} + +namespace +{ + struct FrameMaps + { + FrameMap const * pMap; + size_t nCount; + }; +} + +void SwFramePage::setOptimalFrameWidth() +{ + static FrameMaps const aMaps[] = { + { aHPageMap, std::size(aHPageMap) }, + { aHPageHtmlMap, std::size(aHPageHtmlMap) }, + { aVPageMap, std::size(aVPageMap) }, + { aVPageHtmlMap, std::size(aVPageHtmlMap) }, + { aHFrameMap, std::size(aHFrameMap) }, + { aHFlyHtmlMap, std::size(aHFlyHtmlMap) }, + { aVFrameMap, std::size(aVFrameMap) }, + { aVFlyHtmlMap, std::size(aVFlyHtmlMap) }, + { aHParaMap, std::size(aHParaMap) }, + { aHParaHtmlMap, std::size(aHParaHtmlMap) }, + { aHParaHtmlAbsMap, std::size(aHParaHtmlAbsMap) }, + { aVParaMap, std::size(aVParaMap) }, + { aVParaHtmlMap, std::size(aVParaHtmlMap) }, + { aHCharMap, std::size(aHCharMap) }, + { aHCharHtmlMap, std::size(aHCharHtmlMap) }, + { aHCharHtmlAbsMap, std::size(aHCharHtmlAbsMap) }, + { aVCharMap, std::size(aVCharMap) }, + { aVCharHtmlMap, std::size(aVCharHtmlMap) }, + { aVCharHtmlAbsMap, std::size(aVCharHtmlAbsMap) }, + { aVAsCharMap, std::size(aVAsCharMap) }, + { aVAsCharHtmlMap, std::size(aVAsCharHtmlMap) } + }; + + std::vector<SvxSwFramePosString::StringId> aFrames; + for (const FrameMaps & rMap : aMaps) + { + for (size_t j = 0; j < rMap.nCount; ++j) + { + aFrames.push_back(rMap.pMap[j].eStrId); + aFrames.push_back(rMap.pMap[j].eMirrorStrId); + } + } + + std::sort(aFrames.begin(), aFrames.end()); + aFrames.erase(std::unique(aFrames.begin(), aFrames.end()), aFrames.end()); + + for (const auto& rFrame : aFrames) + { + m_xHorizontalDLB->append_text(SvxSwFramePosString::GetString(rFrame)); + } + + Size aBiggest(m_xHorizontalDLB->get_preferred_size()); + m_xHorizontalDLB->set_size_request(aBiggest.Width(), -1); + m_xVerticalDLB->set_size_request(aBiggest.Width(), -1); + m_xHorizontalDLB->clear(); +} + +namespace +{ + struct RelationMaps + { + RelationMap const * pMap; + size_t nCount; + }; + +/// Checks if the current fly frame contains exactly one table. +bool ContainsSingleTable(const SwFrameFormat& rFlyFormat) +{ + const SwNodeIndex* pStartNode = rFlyFormat.GetContent().GetContentIdx(); + if (!pStartNode) + { + return false; + } + + // Check if the frame content starts with a table. + SwNodeIndex aNodeIndex(*pStartNode); + ++aNodeIndex; + if (!aNodeIndex.GetNode().IsTableNode()) + { + return false; + } + + // Check if the frame content ends with the same table. + SwNodeIndex aEndIndex(*aNodeIndex.GetNode().EndOfSectionNode()); + ++aEndIndex; + if (&aEndIndex.GetNode() != pStartNode->GetNode().EndOfSectionNode()) + { + return false; + } + + return true; +} + +bool ContainsChain(const SwFrameFormat& rFlyFormat) +{ + const SwFormatChain& rChain = rFlyFormat.GetChain(); + return rChain.GetPrev() || rChain.GetNext(); +} + +/// Determines if rFlyFormat is anchored in a fly frame that is part of a draw-format + fly-format +/// ("textbox") pair. +bool InTextBox(const SwFrameFormat& rFlyFormat) +{ + const SwFormatAnchor& rAnchor = rFlyFormat.GetAnchor(); + SwNode* pAnchorNode = rAnchor.GetAnchorNode(); + if (!pAnchorNode) + { + return false; + } + + const SwStartNode* pFlyNode = pAnchorNode->FindFlyStartNode(); + if (!pFlyNode) + { + return false; + } + + if (!pFlyNode->GetFlyFormat()->GetOtherTextBoxFormats()) + { + return false; + } + + return true; +} +} + +void SwFramePage::setOptimalRelWidth() +{ + static const RelationMaps aMaps[] = { + { aRelationMap, SAL_N_ELEMENTS(aRelationMap) }, + { aAsCharRelationMap, SAL_N_ELEMENTS(aAsCharRelationMap) } + }; + + std::vector<SvxSwFramePosString::StringId> aRels; + for (const RelationMaps & rMap : aMaps) + { + for (size_t j = 0; j < rMap.nCount; ++j) + { + aRels.push_back(rMap.pMap[j].eStrId); + aRels.push_back(rMap.pMap[j].eMirrorStrId); + } + } + + std::sort(aRels.begin(), aRels.end()); + aRels.erase(std::unique(aRels.begin(), aRels.end()), aRels.end()); + + for (const auto& rRel : aRels) + { + m_xHoriRelationLB->append_text(SvxSwFramePosString::GetString(rRel)); + } + + Size aBiggest(m_xHoriRelationLB->get_preferred_size()); + m_xHoriRelationLB->set_size_request(aBiggest.Width(), -1); + m_xVertRelationLB->set_size_request(aBiggest.Width(), -1); + m_xRelWidthRelationLB->set_size_request(aBiggest.Width(), -1); + m_xRelHeightRelationLB->set_size_request(aBiggest.Width(), -1); + m_xHoriRelationLB->clear(); +} + +std::unique_ptr<SfxTabPage> SwFramePage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet) +{ + return std::make_unique<SwFramePage>(pPage, pController, *rSet); +} + +void SwFramePage::EnableGraficMode() +{ + // i#39692 - mustn't be called more than once + if (!m_xRealSizeBT->get_visible()) + { + m_xWidthFT->show(); + m_xWidthAutoFT->hide(); + m_xAutoHeightCB->hide(); + + m_xHeightFT->show(); + m_xHeightAutoFT->hide(); + m_xAutoWidthCB->hide(); + + m_xRealSizeBT->show(); + } +} + +SwWrtShell *SwFramePage::getFrameDlgParentShell() +{ + return static_cast<SwFrameDlg*>(GetDialogController())->GetWrtShell(); +} + +void SwFramePage::Reset( const SfxItemSet *rSet ) +{ + SwWrtShell* pSh = m_bFormat ? ::GetActiveWrtShell() : + getFrameDlgParentShell(); + OSL_ENSURE(pSh , "shell not found"); + if (!pSh) + return; + + m_nHtmlMode = ::GetHtmlMode(pSh->GetView().GetDocShell()); + m_bHtmlMode = (m_nHtmlMode & HTMLMODE_ON) != 0; + + FieldUnit aMetric = ::GetDfltMetric(m_bHtmlMode); + m_xWidthED->SetMetric(aMetric); + m_xHeightED->SetMetric(aMetric); + ::SetFieldUnit(*m_xAtHorzPosED, aMetric); + ::SetFieldUnit(*m_xAtVertPosED, aMetric); + + const SwFormatAnchor& rAnchor = rSet->Get(RES_ANCHOR); + + if (const SfxBoolItem* pMathItem = rSet->GetItemIfSet(FN_OLE_IS_MATH, false)) + m_bIsMathOLE = pMathItem->GetValue(); + if (const SfxBoolItem* pAlignItem = rSet->GetItemIfSet(FN_MATH_BASELINE_ALIGNMENT, false)) + m_bIsMathBaselineAlignment = pAlignItem->GetValue(); + EnableVerticalPositioning( !(m_bIsMathOLE && m_bIsMathBaselineAlignment + && RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId()) ); + + if (m_bFormat) + { + // at formats no to-fly anchor + m_xAnchorAtFrameRB->set_sensitive(false); + if (rSet->GetItemState(FN_KEEP_ASPECT_RATIO) != SfxItemState::SET) + { + m_xFixedRatioCB->set_sensitive(false); + } + } + else + { + if (rAnchor.GetAnchorId() != RndStdIds::FLY_AT_FLY && !pSh->IsFlyInFly()) + m_xAnchorAtFrameRB->hide(); + if ( pSh->IsFrameVertical( true, m_bIsInRightToLeft, m_bIsVerticalL2R ) ) + { + OUString sHLabel = m_xHorizontalFT->get_label(); + m_xHorizontalFT->set_label(m_xVerticalFT->get_label()); + m_xVerticalFT->set_label(sHLabel); + m_bIsVerticalFrame = true; + } + } + + if ( m_sDlgType == "PictureDialog" || m_sDlgType == "ObjectDialog" ) + { + pSh->GetGrfSize( m_aGrfSize ); + + if ( !m_bNew ) + { + m_xRealSizeBT->connect_clicked(LINK(this, SwFramePage, RealSizeHdl)); + EnableGraficMode(); + } + + if (m_sDlgType == "PictureDialog") + m_xFixedRatioCB->set_active(false); + else + { + if ( m_bNew ) + SetPageTitle(SwResId(STR_FRMUI_OLE_INSERT)); + else + SetPageTitle(SwResId(STR_FRMUI_OLE_EDIT)); + } + } + else + { + m_aGrfSize = rSet->Get(RES_FRM_SIZE).GetSize(); + } + + // entering percent value made possible + + // the available space is not yet known so the RefValue has to be calculated from size and relative size values + // this is needed only if relative values are already set + const SwFormatFrameSize& rFrameSize = rSet->Get(RES_FRM_SIZE); + + m_xRelWidthRelationLB->append_text(SvxSwFramePosString::GetString(SwFPos::FRAME)); + m_xRelWidthRelationLB->append_text(SvxSwFramePosString::GetString(SwFPos::REL_PG_FRAME)); + if (rFrameSize.GetWidthPercent() != SwFormatFrameSize::SYNCED && rFrameSize.GetWidthPercent() != 0) + { + //calculate the reference value from the width and relative width values + sal_Int32 nSpace = rFrameSize.GetWidth() * 100 / rFrameSize.GetWidthPercent(); + m_xWidthED->SetRefValue( nSpace ); + + m_xRelWidthRelationLB->set_sensitive(true); + } + else + m_xRelWidthRelationLB->set_sensitive(false); + + m_xRelHeightRelationLB->append_text(SvxSwFramePosString::GetString(SwFPos::FRAME)); + m_xRelHeightRelationLB->append_text(SvxSwFramePosString::GetString(SwFPos::REL_PG_FRAME)); + if (rFrameSize.GetHeightPercent() != SwFormatFrameSize::SYNCED && rFrameSize.GetHeightPercent() != 0) + { + //calculate the reference value from the with and relative width values + sal_Int32 nSpace = rFrameSize.GetHeight() * 100 / rFrameSize.GetHeightPercent(); + m_xHeightED->SetRefValue( nSpace ); + + m_xRelHeightRelationLB->set_sensitive(true); + } + else + m_xRelHeightRelationLB->set_sensitive(false); + + // general initialisation part + switch(rAnchor.GetAnchorId()) + { + case RndStdIds::FLY_AT_PAGE: m_xAnchorAtPageRB->set_active(true); break; + case RndStdIds::FLY_AT_PARA: m_xAnchorAtParaRB->set_active(true); break; + case RndStdIds::FLY_AT_CHAR: m_xAnchorAtCharRB->set_active(true); break; + case RndStdIds::FLY_AS_CHAR: m_xAnchorAsCharRB->set_active(true); break; + case RndStdIds::FLY_AT_FLY: m_xAnchorAtFrameRB->set_active(true);break; + default:; //prevent warning + } + + // i#22341 - determine content position of character + // Note: content position can be NULL + mpToCharContentPos = rAnchor.GetAnchorNode() ? &rAnchor : nullptr; + + // i#18732 - init checkbox value + { + const bool bFollowTextFlow = + rSet->Get(RES_FOLLOW_TEXT_FLOW).GetValue(); + m_xFollowTextFlowCB->set_active(bFollowTextFlow); + } + { + const bool bFlySplit = rSet->Get(RES_FLY_SPLIT).GetValue(); + m_xFlySplitCB->set_active(bFlySplit); + } + + if(m_bHtmlMode) + { + m_xAutoHeightCB->set_sensitive(false); + m_xAutoWidthCB->set_sensitive(false); + m_xMirrorPagesCB->hide(); + if (m_sDlgType == "FrameDialog") + m_xFixedRatioCB->set_sensitive(false); + // i#18732 hide checkbox in HTML mode + m_xFollowTextFlowCB->hide(); + } + else + { + // enable/disable of check box 'Mirror on..' + m_xMirrorPagesCB->set_sensitive(!m_xAnchorAsCharRB->get_active()); + + // enable/disable check box 'Follow text flow'. + // enable check box 'Follow text + // flow' also for anchor type to-frame. + m_xFollowTextFlowCB->set_sensitive(m_xAnchorAtParaRB->get_active() || + m_xAnchorAtCharRB->get_active() || + m_xAnchorAtFrameRB->get_active()); + m_xFlySplitCB->set_sensitive(m_xAnchorAtParaRB->get_active()); + } + + const SwFrameFormat* pFlyFormat = pSh->GetFlyFrameFormat(); + if (!pFlyFormat || !ContainsSingleTable(*pFlyFormat) || ContainsChain(*pFlyFormat)) + { + bool bSingleTable = false; + if (!pFlyFormat && m_bNew) + { + // No fly is selected: check if a whole table is selected. If so, allow moving that into + // a split fly. + if (SwFlyFrameAttrMgr::SingleTableSelected(*pSh)) + { + bSingleTable = true; + } + } + + // Only allow fly split if the frame contains a single table, otherwise it would be hard to + // save the resulting model to Word formats. + if (!bSingleTable) + { + m_xFlySplitCB->hide(); + } + } + else if (pFlyFormat && !m_bNew && InTextBox(*pFlyFormat)) + { + // Disallow split flys in fly frames which form a textbox, i.e. non-editeng shape text. + m_xFlySplitCB->hide(); + } + + Init(*rSet); + m_xAtVertPosED->save_value(); + m_xAtHorzPosED->save_value(); + m_xFollowTextFlowCB->save_state(); + m_xFlySplitCB->save_state(); + + m_xWidthED->save_value(); + m_xHeightED->save_value(); + + m_bNoModifyHdl = false; + //lock PercentFields + m_xWidthED->LockAutoCalculation(true); + m_xHeightED->LockAutoCalculation(true); + RangeModifyHdl(); // set all maximum values initially + m_xHeightED->LockAutoCalculation(false); + m_xWidthED->LockAutoCalculation(false); + + m_xAutoHeightCB->save_state(); + m_xAutoWidthCB->save_state(); + + SwTwips nWidth = static_cast< SwTwips >(m_xWidthED->DenormalizePercent(m_xWidthED->get_value(FieldUnit::TWIP))); + SwTwips nHeight = static_cast< SwTwips >(m_xHeightED->DenormalizePercent(m_xHeightED->get_value(FieldUnit::TWIP))); + m_fWidthHeightRatio = nHeight ? double(nWidth) / double(nHeight) : 1.0; +} + +// stuff attributes into the set when OK +bool SwFramePage::FillItemSet(SfxItemSet *rSet) +{ + bool bRet = false; + + const SfxItemSet& rOldSet = GetItemSet(); + const SfxPoolItem* pOldItem = nullptr; + + RndStdIds eAnchorId = GetAnchor(); + + if ( !m_bFormat || eAnchorId != RndStdIds::FLY_AT_FLY ) + { + pOldItem = GetOldItem(*rSet, RES_ANCHOR); + if (m_bNew || !pOldItem || eAnchorId != static_cast<const SwFormatAnchor*>(pOldItem)->GetAnchorId()) + { + SwWrtShell* pSh = m_bFormat ? ::GetActiveWrtShell() + : getFrameDlgParentShell(); + OSL_ENSURE( pSh , "shell not found"); + if (pSh) + { + SwFormatAnchor aAnc( eAnchorId, eAnchorId == RndStdIds::FLY_AT_PAGE ? pSh->GetPhyPageNum() : 0 ); + bRet = nullptr != rSet->Put( aAnc ); + } + } + } + + if ( m_pHMap ) + { + SwFormatHoriOrient aHoriOrient( rOldSet.Get(RES_HORI_ORIENT) ); + + const sal_Int32 nMapPos = GetMapPos(m_pHMap, *m_xHorizontalDLB); + const sal_Int16 eHOri = GetAlignment(m_pHMap, nMapPos, *m_xHoriRelationLB); + const sal_Int16 eRel = GetRelation(*m_xHoriRelationLB); + + aHoriOrient.SetHoriOrient( eHOri ); + aHoriOrient.SetRelationOrient( eRel ); + aHoriOrient.SetPosToggle(m_xMirrorPagesCB->get_active()); + + bool bMod = m_xAtHorzPosED->get_value_changed_from_saved(); + bMod |= m_xMirrorPagesCB->get_state_changed_from_saved(); + + if ( eHOri == text::HoriOrientation::NONE && + (m_bNew || (m_bAtHorzPosModified || bMod) || m_nOldH != eHOri ) ) + { + SwTwips nX = static_cast< SwTwips >(m_xAtHorzPosED->denormalize(m_xAtHorzPosED->get_value(FieldUnit::TWIP))); + aHoriOrient.SetPos( nX ); + } + + pOldItem = GetOldItem(*rSet, FN_HORI_ORIENT); + bool bSame = false; + if ((m_bNew == m_bFormat) && pOldItem) + { + bSame = aHoriOrient == static_cast<const SwFormatHoriOrient&>(*pOldItem); + } + if ((m_bNew && !m_bFormat) || ((m_bAtHorzPosModified || bMod) && !bSame)) + { + bRet |= nullptr != rSet->Put( aHoriOrient ); + } + } + + if ( m_pVMap ) + { + // alignment vertical + SwFormatVertOrient aVertOrient( rOldSet.Get(RES_VERT_ORIENT) ); + + const sal_Int32 nMapPos = GetMapPos(m_pVMap, *m_xVerticalDLB); + const sal_Int16 eVOri = GetAlignment(m_pVMap, nMapPos, *m_xVertRelationLB); + const sal_Int16 eRel = GetRelation(*m_xVertRelationLB); + + aVertOrient.SetVertOrient ( eVOri); + aVertOrient.SetRelationOrient( eRel ); + + bool bMod = m_xAtVertPosED->get_value_changed_from_saved(); + + if ( eVOri == text::VertOrientation::NONE && + ( m_bNew || (m_bAtVertPosModified || bMod) || m_nOldV != eVOri) ) + { + // vertical position + // recalculate offset for character bound frames + SwTwips nY = static_cast< SwTwips >(m_xAtVertPosED->denormalize(m_xAtVertPosED->get_value(FieldUnit::TWIP))); + if (eAnchorId == RndStdIds::FLY_AS_CHAR) + { + nY *= -1; + } + aVertOrient.SetPos( nY ); + } + pOldItem = GetOldItem(*rSet, FN_VERT_ORIENT); + bool bSame = false; + if((m_bNew == m_bFormat) && pOldItem) + { + bSame = m_bFormat ? + aVertOrient.GetVertOrient() == static_cast<const SwFormatVertOrient*>(pOldItem)->GetVertOrient() && + aVertOrient.GetRelationOrient() == static_cast<const SwFormatVertOrient*>(pOldItem)->GetRelationOrient() && + aVertOrient.GetPos() == static_cast<const SwFormatVertOrient*>(pOldItem)->GetPos() + : aVertOrient == static_cast<const SwFormatVertOrient&>(*pOldItem); + } + if( ( m_bNew && !m_bFormat ) || ((m_bAtVertPosModified || bMod) && !bSame )) + { + bRet |= nullptr != rSet->Put( aVertOrient ); + } + } + + // set size + // new exception: when the size of pMgr(, 0), then the properties + // for a graphic that isn't even loaded, are set. Then no SetSize + // is done here when the size settings were not changed by the + // user. + const SwFormatFrameSize& rOldSize = rOldSet.Get(RES_FRM_SIZE); + SwFormatFrameSize aSz( rOldSize ); + + auto nRelWidthRelation = m_xRelWidthRelationLB->get_active(); + if (nRelWidthRelation != -1) + { + if (nRelWidthRelation == 0) + aSz.SetWidthPercentRelation(text::RelOrientation::FRAME); + else if (nRelWidthRelation == 1) + aSz.SetWidthPercentRelation(text::RelOrientation::PAGE_FRAME); + } + auto nRelHeightRelation = m_xRelHeightRelationLB->get_active(); + if (nRelHeightRelation != -1) + { + if (nRelHeightRelation == 0) + aSz.SetHeightPercentRelation(text::RelOrientation::FRAME); + else if (nRelHeightRelation == 1) + aSz.SetHeightPercentRelation(text::RelOrientation::PAGE_FRAME); + } + + bool bValueModified = m_xWidthED->get_value_changed_from_saved() || + m_xHeightED->get_value_changed_from_saved(); + bool bCheckChanged = m_xRelWidthCB->get_state_changed_from_saved() || + m_xRelHeightCB->get_state_changed_from_saved() || + m_xFixedRatioCB->get_state_changed_from_saved(); + + bool bLegalValue = !(!rOldSize.GetWidth () && !rOldSize.GetHeight() && + m_xWidthED->get_value() == m_xWidthED->get_min() && + m_xHeightED->get_value() == m_xHeightED->get_min()); + + if ((m_bNew && !m_bFormat) || ((bValueModified || bCheckChanged) && bLegalValue)) + { + sal_Int64 nNewWidth = m_xWidthED->DenormalizePercent(m_xWidthED->GetRealValue(FieldUnit::TWIP)); + sal_Int64 nNewHeight = m_xHeightED->DenormalizePercent(m_xHeightED->GetRealValue(FieldUnit::TWIP)); + aSz.SetWidth (static_cast< SwTwips >(nNewWidth)); + aSz.SetHeight(static_cast< SwTwips >(nNewHeight)); + + if (m_xRelWidthCB->get_active()) + { + aSz.SetWidthPercent(static_cast<sal_uInt8>(std::min(MAX_PERCENT_WIDTH, m_xWidthED->Convert(m_xWidthED->NormalizePercent(nNewWidth), FieldUnit::TWIP, FieldUnit::PERCENT)))); + } + else + aSz.SetWidthPercent(0); + if (m_xRelHeightCB->get_active()) + aSz.SetHeightPercent(static_cast<sal_uInt8>(std::min(MAX_PERCENT_HEIGHT, m_xHeightED->Convert(m_xHeightED->NormalizePercent(nNewHeight), FieldUnit::TWIP, FieldUnit::PERCENT)))); + else + aSz.SetHeightPercent(0); + + if (m_xFixedRatioCB->get_active() && (m_xRelWidthCB->get_active() != m_xRelHeightCB->get_active())) + { + if (m_xRelWidthCB->get_active()) + aSz.SetHeightPercent(SwFormatFrameSize::SYNCED); + else + aSz.SetWidthPercent(SwFormatFrameSize::SYNCED); + } + } + + if( !IsInGraficMode() ) + { + if (m_xAutoHeightCB->get_state_changed_from_saved()) + { + SwFrameSize eFrameSize = m_xAutoHeightCB->get_active()? SwFrameSize::Minimum : SwFrameSize::Fixed; + if( eFrameSize != aSz.GetHeightSizeType() ) + aSz.SetHeightSizeType(eFrameSize); + } + if (m_xAutoWidthCB->get_state_changed_from_saved()) + { + SwFrameSize eFrameSize = m_xAutoWidthCB->get_active()? SwFrameSize::Minimum : SwFrameSize::Fixed; + if( eFrameSize != aSz.GetWidthSizeType() ) + aSz.SetWidthSizeType( eFrameSize ); + } + } + if (m_xFixedRatioCB->get_state_changed_from_saved()) + bRet |= nullptr != rSet->Put(SfxBoolItem(FN_KEEP_ASPECT_RATIO, m_xFixedRatioCB->get_active())); + + pOldItem = GetOldItem(*rSet, RES_FRM_SIZE); + + bool bSizeChanged = pOldItem && aSz != *pOldItem; + if (!bSizeChanged && m_bNew) + { + // If no custom size is provided, always set a size for a new frame, to avoid ~zero width. + bSizeChanged = true; + } + if (bSizeChanged || (!pOldItem && !m_bFormat) || + (m_bFormat && + (aSz.GetWidth() > 0 || aSz.GetWidthPercent() > 0) && + (aSz.GetHeight() > 0 || aSz.GetHeightPercent() > 0))) + { + if (aSz.GetHeightSizeType() == SwFrameSize::Variable) // there is no VAR_SIZE in frames + aSz.SetHeightSizeType(SwFrameSize::Minimum); + + bRet |= nullptr != rSet->Put( aSz ); + } + if (m_xFollowTextFlowCB->get_state_changed_from_saved()) + { + bRet |= nullptr != rSet->Put(SwFormatFollowTextFlow(m_xFollowTextFlowCB->get_active())); + } + if (m_xFlySplitCB->get_state_changed_from_saved()) + { + bRet |= rSet->Put(SwFormatFlySplit(m_xFlySplitCB->get_active())) != nullptr; + } + return bRet; +} + +// initialise horizontal and vertical Pos +void SwFramePage::InitPos(RndStdIds eId, + sal_Int16 nH, + sal_Int16 nHRel, + sal_Int16 nV, + sal_Int16 nVRel, + tools::Long nX, + tools::Long nY) +{ + auto nPos = m_xVerticalDLB->get_active(); + if (nPos != -1 && m_pVMap) + { + m_nOldV = m_pVMap[nPos].nAlign; + + nPos = m_xVertRelationLB->get_active(); + if (nPos != -1) + m_nOldVRel = weld::fromId<RelationMap*>(m_xVertRelationLB->get_id(nPos))->nRelation; + } + + nPos = m_xHorizontalDLB->get_active(); + if (nPos != -1 && m_pHMap) + { + m_nOldH = m_pHMap[nPos].nAlign; + + nPos = m_xHoriRelationLB->get_active(); + if (nPos != -1) + m_nOldHRel = weld::fromId<RelationMap*>(m_xHoriRelationLB->get_id(nPos))->nRelation; + } + + bool bEnable = true; + if ( eId == RndStdIds::FLY_AT_PAGE ) + { + m_pVMap = m_bHtmlMode ? aVPageHtmlMap : aVPageMap; + m_pHMap = m_bHtmlMode ? aHPageHtmlMap : aHPageMap; + } + else if ( eId == RndStdIds::FLY_AT_FLY ) + { + // own vertical alignment map for to frame + // anchored objects. + m_pVMap = m_bHtmlMode ? aVFlyHtmlMap : aVFrameMap; + m_pHMap = m_bHtmlMode ? aHFlyHtmlMap : aHFrameMap; + } + else if ( eId == RndStdIds::FLY_AT_PARA ) + { + if(m_bHtmlMode) + { + m_pVMap = aVParaHtmlMap; + m_pHMap = aHParaHtmlAbsMap; + } + else + { + m_pVMap = aVParaMap; + m_pHMap = aHParaMap; + } + } + else if ( eId == RndStdIds::FLY_AT_CHAR ) + { + if(m_bHtmlMode) + { + m_pVMap = aVCharHtmlAbsMap; + m_pHMap = aHCharHtmlAbsMap; + } + else + { + m_pVMap = aVCharMap; + m_pHMap = aHCharMap; + } + } + else if ( eId == RndStdIds::FLY_AS_CHAR ) + { + m_pVMap = m_bHtmlMode ? aVAsCharHtmlMap : aVAsCharMap; + m_pHMap = nullptr; + bEnable = false; + } + m_xHorizontalDLB->set_sensitive( bEnable ); + m_xHorizontalFT->set_sensitive( bEnable ); + + // select current Pos + // horizontal + if ( nH < 0 ) + { + nH = m_nOldH; + nHRel = m_nOldHRel; + } + sal_Int32 nMapPos = FillPosLB(m_pHMap, nH, nHRel, *m_xHorizontalDLB); + FillRelLB(m_pHMap, nMapPos, nH, nHRel, *m_xHoriRelationLB, *m_xHoriRelationFT); + + // vertical + if ( nV < 0 ) + { + nV = m_nOldV; + nVRel = m_nOldVRel; + } + nMapPos = FillPosLB(m_pVMap, nV, nVRel, *m_xVerticalDLB); + FillRelLB(m_pVMap, nMapPos, nV, nVRel, *m_xVertRelationLB, *m_xVertRelationFT); + + bEnable = nH == text::HoriOrientation::NONE && eId != RndStdIds::FLY_AS_CHAR; + if (!bEnable) + m_xAtHorzPosED->set_value(0, FieldUnit::TWIP); + else + { + if (nX != LONG_MAX) + m_xAtHorzPosED->set_value(m_xAtHorzPosED->normalize(nX), FieldUnit::TWIP); + } + m_xAtHorzPosFT->set_sensitive( bEnable ); + m_xAtHorzPosED->set_sensitive( bEnable ); + + bEnable = nV == text::VertOrientation::NONE; + if ( !bEnable ) + m_xAtVertPosED->set_value(0, FieldUnit::TWIP); + else + { + if (eId == RndStdIds::FLY_AS_CHAR) + { + if ( nY == LONG_MAX ) + nY = 0; + else + nY *= -1; + } + if ( nY != LONG_MAX ) + m_xAtVertPosED->set_value(m_xAtVertPosED->normalize(nY), FieldUnit::TWIP); + } + m_xAtVertPosFT->set_sensitive( bEnable && m_bAllowVertPositioning ); + m_xAtVertPosED->set_sensitive( bEnable && m_bAllowVertPositioning ); + UpdateExample(); +} + +sal_Int32 SwFramePage::FillPosLB(const FrameMap* _pMap, + const sal_Int16 _nAlign, + const sal_Int16 _nRel, + weld::ComboBox& _rLB ) +{ + OUString sSelEntry; + const OUString sOldEntry = _rLB.get_active_text(); + + _rLB.clear(); + + // i#22341 determine all possible listbox relations for + // given relation for map <aVCharMap> + const LB nLBRelations = (_pMap != aVCharMap) + ? LB::NONE + : ::lcl_GetLBRelationsForRelations( _nRel ); + + // fill Listbox + size_t nCount = ::lcl_GetFrameMapCount(_pMap); + for (size_t i = 0; _pMap && i < nCount; ++i) + { +// Why not from the left/from inside or from above? + SvxSwFramePosString::StringId eStrId = m_xMirrorPagesCB->get_active() ? _pMap[i].eMirrorStrId : _pMap[i].eStrId; + // --> OD 2009-08-31 #mongolianlayout# + eStrId = lcl_ChangeResIdToVerticalOrRTL( eStrId, + m_bIsVerticalFrame, + m_bIsVerticalL2R, + m_bIsInRightToLeft); + OUString sEntry(SvxSwFramePosString::GetString(eStrId)); + if (_rLB.find_text(sEntry) == -1) + { + // don't insert entries when frames are character bound + _rLB.append_text(sEntry); + } + // i#22341 - add condition to handle map <aVCharMap> + // that is ambiguous in the alignment. + if ( _pMap[i].nAlign == _nAlign && + ( (_pMap != aVCharMap) || _pMap[i].nLBRelations & nLBRelations ) ) + { + sSelEntry = sEntry; + } + } + + _rLB.set_active_text(sSelEntry); + if (_rLB.get_active() == -1) + _rLB.set_active_text(sOldEntry); + + if (_rLB.get_active() == -1 && _rLB.get_count()) + _rLB.set_active(0); + + PosHdl(_rLB); + + return GetMapPos(_pMap, _rLB); +} + +void SwFramePage::FillRelLB(const FrameMap* _pMap, + const sal_uInt16 _nLBSelPos, + const sal_Int16 _nAlign, + const sal_Int16 _nRel, + weld::ComboBox& _rLB, + weld::Label& _rFT) +{ + OUString sSelEntry; + LB nLBRelations = LB::NONE; + size_t nMapCount = ::lcl_GetFrameMapCount(_pMap); + + _rLB.clear(); + + if (_nLBSelPos < nMapCount) + { + if (_pMap == aVAsCharHtmlMap || _pMap == aVAsCharMap) + { + const OUString sOldEntry(_rLB.get_active_text()); + SvxSwFramePosString::StringId eStrId = _pMap[_nLBSelPos].eStrId; + + for (size_t nMapPos = 0; nMapPos < nMapCount; nMapPos++) + { + if (_pMap[nMapPos].eStrId == eStrId) + { + nLBRelations = _pMap[nMapPos].nLBRelations; + for (RelationMap const & rCharMap : aAsCharRelationMap) + { + if (nLBRelations & rCharMap.nLBRelation) + { + // --> OD 2009-08-31 #mongolianlayout# + SvxSwFramePosString::StringId sStrId1 = + lcl_ChangeResIdToVerticalOrRTL( rCharMap.eStrId, + m_bIsVerticalFrame, + m_bIsVerticalL2R, + m_bIsInRightToLeft); + const OUString sEntry = SvxSwFramePosString::GetString(sStrId1); + _rLB.append(weld::toId(&rCharMap), sEntry); + if (_pMap[nMapPos].nAlign == _nAlign) + sSelEntry = sEntry; + break; + } + } + } + } + if (!sSelEntry.isEmpty()) + _rLB.set_active_text(sSelEntry); + else + { + _rLB.set_active_text(sOldEntry); + + if (_rLB.get_active() == -1) + { + for (int i = 0; i < _rLB.get_count(); i++) + { + RelationMap *pEntry = weld::fromId<RelationMap*>(_rLB.get_id(i)); + if (pEntry->nLBRelation == LB::RelChar) // default + { + _rLB.set_active(i); + break; + } + } + } + } + } + else + { + // special handling for map <aVCharMap>, + // because its ambiguous in its <eStrId>/<eMirrorStrId>. + if ( _pMap == aVCharMap ) + { + nLBRelations = ::lcl_GetLBRelationsForStrID( _pMap, + ( m_xMirrorPagesCB->get_active() + ? _pMap[_nLBSelPos].eMirrorStrId + : _pMap[_nLBSelPos].eStrId), + m_xMirrorPagesCB->get_active() ); + } + else + { + nLBRelations = _pMap[_nLBSelPos].nLBRelations; + } + + for (sal_uLong nBit = 1; nBit < 0x80000000; nBit <<= 1) + { + if (nLBRelations & static_cast<LB>(nBit)) + { + for (RelationMap const & rMap : aRelationMap) + { + if (rMap.nLBRelation == static_cast<LB>(nBit)) + { + SvxSwFramePosString::StringId eStrId1 = m_xMirrorPagesCB->get_active() ? + rMap.eMirrorStrId : rMap.eStrId; + // --> OD 2009-08-31 #mongolianlayout# + eStrId1 = + lcl_ChangeResIdToVerticalOrRTL( eStrId1, + m_bIsVerticalFrame, + m_bIsVerticalL2R, + m_bIsInRightToLeft); + const OUString sEntry = SvxSwFramePosString::GetString(eStrId1); + _rLB.append(weld::toId(&rMap), sEntry); + if (sSelEntry.isEmpty() && rMap.nRelation == _nRel) + sSelEntry = sEntry; + } + } + } + } + if (!sSelEntry.isEmpty()) + _rLB.set_active_text(sSelEntry); + else + { + // Probably anchor switch. So look for similar relation + sal_Int16 nSimRel = -1; + switch (_nRel) + { + case text::RelOrientation::FRAME: + nSimRel = text::RelOrientation::PAGE_FRAME; + break; + case text::RelOrientation::PRINT_AREA: + nSimRel = text::RelOrientation::PAGE_PRINT_AREA; + break; + case text::RelOrientation::PAGE_LEFT: + nSimRel = text::RelOrientation::FRAME_LEFT; + break; + case text::RelOrientation::PAGE_RIGHT: + nSimRel = text::RelOrientation::FRAME_RIGHT; + break; + case text::RelOrientation::FRAME_LEFT: + nSimRel = text::RelOrientation::PAGE_LEFT; + break; + case text::RelOrientation::FRAME_RIGHT: + nSimRel = text::RelOrientation::PAGE_RIGHT; + break; + case text::RelOrientation::PAGE_FRAME: + nSimRel = text::RelOrientation::FRAME; + break; + case text::RelOrientation::PAGE_PRINT_AREA: + nSimRel = text::RelOrientation::PRINT_AREA; + break; + + default: + if (_rLB.get_active() != -1) + { + RelationMap *pEntry = weld::fromId<RelationMap*>(_rLB.get_id(_rLB.get_count() - 1)); + nSimRel = pEntry->nRelation; + } + break; + } + + for (int i = 0; i < _rLB.get_count(); i++) + { + RelationMap *pEntry = weld::fromId<RelationMap*>(_rLB.get_id(i)); + if (pEntry->nRelation == nSimRel) + { + _rLB.set_active(i); + break; + } + } + + if (_rLB.get_active() == -1) + _rLB.set_active(0); + } + } + } + + const bool bEnable = _rLB.get_count() != 0 + && (&_rLB != m_xVertRelationLB.get() || m_bAllowVertPositioning); + _rLB.set_sensitive( bEnable ); + _rFT.set_sensitive( bEnable ); + + RelHdl(_rLB); +} + +sal_Int16 SwFramePage::GetRelation(const weld::ComboBox& rRelationLB) +{ + const auto nPos = rRelationLB.get_active(); + if (nPos != -1) + { + RelationMap *pEntry = weld::fromId<RelationMap *>(rRelationLB.get_id(nPos)); + return pEntry->nRelation; + } + + return 0; +} + +sal_Int16 SwFramePage::GetAlignment(FrameMap const *pMap, sal_Int32 nMapPos, + const weld::ComboBox& rRelationLB) +{ + if (!pMap || nMapPos < 0) + return 0; + + const size_t nMapCount = ::lcl_GetFrameMapCount(pMap); + + if (o3tl::make_unsigned(nMapPos) >= nMapCount) + return 0; + + // i#22341 special handling also for map <aVCharMap>, + // because it contains ambiguous items for alignment + if ( pMap != aVAsCharHtmlMap && pMap != aVAsCharMap && pMap != aVCharMap ) + return pMap[nMapPos].nAlign; + + if (rRelationLB.get_active() == -1) + return 0; + + const RelationMap *const pRelationMap = weld::fromId<const RelationMap*>( + rRelationLB.get_active_id()); + const LB nRel = pRelationMap->nLBRelation; + const SvxSwFramePosString::StringId eStrId = pMap[nMapPos].eStrId; + + for (size_t i = 0; i < nMapCount; ++i) + { + if (pMap[i].eStrId == eStrId && (pMap[i].nLBRelations & nRel)) + return pMap[i].nAlign; + } + + return 0; +} + +sal_Int32 SwFramePage::GetMapPos(const FrameMap *pMap, const weld::ComboBox& rAlignLB) +{ + sal_Int32 nMapPos = 0; + auto nLBSelPos = rAlignLB.get_active(); + + if (nLBSelPos != -1) + { + if (pMap == aVAsCharHtmlMap || pMap == aVAsCharMap) + { + const size_t nMapCount = ::lcl_GetFrameMapCount(pMap); + const OUString sSelEntry(rAlignLB.get_active_text()); + + for (size_t i = 0; i < nMapCount; i++) + { + SvxSwFramePosString::StringId eResId = pMap[i].eStrId; + + OUString sEntry = SvxSwFramePosString::GetString(eResId); + sEntry = MnemonicGenerator::EraseAllMnemonicChars( sEntry ); + + if (sEntry == sSelEntry) + { + nMapPos = static_cast< sal_Int32 >(i); + break; + } + } + } + else + nMapPos = nLBSelPos; + } + + return nMapPos; +} + +RndStdIds SwFramePage::GetAnchor() const +{ + RndStdIds nRet = RndStdIds::FLY_AT_PAGE; + if (m_xAnchorAtParaRB->get_active()) + { + nRet = RndStdIds::FLY_AT_PARA; + } + else if (m_xAnchorAtCharRB->get_active()) + { + nRet = RndStdIds::FLY_AT_CHAR; + } + else if (m_xAnchorAsCharRB->get_active()) + { + nRet = RndStdIds::FLY_AS_CHAR; + } + else if (m_xAnchorAtFrameRB->get_active()) + { + nRet = RndStdIds::FLY_AT_FLY; + } + return nRet; +} + +// Bsp - Update +void SwFramePage::ActivatePage(const SfxItemSet& rSet) +{ + m_bNoModifyHdl = true; + Init(rSet); + m_bNoModifyHdl = false; + //lock PercentFields + m_xWidthED->LockAutoCalculation(true); + m_xHeightED->LockAutoCalculation(true); + RangeModifyHdl(); // set all maximum values initially + m_xHeightED->LockAutoCalculation(false); + m_xWidthED->LockAutoCalculation(false); + m_xFollowTextFlowCB->save_state(); + m_xFlySplitCB->save_state(); +} + +DeactivateRC SwFramePage::DeactivatePage(SfxItemSet * _pSet) +{ + if ( _pSet ) + { + FillItemSet( _pSet ); + + if (!m_bFormat) // tdf#112574 no anchor in styles + { + //FillItemSet doesn't set the anchor into the set when it matches + //the original. But for the other pages we need the current anchor. + SwWrtShell* pSh = m_bFormat ? ::GetActiveWrtShell() + : getFrameDlgParentShell(); + if (pSh) + { + RndStdIds eAnchorId = GetAnchor(); + SwFormatAnchor aAnc( eAnchorId, eAnchorId == RndStdIds::FLY_AT_PAGE ? pSh->GetPhyPageNum() : 0 ); + _pSet->Put( aAnc ); + } + } + } + + return DeactivateRC::LeavePage; +} + +// swap left/right with inside/outside +IMPL_LINK_NOARG(SwFramePage, MirrorHdl, weld::Toggleable&, void) +{ + RndStdIds eId = GetAnchor(); + InitPos(eId, -1, 0, -1, 0, LONG_MAX, LONG_MAX); +} + +IMPL_LINK( SwFramePage, RelSizeClickHdl, weld::Toggleable&, rBtn, void ) +{ + if (&rBtn == m_xRelWidthCB.get()) + { + m_xWidthED->ShowPercent(rBtn.get_active()); + m_xRelWidthRelationLB->set_sensitive(rBtn.get_active()); + if (rBtn.get_active()) + m_xWidthED->get()->set_max(MAX_PERCENT_WIDTH, FieldUnit::NONE); + } + else // rBtn == m_xRelHeightCB.get() + { + m_xHeightED->ShowPercent(rBtn.get_active()); + m_xRelHeightRelationLB->set_sensitive(rBtn.get_active()); + if (rBtn.get_active()) + m_xHeightED->get()->set_max(MAX_PERCENT_HEIGHT, FieldUnit::NONE); + } + + RangeModifyHdl(); // correct the values again + + if (&rBtn == m_xRelWidthCB.get()) + ModifyHdl(*m_xWidthED->get()); + else // rBtn == m_xRelHeightCB.get() + ModifyHdl(*m_xHeightED->get()); +} + +// range check +IMPL_LINK_NOARG(SwFramePage, RangeModifyClickHdl, weld::Toggleable&, void) +{ + RangeModifyHdl(); +} + +void SwFramePage::RangeModifyHdl() +{ + if (m_bNoModifyHdl) + return; + + SwWrtShell* pSh = m_bFormat ? ::GetActiveWrtShell() + : getFrameDlgParentShell(); + OSL_ENSURE(pSh , "shell not found"); + if (!pSh) + return; + + SwFlyFrameAttrMgr aMgr( m_bNew, pSh, GetItemSet() ); + SvxSwFrameValidation aVal; + + aVal.nAnchorType = GetAnchor(); + aVal.bAutoHeight = m_xAutoHeightCB->get_active(); + aVal.bMirror = m_xMirrorPagesCB->get_active(); + aVal.bFollowTextFlow = m_xFollowTextFlowCB->get_active(); + + if ( m_pHMap ) + { + // alignment horizontal + const sal_Int32 nMapPos = GetMapPos(m_pHMap, *m_xHorizontalDLB); + aVal.nHoriOrient = GetAlignment(m_pHMap, nMapPos, *m_xHoriRelationLB); + aVal.nHRelOrient = GetRelation(*m_xHoriRelationLB); + } + else + aVal.nHoriOrient = text::HoriOrientation::NONE; + + if ( m_pVMap ) + { + // alignment vertical + const sal_Int32 nMapPos = GetMapPos(m_pVMap, *m_xVerticalDLB); + aVal.nVertOrient = GetAlignment(m_pVMap, nMapPos, *m_xVertRelationLB); + aVal.nVRelOrient = GetRelation(*m_xVertRelationLB); + } + else + aVal.nVertOrient = text::VertOrientation::NONE; + + const tools::Long nAtHorzPosVal = static_cast< tools::Long >( + m_xAtHorzPosED->denormalize(m_xAtHorzPosED->get_value(FieldUnit::TWIP)) ); + const tools::Long nAtVertPosVal = static_cast< tools::Long >( + m_xAtVertPosED->denormalize(m_xAtVertPosED->get_value(FieldUnit::TWIP)) ); + + aVal.nHPos = nAtHorzPosVal; + aVal.nVPos = nAtVertPosVal; + + aMgr.ValidateMetrics(aVal, mpToCharContentPos, true); // one time, to get reference values for percental values + + // set reference values for percental values (100%) ... + m_xWidthED->SetRefValue(aVal.aPercentSize.Width()); + m_xHeightED->SetRefValue(aVal.aPercentSize.Height()); + + // ... and correctly convert width and height with it + SwTwips nWidth = static_cast< SwTwips >(m_xWidthED->DenormalizePercent(m_xWidthED->get_value(FieldUnit::TWIP))); + SwTwips nHeight = static_cast< SwTwips >(m_xHeightED->DenormalizePercent(m_xHeightED->get_value(FieldUnit::TWIP))); + aVal.nWidth = nWidth; + aVal.nHeight = nHeight; + + aMgr.ValidateMetrics(aVal, mpToCharContentPos); // one more time, to determine all remaining values with correct width and height. + + // all columns have to be correct + const SfxItemSet* pExampleSet = GetDialogExampleSet(); + if (pExampleSet && SfxItemState::DEFAULT <= pExampleSet->GetItemState(RES_COL)) + { + const SwFormatCol& rCol = pExampleSet->Get(RES_COL); + if ( rCol.GetColumns().size() > 1 ) + { + for (const SwColumn & i : rCol.GetColumns()) + { + aVal.nMinWidth += i.GetLeft() + + i.GetRight() + + MINFLY; + } + aVal.nMinWidth -= MINFLY;//one was already in there! + } + } + + nWidth = aVal.nWidth; + nHeight = aVal.nHeight; + + // minimum range also for template + m_xHeightED->set_min(m_xHeightED->NormalizePercent(aVal.nMinHeight), FieldUnit::TWIP); + m_xWidthED->set_min(m_xWidthED->NormalizePercent(aVal.nMinWidth), FieldUnit::TWIP); + + SwTwips nMaxWidth(aVal.nMaxWidth); + SwTwips nMaxHeight(aVal.nMaxHeight); + + if (aVal.bAutoHeight && (m_sDlgType == "PictureDialog" || m_sDlgType == "ObjectDialog")) + { + SwTwips nTmp = std::min(nWidth * nMaxHeight / std::max(nHeight, SwTwips(1)), nMaxHeight); + m_xWidthED->set_max(m_xWidthED->NormalizePercent(nTmp), FieldUnit::TWIP); + + nTmp = std::min(nHeight * nMaxWidth / std::max(nWidth, SwTwips(1)), nMaxWidth); + m_xHeightED->set_max(m_xWidthED->NormalizePercent(nTmp), FieldUnit::TWIP); + } + else + { + SwTwips nTmp = static_cast< SwTwips >(m_xHeightED->NormalizePercent(nMaxHeight)); + m_xHeightED->set_max(nTmp, FieldUnit::TWIP); + + nTmp = static_cast< SwTwips >(m_xWidthED->NormalizePercent(nMaxWidth)); + m_xWidthED->set_max(nTmp, FieldUnit::TWIP); + } + + m_xAtHorzPosED->set_range(m_xAtHorzPosED->normalize(aVal.nMinHPos), + m_xAtHorzPosED->normalize(aVal.nMaxHPos), + FieldUnit::TWIP); + if (aVal.nHPos != nAtHorzPosVal) + m_xAtHorzPosED->set_value(m_xAtHorzPosED->normalize(aVal.nHPos), FieldUnit::TWIP); + + const SwTwips nUpperOffset = (aVal.nAnchorType == RndStdIds::FLY_AS_CHAR) + ? m_nUpperBorder : 0; + const SwTwips nLowerOffset = (aVal.nAnchorType == RndStdIds::FLY_AS_CHAR) + ? m_nLowerBorder : 0; + + m_xAtVertPosED->set_range(m_xAtVertPosED->normalize(aVal.nMinVPos + nLowerOffset + nUpperOffset), + m_xAtVertPosED->normalize(aVal.nMaxVPos), + FieldUnit::TWIP); + if (aVal.nVPos != nAtVertPosVal) + m_xAtVertPosED->set_value(m_xAtVertPosED->normalize(aVal.nVPos), FieldUnit::TWIP); +} + +IMPL_LINK_NOARG(SwFramePage, AnchorTypeHdl, weld::Toggleable&, void) +{ + m_xMirrorPagesCB->set_sensitive(!m_xAnchorAsCharRB->get_active()); + + // i#18732 - enable check box 'Follow text flow' for anchor + // type to-paragraph' and to-character + // i#22305 - enable check box 'Follow text + // flow' also for anchor type to-frame. + m_xFollowTextFlowCB->set_sensitive(m_xAnchorAtParaRB->get_active() || + m_xAnchorAtCharRB->get_active() || + m_xAnchorAtFrameRB->get_active()); + m_xFlySplitCB->set_sensitive(m_xAnchorAtParaRB->get_active()); + + RndStdIds eId = GetAnchor(); + + InitPos( eId, -1, 0, -1, 0, LONG_MAX, LONG_MAX); + RangeModifyHdl(); + + if(m_bHtmlMode) + { + PosHdl(*m_xHorizontalDLB); + PosHdl(*m_xVerticalDLB); + } + + EnableVerticalPositioning( !(m_bIsMathOLE && m_bIsMathBaselineAlignment + && RndStdIds::FLY_AS_CHAR == eId) ); +} + +IMPL_LINK( SwFramePage, PosHdl, weld::ComboBox&, rLB, void ) +{ + bool bHori = &rLB == m_xHorizontalDLB.get(); + weld::ComboBox *pRelLB = bHori ? m_xHoriRelationLB.get() : m_xVertRelationLB.get(); + weld::Label *pRelFT = bHori ? m_xHoriRelationFT.get() : m_xVertRelationFT.get(); + FrameMap const *pMap = bHori ? m_pHMap : m_pVMap; + + const sal_Int32 nMapPos = GetMapPos(pMap, rLB); + const sal_Int16 nAlign = GetAlignment(pMap, nMapPos, *pRelLB); + + if (bHori) + { + bool bEnable = text::HoriOrientation::NONE == nAlign; + m_xAtHorzPosED->set_sensitive( bEnable ); + m_xAtHorzPosFT->set_sensitive( bEnable ); + } + else + { + bool bEnable = text::VertOrientation::NONE == nAlign && m_bAllowVertPositioning; + m_xAtVertPosED->set_sensitive( bEnable ); + m_xAtVertPosFT->set_sensitive( bEnable ); + } + + RangeModifyHdl(); + + sal_Int16 nRel = 0; + if (rLB.get_active() != -1) + { + if (pRelLB->get_active() != -1) + nRel = weld::fromId<RelationMap*>(pRelLB->get_active_id())->nRelation; + FillRelLB(pMap, nMapPos, nAlign, nRel, *pRelLB, *pRelFT); + } + else + pRelLB->clear(); + + UpdateExample(); + + if (bHori) + m_bAtHorzPosModified = true; + else + m_bAtVertPosModified = true; + + // special treatment for HTML-Mode with horizontal-vertical-dependencies + if(!(m_bHtmlMode && (RndStdIds::FLY_AT_CHAR == GetAnchor()))) + return; + + bool bSet = false; + if(bHori) + { + // right is allowed only above - from the left only above + // from the left at character -> below + if((text::HoriOrientation::LEFT == nAlign || text::HoriOrientation::RIGHT == nAlign) && + 0 == m_xVerticalDLB->get_active()) + { + if(text::RelOrientation::FRAME == nRel) + m_xVerticalDLB->set_active(1); + else + m_xVerticalDLB->set_active(0); + bSet = true; + } + else if(text::HoriOrientation::LEFT == nAlign && 1 == m_xVerticalDLB->get_active()) + { + m_xVerticalDLB->set_active(0); + bSet = true; + } + else if(text::HoriOrientation::NONE == nAlign && 1 == m_xVerticalDLB->get_active()) + { + m_xVerticalDLB->set_active(0); + bSet = true; + } + if(bSet) + PosHdl(*m_xVerticalDLB); + } + else + { + if(text::VertOrientation::TOP == nAlign) + { + if (1 == m_xHorizontalDLB->get_active()) + { + m_xHorizontalDLB->set_active(0); + bSet = true; + } + m_xHoriRelationLB->set_active(1); + } + else if(text::VertOrientation::CHAR_BOTTOM == nAlign) + { + if (2 == m_xHorizontalDLB->get_active()) + { + m_xHorizontalDLB->set_active(0); + bSet = true; + } + m_xHoriRelationLB->set_active(0) ; + } + if(bSet) + PosHdl(*m_xHorizontalDLB); + } +} + +// horizontal Pos +IMPL_LINK( SwFramePage, RelHdl, weld::ComboBox&, rLB, void ) +{ + bool bHori = &rLB == m_xHoriRelationLB.get(); + + UpdateExample(); + + if (bHori) + m_bAtHorzPosModified = true; + else + m_bAtVertPosModified = true; + + if (m_bHtmlMode && (RndStdIds::FLY_AT_CHAR == GetAnchor())) + { + if(bHori) + { + const sal_Int16 nRel = GetRelation(*m_xHoriRelationLB); + if(text::RelOrientation::PRINT_AREA == nRel && 0 == m_xVerticalDLB->get_active()) + { + m_xVerticalDLB->set_active(1); + } + else if(text::RelOrientation::CHAR == nRel && 1 == m_xVerticalDLB->get_active()) + { + m_xVerticalDLB->set_active(0); + } + } + } + RangeModifyHdl(); +} + +IMPL_LINK_NOARG(SwFramePage, RealSizeHdl, weld::Button&, void) +{ + m_xWidthED->set_value(m_xWidthED->NormalizePercent(m_aGrfSize.Width()), FieldUnit::TWIP); + m_xHeightED->set_value(m_xHeightED->NormalizePercent(m_aGrfSize.Height()), FieldUnit::TWIP); + m_fWidthHeightRatio = m_aGrfSize.Height() ? double(m_aGrfSize.Width()) / double(m_aGrfSize.Height()) : 1.0; + UpdateExample(); +} + +IMPL_LINK_NOARG(SwFramePage, AutoWidthClickHdl, weld::Toggleable&, void) +{ + if( !IsInGraficMode() ) + HandleAutoCB( m_xAutoWidthCB->get_active(), *m_xWidthFT, *m_xWidthAutoFT, *m_xWidthED->get() ); +} + +IMPL_LINK_NOARG(SwFramePage, AutoHeightClickHdl, weld::Toggleable&, void) +{ + if (!IsInGraficMode()) + HandleAutoCB(m_xAutoHeightCB->get_active(), *m_xHeightFT, *m_xHeightAutoFT, *m_xWidthED->get()); +} + +IMPL_LINK( SwFramePage, ModifyHdl, weld::MetricSpinButton&, rEdit, void ) +{ + SwTwips nWidth = static_cast< SwTwips >(m_xWidthED->DenormalizePercent(m_xWidthED->get_value(FieldUnit::TWIP))); + SwTwips nHeight = static_cast< SwTwips >(m_xHeightED->DenormalizePercent(m_xHeightED->get_value(FieldUnit::TWIP))); + if (m_xFixedRatioCB->get_active()) + { + if (&rEdit == m_xWidthED->get()) + { + nHeight = SwTwips(static_cast<double>(nWidth) / m_fWidthHeightRatio); + m_xHeightED->set_value(m_xHeightED->NormalizePercent(nHeight), FieldUnit::TWIP); + } + else if (&rEdit == m_xHeightED->get()) + { + nWidth = SwTwips(static_cast<double>(nHeight) * m_fWidthHeightRatio); + m_xWidthED->set_value(m_xWidthED->NormalizePercent(nWidth), FieldUnit::TWIP); + } + } + m_fWidthHeightRatio = nHeight ? double(nWidth) / double(nHeight) : 1.0; + UpdateExample(); +} + +void SwFramePage::UpdateExample() +{ + auto nPos = m_xHorizontalDLB->get_active(); + if (m_pHMap && nPos != -1) + { + const sal_Int32 nMapPos = GetMapPos(m_pHMap, *m_xHorizontalDLB); + m_aExampleWN.SetHAlign(GetAlignment(m_pHMap, nMapPos, *m_xHoriRelationLB)); + m_aExampleWN.SetHoriRel(GetRelation(*m_xHoriRelationLB)); + } + + nPos = m_xVerticalDLB->get_active(); + if (m_pVMap && nPos != -1) + { + const sal_Int32 nMapPos = GetMapPos(m_pVMap, *m_xVerticalDLB); + m_aExampleWN.SetVAlign(GetAlignment(m_pVMap, nMapPos, *m_xVertRelationLB)); + m_aExampleWN.SetVertRel(GetRelation(*m_xVertRelationLB)); + } + + // size + auto nXPos = m_xAtHorzPosED->denormalize(m_xAtHorzPosED->get_value(FieldUnit::TWIP)); + auto nYPos = m_xAtVertPosED->denormalize(m_xAtVertPosED->get_value(FieldUnit::TWIP)); + m_aExampleWN.SetRelPos(Point(nXPos, nYPos)); + + m_aExampleWN.SetAnchor(GetAnchor()); + m_aExampleWN.Invalidate(); +} + +void SwFramePage::Init(const SfxItemSet& rSet) +{ + if(!m_bFormat) + { + SwWrtShell* pSh = getFrameDlgParentShell(); + + // size + const bool bSizeFixed = pSh->IsSelObjProtected( FlyProtectFlags::Fixed ) != FlyProtectFlags::NONE; + + m_xWidthED->set_sensitive( !bSizeFixed ); + m_xHeightED->set_sensitive( !bSizeFixed ); + + // size controls for math OLE objects + if ( m_sDlgType == "ObjectDialog" && ! m_bNew ) + { + // disable width and height for math objects + const SvGlobalName& rFactNm( pSh->GetOLEObject()->getClassID() ); + + static struct GlobalNameId { + sal_uInt32 n1; + sal_uInt16 n2, n3; + sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15; + } const aGlbNmIds[] = { { SO3_SM_CLASSID_60 }, { SO3_SM_CLASSID_50 }, + { SO3_SM_CLASSID_40 }, { SO3_SM_CLASSID_30 } }; + + for (const GlobalNameId & rId : aGlbNmIds) { + SvGlobalName aGlbNm( rId.n1, rId.n2, rId.n3, + rId.b8, rId.b9, rId.b10, rId.b11, + rId.b12, rId.b13, rId.b14, rId.b15 ); + + if( rFactNm == aGlbNm ) + { + // disable size controls for math OLE objects + m_xWidthFT->set_sensitive(false); + m_xWidthED->set_sensitive(false); + m_xRelWidthCB->set_sensitive(false); + m_xHeightFT->set_sensitive(false); + m_xHeightED->set_sensitive(false); + m_xRelHeightCB->set_sensitive(false); + m_xFixedRatioCB->set_sensitive(false); + m_xRealSizeBT->set_sensitive(false); + break; + } + } + + // TODO/LATER: get correct aspect + if(0 != (pSh->GetOLEObject()->getStatus( embed::Aspects::MSOLE_CONTENT ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE ) ) + m_xRealSizeBT->set_sensitive(false); + } + } + + const SwFormatFrameSize& rSize = rSet.Get(RES_FRM_SIZE); + sal_Int64 nWidth = m_xWidthED->NormalizePercent(rSize.GetWidth()); + sal_Int64 nHeight = m_xHeightED->NormalizePercent(rSize.GetHeight()); + + if (nWidth != m_xWidthED->get_value(FieldUnit::TWIP)) + m_xWidthED->set_value(nWidth, FieldUnit::TWIP); + + if (nHeight != m_xHeightED->get_value(FieldUnit::TWIP)) + m_xHeightED->set_value(nHeight, FieldUnit::TWIP); + + if (!IsInGraficMode()) + { + SwFrameSize eSize = rSize.GetHeightSizeType(); + bool bCheck = eSize != SwFrameSize::Fixed; + m_xAutoHeightCB->set_active(bCheck); + HandleAutoCB( bCheck, *m_xHeightFT, *m_xHeightAutoFT, *m_xWidthED->get() ); + if( eSize == SwFrameSize::Variable ) + m_xHeightED->set_value(m_xHeightED->get_min()); + + eSize = rSize.GetWidthSizeType(); + bCheck = eSize != SwFrameSize::Fixed; + m_xAutoWidthCB->set_active(bCheck); + HandleAutoCB( bCheck, *m_xWidthFT, *m_xWidthAutoFT, *m_xWidthED->get() ); + if( eSize == SwFrameSize::Variable ) + m_xWidthED->set_value(m_xWidthED->get_min()); + + if ( !m_bFormat ) + { + SwWrtShell* pSh = getFrameDlgParentShell(); + const SwFrameFormat* pFormat = pSh->GetFlyFrameFormat(); + if( pFormat && pFormat->GetChain().GetNext() ) + m_xAutoHeightCB->set_sensitive( false ); + } + } + else + m_xAutoHeightCB->hide(); + + // organise circulation-gap for character bound frames + const SvxULSpaceItem &rUL = rSet.Get(RES_UL_SPACE); + m_nUpperBorder = rUL.GetUpper(); + m_nLowerBorder = rUL.GetLower(); + + if (SfxItemState::SET == rSet.GetItemState(FN_KEEP_ASPECT_RATIO)) + m_xFixedRatioCB->set_active(rSet.Get(FN_KEEP_ASPECT_RATIO).GetValue()); + + // columns + SwFormatCol aCol( rSet.Get(RES_COL) ); + ::FitToActualSize( aCol, o3tl::narrowing<sal_uInt16>(rSize.GetWidth()) ); + + RndStdIds eAnchorId = GetAnchor(); + + if ( m_bNew && !m_bFormat ) + InitPos(eAnchorId, -1, 0, -1, 0, LONG_MAX, LONG_MAX); + else + { + const SwFormatHoriOrient& rHori = rSet.Get(RES_HORI_ORIENT); + const SwFormatVertOrient& rVert = rSet.Get(RES_VERT_ORIENT); + m_nOldH = rHori.GetHoriOrient(); + m_nOldHRel = rHori.GetRelationOrient(); + m_nOldV = rVert.GetVertOrient(); + m_nOldVRel = rVert.GetRelationOrient(); + + if (eAnchorId == RndStdIds::FLY_AT_PAGE) + { + if (m_nOldHRel == text::RelOrientation::FRAME) + m_nOldHRel = text::RelOrientation::PAGE_FRAME; + else if (m_nOldHRel == text::RelOrientation::PRINT_AREA) + m_nOldHRel = text::RelOrientation::PAGE_PRINT_AREA; + if (m_nOldVRel == text::RelOrientation::FRAME) + m_nOldVRel = text::RelOrientation::PAGE_FRAME; + else if (m_nOldVRel == text::RelOrientation::PRINT_AREA) + m_nOldVRel = text::RelOrientation::PAGE_PRINT_AREA; + } + + m_xMirrorPagesCB->set_active(rHori.IsPosToggle()); + m_xMirrorPagesCB->save_state(); + + InitPos(eAnchorId, + m_nOldH, + m_nOldHRel, + m_nOldV, + m_nOldVRel, + rHori.GetPos(), + rVert.GetPos()); + } + + // transparent for example + // circulation for example + const SwFormatSurround& rSurround = rSet.Get(RES_SURROUND); + m_aExampleWN.SetWrap( rSurround.GetSurround() ); + + if ( rSurround.GetSurround() == css::text::WrapTextMode_THROUGH ) + { + const SvxOpaqueItem& rOpaque = rSet.Get(RES_OPAQUE); + m_aExampleWN.SetTransparent(!rOpaque.GetValue()); + } + + // switch to percent if applicable + RangeModifyHdl(); // set reference values (for 100%) + + if (rSize.GetWidthPercent() == SwFormatFrameSize::SYNCED || rSize.GetHeightPercent() == SwFormatFrameSize::SYNCED) + m_xFixedRatioCB->set_active(true); + m_xFixedRatioCB->save_state(); + if (rSize.GetWidthPercent() && rSize.GetWidthPercent() != SwFormatFrameSize::SYNCED && + !m_xRelWidthCB->get_active()) + { + m_xRelWidthCB->set_active(true); + RelSizeClickHdl(*m_xRelWidthCB); + m_xWidthED->set_value(rSize.GetWidthPercent(), FieldUnit::PERCENT); + } + if (rSize.GetHeightPercent() && rSize.GetHeightPercent() != SwFormatFrameSize::SYNCED && + !m_xRelHeightCB->get_active()) + { + m_xRelHeightCB->set_active(true); + RelSizeClickHdl(*m_xRelHeightCB); + m_xHeightED->set_value(rSize.GetHeightPercent(), FieldUnit::PERCENT); + } + m_xRelWidthCB->save_state(); + m_xRelHeightCB->save_state(); + + if (rSize.GetWidthPercentRelation() == text::RelOrientation::PAGE_FRAME) + m_xRelWidthRelationLB->set_active(1); + else + m_xRelWidthRelationLB->set_active(0); + + if (rSize.GetHeightPercentRelation() == text::RelOrientation::PAGE_FRAME) + m_xRelHeightRelationLB->set_active(1); + else + m_xRelHeightRelationLB->set_active(0); +} + +void SwFramePage::SetFormatUsed(bool bFormatUsed) +{ + m_bFormat = bFormatUsed; + if (m_bFormat) + m_xAnchorAtFrameRB->hide(); +} + +void SwFramePage::EnableVerticalPositioning( bool bEnable ) +{ + m_bAllowVertPositioning = bEnable; + m_xVerticalFT->set_sensitive( bEnable ); + m_xVerticalDLB->set_sensitive( bEnable ); + m_xAtVertPosFT->set_sensitive( bEnable ); + m_xAtVertPosED->set_sensitive( bEnable ); + m_xVertRelationFT->set_sensitive( bEnable ); + m_xVertRelationLB->set_sensitive( bEnable ); +} + +SwGrfExtPage::SwGrfExtPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/picturepage.ui", "PicturePage", &rSet) + , m_bHtmlMode(false) + , m_xMirror(m_xBuilder->weld_widget("flipframe")) + , m_xMirrorVertBox(m_xBuilder->weld_check_button("vert")) + , m_xMirrorHorzBox(m_xBuilder->weld_check_button("hori")) + , m_xAllPagesRB(m_xBuilder->weld_radio_button("allpages")) + , m_xLeftPagesRB(m_xBuilder->weld_radio_button("leftpages")) + , m_xRightPagesRB(m_xBuilder->weld_radio_button("rightpages")) + , m_xConnectED(m_xBuilder->weld_entry("entry")) + , m_xBrowseBT(m_xBuilder->weld_button("browse")) + , m_xLinkFrame(m_xBuilder->weld_frame("linkframe")) + // RotGrfFlyFrame: Need Angle and RotateControls now + , m_xFlAngle(m_xBuilder->weld_frame("FL_ANGLE")) + , m_xNfAngle(m_xBuilder->weld_metric_spin_button("NF_ANGLE", FieldUnit::DEGREE)) + , m_xCtlAngle(new svx::DialControl) + , m_xCtlAngleWin(new weld::CustomWeld(*m_xBuilder, "CTL_ANGLE", *m_xCtlAngle)) + , m_xBmpWin(new weld::CustomWeld(*m_xBuilder, "preview", m_aBmpWin)) + // tdf#138843 place holder for the graphic type + , m_xLabelGraphicType(m_xBuilder->weld_label("label-graphic-type")) +{ + m_aBmpWin.SetBitmapEx(BitmapEx(RID_BMP_PREVIEW_FALLBACK)); + + m_xCtlAngle->SetLinkedField(m_xNfAngle.get(), 2); + + SetExchangeSupport(); + m_xMirrorHorzBox->connect_toggled(LINK(this, SwGrfExtPage, MirrorHdl)); + m_xMirrorVertBox->connect_toggled(LINK(this, SwGrfExtPage, MirrorHdl)); + m_xBrowseBT->connect_clicked(LINK(this, SwGrfExtPage, BrowseHdl)); +} + +SwGrfExtPage::~SwGrfExtPage() +{ + m_xBmpWin.reset(); + m_xCtlAngleWin.reset(); + m_xCtlAngle.reset(); + m_xGrfDlg.reset(); +} + +std::unique_ptr<SfxTabPage> SwGrfExtPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet) +{ + return std::make_unique<SwGrfExtPage>(pPage, pController, *rSet); +} + +void SwGrfExtPage::Reset(const SfxItemSet *rSet) +{ + const sal_uInt16 nHtmlMode = ::GetHtmlMode(static_cast<const SwDocShell*>(SfxObjectShell::Current())); + m_bHtmlMode = (nHtmlMode & HTMLMODE_ON) != 0; + + const SfxBoolItem* pConnectItem = rSet->GetItemIfSet( FN_PARAM_GRF_CONNECT ); + if( pConnectItem && pConnectItem->GetValue() ) + { + m_xBrowseBT->set_sensitive(true); + m_xConnectED->set_editable(true); + } + + // RotGrfFlyFrame: Get RotationAngle and set at control + if(const SdrAngleItem* pAngleItem = rSet->GetItemIfSet( SID_ATTR_TRANSFORM_ANGLE, false)) + { + m_xCtlAngle->SetRotation(pAngleItem->GetValue()); + } + else + { + m_xCtlAngle->SetRotation(0_deg100); + } + m_xCtlAngle->SaveValue(); + + ActivatePage(*rSet); +} + +void SwGrfExtPage::ActivatePage(const SfxItemSet& rSet) +{ + const SvxProtectItem& rProt = rSet.Get(RES_PROTECT); + bool bProtContent = rProt.IsContentProtected(); + + const SfxPoolItem* pItem = nullptr; + bool bEnable = false; + bool bEnableMirrorRB = false; + + SfxItemState eState = rSet.GetItemState(RES_GRFATR_MIRRORGRF, true, &pItem); + if (SfxItemState::UNKNOWN != eState && !bProtContent && !m_bHtmlMode) + { + if( SfxItemState::SET != eState ) + pItem = &rSet.Get( RES_GRFATR_MIRRORGRF ); + + bEnable = true; + + MirrorGraph eMirror = static_cast<const SwMirrorGrf* >(pItem)->GetValue(); + switch( eMirror ) + { + case MirrorGraph::Dont: break; + case MirrorGraph::Vertical: m_xMirrorHorzBox->set_active(true); break; + case MirrorGraph::Horizontal: m_xMirrorVertBox->set_active(true); break; + case MirrorGraph::Both: m_xMirrorHorzBox->set_active(true); + m_xMirrorVertBox->set_active(true); + break; + default: + ; + } + + const int nPos = (static_cast<const SwMirrorGrf* >(pItem)->IsGrfToggle() ? 1 : 0) + + ((eMirror == MirrorGraph::Vertical || eMirror == MirrorGraph::Both) ? 2 : 0); + + bEnableMirrorRB = nPos != 0; + + switch (nPos) + { + case 1: // mirror at left / even pages + m_xLeftPagesRB->set_active(true); + m_xMirrorHorzBox->set_active(true); + break; + case 2: // mirror on all pages + m_xAllPagesRB->set_active(true); + break; + case 3: // mirror on right / odd pages + m_xRightPagesRB->set_active(true); + break; + default: + m_xAllPagesRB->set_active(true); + break; + } + } + + if( const SvxBrushItem* pGraphicBrushItem = rSet.GetItemIfSet( SID_ATTR_GRAF_GRAPHIC, false ) ) + { + if( !pGraphicBrushItem->GetGraphicLink().isEmpty() ) + { + m_aGrfName = m_aNewGrfName = pGraphicBrushItem->GetGraphicLink(); + m_xConnectED->set_text(m_aNewGrfName); + } + OUString referer; + SfxStringItem const * it = rSet.GetItem(SID_REFERER); + if (it != nullptr) { + referer = it->GetValue(); + } + const Graphic* pGrf = pGraphicBrushItem->GetGraphic(referer); + if( pGrf ) + { + m_aBmpWin.SetGraphic( *pGrf ); + m_xLabelGraphicType->set_label(GraphicHelper::GetImageType(*pGrf)); + } + } + + m_xConnectED->save_value(); + + m_xMirror->set_sensitive(bEnable); + m_xAllPagesRB->set_sensitive(bEnableMirrorRB); + m_xLeftPagesRB->set_sensitive(bEnableMirrorRB); + m_xRightPagesRB->set_sensitive(bEnableMirrorRB); + + m_xAllPagesRB->save_state(); + m_xLeftPagesRB->save_state(); + m_xRightPagesRB->save_state(); + m_xMirrorHorzBox->save_state(); + m_xMirrorVertBox->save_state(); + + m_aBmpWin.MirrorHorz( m_xMirrorVertBox->get_active() ); + m_aBmpWin.MirrorVert( m_xMirrorHorzBox->get_active() ); + m_aBmpWin.Invalidate(); +} + +bool SwGrfExtPage::FillItemSet( SfxItemSet *rSet ) +{ + bool bModified = false; + if ( m_xMirrorHorzBox->get_state_changed_from_saved() || + m_xMirrorVertBox->get_state_changed_from_saved() || + m_xAllPagesRB->get_state_changed_from_saved() || + m_xLeftPagesRB->get_state_changed_from_saved() || + m_xRightPagesRB->get_state_changed_from_saved() ) + { + bModified = true; + + bool bHori = false; + + if (m_xMirrorHorzBox->get_active() && + !m_xLeftPagesRB->get_active()) + bHori = true; + + MirrorGraph eMirror; + eMirror = m_xMirrorVertBox->get_active() && bHori ? + MirrorGraph::Both : bHori ? + MirrorGraph::Vertical : m_xMirrorVertBox->get_active() ? + MirrorGraph::Horizontal : MirrorGraph::Dont; + + bool bMirror = !m_xAllPagesRB->get_active(); + SwMirrorGrf aMirror( eMirror ); + aMirror.SetGrfToggle(bMirror ); + rSet->Put( aMirror ); + } + + if (m_aGrfName != m_aNewGrfName || m_xConnectED->get_value_changed_from_saved()) + { + bModified = true; + m_aGrfName = m_xConnectED->get_text(); + rSet->Put( SvxBrushItem( m_aGrfName, m_aFilterName, GPOS_LT, + SID_ATTR_GRAF_GRAPHIC )); + } + + // RotGrfFlyFrame: Safe rotation if modified + if(m_xCtlAngle->IsValueModified()) + { + rSet->Put(SdrAngleItem(SID_ATTR_TRANSFORM_ANGLE, m_xCtlAngle->GetRotation())); + bModified = true; + } + + return bModified; +} + +DeactivateRC SwGrfExtPage::DeactivatePage(SfxItemSet *_pSet) +{ + if( _pSet ) + FillItemSet( _pSet ); + return DeactivateRC::LeavePage; +} + +IMPL_LINK_NOARG(SwGrfExtPage, BrowseHdl, weld::Button&, void) +{ + if(!m_xGrfDlg) + { + m_xGrfDlg.reset(new FileDialogHelper( + ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW, + FileDialogFlags::Graphic, GetFrameWeld())); + m_xGrfDlg->SetTitle(m_xLinkFrame->get_label()); + } + m_xGrfDlg->SetDisplayDirectory(m_xConnectED->get_text()); + uno::Reference < ui::dialogs::XFilePicker3 > xFP = m_xGrfDlg->GetFilePicker(); + uno::Reference < ui::dialogs::XFilePickerControlAccess > xCtrlAcc(xFP, uno::UNO_QUERY); + xCtrlAcc->setValue( ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK, 0, uno::Any(true) ); + + if ( m_xGrfDlg->Execute() != ERRCODE_NONE ) + return; + +// remember selected filter + m_aFilterName = m_xGrfDlg->GetCurrentFilter(); + m_aNewGrfName = INetURLObject::decode( m_xGrfDlg->GetPath(), + INetURLObject::DecodeMechanism::Unambiguous ); + m_xConnectED->set_text(m_aNewGrfName); + //reset mirrors because maybe a Bitmap was swapped with + //another type of graphic that cannot be mirrored. + m_xMirrorVertBox->set_active(false); + m_xMirrorHorzBox->set_active(false); + m_xAllPagesRB->set_sensitive(false); + m_xLeftPagesRB->set_sensitive(false); + m_xRightPagesRB->set_sensitive(false); + m_aBmpWin.MirrorHorz(false); + m_aBmpWin.MirrorVert(false); + + Graphic aGraphic; + (void)GraphicFilter::LoadGraphic(m_xGrfDlg->GetPath(), OUString(), aGraphic); + m_aBmpWin.SetGraphic(aGraphic); + m_xLabelGraphicType->set_label(GraphicHelper::GetImageType(aGraphic)); + + bool bEnable = GraphicType::Bitmap == aGraphic.GetType() || + GraphicType::GdiMetafile == aGraphic.GetType(); + m_xMirrorVertBox->set_sensitive(bEnable); + m_xMirrorHorzBox->set_sensitive(bEnable); + m_xAllPagesRB->set_sensitive(bEnable); + m_xLeftPagesRB->set_sensitive(bEnable); + m_xRightPagesRB->set_sensitive(bEnable); + +} + +IMPL_LINK_NOARG(SwGrfExtPage, MirrorHdl, weld::Toggleable&, void) +{ + bool bEnable = m_xMirrorHorzBox->get_active(); + + m_aBmpWin.MirrorHorz( m_xMirrorVertBox->get_active() ); + m_aBmpWin.MirrorVert( bEnable ); + + m_xAllPagesRB->set_sensitive(bEnable); + m_xLeftPagesRB->set_sensitive(bEnable); + m_xRightPagesRB->set_sensitive(bEnable); + + if (!m_xAllPagesRB->get_active() && !m_xLeftPagesRB->get_active() && !m_xRightPagesRB->get_active()) + m_xAllPagesRB->set_active(true); +} + +// example window +BmpWindow::BmpWindow() + : m_bHorz(false) + , m_bVert(false) + , m_bGraphic(false) +{ +} + +void BmpWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + CustomWidgetController::SetDrawingArea(pDrawingArea); + Size aSize = pDrawingArea->get_ref_device().LogicToPixel(Size(127 , 66), MapMode(MapUnit::MapAppFont)); + set_size_request(aSize.Width(), aSize.Height()); + SetOutputSizePixel(aSize); +} + +void BmpWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + // Setup + rRenderContext.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetDialogColor())); + rRenderContext.Erase(); + // #i119307# the graphic might have transparency, set up white as the color + // to use when drawing a rectangle under the image + rRenderContext.SetLineColor(COL_WHITE); + rRenderContext.SetFillColor(COL_WHITE); + + // Paint + Point aPntPos; + Size aPntSz(GetOutputSizePixel()); + Size aGrfSize; + if (m_bGraphic) + aGrfSize = ::GetGraphicSizeTwip(m_aGraphic, &rRenderContext); + //it should show the default bitmap also if no graphic can be found + if (!aGrfSize.Width() && !aGrfSize.Height()) + aGrfSize = rRenderContext.PixelToLogic(m_aBmp.GetSizePixel()); + + tools::Long nRelGrf = aGrfSize.Width() * 100 / aGrfSize.Height(); + tools::Long nRelWin = aPntSz.Width() * 100 / aPntSz.Height(); + if (nRelGrf < nRelWin) + { + const tools::Long nWidth = aPntSz.Width(); + // if we use a replacement preview, try to draw at original size + if (!m_bGraphic && (aGrfSize.Width() <= aPntSz.Width()) + && (aGrfSize.Height() <= aPntSz.Height())) + { + const tools::Long nHeight = aPntSz.Height(); + aPntSz.setWidth( aGrfSize.Width() ); + aPntSz.setHeight( aGrfSize.Height() ); + aPntPos.AdjustY((nHeight - aPntSz.Height()) / 2 ); + } + else + aPntSz.setWidth( aPntSz.Height() * nRelGrf /100 ); + + aPntPos.AdjustX(nWidth - aPntSz.Width() ) ; + } + + // #i119307# clear window background, the graphic might have transparency + rRenderContext.DrawRect(tools::Rectangle(aPntPos, aPntSz)); + + if (m_bHorz || m_bVert) + { + BitmapEx aTmpBmp(m_bGraphic ? m_aGraphic.GetBitmapEx() : m_aBmp); + BmpMirrorFlags nMirrorFlags(BmpMirrorFlags::NONE); + if (m_bHorz) + nMirrorFlags |= BmpMirrorFlags::Vertical; + if (m_bVert) + nMirrorFlags |= BmpMirrorFlags::Horizontal; + aTmpBmp.Mirror(nMirrorFlags); + rRenderContext.DrawBitmapEx(aPntPos, aPntSz, aTmpBmp); + } + else if (m_bGraphic) //draw unmirrored preview graphic + { + m_aGraphic.Draw(rRenderContext, aPntPos, aPntSz); + } + else //draw unmirrored stock sample image + { + rRenderContext.DrawBitmapEx(aPntPos, aPntSz, m_aBmp); + } +} + +BmpWindow::~BmpWindow() +{ +} + +void BmpWindow::SetGraphic(const Graphic& rGraphic) +{ + m_aGraphic = rGraphic; + Size aSize = m_aGraphic.GetPrefSize(); + m_bGraphic = aSize.Width() && aSize.Height(); + Invalidate(); +} + +void BmpWindow::SetBitmapEx(const BitmapEx& rBmp) +{ + m_aBmp = rBmp; + Invalidate(); +} + +// set URL and ImageMap at frames +SwFrameURLPage::SwFrameURLPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/frmurlpage.ui", "FrameURLPage", &rSet) + , m_xURLED(m_xBuilder->weld_entry("url")) + , m_xSearchPB(m_xBuilder->weld_button("search")) + , m_xNameED(m_xBuilder->weld_entry("name")) + , m_xFrameCB(m_xBuilder->weld_combo_box("frame")) + , m_xServerCB(m_xBuilder->weld_check_button("server")) + , m_xClientCB(m_xBuilder->weld_check_button("client")) +{ + m_xSearchPB->connect_clicked(LINK(this, SwFrameURLPage, InsertFileHdl)); +} + +SwFrameURLPage::~SwFrameURLPage() +{ +} + +void SwFrameURLPage::Reset( const SfxItemSet *rSet ) +{ + if ( SfxItemState::SET == rSet->GetItemState( SID_DOCFRAME )) + { + TargetList aList; + SfxFrame::GetDefaultTargetList(aList); + size_t nCount = aList.size(); + for (size_t i = 0; i < nCount; ++i) + { + m_xFrameCB->append_text(aList.at(i)); + } + } + + if ( const SwFormatURL* pFormatURL = rSet->GetItemIfSet( RES_URL ) ) + { + m_xURLED->set_text(INetURLObject::decode(pFormatURL->GetURL(), + INetURLObject::DecodeMechanism::Unambiguous)); + m_xNameED->set_text(pFormatURL->GetName()); + + m_xClientCB->set_sensitive(pFormatURL->GetMap() != nullptr); + m_xClientCB->set_active(pFormatURL->GetMap() != nullptr); + m_xServerCB->set_active(pFormatURL->IsServerMap()); + + m_xFrameCB->set_entry_text(pFormatURL->GetTargetFrameName()); + m_xFrameCB->save_value(); + } + else + m_xClientCB->set_sensitive(false); + + m_xServerCB->save_state(); + m_xClientCB->save_state(); +} + +bool SwFrameURLPage::FillItemSet(SfxItemSet *rSet) +{ + bool bModified = false; + const SwFormatURL* pOldURL = GetOldItem(*rSet, RES_URL); + std::unique_ptr<SwFormatURL> pFormatURL; + if(pOldURL) + pFormatURL.reset(pOldURL->Clone()); + else + pFormatURL.reset(new SwFormatURL()); + + { + const OUString sText = m_xURLED->get_text(); + + if( pFormatURL->GetURL() != sText || + pFormatURL->GetName() != m_xNameED->get_text() || + m_xServerCB->get_active() != pFormatURL->IsServerMap() ) + { + pFormatURL->SetURL(sText, m_xServerCB->get_active()); + pFormatURL->SetName(m_xNameED->get_text()); + bModified = true; + } + } + + if (!m_xClientCB->get_active() && pFormatURL->GetMap() != nullptr) + { + pFormatURL->SetMap(nullptr); + bModified = true; + } + + if(pFormatURL->GetTargetFrameName() != m_xFrameCB->get_active_text()) + { + pFormatURL->SetTargetFrameName(m_xFrameCB->get_active_text()); + bModified = true; + } + rSet->Put(std::move(pFormatURL)); + return bModified; +} + +std::unique_ptr<SfxTabPage> SwFrameURLPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet) +{ + return std::make_unique<SwFrameURLPage>(pPage, pController, *rSet); +} + +IMPL_LINK_NOARG(SwFrameURLPage, InsertFileHdl, weld::Button&, void) +{ + FileDialogHelper aDlgHelper(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, GetFrameWeld()); + uno::Reference < ui::dialogs::XFilePicker3 > xFP = aDlgHelper.GetFilePicker(); + + try + { + const OUString sTemp(m_xURLED->get_text()); + if(!sTemp.isEmpty()) + xFP->setDisplayDirectory(sTemp); + } + catch( const uno::Exception& ) {} + if( aDlgHelper.Execute() == ERRCODE_NONE ) + { + m_xURLED->set_text(xFP->getSelectedFiles().getConstArray()[0]); + } +} + +SwFrameAddPage::SwFrameAddPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/frmaddpage.ui", "FrameAddPage", &rSet) + , m_pWrtSh(nullptr) + , m_bHtmlMode(false) + , m_bFormat(false) + , m_bNew(false) + , m_xNameFrame(m_xBuilder->weld_widget("nameframe")) + , m_xNameFT(m_xBuilder->weld_label("name_label")) + , m_xNameED(m_xBuilder->weld_entry("name")) + , m_xAltNameFT(m_xBuilder->weld_label("altname_label")) + , m_xAltNameED(m_xBuilder->weld_entry("altname")) + , m_xDescriptionFT(m_xBuilder->weld_label("description_label")) + , m_xDescriptionED(m_xBuilder->weld_text_view("description")) + , m_xDecorativeCB(m_xBuilder->weld_check_button("decorative")) + , m_xSequenceFrame(m_xBuilder->weld_widget("frmSequence")) + , m_xPrevLB(m_xBuilder->weld_combo_box("prev")) + , m_xNextLB(m_xBuilder->weld_combo_box("next")) + , m_xProtectFrame(m_xBuilder->weld_widget("protect")) + , m_xProtectContentCB(m_xBuilder->weld_check_button("protectcontent")) + , m_xProtectFrameCB(m_xBuilder->weld_check_button("protectframe")) + , m_xProtectSizeCB(m_xBuilder->weld_check_button("protectsize")) + , m_xContentAlignFrame(m_xBuilder->weld_widget("contentalign")) + , m_xVertAlignLB(m_xBuilder->weld_combo_box("vertalign")) + , m_xPropertiesFrame(m_xBuilder->weld_widget("properties")) + , m_xEditInReadonlyCB(m_xBuilder->weld_check_button("editinreadonly")) + , m_xPrintFrameCB(m_xBuilder->weld_check_button("printframe")) + , m_xTextFlowFT(m_xBuilder->weld_label("textflow_label")) + , m_xTextFlowLB(new svx::FrameDirectionListBox(m_xBuilder->weld_combo_box("textflow"))) +{ + m_xTextFlowLB->append(SvxFrameDirection::Horizontal_LR_TB, SvxResId(RID_SVXSTR_FRAMEDIR_LTR)); + m_xTextFlowLB->append(SvxFrameDirection::Horizontal_RL_TB, SvxResId(RID_SVXSTR_FRAMEDIR_RTL)); + m_xTextFlowLB->append(SvxFrameDirection::Vertical_RL_TB, SvxResId(RID_SVXSTR_PAGEDIR_RTL_VERT)); + m_xTextFlowLB->append(SvxFrameDirection::Vertical_LR_TB, SvxResId(RID_SVXSTR_PAGEDIR_LTR_VERT)); + m_xTextFlowLB->append(SvxFrameDirection::Vertical_LR_BT, SvxResId(RID_SVXSTR_PAGEDIR_LTR_BTT_VERT)); + m_xTextFlowLB->append(SvxFrameDirection::Environment, SvxResId(RID_SVXSTR_FRAMEDIR_SUPER)); + m_xDescriptionED->set_size_request(-1, m_xDescriptionED->get_preferred_size().Height()); + + m_xDecorativeCB->connect_toggled(LINK(this, SwFrameAddPage, DecorativeHdl)); +} + +SwFrameAddPage::~SwFrameAddPage() +{ + m_xTextFlowLB.reset(); +} + +std::unique_ptr<SfxTabPage> SwFrameAddPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet) +{ + return std::make_unique<SwFrameAddPage>(pPage, pController, *rSet); +} + +void SwFrameAddPage::Reset(const SfxItemSet *rSet ) +{ + sal_uInt16 nHtmlMode = ::GetHtmlMode(static_cast<const SwDocShell*>(SfxObjectShell::Current())); + m_bHtmlMode = (nHtmlMode & HTMLMODE_ON) != 0; + if (m_bHtmlMode) + { + m_xProtectFrame->hide(); + m_xEditInReadonlyCB->hide(); + m_xPrintFrameCB->hide(); + } + if (m_sDlgType == "PictureDialog" || m_sDlgType == "ObjectDialog") + { + m_xSequenceFrame->hide(); + m_xEditInReadonlyCB->hide(); + if (m_bHtmlMode) + { + m_xPropertiesFrame->hide(); + } + m_xContentAlignFrame->hide(); + } + + if(const SfxStringItem* pNameItem = rSet->GetItemIfSet(FN_SET_FRM_ALT_NAME, false)) + { + m_xAltNameED->set_text(pNameItem->GetValue()); + m_xAltNameED->save_value(); + } + + if(const SfxStringItem* pDescriptionItem = rSet->GetItemIfSet(FN_UNO_DESCRIPTION, false)) + { + m_xDescriptionED->set_text(pDescriptionItem->GetValue()); + m_xDescriptionED->save_value(); + } + + if(!m_bFormat) + { + // insert graphic - properties + // bNew is not set, so recognise by selection + OUString aTmpName1; + if(const SfxStringItem* pNameItem = rSet->GetItemIfSet(FN_SET_FRM_NAME, false)) + { + aTmpName1 = pNameItem->GetValue(); + } + + OSL_ENSURE(m_pWrtSh, "no Shell?"); + if( m_bNew || aTmpName1.isEmpty() ) + { + if (m_sDlgType == "PictureDialog") + aTmpName1 = m_pWrtSh->GetUniqueGrfName(); + else if (m_sDlgType == "ObjectDialog") + aTmpName1 = m_pWrtSh->GetUniqueOLEName(); + else + aTmpName1 = m_pWrtSh->GetUniqueFrameName(); + + m_pWrtSh->SetFlyName(aTmpName1); + } + + m_xNameED->set_text( aTmpName1 ); + m_xNameED->save_value(); + } + else + { + m_xNameED->set_sensitive( false ); + m_xAltNameED->set_sensitive(false); + m_xNameFT->set_sensitive( false ); + m_xAltNameFT->set_sensitive(false); + } + if (m_sDlgType == "FrameDialog" && m_xAltNameFT->get_visible()) + { + m_xAltNameFT->hide(); + m_xAltNameED->hide(); + } + else + { + m_xNameED->connect_changed(LINK(this, SwFrameAddPage, EditModifyHdl)); + } + + if (!m_bNew) + { + SwFrameFormat* pFormat = m_pWrtSh->GetFlyFrameFormat(); + + if (pFormat) + { + const SwFormatChain &rChain = pFormat->GetChain(); + const SwFlyFrameFormat* pFlyFormat; + OUString sNextChain, sPrevChain; + pFlyFormat = rChain.GetPrev(); + if (pFlyFormat != nullptr) + { + sPrevChain = pFlyFormat->GetName(); + } + + pFlyFormat = rChain.GetNext(); + if (pFlyFormat != nullptr) + { + sNextChain = pFlyFormat->GetName(); + } + //determine chainable frames + std::vector< OUString > aPrevPageFrames; + std::vector< OUString > aThisPageFrames; + std::vector< OUString > aNextPageFrames; + std::vector< OUString > aRemainFrames; + m_pWrtSh->GetConnectableFrameFormats(*pFormat, sNextChain, false, + aPrevPageFrames, aThisPageFrames, aNextPageFrames, aRemainFrames ); + for (sal_Int32 nEntry = m_xPrevLB->get_count(); nEntry > 1; nEntry--) + m_xPrevLB->remove(nEntry - 1); + lcl_InsertVectors(*m_xPrevLB, aPrevPageFrames, aThisPageFrames, aNextPageFrames, aRemainFrames); + if(!sPrevChain.isEmpty()) + { + if (m_xPrevLB->find_text(sPrevChain) == -1) + m_xPrevLB->insert_text(1, sPrevChain); + m_xPrevLB->set_active_text(sPrevChain); + } + else + m_xPrevLB->set_active(0); + aPrevPageFrames.clear(); + aNextPageFrames.clear(); + aThisPageFrames.clear(); + aRemainFrames.clear(); + + m_pWrtSh->GetConnectableFrameFormats(*pFormat, sPrevChain, true, + aPrevPageFrames, aThisPageFrames, aNextPageFrames, aRemainFrames ); + for (sal_Int32 nEntry = m_xNextLB->get_count(); nEntry > 1; nEntry--) + m_xNextLB->remove(nEntry - 1); + lcl_InsertVectors(*m_xNextLB, aPrevPageFrames, aThisPageFrames, aNextPageFrames, aRemainFrames); + if(!sNextChain.isEmpty()) + { + if (m_xNextLB->find_text(sNextChain) == -1) + m_xNextLB->insert_text(1, sNextChain); + m_xNextLB->set_active_text(sNextChain); + } + else + m_xNextLB->set_active(0); + Link<weld::ComboBox&,void> aLink(LINK(this, SwFrameAddPage, ChainModifyHdl)); + m_xPrevLB->connect_changed(aLink); + m_xNextLB->connect_changed(aLink); + } + } + // Pos Protected + const SvxProtectItem& rProt = rSet->Get(RES_PROTECT); + m_xProtectFrameCB->set_active(rProt.IsPosProtected()); + m_xProtectContentCB->set_active(rProt.IsContentProtected()); + m_xProtectSizeCB->set_active(rProt.IsSizeProtected()); + + const SwFormatEditInReadonly& rEdit = rSet->Get(RES_EDIT_IN_READONLY); + m_xEditInReadonlyCB->set_active(rEdit.GetValue()); + m_xEditInReadonlyCB->save_state(); + + // print + const SvxPrintItem& rPrt = rSet->Get(RES_PRINT); + m_xPrintFrameCB->set_active(rPrt.GetValue()); + m_xPrintFrameCB->save_state(); + + SfxBoolItem const& rDecorative = rSet->Get(RES_DECORATIVE); + m_xDecorativeCB->set_active(rDecorative.GetValue()); + m_xDecorativeCB->save_state(); + + // textflow + if( (!m_bHtmlMode || (0 != (nHtmlMode&HTMLMODE_SOME_STYLES))) + && m_sDlgType != "PictureDialog" && m_sDlgType != "ObjectDialog" + && SfxItemState::UNKNOWN != rSet->GetItemState( RES_FRAMEDIR ) ) + { + m_xTextFlowFT->show(); + m_xTextFlowLB->show(); + + //vertical text flow is not possible in HTML + if(m_bHtmlMode) + { + m_xTextFlowLB->remove_id(SvxFrameDirection::Vertical_RL_TB); + } + SvxFrameDirection nVal = rSet->Get(RES_FRAMEDIR).GetValue(); + m_xTextFlowLB->set_active_id(nVal); + m_xTextFlowLB->save_value(); + } + else + { + m_xTextFlowFT->hide(); + m_xTextFlowLB->hide(); + } + + // Content alignment + if ( rSet->GetItemState(RES_TEXT_VERT_ADJUST) > SfxItemState::DEFAULT ) + { + SdrTextVertAdjust nAdjust = rSet->Get(RES_TEXT_VERT_ADJUST).GetValue(); + sal_Int32 nPos = 0; + switch(nAdjust) + { + case SDRTEXTVERTADJUST_TOP: nPos = 0; break; + case SDRTEXTVERTADJUST_CENTER: + case SDRTEXTVERTADJUST_BLOCK: nPos = 1; break; + case SDRTEXTVERTADJUST_BOTTOM: nPos = 2; break; + } + m_xVertAlignLB->set_active(nPos); + } + m_xVertAlignLB->save_value(); + + DecorativeHdl(*m_xDecorativeCB); +} + +bool SwFrameAddPage::FillItemSet(SfxItemSet *rSet) +{ + bool bRet = false; + if (m_xNameED->get_value_changed_from_saved()) + bRet |= nullptr != rSet->Put(SfxStringItem(FN_SET_FRM_NAME, m_xNameED->get_text())); + if (m_xAltNameED->get_value_changed_from_saved()) + bRet |= nullptr != rSet->Put(SfxStringItem(FN_SET_FRM_ALT_NAME, m_xAltNameED->get_text())); + if (m_xDescriptionED->get_value_changed_from_saved()) + bRet |= nullptr != rSet->Put(SfxStringItem(FN_UNO_DESCRIPTION, m_xDescriptionED->get_text())); + + const SfxPoolItem* pOldItem; + SvxProtectItem aProt ( GetItemSet().Get(RES_PROTECT) ); + aProt.SetContentProtect( m_xProtectContentCB->get_active() ); + aProt.SetSizeProtect ( m_xProtectSizeCB->get_active() ); + aProt.SetPosProtect ( m_xProtectFrameCB->get_active() ); + if ( nullptr == (pOldItem = GetOldItem(*rSet, FN_SET_PROTECT)) || + aProt != *pOldItem ) + bRet |= nullptr != rSet->Put( aProt); + + if ( m_xEditInReadonlyCB->get_state_changed_from_saved() ) + bRet |= nullptr != rSet->Put( SwFormatEditInReadonly( RES_EDIT_IN_READONLY, m_xEditInReadonlyCB->get_active())); + + if ( m_xPrintFrameCB->get_state_changed_from_saved() ) + bRet |= nullptr != rSet->Put( SvxPrintItem( RES_PRINT, m_xPrintFrameCB->get_active())); + + if (m_xDecorativeCB->get_state_changed_from_saved()) + { + bRet |= nullptr != rSet->Put(SfxBoolItem(RES_DECORATIVE, m_xDecorativeCB->get_active())); + } + + // textflow + if (m_xTextFlowLB->get_visible() && m_xTextFlowLB->get_value_changed_from_saved()) + { + SvxFrameDirection eDirection = m_xTextFlowLB->get_active_id(); + bRet |= nullptr != rSet->Put( SvxFrameDirectionItem(eDirection, RES_FRAMEDIR )); + } + if(m_pWrtSh) + { + const SwFrameFormat* pFormat = m_pWrtSh->GetFlyFrameFormat(); + if (pFormat) + { + OUString sCurrentPrevChain, sCurrentNextChain; + if (m_xPrevLB->get_active()) + sCurrentPrevChain = m_xPrevLB->get_active_text(); + if (m_xNextLB->get_active()) + sCurrentNextChain = m_xNextLB->get_active_text(); + const SwFormatChain &rChain = pFormat->GetChain(); + const SwFlyFrameFormat* pFlyFormat; + OUString sNextChain, sPrevChain; + pFlyFormat = rChain.GetPrev(); + if (pFlyFormat != nullptr) + sPrevChain = pFlyFormat->GetName(); + + pFlyFormat = rChain.GetNext(); + if (pFlyFormat != nullptr) + sNextChain = pFlyFormat->GetName(); + if(sPrevChain != sCurrentPrevChain) + bRet |= nullptr != rSet->Put(SfxStringItem(FN_PARAM_CHAIN_PREVIOUS, sCurrentPrevChain)); + if(sNextChain != sCurrentNextChain) + bRet |= nullptr != rSet->Put(SfxStringItem(FN_PARAM_CHAIN_NEXT, sCurrentNextChain)); + } + } + + if (m_xVertAlignLB->get_value_changed_from_saved()) + { + SdrTextVertAdjust nAdjust; + switch (m_xVertAlignLB->get_active()) + { + default: + case 0 : nAdjust = SDRTEXTVERTADJUST_TOP; break; + case 1 : nAdjust = SDRTEXTVERTADJUST_CENTER; break; + case 2 : nAdjust = SDRTEXTVERTADJUST_BOTTOM; break; + } + bRet |= nullptr != rSet->Put(SdrTextVertAdjustItem(nAdjust, RES_TEXT_VERT_ADJUST)); + } + + return bRet; +} + +IMPL_LINK_NOARG(SwFrameAddPage, EditModifyHdl, weld::Entry&, void) +{ + bool bEnable = !m_xNameED->get_text().isEmpty(); + m_xAltNameED->set_sensitive(bEnable); + m_xAltNameFT->set_sensitive(bEnable); +} + +IMPL_LINK_NOARG(SwFrameAddPage, DecorativeHdl, weld::Toggleable&, void) +{ + bool const bEnable(!m_xDecorativeCB->get_active()); + m_xAltNameED->set_sensitive(bEnable); + m_xAltNameFT->set_sensitive(bEnable); + m_xDescriptionED->set_sensitive(bEnable); + m_xDescriptionFT->set_sensitive(bEnable); +} + +void SwFrameAddPage::SetFormatUsed(bool bFormatUsed) +{ + m_bFormat = bFormatUsed; + if (m_bFormat) + { + m_xNameFrame->hide(); + } +} + +IMPL_LINK(SwFrameAddPage, ChainModifyHdl, weld::ComboBox&, rBox, void) +{ + OUString sCurrentPrevChain, sCurrentNextChain; + if (m_xPrevLB->get_active()) + sCurrentPrevChain = m_xPrevLB->get_active_text(); + if (m_xNextLB->get_active()) + sCurrentNextChain = m_xNextLB->get_active_text(); + SwFrameFormat* pFormat = m_pWrtSh->GetFlyFrameFormat(); + if (!pFormat) + return; + + bool bNextBox = m_xNextLB.get() == &rBox; + weld::ComboBox& rChangeLB = bNextBox ? *m_xPrevLB : *m_xNextLB; + for (sal_Int32 nEntry = rChangeLB.get_count(); nEntry > 1; nEntry--) + rChangeLB.remove(nEntry - 1); + //determine chainable frames + std::vector< OUString > aPrevPageFrames; + std::vector< OUString > aThisPageFrames; + std::vector< OUString > aNextPageFrames; + std::vector< OUString > aRemainFrames; + m_pWrtSh->GetConnectableFrameFormats(*pFormat, bNextBox ? sCurrentNextChain : sCurrentPrevChain, !bNextBox, + aPrevPageFrames, aThisPageFrames, aNextPageFrames, aRemainFrames ); + lcl_InsertVectors(rChangeLB, + aPrevPageFrames, aThisPageFrames, aNextPageFrames, aRemainFrames); + const OUString sToSelect = bNextBox ? sCurrentPrevChain : sCurrentNextChain; + if (rChangeLB.find_text(sToSelect) != -1) + rChangeLB.set_active_text(sToSelect); + else + rChangeLB.set_active(0); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/frmdlg/pattern.cxx b/sw/source/ui/frmdlg/pattern.cxx new file mode 100644 index 0000000000..097ed18230 --- /dev/null +++ b/sw/source/ui/frmdlg/pattern.cxx @@ -0,0 +1,42 @@ +/* -*- 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/sfxdlg.hxx> +#include <svx/dialogs.hrc> +#include <swtypes.hxx> +#include <pattern.hxx> +#include <strings.hrc> + +SwBackgroundDlg::SwBackgroundDlg(weld::Window* pParent, const SfxItemSet& rSet) + : SfxSingleTabDialogController(pParent, &rSet) + +{ + m_xDialog->set_title(SwResId(STR_FRMUI_PATTERN)); + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + ::CreateTabPage fnCreatePage = pFact->GetTabPageCreatorFunc(RID_SVXPAGE_BKG); + if (fnCreatePage) + { + std::unique_ptr<SfxTabPage> xRet = (*fnCreatePage)(get_content_area(), this, &rSet); + xRet->PageCreated(rSet); + xRet->ActivatePage(rSet); + SetTabPage(std::move(xRet)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/frmdlg/uiborder.cxx b/sw/source/ui/frmdlg/uiborder.cxx new file mode 100644 index 0000000000..73c55b0e3c --- /dev/null +++ b/sw/source/ui/frmdlg/uiborder.cxx @@ -0,0 +1,54 @@ +/* -*- 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/svxids.hrc> +#include <svx/dialogs.hrc> +#include <svl/itemset.hxx> +#include <svx/flagsdef.hxx> +#include <sfx2/sfxdlg.hxx> +#include <sfx2/tabdlg.hxx> +#include <svl/intitem.hxx> + +#include <swtypes.hxx> +#include <uiborder.hxx> +#include <strings.hrc> + +SwBorderDlg::SwBorderDlg(weld::Window* pParent, const SfxItemSet& rSet, SwBorderModes nType) + : SfxSingleTabDialogController(pParent, &rSet) +{ + m_xDialog->set_title(SwResId(STR_FRMUI_BORDER)); + + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + ::CreateTabPage fnCreatePage = pFact->GetTabPageCreatorFunc(RID_SVXPAGE_BORDER); + + if (fnCreatePage) + { + std::unique_ptr<SfxTabPage> xNewPage = (*fnCreatePage)(get_content_area(), this, &rSet); + SfxAllItemSet aSet(*(rSet.GetPool())); + aSet.Put(SfxUInt16Item(SID_SWMODE_TYPE, static_cast<sal_uInt16>(nType))); + if (SwBorderModes::TABLE == nType) + aSet.Put(SfxUInt32Item(SID_FLAG_TYPE, SVX_HIDESHADOWCTL)); + xNewPage->PageCreated(aSet); + SetTabPage(std::move(xNewPage)); + } +} + +SwBorderDlg::~SwBorderDlg() {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/frmdlg/wrap.cxx b/sw/source/ui/frmdlg/wrap.cxx new file mode 100644 index 0000000000..684fe38b22 --- /dev/null +++ b/sw/source/ui/frmdlg/wrap.cxx @@ -0,0 +1,631 @@ +/* -*- 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/graph.hxx> + +#include <sfx2/htmlmode.hxx> +#include <sfx2/objsh.hxx> +#include <svl/intitem.hxx> +#include <editeng/opaqitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <fmtfollowtextflow.hxx> +#include <svtools/unitconv.hxx> +#include <svx/swframevalidation.hxx> + +#include <cmdid.h> +#include <docsh.hxx> +#include <uitool.hxx> +#include <wrtsh.hxx> +#include <swmodule.hxx> +#include <viewopt.hxx> +#include <fmtsrnd.hxx> +#include <frmmgr.hxx> +#include <wrap.hxx> +#include <bitmaps.hlst> +#include <fmtwrapinfluenceonobjpos.hxx> + +using namespace ::com::sun::star; + +const WhichRangesContainer SwWrapTabPage::s_aWrapPageRg(svl::Items< + RES_LR_SPACE, RES_UL_SPACE, + RES_PRINT, RES_PRINT, + RES_PROTECT, RES_SURROUND +>); + +SwWrapDlg::SwWrapDlg(weld::Window* pParent, const SfxItemSet& rSet, SwWrtShell* pWrtShell, bool bDrawMode) + : SfxSingleTabDialogController(pParent, &rSet, "modules/swriter/ui/wrapdialog.ui", "WrapDialog") +{ + // create TabPage + auto xNewPage = SwWrapTabPage::Create(get_content_area(), this, &rSet); + SwWrapTabPage* pWrapPage = static_cast<SwWrapTabPage*>(xNewPage.get()); + pWrapPage->SetFormatUsed(false, bDrawMode); + pWrapPage->SetShell(pWrtShell); + SetTabPage(std::move(xNewPage)); +} + +SwWrapTabPage::SwWrapTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/wrappage.ui", "WrapPage", &rSet) + , m_nAnchorId(RndStdIds::FLY_AT_PARA) + , m_nHtmlMode(0) + , m_pWrtSh(nullptr) + , m_bFormat(false) + , m_bNew(true) + , m_bHtmlMode(false) + , m_bDrawMode(false) + , m_bContourImage(false) + , m_xNoWrapImg(m_xBuilder->weld_image("noneimg")) + , m_xNoWrapRB(m_xBuilder->weld_radio_button("none")) + , m_xWrapLeftImg(m_xBuilder->weld_image("beforeimg")) + , m_xWrapLeftRB(m_xBuilder->weld_radio_button("before")) + , m_xWrapRightImg(m_xBuilder->weld_image("afterimg")) + , m_xWrapRightRB(m_xBuilder->weld_radio_button("after")) + , m_xWrapParallelImg(m_xBuilder->weld_image("parallelimg")) + , m_xWrapParallelRB(m_xBuilder->weld_radio_button("parallel")) + , m_xWrapThroughImg(m_xBuilder->weld_image("throughimg")) + , m_xWrapThroughRB(m_xBuilder->weld_radio_button("through")) + , m_xIdealWrapImg(m_xBuilder->weld_image("optimalimg")) + , m_xIdealWrapRB(m_xBuilder->weld_radio_button("optimal")) + , m_xLeftMarginED(m_xBuilder->weld_metric_spin_button("left", FieldUnit::CM)) + , m_xRightMarginED(m_xBuilder->weld_metric_spin_button("right", FieldUnit::CM)) + , m_xTopMarginED(m_xBuilder->weld_metric_spin_button("top", FieldUnit::CM)) + , m_xBottomMarginED(m_xBuilder->weld_metric_spin_button("bottom", FieldUnit::CM)) + , m_xWrapAnchorOnlyCB(m_xBuilder->weld_check_button("anchoronly")) + , m_xWrapTransparentCB(m_xBuilder->weld_check_button("transparent")) + , m_xWrapOutlineCB(m_xBuilder->weld_check_button("outline")) + , m_xWrapOutsideCB(m_xBuilder->weld_check_button("outside")) + , m_xAllowOverlapCB(m_xBuilder->weld_check_button("allowoverlap")) +{ + SetExchangeSupport(); + + Link<weld::MetricSpinButton&,void> aLk = LINK(this, SwWrapTabPage, RangeModifyHdl); + m_xLeftMarginED->connect_value_changed(aLk); + m_xRightMarginED->connect_value_changed(aLk); + m_xTopMarginED->connect_value_changed(aLk); + m_xBottomMarginED->connect_value_changed(aLk); + + Link<weld::Toggleable&,void> aLk2 = LINK(this, SwWrapTabPage, WrapTypeHdl); + m_xNoWrapRB->connect_toggled(aLk2); + m_xWrapLeftRB->connect_toggled(aLk2); + m_xWrapRightRB->connect_toggled(aLk2); + m_xWrapParallelRB->connect_toggled(aLk2); + m_xWrapThroughRB->connect_toggled(aLk2); + m_xIdealWrapRB->connect_toggled(aLk2); + SetImages(); + m_xWrapOutlineCB->connect_toggled(LINK(this, SwWrapTabPage, ContourHdl)); +} + +SwWrapTabPage::~SwWrapTabPage() +{ +} + +std::unique_ptr<SfxTabPage> SwWrapTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet) +{ + return std::make_unique<SwWrapTabPage>(pPage, pController, *rSet); +} + +void SwWrapTabPage::Reset(const SfxItemSet *rSet) +{ + // contour for Draw, Graphic and OLE (Insert/Graphic/Properties still missing!) + if( m_bDrawMode ) + { + m_xWrapOutlineCB->show(); + m_xWrapOutsideCB->show(); + + m_xWrapTransparentCB->set_active( 0 == rSet->Get(FN_DRAW_WRAP_DLG).GetValue() ); + m_xWrapTransparentCB->save_state(); + } + else + { + bool bShowCB = m_bFormat; + if( !m_bFormat ) + { + SelectionType nSelType = m_pWrtSh->GetSelectionType(); + if( ( nSelType & SelectionType::Graphic ) || + ( nSelType & SelectionType::Ole && GraphicType::NONE != + m_pWrtSh->GetIMapGraphic().GetType() )) + bShowCB = true; + } + if( bShowCB ) + { + m_xWrapOutlineCB->show(); + m_xWrapOutsideCB->show(); + } + } + + m_nHtmlMode = ::GetHtmlMode(static_cast<const SwDocShell*>(SfxObjectShell::Current())); + m_bHtmlMode = (m_nHtmlMode & HTMLMODE_ON) != 0; + + FieldUnit aMetric = ::GetDfltMetric(m_bHtmlMode); + SetFieldUnit(*m_xLeftMarginED, aMetric); + SetFieldUnit(*m_xRightMarginED, aMetric); + SetFieldUnit(*m_xTopMarginED, aMetric); + SetFieldUnit(*m_xBottomMarginED, aMetric); + + const SwFormatSurround& rSurround = rSet->Get(RES_SURROUND); + + css::text::WrapTextMode nSur = rSurround.GetSurround(); + const SwFormatAnchor &rAnch = rSet->Get(RES_ANCHOR); + m_nAnchorId = rAnch.GetAnchorId(); + + if (((m_nAnchorId == RndStdIds::FLY_AT_PARA) || (m_nAnchorId == RndStdIds::FLY_AT_CHAR)) + && (nSur != css::text::WrapTextMode_NONE)) + { + m_xWrapAnchorOnlyCB->set_active(rSurround.IsAnchorOnly()); + } + else + { + m_xWrapAnchorOnlyCB->set_sensitive(false); + } + + const bool bContour = rSurround.IsContour(); + m_xWrapOutlineCB->set_active(bContour); + m_xWrapOutsideCB->set_active(rSurround.IsOutside()); + m_xWrapThroughRB->set_sensitive(!m_xWrapOutlineCB->get_active()); + m_bContourImage = !bContour; + + weld::RadioButton* pBtn = nullptr; + + switch (nSur) + { + case css::text::WrapTextMode_NONE: + { + pBtn = m_xNoWrapRB.get(); + break; + } + + case css::text::WrapTextMode_THROUGH: + { + // transparent ? + pBtn = m_xWrapThroughRB.get(); + + if (!m_bDrawMode) + { + const SvxOpaqueItem& rOpaque = rSet->Get(RES_OPAQUE); + m_xWrapTransparentCB->set_active(!rOpaque.GetValue()); + } + break; + } + + case css::text::WrapTextMode_PARALLEL: + { + pBtn = m_xWrapParallelRB.get(); + break; + } + + case css::text::WrapTextMode_DYNAMIC: + { + pBtn = m_xIdealWrapRB.get(); + break; + } + + default: + { + if (nSur == css::text::WrapTextMode_LEFT) + pBtn = m_xWrapLeftRB.get(); + else if (nSur == css::text::WrapTextMode_RIGHT) + pBtn = m_xWrapRightRB.get(); + } + } + if (pBtn) + { + pBtn->set_active(true); + WrapTypeHdl(*pBtn); + // For character objects that currently are in passage, the default + // "contour on" is prepared here, in case we switch to any other + // passage later. + if (m_bDrawMode && !m_xWrapOutlineCB->get_sensitive()) + m_xWrapOutlineCB->set_active(true); + } + m_xWrapTransparentCB->set_sensitive(pBtn == m_xWrapThroughRB.get() && !m_bHtmlMode); + + const SvxULSpaceItem& rUL = rSet->Get(RES_UL_SPACE); + const SvxLRSpaceItem& rLR = rSet->Get(RES_LR_SPACE); + + // gap to text + m_xLeftMarginED->set_value(m_xLeftMarginED->normalize(rLR.GetLeft()), FieldUnit::TWIP); + m_xRightMarginED->set_value(m_xRightMarginED->normalize(rLR.GetRight()), FieldUnit::TWIP); + m_xTopMarginED->set_value(m_xTopMarginED->normalize(rUL.GetUpper()), FieldUnit::TWIP); + m_xBottomMarginED->set_value(m_xBottomMarginED->normalize(rUL.GetLower()), FieldUnit::TWIP); + + m_xLeftMarginED->save_value(); + m_xRightMarginED->save_value(); + m_xTopMarginED->save_value(); + m_xBottomMarginED->save_value(); + + ContourHdl(*m_xWrapOutlineCB); + + const SwFormatWrapInfluenceOnObjPos& rInfluence = rSet->Get(RES_WRAP_INFLUENCE_ON_OBJPOS); + m_xAllowOverlapCB->set_active(rInfluence.GetAllowOverlap()); + + ActivatePage( *rSet ); +} + +// stuff attributes into the set when OK +bool SwWrapTabPage::FillItemSet(SfxItemSet *rSet) +{ + bool bModified = false; + const SfxPoolItem* pOldItem; + const SwFormatSurround& rOldSur = GetItemSet().Get(RES_SURROUND); + SwFormatSurround aSur( rOldSur ); + + std::shared_ptr<SvxOpaqueItem> aOp(std::make_shared<SvxOpaqueItem>(RES_OPAQUE)); + + if (!m_bDrawMode) + { + aOp.reset(GetItemSet().Get(RES_OPAQUE).Clone()); + aOp->SetValue(true); + } + + if (m_xNoWrapRB->get_active()) + aSur.SetSurround(css::text::WrapTextMode_NONE); + else if (m_xWrapLeftRB->get_active()) + aSur.SetSurround(css::text::WrapTextMode_LEFT); + else if (m_xWrapRightRB->get_active()) + aSur.SetSurround(css::text::WrapTextMode_RIGHT); + else if (m_xWrapParallelRB->get_active()) + aSur.SetSurround(css::text::WrapTextMode_PARALLEL); + else if (m_xWrapThroughRB->get_active()) + { + aSur.SetSurround(css::text::WrapTextMode_THROUGH); + if (m_xWrapTransparentCB->get_active() && !m_bDrawMode) + aOp->SetValue(false); + } + else if (m_xIdealWrapRB->get_active()) + aSur.SetSurround(css::text::WrapTextMode_DYNAMIC); + + aSur.SetAnchorOnly( m_xWrapAnchorOnlyCB->get_active() ); + bool bContour = m_xWrapOutlineCB->get_active() && m_xWrapOutlineCB->get_sensitive(); + aSur.SetContour( bContour ); + + if ( bContour ) + aSur.SetOutside(m_xWrapOutsideCB->get_active()); + + if(nullptr == (pOldItem = GetOldItem( *rSet, RES_SURROUND )) || + aSur != *pOldItem ) + { + rSet->Put(aSur); + bModified = true; + } + + if (!m_bDrawMode) + { + if(nullptr == (pOldItem = GetOldItem( *rSet, FN_OPAQUE )) || + *aOp != *pOldItem ) + { + rSet->Put(*aOp); + bModified = true; + } + } + + bool bTopMod = m_xTopMarginED->get_value_changed_from_saved(); + bool bBottomMod = m_xBottomMarginED->get_value_changed_from_saved(); + + SvxULSpaceItem aUL( RES_UL_SPACE ); + aUL.SetUpper(o3tl::narrowing<sal_uInt16>(m_xTopMarginED->denormalize(m_xTopMarginED->get_value(FieldUnit::TWIP)))); + aUL.SetLower(o3tl::narrowing<sal_uInt16>(m_xBottomMarginED->denormalize(m_xBottomMarginED->get_value(FieldUnit::TWIP)))); + + if ( bTopMod || bBottomMod ) + { + if(nullptr == (pOldItem = GetOldItem(*rSet, RES_UL_SPACE)) || + aUL != *pOldItem ) + { + rSet->Put( aUL ); + bModified = true; + } + } + + bool bLeftMod = m_xLeftMarginED->get_value_changed_from_saved(); + bool bRightMod = m_xRightMarginED->get_value_changed_from_saved(); + + SvxLRSpaceItem aLR( RES_LR_SPACE ); + aLR.SetLeft(o3tl::narrowing<sal_uInt16>(m_xLeftMarginED->denormalize(m_xLeftMarginED->get_value(FieldUnit::TWIP)))); + aLR.SetRight(o3tl::narrowing<sal_uInt16>(m_xRightMarginED->denormalize(m_xRightMarginED->get_value(FieldUnit::TWIP)))); + + if ( bLeftMod || bRightMod ) + { + if( nullptr == (pOldItem = GetOldItem(*rSet, RES_LR_SPACE)) || + aLR != *pOldItem ) + { + rSet->Put(aLR); + bModified = true; + } + } + + if ( m_bDrawMode ) + { + bool bChecked = m_xWrapTransparentCB->get_active() && m_xWrapTransparentCB->get_sensitive(); + if ((m_xWrapTransparentCB->get_saved_state() == TRISTATE_TRUE) != bChecked) + bModified |= nullptr != rSet->Put(SfxInt16Item(FN_DRAW_WRAP_DLG, bChecked ? 0 : 1)); + } + + const SwFormatWrapInfluenceOnObjPos& rOldInfluence + = GetItemSet().Get(RES_WRAP_INFLUENCE_ON_OBJPOS); + SwFormatWrapInfluenceOnObjPos aInfluence(rOldInfluence); + aInfluence.SetAllowOverlap(m_xAllowOverlapCB->get_active()); + + pOldItem = GetOldItem(*rSet, RES_WRAP_INFLUENCE_ON_OBJPOS); + if (!pOldItem || aInfluence != *pOldItem) + { + rSet->Put(aInfluence); + bModified = true; + } + + return bModified; +} + +// example update +void SwWrapTabPage::ActivatePage(const SfxItemSet& rSet) +{ + // anchor + const SwFormatAnchor &rAnch = rSet.Get(RES_ANCHOR); + m_nAnchorId = rAnch.GetAnchorId(); + bool bEnable = (m_nAnchorId != RndStdIds::FLY_AS_CHAR); + + SwWrtShell* pSh = m_bFormat ? ::GetActiveWrtShell() : m_pWrtSh; + if (pSh && !m_bDrawMode) + { + SwFlyFrameAttrMgr aMgr( m_bNew, pSh, GetItemSet() ); + SvxSwFrameValidation aVal; + + // size + const SwFormatFrameSize& rFrameSize = rSet.Get(RES_FRM_SIZE); + Size aSize = rFrameSize.GetSize(); + + // position + const SwFormatHoriOrient& rHori = rSet.Get(RES_HORI_ORIENT); + const SwFormatVertOrient& rVert = rSet.Get(RES_VERT_ORIENT); + + aVal.nAnchorType = m_nAnchorId; + aVal.bAutoHeight = rFrameSize.GetHeightSizeType() == SwFrameSize::Minimum; + aVal.bMirror = rHori.IsPosToggle(); + // #i18732# + aVal.bFollowTextFlow = rSet.Get(RES_FOLLOW_TEXT_FLOW).GetValue(); + + aVal.nHoriOrient = static_cast<short>(rHori.GetHoriOrient()); + aVal.nVertOrient = static_cast<short>(rVert.GetVertOrient()); + + aVal.nHPos = rHori.GetPos(); + aVal.nHRelOrient = rHori.GetRelationOrient(); + aVal.nVPos = rVert.GetPos(); + aVal.nVRelOrient = rVert.GetRelationOrient(); + + if (rFrameSize.GetWidthPercent() && rFrameSize.GetWidthPercent() != SwFormatFrameSize::SYNCED) + aSize.setWidth( aSize.Width() * rFrameSize.GetWidthPercent() / 100 ); + + if (rFrameSize.GetHeightPercent() && rFrameSize.GetHeightPercent() != SwFormatFrameSize::SYNCED) + aSize.setHeight( aSize.Height() * rFrameSize.GetHeightPercent() / 100 ); + + aVal.nWidth = aSize.Width(); + aVal.nHeight = aSize.Height(); + + aMgr.ValidateMetrics(aVal, nullptr); + + SwTwips nLeft; + SwTwips nRight; + SwTwips nTop; + SwTwips nBottom; + + nLeft = aVal.nHPos - aVal.nMinHPos; + nRight = aVal.nMaxWidth - aVal.nWidth; + nTop = aVal.nVPos - aVal.nMinVPos; + nBottom = aVal.nMaxHeight - aVal.nHeight; + + { + if (aVal.nAnchorType == RndStdIds::FLY_AS_CHAR) + { + nLeft = nRight; + + if (aVal.nVPos < 0) + { + if (aVal.nVPos <= aVal.nMaxHeight) + nTop = aVal.nMaxVPos - aVal.nHeight; + else + nTop = 0; // no passage + } + else + nTop = aVal.nMaxVPos - aVal.nHeight - aVal.nVPos; + } + else + { + nLeft += nRight; + nTop += nBottom; + } + + nBottom = nTop; + nRight = nLeft; + } + + m_xLeftMarginED->set_max(m_xLeftMarginED->normalize(nLeft), FieldUnit::TWIP); + m_xRightMarginED->set_max(m_xRightMarginED->normalize(nRight), FieldUnit::TWIP); + + m_xTopMarginED->set_max(m_xTopMarginED->normalize(nTop), FieldUnit::TWIP); + m_xBottomMarginED->set_max(m_xBottomMarginED->normalize(nBottom), FieldUnit::TWIP); + + RangeModifyHdl(*m_xLeftMarginED); + RangeModifyHdl(*m_xTopMarginED); + } + + const SwFormatSurround& rSurround = rSet.Get(RES_SURROUND); + css::text::WrapTextMode nSur = rSurround.GetSurround(); + + m_xWrapTransparentCB->set_sensitive(bEnable && !m_bHtmlMode && nSur == css::text::WrapTextMode_THROUGH); + if(m_bHtmlMode) + { + const SwFormatHoriOrient& rHori = rSet.Get(RES_HORI_ORIENT); + sal_Int16 eHOrient = rHori.GetHoriOrient(); + sal_Int16 eHRelOrient = rHori.GetRelationOrient(); + m_xWrapOutlineCB->hide(); + const bool bAllHtmlModes = + ((m_nAnchorId == RndStdIds::FLY_AT_PARA) || (m_nAnchorId == RndStdIds::FLY_AT_CHAR)) && + (eHOrient == text::HoriOrientation::RIGHT || eHOrient == text::HoriOrientation::LEFT); + m_xWrapAnchorOnlyCB->set_sensitive(bAllHtmlModes && nSur != css::text::WrapTextMode_NONE); + m_xWrapOutsideCB->hide(); + m_xIdealWrapRB->set_sensitive(false); + + m_xWrapTransparentCB->set_sensitive(false); + m_xNoWrapRB->set_sensitive(RndStdIds::FLY_AT_PARA == m_nAnchorId); + m_xWrapParallelRB->set_sensitive(false); + m_xWrapLeftRB->set_sensitive + ( (RndStdIds::FLY_AT_PARA == m_nAnchorId) + || ( (RndStdIds::FLY_AT_CHAR == m_nAnchorId) + && (eHOrient == text::HoriOrientation::RIGHT) + && (eHRelOrient == text::RelOrientation::PRINT_AREA))); + m_xWrapRightRB->set_sensitive + ( (RndStdIds::FLY_AT_PARA == m_nAnchorId) + || ( (RndStdIds::FLY_AT_CHAR == m_nAnchorId) + && (eHOrient == text::HoriOrientation::LEFT) + && (eHRelOrient == text::RelOrientation::PRINT_AREA))); + + m_xWrapThroughRB->set_sensitive + ( ( (RndStdIds::FLY_AT_PAGE == m_nAnchorId) + || ( (RndStdIds::FLY_AT_CHAR == m_nAnchorId) + && (eHRelOrient != text::RelOrientation::PRINT_AREA)) + || (RndStdIds::FLY_AT_PARA == m_nAnchorId)) + && (eHOrient != text::HoriOrientation::RIGHT)); + if (m_xNoWrapRB->get_active() && !m_xNoWrapRB->get_sensitive()) + { + if(m_xWrapThroughRB->get_sensitive()) + m_xWrapThroughRB->set_active(true); + else if(m_xWrapLeftRB->get_sensitive()) + m_xWrapLeftRB->set_active(true); + else if(m_xWrapRightRB->get_sensitive()) + m_xWrapRightRB->set_active(true); + + } + if (m_xWrapLeftRB->get_active() && !m_xWrapLeftRB->get_sensitive()) + { + if(m_xWrapRightRB->get_sensitive()) + m_xWrapRightRB->set_active(true); + else if(m_xWrapThroughRB->get_sensitive()) + m_xWrapThroughRB->set_active(true); + } + if (m_xWrapRightRB->get_active() && !m_xWrapRightRB->get_sensitive()) + { + if(m_xWrapLeftRB->get_sensitive()) + m_xWrapLeftRB->set_active(true); + else if(m_xWrapThroughRB->get_sensitive()) + m_xWrapThroughRB->set_active(true); + } + if (m_xWrapThroughRB->get_active() && !m_xWrapThroughRB->get_sensitive()) + if(m_xNoWrapRB->get_sensitive()) + m_xNoWrapRB->set_active(true); + + if (m_xWrapParallelRB->get_active() && !m_xWrapParallelRB->get_sensitive()) + m_xWrapThroughRB->set_active(true); + } + else + { + m_xNoWrapRB->set_sensitive(bEnable); + m_xWrapLeftRB->set_sensitive(bEnable); + m_xWrapRightRB->set_sensitive(bEnable); + m_xIdealWrapRB->set_sensitive(bEnable); + m_xWrapThroughRB->set_sensitive(bEnable); + m_xWrapParallelRB->set_sensitive(bEnable); + m_xWrapAnchorOnlyCB->set_sensitive( + ((m_nAnchorId == RndStdIds::FLY_AT_PARA) || (m_nAnchorId == RndStdIds::FLY_AT_CHAR)) + && nSur != css::text::WrapTextMode_NONE ); + } + ContourHdl(*m_xWrapOutlineCB); +} + +DeactivateRC SwWrapTabPage::DeactivatePage(SfxItemSet* _pSet) +{ + if(_pSet) + FillItemSet(_pSet); + + return DeactivateRC::LeavePage; +} + +IMPL_LINK(SwWrapTabPage, RangeModifyHdl, weld::MetricSpinButton&, rEdit, void) +{ + auto nValue = rEdit.get_value(FieldUnit::NONE); + weld::MetricSpinButton* pOpposite = nullptr; + if (&rEdit == m_xLeftMarginED.get()) + pOpposite = m_xRightMarginED.get(); + else if (&rEdit == m_xRightMarginED.get()) + pOpposite = m_xLeftMarginED.get(); + else if (&rEdit == m_xTopMarginED.get()) + pOpposite = m_xBottomMarginED.get(); + else if (&rEdit == m_xBottomMarginED.get()) + pOpposite = m_xTopMarginED.get(); + + assert(pOpposite); + + if (pOpposite) + { + auto nOpposite = pOpposite->get_value(FieldUnit::NONE); + + if (nValue + nOpposite > std::max(rEdit.get_max(FieldUnit::NONE), pOpposite->get_max(FieldUnit::NONE))) + pOpposite->set_value(pOpposite->get_max(FieldUnit::NONE) - nValue, FieldUnit::NONE); + } +} + +IMPL_LINK_NOARG(SwWrapTabPage, WrapTypeHdl, weld::Toggleable&, void) +{ + bool bWrapThrough = m_xWrapThroughRB->get_active(); + m_xWrapTransparentCB->set_sensitive(bWrapThrough && !m_bHtmlMode); + bWrapThrough |= ( m_nAnchorId == RndStdIds::FLY_AS_CHAR ); + m_xWrapOutlineCB->set_sensitive(!bWrapThrough && !m_xNoWrapRB->get_active()); + m_xWrapOutsideCB->set_sensitive(!bWrapThrough && m_xWrapOutlineCB->get_active()); + m_xWrapAnchorOnlyCB->set_sensitive( + ((m_nAnchorId == RndStdIds::FLY_AT_PARA) || (m_nAnchorId == RndStdIds::FLY_AT_CHAR)) && + (!m_xNoWrapRB->get_active()) ); + + ContourHdl(*m_xWrapOutlineCB); +} + +IMPL_LINK_NOARG(SwWrapTabPage, ContourHdl, weld::Toggleable&, void) +{ + bool bEnable = !(m_xWrapOutlineCB->get_active() && m_xWrapOutlineCB->get_sensitive()); + + m_xWrapOutsideCB->set_sensitive(!bEnable); + + bEnable = !m_xWrapOutlineCB->get_active(); + if (bEnable == m_bContourImage) // so that it doesn't always flicker + { + m_bContourImage = !bEnable; + SetImages(); + } +} + +void SwWrapTabPage::SetImages() +{ + m_xWrapThroughImg->set_from_icon_name(RID_BMP_WRAP_THROUGH); + bool bWrapOutline = !m_xWrapOutlineCB->get_active(); + if (bWrapOutline) + { + m_xNoWrapImg->set_from_icon_name(RID_BMP_WRAP_NONE); + m_xWrapLeftImg->set_from_icon_name(RID_BMP_WRAP_LEFT); + m_xWrapRightImg->set_from_icon_name(RID_BMP_WRAP_RIGHT); + m_xWrapParallelImg->set_from_icon_name(RID_BMP_WRAP_PARALLEL); + m_xIdealWrapImg->set_from_icon_name(RID_BMP_WRAP_IDEAL); + } + else + { + m_xNoWrapImg->set_from_icon_name(RID_BMP_WRAP_CONTOUR_NONE); + m_xWrapLeftImg->set_from_icon_name(RID_BMP_WRAP_CONTOUR_LEFT); + m_xWrapRightImg->set_from_icon_name(RID_BMP_WRAP_CONTOUR_RIGHT); + m_xWrapParallelImg->set_from_icon_name(RID_BMP_WRAP_CONTOUR_PARALLEL); + m_xIdealWrapImg->set_from_icon_name(RID_BMP_WRAP_CONTOUR_IDEAL); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/inc/mmresultdialogs.hxx b/sw/source/ui/inc/mmresultdialogs.hxx new file mode 100644 index 0000000000..3af52dc4c5 --- /dev/null +++ b/sw/source/ui/inc/mmresultdialogs.hxx @@ -0,0 +1,189 @@ +/* -*- 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 . + */ + +#pragma once + +#include <vcl/weld.hxx> +#include <vcl/print.hxx> +#include <sfx2/basedlgs.hxx> +#include <mailmergehelper.hxx> + +class SwMailMergeWizard; +class SfxPrinter; +class SwSendMailDialog; +class Timer; +namespace com::sun::star::mail { class XMailMessage; } + + +/// Dialog implementing the saving as of the result document. +class SwMMResultSaveDialog final : public SfxDialogController +{ + bool m_bCancelSaving; + + std::unique_ptr<weld::RadioButton> m_xSaveAsOneRB; + std::unique_ptr<weld::RadioButton> m_xSaveIndividualRB; + std::unique_ptr<weld::CheckButton> m_xFromRB; + std::unique_ptr<weld::SpinButton> m_xFromNF; + std::unique_ptr<weld::Label> m_xToFT; + std::unique_ptr<weld::SpinButton> m_xToNF; + std::unique_ptr<weld::Button> m_xOKButton; + + DECL_LINK(SaveOutputHdl_Impl, weld::Button& , void); + DECL_LINK(DocumentSelectionHdl_Impl, weld::Toggleable&, void); + +public: + SwMMResultSaveDialog(weld::Window* pParent); + virtual ~SwMMResultSaveDialog() override; +}; + +/// Dialog implementing the printing of the result document. +class SwMMResultPrintDialog final : public SfxDialogController +{ + VclPtr<Printer> m_pTempPrinter; + + std::unique_ptr<weld::ComboBox> m_xPrinterLB; + std::unique_ptr<weld::Button> m_xPrinterSettingsPB; + std::unique_ptr<weld::RadioButton> m_xPrintAllRB; + std::unique_ptr<weld::RadioButton> m_xFromRB; + std::unique_ptr<weld::SpinButton> m_xFromNF; + std::unique_ptr<weld::Label> m_xToFT; + std::unique_ptr<weld::SpinButton> m_xToNF; + std::unique_ptr<weld::Button> m_xOKButton; + + DECL_LINK(PrinterChangeHdl_Impl, weld::ComboBox&, void ); + DECL_LINK(PrintHdl_Impl, weld::Button&, void); + DECL_LINK(PrinterSetupHdl_Impl, weld::Button&, void ); + DECL_LINK(DocumentSelectionHdl_Impl, weld::Toggleable&, void); + + void FillInPrinterSettings(); + +public: + SwMMResultPrintDialog(weld::Window* pParent); + virtual ~SwMMResultPrintDialog() override; +}; + +/// Dialog implementing the sending as email of the result document. +class SwMMResultEmailDialog final : public SfxDialogController +{ + OUString m_sConfigureMail; + OUString m_sCC; + OUString m_sBCC; + OUString m_sBody; + + std::unique_ptr<weld::ComboBox> m_xMailToLB; + std::unique_ptr<weld::Button> m_xCopyToPB; + std::unique_ptr<weld::Entry> m_xSubjectED; + std::unique_ptr<weld::ComboBox> m_xSendAsLB; + std::unique_ptr<weld::Button> m_xSendAsPB; + std::unique_ptr<weld::Widget> m_xAttachmentGroup; + std::unique_ptr<weld::Entry> m_xAttachmentED; + std::unique_ptr<weld::Label> m_xPasswordFT; + std::unique_ptr<weld::ComboBox> m_xPasswordLB; + std::unique_ptr<weld::CheckButton> m_xPasswordCB; + std::unique_ptr<weld::RadioButton> m_xSendAllRB; + std::unique_ptr<weld::RadioButton> m_xFromRB; + std::unique_ptr<weld::SpinButton> m_xFromNF; + std::unique_ptr<weld::Label> m_xToFT; + std::unique_ptr<weld::SpinButton> m_xToNF; + std::unique_ptr<weld::Button> m_xOKButton; + + DECL_LINK(CopyToHdl_Impl, weld::Button&, void); + DECL_LINK(SendTypeHdl_Impl, weld::ComboBox&, void); + DECL_LINK(SendAsHdl_Impl, weld::Button&, void); + DECL_LINK(SendDocumentsHdl_Impl, weld::Button&, void); + DECL_LINK(DocumentSelectionHdl_Impl, weld::Toggleable&, void); + DECL_LINK(CheckHdl, weld::Toggleable&, void ); + + void FillInEmailSettings(); + +public: + SwMMResultEmailDialog(weld::Window *pParent); + virtual ~SwMMResultEmailDialog() override; +}; + +struct SwMailDescriptor +{ + OUString sEMail; + OUString sAttachmentURL; + OUString sAttachmentName; + OUString sMimeType; + OUString sSubject; + OUString sBodyMimeType; + OUString sBodyContent; + + OUString sCC; + OUString sBCC; +}; +struct SwSendMailDialog_Impl; +class SwMailMergeConfigItem; +class SwSendMailDialog final : public weld::GenericDialogController +{ + OUString m_sContinue; + OUString m_sStop; + OUString m_sClose; + OUString m_sTransferStatus; + OUString m_sErrorStatus; + OUString m_sSendingTo; + OUString m_sCompleted; + OUString m_sFailed; + OUString m_sAddressInvalid; + + bool m_bCancel; + bool m_bDestructionEnabled; + + std::unique_ptr<SwSendMailDialog_Impl> m_pImpl; + SwMailMergeConfigItem* m_pConfigItem; + sal_Int32 m_nExpectedCount; + sal_Int32 m_nProcessedCount; + sal_Int32 m_nErrorCount; + + std::unique_ptr<weld::Label> m_xTransferStatus; + std::unique_ptr<weld::Label> m_xPaused; + std::unique_ptr<weld::ProgressBar> m_xProgressBar; + std::unique_ptr<weld::Label> m_xErrorStatus; + std::unique_ptr<weld::TreeView> m_xStatus; + std::unique_ptr<weld::Button> m_xStop; + std::unique_ptr<weld::Button> m_xCancel; + + DECL_LINK( StopHdl_Impl, weld::Button&, void ); + DECL_LINK( CancelHdl_Impl, weld::Button& , void); + DECL_STATIC_LINK( SwSendMailDialog, StartSendMails, void*, void ); + DECL_STATIC_LINK( SwSendMailDialog, StopSendMails, void*, void ); + DECL_LINK( RemoveThis, Timer*, void ); + + void IterateMails(); + void SendMails(); + void UpdateTransferStatus(); + +public: + SwSendMailDialog( weld::Window* pParent, SwMailMergeConfigItem& ); + virtual ~SwSendMailDialog() override; + + void AddDocument( SwMailDescriptor const & rDesc ); + void EnableDestruction() {m_bDestructionEnabled = true;} + void StartSend(sal_Int32 nExpectedCount); + + void DocumentSent( css::uno::Reference< css::mail::XMailMessage> const & xMessage, + bool bResult, + const OUString* pError ); + void AllMailsSent(); + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/inc/swuiexp.hxx b/sw/source/ui/inc/swuiexp.hxx new file mode 100644 index 0000000000..a5fa95e7a0 --- /dev/null +++ b/sw/source/ui/inc/swuiexp.hxx @@ -0,0 +1,29 @@ +/* -*- 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 . + */ + +#pragma once + +#include <swabstdlg.hxx> + +namespace swui +{ +SwAbstractDialogFactory& GetFactory(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/index/cntex.cxx b/sw/source/ui/index/cntex.cxx new file mode 100644 index 0000000000..d2e6b751cf --- /dev/null +++ b/sw/source/ui/index/cntex.cxx @@ -0,0 +1,395 @@ +/* -*- 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 <com/sun/star/text/XDocumentIndexesSupplier.hpp> +#include <com/sun/star/text/XTextSectionsSupplier.hpp> +#include <com/sun/star/text/XDependentTextField.hpp> +#include <com/sun/star/text/XDocumentIndex.hpp> +#include <com/sun/star/text/ChapterFormat.hpp> +#include <com/sun/star/text/XTextSection.hpp> +#include <com/sun/star/beans/PropertyValues.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <comphelper/string.hxx> +#include <comphelper/servicehelper.hxx> +#include <tools/UnitConversion.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <cnttab.hxx> +#include <unoprnms.hxx> +#include <unotools.hxx> +#include <unotxdoc.hxx> +#include <docsh.hxx> + +#include <SwStyleNameMapper.hxx> +#include <swuicnttab.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::uno; +using namespace com::sun::star::ui::dialogs; + +static void lcl_SetProp( uno::Reference< XPropertySetInfo > const & xInfo, + uno::Reference< XPropertySet > const & xProps, + OUString const & aPropName, const OUString& rValue) +{ + if(xInfo->hasPropertyByName(aPropName)) + { + uno::Any aValue; + aValue <<= rValue; + xProps->setPropertyValue(aPropName, aValue); + } +} + +static void lcl_SetProp( uno::Reference< XPropertySetInfo > const & xInfo, + uno::Reference< XPropertySet > const & xProps, + OUString const & aPropName, sal_Int16 nValue ) +{ + if(xInfo->hasPropertyByName(aPropName)) + { + uno::Any aValue; + aValue <<= nValue; + xProps->setPropertyValue(aPropName, aValue); + } +} + +static void lcl_SetBOOLProp( + uno::Reference< beans::XPropertySetInfo > const & xInfo, + uno::Reference< beans::XPropertySet > const & xProps, + OUString const & aPropName, bool bValue ) +{ + if(xInfo->hasPropertyByName(aPropName)) + { + xProps->setPropertyValue(aPropName, Any(bValue)); + } +} + +IMPL_LINK_NOARG(SwMultiTOXTabDialog, CreateExample_Hdl, SwOneExampleFrame&, void) +{ + try + { + uno::Reference< frame::XModel > & xModel = m_xExampleFrame->GetModel(); + auto pDoc = comphelper::getFromUnoTunnel<SwXTextDocument>(xModel); + + if( pDoc ) + pDoc->GetDocShell()->LoadStyles_( *m_rWrtShell.GetView().GetDocShell(), true ); + + uno::Reference< text::XTextSectionsSupplier > xSectionSupplier( + xModel, uno::UNO_QUERY); + uno::Reference< container::XNameAccess > xSections = + xSectionSupplier->getTextSections(); + + for(int i = 0; i < 7; ++i ) + { + OUString sTmp = "IndexSection_" + OUString::number(i); + uno::Any aSection = xSections->getByName( sTmp ); + aSection >>= m_vTypeData[i].m_oIndexSections->xContainerSection; + } + uno::Reference< text::XDocumentIndexesSupplier > xIdxSupp(xModel, uno::UNO_QUERY); + uno::Reference< container::XIndexAccess > xIdxs = xIdxSupp->getDocumentIndexes(); + int n = xIdxs->getCount(); + while(n) + { + n--; + uno::Any aIdx = xIdxs->getByIndex(n); + uno::Reference< text::XDocumentIndex > xIdx; + aIdx >>= xIdx; + xIdx->dispose(); + } + CreateOrUpdateExample(m_eCurrentTOXType.eType); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "sw", "::CreateExample()"); + } +} + +void SwMultiTOXTabDialog::CreateOrUpdateExample( + TOXTypes nTOXIndex, sal_uInt16 nPage, sal_uInt16 nCurrentLevel) +{ + if(!m_xExampleFrame || !m_xExampleFrame->IsInitialized()) + return; + + try + { + static const char* IndexServiceNames[] = + { + "com.sun.star.text.DocumentIndex", + "com.sun.star.text.UserIndex", + "com.sun.star.text.ContentIndex", + "com.sun.star.text.IllustrationsIndex", + "com.sun.star.text.ObjectIndex", + "com.sun.star.text.TableIndex", + "com.sun.star.text.Bibliography" + }; + + OSL_ENSURE(m_vTypeData[nTOXIndex].m_oIndexSections && + m_vTypeData[nTOXIndex].m_oIndexSections->xContainerSection.is(), + "Section not created"); + uno::Reference< frame::XModel > & xModel = m_xExampleFrame->GetModel(); + bool bInitialCreate = true; + if(!m_vTypeData[nTOXIndex].m_oIndexSections->xDocumentIndex.is()) + { + bInitialCreate = true; + if(!m_vTypeData[nTOXIndex].m_oIndexSections->xContainerSection.is()) + throw uno::RuntimeException(); + uno::Reference< text::XTextRange > xAnchor = m_vTypeData[nTOXIndex].m_oIndexSections->xContainerSection->getAnchor(); + xAnchor = xAnchor->getStart(); + uno::Reference< text::XTextCursor > xCursor = xAnchor->getText()->createTextCursorByRange(xAnchor); + + uno::Reference< lang::XMultiServiceFactory > xFact(xModel, uno::UNO_QUERY); + + OUString sIndexTypeName(OUString::createFromAscii( IndexServiceNames[ + nTOXIndex <= TOX_AUTHORITIES ? nTOXIndex : TOX_USER] )); + m_vTypeData[nTOXIndex].m_oIndexSections->xDocumentIndex.set(xFact->createInstance(sIndexTypeName), uno::UNO_QUERY); + uno::Reference< text::XTextContent > xContent = m_vTypeData[nTOXIndex].m_oIndexSections->xDocumentIndex; + xCursor->getText()->insertTextContent(xCursor, xContent, false); + } + for(sal_uInt16 i = 0 ; i <= TOX_AUTHORITIES; i++) + { + uno::Reference< beans::XPropertySet > xSectPr(m_vTypeData[i].m_oIndexSections->xContainerSection, uno::UNO_QUERY); + if(xSectPr.is()) + { + xSectPr->setPropertyValue(UNO_NAME_IS_VISIBLE, Any(i == nTOXIndex)); + } + } + // set properties + uno::Reference< beans::XPropertySet > xIdxProps(m_vTypeData[nTOXIndex].m_oIndexSections->xDocumentIndex, uno::UNO_QUERY); + uno::Reference< beans::XPropertySetInfo > xInfo = xIdxProps->getPropertySetInfo(); + SwTOXDescription& rDesc = GetTOXDescription(m_eCurrentTOXType); + SwTOIOptions nIdxOptions = rDesc.GetIndexOptions(); + if(bInitialCreate || !nPage || nPage == TOX_PAGE_SELECT) + { + //title + if(rDesc.GetTitle()) + lcl_SetProp(xInfo, xIdxProps, UNO_NAME_TITLE, *rDesc.GetTitle()); + + //stylenames + SwTOXElement nContentOptions = rDesc.GetContentOptions(); + if(xInfo->hasPropertyByName(UNO_NAME_LEVEL_PARAGRAPH_STYLES)) + { + bool bOn( nContentOptions&SwTOXElement::Template ); + uno::Any aStyleNames(xIdxProps->getPropertyValue(UNO_NAME_LEVEL_PARAGRAPH_STYLES)); + uno::Reference< container::XIndexReplace > xAcc; + aStyleNames >>= xAcc; + + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + OUString sLevel; + if(bOn) + sLevel = rDesc.GetStyleNames(i); + const sal_Int32 nStyles = + comphelper::string::getTokenCount(sLevel, TOX_STYLE_DELIMITER); + uno::Sequence<OUString> aStyles(nStyles); + OUString* pArr = aStyles.getArray(); + sal_Int32 nPos {0}; + for(sal_Int32 nStyle = 0; nStyle < nStyles; ++nStyle) + pArr[nStyle] = sLevel.getToken(0, TOX_STYLE_DELIMITER, nPos); + uno::Any aAny(&aStyles, cppu::UnoType<uno::Sequence<OUString>>::get()); + xAcc->replaceByIndex(i, aAny); + } + } + lcl_SetProp(xInfo, xIdxProps, UNO_NAME_LEVEL, static_cast<sal_Int16>(rDesc.GetLevel())); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_MARKS, bool(nContentOptions & SwTOXElement::Mark )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_OUTLINE, bool(nContentOptions & SwTOXElement::OutlineLevel)); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_EMBEDDED_OBJECTS,bool(nContentOptions & SwTOXElement::Ole )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_TABLES , bool(nContentOptions & SwTOXElement::Table )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_GRAPHIC_OBJECTS, bool(nContentOptions & SwTOXElement::Graphic )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_TEXT_FRAMES, bool(nContentOptions & SwTOXElement::Frame )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_LABELS, bool(nContentOptions & SwTOXElement::Sequence )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_HIDE_TAB_LEADER_AND_PAGE_NUMBERS, bool(nContentOptions & SwTOXElement::TableLeader )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_TAB_IN_TOC, bool(nContentOptions & SwTOXElement::TableInToc )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_TOC_NEWLINE, bool(nContentOptions & SwTOXElement::Newline)); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_TOC_PARAGRAPH_OUTLINE_LEVEL, bool(nContentOptions & SwTOXElement::ParagraphOutlineLevel)); + + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_CHAPTER, rDesc.IsFromChapter()); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_IS_PROTECTED, rDesc.IsReadonly()); + + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_USE_COMBINED_ENTRIES, bool(nIdxOptions & SwTOIOptions::SameEntry )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_USE_P_P, bool(nIdxOptions & SwTOIOptions::FF )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_IS_CASE_SENSITIVE, bool(nIdxOptions & SwTOIOptions::CaseSensitive )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_USE_KEY_AS_ENTRY, bool(nIdxOptions & SwTOIOptions::KeyAsEntry )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_USE_ALPHABETICAL_SEPARATORS, bool(nIdxOptions & SwTOIOptions::AlphaDelimiter)); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_USE_DASH, bool(nIdxOptions & SwTOIOptions::Dash )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_USE_UPPER_CASE, bool(nIdxOptions & SwTOIOptions::InitialCaps )); + + OUString aTmpName( SwStyleNameMapper::GetSpecialExtraProgName( rDesc.GetSequenceName() ) ); + lcl_SetProp(xInfo, xIdxProps, UNO_NAME_LABEL_CATEGORY, aTmpName ); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_LABELS, !rDesc.IsCreateFromObjectNames()); + + sal_Int16 nSet = text::ChapterFormat::NAME_NUMBER; + switch (rDesc.GetCaptionDisplay()) + { + case CAPTION_COMPLETE: nSet = text::ChapterFormat::NAME_NUMBER;break; + case CAPTION_NUMBER : nSet = text::ChapterFormat::NUMBER; break; + case CAPTION_TEXT : nSet = text::ChapterFormat::NAME; break; + } + lcl_SetProp(xInfo, xIdxProps, UNO_NAME_LABEL_DISPLAY_TYPE, nSet); + + SwTOOElements nOLEOptions = rDesc.GetOLEOptions(); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_STAR_MATH, bool(SwTOOElements::Math &nOLEOptions )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_STAR_CHART, bool(SwTOOElements::Chart &nOLEOptions )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_STAR_CALC, bool(SwTOOElements::Calc &nOLEOptions )); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_STAR_DRAW, bool(SwTOOElements::DrawImpress&nOLEOptions)); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_CREATE_FROM_OTHER_EMBEDDED_OBJECTS, bool(SwTOOElements::Other & nOLEOptions)); + } + const SwForm* pForm = GetForm(m_eCurrentTOXType); + if(bInitialCreate || !nPage || nPage == TOX_PAGE_ENTRY) + { + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_IS_COMMA_SEPARATED, pForm->IsCommaSeparated()); + lcl_SetBOOLProp(xInfo, xIdxProps, UNO_NAME_USE_ALPHABETICAL_SEPARATORS, bool(nIdxOptions&SwTOIOptions::AlphaDelimiter)); + const bool bUseCurrent = nCurrentLevel < pForm->GetFormMax(); + const sal_uInt16 nStartLevel = bUseCurrent ? nCurrentLevel : 0; + const sal_uInt16 nEndLevel = bUseCurrent ? nCurrentLevel : pForm->GetFormMax() - 1; + if(xInfo->hasPropertyByName(UNO_NAME_LEVEL_FORMAT)) + { + for(sal_uInt16 nCurrLevel = nStartLevel; nCurrLevel <= nEndLevel; nCurrLevel++) + { + OUString sTokenType; + uno::Sequence< beans::PropertyValues> aSequPropVals(10); + tools::Long nTokenIndex = 0; + tools::Long nParamCount = 2; + + // #i24377# + SwFormTokens aPattern = pForm->GetPattern(nCurrLevel); + + for(const auto& aToken : aPattern) + { + if( aSequPropVals.getLength() <= nTokenIndex) + aSequPropVals.realloc(nTokenIndex + 10); + + switch(aToken.eTokenType) + { + case TOKEN_ENTRY_NO : + sTokenType = "TokenEntryNumber"; + // numbering for content index + break; + case TOKEN_ENTRY_TEXT : + case TOKEN_ENTRY : + sTokenType = "TokenEntryText"; + break; + case TOKEN_TAB_STOP : + nParamCount += 3; + sTokenType = "TokenTabStop"; + break; + case TOKEN_TEXT : + sTokenType = "TokenText"; + nParamCount += 1; + break; + case TOKEN_PAGE_NUMS : + sTokenType = "TokenPageNumber"; + break; + case TOKEN_CHAPTER_INFO : + sTokenType = "TokenChapterInfo"; + break; + case TOKEN_LINK_START : + sTokenType = "TokenHyperlinkStart"; + break; + case TOKEN_LINK_END : + sTokenType = "TokenHyperlinkEnd"; + break; + case TOKEN_AUTHORITY : + { + sTokenType = "TokenBibliographyDataField"; + } + break; + default:; //prevent warning + } + beans::PropertyValues aPropVals(nParamCount); + beans::PropertyValue* pPropValArr = aPropVals.getArray(); + pPropValArr[0].Name = "TokenType"; + pPropValArr[0].Value <<= sTokenType; + pPropValArr[1].Name = "CharacterStyleName"; + pPropValArr[1].Value <<= aToken.sCharStyleName; + if(TOKEN_TAB_STOP == aToken.eTokenType) + { + pPropValArr[2].Name = "TabStopRightAligned"; + pPropValArr[2].Value <<= SvxTabAdjust::End == aToken.eTabAlign; + pPropValArr[3].Name = "TabStopFillCharacter"; + pPropValArr[3].Value <<= OUString(aToken.cTabFillChar); + pPropValArr[4].Name = "TabStopPosition"; + SwTwips nTempPos = aToken.nTabStopPosition >= 0 ? + aToken.nTabStopPosition : 0; + nTempPos = convertTwipToMm100(nTempPos); + pPropValArr[4].Value <<= static_cast<sal_Int32>(nTempPos); + } + else if(TOKEN_TEXT == aToken.eTokenType) + { + pPropValArr[2].Name = "Text"; + pPropValArr[2].Value <<= aToken.sText; + } + beans::PropertyValues* pValues = aSequPropVals.getArray(); + pValues[nTokenIndex] = aPropVals; + nTokenIndex++; + } + aSequPropVals.realloc(nTokenIndex); + + uno::Any aFormatAccess = xIdxProps->getPropertyValue(UNO_NAME_LEVEL_FORMAT); + OSL_ENSURE(aFormatAccess.getValueType() == cppu::UnoType<container::XIndexReplace>::get(), + "wrong property type"); + + uno::Reference< container::XIndexReplace > xFormatAccess; + aFormatAccess >>= xFormatAccess; + uno::Any aLevelProp(&aSequPropVals, cppu::UnoType<uno::Sequence<beans::PropertyValues>>::get()); + xFormatAccess->replaceByIndex(nCurrLevel, aLevelProp); + } + } + } + if(bInitialCreate || !nPage || nPage == TOX_PAGE_STYLES) + { + lcl_SetProp(xInfo, xIdxProps, "ParaStyleHeading", pForm->GetTemplate(0)); + sal_uInt16 nOffset = 0; + sal_uInt16 nEndLevel = 2; + switch(m_eCurrentTOXType.eType) + { + case TOX_INDEX: + { + nOffset = 1; + nEndLevel = 4; + lcl_SetProp(xInfo, xIdxProps, "ParaStyleSeparator", pForm->GetTemplate(1)); + } + break; + case TOX_CONTENT : + nEndLevel = 11; + break; + default:; //prevent warning + } + for(sal_uInt16 i = 1; i < nEndLevel; i++) + { + lcl_SetProp(xInfo, + xIdxProps, + "ParaStyleLevel" + OUString::number( i ), + pForm->GetTemplate(i + nOffset)); + } + } + m_vTypeData[nTOXIndex].m_oIndexSections->xDocumentIndex->update(); + + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "sw", "::CreateExample()"); + } + m_xExampleFrame->Invalidate(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/index/cnttab.cxx b/sw/source/ui/index/cnttab.cxx new file mode 100644 index 0000000000..a5d3bf92dd --- /dev/null +++ b/sw/source/ui/index/cnttab.cxx @@ -0,0 +1,4136 @@ +/* -*- 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 <sal/config.h> + +#include <osl/diagnose.h> +#include <o3tl/safeint.hxx> +#include <sal/log.hxx> +#include <svl/style.hxx> +#include <utility> +#include <vcl/weld.hxx> +#include <svl/stritem.hxx> +#include <unotools/pathoptions.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/sfxdlg.hxx> +#include <svx/dialogs.hrc> +#include <svx/flagsdef.hxx> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <svtools/indexentryres.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <column.hxx> +#include <fmtfsize.hxx> +#include <authfld.hxx> +#include <swtypes.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <cnttab.hxx> +#include <swuicnttab.hxx> +#include <poolfmt.hxx> +#include <strings.hrc> +#include <uitool.hxx> +#include <fmtcol.hxx> +#include <fldbas.hxx> +#include <expfld.hxx> +#include <unotools.hxx> +#include <docsh.hxx> +#include <swmodule.hxx> +#include <modcfg.hxx> +#include <iodetect.hxx> + +#include <cmdid.h> +#include <cnttab.hrc> +#include <SwStyleNameMapper.hxx> +#include <sfx2/filedlghelper.hxx> +#include <toxwrap.hxx> +#include <chpfld.hxx> +#include <svtools/editbrowsebox.hxx> + +#include <cmath> +#include <memory> +#include <string_view> +#include <vector> +#include <numeric> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace com::sun::star::ui::dialogs; +using namespace ::sfx2; + +const sal_Unicode aDeliStart = '['; // for the form +const sal_Unicode aDeliEnd = ']'; // for the form + +static OUString lcl_CreateAutoMarkFileDlg(weld::Window* pParent, const OUString& rURL, + const OUString& rFileString, bool bOpen) +{ + OUString sRet; + + FileDialogHelper aDlgHelper( bOpen ? + TemplateDescription::FILEOPEN_SIMPLE : TemplateDescription::FILESAVE_AUTOEXTENSION, + FileDialogFlags::NONE, pParent); + uno::Reference < XFilePicker3 > xFP = aDlgHelper.GetFilePicker(); + + xFP->appendFilter( rFileString, "*.sdi" ); + xFP->setCurrentFilter( rFileString ) ; + + if( !rURL.isEmpty() ) + xFP->setDisplayDirectory( rURL ); + else + { + SvtPathOptions aPathOpt; + xFP->setDisplayDirectory( aPathOpt.GetUserConfigPath() ); + } + + const ErrCode aErrCode = aDlgHelper.Execute(); + if (aErrCode == ERRCODE_NONE) + { + sRet = xFP->getSelectedFiles().getConstArray()[0]; + } + // tdf#120405 - use previously selected file, if selection is aborted + else if (aErrCode == ERRCODE_ABORT && !rURL.isEmpty()) + { + sRet = rURL; + } + + return sRet; +} + +namespace { + +struct AutoMarkEntry +{ + OUString sSearch; + OUString sAlternative; + OUString sPrimKey; + OUString sSecKey; + OUString sComment; + bool bCase; + bool bWord; + + AutoMarkEntry() : + bCase(false), + bWord(false){} +}; + +} + +typedef ::svt::EditBrowseBox SwEntryBrowseBox_Base; + +namespace { + +class SwEntryBrowseBox : public SwEntryBrowseBox_Base +{ + VclPtr<svt::EditControl> m_aCellEdit; + VclPtr<svt::CheckBoxControl> m_aCellCheckBox; + + OUString m_sYes; + OUString m_sNo; + + std::vector<std::unique_ptr<AutoMarkEntry>> m_Entries; + + ::svt::CellControllerRef m_xController; + ::svt::CellControllerRef m_xCheckController; + + sal_Int32 m_nCurrentRow; + bool m_bModified; + +protected: + virtual bool SeekRow( sal_Int32 nRow ) override; + virtual void PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColId) const override; + virtual void InitController(::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol) override; + virtual ::svt::CellController* GetController(sal_Int32 nRow, sal_uInt16 nCol) override; + virtual bool SaveModified() override; + + std::vector<tools::Long> GetOptimalColWidths() const; + +public: + SwEntryBrowseBox(const css::uno::Reference<css::awt::XWindow> &rParent); + virtual ~SwEntryBrowseBox() override; + virtual void dispose() override; + void ReadEntries(SvStream& rInStr); + void WriteEntries(SvStream& rOutStr); + + bool IsModified()const override; + + virtual OUString GetCellText( sal_Int32 nRow, sal_uInt16 nColumn ) const override; + virtual void Resize() override; + virtual Size GetOptimalSize() const override; +}; + +class SwAutoMarkDlg_Impl : public weld::GenericDialogController +{ + OUString m_sAutoMarkURL; + bool m_bCreateMode; + + std::unique_ptr<weld::Button> m_xOKPB; + std::unique_ptr<weld::Container> m_xTable; + css::uno::Reference<css::awt::XWindow> m_xTableCtrlParent; + VclPtr<SwEntryBrowseBox> m_xEntriesBB; + + DECL_LINK(OkHdl, weld::Button&, void); +public: + SwAutoMarkDlg_Impl(weld::Window* pParent, OUString aAutoMarkURL, + bool bCreate); + virtual ~SwAutoMarkDlg_Impl() override; +}; + +} + +sal_uInt16 CurTOXType::GetFlatIndex() const +{ + return static_cast< sal_uInt16 >( (eType == TOX_USER && nIndex) + ? TOX_AUTHORITIES + nIndex : eType ); +} + +SwMultiTOXTabDialog::SwMultiTOXTabDialog(weld::Widget* pParent, const SfxItemSet& rSet, + SwWrtShell &rShell, SwTOXBase* pCurTOX, + sal_uInt16 nToxType, bool bGlobal) + : SfxTabDialogController(pParent, "modules/swriter/ui/tocdialog.ui", "TocDialog", &rSet) + , m_pMgr( new SwTOXMgr( &rShell ) ) + , m_rWrtShell(rShell) + , m_pParamTOXBase(pCurTOX) + , m_sUserDefinedIndex(SwResId(STR_USER_DEFINED_INDEX)) + , m_nInitialTOXType(nToxType) + , m_bEditTOX(false) + , m_bExampleCreated(false) + , m_bGlobalFlag(bGlobal) + , m_xShowExampleCB(m_xBuilder->weld_check_button("showexample")) +{ + m_eCurrentTOXType.eType = TOX_CONTENT; + m_eCurrentTOXType.nIndex = 0; + + const sal_uInt16 nUserTypeCount = m_rWrtShell.GetTOXTypeCount(TOX_USER); + m_vTypeData.resize(nUserTypeCount + 6); + //the standard user index is on position TOX_USER + //all user indexes follow after position TOX_AUTHORITIES + if(pCurTOX) + { + m_bEditTOX = true; + } + for(int i = m_vTypeData.size() - 1; i > -1; i--) + { + m_vTypeData[i].m_oIndexSections.emplace(); + if(pCurTOX) + { + m_eCurrentTOXType.eType = pCurTOX->GetType(); + sal_uInt16 nArrayIndex = static_cast< sal_uInt16 >(m_eCurrentTOXType.eType); + if(m_eCurrentTOXType.eType == TOX_USER) + { + //which user type is it? + for(sal_uInt16 nUser = 0; nUser < nUserTypeCount; nUser++) + { + const SwTOXType* pTemp = m_rWrtShell.GetTOXType(TOX_USER, nUser); + if(pCurTOX->GetTOXType() == pTemp) + { + m_eCurrentTOXType.nIndex = nUser; + nArrayIndex = static_cast< sal_uInt16 >(nUser > 0 ? TOX_AUTHORITIES + nUser : TOX_USER); + break; + } + } + } + m_vTypeData[nArrayIndex].m_pForm.reset(new SwForm(pCurTOX->GetTOXForm())); + m_vTypeData[nArrayIndex].m_pDescription = CreateTOXDescFromTOXBase(pCurTOX); + if(TOX_AUTHORITIES == m_eCurrentTOXType.eType) + { + const SwAuthorityFieldType* pFType = static_cast<const SwAuthorityFieldType*>( + m_rWrtShell.GetFieldType(SwFieldIds::TableOfAuthorities, OUString())); + if(pFType) + { + OUString sBrackets; + if(pFType->GetPrefix()) + sBrackets += OUStringChar(pFType->GetPrefix()); + if(pFType->GetSuffix()) + sBrackets += OUStringChar(pFType->GetSuffix()); + m_vTypeData[nArrayIndex].m_pDescription->SetAuthBrackets(sBrackets); + m_vTypeData[nArrayIndex].m_pDescription->SetAuthSequence(pFType->IsSequence()); + } + else + { + m_vTypeData[nArrayIndex].m_pDescription->SetAuthBrackets("[]"); + } + } + } + } + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + AddTabPage("index", SwTOXSelectTabPage::Create, nullptr); + AddTabPage("styles", SwTOXStylesTabPage::Create, nullptr); + AddTabPage("columns", SwColumnPage::Create, nullptr); + AddTabPage("background", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_BKG), nullptr); + AddTabPage("entries", SwTOXEntryTabPage::Create, nullptr); + if (!pCurTOX) + SetCurPageId("index"); + + m_xShowExampleCB->connect_toggled(LINK(this, SwMultiTOXTabDialog, ShowPreviewHdl)); + m_xShowExampleCB->set_active(SW_MOD()->GetModuleConfig()->IsShowIndexPreview()); + + ShowPreview(); +} + +SwMultiTOXTabDialog::~SwMultiTOXTabDialog() +{ + SW_MOD()->GetModuleConfig()->SetShowIndexPreview(m_xShowExampleCB->get_active()); +} + +void SwMultiTOXTabDialog::PageCreated(const OUString& rId, SfxTabPage &rPage) +{ + if (rId == "background") + { + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE, static_cast<sal_uInt32>(SvxBackgroundTabFlags::SHOW_SELECTOR))); + rPage.PageCreated(aSet); + } + else if (rId == "columns") + { + const SwFormatFrameSize& rSize = GetInputSetImpl()->Get(RES_FRM_SIZE); + + static_cast<SwColumnPage&>(rPage).SetPageWidth(rSize.GetWidth()); + } + else if (rId == "entries") + static_cast<SwTOXEntryTabPage&>(rPage).SetWrtShell(m_rWrtShell); + else if (rId == "index") + { + static_cast<SwTOXSelectTabPage&>(rPage).SetWrtShell(m_rWrtShell); + if(USHRT_MAX != m_nInitialTOXType) + static_cast<SwTOXSelectTabPage&>(rPage).SelectType(static_cast<TOXTypes>(m_nInitialTOXType)); + } +} + +short SwMultiTOXTabDialog::Ok() +{ + short nRet = SfxTabDialogController::Ok(); + SwTOXDescription& rDesc = GetTOXDescription(m_eCurrentTOXType); + SwTOXBase aNewDef(*m_rWrtShell.GetDefaultTOXBase( m_eCurrentTOXType.eType, true )); + + const sal_uInt16 nIndex = m_eCurrentTOXType.GetFlatIndex(); + if(m_vTypeData[nIndex].m_pForm) + { + rDesc.SetForm(*m_vTypeData[nIndex].m_pForm); + aNewDef.SetTOXForm(*m_vTypeData[nIndex].m_pForm); + } + rDesc.ApplyTo(aNewDef); + if(!m_bGlobalFlag) + m_pMgr->UpdateOrInsertTOX( + rDesc, nullptr, GetOutputItemSet()); + else if(m_bEditTOX) + m_pMgr->UpdateOrInsertTOX( + rDesc, &m_pParamTOXBase, GetOutputItemSet()); + + if(!m_eCurrentTOXType.nIndex) + m_rWrtShell.SetDefaultTOXBase(aNewDef); + + return nRet; +} + +SwForm* SwMultiTOXTabDialog::GetForm(CurTOXType eType) +{ + const sal_uInt16 nIndex = eType.GetFlatIndex(); + if(!m_vTypeData[nIndex].m_pForm) + m_vTypeData[nIndex].m_pForm.reset(new SwForm(eType.eType)); + return m_vTypeData[nIndex].m_pForm.get(); +} + +SwTOXDescription& SwMultiTOXTabDialog::GetTOXDescription(CurTOXType eType) +{ + const sal_uInt16 nIndex = eType.GetFlatIndex(); + if(!m_vTypeData[nIndex].m_pDescription) + { + const SwTOXBase* pDef = m_rWrtShell.GetDefaultTOXBase( eType.eType ); + if(pDef) + m_vTypeData[nIndex].m_pDescription = CreateTOXDescFromTOXBase(pDef); + else + { + m_vTypeData[nIndex].m_pDescription.reset(new SwTOXDescription(eType.eType)); + if(eType.eType == TOX_USER) + m_vTypeData[nIndex].m_pDescription->SetTitle(m_sUserDefinedIndex); + else + m_vTypeData[nIndex].m_pDescription->SetTitle( + m_rWrtShell.GetTOXType(eType.eType, 0)->GetTypeName()); + } + if(TOX_AUTHORITIES == eType.eType) + { + const SwAuthorityFieldType* pFType = static_cast<const SwAuthorityFieldType*>( + m_rWrtShell.GetFieldType(SwFieldIds::TableOfAuthorities, OUString())); + if(pFType) + { + m_vTypeData[nIndex].m_pDescription->SetAuthBrackets(OUStringChar(pFType->GetPrefix()) + + OUStringChar(pFType->GetSuffix())); + m_vTypeData[nIndex].m_pDescription->SetAuthSequence(pFType->IsSequence()); + } + else + { + m_vTypeData[nIndex].m_pDescription->SetAuthBrackets("[]"); + } + } + else if(TOX_INDEX == eType.eType) + m_vTypeData[nIndex].m_pDescription->SetMainEntryCharStyle(SwResId(STR_POOLCHR_IDX_MAIN_ENTRY)); + + } + return *m_vTypeData[nIndex].m_pDescription; +} + +std::unique_ptr<SwTOXDescription> SwMultiTOXTabDialog::CreateTOXDescFromTOXBase( + const SwTOXBase*pCurTOX) +{ + std::unique_ptr<SwTOXDescription> pDesc(new SwTOXDescription(pCurTOX->GetType())); + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + pDesc->SetStyleNames(pCurTOX->GetStyleNames(i), i); + pDesc->SetAutoMarkURL(m_rWrtShell.GetTOIAutoMarkURL()); + pDesc->SetTitle(pCurTOX->GetTitle()); + + pDesc->SetContentOptions(pCurTOX->GetCreateType()); + if(pDesc->GetTOXType() == TOX_INDEX) + pDesc->SetIndexOptions(pCurTOX->GetOptions()); + pDesc->SetMainEntryCharStyle(pCurTOX->GetMainEntryCharStyle()); + if(pDesc->GetTOXType() != TOX_INDEX) + pDesc->SetLevel(static_cast<sal_uInt8>(pCurTOX->GetLevel())); + pDesc->SetCreateFromObjectNames(pCurTOX->IsFromObjectNames()); + pDesc->SetSequenceName(pCurTOX->GetSequenceName()); + pDesc->SetCaptionDisplay(pCurTOX->GetCaptionDisplay()); + pDesc->SetFromChapter(pCurTOX->IsFromChapter()); + pDesc->SetReadonly(pCurTOX->IsProtected()); + pDesc->SetOLEOptions(pCurTOX->GetOLEOptions()); + pDesc->SetLevelFromChapter(pCurTOX->IsLevelFromChapter()); + pDesc->SetLanguage(pCurTOX->GetLanguage()); + pDesc->SetSortAlgorithm(pCurTOX->GetSortAlgorithm()); + return pDesc; +} + +void SwMultiTOXTabDialog::ShowPreview() +{ + if (m_xShowExampleCB->get_active()) + { + if(!m_xExampleFrame && !m_bExampleCreated) + { + m_bExampleCreated = true; + OUString sTemplate("internal/idxexample.odt"); + + SvtPathOptions aOpt; + bool bExist = aOpt.SearchFile( sTemplate, SvtPathOptions::Paths::Template ); + + if(!bExist) + { + OUString sInfo(SwResId(STR_FILE_NOT_FOUND)); + sInfo = sInfo.replaceFirst( "%1", sTemplate ); + sInfo = sInfo.replaceFirst( "%2", aOpt.GetTemplatePath() ); + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Info, VclButtonsType::Ok, + sInfo)); + xInfoBox->run(); + } + else + { + Link<SwOneExampleFrame&,void> aLink(LINK(this, SwMultiTOXTabDialog, CreateExample_Hdl)); + m_xExampleFrame.reset(new SwOneExampleFrame(EX_SHOW_ONLINE_LAYOUT | EX_LOCALIZE_TOC_STRINGS, &aLink, &sTemplate)); + m_xExampleFrameWin.reset(new weld::CustomWeld(*m_xBuilder, "example", *m_xExampleFrame)); + } + m_xShowExampleCB->set_visible(m_xExampleFrame != nullptr); + } + } + + if (m_xExampleFrame) + { + const bool bSetViewWindow = m_xShowExampleCB->get_active(); + if (bSetViewWindow) + m_xExampleFrame->Show(); + else + m_xExampleFrame->Hide(); + } +} + +IMPL_LINK_NOARG(SwMultiTOXTabDialog, ShowPreviewHdl, weld::Toggleable&, void) +{ + ShowPreview(); + m_xDialog->resize_to_request(); +} + +bool SwMultiTOXTabDialog::IsNoNum(SwWrtShell& rSh, const OUString& rName) +{ + SwTextFormatColl* pColl = rSh.GetParaStyle(rName); + if(pColl && ! pColl->IsAssignedToListLevelOfOutlineStyle()) + return true; + + const sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( + rName, SwGetPoolIdFromName::TxtColl); + return nId != USHRT_MAX && + ! rSh.GetTextCollFromPool(nId)->IsAssignedToListLevelOfOutlineStyle(); +} + +namespace { + +class SwAddStylesDlg_Impl : public SfxDialogController +{ + OUString* m_pStyleArr; + + std::unique_ptr<weld::Button> m_xOk; + std::unique_ptr<weld::Button> m_xLeftPB; + std::unique_ptr<weld::Button> m_xRightPB; + std::unique_ptr<weld::TreeView> m_xHeaderTree; + + void ToggleOn(int nEntry, int nToggleColumn); + + DECL_LINK(OkHdl, weld::Button&, void); + DECL_LINK(LeftRightHdl, weld::Button&, void); + DECL_LINK(KeyInput, const KeyEvent&, bool); + DECL_LINK(TreeSizeAllocHdl, const Size&, void); + DECL_LINK(RadioToggleOnHdl, const weld::TreeView::iter_col&, void); + DECL_LINK(HeaderBarClick, int, void); + +public: + SwAddStylesDlg_Impl(weld::Window* pParent, SwWrtShell const & rWrtSh, OUString rStringArr[]); +}; + +} + +SwAddStylesDlg_Impl::SwAddStylesDlg_Impl(weld::Window* pParent, + SwWrtShell const & rWrtSh, OUString rStringArr[]) + : SfxDialogController(pParent, "modules/swriter/ui/assignstylesdialog.ui", "AssignStylesDialog") + , m_pStyleArr(rStringArr) + , m_xOk(m_xBuilder->weld_button("ok")) + , m_xLeftPB(m_xBuilder->weld_button("left")) + , m_xRightPB(m_xBuilder->weld_button("right")) + , m_xHeaderTree(m_xBuilder->weld_tree_view("styles")) +{ + m_xOk->connect_clicked(LINK(this, SwAddStylesDlg_Impl, OkHdl)); + m_xLeftPB->connect_clicked(LINK(this, SwAddStylesDlg_Impl, LeftRightHdl)); + m_xRightPB->connect_clicked(LINK(this, SwAddStylesDlg_Impl, LeftRightHdl)); + + m_xHeaderTree->connect_size_allocate(LINK(this, SwAddStylesDlg_Impl, TreeSizeAllocHdl)); + m_xHeaderTree->enable_toggle_buttons(weld::ColumnToggleType::Radio); + m_xHeaderTree->connect_toggled(LINK(this, SwAddStylesDlg_Impl, RadioToggleOnHdl)); + m_xHeaderTree->connect_column_clicked(LINK(this, SwAddStylesDlg_Impl, HeaderBarClick)); + + std::vector<int> aWidths + { + o3tl::narrowing<int>(m_xHeaderTree->get_approximate_digit_width() * 30) + }; + int nPadding = m_xHeaderTree->get_approximate_digit_width() * 2; + OUString sTitle(m_xHeaderTree->get_column_title(1)); + for (sal_uInt16 i = 0; i <= MAXLEVEL; ++i) + { + sTitle = OUString::number(i); + m_xHeaderTree->set_column_title(i + 1, sTitle); + aWidths.push_back(m_xHeaderTree->get_pixel_size(sTitle).Width() + nPadding); + } + m_xHeaderTree->set_column_fixed_widths(aWidths); + auto nWidth = std::accumulate(aWidths.begin(), aWidths.end(), + Application::GetSettings().GetStyleSettings().GetScrollBarSize()); + m_xHeaderTree->set_size_request(nWidth, m_xHeaderTree->get_height_rows(15)); + + int nRow(0); + for (sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + const OUString &rStyles{rStringArr[i]}; + if (rStyles.isEmpty()) + continue; + sal_Int32 nPos(0); + do + { + OUString sEntry = rStyles.getToken(0, TOX_STYLE_DELIMITER, nPos); + m_xHeaderTree->append_text(sEntry); + for (sal_uInt16 j = 0; j <= MAXLEVEL; ++j) + { + TriState eState = i == j - 1 ? TRISTATE_TRUE : TRISTATE_FALSE; + m_xHeaderTree->set_toggle(nRow, eState, j + 1); + } + ++nRow; + } while (nPos>=0); + } + // now the other styles + + const sal_uInt16 nSz = rWrtSh.GetTextFormatCollCount(); + for (sal_uInt16 j = 0; j < nSz; ++j) + { + const SwTextFormatColl& rColl = rWrtSh.GetTextFormatColl(j); + if (rColl.IsDefault()) + continue; + + const OUString aName = rColl.GetName(); + if (!aName.isEmpty()) + { + bool bEntry = false; + int nChildren = m_xHeaderTree->n_children(); + for (int i = 0; i < nChildren; ++i) + { + if (m_xHeaderTree->get_text(i, 0) == aName) + { + bEntry = true; + break; + } + } + if (!bEntry) + { + m_xHeaderTree->append_text(aName); + for (sal_uInt16 k = 0; k <= MAXLEVEL; ++k) + { + TriState eState = k == 0 ? TRISTATE_TRUE : TRISTATE_FALSE; + m_xHeaderTree->set_toggle(nRow, eState, k + 1); + } + ++nRow; + } + } + } + + m_xHeaderTree->make_sorted(); + m_xHeaderTree->set_sort_column(0); + m_xHeaderTree->set_sort_order(true); + m_xHeaderTree->set_sort_indicator(TRISTATE_TRUE, 0); + + m_xHeaderTree->select(0); + m_xHeaderTree->connect_key_release(LINK(this, SwAddStylesDlg_Impl, KeyInput)); +} + +IMPL_LINK(SwAddStylesDlg_Impl, HeaderBarClick, int, nColumn, void) +{ + bool bSortAtoZ = m_xHeaderTree->get_sort_order(); + + //set new arrow positions in headerbar + if (nColumn == m_xHeaderTree->get_sort_column()) + { + bSortAtoZ = !bSortAtoZ; + m_xHeaderTree->set_sort_order(bSortAtoZ); + } + + if (nColumn != -1) + { + //sort lists + m_xHeaderTree->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn); + } +} + +IMPL_LINK(SwAddStylesDlg_Impl, TreeSizeAllocHdl, const Size&, rSize, void) +{ + auto nWidth = rSize.Width() - Application::GetSettings().GetStyleSettings().GetScrollBarSize(); + + std::vector<int> aWidths { 0 }; + int nPadding = m_xHeaderTree->get_approximate_digit_width() * 2; + for (sal_uInt16 i = 0; i <= MAXLEVEL; ++i) + { + OUString sTitle(m_xHeaderTree->get_column_title(i + 1)); + aWidths.push_back(m_xHeaderTree->get_pixel_size(sTitle).Width() + nPadding); + } + auto nOtherWidth = std::accumulate(aWidths.begin(), aWidths.end(), 0); + aWidths[0] = nWidth - nOtherWidth; + m_xHeaderTree->set_column_fixed_widths(aWidths); +} + +IMPL_LINK(SwAddStylesDlg_Impl, RadioToggleOnHdl, const weld::TreeView::iter_col&, rRowCol, void) +{ + for (sal_uInt16 i = 0; i <= MAXLEVEL; ++i) + { + TriState eState = rRowCol.second == i + 1 ? TRISTATE_TRUE : TRISTATE_FALSE; + m_xHeaderTree->set_toggle(rRowCol.first, eState, i + 1); + } +} + +IMPL_LINK(SwAddStylesDlg_Impl, KeyInput, const KeyEvent&, rKEvt, bool) +{ + vcl::KeyCode aCode = rKEvt.GetKeyCode(); + bool bHandled = false; + + sal_uInt16 nCode = aCode.GetCode(); + switch (nCode) + { + case KEY_ADD: + LeftRightHdl(*m_xRightPB); + bHandled = true; + break; + case KEY_SUBTRACT: + LeftRightHdl(*m_xLeftPB); + bHandled = true; + break; + case KEY_0: + case KEY_1: + case KEY_2: + case KEY_3: + case KEY_4: + case KEY_5: + case KEY_6: + case KEY_7: + case KEY_8: + case KEY_9: + case KEY_A: + { + int nEntry = m_xHeaderTree->get_selected_index(); + if (nEntry != -1) + { + ToggleOn(nEntry, nCode != KEY_A ? nCode - KEY_0 : 10); + bHandled = true; + } + break; + } + } + + return bHandled; +} + +IMPL_LINK_NOARG(SwAddStylesDlg_Impl, OkHdl, weld::Button&, void) +{ + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + m_pStyleArr[i].clear(); + + int nChildren = m_xHeaderTree->n_children(); + for (int i = 0; i < nChildren; ++i) + { + int nToggleColumn = 0; + for (sal_uInt16 j = 0; j <= MAXLEVEL; ++j) + { + if (m_xHeaderTree->get_toggle(i, j + 1) == TRISTATE_TRUE) + { + nToggleColumn = j; + break; + } + } + if (nToggleColumn) + { + int nLevel = nToggleColumn - 1; + if(!m_pStyleArr[nLevel].isEmpty()) + m_pStyleArr[nLevel] += OUStringChar(TOX_STYLE_DELIMITER); + m_pStyleArr[nLevel] += m_xHeaderTree->get_text(i, 0); + } + } + + //TODO write back style names + m_xDialog->response(RET_OK); +} + +IMPL_LINK(SwAddStylesDlg_Impl, LeftRightHdl, weld::Button&, rBtn, void) +{ + bool bLeft = &rBtn == m_xLeftPB.get(); + int nEntry = m_xHeaderTree->get_selected_index(); + if (nEntry == -1) + return; + + int nToggleColumn = 0; + for (sal_uInt16 j = 0; j <= MAXLEVEL; ++j) + { + if (m_xHeaderTree->get_toggle(nEntry, j + 1) == TRISTATE_TRUE) + { + nToggleColumn = j; + break; + } + } + + if (bLeft) + { + if (nToggleColumn) + --nToggleColumn; + } + else + { + if (nToggleColumn < MAXLEVEL) + ++nToggleColumn; + } + + ToggleOn(nEntry, nToggleColumn); +} + +void SwAddStylesDlg_Impl::ToggleOn(int nEntry, int nToggleColumn) +{ + for (sal_uInt16 j = 0; j <= MAXLEVEL; ++j) + { + m_xHeaderTree->set_toggle(nEntry, j == nToggleColumn ? TRISTATE_TRUE : TRISTATE_FALSE, j + 1); + } +} + +SwTOXSelectTabPage::SwTOXSelectTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/tocindexpage.ui", "TocIndexPage", &rAttrSet) + , m_sAutoMarkType(SwResId(STR_AUTOMARK_TYPE)) + , m_bWaitingInitialSettings(true) + , m_xTitleED(m_xBuilder->weld_entry("title")) + , m_xTypeFT(m_xBuilder->weld_label("typeft")) + , m_xTypeLB(m_xBuilder->weld_combo_box("type")) + , m_xReadOnlyCB(m_xBuilder->weld_check_button("readonly")) + , m_xAreaFrame(m_xBuilder->weld_widget("areaframe")) + , m_xAreaLB(m_xBuilder->weld_combo_box("scope")) + , m_xLevelFT(m_xBuilder->weld_label("levelft")) + , m_xLevelNF(m_xBuilder->weld_spin_button("level")) + , m_xCreateFrame(m_xBuilder->weld_widget("createframe")) + , m_xFromHeadingsCB(m_xBuilder->weld_check_button("fromheadings")) + , m_xStylesCB(m_xBuilder->weld_check_button("stylescb")) + , m_xAddStylesCB(m_xBuilder->weld_check_button("addstylescb")) + , m_xAddStylesPB(m_xBuilder->weld_button("styles")) + , m_xFromTablesCB(m_xBuilder->weld_check_button("fromtables")) + , m_xFromFramesCB(m_xBuilder->weld_check_button("fromframes")) + , m_xFromGraphicsCB(m_xBuilder->weld_check_button("fromgraphics")) + , m_xFromOLECB(m_xBuilder->weld_check_button("fromoles")) + , m_xLevelFromChapterCB(m_xBuilder->weld_check_button("uselevel")) + , m_xFromCaptionsRB(m_xBuilder->weld_radio_button("captions")) + , m_xFromObjectNamesRB(m_xBuilder->weld_radio_button("objnames")) + , m_xCaptionSequenceFT(m_xBuilder->weld_label("categoryft")) + , m_xCaptionSequenceLB(m_xBuilder->weld_combo_box("category")) + , m_xDisplayTypeFT(m_xBuilder->weld_label("displayft")) + , m_xDisplayTypeLB(m_xBuilder->weld_combo_box("display")) + , m_xParaStyleCB(m_xBuilder->weld_check_button("useparastyle")) + , m_xParaStyleLB(m_xBuilder->weld_combo_box("parastyle")) + , m_xTOXMarksCB(m_xBuilder->weld_check_button("indexmarks")) + , m_xIdxOptionsFrame(m_xBuilder->weld_widget("optionsframe")) + , m_xCollectSameCB(m_xBuilder->weld_check_button("combinesame")) + , m_xUseFFCB(m_xBuilder->weld_check_button("useff")) + , m_xUseDashCB(m_xBuilder->weld_check_button("usedash")) + , m_xCaseSensitiveCB(m_xBuilder->weld_check_button("casesens")) + , m_xInitialCapsCB(m_xBuilder->weld_check_button("initcaps")) + , m_xKeyAsEntryCB(m_xBuilder->weld_check_button("keyasentry")) + , m_xFromFileCB(m_xBuilder->weld_check_button("fromfile")) + , m_xAutoMarkPB(m_xBuilder->weld_menu_button("file")) + , m_xFromObjCLB(m_xBuilder->weld_tree_view("objects")) + , m_xFromObjFrame(m_xBuilder->weld_widget("objectframe")) + , m_xSequenceCB(m_xBuilder->weld_check_button("numberentries")) + , m_xBracketLB(m_xBuilder->weld_combo_box("brackets")) + , m_xAuthorityFrame(m_xBuilder->weld_widget("authframe")) + , m_xSortFrame(m_xBuilder->weld_widget("sortframe")) + , m_xLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("lang"))) + , m_xSortAlgorithmLB(m_xBuilder->weld_combo_box("keytype")) +{ + m_sAddStyleUser = m_xStylesCB->get_label(); + m_pIndexEntryWrapper.reset(new IndexEntrySupplierWrapper()); + + m_xLanguageLB->SetLanguageList( SvxLanguageListFlags::ALL | SvxLanguageListFlags::ONLY_KNOWN, + false ); + + //Default mode is arranged to be the tallest mode + //of alphabetical index, lock that size in now + LanguageHdl(nullptr); //fill sort algorithm list + Size aPrefSize(m_xContainer->get_preferred_size()); + m_xContainer->set_size_request(aPrefSize.Width(), aPrefSize.Height()); + + m_sAddStyleContent = m_xAddStylesCB->get_label(); + + m_xFromObjCLB->enable_toggle_buttons(weld::ColumnToggleType::Check); + + for (size_t i = 0; i < SAL_N_ELEMENTS(RES_SRCTYPES); ++i) + { + OUString sId(OUString::number(static_cast<sal_uInt32>(RES_SRCTYPES[i].second))); + m_xFromObjCLB->append(); + m_xFromObjCLB->set_toggle(i, TRISTATE_FALSE); + m_xFromObjCLB->set_text(i, SwResId(RES_SRCTYPES[i].first), 0); + m_xFromObjCLB->set_id(i, sId); + } + m_xFromObjCLB->set_size_request(-1, std::max<int>(m_xFromObjCLB->get_preferred_size().Height(), + m_xFromObjCLB->get_height_rows(SAL_N_ELEMENTS(RES_SRCTYPES))) + 2); + + SetExchangeSupport(); + m_xTypeLB->connect_changed(LINK(this, SwTOXSelectTabPage, TOXTypeHdl)); + + m_xAddStylesPB->connect_clicked(LINK(this, SwTOXSelectTabPage, AddStylesHdl)); + + m_xAutoMarkPB->connect_toggled(LINK(this, SwTOXSelectTabPage, MenuEnableHdl)); + m_xAutoMarkPB->connect_selected(LINK(this, SwTOXSelectTabPage, MenuExecuteHdl)); + + Link<weld::Toggleable&,void> aLk = LINK(this, SwTOXSelectTabPage, CheckBoxHdl); + m_xAddStylesCB->connect_toggled(aLk); + m_xFromHeadingsCB->connect_toggled(aLk); + m_xTOXMarksCB->connect_toggled(aLk); + m_xFromFileCB->connect_toggled(aLk); + m_xCollectSameCB->connect_toggled(aLk); + m_xUseFFCB->connect_toggled(aLk); + m_xUseDashCB->connect_toggled(aLk); + m_xInitialCapsCB->connect_toggled(aLk); + m_xKeyAsEntryCB->connect_toggled(aLk); + m_xParaStyleCB->connect_toggled(aLk); + + m_xTitleED->connect_changed(LINK(this, SwTOXSelectTabPage, ModifyEntryHdl)); + m_xLevelNF->connect_value_changed(LINK(this, SwTOXSelectTabPage, ModifySpinHdl)); + m_xSortAlgorithmLB->connect_changed(LINK(this, SwTOXSelectTabPage, ModifyListBoxHdl)); + m_xParaStyleLB->connect_changed(LINK(this, SwTOXSelectTabPage, ModifyListBoxHdl)); + + aLk = LINK(this, SwTOXSelectTabPage, RadioButtonHdl); + m_xFromCaptionsRB->connect_toggled(aLk); + m_xFromObjectNamesRB->connect_toggled(aLk); + RadioButtonHdl(*m_xFromCaptionsRB); + + m_xLanguageLB->connect_changed(LINK(this, SwTOXSelectTabPage, LanguageListBoxHdl)); + m_xTypeLB->set_active(0); + m_xTitleED->save_value(); +} + +SwTOXSelectTabPage::~SwTOXSelectTabPage() +{ + m_pIndexRes.reset(); + m_pIndexEntryWrapper.reset(); + m_xLanguageLB.reset(); +} + +void SwTOXSelectTabPage::SetWrtShell(SwWrtShell const & rSh) +{ + const sal_uInt16 nUserTypeCount = rSh.GetTOXTypeCount(TOX_USER); + if(nUserTypeCount <= 1) + return; + + //insert all new user indexes names after the standard user index + sal_Int32 nPos = m_xTypeLB->find_id(OUString::number(sal_uInt32(TO_USER))) + 1; + for (sal_uInt16 nUser = 1; nUser < nUserTypeCount; nUser++) + { + sal_uInt32 nEntryData = nUser << 8; + nEntryData |= TO_USER; + OUString sId(OUString::number(nEntryData)); + m_xTypeLB->insert(nPos++, rSh.GetTOXType(TOX_USER, nUser)->GetTypeName(), + &sId, nullptr, nullptr); + } +} + +bool SwTOXSelectTabPage::FillItemSet( SfxItemSet* ) +{ + return true; +} + +static tools::Long lcl_TOXTypesToUserData(CurTOXType eType) +{ + sal_uInt16 nRet = TOX_INDEX; + switch(eType.eType) + { + case TOX_INDEX : nRet = TO_INDEX; break; + case TOX_USER : + { + nRet = eType.nIndex << 8; + nRet |= TO_USER; + } + break; + case TOX_CONTENT : nRet = TO_CONTENT; break; + case TOX_ILLUSTRATIONS:nRet = TO_ILLUSTRATION; break; + case TOX_OBJECTS : nRet = TO_OBJECT; break; + case TOX_TABLES : nRet = TO_TABLE; break; + case TOX_AUTHORITIES : nRet = TO_AUTHORITIES; break; + case TOX_BIBLIOGRAPHY : nRet = TO_BIBLIOGRAPHY; break; + case TOX_CITATION :break; + } + return nRet; +} + +void SwTOXSelectTabPage::SelectType(TOXTypes eSet) +{ + CurTOXType eCurType (eSet); + + sal_uInt32 nData = lcl_TOXTypesToUserData(eCurType); + m_xTypeLB->set_active_id(OUString::number(nData)); + m_xTypeFT->set_sensitive(false); + m_xTypeLB->set_sensitive(false); + TOXTypeHdl(*m_xTypeLB); +} + +static CurTOXType lcl_UserData2TOXTypes(sal_uInt16 nData) +{ + CurTOXType eRet; + + switch(nData&0xff) + { + case TO_INDEX : eRet.eType = TOX_INDEX; break; + case TO_USER : + { + eRet.eType = TOX_USER; + eRet.nIndex = (nData&0xff00) >> 8; + } + break; + case TO_CONTENT : eRet.eType = TOX_CONTENT; break; + case TO_ILLUSTRATION: eRet.eType = TOX_ILLUSTRATIONS; break; + case TO_OBJECT : eRet.eType = TOX_OBJECTS; break; + case TO_TABLE : eRet.eType = TOX_TABLES; break; + case TO_AUTHORITIES : eRet.eType = TOX_AUTHORITIES; break; + case TO_BIBLIOGRAPHY : eRet.eType = TOX_BIBLIOGRAPHY; break; + default: OSL_FAIL("what a type?"); + } + return eRet; +} + +void SwTOXSelectTabPage::ApplyTOXDescription() +{ + SwMultiTOXTabDialog* pTOXDlg = static_cast<SwMultiTOXTabDialog*>(GetDialogController()); + const CurTOXType aCurType = pTOXDlg->GetCurrentTOXType(); + SwTOXDescription& rDesc = pTOXDlg->GetTOXDescription(aCurType); + + m_xReadOnlyCB->set_active(rDesc.IsReadonly()); + if (!m_xTitleED->get_value_changed_from_saved()) + { + if (rDesc.GetTitle()) + m_xTitleED->set_text(*rDesc.GetTitle()); + else + m_xTitleED->set_text(OUString()); + m_xTitleED->save_value(); + } + + m_xAreaLB->set_active(rDesc.IsFromChapter() ? 1 : 0); + + if (aCurType.eType != TOX_INDEX) + m_xLevelNF->set_value(rDesc.GetLevel()); //content, user + + SwTOXElement nCreateType = rDesc.GetContentOptions(); + + //user + content + bool bHasStyleNames = false; + + for( sal_uInt16 i = 0; i < MAXLEVEL; i++) + if(!rDesc.GetStyleNames(i).isEmpty()) + { + bHasStyleNames = true; + break; + } + m_xAddStylesCB->set_active(bHasStyleNames && (nCreateType & SwTOXElement::Template)); + + m_xFromOLECB->set_active( bool(nCreateType & SwTOXElement::Ole) ); + m_xFromTablesCB->set_active( bool(nCreateType & SwTOXElement::Table) ); + m_xFromGraphicsCB->set_active( bool(nCreateType & SwTOXElement::Graphic) ); + m_xFromFramesCB->set_active( bool(nCreateType & SwTOXElement::Frame) ); + + m_xLevelFromChapterCB->set_active(rDesc.IsLevelFromChapter()); + + //all but illustration and table + m_xTOXMarksCB->set_active( bool(nCreateType & SwTOXElement::Mark) ); + + if (TOX_ILLUSTRATIONS == aCurType.eType || TOX_TABLES == aCurType.eType + || TOX_OBJECTS== aCurType.eType) + { + // load all para styles... + m_xParaStyleLB->clear(); + SwWrtShell const& rWrtSh(static_cast<SwMultiTOXTabDialog*>(GetDialogController())->GetWrtShell()); + const sal_uInt16 nSz = rWrtSh.GetTextFormatCollCount(); + for (sal_uInt16 j = 0; j < nSz; ++j) + { + SwTextFormatColl const& rColl = rWrtSh.GetTextFormatColl(j); + if (rColl.IsDefault()) + continue; + + OUString const name(rColl.GetName()); + if (!name.isEmpty()) + { + m_xParaStyleLB->append_text(name); + } + } + // first, init ParaStyle - because any later init (e.g. m_xFromCaptionsRB) + // ends up calling FillTOXDescription() resetting rDesc! + OUString const& rStyle(rDesc.GetStyleNames(0)); + assert(rStyle.indexOf(TOX_STYLE_DELIMITER) == -1); + if (rStyle.isEmpty()) + { + m_xParaStyleCB->set_active(false); + m_xParaStyleLB->set_sensitive(false); + } + else + { + m_xParaStyleCB->set_active(true); + m_xParaStyleLB->set_sensitive(true); + m_xParaStyleLB->set_active_text(rStyle); + } + } + + //content + if(TOX_CONTENT == aCurType.eType) + { + m_xFromHeadingsCB->set_active( bool(nCreateType & SwTOXElement::OutlineLevel) ); + m_xAddStylesCB->set_label(m_sAddStyleContent); + m_xAddStylesPB->set_sensitive(m_xAddStylesCB->get_active()); + } + //index only + else if(TOX_INDEX == aCurType.eType) + { + const SwTOIOptions nIndexOptions = rDesc.GetIndexOptions(); + m_xCollectSameCB->set_active( bool(nIndexOptions & SwTOIOptions::SameEntry) ); + m_xUseFFCB->set_active( bool(nIndexOptions & SwTOIOptions::FF) ); + m_xUseDashCB->set_active( bool(nIndexOptions & SwTOIOptions::Dash) ); + if (m_xUseFFCB->get_active()) + m_xUseDashCB->set_sensitive(false); + else if (m_xUseDashCB->get_active()) + m_xUseFFCB->set_sensitive(false); + + m_xCaseSensitiveCB->set_active( bool(nIndexOptions & SwTOIOptions::CaseSensitive) ); + m_xInitialCapsCB->set_active( bool(nIndexOptions & SwTOIOptions::InitialCaps) ); + m_xKeyAsEntryCB->set_active( bool(nIndexOptions & SwTOIOptions::KeyAsEntry) ); + } + else if (TOX_ILLUSTRATIONS == aCurType.eType || TOX_TABLES == aCurType.eType) + { + OUString sName(rDesc.GetSequenceName()); + int nIndex = m_xCaptionSequenceLB->find_text(sName); + if (nIndex != -1) + m_xCaptionSequenceLB->set_active(nIndex); + m_xDisplayTypeLB->set_active(static_cast<sal_Int32>(rDesc.GetCaptionDisplay())); + if (m_xDisplayTypeLB->get_active() == -1) + m_xDisplayTypeLB->set_active(0); + m_xFromObjectNamesRB->set_active(rDesc.IsCreateFromObjectNames()); + m_xFromCaptionsRB->set_active(!rDesc.IsCreateFromObjectNames()); + RadioButtonHdl(*m_xFromCaptionsRB); + } + else if(TOX_OBJECTS == aCurType.eType) + { + SwTOOElements nOLEData = rDesc.GetOLEOptions(); + for (int nFromObj = 0, nCount = m_xFromObjCLB->n_children(); nFromObj < nCount; ++nFromObj) + { + SwTOOElements nData = static_cast<SwTOOElements>(m_xFromObjCLB->get_id(nFromObj).toInt32()); + m_xFromObjCLB->set_toggle(nFromObj, bool(nData & nOLEData) ? TRISTATE_TRUE : TRISTATE_FALSE); + } + } + else if(TOX_AUTHORITIES == aCurType.eType) + { + const OUString& sBrackets(rDesc.GetAuthBrackets()); + if(sBrackets.isEmpty() || sBrackets == " ") + m_xBracketLB->set_active(0); + else + m_xBracketLB->set_active_text(sBrackets); + m_xSequenceCB->set_active(rDesc.IsAuthSequence()); + } + m_xAutoMarkPB->set_sensitive(m_xFromFileCB->get_active()); + + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + m_aStyleArr[i] = rDesc.GetStyleNames(i); + + m_xLanguageLB->set_active_id(rDesc.GetLanguage()); + LanguageHdl(nullptr); + for (int nCnt = 0, nEntryCount = m_xSortAlgorithmLB->get_count(); nCnt < nEntryCount; ++nCnt) + { + const OUString& rEntryData = m_xSortAlgorithmLB->get_id(nCnt); + if (rEntryData == rDesc.GetSortAlgorithm()) + { + m_xSortAlgorithmLB->set_active(nCnt); + break; + } + } +} + +void SwTOXSelectTabPage::FillTOXDescription() +{ + SwMultiTOXTabDialog* pTOXDlg = static_cast<SwMultiTOXTabDialog*>(GetDialogController()); + CurTOXType aCurType = pTOXDlg->GetCurrentTOXType(); + SwTOXDescription& rDesc = pTOXDlg->GetTOXDescription(aCurType); + rDesc.SetTitle(m_xTitleED->get_text()); + rDesc.SetFromChapter(1 == m_xAreaLB->get_active()); + SwTOXElement nContentOptions = SwTOXElement::NONE; + if (m_xTOXMarksCB->get_visible() && m_xTOXMarksCB->get_active()) + nContentOptions |= SwTOXElement::Mark; + + SwTOIOptions nIndexOptions = rDesc.GetIndexOptions()&SwTOIOptions::AlphaDelimiter; + switch(rDesc.GetTOXType()) + { + case TOX_CONTENT: + if(m_xFromHeadingsCB->get_active()) + nContentOptions |= SwTOXElement::OutlineLevel; + break; + case TOX_USER: + { + rDesc.SetTOUName(m_xTypeLB->get_active_text()); + + if(m_xFromOLECB->get_active()) + nContentOptions |= SwTOXElement::Ole; + if(m_xFromTablesCB->get_active()) + nContentOptions |= SwTOXElement::Table; + if(m_xFromFramesCB->get_active()) + nContentOptions |= SwTOXElement::Frame; + if(m_xFromGraphicsCB->get_active()) + nContentOptions |= SwTOXElement::Graphic; + } + break; + case TOX_INDEX: + { + nContentOptions = SwTOXElement::Mark; + + if(m_xCollectSameCB->get_active()) + nIndexOptions |= SwTOIOptions::SameEntry; + if(m_xUseFFCB->get_active()) + nIndexOptions |= SwTOIOptions::FF; + if(m_xUseDashCB->get_active()) + nIndexOptions |= SwTOIOptions::Dash; + if(m_xCaseSensitiveCB->get_active()) + nIndexOptions |= SwTOIOptions::CaseSensitive; + if(m_xInitialCapsCB->get_active()) + nIndexOptions |= SwTOIOptions::InitialCaps; + if(m_xKeyAsEntryCB->get_active()) + nIndexOptions |= SwTOIOptions::KeyAsEntry; + if(m_xFromFileCB->get_active()) + rDesc.SetAutoMarkURL(m_sAutoMarkURL); + else + rDesc.SetAutoMarkURL(OUString()); + } + break; + case TOX_ILLUSTRATIONS: + case TOX_TABLES : + rDesc.SetCreateFromObjectNames(m_xFromObjectNamesRB->get_active()); + rDesc.SetSequenceName(m_xCaptionSequenceLB->get_active_text()); + rDesc.SetCaptionDisplay(static_cast<SwCaptionDisplay>(m_xDisplayTypeLB->get_active())); + if (m_xParaStyleCB->get_active()) + { + m_aStyleArr[0] = m_xParaStyleLB->get_active_text(); + } + else + { + m_aStyleArr[0] = OUString(); + } + break; + case TOX_OBJECTS: + { + SwTOOElements nOLEData = SwTOOElements::NONE; + for (int i = 0, nCount = m_xFromObjCLB->n_children(); i < nCount; ++i) + { + if (m_xFromObjCLB->get_toggle(i) == TRISTATE_TRUE) + { + SwTOOElements nData = static_cast<SwTOOElements>(m_xFromObjCLB->get_id(i).toInt32()); + nOLEData |= nData; + } + } + rDesc.SetOLEOptions(nOLEData); + if (m_xParaStyleCB->get_active()) + { + m_aStyleArr[0] = m_xParaStyleLB->get_active_text(); + } + else + { + m_aStyleArr[0] = OUString(); + } + } + break; + case TOX_AUTHORITIES: + case TOX_BIBLIOGRAPHY : + { + if (m_xBracketLB->get_active()) + rDesc.SetAuthBrackets(m_xBracketLB->get_active_text()); + else + rDesc.SetAuthBrackets(OUString()); + rDesc.SetAuthSequence(m_xSequenceCB->get_active()); + } + break; + case TOX_CITATION : + break; + } + + rDesc.SetLevelFromChapter( m_xLevelFromChapterCB->get_visible() && + m_xLevelFromChapterCB->get_active()); + if (m_xTOXMarksCB->get_active() && m_xTOXMarksCB->get_visible()) + nContentOptions |= SwTOXElement::Mark; + if (m_xFromHeadingsCB->get_active() && m_xFromHeadingsCB->get_visible()) + nContentOptions |= SwTOXElement::OutlineLevel; + if ((m_xAddStylesCB->get_active() && m_xAddStylesCB->get_visible()) + || (m_xParaStyleCB->get_active() && m_xParaStyleCB->get_visible())) + { + nContentOptions |= SwTOXElement::Template; + } + + rDesc.SetContentOptions(nContentOptions); + rDesc.SetIndexOptions(nIndexOptions); + rDesc.SetLevel(m_xLevelNF->get_value()); + + rDesc.SetReadonly(m_xReadOnlyCB->get_active()); + + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + rDesc.SetStyleNames(m_aStyleArr[i], i); + + rDesc.SetLanguage(m_xLanguageLB->get_active_id()); + const OUString& rEntryData = m_xSortAlgorithmLB->get_active_id(); + rDesc.SetSortAlgorithm(rEntryData); +} + +void SwTOXSelectTabPage::Reset( const SfxItemSet* ) +{ + SwMultiTOXTabDialog* pTOXDlg = static_cast<SwMultiTOXTabDialog*>(GetDialogController()); + SwWrtShell& rSh = pTOXDlg->GetWrtShell(); + const CurTOXType aCurType = pTOXDlg->GetCurrentTOXType(); + sal_uInt32 nData = lcl_TOXTypesToUserData(aCurType); + m_xTypeLB->set_active_id(OUString::number(nData)); + + m_sAutoMarkURL = INetURLObject::decode( rSh.GetTOIAutoMarkURL(), + INetURLObject::DecodeMechanism::Unambiguous ); + m_xFromFileCB->set_active(!m_sAutoMarkURL.isEmpty()); + + m_xCaptionSequenceLB->clear(); + const size_t nCount = rSh.GetFieldTypeCount(SwFieldIds::SetExp); + for (size_t i = 0; i < nCount; ++i) + { + SwFieldType *pType = rSh.GetFieldType( i, SwFieldIds::SetExp ); + if( pType->Which() == SwFieldIds::SetExp && + static_cast<SwSetExpFieldType *>( pType)->GetType() & nsSwGetSetExpType::GSE_SEQ ) + m_xCaptionSequenceLB->append_text(pType->GetName()); + } + + if(pTOXDlg->IsTOXEditMode()) + { + m_xTypeFT->set_sensitive(false); + m_xTypeLB->set_sensitive(false); + } + + if(!m_bWaitingInitialSettings) + { + // save current values into the proper TOXDescription + FillTOXDescription(); + } + m_bWaitingInitialSettings = false; + + TOXTypeHdl(*m_xTypeLB); + CheckBoxHdl(*m_xAddStylesCB); +} + +void SwTOXSelectTabPage::ActivatePage( const SfxItemSet& ) +{ + //nothing to do +} + +DeactivateRC SwTOXSelectTabPage::DeactivatePage(SfxItemSet* _pSet) +{ + if (_pSet) + _pSet->Put(SfxUInt16Item(FN_PARAM_TOX_TYPE, m_xTypeLB->get_active_id().toUInt32())); + FillTOXDescription(); + return DeactivateRC::LeavePage; +} + +std::unique_ptr<SfxTabPage> SwTOXSelectTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwTOXSelectTabPage>(pPage, pController, *rAttrSet); +} + +IMPL_LINK(SwTOXSelectTabPage, TOXTypeHdl, weld::ComboBox&, rBox, void) +{ + SwMultiTOXTabDialog* pTOXDlg = static_cast<SwMultiTOXTabDialog*>(GetDialogController()); + const sal_uInt16 nType = rBox.get_active_id().toUInt32(); + CurTOXType eCurType = lcl_UserData2TOXTypes(nType); + pTOXDlg->SetCurrentTOXType(eCurType); + + m_xAreaLB->set_visible( 0 != (nType & (TO_CONTENT|TO_ILLUSTRATION|TO_USER|TO_INDEX|TO_TABLE|TO_OBJECT)) ); + m_xLevelFT->set_visible( 0 != (nType & (TO_CONTENT)) ); + m_xLevelNF->set_visible( 0 != (nType & (TO_CONTENT)) ); + m_xLevelFromChapterCB->set_visible( 0 != (nType & (TO_USER)) ); + m_xAreaFrame->set_visible( 0 != (nType & (TO_CONTENT|TO_ILLUSTRATION|TO_USER|TO_INDEX|TO_TABLE|TO_OBJECT)) ); + + m_xFromHeadingsCB->set_visible( 0 != (nType & (TO_CONTENT)) ); + m_xAddStylesCB->set_visible( 0 != (nType & (TO_CONTENT|TO_USER)) ); + m_xAddStylesPB->set_visible( 0 != (nType & (TO_CONTENT|TO_USER)) ); + + m_xFromTablesCB->set_visible( 0 != (nType & (TO_USER)) ); + m_xFromFramesCB->set_visible( 0 != (nType & (TO_USER)) ); + m_xFromGraphicsCB->set_visible( 0 != (nType & (TO_USER)) ); + m_xFromOLECB->set_visible( 0 != (nType & (TO_USER)) ); + + m_xFromCaptionsRB->set_visible( 0 != (nType & (TO_ILLUSTRATION|TO_TABLE)) ); + m_xFromObjectNamesRB->set_visible( 0 != (nType & (TO_ILLUSTRATION|TO_TABLE)) ); + + m_xTOXMarksCB->set_visible( 0 != (nType & (TO_CONTENT|TO_USER)) ); + + m_xCreateFrame->set_visible( 0 != (nType & (TO_CONTENT|TO_ILLUSTRATION|TO_USER|TO_TABLE)) ); + m_xCaptionSequenceFT->set_visible( 0 != (nType & (TO_ILLUSTRATION|TO_TABLE)) ); + m_xCaptionSequenceLB->set_visible( 0 != (nType & (TO_ILLUSTRATION|TO_TABLE)) ); + m_xDisplayTypeFT->set_visible( 0 != (nType & (TO_ILLUSTRATION|TO_TABLE)) ); + m_xDisplayTypeLB->set_visible( 0 != (nType & (TO_ILLUSTRATION|TO_TABLE)) ); + m_xParaStyleCB->set_visible(0 != (nType & (TO_ILLUSTRATION|TO_TABLE|TO_OBJECT))); + m_xParaStyleLB->set_visible(0 != (nType & (TO_ILLUSTRATION|TO_TABLE|TO_OBJECT))); + + m_xAuthorityFrame->set_visible( 0 != (nType & TO_AUTHORITIES) ); + + bool bEnableSortLanguage = 0 != (nType & (TO_INDEX|TO_AUTHORITIES)); + m_xSortFrame->set_visible(bEnableSortLanguage); + + if( nType & TO_ILLUSTRATION ) + { + OUString sName(SwStyleNameMapper::GetUIName(RES_POOLCOLL_LABEL_FIGURE, OUString())); + m_xCaptionSequenceLB->set_active_text(sName); + } + else if( nType & TO_TABLE ) + { + OUString sName(SwStyleNameMapper::GetUIName(RES_POOLCOLL_LABEL_TABLE, OUString())); + m_xCaptionSequenceLB->set_active_text(sName); + } + else if( nType & TO_USER ) + { + m_xAddStylesCB->set_label(m_sAddStyleUser); + } + + m_xIdxOptionsFrame->set_visible( 0 != (nType & TO_INDEX) ); + + //object index + m_xFromObjFrame->set_visible( 0 != (nType & TO_OBJECT) ); + + //set control values from the proper TOXDescription + { + ApplyTOXDescription(); + } + ModifyHdl(); +} + +void SwTOXSelectTabPage::ModifyHdl() +{ + if(!m_bWaitingInitialSettings) + { + FillTOXDescription(); + SwMultiTOXTabDialog* pTOXDlg = static_cast<SwMultiTOXTabDialog*>(GetDialogController()); + pTOXDlg->CreateOrUpdateExample(pTOXDlg->GetCurrentTOXType().eType, TOX_PAGE_SELECT); + } +} + +IMPL_LINK_NOARG(SwTOXSelectTabPage, ModifyListBoxHdl, weld::ComboBox&, void) +{ + ModifyHdl(); +} + +IMPL_LINK_NOARG(SwTOXSelectTabPage, ModifyEntryHdl, weld::Entry&, void) +{ + ModifyHdl(); +} + +IMPL_LINK_NOARG(SwTOXSelectTabPage, ModifySpinHdl, weld::SpinButton&, void) +{ + ModifyHdl(); +} + +IMPL_LINK(SwTOXSelectTabPage, CheckBoxHdl, weld::Toggleable&, rButton, void) +{ + SwMultiTOXTabDialog* pTOXDlg = static_cast<SwMultiTOXTabDialog*>(GetDialogController()); + const CurTOXType aCurType = pTOXDlg->GetCurrentTOXType(); + if(TOX_CONTENT == aCurType.eType) + { + //at least one of the three CheckBoxes must be checked + if (!m_xAddStylesCB->get_active() && !m_xFromHeadingsCB->get_active() && !m_xTOXMarksCB->get_active()) + { + //TODO: InfoBox? + rButton.set_active(true); + } + m_xAddStylesPB->set_sensitive(m_xAddStylesCB->get_active()); + } + if (TOX_USER == aCurType.eType) + { + m_xAddStylesPB->set_sensitive(m_xAddStylesCB->get_active()); + } + else if (TOX_INDEX == aCurType.eType) + { + m_xAutoMarkPB->set_sensitive(m_xFromFileCB->get_active()); + m_xUseFFCB->set_sensitive(m_xCollectSameCB->get_active() && !m_xUseDashCB->get_active()); + m_xUseDashCB->set_sensitive(m_xCollectSameCB->get_active() && !m_xUseFFCB->get_active()); + m_xCaseSensitiveCB->set_sensitive(m_xCollectSameCB->get_active()); + } + else if (TOX_ILLUSTRATIONS == aCurType.eType + || TOX_TABLES == aCurType.eType + || TOX_OBJECTS == aCurType.eType) + { + bool const bEnable(m_xParaStyleCB->get_active()); + m_xParaStyleLB->set_sensitive(bEnable); + } + ModifyHdl(); +}; + +IMPL_LINK_NOARG(SwTOXSelectTabPage, RadioButtonHdl, weld::Toggleable&, void) +{ + bool bEnable = m_xFromCaptionsRB->get_active(); + m_xCaptionSequenceFT->set_sensitive(bEnable); + m_xCaptionSequenceLB->set_sensitive(bEnable); + m_xDisplayTypeFT->set_sensitive(bEnable); + m_xDisplayTypeLB->set_sensitive(bEnable); + ModifyHdl(); +} + +IMPL_LINK(SwTOXSelectTabPage, LanguageListBoxHdl, weld::ComboBox&, rBox, void) +{ + LanguageHdl(&rBox); +} + +void SwTOXSelectTabPage::LanguageHdl(const weld::ComboBox* pBox) +{ + lang::Locale aLcl( LanguageTag( m_xLanguageLB->get_active_id() ).getLocale() ); + Sequence< OUString > aSeq = m_pIndexEntryWrapper->GetAlgorithmList( aLcl ); + + if( !m_pIndexRes ) + m_pIndexRes.reset(new IndexEntryResource()); + + OUString sOldString = m_xSortAlgorithmLB->get_active_id(); + m_xSortAlgorithmLB->clear(); + + sal_Int32 nEnd = aSeq.getLength(); + for( sal_Int32 nCnt = 0; nCnt < nEnd; ++nCnt ) + { + const OUString sAlg(aSeq[ nCnt ]); + const OUString sUINm = m_pIndexRes->GetTranslation( sAlg ); + m_xSortAlgorithmLB->append(sAlg, sUINm); + if( sAlg == sOldString ) + m_xSortAlgorithmLB->set_active(nCnt); + } + + if (m_xSortAlgorithmLB->get_active() == -1) + m_xSortAlgorithmLB->set_active(0); + + if (pBox) + ModifyHdl(); +}; + +IMPL_LINK_NOARG(SwTOXSelectTabPage, AddStylesHdl, weld::Button&, void) +{ + SwAddStylesDlg_Impl aDlg(GetFrameWeld(), static_cast<SwMultiTOXTabDialog*>(GetDialogController())->GetWrtShell(), + m_aStyleArr); + aDlg.run(); + ModifyHdl(); +} + +IMPL_LINK_NOARG(SwTOXSelectTabPage, MenuEnableHdl, weld::Toggleable&, void) +{ + m_xAutoMarkPB->set_item_sensitive("edit", !m_sAutoMarkURL.isEmpty()); +} + +IMPL_LINK(SwTOXSelectTabPage, MenuExecuteHdl, const OUString&, rIdent, void) +{ + const OUString sSaveAutoMarkURL = m_sAutoMarkURL; + + if (rIdent == "open") + { + m_sAutoMarkURL = lcl_CreateAutoMarkFileDlg(GetFrameWeld(), + m_sAutoMarkURL, m_sAutoMarkType, true); + } + else if (rIdent == "new" || rIdent == "edit") + { + bool bNew = (rIdent == "new"); + if (bNew) + { + m_sAutoMarkURL = lcl_CreateAutoMarkFileDlg(GetFrameWeld(), + m_sAutoMarkURL, m_sAutoMarkType, false); + if (m_sAutoMarkURL.isEmpty()) + return; + } + + SwAutoMarkDlg_Impl aAutoMarkDlg(GetFrameWeld(), m_sAutoMarkURL, bNew); + if (RET_OK != aAutoMarkDlg.run() && bNew) + m_sAutoMarkURL = sSaveAutoMarkURL; + } +} + +class SwTOXWidget +{ +protected: + Link<SwTOXWidget&,void> m_aGetFocusLink; +public: + virtual WindowType GetType() const = 0; + virtual void GrabFocus() = 0; + virtual void Hide() = 0; + virtual void set_grid_left_attach(int nPos) = 0; + virtual void get_extents_relative_to(weld::Widget& rRelative, int& x, int& y, int& width, int& height) = 0; + void SetGetFocusHdl(const Link<SwTOXWidget&,void>& rLink) { m_aGetFocusLink = rLink; } + virtual ~SwTOXWidget() {} +}; + +class SwTOXEdit : public SwTOXWidget +{ + std::unique_ptr<weld::Builder> m_xBuilder; + SwFormToken m_aFormToken; + Link<SwTOXEdit&,void> m_aModifiedLink; + Link<SwTOXEdit&,void> m_aPrevNextControlLink; + bool m_bNextControl; + SwTokenWindow* m_pParent; + std::unique_ptr<weld::Entry> m_xEntry; + + DECL_LINK(ModifyHdl, weld::Entry&, void); +public: + SwTOXEdit(SwTokenWindow* pTokenWin, const SwFormToken& rToken) + : m_xBuilder(Application::CreateBuilder(pTokenWin->get_child_container(), "modules/swriter/ui/toxentrywidget.ui")) + , m_aFormToken(rToken) + , m_bNextControl(false) + , m_pParent(pTokenWin) + , m_xEntry(m_xBuilder->weld_entry("entry")) + { + m_xEntry->connect_changed(LINK(this, SwTOXEdit, ModifyHdl)); + m_xEntry->connect_key_press(LINK(this, SwTOXEdit, KeyInputHdl)); + m_xEntry->connect_focus_in(LINK(this, SwTOXEdit, FocusInHdl)); + m_xEntry->set_tooltip_text(m_pParent->CreateQuickHelp(rToken)); + } + + virtual ~SwTOXEdit() override + { + m_pParent->get_child_container()->move(m_xEntry.get(), nullptr); + } + + virtual WindowType GetType() const override + { + return WindowType::EDIT; + } + + virtual void GrabFocus() override + { + m_xEntry->grab_focus(); + } + + virtual void Hide() override + { + m_xEntry->hide(); + } + + void Show() + { + m_xEntry->show(); + } + + void SetAccessibleName(const OUString& rName) + { + m_xEntry->set_accessible_name(rName); + } + + virtual void set_grid_left_attach(int nPos) override + { + m_xEntry->set_grid_left_attach(nPos); + } + + virtual void get_extents_relative_to(weld::Widget& rRelative, int& x, int& y, int& width, int& height) override + { + m_xEntry->get_extents_relative_to(rRelative, x, y, width, height); + } + + OUString GetText() const + { + return m_xEntry->get_text(); + } + + void SetText(const OUString& rText) + { + m_xEntry->set_text(rText); + } + + void get_selection_bounds(int& rStartPos, int& rEndPos) + { + m_xEntry->get_selection_bounds(rStartPos, rEndPos); + } + + void select_region(int nStartPos, int nEndPos) + { + m_xEntry->select_region(nStartPos, nEndPos); + } + + void SetModifyHdl(const Link<SwTOXEdit&,void>& rLink) + { + m_aModifiedLink = rLink; + } + + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(FocusInHdl, weld::Widget&, void); + + bool IsNextControl() const { return m_bNextControl; } + void SetPrevNextLink(const Link<SwTOXEdit&,void>& rLink) { m_aPrevNextControlLink = rLink; } + + const SwFormToken& GetFormToken() + { + m_aFormToken.sText = m_xEntry->get_text(); + return m_aFormToken; + } + + void SetCharStyleName(const OUString& rSet, sal_uInt16 nPoolId) + { + m_aFormToken.sCharStyleName = rSet; + m_aFormToken.nPoolId = nPoolId; + } + + void AdjustSize(); +}; + +IMPL_LINK_NOARG(SwTOXEdit, ModifyHdl, weld::Entry&, void) +{ + m_aModifiedLink.Call(*this); +} + +IMPL_LINK(SwTOXEdit, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + bool bCall = false; + int nStartPos, nEndPos; + bool bStartIsEnd = !m_xEntry->get_selection_bounds(nStartPos, nEndPos); + int nMin = std::min(nStartPos, nEndPos); + const sal_Int32 nTextLen = GetText().getLength(); + if ((bStartIsEnd && !nMin) || nMin == nTextLen) + { + vcl::KeyCode aCode = rKEvt.GetKeyCode(); + if (aCode.GetCode() == KEY_RIGHT && nMin == nTextLen) + { + m_bNextControl = true; + bCall = true; + } + else if (aCode.GetCode() == KEY_LEFT && !nMin) + { + m_bNextControl = false; + bCall = true; + } + else if ( (aCode.GetCode() == KEY_F3) && aCode.IsShift() && !aCode.IsMod1() && !aCode.IsMod2() ) + { + if (m_pParent) + { + m_pParent->SetFocus2theAllBtn(); + } + } + if (bCall && m_aPrevNextControlLink.IsSet()) + m_aPrevNextControlLink.Call(*this); + else + bCall = false; + + } + return bCall; +} + +IMPL_LINK_NOARG(SwTOXEdit, FocusInHdl, weld::Widget&, void) +{ + m_aGetFocusLink.Call(*this); +} + +void SwTOXEdit::AdjustSize() +{ + auto nWidth = m_xEntry->get_pixel_size(GetText()).Width(); + float fChars = nWidth / m_xEntry->get_approximate_digit_width(); + m_xEntry->set_width_chars(std::max(1.0f, std::ceil(fChars))); +} + +class SwTOXButton : public SwTOXWidget +{ + std::unique_ptr<weld::Builder> m_xBuilder; + SwFormToken m_aFormToken; + Link<SwTOXButton&,void> m_aPrevNextControlLink; + bool m_bNextControl; + SwTokenWindow* m_pParent; + std::unique_ptr<weld::ToggleButton> m_xButton; +public: + SwTOXButton(SwTokenWindow* pTokenWin, const SwFormToken& rToken) + : m_xBuilder(Application::CreateBuilder(pTokenWin->get_child_container(), "modules/swriter/ui/toxbuttonwidget.ui")) + , m_aFormToken(rToken) + , m_bNextControl(false) + , m_pParent(pTokenWin) + , m_xButton(m_xBuilder->weld_toggle_button("button")) + { + m_xButton->connect_key_press(LINK(this, SwTOXButton, KeyInputHdl)); + m_xButton->connect_focus_in(LINK(this, SwTOXButton, FocusInHdl)); + m_xButton->set_tooltip_text(m_pParent->CreateQuickHelp(rToken)); + } + + virtual ~SwTOXButton() override + { + m_pParent->get_child_container()->move(m_xButton.get(), nullptr); + } + + virtual WindowType GetType() const override + { + return WindowType::PUSHBUTTON; + } + + virtual void GrabFocus() override + { + m_xButton->grab_focus(); + } + + virtual void Hide() override + { + m_xButton->hide(); + } + + void Show() + { + m_xButton->show(); + } + + void SetAccessibleName(const OUString& rName) + { + m_xButton->set_accessible_name(rName); + } + + virtual void set_grid_left_attach(int nPos) override + { + m_xButton->set_grid_left_attach(nPos); + } + + void get_extents_relative_to(weld::Widget& rRelative, int& x, int& y, int& width, int& height) override + { + m_xButton->get_extents_relative_to(rRelative, x, y, width, height); + } + + void Check(bool bCheck = true) + { + m_xButton->set_active(bCheck); + } + + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(FocusInHdl, weld::Widget&, void); + + bool IsNextControl() const {return m_bNextControl;} + void SetPrevNextLink(const Link<SwTOXButton&,void>& rLink) {m_aPrevNextControlLink = rLink;} + const SwFormToken& GetFormToken() const {return m_aFormToken;} + + void SetCharStyleName(const OUString& rSet, sal_uInt16 nPoolId) + { + m_aFormToken.sCharStyleName = rSet; + m_aFormToken.nPoolId = nPoolId; + } + + void SetTabPosition(SwTwips nSet) + { m_aFormToken.nTabStopPosition = nSet; } + + void SetFillChar( sal_Unicode cSet ) + { m_aFormToken.cTabFillChar = cSet; } + + void SetTabAlign(SvxTabAdjust eAlign) + { m_aFormToken.eTabAlign = eAlign;} + +//---> i89791 + //used for entry number format, in TOC only + //needed for different UI dialog position + void SetEntryNumberFormat(sal_uInt16 nSet) { + switch(nSet) + { + default: + case 0: + m_aFormToken.nChapterFormat = CF_NUMBER; + break; + case 1: + m_aFormToken.nChapterFormat = CF_NUM_NOPREPST_TITLE; + break; + } + } + + void SetChapterInfo(sal_uInt16 nSet) { + switch(nSet) + { + default: + case 0: + m_aFormToken.nChapterFormat = CF_NUM_NOPREPST_TITLE; + break; + case 1: + m_aFormToken.nChapterFormat = CF_TITLE; + break; + case 2: + m_aFormToken.nChapterFormat = CF_NUMBER_NOPREPST; + break; + } + } + + void SetOutlineLevel( sal_uInt16 nSet ) { m_aFormToken.nOutlineLevel = nSet;}//i53420 + + void SetText(const OUString& rText) + { + m_xButton->set_label(rText); + } + + void SetLinkEnd() + { + OSL_ENSURE(TOKEN_LINK_START == m_aFormToken.eTokenType, + "call SetLinkEnd for link start only!"); + m_aFormToken.eTokenType = TOKEN_LINK_END; + m_aFormToken.sText = SwForm::GetFormLinkEnd(); + SetText(m_aFormToken.sText); + } + + void SetLinkStart() + { + OSL_ENSURE(TOKEN_LINK_END == m_aFormToken.eTokenType, + "call SetLinkStart for link start only!"); + m_aFormToken.eTokenType = TOKEN_LINK_START; + m_aFormToken.sText = SwForm::GetFormLinkStt(); + SetText(m_aFormToken.sText); + } +}; + +IMPL_LINK(SwTOXButton, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + bool bCall = false; + vcl::KeyCode aCode = rKEvt.GetKeyCode(); + if (aCode.GetCode() == KEY_RIGHT) + { + m_bNextControl = true; + bCall = true; + } + else if (aCode.GetCode() == KEY_LEFT) + { + m_bNextControl = false; + bCall = true; + } + else if (aCode.GetCode() == KEY_DELETE) + { + m_pParent->RemoveControl(this, true); + //this is invalid here + return true; + } + else if ( (aCode.GetCode() == KEY_F3) && aCode.IsShift() && !aCode.IsMod1() && !aCode.IsMod2() ) + { + if (m_pParent) + { + m_pParent->SetFocus2theAllBtn(); + } + } + if (bCall && m_aPrevNextControlLink.IsSet()) + m_aPrevNextControlLink.Call(*this); + else + bCall = false; + return bCall; +} + +IMPL_LINK_NOARG(SwTOXButton, FocusInHdl, weld::Widget&, void) +{ + m_aGetFocusLink.Call(*this); +} + +namespace +{ + const TranslateId STR_AUTH_FIELD_ARY[] = + { + STR_AUTH_FIELD_IDENTIFIER, + STR_AUTH_FIELD_AUTHORITY_TYPE, + STR_AUTH_FIELD_ADDRESS, + STR_AUTH_FIELD_ANNOTE, + STR_AUTH_FIELD_AUTHOR, + STR_AUTH_FIELD_BOOKTITLE, + STR_AUTH_FIELD_CHAPTER, + STR_AUTH_FIELD_EDITION, + STR_AUTH_FIELD_EDITOR, + STR_AUTH_FIELD_HOWPUBLISHED, + STR_AUTH_FIELD_INSTITUTION, + STR_AUTH_FIELD_JOURNAL, + STR_AUTH_FIELD_MONTH, + STR_AUTH_FIELD_NOTE, + STR_AUTH_FIELD_NUMBER, + STR_AUTH_FIELD_ORGANIZATIONS, + STR_AUTH_FIELD_PAGES, + STR_AUTH_FIELD_PUBLISHER, + STR_AUTH_FIELD_SCHOOL, + STR_AUTH_FIELD_SERIES, + STR_AUTH_FIELD_TITLE, + STR_AUTH_FIELD_TYPE, + STR_AUTH_FIELD_VOLUME, + STR_AUTH_FIELD_YEAR, + STR_AUTH_FIELD_URL, + STR_AUTH_FIELD_CUSTOM1, + STR_AUTH_FIELD_CUSTOM2, + STR_AUTH_FIELD_CUSTOM3, + STR_AUTH_FIELD_CUSTOM4, + STR_AUTH_FIELD_CUSTOM5, + STR_AUTH_FIELD_ISBN, + STR_AUTH_FIELD_LOCAL_URL, + STR_AUTH_FIELD_TARGET_TYPE, + STR_AUTH_FIELD_TARGET_URL, + }; +} + +SwTOXEntryTabPage::SwTOXEntryTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/tocentriespage.ui", "TocEntriesPage", &rAttrSet) + , m_sDelimStr(SwResId(STR_DELIM)) + , m_sNoCharStyle(SwResId(STR_NO_CHAR_STYLE)) + , m_pCurrentForm(nullptr) + , m_bInLevelHdl(false) + , m_xTypeFT(m_xBuilder->weld_label("typeft")) + , m_xLevelFT(m_xBuilder->weld_label("levelft")) + , m_xLevelLB(m_xBuilder->weld_tree_view("level")) + , m_xAllLevelsPB(m_xBuilder->weld_button("all")) + , m_xEntryNoPB(m_xBuilder->weld_button("chapterno")) + , m_xEntryPB(m_xBuilder->weld_button("entrytext")) + , m_xTabPB(m_xBuilder->weld_button("tabstop")) + , m_xChapterInfoPB(m_xBuilder->weld_button("chapterinfo")) + , m_xPageNoPB(m_xBuilder->weld_button("pageno")) + , m_xHyperLinkPB(m_xBuilder->weld_button("hyperlink")) + , m_xFieldBox(m_xBuilder->weld_widget("fieldbox")) + , m_xAuthFieldsLB(m_xBuilder->weld_combo_box("authfield")) + , m_xAuthInsertPB(m_xBuilder->weld_button("insert")) + , m_xAuthRemovePB(m_xBuilder->weld_button("remove")) + , m_xCharStyleLB(m_xBuilder->weld_combo_box("charstyle")) + , m_xEditStylePB(m_xBuilder->weld_button("edit")) + , m_xChapterEntryFT(m_xBuilder->weld_label("chapterentryft")) + , m_xChapterEntryLB(m_xBuilder->weld_combo_box("chapterentry")) + , m_xNumberFormatFT(m_xBuilder->weld_label("numberformatft")) + , m_xNumberFormatLB(m_xBuilder->weld_combo_box("numberformat")) + , m_xEntryOutlineLevelFT(m_xBuilder->weld_label("entryoutlinelevelft")) + , m_xEntryOutlineLevelNF(m_xBuilder->weld_spin_button("entryoutlinelevel")) + , m_xFillCharFT(m_xBuilder->weld_label("fillcharft")) + , m_xFillCharCB(m_xBuilder->weld_combo_box("fillchar")) + , m_xTabPosFT(m_xBuilder->weld_label("tabstopposft")) + , m_xTabPosMF(m_xBuilder->weld_metric_spin_button("tabstoppos", FieldUnit::CM)) + , m_xAutoRightCB(m_xBuilder->weld_check_button("alignright")) + , m_xFormatFrame(m_xBuilder->weld_widget("formatframe")) + , m_xMainEntryStyleFT(m_xBuilder->weld_label("mainstyleft")) + , m_xMainEntryStyleLB(m_xBuilder->weld_combo_box("mainstyle")) + , m_xAlphaDelimCB(m_xBuilder->weld_check_button("alphadelim")) + , m_xCommaSeparatedCB(m_xBuilder->weld_check_button("commasep")) + , m_xRelToStyleCB(m_xBuilder->weld_check_button("reltostyle")) + , m_xSortingFrame(m_xBuilder->weld_widget("sortingframe")) + , m_xSortDocPosRB(m_xBuilder->weld_radio_button("sortpos")) + , m_xSortContentRB(m_xBuilder->weld_radio_button("sortcontents")) + , m_xSortKeyFrame(m_xBuilder->weld_widget("sortkeyframe")) + , m_xFirstKeyLB(m_xBuilder->weld_combo_box("key1lb")) + , m_xFirstSortUpRB(m_xBuilder->weld_toggle_button("up1cb")) + , m_xFirstSortDownRB(m_xBuilder->weld_toggle_button("down1cb")) + , m_xSecondKeyLB(m_xBuilder->weld_combo_box("key2lb")) + , m_xSecondSortUpRB(m_xBuilder->weld_toggle_button("up2cb")) + , m_xSecondSortDownRB(m_xBuilder->weld_toggle_button("down2cb")) + , m_xThirdKeyLB(m_xBuilder->weld_combo_box("key3lb")) + , m_xThirdSortUpRB(m_xBuilder->weld_toggle_button("up3cb")) + , m_xThirdSortDownRB(m_xBuilder->weld_toggle_button("down3cb")) + , m_xTokenWIN(new SwTokenWindow(m_xBuilder->weld_container("token"))) +{ + const OUString sNoCharSortKey(SwResId(STR_NOSORTKEY)); + + m_sAuthTypeStr = m_xTypeFT->get_label(); + m_sLevelStr = m_xLevelFT->get_label(); + m_xAuthFieldsLB->make_sorted(); + m_xTokenWIN->SetTabPage(this); + + m_aLastTOXType.eType = TOXTypes(USHRT_MAX); + m_aLastTOXType.nIndex = 0; + + SetExchangeSupport(); + m_xEntryNoPB->connect_clicked(LINK(this, SwTOXEntryTabPage, InsertTokenHdl)); + m_xEntryPB->connect_clicked(LINK(this, SwTOXEntryTabPage, InsertTokenHdl)); + m_xChapterInfoPB->connect_clicked(LINK(this, SwTOXEntryTabPage, InsertTokenHdl)); + m_xPageNoPB->connect_clicked(LINK(this, SwTOXEntryTabPage, InsertTokenHdl)); + m_xTabPB->connect_clicked(LINK(this, SwTOXEntryTabPage, InsertTokenHdl)); + m_xHyperLinkPB->connect_clicked(LINK(this, SwTOXEntryTabPage, InsertTokenHdl)); + m_xEditStylePB->connect_clicked(LINK(this, SwTOXEntryTabPage, EditStyleHdl)); + m_xLevelLB->connect_changed(LINK(this, SwTOXEntryTabPage, LevelHdl)); + m_xTokenWIN->SetButtonSelectedHdl(LINK(this, SwTOXEntryTabPage, TokenSelectedHdl)); + m_xTokenWIN->SetModifyHdl(LINK(this, SwTOXEntryTabPage, ModifyHdl)); + m_xCharStyleLB->connect_changed(LINK(this, SwTOXEntryTabPage, StyleSelectHdl)); + m_xCharStyleLB->append_text(m_sNoCharStyle); + m_xChapterEntryLB->connect_changed(LINK(this, SwTOXEntryTabPage, ChapterInfoHdl)); + m_xEntryOutlineLevelNF->connect_value_changed(LINK(this, SwTOXEntryTabPage, ChapterInfoOutlineHdl)); + m_xNumberFormatLB->connect_changed(LINK(this, SwTOXEntryTabPage, NumberFormatHdl)); + + m_xTabPosMF->connect_value_changed(LINK(this, SwTOXEntryTabPage, TabPosHdl)); + m_xFillCharCB->connect_changed(LINK(this, SwTOXEntryTabPage, FillCharHdl)); + m_xAutoRightCB->connect_toggled(LINK(this, SwTOXEntryTabPage, AutoRightHdl)); + m_xAuthInsertPB->connect_clicked(LINK(this, SwTOXEntryTabPage, RemoveInsertAuthHdl)); + m_xAuthRemovePB->connect_clicked(LINK(this, SwTOXEntryTabPage, RemoveInsertAuthHdl)); + m_xSortDocPosRB->connect_toggled(LINK(this, SwTOXEntryTabPage, SortKeyHdl)); + m_xSortContentRB->connect_toggled(LINK(this, SwTOXEntryTabPage, SortKeyHdl)); + m_xAllLevelsPB->connect_clicked(LINK(this, SwTOXEntryTabPage, AllLevelsHdl)); + + m_xAlphaDelimCB->connect_toggled(LINK(this, SwTOXEntryTabPage, ModifyClickHdl)); + m_xCommaSeparatedCB->connect_toggled(LINK(this, SwTOXEntryTabPage, ModifyClickHdl)); + m_xRelToStyleCB->connect_toggled(LINK(this, SwTOXEntryTabPage, ModifyClickHdl)); + + m_xFirstSortUpRB->set_active(true); + m_xSecondSortUpRB->set_active(true); + m_xThirdSortUpRB->set_active(true); + + m_xFirstSortUpRB->connect_toggled(LINK(this, SwTOXEntryTabPage, ToggleHdl)); + m_xFirstSortDownRB->connect_toggled(LINK(this, SwTOXEntryTabPage, ToggleHdl)); + m_xSecondSortUpRB->connect_toggled(LINK(this, SwTOXEntryTabPage, ToggleHdl)); + m_xSecondSortDownRB->connect_toggled(LINK(this, SwTOXEntryTabPage, ToggleHdl)); + m_xThirdSortUpRB->connect_toggled(LINK(this, SwTOXEntryTabPage, ToggleHdl)); + m_xThirdSortDownRB->connect_toggled(LINK(this, SwTOXEntryTabPage, ToggleHdl)); + + FieldUnit aMetric = ::GetDfltMetric(false); + ::SetFieldUnit(*m_xTabPosMF, aMetric); + + m_xSortDocPosRB->set_active(true); + + m_xFillCharCB->set_entry_max_length(1); + m_xFillCharCB->append_text(OUString(' ')); + m_xFillCharCB->append_text(OUString('.')); + m_xFillCharCB->append_text(OUString('-')); + m_xFillCharCB->append_text(OUString('_')); + m_xFillCharCB->append_text(OUString(u'\x2024')); // ONE DOT LEADER + m_xFillCharCB->append_text(OUString(u'\x2025')); // TWO DOT LEADER + m_xFillCharCB->append_text(OUString(u'\x2026')); // HORIZONTAL ELLIPSIS + + m_xEditStylePB->set_sensitive(false); + + //fill the types in + for (sal_uInt16 i = 0; i < AUTH_FIELD_END; ++i) + { + OUString sId(OUString::number(i)); + m_xAuthFieldsLB->append(sId, SwResId(STR_AUTH_FIELD_ARY[i])); + } + + m_xFirstKeyLB->append(OUString::number(USHRT_MAX), sNoCharSortKey); + m_xSecondKeyLB->append(OUString::number(USHRT_MAX), sNoCharSortKey); + m_xThirdKeyLB->append(OUString::number(USHRT_MAX), sNoCharSortKey); + + for (sal_uInt16 i = 0; i < AUTH_FIELD_END; ++i) + { + const OUString sTmp(m_xAuthFieldsLB->get_text(i)); + const OUString sEntryData(m_xAuthFieldsLB->get_id(i)); + m_xFirstKeyLB->append(sEntryData, sTmp); + m_xSecondKeyLB->append(sEntryData, sTmp); + m_xThirdKeyLB->append(sEntryData, sTmp); + } + m_xFirstKeyLB->set_active(0); + m_xSecondKeyLB->set_active(0); + m_xThirdKeyLB->set_active(0); + + // lock size of dialog. Determine the field box's widest possible + // configuration (tdf#149186) before doing so. + int nFieldBoxWidth = 0; + for (int eType = TOX_CITATION; eType >= TOX_INDEX; --eType) + { + ShowHideControls(eType); + nFieldBoxWidth = std::max<int>(m_xFieldBox->get_preferred_size().Width(), nFieldBoxWidth); + } + m_xFieldBox->set_size_request(nFieldBoxWidth, -1); + Size aPrefSize(m_xContainer->get_preferred_size()); + m_xFieldBox->set_size_request(-1, -1); + m_xContainer->set_size_request(aPrefSize.Width(), aPrefSize.Height()); +} + +SwTOXEntryTabPage::~SwTOXEntryTabPage() +{ + m_xTokenWIN.reset(); + + // tdf#135266 - remember last used entry level depending on the index type + if (const auto aSelectedIndex = m_xLevelLB->get_selected_index(); aSelectedIndex != -1) + { + auto& rSh = static_cast<SwMultiTOXTabDialog*>(GetDialogController())->GetWrtShell(); + SwViewOption* pVOpt = const_cast<SwViewOption*>(rSh.GetViewOptions()); + if (m_aLastTOXType == TOX_INDEX) + pVOpt->SetIdxEntryLvl(aSelectedIndex); + else + pVOpt->SetTocEntryLvl(aSelectedIndex); + } +} + +IMPL_LINK_NOARG(SwTOXEntryTabPage, ModifyClickHdl, weld::Toggleable&, void) +{ + OnModify(true); +} + +IMPL_LINK_NOARG(SwTOXEntryTabPage, ModifyHdl, LinkParamNone*, void) +{ + OnModify(false); +} + +IMPL_LINK(SwTOXEntryTabPage, ToggleHdl, weld::Toggleable&, rToggle, void) +{ + if (&rToggle == m_xFirstSortUpRB.get()) + m_xFirstSortDownRB->set_active(!m_xFirstSortUpRB->get_active()); + else if (&rToggle == m_xFirstSortDownRB.get()) + m_xFirstSortUpRB->set_active(!m_xFirstSortDownRB->get_active()); + else if (&rToggle == m_xSecondSortUpRB.get()) + m_xSecondSortDownRB->set_active(!m_xSecondSortUpRB->get_active()); + else if (&rToggle == m_xSecondSortDownRB.get()) + m_xSecondSortUpRB->set_active(!m_xSecondSortDownRB->get_active()); + else if (&rToggle == m_xThirdSortUpRB.get()) + m_xThirdSortDownRB->set_active(!m_xThirdSortUpRB->get_active()); + else if (&rToggle == m_xThirdSortDownRB.get()) + m_xThirdSortUpRB->set_active(!m_xThirdSortDownRB->get_active()); +} + +// bAllLevels is used as signal to change all levels of the example +void SwTOXEntryTabPage::OnModify(bool bAllLevels) +{ + UpdateDescriptor(); + + SwMultiTOXTabDialog* pTOXDlg = static_cast<SwMultiTOXTabDialog*>(GetDialogController()); + if (pTOXDlg) + { + sal_uInt16 nCurLevel = m_xLevelLB->get_selected_index() + 1; + if (m_aLastTOXType.eType == TOX_CONTENT && bAllLevels) + nCurLevel = USHRT_MAX; + pTOXDlg->CreateOrUpdateExample( + pTOXDlg->GetCurrentTOXType().eType, TOX_PAGE_ENTRY, nCurLevel); + } +} + +bool SwTOXEntryTabPage::FillItemSet( SfxItemSet* ) +{ + // nothing to do + return true; +} + +void SwTOXEntryTabPage::Reset( const SfxItemSet* ) +{ + SwMultiTOXTabDialog* pTOXDlg = static_cast<SwMultiTOXTabDialog*>(GetDialogController()); + const CurTOXType aCurType = pTOXDlg->GetCurrentTOXType(); + m_pCurrentForm = pTOXDlg->GetForm(aCurType); + if(TOX_INDEX == aCurType.eType) + { + SwTOXDescription& rDesc = pTOXDlg->GetTOXDescription(aCurType); + const OUString& sMainEntryCharStyle = rDesc.GetMainEntryCharStyle(); + if(!sMainEntryCharStyle.isEmpty()) + { + if (m_xMainEntryStyleLB->find_text(sMainEntryCharStyle) == -1) + m_xMainEntryStyleLB->append_text(sMainEntryCharStyle); + m_xMainEntryStyleLB->set_active_text(sMainEntryCharStyle); + } + else + m_xMainEntryStyleLB->set_active_text(m_sNoCharStyle); + m_xAlphaDelimCB->set_active( bool(rDesc.GetIndexOptions() & SwTOIOptions::AlphaDelimiter) ); + } + m_xRelToStyleCB->set_active(m_pCurrentForm->IsRelTabPos()); + m_xCommaSeparatedCB->set_active(m_pCurrentForm->IsCommaSeparated()); +} + +void SwTOXEntryTabPage::ShowHideControls(int eType) +{ + bool bToxIsAuthorities = TOX_AUTHORITIES == eType; + bool bToxIsIndex = TOX_INDEX == eType; + bool bToxIsContent = TOX_CONTENT == eType; + bool bToxSupportsLinks = TOX_CONTENT == eType || + TOX_ILLUSTRATIONS == eType || + TOX_TABLES == eType || + TOX_OBJECTS == eType || + TOX_USER == eType; + + //show or hide controls + m_xEntryNoPB->set_visible(bToxIsContent); + m_xHyperLinkPB->set_visible(bToxSupportsLinks); + m_xRelToStyleCB->set_visible(!bToxIsAuthorities); + m_xChapterInfoPB->set_visible(!bToxIsContent && !bToxIsAuthorities); + m_xEntryPB->set_visible(!bToxIsAuthorities); + m_xPageNoPB->set_visible(!bToxIsAuthorities); + m_xAuthFieldsLB->set_visible(bToxIsAuthorities); + m_xAuthInsertPB->set_visible(bToxIsAuthorities); + m_xAuthRemovePB->set_visible(bToxIsAuthorities); + + m_xFormatFrame->set_visible(!bToxIsAuthorities); + + m_xSortingFrame->set_visible(bToxIsAuthorities); + m_xSortKeyFrame->set_visible(bToxIsAuthorities); + + m_xMainEntryStyleFT->set_visible(bToxIsIndex); + m_xMainEntryStyleLB->set_visible(bToxIsIndex); + m_xAlphaDelimCB->set_visible(bToxIsIndex); + m_xCommaSeparatedCB->set_visible(bToxIsIndex); +} + +void SwTOXEntryTabPage::ActivatePage( const SfxItemSet& /*rSet*/) +{ + SwMultiTOXTabDialog* pTOXDlg = static_cast<SwMultiTOXTabDialog*>(GetDialogController()); + const CurTOXType aCurType = pTOXDlg->GetCurrentTOXType(); + + m_pCurrentForm = pTOXDlg->GetForm(aCurType); + if( !( m_aLastTOXType == aCurType )) + { + bool bToxIsAuthorities = TOX_AUTHORITIES == aCurType.eType; + bool bToxIsIndex = TOX_INDEX == aCurType.eType; + + m_xLevelLB->clear(); + for(sal_uInt16 i = 1; i < m_pCurrentForm->GetFormMax(); i++) + { + if(bToxIsAuthorities) + m_xLevelLB->append_text( SwAuthorityFieldType::GetAuthTypeName( + static_cast<ToxAuthorityType>(i - 1)) ); + else if( bToxIsIndex ) + { + if(i == 1) + m_xLevelLB->append_text( m_sDelimStr ); + else + m_xLevelLB->append_text( OUString::number(i - 1) ); + } + else + m_xLevelLB->append_text(OUString::number(i)); + } + if(bToxIsAuthorities) + { + SwWrtShell& rSh = pTOXDlg->GetWrtShell(); + const SwAuthorityFieldType* pFType = static_cast<const SwAuthorityFieldType*>( + rSh.GetFieldType(SwFieldIds::TableOfAuthorities, OUString())); + if(pFType) + { + if(pFType->IsSortByDocument()) + m_xSortDocPosRB->set_active(true); + else + { + m_xSortContentRB->set_active(true); + const sal_uInt16 nKeyCount = pFType->GetSortKeyCount(); + if(0 < nKeyCount) + { + const SwTOXSortKey* pKey = pFType->GetSortKey(0); + m_xFirstKeyLB->set_active_id(OUString::number(pKey->eField)); + m_xFirstSortUpRB->set_active(pKey->bSortAscending); + m_xFirstSortDownRB->set_active(!pKey->bSortAscending); + } + if(1 < nKeyCount) + { + const SwTOXSortKey* pKey = pFType->GetSortKey(1); + m_xSecondKeyLB->set_active_id(OUString::number(pKey->eField)); + m_xSecondSortUpRB->set_active(pKey->bSortAscending); + m_xSecondSortDownRB->set_active(!pKey->bSortAscending); + } + if(2 < nKeyCount) + { + const SwTOXSortKey* pKey = pFType->GetSortKey(2); + m_xThirdKeyLB->set_active_id(OUString::number(pKey->eField)); + m_xThirdSortUpRB->set_active(pKey->bSortAscending); + m_xThirdSortDownRB->set_active(!pKey->bSortAscending); + } + } + } + SortKeyHdl(m_xSortDocPosRB->get_active() ? *m_xSortDocPosRB : *m_xSortContentRB); + m_xLevelFT->set_label(m_sAuthTypeStr); + } + else + m_xLevelFT->set_label(m_sLevelStr); + + // tdf#135266 - remember last used entry level depending on the index type + m_xLevelLB->select(bToxIsIndex ? pTOXDlg->GetWrtShell().GetViewOptions()->GetIdxEntryLvl() + : pTOXDlg->GetWrtShell().GetViewOptions()->GetTocEntryLvl()); + + + //show or hide controls + ShowHideControls(aCurType.eType); + } + m_aLastTOXType = aCurType; + + //invalidate PatternWindow + m_xTokenWIN->SetInvalid(); + LevelHdl(*m_xLevelLB); +} + +void SwTOXEntryTabPage::UpdateDescriptor() +{ + WriteBackLevel(); + SwMultiTOXTabDialog* pTOXDlg = static_cast<SwMultiTOXTabDialog*>(GetDialogController()); + SwTOXDescription& rDesc = pTOXDlg->GetTOXDescription(m_aLastTOXType); + if(TOX_INDEX == m_aLastTOXType.eType) + { + const OUString sTemp(m_xMainEntryStyleLB->get_active_text()); + rDesc.SetMainEntryCharStyle(m_sNoCharStyle == sTemp ? OUString(): sTemp); + SwTOIOptions nIdxOptions = rDesc.GetIndexOptions() & ~SwTOIOptions::AlphaDelimiter; + if (m_xAlphaDelimCB->get_active()) + nIdxOptions |= SwTOIOptions::AlphaDelimiter; + rDesc.SetIndexOptions(nIdxOptions); + } + else if (TOX_AUTHORITIES == m_aLastTOXType.eType) + { + rDesc.SetSortByDocument(m_xSortDocPosRB->get_active()); + SwTOXSortKey aKey1, aKey2, aKey3; + aKey1.eField = static_cast<ToxAuthorityField>(m_xFirstKeyLB->get_active_id().toInt32()); + aKey1.bSortAscending = m_xFirstSortUpRB->get_active(); + aKey2.eField = static_cast<ToxAuthorityField>(m_xSecondKeyLB->get_active_id().toInt32()); + aKey2.bSortAscending = m_xSecondSortUpRB->get_active(); + aKey3.eField = static_cast<ToxAuthorityField>(m_xThirdKeyLB->get_active_id().toInt32()); + aKey3.bSortAscending = m_xThirdSortUpRB->get_active(); + + rDesc.SetSortKeys(aKey1, aKey2, aKey3); + } + SwForm* pCurrentForm = pTOXDlg->GetForm(m_aLastTOXType); + if (m_xRelToStyleCB->get_visible()) + pCurrentForm->SetRelTabPos(m_xRelToStyleCB->get_active()); + if (m_xCommaSeparatedCB->get_visible()) + pCurrentForm->SetCommaSeparated(m_xCommaSeparatedCB->get_active()); +} + +DeactivateRC SwTOXEntryTabPage::DeactivatePage( SfxItemSet* /*pSet*/) +{ + UpdateDescriptor(); + return DeactivateRC::LeavePage; +} + +std::unique_ptr<SfxTabPage> SwTOXEntryTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwTOXEntryTabPage>(pPage, pController, *rAttrSet); +} + +IMPL_LINK_NOARG(SwTOXEntryTabPage, EditStyleHdl, weld::Button&, void) +{ + if (m_xCharStyleLB->get_active() != -1) + { + SfxStringItem aStyle(SID_STYLE_EDIT, m_xCharStyleLB->get_active_text()); + SfxUInt16Item aFamily(SID_STYLE_FAMILY, sal_uInt16(SfxStyleFamily::Char)); + static_cast<SwMultiTOXTabDialog*>(GetDialogController())->GetWrtShell(). + GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_STYLE_EDIT, + SfxCallMode::SYNCHRON, + { &aStyle, &aFamily }); + } +} + +IMPL_LINK(SwTOXEntryTabPage, RemoveInsertAuthHdl, weld::Button&, rButton, void) +{ + bool bInsert = &rButton == m_xAuthInsertPB.get(); + if(bInsert) + { + sal_Int32 nSelPos = m_xAuthFieldsLB->get_active(); + const OUString sToInsert(m_xAuthFieldsLB->get_active_text()); + SwFormToken aInsert(TOKEN_AUTHORITY); + aInsert.nAuthorityField = m_xAuthFieldsLB->get_id(nSelPos).toUInt32(); + m_xTokenWIN->InsertAtSelection(aInsert); + m_xAuthFieldsLB->remove_text(sToInsert); + m_xAuthFieldsLB->set_active(nSelPos ? nSelPos - 1 : 0); + } + else + { + SwTOXWidget* pCtrl = m_xTokenWIN->GetActiveControl(); + OSL_ENSURE(WindowType::EDIT != pCtrl->GetType(), "Remove should be disabled"); + if (WindowType::EDIT != pCtrl->GetType()) + { + //fill it into the ListBox + const SwFormToken& rToken = static_cast<SwTOXButton*>(pCtrl)->GetFormToken(); + PreTokenButtonRemoved(rToken); + m_xTokenWIN->RemoveControl(static_cast<SwTOXButton*>(pCtrl)); + } + } + ModifyHdl(nullptr); +} + +void SwTOXEntryTabPage::PreTokenButtonRemoved(const SwFormToken& rToken) +{ + //fill it into the ListBox + sal_uInt32 nData = rToken.nAuthorityField; + m_xAuthFieldsLB->append(OUString::number(nData), SwResId(STR_AUTH_FIELD_ARY[nData])); +} + +void SwTOXEntryTabPage::SetFocus2theAllBtn() +{ + m_xAllLevelsPB->grab_focus(); +} + +// This function initializes the default value in the Token +// put here the UI dependent initializations +IMPL_LINK(SwTOXEntryTabPage, InsertTokenHdl, weld::Button&, rBtn, void) +{ + FormTokenType eTokenType = TOKEN_ENTRY_NO; + OUString sCharStyle; + sal_uInt16 nChapterFormat = CF_NUMBER; // i89791 + if (&rBtn == m_xEntryNoPB.get()) + { + eTokenType = TOKEN_ENTRY_NO; + } + else if (&rBtn == m_xEntryPB.get()) + { + if( TOX_CONTENT == m_pCurrentForm->GetTOXType() ) + { + eTokenType = TOKEN_ENTRY_TEXT; + } + else + { + eTokenType = TOKEN_ENTRY; + } + } + else if (&rBtn == m_xChapterInfoPB.get()) + { + eTokenType = TOKEN_CHAPTER_INFO; + nChapterFormat = CF_NUM_NOPREPST_TITLE; // i89791 + } + else if (&rBtn == m_xPageNoPB.get()) + { + eTokenType = TOKEN_PAGE_NUMS; + } + else if (&rBtn == m_xHyperLinkPB.get()) + { + eTokenType = TOKEN_LINK_START; + sCharStyle = SwResId(STR_POOLCHR_TOXJUMP); + } + else if (&rBtn == m_xTabPB.get()) + { + eTokenType = TOKEN_TAB_STOP; + } + SwFormToken aInsert(eTokenType); + aInsert.sCharStyleName = sCharStyle; + aInsert.nTabStopPosition = 0; + aInsert.nChapterFormat = nChapterFormat; // i89791 + m_xTokenWIN->InsertAtSelection(aInsert); + ModifyHdl(nullptr); +} + +IMPL_LINK_NOARG(SwTOXEntryTabPage, AllLevelsHdl, weld::Button&, void) +{ + //get current level + //write it into all levels + if(m_xTokenWIN->IsValid()) + { + const OUString sNewToken = m_xTokenWIN->GetPattern(); + for(sal_uInt16 i = 1; i < m_pCurrentForm->GetFormMax(); i++) + m_pCurrentForm->SetPattern(i, sNewToken); + + OnModify(true); + } +} + +void SwTOXEntryTabPage::WriteBackLevel() +{ + if(m_xTokenWIN->IsValid()) + { + const OUString sNewToken = m_xTokenWIN->GetPattern(); + const sal_uInt16 nLastLevel = m_xTokenWIN->GetLastLevel(); + if(nLastLevel != USHRT_MAX) + m_pCurrentForm->SetPattern(nLastLevel + 1, sNewToken); + } +} + +IMPL_LINK(SwTOXEntryTabPage, LevelHdl, weld::TreeView&, rBox, void) +{ + if(m_bInLevelHdl) + return; + m_bInLevelHdl = true; + WriteBackLevel(); + + const sal_uInt16 nLevel = rBox.get_selected_index(); + m_xTokenWIN->SetForm(*m_pCurrentForm, nLevel); + if(TOX_AUTHORITIES == m_pCurrentForm->GetTOXType()) + { + //fill the types in + m_xAuthFieldsLB->clear(); + for( sal_uInt32 i = 0; i < AUTH_FIELD_END; i++) + { + m_xAuthFieldsLB->append(OUString::number(i), SwResId(STR_AUTH_FIELD_ARY[i])); + } + + // #i21237# + SwFormTokens aPattern = m_pCurrentForm->GetPattern(nLevel + 1); + + for(const auto& aToken : aPattern) + { + if(TOKEN_AUTHORITY == aToken.eTokenType) + { + sal_uInt32 nSearch = aToken.nAuthorityField; + int nLstBoxPos = m_xAuthFieldsLB->find_id(OUString::number(nSearch)); + OSL_ENSURE(nLstBoxPos != -1, "Entry not found?"); + m_xAuthFieldsLB->remove(nLstBoxPos); + } + } + m_xAuthFieldsLB->set_active(0); + } + m_bInLevelHdl = false; + rBox.grab_focus(); +} + +IMPL_LINK_NOARG(SwTOXEntryTabPage, SortKeyHdl, weld::Toggleable&, void) +{ + bool bEnable = m_xSortContentRB->get_active(); + m_xSortKeyFrame->set_sensitive(bEnable); +} + +IMPL_LINK(SwTOXEntryTabPage, TokenSelectedHdl, SwFormToken&, rToken, void) +{ + if (!rToken.sCharStyleName.isEmpty()) + m_xCharStyleLB->set_active_text(rToken.sCharStyleName); + else + m_xCharStyleLB->set_active_text(m_sNoCharStyle); + + const OUString sEntry = m_xCharStyleLB->get_active_text(); + m_xEditStylePB->set_sensitive(sEntry != m_sNoCharStyle); + + if(rToken.eTokenType == TOKEN_CHAPTER_INFO) + { +//---> i89791 + switch(rToken.nChapterFormat) + { + default: + m_xChapterEntryLB->set_active(-1);//to alert the user + break; + case CF_NUM_NOPREPST_TITLE: + m_xChapterEntryLB->set_active(0); + break; + case CF_TITLE: + m_xChapterEntryLB->set_active(1); + break; + case CF_NUMBER_NOPREPST: + m_xChapterEntryLB->set_active(2); + break; + } +//i53420 + + m_xEntryOutlineLevelNF->set_value(rToken.nOutlineLevel); + } + +//i53420 + if(rToken.eTokenType == TOKEN_ENTRY_NO) + { + m_xEntryOutlineLevelNF->set_value(rToken.nOutlineLevel); + const sal_uInt16 nFormat = + rToken.nChapterFormat == CF_NUM_NOPREPST_TITLE ? 1 : 0; + m_xNumberFormatLB->set_active(nFormat); + } + + bool bTabStop = TOKEN_TAB_STOP == rToken.eTokenType; + m_xFillCharFT->set_visible(bTabStop); + m_xFillCharCB->set_visible(bTabStop); + m_xTabPosFT->set_visible(bTabStop); + m_xTabPosMF->set_visible(bTabStop); + m_xAutoRightCB->set_visible(bTabStop); + m_xAutoRightCB->set_sensitive(bTabStop); + if(bTabStop) + { + m_xTabPosMF->set_value(m_xTabPosMF->normalize(rToken.nTabStopPosition), FieldUnit::TWIP); + m_xAutoRightCB->set_active(SvxTabAdjust::End == rToken.eTabAlign); + m_xFillCharCB->set_entry_text(OUString(rToken.cTabFillChar)); + m_xTabPosFT->set_sensitive(!m_xAutoRightCB->get_active()); + m_xTabPosMF->set_sensitive(!m_xAutoRightCB->get_active()); + } + else + { + m_xTabPosMF->set_sensitive(false); + } + + bool bIsChapterInfo = rToken.eTokenType == TOKEN_CHAPTER_INFO; + bool bIsEntryNumber = rToken.eTokenType == TOKEN_ENTRY_NO; + m_xChapterEntryFT->set_visible( bIsChapterInfo ); + m_xChapterEntryLB->set_visible( bIsChapterInfo ); + m_xEntryOutlineLevelFT->set_visible( bIsChapterInfo || bIsEntryNumber ); + m_xEntryOutlineLevelNF->set_visible( bIsChapterInfo || bIsEntryNumber ); + m_xNumberFormatFT->set_visible( bIsEntryNumber ); + m_xNumberFormatLB->set_visible( bIsEntryNumber ); + + //now enable the visible buttons + //- inserting the same type of control is not allowed + //- some types of controls can only appear once (EntryText EntryNumber) + + if (m_xEntryNoPB->get_visible()) + { + m_xEntryNoPB->set_sensitive(TOKEN_ENTRY_NO != rToken.eTokenType ); + } + if (m_xEntryPB->get_visible()) + { + m_xEntryPB->set_sensitive(TOKEN_ENTRY_TEXT != rToken.eTokenType && + !m_xTokenWIN->Contains(TOKEN_ENTRY_TEXT) + && !m_xTokenWIN->Contains(TOKEN_ENTRY)); + } + + if (m_xChapterInfoPB->get_visible()) + { + m_xChapterInfoPB->set_sensitive(TOKEN_CHAPTER_INFO != rToken.eTokenType); + } + if (m_xPageNoPB->get_visible()) + { + m_xPageNoPB->set_sensitive(TOKEN_PAGE_NUMS != rToken.eTokenType && + !m_xTokenWIN->Contains(TOKEN_PAGE_NUMS)); + } + if (m_xTabPB->get_visible()) + { + m_xTabPB->set_sensitive(!bTabStop); + } + if (m_xHyperLinkPB->get_visible()) + { + m_xHyperLinkPB->set_sensitive(TOKEN_LINK_START != rToken.eTokenType && + TOKEN_LINK_END != rToken.eTokenType); + } + //table of authorities + if (m_xAuthInsertPB->get_visible()) + { + bool bText = TOKEN_TEXT == rToken.eTokenType; + m_xAuthInsertPB->set_sensitive(bText && !m_xAuthFieldsLB->get_active_text().isEmpty()); + m_xAuthRemovePB->set_sensitive(!bText); + } +} + +IMPL_LINK(SwTOXEntryTabPage, StyleSelectHdl, weld::ComboBox&, rBox, void) +{ + OUString sEntry = rBox.get_active_text(); + const sal_uInt16 nId = rBox.get_active_id().toUInt32(); + const bool bEqualsNoCharStyle = sEntry == m_sNoCharStyle; + m_xEditStylePB->set_sensitive(!bEqualsNoCharStyle); + if (bEqualsNoCharStyle) + sEntry.clear(); + SwTOXWidget* pCtrl = m_xTokenWIN->GetActiveControl(); + OSL_ENSURE(pCtrl, "no active control?"); + if(pCtrl) + { + if(WindowType::EDIT == pCtrl->GetType()) + static_cast<SwTOXEdit*>(pCtrl)->SetCharStyleName(sEntry, nId); + else + static_cast<SwTOXButton*>(pCtrl)->SetCharStyleName(sEntry, nId); + + } + ModifyHdl(nullptr); +} + +IMPL_LINK(SwTOXEntryTabPage, ChapterInfoHdl, weld::ComboBox&, rBox, void) +{ + int nPos = rBox.get_active(); + if (nPos != -1) + { + SwTOXWidget* pCtrl = m_xTokenWIN->GetActiveControl(); + OSL_ENSURE(pCtrl, "no active control?"); + if(pCtrl && WindowType::EDIT != pCtrl->GetType()) + static_cast<SwTOXButton*>(pCtrl)->SetChapterInfo(nPos); + ModifyHdl(nullptr); + } +} + +IMPL_LINK(SwTOXEntryTabPage, ChapterInfoOutlineHdl, weld::SpinButton&, rEdit, void) +{ + const sal_uInt16 nLevel = rEdit.get_value(); + + SwTOXWidget* pCtrl = m_xTokenWIN->GetActiveControl(); + OSL_ENSURE(pCtrl, "no active control?"); + if(pCtrl && WindowType::EDIT != pCtrl->GetType()) + static_cast<SwTOXButton*>(pCtrl)->SetOutlineLevel(nLevel); + + ModifyHdl(nullptr); +} + +IMPL_LINK(SwTOXEntryTabPage, NumberFormatHdl, weld::ComboBox&, rBox, void) +{ + const sal_Int32 nPos = rBox.get_active(); + if (nPos != -1) + { + SwTOXWidget* pCtrl = m_xTokenWIN->GetActiveControl(); + OSL_ENSURE(pCtrl, "no active control?"); + if(pCtrl && WindowType::EDIT != pCtrl->GetType()) + { + static_cast<SwTOXButton*>(pCtrl)->SetEntryNumberFormat(nPos);//i89791 + } + ModifyHdl(nullptr); + } +} + +IMPL_LINK(SwTOXEntryTabPage, TabPosHdl, weld::MetricSpinButton&, rEdit, void) +{ + SwTOXWidget* pCtrl = m_xTokenWIN->GetActiveControl(); + OSL_ENSURE(pCtrl && WindowType::EDIT != pCtrl->GetType() && + TOKEN_TAB_STOP == static_cast<SwTOXButton*>(pCtrl)->GetFormToken().eTokenType, + "no active style::TabStop control?"); + if( pCtrl && WindowType::EDIT != pCtrl->GetType() ) + { + static_cast<SwTOXButton*>(pCtrl)->SetTabPosition( static_cast< SwTwips >( + rEdit.denormalize(rEdit.get_value(FieldUnit::TWIP)))); + } + ModifyHdl(nullptr); +} + +IMPL_LINK(SwTOXEntryTabPage, FillCharHdl, weld::ComboBox&, rBox, void) +{ + SwTOXWidget* pCtrl = m_xTokenWIN->GetActiveControl(); + OSL_ENSURE(pCtrl && WindowType::EDIT != pCtrl->GetType() && + TOKEN_TAB_STOP == static_cast<SwTOXButton*>(pCtrl)->GetFormToken().eTokenType, + "no active style::TabStop control?"); + if (pCtrl && WindowType::EDIT != pCtrl->GetType()) + { + sal_Unicode cSet; + if (!rBox.get_active_text().isEmpty()) + cSet = rBox.get_active_text()[0]; + else + cSet = ' '; + static_cast<SwTOXButton*>(pCtrl)->SetFillChar( cSet ); + } + ModifyHdl(nullptr); +} + +IMPL_LINK(SwTOXEntryTabPage, AutoRightHdl, weld::Toggleable&, rBox, void) +{ + //the most right style::TabStop is usually right aligned + SwTOXWidget* pCurCtrl = m_xTokenWIN->GetActiveControl(); + OSL_ENSURE(WindowType::EDIT != pCurCtrl->GetType() && + static_cast<SwTOXButton*>(pCurCtrl)->GetFormToken().eTokenType == TOKEN_TAB_STOP, + "no style::TabStop selected!"); + + const SwFormToken& rToken = static_cast<SwTOXButton*>(pCurCtrl)->GetFormToken(); + bool bChecked = rBox.get_active(); + if(rToken.eTokenType == TOKEN_TAB_STOP) + static_cast<SwTOXButton*>(pCurCtrl)->SetTabAlign( + bChecked ? SvxTabAdjust::End : SvxTabAdjust::Left); + m_xTabPosFT->set_sensitive(!bChecked); + m_xTabPosMF->set_sensitive(!bChecked); + ModifyHdl(nullptr); +} + +void SwTOXEntryTabPage::SetWrtShell(SwWrtShell& rSh) +{ + SwDocShell* pDocSh = rSh.GetView().GetDocShell(); + ::FillCharStyleListBox(*m_xCharStyleLB, pDocSh, true, true); + const OUString sDefault(SwResId(STR_POOLCHR_STANDARD)); + for (int i = 0, nCount = m_xCharStyleLB->get_count(); i < nCount; ++i) + { + const OUString sEntry = m_xCharStyleLB->get_text(i); + if(sDefault != sEntry) + { + m_xMainEntryStyleLB->append(m_xCharStyleLB->get_id(i), sEntry); + } + } + m_xMainEntryStyleLB->set_active_text(SwStyleNameMapper::GetUIName( + RES_POOLCHR_IDX_MAIN_ENTRY, OUString())); +} + + const TranslateId STR_TOKEN_ARY[] = +{ + STR_TOKEN_ENTRY_NO, + STR_TOKEN_ENTRY, //mapped from original STR_TOKEN_ENTRY_TEXT, + STR_TOKEN_ENTRY, + STR_TOKEN_TAB_STOP, + {}, + STR_TOKEN_PAGE_NUMS, + STR_TOKEN_CHAPTER_INFO, + STR_TOKEN_LINK_START, + STR_TOKEN_LINK_END, + STR_TOKEN_AUTHORITY +}; + + const TranslateId STR_TOKEN_HELP_ARY[] = +{ + STR_TOKEN_HELP_ENTRY_NO, + STR_TOKEN_HELP_ENTRY, // mapped from original STR_TOKEN_HELP_ENTRY_TEXT, + STR_TOKEN_HELP_ENTRY, + STR_TOKEN_HELP_TAB_STOP, + STR_TOKEN_HELP_TEXT, + STR_TOKEN_HELP_PAGE_NUMS, + STR_TOKEN_HELP_CHAPTER_INFO, + STR_TOKEN_HELP_LINK_START, + STR_TOKEN_HELP_LINK_END, + STR_TOKEN_HELP_AUTHORITY +}; + +SwTokenWindow::SwTokenWindow(std::unique_ptr<weld::Container> xParent) + : m_pForm(nullptr) + , m_nLevel(0) + , m_bValid(false) + , m_sCharStyle(SwResId(STR_CHARSTYLE)) + , m_pActiveCtrl(nullptr) + , m_aAdjustPositionsIdle("SwTokenWindow m_aAdjustPositionsIdle") + , m_pParent(nullptr) + , m_xParentWidget(std::move(xParent)) + , m_xBuilder(Application::CreateBuilder(m_xParentWidget.get(), "modules/swriter/ui/tokenwidget.ui")) + , m_xContainer(m_xBuilder->weld_container("TokenWidget")) + , m_xLeftScrollWin(m_xBuilder->weld_button("left")) + , m_xCtrlParentWin(m_xBuilder->weld_container("ctrl")) + , m_xScrollWin(m_xBuilder->weld_scrolled_window("scrollwin")) + , m_xRightScrollWin(m_xBuilder->weld_button("right")) +{ + m_xScrollWin->connect_hadjustment_changed(LINK(this, SwTokenWindow, ScrollHdl)); + m_xCtrlParentWin->connect_size_allocate(LINK(this, SwTokenWindow, AdjustPositionsHdl)); + + for (sal_uInt32 i = 0; i < TOKEN_END; ++i) + { + TranslateId pTextId = STR_TOKEN_ARY[i]; + if (pTextId) + m_aButtonTexts[i] = SwResId(pTextId); + + TranslateId pHelpId = STR_TOKEN_HELP_ARY[i]; + m_aButtonHelpTexts[i] = SwResId(pHelpId); + } + + m_sAccessibleName = SwResId(STR_STRUCTURE); + m_sAdditionalAccnameString1 = SwResId(STR_ADDITIONAL_ACCNAME_STRING1); + m_sAdditionalAccnameString2 = SwResId(STR_ADDITIONAL_ACCNAME_STRING2); + m_sAdditionalAccnameString3 = SwResId(STR_ADDITIONAL_ACCNAME_STRING3); + + Link<weld::Button&,void> aLink(LINK(this, SwTokenWindow, ScrollBtnHdl)); + m_xLeftScrollWin->connect_clicked(aLink); + m_xRightScrollWin->connect_clicked(aLink); +} + +SwTokenWindow::~SwTokenWindow() +{ +} + +void SwTokenWindow::SetForm(SwForm& rForm, sal_uInt16 nL) +{ + SetActiveControl(nullptr); + m_bValid = true; + + if (m_pForm) + { + //apply current level settings to the form + m_aControlList.clear(); + } + + m_nLevel = nL; + m_pForm = &rForm; + //now the display + if(m_nLevel < MAXLEVEL || rForm.GetTOXType() == TOX_AUTHORITIES) + { + // #i21237# + SwFormTokens aPattern = m_pForm->GetPattern(m_nLevel + 1); + bool bLastWasText = false; //assure alternating text - code - text + + SwTOXWidget* pSetActiveControl = nullptr; + for (const auto& aToken : aPattern) // #i21237# + { + if(TOKEN_TEXT == aToken.eTokenType) + { + SAL_WARN_IF(bLastWasText, "sw", "text following text is invalid"); + SwTOXWidget* pCtrl = InsertItem(aToken.sText, aToken); + bLastWasText = true; + if (!GetActiveControl()) + SetActiveControl(pCtrl); + } + else + { + if( !bLastWasText ) + { + SwFormToken aTemp(TOKEN_TEXT); + SwTOXWidget* pCtrl = InsertItem(OUString(), aTemp); + if(!pSetActiveControl) + pSetActiveControl = pCtrl; + } + + OUString sForm; + switch( aToken.eTokenType ) + { + case TOKEN_ENTRY_NO: sForm = SwForm::GetFormEntryNum(); break; + case TOKEN_ENTRY_TEXT: sForm = SwForm::GetFormEntryText(); break; + case TOKEN_ENTRY: sForm = SwForm::GetFormEntry(); break; + case TOKEN_TAB_STOP: sForm = SwForm::GetFormTab(); break; + case TOKEN_PAGE_NUMS: sForm = SwForm::GetFormPageNums(); break; + case TOKEN_CHAPTER_INFO: sForm = SwForm::GetFormChapterMark(); break; + case TOKEN_LINK_START: sForm = SwForm::GetFormLinkStt(); break; + case TOKEN_LINK_END: sForm = SwForm::GetFormLinkEnd(); break; + case TOKEN_AUTHORITY: sForm = SwForm::GetFormAuth(); break; + default:; //prevent warning + } + + InsertItem( sForm, aToken ); + bLastWasText = false; + } + } + if(!bLastWasText) + { + SwFormToken aTemp(TOKEN_TEXT); + SwTOXWidget* pCtrl = InsertItem(OUString(), aTemp); + if(!pSetActiveControl) + pSetActiveControl = pCtrl; + } + SetActiveControl(pSetActiveControl); + } + AdjustScrolling(); +} + +void SwTokenWindow::SetActiveControl(SwTOXWidget* pSet) +{ + if (pSet == m_pActiveCtrl) + return; + + m_pActiveCtrl = pSet; + if( !m_pActiveCtrl ) + return; + + m_pActiveCtrl->GrabFocus(); + //it must be a SwTOXEdit + const SwFormToken* pFToken; + if( WindowType::EDIT == m_pActiveCtrl->GetType() ) + pFToken = &static_cast<SwTOXEdit*>(m_pActiveCtrl)->GetFormToken(); + else + pFToken = &static_cast<SwTOXButton*>(m_pActiveCtrl)->GetFormToken(); + + SwFormToken aTemp( *pFToken ); + m_aButtonSelectedHdl.Call( aTemp ); +} + +SwTOXWidget* SwTokenWindow::InsertItem(const OUString& rText, const SwFormToken& rToken) +{ + SwTOXWidget* pRet = nullptr; + + if (TOKEN_TEXT == rToken.eTokenType) + { + SwTOXEdit* pEdit = new SwTOXEdit(this, rToken); + pEdit->set_grid_left_attach(m_aControlList.size()); + + m_aControlList.emplace_back(pEdit); + + pEdit->SetText(rText); + sal_uInt32 nIndex = GetControlIndex( TOKEN_TEXT ); + OUString strName(m_sAccessibleName + OUString::number(nIndex)); + if ( nIndex == 1 ) + { + /*Press left or right arrow to choose the structure controls*/ + strName += " (" + m_sAdditionalAccnameString2 + ", " + /*Press Ctrl+Alt+A to move focus for more operations*/ + + m_sAdditionalAccnameString1 + ", " + /*Press Ctrl+Alt+B to move focus back to the current structure control*/ + + m_sAdditionalAccnameString3 + ")"; + } + pEdit->SetAccessibleName(strName); + pEdit->AdjustSize(); + pEdit->SetModifyHdl(LINK(this, SwTokenWindow, EditResize )); + pEdit->SetPrevNextLink(LINK(this, SwTokenWindow, NextItemHdl)); + pEdit->SetGetFocusHdl(LINK(this, SwTokenWindow, TbxFocusHdl)); + pEdit->Show(); + pRet = pEdit; + } + else + { + SwTOXButton* pButton = new SwTOXButton(this, rToken); + pButton->set_grid_left_attach(m_aControlList.size()); + + m_aControlList.emplace_back(pButton); + + pButton->SetPrevNextLink(LINK(this, SwTokenWindow, NextItemBtnHdl)); + pButton->SetGetFocusHdl(LINK(this, SwTokenWindow, TbxFocusBtnHdl)); + + if(TOKEN_AUTHORITY != rToken.eTokenType) + pButton->SetText(m_aButtonTexts[rToken.eTokenType]); + else + { + //use the first two chars as symbol + OUString sTmp(SwAuthorityFieldType::GetAuthFieldName( + static_cast<ToxAuthorityField>(rToken.nAuthorityField))); + pButton->SetText(sTmp.copy(0, 2)); + } + + sal_uInt32 nIndex = GetControlIndex( rToken.eTokenType ); + OUString sAccName = m_aButtonHelpTexts[rToken.eTokenType]; + if ( nIndex ) + { + sAccName += " " + OUString::number(nIndex); + } + pButton->SetAccessibleName( sAccName ); + + pButton->Show(); + pRet = pButton; + } + + return pRet; +} + +void SwTokenWindow::InsertAtSelection(const SwFormToken& rToken) +{ + OSL_ENSURE(m_pActiveCtrl, "no active control!"); + + if(!m_pActiveCtrl) + return; + + SwFormToken aToInsertToken(rToken); + + if(TOKEN_LINK_START == aToInsertToken.eTokenType) + { + //determine if start or end of hyperlink is appropriate + //eventually change a following link start into a link end + // groups of LS LE should be ignored + // <insert> + //LS <insert> + //LE <insert> + //<insert> LS + //<insert> LE + //<insert> + bool bPreStartLinkFound = false; + bool bPreEndLinkFound = false; + + const SwTOXWidget* pControl = nullptr; + const SwTOXWidget* pExchange = nullptr; + + auto it = m_aControlList.cbegin(); + for( ; it != m_aControlList.cend() && m_pActiveCtrl != it->get(); ++it ) + { + pControl = it->get(); + + if( WindowType::EDIT != pControl->GetType()) + { + const SwFormToken& rNewToken = + static_cast<const SwTOXButton*>(pControl)->GetFormToken(); + + if( TOKEN_LINK_START == rNewToken.eTokenType ) + { + bPreStartLinkFound = true; + pExchange = nullptr; + } + else if(TOKEN_LINK_END == rNewToken.eTokenType) + { + if( bPreStartLinkFound ) + bPreStartLinkFound = false; + else + { + bPreEndLinkFound = false; + pExchange = pControl; + } + } + } + } + + bool bPostLinkStartFound = false; + + if(!bPreStartLinkFound && !bPreEndLinkFound) + { + for( ; it != m_aControlList.cend(); ++it ) + { + pControl = it->get(); + + if( pControl != m_pActiveCtrl && + WindowType::EDIT != pControl->GetType()) + { + const SwFormToken& rNewToken = + static_cast<const SwTOXButton*>(pControl)->GetFormToken(); + + if( TOKEN_LINK_START == rNewToken.eTokenType ) + { + if(bPostLinkStartFound) + break; + bPostLinkStartFound = true; + pExchange = pControl; + } + else if(TOKEN_LINK_END == rNewToken.eTokenType ) + { + if(bPostLinkStartFound) + { + bPostLinkStartFound = false; + pExchange = nullptr; + } + break; + } + } + } + } + + if(bPreStartLinkFound) + { + aToInsertToken.eTokenType = TOKEN_LINK_END; + aToInsertToken.sText = m_aButtonTexts[TOKEN_LINK_END]; + } + + if(bPostLinkStartFound) + { + OSL_ENSURE(pExchange, "no control to exchange?"); + if(pExchange) + { + const_cast<SwTOXButton*>(static_cast<const SwTOXButton*>(pExchange))->SetLinkEnd(); + const_cast<SwTOXButton*>(static_cast<const SwTOXButton*>(pExchange))->SetText(m_aButtonTexts[TOKEN_LINK_END]); + } + } + + if(bPreEndLinkFound) + { + OSL_ENSURE(pExchange, "no control to exchange?"); + + if(pExchange) + { + const_cast<SwTOXButton*>(static_cast<const SwTOXButton*>(pExchange))->SetLinkStart(); + const_cast<SwTOXButton*>(static_cast<const SwTOXButton*>(pExchange))->SetText(m_aButtonTexts[TOKEN_LINK_START]); + } + } + } + + //if the active control is text then insert a new button at the selection + //else replace the button + auto iterActive = std::find_if(m_aControlList.begin(), m_aControlList.end(), + [this](const auto& rControl) + { + SwTOXWidget* pCtrl = rControl.get(); + return pCtrl == m_pActiveCtrl; + }); + + assert(iterActive != m_aControlList.end()); + if (iterActive == m_aControlList.end()) + return; + + if (WindowType::EDIT == m_pActiveCtrl->GetType()) + { + ++iterActive; + + int nStartPos, nEndPos; + static_cast<SwTOXEdit*>(m_pActiveCtrl)->get_selection_bounds(nStartPos, nEndPos); + + const OUString sEditText = static_cast<SwTOXEdit*>(m_pActiveCtrl)->GetText(); + const OUString sLeft = sEditText.copy( 0, std::min(nStartPos, nEndPos) ); + const OUString sRight = sEditText.copy( std::max(nStartPos, nEndPos) ); + + static_cast<SwTOXEdit*>(m_pActiveCtrl)->SetText(sLeft); + static_cast<SwTOXEdit*>(m_pActiveCtrl)->AdjustSize(); + + SwFormToken aTmpToken(TOKEN_TEXT); + SwTOXEdit* pEdit = new SwTOXEdit(this, aTmpToken); + iterActive = m_aControlList.emplace(iterActive, pEdit); + + pEdit->SetText(sRight); + sal_uInt32 nIndex = GetControlIndex( TOKEN_TEXT ); + OUString strName(m_sAccessibleName + OUString::number(nIndex)); + if ( nIndex == 1) + { + /*Press left or right arrow to choose the structure controls*/ + strName += " (" + m_sAdditionalAccnameString2 + ", " + /*Press Ctrl+Alt+A to move focus for more operations*/ + + m_sAdditionalAccnameString1 + ", " + /*Press Ctrl+Alt+B to move focus back to the current structure control*/ + + m_sAdditionalAccnameString3 + ")"; + } + pEdit->SetAccessibleName(strName); + pEdit->AdjustSize(); + pEdit->SetModifyHdl(LINK(this, SwTokenWindow, EditResize )); + pEdit->SetPrevNextLink(LINK(this, SwTokenWindow, NextItemHdl)); + pEdit->SetGetFocusHdl(LINK(this, SwTokenWindow, TbxFocusHdl)); + pEdit->Show(); + } + else + { + m_pActiveCtrl->Hide(); + m_pActiveCtrl = nullptr; + iterActive = m_aControlList.erase(iterActive); + } + + //now the new button + SwTOXButton* pButton = new SwTOXButton(this, aToInsertToken); + m_aControlList.emplace(iterActive, pButton); + + pButton->SetPrevNextLink(LINK(this, SwTokenWindow, NextItemBtnHdl)); + pButton->SetGetFocusHdl(LINK(this, SwTokenWindow, TbxFocusBtnHdl)); + + if (TOKEN_AUTHORITY != aToInsertToken.eTokenType) + { + pButton->SetText(m_aButtonTexts[aToInsertToken.eTokenType]); + } + else + { + //use the first two chars as symbol + OUString sTmp(SwAuthorityFieldType::GetAuthFieldName( + static_cast<ToxAuthorityField>(aToInsertToken.nAuthorityField))); + pButton->SetText(sTmp.copy(0, 2)); + } + + pButton->Check(); + pButton->Show(); + SetActiveControl(pButton); + + AdjustPositions(); +} + +void SwTokenWindow::RemoveControl(const SwTOXButton* pDel, bool bInternalCall) +{ + if (bInternalCall && TOX_AUTHORITIES == m_pForm->GetTOXType()) + m_pParent->PreTokenButtonRemoved(pDel->GetFormToken()); + + auto it = std::find_if(m_aControlList.begin(), m_aControlList.end(), + [pDel](const auto& rControl) + { + SwTOXWidget* pCtrl = rControl.get(); + return pCtrl == pDel; + }); + assert(it != m_aControlList.end()); //Control does not exist! + if (it == m_aControlList.end()) + return; + + // the two neighbours of the box must be merged + // the properties of the right one will be lost + assert(it != m_aControlList.begin() && it != m_aControlList.end() - 1); //Button at first or last position? + if (it == m_aControlList.begin() || it == m_aControlList.end() - 1) + return; + + auto itLeft = it, itRight = it; + --itLeft; + ++itRight; + SwTOXWidget* pLeftEdit = itLeft->get(); + SwTOXWidget* pRightEdit = itRight->get(); + + static_cast<SwTOXEdit*>(pLeftEdit)->SetText(static_cast<SwTOXEdit*>(pLeftEdit)->GetText() + + static_cast<SwTOXEdit*>(pRightEdit)->GetText()); + static_cast<SwTOXEdit*>(pLeftEdit)->AdjustSize(); + + m_pActiveCtrl->Hide(); + m_pActiveCtrl = nullptr; + + m_aControlList.erase(itRight); + m_aControlList.erase(it); + + SetActiveControl(pLeftEdit); + AdjustPositions(); + m_aModifyHdl.Call(nullptr); +} + +IMPL_LINK_NOARG(SwTokenWindow, AdjustPositionsHdl, const Size&, void) +{ + AdjustScrolling(); +} + +void SwTokenWindow::AdjustPositions() +{ + for (size_t i = 0; i < m_aControlList.size(); ++i) + m_aControlList[i]->set_grid_left_attach(i); + AdjustScrolling(); +} + +void SwTokenWindow::MoveControls(tools::Long nOffset) +{ + m_xScrollWin->hadjustment_set_value(nOffset); +} + +IMPL_LINK_NOARG(SwTokenWindow, ScrollHdl, weld::ScrolledWindow&, void) +{ + AdjustScrolling(); +} + +void SwTokenWindow::AdjustScrolling() +{ + if (m_aControlList.size() <= 1) + return; + + //validate scroll buttons + + auto nLeft = m_xScrollWin->hadjustment_get_value(); + auto nSpace = m_xScrollWin->hadjustment_get_page_size(); + auto nWidth = m_xScrollWin->hadjustment_get_upper(); + + bool bEnable = nWidth > nSpace; + + //the active control must be visible + if (bEnable && m_pActiveCtrl) + { + int x, y, width, height; + m_pActiveCtrl->get_extents_relative_to(*m_xCtrlParentWin, x, y, width, height); + + if (x < nLeft || x + width > nLeft + nSpace) + { + MoveControls(x); + nLeft = x; + } + + m_xLeftScrollWin->set_sensitive(nLeft > 0); + m_xRightScrollWin->set_sensitive(nLeft + nSpace < nWidth); + } + else + { + //if the control fits into the space then the first control must be at position 0 + m_xRightScrollWin->set_sensitive(false); + m_xLeftScrollWin->set_sensitive(false); + } +} + +IMPL_LINK(SwTokenWindow, ScrollBtnHdl, weld::Button&, rBtn, void) +{ + if (m_aControlList.empty()) + return; + + const auto nSpace = m_xScrollWin->hadjustment_get_page_size(); + const auto nWidth = m_xScrollWin->hadjustment_get_upper(); + const auto nLeft = m_xScrollWin->hadjustment_get_value(); + + tools::Long nMove = nLeft; + if (&rBtn == m_xLeftScrollWin.get()) + { + //find the first completely visible control (left edge visible) + auto it = std::find_if(m_aControlList.begin(), m_aControlList.end(), + [this, nLeft](const auto& rControl) + { + SwTOXWidget* pCtrl = rControl.get(); + + int x, y, width, height; + pCtrl->get_extents_relative_to(*m_xCtrlParentWin, x, y, width, height); + + return x >= nLeft; + }); + if (it != m_aControlList.end()) + { + if (it == m_aControlList.begin()) + { + nMove = 0; + } + else + { + //move the left neighbor to the start position + auto itLeft = it; + --itLeft; + SwTOXWidget* pLeft = itLeft->get(); + + int x, y, width, height; + pLeft->get_extents_relative_to(*m_xCtrlParentWin, x, y, width, height); + + nMove = x; + } + } + } + else + { + //find the first completely visible control (right edge visible) + auto it = std::find_if(m_aControlList.rbegin(), m_aControlList.rend(), + [this, nLeft, nSpace](const auto& rControl) { + SwTOXWidget* pCtrl = rControl.get(); + + int x, y, width, height; + pCtrl->get_extents_relative_to(*m_xCtrlParentWin, x, y, width, height); + + auto nXPos = x + width; + return nXPos <= nLeft + nSpace; + }); + if (it != m_aControlList.rend() && it != m_aControlList.rbegin()) + { + //move the right neighbor to the right edge right aligned + auto itRight = it; + --itRight; + SwTOXWidget* pRight = itRight->get(); + + int x, y, width, height; + pRight->get_extents_relative_to(*m_xCtrlParentWin, x, y, width, height); + + nMove = x + width - nSpace; + } + + //move it left until it's completely visible + } + + if (nMove != nLeft) + { + // move the complete list + MoveControls(nMove); + m_xLeftScrollWin->set_sensitive(nMove > 0); + m_xRightScrollWin->set_sensitive(nMove + nSpace < nWidth); + } +} + +OUString SwTokenWindow::GetPattern() const +{ + OUStringBuffer sRet; + + for (const auto& elem : m_aControlList) + { + const SwTOXWidget* pCtrl = elem.get(); + + const SwFormToken &rNewToken = pCtrl->GetType() == WindowType::EDIT + ? const_cast<SwTOXEdit*>(static_cast<const SwTOXEdit*>(pCtrl))->GetFormToken() + : static_cast<const SwTOXButton*>(pCtrl)->GetFormToken(); + + //TODO: prevent input of TOX_STYLE_DELIMITER in KeyInput + sRet.append(rNewToken.GetString()); + } + + return sRet.makeStringAndClear(); +} + +// Check if a control of the specified TokenType is already contained in the list +bool SwTokenWindow::Contains(FormTokenType eSearchFor) const +{ + bool bRet = false; + + for (const auto& elem : m_aControlList) + { + const SwTOXWidget* pCtrl = elem.get(); + const SwFormToken &rNewToken = pCtrl->GetType() == WindowType::EDIT + ? const_cast<SwTOXEdit*>(static_cast<const SwTOXEdit*>(pCtrl))->GetFormToken() + : static_cast<const SwTOXButton*>(pCtrl)->GetFormToken(); + + if (eSearchFor == rNewToken.eTokenType) + { + bRet = true; + break; + } + } + + return bRet; +} + +OUString SwTokenWindow::CreateQuickHelp(const SwFormToken& rToken) +{ + OUString sEntry; + if (rToken.eTokenType != TOKEN_AUTHORITY) + sEntry = m_aButtonHelpTexts[rToken.eTokenType]; + else + { + sEntry += SwAuthorityFieldType::GetAuthFieldName( + static_cast<ToxAuthorityField>(rToken.nAuthorityField)); + } + + if (rToken.eTokenType != TOKEN_TAB_STOP) + { + if (!rToken.sCharStyleName.isEmpty()) + { + sEntry += " " + m_sCharStyle + rToken.sCharStyleName; + } + } + + return sEntry; +} + +IMPL_LINK(SwTokenWindow, EditResize, SwTOXEdit&, rEdit, void) +{ + rEdit.AdjustSize(); + AdjustPositions(); + m_aModifyHdl.Call(nullptr); +} + +IMPL_LINK(SwTokenWindow, NextItemHdl, SwTOXEdit&, rEdit, void) +{ + auto it = std::find_if(m_aControlList.begin(), m_aControlList.end(), + [&rEdit](const auto& rControl) + { + SwTOXWidget* pCtrl = rControl.get(); + return pCtrl == &rEdit; + }); + + if (it == m_aControlList.end()) + return; + + auto itTest = it; + ++itTest; + + if ((it != m_aControlList.begin() && !rEdit.IsNextControl()) || + (itTest != m_aControlList.end() && rEdit.IsNextControl())) + { + auto iterFocus = it; + rEdit.IsNextControl() ? ++iterFocus : --iterFocus; + + SwTOXWidget *pCtrlFocus = iterFocus->get(); + pCtrlFocus->GrabFocus(); + static_cast<SwTOXButton*>(pCtrlFocus)->Check(); + + AdjustScrolling(); + } +} + +IMPL_LINK(SwTokenWindow, TbxFocusHdl, SwTOXWidget&, rControl, void) +{ + SwTOXEdit* pEdit = static_cast<SwTOXEdit*>(&rControl); + for (const auto& aControl : m_aControlList) + { + SwTOXWidget* pCtrl = aControl.get(); + if (pCtrl && pCtrl->GetType() != WindowType::EDIT) + static_cast<SwTOXButton*>(pCtrl)->Check(false); + } + + SetActiveControl(pEdit); +} + +IMPL_LINK(SwTokenWindow, NextItemBtnHdl, SwTOXButton&, rBtn, void ) +{ + auto it = std::find_if(m_aControlList.begin(), m_aControlList.end(), + [&rBtn](const auto& rControl) + { + SwTOXWidget* pCtrl = rControl.get(); + return pCtrl == &rBtn; + }); + + if (it == m_aControlList.end()) + return; + + auto itTest = it; + ++itTest; + + if (rBtn.IsNextControl() && (itTest == m_aControlList.end() || !rBtn.IsNextControl())) + return; + + bool isNext = rBtn.IsNextControl(); + + auto iterFocus = it; + isNext ? ++iterFocus : --iterFocus; + + SwTOXWidget* pCtrlFocus = iterFocus->get(); + pCtrlFocus->GrabFocus(); + int nStartPos(0), nEndPos(0); + + if (!isNext) + { + const sal_Int32 nLen = static_cast<SwTOXEdit*>(pCtrlFocus)->GetText().getLength(); + + nStartPos = nLen; + nEndPos = nLen; + } + + static_cast<SwTOXEdit*>(pCtrlFocus)->select_region(nStartPos, nEndPos); + + rBtn.Check(false); + + AdjustScrolling(); +} + +IMPL_LINK(SwTokenWindow, TbxFocusBtnHdl, SwTOXWidget&, rControl, void) +{ + SwTOXButton* pBtn = static_cast<SwTOXButton*>(&rControl); + for (const auto& aControl : m_aControlList) + { + SwTOXWidget* pControl = aControl.get(); + + if (pControl && WindowType::EDIT != pControl->GetType()) + static_cast<SwTOXButton*>(pControl)->Check(pBtn == pControl); + } + + SetActiveControl(pBtn); +} + +void SwTokenWindow::SetFocus2theAllBtn() +{ + if (m_pParent) + { + m_pParent->SetFocus2theAllBtn(); + } +} + +sal_uInt32 SwTokenWindow::GetControlIndex(FormTokenType eType) const +{ + //there are only one entry-text button and only one page-number button, + //so we need not add index for these two buttons. + if ( eType == TOKEN_ENTRY_TEXT || eType == TOKEN_PAGE_NUMS ) + { + return 0; + } + + sal_uInt32 nIndex = 0; + for (const auto& elem : m_aControlList) + { + const SwTOXWidget* pControl = elem.get(); + + const SwFormToken& rNewToken = WindowType::EDIT == pControl->GetType() + ? const_cast<SwTOXEdit*>(static_cast<const SwTOXEdit*>(pControl))->GetFormToken() + : static_cast<const SwTOXButton*>(pControl)->GetFormToken(); + + if(eType == rNewToken.eTokenType) + { + ++nIndex; + } + } + + return nIndex; +} + +SwTOXStylesTabPage::SwTOXStylesTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/tocstylespage.ui", "TocStylesPage", &rAttrSet) + , m_xLevelLB(m_xBuilder->weld_tree_view("levels")) + , m_xAssignBT(m_xBuilder->weld_button("assign")) + , m_xParaLayLB(m_xBuilder->weld_tree_view("styles")) + , m_xStdBT(m_xBuilder->weld_button("default")) + , m_xEditStyleBT(m_xBuilder->weld_button("edit")) +{ + m_xParaLayLB->make_sorted(); + auto nHeight = m_xLevelLB->get_height_rows(16); + m_xLevelLB->set_size_request(-1, nHeight); + m_xParaLayLB->set_size_request(-1, nHeight); + + SetExchangeSupport(); + + m_xEditStyleBT->connect_clicked(LINK(this, SwTOXStylesTabPage, EditStyleHdl)); + m_xAssignBT->connect_clicked(LINK(this, SwTOXStylesTabPage, AssignHdl)); + m_xStdBT->connect_clicked(LINK(this, SwTOXStylesTabPage, StdHdl)); + m_xParaLayLB->connect_changed(LINK(this, SwTOXStylesTabPage, EnableSelectHdl)); + m_xLevelLB->connect_changed(LINK(this, SwTOXStylesTabPage, EnableSelectHdl)); + m_xParaLayLB->connect_row_activated(LINK(this, SwTOXStylesTabPage, DoubleClickHdl)); +} + +SwTOXStylesTabPage::~SwTOXStylesTabPage() +{ +} + +bool SwTOXStylesTabPage::FillItemSet( SfxItemSet* ) +{ + return true; +} + +void SwTOXStylesTabPage::Reset( const SfxItemSet* rSet ) +{ + ActivatePage(*rSet); +} + +void SwTOXStylesTabPage::ActivatePage( const SfxItemSet& ) +{ + m_pCurrentForm.reset(new SwForm(GetForm())); + + // not hyperlink for user directories + const sal_uInt16 nSize = m_pCurrentForm->GetFormMax(); + + // display form pattern without title + + m_xLevelLB->freeze(); + m_xLevelLB->clear(); + // display 1st TemplateEntry + OUString aStr( SwResId( STR_TITLE )); + if( !m_pCurrentForm->GetTemplate( 0 ).isEmpty() ) + { + aStr += " " + OUStringChar(aDeliStart) + + m_pCurrentForm->GetTemplate( 0 ) + + OUStringChar(aDeliEnd); + } + m_xLevelLB->append_text(aStr); + + for( sal_uInt16 i=1; i < nSize; ++i ) + { + if( TOX_INDEX == m_pCurrentForm->GetTOXType() && + FORM_ALPHA_DELIMITER == i ) + { + aStr = SwResId(STR_ALPHA); + } + else + { + aStr = SwResId(STR_LEVEL) + OUString::number( + TOX_INDEX == m_pCurrentForm->GetTOXType() ? i - 1 : i ); + } + if( !m_pCurrentForm->GetTemplate( i ).isEmpty() ) + { + aStr += " " + OUStringChar(aDeliStart) + + m_pCurrentForm->GetTemplate( i ) + + OUStringChar(aDeliEnd); + } + m_xLevelLB->append_text(aStr); + } + m_xLevelLB->thaw(); + + // initialise templates + SwWrtShell& rSh = static_cast<SwMultiTOXTabDialog*>(GetDialogController())->GetWrtShell(); + const sal_uInt16 nSz = rSh.GetTextFormatCollCount(); + + m_xParaLayLB->freeze(); + m_xParaLayLB->clear(); + for( sal_uInt16 i = 0; i < nSz; ++i ) + { + const SwTextFormatColl *pColl = &rSh.GetTextFormatColl( i ); + if( !pColl->IsDefault() ) + m_xParaLayLB->append_text( pColl->GetName() ); + } + + // query pool collections and set them for the directory + for( sal_uInt16 i = 0; i < m_pCurrentForm->GetFormMax(); ++i ) + { + aStr = m_pCurrentForm->GetTemplate( i ); + if (!aStr.isEmpty() && m_xParaLayLB->find_text(aStr) == -1) + m_xParaLayLB->append_text(aStr); + } + m_xParaLayLB->thaw(); + + EnableSelectHdl(*m_xParaLayLB); +} + +DeactivateRC SwTOXStylesTabPage::DeactivatePage( SfxItemSet* /*pSet*/ ) +{ + GetForm() = *m_pCurrentForm; + return DeactivateRC::LeavePage; +} + +std::unique_ptr<SfxTabPage> SwTOXStylesTabPage::Create(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwTOXStylesTabPage>(pPage, pController, *rAttrSet); +} + +IMPL_LINK_NOARG(SwTOXStylesTabPage, EditStyleHdl, weld::Button&, void) +{ + if (m_xParaLayLB->get_selected_index() != -1) + { + SfxStringItem aStyle(SID_STYLE_EDIT, m_xParaLayLB->get_selected_text()); + SfxUInt16Item aFamily(SID_STYLE_FAMILY, sal_uInt16(SfxStyleFamily::Para)); + SwWrtShell& rSh = static_cast<SwMultiTOXTabDialog*>(GetDialogController())->GetWrtShell(); + rSh.GetView().GetViewFrame().GetDispatcher()->ExecuteList(SID_STYLE_EDIT, + SfxCallMode::SYNCHRON, + { &aStyle, &aFamily }); + } +} + +// allocate templates +IMPL_LINK_NOARG(SwTOXStylesTabPage, AssignHdl, weld::Button&, void) +{ + auto nLevPos = m_xLevelLB->get_selected_index(); + auto nTemplPos = m_xParaLayLB->get_selected_index(); + if (nLevPos == -1 || nTemplPos == -1) + return; + + const OUString aStr(o3tl::getToken(m_xLevelLB->get_text(nLevPos), 0, aDeliStart) + + OUStringChar(aDeliStart) + + m_xParaLayLB->get_selected_text() + + OUStringChar(aDeliEnd)); + + m_pCurrentForm->SetTemplate(nLevPos, m_xParaLayLB->get_selected_text()); + + m_xLevelLB->remove(nLevPos); + m_xLevelLB->insert_text(nLevPos, aStr); + m_xLevelLB->select_text(aStr); + Modify(); +} + +IMPL_LINK_NOARG(SwTOXStylesTabPage, StdHdl, weld::Button&, void) +{ + const auto nPos = m_xLevelLB->get_selected_index(); + if (nPos != -1) + { + const OUString aStr(m_xLevelLB->get_text(nPos).getToken(0, aDeliStart)); + m_xLevelLB->remove(nPos); + m_xLevelLB->insert_text(nPos, aStr); + m_xLevelLB->select_text(aStr); + m_pCurrentForm->SetTemplate(nPos, OUString()); + Modify(); + } +} + +IMPL_LINK_NOARG(SwTOXStylesTabPage, DoubleClickHdl, weld::TreeView&, bool) +{ + const OUString aTmpName(m_xParaLayLB->get_selected_text()); + SwWrtShell& rSh = static_cast<SwMultiTOXTabDialog*>(GetDialogController())->GetWrtShell(); + + if(m_xParaLayLB->get_selected_index() != -1 && + (m_xLevelLB->get_selected_index() == 0 || SwMultiTOXTabDialog::IsNoNum(rSh, aTmpName))) + AssignHdl(*m_xAssignBT); + + return true; +} + +// enable only when selected +IMPL_LINK_NOARG(SwTOXStylesTabPage, EnableSelectHdl, weld::TreeView&, void) +{ + m_xStdBT->set_sensitive(m_xLevelLB->get_selected_index() != -1); + + SwWrtShell& rSh = static_cast<SwMultiTOXTabDialog*>(GetDialogController())->GetWrtShell(); + const OUString aTmpName(m_xParaLayLB->get_selected_text()); + m_xAssignBT->set_sensitive(m_xParaLayLB->get_selected_index() != -1 && + m_xLevelLB->get_selected_index() != -1 && + (m_xLevelLB->get_selected_index() == 0 || SwMultiTOXTabDialog::IsNoNum(rSh, aTmpName))); + m_xEditStyleBT->set_sensitive(m_xParaLayLB->get_selected_index() != -1); +} + +void SwTOXStylesTabPage::Modify() +{ + SwMultiTOXTabDialog* pTOXDlg = static_cast<SwMultiTOXTabDialog*>(GetDialogController()); + if (pTOXDlg) + { + GetForm() = *m_pCurrentForm; + pTOXDlg->CreateOrUpdateExample(pTOXDlg->GetCurrentTOXType().eType, TOX_PAGE_STYLES); + } +} + +#define ITEM_SEARCH 1 +#define ITEM_ALTERNATIVE 2 +#define ITEM_PRIM_KEY 3 +#define ITEM_SEC_KEY 4 +#define ITEM_COMMENT 5 +#define ITEM_CASE 6 +#define ITEM_WORDONLY 7 + +SwEntryBrowseBox::SwEntryBrowseBox(const css::uno::Reference<css::awt::XWindow> &rParent) + : SwEntryBrowseBox_Base(VCLUnoHelper::GetWindow(rParent), EditBrowseBoxFlags::NONE, WB_TABSTOP | WB_BORDER, + BrowserMode::KEEPHIGHLIGHT | + BrowserMode::COLUMNSELECTION | + BrowserMode::MULTISELECTION | + BrowserMode::TRACKING_TIPS | + BrowserMode::HLINES | + BrowserMode::VLINES | + BrowserMode::AUTO_VSCROLL| + BrowserMode::HIDECURSOR ) + , m_aCellEdit(VclPtr<svt::EditControl>::Create(&GetDataWindow())) + , m_aCellCheckBox(VclPtr<svt::CheckBoxControl>::Create(&GetDataWindow())) + , m_nCurrentRow(0) + , m_bModified(false) +{ + OUString sSearch = SwResId(STR_AUTOMARK_SEARCHTERM); + OUString sAlternative = SwResId(STR_AUTOMARK_ALTERNATIVE); + OUString sPrimKey = SwResId(STR_AUTOMARK_KEY1); + OUString sSecKey = SwResId(STR_AUTOMARK_KEY2); + OUString sComment = SwResId(STR_AUTOMARK_COMMENT); + OUString sCaseSensitive = SwResId(STR_AUTOMARK_CASESENSITIVE); + OUString sWordOnly = SwResId(STR_AUTOMARK_WORDONLY); + m_sYes = SwResId(STR_AUTOMARK_YES); + m_sNo = SwResId(STR_AUTOMARK_NO); + + m_aCellCheckBox->EnableTriState(false); + m_xController = new ::svt::EditCellController(m_aCellEdit.get()); + m_xCheckController = new ::svt::CheckBoxCellController(m_aCellCheckBox.get()); + + // HACK: BrowseBox doesn't invalidate its children, how it should be. + // That's why WB_CLIPCHILDREN is reset in order to enforce the + // children' invalidation + WinBits aStyle = GetStyle(); + if( aStyle & WB_CLIPCHILDREN ) + { + aStyle &= ~WB_CLIPCHILDREN; + SetStyle( aStyle ); + } + + const OUString* aTitles[7] = + { + &sSearch, + &sAlternative, + &sPrimKey, + &sSecKey, + &sComment, + &sCaseSensitive, + &sWordOnly + }; + + tools::Long nWidth = GetSizePixel().Width(); + nWidth /=7; + --nWidth; + for(sal_uInt16 i = 1; i < 8; i++) + InsertDataColumn( i, *aTitles[i - 1], nWidth ); +} + +SwEntryBrowseBox::~SwEntryBrowseBox() +{ + disposeOnce(); +} + +void SwEntryBrowseBox::dispose() +{ + m_aCellEdit.disposeAndClear(); + m_aCellCheckBox.disposeAndClear(); + SwEntryBrowseBox_Base::dispose(); +} + +void SwEntryBrowseBox::Resize() +{ + SwEntryBrowseBox_Base::Resize(); + + tools::Long nWidth = GetSizePixel().Width(); + std::vector<tools::Long> aWidths = GetOptimalColWidths(); + tools::Long nNaturalWidth(std::accumulate(aWidths.begin(), aWidths.end(), 0)); + tools::Long nExcess = ((nWidth - nNaturalWidth) / aWidths.size()) - 1; + + for (size_t i = 0; i < aWidths.size(); ++i) + SetColumnWidth(i+1, aWidths[i] + nExcess); +} + +std::vector<tools::Long> SwEntryBrowseBox::GetOptimalColWidths() const +{ + std::vector<tools::Long> aWidths; + + tools::Long nStandardColMinWidth = approximate_digit_width() * 15; + tools::Long nYesNoWidth = approximate_digit_width() * 5; + nYesNoWidth = std::max(nYesNoWidth, GetTextWidth(m_sYes)); + nYesNoWidth = std::max(nYesNoWidth, GetTextWidth(m_sNo)); + for (sal_uInt16 i = 1; i < 6; i++) + { + tools::Long nColWidth = std::max(nStandardColMinWidth, + GetTextWidth(GetColumnTitle(i))); + nColWidth += 12; + aWidths.push_back(nColWidth); + } + + for (sal_uInt16 i = 6; i < 8; i++) + { + tools::Long nColWidth = std::max(nYesNoWidth, + GetTextWidth(GetColumnTitle(i))); + nColWidth += 12; + aWidths.push_back(nColWidth); + } + + return aWidths; +} + +Size SwEntryBrowseBox::GetOptimalSize() const +{ + Size aSize = LogicToPixel(Size(276 , 175), MapMode(MapUnit::MapAppFont)); + + std::vector<tools::Long> aWidths = GetOptimalColWidths(); + + tools::Long nWidth(std::accumulate(aWidths.begin(), aWidths.end(), 0)); + + aSize.setWidth( std::max(aSize.Width(), nWidth) ); + + return aSize; +} + +bool SwEntryBrowseBox::SeekRow( sal_Int32 nRow ) +{ + m_nCurrentRow = nRow; + return true; +} + +OUString SwEntryBrowseBox::GetCellText(sal_Int32 nRow, sal_uInt16 nColumn) const +{ + OUString pRet; + if (o3tl::make_unsigned(nRow) < m_Entries.size()) + { + const AutoMarkEntry* pEntry = m_Entries[ nRow ].get(); + switch(nColumn) + { + case ITEM_SEARCH : pRet = pEntry->sSearch; break; + case ITEM_ALTERNATIVE : pRet = pEntry->sAlternative; break; + case ITEM_PRIM_KEY : pRet = pEntry->sPrimKey; break; + case ITEM_SEC_KEY : pRet = pEntry->sSecKey; break; + case ITEM_COMMENT : pRet = pEntry->sComment; break; + case ITEM_CASE : pRet = pEntry->bCase ? m_sYes : m_sNo; break; + case ITEM_WORDONLY : pRet = pEntry->bWord ? m_sYes : m_sNo; break; + } + } + return pRet; +} + +void SwEntryBrowseBox::PaintCell(OutputDevice& rDev, + const tools::Rectangle& rRect, sal_uInt16 nColumnId) const +{ + const DrawTextFlags nStyle = DrawTextFlags::Clip | DrawTextFlags::Center; + rDev.DrawText( rRect, GetCellText( m_nCurrentRow, nColumnId ), nStyle ); +} + +::svt::CellController* SwEntryBrowseBox::GetController(sal_Int32 /*nRow*/, sal_uInt16 nCol) +{ + return nCol < ITEM_CASE ? m_xController.get() : m_xCheckController.get(); +} + +bool SwEntryBrowseBox::SaveModified() +{ + m_bModified = true; + const size_t nRow = GetCurRow(); + const sal_uInt16 nCol = GetCurColumnId(); + + OUString sNew; + bool bVal = false; + ::svt::CellController* pController = nullptr; + if(nCol < ITEM_CASE) + { + pController = m_xController.get(); + sNew = static_cast< ::svt::EditCellController*>(pController)->GetEditImplementation()->GetText( LINEEND_LF ); + } + else + { + pController = m_xCheckController.get(); + bVal = static_cast< ::svt::CheckBoxCellController*>(pController)->GetCheckBox().get_active(); + } + const bool bAddEntry = nRow >= m_Entries.size(); + std::unique_ptr<AutoMarkEntry> xNewEntry(bAddEntry ? new AutoMarkEntry : nullptr); + AutoMarkEntry* pEntry = bAddEntry ? xNewEntry.get() : m_Entries[nRow].get(); + switch(nCol) + { + case ITEM_SEARCH : pEntry->sSearch = sNew; break; + case ITEM_ALTERNATIVE : pEntry->sAlternative = sNew; break; + case ITEM_PRIM_KEY : pEntry->sPrimKey = sNew; break; + case ITEM_SEC_KEY : pEntry->sSecKey = sNew; break; + case ITEM_COMMENT : pEntry->sComment = sNew; break; + case ITEM_CASE : pEntry->bCase = bVal; break; + case ITEM_WORDONLY : pEntry->bWord = bVal; break; + } + if (bAddEntry) + { + m_Entries.push_back(std::move(xNewEntry)); + RowInserted(nRow, 1, true, true); + if(nCol < ITEM_WORDONLY) + { + pController->SaveValue(); + GoToRow( nRow ); + } + } + return true; +} + +void SwEntryBrowseBox::InitController( + ::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol) +{ + const OUString rText = GetCellText( nRow, nCol ); + if(nCol < ITEM_CASE) + { + rController = m_xController; + ::svt::CellController* pController = m_xController.get(); + static_cast< ::svt::EditCellController*>(pController)->GetEditImplementation()->SetText( rText ); + } + else + { + rController = m_xCheckController; + ::svt::CellController* pController = m_xCheckController.get(); + static_cast< ::svt::CheckBoxCellController*>(pController)->GetCheckBox().set_active( + rText == m_sYes ); + } +} + +void SwEntryBrowseBox::ReadEntries(SvStream& rInStr) +{ + AutoMarkEntry* pToInsert = nullptr; + // tdf#108910, tdf#125496 - read index entries using the appropriate character set + rtl_TextEncoding eTEnc = SwIoSystem::GetTextEncoding(rInStr); + if (eTEnc == RTL_TEXTENCODING_DONTKNOW) + eTEnc = osl_getThreadTextEncoding(); + while (rInStr.good()) + { + OUString sLine; + rInStr.ReadByteStringLine( sLine, eTEnc ); + + // # -> comment + // ; -> delimiter between entries -> + // Format: TextToSearchFor;AlternativeString;PrimaryKey;SecondaryKey + // Leading and trailing blanks are ignored + if( !sLine.isEmpty() ) + { + //comments are contained in separate lines but are put into the struct of the following data + //line (if available) + if( '#' != sLine[0] ) + { + if( !pToInsert ) + pToInsert = new AutoMarkEntry; + + sal_Int32 nSttPos = 0; + pToInsert->sSearch = sLine.getToken(0, ';', nSttPos ); + pToInsert->sAlternative = sLine.getToken(0, ';', nSttPos ); + pToInsert->sPrimKey = sLine.getToken(0, ';', nSttPos ); + pToInsert->sSecKey = sLine.getToken(0, ';', nSttPos ); + + std::u16string_view sStr = o3tl::getToken(sLine, 0, ';', nSttPos ); + pToInsert->bCase = !sStr.empty() && sStr != u"0"; + + sStr = o3tl::getToken(sLine, 0, ';', nSttPos ); + pToInsert->bWord = !sStr.empty() && sStr != u"0"; + + m_Entries.push_back(std::unique_ptr<AutoMarkEntry>(pToInsert)); + pToInsert = nullptr; + } + else + { + if(pToInsert) + m_Entries.push_back(std::unique_ptr<AutoMarkEntry>(pToInsert)); + pToInsert = new AutoMarkEntry; + pToInsert->sComment = sLine.copy(1); + } + } + } + if( pToInsert ) + m_Entries.push_back(std::unique_ptr<AutoMarkEntry>(pToInsert)); + RowInserted(0, m_Entries.size() + 1); +} + +void SwEntryBrowseBox::WriteEntries(SvStream& rOutStr) +{ + //check if the current controller is modified + const sal_uInt16 nCol = GetCurColumnId(); + ::svt::CellController* pController; + if(nCol < ITEM_CASE) + pController = m_xController.get(); + else + pController = m_xCheckController.get(); + if (pController->IsValueChangedFromSaved()) + GoToColumnId(nCol + (nCol < ITEM_CASE ? 1 : -1 )); + + for(const std::unique_ptr<AutoMarkEntry> & rpEntry : m_Entries) + { + AutoMarkEntry* pEntry = rpEntry.get(); + if(!pEntry->sComment.isEmpty()) + { + // tdf#108910, tdf#125496 - write index entries using the utf8 text encoding + rOutStr.WriteByteStringLine( Concat2View("#" + pEntry->sComment), RTL_TEXTENCODING_UTF8 ); + } + + OUString sWrite( pEntry->sSearch + ";" + + pEntry->sAlternative + ";" + + pEntry->sPrimKey + ";" + + pEntry->sSecKey + ";" + + (pEntry->bCase ? std::u16string_view(u"1") : std::u16string_view(u"0")) + + ";" + + (pEntry->bWord ? std::u16string_view(u"1") : std::u16string_view(u"0")) ); + + if( sWrite.getLength() > 5 ) + // tdf#108910, tdf#125496 - write index entries using the utf8 text encoding + rOutStr.WriteByteStringLine( sWrite, RTL_TEXTENCODING_UTF8 ); + } +} + +bool SwEntryBrowseBox::IsModified()const +{ + if(m_bModified) + return true; + + //check if the current controller is modified + const sal_uInt16 nCol = GetCurColumnId(); + ::svt::CellController* pController; + if(nCol < ITEM_CASE) + pController = m_xController.get(); + else + pController = m_xCheckController.get(); + return pController->IsValueChangedFromSaved(); +} + +SwAutoMarkDlg_Impl::SwAutoMarkDlg_Impl(weld::Window* pParent, OUString aAutoMarkURL, + bool bCreate) + : GenericDialogController(pParent, "modules/swriter/ui/createautomarkdialog.ui", "CreateAutomarkDialog") + , m_sAutoMarkURL(std::move(aAutoMarkURL)) + , m_bCreateMode(bCreate) + , m_xOKPB(m_xBuilder->weld_button("ok")) + , m_xTable(m_xBuilder->weld_container("area")) + , m_xTableCtrlParent(m_xTable->CreateChildFrame()) + , m_xEntriesBB(VclPtr<SwEntryBrowseBox>::Create(m_xTableCtrlParent)) +{ + m_xEntriesBB->Show(); + m_xOKPB->connect_clicked(LINK(this, SwAutoMarkDlg_Impl, OkHdl)); + + m_xDialog->set_title(m_xDialog->get_title() + ": " + m_sAutoMarkURL); + bool bError = false; + if( m_bCreateMode ) + m_xEntriesBB->RowInserted(0); + else + { + SfxMedium aMed( m_sAutoMarkURL, StreamMode::STD_READ ); + if( aMed.GetInStream() && !aMed.GetInStream()->GetError() ) + m_xEntriesBB->ReadEntries( *aMed.GetInStream() ); + else + bError = true; + } + + Size aPrefSize = m_xEntriesBB->GetOptimalSize(); + m_xTable->set_size_request(aPrefSize.Width(), aPrefSize.Height()); + + if (bError) + m_xDialog->response(RET_CANCEL); +} + +SwAutoMarkDlg_Impl::~SwAutoMarkDlg_Impl() +{ + m_xEntriesBB.disposeAndClear(); + m_xTableCtrlParent->dispose(); + m_xTableCtrlParent.clear(); +} + +IMPL_LINK_NOARG(SwAutoMarkDlg_Impl, OkHdl, weld::Button&, void) +{ + bool bError = false; + if (m_xEntriesBB->IsModified() || m_bCreateMode) + { + SfxMedium aMed( m_sAutoMarkURL, + m_bCreateMode ? StreamMode::WRITE + : StreamMode::WRITE| StreamMode::TRUNC ); + SvStream* pStrm = aMed.GetOutStream(); + // tdf#108910, tdf#125496 - write index entries using the utf8 text encoding + pStrm->SetStreamCharSet( RTL_TEXTENCODING_UTF8 ); + if( !pStrm->GetError() ) + { + m_xEntriesBB->WriteEntries( *pStrm ); + aMed.Commit(); + } + else + bError = true; + } + if (!bError) + m_xDialog->response(RET_OK); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/index/multmrk.cxx b/sw/source/ui/index/multmrk.cxx new file mode 100644 index 0000000000..e944bf24a5 --- /dev/null +++ b/sw/source/ui/index/multmrk.cxx @@ -0,0 +1,65 @@ +/* -*- 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 <multmrk.hxx> +#include <toxmgr.hxx> +#include <wrtsh.hxx> + +SwMultiTOXMarkDlg::SwMultiTOXMarkDlg(weld::Window* pParent, SwTOXMgr& rTOXMgr) + : GenericDialogController(pParent, "modules/swriter/ui/selectindexdialog.ui", + "SelectIndexDialog") + , m_rMgr(rTOXMgr) + , m_nPos(0) + , m_xTextFT(m_xBuilder->weld_label("type")) + , m_xTOXLB(m_xBuilder->weld_tree_view("treeview")) +{ + m_xTOXLB->set_size_request(m_xTOXLB->get_approximate_digit_width() * 32, + m_xTOXLB->get_height_rows(8)); + + m_xTOXLB->connect_changed(LINK(this, SwMultiTOXMarkDlg, SelectHdl)); + + sal_uInt16 nSize = m_rMgr.GetTOXMarkCount(); + for (sal_uInt16 i = 0; i < nSize; ++i) + m_xTOXLB->append_text(m_rMgr.GetTOXMark(i)->GetText(m_rMgr.GetShell()->GetLayout())); + + m_xTOXLB->select(0); + m_xTextFT->set_label(m_rMgr.GetTOXMark(0)->GetTOXType()->GetTypeName()); +} + +IMPL_LINK(SwMultiTOXMarkDlg, SelectHdl, weld::TreeView&, rBox, void) +{ + if (rBox.get_selected_index() != -1) + { + SwTOXMark* pMark = m_rMgr.GetTOXMark(rBox.get_selected_index()); + m_xTextFT->set_label(pMark->GetTOXType()->GetTypeName()); + m_nPos = rBox.get_selected_index(); + } +} + +short SwMultiTOXMarkDlg::run() +{ + short nRet = GenericDialogController::run(); + if (nRet == RET_OK) + m_rMgr.SetCurTOXMark(m_nPos); + return nRet; +} + +SwMultiTOXMarkDlg::~SwMultiTOXMarkDlg() {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/index/swuiidxmrk.cxx b/sw/source/ui/index/swuiidxmrk.cxx new file mode 100644 index 0000000000..39443f7e7b --- /dev/null +++ b/sw/source/ui/index/swuiidxmrk.cxx @@ -0,0 +1,1965 @@ +/* -*- 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 <swuiidxmrk.hxx> +#include <hintids.hxx> +#include <helpids.h> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/Bibliography.hpp> +#include <com/sun/star/i18n/IndexEntrySupplier.hpp> +#include <com/sun/star/util/SearchAlgorithms2.hpp> +#include <com/sun/star/util/SearchFlags.hpp> +#include <com/sun/star/uri/UriReferenceFactory.hpp> +#include <rtl/ustrbuf.hxx> +#include <i18nutil/searchopt.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/itemset.hxx> +#include <editeng/langitem.hxx> +#include <osl/diagnose.h> +#include <o3tl/string_view.hxx> +#include <swtypes.hxx> +#include <toxmgr.hxx> +#include <txttxmrk.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <swundo.hxx> +#include <cmdid.h> +#include <swmodule.hxx> +#include <fldmgr.hxx> +#include <fldbas.hxx> +#include <strings.hrc> +#include <svl/cjkoptions.hxx> +#include <sfx2/filedlghelper.hxx> +#include <ndtxt.hxx> +#include <SwRewriter.hxx> +#include <doc.hxx> +#include <docsh.hxx> + +#define POS_CONTENT 0 +#define POS_INDEX 1 + +static sal_Int32 nTypePos = 1; // TOX_INDEX as standard +static sal_uInt16 nKey1Pos = USHRT_MAX; + +static sal_uInt16 nKey2Pos = USHRT_MAX; + +using namespace com::sun::star; +using namespace com::sun::star::i18n; +using namespace com::sun::star::lang; +using namespace com::sun::star::util; +using namespace ::comphelper; + +namespace +{ +bool SplitUrlAndPage(const OUString& rText, OUString& rUrl, int& nPageNumber) +{ + uno::Reference<uri::XUriReferenceFactory> xUriReferenceFactory + = uri::UriReferenceFactory::create(comphelper::getProcessComponentContext()); + uno::Reference<uri::XUriReference> xUriRef; + try + { + xUriRef = xUriReferenceFactory->parse(rText); + } + catch (const uno::Exception& rException) + { + SAL_WARN("sw.ui", "SplitUrlAndPage: failed to parse url: " << rException.Message); + return false; + } + + OUString aPagePrefix("page="); + if (!xUriRef->getFragment().startsWith(aPagePrefix)) + { + return false; + } + + nPageNumber = o3tl::toInt32(xUriRef->getFragment().subView(aPagePrefix.getLength())); + xUriRef->clearFragment(); + rUrl = xUriRef->getUriReference(); + return true; +} + +OUString MergeUrlAndPage(const OUString& rUrl, const std::unique_ptr<weld::SpinButton>& xPageSB) +{ + if (!xPageSB->get_sensitive()) + { + return rUrl; + } + + uno::Reference<uri::XUriReferenceFactory> xUriReferenceFactory + = uri::UriReferenceFactory::create(comphelper::getProcessComponentContext()); + uno::Reference<uri::XUriReference> xUriRef; + try + { + xUriRef = xUriReferenceFactory->parse(rUrl); + } + catch (const uno::Exception& rException) + { + SAL_WARN("sw.ui", "MergeUrlAndPage: failed to parse url: " << rException.Message); + return rUrl; + } + + OUString aFragment("page=" + OUString::number(xPageSB->get_value())); + xUriRef->setFragment(aFragment); + return xUriRef->getUriReference(); +} +} + +// dialog to insert a directory selection +SwIndexMarkPane::SwIndexMarkPane(std::shared_ptr<weld::Dialog> xDialog, weld::Builder& rBuilder, bool bNewDlg, + SwWrtShell* pWrtShell) + : m_xDialog(std::move(xDialog)) + , m_bDel(false) + , m_bNewMark(bNewDlg) + , m_bSelected(false) + , m_bPhoneticED0_ChangedByUser(false) + , m_bPhoneticED1_ChangedByUser(false) + , m_bPhoneticED2_ChangedByUser(false) + , m_nLangForPhoneticReading(LANGUAGE_CHINESE_SIMPLIFIED) + , m_bIsPhoneticReadingEnabled(false) + , m_pSh(pWrtShell) + , m_xTypeFT(rBuilder.weld_label("typeft")) + , m_xTypeDCB(rBuilder.weld_combo_box("typecb")) + , m_xNewBT(rBuilder.weld_button("new")) + , m_xEntryED(rBuilder.weld_entry("entryed")) + , m_xSyncED(rBuilder.weld_button("sync")) + , m_xPhoneticFT0(rBuilder.weld_label("phonetic0ft")) + , m_xPhoneticED0(rBuilder.weld_entry("phonetic0ed")) + , m_xKey1FT(rBuilder.weld_label("key1ft")) + , m_xKey1DCB(rBuilder.weld_combo_box("key1cb")) + , m_xPhoneticFT1(rBuilder.weld_label("phonetic1ft")) + , m_xPhoneticED1(rBuilder.weld_entry("phonetic1ed")) + , m_xKey2FT(rBuilder.weld_label("key2ft")) + , m_xKey2DCB(rBuilder.weld_combo_box("key2cb")) + , m_xPhoneticFT2(rBuilder.weld_label("phonetic2ft")) + , m_xPhoneticED2(rBuilder.weld_entry("phonetic2ed")) + , m_xLevelFT(rBuilder.weld_label("levelft")) + , m_xLevelNF(rBuilder.weld_spin_button("levelnf")) + , m_xMainEntryCB(rBuilder.weld_check_button("mainentrycb")) + , m_xApplyToAllCB(rBuilder.weld_check_button("applytoallcb")) + , m_xSearchCaseSensitiveCB(rBuilder.weld_check_button("searchcasesensitivecb")) + , m_xSearchCaseWordOnlyCB(rBuilder.weld_check_button("searchcasewordonlycb")) + , m_xOKBT(bNewDlg ? rBuilder.weld_button("insert") : rBuilder.weld_button("ok")) + , m_xCloseBT(rBuilder.weld_button("close")) + , m_xDelBT(rBuilder.weld_button("delete")) + , m_xPrevSameBT(rBuilder.weld_button("first")) + , m_xNextSameBT(rBuilder.weld_button("last")) + , m_xPrevBT(rBuilder.weld_button("previous")) + , m_xNextBT(rBuilder.weld_button("next")) + , m_xForSelectedEntry(rBuilder.weld_label("selectedentrytitle")) +{ + m_xSyncED->show(); + + if (SvtCJKOptions::IsCJKFontEnabled()) + { + uno::Reference< uno::XComponentContext > xContext = getProcessComponentContext(); + + m_xExtendedIndexEntrySupplier = i18n::IndexEntrySupplier::create(xContext); + + m_xPhoneticFT0->show(); + m_xPhoneticED0->show(); + m_xPhoneticFT1->show(); + m_xPhoneticED1->show(); + m_xPhoneticFT2->show(); + m_xPhoneticED2->show(); + } + + // tdf#129726 there are two help pages for this dialog, one for each mode, + // where a widget/dialog appears in both, use -insert/-edit to disambiguate + if (m_bNewMark) + { + m_xDialog->set_title(SwResId(STR_IDXMRK_INSERT)); + m_xDialog->set_help_id(m_xDialog->get_help_id() + "-insert"); + m_xTypeDCB->set_help_id(m_xTypeDCB->get_help_id() + "-insert"); + } + else + { + m_xDialog->set_title(SwResId(STR_IDXMRK_EDIT)); + m_xDialog->set_help_id(m_xDialog->get_help_id() + "-edit"); + m_xTypeDCB->set_help_id(m_xTypeDCB->get_help_id() + "-edit"); + } + + m_xDelBT->connect_clicked(LINK(this,SwIndexMarkPane, DelHdl)); + m_xPrevBT->connect_clicked(LINK(this,SwIndexMarkPane, PrevHdl)); + m_xPrevSameBT->connect_clicked(LINK(this,SwIndexMarkPane, PrevSameHdl)); + m_xNextBT->connect_clicked(LINK(this,SwIndexMarkPane, NextHdl)); + m_xNextSameBT->connect_clicked(LINK(this,SwIndexMarkPane, NextSameHdl)); + m_xTypeDCB->connect_changed(LINK(this,SwIndexMarkPane, ModifyListBoxHdl)); + m_xKey1DCB->connect_changed(LINK(this,SwIndexMarkPane, KeyDCBModifyHdl)); + m_xKey2DCB->connect_changed(LINK(this,SwIndexMarkPane, KeyDCBModifyHdl)); + m_xCloseBT->connect_clicked(LINK(this,SwIndexMarkPane, CloseHdl)); + m_xEntryED->connect_changed(LINK(this,SwIndexMarkPane, ModifyEditHdl)); + m_xNewBT->connect_clicked(LINK(this, SwIndexMarkPane, NewUserIdxHdl)); + m_xApplyToAllCB->connect_toggled(LINK(this, SwIndexMarkPane, SearchTypeHdl)); + m_xPhoneticED0->connect_changed(LINK(this,SwIndexMarkPane, PhoneticEDModifyHdl)); + m_xPhoneticED1->connect_changed(LINK(this,SwIndexMarkPane, PhoneticEDModifyHdl)); + m_xPhoneticED2->connect_changed(LINK(this,SwIndexMarkPane, PhoneticEDModifyHdl)); + m_xSyncED->connect_clicked(LINK(this, SwIndexMarkPane, SyncSelectionHdl)); + + if (m_bNewMark) + m_xDelBT->hide(); + else + m_xNewBT->hide(); + m_xOKBT->show(); + m_xOKBT->connect_clicked(LINK(this, SwIndexMarkPane, InsertHdl)); + + m_xEntryED->grab_focus(); +} + +// Newly initialise controls with the new selection +void SwIndexMarkPane::InitControls() +{ + assert(m_pSh && m_pTOXMgr && "no shell?"); + // contents index + const SwTOXType* pType = m_pTOXMgr->GetTOXType(TOX_CONTENT); + assert(pType && "No directory type !!"); + OUString sTmpTypeSelection; + if (m_xTypeDCB->get_active() != -1) + sTmpTypeSelection = m_xTypeDCB->get_active_text(); + m_xTypeDCB->clear(); + m_xTypeDCB->append_text(pType->GetTypeName()); + + // keyword index + pType = m_pTOXMgr->GetTOXType(TOX_INDEX); + assert(pType && "No directory type !!"); + m_xTypeDCB->append_text(pType->GetTypeName()); + + // user index + sal_uInt16 nCount = m_pSh->GetTOXTypeCount(TOX_USER); + for (sal_uInt16 i = 0; i < nCount; ++i) + m_xTypeDCB->append_text(m_pSh->GetTOXType(TOX_USER, i)->GetTypeName()); + + // read keywords primary + { + std::vector<OUString> aArr; + m_pSh->GetTOIKeys(TOI_PRIMARY, aArr); + std::sort(aArr.begin(), aArr.end()); + auto last = std::unique(aArr.begin(), aArr.end()); + for (auto it = aArr.begin(); it != last; ++it) + m_xKey1DCB->append_text(*it); + } + + // read keywords secondary + { + std::vector<OUString> aArr; + m_pSh->GetTOIKeys( TOI_SECONDARY, aArr ); + std::sort(aArr.begin(), aArr.end()); + auto last = std::unique(aArr.begin(), aArr.end()); + for (auto it = aArr.begin(); it != last; ++it) + m_xKey2DCB->append_text(*it); + } + + UpdateLanguageDependenciesForPhoneticReading(); + + // current entry + const SwTOXMark* pMark = m_pTOXMgr->GetCurTOXMark(); + if( pMark && !m_bNewMark) + { + // Controls-Handling + + // only if there are more than one + // if equal it lands at the same entry + m_pSh->SttCursorMove(); + + const SwTOXMark* pMoveMark; + bool bShow = false; + + pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_PRV ); + if (!SfxPoolItem::areSame( pMoveMark, pMark )) + { + m_pSh->GotoTOXMark( *pMoveMark, TOX_NXT ); + bShow = true; + } + m_xPrevBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark)); + pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_NXT ); + if (!SfxPoolItem::areSame( pMoveMark, pMark )) + { + m_pSh->GotoTOXMark( *pMoveMark, TOX_PRV ); + bShow = true; + } + m_xNextBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark)); + if( bShow ) + { + m_xPrevBT->show(); + m_xNextBT->show(); + bShow = false; + } + + pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_PRV ); + if (!SfxPoolItem::areSame( pMoveMark, pMark )) + { + m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_NXT ); + bShow = true; + } + m_xPrevSameBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark)); + pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_NXT ); + if (!SfxPoolItem::areSame( pMoveMark, pMark )) + { + m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_PRV ); + bShow = true; + } + m_xNextSameBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark)); + if( bShow ) + { + m_xNextSameBT->show(); + m_xPrevSameBT->show(); + } + m_pSh->EndCursorMove(); + + m_xTypeFT->show(); + + m_xTypeDCB->set_sensitive(false); + m_xTypeFT->set_sensitive(false); + + UpdateDialog(); + } + else + { // display current selection (first element) ???? + if (m_pSh->GetCursorCnt() < 2) + { + m_bSelected = !m_pSh->HasSelection(); + m_aOrgStr = m_pSh->GetView().GetSelectionTextParam(true, false); + m_xEntryED->set_text(m_aOrgStr); + + //to include all equal entries may only be allowed in the body and even there + //only when a simple selection exists + const FrameTypeFlags nFrameType = m_pSh->GetFrameType(nullptr,true); + m_xForSelectedEntry->show(); + m_xApplyToAllCB->show(); + m_xSearchCaseSensitiveCB->show(); + m_xSearchCaseWordOnlyCB->show(); + m_xApplyToAllCB->set_sensitive(!m_aOrgStr.isEmpty() && + !(nFrameType & ( FrameTypeFlags::HEADER | FrameTypeFlags::FOOTER | FrameTypeFlags::FLY_ANY ))); + SearchTypeHdl(*m_xApplyToAllCB); + } + + // index type is default + if (!sTmpTypeSelection.isEmpty() && m_xTypeDCB->find_text(sTmpTypeSelection) != -1) + m_xTypeDCB->set_active_text(sTmpTypeSelection); + else + m_xTypeDCB->set_active_text(m_xTypeDCB->get_text(nTypePos)); + ModifyHdl(*m_xTypeDCB); + } +} + +void SwIndexMarkPane::UpdateLanguageDependenciesForPhoneticReading() +{ + //no phonetic reading if no global cjk support + if( !m_xExtendedIndexEntrySupplier.is() ) + { + m_bIsPhoneticReadingEnabled = false; + return; + } + m_bIsPhoneticReadingEnabled = true; + + //get the current language + if(!m_bNewMark) //if dialog is opened to iterate existing marks + { + OSL_ENSURE(m_pTOXMgr, "need TOXMgr"); + if(!m_pTOXMgr) + return; + SwTOXMark* pMark = m_pTOXMgr->GetCurTOXMark(); + OSL_ENSURE(pMark, "need current SwTOXMark"); + if(!pMark) + return; + SwTextTOXMark* pTextTOXMark = pMark->GetTextTOXMark(); + OSL_ENSURE(pTextTOXMark, "need current SwTextTOXMark"); + if(!pTextTOXMark) + return; + const SwTextNode* pTextNode = pTextTOXMark->GetpTextNd(); + OSL_ENSURE(pTextNode, "need current SwTextNode"); + if(!pTextNode) + return; + sal_Int32 nTextIndex = pTextTOXMark->GetStart(); + m_nLangForPhoneticReading = pTextNode->GetLang( nTextIndex ); + } + else //if dialog is opened to create a new mark + { + sal_uInt16 nWhich; + switch(m_pSh->GetScriptType()) + { + case SvtScriptType::ASIAN: nWhich = RES_CHRATR_CJK_LANGUAGE; break; + case SvtScriptType::COMPLEX:nWhich = RES_CHRATR_CTL_LANGUAGE; break; + default:nWhich = RES_CHRATR_LANGUAGE; break; + } + SfxItemSet aLangSet(m_pSh->GetAttrPool(), nWhich, nWhich); + m_pSh->GetCurAttr(aLangSet); + m_nLangForPhoneticReading = static_cast<const SvxLanguageItem&>(aLangSet.Get(nWhich)).GetLanguage(); + } + +} + +OUString SwIndexMarkPane::GetDefaultPhoneticReading( const OUString& rText ) +{ + if( !m_bIsPhoneticReadingEnabled ) + return OUString(); + + return m_xExtendedIndexEntrySupplier->getPhoneticCandidate(rText, LanguageTag::convertToLocale( m_nLangForPhoneticReading )); +} + +void SwIndexMarkPane::Activate() +{ + // display current selection (first element) ???? + if (m_bNewMark) + { + m_xSyncED->set_sensitive(m_pSh->GetCursorCnt() < 2); + } +} + +IMPL_LINK_NOARG(SwIndexMarkPane, SyncSelectionHdl, weld::Button&, void) +{ + m_bSelected = !m_pSh->HasSelection(); + m_aOrgStr = m_pSh->GetView().GetSelectionTextParam(true, false); + m_xEntryED->set_text(m_aOrgStr); + + //to include all equal entries may only be allowed in the body and even there + //only when a simple selection exists + const FrameTypeFlags nFrameType = m_pSh->GetFrameType(nullptr,true); + m_xApplyToAllCB->show(); + m_xSearchCaseSensitiveCB->show(); + m_xSearchCaseWordOnlyCB->show(); + m_xApplyToAllCB->set_sensitive(!m_aOrgStr.isEmpty() && + !(nFrameType & ( FrameTypeFlags::HEADER | FrameTypeFlags::FOOTER | FrameTypeFlags::FLY_ANY ))); + SearchTypeHdl(*m_xApplyToAllCB); + ModifyHdl(*m_xEntryED); +} + +// evaluate Ok-Button +void SwIndexMarkPane::Apply() +{ + InsertUpdate(); + if(m_bSelected) + m_pSh->ResetSelect(nullptr, false); +} + +// apply changes +void SwIndexMarkPane::InsertUpdate() +{ + m_pSh->StartUndo(m_bDel ? SwUndoId::INDEX_ENTRY_DELETE : SwUndoId::INDEX_ENTRY_INSERT); + m_pSh->StartAllAction(); + SwRewriter aRewriter; + + if( m_bNewMark ) + { + InsertMark(); + + if ( m_pTOXMgr->GetCurTOXMark()) + aRewriter.AddRule(UndoArg1, + m_pTOXMgr->GetCurTOXMark()->GetText(m_pSh->GetLayout())); + } + else if( !m_pSh->HasReadonlySel() ) + { + if ( m_pTOXMgr->GetCurTOXMark()) + aRewriter.AddRule(UndoArg1, + m_pTOXMgr->GetCurTOXMark()->GetText(m_pSh->GetLayout())); + + if( m_bDel ) + m_pTOXMgr->DeleteTOXMark(); + else if( m_pTOXMgr->GetCurTOXMark() ) + UpdateMark(); + } + + m_pSh->EndAllAction(); + m_pSh->EndUndo(m_bDel ? SwUndoId::INDEX_ENTRY_DELETE : SwUndoId::INDEX_ENTRY_INSERT); + + nTypePos = m_xTypeDCB->find_text(m_xTypeDCB->get_active_text()); + if(nTypePos == -1) + nTypePos = 0; + + nKey1Pos = m_xKey1DCB->find_text(m_xKey1DCB->get_active_text()); + nKey2Pos = m_xKey2DCB->find_text(m_xKey2DCB->get_active_text()); +} + +// insert mark +static void lcl_SelectSameStrings(SwWrtShell& rSh, bool bWordOnly, bool bCaseSensitive) +{ + rSh.Push(); + + i18nutil::SearchOptions2 aSearchOpt( + ( bWordOnly ? SearchFlags::NORM_WORD_ONLY : 0 ), + rSh.GetSelText(), OUString(), + GetAppLanguageTag().getLocale(), + 0, 0, 0, + (bCaseSensitive + ? TransliterationFlags::NONE + : TransliterationFlags::IGNORE_CASE), + SearchAlgorithms2::ABSOLUTE, + '\\' ); + + rSh.ClearMark(); + bool bCancel; + + //todo/mba: assuming that notes should not be searched + rSh.Find_Text(aSearchOpt, false/*bSearchInNotes*/, SwDocPositions::Start, SwDocPositions::End, bCancel, + FindRanges::InSelAll | FindRanges::InBodyOnly ); +} + +void SwIndexMarkPane::InsertMark() +{ + auto nPos = m_xTypeDCB->find_text(m_xTypeDCB->get_active_text()); + TOXTypes eType = nPos == POS_CONTENT ? TOX_CONTENT : + nPos == POS_INDEX ? TOX_INDEX : TOX_USER; + + SwTOXMarkDescription aDesc(eType); + + const int nLevel = m_xLevelNF->denormalize(m_xLevelNF->get_value()); + switch( nPos) + { + case POS_CONTENT : break; + case POS_INDEX: // keyword index mark + { + UpdateKeyBoxes(); + aDesc.SetPrimKey(m_xKey1DCB->get_active_text()); + aDesc.SetSecKey(m_xKey2DCB->get_active_text()); + aDesc.SetMainEntry(m_xMainEntryCB->get_active()); + aDesc.SetPhoneticReadingOfAltStr(m_xPhoneticED0->get_text()); + aDesc.SetPhoneticReadingOfPrimKey(m_xPhoneticED1->get_text()); + aDesc.SetPhoneticReadingOfSecKey(m_xPhoneticED2->get_text()); + } + break; + default: // Userdefined index mark + { + aDesc.SetTOUName(m_xTypeDCB->get_active_text()); + } + } + if (m_aOrgStr != m_xEntryED->get_text()) + aDesc.SetAltStr(m_xEntryED->get_text()); + bool bApplyAll = m_xApplyToAllCB->get_active(); + bool bWordOnly = m_xSearchCaseWordOnlyCB->get_active(); + bool bCaseSensitive = m_xSearchCaseSensitiveCB->get_active(); + + m_pSh->StartAllAction(); + // all equal strings have to be selected here so that the + // entry is applied to all equal strings + if(bApplyAll) + { + lcl_SelectSameStrings(*m_pSh, bWordOnly, bCaseSensitive); + } + aDesc.SetLevel(nLevel); + SwTOXMgr aMgr(m_pSh); + aMgr.InsertTOXMark(aDesc); + if(bApplyAll) + m_pSh->Pop(SwCursorShell::PopMode::DeleteCurrent); + + m_pSh->EndAllAction(); +} + +// update mark +void SwIndexMarkPane::UpdateMark() +{ + OUString aAltText(m_xEntryED->get_text()); + OUString* pAltText = m_aOrgStr != m_xEntryED->get_text() ? &aAltText : nullptr; + //empty alternative texts are not allowed + if(pAltText && pAltText->isEmpty()) + return; + + UpdateKeyBoxes(); + + auto nPos = m_xTypeDCB->find_text(m_xTypeDCB->get_active_text()); + TOXTypes eType = TOX_USER; + if(POS_CONTENT == nPos) + eType = TOX_CONTENT; + else if(POS_INDEX == nPos) + eType = TOX_INDEX; + + SwTOXMarkDescription aDesc(eType); + aDesc.SetLevel(m_xLevelNF->get_value()); + if(pAltText) + aDesc.SetAltStr(*pAltText); + + OUString aPrim(m_xKey1DCB->get_active_text()); + if(!aPrim.isEmpty()) + aDesc.SetPrimKey(aPrim); + OUString aSec(m_xKey2DCB->get_active_text()); + if(!aSec.isEmpty()) + aDesc.SetSecKey(aSec); + + if(eType == TOX_INDEX) + { + aDesc.SetPhoneticReadingOfAltStr(m_xPhoneticED0->get_text()); + aDesc.SetPhoneticReadingOfPrimKey(m_xPhoneticED1->get_text()); + aDesc.SetPhoneticReadingOfSecKey(m_xPhoneticED2->get_text()); + } + aDesc.SetMainEntry(m_xMainEntryCB->get_visible() && m_xMainEntryCB->get_active()); + m_pTOXMgr->UpdateTOXMark(aDesc); +} + +// insert new keys +void SwIndexMarkPane::UpdateKeyBoxes() +{ + OUString aKey(m_xKey1DCB->get_active_text()); + auto nPos = m_xKey1DCB->find_text(aKey); + if(nPos == -1 && !aKey.isEmpty()) + { // create new key + m_xKey1DCB->append_text(aKey); + } + + aKey = m_xKey2DCB->get_active_text(); + nPos = m_xKey2DCB->find_text(aKey); + + if(nPos == -1 && !aKey.isEmpty()) + { // create new key + m_xKey2DCB->append_text(aKey); + } +} + +namespace { + +class SwNewUserIdxDlg : public weld::GenericDialogController +{ + SwIndexMarkPane* m_pDlg; + + std::unique_ptr<weld::Button> m_xOKPB; + std::unique_ptr<weld::Entry> m_xNameED; + + DECL_LINK(ModifyHdl, weld::Entry&, void); + +public: + explicit SwNewUserIdxDlg(SwIndexMarkPane* pPane, weld::Window* pParent) + : GenericDialogController(pParent, "modules/swriter/ui/newuserindexdialog.ui", "NewUserIndexDialog") + , m_pDlg(pPane) + , m_xOKPB(m_xBuilder->weld_button("ok")) + , m_xNameED(m_xBuilder->weld_entry("entry")) + { + m_xNameED->connect_changed(LINK(this, SwNewUserIdxDlg, ModifyHdl)); + m_xOKPB->set_sensitive(false); + m_xNameED->grab_focus(); + } + OUString GetName() const { return m_xNameED->get_text(); } +}; + +} + +IMPL_LINK( SwNewUserIdxDlg, ModifyHdl, weld::Entry&, rEdit, void) +{ + m_xOKPB->set_sensitive(!rEdit.get_text().isEmpty() && !m_pDlg->IsTOXType(rEdit.get_text())); +} + +IMPL_LINK_NOARG(SwIndexMarkPane, NewUserIdxHdl, weld::Button&, void) +{ + SwNewUserIdxDlg aDlg(this, m_xDialog.get()); + if (aDlg.run() == RET_OK) + { + OUString sNewName(aDlg.GetName()); + m_xTypeDCB->append_text(sNewName); + m_xTypeDCB->set_active_text(sNewName); + } +} + +IMPL_LINK( SwIndexMarkPane, SearchTypeHdl, weld::Toggleable&, rBox, void) +{ + const bool bEnable = rBox.get_active() && rBox.get_sensitive(); + m_xSearchCaseWordOnlyCB->set_sensitive(bEnable); + m_xSearchCaseSensitiveCB->set_sensitive(bEnable); +} + +IMPL_LINK(SwIndexMarkPane, InsertHdl, weld::Button&, rButton, void) +{ + Apply(); + //close the dialog if only one entry is available + if(!m_bNewMark && !m_xPrevBT->get_visible() && !m_xNextBT->get_visible()) + CloseHdl(rButton); +} + +IMPL_LINK_NOARG(SwIndexMarkPane, CloseHdl, weld::Button&, void) +{ + if (m_bNewMark) + { + if (SfxViewFrame* pViewFrm = SfxViewFrame::Current()) + { + pViewFrm->GetDispatcher()->Execute(FN_INSERT_IDX_ENTRY_DLG, + SfxCallMode::ASYNCHRON|SfxCallMode::RECORD); + } + } + else + { + m_xDialog->response(RET_CLOSE); + } +} + +// select index type only when inserting +IMPL_LINK(SwIndexMarkPane, ModifyListBoxHdl, weld::ComboBox&, rBox, void) +{ + ModifyHdl(rBox); +} + +IMPL_LINK(SwIndexMarkPane, ModifyEditHdl, weld::Entry&, rEdit, void) +{ + ModifyHdl(rEdit); +} + +void SwIndexMarkPane::ModifyHdl(const weld::Widget& rBox) +{ + if (m_xTypeDCB.get() == &rBox) + { + // set index type + auto nPos = m_xTypeDCB->find_text(m_xTypeDCB->get_active_text()); + bool bLevelEnable = false, + bKeyEnable = false, + bSetKey2 = false, + bKey2Enable = false, + bEntryHasText = false, + bKey1HasText = false, + bKey2HasText = false; + if(nPos == POS_INDEX) + { + if (!m_xEntryED->get_text().isEmpty()) + bEntryHasText = true; + m_xPhoneticED0->set_text(GetDefaultPhoneticReading(m_xEntryED->get_text())); + + bKeyEnable = true; + m_xKey1DCB->set_active_text(m_xKey1DCB->get_text(nKey1Pos)); + m_xPhoneticED1->set_text(GetDefaultPhoneticReading(m_xKey1DCB->get_active_text())); + if (!m_xKey1DCB->get_active_text().isEmpty()) + { + bKey1HasText = bSetKey2 = bKey2Enable = true; + m_xKey2DCB->set_active_text(m_xKey2DCB->get_text(nKey2Pos)); + m_xPhoneticED2->set_text(GetDefaultPhoneticReading(m_xKey2DCB->get_active_text())); + if(!m_xKey2DCB->get_active_text().isEmpty()) + bKey2HasText = true; + } + } + else + { + bLevelEnable = true; + m_xLevelNF->set_max(MAXLEVEL); + m_xLevelNF->set_value(m_xLevelNF->normalize(0)); + bSetKey2 = true; + } + m_xLevelFT->set_visible(bLevelEnable); + m_xLevelNF->set_visible(bLevelEnable); + m_xMainEntryCB->set_visible(nPos == POS_INDEX); + + m_xKey1FT->set_sensitive(bKeyEnable); + m_xKey1DCB->set_sensitive(bKeyEnable); + if ( bSetKey2 ) + { + m_xKey2DCB->set_sensitive(bKey2Enable); + m_xKey2FT->set_sensitive(bKey2Enable); + } + m_xPhoneticFT0->set_sensitive(bKeyEnable&&bEntryHasText&&m_bIsPhoneticReadingEnabled); + m_xPhoneticED0->set_sensitive(bKeyEnable&&bEntryHasText&&m_bIsPhoneticReadingEnabled); + m_xPhoneticFT1->set_sensitive(bKeyEnable&&bKey1HasText&&m_bIsPhoneticReadingEnabled); + m_xPhoneticED1->set_sensitive(bKeyEnable&&bKey1HasText&&m_bIsPhoneticReadingEnabled); + m_xPhoneticFT2->set_sensitive(bKeyEnable&&bKey2HasText&&m_bIsPhoneticReadingEnabled); + m_xPhoneticED2->set_sensitive(bKeyEnable&&bKey2HasText&&m_bIsPhoneticReadingEnabled); + } + else //m_xEntryED !!m_xEntryED is not a ListBox but an Edit + { + bool bHasText = !m_xEntryED->get_text().isEmpty(); + if(!bHasText) + { + m_xPhoneticED0->set_text(OUString()); + m_bPhoneticED0_ChangedByUser = false; + } + else if(!m_bPhoneticED0_ChangedByUser) + m_xPhoneticED0->set_text(GetDefaultPhoneticReading(m_xEntryED->get_text())); + + m_xPhoneticFT0->set_sensitive(bHasText&&m_bIsPhoneticReadingEnabled); + m_xPhoneticED0->set_sensitive(bHasText&&m_bIsPhoneticReadingEnabled); + } + m_xOKBT->set_sensitive(!m_pSh->HasReadonlySel() && + (!m_xEntryED->get_text().isEmpty() || m_pSh->GetCursorCnt(false))); +} + +IMPL_LINK_NOARG(SwIndexMarkPane, NextHdl, weld::Button&, void) +{ + InsertUpdate(); + m_pTOXMgr->NextTOXMark(); + UpdateDialog(); +} + +IMPL_LINK_NOARG(SwIndexMarkPane, NextSameHdl, weld::Button&, void) +{ + InsertUpdate(); + m_pTOXMgr->NextTOXMark(true); + UpdateDialog(); +} + +IMPL_LINK_NOARG(SwIndexMarkPane, PrevHdl, weld::Button&, void) +{ + InsertUpdate(); + m_pTOXMgr->PrevTOXMark(); + UpdateDialog(); +} + +IMPL_LINK_NOARG(SwIndexMarkPane, PrevSameHdl, weld::Button&, void) +{ + InsertUpdate(); + m_pTOXMgr->PrevTOXMark(true); + UpdateDialog(); +} + +IMPL_LINK_NOARG(SwIndexMarkPane, DelHdl, weld::Button&, void) +{ + m_bDel = true; + InsertUpdate(); + m_bDel = false; + + if(m_pTOXMgr->GetCurTOXMark()) + UpdateDialog(); + else + { + CloseHdl(*m_xCloseBT); + if (SfxViewFrame* pViewFrm = SfxViewFrame::Current()) + pViewFrm->GetBindings().Invalidate(FN_EDIT_IDX_ENTRY_DLG); + } +} + +// renew dialog view +void SwIndexMarkPane::UpdateDialog() +{ + OSL_ENSURE(m_pSh && m_pTOXMgr, "no shell?"); + SwTOXMark* pMark = m_pTOXMgr->GetCurTOXMark(); + OSL_ENSURE(pMark, "no current marker"); + if(!pMark) + return; + + SwViewShell::SetCareDialog(m_xDialog); + + m_aOrgStr = pMark->GetText(m_pSh->GetLayout()); + m_xEntryED->set_text(m_aOrgStr); + + // set index type + bool bLevelEnable = true, + bKeyEnable = false, + bKey2Enable = false, + bEntryHasText = false, + bKey1HasText = false, + bKey2HasText = false; + + TOXTypes eCurType = pMark->GetTOXType()->GetType(); + if(TOX_INDEX == eCurType) + { + bLevelEnable = false; + bKeyEnable = true; + bKey1HasText = bKey2Enable = !pMark->GetPrimaryKey().isEmpty(); + bKey2HasText = !pMark->GetSecondaryKey().isEmpty(); + bEntryHasText = !pMark->GetText(m_pSh->GetLayout()).isEmpty(); + m_xKey1DCB->set_entry_text( pMark->GetPrimaryKey() ); + m_xKey2DCB->set_entry_text( pMark->GetSecondaryKey() ); + m_xPhoneticED0->set_text( pMark->GetTextReading() ); + m_xPhoneticED1->set_text( pMark->GetPrimaryKeyReading() ); + m_xPhoneticED2->set_text( pMark->GetSecondaryKeyReading() ); + m_xMainEntryCB->set_active(pMark->IsMainEntry()); + } + else if(TOX_CONTENT == eCurType || TOX_USER == eCurType) + { + m_xLevelNF->set_value(m_xLevelNF->normalize(pMark->GetLevel())); + } + m_xKey1FT->set_sensitive(bKeyEnable); + m_xKey1DCB->set_sensitive(bKeyEnable); + m_xLevelNF->set_max(MAXLEVEL); + m_xLevelFT->set_visible(bLevelEnable); + m_xLevelNF->set_visible(bLevelEnable); + m_xMainEntryCB->set_visible(!bLevelEnable); + m_xKey2FT->set_sensitive(bKey2Enable); + m_xKey2DCB->set_sensitive(bKey2Enable); + + UpdateLanguageDependenciesForPhoneticReading(); + m_xPhoneticFT0->set_sensitive(bKeyEnable&&bEntryHasText&&m_bIsPhoneticReadingEnabled); + m_xPhoneticED0->set_sensitive(bKeyEnable&&bEntryHasText&&m_bIsPhoneticReadingEnabled); + m_xPhoneticFT1->set_sensitive(bKeyEnable&&bKey1HasText&&m_bIsPhoneticReadingEnabled); + m_xPhoneticED1->set_sensitive(bKeyEnable&&bKey1HasText&&m_bIsPhoneticReadingEnabled); + m_xPhoneticFT2->set_sensitive(bKeyEnable&&bKey2HasText&&m_bIsPhoneticReadingEnabled); + m_xPhoneticED2->set_sensitive(bKeyEnable&&bKey2HasText&&m_bIsPhoneticReadingEnabled); + + // set index type + m_xTypeDCB->set_active_text(pMark->GetTOXType()->GetTypeName()); + + // set Next - Prev - Buttons + m_pSh->SttCursorMove(); + if( m_xPrevBT->get_visible() ) + { + const SwTOXMark* pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_PRV ); + if (!SfxPoolItem::areSame( pMoveMark, pMark )) + m_pSh->GotoTOXMark( *pMoveMark, TOX_NXT ); + m_xPrevBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) ); + pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_NXT ); + if (!SfxPoolItem::areSame( pMoveMark, pMark )) + m_pSh->GotoTOXMark( *pMoveMark, TOX_PRV ); + m_xNextBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) ); + } + + if (m_xPrevSameBT->get_visible()) + { + const SwTOXMark* pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_PRV ); + if (!SfxPoolItem::areSame( pMoveMark, pMark )) + m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_NXT ); + m_xPrevSameBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) ); + pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_NXT ); + if (!SfxPoolItem::areSame( pMoveMark, pMark )) + m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_PRV ); + m_xNextSameBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) ); + } + + const bool bEnable = !m_pSh->HasReadonlySel(); + m_xOKBT->set_sensitive(bEnable); + m_xDelBT->set_sensitive(bEnable); + m_xEntryED->set_sensitive(bEnable); + m_xLevelNF->set_sensitive(bEnable); + m_xKey1DCB->set_sensitive(bEnable); + m_xKey2DCB->set_sensitive(bEnable); + + m_pSh->SelectTextAttr( RES_TXTATR_TOXMARK, pMark->GetTextTOXMark() ); + // we need the point at the start of the attribute + m_pSh->SwapPam(); + + m_pSh->EndCursorMove(); +} + +// Remind whether the edit boxes for Phonetic reading are changed manually +IMPL_LINK(SwIndexMarkPane, PhoneticEDModifyHdl, weld::Entry&, rEdit, void) +{ + if (m_xPhoneticED0.get() == &rEdit) + { + m_bPhoneticED0_ChangedByUser = !rEdit.get_text().isEmpty(); + } + else if (m_xPhoneticED1.get() == &rEdit) + { + m_bPhoneticED1_ChangedByUser = !rEdit.get_text().isEmpty(); + } + else if (m_xPhoneticED2.get() == &rEdit) + { + m_bPhoneticED2_ChangedByUser = !rEdit.get_text().isEmpty(); + } +} + +// Enable Disable of the 2nd key +IMPL_LINK( SwIndexMarkPane, KeyDCBModifyHdl, weld::ComboBox&, rBox, void ) +{ + if (m_xKey1DCB.get() == &rBox) + { + bool bEnable = !rBox.get_active_text().isEmpty(); + if(!bEnable) + { + m_xKey2DCB->set_entry_text(OUString()); + m_xPhoneticED1->set_text(OUString()); + m_xPhoneticED2->set_text(OUString()); + m_bPhoneticED1_ChangedByUser = false; + m_bPhoneticED2_ChangedByUser = false; + } + else + { + if (rBox.get_popup_shown()) + { + //reset bPhoneticED1_ChangedByUser if a completely new string is selected + m_bPhoneticED1_ChangedByUser = false; + } + if (!m_bPhoneticED1_ChangedByUser) + m_xPhoneticED1->set_text(GetDefaultPhoneticReading(rBox.get_active_text())); + } + m_xKey2DCB->set_sensitive(bEnable); + m_xKey2FT->set_sensitive(bEnable); + } + else if (m_xKey2DCB.get() == &rBox) + { + if (rBox.get_active_text().isEmpty()) + { + m_xPhoneticED2->set_text(OUString()); + m_bPhoneticED2_ChangedByUser = false; + } + else + { + if (rBox.get_popup_shown()) + { + //reset bPhoneticED1_ChangedByUser if a completely new string is selected + m_bPhoneticED2_ChangedByUser = false; + } + if(!m_bPhoneticED2_ChangedByUser) + m_xPhoneticED2->set_text(GetDefaultPhoneticReading(rBox.get_active_text())); + } + } + + bool bKey1HasText = !m_xKey1DCB->get_active_text().isEmpty(); + bool bKey2HasText = !m_xKey2DCB->get_active_text().isEmpty(); + + m_xPhoneticFT1->set_sensitive(bKey1HasText && m_bIsPhoneticReadingEnabled); + m_xPhoneticED1->set_sensitive(bKey1HasText && m_bIsPhoneticReadingEnabled); + m_xPhoneticFT2->set_sensitive(bKey2HasText && m_bIsPhoneticReadingEnabled); + m_xPhoneticED2->set_sensitive(bKey2HasText && m_bIsPhoneticReadingEnabled); +} + +SwIndexMarkPane::~SwIndexMarkPane() +{ +} + +void SwIndexMarkPane::ReInitDlg(SwWrtShell& rWrtShell, SwTOXMark const * pCurTOXMark) +{ + m_pSh = &rWrtShell; + m_pTOXMgr.reset( new SwTOXMgr(m_pSh) ); + if(pCurTOXMark) + { + for(sal_uInt16 i = 0; i < m_pTOXMgr->GetTOXMarkCount(); i++) + if (SfxPoolItem::areSame(m_pTOXMgr->GetTOXMark(i), pCurTOXMark)) + { + m_pTOXMgr->SetCurTOXMark(i); + break; + } + } + InitControls(); +} + +SwIndexMarkFloatDlg::SwIndexMarkFloatDlg(SfxBindings* _pBindings, + SfxChildWindow* pChild, weld::Window *pParent, + SfxChildWinInfo const * pInfo, bool bNew) + : SfxModelessDialogController(_pBindings, pChild, pParent, + "modules/swriter/ui/indexentry.ui", "IndexEntryDialog") + , m_aContent(m_xDialog, *m_xBuilder, bNew, ::GetActiveWrtShell()) +{ + if (SwWrtShell* pWrtShell = ::GetActiveWrtShell()) + m_aContent.ReInitDlg(*pWrtShell); + Initialize(pInfo); +} + +void SwIndexMarkFloatDlg::Activate() +{ + SfxModelessDialogController::Activate(); + m_aContent.Activate(); +} + +void SwIndexMarkFloatDlg::ReInitDlg(SwWrtShell& rWrtShell) +{ + m_aContent.ReInitDlg( rWrtShell ); +} + +SwIndexMarkModalDlg::SwIndexMarkModalDlg(weld::Window *pParent, SwWrtShell& rSh, SwTOXMark const * pCurTOXMark) + : SfxDialogController(pParent, "modules/swriter/ui/indexentry.ui", + "IndexEntryDialog") + , m_aContent(m_xDialog, *m_xBuilder, false, &rSh) +{ + m_aContent.ReInitDlg(rSh, pCurTOXMark); +} + +SwIndexMarkModalDlg::~SwIndexMarkModalDlg() +{ + SwViewShell::SetCareDialog(nullptr); +} + +short SwIndexMarkModalDlg::run() +{ + short nRet = SfxDialogController::run(); + if (RET_OK == nRet) + m_aContent.Apply(); + return nRet; +} + +namespace { + +class SwCreateAuthEntryDlg_Impl : public weld::GenericDialogController +{ + std::vector<std::unique_ptr<weld::Builder>> m_aBuilders; + + Link<weld::Entry&,bool> m_aShortNameCheckLink; + + SwWrtShell& m_rWrtSh; + + bool m_bNewEntryMode; + bool m_bNameAllowed; + + std::vector<std::unique_ptr<weld::Container>> m_aOrigContainers; + std::vector<std::unique_ptr<weld::Label>> m_aFixedTexts; + std::unique_ptr<weld::Box> m_pBoxes[AUTH_FIELD_END]; + std::unique_ptr<weld::Entry> m_pEdits[AUTH_FIELD_END]; + std::unique_ptr<weld::Button> m_xOKBT; + std::unique_ptr<weld::Container> m_xBox; + std::unique_ptr<weld::Container> m_xLeft; + std::unique_ptr<weld::Container> m_xRight; + std::unique_ptr<weld::ComboBox> m_xTypeListBox; + std::unique_ptr<weld::ComboBox> m_xIdentifierBox; + std::unique_ptr<weld::Button> m_xLocalBrowseButton; + std::unique_ptr<weld::CheckButton> m_xLocalPageCB; + std::unique_ptr<weld::SpinButton> m_xLocalPageSB; + std::unique_ptr<weld::ComboBox> m_xTargetTypeListBox; + weld::Entry* m_pTargetURLField; + + DECL_LINK(IdentifierHdl, weld::ComboBox&, void); + DECL_LINK(ShortNameHdl, weld::Entry&, void); + DECL_LINK(EnableHdl, weld::ComboBox&, void); + DECL_LINK(BrowseHdl, weld::Button&, void); + DECL_LINK(PageNumHdl, weld::Toggleable&, void); + DECL_LINK(TargetTypeHdl, weld::ComboBox&, void); + +public: + SwCreateAuthEntryDlg_Impl(weld::Window* pParent, + const OUString pFields[], + SwWrtShell& rSh, + bool bNewEntry, + bool bCreate); + + OUString GetEntryText(ToxAuthorityField eField) const; + + void SetCheckNameHdl(const Link<weld::Entry&,bool>& rLink) {m_aShortNameCheckLink = rLink;} + +}; + +struct TextInfo +{ + ToxAuthorityField nToxField; + const OUString pHelpId; +}; + +} + +const TextInfo aTextInfoArr[] = +{ + {AUTH_FIELD_IDENTIFIER, HID_AUTH_FIELD_IDENTIFIER }, + {AUTH_FIELD_AUTHORITY_TYPE, HID_AUTH_FIELD_AUTHORITY_TYPE }, + {AUTH_FIELD_AUTHOR, HID_AUTH_FIELD_AUTHOR }, + {AUTH_FIELD_TITLE, HID_AUTH_FIELD_TITLE }, + {AUTH_FIELD_YEAR, HID_AUTH_FIELD_YEAR }, + {AUTH_FIELD_PUBLISHER, HID_AUTH_FIELD_PUBLISHER }, + {AUTH_FIELD_ADDRESS, HID_AUTH_FIELD_ADDRESS }, + {AUTH_FIELD_ISBN, HID_AUTH_FIELD_ISBN }, + {AUTH_FIELD_CHAPTER, HID_AUTH_FIELD_CHAPTER }, + {AUTH_FIELD_PAGES, HID_AUTH_FIELD_PAGES }, + {AUTH_FIELD_EDITOR, HID_AUTH_FIELD_EDITOR }, + {AUTH_FIELD_EDITION, HID_AUTH_FIELD_EDITION }, + {AUTH_FIELD_BOOKTITLE, HID_AUTH_FIELD_BOOKTITLE }, + {AUTH_FIELD_VOLUME, HID_AUTH_FIELD_VOLUME }, + {AUTH_FIELD_HOWPUBLISHED, HID_AUTH_FIELD_HOWPUBLISHED }, + {AUTH_FIELD_ORGANIZATIONS, HID_AUTH_FIELD_ORGANIZATIONS }, + {AUTH_FIELD_INSTITUTION, HID_AUTH_FIELD_INSTITUTION }, + {AUTH_FIELD_SCHOOL, HID_AUTH_FIELD_SCHOOL }, + {AUTH_FIELD_REPORT_TYPE, HID_AUTH_FIELD_REPORT_TYPE }, + {AUTH_FIELD_MONTH, HID_AUTH_FIELD_MONTH }, + {AUTH_FIELD_JOURNAL, HID_AUTH_FIELD_JOURNAL }, + {AUTH_FIELD_NUMBER, HID_AUTH_FIELD_NUMBER }, + {AUTH_FIELD_SERIES, HID_AUTH_FIELD_SERIES }, + {AUTH_FIELD_ANNOTE, HID_AUTH_FIELD_ANNOTE }, + {AUTH_FIELD_NOTE, HID_AUTH_FIELD_NOTE }, + {AUTH_FIELD_URL, HID_AUTH_FIELD_URL }, + {AUTH_FIELD_TARGET_TYPE, HID_AUTH_FIELD_TARGET_TYPE }, + {AUTH_FIELD_TARGET_URL, HID_AUTH_FIELD_TARGET_URL }, + {AUTH_FIELD_LOCAL_URL, HID_AUTH_FIELD_LOCAL_URL }, + {AUTH_FIELD_CUSTOM1, HID_AUTH_FIELD_CUSTOM1 }, + {AUTH_FIELD_CUSTOM2, HID_AUTH_FIELD_CUSTOM2 }, + {AUTH_FIELD_CUSTOM3, HID_AUTH_FIELD_CUSTOM3 }, + {AUTH_FIELD_CUSTOM4, HID_AUTH_FIELD_CUSTOM4 }, + {AUTH_FIELD_CUSTOM5, HID_AUTH_FIELD_CUSTOM5 } +}; + +static OUString lcl_FindColumnEntry(const uno::Sequence<beans::PropertyValue>& rFields, std::u16string_view rColumnTitle) +{ + for(const auto& rField : rFields) + { + OUString sRet; + if(rField.Name == rColumnTitle && + (rField.Value >>= sRet)) + { + return sRet; + } + } + return OUString(); +} + +bool SwAuthorMarkPane::s_bIsFromComponent = true; + +SwAuthorMarkPane::SwAuthorMarkPane(weld::DialogController &rDialog, weld::Builder& rBuilder, bool bNewDlg) + : m_rDialog(rDialog) + , m_bNewEntry(bNewDlg) + , m_bBibAccessInitialized(false) + , m_pSh(nullptr) + , m_xFromComponentRB(rBuilder.weld_radio_button("frombibliography")) + , m_xFromDocContentRB(rBuilder.weld_radio_button("fromdocument")) + , m_xAuthorFI(rBuilder.weld_label("author")) + , m_xTitleFI(rBuilder.weld_label("title")) + , m_xEntryED(rBuilder.weld_entry("entryed")) + , m_xEntryLB(rBuilder.weld_combo_box("entrylb")) + , m_xActionBT(rBuilder.weld_button(m_bNewEntry ? OUString("insert") : OUString("modify"))) + , m_xCloseBT(rBuilder.weld_button("close")) + , m_xCreateEntryPB(rBuilder.weld_button("new")) + , m_xEditEntryPB(rBuilder.weld_button("edit")) +{ + m_xActionBT->show(); + m_xFromComponentRB->set_visible(m_bNewEntry); + m_xFromDocContentRB->set_visible(m_bNewEntry); + m_xFromComponentRB->set_active(s_bIsFromComponent); + m_xFromDocContentRB->set_active(!s_bIsFromComponent); + + m_xActionBT->connect_clicked(LINK(this,SwAuthorMarkPane, InsertHdl)); + m_xCloseBT->connect_clicked(LINK(this,SwAuthorMarkPane, CloseHdl)); + m_xCreateEntryPB->connect_clicked(LINK(this,SwAuthorMarkPane, CreateEntryHdl)); + m_xEditEntryPB->connect_clicked(LINK(this,SwAuthorMarkPane, CreateEntryHdl)); + m_xFromComponentRB->connect_toggled(LINK(this,SwAuthorMarkPane, ChangeSourceHdl)); + m_xFromDocContentRB->connect_toggled(LINK(this,SwAuthorMarkPane, ChangeSourceHdl)); + m_xEntryED->connect_changed(LINK(this,SwAuthorMarkPane, EditModifyHdl)); + + m_rDialog.set_title(SwResId( + m_bNewEntry ? STR_AUTHMRK_INSERT : STR_AUTHMRK_EDIT)); + + m_xEntryED->set_visible(!m_bNewEntry); + m_xEntryLB->set_visible(m_bNewEntry); + // tdf#90641 - sort bibliography entries by identifier + m_xEntryLB->make_sorted(); + if (m_bNewEntry) + { + m_xEntryLB->connect_changed(LINK(this, SwAuthorMarkPane, CompEntryHdl)); + } +} + +void SwAuthorMarkPane::ReInitDlg(SwWrtShell& rWrtShell) +{ + m_pSh = &rWrtShell; + InitControls(); +} + +IMPL_LINK_NOARG(SwAuthorMarkPane, CloseHdl, weld::Button&, void) +{ + if(m_bNewEntry) + { + if (SfxViewFrame* pViewFrm = SfxViewFrame::Current()) + { + pViewFrm->GetDispatcher()->Execute(FN_INSERT_AUTH_ENTRY_DLG, + SfxCallMode::ASYNCHRON|SfxCallMode::RECORD); + } + } + else + { + m_rDialog.response(RET_CANCEL); + } +} + +IMPL_LINK( SwAuthorMarkPane, CompEntryHdl, weld::ComboBox&, rBox, void) +{ + const OUString sEntry(rBox.get_active_text()); + if(s_bIsFromComponent) + { + if(m_xBibAccess.is() && !sEntry.isEmpty()) + { + if(m_xBibAccess->hasByName(sEntry)) + { + uno::Any aEntry(m_xBibAccess->getByName(sEntry)); + uno::Sequence<beans::PropertyValue> aFieldProps; + if(aEntry >>= aFieldProps) + { + auto nSize = std::min(static_cast<sal_Int32>(AUTH_FIELD_END), aFieldProps.getLength()); + for(sal_Int32 i = 0; i < nSize; i++) + { + m_sFields[i] = lcl_FindColumnEntry(aFieldProps, m_sColumnTitles[i]); + } + } + } + } + } + else + { + if(!sEntry.isEmpty()) + { + const SwAuthorityFieldType* pFType = static_cast<const SwAuthorityFieldType*>( + m_pSh->GetFieldType(SwFieldIds::TableOfAuthorities, OUString())); + const SwAuthEntry* pEntry = pFType ? pFType->GetEntryByIdentifier(sEntry) : nullptr; + for(int i = 0; i < AUTH_FIELD_END; i++) + m_sFields[i] = pEntry ? + pEntry->GetAuthorField(static_cast<ToxAuthorityField>(i)) : OUString(); + } + } + if (rBox.get_active_text().isEmpty()) + { + for(OUString & s : m_sFields) + s.clear(); + } + m_xAuthorFI->set_label(m_sFields[AUTH_FIELD_AUTHOR]); + m_xTitleFI->set_label(m_sFields[AUTH_FIELD_TITLE]); +} + +IMPL_LINK_NOARG(SwAuthorMarkPane, InsertHdl, weld::Button&, void) +{ + //insert or update the SwAuthorityField... + if(m_pSh) + { + bool bDifferent = false; + OSL_ENSURE(!m_sFields[AUTH_FIELD_IDENTIFIER].isEmpty() , "No Id is set!"); + OSL_ENSURE(!m_sFields[AUTH_FIELD_AUTHORITY_TYPE].isEmpty() , "No authority type is set!"); + //check if the entry already exists with different content + const SwAuthorityFieldType* pFType = static_cast<const SwAuthorityFieldType*>( + m_pSh->GetFieldType(SwFieldIds::TableOfAuthorities, OUString())); + const SwAuthEntry* pEntry = pFType ? + pFType->GetEntryByIdentifier( m_sFields[AUTH_FIELD_IDENTIFIER]) + : nullptr; + if(pEntry) + { + for(int i = 0; i < AUTH_FIELD_END && !bDifferent; i++) + bDifferent |= m_sFields[i] != pEntry->GetAuthorField(static_cast<ToxAuthorityField>(i)); + if(bDifferent) + { + std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(m_rDialog.getDialog(), + VclMessageType::Question, VclButtonsType::YesNo, + SwResId(STR_QUERY_CHANGE_AUTH_ENTRY))); + if (RET_YES != xQuery->run()) + return; + } + } + + SwFieldMgr aMgr(m_pSh); + OUStringBuffer sFields; + for(OUString & s : m_sFields) + { + sFields.append(s + OUStringChar(TOX_STYLE_DELIMITER)); + } + if(m_bNewEntry) + { + if(bDifferent) + { + rtl::Reference<SwAuthEntry> xNewData(new SwAuthEntry); + for(int i = 0; i < AUTH_FIELD_END; i++) + xNewData->SetAuthorField(static_cast<ToxAuthorityField>(i), m_sFields[i]); + m_pSh->ChangeAuthorityData(xNewData.get()); + } + SwInsertField_Data aData(SwFieldTypesEnum::Authority, 0, sFields.makeStringAndClear(), OUString(), 0 ); + aMgr.InsertField( aData ); + } + else if(aMgr.GetCurField()) + { + aMgr.UpdateCurField(0, sFields.makeStringAndClear(), OUString()); + } + } + if(!m_bNewEntry) + CloseHdl(*m_xCloseBT); +} + +IMPL_LINK(SwAuthorMarkPane, CreateEntryHdl, weld::Button&, rButton, void) +{ + bool bCreate = &rButton == m_xCreateEntryPB.get(); + OUString sOldId = m_sCreatedEntry[0]; + for(int i = 0; i < AUTH_FIELD_END; i++) + m_sCreatedEntry[i] = bCreate ? OUString() : m_sFields[i]; + SwCreateAuthEntryDlg_Impl aDlg(m_rDialog.getDialog(), + bCreate ? m_sCreatedEntry : m_sFields, + *m_pSh, m_bNewEntry, bCreate); + if(m_bNewEntry) + { + aDlg.SetCheckNameHdl(LINK(this, SwAuthorMarkPane, IsEntryAllowedHdl)); + } + if(RET_OK != aDlg.run()) + return; + + if(bCreate && !sOldId.isEmpty()) + { + m_xEntryLB->remove_text(sOldId); + } + for(int i = 0; i < AUTH_FIELD_END; i++) + { + m_sFields[i] = aDlg.GetEntryText(static_cast<ToxAuthorityField>(i)); + m_sCreatedEntry[i] = m_sFields[i]; + } + if(m_bNewEntry && !m_xFromDocContentRB->get_active()) + { + m_xFromDocContentRB->set_active(true); + ChangeSourceHdl(*m_xFromDocContentRB); + } + if(bCreate) + { + OSL_ENSURE(m_xEntryLB->find_text(m_sFields[AUTH_FIELD_IDENTIFIER]) == -1, + "entry exists!"); + m_xEntryLB->append_text(m_sFields[AUTH_FIELD_IDENTIFIER]); + m_xEntryLB->set_active_text(m_sFields[AUTH_FIELD_IDENTIFIER]); + } + m_xEntryED->set_text(m_sFields[AUTH_FIELD_IDENTIFIER]); + m_xAuthorFI->set_label(m_sFields[AUTH_FIELD_AUTHOR]); + m_xTitleFI->set_label(m_sFields[AUTH_FIELD_TITLE]); + m_xActionBT->set_sensitive(true); + + if (!m_bNewEntry) + { + // When in edit mode, automatically apply the changed entry to update the field in the doc + // model. + InsertHdl(*m_xActionBT); + } +} + +IMPL_LINK_NOARG(SwAuthorMarkPane, ChangeSourceHdl, weld::Toggleable&, void) +{ + bool bFromComp = m_xFromComponentRB->get_active(); + s_bIsFromComponent = bFromComp; + m_xCreateEntryPB->set_sensitive(!s_bIsFromComponent); + m_xEntryLB->clear(); + if(s_bIsFromComponent) + { + if(!m_bBibAccessInitialized) + { + uno::Reference< uno::XComponentContext > xContext = getProcessComponentContext(); + m_xBibAccess = frame::Bibliography::create( xContext ); + uno::Reference< beans::XPropertySet > xPropSet(m_xBibAccess, uno::UNO_QUERY); + OUString uPropName("BibliographyDataFieldNames"); + if(xPropSet.is() && xPropSet->getPropertySetInfo()->hasPropertyByName(uPropName)) + { + uno::Any aNames = xPropSet->getPropertyValue(uPropName); + uno::Sequence<beans::PropertyValue> aSeq; + if( aNames >>= aSeq) + { + for(const beans::PropertyValue& rProp : std::as_const(aSeq)) + { + sal_Int16 nField = 0; + rProp.Value >>= nField; + if(nField >= 0 && nField < AUTH_FIELD_END) + m_sColumnTitles[nField] = rProp.Name; + } + } + } + m_bBibAccessInitialized = true; + } + if(m_xBibAccess.is()) + { + const uno::Sequence<OUString> aIdentifiers = m_xBibAccess->getElementNames(); + for(const OUString& rName : aIdentifiers) + m_xEntryLB->append_text(rName); + } + } + else + { + const SwAuthorityFieldType* pFType = static_cast<const SwAuthorityFieldType*>( + m_pSh->GetFieldType(SwFieldIds::TableOfAuthorities, OUString())); + if(pFType) + { + std::vector<OUString> aIds; + pFType->GetAllEntryIdentifiers( aIds ); + for(const OUString & i : aIds) + m_xEntryLB->append_text(i); + } + if(!m_sCreatedEntry[AUTH_FIELD_IDENTIFIER].isEmpty()) + m_xEntryLB->append_text(m_sCreatedEntry[AUTH_FIELD_IDENTIFIER]); + } + m_xEntryLB->set_active(0); + CompEntryHdl(*m_xEntryLB); +} + +IMPL_LINK(SwAuthorMarkPane, EditModifyHdl, weld::Entry&, rEdit, void) +{ + Link<weld::Entry&,bool> aAllowed = LINK(this, SwAuthorMarkPane, IsEditAllowedHdl); + bool bResult = aAllowed.Call(rEdit); + m_xActionBT->set_sensitive(bResult); + if(bResult) + { + OUString sEntry(rEdit.get_text()); + m_sFields[AUTH_FIELD_IDENTIFIER] = sEntry; + m_sCreatedEntry[AUTH_FIELD_IDENTIFIER] = sEntry; + } +}; + +IMPL_LINK(SwAuthorMarkPane, IsEntryAllowedHdl, weld::Entry&, rEdit, bool) +{ + OUString sEntry = rEdit.get_text(); + bool bAllowed = false; + if(!sEntry.isEmpty()) + { + if (m_xEntryLB->find_text(sEntry) != -1) + return false; + else if(s_bIsFromComponent) + { + const SwAuthorityFieldType* pFType = static_cast<const SwAuthorityFieldType*>( + m_pSh->GetFieldType(SwFieldIds::TableOfAuthorities, OUString())); + bAllowed = !pFType || !pFType->GetEntryByIdentifier(sEntry); + } + else + { + bAllowed = !m_xBibAccess.is() || !m_xBibAccess->hasByName(sEntry); + } + } + return bAllowed; +} + +IMPL_LINK(SwAuthorMarkPane, IsEditAllowedHdl, weld::Entry&, rEdit, bool) +{ + OUString sEntry = rEdit.get_text(); + bool bAllowed = false; + if(!sEntry.isEmpty()) + { + if (m_xEntryLB->find_text(sEntry) != -1) + return false; + else if(s_bIsFromComponent) + { + const SwAuthorityFieldType* pFType = static_cast<const SwAuthorityFieldType*>( + m_pSh->GetFieldType(SwFieldIds::TableOfAuthorities, OUString())); + bAllowed = !pFType || !pFType->GetEntryByIdentifier(sEntry); + } + else + { + bAllowed = !m_xBibAccess.is() || !m_xBibAccess->hasByName(sEntry); + } + } + return bAllowed; +} + +void SwAuthorMarkPane::InitControls() +{ + OSL_ENSURE(m_pSh, "no shell?"); + SwField* pField = m_pSh->GetCurField(); + OSL_ENSURE(m_bNewEntry || pField, "no current marker"); + if(m_bNewEntry) + { + ChangeSourceHdl(m_xFromComponentRB->get_active() ? *m_xFromComponentRB : *m_xFromDocContentRB); + m_xCreateEntryPB->set_sensitive(!m_xFromComponentRB->get_active()); + if(!m_xFromComponentRB->get_active() && !m_sCreatedEntry[0].isEmpty()) + for(int i = 0; i < AUTH_FIELD_END; i++) + m_sFields[i] = m_sCreatedEntry[i]; + } + if(m_bNewEntry || !pField || pField->GetTyp()->Which() != SwFieldIds::TableOfAuthorities) + return; + + const SwAuthEntry* pEntry = static_cast<SwAuthorityField*>(pField)->GetAuthEntry(); + + OSL_ENSURE(pEntry, "No authority entry found"); + if(!pEntry) + return; + for(int i = 0; i < AUTH_FIELD_END; i++) + m_sFields[i] = pEntry->GetAuthorField(static_cast<ToxAuthorityField>(i)); + + m_xEntryED->set_text(pEntry->GetAuthorField(AUTH_FIELD_IDENTIFIER)); + m_xAuthorFI->set_label(pEntry->GetAuthorField(AUTH_FIELD_AUTHOR)); + m_xTitleFI->set_label(pEntry->GetAuthorField(AUTH_FIELD_TITLE)); +} + +void SwAuthorMarkPane::Activate() +{ + m_xActionBT->set_sensitive(!m_pSh->HasReadonlySel()); +} + +namespace +{ + const TranslateId STR_AUTH_FIELD_ARY[] = + { + STR_AUTH_FIELD_IDENTIFIER, + STR_AUTH_FIELD_AUTHORITY_TYPE, + STR_AUTH_FIELD_ADDRESS, + STR_AUTH_FIELD_ANNOTE, + STR_AUTH_FIELD_AUTHOR, + STR_AUTH_FIELD_BOOKTITLE, + STR_AUTH_FIELD_CHAPTER, + STR_AUTH_FIELD_EDITION, + STR_AUTH_FIELD_EDITOR, + STR_AUTH_FIELD_HOWPUBLISHED, + STR_AUTH_FIELD_INSTITUTION, + STR_AUTH_FIELD_JOURNAL, + STR_AUTH_FIELD_MONTH, + STR_AUTH_FIELD_NOTE, + STR_AUTH_FIELD_NUMBER, + STR_AUTH_FIELD_ORGANIZATIONS, + STR_AUTH_FIELD_PAGES, + STR_AUTH_FIELD_PUBLISHER, + STR_AUTH_FIELD_SCHOOL, + STR_AUTH_FIELD_SERIES, + STR_AUTH_FIELD_TITLE, + STR_AUTH_FIELD_TYPE, + STR_AUTH_FIELD_VOLUME, + STR_AUTH_FIELD_YEAR, + STR_AUTH_FIELD_URL, + STR_AUTH_FIELD_CUSTOM1, + STR_AUTH_FIELD_CUSTOM2, + STR_AUTH_FIELD_CUSTOM3, + STR_AUTH_FIELD_CUSTOM4, + STR_AUTH_FIELD_CUSTOM5, + STR_AUTH_FIELD_ISBN, + STR_AUTH_FIELD_LOCAL_URL, + STR_AUTH_FIELD_TARGET_TYPE, + STR_AUTH_FIELD_TARGET_URL, + }; +} + +SwCreateAuthEntryDlg_Impl::SwCreateAuthEntryDlg_Impl(weld::Window* pParent, + const OUString pFields[], + SwWrtShell& rSh, + bool bNewEntry, + bool bCreate) + : GenericDialogController(pParent, "modules/swriter/ui/createauthorentry.ui", "CreateAuthorEntryDialog") + , m_rWrtSh(rSh) + , m_bNewEntryMode(bNewEntry) + , m_bNameAllowed(true) + , m_xOKBT(m_xBuilder->weld_button("ok")) + , m_xBox(m_xBuilder->weld_container("box")) + , m_xLeft(m_xBuilder->weld_container("leftgrid")) + , m_xRight(m_xBuilder->weld_container("rightgrid")) + , m_pTargetURLField(nullptr) +{ + bool bLeft = true; + sal_Int32 nLeftRow(0), nRightRow(0); + for(int nIndex = 0; nIndex < AUTH_FIELD_END; nIndex++) + { + //m_xBox parent just to have some parent during setup, added contents are not directly visible under m_xBox + m_aBuilders.emplace_back(Application::CreateBuilder(m_xBox.get(), "modules/swriter/ui/bibliofragment.ui")); + const TextInfo aCurInfo = aTextInfoArr[nIndex]; + + m_aOrigContainers.emplace_back(m_aBuilders.back()->weld_container("biblioentry")); + m_aFixedTexts.emplace_back(m_aBuilders.back()->weld_label("label")); + if (bLeft) + m_aOrigContainers.back()->move(m_aFixedTexts.back().get(), m_xLeft.get()); + else + m_aOrigContainers.back()->move(m_aFixedTexts.back().get(), m_xRight.get()); + m_aFixedTexts.back()->set_grid_left_attach(0); + m_aFixedTexts.back()->set_grid_top_attach(bLeft ? nLeftRow : nRightRow); + m_aFixedTexts.back()->set_label(SwResId(STR_AUTH_FIELD_ARY[aCurInfo.nToxField])); + m_aFixedTexts.back()->show(); + if( AUTH_FIELD_AUTHORITY_TYPE == aCurInfo.nToxField ) + { + m_xTypeListBox = m_aBuilders.back()->weld_combo_box("listbox"); + if (bLeft) + m_aOrigContainers.back()->move(m_xTypeListBox.get(), m_xLeft.get()); + else + m_aOrigContainers.back()->move(m_xTypeListBox.get(), m_xRight.get()); + + for (int j = 0; j < AUTH_TYPE_END; j++) + { + m_xTypeListBox->append_text( + SwAuthorityFieldType::GetAuthTypeName(static_cast<ToxAuthorityType>(j))); + } + if(!pFields[aCurInfo.nToxField].isEmpty()) + { + m_xTypeListBox->set_active(pFields[aCurInfo.nToxField].toInt32()); + } + m_xTypeListBox->set_grid_left_attach(1); + m_xTypeListBox->set_grid_top_attach(bLeft ? nLeftRow : nRightRow); + m_xTypeListBox->set_hexpand(true); + m_xTypeListBox->show(); + m_xTypeListBox->connect_changed(LINK(this, SwCreateAuthEntryDlg_Impl, EnableHdl)); + m_xTypeListBox->set_help_id(aCurInfo.pHelpId); + m_aFixedTexts.back()->set_mnemonic_widget(m_xTypeListBox.get()); + } + else if(AUTH_FIELD_IDENTIFIER == aCurInfo.nToxField && !m_bNewEntryMode) + { + m_xIdentifierBox = m_aBuilders.back()->weld_combo_box("combobox"); + if (bLeft) + m_aOrigContainers.back()->move(m_xIdentifierBox.get(), m_xLeft.get()); + else + m_aOrigContainers.back()->move(m_xIdentifierBox.get(), m_xRight.get()); + + m_xIdentifierBox->connect_changed(LINK(this, + SwCreateAuthEntryDlg_Impl, IdentifierHdl)); + + const SwAuthorityFieldType* pFType = static_cast<const SwAuthorityFieldType*>( + rSh.GetFieldType(SwFieldIds::TableOfAuthorities, OUString())); + if(pFType) + { + std::vector<OUString> aIds; + pFType->GetAllEntryIdentifiers( aIds ); + for (const OUString& a : aIds) + m_xIdentifierBox->append_text(a); + } + m_xIdentifierBox->set_entry_text(pFields[aCurInfo.nToxField]); + m_xIdentifierBox->set_grid_left_attach(1); + m_xIdentifierBox->set_grid_top_attach(bLeft ? nLeftRow : nRightRow); + m_xIdentifierBox->set_hexpand(true); + m_xIdentifierBox->show(); + m_xIdentifierBox->set_help_id(aCurInfo.pHelpId); + m_aFixedTexts.back()->set_mnemonic_widget(m_xIdentifierBox.get()); + } + else if (AUTH_FIELD_TARGET_TYPE == aCurInfo.nToxField) + { + m_xTargetTypeListBox = m_aBuilders.back()->weld_combo_box("listbox-target-type"); + if (bLeft) + m_aOrigContainers.back()->move(m_xTargetTypeListBox.get(), m_xLeft.get()); + else + m_aOrigContainers.back()->move(m_xTargetTypeListBox.get(), m_xRight.get()); + + if(!pFields[aCurInfo.nToxField].isEmpty()) + { + m_xTargetTypeListBox->set_active(pFields[aCurInfo.nToxField].toInt32()); + } + else if(m_bNewEntryMode) + { + // For new documents, set value to "BibliographyTableRow" + m_xTargetTypeListBox->set_active(SwAuthorityField::TargetType::BibliographyTableRow); + } + m_xTargetTypeListBox->set_grid_left_attach(1); + m_xTargetTypeListBox->set_grid_top_attach(bLeft ? nLeftRow : nRightRow); + m_xTargetTypeListBox->set_hexpand(true); + m_xTargetTypeListBox->show(); + m_xTargetTypeListBox->connect_changed(LINK(this, SwCreateAuthEntryDlg_Impl, TargetTypeHdl)); + m_xTargetTypeListBox->set_help_id(aCurInfo.pHelpId); + m_aFixedTexts.back()->set_mnemonic_widget(m_xTargetTypeListBox.get()); + } + else + { + m_pBoxes[nIndex] = m_aBuilders.back()->weld_box("vbox"); + m_pEdits[nIndex] = m_aBuilders.back()->weld_entry("entry"); + + if (AUTH_FIELD_TARGET_URL == aCurInfo.nToxField) + { + m_pTargetURLField = m_pEdits[nIndex].get(); + assert(m_xTargetTypeListBox); + m_pTargetURLField->set_sensitive( + m_xTargetTypeListBox->get_active() == SwAuthorityField::TargetType::UseTargetURL); + } + + if (bLeft) + m_aOrigContainers.back()->move(m_pBoxes[nIndex].get(), m_xLeft.get()); + else + m_aOrigContainers.back()->move(m_pBoxes[nIndex].get(), m_xRight.get()); + + m_pBoxes[nIndex]->set_grid_left_attach(1); + m_pBoxes[nIndex]->set_grid_top_attach(bLeft ? nLeftRow : nRightRow); + m_pBoxes[nIndex]->set_hexpand(true); + if (aCurInfo.nToxField == AUTH_FIELD_LOCAL_URL) + { + m_xLocalBrowseButton = m_aBuilders.back()->weld_button("browse"); + m_xLocalBrowseButton->connect_clicked( + LINK(this, SwCreateAuthEntryDlg_Impl, BrowseHdl)); + m_xLocalPageCB = m_aBuilders.back()->weld_check_button("pagecb"); + // Distinguish different instances of this for ui-testing. + m_xLocalPageCB->set_buildable_name(m_xLocalPageCB->get_buildable_name() + + "-local-visible"); + m_xLocalPageSB = m_aBuilders.back()->weld_spin_button("pagesb"); + } + + // Now that both pEdits[nIndex] and m_xPageSB is initialized, set their values. + OUString aText = pFields[aCurInfo.nToxField]; + if (aCurInfo.nToxField == AUTH_FIELD_LOCAL_URL) + { + OUString aUrl; + int nPageNumber; + if (SplitUrlAndPage(aText, aUrl, nPageNumber)) + { + m_pEdits[nIndex]->set_text(aUrl); + m_xLocalPageCB->set_active(true); + m_xLocalPageSB->set_sensitive(true); + m_xLocalPageSB->set_value(nPageNumber); + } + else + { + m_pEdits[nIndex]->set_text(aText); + } + } + else + { + m_pEdits[nIndex]->set_text(aText); + } + m_pEdits[nIndex]->show(); + m_pEdits[nIndex]->set_help_id(aCurInfo.pHelpId); + + if(AUTH_FIELD_IDENTIFIER == aCurInfo.nToxField) + { + m_pEdits[nIndex]->connect_changed(LINK(this, SwCreateAuthEntryDlg_Impl, ShortNameHdl)); + m_bNameAllowed = !pFields[nIndex].isEmpty(); + if(!bCreate) + { + m_aFixedTexts.back()->set_sensitive(false); + m_pEdits[nIndex]->set_sensitive(false); + } + } + else if (aCurInfo.nToxField == AUTH_FIELD_LOCAL_URL) + { + m_xLocalPageCB->show(); + m_xLocalPageCB->connect_toggled(LINK(this, SwCreateAuthEntryDlg_Impl, PageNumHdl)); + m_xLocalPageSB->show(); + } + + m_aFixedTexts.back()->set_mnemonic_widget(m_pEdits[nIndex].get()); + } + if(bLeft) + ++nLeftRow; + else + ++nRightRow; + bLeft = !bLeft; + } + assert(m_xTypeListBox && "this will exist after the loop"); + EnableHdl(*m_xTypeListBox); +} + +OUString SwCreateAuthEntryDlg_Impl::GetEntryText(ToxAuthorityField eField) const +{ + if( AUTH_FIELD_AUTHORITY_TYPE == eField ) + { + assert(m_xTypeListBox && "No ListBox"); + return OUString::number(m_xTypeListBox->get_active()); + } + + if( AUTH_FIELD_IDENTIFIER == eField && !m_bNewEntryMode) + { + assert(m_xIdentifierBox && "No ComboBox"); + return m_xIdentifierBox->get_active_text(); + } + + if (AUTH_FIELD_TARGET_TYPE == eField) + { + assert(m_xTargetTypeListBox && "No TargetType ListBox"); + return OUString::number(m_xTargetTypeListBox->get_active()); + } + + for(int nIndex = 0; nIndex < AUTH_FIELD_END; nIndex++) + { + const TextInfo aCurInfo = aTextInfoArr[nIndex]; + if(aCurInfo.nToxField == eField) + { + if (aCurInfo.nToxField == AUTH_FIELD_LOCAL_URL) + { + return MergeUrlAndPage(m_pEdits[nIndex]->get_text(), m_xLocalPageSB); + } + else + { + return m_pEdits[nIndex]->get_text(); + } + } + } + + return OUString(); +} + +IMPL_LINK(SwCreateAuthEntryDlg_Impl, IdentifierHdl, weld::ComboBox&, rBox, void) +{ + const SwAuthorityFieldType* pFType = static_cast<const SwAuthorityFieldType*>( + m_rWrtSh.GetFieldType(SwFieldIds::TableOfAuthorities, OUString())); + if(!pFType) + return; + + const SwAuthEntry* pEntry = pFType->GetEntryByIdentifier( + rBox.get_active_text()); + if(!pEntry) + return; + + for(int i = 0; i < AUTH_FIELD_END; i++) + { + const TextInfo aCurInfo = aTextInfoArr[i]; + if(AUTH_FIELD_IDENTIFIER == aCurInfo.nToxField) + continue; + if(AUTH_FIELD_AUTHORITY_TYPE == aCurInfo.nToxField) + m_xTypeListBox->set_active_text( + pEntry->GetAuthorField(aCurInfo.nToxField)); + else + m_pEdits[i]->set_text( + pEntry->GetAuthorField(aCurInfo.nToxField)); + } +} + +IMPL_LINK(SwCreateAuthEntryDlg_Impl, ShortNameHdl, weld::Entry&, rEdit, void) +{ + if (m_aShortNameCheckLink.IsSet()) + { + bool bEnable = m_aShortNameCheckLink.Call(rEdit); + m_bNameAllowed |= bEnable; + m_xOKBT->set_sensitive(m_xTypeListBox->get_active() != -1 && bEnable); + } +} + +IMPL_LINK(SwCreateAuthEntryDlg_Impl, EnableHdl, weld::ComboBox&, rBox, void) +{ + m_xOKBT->set_sensitive(m_bNameAllowed && rBox.get_active() != -1); + m_xLocalBrowseButton->show(); +}; + +IMPL_LINK(SwCreateAuthEntryDlg_Impl, TargetTypeHdl, weld::ComboBox&, rBox, void) +{ + assert(m_pTargetURLField); + m_pTargetURLField->set_sensitive(rBox.get_active() == SwAuthorityField::TargetType::UseTargetURL); +} + +IMPL_LINK(SwCreateAuthEntryDlg_Impl, BrowseHdl, weld::Button&, rButton, void) +{ + sfx2::FileDialogHelper aFileDlg(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, getDialog()); + OUString aPath; + if (&rButton == m_xLocalBrowseButton.get()) + { + aPath = GetEntryText(AUTH_FIELD_LOCAL_URL); + } + if (!aPath.isEmpty()) + { + aFileDlg.SetDisplayDirectory(aPath); + } + else + { + OUString aBaseURL = m_rWrtSh.GetDoc()->GetDocShell()->getDocumentBaseURL(); + if (!aBaseURL.isEmpty()) + { + aFileDlg.SetDisplayDirectory(aBaseURL); + } + } + + if (aFileDlg.Execute() != ERRCODE_NONE) + { + return; + } + + aPath = aFileDlg.GetPath(); + + for (int nIndex = 0; nIndex < AUTH_FIELD_END; nIndex++) + { + const TextInfo& rCurInfo = aTextInfoArr[nIndex]; + if (rCurInfo.nToxField == AUTH_FIELD_LOCAL_URL && &rButton == m_xLocalBrowseButton.get()) + { + m_pEdits[nIndex]->set_text(aPath); + break; + } + } +}; + +IMPL_LINK(SwCreateAuthEntryDlg_Impl, PageNumHdl, weld::Toggleable&, rPageCB, void) +{ + if (rPageCB.get_active()) + { + m_xLocalPageSB->set_sensitive(true); + m_xLocalPageSB->set_value(1); + } + else + { + m_xLocalPageSB->set_sensitive(false); + } +} + +SwAuthMarkFloatDlg::SwAuthMarkFloatDlg(SfxBindings* _pBindings, + SfxChildWindow* pChild, + weld::Window *pParent, + SfxChildWinInfo const * pInfo, + bool bNew) + : SfxModelessDialogController(_pBindings, pChild, pParent, + "modules/swriter/ui/bibliographyentry.ui", "BibliographyEntryDialog") + , m_aContent(*this, *m_xBuilder, bNew) +{ + Initialize(pInfo); + if (SwWrtShell* pWrtShell = ::GetActiveWrtShell()) + m_aContent.ReInitDlg(*pWrtShell); +} + +void SwAuthMarkFloatDlg::Activate() +{ + SfxModelessDialogController::Activate(); + m_aContent.Activate(); +} + +void SwAuthMarkFloatDlg::ReInitDlg(SwWrtShell& rWrtShell) +{ + m_aContent.ReInitDlg( rWrtShell ); +} + +SwAuthMarkModalDlg::SwAuthMarkModalDlg(weld::Window *pParent, SwWrtShell& rSh) + : SfxDialogController(pParent, "modules/swriter/ui/bibliographyentry.ui", + "BibliographyEntryDialog") + , m_aContent(*this, *m_xBuilder, false) +{ + m_aContent.ReInitDlg(rSh); +} + +short SwAuthMarkModalDlg::run() +{ + short ret = SfxDialogController::run(); + if (ret == RET_OK) + Apply(); + return ret; +} + +void SwAuthMarkModalDlg::Apply() +{ + m_aContent.InsertHdl(*m_aContent.m_xActionBT); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/misc/bookmark.cxx b/sw/source/ui/misc/bookmark.cxx new file mode 100644 index 0000000000..6431809c95 --- /dev/null +++ b/sw/source/ui/misc/bookmark.cxx @@ -0,0 +1,590 @@ +/* -*- 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::s_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::s_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_xEditTextBtn->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 = m_rSh.getIDocumentMarkAccess(); + pMarkAccess->deleteMark(pMarkAccess->findMark(sRemoved), false); + SfxRequest aReq(m_rSh.GetView().GetViewFrame(), FN_DELETE_BOOKMARK); + aReq.AppendItem(SfxStringItem(FN_DELETE_BOOKMARK, sRemoved)); + aReq.Done(); + std::erase(m_aTableBookmarks, std::make_pair(pBookmark, sRemoved)); + + ++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_xEditTextBtn->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; + + SelectionChanged(); +} + +void SwInsertBookmarkDlg::SelectionChanged() +{ + 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_xEditTextBtn->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_xEditTextBtn->set_sensitive(false); + m_xRenameBtn->set_sensitive(false); + m_xDeleteBtn->set_sensitive(false); + } +} + +IMPL_LINK_NOARG(SwInsertBookmarkDlg, EditTextHdl, weld::Button&, void) +{ + if (!ValidateBookmarks()) + return; + auto pSelected = m_xBookmarksBox->get_selected(); + if (!pSelected) + return; + + m_xBookmarksBox->start_editing(*pSelected); +} + +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 = m_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::s_cSeparator)); + + if (pDlg->Execute()) + { + ValidateBookmarks(); + m_xDeleteBtn->set_sensitive(false); + m_xGotoBtn->set_sensitive(false); + m_xEditTextBtn->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(); + m_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); +} + +IMPL_LINK(SwInsertBookmarkDlg, EditingHdl, weld::TreeIter const&, rIter, bool) +{ + sw::mark::IMark const* const pBookmark( + weld::fromId<sw::mark::IMark*>(m_xBookmarksBox->get_id(rIter))); + assert(pBookmark); + return pBookmark->IsExpanded() + && pBookmark->GetMarkPos().GetNode() == pBookmark->GetOtherMarkPos().GetNode() + && !m_xBookmarksBox->get_text(rIter).endsWith(u"…"); +} + +IMPL_LINK(SwInsertBookmarkDlg, EditedHdl, weld::TreeView::iter_string const&, rIterString, bool) +{ + sw::mark::IMark const* const pBookmark( + weld::fromId<sw::mark::IMark*>(m_xBookmarksBox->get_id(rIterString.first))); + assert(pBookmark); + bool bRet(false); + if (pBookmark->GetMarkPos() != pBookmark->GetOtherMarkPos()) + { + if (pBookmark->GetMarkPos().GetNode() != pBookmark->GetOtherMarkPos().GetNode()) + { + return false; // don't allow editing if it spans multiple nodes + } + m_rSh.Push(); + m_rSh.GotoMark(pBookmark); + // GetSelText only works for 1 paragraph, but it's checked above + if (m_rSh.GetSelText() != rIterString.second) + { + bRet = m_rSh.Replace(rIterString.second, false); + } + m_rSh.Pop(SwEditShell::PopMode::DeleteCurrent); + } + else if (pBookmark->IsExpanded() && !rIterString.second.isEmpty()) + { // SwEditShell::Replace does nothing for empty selection + m_rSh.Insert(rIterString.second); + bRet = true; + } + return bRet; +} + +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)); + + m_rSh.EnterStdMode(); + m_rSh.GotoMark(pBookmark); +} + +bool SwInsertBookmarkDlg::ValidateBookmarks() +{ + if (HaveBookmarksChanged()) + { + PopulateTable(); + m_xEditBox->set_text(""); + return false; + } + return true; +} + +bool SwInsertBookmarkDlg::HaveBookmarksChanged() +{ + IDocumentMarkAccess* const pMarkAccess = m_rSh.getIDocumentMarkAccess(); + if (pMarkAccess->getBookmarksCount() != m_nLastBookmarksCount) + return true; + + std::vector<std::pair<sw::mark::IMark*, OUString>>::const_iterator aListIter + = m_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 == m_aTableBookmarks.end()) + return true; + if (aListIter->first != *ppBookmark || aListIter->second != (*ppBookmark)->GetName()) + return true; + ++aListIter; + } + } + // less bookmarks then expected + return aListIter != m_aTableBookmarks.end(); +} + +void SwInsertBookmarkDlg::PopulateTable() +{ + m_aTableBookmarks.clear(); + m_xBookmarksBox->clear(); + + IDocumentMarkAccess* const pMarkAccess = m_rSh.getIDocumentMarkAccess(); + for (IDocumentMarkAccess::const_iterator_t ppBookmark = pMarkAccess->getBookmarksBegin(); + ppBookmark != pMarkAccess->getBookmarksEnd(); ++ppBookmark) + { + if (IDocumentMarkAccess::MarkType::BOOKMARK == IDocumentMarkAccess::GetType(**ppBookmark)) + { + m_xBookmarksBox->InsertBookmark(m_rSh, *ppBookmark); + m_aTableBookmarks.emplace_back(*ppBookmark, (*ppBookmark)->GetName()); + } + } + m_nLastBookmarksCount = pMarkAccess->getBookmarksCount(); +} + +SwInsertBookmarkDlg::SwInsertBookmarkDlg(weld::Window* pParent, SwWrtShell& rS, + OUString const* const pSelected) + : SfxDialogController(pParent, "modules/swriter/ui/insertbookmark.ui", "InsertBookmarkDialog") + , m_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_xEditTextBtn(m_xBuilder->weld_button("edittext")) + , 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_xBookmarksBox->connect_editing(LINK(this, SwInsertBookmarkDlg, EditingHdl), + LINK(this, SwInsertBookmarkDlg, EditedHdl)); + 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_xEditTextBtn->connect_clicked(LINK(this, SwInsertBookmarkDlg, EditTextHdl)); + 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_xEditTextBtn->set_sensitive(false); + m_xRenameBtn->set_sensitive(false); + + // select 3rd column, otherwise it'll pick 1st one + m_xBookmarksBox->set_column_editables({ false, false, true, false, 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 = m_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()); + + if (pSelected) + { + if (m_xBookmarksBox->SelectByName(*pSelected)) + { + SelectionChanged(); + // which is better, focus on a button or focus on the table row? + // as long as editing doesn't work via the TreeView with VCL + // widgets, better on button. + m_xEditTextBtn->grab_focus(); + } + } +} + +SwInsertBookmarkDlg::~SwInsertBookmarkDlg() +{ + // tdf#146261 - Remember size of bookmark dialog + SvtViewOptions aDlgOpt(EViewType::Dialog, "BookmarkDialog"); + OUString sWindowState = m_xDialog->get_window_state(vcl::WindowDataMask::PosSize); + aDlgOpt.SetWindowState(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(SwWrtShell& rSh, sw::mark::IMark* const pMark) +{ + sw::mark::IBookmark* pBookmark = dynamic_cast<sw::mark::IBookmark*>(pMark); + assert(pBookmark); + + OUString sBookmarkNodeText; + static const sal_Int32 nMaxTextLen = 50; + + if (pBookmark->IsExpanded()) + { + rSh.Push(); + rSh.GotoMark(pBookmark); + rSh.GetSelectedText(sBookmarkNodeText, ParaBreakType::ToBlank); + rSh.Pop(SwEditShell::PopMode::DeleteCurrent); + } + if (nMaxTextLen < sBookmarkNodeText.getLength()) + { + sBookmarkNodeText = sBookmarkNodeText.subView(0, nMaxTextLen); + ; + sBookmarkNodeText += u"…"; + } + + const OUString& sHideCondition = pBookmark->GetHideCondition(); + const OUString& sName = pBookmark->GetName(); + OUString sHidden + = (pBookmark->IsHidden() || !sHideCondition.isEmpty() || + // tdf#150955 add "hidden" status to the imported OOXML _Toc and _Ref bookmarks + // to allow separating custom bookmarks by sorting based on their Hidden status. + // Note: this "hidden" means here only that these bookmarks haven't got + // visible bookmark formatting aids (gray I-shape or brackets), otherwise + // their anchor are still visible. + sName.startsWith("_Toc") || sName.startsWith("_Ref")) + ? SwResId(STR_BOOKMARK_YES) + : SwResId(STR_BOOKMARK_NO); + + 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, sName, 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)); +} + +bool BookmarkTable::SelectByName(const OUString& sName) +{ + auto xEntry = GetRowByBookmarkName(sName); + if (!xEntry) + return false; + select(*xEntry); + return true; +} + +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 0000000000..f318fa6a69 --- /dev/null +++ b/sw/source/ui/misc/contentcontroldlg.cxx @@ -0,0 +1,477 @@ +/* -*- 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_xAlias(m_xBuilder->weld_entry("aliasentry")) + , m_xTag(m_xBuilder->weld_entry("tagentry")) + , m_xId(m_xBuilder->weld_spin_button("idspinbutton")) + , m_xTabIndex(m_xBuilder->weld_spin_button("tabindexspinbutton")) + , 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->GetNode().GetTextNode(); + if (!pTextNode) + { + return; + } + + SwTextAttr* pAttr = pTextNode->GetTextAttrAt( + pStart->GetContentIndex(), RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::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->GetAlias().isEmpty()) + { + m_xAlias->set_text(m_pContentControl->GetAlias()); + m_xAlias->save_value(); + } + + if (!m_pContentControl->GetTag().isEmpty()) + { + m_xTag->set_text(m_pContentControl->GetTag()); + m_xTag->save_value(); + } + + // The ID is supposed to be a unique ID, but it isn't really used for much + // and in MS Word it (supposedly) is automatically made unique if it is a duplicate. + // The main purpose for having it here is lookup, not modification, + // since AFAIK the only use of the ID is for VBA macro name lookup. + // Since it is used as unsigned in VBA, make the UI display the unsigned values too. + m_xId->set_range(0, SAL_MAX_UINT32); + m_xId->set_increments(1, 10); + const sal_uInt32 nId = static_cast<sal_uInt32>(m_pContentControl->GetId()); + m_xId->set_value(nId); + // a one-time chance to set the ID - only allow setting it when it is undefined. + if (nId) + m_xId->set_editable(false); // still available for copy/paste + m_xId->save_value(); + + // And on the contrary, the tabIndex is stored as unsigned, + // even though humanly speaking it is much nicer to use -1 to indicate a no tab stop. Oh well. + m_xTabIndex->set_range(SAL_MIN_INT32, SAL_MAX_INT32); + m_xTabIndex->set_increments(1, 10); + const sal_Int32 nTabIndex = static_cast<sal_Int32>(m_pContentControl->GetTabIndex()); + m_xTabIndex->set_value(nTabIndex); + m_xTabIndex->save_value(); + + 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->GetComboBox() || m_pContentControl->GetDropDown()) + { + 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() +{ + if (m_xListItemDialog) + m_xListItemDialog.disposeAndClear(); +} + +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_xAlias->get_value_changed_from_saved()) + { + m_pContentControl->SetAlias(m_xAlias->get_text()); + bChanged = true; + } + + if (m_xTag->get_value_changed_from_saved()) + { + m_pContentControl->SetTag(m_xTag->get_text()); + bChanged = true; + } + + if (m_xId->get_value_changed_from_saved()) + { + m_pContentControl->SetId(o3tl::narrowing<sal_Int32>(m_xId->get_value())); + bChanged = true; + } + + if (m_xTabIndex->get_value_changed_from_saved()) + { + m_pContentControl->SetTabIndex(o3tl::narrowing<sal_uInt32>(m_xTabIndex->get_value())); + 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) +{ + std::shared_ptr<SwContentControlListItem> aItem = std::make_shared<SwContentControlListItem>(); + SwAbstractDialogFactory& rFact = swui::GetFactory(); + m_xListItemDialog = rFact.CreateSwContentControlListItemDlg(m_xDialog.get(), *aItem); + m_xListItemDialog->StartExecuteAsync([this, aItem](sal_Int32 nResult) { + if (nResult == RET_OK) + { + 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); + } + + m_xListItemDialog.disposeAndClear(); + }); +} + +IMPL_LINK_NOARG(SwContentControlDlg, RenameHdl, weld::Button&, void) +{ + int nRow = m_xListItems->get_selected_index(); + if (nRow < 0) + { + return; + } + + std::shared_ptr<SwContentControlListItem> aItem = std::make_shared<SwContentControlListItem>(); + aItem->m_aDisplayText = m_xListItems->get_text(nRow, 0); + aItem->m_aValue = m_xListItems->get_text(nRow, 1); + SwAbstractDialogFactory& rFact = swui::GetFactory(); + m_xListItemDialog = rFact.CreateSwContentControlListItemDlg(m_xDialog.get(), *aItem); + m_xListItemDialog->StartExecuteAsync([this, aItem, nRow](sal_Int32 nResult) { + if (nResult == RET_OK) + { + 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); + } + + m_xListItemDialog.disposeAndClear(); + }); +} + +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) +{ + 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 0000000000..6ac160aebb --- /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 0000000000..0fbe3b7c6f --- /dev/null +++ b/sw/source/ui/misc/docfnote.cxx @@ -0,0 +1,393 @@ +/* -*- 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") + , m_rSh( rS ) +{ + RemoveResetButton(); + + GetOKButton().connect_clicked(LINK(this, SwFootNoteOptionDlg, OkHdl)); + + AddTabPage("footnotes", SwFootNoteOptionPage::Create, nullptr); + AddTabPage("endnotes", SwEndNoteOptionPage::Create, nullptr); +} + +void SwFootNoteOptionDlg::PageCreated(const OUString& /*rId*/, SfxTabPage &rPage) +{ + static_cast<SwEndNoteOptionPage&>(rPage).SetShell(m_rSh); +} + +IMPL_LINK(SwFootNoteOptionDlg, OkHdl, weld::Button&, rBtn, void) +{ + SfxItemSetFixed<1, 1> aDummySet(m_rSh.GetAttrPool()); + SfxTabPage *pPage = GetTabPage(u"footnotes"); + if ( pPage ) + pPage->FillItemSet( &aDummySet ); + pPage = GetTabPage(u"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 ? OUString("EndnotePage") : OUString("FootnotePage"), + &rSet) + , m_pSh(nullptr) + , m_bPosDoc(false) + , m_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_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 (!m_bEndNote) + { + m_xNumCountBox->connect_changed(LINK(this, SwEndNoteOptionPage, NumCountHdl)); + m_aNumDoc = m_xNumCountBox->get_text(FTNNUM_DOC); + m_aNumPage = m_xNumCountBox->get_text(FTNNUM_PAGE); + m_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(m_bEndNote ? new SwEndNoteInfo( m_pSh->GetEndNoteInfo() ) + : new SwFootnoteInfo( m_pSh->GetFootnoteInfo() )); + SfxObjectShell * pDocSh = SfxObjectShell::Current(); + + if (dynamic_cast<SwWebDocShell*>( pDocSh) ) + m_xStylesContainer->hide(); + + if ( m_bEndNote ) + { + m_bPosDoc = true; + } + else + { + const SwFootnoteInfo &rInf = m_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(m_aNumPage); + m_xNumCountBox->remove_text(m_aNumChapter); + m_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( + *m_pSh->GetView().GetDocShell()->GetDoc()); + m_xFootnoteCharTextTemplBox->set_active_text(pCharFormat->GetName()); + m_xFootnoteCharTextTemplBox->save_value(); + + pCharFormat = pInf->GetAnchorCharFormat( *m_pSh->GetDoc() ); + m_xFootnoteCharAnchorTemplBox->set_active_text( pCharFormat->GetName() ); + m_xFootnoteCharAnchorTemplBox->save_value(); + + // styles special regions + // paragraph + SfxStyleSheetBasePool* pStyleSheetPool = m_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 >(m_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 = m_pSh->GetPageDescCnt(); + for(size_t i = 0; i < nCount; ++i) + { + const SwPageDesc &rPageDesc = m_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(*m_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 = m_aNumDoc; + break; + case FTNNUM_PAGE: + sSelect = m_aNumPage; + break; + case FTNNUM_CHAPTER: + sSelect = m_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>(m_bPosDoc ? nPos + 2 : nPos); +} + +void SwEndNoteOptionPage::SetShell( SwWrtShell &rShell ) +{ + m_pSh = &rShell; + // collect character templates + m_xFootnoteCharTextTemplBox->clear(); + m_xFootnoteCharAnchorTemplBox->clear(); + ::FillCharStyleListBox(*m_xFootnoteCharTextTemplBox, + m_pSh->GetView().GetDocShell(), true); + + ::FillCharStyleListBox(*m_xFootnoteCharAnchorTemplBox, + m_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(); + m_bPosDoc = false; + if (m_xNumCountBox->find_text(m_aNumPage) == -1) + { + m_xNumCountBox->insert_text(FTNNUM_PAGE, m_aNumPage); + m_xNumCountBox->insert_text(FTNNUM_CHAPTER, m_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 ( !m_bPosDoc ) + SelectNumbering(FTNNUM_DOC); + + m_bPosDoc = true; + m_xNumCountBox->remove_text(m_aNumPage); + m_xNumCountBox->remove_text(m_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(m_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( m_pSh, + m_xFootnoteCharTextTemplBox->get_active_text() ) ); + pInf->SetAnchorCharFormat( lcl_GetCharFormat( m_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 = m_pSh->GetParaStyle(aFormatName, SwWrtShell::GETSTYLE_CREATEANY); + OSL_ENSURE(pColl, "paragraph style not found"); + pInf->SetFootnoteTextColl(*pColl); + } + + // page template + pInf->ChgPageDesc( m_pSh->FindPageDescByName( + m_xPageTemplBox->get_active_text(), true ) ); + + if ( m_bEndNote ) + { + if ( !(*pInf == m_pSh->GetEndNoteInfo()) ) + m_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 == m_pSh->GetFootnoteInfo()) ) + m_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 0000000000..ed74973a1b --- /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) + , m_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::TempFileNamed 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 constexpr 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)); + m_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()) + m_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)); + m_pGlosHdl->RenameGroup(sOld, sNew, sTitle); + if (it == m_RenamedArr.begin()) + { + m_sCreatedGroup = sNew; + } + } + for (auto& sNewGroup : m_InsertedArr) + { + OUString sNewTitle = sNewGroup.getToken(0, GLOS_DELIM); + if( sNewGroup != aActGroup ) + { + m_pGlosHdl->NewGroup(sNewGroup, sNewTitle); + if(m_sCreatedGroup.isEmpty()) + m_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(!m_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(!m_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 = !m_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 0000000000..8b2860c20c --- /dev/null +++ b/sw/source/ui/misc/glossary.cxx @@ -0,0 +1,1100 @@ +/* -*- 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 <unotextcursor.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(OUString::number(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(const SfxViewFrame& rViewFrame, + SwGlossaryHdl * pGlosHdl, SwWrtShell *pWrtShell) + : SfxDialogController(rViewFrame.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 + 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 OUString&, 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 constexpr 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 (!xSelEntry || !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)); + + // tdf#124088 - propose autotext and shortcut name based on selected text + if (m_pShell->HasSelection()) + { + OUString aSelText; + m_pShell->GetSelectedText(aSelText, ParaBreakType::ToBlank); + + aSelText = aSelText.trim(); + if (aSelText.getLength() > 25) + { + aSelText = aSelText.copy(0, 25); + if (const sal_Int32 nBlankIndex = aSelText.lastIndexOf(' '); nBlankIndex != -1) + aSelText = aSelText.copy(0, nBlankIndex); + } + + m_xNameED->set_text(aSelText); + m_xNameED->select_region(0, -1); + m_xShortNameEdit->set_text(lcl_GetValidShortCut(aSelText)); + } +} + +// 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() ); + } + + rtl::Reference< SwXTextCursor > & 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(static_cast<XSentenceCursor*>(xCursor.get())); + } + } + } + } + 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 0000000000..eb5c491a45 --- /dev/null +++ b/sw/source/ui/misc/impfnote.hxx @@ -0,0 +1,82 @@ +/* -*- 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 m_aNumDoc; + OUString m_aNumPage; + OUString m_aNumChapter; + SwWrtShell *m_pSh; + bool m_bPosDoc; + bool m_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::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 0000000000..f468ae51c6 --- /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(SwCursorSkipMode::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(SwCursorSkipMode::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(SwCursorSkipMode::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(SwCursorSkipMode::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( SwCursorSkipMode::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(SwCursorSkipMode::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 0000000000..8e9ad04111 --- /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 0000000000..fadef24662 --- /dev/null +++ b/sw/source/ui/misc/num.cxx @@ -0,0 +1,949 @@ +/* -*- 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) + , m_pSaveNum(nullptr) + , m_pWrtSh(nullptr) + , m_pOutlineDlg(nullptr) + , m_nActNumLvl(0) + , m_bModified(false) + , m_bPreset(false) + , m_bInInintControl(false) + , m_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_xAlignedAtMF->set_range(0, SAL_MAX_INT32, FieldUnit::NONE); + m_xListtabMF->set_range(0, SAL_MAX_INT32, FieldUnit::NONE); + m_xIndentAtMF->set_range(0, SAL_MAX_INT32, FieldUnit::NONE); + + 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() +{ + m_pActNum.reset(); + m_pOutlineDlg = nullptr; +} + +void SwNumPositionTabPage::InitControls() +{ + m_bInInintControl = true; + const bool bRelative = !m_bLabelAlignmentPosAndSpaceModeActive && + m_xRelativeCB->get_sensitive() && m_xRelativeCB->get_active(); + const bool bSingleSelection = m_xLevelLB->count_selected_rows() == 1 && + USHRT_MAX != m_nActNumLvl; + + m_xDistBorderMF->set_sensitive( !m_bLabelAlignmentPosAndSpaceModeActive && + ( bSingleSelection || bRelative || m_pOutlineDlg != nullptr ) ); + m_xDistBorderFT->set_sensitive( !m_bLabelAlignmentPosAndSpaceModeActive && + ( bSingleSelection || bRelative || m_pOutlineDlg != nullptr ) ); + + bool bSetDistEmpty = false; + bool bSameDistBorderNum = !m_bLabelAlignmentPosAndSpaceModeActive; + bool bSameDist = !m_bLabelAlignmentPosAndSpaceModeActive; + bool bSameIndent = !m_bLabelAlignmentPosAndSpaceModeActive; + bool bSameAdjust = true; + + bool bSameLabelFollowedBy = m_bLabelAlignmentPosAndSpaceModeActive; + bool bSameListtab = m_bLabelAlignmentPosAndSpaceModeActive; + bool bSameAlignAt = m_bLabelAlignmentPosAndSpaceModeActive; + bool bSameIndentAt = m_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] = &m_pActNum->Get(i); + if(m_nActNumLvl & nMask) + { + if(USHRT_MAX == nLvl) + { + nLvl = i; + } + + if( i > nLvl) + { + bSameAdjust &= aNumFormatArr[i]->GetNumAdjust() == aNumFormatArr[nLvl]->GetNumAdjust(); + if ( !m_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()); + + m_bInInintControl = false; +} + +void SwNumPositionTabPage::ActivatePage(const SfxItemSet& ) +{ + const SfxPoolItem* pItem; + sal_uInt16 nTmpNumLvl = + m_pOutlineDlg ? SwOutlineTabDialog::GetActNumLevel() : 0; + const SfxItemSet* pExampleSet = GetDialogExampleSet(); + if(pExampleSet && pExampleSet->GetItemState(FN_PARAM_NUM_PRESET, false, &pItem) != SfxItemState::UNKNOWN) + { + m_bPreset = static_cast<const SfxBoolItem*>(pItem)->GetValue(); + } + m_bModified = (!m_pActNum->GetNumFormat( 0 ) || m_bPreset); + if(*m_pActNum != *m_pSaveNum || + m_nActNumLvl != nTmpNumLvl ) + { + *m_pActNum = *m_pSaveNum; + m_nActNumLvl = nTmpNumLvl; + sal_uInt16 nMask = 1; + m_xLevelLB->unselect_all(); + if (m_nActNumLvl == USHRT_MAX) + m_xLevelLB->select(MAXLEVEL); + else + { + for (sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + if (m_nActNumLvl & nMask) + m_xLevelLB->select(i); + nMask <<= 1 ; + } + } + + InitPosAndSpaceMode(); + ShowControlsDependingOnPosAndSpaceMode(); + + InitControls(); + } + m_xRelativeCB->set_sensitive(1 != m_nActNumLvl); + m_aPreviewWIN.Invalidate(); +} + +DeactivateRC SwNumPositionTabPage::DeactivatePage(SfxItemSet *_pSet) +{ + SwOutlineTabDialog::SetActNumLevel(m_nActNumLvl); + if(_pSet) + FillItemSet(_pSet); + return DeactivateRC::LeavePage; + +} + +bool SwNumPositionTabPage::FillItemSet( SfxItemSet* rSet ) +{ + if(m_pOutlineDlg) + *m_pOutlineDlg->GetNumRule() = *m_pActNum; + else if(m_bModified && m_pActNum) + { + *m_pSaveNum = *m_pActNum; + rSet->Put(SwUINumRuleItem( *m_pSaveNum )); + rSet->Put(SfxBoolItem(FN_PARAM_NUM_PRESET, false)); + } + return m_bModified; +} + +void SwNumPositionTabPage::Reset( const SfxItemSet* rSet ) +{ + if (m_pOutlineDlg) + { + m_pSaveNum = m_pOutlineDlg->GetNumRule(); + m_xLevelLB->set_selection_mode(SelectionMode::Single); + } + else if(const SwUINumRuleItem* pNumberItem = rSet->GetItemIfSet(FN_PARAM_ACT_NUMBER, false)) + m_pSaveNum = const_cast<SwUINumRuleItem*>(pNumberItem)->GetNumRule(); + + m_nActNumLvl = SwOutlineTabDialog::GetActNumLevel(); + sal_uInt16 nMask = 1; + m_xLevelLB->unselect_all(); + if(m_nActNumLvl == USHRT_MAX) + { + m_xLevelLB->select(MAXLEVEL); + } + else + { + for (sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + if (m_nActNumLvl & nMask) + m_xLevelLB->select(i); + nMask <<= 1; + } + } + + if(!m_pActNum) + m_pActNum.reset(new SwNumRule(*m_pSaveNum)); + else if(*m_pSaveNum != *m_pActNum) + *m_pActNum = *m_pSaveNum; + m_aPreviewWIN.SetNumRule(m_pActNum.get()); + InitPosAndSpaceMode(); + ShowControlsDependingOnPosAndSpaceMode(); + InitControls(); + m_bModified = false; +} + +void SwNumPositionTabPage::InitPosAndSpaceMode() +{ + if ( m_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(m_nActNumLvl & nMask) + { + SvxNumberFormat aNumFormat( m_pActNum->Get(i) ); + ePosAndSpaceMode = aNumFormat.GetPositionAndSpaceMode(); + if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + break; + } + } + nMask <<= 1; + } + + m_bLabelAlignmentPosAndSpaceModeActive = + ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT; +} + +void SwNumPositionTabPage::ShowControlsDependingOnPosAndSpaceMode() +{ + m_xDistBorderFT->set_visible( !m_bLabelAlignmentPosAndSpaceModeActive ); + m_xDistBorderMF->set_visible( !m_bLabelAlignmentPosAndSpaceModeActive ); + m_xRelativeCB->set_visible( !m_bLabelAlignmentPosAndSpaceModeActive ); + m_xIndentFT->set_visible( !m_bLabelAlignmentPosAndSpaceModeActive ); + m_xIndentMF->set_visible( !m_bLabelAlignmentPosAndSpaceModeActive ); + m_xDistNumFT->set_visible( !m_bLabelAlignmentPosAndSpaceModeActive ); + m_xDistNumMF->set_visible( !m_bLabelAlignmentPosAndSpaceModeActive ); + m_xAlignFT->set_visible( !m_bLabelAlignmentPosAndSpaceModeActive ); + m_xAlignLB->set_visible( !m_bLabelAlignmentPosAndSpaceModeActive ); + + m_xLabelFollowedByFT->set_visible( m_bLabelAlignmentPosAndSpaceModeActive ); + m_xLabelFollowedByLB->set_visible( m_bLabelAlignmentPosAndSpaceModeActive ); + m_xListtabFT->set_visible( m_bLabelAlignmentPosAndSpaceModeActive ); + m_xListtabMF->set_visible( m_bLabelAlignmentPosAndSpaceModeActive ); + m_xAlign2FT->set_visible( m_bLabelAlignmentPosAndSpaceModeActive ); + m_xAlign2LB->set_visible( m_bLabelAlignmentPosAndSpaceModeActive ); + m_xAlignedAtFT->set_visible( m_bLabelAlignmentPosAndSpaceModeActive ); + m_xAlignedAtMF->set_visible( m_bLabelAlignmentPosAndSpaceModeActive ); + m_xIndentAtFT->set_visible( m_bLabelAlignmentPosAndSpaceModeActive ); + m_xIndentAtMF->set_visible( m_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) +{ + m_pWrtSh = pSh; + + const SwTwips nWidth = m_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 ); + + const SwRect& rPrtRect = m_pWrtSh->GetAnyCurRect(CurRectType::Page); + m_aPreviewWIN.SetPageWidth(rPrtRect.Width()); + FieldUnit eMetric = ::GetDfltMetric( dynamic_cast<SwWebView*>( &m_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(m_nActNumLvl & nMask) + { + SwNumFormat aNumFormat(m_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 ); + m_pActNum->Set(i, aNumFormat); + } + nMask <<= 1; + } + SetModified(); +} + +IMPL_LINK( SwNumPositionTabPage, LevelHdl, weld::TreeView&, rBox, void ) +{ + sal_uInt16 nSaveNumLvl = m_nActNumLvl; + m_nActNumLvl = 0; + auto aRows = rBox.get_selected_rows(); + if ((std::find(aRows.begin(), aRows.end(), MAXLEVEL) != aRows.end()) && + (aRows.size() == 1 || nSaveNumLvl != 0xffff)) + { + m_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()) + m_nActNumLvl |= nMask; + nMask <<= 1; + } + rBox.unselect(MAXLEVEL); + } + else + { + m_nActNumLvl = nSaveNumLvl; + sal_uInt16 nMask = 1; + for (sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + if(m_nActNumLvl & nMask) + { + rBox.select(i); + break; + } + nMask <<=1; + } + } + m_xRelativeCB->set_sensitive(1 != m_nActNumLvl); + SetModified(); + InitPosAndSpaceMode(); + ShowControlsDependingOnPosAndSpaceMode(); + InitControls(); +} + +IMPL_LINK(SwNumPositionTabPage, DistanceHdl, weld::MetricSpinButton&, rField, void) +{ + if(m_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(m_nActNumLvl & nMask) + { + SwNumFormat aNumFormat( m_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 = m_pActNum->Get( i - 1 ).GetAbsLSpace() + + m_pActNum->Get( i - 1 ).GetFirstLineOffset() - + m_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 ); + } + + m_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 != m_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(m_nActNumLvl & nMask) + { + const SwNumFormat &rNumFormat = m_pActNum->Get(i); + if(bFirst) + { + nValue = rNumFormat.GetAbsLSpace(); + if(bOn && i) + nValue -= m_pActNum->Get(i - 1).GetAbsLSpace(); + } + else + bSetValue = nValue == rNumFormat.GetAbsLSpace() - m_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 || m_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 ( m_nActNumLvl & nMask ) + { + SwNumFormat aNumFormat( m_pActNum->Get(i) ); + aNumFormat.SetLabelFollowedBy( eLabelFollowedBy ); + m_pActNum->Set( i, aNumFormat ); + + if ( nFirstLvl == USHRT_MAX ) + { + nFirstLvl = i; + } + else + { + bSameListtabPos &= aNumFormat.GetListtabPos() == + m_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( m_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 ( m_nActNumLvl & nMask ) + { + SwNumFormat aNumFormat( m_pActNum->Get(i) ); + aNumFormat.SetListtabPos( nValue ); + m_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 ( m_nActNumLvl & nMask ) + { + SwNumFormat aNumFormat( m_pActNum->Get(i) ); + const tools::Long nFirstLineIndent = nValue - aNumFormat.GetIndentAt(); + aNumFormat.SetFirstLineIndent( nFirstLineIndent ); + m_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 ( m_nActNumLvl & nMask ) + { + SwNumFormat aNumFormat( m_pActNum->Get(i) ); + const tools::Long nAlignedAt = aNumFormat.GetIndentAt() + + aNumFormat.GetFirstLineIndent(); + aNumFormat.SetIndentAt( nValue ); + const tools::Long nNewFirstLineIndent = nAlignedAt - nValue; + aNumFormat.SetFirstLineIndent( nNewFirstLineIndent ); + m_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(m_nActNumLvl & nMask) + { + SwNumFormat aNumFormat( m_pActNum->Get( i ) ); + SwNumRule aTmpNumRule( m_pWrtSh->GetUniqueNumRuleName(), + aNumFormat.GetPositionAndSpaceMode(), + m_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() ); + } + m_pActNum->Set( i, aNumFormat ); + } + nMask <<= 1; + } + + InitControls(); + SetModified(); +} + +#ifdef DBG_UTIL +void SwNumPositionTabPage::SetModified() +{ + m_bModified = true; + m_aPreviewWIN.SetLevel(m_nActNumLvl); + m_aPreviewWIN.Invalidate(); +} +#endif + +SwSvxNumBulletTabDialog::SwSvxNumBulletTabDialog(weld::Window* pParent, + const SfxItemSet& rSwItemSet, SwWrtShell & rSh) + : SfxTabDialogController(pParent, "modules/swriter/ui/bulletsandnumbering.ui", "BulletsAndNumberingDialog", + &rSwItemSet) + , m_rWrtSh(rSh) + , m_xDummyCombo(m_xBuilder->weld_combo_box("dummycombo")) +{ + weld::Button* pButton = GetUserButton(); + pButton->connect_clicked(LINK(this, SwSvxNumBulletTabDialog, RemoveNumberingHdl)); + pButton->set_sensitive(m_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 ); + AddTabPage("customize", RID_SVXPAGE_NUM_OPTIONS ); + AddTabPage("position", RID_SVXPAGE_NUM_POSITION ); +} + +SwSvxNumBulletTabDialog::~SwSvxNumBulletTabDialog() +{ +} + +void SwSvxNumBulletTabDialog::PageCreated(const OUString& 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 = m_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 = m_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 0000000000..6500bfdd6e --- /dev/null +++ b/sw/source/ui/misc/outline.cxx @@ -0,0 +1,1073 @@ +/* -*- 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 (auto const& aID : OUTLINE_STYLE) + m_xFormBox->append_text(SwResId(aID)); + + 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) +{ + constexpr sal_uInt16 MAXLEVEL_MASK = USHRT_MAX >> (sizeof(sal_uInt16) * CHAR_BIT - MAXLEVEL); + assert((nActLevel & MAXLEVEL_MASK) == nActLevel); + sal_uInt16 nTmp = nActLevel & MAXLEVEL_MASK; // a safety measure + sal_uInt16 nTmpLevel = 0; + while( 0 != (nTmp >>= 1) ) + nTmpLevel++; + return nTmpLevel; +} + +sal_uInt16 SwOutlineTabDialog::s_nNumLevel = 1; + +SwOutlineTabDialog::SwOutlineTabDialog(weld::Window* pParent, const SfxItemSet* pSwItemSet, + SwWrtShell &rSh) + : SfxTabDialogController(pParent, "modules/swriter/ui/outlinenumbering.ui", "OutlineNumberingDialog", pSwItemSet) + , m_rWrtSh(rSh) + , m_pChapterNumRules(SW_MOD()->GetChapterNumRules()) + , m_bModified(m_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)); + + m_xNumRule.reset(new SwNumRule(*rSh.GetOutlineNumRule())); + GetCancelButton().connect_clicked(LINK(this, SwOutlineTabDialog, CancelHdl)); + + if (auto nOutlinePos = m_rWrtSh.GetOutlinePos(MAXLEVEL); nOutlinePos != SwOutlineNodes::npos) + { + int nTmp = m_rWrtSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos); + assert(nTmp < MAXLEVEL); + SetActNumLevel(nTmp < 0 ? USHRT_MAX : (1 << nTmp)); + } + + 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( !m_rWrtSh.GetParaStyle( sHeadline = + SwStyleNameMapper::GetUIName( static_cast< sal_uInt16 >(RES_POOLCOLL_HEADLINE1 + i), + sHeadline )) ) + m_aCollNames[i] = sHeadline; + } + + // query the text templates' outlining levels + const sal_uInt16 nCount = m_rWrtSh.GetTextFormatCollCount(); + for(i = 0; i < nCount; ++i ) + { + SwTextFormatColl &rTextColl = m_rWrtSh.GetTextFormatColl(i); + if(!rTextColl.IsDefault()) + { + if(rTextColl.IsAssignedToListLevelOfOutlineStyle()) + { + int nOutLevel = rTextColl.GetAssignedOutlineStyleLevel(); + m_aCollNames[ nOutLevel ] = rTextColl.GetName(); + } + } + } +} + +SwOutlineTabDialog::~SwOutlineTabDialog() +{ +} + +void SwOutlineTabDialog::PageCreated(const OUString& rPageId, SfxTabPage& rPage) +{ + if (rPageId == "position") + { + static_cast<SwNumPositionTabPage&>(rPage).SetWrtShell(&m_rWrtSh); + static_cast<SwNumPositionTabPage&>(rPage).SetOutlineTabDialog(this); + } + else if (rPageId == "numbering") + { + static_cast<SwOutlineSettingsTabPage&>(rPage).SetWrtShell(&m_rWrtSh); + } +} + +IMPL_LINK_NOARG(SwOutlineTabDialog, CancelHdl, weld::Button&, void) +{ + if (!m_bModified) + m_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 = m_pChapterNumRules->GetRules(i); + if (!pRules) + continue; + m_xMenuButton->set_item_label("form" + OUString::number(i + 1), pRules->GetName()); + } +} + +IMPL_LINK(SwOutlineTabDialog, MenuSelectHdl, const OUString&, 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 = m_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()); + m_pChapterNumRules->ApplyNumRules( SwNumRulesWithName( + *m_xNumRule, aName ), aDlg.GetCurEntryPos() ); + m_xMenuButton->set_item_label("form" + OUString::number(aDlg.GetCurEntryPos() + 1), aName); + } + return; + } + + if( nLevelNo-- ) + { + const SwNumRulesWithName *pRules = m_pChapterNumRules->GetRules( nLevelNo ); + if( pRules ) + { + pRules->ResetNumRule(m_rWrtSh, *m_xNumRule); + m_xNumRule->SetRuleType( OUTLINE_RULE ); + SfxTabPage* pOutlinePage = GetTabPage(u"numbering"); + assert(pOutlinePage); + static_cast<SwOutlineSettingsTabPage*>(pOutlinePage)->SetNumRule(m_xNumRule.get()); + } + else + *m_xNumRule = *m_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(m_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. + m_rWrtSh.StartAction(); + + const SwNumRule * pOutlineRule = m_rWrtSh.GetOutlineNumRule(); + + sal_uInt16 i, nCount = m_rWrtSh.GetTextFormatCollCount(); + for( i = 0; i < nCount; ++i ) + { + SwTextFormatColl &rTextColl = m_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 = m_rWrtSh.FindTextFormatCollByName( sHeadline ); + if( !pColl && m_aCollNames[i] != sHeadline) + { + SwTextFormatColl* pTextColl = m_rWrtSh.GetTextCollFromPool( + static_cast< sal_uInt16 >(RES_POOLCOLL_HEADLINE1 + i) ); + pTextColl->DeleteAssignmentToListLevelOfOutlineStyle(); + pTextColl->ResetFormatAttr(RES_PARATR_NUMRULE); + + if( !m_aCollNames[i].isEmpty() ) + { + pTextColl = m_rWrtSh.GetParaStyle( + m_aCollNames[i], SwWrtShell::GETSTYLE_CREATESOME); + if(pTextColl) + { + pTextColl->AssignToListLevelOfOutlineStyle(i); + SwNumRuleItem aItem(pOutlineRule->GetName()); + pTextColl->SetFormatAttr(aItem); + } + } + } + } + + m_rWrtSh.SetOutlineNumRule(*m_xNumRule); + + // #i30443# + m_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) + , m_aNoFormatName(SwResId(SW_STR_NONE)) + , m_pSh(nullptr) + , m_pNumRule(nullptr) + , m_pCollNames(nullptr) + , m_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(m_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 != m_nActLevel); + if(USHRT_MAX == m_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 ] = &m_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(m_nActLevel); + OUString aColl(m_pCollNames[nTmpLevel]); + if(!aColl.isEmpty()) + m_xCollBox->set_active_text(aColl); + else + m_xCollBox->set_active_text(m_aNoFormatName); + const SwNumFormat &rFormat = m_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 ) +{ + auto aRows = rBox.get_selected_rows(); + assert(aRows.empty() || aRows.size() == 1); // Single selection only + if (aRows.empty() || aRows[0] == MAXLEVEL) + { + m_nActLevel = USHRT_MAX; + } + else + { + m_nActLevel = 1 << aRows[0]; + } + Update(); +} + +IMPL_LINK(SwOutlineSettingsTabPage, ToggleComplete, weld::SpinButton&, rEdit, void) +{ + sal_uInt16 nMask = 1; + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + if(m_nActLevel & nMask) + { + SwNumFormat aNumFormat(m_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); + m_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(m_nActLevel); + OUString sOldName( m_pCollNames[nTmpLevel] ); + + for( i = 0; i < MAXLEVEL; ++i) + m_pCollNames[i] = m_aSaveCollNames[i]; + + m_pCollNames[nTmpLevel] = aCollName; + // template already in use? + for( i = 0; i < MAXLEVEL; ++i) + if(i != nTmpLevel && m_pCollNames[i] == aCollName ) + m_pCollNames[i].clear(); + + // search the oldname and put it into the current entries + if( !sOldName.isEmpty() ) + for( i = 0; i < MAXLEVEL; ++i) + if( m_aSaveCollNames[ i ] == sOldName && i != nTmpLevel && + m_pCollNames[ i ].isEmpty() ) + { + sal_uInt8 n; + for( n = 0; n < MAXLEVEL; ++n ) + if( m_pCollNames[ n ] == sOldName ) + break; + + if( MAXLEVEL == n ) + // it was an outline level name and the current entries is zero. + m_pCollNames[ i ] = sOldName; + } + + SetModified(); + CollSave(); +} + +void SwOutlineSettingsTabPage::CollSave() +{ + for (sal_uInt8 i = 0; i < MAXLEVEL; ++i) + m_aSaveCollNames[i] = m_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(m_nActLevel & nMask) + { + SwNumFormat aNumFormat(m_pNumRule->Get(i)); + aNumFormat.SetNumberingType(nNumberType); + m_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(m_nActLevel & nMask) + { + SwNumFormat aNumFormat(m_pNumRule->Get(i)); + aNumFormat.SetListFormat( m_xPrefixED->get_text(), m_xSuffixED->get_text(), i ); + m_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(m_nActLevel & nMask) + { + SwNumFormat aNumFormat(m_pNumRule->Get(i)); + aNumFormat.SetStart(o3tl::narrowing<sal_uInt16>(rEdit.get_value())); + m_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 = m_pSh->GetCharFormatCount(); + for(sal_uInt16 i = 0; i < nChCount; i++) + { + SwCharFormat& rChFormat = m_pSh->GetCharFormat(i); + if(rChFormat.GetName() == sEntry) + { + pFormat = &rChFormat; + break; + } + } + if(!pFormat) + { + SfxStyleSheetBasePool* pPool = m_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(m_nActLevel & nMask) + { + SwNumFormat aNumFormat(m_pNumRule->Get(i)); + if(bFormatNone) + aNumFormat.SetCharFormat(nullptr); + else + aNumFormat.SetCharFormat(pFormat); + m_pNumRule->Set(i, aNumFormat); + } + nMask <<= 1; + } +} + +SwOutlineSettingsTabPage::~SwOutlineSettingsTabPage() +{ +} + +void SwOutlineSettingsTabPage::SetWrtShell(SwWrtShell* pShell) +{ + m_pSh = pShell; + // query this document's NumRules + m_pNumRule = static_cast<SwOutlineTabDialog*>(GetDialogController())->GetNumRule(); + m_pCollNames = static_cast<SwOutlineTabDialog*>(GetDialogController())->GetCollNames(); + + CollSave(); + + m_aPreviewWIN.SetNumRule(m_pNumRule); + m_aPreviewWIN.SetOutlineNames(m_pCollNames); + // set start value - nActLevel must be 1 here + sal_uInt16 nTmpLevel = lcl_BitToLevel(m_nActLevel); + const SwNumFormat& rNumFormat = m_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 = m_pSh->GetTextFormatCollCount(); + for (sal_uInt16 i = 0; i < nCount; ++i) + { + SwTextFormatColl &rTextColl = m_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()); + + // collect char styles + m_xCharFormatLB->clear(); + m_xCharFormatLB->append_text(SwViewShell::GetShellRes()->aStrNone); + + // char styles + ::FillCharStyleListBox(*m_xCharFormatLB, + m_pSh->GetView().GetDocShell()); + Update(); +} + +void SwOutlineSettingsTabPage::ActivatePage(const SfxItemSet& ) +{ + m_nActLevel = SwOutlineTabDialog::GetActNumLevel(); + if(m_nActLevel != USHRT_MAX) + m_xLevelLB->select(lcl_BitToLevel(m_nActLevel)); + else + m_xLevelLB->select(MAXLEVEL); + LevelHdl(*m_xLevelLB); +} + +DeactivateRC SwOutlineSettingsTabPage::DeactivatePage(SfxItemSet*) +{ + SwOutlineTabDialog::SetActNumLevel(m_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); + + const SwViewOption& pOpt = SwViewOption::GetCurrentViewOptions(); + const Color& rDocColor = pOpt.GetDocColor(); + const Color& rDocBoundariesColor = pOpt.GetDocBoundariesColor(); + const Color& rFontColor = pOpt.GetFontColor(); + // #101524# OJ + pVDev->SetFillColor(rDocColor); + pVDev->SetLineColor(rDocBoundariesColor); + pVDev->DrawRect(tools::Rectangle(Point(0,0), aSize)); + + if (m_pActNum) + { + tools::Long nWidthRelation = 30; // chapter dialog + if(m_nPageWidth) + { + nWidthRelation = m_nPageWidth / aSize.Width(); + if(m_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; + m_aStdFont = OutputDevice::GetDefaultFont(DefaultFontType::UI_SANS, GetAppLanguage(), + GetDefaultFontFlags::OnlyOne, &rRenderContext); + + if (svtools::ColorConfig().GetColorValue(svtools::FONTCOLOR, false).nColor == COL_AUTO) + m_aStdFont.SetColor( rDocColor.IsDark() ? COL_WHITE : COL_BLACK ); + else + m_aStdFont.SetColor( rFontColor ); + + const tools::Long nFontHeight = nYStep * ( m_bPosition ? 15 : 6 ) / 10; + m_aStdFont.SetFontSize(Size( 0, nFontHeight )); + + tools::Long nPreNum = m_pActNum->Get(0).GetStart(); + + if (m_bPosition) + { + const tools::Long nLineHeight = nFontHeight * 8 / 7; + sal_uInt8 nStart = 0; + while (!(m_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 = m_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, m_aStdFont.GetFontSize()); + } + else + { + pVDev->SetFont(m_aStdFont); + if(m_pActNum->IsContinusNum()) + aNumVector[nLevel] = nPreNum; + OUString aText(m_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(m_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 = m_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, m_aStdFont.GetFontSize()); + nTextOffset += nXStep; + } + else + { + pVDev->SetFont(m_aStdFont); + if (m_pActNum->IsContinusNum()) + aNumVector[nLevel] = nPreNum; + OUString aText(m_pActNum->MakeNumString( aNumVector )); + pVDev->DrawText( Point(nXStart, nYStart), aText ); + nTextOffset = pVDev->GetTextWidth(aText) + nXStep; + nPreNum++; + } + pVDev->SetFont(m_aStdFont); + pVDev->DrawText( + Point(nXStart + nTextOffset, nYStart), + (m_pOutlineNames == nullptr + ? utl::ConfigManager::getProductName() + : m_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/pagenumberdlg.cxx b/sw/source/ui/misc/pagenumberdlg.cxx new file mode 100644 index 0000000000..fe965d69db --- /dev/null +++ b/sw/source/ui/misc/pagenumberdlg.cxx @@ -0,0 +1,143 @@ +/* -*- 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 <pagenumberdlg.hxx> +#include <svx/SvxNumOptionsTabPageHelper.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/graph.hxx> +#include <vcl/BitmapTools.hxx> +#include <vcl/virdev.hxx> +#include <tools/gen.hxx> + +SwPageNumberDlg::SwPageNumberDlg(weld::Window* pParent) + : SfxDialogController(pParent, "modules/swriter/ui/pagenumberdlg.ui", "PageNumberDialog") + , m_xOk(m_xBuilder->weld_button("ok")) + , m_xCancel(m_xBuilder->weld_button("cancel")) + , m_xPageNumberPosition(m_xBuilder->weld_combo_box("positionCombo")) + , m_xPageNumberAlignment(m_xBuilder->weld_combo_box("alignmentCombo")) + , m_xMirrorOnEvenPages(m_xBuilder->weld_check_button("mirrorCheckbox")) + , m_xIncludePageTotal(m_xBuilder->weld_check_button("pagetotalCheckbox")) + , m_xPageNumberTypeLB(new SvxPageNumberListBox(m_xBuilder->weld_combo_box("numfmtlb"))) + , m_xPreviewImage(m_xBuilder->weld_image("previewImage")) + , m_aPageNumberPosition(1) // bottom + , m_aPageNumberAlignment(1) // center + , m_nPageNumberType(SVX_NUM_CHARS_UPPER_LETTER) +{ + m_xOk->connect_clicked(LINK(this, SwPageNumberDlg, OkHdl)); + m_xPageNumberPosition->connect_changed(LINK(this, SwPageNumberDlg, PositionSelectHdl)); + m_xPageNumberAlignment->connect_changed(LINK(this, SwPageNumberDlg, AlignmentSelectHdl)); + m_xPageNumberPosition->set_active(m_aPageNumberPosition); + m_xPageNumberAlignment->set_active(m_aPageNumberAlignment); + m_xMirrorOnEvenPages->set_sensitive(false); + m_xMirrorOnEvenPages->set_state(TRISTATE_TRUE); + m_xIncludePageTotal->set_state(TRISTATE_FALSE); + SvxNumOptionsTabPageHelper::GetI18nNumbering(m_xPageNumberTypeLB->get_widget(), + ::std::numeric_limits<sal_uInt16>::max()); + m_xPageNumberTypeLB->connect_changed(LINK(this, SwPageNumberDlg, NumberTypeSelectHdl)); + m_xIncludePageTotal->connect_toggled(LINK(this, SwPageNumberDlg, IncludePageTotalChangeHdl)); + updateImage(); +} + +IMPL_LINK_NOARG(SwPageNumberDlg, OkHdl, weld::Button&, void) { m_xDialog->response(RET_OK); } + +IMPL_LINK_NOARG(SwPageNumberDlg, PositionSelectHdl, weld::ComboBox&, void) +{ + m_aPageNumberPosition = m_xPageNumberPosition->get_active(); + updateImage(); +} + +IMPL_LINK_NOARG(SwPageNumberDlg, AlignmentSelectHdl, weld::ComboBox&, void) +{ + m_aPageNumberAlignment = m_xPageNumberAlignment->get_active(); + updateImage(); + + if (m_aPageNumberAlignment == 1) // centered + m_xMirrorOnEvenPages->set_sensitive(false); + else + m_xMirrorOnEvenPages->set_sensitive(true); +} + +IMPL_LINK_NOARG(SwPageNumberDlg, NumberTypeSelectHdl, weld::ComboBox&, void) +{ + m_nPageNumberType = m_xPageNumberTypeLB->get_active_id(); +} + +IMPL_LINK_NOARG(SwPageNumberDlg, IncludePageTotalChangeHdl, weld::Toggleable&, void) +{ + updateImage(); +} + +bool SwPageNumberDlg::GetMirrorOnEvenPages() +{ + return m_xMirrorOnEvenPages->get_sensitive() + && m_xMirrorOnEvenPages->get_state() == TRISTATE_TRUE; +} + +bool SwPageNumberDlg::GetIncludePageTotal() +{ + return m_xIncludePageTotal->get_state() == TRISTATE_TRUE; +} + +void SwPageNumberDlg::SetPageNumberType(SvxNumType nSet) +{ + m_nPageNumberType = nSet; + m_xPageNumberTypeLB->set_active_id(nSet); +} + +void SwPageNumberDlg::updateImage() +{ + int nBackgroundWidth = 75; + int nBackgroundHeight = 105; + + int nMargin = 7; + + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + Size aVDSize(nBackgroundWidth, nBackgroundHeight); + pVirtualDev->SetOutputSizePixel(aVDSize); + pVirtualDev->SetBackground(Color(0xF0, 0xF0, 0xF0)); + pVirtualDev->Erase(); + + OUString sText = "#"; + + if (m_xIncludePageTotal->get_state() == TRISTATE_TRUE) + { + sText += " / #"; + } + + DrawTextFlags eFlags = DrawTextFlags::Left; + + if (m_aPageNumberAlignment == 1) + { + eFlags = DrawTextFlags::Center; + } + else if (m_aPageNumberAlignment == 2) + { + eFlags = DrawTextFlags::Right; + } + + eFlags |= m_aPageNumberPosition ? DrawTextFlags::Bottom : DrawTextFlags::Top; + + pVirtualDev->DrawText( + tools::Rectangle(nMargin, nMargin, nBackgroundWidth - nMargin, nBackgroundHeight - nMargin), + sText, eFlags); + + m_xPreviewImage->set_image(pVirtualDev); +} + +/* 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 0000000000..14eec4b21b --- /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::s_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(m_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(m_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(m_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) + , m_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 ); + m_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)); + m_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 ) ); + m_lMaxHeight -= rSizeItem.GetSize().Height(); + } + } + + if ( const SvxULSpaceItem* pSpaceItem = rSet.GetItemIfSet( RES_UL_SPACE , false ) ) + { + m_lMaxHeight -= pSpaceItem->GetUpper() + pSpaceItem->GetLower(); + } + + m_lMaxHeight *= 8; + m_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 0000000000..3eef17523c --- /dev/null +++ b/sw/source/ui/misc/pggrid.cxx @@ -0,0 +1,550 @@ +/* -*- 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()) + { + if (SwWrtShell* pSh = pView->GetWrtShellPtr()) + { + 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_Int32 >(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(m_xCharWidthMF->get_value(FieldUnit::MM)); + pView->GetVRuler().SetLineHeight(m_xTextSizeMF->get_value(FieldUnit::MM)); + } +} + +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 0000000000..cd45654b8d --- /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")) + , m_aColText(SwResId(STR_COL)) + , m_aRowText(SwResId(STR_ROW)) + , m_aNumericText(SwResId(STR_NUMERIC)) + , m_rSh(rShell) + , m_nX(99) + , m_nY(99) +{ + if(m_rSh.GetSelectionType() & + (SelectionType::Table|SelectionType::TableCell) ) + { + m_xColumnRB->set_active(bCol); + m_xColLbl->set_label(bCol ? m_aRowText : m_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(m_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( m_rSh, m_nX, m_nY) ) + { + sal_uInt16 nMax = m_xRowRB->get_active()? m_nY : m_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 == m_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 == m_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 == m_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 = m_rSh.IsTableMode(); + aOptions.bIgnoreCase = !bCsSens; + + bool bRet; + { + SwWait aWait( *m_rSh.GetView().GetDocShell(), true ); + m_rSh.StartAllAction(); + bRet = m_rSh.Sort( aOptions ); + if( bRet ) + m_rSh.SetModified(); + m_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( m_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(m_aColText); + m_xColEdt1->set_max(m_nY); + m_xColEdt2->set_max(m_nY); + m_xColEdt3->set_max(m_nY); + + m_xColEdt1->set_accessible_name(m_aColText); + m_xColEdt2->set_accessible_name(m_aColText); + m_xColEdt3->set_accessible_name(m_aColText); + } + else if (&rControl == m_xColumnRB.get()) + { + m_xColLbl->set_label(m_aRowText); + m_xColEdt1->set_max(m_nX); + m_xColEdt2->set_max(m_nX); + m_xColEdt3->set_max(m_nX); + + m_xColEdt1->set_accessible_name(m_aRowText); + m_xColEdt2->set_accessible_name(m_aRowText); + m_xColEdt3->set_accessible_name(m_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 = m_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 0000000000..8bc8baf755 --- /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, m_xDialog->get_help_id()); + 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, m_xDialog->get_help_id()); + 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 0000000000..0d8c776cce --- /dev/null +++ b/sw/source/ui/misc/titlepage.cxx @@ -0,0 +1,335 @@ +/* -*- 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_xInsertNewPagesRB(m_xBuilder->weld_radio_button("RB_INSERT_NEW_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: */ diff --git a/sw/source/ui/misc/translatelangselect.cxx b/sw/source/ui/misc/translatelangselect.cxx new file mode 100644 index 0000000000..f03d64c755 --- /dev/null +++ b/sw/source/ui/misc/translatelangselect.cxx @@ -0,0 +1,164 @@ +/* -*- 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 <vcl/svapp.hxx> +#include <osl/diagnose.h> +#include <uitool.hxx> +#include <swtypes.hxx> +#include <wrtsh.hxx> +#include <view.hxx> +#include <viewopt.hxx> +#include <translatelangselect.hxx> +#include <pagedesc.hxx> +#include <poolfmt.hxx> +#include <sal/log.hxx> +#include <ndtxt.hxx> +#include <shellio.hxx> +#include <vcl/idle.hxx> +#include <mdiexp.hxx> +#include <strings.hrc> +#include <com/sun/star/task/XStatusIndicator.hpp> +#include <sfx2/viewfrm.hxx> +#include <com/sun/star/task/XStatusIndicatorFactory.hpp> +#include <linguistic/translate.hxx> +#include <officecfg/Office/Linguistic.hxx> + +static const std::vector<SwLanguageListItem>& getLanguageVec() +{ + static const std::vector<SwLanguageListItem> gLanguageVec{ + SwLanguageListItem("BG"_ostr, "Bulgarian"_ostr), + SwLanguageListItem("CS"_ostr, "Czech"_ostr), + SwLanguageListItem("DA"_ostr, "Danish"_ostr), + SwLanguageListItem("DE"_ostr, "German"_ostr), + SwLanguageListItem("EL"_ostr, "Greek"_ostr), + SwLanguageListItem("EN-GB"_ostr, "English (British)"_ostr), + SwLanguageListItem("EN-US"_ostr, "English (American)"_ostr), + SwLanguageListItem("ES"_ostr, "Spanish"_ostr), + SwLanguageListItem("ET"_ostr, "Estonian"_ostr), + SwLanguageListItem("FI"_ostr, "Finnish"_ostr), + SwLanguageListItem("FR"_ostr, "French"_ostr), + SwLanguageListItem("HU"_ostr, "Hungarian"_ostr), + SwLanguageListItem("ID"_ostr, "Indonesian"_ostr), + SwLanguageListItem("IT"_ostr, "Italian"_ostr), + SwLanguageListItem("JA"_ostr, "Japanese"_ostr), + SwLanguageListItem("LT"_ostr, "Lithuanian"_ostr), + SwLanguageListItem("LV"_ostr, "Latvian"_ostr), + SwLanguageListItem("NL"_ostr, "Dutch"_ostr), + SwLanguageListItem("PL"_ostr, "Polish"_ostr), + SwLanguageListItem("PT-BR"_ostr, "Portuguese (Brazilian)"_ostr), + SwLanguageListItem("PT-PT"_ostr, "Portuguese (European)"_ostr), + SwLanguageListItem("RO"_ostr, "Romanian"_ostr), + SwLanguageListItem("RU"_ostr, "Russian"_ostr), + SwLanguageListItem("SK"_ostr, "Slovak"_ostr), + SwLanguageListItem("SL"_ostr, "Slovenian"_ostr), + SwLanguageListItem("SV"_ostr, "Swedish"_ostr), + SwLanguageListItem("TR"_ostr, "Turkish"_ostr), + SwLanguageListItem("ZH"_ostr, "Chinese (simplified)"_ostr) + }; + return gLanguageVec; +} + +int SwTranslateLangSelectDlg::selectedLangIdx = -1; +SwTranslateLangSelectDlg::SwTranslateLangSelectDlg(weld::Window* pParent, SwWrtShell& rSh) + : GenericDialogController(pParent, "modules/swriter/ui/translationdialog.ui", + "LanguageSelectDialog") + , m_rWrtSh(rSh) + , m_xLanguageListBox(m_xBuilder->weld_combo_box("combobox1")) + , m_xBtnCancel(m_xBuilder->weld_button("cancel")) + , m_xBtnTranslate(m_xBuilder->weld_button("translate")) + , m_bTranslationStarted(false) + , m_bCancelTranslation(false) +{ + m_xLanguageListBox->connect_changed(LINK(this, SwTranslateLangSelectDlg, LangSelectHdl)); + m_xBtnCancel->connect_clicked(LINK(this, SwTranslateLangSelectDlg, LangSelectCancelHdl)); + m_xBtnTranslate->connect_clicked(LINK(this, SwTranslateLangSelectDlg, LangSelectTranslateHdl)); + + for (const auto& item : getLanguageVec()) + { + m_xLanguageListBox->append_text(OStringToOUString(item.getName(), RTL_TEXTENCODING_UTF8)); + } + + if (SwTranslateLangSelectDlg::selectedLangIdx != -1) + { + m_xLanguageListBox->set_active(SwTranslateLangSelectDlg::selectedLangIdx); + } +} + +std::optional<SwLanguageListItem> SwTranslateLangSelectDlg::GetSelectedLanguage() +{ + if (SwTranslateLangSelectDlg::selectedLangIdx != -1) + { + return getLanguageVec().at(SwTranslateLangSelectDlg::selectedLangIdx); + } + + return {}; +} + +IMPL_STATIC_LINK(SwTranslateLangSelectDlg, LangSelectHdl, weld::ComboBox&, rBox, void) +{ + const auto selected = rBox.get_active(); + SwTranslateLangSelectDlg::selectedLangIdx = selected; +} + +IMPL_LINK_NOARG(SwTranslateLangSelectDlg, LangSelectCancelHdl, weld::Button&, void) +{ + // stop translation first + if (m_bTranslationStarted) + m_bCancelTranslation = true; + else + m_xDialog->response(RET_CANCEL); +} + +IMPL_LINK_NOARG(SwTranslateLangSelectDlg, LangSelectTranslateHdl, weld::Button&, void) +{ + if (m_bTranslationStarted) + return; + if (SwTranslateLangSelectDlg::selectedLangIdx == -1) + { + m_xDialog->response(RET_CANCEL); + return; + } + + std::optional<OUString> oDeeplAPIUrl + = officecfg::Office::Linguistic::Translation::Deepl::ApiURL::get(); + std::optional<OUString> oDeeplKey + = officecfg::Office::Linguistic::Translation::Deepl::AuthKey::get(); + if (!oDeeplAPIUrl || oDeeplAPIUrl->isEmpty() || !oDeeplKey || oDeeplKey->isEmpty()) + { + SAL_WARN("sw.ui", "SwTranslateLangSelectDlg: API options are not set"); + m_xDialog->response(RET_CANCEL); + return; + } + + const OString aAPIUrl + = OUStringToOString(rtl::Concat2View(*oDeeplAPIUrl + "?tag_handling=html"), + RTL_TEXTENCODING_UTF8) + .trim(); + const OString aAuthKey = OUStringToOString(*oDeeplKey, RTL_TEXTENCODING_UTF8).trim(); + const auto aTargetLang + = getLanguageVec().at(SwTranslateLangSelectDlg::selectedLangIdx).getLanguage(); + + m_bTranslationStarted = true; + + SwTranslateHelper::TranslateAPIConfig aConfig({ aAPIUrl, aAuthKey, aTargetLang }); + SwTranslateHelper::TranslateDocumentCancellable(m_rWrtSh, aConfig, m_bCancelTranslation); + m_xDialog->response(RET_OK); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/table/autoformatpreview.cxx b/sw/source/ui/table/autoformatpreview.cxx new file mode 100644 index 0000000000..e04fffefca --- /dev/null +++ b/sw/source/ui/table/autoformatpreview.cxx @@ -0,0 +1,466 @@ +/* -*- 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/adjustitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/contouritem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <vcl/settings.hxx> +#include <com/sun/star/i18n/BreakIterator.hpp> +#include <comphelper/processfactory.hxx> +#include <svtools/scriptedtext.hxx> +#include <svx/framelink.hxx> +#include <drawinglayer/processor2d/baseprocessor2d.hxx> +#include <drawinglayer/processor2d/processor2dtools.hxx> +#include <strings.hrc> +#include <svtools/colorcfg.hxx> +#include <swmodule.hxx> + +#include <autoformatpreview.hxx> + +#define FRAME_OFFSET 4 + +AutoFormatPreview::AutoFormatPreview() + : maCurrentData(OUString()) + , mbFitWidth(false) + , mbRTL(false) + , maStringJan(SwResId(STR_JAN)) + , maStringFeb(SwResId(STR_FEB)) + , maStringMar(SwResId(STR_MAR)) + , maStringNorth(SwResId(STR_NORTH)) + , maStringMid(SwResId(STR_MID)) + , maStringSouth(SwResId(STR_SOUTH)) + , maStringSum(SwResId(STR_SUM)) +{ + uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext(); + m_xBreak = i18n::BreakIterator::create(xContext); + mxNumFormat.reset(new SvNumberFormatter(xContext, LANGUAGE_SYSTEM)); + + Init(); +} + +void AutoFormatPreview::Resize() +{ + Size aSize = GetOutputSizePixel(); + maPreviousSize = Size(aSize.Width() - 6, aSize.Height() - 30); + mnLabelColumnWidth = (maPreviousSize.Width() - 4) / 4 - 12; + mnDataColumnWidth1 = (maPreviousSize.Width() - 4 - 2 * mnLabelColumnWidth) / 3; + mnDataColumnWidth2 = (maPreviousSize.Width() - 4 - 2 * mnLabelColumnWidth) / 4; + mnRowHeight = (maPreviousSize.Height() - 4) / 5; + NotifyChange(maCurrentData); +} + +void AutoFormatPreview::DetectRTL(SwWrtShell const* pWrtShell) +{ + if (!pWrtShell->IsCursorInTable()) // We haven't created the table yet + mbRTL = AllSettings::GetLayoutRTL(); + else + mbRTL = pWrtShell->IsTableRightToLeft(); +} + +static void lcl_SetFontProperties(vcl::Font& rFont, const SvxFontItem& rFontItem, + const SvxWeightItem& rWeightItem, + const SvxPostureItem& rPostureItem) +{ + rFont.SetFamily(rFontItem.GetFamily()); + rFont.SetFamilyName(rFontItem.GetFamilyName()); + rFont.SetStyleName(rFontItem.GetStyleName()); + rFont.SetCharSet(rFontItem.GetCharSet()); + rFont.SetPitch(rFontItem.GetPitch()); + rFont.SetWeight(rWeightItem.GetValue()); + rFont.SetItalic(rPostureItem.GetValue()); +} + +#define SETONALLFONTS(MethodName, Value) \ + rFont.MethodName(Value); \ + rCJKFont.MethodName(Value); \ + rCTLFont.MethodName(Value); + +void AutoFormatPreview::MakeFonts(vcl::RenderContext const& rRenderContext, sal_uInt8 nIndex, + vcl::Font& rFont, vcl::Font& rCJKFont, vcl::Font& rCTLFont) +{ + const SwBoxAutoFormat& rBoxFormat = maCurrentData.GetBoxFormat(nIndex); + + rFont = rCJKFont = rCTLFont = rRenderContext.GetFont(); + Size aFontSize(rFont.GetFontSize().Width(), 10 * rRenderContext.GetDPIScaleFactor()); + + lcl_SetFontProperties(rFont, rBoxFormat.GetFont(), rBoxFormat.GetWeight(), + rBoxFormat.GetPosture()); + lcl_SetFontProperties(rCJKFont, rBoxFormat.GetCJKFont(), rBoxFormat.GetCJKWeight(), + rBoxFormat.GetCJKPosture()); + lcl_SetFontProperties(rCTLFont, rBoxFormat.GetCTLFont(), rBoxFormat.GetCTLWeight(), + rBoxFormat.GetCTLPosture()); + + SETONALLFONTS(SetUnderline, rBoxFormat.GetUnderline().GetValue()); + SETONALLFONTS(SetOverline, rBoxFormat.GetOverline().GetValue()); + SETONALLFONTS(SetStrikeout, rBoxFormat.GetCrossedOut().GetValue()); + SETONALLFONTS(SetOutline, rBoxFormat.GetContour().GetValue()); + SETONALLFONTS(SetShadow, rBoxFormat.GetShadowed().GetValue()); + SETONALLFONTS(SetColor, rBoxFormat.GetColor().GetValue()); + SETONALLFONTS(SetFontSize, aFontSize); + SETONALLFONTS(SetTransparent, true); +} + +sal_uInt8 AutoFormatPreview::GetFormatIndex(size_t nCol, size_t nRow) const +{ + static const sal_uInt8 pnFormatMap[] + = { 0, 1, 2, 1, 3, 4, 5, 6, 5, 7, 8, 9, 10, 9, 11, 4, 5, 6, 5, 7, 12, 13, 14, 13, 15 }; + return pnFormatMap[maArray.GetCellIndex(nCol, nRow, mbRTL)]; +} + +void AutoFormatPreview::DrawString(vcl::RenderContext& rRenderContext, size_t nCol, size_t nRow) +{ + // Output of the cell text: + sal_uLong nNum; + double nVal; + OUString cellString; + sal_uInt8 nIndex = static_cast<sal_uInt8>(maArray.GetCellIndex(nCol, nRow, mbRTL)); + + switch (nIndex) + { + case 1: + cellString = maStringJan; + break; + case 2: + cellString = maStringFeb; + break; + case 3: + cellString = maStringMar; + break; + case 5: + cellString = maStringNorth; + break; + case 10: + cellString = maStringMid; + break; + case 15: + cellString = maStringSouth; + break; + case 4: + case 20: + cellString = maStringSum; + break; + case 6: + case 8: + case 16: + case 18: + nVal = nIndex; + nNum = 5; + goto MAKENUMSTR; + case 17: + case 7: + nVal = nIndex; + nNum = 6; + goto MAKENUMSTR; + case 11: + case 12: + case 13: + nVal = nIndex; + nNum = 12 == nIndex ? 10 : 9; + goto MAKENUMSTR; + case 9: + nVal = 21; + nNum = 7; + goto MAKENUMSTR; + case 14: + nVal = 36; + nNum = 11; + goto MAKENUMSTR; + case 19: + nVal = 51; + nNum = 7; + goto MAKENUMSTR; + case 21: + nVal = 33; + nNum = 13; + goto MAKENUMSTR; + case 22: + nVal = 36; + nNum = 14; + goto MAKENUMSTR; + case 23: + nVal = 39; + nNum = 13; + goto MAKENUMSTR; + case 24: + nVal = 108; + nNum = 15; + goto MAKENUMSTR; + + MAKENUMSTR: + if (maCurrentData.IsValueFormat()) + { + OUString sFormat; + LanguageType eLng, eSys; + maCurrentData.GetBoxFormat(sal_uInt8(nNum)).GetValueFormat(sFormat, eLng, eSys); + + SvNumFormatType nType; + bool bNew; + sal_Int32 nCheckPos; + sal_uInt32 nKey = mxNumFormat->GetIndexPuttingAndConverting(sFormat, eLng, eSys, + nType, bNew, nCheckPos); + const Color* pDummy; + mxNumFormat->GetOutputString(nVal, nKey, cellString, &pDummy); + } + else + cellString = OUString::number(sal_Int32(nVal)); + break; + } + + if (cellString.isEmpty()) + return; + + SvtScriptedTextHelper aScriptedText(rRenderContext); + Size aStrSize; + sal_uInt8 nFormatIndex = GetFormatIndex(nCol, nRow); + const basegfx::B2DRange aCellRange(maArray.GetCellRange(nCol, nRow)); + const tools::Rectangle cellRect( + basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()), + basegfx::fround(aCellRange.getMaxX()), basegfx::fround(aCellRange.getMaxY())); + Point aPos = cellRect.TopLeft(); + tools::Long nRightX = 0; + + Size theMaxStrSize(cellRect.GetWidth() - FRAME_OFFSET, cellRect.GetHeight() - FRAME_OFFSET); + if (maCurrentData.IsFont()) + { + vcl::Font aFont, aCJKFont, aCTLFont; + MakeFonts(rRenderContext, nFormatIndex, aFont, aCJKFont, aCTLFont); + aScriptedText.SetFonts(&aFont, &aCJKFont, &aCTLFont); + } + else + aScriptedText.SetDefaultFont(); + + aScriptedText.SetText(cellString, m_xBreak); + aStrSize = aScriptedText.GetTextSize(); + + if (maCurrentData.IsFont() && theMaxStrSize.Height() < aStrSize.Height()) + { + // If the string in this font does not + // fit into the cell, the standard font + // is taken again: + aScriptedText.SetDefaultFont(); + aStrSize = aScriptedText.GetTextSize(); + } + + while (theMaxStrSize.Width() <= aStrSize.Width() && cellString.getLength() > 1) + { + cellString = cellString.copy(0, cellString.getLength() - 1); + aScriptedText.SetText(cellString, m_xBreak); + aStrSize = aScriptedText.GetTextSize(); + } + + nRightX = cellRect.GetWidth() - aStrSize.Width() - FRAME_OFFSET; + + // vertical (always centering): + aPos.AdjustY((mnRowHeight - aStrSize.Height()) / 2); + + // horizontal + if (mbRTL) + aPos.AdjustX(nRightX); + else if (maCurrentData.IsJustify()) + { + const SvxAdjustItem& rAdj = maCurrentData.GetBoxFormat(nFormatIndex).GetAdjust(); + switch (rAdj.GetAdjust()) + { + case SvxAdjust::Left: + aPos.AdjustX(FRAME_OFFSET); + break; + case SvxAdjust::Right: + aPos.AdjustX(nRightX); + break; + default: + aPos.AdjustX((cellRect.GetWidth() - aStrSize.Width()) / 2); + break; + } + } + else + { + // Standard align: + if (nCol == 0 || nIndex == 4) + { + // Text-Label left or sum left aligned + aPos.AdjustX(FRAME_OFFSET); + } + else + { + // numbers/dates right aligned + aPos.AdjustX(nRightX); + } + } + + aScriptedText.DrawText(aPos); +} + +void AutoFormatPreview::DrawBackground(vcl::RenderContext& rRenderContext) +{ + for (size_t nRow = 0; nRow < 5; ++nRow) + { + for (size_t nCol = 0; nCol < 5; ++nCol) + { + SvxBrushItem aBrushItem( + maCurrentData.GetBoxFormat(GetFormatIndex(nCol, nRow)).GetBackground()); + + rRenderContext.Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR); + rRenderContext.SetLineColor(); + rRenderContext.SetFillColor(aBrushItem.GetColor()); + const basegfx::B2DRange aCellRange(maArray.GetCellRange(nCol, nRow)); + rRenderContext.DrawRect(tools::Rectangle( + basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()), + basegfx::fround(aCellRange.getMaxX()), basegfx::fround(aCellRange.getMaxY()))); + rRenderContext.Pop(); + } + } +} + +void AutoFormatPreview::PaintCells(vcl::RenderContext& rRenderContext) +{ + // 1) background + if (maCurrentData.IsBackground()) + DrawBackground(rRenderContext); + + // 2) values + for (size_t nRow = 0; nRow < 5; ++nRow) + for (size_t nCol = 0; nCol < 5; ++nCol) + DrawString(rRenderContext, nCol, nRow); + + // 3) border + if (!maCurrentData.IsFrame()) + return; + + const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D; + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D( + drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(rRenderContext, + aNewViewInformation2D)); + + if (pProcessor2D) + { + pProcessor2D->process(maArray.CreateB2DPrimitiveArray()); + pProcessor2D.reset(); + } +} + +void AutoFormatPreview::Init() +{ + maArray.Initialize(5, 5); + mnLabelColumnWidth = 0; + mnDataColumnWidth1 = 0; + mnDataColumnWidth2 = 0; + mnRowHeight = 0; + CalcCellArray(false); + CalcLineMap(); +} + +void AutoFormatPreview::CalcCellArray(bool _bFitWidth) +{ + maArray.SetAllColWidths(_bFitWidth ? mnDataColumnWidth2 : mnDataColumnWidth1); + maArray.SetColWidth(0, mnLabelColumnWidth); + maArray.SetColWidth(4, mnLabelColumnWidth); + + maArray.SetAllRowHeights(mnRowHeight); + + maPreviousSize.setWidth(maArray.GetWidth() + 4); + maPreviousSize.setHeight(maArray.GetHeight() + 4); +} + +static void lclSetStyleFromBorder(svx::frame::Style& rStyle, + const ::editeng::SvxBorderLine* pBorder) +{ + rStyle.Set(pBorder, 0.05, 5); +} + +void AutoFormatPreview::CalcLineMap() +{ + for (size_t nRow = 0; nRow < 5; ++nRow) + { + for (size_t nCol = 0; nCol < 5; ++nCol) + { + svx::frame::Style aStyle; + + const SvxBoxItem& rItem + = maCurrentData.GetBoxFormat(GetFormatIndex(nCol, nRow)).GetBox(); + lclSetStyleFromBorder(aStyle, rItem.GetLeft()); + maArray.SetCellStyleLeft(nCol, nRow, aStyle); + lclSetStyleFromBorder(aStyle, rItem.GetRight()); + maArray.SetCellStyleRight(nCol, nRow, aStyle); + lclSetStyleFromBorder(aStyle, rItem.GetTop()); + maArray.SetCellStyleTop(nCol, nRow, aStyle); + lclSetStyleFromBorder(aStyle, rItem.GetBottom()); + maArray.SetCellStyleBottom(nCol, nRow, aStyle); + + // FIXME - uncomment to draw diagonal borders + // lclSetStyleFromBorder( aStyle, GetDiagItem( nCol, nRow, true ).GetLine() ); + // maArray.SetCellStyleTLBR( nCol, nRow, aStyle ); + // lclSetStyleFromBorder( aStyle, GetDiagItem( nCol, nRow, false ).GetLine() ); + // maArray.SetCellStyleBLTR( nCol, nRow, aStyle ); + } + } +} + +void AutoFormatPreview::NotifyChange(const SwTableAutoFormat& rNewData) +{ + maCurrentData = rNewData; + mbFitWidth = maCurrentData.IsJustify(); // true; //??? + CalcCellArray(mbFitWidth); + CalcLineMap(); + Invalidate(); +} + +void AutoFormatPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + rRenderContext.Push(vcl::PushFlags::ALL); + + const Color& rWinColor = SW_MOD()->GetColorConfig().GetColorValue(::svtools::DOCCOLOR).nColor; + rRenderContext.SetBackground(Wallpaper(rWinColor)); + rRenderContext.Erase(); + + DrawModeFlags nOldDrawMode = rRenderContext.GetDrawMode(); + if (rRenderContext.GetSettings().GetStyleSettings().GetHighContrastMode()) + rRenderContext.SetDrawMode(DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill + | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient); + + Size theWndSize = rRenderContext.GetOutputSizePixel(); + + vcl::Font aFont(rRenderContext.GetFont()); + aFont.SetTransparent(true); + rRenderContext.SetFont(aFont); + + // Draw the Frame + Color oldColor = rRenderContext.GetLineColor(); + rRenderContext.SetLineColor(); + rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), theWndSize)); + rRenderContext.SetLineColor(oldColor); + + // Center the preview + maArray.SetXOffset(2 + (theWndSize.Width() - maPreviousSize.Width()) / 2); + maArray.SetYOffset(2 + (theWndSize.Height() - maPreviousSize.Height()) / 2); + // Draw cells on virtual device + PaintCells(rRenderContext); + + rRenderContext.SetDrawMode(nOldDrawMode); + rRenderContext.Pop(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/table/colwd.cxx b/sw/source/ui/table/colwd.cxx new file mode 100644 index 0000000000..2440d8696f --- /dev/null +++ b/sw/source/ui/table/colwd.cxx @@ -0,0 +1,75 @@ +/* -*- 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 <svtools/unitconv.hxx> +#include <colwd.hxx> +#include <tablemgr.hxx> +#include <wrtsh.hxx> +#include <wdocsh.hxx> +#include <view.hxx> +#include <swmodule.hxx> +#include <usrpref.hxx> + +IMPL_LINK_NOARG(SwTableWidthDlg, LoseFocusHdl, weld::SpinButton&, void) +{ + sal_uInt16 nId = o3tl::narrowing<sal_uInt16>(m_xColNF->get_value()) - 1; + const SwTwips lWidth = m_rFnc.GetColWidth(nId); + m_xWidthMF->set_max(m_xWidthMF->normalize(m_rFnc.GetMaxColWidth(nId)), FieldUnit::TWIP); + m_xWidthMF->set_value(m_xWidthMF->normalize(lWidth), FieldUnit::TWIP); +} + +SwTableWidthDlg::SwTableWidthDlg(weld::Window *pParent, SwTableFUNC &rTableFnc) + : GenericDialogController(pParent, "modules/swriter/ui/columnwidth.ui", "ColumnWidthDialog") + , m_rFnc(rTableFnc) + , m_xColNF(m_xBuilder->weld_spin_button("column")) + , m_xWidthMF(m_xBuilder->weld_metric_spin_button("width", FieldUnit::CM)) +{ + bool bIsWeb = rTableFnc.GetShell() + && (dynamic_cast< const SwWebDocShell* >( + rTableFnc.GetShell()->GetView().GetDocShell()) != nullptr ); + FieldUnit eFieldUnit = SW_MOD()->GetUsrPref( bIsWeb )->GetMetric(); + ::SetFieldUnit(*m_xWidthMF, eFieldUnit); + + m_xColNF->set_max(m_rFnc.GetColCount() + 1); + m_xColNF->set_value(m_rFnc.GetCurColNum() + 1); + + if (m_rFnc.GetColCount() == 0) + m_xWidthMF->set_min(m_xWidthMF->normalize(m_rFnc.GetColWidth(0)), FieldUnit::TWIP); + else + m_xWidthMF->set_min(m_xWidthMF->normalize(MINLAY), FieldUnit::TWIP); + m_xColNF->connect_value_changed(LINK(this, SwTableWidthDlg, LoseFocusHdl)); + LoseFocusHdl(*m_xColNF); +} + +void SwTableWidthDlg::Apply() +{ + m_rFnc.InitTabCols(); + m_rFnc.SetColWidth(o3tl::narrowing<sal_uInt16>(m_xColNF->get_value() - 1), + o3tl::narrowing<sal_uInt16>(m_xWidthMF->denormalize(m_xWidthMF->get_value(FieldUnit::TWIP)))); +} + +short SwTableWidthDlg::run() +{ + short nRet = GenericDialogController::run(); + if (nRet == RET_OK) + Apply(); + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/table/convert.cxx b/sw/source/ui/table/convert.cxx new file mode 100644 index 0000000000..fa5184cd69 --- /dev/null +++ b/sw/source/ui/table/convert.cxx @@ -0,0 +1,203 @@ +/* -*- 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 <modcfg.hxx> +#include <sfx2/htmlmode.hxx> +#include <viewopt.hxx> +#include <swmodule.hxx> +#include <convert.hxx> +#include <tablemgr.hxx> +#include <view.hxx> +#include <tblafmt.hxx> + +#include <strings.hrc> +#include <swabstdlg.hxx> +#include <swuiexp.hxx> +#include <memory> + +//keep the state of the buttons on runtime +static int nSaveButtonState = -1; // 0: tab, 1: semicolon, 2: paragraph, 3: other, -1: not yet used +static bool bIsKeepColumn = true; +static sal_Unicode uOther = ','; + +void SwConvertTableDlg::GetValues(sal_Unicode& rDelim, SwInsertTableOptions& rInsTableOpts, + SwTableAutoFormat const*& prTAFormat) +{ + if (m_xTabBtn->get_active()) + { + //0x0b mustn't be set when re-converting table into text + bIsKeepColumn = !m_xKeepColumn->get_visible() || m_xKeepColumn->get_active(); + rDelim = bIsKeepColumn ? 0x09 : 0x0b; + nSaveButtonState = 0; + } + else if (m_xSemiBtn->get_active()) + { + rDelim = ';'; + nSaveButtonState = 1; + } + else if (m_xOtherBtn->get_active() && !m_xOtherEd->get_text().isEmpty()) + { + uOther = m_xOtherEd->get_text()[0]; + rDelim = uOther; + nSaveButtonState = 3; + } + else + { + nSaveButtonState = 2; + rDelim = cParaDelim; + if (m_xOtherBtn->get_active()) + { + nSaveButtonState = 3; + uOther = 0; + } + } + + SwInsertTableFlags nInsMode = SwInsertTableFlags::NONE; + if (m_xHeaderCB->get_active()) + nInsMode |= SwInsertTableFlags::Headline; + if (m_xRepeatHeaderCB->get_sensitive() && m_xRepeatHeaderCB->get_active()) + rInsTableOpts.mnRowsToRepeat = m_xRepeatHeaderNF->get_value(); + else + rInsTableOpts.mnRowsToRepeat = 0; + if (!m_xDontSplitCB->get_active()) + nInsMode |= SwInsertTableFlags::SplitLayout; + + if (mxTAutoFormat) + prTAFormat = new SwTableAutoFormat(*mxTAutoFormat); + + rInsTableOpts.mnInsMode = nInsMode; +} + +SwConvertTableDlg::SwConvertTableDlg(SwView& rView, bool bToTable) + : SfxDialogController(rView.GetFrameWeld(), "modules/swriter/ui/converttexttable.ui", + "ConvertTextTableDialog") + , m_xTabBtn(m_xBuilder->weld_radio_button("tabs")) + , m_xSemiBtn(m_xBuilder->weld_radio_button("semicolons")) + , m_xParaBtn(m_xBuilder->weld_radio_button("paragraph")) + , m_xOtherBtn(m_xBuilder->weld_radio_button("other")) + , m_xOtherEd(m_xBuilder->weld_entry("othered")) + , m_xKeepColumn(m_xBuilder->weld_check_button("keepcolumn")) + , m_xOptions(m_xBuilder->weld_container("options")) + , m_xHeaderCB(m_xBuilder->weld_check_button("headingcb")) + , m_xRepeatHeaderCB(m_xBuilder->weld_check_button("repeatheading")) + , m_xRepeatRows(m_xBuilder->weld_container("repeatrows")) + , m_xRepeatHeaderNF(m_xBuilder->weld_spin_button("repeatheadersb")) + , m_xDontSplitCB(m_xBuilder->weld_check_button("dontsplitcb")) + , m_xAutoFormatBtn(m_xBuilder->weld_button("autofmt")) + , m_pShell(&rView.GetWrtShell()) +{ + if (nSaveButtonState > -1) + { + switch (nSaveButtonState) + { + case 0: + m_xTabBtn->set_active(true); + m_xKeepColumn->set_active(bIsKeepColumn); + break; + case 1: + m_xSemiBtn->set_active(true); + break; + case 2: + m_xParaBtn->set_active(true); + break; + case 3: + m_xOtherBtn->set_active(true); + if (uOther) + m_xOtherEd->set_text(OUString(uOther)); + break; + } + } + if (bToTable) + { + m_xDialog->set_title(SwResId(STR_CONVERT_TEXT_TABLE)); + m_xAutoFormatBtn->connect_clicked(LINK(this, SwConvertTableDlg, AutoFormatHdl)); + m_xAutoFormatBtn->show(); + m_xKeepColumn->show(); + m_xKeepColumn->set_sensitive(m_xTabBtn->get_active()); + } + else + { + //hide insert options + m_xOptions->hide(); + } + m_xKeepColumn->save_state(); + + Link<weld::Toggleable&, void> aLk(LINK(this, SwConvertTableDlg, BtnHdl)); + m_xTabBtn->connect_toggled(aLk); + m_xSemiBtn->connect_toggled(aLk); + m_xParaBtn->connect_toggled(aLk); + m_xOtherBtn->connect_toggled(aLk); + m_xOtherEd->set_sensitive(m_xOtherBtn->get_active()); + + const SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig(); + + bool bHTMLMode = 0 != (::GetHtmlMode(rView.GetDocShell()) & HTMLMODE_ON); + + SwInsertTableOptions aInsOpts = pModOpt->GetInsTableFlags(bHTMLMode); + SwInsertTableFlags nInsTableFlags = aInsOpts.mnInsMode; + + m_xHeaderCB->set_active(bool(nInsTableFlags & SwInsertTableFlags::Headline)); + m_xRepeatHeaderCB->set_active(aInsOpts.mnRowsToRepeat > 0); + m_xDontSplitCB->set_active(!(nInsTableFlags & SwInsertTableFlags::SplitLayout)); + + m_xHeaderCB->connect_toggled(LINK(this, SwConvertTableDlg, CheckBoxHdl)); + m_xRepeatHeaderCB->connect_toggled(LINK(this, SwConvertTableDlg, RepeatHeaderCheckBoxHdl)); + RepeatHeaderCheckBoxHdl(*m_xRepeatHeaderCB); + CheckBoxHdl(*m_xHeaderCB); +} + +IMPL_LINK_NOARG(SwConvertTableDlg, AutoFormatHdl, weld::Button&, void) +{ + SwAbstractDialogFactory& rFact = swui::GetFactory(); + + ScopedVclPtr<AbstractSwAutoFormatDlg> pDlg( + rFact.CreateSwAutoFormatDlg(m_xDialog.get(), m_pShell, false, mxTAutoFormat.get())); + if (RET_OK == pDlg->Execute()) + mxTAutoFormat = pDlg->FillAutoFormatOfIndex(); +} + +IMPL_LINK(SwConvertTableDlg, BtnHdl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + if (m_xTabBtn->get_active()) + m_xKeepColumn->set_state(m_xKeepColumn->get_saved_state()); + else + { + if (m_xKeepColumn->get_sensitive()) + m_xKeepColumn->save_state(); + m_xKeepColumn->set_active(true); + } + m_xKeepColumn->set_sensitive(m_xTabBtn->get_active()); + m_xOtherEd->set_sensitive(m_xOtherBtn->get_active()); +} + +IMPL_LINK_NOARG(SwConvertTableDlg, CheckBoxHdl, weld::Toggleable&, void) +{ + m_xRepeatHeaderCB->set_sensitive(m_xHeaderCB->get_active()); + RepeatHeaderCheckBoxHdl(*m_xRepeatHeaderCB); +} + +IMPL_LINK_NOARG(SwConvertTableDlg, RepeatHeaderCheckBoxHdl, weld::Toggleable&, void) +{ + bool bEnable = m_xHeaderCB->get_active() && m_xRepeatHeaderCB->get_active(); + m_xRepeatRows->set_sensitive(bEnable); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/table/instable.cxx b/sw/source/ui/table/instable.cxx new file mode 100644 index 0000000000..a5aa4cd838 --- /dev/null +++ b/sw/source/ui/table/instable.cxx @@ -0,0 +1,298 @@ +/* -*- 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 <instable.hxx> +#include <shellres.hxx> +#include <modcfg.hxx> +#include <swmodule.hxx> +#include <sfx2/htmlmode.hxx> +#include <viewopt.hxx> +#include <comphelper/lok.hxx> + + +void SwInsTableDlg::GetValues( OUString& rName, sal_uInt16& rRow, sal_uInt16& rCol, + SwInsertTableOptions& rInsTableOpts, OUString& rAutoName, + std::unique_ptr<SwTableAutoFormat>& prTAFormat ) +{ + SwInsertTableFlags nInsMode = SwInsertTableFlags::NONE; + rName = m_xNameEdit->get_text(); + rRow = m_xRowSpinButton->get_value(); + rCol = m_xColSpinButton->get_value(); + + if (m_xHeaderCB->get_active()) + nInsMode |= SwInsertTableFlags::Headline; + if (m_xRepeatHeaderCB->get_sensitive() && m_xRepeatHeaderCB->get_active()) + rInsTableOpts.mnRowsToRepeat = m_xRepeatHeaderNF->get_value(); + else + rInsTableOpts.mnRowsToRepeat = 0; + if (!m_xDontSplitCB->get_active()) + nInsMode |= SwInsertTableFlags::SplitLayout; + if( m_xTAutoFormat ) + { + prTAFormat.reset(new SwTableAutoFormat( *m_xTAutoFormat )); + rAutoName = prTAFormat->GetName(); + } + + rInsTableOpts.mnInsMode = nInsMode; +} + +IMPL_LINK(SwInsTableDlg, TextFilterHdl, OUString&, rTest, bool) +{ + rTest = m_aTextFilter.filter(rTest); + return true; +} + +SwInsTableDlg::SwInsTableDlg(SwView& rView) + : SfxDialogController(rView.GetFrameWeld(), "modules/swriter/ui/inserttable.ui", "InsertTableDialog") + , m_aTextFilter(" .<>") + , m_pShell(&rView.GetWrtShell()) + , m_nEnteredValRepeatHeaderNF(-1) + , m_xNameEdit(m_xBuilder->weld_entry("nameedit")) + , m_xWarning(m_xBuilder->weld_label("lbwarning")) + , m_xColSpinButton(m_xBuilder->weld_spin_button("colspin")) + , m_xRowSpinButton(m_xBuilder->weld_spin_button("rowspin")) + , m_xHeaderCB(m_xBuilder->weld_check_button("headercb")) + , m_xRepeatHeaderCB(m_xBuilder->weld_check_button("repeatcb")) + , m_xRepeatHeaderNF(m_xBuilder->weld_spin_button("repeatheaderspin")) + , m_xRepeatGroup(m_xBuilder->weld_widget("repeatgroup")) + , m_xDontSplitCB(m_xBuilder->weld_check_button("dontsplitcb")) + , m_xInsertBtn(m_xBuilder->weld_button("ok")) + , m_xLbFormat(m_xBuilder->weld_tree_view("formatlbinstable")) + , m_xWndPreview(new weld::CustomWeld(*m_xBuilder, "previewinstable", m_aWndPreview)) + , m_xStyleFrame(m_xBuilder->weld_frame("stylesframe")) +{ + if (comphelper::LibreOfficeKit::isActive()) + m_xStyleFrame->hide(); + + const int nWidth = m_xLbFormat->get_approximate_digit_width() * 32; + const int nHeight = m_xLbFormat->get_height_rows(8); + m_xLbFormat->set_size_request(nWidth, nHeight); + m_xWndPreview->set_size_request(nWidth, nHeight); + + m_xNameEdit->connect_insert_text(LINK(this, SwInsTableDlg, TextFilterHdl)); + m_xNameEdit->set_text(m_pShell->GetUniqueTableName()); + m_xNameEdit->connect_changed(LINK(this, SwInsTableDlg, ModifyName)); + m_xRowSpinButton->connect_changed(LINK(this, SwInsTableDlg, ModifyRowCol)); + m_xColSpinButton->connect_changed(LINK(this, SwInsTableDlg, ModifyRowCol)); + + m_xInsertBtn->connect_clicked(LINK(this, SwInsTableDlg, OKHdl)); + + bool bHTMLMode = 0 != (::GetHtmlMode(rView.GetDocShell())&HTMLMODE_ON); + const SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig(); + + SwInsertTableOptions aInsOpts = pModOpt->GetInsTableFlags(bHTMLMode); + SwInsertTableFlags nInsTableFlags = aInsOpts.mnInsMode; + + m_xHeaderCB->set_active(bool(nInsTableFlags & SwInsertTableFlags::Headline)); + m_xRepeatHeaderCB->set_active(aInsOpts.mnRowsToRepeat > 0); + if (bHTMLMode) + m_xDontSplitCB->hide(); + else + m_xDontSplitCB->set_active(!(nInsTableFlags & SwInsertTableFlags::SplitLayout)); + + m_xRepeatHeaderNF->connect_value_changed( LINK( this, SwInsTableDlg, ModifyRepeatHeaderNF_Hdl ) ); + m_xHeaderCB->connect_toggled( LINK( this, SwInsTableDlg, CheckBoxHdl ) ); + m_xRepeatHeaderCB->connect_toggled( LINK( this, SwInsTableDlg, RepeatHeaderCheckBoxHdl ) ); + RepeatHeaderCheckBoxHdl(*m_xRepeatHeaderCB); + CheckBoxHdl(*m_xHeaderCB); + + sal_Int64 nMax = m_xRowSpinButton->get_value(); + if( nMax <= 1 ) + nMax = 1; + else + --nMax; + m_xRepeatHeaderNF->set_max( nMax ); + + InitAutoTableFormat(); + m_xWarning->set_label_type(weld::LabelType::Warning); +} + +void SwInsTableDlg::InitAutoTableFormat() +{ + m_aWndPreview.DetectRTL(m_pShell); + + m_xLbFormat->connect_changed(LINK(this, SwInsTableDlg, SelFormatHdl)); + + m_xTableTable.reset(new SwTableAutoFormatTable); + m_xTableTable->Load(); + + // Add "- none -" style autoformat table. + m_xLbFormat->append_text(SwViewShell::GetShellRes()->aStrNone); // Insert to listbox + + // Add other styles of autoformat tables. + for (sal_uInt8 i = 0, nCount = static_cast<sal_uInt8>(m_xTableTable->size()); + i < nCount; i++) + { + SwTableAutoFormat const& rFormat = (*m_xTableTable)[ i ]; + m_xLbFormat->append_text(rFormat.GetName()); + if (m_xTAutoFormat && rFormat.GetName() == m_xTAutoFormat->GetName()) + m_lbIndex = i; + } + + // Change this min variable if you add autotable manually. + minTableIndexInLb = 1; + maxTableIndexInLb = minTableIndexInLb + static_cast<sal_uInt8>(m_xTableTable->size()); + // 1 means default table style + // unfortunately when the table has a style sw/qa/uitest/writer_tests4/tdf115573.py fails + // because tables that have pre-applied style resets the style of the elements in their cells + // when a new row is inserted and the ui test above relies on that. For now this is LOK only + m_lbIndex = comphelper::LibreOfficeKit::isActive() ? 1 : 0; + m_xLbFormat->select(m_lbIndex); + m_tbIndex = lbIndexToTableIndex(m_lbIndex); + + SelFormatHdl( *m_xLbFormat ); +} + +sal_uInt8 SwInsTableDlg::lbIndexToTableIndex( const sal_uInt8 listboxIndex ) +{ + if( minTableIndexInLb != maxTableIndexInLb && + minTableIndexInLb <= listboxIndex && + listboxIndex < maxTableIndexInLb ) + { + return listboxIndex - minTableIndexInLb; + } + + return 255; +} + +static void lcl_SetProperties( SwTableAutoFormat* pTableAutoFormat, bool bVal ) +{ + pTableAutoFormat->SetFont( bVal ); + pTableAutoFormat->SetJustify( bVal ); + pTableAutoFormat->SetFrame( bVal ); + pTableAutoFormat->SetBackground( bVal ); + pTableAutoFormat->SetValueFormat( bVal ); + pTableAutoFormat->SetWidthHeight( bVal ); +} + +IMPL_LINK_NOARG(SwInsTableDlg, SelFormatHdl, weld::TreeView&, void) +{ + // Get index of selected item from the listbox + m_lbIndex = static_cast<sal_uInt8>(m_xLbFormat->get_selected_index()); + m_tbIndex = lbIndexToTableIndex( m_lbIndex ); + + // To understand this index mapping, look InitAutoTableFormat function to + // see how listbox item is implemented. + if( m_tbIndex < 255 ) + m_aWndPreview.NotifyChange( (*m_xTableTable)[m_tbIndex] ); + else + { + SwTableAutoFormat aTmp( SwViewShell::GetShellRes()->aStrNone ); + lcl_SetProperties( &aTmp, false ); + + m_aWndPreview.NotifyChange( aTmp ); + } +} + +IMPL_LINK_NOARG(SwInsTableDlg, OKHdl, weld::Button&, void) +{ + if( m_tbIndex < 255 ) + m_pShell->SetTableStyle((*m_xTableTable)[m_tbIndex]); + + if( m_tbIndex < 255 ) + { + if( m_xTAutoFormat ) + *m_xTAutoFormat = (*m_xTableTable)[ m_tbIndex ]; + else + m_xTAutoFormat.reset(new SwTableAutoFormat( (*m_xTableTable)[ m_tbIndex ] )); + } + else + { + m_xTAutoFormat.reset(new SwTableAutoFormat( SwViewShell::GetShellRes()->aStrNone )); + lcl_SetProperties( m_xTAutoFormat.get(), false ); + } + + m_xDialog->response(RET_OK); +} + +IMPL_LINK( SwInsTableDlg, ModifyName, weld::Entry&, rEdit, void ) +{ + OUString sTableName = rEdit.get_text(); + m_xInsertBtn->set_sensitive(m_pShell->GetTableStyle(sTableName) == nullptr); +} + +// We use weld::Entry's "changed" notification here, not weld::SpinButton's "value_changed", because +// the latter only fires after the control looses focus; so the notification would not fire during +// typing a big number, so that user typing it and immediately clicking "Insert" would not see the +// warning. +// Since the notification is called in weld::Entry context, we can only rely on what's available for +// used weld::Entry's notification; specifically, we have to call spin buttons' get_text() instead +// of get_value(), because the latter is not guaranteed to return an up-to-date value at this point +// (depends on vcl plugin used). +IMPL_LINK( SwInsTableDlg, ModifyRowCol, weld::Entry&, rEdit, void ) +{ + sal_Int64 nRow = m_xRowSpinButton->get_text().toInt64(); + sal_Int64 nCol = m_xColSpinButton->get_text().toInt64(); + if (nRow > 255) + { + m_xRowSpinButton->set_message_type(weld::EntryMessageType::Warning); + m_xWarning->set_visible(true); + } + else + { + m_xRowSpinButton->set_message_type(weld::EntryMessageType::Normal); + } + if (nCol > 63) + { + m_xColSpinButton->set_message_type(weld::EntryMessageType::Warning); + m_xWarning->set_visible(true); + } + else + { + m_xColSpinButton->set_message_type(weld::EntryMessageType::Normal); + } + if (nRow <= 255 && nCol <= 63) + { + m_xWarning->set_visible(false); + } + if (&rEdit == m_xColSpinButton.get()) + return; + + if(!nRow) + nRow = 1; + + // adjust depending NF for repeated rows + sal_Int64 nMax = ( nRow == 1 )? 1 : nRow - 1 ; + sal_Int64 nActVal = m_xRepeatHeaderNF->get_value(); + + m_xRepeatHeaderNF->set_max( nMax ); + + if( nActVal > nMax ) + m_xRepeatHeaderNF->set_value( nMax ); + else if( nActVal < m_nEnteredValRepeatHeaderNF ) + m_xRepeatHeaderNF->set_value(std::min(m_nEnteredValRepeatHeaderNF, nMax)); +} + +IMPL_LINK_NOARG(SwInsTableDlg, CheckBoxHdl, weld::Toggleable&, void) +{ + m_xRepeatHeaderCB->set_sensitive(m_xHeaderCB->get_active()); + RepeatHeaderCheckBoxHdl(*m_xRepeatHeaderCB); +} + +IMPL_LINK_NOARG(SwInsTableDlg, RepeatHeaderCheckBoxHdl, weld::Toggleable&, void) +{ + m_xRepeatGroup->set_sensitive(m_xHeaderCB->get_active() && m_xRepeatHeaderCB->get_active()); +} + +IMPL_LINK_NOARG(SwInsTableDlg, ModifyRepeatHeaderNF_Hdl, weld::SpinButton&, void) +{ + m_nEnteredValRepeatHeaderNF = m_xRepeatHeaderNF->get_value(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/table/mergetbl.cxx b/sw/source/ui/table/mergetbl.cxx new file mode 100644 index 0000000000..c715b8a5f6 --- /dev/null +++ b/sw/source/ui/table/mergetbl.cxx @@ -0,0 +1,40 @@ +/* -*- 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 <mergetbl.hxx> + +SwMergeTableDlg::SwMergeTableDlg(weld::Window* pParent, bool& rWithPrev) + : GenericDialogController(pParent, "modules/swriter/ui/mergetabledialog.ui", "MergeTableDialog") + , m_rMergePrev(rWithPrev) + , m_xMergePrevRB(m_xBuilder->weld_radio_button("prev")) +{ + m_xMergePrevRB->set_active(true); +} + +void SwMergeTableDlg::Apply() { m_rMergePrev = m_xMergePrevRB->get_active(); } + +short SwMergeTableDlg::run() +{ + int nRet = GenericDialogController::run(); + if (nRet == RET_OK) + Apply(); + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/table/rowht.cxx b/sw/source/ui/table/rowht.cxx new file mode 100644 index 0000000000..f46297bf7d --- /dev/null +++ b/sw/source/ui/table/rowht.cxx @@ -0,0 +1,72 @@ +/* -*- 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 <svtools/unitconv.hxx> + +#include <fmtfsize.hxx> +#include <swtypes.hxx> +#include <rowht.hxx> +#include <wrtsh.hxx> +#include <wdocsh.hxx> +#include <view.hxx> +#include <swmodule.hxx> +#include <usrpref.hxx> + +void SwTableHeightDlg::Apply() +{ + SwTwips nHeight = static_cast< SwTwips >(m_xHeightEdit->denormalize(m_xHeightEdit->get_value(FieldUnit::TWIP))); + SwFormatFrameSize aSz(SwFrameSize::Fixed, 0, nHeight); + + SwFrameSize eFrameSize = m_xAutoHeightCB->get_active() ? SwFrameSize::Minimum : SwFrameSize::Fixed; + if(eFrameSize != aSz.GetHeightSizeType()) + { + aSz.SetHeightSizeType(eFrameSize); + } + m_rSh.SetRowHeight(aSz); +} + +SwTableHeightDlg::SwTableHeightDlg(weld::Window *pParent, SwWrtShell &rS) + : GenericDialogController(pParent, "modules/swriter/ui/rowheight.ui", "RowHeightDialog") + , m_rSh(rS) + , m_xHeightEdit(m_xBuilder->weld_metric_spin_button("heightmf", FieldUnit::CM)) + , m_xAutoHeightCB(m_xBuilder->weld_check_button("fit")) +{ + FieldUnit eFieldUnit = SW_MOD()->GetUsrPref( dynamic_cast< const SwWebDocShell*>( + m_rSh.GetView().GetDocShell() ) != nullptr )->GetMetric(); + ::SetFieldUnit(*m_xHeightEdit, eFieldUnit); + + m_xHeightEdit->set_min(MINLAY, FieldUnit::TWIP); + std::unique_ptr<SwFormatFrameSize> pSz = m_rSh.GetRowHeight(); + if (pSz) + { + auto nHeight = pSz->GetHeight(); + m_xAutoHeightCB->set_active(pSz->GetHeightSizeType() != SwFrameSize::Fixed); + m_xHeightEdit->set_value(m_xHeightEdit->normalize(nHeight), FieldUnit::TWIP); + } +} + +short SwTableHeightDlg::run() +{ + short nRet = GenericDialogController::run(); + if (nRet == RET_OK) + Apply(); + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/table/splittbl.cxx b/sw/source/ui/table/splittbl.cxx new file mode 100644 index 0000000000..5a7ef0ae08 --- /dev/null +++ b/sw/source/ui/table/splittbl.cxx @@ -0,0 +1,72 @@ +/* -*- 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 <wrtsh.hxx> +#include <splittbl.hxx> +#include <tblenum.hxx> + +SplitTable_HeadlineOption SwSplitTableDlg::m_eRememberedSplitOption + = SplitTable_HeadlineOption::ContentCopy; + +SwSplitTableDlg::SwSplitTableDlg(weld::Window* pParent, SwWrtShell& rSh) + : GenericDialogController(pParent, "modules/swriter/ui/splittable.ui", "SplitTableDialog") + , m_xBoxAttrCopyWithParaRB(m_xBuilder->weld_radio_button("customheadingapplystyle")) + , m_xBoxAttrCopyNoParaRB(m_xBuilder->weld_radio_button("customheading")) + , m_xBorderCopyRB(m_xBuilder->weld_radio_button("noheading")) + , m_rShell(rSh) + , m_nSplit(SplitTable_HeadlineOption::ContentCopy) +{ + // tdf#131759 - remember last used option in split table dialog + m_nSplit = m_eRememberedSplitOption; + switch (m_nSplit) + { + case SplitTable_HeadlineOption::BoxAttrAllCopy: + m_xBoxAttrCopyWithParaRB->set_active(true); + break; + case SplitTable_HeadlineOption::BoxAttrCopy: + m_xBoxAttrCopyNoParaRB->set_active(true); + break; + case SplitTable_HeadlineOption::BorderCopy: + m_xBorderCopyRB->set_active(true); + break; + case SplitTable_HeadlineOption::NONE: + case SplitTable_HeadlineOption::ContentCopy: + default: + // Use the default value in case of an invalid option + m_nSplit = SplitTable_HeadlineOption::ContentCopy; + } +} + +void SwSplitTableDlg::Apply() +{ + m_nSplit = SplitTable_HeadlineOption::ContentCopy; + if (m_xBoxAttrCopyWithParaRB->get_active()) + m_nSplit = SplitTable_HeadlineOption::BoxAttrAllCopy; + else if (m_xBoxAttrCopyNoParaRB->get_active()) + m_nSplit = SplitTable_HeadlineOption::BoxAttrCopy; + else if (m_xBorderCopyRB->get_active()) + m_nSplit = SplitTable_HeadlineOption::BorderCopy; + + // tdf#131759 - remember last used option in split table dialog + m_eRememberedSplitOption = m_nSplit; + + m_rShell.SplitTable(m_nSplit); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/table/tabledlg.cxx b/sw/source/ui/table/tabledlg.cxx new file mode 100644 index 0000000000..daedfffe46 --- /dev/null +++ b/sw/source/ui/table/tabledlg.cxx @@ -0,0 +1,1762 @@ +/* -*- 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/svapp.hxx> +#include <vcl/weld.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/formatbreakitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <svl/ctloptions.hxx> +#include <swmodule.hxx> +#include <fmtpdsc.hxx> +#include <fmtlsplt.hxx> + +#include <fmtrowsplt.hxx> +#include <sfx2/htmlmode.hxx> +#include <sfx2/sfxdlg.hxx> + +#include <strings.hrc> +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> + +#include <wrtsh.hxx> +#include <view.hxx> +#include <viewopt.hxx> +#include <uitool.hxx> +#include <tabledlg.hxx> +#include "../../uibase/table/tablepg.hxx" +#include <tablemgr.hxx> +#include <pagedesc.hxx> +#include <uiitems.hxx> +#include <poolfmt.hxx> +#include <swtablerep.hxx> +#include <SwStyleNameMapper.hxx> + +#include <cmdid.h> +#include <svx/dialogs.hrc> +#include <svx/flagsdef.hxx> +#include <osl/diagnose.h> +#include <officecfg/Office/Common.hxx> + +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> + +using namespace ::com::sun::star; + +SwFormatTablePage::SwFormatTablePage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/formattablepage.ui", "FormatTablePage", &rSet) + , m_pTableData(nullptr) + , m_nSaveWidth(0) + , m_nMinTableWidth(MINLAY) + , m_bModified(false) + , m_bFull(false) + , m_bHtmlMode(false) + , m_xNameED(m_xBuilder->weld_entry("name")) + , m_xWidthFT(m_xBuilder->weld_label("widthft")) + , m_xWidthMF(new SwPercentField(m_xBuilder->weld_metric_spin_button("widthmf", FieldUnit::CM))) + , m_xRelWidthCB(m_xBuilder->weld_check_button("relwidth")) + , m_xFullBtn(m_xBuilder->weld_radio_button("full")) + , m_xLeftBtn(m_xBuilder->weld_radio_button("left")) + , m_xFromLeftBtn(m_xBuilder->weld_radio_button("fromleft")) + , m_xRightBtn(m_xBuilder->weld_radio_button("right")) + , m_xCenterBtn(m_xBuilder->weld_radio_button("center")) + , m_xFreeBtn(m_xBuilder->weld_radio_button("free")) + , m_xLeftFT(m_xBuilder->weld_label("leftft")) + , m_xLeftMF(new SwPercentField(m_xBuilder->weld_metric_spin_button("leftmf", FieldUnit::CM))) + , m_xRightFT(m_xBuilder->weld_label("rightft")) + , m_xRightMF(new SwPercentField(m_xBuilder->weld_metric_spin_button("rightmf", FieldUnit::CM))) + , m_xTopFT(m_xBuilder->weld_label("aboveft")) + , m_xTopMF(m_xBuilder->weld_metric_spin_button("abovemf", FieldUnit::CM)) + , m_xBottomFT(m_xBuilder->weld_label("belowft")) + , m_xBottomMF(m_xBuilder->weld_metric_spin_button("belowmf", FieldUnit::CM)) + , m_xTextDirectionLB(new svx::FrameDirectionListBox(m_xBuilder->weld_combo_box("textdirection"))) + , m_xProperties(m_xBuilder->weld_widget("properties")) +{ + m_xWidthMF->GetMetricFieldRange(m_nOrigWidthMin, m_nOrigWidthMax); + m_xLeftMF->GetMetricFieldRange(m_nOrigLeftMin, m_nOrigLeftMax); + m_xRightMF->GetMetricFieldRange(m_nOrigRightMin, m_nOrigRightMax); + + //lock these to initial sizes so they don't change on percent to non percent change + Size aPrefSize(m_xLeftMF->get()->get_preferred_size()); + m_xLeftMF->get()->set_size_request(aPrefSize.Width(), aPrefSize.Height()); + m_xRightMF->get()->set_size_request(aPrefSize.Width(), aPrefSize.Height()); + m_xWidthMF->get()->set_size_request(aPrefSize.Width(), aPrefSize.Height()); + + m_xTextDirectionLB->append(SvxFrameDirection::Horizontal_LR_TB, SvxResId(RID_SVXSTR_FRAMEDIR_LTR)); + m_xTextDirectionLB->append(SvxFrameDirection::Horizontal_RL_TB, SvxResId(RID_SVXSTR_FRAMEDIR_RTL)); + m_xTextDirectionLB->append(SvxFrameDirection::Environment, SvxResId(RID_SVXSTR_FRAMEDIR_SUPER)); + + SetExchangeSupport(); + + if(const SfxUInt16Item* pModeItem = rSet.GetItemIfSet(SID_HTML_MODE, false)) + m_bHtmlMode = 0 != (pModeItem->GetValue() & HTMLMODE_ON); + + bool bCTL = SvtCTLOptions::IsCTLFontEnabled(); + m_xProperties->set_visible(!m_bHtmlMode && bCTL); + + Init(); +} + +SwFormatTablePage::~SwFormatTablePage() +{ +} + +void SwFormatTablePage::Init() +{ + m_xLeftMF->SetMetricFieldMin(-999999); + m_xRightMF->SetMetricFieldMin(-999999); + + //handler + Link<weld::Toggleable&,void> aLk2 = LINK( this, SwFormatTablePage, AutoClickHdl ); + m_xFullBtn->connect_toggled( aLk2 ); + m_xFreeBtn->connect_toggled( aLk2 ); + m_xLeftBtn->connect_toggled( aLk2 ); + m_xFromLeftBtn->connect_toggled( aLk2 ); + m_xRightBtn->connect_toggled( aLk2 ); + m_xCenterBtn->connect_toggled( aLk2 ); + + Link<weld::MetricSpinButton&,void> aLk = LINK(this, SwFormatTablePage, ValueChangedHdl); + m_xTopMF->connect_value_changed(aLk); + m_xBottomMF->connect_value_changed(aLk); + m_xRightMF->connect_value_changed(aLk); + m_xLeftMF->connect_value_changed(aLk); + m_xWidthMF->connect_value_changed(aLk); + + m_xRelWidthCB->connect_toggled(LINK( this, SwFormatTablePage, RelWidthClickHdl )); +} + +IMPL_LINK( SwFormatTablePage, RelWidthClickHdl, weld::Toggleable&, rBtn, void ) +{ + OSL_ENSURE(m_pTableData, "table data not available?"); + bool bIsChecked = rBtn.get_active(); + sal_Int64 nLeft = m_xLeftMF->DenormalizePercent(m_xLeftMF->get_value(FieldUnit::TWIP)); + sal_Int64 nRight = m_xRightMF->DenormalizePercent(m_xRightMF->get_value(FieldUnit::TWIP)); + m_xWidthMF->ShowPercent(bIsChecked); + m_xLeftMF->ShowPercent(bIsChecked); + m_xRightMF->ShowPercent(bIsChecked); + + if (bIsChecked) + { + m_xWidthMF->SetRefValue(m_pTableData->GetSpace()); + m_xLeftMF->SetRefValue(m_pTableData->GetSpace()); + m_xRightMF->SetRefValue(m_pTableData->GetSpace()); + m_xLeftMF->SetMetricFieldMin(0); //will be overwritten by the Percentfield + m_xRightMF->SetMetricFieldMin(0); //ditto + m_xLeftMF->SetMetricFieldMax(99); + m_xRightMF->SetMetricFieldMax(99); + m_xLeftMF->set_value(m_xLeftMF->NormalizePercent(nLeft ), FieldUnit::TWIP ); + m_xRightMF->set_value(m_xRightMF->NormalizePercent(nRight ), FieldUnit::TWIP ); + } + else + ModifyHdl(*m_xLeftMF->get()); //correct values again + + if (m_xFreeBtn->get_active()) + { + bool bEnable = !rBtn.get_active(); + m_xRightMF->set_sensitive(bEnable); + m_xRightFT->set_sensitive(bEnable); + } + m_bModified = true; +} + +IMPL_LINK_NOARG(SwFormatTablePage, AutoClickHdl, weld::Toggleable&, void) +{ + bool bRestore = true, + bLeftEnable = false, + bRightEnable= false, + bWidthEnable= false, + bOthers = true; + if (m_xFullBtn->get_active()) + { + m_xLeftMF->set_value(0); + m_xRightMF->set_value(0); + m_nSaveWidth = static_cast<SwTwips>(m_xWidthMF->DenormalizePercent(m_xWidthMF->get_value(FieldUnit::TWIP))); + m_xWidthMF->set_value(m_xWidthMF->NormalizePercent(m_pTableData->GetSpace()), FieldUnit::TWIP); + m_bFull = true; + bRestore = false; + } + else if (m_xLeftBtn->get_active()) + { + bRightEnable = bWidthEnable = true; + m_xLeftMF->set_value(0); + } + else if (m_xFromLeftBtn->get_active()) + { + bLeftEnable = bWidthEnable = true; + m_xRightMF->set_value(0); + } + else if (m_xRightBtn->get_active()) + { + bLeftEnable = bWidthEnable = true; + m_xRightMF->set_value(0); + } + else if (m_xCenterBtn->get_active()) + { + bLeftEnable = bWidthEnable = true; + } + else if (m_xFreeBtn->get_active()) + { + RightModify(); + bLeftEnable = true; + bWidthEnable = true; + bOthers = false; + } + m_xLeftMF->set_sensitive(bLeftEnable); + m_xLeftFT->set_sensitive(bLeftEnable); + m_xWidthMF->set_sensitive(bWidthEnable); + m_xWidthFT->set_sensitive(bWidthEnable); + if ( bOthers ) + { + m_xRightMF->set_sensitive(bRightEnable); + m_xRightFT->set_sensitive(bRightEnable); + m_xRelWidthCB->set_sensitive(bWidthEnable); + } + + if(m_bFull && bRestore) + { + //After being switched on automatic, the width was pinned + //in order to restore the width while switching back to. + m_bFull = false; + m_xWidthMF->set_value(m_xWidthMF->NormalizePercent(m_nSaveWidth ), FieldUnit::TWIP ); + } + ModifyHdl(*m_xWidthMF->get()); + m_bModified = true; +} + +void SwFormatTablePage::RightModify() +{ + if (!m_xFreeBtn->get_active()) + return; + + bool bEnable = m_xRightMF->get_value() == 0; + m_xRelWidthCB->set_sensitive(bEnable); + if ( !bEnable ) + { + m_xRelWidthCB->set_active(false); + RelWidthClickHdl(*m_xRelWidthCB); + } + bEnable = m_xRelWidthCB->get_active(); + m_xRightMF->set_sensitive(!bEnable); + m_xRightFT->set_sensitive(!bEnable); +} + +IMPL_LINK( SwFormatTablePage, ValueChangedHdl, weld::MetricSpinButton&, rEdit, void ) +{ + if (m_xRightMF->get() == &rEdit) + RightModify(); + ModifyHdl(rEdit); +} + +void SwFormatTablePage::ModifyHdl(const weld::MetricSpinButton& rEdit, bool bAllowInconsistencies) +{ + SwTwips nCurWidth = static_cast< SwTwips >(m_xWidthMF->DenormalizePercent(m_xWidthMF->get_value(FieldUnit::TWIP))); + SwTwips nPrevWidth = nCurWidth; + SwTwips nRight = static_cast< SwTwips >(m_xRightMF->DenormalizePercent(m_xRightMF->get_value(FieldUnit::TWIP))); + SwTwips nLeft = static_cast< SwTwips >(m_xLeftMF->DenormalizePercent(m_xLeftMF->get_value(FieldUnit::TWIP))); + SwTwips nDiff; + + if (&rEdit == m_xWidthMF->get()) + { + if( nCurWidth < MINLAY ) + nCurWidth = MINLAY; + nDiff = nRight + nLeft + nCurWidth - m_pTableData->GetSpace() ; + //right aligned: only change the left margin + if (m_xRightBtn->get_active()) + nLeft -= nDiff; + //left aligned: only change the right margin + else if(m_xLeftBtn->get_active()) + nRight -= nDiff; + //left margin and width allowed - first right - then left + else if (m_xFromLeftBtn->get_active()) + { + if( nRight >= nDiff ) + nRight -= nDiff; + else + { + nDiff -= nRight; + nRight = 0; + if(nLeft >= nDiff) + nLeft -= nDiff; + else + { + nRight += nLeft - nDiff; + nLeft = 0; + nCurWidth = m_pTableData->GetSpace(); + } + } + } + //centered: change both sides equally + else if (m_xCenterBtn->get_active()) + { + if(nLeft != nRight) + { + nDiff += nLeft + nRight; + nLeft = nDiff/2; + nRight = nDiff/2; + } + else + { + nLeft -= nDiff/2; + nRight -= nDiff/2; + } + } + //free alignment: decrease both margins + else if (m_xFreeBtn->get_active()) + { + nLeft -= nDiff/2; + nRight -= nDiff/2; + } + } + if (&rEdit == m_xRightMF->get()) + { + + if( nRight + nLeft > m_pTableData->GetSpace() - MINLAY ) + nRight = m_pTableData->GetSpace() -nLeft - MINLAY; + + nCurWidth = m_pTableData->GetSpace() - nLeft - nRight; + } + if (&rEdit == m_xLeftMF->get()) + { + if(!m_xFromLeftBtn->get_active()) + { + bool bCenter = m_xCenterBtn->get_active(); + if( bCenter ) + nRight = nLeft; + if(nRight + nLeft > m_pTableData->GetSpace() - MINLAY ) + { + nLeft = bCenter ? (m_pTableData->GetSpace() - MINLAY) /2 : + (m_pTableData->GetSpace() - MINLAY) - nRight; + nRight = bCenter ? (m_pTableData->GetSpace() - MINLAY) /2 : nRight; + } + nCurWidth = m_pTableData->GetSpace() - nLeft - nRight; + } + else + { + //Upon changes on the left side the right margin will be changed at first, + //thereafter the width. + nDiff = nRight + nLeft + nCurWidth - m_pTableData->GetSpace() ; + + nRight -= nDiff; + nCurWidth = m_pTableData->GetSpace() - nLeft - nRight; + } + } + + m_xRightMF->set_value( m_xRightMF->NormalizePercent( nRight ), FieldUnit::TWIP ); + m_xLeftMF->set_value( m_xLeftMF->NormalizePercent( nLeft ), FieldUnit::TWIP ); + + if (nCurWidth != nPrevWidth ) + { + m_xWidthMF->set_value(m_xWidthMF->NormalizePercent(nCurWidth), FieldUnit::TWIP); + + // tdf#135021 if the user changed the width spinbutton, and in this + // ModifyHdl we changed the value of that width spinbutton, then rerun + // the ModifyHdl on the replaced value so the left/right/width value + // relationships are consistent. + // But (tdf#135693) only make one effort of rectifying the inconsistency + if (&rEdit == m_xWidthMF->get() && !bAllowInconsistencies) + ModifyHdl(rEdit, true); + } + + m_bModified = true; +} + +std::unique_ptr<SfxTabPage> SwFormatTablePage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwFormatTablePage>(pPage, pController, *rAttrSet); +} + +bool SwFormatTablePage::FillItemSet( SfxItemSet* rCoreSet ) +{ + //Test if one of the controls still has the focus + if (m_xWidthMF->has_focus()) + ModifyHdl(*m_xWidthMF->get()); + else if (m_xLeftMF->has_focus()) + ModifyHdl(*m_xLeftMF->get()); + else if (m_xRightMF->has_focus()) + ModifyHdl(*m_xRightMF->get()); + else if (m_xTopMF->has_focus()) + ModifyHdl(*m_xTopMF); + else if (m_xBottomMF->has_focus()) + ModifyHdl(*m_xBottomMF); + + if (m_bModified) + { + if (m_xBottomMF->get_value_changed_from_saved() || + m_xTopMF->get_value_changed_from_saved() ) + { + SvxULSpaceItem aULSpace(RES_UL_SPACE); + aULSpace.SetUpper(m_xTopMF->denormalize(m_xTopMF->get_value(FieldUnit::TWIP))); + aULSpace.SetLower(m_xBottomMF->denormalize(m_xBottomMF->get_value(FieldUnit::TWIP))); + rCoreSet->Put(aULSpace); + } + + } + if (m_xNameED->get_value_changed_from_saved()) + { + rCoreSet->Put(SfxStringItem(FN_PARAM_TABLE_NAME, m_xNameED->get_text())); + m_bModified = true; + } + + if (m_xTextDirectionLB->get_visible()) + { + if (m_xTextDirectionLB->get_value_changed_from_saved()) + { + SvxFrameDirection nDirection = m_xTextDirectionLB->get_active_id(); + rCoreSet->Put(SvxFrameDirectionItem(nDirection, RES_FRAMEDIR)); + m_bModified = true; + } + } + + return m_bModified; +} + +void SwFormatTablePage::Reset( const SfxItemSet* ) +{ + const SfxItemSet& rSet = GetItemSet(); + + if(m_bHtmlMode) + { + m_xNameED->set_sensitive(false); + m_xTopFT->hide(); + m_xTopMF->hide(); + m_xBottomFT->hide(); + m_xBottomMF->hide(); + m_xFreeBtn->set_sensitive(false); + } + + // set back to original state + m_xRelWidthCB->set_active(false); + m_xWidthMF->ShowPercent(false); + m_xLeftMF->ShowPercent(false); + m_xRightMF->ShowPercent(false); + m_xWidthMF->SetMetricFieldRange(m_nOrigWidthMin, m_nOrigWidthMax); + m_xLeftMF->SetMetricFieldRange(m_nOrigLeftMin, m_nOrigLeftMax); + m_xRightMF->SetMetricFieldRange(m_nOrigRightMin, m_nOrigRightMax); + + FieldUnit aMetric = ::GetDfltMetric(m_bHtmlMode); + m_xWidthMF->SetMetric(aMetric); + m_xRightMF->SetMetric(aMetric); + m_xLeftMF->SetMetric(aMetric); + SetFieldUnit(*m_xTopMF, aMetric); + SetFieldUnit(*m_xBottomMF, aMetric); + + //Name + if(const SfxStringItem* pNameItem = rSet.GetItemIfSet( FN_PARAM_TABLE_NAME, false )) + { + m_xNameED->set_text(pNameItem->GetValue()); + m_xNameED->save_value(); + } + + if(const SwPtrItem* pRepItem = rSet.GetItemIfSet( FN_TABLE_REP, false )) + { + m_pTableData = static_cast<SwTableRep*>( pRepItem->GetValue()); + if (!m_xOrigTableData) + m_xOrigTableData.reset(new SwTableRep(*m_pTableData)); + else // tdf#134925 and tdf#134913, reset back to the original data seen on dialog creation + *m_pTableData = *m_xOrigTableData; + + m_nMinTableWidth = m_pTableData->GetColCount() * MINLAY; + + if(m_pTableData->GetWidthPercent()) + { + m_xRelWidthCB->set_active(true); + RelWidthClickHdl(*m_xRelWidthCB); + m_xWidthMF->set_value(m_pTableData->GetWidthPercent(), FieldUnit::PERCENT); + + m_xWidthMF->save_value(); + m_nSaveWidth = static_cast< SwTwips >(m_xWidthMF->get_value(FieldUnit::PERCENT)); + } + else + { + m_xWidthMF->set_value(m_xWidthMF->NormalizePercent( + m_pTableData->GetWidth()), FieldUnit::TWIP); + m_xWidthMF->save_value(); + m_nSaveWidth = m_pTableData->GetWidth(); + m_nMinTableWidth = std::min( m_nSaveWidth, m_nMinTableWidth ); + } + + m_xWidthMF->SetRefValue(m_pTableData->GetSpace()); + + m_xLeftMF->set_value(m_xLeftMF->NormalizePercent( + m_pTableData->GetLeftSpace()), FieldUnit::TWIP); + m_xRightMF->set_value(m_xRightMF->NormalizePercent( + m_pTableData->GetRightSpace()), FieldUnit::TWIP); + m_xLeftMF->save_value(); + m_xRightMF->save_value(); + + bool bSetRight = false, bSetLeft = false; + switch( m_pTableData->GetAlign() ) + { + case text::HoriOrientation::NONE: + m_xFreeBtn->set_active(true); + if (m_xRelWidthCB->get_active()) + bSetRight = true; + break; + case text::HoriOrientation::FULL: + { + bSetRight = bSetLeft = true; + m_xFullBtn->set_active(true); + m_xWidthMF->set_sensitive(false); + m_xRelWidthCB->set_sensitive(false); + m_xWidthFT->set_sensitive(false); + } + break; + case text::HoriOrientation::LEFT: + { + bSetLeft = true; + m_xLeftBtn->set_active(true); + } + break; + case text::HoriOrientation::LEFT_AND_WIDTH : + { + bSetRight = true; + m_xFromLeftBtn->set_active(true); + } + break; + case text::HoriOrientation::RIGHT: + { + bSetRight = true; + m_xRightBtn->set_active(true); + } + break; + case text::HoriOrientation::CENTER: + { + bSetRight = true; + m_xCenterBtn->set_active(true); + } + break; + } + if ( bSetRight ) + { + m_xRightMF->set_sensitive(false); + m_xRightFT->set_sensitive(false); + } + if ( bSetLeft ) + { + m_xLeftMF->set_sensitive(false); + m_xLeftFT->set_sensitive(false); + } + + } + + //Margins + if(const SvxULSpaceItem* pSpaceItem = rSet.GetItemIfSet( RES_UL_SPACE, false )) + { + m_xTopMF->set_value(m_xTopMF->normalize( + pSpaceItem->GetUpper()), FieldUnit::TWIP); + m_xBottomMF->set_value(m_xBottomMF->normalize( + pSpaceItem->GetLower()), FieldUnit::TWIP); + m_xTopMF->save_value(); + m_xBottomMF->save_value(); + } + + //Text direction + if( const SvxFrameDirectionItem* pDirectionItem = rSet.GetItemIfSet( RES_FRAMEDIR ) ) + { + SvxFrameDirection nVal = pDirectionItem->GetValue(); + m_xTextDirectionLB->set_active_id(nVal); + m_xTextDirectionLB->save_value(); + } + + m_xWidthMF->set_max( 2*m_xWidthMF->NormalizePercent( m_pTableData->GetSpace() ), FieldUnit::TWIP ); + m_xRightMF->set_max( m_xRightMF->NormalizePercent( m_pTableData->GetSpace() ), FieldUnit::TWIP ); + m_xLeftMF->set_max( m_xLeftMF->NormalizePercent( m_pTableData->GetSpace() ), FieldUnit::TWIP ); + m_xWidthMF->set_min( m_xWidthMF->NormalizePercent( m_nMinTableWidth ), FieldUnit::TWIP ); +} + +void SwFormatTablePage::ActivatePage( const SfxItemSet& rSet ) +{ + OSL_ENSURE(m_pTableData, "table data not available?"); + if(SfxItemState::SET != rSet.GetItemState( FN_TABLE_REP )) + return; + + SwTwips nCurWidth = text::HoriOrientation::FULL != m_pTableData->GetAlign() ? + m_pTableData->GetWidth() : + m_pTableData->GetSpace(); + if(m_pTableData->GetWidthPercent() != 0 || + nCurWidth == m_xWidthMF->DenormalizePercent(m_xWidthMF->get_value(FieldUnit::TWIP))) + return; + + m_xWidthMF->set_value(m_xWidthMF->NormalizePercent( + nCurWidth), FieldUnit::TWIP); + m_xWidthMF->save_value(); + m_nSaveWidth = nCurWidth; + m_xLeftMF->set_value(m_xLeftMF->NormalizePercent( + m_pTableData->GetLeftSpace()), FieldUnit::TWIP); + m_xLeftMF->save_value(); + m_xRightMF->set_value(m_xRightMF->NormalizePercent( + m_pTableData->GetRightSpace()), FieldUnit::TWIP); + m_xRightMF->save_value(); +} + +DeactivateRC SwFormatTablePage::DeactivatePage( SfxItemSet* _pSet ) +{ + //test the table name for spaces + OUString sTableName = m_xNameED->get_text(); + if(sTableName.indexOf(' ') != -1) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_WRONG_TABLENAME))); + xInfoBox->run(); + m_xNameED->grab_focus(); + return DeactivateRC::KeepPage; + } + if(_pSet) + { + FillItemSet(_pSet); + if(m_bModified) + { + SwTwips lLeft = static_cast< SwTwips >(m_xLeftMF->DenormalizePercent(m_xLeftMF->get_value(FieldUnit::TWIP))); + SwTwips lRight = static_cast< SwTwips >(m_xRightMF->DenormalizePercent(m_xRightMF->get_value(FieldUnit::TWIP))); + + if( m_xLeftMF->get_value_changed_from_saved() || + m_xRightMF->get_value_changed_from_saved() ) + { + m_pTableData->SetWidthChanged(); + m_pTableData->SetLeftSpace( lLeft); + m_pTableData->SetRightSpace( lRight); + } + + SwTwips lWidth; + if (m_xRelWidthCB->get_active() && m_xRelWidthCB->get_sensitive()) + { + lWidth = m_pTableData->GetSpace() - lRight - lLeft; + const sal_uInt16 nPercentWidth = m_xWidthMF->get_value(FieldUnit::PERCENT); + if(m_pTableData->GetWidthPercent() != nPercentWidth) + { + m_pTableData->SetWidthPercent(nPercentWidth); + m_pTableData->SetWidthChanged(); + } + } + else + { + m_pTableData->SetWidthPercent(0); + lWidth = static_cast<SwTwips>(m_xWidthMF->DenormalizePercent(m_xWidthMF->get_value(FieldUnit::TWIP))); + } + m_pTableData->SetWidth(lWidth); + + SwTwips nColSum = 0; + + for( sal_uInt16 i = 0; i < m_pTableData->GetColCount(); i++) + { + nColSum += m_pTableData->GetColumns()[i].nWidth; + } + if(nColSum != m_pTableData->GetWidth()) + { + SwTwips nMinWidth = std::min( tools::Long(MINLAY), + static_cast<tools::Long>(m_pTableData->GetWidth() / + m_pTableData->GetColCount() - 1)); + SwTwips nDiff = nColSum - m_pTableData->GetWidth(); + while ( std::abs(nDiff) > m_pTableData->GetColCount() + 1 ) + { + SwTwips nSub = nDiff / m_pTableData->GetColCount(); + for( sal_uInt16 i = 0; i < m_pTableData->GetColCount(); i++) + { + if(m_pTableData->GetColumns()[i].nWidth - nMinWidth > nSub) + { + m_pTableData->GetColumns()[i].nWidth -= nSub; + nDiff -= nSub; + } + else + { + nDiff -= m_pTableData->GetColumns()[i].nWidth - nMinWidth; + m_pTableData->GetColumns()[i].nWidth = nMinWidth; + } + + } + } + } + + sal_Int16 nAlign = 0; + if (m_xRightBtn->get_active()) + nAlign = text::HoriOrientation::RIGHT; + else if(m_xLeftBtn->get_active()) + nAlign = text::HoriOrientation::LEFT; + else if(m_xFromLeftBtn->get_active()) + nAlign = text::HoriOrientation::LEFT_AND_WIDTH; + else if(m_xCenterBtn->get_active()) + nAlign = text::HoriOrientation::CENTER; + else if(m_xFreeBtn->get_active()) + nAlign = text::HoriOrientation::NONE; + else if(m_xFullBtn->get_active()) + { + nAlign = text::HoriOrientation::FULL; + lWidth = lAutoWidth; + } + if(nAlign != m_pTableData->GetAlign()) + { + m_pTableData->SetWidthChanged(); + m_pTableData->SetAlign(nAlign); + } + + if(m_pTableData->GetWidth() != lWidth ) + { + m_pTableData->SetWidthChanged(); + m_pTableData->SetWidth( + nAlign == text::HoriOrientation::FULL ? m_pTableData->GetSpace() : lWidth ); + } + if(m_pTableData->HasWidthChanged()) + _pSet->Put(SwPtrItem(FN_TABLE_REP, m_pTableData)); + } + } + return DeactivateRC::LeavePage; +} + +//Description: Page column configuration +SwTableColumnPage::SwTableColumnPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/tablecolumnpage.ui", "TableColumnPage", &rSet) + , m_pTableData(nullptr) + , m_pSizeHdlEvent(nullptr) + , m_nTableWidth(0) + , m_nMinWidth(MINLAY) + , m_nMetFields(MET_FIELDS) + , m_nNoOfCols(0) + , m_nNoOfVisibleCols(0) + , m_bModified(false) + , m_bModifyTable(false) + , m_bPercentMode(false) + , m_aFieldArr { m_xBuilder->weld_metric_spin_button("width1", FieldUnit::CM), + m_xBuilder->weld_metric_spin_button("width2", FieldUnit::CM), + m_xBuilder->weld_metric_spin_button("width3", FieldUnit::CM), + m_xBuilder->weld_metric_spin_button("width4", FieldUnit::CM), + m_xBuilder->weld_metric_spin_button("width5", FieldUnit::CM)} + , m_aTextArr { m_xBuilder->weld_label("1"), + m_xBuilder->weld_label("2"), + m_xBuilder->weld_label("3"), + m_xBuilder->weld_label("4"), + m_xBuilder->weld_label("5")} + , m_xModifyTableCB(m_xBuilder->weld_check_button("adaptwidth")) + , m_xProportionalCB(m_xBuilder->weld_check_button("adaptcolumns")) + , m_xSpaceFT(m_xBuilder->weld_label("spaceft")) + , m_xSpaceSFT(m_xBuilder->weld_label("space")) + , m_xSpaceED(m_xBuilder->weld_metric_spin_button("spacefmt", FieldUnit::CM)) + , m_xUpBtn(m_xBuilder->weld_button("next")) + , m_xDownBtn(m_xBuilder->weld_button("back")) +{ + SetExchangeSupport(); + + // fire off this handler to happen on next event loop when all the rest of + // the pages are instantiated and the dialog preferred size is that of the + // all the pages that currently exist and the rest to come after this one + m_pSizeHdlEvent = Application::PostUserEvent(LINK(this, SwTableColumnPage, SizeHdl)); + + const SfxUInt16Item* pModeItem = GetItemSet().GetItemIfSet(SID_HTML_MODE, false); + Init(pModeItem && pModeItem->GetValue() & HTMLMODE_ON); +} + +IMPL_LINK_NOARG(SwTableColumnPage, SizeHdl, void*, void) +{ + m_pSizeHdlEvent = nullptr; + + //tdf#120420 keeping showing column width fields unless + //the dialog begins to grow, then stop adding them + weld::Window* pTopLevel = GetFrameWeld(); + Size aOrigSize = pTopLevel->get_preferred_size(); + for (sal_uInt16 i = 0; i < MET_FIELDS; ++i) + { + m_aFieldArr[i].show(); + m_aTextArr[i]->show(); + + if (pTopLevel->get_preferred_size().Width() > aOrigSize.Width()) + { + m_nMetFields = i + 1; + m_aTextArr[i]->set_grid_width(1); + m_xUpBtn->set_grid_left_attach(m_nMetFields * 2 - 1); + break; + } + } + + // tdf#143142 m_nMetFields has been updated and we need to re-check whether to show right button or not. + if (m_nNoOfVisibleCols > m_nMetFields) + { + m_xUpBtn->set_sensitive(true); + } + +} + +SwTableColumnPage::~SwTableColumnPage() +{ + if (m_pSizeHdlEvent) + { + Application::RemoveUserEvent(m_pSizeHdlEvent); + m_pSizeHdlEvent = nullptr; + } +} + +std::unique_ptr<SfxTabPage> SwTableColumnPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwTableColumnPage>(pPage, pController, *rAttrSet); +} + +void SwTableColumnPage::Reset( const SfxItemSet* ) +{ + const SfxItemSet& rSet = GetItemSet(); + + if(const SwPtrItem* pRepItem = rSet.GetItemIfSet( FN_TABLE_REP, false )) + { + m_pTableData = static_cast<SwTableRep*>( pRepItem->GetValue()); + if (!m_xOrigTableData) + m_xOrigTableData.reset(new SwTableRep(*m_pTableData)); + else // tdf#134925 and tdf#134913, reset back to the original data seen on dialog creation + *m_pTableData = *m_xOrigTableData; + + m_nNoOfVisibleCols = m_pTableData->GetColCount(); + m_nNoOfCols = m_pTableData->GetAllColCount(); + m_nTableWidth = m_pTableData->GetAlign() != text::HoriOrientation::FULL && + m_pTableData->GetAlign() != text::HoriOrientation::LEFT_AND_WIDTH? + m_pTableData->GetWidth() : m_pTableData->GetSpace(); + + for( sal_uInt16 i = 0; i < m_nNoOfCols; i++ ) + { + if (m_pTableData->GetColumns()[i].nWidth < m_nMinWidth) + m_nMinWidth = m_pTableData->GetColumns()[i].nWidth; + } + sal_Int64 nMinTwips = m_aFieldArr[0].NormalizePercent( m_nMinWidth ); + sal_Int64 nMaxTwips = m_aFieldArr[0].NormalizePercent( m_nTableWidth ); + for( sal_uInt16 i = 0; (i < m_nMetFields) && (i < m_nNoOfVisibleCols); i++ ) + { + m_aFieldArr[i].set_value( m_aFieldArr[i].NormalizePercent( + GetVisibleWidth(i) ), FieldUnit::TWIP ); + m_aFieldArr[i].set_min(nMinTwips, FieldUnit::TWIP); + m_aFieldArr[i].set_max(nMaxTwips, FieldUnit::TWIP); + m_aFieldArr[i].set_sensitive(true); + m_aTextArr[i]->set_sensitive(true); + } + + if (m_nNoOfVisibleCols > m_nMetFields) + { + m_xUpBtn->set_sensitive(true); + } + + for( sal_uInt16 i = m_nNoOfVisibleCols; i < m_nMetFields; ++i ) + { + m_aFieldArr[i].set_text(OUString()); + m_aTextArr[i]->set_sensitive(false); + } + } + ActivatePage(rSet); +} + +void SwTableColumnPage::Init(bool bWeb) +{ + FieldUnit aMetric = ::GetDfltMetric(bWeb); + Link<weld::MetricSpinButton&,void> aLk = LINK(this, SwTableColumnPage, ValueChangedHdl); + for (sal_uInt16 i = 0; i < MET_FIELDS; ++i) + { + m_aValueTable[i] = i; + m_aFieldArr[i].SetMetric(aMetric); + m_aFieldArr[i].connect_value_changed(aLk); + } + SetFieldUnit(*m_xSpaceED, aMetric); + + Link<weld::Button&,void> aClickLk = LINK(this, SwTableColumnPage, AutoClickHdl); + m_xUpBtn->connect_clicked(aClickLk); + m_xDownBtn->connect_clicked(aClickLk); + + Link<weld::Toggleable&,void> aToggleLk = LINK(this, SwTableColumnPage, ModeHdl); + m_xModifyTableCB->connect_toggled(aToggleLk); + m_xProportionalCB->connect_toggled(aToggleLk); +} + +IMPL_LINK(SwTableColumnPage, AutoClickHdl, weld::Button&, rControl, void) +{ + //move display window + if (&rControl == m_xDownBtn.get()) + { + if(m_aValueTable[0] > 0) + { + for(sal_uInt16 & rn : m_aValueTable) + rn -= 1; + } + } + if (&rControl == m_xUpBtn.get()) + { + if( m_aValueTable[ m_nMetFields -1 ] < m_nNoOfVisibleCols -1 ) + { + for(sal_uInt16 & rn : m_aValueTable) + rn += 1; + } + } + for( sal_uInt16 i = 0; (i < m_nNoOfVisibleCols ) && ( i < m_nMetFields); i++ ) + { + OUString sEntry('~'); + OUString sIndex = OUString::number( m_aValueTable[i] + 1 ); + sEntry += sIndex; + m_aTextArr[i]->set_label(sEntry); + } + + m_xDownBtn->set_sensitive(m_aValueTable[0] > 0); + m_xUpBtn->set_sensitive(m_aValueTable[ m_nMetFields -1 ] < m_nNoOfVisibleCols -1 ); + UpdateCols(0); +} + +IMPL_LINK(SwTableColumnPage, ValueChangedHdl, weld::MetricSpinButton&, rEdit, void) +{ + m_bModified = true; + ModifyHdl(&rEdit); +} + +IMPL_LINK(SwTableColumnPage, ModeHdl, weld::Toggleable&, rBox, void) +{ + const bool bCheck = rBox.get_active(); + if (&rBox == m_xProportionalCB.get()) + { + if (bCheck) + m_xModifyTableCB->set_active(true); + m_xModifyTableCB->set_sensitive(!bCheck && m_bModifyTable); + } +} + +bool SwTableColumnPage::FillItemSet( SfxItemSet* ) +{ + for (SwPercentField & i : m_aFieldArr) + { + if (i.has_focus()) + { + ModifyHdl(i.get()); + break; + } + } + + if (m_bModified) + { + m_pTableData->SetColsChanged(); + } + return m_bModified; +} + +void SwTableColumnPage::ModifyHdl(const weld::MetricSpinButton* pField) +{ + SwPercentField *pEdit = nullptr; + sal_uInt16 i; + + for( i = 0; i < m_nMetFields; i++) + { + if (pField == m_aFieldArr[i].get()) + { + pEdit = &m_aFieldArr[i]; + break; + } + } + + if (m_nMetFields <= i || !pEdit) + { + OSL_ENSURE(false, "cannot happen."); + return; + } + + SetVisibleWidth(m_aValueTable[i], pEdit->DenormalizePercent(pEdit->get_value(FieldUnit::TWIP))); + + UpdateCols( m_aValueTable[i] ); +} + +void SwTableColumnPage::UpdateCols( sal_uInt16 nCurrentPos ) +{ + SwTwips nSum = 0; + + for( sal_uInt16 i = 0; i < m_nNoOfCols; i++ ) + { + nSum += (m_pTableData->GetColumns())[i].nWidth; + } + SwTwips nDiff = nSum - m_nTableWidth; + + bool bModifyTableChecked = m_xModifyTableCB->get_active(); + bool bProp = m_xProportionalCB->get_active(); + + if (!bModifyTableChecked && !bProp) + { + //The table width is constant, the difference is balanced with the other columns + sal_uInt16 nLoopCount = 0; + while( nDiff ) + { + if( ++nCurrentPos == m_nNoOfVisibleCols) + { + nCurrentPos = 0; + ++nLoopCount; + //#i101353# in small tables it might not be possible to balance column width + if( nLoopCount > 1 ) + break; + } + if( nDiff < 0 ) + { + SetVisibleWidth(nCurrentPos, GetVisibleWidth(nCurrentPos) -nDiff); + nDiff = 0; + } + else if( GetVisibleWidth(nCurrentPos) >= nDiff + m_nMinWidth ) + { + SetVisibleWidth(nCurrentPos, GetVisibleWidth(nCurrentPos) -nDiff); + nDiff = 0; + } + if( nDiff > 0 && GetVisibleWidth(nCurrentPos) > m_nMinWidth ) + { + if( nDiff >= (GetVisibleWidth(nCurrentPos) - m_nMinWidth) ) + { + nDiff -= (GetVisibleWidth(nCurrentPos) - m_nMinWidth); + SetVisibleWidth(nCurrentPos, m_nMinWidth); + } + else + { + nDiff = 0; + SetVisibleWidth(nCurrentPos, GetVisibleWidth(nCurrentPos) -nDiff); + } + OSL_ENSURE(nDiff >= 0, "nDiff < 0 cannot be here!"); + } + } + } + else if (bModifyTableChecked && !bProp) + { + //Difference is balanced by the width of the table, + //other columns remain unchanged. + OSL_ENSURE(nDiff <= m_pTableData->GetSpace() - m_nTableWidth, "wrong maximum" ); + SwTwips nActSpace = m_pTableData->GetSpace() - m_nTableWidth; + if(nDiff > nActSpace) + { + m_nTableWidth = m_pTableData->GetSpace(); + SetVisibleWidth(nCurrentPos, GetVisibleWidth(nCurrentPos) - nDiff + nActSpace ); + } + else + { + m_nTableWidth += nDiff; + } + } + else if (bModifyTableChecked && bProp) + { + //All columns will be changed proportionally with, + //the table width is adjusted accordingly. + const double fOrigColWidth = std::max(SwTwips(1), GetVisibleWidth(nCurrentPos) - nDiff); + const double fMaxWidth = std::max(m_pTableData->GetSpace(), m_nTableWidth); + const double fMaxPercent = fMaxWidth / m_nTableWidth; + const double fPercentChange = std::min(fMaxPercent, GetVisibleWidth(nCurrentPos)/fOrigColWidth); + SwTwips nNewTableSize = 0; + for( sal_uInt16 i = 0; i < m_nNoOfVisibleCols; i++ ) + { + SwTwips nNewColWidth = round( fPercentChange * (i == nCurrentPos ? fOrigColWidth : GetVisibleWidth(i)) ); + if ( nNewColWidth < MINLAY ) + nNewColWidth = MINLAY; + SetVisibleWidth(i, nNewColWidth); + nNewTableSize += nNewColWidth; + } + m_nTableWidth = nNewTableSize; + } + + if (!m_bPercentMode) + { + m_xSpaceED->set_value(m_xSpaceED->normalize(m_pTableData->GetSpace() - m_nTableWidth), FieldUnit::TWIP); + m_xSpaceSFT->set_label(m_xSpaceED->get_text()); + } + else + m_xSpaceSFT->set_label(OUString()); + + for( sal_uInt16 i = 0; ( i < m_nNoOfVisibleCols ) && ( i < m_nMetFields ); i++) + { + m_aFieldArr[i].set_value(m_aFieldArr[i].NormalizePercent( + GetVisibleWidth(m_aValueTable[i]) ), FieldUnit::TWIP); + } +} + +void SwTableColumnPage::ActivatePage( const SfxItemSet& ) +{ + m_bPercentMode = m_pTableData->GetWidthPercent() != 0; + for( sal_uInt16 i = 0; (i < m_nMetFields) && (i < m_nNoOfVisibleCols); i++ ) + { + m_aFieldArr[i].SetRefValue(m_pTableData->GetWidth()); + m_aFieldArr[i].ShowPercent( m_bPercentMode ); + } + + const sal_uInt16 nTableAlign = m_pTableData->GetAlign(); + if((text::HoriOrientation::FULL != nTableAlign && m_nTableWidth != m_pTableData->GetWidth()) || + (text::HoriOrientation::FULL == nTableAlign && m_nTableWidth != m_pTableData->GetSpace())) + { + m_nTableWidth = text::HoriOrientation::FULL == nTableAlign ? + m_pTableData->GetSpace() : + m_pTableData->GetWidth(); + UpdateCols(0); + } + m_bModifyTable = true; + if (m_pTableData->GetWidthPercent() || + text::HoriOrientation::FULL == nTableAlign || + m_pTableData->IsLineSelected() ) + m_bModifyTable = false; + if (m_bPercentMode) + { + m_xModifyTableCB->set_active(false); + m_xProportionalCB->set_active(false); + } + else if (!m_bModifyTable) + { + m_xProportionalCB->set_active(false); + m_xModifyTableCB->set_active(false); + } + m_xSpaceFT->set_sensitive(!m_bPercentMode); + m_xSpaceSFT->set_sensitive(!m_bPercentMode); + m_xModifyTableCB->set_sensitive( !m_bPercentMode && m_bModifyTable ); + m_xProportionalCB->set_sensitive(!m_bPercentMode && m_bModifyTable ); + + m_xSpaceED->set_value(m_xSpaceED->normalize( + m_pTableData->GetSpace() - m_nTableWidth), FieldUnit::TWIP); + m_xSpaceSFT->set_label(m_xSpaceED->get_text()); + +} + +DeactivateRC SwTableColumnPage::DeactivatePage( SfxItemSet* _pSet ) +{ + if(_pSet) + { + FillItemSet(_pSet); + if(text::HoriOrientation::FULL != m_pTableData->GetAlign() && m_pTableData->GetWidth() != m_nTableWidth) + { + m_pTableData->SetWidth(m_nTableWidth); + SwTwips nDiff = m_pTableData->GetSpace() - m_pTableData->GetWidth() - + m_pTableData->GetLeftSpace() - m_pTableData->GetRightSpace(); + switch( m_pTableData->GetAlign() ) + { + case text::HoriOrientation::RIGHT: + m_pTableData->SetLeftSpace(m_pTableData->GetLeftSpace() + nDiff); + break; + case text::HoriOrientation::LEFT: + m_pTableData->SetRightSpace(m_pTableData->GetRightSpace() + nDiff); + break; + case text::HoriOrientation::NONE: + { + SwTwips nDiff2 = nDiff/2; + if( nDiff > 0 || + (-nDiff2 < m_pTableData->GetRightSpace() && - nDiff2 < m_pTableData->GetLeftSpace())) + { + m_pTableData->SetRightSpace(m_pTableData->GetRightSpace() + nDiff2); + m_pTableData->SetLeftSpace(m_pTableData->GetLeftSpace() + nDiff2); + } + else + { + if(m_pTableData->GetRightSpace() > m_pTableData->GetLeftSpace()) + { + m_pTableData->SetLeftSpace(0); + m_pTableData->SetRightSpace(m_pTableData->GetSpace() - m_pTableData->GetWidth()); + } + else + { + m_pTableData->SetRightSpace(0); + m_pTableData->SetLeftSpace(m_pTableData->GetSpace() - m_pTableData->GetWidth()); + } + } + } + break; + case text::HoriOrientation::CENTER: + m_pTableData->SetRightSpace(m_pTableData->GetRightSpace() + nDiff/2); + m_pTableData->SetLeftSpace(m_pTableData->GetLeftSpace() + nDiff/2); + break; + case text::HoriOrientation::LEFT_AND_WIDTH : + if(nDiff > m_pTableData->GetRightSpace()) + { + m_pTableData->SetLeftSpace(m_pTableData->GetSpace() - m_pTableData->GetWidth()); + } + m_pTableData->SetRightSpace( + m_pTableData->GetSpace() - m_pTableData->GetWidth() - m_pTableData->GetLeftSpace()); + break; + } + m_pTableData->SetWidthChanged(); + } + _pSet->Put(SwPtrItem( FN_TABLE_REP, m_pTableData )); + } + return DeactivateRC::LeavePage; +} + +SwTwips SwTableColumnPage::GetVisibleWidth(sal_uInt16 nPos) +{ + sal_uInt16 i=0; + + while( nPos ) + { + if(m_pTableData->GetColumns()[i].bVisible) + nPos--; + i++; + } + SwTwips nReturn = m_pTableData->GetColumns()[i].nWidth; + OSL_ENSURE(i < m_nNoOfCols, "Array index out of range"); + while(!m_pTableData->GetColumns()[i].bVisible && (i + 1) < m_nNoOfCols) + nReturn += m_pTableData->GetColumns()[++i].nWidth; + + return nReturn; +} + +void SwTableColumnPage::SetVisibleWidth(sal_uInt16 nPos, SwTwips nNewWidth) +{ + sal_uInt16 i=0; + while( nPos ) + { + if(m_pTableData->GetColumns()[i].bVisible) + nPos--; + i++; + } + OSL_ENSURE(i < m_nNoOfCols, "Array index out of range"); + m_pTableData->GetColumns()[i].nWidth = nNewWidth; + while(!m_pTableData->GetColumns()[i].bVisible && (i + 1) < m_nNoOfCols) + m_pTableData->GetColumns()[++i].nWidth = 0; + +} + +SwTableTabDlg::SwTableTabDlg(weld::Window* pParent, const SfxItemSet* pItemSet, SwWrtShell* pSh) + : SfxTabDialogController(pParent, "modules/swriter/ui/tableproperties.ui", "TablePropertiesDialog", pItemSet) + , m_pShell(pSh) +{ + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + AddTabPage("table", &SwFormatTablePage::Create, nullptr); + AddTabPage("textflow", &SwTextFlowPage::Create, nullptr); + AddTabPage("columns", &SwTableColumnPage::Create, nullptr); + AddTabPage("background", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_BKG), nullptr); + AddTabPage("borders", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_BORDER), nullptr); +} + +void SwTableTabDlg::PageCreated(const OUString& rId, SfxTabPage& rPage) +{ + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + if (rId == "background") + { + SvxBackgroundTabFlags const nFlagType = SvxBackgroundTabFlags::SHOW_TBLCTL; + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE, static_cast<sal_uInt32>(nFlagType))); + rPage.PageCreated(aSet); + } + else if (rId == "borders") + { + aSet.Put (SfxUInt16Item(SID_SWMODE_TYPE, static_cast<sal_uInt16>(SwBorderModes::TABLE))); + rPage.PageCreated(aSet); + } + else if (rId == "textflow") + { + static_cast<SwTextFlowPage&>(rPage).SetShell(m_pShell); + const FrameTypeFlags eType = m_pShell->GetFrameType(nullptr,true); + if( !(FrameTypeFlags::BODY & eType) ) + static_cast<SwTextFlowPage&>(rPage).DisablePageBreak(); + } +} + +SwTextFlowPage::SwTextFlowPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet) + : SfxTabPage(pPage, pController, "modules/swriter/ui/tabletextflowpage.ui", "TableTextFlowPage", &rSet) + , m_pShell(nullptr) + , m_bPageBreak(true) + , m_bHtmlMode(false) + , m_xPgBrkCB(m_xBuilder->weld_check_button("break")) + , m_xPgBrkRB(m_xBuilder->weld_radio_button("page")) + , m_xColBrkRB(m_xBuilder->weld_radio_button("column")) + , m_xPgBrkBeforeRB(m_xBuilder->weld_radio_button("before")) + , m_xPgBrkAfterRB(m_xBuilder->weld_radio_button("after")) + , m_xPageCollCB(m_xBuilder->weld_check_button("pagestyle")) + , m_xPageCollLB(m_xBuilder->weld_combo_box("pagestylelb")) + , m_xPageNoCB(m_xBuilder->weld_check_button("pagenoft")) + , m_xPageNoNF(m_xBuilder->weld_spin_button("pagenonf")) + , m_xSplitCB(m_xBuilder->weld_check_button("split")) + , m_xSplitRowCB(m_xBuilder->weld_check_button("splitrow")) + , m_xKeepCB(m_xBuilder->weld_check_button("keep")) + , m_xHeadLineCB(m_xBuilder->weld_check_button("headline")) + , m_xRepeatHeaderCombo(m_xBuilder->weld_widget("repeatheader")) + , m_xRepeatHeaderNF(m_xBuilder->weld_spin_button("repeatheadernf")) + , m_xTextDirectionLB(m_xBuilder->weld_combo_box("textorientation")) + , m_xVertOrientLB(m_xBuilder->weld_combo_box("vertorient")) +{ + m_xPgBrkCB->connect_toggled(LINK(this, SwTextFlowPage, PageBreakHdl_Impl)); + m_xPgBrkBeforeRB->connect_toggled( + LINK(this, SwTextFlowPage, PageBreakPosHdl_Impl)); + m_xPgBrkAfterRB->connect_toggled( + LINK(this, SwTextFlowPage, PageBreakPosHdl_Impl)); + m_xPageCollCB->connect_toggled( + LINK(this, SwTextFlowPage, ApplyCollClickHdl_Impl)); + m_xColBrkRB->connect_toggled( + LINK(this, SwTextFlowPage, PageBreakTypeHdl_Impl)); + m_xPgBrkRB->connect_toggled( + LINK(this, SwTextFlowPage, PageBreakTypeHdl_Impl)); + m_xPageNoCB->connect_toggled( + LINK(this, SwTextFlowPage, PageNoClickHdl_Impl)); + m_xSplitCB->connect_toggled( + LINK(this, SwTextFlowPage, SplitHdl_Impl)); + m_xHeadLineCB->connect_toggled(LINK(this, SwTextFlowPage, HeadLineCBClickHdl)); + + const SfxUInt16Item *pModeItem = rSet.GetItemIfSet( SID_HTML_MODE, false ); + if(pModeItem && pModeItem->GetValue() & HTMLMODE_ON) + { + m_xKeepCB->hide(); + m_xSplitCB->hide(); + m_xSplitRowCB->hide(); + } + + HeadLineCBClickHdl(*m_xHeadLineCB); +} + +SwTextFlowPage::~SwTextFlowPage() +{ +} + +std::unique_ptr<SfxTabPage> SwTextFlowPage::Create(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<SwTextFlowPage>(pPage, pController, *rAttrSet); +} + +bool SwTextFlowPage::FillItemSet( SfxItemSet* rSet ) +{ + bool bModified = false; + + //Repeat Heading + if (m_xHeadLineCB->get_state_changed_from_saved() || + m_xRepeatHeaderNF->get_value_changed_from_saved() ) + { + bModified |= nullptr != rSet->Put( + SfxUInt16Item(FN_PARAM_TABLE_HEADLINE, m_xHeadLineCB->get_active() ? sal_uInt16(m_xRepeatHeaderNF->get_value()) : 0)); + } + if (m_xKeepCB->get_state_changed_from_saved()) + bModified |= nullptr != rSet->Put( SvxFormatKeepItem( m_xKeepCB->get_active(), RES_KEEP)); + + if (m_xSplitCB->get_state_changed_from_saved()) + bModified |= nullptr != rSet->Put( SwFormatLayoutSplit( m_xSplitCB->get_active())); + + if (m_xSplitRowCB->get_state_changed_from_saved()) + bModified |= nullptr != rSet->Put( SwFormatRowSplit( m_xSplitRowCB->get_active())); + + const SvxFormatBreakItem* pBreak = GetOldItem( *rSet, RES_BREAK ); + const SwFormatPageDesc* pDesc = GetOldItem( *rSet, RES_PAGEDESC ); + + bool bState = m_xPageCollCB->get_active(); + + //If we have a page style, then there's no break + bool bPageItemPut = false; + if ( bState != (m_xPageCollCB->get_saved_state() == TRISTATE_TRUE) + || (bState && m_xPageCollLB->get_value_changed_from_saved()) + || (m_xPageNoCB->get_sensitive() && m_xPageNoCB->get_state_changed_from_saved()) + || (m_xPageNoNF->get_sensitive() && m_xPageNoNF->get_value_changed_from_saved())) + { + OUString sPage; + + if ( bState ) + { + sPage = m_xPageCollLB->get_active_text(); + } + sal_uInt16 nPgNum = o3tl::narrowing<sal_uInt16>(m_xPageNoNF->get_value()); + bool const usePageNo(bState && m_xPageNoCB->get_active()); + std::optional<sal_uInt16> const oPageNum( + usePageNo ? nPgNum : std::optional<sal_Int16>()); + if (!pDesc || !pDesc->GetPageDesc() + || (pDesc->GetPageDesc()->GetName() != sPage) + || (pDesc->GetNumOffset() != oPageNum)) + { + SwFormatPageDesc aFormat( m_pShell->FindPageDescByName( sPage, true ) ); + aFormat.SetNumOffset(oPageNum); + bModified |= nullptr != rSet->Put( aFormat ); + bPageItemPut = bState; + } + } + bool bIsChecked = m_xPgBrkCB->get_active(); + if ( !bPageItemPut && + ( bState != (m_xPageCollCB->get_saved_state() == TRISTATE_TRUE) || + bIsChecked != (m_xPgBrkCB->get_saved_state() == TRISTATE_TRUE) || + m_xPgBrkBeforeRB->get_state_changed_from_saved() || + m_xPgBrkRB->get_state_changed_from_saved() )) + { + SvxFormatBreakItem aBreak( GetItemSet().Get( RES_BREAK ) ); + + if(bIsChecked) + { + bool bBefore = m_xPgBrkBeforeRB->get_active(); + + if (m_xPgBrkRB->get_active()) + { + if ( bBefore ) + aBreak.SetValue( SvxBreak::PageBefore ); + else + aBreak.SetValue( SvxBreak::PageAfter ); + } + else + { + if ( bBefore ) + aBreak.SetValue( SvxBreak::ColumnBefore ); + else + aBreak.SetValue( SvxBreak::ColumnAfter ); + } + } + else + { + aBreak.SetValue( SvxBreak::NONE ); + } + + if ( !pBreak || !( *pBreak == aBreak ) ) + { + bModified |= nullptr != rSet->Put( aBreak ); + } + } + + if (m_xTextDirectionLB->get_value_changed_from_saved()) + { + OUString sId = m_xTextDirectionLB->get_active_id(); + bModified |= nullptr != rSet->Put(SvxFrameDirectionItem(static_cast<SvxFrameDirection>(sId.toUInt32()), FN_TABLE_BOX_TEXTORIENTATION)); + } + + if (m_xVertOrientLB->get_value_changed_from_saved()) + { + sal_uInt16 nOrient = USHRT_MAX; + switch (m_xVertOrientLB->get_active()) + { + case 0 : nOrient = text::VertOrientation::NONE; break; + case 1 : nOrient = text::VertOrientation::CENTER; break; + case 2 : nOrient = text::VertOrientation::BOTTOM; break; + } + if (nOrient != USHRT_MAX) + bModified |= nullptr != rSet->Put(SfxUInt16Item(FN_TABLE_SET_VERT_ALIGN, nOrient)); + } + + return bModified; + +} + +void SwTextFlowPage::Reset( const SfxItemSet* rSet ) +{ + bool bFlowAllowed = !m_bHtmlMode || officecfg::Office::Common::Filter::HTML::Export::PrintLayout::get(); + if(bFlowAllowed) + { + //Inserting of the existing page templates in the list box + const size_t nCount = m_pShell->GetPageDescCnt(); + + for( size_t i = 0; i < nCount; ++i) + { + const SwPageDesc &rPageDesc = m_pShell->GetPageDesc(i); + m_xPageCollLB->append_text(rPageDesc.GetName()); + } + + OUString aFormatName; + for (sal_uInt16 i = RES_POOLPAGE_BEGIN; i < RES_POOLPAGE_END; ++i) + { + aFormatName = SwStyleNameMapper::GetUIName(i, aFormatName); + if (m_xPageCollLB->find_text(aFormatName) == -1) + m_xPageCollLB->append_text(aFormatName); + } + + if(const SvxFormatKeepItem* pKeepItem = rSet->GetItemIfSet( RES_KEEP, false )) + { + m_xKeepCB->set_active( pKeepItem->GetValue() ); + m_xKeepCB->save_state(); + } + if(const SwFormatLayoutSplit* pSplitItem = rSet->GetItemIfSet( RES_LAYOUT_SPLIT, false )) + { + m_xSplitCB->set_active( pSplitItem->GetValue() ); + } + else + m_xSplitCB->set_active(true); + + m_xSplitCB->save_state(); + SplitHdl_Impl(*m_xSplitCB); + + if(const SwFormatRowSplit* pSplitItem = rSet->GetItemIfSet( RES_ROW_SPLIT, false )) + { + m_xSplitRowCB->set_active( pSplitItem->GetValue() ); + } + else + m_xSplitRowCB->set_state(TRISTATE_INDET); + m_xSplitRowCB->save_state(); + + if(m_bPageBreak) + { + if(const SwFormatPageDesc* pPageDescItem = rSet->GetItemIfSet( RES_PAGEDESC, false )) + { + OUString sPageDesc; + const SwPageDesc* pDesc = pPageDescItem->GetPageDesc(); + + ::std::optional<sal_uInt16> oNumOffset = pPageDescItem->GetNumOffset(); + if (oNumOffset) + { + m_xPageNoCB->set_active(true); + m_xPageNoNF->set_sensitive(true); + m_xPageNoNF->set_value(*oNumOffset); + } + else + { + m_xPageNoCB->set_active(false); + m_xPageNoNF->set_sensitive(false); + } + + if(pDesc) + sPageDesc = pDesc->GetName(); + if (!sPageDesc.isEmpty() && m_xPageCollLB->find_text(sPageDesc) != -1) + { + m_xPageCollLB->set_active_text(sPageDesc); + m_xPageCollCB->set_active(true); + + m_xPgBrkCB->set_sensitive(true); + m_xPgBrkRB->set_sensitive(true); + m_xColBrkRB->set_sensitive(true); + m_xPgBrkBeforeRB->set_sensitive(true); + m_xPgBrkAfterRB->set_sensitive(true); + m_xPageCollCB->set_sensitive(true); + + m_xPgBrkCB->set_active(true); + m_xColBrkRB->set_active( false ); + m_xPgBrkBeforeRB->set_active(true); + m_xPgBrkAfterRB->set_active( false ); + } + else + { + m_xPageCollLB->set_active(-1); + m_xPageCollCB->set_active(false); + } + } + + if(const SvxFormatBreakItem* pPageBreak = rSet->GetItemIfSet( RES_BREAK, false )) + { + SvxBreak eBreak = pPageBreak->GetBreak(); + + if ( eBreak != SvxBreak::NONE ) + { + m_xPgBrkCB->set_active(true); + m_xPageCollCB->set_sensitive(false); + m_xPageCollLB->set_sensitive(false); + m_xPageNoCB->set_sensitive(false); + m_xPageNoNF->set_sensitive(false); + } + switch ( eBreak ) + { + case SvxBreak::PageBefore: + m_xPgBrkRB->set_active(true); + m_xColBrkRB->set_active( false ); + m_xPgBrkBeforeRB->set_active(true); + m_xPgBrkAfterRB->set_active( false ); + break; + case SvxBreak::PageAfter: + m_xPgBrkRB->set_active(true); + m_xColBrkRB->set_active( false ); + m_xPgBrkBeforeRB->set_active( false ); + m_xPgBrkAfterRB->set_active(true); + break; + case SvxBreak::ColumnBefore: + m_xPgBrkRB->set_active( false ); + m_xColBrkRB->set_active(true); + m_xPgBrkBeforeRB->set_active(true); + m_xPgBrkAfterRB->set_active( false ); + break; + case SvxBreak::ColumnAfter: + m_xPgBrkRB->set_active( false ); + m_xColBrkRB->set_active(true); + m_xPgBrkBeforeRB->set_active( false ); + m_xPgBrkAfterRB->set_active(true); + break; + default:; //prevent warning + } + + } + if (m_xPgBrkBeforeRB->get_active()) + PageBreakPosHdl_Impl(*m_xPgBrkBeforeRB); + else if (m_xPgBrkAfterRB->get_active()) + PageBreakPosHdl_Impl(*m_xPgBrkAfterRB); + PageBreakHdl_Impl(*m_xPgBrkCB); + } + } + else + { + m_xPgBrkRB->set_sensitive(false); + m_xColBrkRB->set_sensitive(false); + m_xPgBrkBeforeRB->set_sensitive(false); + m_xPgBrkAfterRB->set_sensitive(false); + m_xKeepCB->set_sensitive(false); + m_xSplitCB->set_sensitive(false); + m_xPgBrkCB->set_sensitive(false); + m_xPageCollCB->set_sensitive(false); + m_xPageCollLB->set_sensitive(false); + } + + if(const SfxUInt16Item* pHeadlineItem = rSet->GetItemIfSet( FN_PARAM_TABLE_HEADLINE, false )) + { + sal_uInt16 nRep = pHeadlineItem->GetValue(); + m_xHeadLineCB->set_active(nRep > 0); + m_xHeadLineCB->save_state(); + m_xRepeatHeaderNF->set_value(nRep); + m_xRepeatHeaderNF->set_min(1); + m_xRepeatHeaderNF->save_value(); + } + if ( rSet->GetItemState(FN_TABLE_BOX_TEXTORIENTATION) > SfxItemState::DEFAULT ) + { + SvxFrameDirection nDirection = rSet->Get(FN_TABLE_BOX_TEXTORIENTATION).GetValue(); + m_xTextDirectionLB->set_active_id(OUString::number(static_cast<sal_uInt32>(nDirection))); + } + + if ( rSet->GetItemState(FN_TABLE_SET_VERT_ALIGN) > SfxItemState::DEFAULT ) + { + sal_uInt16 nVert = rSet->Get(FN_TABLE_SET_VERT_ALIGN).GetValue(); + sal_uInt16 nPos = 0; + switch(nVert) + { + case text::VertOrientation::NONE: nPos = 0; break; + case text::VertOrientation::CENTER: nPos = 1; break; + case text::VertOrientation::BOTTOM: nPos = 2; break; + } + m_xVertOrientLB->set_active(nPos); + } + + m_xPageCollCB->save_state(); + m_xPageCollLB->save_value(); + m_xPgBrkCB->save_state(); + m_xPgBrkRB->save_state(); + m_xColBrkRB->save_state(); + m_xPgBrkBeforeRB->save_state(); + m_xPgBrkAfterRB->save_state(); + m_xPageNoCB->save_state(); + m_xPageNoNF->save_value(); + m_xTextDirectionLB->save_value(); + m_xVertOrientLB->save_value(); + + HeadLineCBClickHdl(*m_xHeadLineCB); +} + +void SwTextFlowPage::SetShell(SwWrtShell* pSh) +{ + m_pShell = pSh; + m_bHtmlMode = 0 != (::GetHtmlMode(m_pShell->GetView().GetDocShell()) & HTMLMODE_ON); + if(m_bHtmlMode) + { + m_xPageNoNF->set_sensitive(false); + m_xPageNoCB->set_sensitive(false); + } +} + +IMPL_LINK_NOARG(SwTextFlowPage, PageBreakHdl_Impl, weld::Toggleable&, void) +{ + if (m_xPgBrkCB->get_active()) + { + m_xPgBrkRB->set_sensitive(true); + m_xColBrkRB->set_sensitive(true); + m_xPgBrkBeforeRB->set_sensitive(true); + m_xPgBrkAfterRB->set_sensitive(true); + + if (m_xPgBrkRB->get_active() && m_xPgBrkBeforeRB->get_active()) + { + m_xPageCollCB->set_sensitive(true); + + bool bEnable = m_xPageCollCB->get_active() && m_xPageCollLB->get_count(); + m_xPageCollLB->set_sensitive(bEnable); + if (!m_bHtmlMode) + { + m_xPageNoCB->set_sensitive(bEnable); + m_xPageNoNF->set_sensitive(bEnable && m_xPageNoCB->get_active()); + } + } + } + else + { + m_xPageCollCB->set_active(false); + m_xPageCollCB->set_sensitive(false); + m_xPageCollLB->set_sensitive(false); + m_xPageNoCB->set_sensitive(false); + m_xPageNoNF->set_sensitive(false); + m_xPgBrkRB->set_sensitive(false); + m_xColBrkRB->set_sensitive(false); + m_xPgBrkBeforeRB->set_sensitive(false); + m_xPgBrkAfterRB->set_sensitive(false); + } +} + +IMPL_LINK_NOARG(SwTextFlowPage, ApplyCollClickHdl_Impl, weld::Toggleable&, void) +{ + bool bEnable = false; + if (m_xPageCollCB->get_active() && m_xPageCollLB->get_count()) + { + bEnable = true; + m_xPageCollLB->set_active(0); + } + else + { + m_xPageCollLB->set_active(-1); + } + m_xPageCollLB->set_sensitive(bEnable); + if (!m_bHtmlMode) + { + m_xPageNoCB->set_sensitive(bEnable); + m_xPageNoNF->set_sensitive(bEnable && m_xPageNoCB->get_active()); + } +} + +IMPL_LINK_NOARG(SwTextFlowPage, PageBreakPosHdl_Impl, weld::Toggleable&, void) +{ + if (!m_xPgBrkCB->get_active()) + return; + + if (m_xPgBrkBeforeRB->get_active() && m_xPgBrkRB->get_active()) + { + m_xPageCollCB->set_sensitive(true); + + bool bEnable = m_xPageCollCB->get_active() && m_xPageCollLB->get_count(); + + m_xPageCollLB->set_sensitive(bEnable); + if (!m_bHtmlMode) + { + m_xPageNoCB->set_sensitive(bEnable); + m_xPageNoNF->set_sensitive(bEnable && m_xPageNoCB->get_active()); + } + } + else if (m_xPgBrkAfterRB->get_active()) + { + m_xPageCollCB->set_active(false); + m_xPageCollCB->set_sensitive(false); + m_xPageCollLB->set_sensitive(false); + m_xPageNoCB->set_sensitive(false); + m_xPageNoNF->set_sensitive(false); + } +} + +IMPL_LINK_NOARG(SwTextFlowPage, PageBreakTypeHdl_Impl, weld::Toggleable&, void) +{ + if (m_xColBrkRB->get_active() || m_xPgBrkAfterRB->get_active()) + { + m_xPageCollCB->set_active(false); + m_xPageCollCB->set_sensitive(false); + m_xPageCollLB->set_sensitive(false); + m_xPageNoCB->set_sensitive(false); + m_xPageNoNF->set_sensitive(false); + } + else if (m_xPgBrkBeforeRB->get_active()) + PageBreakPosHdl_Impl(*m_xPgBrkBeforeRB); +} + +IMPL_LINK_NOARG(SwTextFlowPage, PageNoClickHdl_Impl, weld::Toggleable&, void) +{ + m_xPageNoNF->set_sensitive(m_xPageNoCB->get_active()); +} + +IMPL_LINK(SwTextFlowPage, SplitHdl_Impl, weld::Toggleable&, rBox, void) +{ + m_xSplitRowCB->set_sensitive(rBox.get_active()); +} + +IMPL_LINK_NOARG(SwTextFlowPage, HeadLineCBClickHdl, weld::Toggleable&, void) +{ + m_xRepeatHeaderCombo->set_sensitive(m_xHeadLineCB->get_active()); +} + +void SwTextFlowPage::DisablePageBreak() +{ + m_bPageBreak = false; + m_xPgBrkCB->set_sensitive(false); + m_xPgBrkRB->set_sensitive(false); + m_xColBrkRB->set_sensitive(false); + m_xPgBrkBeforeRB->set_sensitive(false); + m_xPgBrkAfterRB->set_sensitive(false); + m_xPageCollCB->set_sensitive(false); + m_xPageCollLB->set_sensitive(false); + m_xPageNoCB->set_sensitive(false); + m_xPageNoNF->set_sensitive(false); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/table/tautofmt.cxx b/sw/source/ui/table/tautofmt.cxx new file mode 100644 index 0000000000..8dbc965e80 --- /dev/null +++ b/sw/source/ui/table/tautofmt.cxx @@ -0,0 +1,408 @@ +/* -*- 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 <memory> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <sal/log.hxx> +#include <strings.hrc> +#include <shellres.hxx> +#include <tautofmt.hxx> + +namespace { + +class SwStringInputDlg : public SfxDialogController +{ +private: + std::unique_ptr<weld::Label> m_xLabel; + std::unique_ptr<weld::Entry> m_xEdInput; // Edit obtains the focus. + +public: + SwStringInputDlg(weld::Window* pParent, const OUString& rTitle, + const OUString& rEditTitle, const OUString& rDefault) + : SfxDialogController(pParent, "modules/swriter/ui/stringinput.ui", + "StringInputDialog") + , m_xLabel(m_xBuilder->weld_label("name")) + , m_xEdInput(m_xBuilder->weld_entry("edit")) + { + m_xLabel->set_label(rEditTitle); + m_xDialog->set_title(rTitle); + m_xEdInput->set_text(rDefault); + m_xEdInput->select_region(0, -1); + } + + OUString GetInputString() const + { + return m_xEdInput->get_text(); + } +}; + +} + +// AutoFormat-Dialogue: +SwAutoFormatDlg::SwAutoFormatDlg(weld::Window* pParent, SwWrtShell* pWrtShell, + bool bAutoFormat, const SwTableAutoFormat* pSelFormat) + : SfxDialogController(pParent, "modules/swriter/ui/autoformattable.ui", + "AutoFormatTableDialog") + , m_aStrTitle(SwResId(STR_ADD_AUTOFORMAT_TITLE)) + , m_aStrLabel(SwResId(STR_ADD_AUTOFORMAT_LABEL)) + , m_aStrClose(SwResId(STR_BTN_AUTOFORMAT_CLOSE)) + , m_aStrDelTitle(SwResId(STR_DEL_AUTOFORMAT_TITLE)) + , m_aStrDelMsg(SwResId(STR_DEL_AUTOFORMAT_MSG)) + , m_aStrRenameTitle(SwResId(STR_RENAME_AUTOFORMAT_TITLE)) + , m_aStrInvalidFormat(SwResId(STR_INVALID_AUTOFORMAT_NAME)) + , m_pShell(pWrtShell) + , m_nIndex(0) + , m_nDfltStylePos(0) + , m_bCoreDataChanged(false) + , m_bSetAutoFormat(bAutoFormat) + , m_xTableTable(new SwTableAutoFormatTable) + , m_xLbFormat(m_xBuilder->weld_tree_view("formatlb")) + , m_xBtnNumFormat(m_xBuilder->weld_check_button("numformatcb")) + , m_xBtnBorder(m_xBuilder->weld_check_button("bordercb")) + , m_xBtnFont(m_xBuilder->weld_check_button("fontcb")) + , m_xBtnPattern(m_xBuilder->weld_check_button("patterncb")) + , m_xBtnAlignment(m_xBuilder->weld_check_button("alignmentcb")) + , m_xBtnCancel(m_xBuilder->weld_button("cancel")) + , m_xBtnAdd(m_xBuilder->weld_button("add")) + , m_xBtnRemove(m_xBuilder->weld_button("remove")) + , m_xBtnRename(m_xBuilder->weld_button("rename")) + , m_xWndPreview(new weld::CustomWeld(*m_xBuilder, "preview", m_aWndPreview)) +{ + m_aWndPreview.DetectRTL(pWrtShell); + m_xTableTable->Load(); + + const int nWidth = m_xLbFormat->get_approximate_digit_width() * 32; + const int nHeight = m_xLbFormat->get_height_rows(8); + m_xLbFormat->set_size_request(nWidth, nHeight); + m_xWndPreview->set_size_request(nWidth, nHeight); + + Init(pSelFormat); +} + +SwAutoFormatDlg::~SwAutoFormatDlg() +{ + try + { + if (m_bCoreDataChanged) + m_xTableTable->Save(); + } + catch (...) + { + } + m_xTableTable.reset(); +} + +void SwAutoFormatDlg::Init( const SwTableAutoFormat* pSelFormat ) +{ + Link<weld::Toggleable&, void> aLk(LINK(this, SwAutoFormatDlg, CheckHdl)); + m_xBtnBorder->connect_toggled(aLk); + m_xBtnFont->connect_toggled(aLk); + m_xBtnPattern->connect_toggled(aLk); + m_xBtnAlignment->connect_toggled(aLk); + m_xBtnNumFormat->connect_toggled(aLk); + + m_xBtnAdd->connect_clicked(LINK(this, SwAutoFormatDlg, AddHdl)); + m_xBtnRemove->connect_clicked(LINK(this, SwAutoFormatDlg, RemoveHdl)); + m_xBtnRename->connect_clicked(LINK(this, SwAutoFormatDlg, RenameHdl)); + m_xLbFormat->connect_changed(LINK(this, SwAutoFormatDlg, SelFormatHdl)); + + m_xBtnAdd->set_sensitive(m_bSetAutoFormat); + + m_nIndex = 0; + if( !m_bSetAutoFormat ) + { + // Then the list to be expanded by the entry "- none -". + m_xLbFormat->append_text(SwViewShell::GetShellRes()->aStrNone); + m_nDfltStylePos = 1; + m_nIndex = 255; + } + + for (sal_uInt8 i = 0, nCount = static_cast<sal_uInt8>(m_xTableTable->size()); + i < nCount; i++) + { + SwTableAutoFormat const& rFormat = (*m_xTableTable)[ i ]; + m_xLbFormat->append_text(rFormat.GetName()); + if (pSelFormat && rFormat.GetName() == pSelFormat->GetName()) + m_nIndex = i; + } + + m_xLbFormat->select(255 != m_nIndex ? (m_nDfltStylePos + m_nIndex) : 0); + SelFormatHdl(*m_xLbFormat); +} + +void SwAutoFormatDlg::UpdateChecks( const SwTableAutoFormat& rFormat, bool bEnable ) +{ + m_xBtnNumFormat->set_sensitive(bEnable); + m_xBtnNumFormat->set_active(rFormat.IsValueFormat()); + + m_xBtnBorder->set_sensitive(bEnable); + m_xBtnBorder->set_active(rFormat.IsFrame()); + + m_xBtnFont->set_sensitive(bEnable); + m_xBtnFont->set_active(rFormat.IsFont()); + + m_xBtnPattern->set_sensitive(bEnable); + m_xBtnPattern->set_active(rFormat.IsBackground()); + + m_xBtnAlignment->set_sensitive(bEnable); + m_xBtnAlignment->set_active(rFormat.IsJustify()); +} + +std::unique_ptr<SwTableAutoFormat> SwAutoFormatDlg::FillAutoFormatOfIndex() const +{ + if( 255 != m_nIndex ) + { + return std::make_unique<SwTableAutoFormat>( (*m_xTableTable)[ m_nIndex ] ); + } + + return nullptr; +} + +// Handler: +IMPL_LINK(SwAutoFormatDlg, CheckHdl, weld::Toggleable&, rBtn, void) +{ + if (m_nIndex == 255) + return; + + SwTableAutoFormat& rData = (*m_xTableTable)[m_nIndex]; + bool bCheck = rBtn.get_active(), bDataChgd = true; + + if (&rBtn == m_xBtnNumFormat.get()) + rData.SetValueFormat( bCheck ); + else if (&rBtn == m_xBtnBorder.get()) + rData.SetFrame( bCheck ); + else if (&rBtn == m_xBtnFont.get()) + rData.SetFont( bCheck ); + else if (&rBtn == m_xBtnPattern.get()) + rData.SetBackground( bCheck ); + else if (&rBtn == m_xBtnAlignment.get()) + rData.SetJustify( bCheck ); + else + bDataChgd = false; + + if( bDataChgd ) + { + if( !m_bCoreDataChanged ) + { + m_xBtnCancel->set_label(m_aStrClose); + m_bCoreDataChanged = true; + } + + m_aWndPreview.NotifyChange(rData); + } +} + +IMPL_LINK_NOARG(SwAutoFormatDlg, AddHdl, weld::Button&, void) +{ + bool bOk = false, bFormatInserted = false; + while( !bOk ) + { + SwStringInputDlg aDlg(m_xDialog.get(), m_aStrTitle, m_aStrLabel, OUString()); + if (RET_OK == aDlg.run()) + { + const OUString aFormatName(aDlg.GetInputString()); + + if ( !aFormatName.isEmpty() ) + { + size_t n; + for( n = 0; n < m_xTableTable->size(); ++n ) + if( (*m_xTableTable)[n].GetName() == aFormatName ) + break; + + if( n >= m_xTableTable->size() ) + { + // Format with the name does not already exist, so take up. + std::unique_ptr<SwTableAutoFormat> pNewData( + new SwTableAutoFormat(aFormatName)); + bool bGetOk = m_pShell->GetTableAutoFormat( *pNewData ); + SAL_WARN_IF(!bGetOk, "sw.ui", "GetTableAutoFormat failed for: " << aFormatName); + + // Insert sorted!! + for( n = 1; n < m_xTableTable->size(); ++n ) + if( (*m_xTableTable)[ n ].GetName() > aFormatName ) + break; + + m_xTableTable->InsertAutoFormat(n, std::move(pNewData)); + m_xLbFormat->insert_text(m_nDfltStylePos + n, aFormatName); + m_xLbFormat->select(m_nDfltStylePos + n); + bFormatInserted = true; + m_xBtnAdd->set_sensitive(false); + if ( !m_bCoreDataChanged ) + { + m_xBtnCancel->set_label(m_aStrClose); + m_bCoreDataChanged = true; + } + + SelFormatHdl(*m_xLbFormat); + bOk = true; + } + } + + if( !bFormatInserted ) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Error, VclButtonsType::OkCancel, m_aStrInvalidFormat)); + bOk = RET_CANCEL == xBox->run(); + } + } + else + bOk = true; + } +} + +IMPL_LINK_NOARG(SwAutoFormatDlg, RemoveHdl, weld::Button&, void) +{ + OUString aMessage = m_aStrDelMsg + "\n\n" + + m_xLbFormat->get_selected_text() + "\n"; + + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Question, + VclButtonsType::OkCancel, m_aStrDelTitle)); + xBox->set_secondary_text(aMessage); + + if (xBox->run() == RET_OK) + { + sal_uInt8 nIndex = m_nIndex; + + m_xLbFormat->remove(m_nDfltStylePos + nIndex); + m_xLbFormat->select(m_nDfltStylePos + nIndex - 1); + + m_xTableTable->EraseAutoFormat(nIndex); + m_nIndex = nIndex - 1; + + if( !m_nIndex ) + { + m_xBtnRemove->set_sensitive(false); + m_xBtnRename->set_sensitive(false); + } + + if( !m_bCoreDataChanged ) + { + m_xBtnCancel->set_label(m_aStrClose); + m_bCoreDataChanged = true; + } + } + + SelFormatHdl(*m_xLbFormat); +} + +IMPL_LINK_NOARG(SwAutoFormatDlg, RenameHdl, weld::Button&, void) +{ + bool bOk = false; + while( !bOk ) + { + SwStringInputDlg aDlg(m_xDialog.get(), m_aStrRenameTitle, m_aStrLabel, m_xLbFormat->get_selected_text()); + if (aDlg.run() == RET_OK) + { + bool bFormatRenamed = false; + const OUString aFormatName(aDlg.GetInputString()); + + if ( !aFormatName.isEmpty() ) + { + size_t n; + for( n = 0; n < m_xTableTable->size(); ++n ) + if ((*m_xTableTable)[n].GetName() == aFormatName) + break; + + if( n >= m_xTableTable->size() ) + { + sal_uInt8 nIndex = m_nIndex; + + // no format with this name exists, so rename it + m_xLbFormat->remove(m_nDfltStylePos + nIndex); + std::unique_ptr<SwTableAutoFormat> p( + m_xTableTable->ReleaseAutoFormat(nIndex)); + + p->SetName( aFormatName ); + + // keep all arrays sorted! + for( n = 1; n < m_xTableTable->size(); ++n ) + if ((*m_xTableTable)[n].GetName() > aFormatName) + { + break; + } + + m_xTableTable->InsertAutoFormat( n, std::move(p) ); + m_xLbFormat->insert_text(m_nDfltStylePos + n, aFormatName); + m_xLbFormat->select(m_nDfltStylePos + n); + + if ( !m_bCoreDataChanged ) + { + m_xBtnCancel->set_label(m_aStrClose); + m_bCoreDataChanged = true; + } + + SelFormatHdl(*m_xLbFormat); + bOk = true; + bFormatRenamed = true; + } + } + + if( !bFormatRenamed ) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Error, VclButtonsType::OkCancel, m_aStrInvalidFormat)); + bOk = RET_CANCEL == xBox->run(); + } + } + else + bOk = true; + } +} + +IMPL_LINK_NOARG(SwAutoFormatDlg, SelFormatHdl, weld::TreeView&, void) +{ + bool bBtnEnable = false; + sal_uInt8 nOldIdx = m_nIndex; + int nSelPos = m_xLbFormat->get_selected_index(); + if (nSelPos >= m_nDfltStylePos) + { + m_nIndex = nSelPos - m_nDfltStylePos; + m_aWndPreview.NotifyChange((*m_xTableTable)[m_nIndex]); + bBtnEnable = 0 != m_nIndex; + UpdateChecks( (*m_xTableTable)[m_nIndex], true ); + } + else + { + m_nIndex = 255; + + SwTableAutoFormat aTmp( SwViewShell::GetShellRes()->aStrNone ); + aTmp.SetFont( false ); + aTmp.SetJustify( false ); + aTmp.SetFrame( false ); + aTmp.SetBackground( false ); + aTmp.SetValueFormat( false ); + aTmp.SetWidthHeight( false ); + + if (nOldIdx != m_nIndex) + m_aWndPreview.NotifyChange(aTmp); + UpdateChecks( aTmp, false ); + } + + m_xBtnRemove->set_sensitive(bBtnEnable); + m_xBtnRename->set_sensitive(bBtnEnable); +} + +short SwAutoFormatDlg::run() +{ + short nRet = SfxDialogController::run(); + if (nRet == RET_OK && m_bSetAutoFormat) + m_pShell->SetTableStyle((*m_xTableTable)[m_nIndex]); + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/uno/swdetect.cxx b/sw/source/ui/uno/swdetect.cxx new file mode 100644 index 0000000000..83b7162ae2 --- /dev/null +++ b/sw/source/ui/uno/swdetect.cxx @@ -0,0 +1,171 @@ +/* -*- 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 "swdetect.hxx" + +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <sfx2/docfile.hxx> +#include <sot/storage.hxx> +#include <tools/urlobj.hxx> +#include <unotools/mediadescriptor.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using utl::MediaDescriptor; + +SwFilterDetect::SwFilterDetect() +{ +} + +SwFilterDetect::~SwFilterDetect() +{ +} + +OUString SAL_CALL SwFilterDetect::detect( Sequence< PropertyValue >& lDescriptor ) +{ + MediaDescriptor aMediaDesc( lDescriptor ); + OUString aTypeName = aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_TYPENAME, OUString() ); + uno::Reference< io::XInputStream > xInStream ( aMediaDesc[MediaDescriptor::PROP_INPUTSTREAM], uno::UNO_QUERY ); + if ( !xInStream.is() ) + return OUString(); + + SfxMedium aMedium; + aMedium.UseInteractionHandler( false ); + aMedium.setStreamToLoadFrom( xInStream, true ); + + SvStream *pInStrm = aMedium.GetInStream(); + if ( !pInStrm || pInStrm->GetError() ) + return OUString(); + + bool bIsDetected = false; + + if ( aTypeName == "writer_Rich_Text_Format" ) + { + pInStrm->Seek( STREAM_SEEK_TO_BEGIN ); + bIsDetected = ( read_uInt8s_ToOString( *pInStrm, 5 ) == "{\\rtf" ); + } + else if ( aTypeName == "writer_MS_WinWord_5" ) + { + pInStrm->Seek( STREAM_SEEK_TO_BEGIN ); + const sal_uInt8 nBufSize = 3; + sal_uInt8 nBuffer[ nBufSize ]; + if (pInStrm->ReadBytes(nBuffer, nBufSize) < nBufSize) + return OUString(); + + bIsDetected = (nBuffer[0] == 0x9B && nBuffer[1] == 0xA5 && nBuffer[2] == 0x21) // WinWord 1 + || (nBuffer[0] == 0x9C && nBuffer[1] == 0xA5 && nBuffer[2] == 0x21) // PMWord 1 + || (nBuffer[0] == 0xDB && nBuffer[1] == 0xA5 && nBuffer[2] == 0x2D) // WinWord 2 + || (nBuffer[0] == 0xDC && nBuffer[1] == 0xA5 && nBuffer[2] == 0x65); // WinWord 6.0/95, as a single stream file + } + else + { + // Do not attempt to create an SotStorage on a + // 0-length stream as that would create the compound + // document header on the stream and effectively write to + // disk! + pInStrm->Seek( STREAM_SEEK_TO_BEGIN ); + if ( pInStrm->remainingSize() == 0 ) + return OUString(); + + try + { + tools::SvRef<SotStorage> aStorage = new SotStorage ( pInStrm, false ); + if ( !aStorage->GetError() ) + { + bIsDetected = aStorage->IsContained( "WordDocument" ); + if ( bIsDetected && aTypeName.startsWith( "writer_MS_Word_97" ) ) + { + bIsDetected = ( aStorage->IsContained("0Table") || aStorage->IsContained("1Table") ); + + // If we are checking the template type, and the document is not a .dot, don't + // mis-detect it. + if ( bIsDetected && aTypeName == "writer_MS_Word_97_Vorlage" ) + { + // It is common practice to rename a .doc to .dot to make it a template. + // Since we have detected a.doc-ish format, always accept .dot-named-files + // as valid templates to avoid flagging this as an invalid .dot format.. + INetURLObject aParser(aMediaDesc.getUnpackedValueOrDefault( + utl::MediaDescriptor::PROP_URL, OUString())); + + // Super ugly hack, but we don't want to use the whole WW8Fib thing here in + // the swd library, apparently. We know (do we?) that the "aBits1" byte, as + // the variable is called in WW8Fib::WW8Fib(SvStream&,sal_uInt8,sal_uInt32), + // is at offset 10 in the WordDocument stream. The fDot bit is bit 0x01 of + // that byte. + if (aParser.getExtension().toAsciiLowerCase() != "dot") + { + tools::SvRef<SotStorageStream> xWordDocument + = aStorage->OpenSotStream("WordDocument", StreamMode::STD_READ); + xWordDocument->Seek(10); + if (xWordDocument->Tell() == 10) + { + sal_uInt8 aBits1; + xWordDocument->ReadUChar(aBits1); + // Check fDot bit + bIsDetected = ((aBits1 & 0x01) == 0x01); + } + } + } + } + } + } + catch (...) + { + bIsDetected = false; + } + } + + if ( bIsDetected ) + return aTypeName; + + return OUString(); +} + +/* XServiceInfo */ +OUString SAL_CALL SwFilterDetect::getImplementationName() +{ + return "com.sun.star.comp.writer.FormatDetector"; +} + +/* XServiceInfo */ +sal_Bool SAL_CALL SwFilterDetect::supportsService( const OUString& sServiceName ) +{ + return cppu::supportsService(this, sServiceName); +} + +/* XServiceInfo */ +Sequence< OUString > SAL_CALL SwFilterDetect::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ExtendedTypeDetection", "com.sun.star.text.FormatDetector", "com.sun.star.text.W4WFormatDetector" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_writer_FormatDetector_get_implementation(css::uno::XComponentContext*, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new SwFilterDetect()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/uno/swdetect.hxx b/sw/source/ui/uno/swdetect.hxx new file mode 100644 index 0000000000..a72521004a --- /dev/null +++ b/sw/source/ui/uno/swdetect.hxx @@ -0,0 +1,51 @@ +/* -*- 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_UNO_SWDETECT_HXX +#define INCLUDED_SW_SOURCE_UI_UNO_SWDETECT_HXX + +#include <rtl/ustring.hxx> +#include <com/sun/star/document/XExtendedFilterDetection.hpp> +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> + +namespace com::sun::star::beans { struct PropertyValue; } + +class SfxMedium; +class SfxFilter; +class SfxMedium; + +class SwFilterDetect : public ::cppu::WeakImplHelper< css::document::XExtendedFilterDetection, css::lang::XServiceInfo > +{ +public: + SwFilterDetect(); + virtual ~SwFilterDetect() override; + + /* XServiceInfo */ + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& sServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XExtendedFilterDetect + virtual OUString SAL_CALL detect( css::uno::Sequence< css::beans::PropertyValue >& lDescriptor ) override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/utlui/swrenamexnameddlg.cxx b/sw/source/ui/utlui/swrenamexnameddlg.cxx new file mode 100644 index 0000000000..4bcf29d3c3 --- /dev/null +++ b/sw/source/ui/utlui/swrenamexnameddlg.cxx @@ -0,0 +1,78 @@ +/* -*- 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 <osl/diagnose.h> + +#include <swrenamexnameddlg.hxx> + +using namespace ::com::sun::star; + +SwRenameXNamedDlg::SwRenameXNamedDlg(weld::Widget* pParent, + uno::Reference< container::XNamed > & xN, + uno::Reference< container::XNameAccess > & xNA ) + : GenericDialogController(pParent, "modules/swriter/ui/renameobjectdialog.ui", "RenameObjectDialog") + , m_xNamed(xN) + , m_xNameAccess(xNA) + , m_xNewNameED(m_xBuilder->weld_entry("entry")) + , m_xOk(m_xBuilder->weld_button("ok")) +{ + m_xNewNameED->connect_insert_text(LINK(this, SwRenameXNamedDlg, TextFilterHdl)); + + OUString sTmp(m_xDialog->get_title()); + m_xNewNameED->set_text(m_xNamed->getName()); + m_xNewNameED->select_region(0, -1); + sTmp += m_xNamed->getName(); + m_xDialog->set_title(sTmp); + + m_xOk->connect_clicked(LINK(this, SwRenameXNamedDlg, OkHdl)); + m_xNewNameED->connect_changed(LINK(this, SwRenameXNamedDlg, ModifyHdl)); + m_xOk->set_sensitive(false); +} + +IMPL_LINK(SwRenameXNamedDlg, TextFilterHdl, OUString&, rTest, bool) +{ + rTest = m_aTextFilter.filter(rTest); + return true; +} + +IMPL_LINK_NOARG(SwRenameXNamedDlg, OkHdl, weld::Button&, void) +{ + try + { + m_xNamed->setName(m_xNewNameED->get_text()); + } + catch (const uno::RuntimeException&) + { + OSL_FAIL("name wasn't changed"); + } + m_xDialog->response(RET_OK); +} + +IMPL_LINK(SwRenameXNamedDlg, ModifyHdl, weld::Entry&, rEdit, void) +{ + OUString sTmp(rEdit.get_text()); + + m_xOk->set_sensitive(!sTmp.isEmpty() + && !m_xNameAccess->hasByName(sTmp) + && (!m_xSecondAccess.is() || !m_xSecondAccess->hasByName(sTmp)) + && (!m_xThirdAccess.is() || !m_xThirdAccess->hasByName(sTmp)) + ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaaddin.cxx b/sw/source/ui/vba/vbaaddin.cxx new file mode 100644 index 0000000000..8fdfb00480 --- /dev/null +++ b/sw/source/ui/vba/vbaaddin.cxx @@ -0,0 +1,92 @@ +/* -*- 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 "vbaaddin.hxx" +#include <tools/urlobj.hxx> +#include <osl/file.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaAddin::SwVbaAddin( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, OUString aFileURL ) : + SwVbaAddin_BASE( rParent, rContext ), msFileURL(std::move( aFileURL )), mbInstalled( true ) +{ +} + +SwVbaAddin::~SwVbaAddin() +{ +} + +OUString SAL_CALL SwVbaAddin::getName() +{ + OUString sName; + INetURLObject aURL( msFileURL ); + ::osl::File::getSystemPathFromFileURL( aURL.GetLastName(), sName ); + return sName; +} + +void SAL_CALL +SwVbaAddin::setName( const OUString& ) +{ + throw uno::RuntimeException(" Fail to set name" ); +} + +OUString SAL_CALL SwVbaAddin::getPath() +{ + INetURLObject aURL( msFileURL ); + aURL.CutLastName(); + return aURL.GetURLPath(); +} + +sal_Bool SAL_CALL SwVbaAddin::getAutoload() +{ + return true; +} + +sal_Bool SAL_CALL SwVbaAddin::getInstalled() +{ + return mbInstalled; +} + +void SAL_CALL SwVbaAddin::setInstalled( sal_Bool _installed ) +{ + if( bool(_installed) != mbInstalled ) + { + mbInstalled = _installed; + // TODO: should call AutoExec and AutoExit etc. + } +} + +OUString +SwVbaAddin::getServiceImplName() +{ + return "SwVbaAddin"; +} + +uno::Sequence< OUString > +SwVbaAddin::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Addin" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaaddin.hxx b/sw/source/ui/vba/vbaaddin.hxx new file mode 100644 index 0000000000..f177e7935d --- /dev/null +++ b/sw/source/ui/vba/vbaaddin.hxx @@ -0,0 +1,53 @@ +/* -*- 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_VBA_VBAADDIN_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAADDIN_HXX + +#include <ooo/vba/word/XAddin.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XAddin> SwVbaAddin_BASE; + +class SwVbaAddin : public SwVbaAddin_BASE +{ +private: + OUString msFileURL; + bool mbInstalled; + +public: + /// @throws css::uno::RuntimeException + SwVbaAddin(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext, OUString aFileURL); + virtual ~SwVbaAddin() override; + + // Attributes + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName(const OUString& _name) override; + virtual OUString SAL_CALL getPath() override; + virtual sal_Bool SAL_CALL getAutoload() override; + virtual sal_Bool SAL_CALL getInstalled() override; + virtual void SAL_CALL setInstalled(sal_Bool _installed) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAADDIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaaddins.cxx b/sw/source/ui/vba/vbaaddins.cxx new file mode 100644 index 0000000000..6fd6e42f86 --- /dev/null +++ b/sw/source/ui/vba/vbaaddins.cxx @@ -0,0 +1,96 @@ +/* -*- 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 "vbaaddins.hxx" +#include "vbaaddin.hxx" +#include <unotools/pathoptions.hxx> +#include <sal/log.hxx> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> +#include <com/sun/star/ucb/SimpleFileAccess.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +static uno::Reference< container::XIndexAccess > lcl_getAddinCollection( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext ) +{ + XNamedObjectCollectionHelper< word::XAddin >::XNamedVec aAddins; + + // first get the autoload addins in the directory STARTUP + uno::Reference< lang::XMultiComponentFactory > xMCF( xContext->getServiceManager(), uno::UNO_SET_THROW ); + uno::Reference<ucb::XSimpleFileAccess3> xSFA(ucb::SimpleFileAccess::create(xContext)); + SvtPathOptions aPathOpt; + // FIXME: temporary the STARTUP path is located in $OO/basic3.1/program/addin + const OUString& aAddinPath = aPathOpt.GetAddinPath(); + SAL_INFO("sw.vba", "lcl_getAddinCollection: " << aAddinPath ); + if( xSFA->isFolder( aAddinPath ) ) + { + const uno::Sequence< OUString > sEntries = xSFA->getFolderContents( aAddinPath, false ); + for( const OUString& sUrl : sEntries ) + { + if( !xSFA->isFolder( sUrl ) && sUrl.endsWithIgnoreAsciiCase( ".dot" ) ) + { + aAddins.push_back( uno::Reference< word::XAddin >( new SwVbaAddin( xParent, xContext, sUrl ) ) ); + } + } + } + + // TODO: second get the customize addins in the org.openoffice.Office.Writer/GlobalTemplateList + + uno::Reference< container::XIndexAccess > xAddinsAccess( new XNamedObjectCollectionHelper< word::XAddin >( std::move(aAddins) ) ); + return xAddinsAccess; +} + +SwVbaAddins::SwVbaAddins( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext ): SwVbaAddins_BASE( xParent, xContext, lcl_getAddinCollection( xParent,xContext ) ) +{ +} +// XEnumerationAccess +uno::Type +SwVbaAddins::getElementType() +{ + return cppu::UnoType<word::XAddin>::get(); +} +uno::Reference< container::XEnumeration > +SwVbaAddins::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumerationAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return xEnumerationAccess->createEnumeration(); +} + +uno::Any +SwVbaAddins::createCollectionObject( const css::uno::Any& aSource ) +{ + return aSource; +} + +OUString +SwVbaAddins::getServiceImplName() +{ + return "SwVbaAddins"; +} + +css::uno::Sequence<OUString> +SwVbaAddins::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.Addins" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaaddins.hxx b/sw/source/ui/vba/vbaaddins.hxx new file mode 100644 index 0000000000..0072b36d5a --- /dev/null +++ b/sw/source/ui/vba/vbaaddins.hxx @@ -0,0 +1,46 @@ +/* -*- 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_VBA_VBAADDINS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAADDINS_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XAddins.hpp> + +typedef CollTestImplHelper<ooo::vba::word::XAddins> SwVbaAddins_BASE; + +class SwVbaAddins : public SwVbaAddins_BASE +{ +public: + /// @throws css::uno::RuntimeException + SwVbaAddins(const css::uno::Reference<ov::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override; + + // SwVbaAddins_BASE + virtual css::uno::Any createCollectionObject(const css::uno::Any& aSource) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAADDINS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaapplication.cxx b/sw/source/ui/vba/vbaapplication.cxx new file mode 100644 index 0000000000..d3f290db28 --- /dev/null +++ b/sw/source/ui/vba/vbaapplication.cxx @@ -0,0 +1,529 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column:100 -*- */ +/* + * 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 <com/sun/star/task/XStatusIndicatorSupplier.hpp> +#include <com/sun/star/task/XStatusIndicator.hpp> +#include <com/sun/star/util/thePathSettings.hpp> +#include <com/sun/star/awt/XDevice.hpp> + +#include "vbaapplication.hxx" +#include "vbadocument.hxx" +#include "vbafilterpropsfromformat.hxx" +#include <sal/log.hxx> +#include <osl/file.hxx> +#include <vcl/svapp.hxx> +#include <vbahelper/vbahelper.hxx> +#include "vbawindow.hxx" +#include "vbasystem.hxx" +#include "vbaoptions.hxx" +#include "vbaselection.hxx" +#include "vbadocuments.hxx" +#include "vbaaddins.hxx" +#include "vbamailmerge.hxx" +#include "vbadialogs.hxx" +#include "vbawordbasic.hxx" +#include <ooo/vba/XConnectionPoint.hpp> +#include <ooo/vba/word/WdEnableCancelKey.hpp> +#include <ooo/vba/word/WdWindowState.hpp> +#include <ooo/vba/word/XApplicationOutgoing.hpp> +#include <ooo/vba/word/XBookmarks.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> +#include <cppu/unotype.hxx> +#include <editeng/acorrcfg.hxx> +#include <swdll.hxx> +#include <swmodule.hxx> +#include "vbalistgalleries.hxx" +#include <tools/urlobj.hxx> + +using namespace ::ooo; +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +class SwVbaApplicationOutgoingConnectionPoint : public cppu::WeakImplHelper<XConnectionPoint> +{ +private: + SwVbaApplication* mpApp; + +public: + SwVbaApplicationOutgoingConnectionPoint( SwVbaApplication* pApp ); + + // XConnectionPoint + sal_uInt32 SAL_CALL Advise(const uno::Reference< XSink >& Sink ) override; + void SAL_CALL Unadvise( sal_uInt32 Cookie ) override; +}; + +} + +SwVbaApplication::SwVbaApplication( uno::Reference<uno::XComponentContext >& xContext ): + SwVbaApplication_BASE( xContext ) +{ +} + +SwVbaApplication::~SwVbaApplication() +{ +} + +sal_uInt32 +SwVbaApplication::AddSink( const uno::Reference< XSink >& xSink ) +{ + { + SolarMutexGuard aGuard; + SwGlobals::ensure(); + } + // No harm in potentially calling this several times + SW_MOD()->RegisterAutomationApplicationEventsCaller( uno::Reference< XSinkCaller >(this) ); + mvSinks.push_back(xSink); + return mvSinks.size(); +} + +void +SwVbaApplication::RemoveSink( sal_uInt32 nNumber ) +{ + if (nNumber < 1 || nNumber > mvSinks.size()) + return; + + mvSinks[nNumber-1] = uno::Reference< XSink >(); +} + +OUString SAL_CALL +SwVbaApplication::getName() +{ + return "Microsoft Word"; +} + +uno::Reference< word::XDocument > SAL_CALL +SwVbaApplication::getActiveDocument() +{ + return new SwVbaDocument( this, mxContext, getCurrentDocument() ); +} + +rtl::Reference<SwVbaWindow> +SwVbaApplication::getActiveSwVbaWindow() +{ + // #FIXME so far can't determine Parent + uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW ); + uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW ); + return new SwVbaWindow( uno::Reference< XHelperInterface >(), mxContext, xModel, xController ); +} + +uno::Reference< css::uno::XComponentContext > const & +SwVbaApplication::getContext() const +{ + return mxContext; +} + +uno::Reference< word::XWindow > SAL_CALL +SwVbaApplication::getActiveWindow() +{ + return getActiveSwVbaWindow(); +} + +uno::Reference<word::XSystem > SAL_CALL +SwVbaApplication::getSystem() +{ + return uno::Reference< word::XSystem >( new SwVbaSystem( mxContext ) ); +} + +uno::Reference<word::XOptions > SAL_CALL +SwVbaApplication::getOptions() +{ + return uno::Reference< word::XOptions >( new SwVbaOptions( mxContext ) ); +} + +uno::Any SAL_CALL +SwVbaApplication::CommandBars( const uno::Any& aIndex ) +{ + try + { + return VbaApplicationBase::CommandBars( aIndex ); + } + catch (const uno::RuntimeException&) + { + return uno::Any(); + } +} + +uno::Reference< word::XSelection > SAL_CALL +SwVbaApplication::getSelection() +{ + return new SwVbaSelection( this, mxContext, getCurrentDocument() ); +} + +uno::Reference< word::XWordBasic > SAL_CALL +SwVbaApplication::getWordBasic() +{ + uno::Reference< word::XWordBasic > xWB( new SwWordBasic( this ) ); + return xWB; +} + +uno::Any SAL_CALL +SwVbaApplication::Documents( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaDocuments( this, mxContext ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaApplication::Addins( const uno::Any& index ) +{ + static uno::Reference< XCollection > xCol( new SwVbaAddins( this, mxContext ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaApplication::Dialogs( const uno::Any& index ) +{ + uno::Reference< word::XDialogs > xCol( new SwVbaDialogs( this, mxContext, getCurrentDocument() )); + if ( index.hasValue() ) + return xCol->Item( index ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaApplication::ListGalleries( const uno::Any& index ) +{ + uno::Reference< text::XTextDocument > xTextDoc( getCurrentDocument(), uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xCol( new SwVbaListGalleries( this, mxContext, xTextDoc ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +sal_Bool SAL_CALL SwVbaApplication::getDisplayAutoCompleteTips() +{ + return SvxAutoCorrCfg::Get().IsAutoTextTip(); +} + +void SAL_CALL SwVbaApplication::setDisplayAutoCompleteTips( sal_Bool _displayAutoCompleteTips ) +{ + SvxAutoCorrCfg::Get().SetAutoTextTip( _displayAutoCompleteTips ); +} + +sal_Int32 SAL_CALL SwVbaApplication::getEnableCancelKey() +{ + // the default value is wdCancelInterrupt in Word + return word::WdEnableCancelKey::wdCancelInterrupt; +} + +void SAL_CALL SwVbaApplication::setEnableCancelKey( sal_Int32/* _enableCancelKey */) +{ + // seems not supported in Writer +} + +sal_Int32 SAL_CALL SwVbaApplication::getWindowState() +{ + auto xWindow = getActiveWindow(); + if (xWindow.is()) + { + uno::Any aState = xWindow->getWindowState(); + sal_Int32 nState; + if (aState >>= nState) + return nState; + } + + return word::WdWindowState::wdWindowStateNormal; // ? +} + +void SAL_CALL SwVbaApplication::setWindowState( sal_Int32 _windowstate ) +{ + try + { + auto xWindow = getActiveWindow(); + if (xWindow.is()) + { + uno::Any aState; + aState <<= _windowstate; + xWindow->setWindowState( aState ); + } + } + catch (const uno::RuntimeException&) + { + } +} + +sal_Int32 SAL_CALL SwVbaApplication::getWidth() +{ + auto pWindow = getActiveSwVbaWindow(); + return pWindow->getWidth(); +} + +void SAL_CALL SwVbaApplication::setWidth( sal_Int32 _width ) +{ + auto pWindow = getActiveSwVbaWindow(); + pWindow->setWidth( _width ); +} + +sal_Int32 SAL_CALL SwVbaApplication::getHeight() +{ + auto pWindow = getActiveSwVbaWindow(); + return pWindow->getHeight(); +} + +void SAL_CALL SwVbaApplication::setHeight( sal_Int32 _height ) +{ + auto pWindow = getActiveSwVbaWindow(); + pWindow->setHeight( _height ); +} + +sal_Int32 SAL_CALL SwVbaApplication::getLeft() +{ + auto pWindow = getActiveSwVbaWindow(); + return pWindow->getLeft(); +} + +void SAL_CALL SwVbaApplication::setLeft( sal_Int32 _left ) +{ + auto pWindow = getActiveSwVbaWindow(); + pWindow->setLeft( _left ); +} + +sal_Int32 SAL_CALL SwVbaApplication::getTop() +{ + auto pWindow = getActiveSwVbaWindow(); + return pWindow->getTop(); +} + +void SAL_CALL SwVbaApplication::setTop( sal_Int32 _top ) +{ + auto pWindow = getActiveSwVbaWindow(); + pWindow->setTop( _top ); +} + +OUString SAL_CALL SwVbaApplication::getStatusBar() +{ + return ""; +} + +uno::Any SAL_CALL SwVbaApplication::getCustomizationContext() +{ + return uno::Any(); // ??? +} + +void SAL_CALL SwVbaApplication::setCustomizationContext(const uno::Any& /*_customizationcontext*/) +{ + // ??? +} + +void SAL_CALL SwVbaApplication::setStatusBar( const OUString& _statusbar ) +{ + // ScVbaAppSettings::setStatusBar() also uses the XStatusIndicator to show this, so maybe that is OK? + uno::Reference< frame::XModel > xModel = getCurrentDocument(); + if (xModel.is()) + { + uno::Reference< task::XStatusIndicatorSupplier > xStatusIndicatorSupplier( xModel->getCurrentController(), uno::UNO_QUERY ); + if (xStatusIndicatorSupplier.is()) + { + uno::Reference< task::XStatusIndicator > xStatusIndicator = xStatusIndicatorSupplier->getStatusIndicator(); + if (xStatusIndicator.is()) + xStatusIndicator->start( _statusbar, 100 ); + } + } + + // Yes, we intentionally use the "extensions.olebridge" tag here even if this is sw. We + // interpret setting the StatusBar property as a request from an Automation client to display + // the string in LibreOffice's debug output, and all other generic Automation support debug + // output (in extensions/source/ole) uses that tag. If the check for "cross-module" or mixed log + // areas in compilerplugins/clang/sallogareas.cxx is re-activated, this will have to be added as + // a special case. + + SAL_INFO("extensions.olebridge", "Client debug output: " << _statusbar); +} + +float SAL_CALL SwVbaApplication::CentimetersToPoints( float Centimeters ) +{ + return o3tl::convert(Centimeters, o3tl::Length::cm, o3tl::Length::pt); +} + +float SAL_CALL SwVbaApplication::PointsToCentimeters( float Points ) +{ + return o3tl::convert(Points, o3tl::Length::pt, o3tl::Length::cm); +} + +float SAL_CALL SwVbaApplication::PixelsToPoints( float Pixels, ::sal_Bool fVertical ) +{ + //Set up xDevice + uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW ); + uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW ); + uno::Reference< frame::XFrame > xFrame( xController->getFrame(), uno::UNO_SET_THROW ); + uno::Reference< awt::XWindow > xWindow( xFrame->getContainerWindow(), uno::UNO_SET_THROW ); + css::uno::Reference< css::awt::XDevice > xDevice( xWindow, css::uno::UNO_QUERY ); + + return ooo::vba::PixelsToPoints(xDevice, Pixels, fVertical); +} + +float SAL_CALL SwVbaApplication::PointsToPixels( float Pixels, ::sal_Bool fVertical ) +{ + uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW ); + uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW ); + uno::Reference< frame::XFrame > xFrame( xController->getFrame(), uno::UNO_SET_THROW ); + uno::Reference< awt::XWindow > xWindow( xFrame->getContainerWindow(), uno::UNO_SET_THROW ); + css::uno::Reference< css::awt::XDevice > xDevice( xWindow, css::uno::UNO_QUERY ); + + return ooo::vba::PointsToPixels(xDevice, Pixels, fVertical); +} + +float SAL_CALL SwVbaApplication::InchesToPoints( float Inches ) +{ + return o3tl::convert(Inches, o3tl::Length::in, o3tl::Length::pt); +} + +float SAL_CALL SwVbaApplication::PointsToInches( float Points ) +{ + return o3tl::convert(Points, o3tl::Length::pt, o3tl::Length::in); +} + +float SAL_CALL SwVbaApplication::MillimetersToPoints( float Millimeters ) +{ + return o3tl::convert(Millimeters, o3tl::Length::mm, o3tl::Length::pt); +} + +float SAL_CALL SwVbaApplication::PointsToMillimeters( float Points ) +{ + return o3tl::convert(Points, o3tl::Length::pt, o3tl::Length::mm); +} + +float SAL_CALL SwVbaApplication::PicasToPoints( float Picas ) +{ + return o3tl::convert(Picas, o3tl::Length::pc, o3tl::Length::pt); +} + +float SAL_CALL SwVbaApplication::PointsToPicas( float Points ) +{ + return o3tl::convert(Points, o3tl::Length::pt, o3tl::Length::pc); +} + +void SAL_CALL SwVbaApplication::ShowMe() +{ + // Method no longer supported in word - deprecated +} + +void SAL_CALL SwVbaApplication::Resize( sal_Int32 Width, sal_Int32 Height ) +{ + // Have to do it like this as the Width and Height are hidden away in the ooo::vba::XWindowBase + // which ooo::vba::word::XApplication does not inherit from. SwVbaWindow, however, does inherit + // from XWindowBase. Ugh. + auto pWindow = getActiveSwVbaWindow(); + pWindow->setWidth( Width ); + pWindow->setHeight( Height ); +} + +void SAL_CALL SwVbaApplication::Move( sal_Int32 Left, sal_Int32 Top ) +{ + // See comment in Resize(). + auto pWindow = getActiveSwVbaWindow(); + pWindow->setLeft( Left ); + pWindow->setTop( Top ); +} + +// XInterfaceWithIID + +OUString SAL_CALL +SwVbaApplication::getIID() +{ + return "{82154421-0FBF-11d4-8313-005004526AB4}"; +} + +// XConnectable + +OUString SAL_CALL +SwVbaApplication::GetIIDForClassItselfNotCoclass() +{ + return "{82154423-0FBF-11D4-8313-005004526AB4}"; +} + +TypeAndIID SAL_CALL +SwVbaApplication::GetConnectionPoint() +{ + TypeAndIID aResult = + { cppu::UnoType<word::XApplicationOutgoing>::get(), + "{82154422-0FBF-11D4-8313-005004526AB4}" + }; + + return aResult; +} + +uno::Reference<XConnectionPoint> SAL_CALL +SwVbaApplication::FindConnectionPoint() +{ + uno::Reference<XConnectionPoint> xCP(new SwVbaApplicationOutgoingConnectionPoint(this)); + return xCP; +} + +OUString +SwVbaApplication::getServiceImplName() +{ + return "SwVbaApplication"; +} + +uno::Sequence< OUString > +SwVbaApplication::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Application" + }; + return aServiceNames; +} + +uno::Reference< frame::XModel > +SwVbaApplication::getCurrentDocument() +{ + return getCurrentWordDoc( mxContext ); +} + +// XSinkCaller + +void SAL_CALL +SwVbaApplication::CallSinks( const OUString& Method, uno::Sequence< uno::Any >& Arguments ) +{ + for (auto& i : mvSinks) + { + if (i.is()) + i->Call(Method, Arguments); + } +} + +// SwVbaApplicationOutgoingConnectionPoint + +SwVbaApplicationOutgoingConnectionPoint::SwVbaApplicationOutgoingConnectionPoint( SwVbaApplication* pApp ) : + mpApp(pApp) +{ +} + +// XConnectionPoint +sal_uInt32 SAL_CALL +SwVbaApplicationOutgoingConnectionPoint::Advise( const uno::Reference< XSink >& Sink ) +{ + return mpApp->AddSink(Sink); +} + +void SAL_CALL +SwVbaApplicationOutgoingConnectionPoint::Unadvise( sal_uInt32 Cookie ) +{ + mpApp->RemoveSink( Cookie ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaapplication.hxx b/sw/source/ui/vba/vbaapplication.hxx new file mode 100644 index 0000000000..90b4322835 --- /dev/null +++ b/sw/source/ui/vba/vbaapplication.hxx @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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_VBA_VBAAPPLICATION_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAAPPLICATION_HXX + +#include <vector> + +#include <ooo/vba/XSink.hpp> +#include <ooo/vba/XSinkCaller.hpp> +#include <ooo/vba/word/XApplication.hpp> +#include <ooo/vba/word/XDocument.hpp> +#include <ooo/vba/word/XWindow.hpp> +#include <ooo/vba/word/XSystem.hpp> +#include <ooo/vba/word/XOptions.hpp> +#include <ooo/vba/word/XSelection.hpp> +#include <vbahelper/vbaapplicationbase.hxx> +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> + +#include "vbawindow.hxx" + +typedef cppu::ImplInheritanceHelper< VbaApplicationBase, ooo::vba::word::XApplication, ooo::vba::XSinkCaller > SwVbaApplication_BASE; + +// This class is currently not a singleton. One instance is created per document with (potential?) +// StarBasic code in it, I think, and a shared one for all Automation clients connected to the +// ooo::vba::word::Application (Writer.Application) service. (Of course it probably is not common to +// have several Automation clients at once.) + +// Should it be a true singleton? Hard to say. Anyway, it is actually the SwVbaGlobals class that +// should be a singleton in that case, I think. + +class SwVbaApplication : public SwVbaApplication_BASE +{ + std::vector<css::uno::Reference< ooo::vba::XSink >> mvSinks; + +public: + explicit SwVbaApplication( css::uno::Reference< css::uno::XComponentContext >& xContext ); + virtual ~SwVbaApplication() override; + + sal_uInt32 AddSink( const css::uno::Reference< ooo::vba::XSink >& xSink ); + void RemoveSink( sal_uInt32 nNumber ); + + rtl::Reference<SwVbaWindow> getActiveSwVbaWindow(); + css::uno::Reference< css::uno::XComponentContext > const & getContext() const; + + // XApplication + virtual OUString SAL_CALL getName() override; + virtual css::uno::Reference< ooo::vba::word::XSystem > SAL_CALL getSystem() override; + virtual css::uno::Reference< ov::word::XDocument > SAL_CALL getActiveDocument() override; + virtual css::uno::Reference< ov::word::XWindow > SAL_CALL getActiveWindow() override; + virtual css::uno::Reference< ooo::vba::word::XOptions > SAL_CALL getOptions() override; + virtual css::uno::Reference< ooo::vba::word::XSelection > SAL_CALL getSelection() override; + virtual css::uno::Reference< ooo::vba::word::XWordBasic > SAL_CALL getWordBasic() override; + virtual css::uno::Any SAL_CALL CommandBars( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Documents( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Addins( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Dialogs( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL ListGalleries( const css::uno::Any& aIndex ) override; + virtual sal_Bool SAL_CALL getDisplayAutoCompleteTips() override; + virtual void SAL_CALL setDisplayAutoCompleteTips( sal_Bool _displayAutoCompleteTips ) override; + virtual sal_Int32 SAL_CALL getEnableCancelKey() override; + virtual void SAL_CALL setEnableCancelKey( sal_Int32 _enableCancelKey ) override; + virtual sal_Int32 SAL_CALL getWindowState() override; + virtual void SAL_CALL setWindowState( sal_Int32 _windowstate ) override; + virtual sal_Int32 SAL_CALL getWidth() override; + virtual void SAL_CALL setWidth( sal_Int32 _width ) override; + virtual sal_Int32 SAL_CALL getHeight() override; + virtual void SAL_CALL setHeight( sal_Int32 _height ) override; + virtual sal_Int32 SAL_CALL getLeft() override; + virtual void SAL_CALL setLeft( sal_Int32 _left ) override; + virtual sal_Int32 SAL_CALL getTop() override; + virtual void SAL_CALL setTop( sal_Int32 _top ) override; + virtual OUString SAL_CALL getStatusBar() override; + virtual void SAL_CALL setStatusBar( const OUString& _statusbar ) override; + virtual css::uno::Any SAL_CALL getCustomizationContext() override; + virtual void SAL_CALL setCustomizationContext( const css::uno::Any& _customizationcontext ) override; + virtual float SAL_CALL CentimetersToPoints( float Centimeters ) override; + virtual float SAL_CALL PointsToCentimeters( float Points ) override; + virtual float SAL_CALL PixelsToPoints( float Pixels, ::sal_Bool fVertical ) override; + virtual float SAL_CALL PointsToPixels( float Pixels, ::sal_Bool fVertical ) override; + virtual float SAL_CALL InchesToPoints( float Inches ) override; + virtual float SAL_CALL PointsToInches( float Points ) override; + virtual float SAL_CALL MillimetersToPoints( float Millimeters ) override; + virtual float SAL_CALL PointsToMillimeters( float Points ) override; + virtual float SAL_CALL PicasToPoints( float Picas ) override; + virtual float SAL_CALL PointsToPicas( float Points ) override; + + + + virtual void SAL_CALL ShowMe() override; + virtual void SAL_CALL Resize( sal_Int32 Width, sal_Int32 Height ) override; + virtual void SAL_CALL Move( sal_Int32 Left, sal_Int32 Top ) override; + + // XInterfaceWithIID + virtual OUString SAL_CALL getIID() override; + + // XConnectable + virtual OUString SAL_CALL GetIIDForClassItselfNotCoclass() override; + virtual ov::TypeAndIID SAL_CALL GetConnectionPoint() override; + virtual css::uno::Reference<ov::XConnectionPoint> SAL_CALL FindConnectionPoint() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + + // XSinkCaller + virtual void SAL_CALL CallSinks( const OUString& Method, css::uno::Sequence< css::uno::Any >& Arguments ) override; + + virtual css::uno::Reference< css::frame::XModel > getCurrentDocument() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAAPPLICATION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaautotextentry.cxx b/sw/source/ui/vba/vbaautotextentry.cxx new file mode 100644 index 0000000000..dd1f17f16f --- /dev/null +++ b/sw/source/ui/vba/vbaautotextentry.cxx @@ -0,0 +1,132 @@ +/* -*- 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 "vbaautotextentry.hxx" +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include <com/sun/star/text/XParagraphCursor.hpp> +#include "wordvbahelper.hxx" +#include "vbarange.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaAutoTextEntry::SwVbaAutoTextEntry( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< text::XAutoTextEntry > xEntry ) : + SwVbaAutoTextEntry_BASE( rParent, rContext ), mxEntry(std::move( xEntry )) +{ +} + +SwVbaAutoTextEntry::~SwVbaAutoTextEntry() +{ +} + +uno::Reference< word::XRange > SAL_CALL SwVbaAutoTextEntry::Insert( const uno::Reference< word::XRange >& _where, const uno::Any& _richtext ) +{ + SwVbaRange* pWhere = dynamic_cast<SwVbaRange*>( _where.get() ); + if( pWhere ) + { + uno::Reference< text::XTextRange > xTextRange = pWhere->getXTextRange(); + xTextRange->setString( "x" ); // set marker + uno::Reference< text::XTextRange > xEndMarker = xTextRange->getEnd(); + xEndMarker->setString( "x" ); // set marker + uno::Reference< text::XText > xText = pWhere->getXText(); + mxEntry->applyTo( xEndMarker->getStart() ); + uno::Reference< text::XTextCursor > xTC = xText->createTextCursorByRange( xTextRange->getStart() ); + xTC->goRight( 1, true ); + xTC->setString( "" ); // remove marker + // remove the blank paragraph if it is a rich text + bool bRich = false; + _richtext >>= bRich; + if( bRich ) + { + // check if it is a blank paragraph + uno::Reference< text::XParagraphCursor > xParaCursor( xTC, uno::UNO_QUERY_THROW ); + if( xParaCursor->isStartOfParagraph() && xParaCursor->isEndOfParagraph() ) + { + //remove the blank paragraph + uno::Reference< frame::XModel > xModel( getCurrentWordDoc( mxContext ), uno::UNO_SET_THROW ); + uno::Reference< text::XTextViewCursor > xTVCursor = word::getXTextViewCursor( xModel ); + uno::Reference< text::XTextRange > xCurrentRange( xTC->getEnd(), uno::UNO_SET_THROW ); + xTVCursor->gotoRange( xCurrentRange, false ); + dispatchRequests( xModel,".uno:Delete" ); + xTVCursor->gotoRange( xEndMarker->getEnd(), false ); + } + } + xEndMarker->setString( "" ); // remove marker + xTC = xText->createTextCursorByRange( xEndMarker->getEnd() ); + pWhere->setXTextCursor( xTC ); + } + return uno::Reference< word::XRange >( pWhere ); +} + +OUString +SwVbaAutoTextEntry::getServiceImplName() +{ + return "SwVbaAutoTextEntry"; +} + +uno::Sequence< OUString > +SwVbaAutoTextEntry::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.AutoTextEntry" + }; + return aServiceNames; +} + +SwVbaAutoTextEntries::SwVbaAutoTextEntries( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext > & xContext, const uno::Reference< container::XIndexAccess >& xIndexAccess ) : SwVbaAutoTextEntries_BASE( xParent, xContext, xIndexAccess ) +{ +} + +// XEnumerationAccess +uno::Type +SwVbaAutoTextEntries::getElementType() +{ + return cppu::UnoType<word::XAutoTextEntry>::get(); +} +uno::Reference< container::XEnumeration > +SwVbaAutoTextEntries::createEnumeration() +{ + throw uno::RuntimeException("Not implemented" ); +} + +uno::Any +SwVbaAutoTextEntries::createCollectionObject( const css::uno::Any& aSource ) +{ + uno::Reference< text::XAutoTextEntry > xEntry( aSource, uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< word::XAutoTextEntry >( new SwVbaAutoTextEntry( this, mxContext, xEntry ) ) ); +} + +OUString +SwVbaAutoTextEntries::getServiceImplName() +{ + return "SwVbaAutoTextEntries"; +} + +css::uno::Sequence<OUString> +SwVbaAutoTextEntries::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.AutoTextEntries" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaautotextentry.hxx b/sw/source/ui/vba/vbaautotextentry.hxx new file mode 100644 index 0000000000..9a8ab4ad1d --- /dev/null +++ b/sw/source/ui/vba/vbaautotextentry.hxx @@ -0,0 +1,69 @@ +/* -*- 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_VBA_VBAAUTOTEXTENTRY_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAAUTOTEXTENTRY_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XAutoTextEntries.hpp> +#include <ooo/vba/word/XAutoTextEntry.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <ooo/vba/word/XRange.hpp> +#include <com/sun/star/text/XAutoTextEntry.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XAutoTextEntry > SwVbaAutoTextEntry_BASE; + +class SwVbaAutoTextEntry : public SwVbaAutoTextEntry_BASE +{ +private: + css::uno::Reference< css::text::XAutoTextEntry > mxEntry; + +public: + /// @throws css::uno::RuntimeException + SwVbaAutoTextEntry( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::text::XAutoTextEntry > xEntry ); + virtual ~SwVbaAutoTextEntry() override; + + // XAutoTextEntry + virtual css::uno::Reference< ooo::vba::word::XRange > SAL_CALL Insert( const css::uno::Reference< ooo::vba::word::XRange >& _where, const css::uno::Any& _richtext ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +typedef CollTestImplHelper< ooo::vba::word::XAutoTextEntries > SwVbaAutoTextEntries_BASE; + +class SwVbaAutoTextEntries : public SwVbaAutoTextEntries_BASE +{ +public: + /// @throws css::uno::RuntimeException + SwVbaAutoTextEntries( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::container::XIndexAccess >& xIndexAccess ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaAutoTextEntries_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAAUTOTEXTENTRY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbabookmark.cxx b/sw/source/ui/vba/vbabookmark.cxx new file mode 100644 index 0000000000..aecc0760bc --- /dev/null +++ b/sw/source/ui/vba/vbabookmark.cxx @@ -0,0 +1,99 @@ +/* -*- 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 "vbabookmark.hxx" +#include <com/sun/star/text/XBookmarksSupplier.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <utility> +#include "vbarange.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaBookmark::SwVbaBookmark( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, + css::uno::Reference< frame::XModel > xModel, OUString aBookmarkName ) : + SwVbaBookmark_BASE( rParent, rContext ), mxModel(std::move( xModel )), maBookmarkName(std::move( aBookmarkName )), mbValid( true ) +{ + uno::Reference< text::XBookmarksSupplier > xBookmarksSupplier( mxModel, uno::UNO_QUERY_THROW ); + mxBookmark.set( xBookmarksSupplier->getBookmarks()->getByName( maBookmarkName ), uno::UNO_QUERY_THROW ); +} + +SwVbaBookmark::~SwVbaBookmark() +{ +} + +void SwVbaBookmark::checkVality() +{ + if( !mbValid ) + throw uno::RuntimeException("The bookmark is not valid" ); +} + +void SAL_CALL SwVbaBookmark::Delete() +{ + checkVality(); + uno::Reference< text::XTextDocument > xTextDocument( mxModel, uno::UNO_QUERY_THROW ); + xTextDocument->getText()->removeTextContent( mxBookmark ); + mbValid = false; +} + +void SAL_CALL SwVbaBookmark::Select() +{ + checkVality(); + uno::Reference< view::XSelectionSupplier > xSelectSupp( mxModel->getCurrentController(), uno::UNO_QUERY_THROW ); + xSelectSupp->select( uno::Any( mxBookmark ) ); +} + +OUString SAL_CALL SwVbaBookmark::getName() +{ + return maBookmarkName; +} + +void SAL_CALL SwVbaBookmark::setName( const OUString& _name ) +{ + uno::Reference< container::XNamed > xNamed( mxBookmark, uno::UNO_QUERY_THROW ); + xNamed->setName( _name ); +} + +uno::Any SAL_CALL SwVbaBookmark::Range() +{ + uno::Reference< text::XTextContent > xTextContent( mxBookmark, uno::UNO_SET_THROW ); + uno::Reference< text::XTextDocument > xTextDocument( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextRange > xTextRange( xTextContent->getAnchor(), uno::UNO_SET_THROW ); + return uno::Any( uno::Reference< word::XRange>( new SwVbaRange( this, mxContext, xTextDocument, xTextRange->getStart(), xTextRange->getEnd(), xTextRange->getText() ) ) ); +} + +OUString +SwVbaBookmark::getServiceImplName() +{ + return "SwVbaBookmark"; +} + +uno::Sequence< OUString > +SwVbaBookmark::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Bookmark" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbabookmark.hxx b/sw/source/ui/vba/vbabookmark.hxx new file mode 100644 index 0000000000..24524df618 --- /dev/null +++ b/sw/source/ui/vba/vbabookmark.hxx @@ -0,0 +1,60 @@ +/* -*- 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_VBA_VBABOOKMARK_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBABOOKMARK_HXX + +#include <ooo/vba/word/XBookmark.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextContent.hpp> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XBookmark> SwVbaBookmark_BASE; + +class SwVbaBookmark : public SwVbaBookmark_BASE +{ +private: + css::uno::Reference<css::frame::XModel> mxModel; + css::uno::Reference<css::text::XTextContent> mxBookmark; + OUString maBookmarkName; + bool mbValid; + +private: + /// @throws css::uno::RuntimeException + void checkVality(); + +public: + /// @throws css::uno::RuntimeException + SwVbaBookmark(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext, + css::uno::Reference<css::frame::XModel> xModel, OUString aName); + virtual ~SwVbaBookmark() override; + + // Methods + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName(const OUString&) override; + virtual void SAL_CALL Delete() override; + virtual void SAL_CALL Select() override; + virtual css::uno::Any SAL_CALL Range() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBABOOKMARK_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbabookmarks.cxx b/sw/source/ui/vba/vbabookmarks.cxx new file mode 100644 index 0000000000..6755413796 --- /dev/null +++ b/sw/source/ui/vba/vbabookmarks.cxx @@ -0,0 +1,229 @@ +/* -*- 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 "vbabookmarks.hxx" +#include "vbabookmark.hxx" +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/text/XTextViewCursor.hpp> +#include <ooo/vba/word/WdBookmarkSortBy.hpp> +#include "vbarange.hxx" +#include "wordvbahelper.hxx" +#include <cppuhelper/implbase.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +class BookmarksEnumeration : public EnumerationHelperImpl +{ + uno::Reference< frame::XModel > mxModel; +public: + /// @throws uno::RuntimeException + BookmarksEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, uno::Reference< frame::XModel > xModel ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ), mxModel(std::move( xModel )) {} + + virtual uno::Any SAL_CALL nextElement( ) override + { + uno::Reference< container::XNamed > xNamed( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); + OUString aName = xNamed->getName(); + return uno::Any( uno::Reference< word::XBookmark > ( new SwVbaBookmark( m_xParent, m_xContext, mxModel, aName ) ) ); + } + +}; + +// Bookmarks use case-insensitive name lookup in MS Word. +class BookmarkCollectionHelper : public ::cppu::WeakImplHelper< container::XNameAccess, + container::XIndexAccess > +{ +private: + uno::Reference< container::XNameAccess > mxNameAccess; + uno::Reference< container::XIndexAccess > mxIndexAccess; + uno::Any m_cachePos; +public: + /// @throws uno::RuntimeException + explicit BookmarkCollectionHelper( uno::Reference< container::XIndexAccess > xIndexAccess ) : mxIndexAccess(std::move( xIndexAccess )) + { + mxNameAccess.set( mxIndexAccess, uno::UNO_QUERY_THROW ); + } + // XElementAccess + virtual uno::Type SAL_CALL getElementType( ) override { return mxIndexAccess->getElementType(); } + virtual sal_Bool SAL_CALL hasElements( ) override { return mxIndexAccess->hasElements(); } + // XNameAccess + virtual uno::Any SAL_CALL getByName( const OUString& aName ) override + { + if ( !hasByName(aName) ) + throw container::NoSuchElementException(); + return m_cachePos; + } + virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override + { + return mxNameAccess->getElementNames(); + } + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { + if( mxNameAccess->hasByName( aName ) ) + { + m_cachePos = mxNameAccess->getByName( aName ); + return true; + } + else + { + for( sal_Int32 nIndex = 0; nIndex < mxIndexAccess->getCount(); nIndex++ ) + { + uno::Reference< container::XNamed > xNamed( mxIndexAccess->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); + OUString aBookmarkName = xNamed->getName(); + if( aName.equalsIgnoreAsciiCase( aBookmarkName ) ) + { + m_cachePos <<= xNamed; + return true; + } + } + } + return false; + } + // XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount( ) override + { + return mxIndexAccess->getCount(); + } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + return mxIndexAccess->getByIndex( Index ); + } +}; + +} + +SwVbaBookmarks::SwVbaBookmarks( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext > & xContext, const uno::Reference< container::XIndexAccess >& xBookmarks, uno::Reference< frame::XModel > xModel ): SwVbaBookmarks_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( new BookmarkCollectionHelper( xBookmarks ) ) ), mxModel(std::move( xModel )) +{ + mxBookmarksSupplier.set( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextDocument > xDocument( mxModel, uno::UNO_QUERY_THROW ); +} +// XEnumerationAccess +uno::Type +SwVbaBookmarks::getElementType() +{ + return cppu::UnoType<word::XBookmark>::get(); +} +uno::Reference< container::XEnumeration > +SwVbaBookmarks::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return new BookmarksEnumeration( getParent(), mxContext,xEnumAccess->createEnumeration(), mxModel ); +} + +uno::Any +SwVbaBookmarks::createCollectionObject( const css::uno::Any& aSource ) +{ + uno::Reference< container::XNamed > xNamed( aSource, uno::UNO_QUERY_THROW ); + OUString aName = xNamed->getName(); + return uno::Any( uno::Reference< word::XBookmark > ( new SwVbaBookmark( getParent(), mxContext, mxModel, aName ) ) ); +} + +void SwVbaBookmarks::removeBookmarkByName( const OUString& rName ) +{ + uno::Reference< text::XTextContent > xBookmark( m_xNameAccess->getByName( rName ), uno::UNO_QUERY_THROW ); + word::getXTextViewCursor( mxModel )->getText()->removeTextContent( xBookmark ); +} + +void SwVbaBookmarks::addBookmarkByName( const uno::Reference< frame::XModel >& xModel, const OUString& rName, const uno::Reference< text::XTextRange >& rTextRange ) +{ + uno::Reference< lang::XMultiServiceFactory > xDocMSF( xModel, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextContent > xBookmark( xDocMSF->createInstance("com.sun.star.text.Bookmark"), uno::UNO_QUERY_THROW ); + uno::Reference< container::XNamed > xNamed( xBookmark, uno::UNO_QUERY_THROW ); + xNamed->setName( rName ); + rTextRange->getText()->insertTextContent( rTextRange, xBookmark, false ); +} + +uno::Any SAL_CALL +SwVbaBookmarks::Add( const OUString& rName, const uno::Any& rRange ) +{ + uno::Reference< text::XTextRange > xTextRange; + uno::Reference< word::XRange > xRange; + if( rRange >>= xRange ) + { + SwVbaRange* pRange = dynamic_cast< SwVbaRange* >( xRange.get() ); + if( pRange ) + xTextRange = pRange->getXTextRange(); + } + else + { + // FIXME: insert the bookmark into current view cursor + xTextRange.set( word::getXTextViewCursor( mxModel ), uno::UNO_QUERY_THROW ); + } + + // remove the exist bookmark + if( m_xNameAccess->hasByName( rName ) ) + removeBookmarkByName( rName ); + + addBookmarkByName( mxModel, rName, xTextRange ); + + return uno::Any( uno::Reference< word::XBookmark >( new SwVbaBookmark( getParent(), mxContext, mxModel, rName ) ) ); +} + +sal_Int32 SAL_CALL +SwVbaBookmarks::getDefaultSorting() +{ + return word::WdBookmarkSortBy::wdSortByName; +} + +void SAL_CALL +SwVbaBookmarks::setDefaultSorting( sal_Int32/* _type*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL +SwVbaBookmarks::getShowHidden() +{ + return true; +} + +void SAL_CALL +SwVbaBookmarks::setShowHidden( sal_Bool /*_hidden*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL +SwVbaBookmarks::Exists( const OUString& rName ) +{ + bool bExist = m_xNameAccess->hasByName( rName ); + return bExist; +} + +OUString +SwVbaBookmarks::getServiceImplName() +{ + return "SwVbaBookmarks"; +} + +css::uno::Sequence<OUString> +SwVbaBookmarks::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.Bookmarks" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbabookmarks.hxx b/sw/source/ui/vba/vbabookmarks.hxx new file mode 100644 index 0000000000..1b264fb6b7 --- /dev/null +++ b/sw/source/ui/vba/vbabookmarks.hxx @@ -0,0 +1,66 @@ +/* -*- 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_VBA_VBABOOKMARKS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBABOOKMARKS_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XBookmarks.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/text/XBookmarksSupplier.hpp> +#include <com/sun/star/text/XTextRange.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XBookmarks > SwVbaBookmarks_BASE; + +class SwVbaBookmarks : public SwVbaBookmarks_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::text::XBookmarksSupplier > mxBookmarksSupplier; + +private: + /// @throws css::uno::RuntimeException + void removeBookmarkByName( const OUString& rName ); + +public: + SwVbaBookmarks( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::container::XIndexAccess >& xBookmarks, css::uno::Reference< css::frame::XModel > xModel ); + + /// @throws css::uno::RuntimeException + static void addBookmarkByName( const css::uno::Reference< css::frame::XModel >& xModel, const OUString& rName, const css::uno::Reference< css::text::XTextRange >& rTextRange ); + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaBookmarks_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + + // XBookmarks + virtual sal_Int32 SAL_CALL getDefaultSorting() override; + virtual void SAL_CALL setDefaultSorting( sal_Int32 _type ) override; + virtual sal_Bool SAL_CALL getShowHidden() override; + virtual void SAL_CALL setShowHidden( sal_Bool _hidden ) override; + + virtual css::uno::Any SAL_CALL Add( const OUString& rName, const css::uno::Any& rRange ) override; + virtual sal_Bool SAL_CALL Exists( const OUString& rName ) override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBABOOKMARKS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaborders.cxx b/sw/source/ui/vba/vbaborders.cxx new file mode 100644 index 0000000000..9e780fe210 --- /dev/null +++ b/sw/source/ui/vba/vbaborders.cxx @@ -0,0 +1,366 @@ +/* -*- 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 "vbaborders.hxx" +#include <ooo/vba/word/XBorder.hpp> +#include <ooo/vba/word/WdBorderType.hpp> +#include <ooo/vba/word/WdLineStyle.hpp> +#include <sal/macros.h> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/table/TableBorder.hpp> +#include <utility> +#include "vbapalette.hxx" + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +typedef ::cppu::WeakImplHelper<container::XIndexAccess > RangeBorders_Base; +typedef InheritedHelperInterfaceWeakImpl<word::XBorder > SwVbaBorder_Base; + +// #TODO sort these indexes to match the order in which Word iterates over the +// borders, the enumeration will match the order in this list +const sal_Int16 supportedIndexTable[] = { word::WdBorderType::wdBorderBottom, word::WdBorderType::wdBorderDiagonalDown, word::WdBorderType::wdBorderDiagonalUp, word::WdBorderType::wdBorderHorizontal, word::WdBorderType::wdBorderLeft, word::WdBorderType::wdBorderRight, word::WdBorderType::wdBorderTop, word::WdBorderType::wdBorderVertical }; + +// Equiv widths in 1/100 mm +const sal_Int32 OOLineHairline = 2; + +namespace { + +class SwVbaBorder : public SwVbaBorder_Base +{ +private: + uno::Reference< beans::XPropertySet > m_xProps; + sal_Int32 m_LineType; + void setBorderLine( table::BorderLine const & rBorderLine ) + { + table::TableBorder aTableBorder; + m_xProps->getPropertyValue( "TableBorder" ) >>= aTableBorder; + + switch ( m_LineType ) + { + case word::WdBorderType::wdBorderLeft: + aTableBorder.IsLeftLineValid = true; + aTableBorder.LeftLine= rBorderLine; + break; + case word::WdBorderType::wdBorderTop: + aTableBorder.IsTopLineValid = true; + aTableBorder.TopLine = rBorderLine; + break; + + case word::WdBorderType::wdBorderBottom: + aTableBorder.IsBottomLineValid = true; + aTableBorder.BottomLine = rBorderLine; + break; + case word::WdBorderType::wdBorderRight: + aTableBorder.IsRightLineValid = true; + aTableBorder.RightLine = rBorderLine; + break; + case word::WdBorderType::wdBorderVertical: + aTableBorder.IsVerticalLineValid = true; + aTableBorder.VerticalLine = rBorderLine; + break; + case word::WdBorderType::wdBorderHorizontal: + aTableBorder.IsHorizontalLineValid = true; + aTableBorder.HorizontalLine = rBorderLine; + break; + case word::WdBorderType::wdBorderDiagonalDown: + case word::WdBorderType::wdBorderDiagonalUp: + // #TODO have to ignore at the moment, would be + // nice to investigate what we can do here + break; + default: + return; + } + m_xProps->setPropertyValue( "TableBorder", uno::Any(aTableBorder) ); + } + + bool getBorderLine( table::BorderLine& rBorderLine ) + { + table::TableBorder aTableBorder; + m_xProps->getPropertyValue( "TableBorder" ) >>= aTableBorder; + switch ( m_LineType ) + { + case word::WdBorderType::wdBorderLeft: + if ( aTableBorder.IsLeftLineValid ) + rBorderLine = aTableBorder.LeftLine; + break; + case word::WdBorderType::wdBorderTop: + if ( aTableBorder.IsTopLineValid ) + rBorderLine = aTableBorder.TopLine; + break; + case word::WdBorderType::wdBorderBottom: + if ( aTableBorder.IsBottomLineValid ) + rBorderLine = aTableBorder.BottomLine; + break; + case word::WdBorderType::wdBorderRight: + if ( aTableBorder.IsRightLineValid ) + rBorderLine = aTableBorder.RightLine; + break; + case word::WdBorderType::wdBorderVertical: + if ( aTableBorder.IsVerticalLineValid ) + rBorderLine = aTableBorder.VerticalLine; + break; + case word::WdBorderType::wdBorderHorizontal: + if ( aTableBorder.IsHorizontalLineValid ) + rBorderLine = aTableBorder.HorizontalLine; + break; + + case word::WdBorderType::wdBorderDiagonalDown: + case word::WdBorderType::wdBorderDiagonalUp: + // #TODO have to ignore at the moment, would be + // nice to investigate what we can do here + break; + default: + return false; + } + return true; + } + +protected: + virtual OUString getServiceImplName() override + { + return "SwVbaBorder"; + } + + virtual css::uno::Sequence<OUString> getServiceNames() override + { + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Border" + }; + return aServiceNames; + } +public: + SwVbaBorder( const uno::Reference< beans::XPropertySet > & xProps, const uno::Reference< uno::XComponentContext >& xContext, sal_Int32 lineType ) : SwVbaBorder_Base( uno::Reference< XHelperInterface >( xProps, uno::UNO_QUERY ), xContext ), m_xProps( xProps ), m_LineType( lineType ) {} + + uno::Any SAL_CALL getLineStyle() override + { + sal_Int32 nLineStyle = word::WdLineStyle::wdLineStyleNone; + table::BorderLine aBorderLine; + if ( getBorderLine( aBorderLine ) ) + { + if( aBorderLine.InnerLineWidth !=0 && aBorderLine.OuterLineWidth !=0 ) + { + nLineStyle = word::WdLineStyle::wdLineStyleDouble; + } + else if( aBorderLine.InnerLineWidth !=0 || aBorderLine.OuterLineWidth !=0 ) + { + nLineStyle = word::WdLineStyle::wdLineStyleSingle; + } + else + { + nLineStyle = word::WdLineStyle::wdLineStyleNone; + } + } + return uno::Any( nLineStyle ); + } + void SAL_CALL setLineStyle( const uno::Any& _linestyle ) override + { + // Urk no choice but to silently ignore we don't support this attribute + // #TODO would be nice to support the word line styles + sal_Int32 nLineStyle = 0; + _linestyle >>= nLineStyle; + table::BorderLine aBorderLine; + if ( !getBorderLine( aBorderLine ) ) + throw uno::RuntimeException("Method failed" ); + + switch ( nLineStyle ) + { + case word::WdLineStyle::wdLineStyleNone: + { + aBorderLine.InnerLineWidth = 0; + aBorderLine.OuterLineWidth = 0; + break; + } + case word::WdLineStyle::wdLineStyleDashDot: + case word::WdLineStyle::wdLineStyleDashDotDot: + case word::WdLineStyle::wdLineStyleDashDotStroked: + case word::WdLineStyle::wdLineStyleDashLargeGap: + case word::WdLineStyle::wdLineStyleDashSmallGap: + case word::WdLineStyle::wdLineStyleDot: + case word::WdLineStyle::wdLineStyleDouble: + case word::WdLineStyle::wdLineStyleDoubleWavy: + case word::WdLineStyle::wdLineStyleEmboss3D: + case word::WdLineStyle::wdLineStyleEngrave3D: + case word::WdLineStyle::wdLineStyleInset: + case word::WdLineStyle::wdLineStyleOutset: + case word::WdLineStyle::wdLineStyleSingle: + case word::WdLineStyle::wdLineStyleSingleWavy: + case word::WdLineStyle::wdLineStyleThickThinLargeGap: + case word::WdLineStyle::wdLineStyleThickThinMedGap: + case word::WdLineStyle::wdLineStyleThickThinSmallGap: + case word::WdLineStyle::wdLineStyleThinThickLargeGap: + case word::WdLineStyle::wdLineStyleThinThickMedGap: + case word::WdLineStyle::wdLineStyleThinThickSmallGap: + case word::WdLineStyle::wdLineStyleThinThickThinLargeGap: + case word::WdLineStyle::wdLineStyleThinThickThinMedGap: + case word::WdLineStyle::wdLineStyleThinThickThinSmallGap: + case word::WdLineStyle::wdLineStyleTriple: + { + aBorderLine.InnerLineWidth = 0; + aBorderLine.OuterLineWidth = OOLineHairline; + break; + } + default: + throw uno::RuntimeException("Bad param" ); + } + setBorderLine( aBorderLine ); + + } +}; + +class RangeBorders : public RangeBorders_Base +{ +private: + uno::Reference< table::XCellRange > m_xRange; + uno::Reference< uno::XComponentContext > m_xContext; + VbaPalette m_Palette; + sal_Int32 getTableIndex( sal_Int32 nConst ) + { + // okay return position of the index in the table + sal_Int32 nIndexes = getCount(); + sal_Int32 realIndex = 0; + const sal_Int16* pTableEntry = supportedIndexTable; + for ( ; realIndex < nIndexes; ++realIndex, ++pTableEntry ) + { + if ( *pTableEntry == nConst ) + return realIndex; + } + return getCount(); // error condition + } +public: + RangeBorders( uno::Reference< table::XCellRange > xRange, uno::Reference< uno::XComponentContext > xContext, VbaPalette aPalette ) : m_xRange(std::move( xRange )), m_xContext(std::move( xContext )), m_Palette(std::move( aPalette )) + { + } + // XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount( ) override + { + return SAL_N_ELEMENTS( supportedIndexTable ); + } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + + sal_Int32 nIndex = getTableIndex( Index ); + if ( nIndex >= 0 && nIndex < getCount() ) + { + uno::Reference< beans::XPropertySet > xProps( m_xRange, uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< word::XBorder >( new SwVbaBorder( xProps, m_xContext, supportedIndexTable[ nIndex ] )) ); + } + throw lang::IndexOutOfBoundsException(); + } + virtual uno::Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<word::XBorder>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + return true; + } +}; + +} + +static uno::Reference< container::XIndexAccess > +rangeToBorderIndexAccess( const uno::Reference< table::XCellRange >& xRange, const uno::Reference< uno::XComponentContext > & xContext, VbaPalette const & rPalette ) +{ + return new RangeBorders( xRange, xContext, rPalette ); +} + +namespace { + +class RangeBorderEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference<container::XIndexAccess > m_xIndexAccess; + sal_Int32 m_nIndex; +public: + explicit RangeBorderEnumWrapper( uno::Reference< container::XIndexAccess > xIndexAccess ) : m_xIndexAccess(std::move( xIndexAccess )), m_nIndex( 0 ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( m_nIndex < m_xIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( m_nIndex < m_xIndexAccess->getCount() ) + return m_xIndexAccess->getByIndex( m_nIndex++ ); + throw container::NoSuchElementException(); + } +}; + +} + +// for Table borders +SwVbaBorders::SwVbaBorders( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< table::XCellRange >& xRange, VbaPalette const & rPalette ): SwVbaBorders_BASE( xParent, xContext, rangeToBorderIndexAccess( xRange ,xContext, rPalette ) ) +{ + m_xProps.set( xRange, uno::UNO_QUERY_THROW ); +} + +uno::Reference< container::XEnumeration > +SwVbaBorders::createEnumeration() +{ + return new RangeBorderEnumWrapper( m_xIndexAccess ); +} + +uno::Any +SwVbaBorders::createCollectionObject( const css::uno::Any& aSource ) +{ + return aSource; // it's already a Border object +} + +uno::Type +SwVbaBorders::getElementType() +{ + return cppu::UnoType<word::XBorders>::get(); +} + +uno::Any +SwVbaBorders::getItemByIntIndex( const sal_Int32 nIndex ) +{ + return createCollectionObject( m_xIndexAccess->getByIndex( nIndex ) ); +} + +sal_Bool SAL_CALL SwVbaBorders::getShadow() +{ + // always return False for table border in MS Word + return false; +} + +void SAL_CALL SwVbaBorders::setShadow( sal_Bool /*_shadow*/ ) +{ + // not support in Table border in Word + // TODO: +} + +OUString +SwVbaBorders::getServiceImplName() +{ + return "SwVbaBorders"; +} + +uno::Sequence< OUString > +SwVbaBorders::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Borders" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaborders.hxx b/sw/source/ui/vba/vbaborders.hxx new file mode 100644 index 0000000000..a4ca819f67 --- /dev/null +++ b/sw/source/ui/vba/vbaborders.hxx @@ -0,0 +1,54 @@ +/* -*- 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_VBA_VBABORDERS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBABORDERS_HXX + +#include <ooo/vba/word/XBorders.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +typedef CollTestImplHelper< ov::word::XBorders > SwVbaBorders_BASE; +class VbaPalette; +class SwVbaBorders : public SwVbaBorders_BASE +{ + // XEnumerationAccess + virtual css::uno::Any getItemByIntIndex( const sal_Int32 nIndex ) override; + css::uno::Reference< css::beans::XPropertySet > m_xProps; +public: + SwVbaBorders( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::table::XCellRange >& xRange, VbaPalette const & rPalette ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaCollectionBaseImpl + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + + virtual sal_Bool SAL_CALL getShadow() override; + virtual void SAL_CALL setShadow( sal_Bool _shadow ) override; + + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBABORDERS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacell.cxx b/sw/source/ui/vba/vbacell.cxx new file mode 100644 index 0000000000..a24dd3dd1c --- /dev/null +++ b/sw/source/ui/vba/vbacell.cxx @@ -0,0 +1,102 @@ +/* -*- 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 <utility> + +#include "vbacell.hxx" +#include "vbatablehelper.hxx" +#include "vbarow.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaCell::SwVbaCell( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< text::XTextTable > xTextTable, sal_Int32 nColumn, sal_Int32 nRow ) : + SwVbaCell_BASE( rParent, rContext ), mxTextTable(std::move( xTextTable )), mnColumn( nColumn ), mnRow( nRow ) +{ +} + +SwVbaCell::~SwVbaCell() +{ +} + +::sal_Int32 SAL_CALL SwVbaCell::getWidth() +{ + SwVbaTableHelper aTableHelper( mxTextTable ); + return aTableHelper.GetColWidth( mnColumn, mnRow ); +} + +void SAL_CALL SwVbaCell::setWidth( ::sal_Int32 _width ) +{ + SwVbaTableHelper aTableHelper( mxTextTable ); + aTableHelper.SetColWidth( _width, mnColumn, mnRow, true ); +} + +uno::Any SAL_CALL SwVbaCell::getHeight() +{ + uno::Reference< word::XRow > xRow( new SwVbaRow( getParent(), mxContext, mxTextTable, mnRow ) ); + return xRow->getHeight(); +} + +void SAL_CALL SwVbaCell::setHeight( const uno::Any& _height ) +{ + uno::Reference< word::XRow > xRow( new SwVbaRow( getParent(), mxContext, mxTextTable, mnRow ) ); + xRow->setHeight( _height ); +} + +::sal_Int32 SAL_CALL SwVbaCell::getHeightRule() +{ + uno::Reference< word::XRow > xRow( new SwVbaRow( getParent(), mxContext, mxTextTable, mnRow ) ); + return xRow->getHeightRule(); +} + +void SAL_CALL SwVbaCell::setHeightRule( ::sal_Int32 _heightrule ) +{ + uno::Reference< word::XRow > xRow( new SwVbaRow( getParent(), mxContext, mxTextTable, mnRow ) ); + xRow->setHeightRule( _heightrule ); +} + +void SAL_CALL SwVbaCell::SetWidth( float width, sal_Int32 /*rulestyle*/ ) +{ + // FIXME: handle the argument: rulestyle + setWidth( static_cast<sal_Int32>(width) ); +} + +void SAL_CALL SwVbaCell::SetHeight( float height, sal_Int32 heightrule ) +{ + // FIXME: handle the argument: heightrule + setHeightRule( heightrule ); + setHeight( uno::Any( height ) ); +} + +OUString +SwVbaCell::getServiceImplName() +{ + return "SwVbaCell"; +} + +uno::Sequence< OUString > +SwVbaCell::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Cell" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacell.hxx b/sw/source/ui/vba/vbacell.hxx new file mode 100644 index 0000000000..8ca9f0adad --- /dev/null +++ b/sw/source/ui/vba/vbacell.hxx @@ -0,0 +1,58 @@ +/* -*- 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_VBA_VBACELL_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBACELL_HXX + +#include <ooo/vba/word/XCell.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextTable.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XCell > SwVbaCell_BASE; + +class SwVbaCell : public SwVbaCell_BASE +{ +private: + css::uno::Reference< css::text::XTextTable > mxTextTable; + sal_Int32 mnColumn; + sal_Int32 mnRow; + +public: + /// @throws css::uno::RuntimeException + SwVbaCell( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::text::XTextTable > xTextTable, sal_Int32 nColumn, sal_Int32 nRow ); + virtual ~SwVbaCell() override; + + // Attributes + virtual ::sal_Int32 SAL_CALL getWidth() override; + virtual void SAL_CALL setWidth( ::sal_Int32 _width ) override; + virtual css::uno::Any SAL_CALL getHeight() override; + virtual void SAL_CALL setHeight( const css::uno::Any& _height ) override; + virtual ::sal_Int32 SAL_CALL getHeightRule() override; + virtual void SAL_CALL setHeightRule( ::sal_Int32 _heightrule ) override; + + // Methods + virtual void SAL_CALL SetWidth( float width, sal_Int32 rulestyle ) override; + virtual void SAL_CALL SetHeight( float height, sal_Int32 heightrule ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBACELL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacells.cxx b/sw/source/ui/vba/vbacells.cxx new file mode 100644 index 0000000000..e30c2ed370 --- /dev/null +++ b/sw/source/ui/vba/vbacells.cxx @@ -0,0 +1,214 @@ +/* -*- 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 "vbacells.hxx" +#include "vbacell.hxx" +#include "vbarow.hxx" +#include <cppuhelper/implbase.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +class CellsEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference< container::XIndexAccess > mxIndexAccess; + sal_Int32 mnIndex; + +public: + explicit CellsEnumWrapper( uno::Reference< container::XIndexAccess > xIndexAccess ) : mxIndexAccess(std::move( xIndexAccess )), mnIndex( 0 ) + { + } + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( mnIndex < mxIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if( mnIndex < mxIndexAccess->getCount() ) + { + return mxIndexAccess->getByIndex( mnIndex++ ); + } + throw container::NoSuchElementException(); + } +}; + +class CellCollectionHelper : public ::cppu::WeakImplHelper< container::XIndexAccess, + container::XEnumerationAccess > +{ +private: + uno::Reference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< css::text::XTextTable > mxTextTable; + sal_Int32 mnLeft; + sal_Int32 mnTop; + sal_Int32 mnRight; + sal_Int32 mnBottom; + +public: + /// @throws css::uno::RuntimeException + CellCollectionHelper( css::uno::Reference< ov::XHelperInterface > xParent, css::uno::Reference< css::uno::XComponentContext > xContext, css::uno::Reference< css::text::XTextTable > xTextTable, sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ): mxParent(std::move( xParent )), mxContext(std::move( xContext )), mxTextTable(std::move( xTextTable )), mnLeft( nLeft ), mnTop( nTop ), mnRight( nRight ), mnBottom( nBottom ) + { + } + + virtual sal_Int32 SAL_CALL getCount( ) override + { + return ( mnRight - mnLeft + 1 ) * ( mnBottom - mnTop + 1 ); + } + virtual uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override + { + if ( Index < 0 || Index >= getCount() ) + throw css::lang::IndexOutOfBoundsException(); + + for( sal_Int32 row = mnTop; row <= mnBottom; row++ ) + { + for( sal_Int32 col = mnLeft; col <= mnRight; col++ ) + { + if( Index == ( ( row - mnTop ) * ( mnRight - mnLeft + 1 ) + ( col - mnLeft ) ) ) + return uno::Any( uno::Reference< word::XCell >( new SwVbaCell( mxParent, mxContext, mxTextTable, col, row ) ) ); + } + } + throw css::lang::IndexOutOfBoundsException(); + + } + virtual uno::Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<word::XCell>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + return true; + } + // XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + return new CellsEnumWrapper( this ); + } +}; + +} + +SwVbaCells::SwVbaCells( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< text::XTextTable >& xTextTable, sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) : SwVbaCells_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( new CellCollectionHelper( xParent, xContext, xTextTable, nLeft, nTop, nRight, nBottom ) ) ), mxTextTable( xTextTable ), mnTop( nTop ), mnBottom( nBottom ) +{ +} + +::sal_Int32 SAL_CALL SwVbaCells::getWidth() +{ + uno::Reference< word::XCell > xCell( m_xIndexAccess->getByIndex( 0 ), uno::UNO_QUERY_THROW ); + return xCell->getWidth(); +} + +void SAL_CALL SwVbaCells::setWidth( ::sal_Int32 _width ) +{ + sal_Int32 nIndex = 0; + while( nIndex < m_xIndexAccess->getCount() ) + { + uno::Reference< word::XCell > xCell( m_xIndexAccess->getByIndex( nIndex++ ), uno::UNO_QUERY_THROW ); + xCell->setWidth( _width ); + } +} + +uno::Any SAL_CALL SwVbaCells::getHeight() +{ + uno::Reference< word::XRow > xRow( new SwVbaRow( getParent(), mxContext, mxTextTable, mnTop ) ); + return xRow->getHeight(); +} + +void SAL_CALL SwVbaCells::setHeight( const uno::Any& _height ) +{ + for( sal_Int32 row = mnTop; row <= mnBottom; row++ ) + { + uno::Reference< word::XRow > xRow( new SwVbaRow( getParent(), mxContext, mxTextTable, row ) ); + xRow->setHeight( _height ); + } +} + +::sal_Int32 SAL_CALL SwVbaCells::getHeightRule() +{ + uno::Reference< word::XRow > xRow( new SwVbaRow( getParent(), mxContext, mxTextTable, mnTop ) ); + return xRow->getHeightRule(); +} + +void SAL_CALL SwVbaCells::setHeightRule( ::sal_Int32 _heightrule ) +{ + for( sal_Int32 row = mnTop; row <= mnBottom; row++ ) + { + uno::Reference< word::XRow > xRow( new SwVbaRow( getParent(), mxContext, mxTextTable, row ) ); + xRow->setHeightRule( _heightrule ); + } +} + +void SAL_CALL SwVbaCells::SetWidth( float width, sal_Int32 rulestyle ) +{ + sal_Int32 nIndex = 0; + while( nIndex < m_xIndexAccess->getCount() ) + { + uno::Reference< word::XCell > xCell( m_xIndexAccess->getByIndex( nIndex++ ), uno::UNO_QUERY_THROW ); + xCell->SetWidth( width, rulestyle ); + } +} + +void SAL_CALL SwVbaCells::SetHeight( float height, sal_Int32 heightrule ) +{ + for( sal_Int32 row = mnTop; row <= mnBottom; row++ ) + { + uno::Reference< word::XRow > xRow( new SwVbaRow( getParent(), mxContext, mxTextTable, row ) ); + xRow->SetHeight( height, heightrule ); + } +} + +// XEnumerationAccess +uno::Type +SwVbaCells::getElementType() +{ + return cppu::UnoType<word::XCell>::get(); +} + +uno::Reference< container::XEnumeration > +SwVbaCells::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return xEnumAccess->createEnumeration(); +} + +uno::Any +SwVbaCells::createCollectionObject( const uno::Any& aSource ) +{ + return aSource; +} + +OUString +SwVbaCells::getServiceImplName() +{ + return "SwVbaCells"; +} + +uno::Sequence<OUString> +SwVbaCells::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.Cells" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacells.hxx b/sw/source/ui/vba/vbacells.hxx new file mode 100644 index 0000000000..e9de9f532f --- /dev/null +++ b/sw/source/ui/vba/vbacells.hxx @@ -0,0 +1,63 @@ +/* -*- 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_VBA_VBACELLS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBACELLS_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XCells.hpp> +#include <com/sun/star/text/XTextTable.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XCells > SwVbaCells_BASE; + +class SwVbaCells : public SwVbaCells_BASE +{ +private: + css::uno::Reference< css::text::XTextTable > mxTextTable; + sal_Int32 mnTop; + sal_Int32 mnBottom; + +public: + /// @throws css::uno::RuntimeException + SwVbaCells( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::text::XTextTable >& xTextTable, sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ); + + // Attributes + virtual ::sal_Int32 SAL_CALL getWidth() override; + virtual void SAL_CALL setWidth( ::sal_Int32 _width ) override; + virtual css::uno::Any SAL_CALL getHeight() override; + virtual void SAL_CALL setHeight( const css::uno::Any& _height ) override; + virtual ::sal_Int32 SAL_CALL getHeightRule() override; + virtual void SAL_CALL setHeightRule( ::sal_Int32 _heightrule ) override; + + // Methods + virtual void SAL_CALL SetWidth( float width, sal_Int32 rulestyle ) override; + virtual void SAL_CALL SetHeight( float height, sal_Int32 heightrule ) override; + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaCells_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBACELLS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacolumn.cxx b/sw/source/ui/vba/vbacolumn.cxx new file mode 100644 index 0000000000..c4411bfab4 --- /dev/null +++ b/sw/source/ui/vba/vbacolumn.cxx @@ -0,0 +1,91 @@ +/* -*- 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 "vbacolumn.hxx" +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include "vbatablehelper.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaColumn::SwVbaColumn( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< text::XTextTable > xTextTable, sal_Int32 nIndex ) : + SwVbaColumn_BASE( rParent, rContext ), mxTextTable(std::move( xTextTable )), mnIndex( nIndex ) +{ +} + +SwVbaColumn::~SwVbaColumn() +{ +} + +sal_Int32 SAL_CALL +SwVbaColumn::getWidth( ) +{ + SwVbaTableHelper aTableHelper( mxTextTable ); + return aTableHelper.GetColWidth( mnIndex ); +} + +void SAL_CALL +SwVbaColumn::setWidth( sal_Int32 _width ) +{ + + SwVbaTableHelper aTableHelper( mxTextTable ); + aTableHelper.SetColWidth( _width, mnIndex ); +} + +void SAL_CALL +SwVbaColumn::Select( ) +{ + SelectColumn( getCurrentWordDoc(mxContext), mxTextTable, mnIndex, mnIndex ); +} + +void SwVbaColumn::SelectColumn( const uno::Reference< frame::XModel >& xModel, const uno::Reference< text::XTextTable >& xTextTable, sal_Int32 nStartColumn, sal_Int32 nEndColumn ) +{ + OUString sStartCol = SwVbaTableHelper::getColumnStr( nStartColumn ); + OUString aRangeName = sStartCol + OUString::number( 1 ); + OUString sEndCol = SwVbaTableHelper::getColumnStr( nEndColumn ); + sal_Int32 nRowCount = xTextTable->getRows()->getCount(); + aRangeName += ":" + sEndCol + OUString::number(nRowCount); + + uno::Reference< table::XCellRange > xCellRange( xTextTable, uno::UNO_QUERY_THROW ); + uno::Reference< table::XCellRange > xSelRange = xCellRange->getCellRangeByName( aRangeName ); + + uno::Reference< view::XSelectionSupplier > xSelection( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); + xSelection->select( uno::Any( xSelRange ) ); +} + +OUString +SwVbaColumn::getServiceImplName() +{ + return "SwVbaColumn"; +} + +uno::Sequence< OUString > +SwVbaColumn::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Column" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacolumn.hxx b/sw/source/ui/vba/vbacolumn.hxx new file mode 100644 index 0000000000..4fe34de54a --- /dev/null +++ b/sw/source/ui/vba/vbacolumn.hxx @@ -0,0 +1,53 @@ +/* -*- 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_VBA_VBACOLUMN_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBACOLUMN_HXX + +#include <ooo/vba/word/XColumn.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextTable.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XColumn > SwVbaColumn_BASE; + +class SwVbaColumn : public SwVbaColumn_BASE +{ +private: + css::uno::Reference< css::text::XTextTable > mxTextTable; + sal_Int32 mnIndex; + +public: + /// @throws css::uno::RuntimeException + SwVbaColumn( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::text::XTextTable > xTextTable, sal_Int32 nIndex ); + virtual ~SwVbaColumn() override; + + // Methods + virtual sal_Int32 SAL_CALL getWidth() override; + virtual void SAL_CALL setWidth( sal_Int32 _width ) override; + virtual void SAL_CALL Select( ) override; + + /// @throws css::uno::RuntimeException + static void SelectColumn( const css::uno::Reference< css::frame::XModel >& xModel, const css::uno::Reference< css::text::XTextTable >& xTextTable, sal_Int32 nStartColumn, sal_Int32 nEndColumn ); + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBACOLUMN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacolumns.cxx b/sw/source/ui/vba/vbacolumns.cxx new file mode 100644 index 0000000000..ffaf662029 --- /dev/null +++ b/sw/source/ui/vba/vbacolumns.cxx @@ -0,0 +1,149 @@ +/* -*- 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 <utility> + +#include "vbacolumns.hxx" +#include "vbacolumn.hxx" +#include "vbatablehelper.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +class ColumnsEnumWrapper : public EnumerationHelper_BASE +{ + uno::WeakReference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< text::XTextTable > mxTextTable; + uno::Reference< container::XIndexAccess > mxIndexAccess; + sal_Int32 mnIndex; + +public: + ColumnsEnumWrapper( const uno::Reference< XHelperInterface >& xParent, uno::Reference< uno::XComponentContext > xContext, uno::Reference< text::XTextTable > xTextTable ) : mxParent( xParent ), mxContext(std::move( xContext )), mxTextTable(std::move( xTextTable )), mnIndex( 0 ) + { + mxIndexAccess = mxTextTable->getColumns(); + } + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( mnIndex < mxIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if( mnIndex < mxIndexAccess->getCount() ) + { + return uno::Any( uno::Reference< word::XColumn > ( new SwVbaColumn( mxParent, mxContext, mxTextTable, mnIndex++ ) ) ); + } + throw container::NoSuchElementException(); + } +}; + +} + +SwVbaColumns::SwVbaColumns( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, uno::Reference< text::XTextTable > xTextTable, const uno::Reference< table::XTableColumns >& xTableColumns ) : SwVbaColumns_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( xTableColumns, uno::UNO_QUERY_THROW ) ), mxTextTable(std::move( xTextTable )) +{ + mnStartColumnIndex = 0; + SwVbaTableHelper aTableHelper( mxTextTable ); + mnEndColumnIndex = aTableHelper.getTabColumnsMaxCount( ) - 1; +} + +SwVbaColumns::SwVbaColumns( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, uno::Reference< text::XTextTable > xTextTable, const uno::Reference< table::XTableColumns >& xTableColumns, sal_Int32 nStartCol, sal_Int32 nEndCol ) : SwVbaColumns_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( xTableColumns, uno::UNO_QUERY_THROW ) ), mxTextTable(std::move( xTextTable )), mnStartColumnIndex( nStartCol ), mnEndColumnIndex( nEndCol ) +{ + if( mnEndColumnIndex < mnStartColumnIndex ) + throw uno::RuntimeException(); +} + +uno::Reference< word::XColumn > SwVbaColumns::getColumnAtIndex( sal_Int32 index ) +{ + return uno::Reference< word::XColumn >( new SwVbaColumn( this, mxContext, mxTextTable, index ) ); +} + +::sal_Int32 SAL_CALL SwVbaColumns::getWidth() +{ + return getColumnAtIndex( mnStartColumnIndex )->getWidth(); +} + +void SAL_CALL SwVbaColumns::setWidth( ::sal_Int32 _width ) +{ + for( sal_Int32 index = mnStartColumnIndex; index <= mnEndColumnIndex; index++ ) + { + getColumnAtIndex( index )->setWidth( _width ); + } +} + +void SAL_CALL SwVbaColumns::Select( ) +{ + SwVbaColumn::SelectColumn( getCurrentWordDoc(mxContext), mxTextTable, mnStartColumnIndex, mnEndColumnIndex ); +} + +::sal_Int32 SAL_CALL SwVbaColumns::getCount() +{ + return ( mnEndColumnIndex - mnStartColumnIndex + 1 ); +} + +uno::Any SAL_CALL SwVbaColumns::Item( const uno::Any& Index1, const uno::Any& /*not processed in this base class*/ ) +{ + sal_Int32 nIndex = 0; + if( Index1 >>= nIndex ) + { + if( nIndex <= 0 || nIndex > getCount() ) + { + throw lang::IndexOutOfBoundsException("Index out of bounds" ); + } + return uno::Any( uno::Reference< word::XColumn >( new SwVbaColumn( this, mxContext, mxTextTable, nIndex - 1 ) ) ); + } + throw uno::RuntimeException("Index out of bounds" ); +} + +// XEnumerationAccess +uno::Type +SwVbaColumns::getElementType() +{ + return cppu::UnoType<word::XColumn>::get(); +} +uno::Reference< container::XEnumeration > +SwVbaColumns::createEnumeration() +{ + return new ColumnsEnumWrapper( this, mxContext, mxTextTable ); +} + +uno::Any +SwVbaColumns::createCollectionObject( const uno::Any& aSource ) +{ + return aSource; +} + +OUString +SwVbaColumns::getServiceImplName() +{ + return "SwVbaColumns"; +} + +uno::Sequence<OUString> +SwVbaColumns::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.Columns" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacolumns.hxx b/sw/source/ui/vba/vbacolumns.hxx new file mode 100644 index 0000000000..712dc03f0b --- /dev/null +++ b/sw/source/ui/vba/vbacolumns.hxx @@ -0,0 +1,66 @@ +/* -*- 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_VBA_VBACOLUMNS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBACOLUMNS_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XColumns.hpp> +#include <ooo/vba/word/XColumn.hpp> +#include <com/sun/star/table/XTableColumns.hpp> +#include <com/sun/star/text/XTextTable.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XColumns > SwVbaColumns_BASE; + +class SwVbaColumns : public SwVbaColumns_BASE +{ +private: + css::uno::Reference< css::text::XTextTable > mxTextTable; + sal_Int32 mnStartColumnIndex; + sal_Int32 mnEndColumnIndex; + +private: + /// @throws css::uno::RuntimeException + css::uno::Reference< ooo::vba::word::XColumn > getColumnAtIndex( sal_Int32 index ); + +public: + /// @throws css::uno::RuntimeException + SwVbaColumns( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, css::uno::Reference< css::text::XTextTable > xTextTable, const css::uno::Reference< css::table::XTableColumns >& xTableColumns ); + /// @throws css::uno::RuntimeException + SwVbaColumns( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, css::uno::Reference< css::text::XTextTable > xTextTable, const css::uno::Reference< css::table::XTableColumns >& xTableColumns, sal_Int32 nStartCol, sal_Int32 nEndCol ); + + virtual sal_Int32 SAL_CALL getWidth( ) override; + virtual void SAL_CALL setWidth( sal_Int32 _width ) override; + virtual void SAL_CALL Select( ) override; + + //XCollection + virtual ::sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index1, const css::uno::Any& /*not processed in this base class*/ ) override; + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaColumns_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBACOLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacontentcontrol.cxx b/sw/source/ui/vba/vbacontentcontrol.cxx new file mode 100644 index 0000000000..dc4e4afc23 --- /dev/null +++ b/sw/source/ui/vba/vbacontentcontrol.cxx @@ -0,0 +1,753 @@ +/* -*- 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 <ooo/vba/word/WdColor.hpp> +#include <ooo/vba/word/WdCalendarType.hpp> +#include <ooo/vba/word/WdContentControlType.hpp> +#include <ooo/vba/word/WdLanguageID.hpp> + +#include <sal/log.hxx> + +#include <ndtxt.hxx> +#include <unotextrange.hxx> + +#include "vbacontentcontrol.hxx" +#include "vbacontentcontrollistentries.hxx" +#include "vbarange.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +/** + * Content controls are the modern version of FormFields, providing inline functionality similar + * to that of ActiveX form controls. Individual content controls may contain contents + * such as dates, lists, or paragraphs of formatted text. + * + * Not all functions are applicable to each type of control, so use getType verification liberally. + */ +SwVbaContentControl::SwVbaContentControl(const uno::Reference<XHelperInterface>& rParent, + const uno::Reference<uno::XComponentContext>& rContext, + const uno::Reference<text::XTextDocument>& xTextDocument, + std::shared_ptr<SwContentControl> pContentControl) + : SwVbaContentControl_BASE(rParent, rContext) + , mxTextDocument(xTextDocument) + , m_pCC(pContentControl) +{ + assert(m_pCC && "SwVbaContentControl created without a shared_ptr. Why would you do that?"); +} + +SwVbaContentControl::~SwVbaContentControl() {} + +sal_Bool SwVbaContentControl::getAllowInsertDeleteSection() +{ + SAL_INFO("sw.vba", "SwVbaContentControl::getAllowInsertDeleteSection stub"); + return false; +} + +void SwVbaContentControl::setAllowInsertDeleteSection(sal_Bool /*bSet*/) +{ + SAL_INFO("sw.vba", "SwVbaContentControl::setAllowInsertDeleteSection stub"); +} + +sal_Int32 SwVbaContentControl::getAppearance() +{ + SAL_INFO("sw.vba", "SwVbaContentControl::getAppearance stub"); + // wdContentControlBoundingBox / wdContentControlHidden / wdContentControlTags + return 0; +} + +void SwVbaContentControl::setAppearance(sal_Int32 nSet) +{ + SAL_INFO("sw.vba", "SwVbaContentControl::setAppearance[" << nSet << "] stub"); +} + +OUString SwVbaContentControl::getBuildingBlockCategory() +{ + SAL_INFO("sw.vba", "SwVbaContentControl::getBuildingBlockCategory stub"); + return OUString(); +} + +void SwVbaContentControl::setBuildingBlockCategory(const OUString& sSet) +{ + SAL_INFO("sw.vba", "SwVbaContentControl::setBuildingBlockCategory[" << sSet << "] stub"); +} + +sal_Int32 SwVbaContentControl::getBuildingBlockType() +{ + SAL_INFO("sw.vba", "SwVbaContentControl::getBuildingBlockType stub"); + // returns a WdBuildingBlockTypes that represents the type of building block + return 0; +} + +void SwVbaContentControl::setBuildingBlockType(sal_Int32 nSet) +{ + SAL_INFO("sw.vba", "SwVbaContentControl::setBuildingBlockType[" << nSet << "] stub"); +} + +sal_Bool SwVbaContentControl::getChecked() { return m_pCC->GetCheckbox() && m_pCC->GetChecked(); } + +void SwVbaContentControl::setChecked(sal_Bool bSet) +{ + // Word 2010: if locked, then the checked status is changed, but not the underlying text. + // Do we really want to do that? That is pretty bizarre behaviour... + // For now, just implement what seems to be a more logical response. + // TODO: test with modern versions. + if (getLockContents()) + return; + + if (m_pCC->GetCheckbox() && m_pCC->GetChecked() != static_cast<bool>(bSet)) + { + m_pCC->SetChecked(bSet); + m_pCC->SetShowingPlaceHolder(false); + if (m_pCC->GetTextAttr()) + m_pCC->GetTextAttr()->Invalidate(); + } +} + +sal_Int32 SwVbaContentControl::getColor() +{ + //This is just an assumed implementation - I have no testing environment to confirm. + OUString sColor = m_pCC->GetColor(); + if (sColor == "wdColorAutomatic") + return word::WdColor::wdColorAutomatic; + if (sColor == "wdColorBlack") + return word::WdColor::wdColorBlack; + if (sColor == "wdColorBlue") + return word::WdColor::wdColorBlue; + if (sColor == "wdColorBlueGray") + return word::WdColor::wdColorBlueGray; + if (sColor == "wdColorBrightGreen") + return word::WdColor::wdColorBrightGreen; + if (sColor == "wdColorBrown") + return word::WdColor::wdColorBrown; + if (sColor == "wdColorDarkBlue") + return word::WdColor::wdColorDarkBlue; + if (sColor == "wdColorDarkGreen") + return word::WdColor::wdColorDarkGreen; + if (sColor == "wdColorDarkRed") + return word::WdColor::wdColorDarkRed; + if (sColor == "wdColorDarkTeal") + return word::WdColor::wdColorDarkTeal; + if (sColor == "wdColorDarkYellow") + return word::WdColor::wdColorDarkYellow; + if (sColor == "wdColorGold") + return word::WdColor::wdColorGold; + if (sColor == "wdColorGray05") + return word::WdColor::wdColorGray05; + if (sColor == "wdColorGray10") + return word::WdColor::wdColorGray10; + if (sColor == "wdColorGray125") + return word::WdColor::wdColorGray125; + if (sColor == "wdColorGray15") + return word::WdColor::wdColorGray15; + if (sColor == "wdColorGray20") + return word::WdColor::wdColorGray20; + if (sColor == "wdColorGray25") + return word::WdColor::wdColorGray25; + if (sColor == "wdColorGray30") + return word::WdColor::wdColorGray30; + if (sColor == "wdColorGray35") + return word::WdColor::wdColorGray35; + if (sColor == "wdColorGray375") + return word::WdColor::wdColorGray375; + if (sColor == "wdColorGray40") + return word::WdColor::wdColorGray40; + if (sColor == "wdColorGray45") + return word::WdColor::wdColorGray45; + if (sColor == "wdColorGray50") + return word::WdColor::wdColorGray50; + if (sColor == "wdColorGray55") + return word::WdColor::wdColorGray55; + if (sColor == "wdColorGray60") + return word::WdColor::wdColorGray60; + if (sColor == "wdColorGray625") + return word::WdColor::wdColorGray625; + if (sColor == "wdColorGray65") + return word::WdColor::wdColorGray65; + if (sColor == "wdColorGray70") + return word::WdColor::wdColorGray70; + if (sColor == "wdColorGray75") + return word::WdColor::wdColorGray75; + if (sColor == "wdColorGray80") + return word::WdColor::wdColorGray80; + if (sColor == "wdColorGray85") + return word::WdColor::wdColorGray85; + if (sColor == "wdColorGray875") + return word::WdColor::wdColorGray875; + if (sColor == "wdColorGray90") + return word::WdColor::wdColorGray90; + if (sColor == "wdColorGray95") + return word::WdColor::wdColorGray95; + if (sColor == "wdColorGreen") + return word::WdColor::wdColorGreen; + if (sColor == "wdColorIndigo") + return word::WdColor::wdColorIndigo; + if (sColor == "wdColorLavender") + return word::WdColor::wdColorLavender; + if (sColor == "wdColorLightBlue") + return word::WdColor::wdColorLightBlue; + if (sColor == "wdColorLightGreen") + return word::WdColor::wdColorLightGreen; + if (sColor == "wdColorLightOrange") + return word::WdColor::wdColorLightOrange; + if (sColor == "wdColorLightTurquoise") + return word::WdColor::wdColorLightTurquoise; + if (sColor == "wdColorLightYellow") + return word::WdColor::wdColorLightYellow; + if (sColor == "wdColorLime") + return word::WdColor::wdColorLime; + if (sColor == "wdColorOliveGreen") + return word::WdColor::wdColorOliveGreen; + if (sColor == "wdColorOrange") + return word::WdColor::wdColorOrange; + if (sColor == "wdColorPaleBlue") + return word::WdColor::wdColorPaleBlue; + if (sColor == "wdColorPink") + return word::WdColor::wdColorPink; + if (sColor == "wdColorPlum") + return word::WdColor::wdColorPlum; + if (sColor == "wdColorRed") + return word::WdColor::wdColorRed; + if (sColor == "wdColorRose") + return word::WdColor::wdColorRose; + if (sColor == "wdColorSeaGreen") + return word::WdColor::wdColorSeaGreen; + if (sColor == "wdColorSkyBlue") + return word::WdColor::wdColorSkyBlue; + if (sColor == "wdColorTan") + return word::WdColor::wdColorTan; + if (sColor == "wdColorTeal") + return word::WdColor::wdColorTeal; + if (sColor == "wdColorTurquoise") + return word::WdColor::wdColorTurquoise; + if (sColor == "wdColorViolet") + return word::WdColor::wdColorViolet; + if (sColor == "wdColorWhite") + return word::WdColor::wdColorWhite; + if (sColor == "wdColorYellow") + return word::WdColor::wdColorYellow; + + return word::WdColor::wdColorBlack; +} + +void SwVbaContentControl::setColor(sal_Int32 nWdColor) +{ + switch (nWdColor) + { + case word::WdColor::wdColorAqua: + m_pCC->SetColor("wdColorAqua"); + break; + case word::WdColor::wdColorAutomatic: + m_pCC->SetColor("wdColorAutomatic"); + break; + case word::WdColor::wdColorBlack: + m_pCC->SetColor("wdColorBlack"); + break; + case word::WdColor::wdColorBlue: + m_pCC->SetColor("wdColorBlue"); + break; + case word::WdColor::wdColorBlueGray: + m_pCC->SetColor("wdColorBlueGray"); + break; + case word::WdColor::wdColorBrightGreen: + m_pCC->SetColor("wdColorBrightGreen"); + break; + case word::WdColor::wdColorBrown: + m_pCC->SetColor("wdColorBrown"); + break; + case word::WdColor::wdColorDarkBlue: + m_pCC->SetColor("wdColorDarkBlue"); + break; + case word::WdColor::wdColorDarkGreen: + m_pCC->SetColor("wdColorDarkGreen"); + break; + case word::WdColor::wdColorDarkRed: + m_pCC->SetColor("wdColorDarkRed"); + break; + case word::WdColor::wdColorDarkTeal: + m_pCC->SetColor("wdColorDarkTeal"); + break; + case word::WdColor::wdColorDarkYellow: + m_pCC->SetColor("wdColorDarkYellow"); + break; + case word::WdColor::wdColorGold: + m_pCC->SetColor("wdColorGold"); + break; + case word::WdColor::wdColorGray05: + m_pCC->SetColor("wdColorGray05"); + break; + case word::WdColor::wdColorGray10: + m_pCC->SetColor("wdColorGray10"); + break; + case word::WdColor::wdColorGray125: + m_pCC->SetColor("wdColorGray125"); + break; + case word::WdColor::wdColorGray15: + m_pCC->SetColor("wdColorGray15"); + break; + case word::WdColor::wdColorGray20: + m_pCC->SetColor("wdColorGray20"); + break; + case word::WdColor::wdColorGray25: + m_pCC->SetColor("wdColorGray25"); + break; + case word::WdColor::wdColorGray30: + m_pCC->SetColor("wdColorGray30"); + break; + case word::WdColor::wdColorGray35: + m_pCC->SetColor("wdColorGray35"); + break; + case word::WdColor::wdColorGray375: + m_pCC->SetColor("wdColorGray375"); + break; + case word::WdColor::wdColorGray40: + m_pCC->SetColor("wdColorGray40"); + break; + case word::WdColor::wdColorGray45: + m_pCC->SetColor("wdColorGray45"); + break; + case word::WdColor::wdColorGray50: + m_pCC->SetColor("wdColorGray50"); + break; + case word::WdColor::wdColorGray55: + m_pCC->SetColor("wdColorGray55"); + break; + case word::WdColor::wdColorGray60: + m_pCC->SetColor("wdColorGray60"); + break; + case word::WdColor::wdColorGray625: + m_pCC->SetColor("wdColorGray625"); + break; + case word::WdColor::wdColorGray65: + m_pCC->SetColor("wdColorGray65"); + break; + case word::WdColor::wdColorGray70: + m_pCC->SetColor("wdColorGray70"); + break; + case word::WdColor::wdColorGray75: + m_pCC->SetColor("wdColorGray75"); + break; + case word::WdColor::wdColorGray80: + m_pCC->SetColor("wdColorGray80"); + break; + case word::WdColor::wdColorGray85: + m_pCC->SetColor("wdColorGray85"); + break; + case word::WdColor::wdColorGray875: + m_pCC->SetColor("wdColorGray875"); + break; + case word::WdColor::wdColorGray90: + m_pCC->SetColor("wdColorGray90"); + break; + case word::WdColor::wdColorGray95: + m_pCC->SetColor("wdColorGray95"); + break; + case word::WdColor::wdColorGreen: + m_pCC->SetColor("wdColorGreen"); + break; + case word::WdColor::wdColorIndigo: + m_pCC->SetColor("wdColorIndigo"); + break; + case word::WdColor::wdColorLavender: + m_pCC->SetColor("wdColorLavender"); + break; + case word::WdColor::wdColorLightBlue: + m_pCC->SetColor("wdColorLightBlue"); + break; + case word::WdColor::wdColorLightGreen: + m_pCC->SetColor("wdColorLightGreen"); + break; + case word::WdColor::wdColorLightOrange: + m_pCC->SetColor("wdColorLightOrange"); + break; + case word::WdColor::wdColorLightTurquoise: + m_pCC->SetColor("wdColorLightTurquoise"); + break; + case word::WdColor::wdColorLightYellow: + m_pCC->SetColor("wdColorLightYellow"); + break; + case word::WdColor::wdColorLime: + m_pCC->SetColor("wdColorLime"); + break; + case word::WdColor::wdColorOliveGreen: + m_pCC->SetColor("wdColorOliveGreen"); + break; + case word::WdColor::wdColorOrange: + m_pCC->SetColor("wdColorOrange"); + break; + case word::WdColor::wdColorPaleBlue: + m_pCC->SetColor("wdColorPaleBlue"); + break; + case word::WdColor::wdColorPink: + m_pCC->SetColor("wdColorPink"); + break; + case word::WdColor::wdColorPlum: + m_pCC->SetColor("wdColorPlum"); + break; + case word::WdColor::wdColorRed: + m_pCC->SetColor("wdColorRed"); + break; + case word::WdColor::wdColorRose: + m_pCC->SetColor("wdColorRose"); + break; + case word::WdColor::wdColorSeaGreen: + m_pCC->SetColor("wdColorSeaGreen"); + break; + case word::WdColor::wdColorSkyBlue: + m_pCC->SetColor("wdColorSkyBlue"); + break; + case word::WdColor::wdColorTan: + m_pCC->SetColor("wdColorTan"); + break; + case word::WdColor::wdColorTeal: + m_pCC->SetColor("wdColorTeal"); + break; + case word::WdColor::wdColorTurquoise: + m_pCC->SetColor("wdColorTurquoise"); + break; + case word::WdColor::wdColorViolet: + m_pCC->SetColor("wdColorViolet"); + break; + case word::WdColor::wdColorWhite: + m_pCC->SetColor("wdColorWhite"); + break; + default:; + } +} + +sal_Int32 SwVbaContentControl::getDateCalendarType() +{ + SAL_INFO("sw.vba", "SwVbaContentControl::getDateCalendarType stub"); + // returns a WdCalendarTypes that represents the type of building block + return word::WdCalendarType::wdCalendarWestern; +} + +void SwVbaContentControl::setDateCalendarType(sal_Int32 nSet) +{ + SAL_INFO("sw.vba", "SwVbaContentControl::setDateCalendarType[" << nSet << "] stub"); +} + +OUString SwVbaContentControl::getDateDisplayFormat() { return m_pCC->GetDateFormat(); } + +void SwVbaContentControl::setDateDisplayFormat(const OUString& sSet) { m_pCC->SetDateFormat(sSet); } + +sal_Int32 SwVbaContentControl::getDateStorageFormat() +{ + SAL_INFO("sw.vba", "SwVbaContentControl::getDateStorageFormat stub"); + // returns a WdContentControlDateStorageFormat when bound to the XML data store. + return 0; +} + +void SwVbaContentControl::setDateStorageFormat(sal_Int32 nSet) +{ + SAL_INFO("sw.vba", "SwVbaContentControl::setDateStorageFormat[" << nSet << "] stub"); +} + +sal_Int32 SwVbaContentControl::getDateDisplayLocale() +{ + SAL_INFO("sw.vba", "SwVbaContentControl::getDateDisplayLocale stub"); + // returns a WdLanguageID that represents the language format for a date content control. + return word::WdLanguageID::wdEnglishUS; +} + +uno::Any SwVbaContentControl::getDropdownListEntries() +{ + if (!m_pCC->GetDropDown() && !m_pCC->GetComboBox()) + return uno::Any(); + + return uno::Any( + uno::Reference<XCollection>(new SwVbaContentControlListEntries(this, mxContext, m_pCC))); +} + +OUString SwVbaContentControl::getID() +{ + // This signed integer is treated in VBA as if it was an unsigned int. + return OUString::number(static_cast<sal_uInt32>(m_pCC->GetId())); +} + +sal_Int32 SwVbaContentControl::getLevel() +{ + SAL_INFO("sw.vba", "SwVbaContentControl::getLevel stub"); + // returns a WdContentControlLevel + return 0; +} + +sal_Bool SwVbaContentControl::getLockContentControl() +{ + std::optional<bool> oLock = m_pCC->GetLock(/*bControl=*/true); + return oLock.has_value() && *oLock; +} + +void SwVbaContentControl::setLockContentControl(sal_Bool bSet) +{ + std::optional<bool> oLock = m_pCC->GetLock(/*bControl=*/false); + m_pCC->SetLock(/*bContents=*/oLock.has_value() && *oLock, /*bControl=*/bSet); +} + +sal_Bool SwVbaContentControl::getLockContents() +{ + // If the theoretical design model says it is locked, then report as locked. + std::optional<bool> oLock = m_pCC->GetLock(/*bControl=*/false); + if (oLock.has_value() && *oLock) + return true; + + // Now check the real implementation. + // Checkbox/DropDown/Picture are normally locked - but not in this sense. Report as unlocked. + if (m_pCC->GetType() == SwContentControlType::CHECKBOX + || m_pCC->GetType() == SwContentControlType::DROP_DOWN_LIST + || m_pCC->GetType() == SwContentControlType::PICTURE) + { + return false; + } + + return m_pCC->GetReadWrite(); +} + +void SwVbaContentControl::setLockContents(sal_Bool bSet) +{ + // Set the lock both theoretically and actually. + std::optional<bool> oLock = m_pCC->GetLock(/*bControl=*/true); + m_pCC->SetLock(/*bContents=*/bSet, /*bControl=*/oLock.has_value() && *oLock); + + // Checkbox/DropDown/Picture are normally locked in LO implementation - don't unlock them. + if (m_pCC->GetType() == SwContentControlType::CHECKBOX + || m_pCC->GetType() == SwContentControlType::DROP_DOWN_LIST + || m_pCC->GetType() == SwContentControlType::PICTURE) + { + return; + } + m_pCC->SetReadWrite(bSet); +} + +sal_Bool SwVbaContentControl::getMultiLine() +{ + SAL_INFO("sw.vba", "SwVbaContentControl::getMultiLine stub"); + return false; +} + +void SwVbaContentControl::setMultiLine(sal_Bool /*bSet*/) +{ + SAL_INFO("sw.vba", "SwVbaContentControl::setMultiLine stub"); +} + +OUString SwVbaContentControl::getPlaceholderText() +{ + // return m_pCC->GetPlaceholderDocPart(); // This is not correct. Much more complex than this... + SAL_INFO("sw.vba", "SwVbaContentControl::getPlaceholderText stub"); + return OUString(); +} + +sal_Bool SwVbaContentControl::getShowingPlaceholderText() { return m_pCC->GetShowingPlaceHolder(); } + +uno::Reference<word::XRange> SwVbaContentControl::getRange() +{ + uno::Reference<word::XRange> xRet; + SwTextNode* pTextNode = m_pCC->GetTextNode(); + if (pTextNode && m_pCC->GetTextAttr()) + { + // Don't select the text attribute itself at the start. + SwPosition aStart(*pTextNode, m_pCC->GetTextAttr()->GetStart() + 1); + // Don't select the CH_TXTATR_BREAKWORD itself at the end. + SwPosition aEnd(*pTextNode, *m_pCC->GetTextAttr()->End() - 1); + uno::Reference<text::XTextRange> xText( + SwXTextRange::CreateXTextRange(pTextNode->GetDoc(), aStart, &aEnd)); + if (xText.is()) + xRet = new SwVbaRange(mxParent, mxContext, mxTextDocument, xText->getStart(), + xText->getEnd()); + } + return xRet; +} + +OUString SwVbaContentControl::getRepeatingSectionItemTitle() +{ + SAL_INFO("sw.vba", "SwVbaContentControl::getRepeatingSectionItemTitle stub"); + return OUString(); +} + +void SwVbaContentControl::setRepeatingSectionItemTitle(const OUString& rSet) +{ + SAL_INFO("sw.vba", "SwVbaContentControl::setRepeatingSectionItemTitle[" << rSet << "] stub"); +} + +OUString SwVbaContentControl::getTag() { return m_pCC->GetTag(); } + +void SwVbaContentControl::setTag(const OUString& rSet) { return m_pCC->SetTag(rSet); } + +sal_Bool SwVbaContentControl::getTemporary() +{ + SAL_INFO("sw.vba", "SwVbaContentControl::getTemporary stub"); + // Is content control removed when user edits (one time use)? Not implemented in LO. + return false; +} + +void SwVbaContentControl::setTemporary(sal_Bool /*bSet*/) +{ + SAL_INFO("sw.vba", "SwVbaContentControl::setTemporary stub"); +} + +OUString SwVbaContentControl::getTitle() { return m_pCC->GetAlias(); } + +void SwVbaContentControl::setTitle(const OUString& rSet) { return m_pCC->SetAlias(rSet); } + +sal_Int32 SwVbaContentControl::getType() +{ + SwContentControlType eType = m_pCC->GetType(); + sal_Int32 eVbaType = word::WdContentControlType::wdContentControlRichText; + + switch (eType) + { + case SwContentControlType::CHECKBOX: + eVbaType = word::WdContentControlType::wdContentControlCheckbox; + break; + case SwContentControlType::DROP_DOWN_LIST: + eVbaType = word::WdContentControlType::wdContentControlDropdownList; + break; + case SwContentControlType::PICTURE: + eVbaType = word::WdContentControlType::wdContentControlPicture; + break; + case SwContentControlType::DATE: + eVbaType = word::WdContentControlType::wdContentControlDate; + break; + case SwContentControlType::PLAIN_TEXT: + eVbaType = word::WdContentControlType::wdContentControlText; + break; + case SwContentControlType::COMBO_BOX: + eVbaType = word::WdContentControlType::wdContentControlComboBox; + break; + case SwContentControlType::RICH_TEXT: + default:; + } + return eVbaType; +} + +void SwVbaContentControl::setType(sal_Int32 nSet) +{ + SAL_INFO("sw.vba", "SwVbaContentControl::setType[" << nSet << "] stub"); + // SwContentControlType eType = SwContentControlType::RICH_TEXT; + // switch(nSet) + // { + // case word::WdContentControlType::wdContentControlCheckbox: + // eType = SwContentControlType::CHECKBOX; + // break; + // case word::WdContentControlType::wdContentControlDropdownList: + // eType = SwContentControlType::DROP_DOWN_LIST; + // break; + // case word::WdContentControlType::wdContentControlPicture: + // eType = SwContentControlType::PICTURE; + // break; + // case word::WdContentControlType::wdContentControlDate: + // eType = SwContentControlType::DATE; + // break; + // case word::WdContentControlType::wdContentControlText: + // eType = SwContentControlType::PLAIN_TEXT; + // break; + // case word::WdContentControlType::wdContentControlComboBox: + // eType = SwContentControlType::COMBO_BOX; + // break; + // case word::WdContentControlType::wdContentControlRichText: + // default:; + // } + // m_pCC->SetType(eType); +} + +void SwVbaContentControl::Copy() +{ + SAL_INFO("sw.vba", "SwVbaContentControl::Copy[" << getID() << "] stub"); +} + +void SwVbaContentControl::Cut() +{ + if (getLockContentControl() || !m_pCC->GetTextAttr()) + return; + + SAL_INFO("sw.vba", + "SwVbaContentControl::Cut[" << getID() << "], but missing sending to clipboard"); + + m_pCC->GetTextAttr()->Delete(/*bSaveContents=*/getLockContents()); +} + +void SwVbaContentControl::Delete(const uno::Any& DeleteContents) +{ + if (getLockContentControl() || !m_pCC->GetTextAttr()) + return; + + bool bDeleteContents = false; + DeleteContents >>= bDeleteContents; + + m_pCC->GetTextAttr()->Delete(/*bSaveContents=*/!bDeleteContents || getLockContents()); +} + +void SwVbaContentControl::SetCheckedSymbol(sal_Int32 Character, const uno::Any& Font) +{ + if (!m_pCC->GetTextAttr()) + return; + + SAL_INFO_IF(Font.hasValue(), "sw.vba", "SetCheckedSymbol Font[" << Font << "] stub"); + if (Character < 31 || Character > SAL_MAX_UINT16) + return; // unsupported character. Would such a thing exist in VBA? + + m_pCC->SetCheckedState(OUString(static_cast<sal_Unicode>(Character))); + + if (m_pCC->GetCheckbox() && m_pCC->GetChecked() && !m_pCC->GetShowingPlaceHolder()) + m_pCC->GetTextAttr()->Invalidate(); +} + +void SwVbaContentControl::SetUnCheckedSymbol(sal_Int32 Character, const uno::Any& Font) +{ + if (!m_pCC->GetTextAttr()) + return; + + SAL_INFO_IF(Font.hasValue(), "sw.vba", "SetUnCheckedSymbol Font[" << Font << "] stub"); + if (Character < 31 || Character > SAL_MAX_UINT16) + return; // unsupported character. Would such a thing exist in VBA? + + m_pCC->SetUncheckedState(OUString(static_cast<sal_Unicode>(Character))); + + if (m_pCC->GetCheckbox() && !m_pCC->GetChecked() && !m_pCC->GetShowingPlaceHolder()) + m_pCC->GetTextAttr()->Invalidate(); +} + +void SwVbaContentControl::SetPlaceholderText(const uno::Any& BuildingBlock, const uno::Any& Range, + const uno::Any& Text) +{ + SAL_INFO("sw.vba", "SwVbaContentControl::SetPlaceholderText stub"); + if (BuildingBlock.hasValue()) + { + // Set placeholder text to the building block - whatever that is. + } + else if (Range.hasValue()) + { + // Set placeholder text to the contents of the Range, however you do that. + } + else if (Text.hasValue()) + { + // Set placeholder text to the provided string + } + else + { + // Remove placeholder text. + m_pCC->SetPlaceholderDocPart(""); + } + if (m_pCC->GetShowingPlaceHolder() && !getLockContents() && m_pCC->GetTextAttr()) + { + //replace the text and ensure showing placeholder is still set + } +} + +void SwVbaContentControl::Ungroup() { SAL_INFO("sw.vba", "SwVbaContentControl::UnGroup stub"); } + +OUString SwVbaContentControl::getServiceImplName() { return "SwVbaContentControl"; } + +uno::Sequence<OUString> SwVbaContentControl::getServiceNames() +{ + static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.ContentControl" }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacontentcontrol.hxx b/sw/source/ui/vba/vbacontentcontrol.hxx new file mode 100644 index 0000000000..9f98b92468 --- /dev/null +++ b/sw/source/ui/vba/vbacontentcontrol.hxx @@ -0,0 +1,142 @@ +/* -*- 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/. + */ +#pragma once + +#include <com/sun/star/text/XTextDocument.hpp> +#include <ooo/vba/word/XContentControl.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +#include <textcontentcontrol.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XContentControl> SwVbaContentControl_BASE; + +class SwVbaContentControl : public SwVbaContentControl_BASE +{ +private: + css::uno::Reference<css::text::XTextDocument> mxTextDocument; + std::shared_ptr<SwContentControl> m_pCC; + +public: + /// @throws css::uno::RuntimeException + SwVbaContentControl(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext, + const css::uno::Reference<css::text::XTextDocument>& xTextDocument, + std::shared_ptr<SwContentControl> pContentControl); + ~SwVbaContentControl() override; + + // XContentControl Properties + sal_Bool SAL_CALL getAllowInsertDeleteSection() override; + void SAL_CALL setAllowInsertDeleteSection(sal_Bool bSet) override; + + sal_Int32 SAL_CALL getAppearance() override; + void SAL_CALL setAppearance(sal_Int32 nSet) override; + + OUString SAL_CALL getBuildingBlockCategory() override; + void SAL_CALL setBuildingBlockCategory(const OUString& sSet) override; + + sal_Int32 SAL_CALL getBuildingBlockType() override; + void SAL_CALL setBuildingBlockType(sal_Int32 nSet) override; + + sal_Bool SAL_CALL getChecked() override; + void SAL_CALL setChecked(sal_Bool bSet) override; + + // returns or sets a WdColor (@since after 2010 I assume) + sal_Int32 SAL_CALL getColor() override; + void SAL_CALL setColor(sal_Int32 nSet) override; + + sal_Int32 SAL_CALL getDateCalendarType() override; + void SAL_CALL setDateCalendarType(sal_Int32 nSet) override; + + OUString SAL_CALL getDateDisplayFormat() override; + void SAL_CALL setDateDisplayFormat(const OUString& sSet) override; + + sal_Int32 SAL_CALL getDateDisplayLocale() override; + + sal_Int32 SAL_CALL getDateStorageFormat() override; + void SAL_CALL setDateStorageFormat(sal_Int32 nSet) override; + + css::uno::Any SAL_CALL getDropdownListEntries() override; + + // This is an integer used as a unique identifier string + OUString SAL_CALL getID() override; + + sal_Int32 SAL_CALL getLevel() override; + + // returns or sets if the user can delete the control + sal_Bool SAL_CALL getLockContentControl() override; + void SAL_CALL setLockContentControl(sal_Bool bSet) override; + + // returns or sets if the user can edit the contents (i.e. read-only flag) + sal_Bool SAL_CALL getLockContents() override; + void SAL_CALL setLockContents(sal_Bool bSet) override; + + sal_Bool SAL_CALL getMultiLine() override; + void SAL_CALL setMultiLine(sal_Bool bSet) override; + + // WRONG- THIS SHOULD RETURN XBUILDINGBLOCK + OUString SAL_CALL getPlaceholderText() override; + + sal_Bool SAL_CALL getShowingPlaceholderText() override; + + OUString SAL_CALL getRepeatingSectionItemTitle() override; + void SAL_CALL setRepeatingSectionItemTitle(const OUString& rSet) override; + + css::uno::Reference<ooo::vba::word::XRange> SAL_CALL getRange() override; + + OUString SAL_CALL getTag() override; + void SAL_CALL setTag(const OUString& rSet) override; + + // returns or sets if the control is removed after accepting user change (i.e. control -> text) + sal_Bool SAL_CALL getTemporary() override; + void SAL_CALL setTemporary(sal_Bool bSet) override; + + OUString SAL_CALL getTitle() override; + void SAL_CALL setTitle(const OUString& rSet) override; + + // returns or sets a WdContentControlType that represents the type for a content control. + sal_Int32 SAL_CALL getType() override; + void SAL_CALL setType(sal_Int32 nSet) override; + + // XContentControl Methods + + // Copies the content control from the active document to the Clipboard. + // Retrieve from the clipboard using the Paste method of the Selection object + // or of the Range object, or use the Paste function from within Microsoft Word. + void SAL_CALL Copy() override; + + // Removes the control from the active document and moves it to the Clipboard. + void SAL_CALL Cut() override; + + // Specifies whether to delete the contents of the content control. The default value is False. + // True removes both the content control and its contents. + // False removes the control but leaves the contents of the content control in the document. + void SAL_CALL Delete(const css::uno::Any& bDeleteContents) override; + + // Set the Unicode character used to display the checked state. + void SAL_CALL SetCheckedSymbol(sal_Int32 Character, const css::uno::Any& sFont) override; + + // Set the Unicode character used to display the unchecked state. + void SAL_CALL SetUnCheckedSymbol(sal_Int32 Character, const css::uno::Any& sFont) override; + + // Sets the placeholder text that displays until a user enters their own text. + // Only one of the parameters is used when specifying placeholder text. + // If more than one parameter is provided, use the text specified in the first parameter. + // If all parameters are omitted, the placeholder text is blank. + void SAL_CALL SetPlaceholderText(const css::uno::Any& BuildingBlock, const css::uno::Any& Range, + const css::uno::Any& sText) override; + + void SAL_CALL Ungroup() override; + + // XHelperInterface + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacontentcontrollistentries.cxx b/sw/source/ui/vba/vbacontentcontrollistentries.cxx new file mode 100644 index 0000000000..552397e156 --- /dev/null +++ b/sw/source/ui/vba/vbacontentcontrollistentries.cxx @@ -0,0 +1,166 @@ +/* -*- 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 "vbacontentcontrollistentries.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace +{ +class ContentControlListEntriesEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference<container::XIndexAccess> mxIndexAccess; + sal_Int32 mnIndex; + +public: + explicit ContentControlListEntriesEnumWrapper( + uno::Reference<container::XIndexAccess> xIndexAccess) + : mxIndexAccess(xIndexAccess) + , mnIndex(0) + { + } + + virtual sal_Bool SAL_CALL hasMoreElements() override + { + return (mnIndex < mxIndexAccess->getCount()); + } + + virtual uno::Any SAL_CALL nextElement() override + { + if (mnIndex < mxIndexAccess->getCount()) + { + return mxIndexAccess->getByIndex(mnIndex++); + } + throw container::NoSuchElementException(); + } +}; + +class ContentControlListEntryCollectionHelper + : public ::cppu::WeakImplHelper<container::XIndexAccess, container::XEnumerationAccess> +{ +private: + uno::Reference<XHelperInterface> mxParent; + uno::Reference<uno::XComponentContext> mxContext; + std::shared_ptr<SwContentControl> m_pCC; + +public: + /// @throws css::uno::RuntimeException + ContentControlListEntryCollectionHelper(uno::Reference<ov::XHelperInterface> xParent, + uno::Reference<uno::XComponentContext> xContext, + std::shared_ptr<SwContentControl> pCC) + : mxParent(xParent) + , mxContext(xContext) + , m_pCC(pCC) + { + } + + sal_Int32 SAL_CALL getCount() override { return m_pCC->GetListItems().size(); } + + uno::Any SAL_CALL getByIndex(sal_Int32 Index) override + { + if (Index < 0 || Index >= getCount()) + throw lang::IndexOutOfBoundsException(); + + return uno::Any(uno::Reference<word::XContentControlListEntry>( + new SwVbaContentControlListEntry(mxParent, mxContext, m_pCC, Index))); + } + + uno::Type SAL_CALL getElementType() override + { + return cppu::UnoType<word::XContentControlListEntry>::get(); + } + + sal_Bool SAL_CALL hasElements() override { return getCount() != 0; } + + // XEnumerationAccess + uno::Reference<container::XEnumeration> SAL_CALL createEnumeration() override + { + return new ContentControlListEntriesEnumWrapper(this); + } +}; +} + +/** + * DropDownLists and ComboBoxes contain a list of name/value pairs to choose from. + * Use of DropDownListEntries from any other control is invalid. + */ +SwVbaContentControlListEntries::SwVbaContentControlListEntries( + const uno::Reference<XHelperInterface>& xParent, + const uno::Reference<uno::XComponentContext>& xContext, std::shared_ptr<SwContentControl> pCC) + : SwVbaContentControlListEntries_BASE( + xParent, xContext, + uno::Reference<container::XIndexAccess>( + new ContentControlListEntryCollectionHelper(xParent, xContext, pCC))) + , m_pCC(pCC) +{ +} + +uno::Reference<word::XContentControlListEntry> +SwVbaContentControlListEntries::Add(const OUString& rName, const uno::Any& rValue, + const uno::Any& rIndex) +{ + // No duplicate Names allowed in VBA + for (auto& rListItem : m_pCC->GetListItems()) + { + if (rListItem.ToString() == rName) + return uno::Reference<word::XContentControlListEntry>(); + } + + sal_Int32 nZIndex = SAL_MAX_INT32; + rIndex >>= nZIndex; + // rIndex is 1-based, nZIndex is 0-based. If rIndex is not given, then add as the last choice. + assert(nZIndex > 0); + --nZIndex; + nZIndex = std::min(static_cast<size_t>(nZIndex), m_pCC->GetListItems().size()); + + OUString sValue; + rValue >>= sValue; + if (m_pCC->AddListItem(nZIndex, rName, sValue)) + { + return uno::Reference<word::XContentControlListEntry>( + new SwVbaContentControlListEntry(mxParent, mxContext, m_pCC, nZIndex)); + } + + return uno::Reference<word::XContentControlListEntry>(); +} + +void SwVbaContentControlListEntries::Clear() { m_pCC->ClearListItems(); } + +sal_Int32 SwVbaContentControlListEntries::getCount() { return m_pCC->GetListItems().size(); } + +// XEnumerationAccess +uno::Type SwVbaContentControlListEntries::getElementType() +{ + return cppu::UnoType<word::XContentControlListEntry>::get(); +} + +uno::Reference<container::XEnumeration> SwVbaContentControlListEntries::createEnumeration() +{ + return new ContentControlListEntriesEnumWrapper(m_xIndexAccess); +} + +// SwVbaContentControlListEntries_BASE +uno::Any SwVbaContentControlListEntries::createCollectionObject(const uno::Any& aSource) +{ + return aSource; +} + +OUString SwVbaContentControlListEntries::getServiceImplName() +{ + return "SwVbaContentControlListEntries"; +} + +uno::Sequence<OUString> SwVbaContentControlListEntries::getServiceNames() +{ + static uno::Sequence<OUString> const sNames{ "ooo.vba.word.ContentControlListEntries" }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacontentcontrollistentries.hxx b/sw/source/ui/vba/vbacontentcontrollistentries.hxx new file mode 100644 index 0000000000..dc32203179 --- /dev/null +++ b/sw/source/ui/vba/vbacontentcontrollistentries.hxx @@ -0,0 +1,51 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/word/XContentControlListEntries.hpp> +#include <ooo/vba/word/XContentControlListEntry.hpp> + +#include <vbahelper/vbacollectionimpl.hxx> + +#include <textcontentcontrol.hxx> + +#include "vbacontentcontrollistentries.hxx" +#include "vbacontentcontrollistentry.hxx" + +typedef CollTestImplHelper<ooo::vba::word::XContentControlListEntries> + SwVbaContentControlListEntries_BASE; + +class SwVbaContentControlListEntries : public SwVbaContentControlListEntries_BASE +{ +private: + std::shared_ptr<SwContentControl> m_pCC; + +public: + /// @throws css::uno::RuntimeException + SwVbaContentControlListEntries(const css::uno::Reference<ov::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext, + std::shared_ptr<SwContentControl> pCC); + + // XContentControlListEntries + css::uno::Reference<ooo::vba::word::XContentControlListEntry> SAL_CALL + Add(const OUString& rName, const css::uno::Any& rValue, const css::uno::Any& rIndex) override; + void SAL_CALL Clear() override; + sal_Int32 SAL_CALL getCount() override; + + // XEnumerationAccess + css::uno::Type SAL_CALL getElementType() override; + css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override; + + // SwVbaContentControlListEntries_BASE + css::uno::Any createCollectionObject(const css::uno::Any& aSource) override; + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacontentcontrollistentry.cxx b/sw/source/ui/vba/vbacontentcontrollistentry.cxx new file mode 100644 index 0000000000..73f5e9d0a2 --- /dev/null +++ b/sw/source/ui/vba/vbacontentcontrollistentry.cxx @@ -0,0 +1,161 @@ +/* -*- 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 "vbacontentcontrollistentry.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaContentControlListEntry::SwVbaContentControlListEntry( + const uno::Reference<ooo::vba::XHelperInterface>& rParent, + const uno::Reference<uno::XComponentContext>& rContext, std::shared_ptr<SwContentControl> pCC, + size_t nZIndex) + : SwVbaContentControlListEntry_BASE(rParent, rContext) + , m_pCC(pCC) + , m_nZIndex(nZIndex) +{ +} + +SwVbaContentControlListEntry::~SwVbaContentControlListEntry() {} + +sal_Int32 SwVbaContentControlListEntry::getIndex() { return m_nZIndex + 1; } + +void SwVbaContentControlListEntry::setIndex(sal_Int32 nSet) +{ + if (nSet < 1 || static_cast<size_t>(nSet) == m_nZIndex + 1) + return; + + // Given a one-based index to set to + size_t nIndex = std::min(static_cast<size_t>(nSet), m_pCC->GetListItems().size()); + // change to zero-based index + --nIndex; + while (nIndex < m_nZIndex) + MoveUp(); + while (m_nZIndex < nIndex) + MoveDown(); +} + +OUString SwVbaContentControlListEntry::getText() +{ + assert(m_nZIndex < m_pCC->GetListItems().size()); + const SwContentControlListItem& rListItem = m_pCC->GetListItems()[m_nZIndex]; + return rListItem.ToString(); +} + +void SwVbaContentControlListEntry::setText(const OUString& rSet) +{ + std::vector<SwContentControlListItem> vListItems = m_pCC->GetListItems(); + assert(m_nZIndex < vListItems.size()); + + // prevent duplicates + for (size_t i = 0; i < vListItems.size(); ++i) + { + if (vListItems[i].ToString() == rSet) + return; + } + + const std::optional<size_t> oSel(m_pCC->GetSelectedListItem(/*bCheckDocModel=*/true)); + const bool bNeedsInvalidation = m_pCC->GetDropDown() && oSel && *oSel == m_nZIndex; + + vListItems[m_nZIndex].m_aDisplayText = rSet; + m_pCC->SetListItems(vListItems); + + if (bNeedsInvalidation) + { + m_pCC->SetSelectedListItem(m_nZIndex); + if (m_pCC->GetTextAttr()) + m_pCC->GetTextAttr()->Invalidate(); + } +} + +OUString SwVbaContentControlListEntry::getValue() +{ + assert(m_nZIndex < m_pCC->GetListItems().size()); + const SwContentControlListItem& rListItem = m_pCC->GetListItems()[m_nZIndex]; + + return rListItem.m_aValue; +} + +void SwVbaContentControlListEntry::setValue(const OUString& rSet) +{ + assert(m_nZIndex < m_pCC->GetListItems().size()); + std::vector<SwContentControlListItem> vListItems = m_pCC->GetListItems(); + + // LO may pull the display text from Value. Ensure changing Value doesn't alter display text. + if (vListItems[m_nZIndex].m_aDisplayText.isEmpty()) + vListItems[m_nZIndex].m_aDisplayText = vListItems[m_nZIndex].ToString(); + + vListItems[m_nZIndex].m_aValue = rSet; + m_pCC->SetListItems(vListItems); +} + +void SwVbaContentControlListEntry::Delete() { m_pCC->DeleteListItem(m_nZIndex); } + +void SwVbaContentControlListEntry::MoveDown() +{ + // if already at last position, can't move down + if (m_nZIndex >= m_pCC->GetListItems().size() - 1) + return; + + const std::optional<size_t> oSelected = m_pCC->GetSelectedListItem(/*bCheckDocModel=*/false); + if (oSelected) + { + if (*oSelected == m_nZIndex) + m_pCC->SetSelectedListItem(m_nZIndex + 1); + else if (*oSelected == m_nZIndex + 1) + m_pCC->SetSelectedListItem(*oSelected - 1); + } + std::vector<SwContentControlListItem> vListItems = m_pCC->GetListItems(); + std::swap(vListItems[m_nZIndex], vListItems[m_nZIndex + 1]); + m_pCC->SetListItems(vListItems); + ++m_nZIndex; +} + +void SwVbaContentControlListEntry::MoveUp() +{ + // if already at position 0, can't move up + if (!m_nZIndex || m_nZIndex >= m_pCC->GetListItems().size()) + return; + + const std::optional<size_t> oSelected = m_pCC->GetSelectedListItem(/*bCheckDocModel=*/false); + if (oSelected) + { + if (*oSelected == m_nZIndex) + m_pCC->SetSelectedListItem(m_nZIndex - 1); + else if (*oSelected == m_nZIndex - 1) + m_pCC->SetSelectedListItem(*oSelected + 1); + } + std::vector<SwContentControlListItem> vListItems = m_pCC->GetListItems(); + std::swap(vListItems[m_nZIndex], vListItems[m_nZIndex - 1]); + m_pCC->SetListItems(vListItems); + --m_nZIndex; +} + +void SwVbaContentControlListEntry::Select() +{ + assert(m_nZIndex < m_pCC->GetListItems().size()); + m_pCC->SetSelectedListItem(m_nZIndex); + m_pCC->SetShowingPlaceHolder(false); + if (m_pCC->GetTextAttr()) + m_pCC->GetTextAttr()->Invalidate(); +} + +// XHelperInterface +OUString SwVbaContentControlListEntry::getServiceImplName() +{ + return "SwVbaContentControlListEntry"; +} + +uno::Sequence<OUString> SwVbaContentControlListEntry::getServiceNames() +{ + static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.ContentControlListEntry" }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacontentcontrollistentry.hxx b/sw/source/ui/vba/vbacontentcontrollistentry.hxx new file mode 100644 index 0000000000..bb55eade34 --- /dev/null +++ b/sw/source/ui/vba/vbacontentcontrollistentry.hxx @@ -0,0 +1,54 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/word/XContentControlListEntry.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +#include <textcontentcontrol.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XContentControlListEntry> + SwVbaContentControlListEntry_BASE; + +class SwVbaContentControlListEntry : public SwVbaContentControlListEntry_BASE +{ +private: + std::shared_ptr<SwContentControl> m_pCC; + // All LO and internal UNO functions are 0-based. Convert to 1-based when sending to VBA + size_t m_nZIndex; + +public: + /// @throws css::uno::RuntimeException + SwVbaContentControlListEntry(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext, + std::shared_ptr<SwContentControl> pCC, size_t nZIndex); + ~SwVbaContentControlListEntry() override; + + // XContentControlListEntry + sal_Int32 SAL_CALL getIndex() override; + void SAL_CALL setIndex(sal_Int32 nSet) override; + + OUString SAL_CALL getText() override; + void SAL_CALL setText(const OUString& sSet) override; + + OUString SAL_CALL getValue() override; + void SAL_CALL setValue(const OUString& sSet) override; + + void SAL_CALL Delete() override; + void SAL_CALL MoveDown() override; + void SAL_CALL MoveUp() override; + void SAL_CALL Select() override; + + // XHelperInterface + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacontentcontrols.cxx b/sw/source/ui/vba/vbacontentcontrols.cxx new file mode 100644 index 0000000000..37199e2cec --- /dev/null +++ b/sw/source/ui/vba/vbacontentcontrols.cxx @@ -0,0 +1,268 @@ +/* -*- 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 <comphelper/sequence.hxx> +#include <sal/log.hxx> + +#include <doc.hxx> +#include <docsh.hxx> +#include <textcontentcontrol.hxx> + +#include "vbacontentcontrol.hxx" +#include "vbacontentcontrols.hxx" +#include "wordvbahelper.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +// Helper function to access the content controls +// @param rIndex +// [in] negative indexes indicate the need to search by name, otherwise get by index, +// using SAL_MAX_INT32 to indicate the need to just get the total count. +// [out] rIndex indicates the found index, or the total number of content controls +static std::shared_ptr<SwContentControl> +lcl_getContentControl(std::u16string_view sName, std::u16string_view sTag, + std::u16string_view sTitle, sal_Int32& rIndex, + const uno::Reference<text::XTextDocument>& xTextDocument, + uno::Sequence<OUString>* pElementNames = nullptr) +{ + SwDoc* pDoc = word::getDocShell(xTextDocument)->GetDoc(); + if (!pDoc) + return nullptr; + + assert(sTag.empty() || sTitle.empty()); // only one grouping at a time is allowed + + std::shared_ptr<SwContentControl> pControl; + std::vector<OUString> vElementNames; + SwContentControlManager& rManager = pDoc->GetContentControlManager(); + const size_t nLen = rManager.GetCount(); + if (!pElementNames && rIndex > 0 && sName.empty() && sTag.empty() && sTitle.empty()) + { + size_t i = static_cast<size_t>(rIndex); + // This is the normal get-by-index/getCount mode - no need for fancy filtering. + if (i < nLen) + pControl = rManager.Get(i)->GetContentControl().GetContentControl(); + else + rIndex = nLen; + } + else + { + // loop through everything collecting names, filtering by Tag/Title + sal_Int32 nCounter = 0; + for (size_t i = 0; i < nLen; ++i) + { + pControl = rManager.Get(i)->GetContentControl().GetContentControl(); + if (!sTag.empty() && sTag != pControl->GetTag()) + { + pControl = nullptr; + continue; + } + if (!sTitle.empty() && sTitle != pControl->GetAlias()) + { + pControl = nullptr; + continue; + } + + // When treated as a name, consider the integer ID to be unsigned + const OUString sID = OUString::number(static_cast<sal_uInt32>(pControl->GetId())); + if (!sName.empty() && sName != sID) + { + pControl = nullptr; + continue; + } + + if (pElementNames) + vElementNames.push_back(sID); + + if (rIndex == nCounter || !sName.empty()) + break; + + pControl = nullptr; + ++nCounter; + } + rIndex = nCounter; + } + if (pElementNames) + *pElementNames = comphelper::containerToSequence(vElementNames); + return pControl; +} + +namespace +{ +class ContentControlsEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference<container::XIndexAccess> mxIndexAccess; + sal_Int32 mnIndex; + +public: + explicit ContentControlsEnumWrapper(uno::Reference<container::XIndexAccess> xIndexAccess) + : mxIndexAccess(std::move(xIndexAccess)) + , mnIndex(0) + { + } + + sal_Bool SAL_CALL hasMoreElements() override { return (mnIndex < mxIndexAccess->getCount()); } + + uno::Any SAL_CALL nextElement() override + { + if (mnIndex < mxIndexAccess->getCount()) + { + return mxIndexAccess->getByIndex(mnIndex++); + } + throw container::NoSuchElementException(); + } +}; + +class ContentControlCollectionHelper + : public ::cppu::WeakImplHelper<container::XNameAccess, container::XIndexAccess, + container::XEnumerationAccess> +{ +private: + uno::Reference<XHelperInterface> mxParent; + uno::Reference<uno::XComponentContext> mxContext; + uno::Reference<text::XTextDocument> mxTextDocument; + const OUString m_sTag; + const OUString m_sTitle; + std::shared_ptr<SwContentControl> m_pCache; + +public: + /// @throws css::uno::RuntimeException + ContentControlCollectionHelper(uno::Reference<ov::XHelperInterface> xParent, + uno::Reference<uno::XComponentContext> xContext, + uno::Reference<text::XTextDocument> xTextDocument, + const OUString& rTag, const OUString& rTitle) + + : mxParent(std::move(xParent)) + , mxContext(std::move(xContext)) + , mxTextDocument(std::move(xTextDocument)) + , m_sTag(rTag) + , m_sTitle(rTitle) + { + } + + // XIndexAccess + sal_Int32 SAL_CALL getCount() override + { + sal_Int32 nCount = SAL_MAX_INT32; + lcl_getContentControl(u"", m_sTag, m_sTitle, nCount, mxTextDocument); + return nCount == SAL_MAX_INT32 || nCount < 0 ? 0 : nCount; + } + + uno::Any SAL_CALL getByIndex(sal_Int32 Index) override + { + m_pCache = lcl_getContentControl(u"", m_sTag, m_sTitle, Index, mxTextDocument); + if (!m_pCache) + throw lang::IndexOutOfBoundsException(); + + return uno::Any(uno::Reference<word::XContentControl>( + new SwVbaContentControl(mxParent, mxContext, mxTextDocument, m_pCache))); + } + + // XNameAccess + uno::Sequence<OUString> SAL_CALL getElementNames() override + { + sal_Int32 nCount = SAL_MAX_INT32; + uno::Sequence<OUString> aSeq; + lcl_getContentControl(u"", m_sTag, m_sTitle, nCount, mxTextDocument, &aSeq); + return aSeq; + } + + uno::Any SAL_CALL getByName(const OUString& aName) override + { + if (!hasByName(aName)) + throw container::NoSuchElementException(); + + return uno::Any(uno::Reference<word::XContentControl>( + new SwVbaContentControl(mxParent, mxContext, mxTextDocument, m_pCache))); + } + + sal_Bool SAL_CALL hasByName(const OUString& aName) override + { + sal_Int32 nCount = -1; + m_pCache = lcl_getContentControl(aName, m_sTag, m_sTitle, nCount, mxTextDocument); + return m_pCache != nullptr; + } + + // XElementAccess + uno::Type SAL_CALL getElementType() override + { + return cppu::UnoType<word::XContentControl>::get(); + } + + sal_Bool SAL_CALL hasElements() override { return getCount() != 0; } + + // XEnumerationAccess + uno::Reference<container::XEnumeration> SAL_CALL createEnumeration() override + { + return new ContentControlsEnumWrapper(this); + } +}; +} + +/** + * Content Controls can be accessed and filtered in many different ways. + * Surprisingly however, there is no clear, descriptive "by name" access. + * Instead, each content control (probably) has a unique _signed-integer_ identifier, + * which can be passed to Item() as a float or _unsigned-integer_ string + * (to differentiate it from getByIndex). + * + * Index access can be filtered by Tag, Title, Range, and XML link. + * TODO: add filtering for Range, SelectLinkedControls, SelectUnlinkedControls + */ +SwVbaContentControls::SwVbaContentControls(const uno::Reference<XHelperInterface>& xParent, + const uno::Reference<uno::XComponentContext>& xContext, + const uno::Reference<text::XTextDocument>& xTextDocument, + const OUString& rTag, const OUString& rTitle) + : SwVbaContentControls_BASE( + xParent, xContext, + uno::Reference<container::XIndexAccess>( + new ContentControlCollectionHelper(xParent, xContext, xTextDocument, rTag, rTitle))) +{ +} + +// uno::Reference<ooo::vba::word::XContentControl> SwVbaContentControls::Add(const uno::Any& Range, +// sal_Int32 Type) +// { +// sw::mark::IFieldmark* pFieldmark = nullptr; +// switch (Type) +// { +// case ooo::vba::word::WdFieldType::wdFieldFormCheckBox: +// break; +// case ooo::vba::word::WdFieldType::wdFieldFormDropDown: +// break; +// case ooo::vba::word::WdFieldType::wdFieldFormTextInput: +// default:; +// } +// +// return uno::Reference<ooo::vba::word::XContentControl>( +// new SwVbaContentControl(mxParent, mxContext, m_xTextDocument, pFieldmark)); +// } + +// XEnumerationAccess +uno::Type SwVbaContentControls::getElementType() +{ + return cppu::UnoType<word::XContentControl>::get(); +} + +uno::Reference<container::XEnumeration> SwVbaContentControls::createEnumeration() +{ + return new ContentControlsEnumWrapper(m_xIndexAccess); +} + +uno::Any SwVbaContentControls::createCollectionObject(const uno::Any& aSource) { return aSource; } + +OUString SwVbaContentControls::getServiceImplName() { return "SwVbaContentControls"; } + +uno::Sequence<OUString> SwVbaContentControls::getServiceNames() +{ + static uno::Sequence<OUString> const sNames{ "ooo.vba.word.ContentControls" }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbacontentcontrols.hxx b/sw/source/ui/vba/vbacontentcontrols.hxx new file mode 100644 index 0000000000..20ff65ae89 --- /dev/null +++ b/sw/source/ui/vba/vbacontentcontrols.hxx @@ -0,0 +1,40 @@ +/* -*- 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/. + */ +#pragma once + +#include <com/sun/star/text/XTextDocument.hpp> +#include <ooo/vba/word/XContentControls.hpp> + +#include <vbahelper/vbacollectionimpl.hxx> + +typedef CollTestImplHelper<ooo::vba::word::XContentControls> SwVbaContentControls_BASE; + +class SwVbaContentControls : public SwVbaContentControls_BASE +{ +public: + /// @throws css::uno::RuntimeException + SwVbaContentControls(const css::uno::Reference<ov::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext, + const css::uno::Reference<css::text::XTextDocument>& xTextDocument, + const OUString& rTag, const OUString& rTitle); + + // XContentControls + //css::uno::Reference<ooo::vba::word::XContentControl> SAL_CALL Add(const css::uno::Any& Type, const css::uno::Any& Range) override; + + // XEnumerationAccess + css::uno::Type SAL_CALL getElementType() override; + css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override; + + // SwVbaContentControls_BASE + css::uno::Any createCollectionObject(const css::uno::Any& aSource) override; + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbadialog.cxx b/sw/source/ui/vba/vbadialog.cxx new file mode 100644 index 0000000000..f6af8f113e --- /dev/null +++ b/sw/source/ui/vba/vbadialog.cxx @@ -0,0 +1,73 @@ +/* -*- 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 "vbadialog.hxx" +#include <ooo/vba/word/WdWordDialog.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +struct WordDialogTable +{ + sal_Int32 wdDialog; + const char* ooDialog; +}; + +} + +const WordDialogTable aWordDialogTable[] = +{ + { word::WdWordDialog::wdDialogFileNew, ".uno:NewDoc" }, + { word::WdWordDialog::wdDialogFileOpen, ".uno:Open" }, + { word::WdWordDialog::wdDialogFilePrint, ".uno:Print" }, + { word::WdWordDialog::wdDialogFileSaveAs, ".uno:SaveAs" }, + { 0, nullptr } +}; + +OUString +SwVbaDialog::mapIndexToName( sal_Int32 nIndex ) +{ + for (const WordDialogTable & rTable : aWordDialogTable) + { + if( nIndex == rTable.wdDialog ) + { + return OUString::createFromAscii( rTable.ooDialog ); + } + } + return OUString(); +} + +OUString +SwVbaDialog::getServiceImplName() +{ + return "SwVbaDialog"; +} + +uno::Sequence< OUString > +SwVbaDialog::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Dialog" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbadialog.hxx b/sw/source/ui/vba/vbadialog.hxx new file mode 100644 index 0000000000..df4443446f --- /dev/null +++ b/sw/source/ui/vba/vbadialog.hxx @@ -0,0 +1,42 @@ +/* -*- 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_VBA_VBADIALOG_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBADIALOG_HXX + +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/word/XDialog.hpp> +#include <vbahelper/vbadialogbase.hxx> + +typedef cppu::ImplInheritanceHelper< VbaDialogBase, ov::word::XDialog > SwVbaDialog_BASE; + +class SwVbaDialog : public SwVbaDialog_BASE +{ +public: + SwVbaDialog( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xModel, sal_Int32 nIndex ):SwVbaDialog_BASE( xParent, xContext, xModel, nIndex ) {} + + // Methods + virtual OUString mapIndexToName( sal_Int32 nIndex ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBADIALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbadialogs.cxx b/sw/source/ui/vba/vbadialogs.cxx new file mode 100644 index 0000000000..2b26a4cfaa --- /dev/null +++ b/sw/source/ui/vba/vbadialogs.cxx @@ -0,0 +1,51 @@ +/* -*- 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 <ooo/vba/word/XDialog.hpp> +#include "vbadialogs.hxx" +#include "vbadialog.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +uno::Any +SwVbaDialogs::Item( const uno::Any &aItem ) +{ + sal_Int32 nIndex = 0; + aItem >>= nIndex; + uno::Reference< word::XDialog > aDialog( new SwVbaDialog( uno::Reference< XHelperInterface >( Application(),uno::UNO_QUERY_THROW ), mxContext, m_xModel, nIndex ) ); + return uno::Any( aDialog ); +} + +OUString +SwVbaDialogs::getServiceImplName() +{ + return "SwVbaDialogs"; +} + +uno::Sequence< OUString > +SwVbaDialogs::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Dialogs" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbadialogs.hxx b/sw/source/ui/vba/vbadialogs.hxx new file mode 100644 index 0000000000..3703868f1b --- /dev/null +++ b/sw/source/ui/vba/vbadialogs.hxx @@ -0,0 +1,44 @@ +/* -*- 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_VBA_VBADIALOGS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBADIALOGS_HXX + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <ooo/vba/word/XDialogs.hpp> +#include <vbahelper/vbadialogsbase.hxx> +#include <cppuhelper/implbase.hxx> + +typedef cppu::ImplInheritanceHelper< VbaDialogsBase, ov::word::XDialogs > SwVbaDialogs_BASE; + +class SwVbaDialogs : public SwVbaDialogs_BASE +{ +public: + SwVbaDialogs( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > &xContext, const css::uno::Reference< css::frame::XModel >& xModel ): SwVbaDialogs_BASE( xParent, xContext, xModel ) {} + + // XCollection + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBADIALOGS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbadocument.cxx b/sw/source/ui/vba/vbadocument.cxx new file mode 100644 index 0000000000..c898546450 --- /dev/null +++ b/sw/source/ui/vba/vbadocument.cxx @@ -0,0 +1,795 @@ +/* -*- 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 <sal/config.h> +#include <sal/log.hxx> + +#include "vbafilterpropsfromformat.hxx" +#include "vbacontentcontrols.hxx" +#include "vbadocument.hxx" +#include "vbaformfields.hxx" +#include "vbarange.hxx" +#include "vbarangehelper.hxx" +#include "vbadocumentproperties.hxx" +#include "vbabookmarks.hxx" +#include "vbamailmerge.hxx" +#include "vbavariables.hxx" +#include "vbawindow.hxx" +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> +#include <cppu/unotype.hxx> + +#include <com/sun/star/text/XBookmarksSupplier.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/form/XFormsSupplier.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/document/XRedlinesSupplier.hpp> +#include <com/sun/star/util/thePathSettings.hpp> +#include <ooo/vba/XControlProvider.hpp> +#include <ooo/vba/word/WdProtectionType.hpp> +#include <ooo/vba/word/WdSaveFormat.hpp> +#include <ooo/vba/word/XDocumentOutgoing.hpp> + +#include "wordvbahelper.hxx" +#include <doc.hxx> +#include <docsh.hxx> +#include "vbatemplate.hxx" +#include "vbaparagraph.hxx" +#include "vbastyles.hxx" +#include "vbatables.hxx" +#include "vbafield.hxx" +#include "vbapagesetup.hxx" +#include "vbasections.hxx" +#include "vbatablesofcontents.hxx" +#include <vbahelper/vbashapes.hxx> +#include <vbahelper/vbahelper.hxx> +#include "vbarevisions.hxx" +#include "vbaframes.hxx" +#include <basic/sberrors.hxx> +#include <osl/file.hxx> +#include <tools/urlobj.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +class SwVbaDocumentOutgoingConnectionPoint : public cppu::WeakImplHelper<XConnectionPoint> +{ +private: + SwVbaDocument* mpDoc; + +public: + SwVbaDocumentOutgoingConnectionPoint( SwVbaDocument* pDoc ); + + // XConnectionPoint + sal_uInt32 SAL_CALL Advise(const uno::Reference< XSink >& Sink ) override; + void SAL_CALL Unadvise( sal_uInt32 Cookie ) override; +}; + +} + +SwVbaDocument::SwVbaDocument( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, uno::Reference< frame::XModel > const & xModel ): SwVbaDocument_BASE( xParent, xContext, xModel ) +{ + Initialize(); +} +SwVbaDocument::SwVbaDocument( uno::Sequence< uno::Any > const& aArgs, uno::Reference< uno::XComponentContext >const& xContext ) : SwVbaDocument_BASE( aArgs, xContext ) +{ + Initialize(); +} + +SwVbaDocument::~SwVbaDocument() +{ +} + +void SwVbaDocument::Initialize() +{ + mxTextDocument.set( getModel(), uno::UNO_QUERY_THROW ); + SwDocShell& rDocSh = *word::getDocShell(mxModel); + rDocSh.RegisterAutomationDocumentObject(this); + rDocSh.GetDoc()->SetVbaEventProcessor(); +} + +sal_uInt32 +SwVbaDocument::AddSink( const uno::Reference< XSink >& xSink ) +{ + word::getDocShell( mxModel )->RegisterAutomationDocumentEventsCaller( uno::Reference< XSinkCaller >(this) ); + mvSinks.push_back(xSink); + return mvSinks.size(); +} + +void +SwVbaDocument::RemoveSink( sal_uInt32 nNumber ) +{ + if (nNumber < 1 || nNumber > mvSinks.size()) + return; + + mvSinks[nNumber-1] = uno::Reference< XSink >(); +} + +uno::Reference< word::XRange > SAL_CALL +SwVbaDocument::getContent() +{ + uno::Reference< text::XTextRange > xStart = mxTextDocument->getText()->getStart(); + uno::Reference< text::XTextRange > xEnd; + return uno::Reference< word::XRange >( new SwVbaRange( this, mxContext, mxTextDocument, xStart, xEnd ) ); +} + +uno::Reference< word::XRange > SAL_CALL +SwVbaDocument::Range( const uno::Any& rStart, const uno::Any& rEnd ) +{ + if( !rStart.hasValue() && !rEnd.hasValue() ) + return getContent(); + + sal_Int32 nStart = 0; + sal_Int32 nEnd = 0; + rStart >>= nStart; + rEnd >>= nEnd; + + uno::Reference< text::XTextRange > xStart; + uno::Reference< text::XTextRange > xEnd; + + if( nStart > nEnd) + throw uno::RuntimeException(); + + if( nEnd != 0) + { + if( nEnd == nStart ) + { + xStart = mxTextDocument->getText()->getEnd(); + xEnd = mxTextDocument->getText()->getEnd(); + } + else + { + xEnd = SwVbaRangeHelper::getRangeByPosition( mxTextDocument->getText(), nEnd ); + + if( nStart != 0 ) + xStart = SwVbaRangeHelper::getRangeByPosition( mxTextDocument->getText(), nStart ); + else + xStart = mxTextDocument->getText()->getStart(); + } + } + else + { + xStart = mxTextDocument->getText()->getEnd(); + xEnd = mxTextDocument->getText()->getEnd(); + } + + if( !xStart.is() && !xEnd.is() ) + { + try + { + // FIXME + xStart = mxTextDocument->getText()->getStart(); + xEnd = mxTextDocument->getText()->getEnd(); + } + catch(const uno::Exception&) + { + DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); + } + } + return uno::Reference< word::XRange >( new SwVbaRange( this, mxContext, mxTextDocument, xStart, xEnd ) ); +} + +uno::Any SAL_CALL +SwVbaDocument::BuiltInDocumentProperties( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaBuiltinDocumentProperties( mxParent, mxContext, getModel() ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaDocument::CustomDocumentProperties( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaCustomDocumentProperties( mxParent, mxContext, getModel() ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaDocument::Bookmarks( const uno::Any& rIndex ) +{ + uno::Reference< text::XBookmarksSupplier > xBookmarksSupplier( getModel(),uno::UNO_QUERY_THROW ); + uno::Reference<container::XIndexAccess > xBookmarks( xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xBookmarksVba( new SwVbaBookmarks( this, mxContext, xBookmarks, getModel() ) ); + if ( rIndex.getValueTypeClass() == uno::TypeClass_VOID ) + return uno::Any( xBookmarksVba ); + + return xBookmarksVba->Item( rIndex, uno::Any() ); +} + +uno::Any SwVbaDocument::ContentControls(const uno::Any& index) +{ + uno::Reference<XCollection> xContentControls( + new SwVbaContentControls(this, mxContext, mxTextDocument, "", "")); + if (index.hasValue()) + { + try + { + return xContentControls->Item(index, uno::Any()); + } + catch (lang::IndexOutOfBoundsException&) + { + // Hack: Instead of an index, it might be a float that was mistakenly treated as a long, + // which can happen with any valid positive integer when specified as a double like + // ActiveDocument.ContentControls(1841581653#). + if (index.getValueTypeClass() == css::uno::TypeClass_LONG) + { + sal_Int32 nLong(0); + index >>= nLong; + return xContentControls->Item(uno::Any(static_cast<double>(nLong)), uno::Any()); + } + } + } + + return uno::Any(xContentControls); +} + +uno::Any SwVbaDocument::SelectContentControlsByTag(const uno::Any& index) +{ + OUString sTag; + index >>= sTag; + return uno::Any(uno::Reference<XCollection>( + new SwVbaContentControls(this, mxContext, mxTextDocument, sTag, ""))); +} + +uno::Any SwVbaDocument::SelectContentControlsByTitle(const uno::Any& index) +{ + OUString sTitle; + index >>= sTitle; + return uno::Any(uno::Reference<XCollection>( + new SwVbaContentControls(this, mxContext, mxTextDocument, "", sTitle))); +} + +uno::Reference<word::XWindow> SwVbaDocument::getActiveWindow() +{ + // copied from vbaapplication which has a #FIXME so far can't determine Parent + return new SwVbaWindow(uno::Reference< XHelperInterface >(), mxContext, mxModel, + mxModel->getCurrentController()); +} + +uno::Any SAL_CALL +SwVbaDocument::Variables( const uno::Any& rIndex ) +{ + uno::Reference< css::document::XDocumentPropertiesSupplier > xDocumentPropertiesSupplier( getModel(),uno::UNO_QUERY_THROW ); + uno::Reference< css::document::XDocumentProperties > xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties(); + uno::Reference< beans::XPropertyAccess > xUserDefined( xDocumentProperties->getUserDefinedProperties(), uno::UNO_QUERY_THROW ); + + uno::Reference< XCollection > xVariables( new SwVbaVariables( this, mxContext, xUserDefined ) ); + if ( rIndex.getValueTypeClass() == uno::TypeClass_VOID ) + return uno::Any( xVariables ); + + return xVariables->Item( rIndex, uno::Any() ); +} + +uno::Any SAL_CALL +SwVbaDocument::Paragraphs( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaParagraphs( mxParent, mxContext, mxTextDocument ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaDocument::Styles( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaStyles( mxParent, mxContext, getModel() ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaDocument::Fields( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaFields( mxParent, mxContext, getModel() ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaDocument::Shapes( const uno::Any& index ) +{ + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( getModel(), uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW ); + uno::Reference< frame::XModel > xModel( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xCol( new ScVbaShapes( this, mxContext, xIndexAccess, xModel ) ); + + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +void SAL_CALL +SwVbaDocument::Select() +{ + auto xRange = getContent(); + if ( xRange ) + xRange->Select(); +} + +uno::Any SAL_CALL +SwVbaDocument::Sections( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaSections( mxParent, mxContext, getModel() ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaDocument::TablesOfContents( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaTablesOfContents( this, mxContext, mxTextDocument ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL SwVbaDocument::FormFields(const uno::Any& index) +{ + uno::Reference<XCollection> xCol(new SwVbaFormFields(this, mxContext, mxTextDocument)); + if (index.hasValue()) + return xCol->Item(index, uno::Any()); + return uno::Any(xCol); +} + +uno::Any SAL_CALL +SwVbaDocument::PageSetup( ) +{ + uno::Reference< beans::XPropertySet > xPageProps( word::getCurrentPageStyle( mxModel ), uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< word::XPageSetup >( new SwVbaPageSetup( this, mxContext, mxModel, xPageProps ) ) ); +} + +OUString +SwVbaDocument::getServiceImplName() +{ + return "SwVbaDocument"; +} + +uno::Any SAL_CALL +SwVbaDocument::getAttachedTemplate() +{ + uno::Reference< word::XTemplate > xTemplate; + uno::Reference<css::document::XDocumentPropertiesSupplier> const xDocPropSupp( + getModel(), uno::UNO_QUERY_THROW); + uno::Reference< css::document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_SET_THROW ); + OUString sTemplateUrl = xDocProps->getTemplateURL(); + + xTemplate = new SwVbaTemplate( this, mxContext, sTemplateUrl ); + return uno::Any( xTemplate ); +} + +void SAL_CALL +SwVbaDocument::setAttachedTemplate( const css::uno::Any& _attachedtemplate ) +{ + OUString sTemplate; + if( !( _attachedtemplate >>= sTemplate ) ) + { + throw uno::RuntimeException(); + } + OUString aURL; + INetURLObject aObj; + aObj.SetURL( sTemplate ); + bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid; + if ( bIsURL ) + aURL = sTemplate; + else + osl::FileBase::getFileURLFromSystemPath( sTemplate, aURL ); + + uno::Reference<css::document::XDocumentPropertiesSupplier> const xDocPropSupp( + getModel(), uno::UNO_QUERY_THROW ); + uno::Reference< css::document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_SET_THROW ); + xDocProps->setTemplateURL( aURL ); +} + +uno::Any SAL_CALL +SwVbaDocument::Tables( const css::uno::Any& aIndex ) +{ + uno::Reference< frame::XModel > xModel( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xColl( new SwVbaTables( mxParent, mxContext, xModel ) ); + + if ( aIndex.hasValue() ) + return xColl->Item( aIndex, uno::Any() ); + return uno::Any( xColl ); +} + +void SAL_CALL SwVbaDocument::Activate() +{ + VbaDocumentBase::Activate(); +} + +::sal_Int32 SAL_CALL SwVbaDocument::getProtectionType() +{ + //TODO + return word::WdProtectionType::wdNoProtection; +} + +void SAL_CALL SwVbaDocument::setProtectionType( ::sal_Int32 /*_protectiontype*/ ) +{ + //TODO +} + +sal_Bool SAL_CALL SwVbaDocument::getUpdateStylesOnOpen() +{ + //TODO + return false; +} + +void SAL_CALL SwVbaDocument::setUpdateStylesOnOpen( sal_Bool /*_updatestylesonopen*/ ) +{ + //TODO +} + +sal_Bool SAL_CALL SwVbaDocument::getAutoHyphenation() +{ + // check this property only in default paragraph style + bool IsAutoHyphenation = false; + uno::Reference< beans::XPropertySet > xParaProps( word::getDefaultParagraphStyle( getModel() ), uno::UNO_QUERY_THROW ); + xParaProps->getPropertyValue("ParaIsHyphenation") >>= IsAutoHyphenation; + return IsAutoHyphenation; +} + +void SAL_CALL SwVbaDocument::setAutoHyphenation( sal_Bool _autohyphenation ) +{ + //TODO + uno::Reference< beans::XPropertySet > xParaProps( word::getDefaultParagraphStyle( getModel() ), uno::UNO_QUERY_THROW ); + xParaProps->setPropertyValue("ParaIsHyphenation", uno::Any( _autohyphenation ) ); +} + +::sal_Int32 SAL_CALL SwVbaDocument::getHyphenationZone() +{ + //TODO + return 0; +} + +void SAL_CALL SwVbaDocument::setHyphenationZone( ::sal_Int32 /*_hyphenationzone*/ ) +{ + //TODO +} + +::sal_Int32 SAL_CALL SwVbaDocument::getConsecutiveHyphensLimit() +{ + //TODO + sal_Int16 nHyphensLimit = 0; + uno::Reference< beans::XPropertySet > xParaProps( word::getDefaultParagraphStyle( getModel() ), uno::UNO_QUERY_THROW ); + xParaProps->getPropertyValue("ParaHyphenationMaxHyphens") >>= nHyphensLimit; + return nHyphensLimit; +} + +void SAL_CALL SwVbaDocument::setConsecutiveHyphensLimit( ::sal_Int32 _consecutivehyphenslimit ) +{ + sal_Int16 nHyphensLimit = static_cast< sal_Int16 >( _consecutivehyphenslimit ); + uno::Reference< beans::XPropertySet > xParaProps( word::getDefaultParagraphStyle( getModel() ), uno::UNO_QUERY_THROW ); + xParaProps->setPropertyValue("ParaHyphenationMaxHyphens", uno::Any( nHyphensLimit ) ); +} + +uno::Reference< ooo::vba::word::XMailMerge > SAL_CALL SwVbaDocument::getMailMerge() +{ + return SwVbaMailMerge::get(mxParent, mxContext); +} + +void SAL_CALL SwVbaDocument::Protect( ::sal_Int32 /*Type*/, const uno::Any& /*NOReset*/, const uno::Any& /*Password*/, const uno::Any& /*UseIRM*/, const uno::Any& /*EnforceStyleLock*/ ) +{ + // Seems not support in Writer + // VbaDocumentBase::Protect( Password ); +} + +void SAL_CALL SwVbaDocument::PrintOut( const uno::Any& /*Background*/, const uno::Any& /*Append*/, const uno::Any& /*Range*/, const uno::Any& /*OutputFileName*/, const uno::Any& /*From*/, const uno::Any& /*To*/, const uno::Any& /*Item*/, const uno::Any& /*Copies*/, const uno::Any& /*Pages*/, const uno::Any& /*PageType*/, const uno::Any& /*PrintToFile*/, const uno::Any& /*Collate*/, const uno::Any& /*FileName*/, const uno::Any& /*ActivePrinterMacGX*/, const uno::Any& /*ManualDuplexPrint*/, const uno::Any& /*PrintZoomColumn*/, const uno::Any& /*PrintZoomRow*/, const uno::Any& /*PrintZoomPaperWidth*/, const uno::Any& /*PrintZoomPaperHeight*/ ) +{ + //TODO +} + +void SAL_CALL SwVbaDocument::PrintPreview( ) +{ + dispatchRequests( mxModel,".uno:PrintPreview" ); +} + +void SAL_CALL SwVbaDocument::ClosePrintPreview( ) +{ + dispatchRequests( mxModel,".uno:ClosePreview" ); +} + +uno::Any SAL_CALL +SwVbaDocument::Revisions( const uno::Any& index ) +{ + uno::Reference< css::document::XRedlinesSupplier > xRedlinesSupp( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xRedlines( xRedlinesSupp->getRedlines(), uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xCol( new SwVbaRevisions( this, mxContext, getModel(), xRedlines ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaDocument::Frames( const uno::Any& index ) +{ + uno::Reference< text::XTextFramesSupplier > xTextFramesSupp( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xFrames( xTextFramesSupp->getTextFrames(), uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xCol( new SwVbaFrames( this, mxContext, xFrames, getModel() ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +void SAL_CALL +SwVbaDocument::SaveAs2000( const uno::Any& FileName, const uno::Any& FileFormat, const uno::Any& /*LockComments*/, const uno::Any& /*Password*/, const uno::Any& /*AddToRecentFiles*/, const uno::Any& /*WritePassword*/, const uno::Any& /*ReadOnlyRecommended*/, const uno::Any& /*EmbedTrueTypeFonts*/, const uno::Any& /*SaveNativePictureFormat*/, const uno::Any& /*SaveFormsData*/, const uno::Any& /*SaveAsAOCELetter*/ ) +{ + SAL_INFO("sw.vba", "Document.SaveAs2000(FileName:=" << FileName << ",FileFormat:=" << FileFormat << ")"); + + // Based on ScVbaWorkbook::SaveAs. + OUString sFileName; + FileName >>= sFileName; + OUString sURL; + osl::FileBase::getFileURLFromSystemPath( sFileName, sURL ); + + // Detect if there is no path then we need to use the current folder. + INetURLObject aURL( sURL ); + sURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ); + if( sURL.isEmpty() ) + { + // Need to add cur dir ( of this document ) or else the 'Work' dir + sURL = getModel()->getURL(); + + if ( sURL.isEmpty() ) + { + // Not path available from 'this' document. Need to add the 'document'/work directory then. + // Based on SwVbaOptions::getValueEvent() + uno::Reference< util::XPathSettings > xPathSettings = util::thePathSettings::get( comphelper::getProcessComponentContext() ); + OUString sPathUrl; + xPathSettings->getPropertyValue( "Work" ) >>= sPathUrl; + // Path could be a multipath, Microsoft doesn't support this feature in Word currently. + // Only the last path is from interest. + sal_Int32 nIndex = sPathUrl.lastIndexOf( ';' ); + if( nIndex != -1 ) + { + sPathUrl = sPathUrl.copy( nIndex + 1 ); + } + + aURL.SetURL( sPathUrl ); + } + else + { + aURL.SetURL( sURL ); + aURL.Append( sFileName ); + } + sURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ); + + } + + sal_Int32 nFileFormat = word::WdSaveFormat::wdFormatDocument; + FileFormat >>= nFileFormat; + + uno::Sequence storeProps{ comphelper::makePropertyValue("FilterName", uno::Any()) }; + + setFilterPropsFromFormat( nFileFormat, storeProps ); + + uno::Reference< frame::XStorable > xStor( getModel(), uno::UNO_QUERY_THROW ); + xStor->storeAsURL( sURL, storeProps ); +} + +void SAL_CALL +SwVbaDocument::SaveAs( const uno::Any& FileName, const uno::Any& FileFormat, const uno::Any& LockComments, const uno::Any& Password, const uno::Any& AddToRecentFiles, const uno::Any& WritePassword, const uno::Any& ReadOnlyRecommended, const uno::Any& EmbedTrueTypeFonts, const uno::Any& SaveNativePictureFormat, const uno::Any& SaveFormsData, const uno::Any& SaveAsAOCELetter, const uno::Any& /*Encoding*/, const uno::Any& /*InsertLineBreaks*/, const uno::Any& /*AllowSubstitutions*/, const uno::Any& /*LineEnding*/, const uno::Any& /*AddBiDiMarks*/ ) +{ + return SaveAs2000( FileName, FileFormat, LockComments, Password, AddToRecentFiles, WritePassword, ReadOnlyRecommended, EmbedTrueTypeFonts, SaveNativePictureFormat, SaveFormsData, SaveAsAOCELetter ); +} + +void SAL_CALL +SwVbaDocument::Close( const uno::Any& SaveChanges, const uno::Any& /*OriginalFormat*/, const uno::Any& /*RouteDocument*/ ) +{ + VbaDocumentBase::Close( SaveChanges, uno::Any(), uno::Any() ); +} + +void SAL_CALL +SwVbaDocument::SavePreviewPngAs( const uno::Any& FileName ) +{ + OUString sFileName; + FileName >>= sFileName; + OUString sURL; + osl::FileBase::getFileURLFromSystemPath( sFileName, sURL ); + + uno::Sequence storeProps{ comphelper::makePropertyValue("FilterName", + OUString("writer_png_Export")) }; + + uno::Reference< frame::XStorable > xStor( getModel(), uno::UNO_QUERY_THROW ); + xStor->storeToURL( sURL, storeProps ); +} + +uno::Any +SwVbaDocument::getControlShape( std::u16string_view sName ) +{ + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW ); + + sal_Int32 nCount = xIndexAccess->getCount(); + for( int index = 0; index < nCount; index++ ) + { + uno::Any aUnoObj = xIndexAccess->getByIndex( index ); + // It seems there are some drawing objects that can not query into Control shapes? + uno::Reference< drawing::XControlShape > xControlShape( aUnoObj, uno::UNO_QUERY ); + if( xControlShape.is() ) + { + uno::Reference< container::XNamed > xNamed( xControlShape->getControl(), uno::UNO_QUERY_THROW ); + if( sName == xNamed->getName() ) + { + return aUnoObj; + } + } + } + return uno::Any(); +} + +uno::Reference< beans::XIntrospectionAccess > SAL_CALL +SwVbaDocument::getIntrospection( ) +{ + return uno::Reference< beans::XIntrospectionAccess >(); +} + +uno::Any SAL_CALL +SwVbaDocument::invoke( const OUString& aFunctionName, const uno::Sequence< uno::Any >& /*aParams*/, uno::Sequence< ::sal_Int16 >& /*aOutParamIndex*/, uno::Sequence< uno::Any >& /*aOutParam*/ ) +{ + SAL_INFO("sw.vba", "** will barf " << aFunctionName ); + throw uno::RuntimeException(); // unsupported operation +} + +void SAL_CALL +SwVbaDocument::setValue( const OUString& /*aPropertyName*/, const uno::Any& /*aValue*/ ) +{ + throw uno::RuntimeException(); // unsupported operation +} +uno::Any SAL_CALL +SwVbaDocument::getValue( const OUString& aPropertyName ) +{ + uno::Reference< drawing::XControlShape > xControlShape( getControlShape( aPropertyName ), uno::UNO_QUERY_THROW ); + + uno::Reference<lang::XMultiComponentFactory > xServiceManager( mxContext->getServiceManager(), uno::UNO_SET_THROW ); + uno::Reference< XControlProvider > xControlProvider( xServiceManager->createInstanceWithContext("ooo.vba.ControlProvider", mxContext ), uno::UNO_QUERY_THROW ); + uno::Reference< msforms::XControl > xControl( xControlProvider->createControl( xControlShape, getModel() ) ); + return uno::Any( xControl ); +} + +sal_Bool SAL_CALL +SwVbaDocument::hasMethod( const OUString& /*aName*/ ) +{ + return false; +} + +sal_Bool SAL_CALL +SwVbaDocument::hasProperty( const OUString& aName ) +{ + uno::Reference< container::XNameAccess > xFormControls( getFormControls() ); + if ( xFormControls.is() ) + return xFormControls->hasByName( aName ); + return false; +} + +uno::Reference< container::XNameAccess > +SwVbaDocument::getFormControls() const +{ + uno::Reference< container::XNameAccess > xFormControls; + try + { + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< form::XFormsSupplier > xFormSupplier( xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xFormSupplier->getForms(), uno::UNO_QUERY_THROW ); + // get the www-standard container ( maybe we should access the + // 'www-standard' by name rather than index, this seems an + // implementation detail + xFormControls.set( xIndexAccess->getByIndex(0), uno::UNO_QUERY_THROW ); + } + catch(const uno::Exception&) + { + } + return xFormControls; +} + +// XInterfaceWithIID + +OUString SAL_CALL +SwVbaDocument::getIID() +{ + return "{82154424-0FBF-11d4-8313-005004526AB4}"; +} + +// XConnectable + +OUString SAL_CALL +SwVbaDocument::GetIIDForClassItselfNotCoclass() +{ + return "{82154428-0FBF-11D4-8313-005004526AB4}"; +} + +TypeAndIID SAL_CALL +SwVbaDocument::GetConnectionPoint() +{ + TypeAndIID aResult = + { cppu::UnoType<word::XDocumentOutgoing>::get(), + "{82154429-0FBF-11D4-8313-005004526AB4}" + }; + + return aResult; +} + +// XSinkCaller + +void SAL_CALL +SwVbaDocument::CallSinks( const OUString& Method, uno::Sequence< uno::Any >& Arguments ) +{ + for (auto& i : mvSinks) + { + if (i.is()) + i->Call(Method, Arguments); + } +} + +uno::Reference<XConnectionPoint> SAL_CALL +SwVbaDocument::FindConnectionPoint() +{ + uno::Reference<XConnectionPoint> xCP(new SwVbaDocumentOutgoingConnectionPoint(this)); + return xCP; +} + +// SwVbaApplicationOutgoingConnectionPoint + +SwVbaDocumentOutgoingConnectionPoint::SwVbaDocumentOutgoingConnectionPoint( SwVbaDocument* pDoc ) : + mpDoc(pDoc) +{ +} + +// XConnectionPoint + +sal_uInt32 SAL_CALL +SwVbaDocumentOutgoingConnectionPoint::Advise( const uno::Reference< XSink >& Sink ) +{ + return mpDoc->AddSink(Sink); +} + +void SAL_CALL +SwVbaDocumentOutgoingConnectionPoint::Unadvise( sal_uInt32 Cookie ) +{ + mpDoc->RemoveSink( Cookie ); +} + +uno::Sequence< OUString > +SwVbaDocument::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Document" + }; + return aServiceNames; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Writer_SwVbaDocument_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args) +{ + return cppu::acquire(new SwVbaDocument(args, context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbadocument.hxx b/sw/source/ui/vba/vbadocument.hxx new file mode 100644 index 0000000000..069215513c --- /dev/null +++ b/sw/source/ui/vba/vbadocument.hxx @@ -0,0 +1,125 @@ +/* -*- 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_VBA_VBADOCUMENT_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBADOCUMENT_HXX + +#include <ooo/vba/XSink.hpp> +#include <ooo/vba/XSinkCaller.hpp> +#include <ooo/vba/word/XDocument.hpp> +#include <vbahelper/vbadocumentbase.hxx> +#include <com/sun/star/text/XTextDocument.hpp> +#include <cppuhelper/implbase.hxx> + +#include <vector> + +typedef cppu::ImplInheritanceHelper< VbaDocumentBase, ooo::vba::word::XDocument, ooo::vba::XSinkCaller > SwVbaDocument_BASE; + +class SwVbaDocument : public SwVbaDocument_BASE +{ +private: + css::uno::Reference< css::text::XTextDocument > mxTextDocument; + + std::vector<css::uno::Reference< ooo::vba::XSink >> mvSinks; + + void Initialize(); + css::uno::Any getControlShape( std::u16string_view sName ); + css::uno::Reference< css::container::XNameAccess > getFormControls() const; + +public: + SwVbaDocument( const css::uno::Reference< ooo::vba::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& m_xContext, css::uno::Reference< css::frame::XModel > const & xModel ); + SwVbaDocument( css::uno::Sequence< css::uno::Any > const& aArgs, css::uno::Reference< css::uno::XComponentContext >const& xContext ); + virtual ~SwVbaDocument() override; + + sal_uInt32 AddSink( const css::uno::Reference< ooo::vba::XSink >& xSink ); + void RemoveSink( sal_uInt32 nNumber ); + + // XDocument + virtual css::uno::Reference< ooo::vba::word::XRange > SAL_CALL getContent() override; + virtual css::uno::Reference< ooo::vba::word::XRange > SAL_CALL Range( const css::uno::Any& rStart, const css::uno::Any& rEnd ) override; + virtual css::uno::Any SAL_CALL BuiltInDocumentProperties( const css::uno::Any& index ) override; + virtual css::uno::Any SAL_CALL CustomDocumentProperties( const css::uno::Any& index ) override; + virtual css::uno::Any SAL_CALL Bookmarks( const css::uno::Any& rIndex ) override; + css::uno::Any SAL_CALL ContentControls(const css::uno::Any& index) override; + css::uno::Any SAL_CALL SelectContentControlsByTag(const css::uno::Any& index) override; + css::uno::Any SAL_CALL SelectContentControlsByTitle(const css::uno::Any& index) override; + css::uno::Reference<ov::word::XWindow> SAL_CALL getActiveWindow() override; + virtual css::uno::Any SAL_CALL Variables( const css::uno::Any& rIndex ) override; + virtual css::uno::Any SAL_CALL getAttachedTemplate() override; + virtual void SAL_CALL setAttachedTemplate( const css::uno::Any& _attachedtemplate ) override; + virtual css::uno::Any SAL_CALL Paragraphs( const css::uno::Any& rIndex ) override; + virtual css::uno::Any SAL_CALL Styles( const css::uno::Any& rIndex ) override; + virtual css::uno::Any SAL_CALL Tables( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Fields( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Shapes( const css::uno::Any& aIndex ) override; + virtual void SAL_CALL Select() override; + virtual css::uno::Any SAL_CALL Sections( const css::uno::Any& aIndex ) override; + virtual void SAL_CALL Activate() override; + virtual css::uno::Any SAL_CALL PageSetup() override; + virtual css::uno::Any SAL_CALL TablesOfContents( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL FormFields( const css::uno::Any& aIndex ) override; + virtual ::sal_Int32 SAL_CALL getProtectionType() override; + virtual void SAL_CALL setProtectionType( ::sal_Int32 _protectiontype ) override; + virtual sal_Bool SAL_CALL getUpdateStylesOnOpen() override; + virtual void SAL_CALL setUpdateStylesOnOpen( sal_Bool _updatestylesonopen ) override; + virtual sal_Bool SAL_CALL getAutoHyphenation() override; + virtual void SAL_CALL setAutoHyphenation( sal_Bool _autohyphenation ) override; + virtual ::sal_Int32 SAL_CALL getHyphenationZone() override; + virtual void SAL_CALL setHyphenationZone( ::sal_Int32 _hyphenationzone ) override; + virtual ::sal_Int32 SAL_CALL getConsecutiveHyphensLimit() override; + virtual void SAL_CALL setConsecutiveHyphensLimit( ::sal_Int32 _consecutivehyphenslimit ) override; + virtual css::uno::Reference< ooo::vba::word::XMailMerge > SAL_CALL getMailMerge() override; + + using VbaDocumentBase::Protect; + virtual void SAL_CALL Protect( ::sal_Int32 Type, const css::uno::Any& NOReset, const css::uno::Any& Password, const css::uno::Any& UseIRM, const css::uno::Any& EnforceStyleLock ) override; + virtual void SAL_CALL PrintOut( const css::uno::Any& Background, const css::uno::Any& Append, const css::uno::Any& Range, const css::uno::Any& OutputFileName, const css::uno::Any& From, const css::uno::Any& To, const css::uno::Any& Item, const css::uno::Any& Copies, const css::uno::Any& Pages, const css::uno::Any& PageType, const css::uno::Any& PrintToFile, const css::uno::Any& Collate, const css::uno::Any& FileName, const css::uno::Any& ActivePrinterMacGX, const css::uno::Any& ManualDuplexPrint, const css::uno::Any& PrintZoomColumn, const css::uno::Any& PrintZoomRow, const css::uno::Any& PrintZoomPaperWidth, const css::uno::Any& PrintZoomPaperHeight ) override; + virtual void SAL_CALL PrintPreview( ) override; + virtual void SAL_CALL ClosePrintPreview( ) override; + virtual css::uno::Any SAL_CALL Revisions( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Frames( const css::uno::Any& aIndex ) override; + virtual void SAL_CALL SaveAs2000( const css::uno::Any& FileName, const css::uno::Any& FileFormat, const css::uno::Any& LockComments, const css::uno::Any& Password, const css::uno::Any& AddToRecentFiles, const css::uno::Any& WritePassword, const css::uno::Any& ReadOnlyRecommended, const css::uno::Any& EmbedTrueTypeFonts, const css::uno::Any& SaveNativePictureFormat, const css::uno::Any& SaveFormsData, const css::uno::Any& SaveAsAOCELetter ) override; + virtual void SAL_CALL SaveAs( const css::uno::Any& FileName, const css::uno::Any& FileFormat, const css::uno::Any& LockComments, const css::uno::Any& Password, const css::uno::Any& AddToRecentFiles, const css::uno::Any& WritePassword, const css::uno::Any& ReadOnlyRecommended, const css::uno::Any& EmbedTrueTypeFonts, const css::uno::Any& SaveNativePictureFormat, const css::uno::Any& SaveFormsData, const css::uno::Any& SaveAsAOCELetter, const css::uno::Any& Encoding, const css::uno::Any& InsertLineBreaks, const css::uno::Any& AllowSubstitutions, const css::uno::Any& LineEnding, const css::uno::Any& AddBiDiMarks ) override; + virtual void SAL_CALL Close( const css::uno::Any& SaveChanges, const css::uno::Any& OriginalFormat, const css::uno::Any& RouteDocument ) override; + virtual void SAL_CALL SavePreviewPngAs( const css::uno::Any& FileName ) override; + + // XInvocation + virtual css::uno::Reference< css::beans::XIntrospectionAccess > SAL_CALL getIntrospection( ) override; + virtual css::uno::Any SAL_CALL invoke( const OUString& aFunctionName, const css::uno::Sequence< css::uno::Any >& aParams, css::uno::Sequence< ::sal_Int16 >& aOutParamIndex, css::uno::Sequence< css::uno::Any >& aOutParam ) override; + virtual void SAL_CALL setValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getValue( const OUString& aPropertyName ) override; + virtual sal_Bool SAL_CALL hasMethod( const OUString& aName ) override; + virtual sal_Bool SAL_CALL hasProperty( const OUString& aName ) override; + + // XInterfaceWithIID + virtual OUString SAL_CALL getIID() override; + + // XConnectable + virtual OUString SAL_CALL GetIIDForClassItselfNotCoclass() override; + virtual ov::TypeAndIID SAL_CALL GetConnectionPoint() override; + virtual css::uno::Reference<ov::XConnectionPoint> SAL_CALL FindConnectionPoint() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + + // XSinkCaller + virtual void SAL_CALL CallSinks( const OUString& Method, css::uno::Sequence< css::uno::Any >& Arguments ) override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBADOCUMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbadocumentproperties.cxx b/sw/source/ui/vba/vbadocumentproperties.cxx new file mode 100644 index 0000000000..6d5f06830f --- /dev/null +++ b/sw/source/ui/vba/vbadocumentproperties.cxx @@ -0,0 +1,921 @@ +/* -*- 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 "vbadocumentproperties.hxx" +#include <cppuhelper/implbase.hxx> +#include <sal/log.hxx> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <ooo/vba/word/WdBuiltInProperty.hpp> +#include <ooo/vba/office/MsoDocProperties.hpp> +#include <comphelper/diagnose_ex.hxx> +#include <memory> +#include "wordvbahelper.hxx" +#include <fesh.hxx> +#include <docsh.hxx> +#include <utility> +using namespace ::ooo::vba; +using namespace css; + +/// @throws lang::IllegalArgumentException +static sal_Int8 lcl_toMSOPropType( const uno::Type& aType ) +{ + sal_Int16 msoType = office::MsoDocProperties::msoPropertyTypeString; + + switch ( aType.getTypeClass() ) + { + case uno::TypeClass_BOOLEAN: + msoType = office::MsoDocProperties::msoPropertyTypeBoolean; + break; + case uno::TypeClass_FLOAT: + msoType = office::MsoDocProperties::msoPropertyTypeFloat; + break; + case uno::TypeClass_STRUCT: // Assume date + msoType = office::MsoDocProperties::msoPropertyTypeDate; + break; + case uno::TypeClass_BYTE: + case uno::TypeClass_SHORT: + case uno::TypeClass_LONG: + case uno::TypeClass_HYPER: + msoType = office::MsoDocProperties::msoPropertyTypeNumber; + break; + default: + throw lang::IllegalArgumentException(); + } + return msoType; +} + +namespace { + +class PropertGetSetHelper +{ +protected: + uno::Reference< frame::XModel > m_xModel; + uno::Reference<document::XDocumentProperties> m_xDocProps; +public: + explicit PropertGetSetHelper( uno::Reference< frame::XModel > xModel ):m_xModel(std::move( xModel )) + { + uno::Reference<document::XDocumentPropertiesSupplier> const + xDocPropSupp(m_xModel, uno::UNO_QUERY_THROW); + m_xDocProps.set(xDocPropSupp->getDocumentProperties(), + uno::UNO_SET_THROW); + } + virtual ~PropertGetSetHelper() {} + virtual uno::Any getPropertyValue( const OUString& rPropName ) = 0; + virtual void setPropertyValue( const OUString& rPropName, const uno::Any& aValue ) = 0; + uno::Reference< beans::XPropertySet > getUserDefinedProperties() { + return uno::Reference<beans::XPropertySet>( + m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); + } + +}; + +class BuiltinPropertyGetSetHelper : public PropertGetSetHelper +{ +public: + explicit BuiltinPropertyGetSetHelper( const uno::Reference< frame::XModel >& xModel ) :PropertGetSetHelper( xModel ) + { + } + virtual uno::Any getPropertyValue( const OUString& rPropName ) override + { + if ( rPropName == "EditingDuration" ) + { + sal_Int32 const nSecs = m_xDocProps->getEditingDuration(); + return uno::Any( nSecs/60 ); // minutes + } + else if ("Title" == rPropName) + { + return uno::Any(m_xDocProps->getTitle()); + } + else if ("Subject" == rPropName) + { + return uno::Any(m_xDocProps->getSubject()); + } + else if ("Author" == rPropName) + { + return uno::Any(m_xDocProps->getAuthor()); + } + else if ("Keywords" == rPropName) + { + return uno::Any(m_xDocProps->getKeywords()); + } + else if ("Description" == rPropName) + { + return uno::Any(m_xDocProps->getDescription()); + } + else if ("Template" == rPropName) + { + return uno::Any(m_xDocProps->getTemplateName()); + } + else if ("ModifiedBy" == rPropName) + { + return uno::Any(m_xDocProps->getModifiedBy()); + } + else if ("Generator" == rPropName) + { + return uno::Any(m_xDocProps->getGenerator()); + } + else if ("PrintDate" == rPropName) + { + return uno::Any(m_xDocProps->getPrintDate()); + } + else if ("CreationDate" == rPropName) + { + return uno::Any(m_xDocProps->getCreationDate()); + } + else if ("ModifyDate" == rPropName) + { + return uno::Any(m_xDocProps->getModificationDate()); + } + else if ("AutoloadURL" == rPropName) + { + return uno::Any(m_xDocProps->getAutoloadURL()); + } + else + { + // fall back to user-defined properties + return getUserDefinedProperties()->getPropertyValue(rPropName); + } + } + virtual void setPropertyValue( const OUString& rPropName, const uno::Any& aValue ) override + { + if ("EditingDuration" == rPropName) + { + sal_Int32 nMins = 0; + if (aValue >>= nMins) + { + m_xDocProps->setEditingDuration(nMins * 60); // convert minutes + } + } + else if ("Title" == rPropName) + { + OUString str; + if (aValue >>= str) + { + m_xDocProps->setTitle(str); + } + } + else if ("Subject" == rPropName) + { + OUString str; + if (aValue >>= str) + { + m_xDocProps->setSubject(str); + } + } + else if ("Author" == rPropName) + { + OUString str; + if (aValue >>= str) + { + m_xDocProps->setAuthor(str); + } + } + else if ("Keywords" == rPropName) + { + uno::Sequence<OUString> keywords; + if (aValue >>= keywords) + { + m_xDocProps->setKeywords(keywords); + } + } + else if ("Description" == rPropName) + { + OUString str; + if (aValue >>= str) + { + m_xDocProps->setDescription(str); + } + } + else if ("Template" == rPropName) + { + OUString str; + if (aValue >>= str) + { + m_xDocProps->setTemplateName(str); + } + } + else if ("ModifiedBy" == rPropName) + { + OUString str; + if (aValue >>= str) + { + m_xDocProps->setModifiedBy(str); + } + } + else if ("Generator" == rPropName) + { + OUString str; + if (aValue >>= str) + { + return m_xDocProps->setGenerator(str); + } + } + else if ("PrintDate" == rPropName) + { + util::DateTime dt; + if (aValue >>= dt) + { + m_xDocProps->setPrintDate(dt); + } + } + else if ("CreationDate" == rPropName) + { + util::DateTime dt; + if (aValue >>= dt) + { + m_xDocProps->setCreationDate(dt); + } + } + else if ("ModifyDate" == rPropName) + { + util::DateTime dt; + if (aValue >>= dt) + { + m_xDocProps->setModificationDate(dt); + } + } + else if ("AutoloadURL" == rPropName) + { + OUString str; + if (aValue >>= str) + { + m_xDocProps->setAutoloadURL(str); + } + } + else + { + // fall back to user-defined properties + getUserDefinedProperties()->setPropertyValue(rPropName, aValue); + } + } +}; + +class CustomPropertyGetSetHelper : public BuiltinPropertyGetSetHelper +{ +public: + explicit CustomPropertyGetSetHelper( const uno::Reference< frame::XModel >& xModel ) :BuiltinPropertyGetSetHelper( xModel ) + { + } + virtual uno::Any getPropertyValue( const OUString& rPropName ) override + { + return getUserDefinedProperties()->getPropertyValue(rPropName); + } + virtual void setPropertyValue( + const OUString& rPropName, const uno::Any& rValue) override + { + return getUserDefinedProperties()->setPropertyValue(rPropName, rValue); + } +}; + +class StatisticPropertyGetSetHelper : public PropertGetSetHelper +{ + SwDocShell* mpDocShell; + uno::Reference< beans::XPropertySet > mxModelProps; +public: + explicit StatisticPropertyGetSetHelper( const uno::Reference< frame::XModel >& xModel ) :PropertGetSetHelper( xModel ) , mpDocShell( nullptr ) + { + mxModelProps.set( m_xModel, uno::UNO_QUERY_THROW ); + mpDocShell = word::getDocShell( xModel ); + } + virtual uno::Any getPropertyValue( const OUString& rPropName ) override + { + try + { + // Characters, ParagraphCount & WordCount are available from + // the model ( and additionally these also update the statics object ) + return mxModelProps->getPropertyValue( rPropName ); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("sw.vba", ""); + } + uno::Any aReturn; + if ( rPropName == "LineCount" ) // special processing needed + { + if ( mpDocShell ) + { + if (SwFEShell* pFEShell = mpDocShell->GetFEShell()) + aReturn <<= pFEShell->GetLineCount(); + } + } + else + { + uno::Sequence< beans::NamedValue > const stats( + m_xDocProps->getDocumentStatistics()); + + auto pStat = std::find_if(stats.begin(), stats.end(), + [&rPropName](const beans::NamedValue& rStat) { return rPropName == rStat.Name; }); + if (pStat == stats.end()) + throw uno::RuntimeException(); // bad Property + + aReturn = pStat->Value; + } + return aReturn; + } + + virtual void setPropertyValue( const OUString& rPropName, const uno::Any& aValue ) override + { + uno::Sequence< beans::NamedValue > stats( + m_xDocProps->getDocumentStatistics()); + + auto [begin, end] = asNonConstRange(stats); + auto pStat = std::find_if(begin, end, + [&rPropName](const beans::NamedValue& rStat) { return rPropName == rStat.Name; }); + if (pStat != end) + { + pStat->Value = aValue; + m_xDocProps->setDocumentStatistics(stats); + } + } +}; + +class DocPropInfo +{ +public: + OUString msMSODesc; + OUString msOOOPropName; + std::shared_ptr< PropertGetSetHelper > mpPropGetSetHelper; + + static DocPropInfo createDocPropInfo( const OUString& sDesc, const OUString& sPropName, std::shared_ptr< PropertGetSetHelper > const & rHelper ) + { + DocPropInfo aItem; + aItem.msMSODesc = sDesc; + aItem.msOOOPropName = sPropName; + aItem.mpPropGetSetHelper = rHelper; + return aItem; + } + + static DocPropInfo createDocPropInfo( const char* sDesc, const char* sPropName, std::shared_ptr< PropertGetSetHelper > const & rHelper ) + { + return createDocPropInfo( OUString::createFromAscii( sDesc ), OUString::createFromAscii( sPropName ), rHelper ); + } + uno::Any getValue() + { + if ( mpPropGetSetHelper ) + return mpPropGetSetHelper->getPropertyValue( msOOOPropName ); + return uno::Any(); + } + void setValue( const uno::Any& rValue ) + { + if ( mpPropGetSetHelper ) + mpPropGetSetHelper->setPropertyValue( msOOOPropName, rValue ); + } + uno::Reference< beans::XPropertySet > getUserDefinedProperties() + { + uno::Reference< beans::XPropertySet > xProps; + if ( mpPropGetSetHelper ) + return mpPropGetSetHelper->getUserDefinedProperties(); + return xProps; + } +}; + +} + +typedef std::unordered_map< sal_Int32, DocPropInfo > MSOIndexToOODocPropInfo; + +namespace { + +class BuiltInIndexHelper +{ + MSOIndexToOODocPropInfo m_docPropInfoMap; + +public: + explicit BuiltInIndexHelper( const uno::Reference< frame::XModel >& xModel ) + { + auto aStandardHelper = std::make_shared<BuiltinPropertyGetSetHelper>( xModel ); + auto aUsingStatsHelper = std::make_shared<StatisticPropertyGetSetHelper>( xModel ); + + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyTitle ] = DocPropInfo::createDocPropInfo( "Title", "Title", aStandardHelper ); + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertySubject ] = DocPropInfo::createDocPropInfo( "Subject", "Subject", aStandardHelper ); + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyAuthor ] = DocPropInfo::createDocPropInfo( "Author", "Author", aStandardHelper ); + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyKeywords ] = DocPropInfo::createDocPropInfo( "Keywords", "Keywords", aStandardHelper ); + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyComments ] = DocPropInfo::createDocPropInfo( "Comments", "Description", aStandardHelper ); + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyTemplate ] = DocPropInfo::createDocPropInfo( "Template", "Template", aStandardHelper ); + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyLastAuthor ] = DocPropInfo::createDocPropInfo( "Last author", "ModifiedBy", aStandardHelper ); // doesn't seem to exist - throw or return nothing ? + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyRevision ] = DocPropInfo::createDocPropInfo( "Revision number", "EditingCycles", aStandardHelper ); // doesn't seem to exist - throw or return nothing ? + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyAppName ] = DocPropInfo::createDocPropInfo( "Application name", "Generator", aStandardHelper ); // doesn't seem to exist - throw or return nothing ? + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyTimeLastPrinted ] = DocPropInfo::createDocPropInfo( "Last print date", "PrintDate", aStandardHelper ); // doesn't seem to exist - throw or return nothing ? + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyTimeCreated ] = DocPropInfo::createDocPropInfo( "Creation date", "CreationDate", aStandardHelper ); + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyTimeLastSaved ] = DocPropInfo::createDocPropInfo( "Last save time", "ModifyDate", aStandardHelper ); + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyVBATotalEdit ] = DocPropInfo::createDocPropInfo( "Total editing time", "EditingDuration", aStandardHelper ); // Not sure if this is correct + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyPages ] = DocPropInfo::createDocPropInfo( "Number of pages", "PageCount", aUsingStatsHelper ); // special handling required ? + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyWords ] = DocPropInfo::createDocPropInfo( "Number of words", "WordCount", aUsingStatsHelper ); // special handling require ? + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyCharacters ] = DocPropInfo::createDocPropInfo( "Number of characters", "CharacterCount", aUsingStatsHelper ); // special handling required ? + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertySecurity ] = DocPropInfo::createDocPropInfo( "Security", "", aStandardHelper ); // doesn't seem to exist + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyCategory ] = DocPropInfo::createDocPropInfo( "Category", "Category", aStandardHelper ); // hacked in + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyFormat ] = DocPropInfo::createDocPropInfo( "Format", "", aStandardHelper ); // doesn't seem to exist + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyManager ] = DocPropInfo::createDocPropInfo( "Manager", "Manager", aStandardHelper ); // hacked in + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyCompany ] = DocPropInfo::createDocPropInfo( "Company", "Company", aStandardHelper ); // hacked in + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyBytes ] = DocPropInfo::createDocPropInfo( "Number of bytes", "", aStandardHelper ); // doesn't seem to exist - size on disk exists ( for an already saved document ) perhaps it will do ( or we need something else ) + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyLines ] = DocPropInfo::createDocPropInfo( "Number of lines", "LineCount", aUsingStatsHelper ); // special handling + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyParas ] = DocPropInfo::createDocPropInfo( "Number of paragraphs", "ParagraphCount", aUsingStatsHelper ); // special handling + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertySlides ] = DocPropInfo::createDocPropInfo( "Number of slides", "" , aStandardHelper ); // doesn't seem to exist + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyNotes ] = DocPropInfo::createDocPropInfo( "Number of notes", "", aStandardHelper ); // doesn't seem to exist + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyHiddenSlides ] = DocPropInfo::createDocPropInfo("Number of hidden Slides", "", aStandardHelper ); // doesn't seem to exist + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyMMClips ] = DocPropInfo::createDocPropInfo( "Number of multimedia clips", "", aStandardHelper ); // doesn't seem to exist + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyHyperlinkBase ] = DocPropInfo::createDocPropInfo( "Hyperlink base", "AutoloadURL", aStandardHelper ); + m_docPropInfoMap[ word::WdBuiltInProperty::wdPropertyCharsWSpaces ] = DocPropInfo::createDocPropInfo( "Number of characters (with spaces)", "", aStandardHelper ); // doesn't seem to be supported + } + + MSOIndexToOODocPropInfo& getDocPropInfoMap() { return m_docPropInfoMap; } +}; + +} + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::XDocumentProperty > SwVbaDocumentProperty_BASE; + +namespace { + +class SwVbaBuiltInDocumentProperty : public SwVbaDocumentProperty_BASE +{ +protected: + DocPropInfo mPropInfo; +public: + SwVbaBuiltInDocumentProperty( const uno::Reference< ov::XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, DocPropInfo rInfo ); + // XDocumentProperty + virtual void SAL_CALL Delete( ) override; + virtual OUString SAL_CALL getName( ) override; + virtual void SAL_CALL setName( const OUString& Name ) override; + virtual ::sal_Int8 SAL_CALL getType( ) override; + virtual void SAL_CALL setType( ::sal_Int8 Type ) override; + virtual sal_Bool SAL_CALL getLinkToContent( ) override; + virtual void SAL_CALL setLinkToContent( sal_Bool LinkToContent ) override; + virtual uno::Any SAL_CALL getValue( ) override; + virtual void SAL_CALL setValue( const uno::Any& Value ) override; + virtual OUString SAL_CALL getLinkSource( ) override; + virtual void SAL_CALL setLinkSource( const OUString& LinkSource ) override; + //XDefaultProperty + virtual OUString SAL_CALL getDefaultPropertyName( ) override { return "Value"; } + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual uno::Sequence<OUString> getServiceNames() override; +}; + +class SwVbaCustomDocumentProperty : public SwVbaBuiltInDocumentProperty +{ +public: + + SwVbaCustomDocumentProperty( const uno::Reference< ov::XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const DocPropInfo& rInfo ); + + virtual sal_Bool SAL_CALL getLinkToContent( ) override; + virtual void SAL_CALL setLinkToContent( sal_Bool LinkToContent ) override; + + virtual OUString SAL_CALL getLinkSource( ) override; + virtual void SAL_CALL setLinkSource( const OUString& LinkSource ) override; + virtual void SAL_CALL Delete( ) override; + virtual void SAL_CALL setName( const OUString& Name ) override; + virtual void SAL_CALL setType( ::sal_Int8 Type ) override; + +}; + +} + +SwVbaCustomDocumentProperty::SwVbaCustomDocumentProperty( const uno::Reference< ov::XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const DocPropInfo& rInfo ) : SwVbaBuiltInDocumentProperty( xParent, xContext, rInfo ) +{ +} + +sal_Bool +SwVbaCustomDocumentProperty::getLinkToContent( ) +{ + // #FIXME we need to store the link content somewhere + return false; +} + +void +SwVbaCustomDocumentProperty::setLinkToContent( sal_Bool /*bLinkContent*/ ) +{ +} + +OUString +SwVbaCustomDocumentProperty::getLinkSource( ) +{ + // #FIXME we need to store the link content somewhere + return OUString(); +} + +void +SwVbaCustomDocumentProperty::setLinkSource( const OUString& /*rsLinkContent*/ ) +{ + // #FIXME we need to store the link source somewhere +} + +void SAL_CALL +SwVbaCustomDocumentProperty::setName( const OUString& /*Name*/ ) +{ + // setName on existing property ? + // #FIXME + // do we need to delete existing property and create a new one? +} + +void SAL_CALL +SwVbaCustomDocumentProperty::setType( ::sal_Int8 /*Type*/ ) +{ + // setType, do we need to do a conversion? + // #FIXME the underlying value needs to be changed to the new type +} + +void SAL_CALL +SwVbaCustomDocumentProperty::Delete( ) +{ + uno::Reference< beans::XPropertyContainer > xContainer( + mPropInfo.getUserDefinedProperties(), uno::UNO_QUERY_THROW); + xContainer->removeProperty( getName() ); +} + +SwVbaBuiltInDocumentProperty::SwVbaBuiltInDocumentProperty( const uno::Reference< ov::XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, DocPropInfo rInfo ) : SwVbaDocumentProperty_BASE( xParent, xContext ), mPropInfo(std::move( rInfo )) +{ +} + +void SAL_CALL +SwVbaBuiltInDocumentProperty::Delete( ) +{ + // not valid for Builtin + throw uno::RuntimeException(); +} + +OUString SAL_CALL +SwVbaBuiltInDocumentProperty::getName( ) +{ + return mPropInfo.msMSODesc; +} + +void SAL_CALL +SwVbaBuiltInDocumentProperty::setName( const OUString& ) +{ + // not valid for Builtin + throw uno::RuntimeException(); +} + +::sal_Int8 SAL_CALL +SwVbaBuiltInDocumentProperty::getType( ) +{ + return lcl_toMSOPropType( getValue().getValueType() ); +} + +void SAL_CALL +SwVbaBuiltInDocumentProperty::setType( ::sal_Int8 /*Type*/ ) +{ + // not valid for Builtin + throw uno::RuntimeException(); +} + +sal_Bool SAL_CALL +SwVbaBuiltInDocumentProperty::getLinkToContent( ) +{ + return false; // built-in always false +} + +void SAL_CALL +SwVbaBuiltInDocumentProperty::setLinkToContent( sal_Bool /*LinkToContent*/ ) +{ + // not valid for Builtin + throw uno::RuntimeException(); +} + +uno::Any SAL_CALL +SwVbaBuiltInDocumentProperty::getValue( ) +{ + uno::Any aRet = mPropInfo.getValue(); + if ( !aRet.hasValue() ) + throw uno::RuntimeException(); + return aRet; +} + +void SAL_CALL +SwVbaBuiltInDocumentProperty::setValue( const uno::Any& Value ) +{ + mPropInfo.setValue( Value ); +} + +OUString SAL_CALL +SwVbaBuiltInDocumentProperty::getLinkSource( ) +{ + // not valid for Builtin + throw uno::RuntimeException(); +} + +void SAL_CALL +SwVbaBuiltInDocumentProperty::setLinkSource( const OUString& /*LinkSource*/ ) +{ + // not valid for Builtin + throw uno::RuntimeException(); +} + +OUString +SwVbaBuiltInDocumentProperty::getServiceImplName() +{ + return "SwVbaBuiltinDocumentProperty"; +} + +uno::Sequence<OUString> +SwVbaBuiltInDocumentProperty::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.DocumentProperty" + }; + return aServiceNames; +} +typedef ::cppu::WeakImplHelper< css::container::XIndexAccess + ,css::container::XNameAccess + ,css::container::XEnumerationAccess + > PropertiesImpl_BASE; + +typedef std::unordered_map< sal_Int32, uno::Reference< XDocumentProperty > > DocProps; + +namespace { + +class DocPropEnumeration : public ::cppu::WeakImplHelper< css::container::XEnumeration > +{ + DocProps mDocProps; + DocProps::iterator mIt; +public: + + explicit DocPropEnumeration( DocProps&& rProps ) : mDocProps( std::move(rProps) ), mIt( mDocProps.begin() ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return mIt != mDocProps.end(); + } + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( !hasMoreElements() ) + throw container::NoSuchElementException(); + return uno::Any( mIt++->second ); + } +}; + +} + +typedef std::unordered_map< OUString, uno::Reference< XDocumentProperty > > DocPropsByName; + +namespace { + +class BuiltInPropertiesImpl : public PropertiesImpl_BASE +{ +protected: + + uno::Reference< frame::XModel > m_xModel; + + DocProps mDocProps; + DocPropsByName mNamedDocProps; + + public: + BuiltInPropertiesImpl( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, uno::Reference< frame::XModel > xModel ) : m_xModel(std::move( xModel )) + { + BuiltInIndexHelper builtIns( m_xModel ); + for ( sal_Int32 index = word::WdBuiltInProperty::wdPropertyTitle; index <= word::WdBuiltInProperty::wdPropertyCharsWSpaces; ++index ) + { + mDocProps[ index ] = new SwVbaBuiltInDocumentProperty( xParent, xContext, builtIns.getDocPropInfoMap()[ index ] ); + mNamedDocProps[ mDocProps[ index ]->getName() ] = mDocProps[ index ]; + } + } +// XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount( ) override + { + return mDocProps.size(); + } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + // correct the correct by the base class for 1 based indices + DocProps::iterator it = mDocProps.find( ++Index ); + if ( it == mDocProps.end() ) + throw lang::IndexOutOfBoundsException(); + return uno::Any( it->second ); + } + virtual uno::Any SAL_CALL getByName( const OUString& aName ) override + { + if ( !hasByName( aName ) ) + throw container::NoSuchElementException(); + DocPropsByName::iterator it = mNamedDocProps.find( aName ); + return uno::Any( it->second ); + + } + virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override + { + uno::Sequence< OUString > aNames( getCount() ); + OUString* pName = aNames.getArray(); + for (const auto& rEntry : mNamedDocProps) + { + *pName = rEntry.first; + ++pName; + } + return aNames; + } + + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { + DocPropsByName::iterator it = mNamedDocProps.find( aName ); + if ( it == mNamedDocProps.end() ) + return false; + return true; + } +// XElementAccess + virtual uno::Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<XDocumentProperty>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + return !mDocProps.empty(); + } + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + return new DocPropEnumeration( std::unordered_map(mDocProps) ); + } +}; + +} + +SwVbaBuiltinDocumentProperties::SwVbaBuiltinDocumentProperties( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< frame::XModel >& xModel ) : SwVbaDocumentproperties_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( new BuiltInPropertiesImpl( xParent, xContext, xModel ) ) ) +{ +} + +uno::Reference< XDocumentProperty > SAL_CALL +SwVbaBuiltinDocumentProperties::Add( const OUString& /*Name*/, sal_Bool /*LinkToContent*/, ::sal_Int8 /*Type*/, const uno::Any& /*value*/, const uno::Any& /*LinkSource*/ ) +{ + throw uno::RuntimeException( "not supported for Builtin properties" ); +} + +// XEnumerationAccess +uno::Type SAL_CALL +SwVbaBuiltinDocumentProperties::getElementType() +{ + return cppu::UnoType<XDocumentProperty>::get(); +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwVbaBuiltinDocumentProperties::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return xEnumAccess->createEnumeration(); +} + +// ScVbaCollectionBaseImpl +uno::Any +SwVbaBuiltinDocumentProperties::createCollectionObject( const uno::Any& aSource ) +{ + // pass through + return aSource; +} + +// XHelperInterface +OUString +SwVbaBuiltinDocumentProperties::getServiceImplName() +{ + return "SwVbaBuiltinDocumentProperties"; +} + +uno::Sequence<OUString> +SwVbaBuiltinDocumentProperties::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.DocumentProperties" + }; + return aServiceNames; +} + +namespace { + +class CustomPropertiesImpl : public PropertiesImpl_BASE +{ + uno::Reference< XHelperInterface > m_xParent; + uno::Reference< uno::XComponentContext > m_xContext; + uno::Reference< frame::XModel > m_xModel; + uno::Reference< beans::XPropertySet > mxUserDefinedProp; + std::shared_ptr< PropertGetSetHelper > mpPropGetSetHelper; +public: + CustomPropertiesImpl( uno::Reference< XHelperInterface > xParent, uno::Reference< uno::XComponentContext > xContext, uno::Reference< frame::XModel > xModel ) : m_xParent(std::move( xParent )), m_xContext(std::move( xContext )), m_xModel(std::move( xModel )) + { + // suck in the document( custom ) properties + mpPropGetSetHelper = std::make_shared<CustomPropertyGetSetHelper>( m_xModel ); + mxUserDefinedProp.set(mpPropGetSetHelper->getUserDefinedProperties(), + uno::UNO_SET_THROW); + }; + // XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount( ) override + { + return mxUserDefinedProp->getPropertySetInfo()->getProperties().getLength(); + } + + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + uno::Sequence< beans::Property > aProps = mxUserDefinedProp->getPropertySetInfo()->getProperties(); + if ( Index >= aProps.getLength() ) + throw lang::IndexOutOfBoundsException(); + // How to determine type e.g Date? ( com.sun.star.util.DateTime ) + DocPropInfo aPropInfo = DocPropInfo::createDocPropInfo( aProps[ Index ].Name, aProps[ Index ].Name, mpPropGetSetHelper ); + return uno::Any( uno::Reference< XDocumentProperty >( new SwVbaCustomDocumentProperty( m_xParent, m_xContext, aPropInfo ) ) ); + } + + virtual uno::Any SAL_CALL getByName( const OUString& aName ) override + { + if ( !hasByName( aName ) ) + throw container::NoSuchElementException(); + + DocPropInfo aPropInfo = DocPropInfo::createDocPropInfo( aName, aName, mpPropGetSetHelper ); + return uno::Any( uno::Reference< XDocumentProperty >( new SwVbaCustomDocumentProperty( m_xParent, m_xContext, aPropInfo ) ) ); + } + + virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override + { + const uno::Sequence< beans::Property > aProps = mxUserDefinedProp->getPropertySetInfo()->getProperties(); + uno::Sequence< OUString > aNames( aProps.getLength() ); + std::transform(aProps.begin(), aProps.end(), aNames.getArray(), + [](const beans::Property& rProp) -> OUString { return rProp.Name; }); + return aNames; + } + + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { + SAL_INFO("sw.vba", "hasByName(" << aName << ") returns " << mxUserDefinedProp->getPropertySetInfo()->hasPropertyByName( aName ) ); + return mxUserDefinedProp->getPropertySetInfo()->hasPropertyByName( aName ); + } + + // XElementAccess + virtual uno::Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<XDocumentProperty>::get(); + } + + virtual sal_Bool SAL_CALL hasElements( ) override + { + return getCount() > 0; + } + + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + // create a map of properties ( the key doesn't matter ) + SAL_INFO("sw.vba", "Creating an enumeration"); + sal_Int32 key = 0; + sal_Int32 nElem = getCount(); + DocProps simpleDocPropSnapShot; + for ( ; key < nElem; ++key ) + simpleDocPropSnapShot[ key ].set( getByIndex( key ), uno::UNO_QUERY_THROW ); + SAL_INFO("sw.vba", "After creating the enumeration"); + return new DocPropEnumeration( std::move(simpleDocPropSnapShot) ); + } + + void addProp( const OUString& Name, const uno::Any& Value ) + { + uno::Reference< beans::XPropertyContainer > xContainer( mxUserDefinedProp, uno::UNO_QUERY_THROW ); + // TODO fixme, perform the necessary Type Value conversions + xContainer->addProperty( Name, sal_Int16(128), Value ); + } + +}; + +} + +SwVbaCustomDocumentProperties::SwVbaCustomDocumentProperties( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< frame::XModel >& xModel ) : SwVbaBuiltinDocumentProperties( xParent, xContext, xModel ) +{ + // replace the m_xIndexAccess implementation ( we need a virtual init ) + m_xIndexAccess.set( new CustomPropertiesImpl( xParent, xContext, xModel ) ); + m_xNameAccess.set( m_xIndexAccess, uno::UNO_QUERY_THROW ); +} + +uno::Reference< XDocumentProperty > SAL_CALL +SwVbaCustomDocumentProperties::Add( const OUString& Name, sal_Bool LinkToContent, ::sal_Int8 /*Type*/, const uno::Any& Value, const uno::Any& LinkSource ) +{ + CustomPropertiesImpl* pCustomProps = dynamic_cast< CustomPropertiesImpl* > ( m_xIndexAccess.get() ); + uno::Reference< XDocumentProperty > xDocProp; + if ( pCustomProps ) + { + OUString sLinkSource; + pCustomProps->addProp( Name, Value ); + + xDocProp.set( m_xNameAccess->getByName( Name ), uno::UNO_QUERY_THROW ); + xDocProp->setLinkToContent( LinkToContent ); + + if ( LinkSource >>= sLinkSource ) + xDocProp->setLinkSource( sLinkSource ); + } + return xDocProp; +} + +// XHelperInterface +OUString +SwVbaCustomDocumentProperties::getServiceImplName() +{ + return "SwVbaCustomDocumentProperties"; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbadocumentproperties.hxx b/sw/source/ui/vba/vbadocumentproperties.hxx new file mode 100644 index 0000000000..740353e829 --- /dev/null +++ b/sw/source/ui/vba/vbadocumentproperties.hxx @@ -0,0 +1,58 @@ +/* -*- 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_VBA_VBADOCUMENTPROPERTIES_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBADOCUMENTPROPERTIES_HXX + +#include <ooo/vba/XDocumentProperties.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +typedef CollTestImplHelper< ov::XDocumentProperties > SwVbaDocumentproperties_BASE; + +class SwVbaBuiltinDocumentProperties : public SwVbaDocumentproperties_BASE +{ +public: + SwVbaBuiltinDocumentProperties( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xDocument ); + + // XDocumentProperties + virtual css::uno::Reference< ::ooo::vba::XDocumentProperty > SAL_CALL Add( const OUString& Name, sal_Bool LinkToContent, ::sal_Int8 Type, const css::uno::Any& Value, const css::uno::Any& LinkSource ) override; + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + // ScVbaCollectionBaseImpl + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +class SwVbaCustomDocumentProperties : public SwVbaBuiltinDocumentProperties +{ +public: + SwVbaCustomDocumentProperties( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xDocument ); +// XDocumentProperties + virtual css::uno::Reference< ::ooo::vba::XDocumentProperty > SAL_CALL Add( const OUString& Name, sal_Bool LinkToContent, ::sal_Int8 Type, const css::uno::Any& Value, const css::uno::Any& LinkSource ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; +}; + +#endif /* SW_VBA_DOCUMENTPROPERTY_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbadocuments.cxx b/sw/source/ui/vba/vbadocuments.cxx new file mode 100644 index 0000000000..ca5f298555 --- /dev/null +++ b/sw/source/ui/vba/vbadocuments.cxx @@ -0,0 +1,161 @@ +/* -*- 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 <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> + +#include <tools/urlobj.hxx> +#include <rtl/ref.hxx> + +#include "vbadocument.hxx" +#include "vbadocuments.hxx" + +#include <osl/file.hxx> +#include <utility> +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +static uno::Any +getDocument( uno::Reference< uno::XComponentContext > const & xContext, const uno::Reference< text::XTextDocument > &xDoc, const uno::Any& aApplication ) +{ + // FIXME: fine as long as SwVbaDocument is stateless ... + if( !xDoc.is() ) + return uno::Any(); + + rtl::Reference<SwVbaDocument> pWb = new SwVbaDocument( uno::Reference< XHelperInterface >( aApplication, uno::UNO_QUERY_THROW ), xContext, xDoc ); + return uno::Any( uno::Reference< word::XDocument > (pWb) ); +} + +namespace { + +class DocumentEnumImpl : public EnumerationHelperImpl +{ + uno::Any m_aApplication; +public: + /// @throws uno::RuntimeException + DocumentEnumImpl( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, uno::Any aApplication ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ), m_aApplication(std::move( aApplication )) {} + + virtual uno::Any SAL_CALL nextElement( ) override + { + uno::Reference< text::XTextDocument > xDoc( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); + return getDocument( m_xContext, xDoc, m_aApplication ); + } +}; + +} + +SwVbaDocuments::SwVbaDocuments( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext ) : SwVbaDocuments_BASE( xParent, xContext, VbaDocumentsBase::WORD_DOCUMENT ) +{ +} +// XEnumerationAccess +uno::Type +SwVbaDocuments::getElementType() +{ + return cppu::UnoType<word::XDocument>::get(); +} +uno::Reference< container::XEnumeration > +SwVbaDocuments::createEnumeration() +{ + // #FIXME it's possible the DocumentEnumImpl here doesn't reflect + // the state of this object (although it should) would be + // safer to create an enumeration based on this objects state + // rather than one effectively based of the desktop component + uno::Reference< container::XEnumerationAccess > xEnumerationAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return new DocumentEnumImpl( mxParent, mxContext, xEnumerationAccess->createEnumeration(), Application() ); +} + +uno::Any +SwVbaDocuments::createCollectionObject( const uno::Any& aSource ) +{ + uno::Reference< text::XTextDocument > xDoc( aSource, uno::UNO_QUERY_THROW ); + return getDocument( mxContext, xDoc, Application() ); +} + +uno::Any SAL_CALL +SwVbaDocuments::Add( const uno::Any& Template, const uno::Any& /*NewTemplate*/, const uno::Any& /*DocumentType*/, const uno::Any& /*Visible*/ ) +{ + OUString sFileName; + if( Template.hasValue() && ( Template >>= sFileName ) ) + { + return Open( sFileName, uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any()); + } + uno::Reference <text::XTextDocument> xTextDoc( createDocument() , uno::UNO_QUERY_THROW ); + return getDocument( mxContext, xTextDoc, Application() ); +} + +// #TODO# #FIXME# can any of the unused params below be used? +// #TODO# #FIXME# surely we should actually close the document here +void SAL_CALL +SwVbaDocuments::Close( const uno::Any& /*SaveChanges*/, const uno::Any& /*OriginalFormat*/, const uno::Any& /*RouteDocument*/ ) +{ +} + +// #TODO# #FIXME# can any of the unused params below be used? +uno::Any SAL_CALL +SwVbaDocuments::Open( const OUString& Filename, const uno::Any& /*ConfirmConversions*/, const uno::Any& ReadOnly, const uno::Any& /*AddToRecentFiles*/, const uno::Any& /*PasswordDocument*/, const uno::Any& /*PasswordTemplate*/, const uno::Any& /*Revert*/, const uno::Any& /*WritePasswordDocument*/, const uno::Any& /*WritePasswordTemplate*/, const uno::Any& /*Format*/, const uno::Any& /*Encoding*/, const uno::Any& /*Visible*/, const uno::Any& /*OpenAndRepair*/, const uno::Any& /*DocumentDirection*/, const uno::Any& /*NoEncodingDialog*/, const uno::Any& /*XMLTransform*/ ) +{ + SAL_INFO("sw.vba", "Documents.Open(Filename:=" << Filename << ",ReadOnly:=" << ReadOnly << ")"); + + // we need to detect if this is a URL, if not then assume it's a file path + OUString aURL; + INetURLObject aObj; + aObj.SetURL( Filename ); + bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid; + if ( bIsURL ) + aURL = Filename; + else + osl::FileBase::getFileURLFromSystemPath( Filename, aURL ); + + uno::Reference <text::XTextDocument> xSpreadDoc( openDocument( Filename, ReadOnly, {}), uno::UNO_QUERY_THROW ); + uno::Any aRet = getDocument( mxContext, xSpreadDoc, Application() ); + uno::Reference< word::XDocument > xDocument( aRet, uno::UNO_QUERY ); + if ( xDocument.is() ) + xDocument->Activate(); + return aRet; +} + +uno::Any SAL_CALL +SwVbaDocuments::OpenNoRepairDialog( const OUString& Filename, const uno::Any& ConfirmConversions, const uno::Any& ReadOnly, const uno::Any& AddToRecentFiles, const uno::Any& PasswordDocument, const uno::Any& PasswordTemplate, const uno::Any& Revert, const uno::Any& WritePasswordDocument, const uno::Any& WritePasswordTemplate, const uno::Any& Format, const uno::Any& Encoding, const uno::Any& Visible, const uno::Any& OpenAndRepair, const uno::Any& DocumentDirection, const uno::Any& NoEncodingDialog, const uno::Any& XMLTransform ) +{ + return Open( Filename, ConfirmConversions, ReadOnly, AddToRecentFiles, PasswordDocument, PasswordTemplate, Revert, WritePasswordDocument, WritePasswordTemplate, Format, Encoding, Visible, OpenAndRepair, DocumentDirection, NoEncodingDialog, XMLTransform ); +} + +uno::Any SAL_CALL +SwVbaDocuments::OpenOld( const OUString& FileName, const uno::Any& ConfirmConversions, const uno::Any& ReadOnly, const uno::Any& AddToRecentFiles, const uno::Any& PasswordDocument, const uno::Any& PasswordTemplate, const uno::Any& Revert, const uno::Any& WritePasswordDocument, const uno::Any& WritePasswordTemplate, const uno::Any& Format ) +{ + return Open( FileName, ConfirmConversions, ReadOnly, AddToRecentFiles, PasswordDocument, PasswordTemplate, Revert, WritePasswordDocument, WritePasswordTemplate, Format, uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any() ); +} + +OUString +SwVbaDocuments::getServiceImplName() +{ + return "SwVbaDocuments"; +} + +uno::Sequence<OUString> +SwVbaDocuments::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.Documents" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbadocuments.hxx b/sw/source/ui/vba/vbadocuments.hxx new file mode 100644 index 0000000000..2b6261adba --- /dev/null +++ b/sw/source/ui/vba/vbadocuments.hxx @@ -0,0 +1,52 @@ +/* -*- 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_VBA_VBADOCUMENTS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBADOCUMENTS_HXX + +#include <ooo/vba/word/XDocuments.hpp> +#include <vbahelper/vbadocumentsbase.hxx> +#include <cppuhelper/implbase.hxx> + +typedef cppu::ImplInheritanceHelper< VbaDocumentsBase, ov::word::XDocuments > SwVbaDocuments_BASE; + +class SwVbaDocuments : public SwVbaDocuments_BASE +{ +public: + SwVbaDocuments( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaDocuments_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + + // Methods + virtual css::uno::Any SAL_CALL Add( const css::uno::Any& Template, const css::uno::Any& NewTemplate, const css::uno::Any& DocumentType, const css::uno::Any& Visible ) override; + virtual css::uno::Any SAL_CALL Open( const OUString& Filename, const css::uno::Any& ConfirmConversions, const css::uno::Any& ReadOnly, const css::uno::Any& AddToRecentFiles, const css::uno::Any& PasswordDocument, const css::uno::Any& PasswordTemplate, const css::uno::Any& Revert, const css::uno::Any& WritePasswordDocument, const css::uno::Any& WritePasswordTemplate, const css::uno::Any& Format, const css::uno::Any& Encoding, const css::uno::Any& Visible, const css::uno::Any& OpenAndRepair, const css::uno::Any& DocumentDirection, const css::uno::Any& NoEncodingDialog, const css::uno::Any& XMLTransform ) override; + virtual css::uno::Any SAL_CALL OpenNoRepairDialog( const OUString& Filename, const css::uno::Any& ConfirmConversions, const css::uno::Any& ReadOnly, const css::uno::Any& AddToRecentFiles, const css::uno::Any& PasswordDocument, const css::uno::Any& PasswordTemplate, const css::uno::Any& Revert, const css::uno::Any& WritePasswordDocument, const css::uno::Any& WritePasswordTemplate, const css::uno::Any& Format, const css::uno::Any& Encoding, const css::uno::Any& Visible, const css::uno::Any& OpenAndRepair, const css::uno::Any& DocumentDirection, const css::uno::Any& NoEncodingDialog, const css::uno::Any& XMLTransform ) override; + virtual css::uno::Any SAL_CALL OpenOld( const OUString& FileName, const css::uno::Any& ConfirmConversions, const css::uno::Any& ReadOnly, const css::uno::Any& AddToRecentFiles, const css::uno::Any& PasswordDocument, const css::uno::Any& PasswordTemplate, const css::uno::Any& Revert, const css::uno::Any& WritePasswordDocument, const css::uno::Any& WritePasswordTemplate, const css::uno::Any& Format ) override; + virtual void SAL_CALL Close( const css::uno::Any& SaveChanges, const css::uno::Any& OriginalFormat, const css::uno::Any& RouteDocument ) override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBADOCUMENTS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaeventshelper.cxx b/sw/source/ui/vba/vbaeventshelper.cxx new file mode 100644 index 0000000000..d928eaba16 --- /dev/null +++ b/sw/source/ui/vba/vbaeventshelper.cxx @@ -0,0 +1,94 @@ +/* -*- 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 <sal/config.h> + +#include "vbaeventshelper.hxx" +#include <com/sun/star/script/ModuleType.hpp> +#include <com/sun/star/script/vba/VBAEventId.hpp> +#include <cppuhelper/supportsservice.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::script::vba::VBAEventId; + +SwVbaEventsHelper::SwVbaEventsHelper( uno::Sequence< css::uno::Any > const& aArgs, uno::Reference< uno::XComponentContext > const& /*xContext*/ ) : + VbaEventsHelperBase( aArgs ) +{ + using namespace ::com::sun::star::script::ModuleType; + registerEventHandler( DOCUMENT_NEW, DOCUMENT, "Document_New" ); + registerEventHandler( AUTO_NEW, NORMAL, "AutoNew" ); + registerEventHandler( DOCUMENT_OPEN, DOCUMENT, "Document_Open" ); + registerEventHandler( AUTO_OPEN, NORMAL, "AutoOpen" ); + registerEventHandler( DOCUMENT_CLOSE, DOCUMENT, "Document_Close" ); + registerEventHandler( AUTO_CLOSE, NORMAL, "AutoClose" ); +} + +SwVbaEventsHelper::~SwVbaEventsHelper() +{ +} + +bool SwVbaEventsHelper::implPrepareEvent(EventQueue& /*rEventQueue*/, + const EventHandlerInfo& /*rInfo*/, const uno::Sequence<uno::Any>& /*rArgs*/) +{ + return true; +} + +uno::Sequence< uno::Any > SwVbaEventsHelper::implBuildArgumentList( const EventHandlerInfo& /*rInfo*/, + const uno::Sequence< uno::Any >& /*rArgs*/ ) +{ + // no event handler expects any arguments + return uno::Sequence< uno::Any >(); +} + +void SwVbaEventsHelper::implPostProcessEvent( EventQueue& /*rEventQueue*/, + const EventHandlerInfo& /*rInfo*/, bool /*bCancel*/ ) +{ + // nothing to do after any event +} + +OUString SwVbaEventsHelper::implGetDocumentModuleName( const EventHandlerInfo& /*rInfo*/, + const uno::Sequence< uno::Any >& /*rArgs*/ ) const +{ + // TODO: get actual codename from document + return "ThisDocument"; +} + + // XServiceInfo +OUString SwVbaEventsHelper::getImplementationName() +{ + return "SwVbaEventsHelper"; +} +sal_Bool SwVbaEventsHelper::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} +css::uno::Sequence< OUString > SwVbaEventsHelper::getSupportedServiceNames() +{ + return { "com.sun.star.script.vba.VBATextEventProcessor" }; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Writer_SwVbaEventsHelper_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args) +{ + return cppu::acquire(new SwVbaEventsHelper(args, context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaeventshelper.hxx b/sw/source/ui/vba/vbaeventshelper.hxx new file mode 100644 index 0000000000..31a6b2808e --- /dev/null +++ b/sw/source/ui/vba/vbaeventshelper.hxx @@ -0,0 +1,47 @@ +/* -*- 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_VBA_VBAEVENTSHELPER_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAEVENTSHELPER_HXX + +#include <vbahelper/vbaeventshelperbase.hxx> + +class SwVbaEventsHelper : public VbaEventsHelperBase +{ +public: + SwVbaEventsHelper( + const css::uno::Sequence< css::uno::Any >& rArgs, + const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + virtual ~SwVbaEventsHelper() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +protected: + virtual bool implPrepareEvent( EventQueue& rEventQueue, const EventHandlerInfo& rInfo, const css::uno::Sequence< css::uno::Any >& rArgs ) override; + virtual css::uno::Sequence< css::uno::Any > implBuildArgumentList( const EventHandlerInfo& rInfo, const css::uno::Sequence< css::uno::Any >& rArgs ) override; + virtual void implPostProcessEvent( EventQueue& rEventQueue, const EventHandlerInfo& rInfo, bool bCancel ) override; + virtual OUString implGetDocumentModuleName( const EventHandlerInfo& rInfo, const css::uno::Sequence< css::uno::Any >& rArgs ) const override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbafield.cxx b/sw/source/ui/vba/vbafield.cxx new file mode 100644 index 0000000000..ded84a6d8b --- /dev/null +++ b/sw/source/ui/vba/vbafield.cxx @@ -0,0 +1,538 @@ +/* -*- 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 "vbafield.hxx" +#include "vbarange.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/text/XTextFieldsSupplier.hpp> +#include <com/sun/star/text/FilenameDisplayFormat.hpp> +#include <com/sun/star/util/XRefreshable.hpp> +#include <com/sun/star/util/XUpdatable.hpp> +#include <ooo/vba/word/WdFieldType.hpp> +#include <basic/sberrors.hxx> +#include <cppuhelper/implbase.hxx> +#include <sal/log.hxx> +#include <tools/long.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaField::SwVbaField( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Reference< css::text::XTextField >& xTextField) : SwVbaField_BASE( rParent, rContext ) +{ + mxTextField.set( xTextField, uno::UNO_SET_THROW ); +} + +sal_Bool SAL_CALL SwVbaField::Update() +{ + uno::Reference< util::XUpdatable > xUpdatable( mxTextField, uno::UNO_QUERY ); + if( xUpdatable.is() ) + { + xUpdatable->update(); + return true; + } + return false; +} + +// XHelperInterface +OUString +SwVbaField::getServiceImplName() +{ + return "SwVbaField"; +} + +uno::Sequence<OUString> +SwVbaField::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Field" + }; + return aServiceNames; +} + +namespace { + +// FIXME? copy and paste code +// the codes are copied from ww8par5.cxx +class SwVbaReadFieldParams +{ +private: + OUString m_aData; + sal_Int32 m_nLen, m_nFnd, m_nNext, m_nSavPtr; + OUString m_aFieldName; +public: + explicit SwVbaReadFieldParams( const OUString& rData ); + + tools::Long SkipToNextToken(); + + sal_Int32 FindNextStringPiece( sal_Int32 _nStart ); + + OUString GetResult() const; + const OUString& GetFieldName()const { return m_aFieldName; } +}; + +} + +SwVbaReadFieldParams::SwVbaReadFieldParams( const OUString& _rData ) + : m_aData( _rData ), m_nLen( _rData.getLength() ), m_nNext( 0 ) +{ + // First search for an opening parenthesis or a space or a quotation mark + // or a backslash, so that the field command + // (thus INCLUDEPICTURE or ...) is ignored. + while( (m_nLen > m_nNext) && (m_aData[ m_nNext ] == ' ') ) + ++m_nNext; + + sal_Unicode c; + while( m_nLen > m_nNext + && (c = m_aData[ m_nNext ]) != ' ' + && c != '"' + && c != '\\' + && c != 132 + && c != 0x201c ) + ++m_nNext; + + m_nFnd = m_nNext; + m_nSavPtr = m_nNext; + m_aFieldName = m_aData.copy( 0, m_nFnd ); +} + +OUString SwVbaReadFieldParams::GetResult() const +{ + return (-1 == m_nFnd) + ? OUString() + : m_aData.copy( m_nFnd, (m_nSavPtr - m_nFnd) ); +} + +// ret: -2: NOT a '\' parameter but normal Text +tools::Long SwVbaReadFieldParams::SkipToNextToken() +{ + tools::Long nRet = -1; // end + if ( + (-1 != m_nNext) && (m_nLen > m_nNext) && + -1 != (m_nFnd = FindNextStringPiece(m_nNext)) + ) + { + m_nSavPtr = m_nNext; + + if ('\\' == m_aData[m_nFnd] && '\\' != m_aData[m_nFnd + 1]) + { + nRet = m_aData[++m_nFnd]; + m_nNext = ++m_nFnd; // and set behind + } + else + { + nRet = -2; + if ( + (-1 != m_nSavPtr ) && + ( + ('"' == m_aData[m_nSavPtr - 1]) || + (0x201d == m_aData[m_nSavPtr - 1]) + ) + ) + { + --m_nSavPtr; + } + } + } + return nRet; +} + +// FindNextPara is searching for the next Backslash-Parameter or the next string +// until blank or the next "\" or until the closing quotation mark +// or until the string end of pStr. + +// Output ppNext (if ppNext != 0) beginning of the search for the next parameter or 0 + +// Return value: 0 if String-End reached, otherwise begin of the parameter or the string + +sal_Int32 SwVbaReadFieldParams::FindNextStringPiece(const sal_Int32 nStart) +{ + sal_Int32 n = ( -1 == nStart ) ? m_nFnd : nStart; // Start + sal_Int32 n2; // End + + m_nNext = -1; // Default for not found + + while( (m_nLen > n) && (m_aData[ n ] == ' ') ) + ++n; + + if( m_nLen == n ) + return -1; // String End reached! + + if( (m_aData[ n ] == '"') // quotation marks are in front of parenthesis? + || (m_aData[ n ] == 0x201c) + || (m_aData[ n ] == 132) ) + { + n++; // ignore quotation marks + n2 = n; // From here search for the end + while( (m_nLen > n2) + && (m_aData[ n2 ] != '"') + && (m_aData[ n2 ] != 0x201d) + && (m_aData[ n2 ] != 147) ) + n2++; // Search for the end of the parenthesis + } + else // no quotation marks + { + n2 = n; // from here search for the end + while( (m_nLen > n2) && (m_aData[ n2 ] != ' ') ) // Search for the end of the parenthesis + { + if( m_aData[ n2 ] == '\\' ) + { + if( m_aData[ n2+1 ] == '\\' ) + n2 += 2; // double-backslash -> OK + else + { + if( n2 > n ) + n2--; + break; // single-backslash -> End + } + } + else + n2++; // no backslash -> OK + } + } + if( m_nLen > n2 ) + { + if(m_aData[ n2 ] != ' ') n2++; + m_nNext = n2; + } + return n; +} + +// SwVbaFields + +static uno::Any lcl_createField( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< frame::XModel >& xModel, const uno::Any& aSource ) +{ + uno::Reference< text::XTextField > xTextField( aSource, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextDocument > xTextDocument( xModel, uno::UNO_QUERY_THROW ); + uno::Reference< word::XField > xField( new SwVbaField( xParent, xContext, xTextField ) ); + return uno::Any( xField ); +} + +namespace { + +class FieldEnumeration : public ::cppu::WeakImplHelper< css::container::XEnumeration > +{ + uno::Reference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< frame::XModel > mxModel; + uno::Reference< container::XEnumeration > mxEnumeration; +public: + FieldEnumeration( uno::Reference< XHelperInterface > xParent, uno::Reference< uno::XComponentContext > xContext, uno::Reference< frame::XModel > xModel, uno::Reference< container::XEnumeration > xEnumeration ) : mxParent(std::move( xParent )), mxContext(std::move( xContext )), mxModel(std::move( xModel )), mxEnumeration(std::move( xEnumeration )) + { + } + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return mxEnumeration->hasMoreElements(); + } + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( !hasMoreElements() ) + throw container::NoSuchElementException(); + return lcl_createField( mxParent, mxContext, mxModel, mxEnumeration->nextElement() ); + } +}; + +class FieldCollectionHelper : public ::cppu::WeakImplHelper< container::XIndexAccess, + container::XEnumerationAccess > +{ + uno::Reference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< frame::XModel > mxModel; + uno::Reference< container::XEnumerationAccess > mxEnumerationAccess; +public: + /// @throws css::uno::RuntimeException + FieldCollectionHelper( uno::Reference< XHelperInterface > xParent, uno::Reference< uno::XComponentContext > xContext, const uno::Reference< frame::XModel >& xModel ) : mxParent(std::move( xParent )), mxContext(std::move( xContext )), mxModel( xModel ) + { + uno::Reference< text::XTextFieldsSupplier > xSupp( xModel, uno::UNO_QUERY_THROW ); + mxEnumerationAccess.set( xSupp->getTextFields(), uno::UNO_SET_THROW ); + } + // XElementAccess + virtual uno::Type SAL_CALL getElementType( ) override { return mxEnumerationAccess->getElementType(); } + virtual sal_Bool SAL_CALL hasElements( ) override { return mxEnumerationAccess->hasElements(); } + // XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount( ) override + { + uno::Reference< container::XEnumeration > xEnumeration = mxEnumerationAccess->createEnumeration(); + sal_Int32 nCount = 0; + while( xEnumeration->hasMoreElements() ) + { + ++nCount; + xEnumeration->nextElement(); + } + return nCount; + } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + if( Index < 0 || Index >= getCount() ) + throw lang::IndexOutOfBoundsException(); + + uno::Reference< container::XEnumeration > xEnumeration = mxEnumerationAccess->createEnumeration(); + sal_Int32 nCount = 0; + while( xEnumeration->hasMoreElements() ) + { + if( nCount == Index ) + { + return xEnumeration->nextElement(); + } + ++nCount; + } + throw lang::IndexOutOfBoundsException(); + } + // XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + uno::Reference< container::XEnumeration > xEnumeration = mxEnumerationAccess->createEnumeration(); + return uno::Reference< container::XEnumeration >( new FieldEnumeration( mxParent, mxContext, mxModel, xEnumeration ) ); + } +}; + +} + +SwVbaFields::SwVbaFields( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< frame::XModel >& xModel ) : SwVbaFields_BASE( xParent, xContext , uno::Reference< container::XIndexAccess >( new FieldCollectionHelper( xParent, xContext, xModel ) ) ), mxModel( xModel ) +{ + mxMSF.set( mxModel, uno::UNO_QUERY_THROW ); +} + +uno::Reference< word::XField > SAL_CALL +SwVbaFields::Add( const css::uno::Reference< ::ooo::vba::word::XRange >& Range, const css::uno::Any& Type, const css::uno::Any& Text, const css::uno::Any& /*PreserveFormatting*/ ) +{ + sal_Int32 nType = word::WdFieldType::wdFieldEmpty; + Type >>= nType; + OUString sText; + Text >>= sText; + + OUString sFieldName; + if( ( nType == word::WdFieldType::wdFieldEmpty ) && !sText.isEmpty() ) + { + SwVbaReadFieldParams aReadParam(sText); + sFieldName = aReadParam.GetFieldName(); + SAL_INFO("sw.vba", "the field name is " << sFieldName ); + } + + uno::Reference< text::XTextContent > xTextField; + if( nType == word::WdFieldType::wdFieldFileName || sFieldName.equalsIgnoreAsciiCase("FILENAME") ) + { + xTextField.set( Create_Field_FileName( sText ), uno::UNO_QUERY_THROW ); + } + else if( nType == word::WdFieldType::wdFieldDocProperty || sFieldName.equalsIgnoreAsciiCase("DOCPROPERTY") ) + { + xTextField.set( Create_Field_DocProperty( sText ), uno::UNO_QUERY_THROW ); + } + else + { + throw uno::RuntimeException("Not implemented" ); + } + + SwVbaRange& rVbaRange = dynamic_cast<SwVbaRange&>(*Range); + uno::Reference< text::XTextRange > xTextRange = rVbaRange.getXTextRange(); + uno::Reference< text::XText > xText = xTextRange->getText(); + xText->insertTextContent( xTextRange, xTextField, true ); + return uno::Reference< word::XField >( new SwVbaField( mxParent, mxContext, uno::Reference< text::XTextField >( xTextField, uno::UNO_QUERY_THROW ) ) ); +} + +uno::Reference< text::XTextField > SwVbaFields::Create_Field_FileName( const OUString& _text ) +{ + uno::Reference< text::XTextField > xTextField( mxMSF->createInstance("com.sun.star.text.TextField.FileName"), uno::UNO_QUERY_THROW ); + sal_Int16 nFileFormat = text::FilenameDisplayFormat::NAME_AND_EXT; + if( !_text.isEmpty() ) + { + tools::Long nRet; + SwVbaReadFieldParams aReadParam( _text ); + while (-1 != (nRet = aReadParam.SkipToNextToken())) + { + switch (nRet) + { + case 'p': + nFileFormat = text::FilenameDisplayFormat::FULL; + break; + case '*': + //Skip over MERGEFORMAT + aReadParam.SkipToNextToken(); + break; + default: + DebugHelper::basicexception(ERRCODE_BASIC_BAD_ARGUMENT, {}); + break; + } + } + } + + uno::Reference< beans::XPropertySet > xProps( xTextField, uno::UNO_QUERY_THROW ); + xProps->setPropertyValue("FileFormat", uno::Any( nFileFormat ) ); + + return xTextField; +} + +namespace { + +struct DocPropertyTable +{ + const char* sDocPropertyName; + const char* sFieldService; +}; + +} + +const DocPropertyTable aDocPropertyTables[] = +{ + { "Author", "com.sun.star.text.textfield.docinfo.CreateAuthor" }, + { "Bytes", nullptr }, + { "Category", nullptr }, + { "Characters",nullptr }, + { "CharactersWithSpaces", nullptr }, + { "Comments", "com.sun.star.text.textfield.docinfo.Description" }, + { "Company", nullptr }, + { "CreateTime", "com.sun.star.text.textfield.docinfo.CreateDateTime" }, + { "HyperlinkBase", nullptr }, + { "Keywords", "com.sun.star.text.textfield.docinfo.Keywords" }, + { "LastPrinted", "com.sun.star.text.textfield.docinfo.PrintDateTime" }, + { "LastSavedBy", "com.sun.star.text.textfield.docinfo.ChangeAuthor" }, + { "LastSavedTime", "com.sun.star.text.textfield.docinfo.ChangeDateTime" }, + { "Lines", nullptr }, + { "Manager", nullptr }, + { "NameofApplication", nullptr }, + { "ODMADocID", nullptr }, + { "Pages", "com.sun.star.text.textfield.PageCount" }, + { "Paragraphs", "com.sun.star.text.textfield.ParagraphCount" }, + { "RevisionNumber", "com.sun.star.text.textfield.docinfo.Revision" }, + { "Security", nullptr }, + { "Subject", "com.sun.star.text.textfield.docinfo.Subject" }, + { "Template", "com.sun.star.text.textfield.TemplateName" }, + { "Title", "com.sun.star.text.textfield.docinfo.Title" }, + { "TotalEditingTime", "com.sun.star.text.textfield.docinfo.EditTime" }, + { "Words", "com.sun.star.text.textfield.WordCount" }, + { nullptr, nullptr } +}; + +uno::Reference< text::XTextField > SwVbaFields::Create_Field_DocProperty( const OUString& _text ) +{ + OUString aDocProperty; + SwVbaReadFieldParams aReadParam( _text ); + tools::Long nRet; + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if( aDocProperty.isEmpty() ) + aDocProperty = aReadParam.GetResult(); + break; + case '*': + //Skip over MERGEFORMAT + aReadParam.SkipToNextToken(); + break; + } + } + aDocProperty = aDocProperty.replaceAll("\"", ""); + SAL_INFO("sw.vba", "SwVbaFields::Create_Field_DocProperty, the document property name is " << aDocProperty ); + if( aDocProperty.isEmpty() ) + { + throw uno::RuntimeException(); + } + + bool bCustom = true; + OUString sFieldService; + // find the build in document properties + for( const DocPropertyTable* pTable = aDocPropertyTables; pTable->sDocPropertyName != nullptr; pTable++ ) + { + if( aDocProperty.equalsIgnoreAsciiCaseAscii( pTable->sDocPropertyName ) ) + { + if( pTable->sFieldService != nullptr ) + sFieldService = OUString::createFromAscii(pTable->sFieldService); + bCustom = false; + break; + } + } + + if( bCustom ) + { + sFieldService = "com.sun.star.text.textfield.docinfo.Custom"; + } + else if( sFieldService.isEmpty() ) + { + throw uno::RuntimeException("Not implemented" ); + } + + uno::Reference< text::XTextField > xTextField( mxMSF->createInstance( sFieldService ), uno::UNO_QUERY_THROW ); + + if( bCustom ) + { + uno::Reference< beans::XPropertySet > xProps( xTextField, uno::UNO_QUERY_THROW ); + xProps->setPropertyValue("Name", uno::Any( aDocProperty ) ); + } + + return xTextField; +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwVbaFields::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumerationAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return xEnumerationAccess->createEnumeration(); +} + +// ScVbaCollectionBaseImpl +uno::Any +SwVbaFields::createCollectionObject( const uno::Any& aSource ) +{ + return lcl_createField( mxParent, mxContext, mxModel, aSource ); +} + +sal_Int32 SAL_CALL SwVbaFields::Update() +{ + sal_Int32 nUpdate = 1; + try + { + uno::Reference< text::XTextFieldsSupplier > xSupp( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< util::XRefreshable > xRef( xSupp->getTextFields(), uno::UNO_QUERY_THROW ); + xRef->refresh(); + nUpdate = 0; + } + catch(const uno::Exception&) + { + nUpdate = 1; + } + return nUpdate; +} + +// XHelperInterface +OUString +SwVbaFields::getServiceImplName() +{ + return "SwVbaFields"; +} + +// XEnumerationAccess +uno::Type SAL_CALL +SwVbaFields::getElementType() +{ + return cppu::UnoType<word::XField>::get(); +} + +uno::Sequence<OUString> +SwVbaFields::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Fields" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbafield.hxx b/sw/source/ui/vba/vbafield.hxx new file mode 100644 index 0000000000..292be2edb7 --- /dev/null +++ b/sw/source/ui/vba/vbafield.hxx @@ -0,0 +1,74 @@ +/* -*- 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_VBA_VBAFIELD_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAFIELD_HXX +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/text/XTextField.hpp> +#include <ooo/vba/word/XField.hpp> +#include <ooo/vba/word/XFields.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XField > SwVbaField_BASE; + +class SwVbaField : public SwVbaField_BASE +{ + css::uno::Reference< css::text::XTextField > mxTextField; +public: + /// @throws css::uno::RuntimeException + SwVbaField( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, const css::uno::Reference< css::text::XTextField >& xTextField); + + virtual sal_Bool SAL_CALL Update() override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +typedef CollTestImplHelper< ov::word::XFields > SwVbaFields_BASE; + +class SwVbaFields : public SwVbaFields_BASE +{ + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::lang::XMultiServiceFactory > mxMSF; +private: + /// @throws css::uno::RuntimeException + /// @throws css::script::BasicErrorException + css::uno::Reference< css::text::XTextField > Create_Field_FileName(const OUString& rText); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::text::XTextField > Create_Field_DocProperty( const OUString& _text ); + +public: + SwVbaFields( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xModel ); + // XFields + virtual css::uno::Reference< ::ooo::vba::word::XField > SAL_CALL Add( const css::uno::Reference< ::ooo::vba::word::XRange >& Range, const css::uno::Any& Type, const css::uno::Any& Text, const css::uno::Any& PreserveFormatting ) override; + virtual sal_Int32 SAL_CALL Update() override; + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + // ScVbaCollectionBaseImpl + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbafilterpropsfromformat.hxx b/sw/source/ui/vba/vbafilterpropsfromformat.hxx new file mode 100644 index 0000000000..cde1da0b4d --- /dev/null +++ b/sw/source/ui/vba/vbafilterpropsfromformat.hxx @@ -0,0 +1,75 @@ +/* -*- 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_VBA_VBAFILTERPROPSFROMFORMAT_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAFILTERPROPSFROMFORMAT_HXX + +#include <sal/config.h> + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <rtl/ustring.hxx> +#include <ooo/vba/word/WdSaveFormat.hpp> + +namespace +{ +inline bool setFilterPropsFromFormat(sal_Int32 nFormat, + css::uno::Sequence<css::beans::PropertyValue>& rProps) +{ + auto[begin, end] = asNonConstRange(rProps); + auto pProp = std::find_if(begin, end, [](const css::beans::PropertyValue& rProp) { + return rProp.Name == "FilterName"; + }); + if (pProp != end) + { + switch (nFormat) + { + case ooo::vba::word::WdSaveFormat::wdFormatDocument: + pProp->Value <<= OUString("MS Word 97"); + break; + // Just save all the text formats as "Text" + case ooo::vba::word::WdSaveFormat::wdFormatDOSText: + case ooo::vba::word::WdSaveFormat::wdFormatDOSTextLineBreaks: + case ooo::vba::word::WdSaveFormat::wdFormatEncodedText: + case ooo::vba::word::WdSaveFormat::wdFormatText: + case ooo::vba::word::WdSaveFormat::wdFormatTextLineBreaks: + pProp->Value <<= OUString("Text"); + break; + case ooo::vba::word::WdSaveFormat::wdFormatFilteredHTML: + case ooo::vba::word::WdSaveFormat::wdFormatHTML: + pProp->Value <<= OUString("HTML"); + break; + case ooo::vba::word::WdSaveFormat::wdFormatRTF: + pProp->Value <<= OUString("Rich Text Format"); + break; + case ooo::vba::word::WdSaveFormat::wdFormatTemplate: + pProp->Value <<= OUString("MS Word 97 Vorlage"); + break; + + // Default to "MS Word 97" + default: + pProp->Value <<= OUString("MS Word 97"); + break; + } + return true; + } + return false; +} +} + +#endif diff --git a/sw/source/ui/vba/vbafind.cxx b/sw/source/ui/vba/vbafind.cxx new file mode 100644 index 0000000000..892e062f3c --- /dev/null +++ b/sw/source/ui/vba/vbafind.cxx @@ -0,0 +1,431 @@ +/* -*- 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 "vbafind.hxx" +#include "vbareplacement.hxx" +#include <ooo/vba/word/WdFindWrap.hpp> +#include <ooo/vba/word/WdReplace.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/text/XTextRangeCompare.hpp> +#include <doc.hxx> +#include <docsh.hxx> +#include "wordvbahelper.hxx" +#include <rtl/ref.hxx> +#include <sal/log.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaFind::SwVbaFind( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< frame::XModel > xModel ) : + SwVbaFind_BASE( rParent, rContext ), mxModel( std::move(xModel) ), mbReplace( false ), mnReplaceType( word::WdReplace::wdReplaceOne ), mnWrap( word::WdFindWrap::wdFindStop ) +{ + mxReplaceable.set( mxModel, uno::UNO_QUERY_THROW ); + mxPropertyReplace.set( mxReplaceable->createReplaceDescriptor(), uno::UNO_QUERY_THROW ); + mxTVC = word::getXTextViewCursor( mxModel ); + mxSelSupp.set( mxModel->getCurrentController(), uno::UNO_QUERY_THROW ); +} + +SwVbaFind::~SwVbaFind() +{ +} + +uno::Reference< word::XFind > SwVbaFind::GetOrCreateFind(const uno::Reference< ooo::vba::XHelperInterface >& rParent, + const uno::Reference< uno::XComponentContext >& rContext, + const uno::Reference< frame::XModel >& xModel, + const uno::Reference< text::XTextRange >& xTextRange) +{ + rtl::Reference< SwVbaFind > xFind; + SwDoc* pDoc = word::getDocShell( xModel )->GetDoc(); + if( pDoc ) + xFind = dynamic_cast<SwVbaFind *>( pDoc->getVbaFind().get() ); + if ( !xFind ) + { + xFind = new SwVbaFind( rParent, rContext, xModel ); + if ( pDoc ) + pDoc->setVbaFind( xFind ); + } + xFind->mxTextRange = xTextRange; + + return xFind; +} + + +bool SwVbaFind::InRange( const uno::Reference< text::XTextRange >& xCurrentRange ) +{ + uno::Reference< text::XTextRangeCompare > xTRC( mxTextRange->getText(), uno::UNO_QUERY_THROW ); + return xTRC->compareRegionStarts( mxTextRange, xCurrentRange ) >= 0 && xTRC->compareRegionEnds( mxTextRange, xCurrentRange ) <= 0; +} + +bool SwVbaFind::InEqualRange( const uno::Reference< text::XTextRange >& xCurrentRange ) +{ + uno::Reference< text::XTextRangeCompare > xTRC( mxTextRange->getText(), uno::UNO_QUERY_THROW ); + return xTRC->compareRegionStarts( mxTextRange, xCurrentRange ) == 0 && xTRC->compareRegionEnds( mxTextRange, xCurrentRange ) == 0; +} + +void SwVbaFind::SetReplaceWith( const OUString& rText ) +{ + mxPropertyReplace->setReplaceString( rText ); + mbReplace = true; +} + +OUString SwVbaFind::GetReplaceWith() +{ + return mxPropertyReplace->getReplaceString(); +} +void SwVbaFind::SetReplace( sal_Int32 type ) +{ + mnReplaceType = type; + mbReplace = true; +} +uno::Reference< text::XTextRange > SwVbaFind::FindOneElement() +{ + uno::Reference< text::XTextRange > xFoundOne; + if( !mxTVC->getString().isEmpty() ) + { + if( getForward() ) + { + xFoundOne.set( mxReplaceable->findNext( mxTextRange->getStart(), uno::Reference< util::XSearchDescriptor >( mxPropertyReplace, uno::UNO_QUERY_THROW ) ), uno::UNO_QUERY ); + } + else + { + xFoundOne.set( mxReplaceable->findNext( mxTextRange->getEnd(), uno::Reference< util::XSearchDescriptor >( mxPropertyReplace, uno::UNO_QUERY_THROW ) ), uno::UNO_QUERY ); + } + + if( xFoundOne.is() && InEqualRange( xFoundOne ) ) + { + xFoundOne.set( mxReplaceable->findNext( xFoundOne, uno::Reference< util::XSearchDescriptor >( mxPropertyReplace, uno::UNO_QUERY_THROW ) ), uno::UNO_QUERY ); + } + else if( xFoundOne.is() && !InRange( xFoundOne ) ) + { + xFoundOne.clear(); + } + } + else + { + xFoundOne.set( mxReplaceable->findNext( mxTextRange, uno::Reference< util::XSearchDescriptor >( mxPropertyReplace, uno::UNO_QUERY_THROW ) ), uno::UNO_QUERY ); + } + + if( !xFoundOne.is() && ( getWrap() == word::WdFindWrap::wdFindContinue || getWrap() == word::WdFindWrap::wdFindAsk ) ) + { + if( getForward() ) + { + mxTVC->gotoStart(false); + xFoundOne.set( mxReplaceable->findNext( mxTextRange->getStart(), uno::Reference< util::XSearchDescriptor >( mxPropertyReplace, uno::UNO_QUERY_THROW ) ), uno::UNO_QUERY ); + } + else + { + mxTVC->gotoEnd( false ); + xFoundOne.set( mxReplaceable->findNext( mxTextRange->getEnd(), uno::Reference< util::XSearchDescriptor >( mxPropertyReplace, uno::UNO_QUERY_THROW ) ), uno::UNO_QUERY ); + + } + } + return xFoundOne; +} + +bool SwVbaFind::SearchReplace() +{ + bool result = false; + + // TODO: map wildcards in area to OOo wildcards + + if( mbReplace ) + { + switch( mnReplaceType ) + { + case word::WdReplace::wdReplaceNone: + { + result = true; + break; + } + case word::WdReplace::wdReplaceOne: + { + uno::Reference< text::XTextRange > xFindOne = FindOneElement(); + if( xFindOne.is() ) + { + xFindOne->setString( GetReplaceWith() ); + result = mxSelSupp->select( uno::Any( xFindOne ) ); + } + break; + } + case word::WdReplace::wdReplaceAll: + { + uno::Reference< container::XIndexAccess > xIndexAccess = mxReplaceable->findAll( uno::Reference< util::XSearchDescriptor >( mxPropertyReplace, uno::UNO_QUERY_THROW ) ); + if( xIndexAccess->getCount() > 0 ) + { + for( sal_Int32 i = 0; i < xIndexAccess->getCount(); i++ ) + { + uno::Reference< text::XTextRange > xTextRange( xIndexAccess->getByIndex( i ), uno::UNO_QUERY_THROW ); + if( mnWrap == word::WdFindWrap::wdFindContinue || mnWrap == word::WdFindWrap::wdFindAsk || InRange( xTextRange ) ) + { + xTextRange->setString( GetReplaceWith() ); + result = true; + } + } + } + break; + } + default: + { + result = false; + } + } + } + else + { + uno::Reference< text::XTextRange > xFindOne = FindOneElement(); + if( xFindOne.is() ) + result = mxSelSupp->select( uno::Any( xFindOne ) ); + } + + return result; +} + +OUString SAL_CALL SwVbaFind::getText() +{ + return mxPropertyReplace->getSearchString(); +} + +void SAL_CALL SwVbaFind::setText( const OUString& _text ) +{ + mxPropertyReplace->setSearchString( _text ); +} + +uno::Any SAL_CALL SwVbaFind::getReplacement() +{ + return uno::Any( uno::Reference< word::XReplacement >( new SwVbaReplacement( this, mxContext, mxPropertyReplace ) ) ); +} + +void SAL_CALL SwVbaFind::setReplacement( const uno::Any& /*_replacement */ ) +{ + throw uno::RuntimeException("Not implemented" ); +} + +sal_Bool SAL_CALL SwVbaFind::getForward() +{ + bool bBackward = false; + mxPropertyReplace->getPropertyValue("SearchBackwards") >>= bBackward; + return !bBackward; +} + +void SAL_CALL SwVbaFind::setForward( sal_Bool _forward ) +{ + bool bBackward = !_forward; + mxPropertyReplace->setPropertyValue("SearchBackwards", uno::Any( bBackward ) ); +} + +::sal_Int32 SAL_CALL SwVbaFind::getWrap() +{ + // seems not supported in Writer + return mnWrap; +} + +void SAL_CALL SwVbaFind::setWrap( ::sal_Int32 _wrap ) +{ + // seems not supported in Writer + mnWrap = _wrap; +} + +sal_Bool SAL_CALL SwVbaFind::getFormat() +{ + return mxPropertyReplace->getValueSearch(); +} + +void SAL_CALL SwVbaFind::setFormat( sal_Bool _format ) +{ + mxPropertyReplace->setValueSearch( _format ); +} + +sal_Bool SAL_CALL SwVbaFind::getMatchCase() +{ + bool value = false; + mxPropertyReplace->getPropertyValue("SearchCaseSensitive") >>= value; + return value; +} + +void SAL_CALL SwVbaFind::setMatchCase( sal_Bool _matchcase ) +{ + mxPropertyReplace->setPropertyValue("SearchCaseSensitive", uno::Any( _matchcase ) ); +} + +sal_Bool SAL_CALL SwVbaFind::getMatchWholeWord() +{ + bool value = false; + mxPropertyReplace->getPropertyValue("SearchWords") >>= value; + return value; +} + +void SAL_CALL SwVbaFind::setMatchWholeWord( sal_Bool _matchwholeword ) +{ + mxPropertyReplace->setPropertyValue("SearchWords", uno::Any( _matchwholeword ) ); +} + +sal_Bool SAL_CALL SwVbaFind::getMatchWildcards() +{ + bool value = false; + mxPropertyReplace->getPropertyValue("SearchRegularExpression") >>= value; + return value; +} + +void SAL_CALL SwVbaFind::setMatchWildcards( sal_Bool _matchwildcards ) +{ + mxPropertyReplace->setPropertyValue("SearchRegularExpression", uno::Any( _matchwildcards ) ); +} + +sal_Bool SAL_CALL SwVbaFind::getMatchSoundsLike() +{ + bool value = false; + mxPropertyReplace->getPropertyValue("SearchSimilarity") >>= value; + return value; +} + +void SAL_CALL SwVbaFind::setMatchSoundsLike( sal_Bool _matchsoundslike ) +{ + // seems not accurate + mxPropertyReplace->setPropertyValue("SearchSimilarity", uno::Any( _matchsoundslike ) ); +} + +sal_Bool SAL_CALL SwVbaFind::getMatchAllWordForms() +{ + bool value = false; + mxPropertyReplace->getPropertyValue("SearchSimilarity") >>= value; + if( value ) + mxPropertyReplace->getPropertyValue("SearchSimilarityRelax") >>= value; + return value; +} + +void SAL_CALL SwVbaFind::setMatchAllWordForms( sal_Bool _matchallwordforms ) +{ + // seems not accurate + mxPropertyReplace->setPropertyValue("SearchSimilarity", uno::Any( _matchallwordforms ) ); + mxPropertyReplace->setPropertyValue("SearchSimilarityRelax", uno::Any( _matchallwordforms ) ); +} + +uno::Any SAL_CALL SwVbaFind::getStyle() +{ + throw uno::RuntimeException("Not implemented" ); +} + +void SAL_CALL SwVbaFind::setStyle( const uno::Any& /*_style */ ) +{ + throw uno::RuntimeException("Not implemented" ); +} + +sal_Bool SAL_CALL +SwVbaFind::Execute( const uno::Any& FindText, const uno::Any& MatchCase, const uno::Any& MatchWholeWord, const uno::Any& MatchWildcards, const uno::Any& MatchSoundsLike, const uno::Any& MatchAllWordForms, const uno::Any& Forward, const uno::Any& Wrap, const uno::Any& Format, const uno::Any& ReplaceWith, const uno::Any& Replace, const uno::Any& /*MatchKashida*/, const uno::Any& /*MatchDiacritics*/, const uno::Any& /*MatchAlefHamza*/, const uno::Any& /*MatchControl*/, const uno::Any& /*MatchPrefix*/, const uno::Any& /*MatchSuffix*/, const uno::Any& /*MatchPhrase*/, const uno::Any& /*IgnoreSpace*/, const uno::Any& /*IgnorePunct*/ ) +{ + bool result = false; + if( FindText.hasValue() ) + { + OUString sText; + FindText >>= sText; + setText( sText ); + } + + bool bValue = false; + if( MatchCase.hasValue() ) + { + MatchCase >>= bValue; + setMatchCase( bValue ); + } + + if( MatchWholeWord.hasValue() ) + { + MatchWholeWord >>= bValue; + setMatchWholeWord( bValue ); + } + + if( MatchWildcards.hasValue() ) + { + MatchWildcards >>= bValue; + setMatchWildcards( bValue ); + } + + if( MatchSoundsLike.hasValue() ) + { + MatchSoundsLike >>= bValue; + setMatchSoundsLike( bValue ); + } + + if( MatchAllWordForms.hasValue() ) + { + MatchAllWordForms >>= bValue; + setMatchAllWordForms( bValue ); + } + + if( Forward.hasValue() ) + { + Forward >>= bValue; + setForward( bValue ); + } + + if( Wrap.hasValue() ) + { + sal_Int32 nWrapType = 0; + Wrap >>= nWrapType; + setWrap( nWrapType ); + } + + if( Format.hasValue() ) + { + Format >>= bValue; + setFormat( bValue ); + } + + if( ReplaceWith.hasValue() ) + { + OUString sValue; + ReplaceWith >>= sValue; + SetReplaceWith( sValue ); + } + + if( Replace.hasValue() ) + { + sal_Int32 nValue(0); + Replace >>= nValue; + SetReplace( nValue ); + } + + result = SearchReplace(); + + return result; +} + +void SAL_CALL +SwVbaFind::ClearFormatting( ) +{ + uno::Sequence< beans::PropertyValue > aSearchAttribs; + mxPropertyReplace->setSearchAttributes( aSearchAttribs ); +} + +OUString +SwVbaFind::getServiceImplName() +{ + return "SwVbaFind"; +} + +uno::Sequence< OUString > +SwVbaFind::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Find" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbafind.hxx b/sw/source/ui/vba/vbafind.hxx new file mode 100644 index 0000000000..110a084bd2 --- /dev/null +++ b/sw/source/ui/vba/vbafind.hxx @@ -0,0 +1,100 @@ +/* -*- 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_VBA_VBAFIND_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAFIND_HXX + +#include <ooo/vba/word/XFind.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/util/XReplaceable.hpp> +#include <com/sun/star/util/XPropertyReplace.hpp> +#include <com/sun/star/text/XTextViewCursor.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XFind > SwVbaFind_BASE; + +class SwVbaFind : public SwVbaFind_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::text::XTextRange > mxTextRange; + css::uno::Reference< css::util::XReplaceable > mxReplaceable; + css::uno::Reference< css::util::XPropertyReplace> mxPropertyReplace; + css::uno::Reference< css::text::XTextViewCursor> mxTVC; + css::uno::Reference< css::view::XSelectionSupplier> mxSelSupp; + bool mbReplace; + sal_Int32 mnReplaceType; + sal_Int32 mnWrap; + +private: + /// @throws css::uno::RuntimeException + bool InRange( const css::uno::Reference< css::text::XTextRange >& xCurrentRange ); + /// @throws css::uno::RuntimeException + bool InEqualRange( const css::uno::Reference< css::text::XTextRange >& xCurrentRange ); + void SetReplace( sal_Int32 type ); + /// @throws css::uno::RuntimeException + void SetReplaceWith( const OUString& rText ); + /// @throws css::uno::RuntimeException + OUString GetReplaceWith(); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::text::XTextRange > FindOneElement(); + /// @throws css::uno::RuntimeException + bool SearchReplace(); + + /// @throws css::uno::RuntimeException + SwVbaFind( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::frame::XModel > xModel ); +public: + static css::uno::Reference< ooo::vba::word::XFind > GetOrCreateFind(const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< com::sun::star::uno::XComponentContext >& rContext, const css::uno::Reference< com::sun::star::frame::XModel >& xModel, const css::uno::Reference< css::text::XTextRange >& xTextRange); + virtual ~SwVbaFind() override; + + // Attributes + virtual OUString SAL_CALL getText() override; + virtual void SAL_CALL setText( const OUString& _text ) override; + virtual css::uno::Any SAL_CALL getReplacement() override; + virtual void SAL_CALL setReplacement( const css::uno::Any& _replacement ) override; + virtual sal_Bool SAL_CALL getForward() override; + virtual void SAL_CALL setForward( sal_Bool _forward ) override; + virtual ::sal_Int32 SAL_CALL getWrap() override; + virtual void SAL_CALL setWrap( ::sal_Int32 _wrap ) override; + virtual sal_Bool SAL_CALL getFormat() override; + virtual void SAL_CALL setFormat( sal_Bool _format ) override; + virtual sal_Bool SAL_CALL getMatchCase() override; + virtual void SAL_CALL setMatchCase( sal_Bool _matchcase ) override; + virtual sal_Bool SAL_CALL getMatchWholeWord() override; + virtual void SAL_CALL setMatchWholeWord( sal_Bool _matchwholeword ) override; + virtual sal_Bool SAL_CALL getMatchWildcards() override; + virtual void SAL_CALL setMatchWildcards( sal_Bool _matchwildcards ) override; + virtual sal_Bool SAL_CALL getMatchSoundsLike() override; + virtual void SAL_CALL setMatchSoundsLike( sal_Bool _matchsoundslike ) override; + virtual sal_Bool SAL_CALL getMatchAllWordForms() override; + virtual void SAL_CALL setMatchAllWordForms( sal_Bool _matchallwordforms ) override; + virtual css::uno::Any SAL_CALL getStyle() override; + virtual void SAL_CALL setStyle( const css::uno::Any& _style ) override; + + // Methods + virtual sal_Bool SAL_CALL Execute( const css::uno::Any& FindText, const css::uno::Any& MatchCase, const css::uno::Any& MatchWholeWord, const css::uno::Any& MatchWildcards, const css::uno::Any& MatchSoundsLike, const css::uno::Any& MatchAllWordForms, const css::uno::Any& Forward, const css::uno::Any& Wrap, const css::uno::Any& Format, const css::uno::Any& ReplaceWith, const css::uno::Any& Replace, const css::uno::Any& MatchKashida, const css::uno::Any& MatchDiacritics, const css::uno::Any& MatchAlefHamza, const css::uno::Any& MatchControl, const css::uno::Any& MatchPrefix, const css::uno::Any& MatchSuffix, const css::uno::Any& MatchPhrase, const css::uno::Any& IgnoreSpace, const css::uno::Any& IgnorePunct ) override; + virtual void SAL_CALL ClearFormatting( ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAFIND_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbafont.cxx b/sw/source/ui/vba/vbafont.cxx new file mode 100644 index 0000000000..91a31ec664 --- /dev/null +++ b/sw/source/ui/vba/vbafont.cxx @@ -0,0 +1,235 @@ +/* -*- 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 "vbafont.hxx" +#include <com/sun/star/awt/FontUnderline.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <ooo/vba/word/WdUnderline.hpp> +#include <sal/macros.h> +#include <unordered_map> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +const uno::Any aLongAnyTrue( sal_Int16(-1) ); +const uno::Any aLongAnyFalse( sal_Int16( 0 ) ); + +namespace { + +struct MapPair +{ + sal_Int32 nMSOConst; + sal_Int32 nOOOConst; +}; + +} + +MapPair const UnderLineTable[] = { + { word::WdUnderline::wdUnderlineNone, css::awt::FontUnderline::NONE }, + { word::WdUnderline::wdUnderlineSingle, css::awt::FontUnderline::SINGLE }, + { word::WdUnderline::wdUnderlineWords, css::awt::FontUnderline::SINGLE }, + { word::WdUnderline::wdUnderlineDouble, css::awt::FontUnderline::DOUBLE }, + { word::WdUnderline::wdUnderlineDotted, css::awt::FontUnderline::DOTTED }, + { word::WdUnderline::wdUnderlineThick, css::awt::FontUnderline::BOLDDASH }, + { word::WdUnderline::wdUnderlineDash, css::awt::FontUnderline::DASH }, + { word::WdUnderline::wdUnderlineDotDash, css::awt::FontUnderline::DASHDOT }, + { word::WdUnderline::wdUnderlineDotDotDash, css::awt::FontUnderline::DASHDOTDOT }, + { word::WdUnderline::wdUnderlineWavy, css::awt::FontUnderline::WAVE }, + { word::WdUnderline::wdUnderlineDottedHeavy, css::awt::FontUnderline::BOLDDOTTED }, + { word::WdUnderline::wdUnderlineDashHeavy, css::awt::FontUnderline::BOLDDASH }, + { word::WdUnderline::wdUnderlineDotDashHeavy, css::awt::FontUnderline::BOLDDASHDOT }, + { word::WdUnderline::wdUnderlineDotDotDashHeavy, css::awt::FontUnderline::BOLDDASHDOTDOT }, + { word::WdUnderline::wdUnderlineWavyHeavy, css::awt::FontUnderline::BOLDWAVE }, + { word::WdUnderline::wdUnderlineDashLong, css::awt::FontUnderline::LONGDASH }, + { word::WdUnderline::wdUnderlineWavyDouble, css::awt::FontUnderline::DOUBLEWAVE }, + { word::WdUnderline::wdUnderlineDashLongHeavy, css::awt::FontUnderline::BOLDLONGDASH }, +}; + +typedef std::unordered_map< sal_Int32, sal_Int32 > ConstToConst; + +namespace { + +class UnderLineMapper +{ + ConstToConst m_MSO2OOO; + ConstToConst m_OOO2MSO; +private: + UnderLineMapper() + { + for ( auto const & index: UnderLineTable ) + { + m_MSO2OOO[ index.nMSOConst ] = index.nOOOConst; + m_OOO2MSO[ index.nOOOConst ] = index.nMSOConst; + } + } +public: + static OUString propName() + { + return "CharUnderline"; + } + + static UnderLineMapper& instance() + { + static UnderLineMapper theMapper; + return theMapper; + } + + /// @throws lang::IllegalArgumentException + sal_Int32 getOOOFromMSO( sal_Int32 nMSOConst ) + { + ConstToConst::iterator it = m_MSO2OOO.find( nMSOConst ); + if ( it == m_MSO2OOO.end() ) + throw lang::IllegalArgumentException(); + return it->second; + } + /// @throws lang::IllegalArgumentException + sal_Int32 getMSOFromOOO( sal_Int32 nOOOConst ) + { + ConstToConst::iterator it = m_OOO2MSO.find( nOOOConst ); + if ( it == m_OOO2MSO.end() ) + throw lang::IllegalArgumentException(); + return it->second; + } +}; + +} + +SwVbaFont::SwVbaFont( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XIndexAccess >& xPalette, uno::Reference< css::beans::XPropertySet > const & xPropertySet ) + : SwVbaFont_BASE( xParent, xContext, xPalette, xPropertySet, Component::WORD ) +{ +} + +uno::Any SAL_CALL +SwVbaFont::getUnderline() +{ + sal_Int32 nOOVal = 0; + mxFont->getPropertyValue( UnderLineMapper::propName() ) >>= nOOVal; + return uno::Any( UnderLineMapper::instance().getMSOFromOOO( nOOVal ) ); +} + +void SAL_CALL +SwVbaFont::setUnderline( const uno::Any& _underline ) +{ + sal_Int32 nMSOVal = 0; + + if ( _underline >>= nMSOVal ) + { + sal_Int32 nOOVal = UnderLineMapper::instance().getOOOFromMSO( nMSOVal ); + mxFont->setPropertyValue( UnderLineMapper::propName(), uno::Any( nOOVal ) ); + } +} + +OUString +SwVbaFont::getServiceImplName() +{ + return "SwVbaFont"; +} + +uno::Any SAL_CALL +SwVbaFont::getColorIndex() +{ + sal_Int32 nColor = 0; + + getColor() >>= nColor; + sal_Int32 nElems = mxPalette->getCount(); + sal_Int32 nIndex = 0; + for ( sal_Int32 count=0; count<nElems; ++count ) + { + sal_Int32 nPaletteColor = 0; + mxPalette->getByIndex( count ) >>= nPaletteColor; + if ( nPaletteColor == nColor ) + { + nIndex = count; + break; + } + } + return uno::Any( nIndex ); +} +uno::Any SAL_CALL +SwVbaFont::getSubscript() +{ + bool bRes = false; + SwVbaFont_BASE::getSubscript() >>= bRes; + if ( bRes ) + return aLongAnyTrue; + return aLongAnyFalse; +} + +uno::Any SAL_CALL +SwVbaFont::getSuperscript() +{ + bool bRes = false; + SwVbaFont_BASE::getSuperscript() >>= bRes; + if ( bRes ) + return aLongAnyTrue; + return aLongAnyFalse; +} + +uno::Any SAL_CALL +SwVbaFont::getBold() +{ + bool bRes = false; + SwVbaFont_BASE::getBold() >>= bRes; + if ( bRes ) + return aLongAnyTrue; + return aLongAnyFalse; +} + +uno::Any SAL_CALL +SwVbaFont::getItalic() +{ + bool bRes = false; + SwVbaFont_BASE::getItalic() >>= bRes; + if ( bRes ) + return aLongAnyTrue; + return aLongAnyFalse; +} + +uno::Any SAL_CALL +SwVbaFont::getStrikethrough() +{ + bool bRes = false; + SwVbaFont_BASE::getStrikethrough() >>= bRes; + if ( bRes ) + return aLongAnyTrue; + return aLongAnyFalse; +} + +uno::Any SAL_CALL +SwVbaFont::getShadow() +{ + bool bRes = false; + SwVbaFont_BASE::getShadow() >>= bRes; + if ( bRes ) + return aLongAnyTrue; + return aLongAnyFalse; +} + +uno::Sequence< OUString > +SwVbaFont::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Font" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbafont.hxx b/sw/source/ui/vba/vbafont.hxx new file mode 100644 index 0000000000..61bfc0f526 --- /dev/null +++ b/sw/source/ui/vba/vbafont.hxx @@ -0,0 +1,49 @@ +/* -*- 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 . + */ +#pragma once + +#include <vbahelper/vbafontbase.hxx> +#include <ooo/vba/word/XFont.hpp> +#include <cppuhelper/implbase.hxx> + +typedef cppu::ImplInheritanceHelper< VbaFontBase, ov::word::XFont > SwVbaFont_BASE; + +class SwVbaFont : public SwVbaFont_BASE +{ +public: + /// @throws css::uno::RuntimeException + SwVbaFont( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::container::XIndexAccess >& xPalette, css::uno::Reference< css::beans::XPropertySet > const & xPropertySet ); + + // Attributes + virtual css::uno::Any SAL_CALL getColorIndex() override; + virtual css::uno::Any SAL_CALL getUnderline() override; + virtual void SAL_CALL setUnderline( const css::uno::Any& _underline ) override; + virtual css::uno::Any SAL_CALL getSubscript() override; + virtual css::uno::Any SAL_CALL getSuperscript() override; + + virtual css::uno::Any SAL_CALL getBold() override; + virtual css::uno::Any SAL_CALL getItalic() override; + virtual css::uno::Any SAL_CALL getStrikethrough() override; + virtual css::uno::Any SAL_CALL getShadow() override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfield.cxx b/sw/source/ui/vba/vbaformfield.cxx new file mode 100644 index 0000000000..cb1351fa74 --- /dev/null +++ b/sw/source/ui/vba/vbaformfield.cxx @@ -0,0 +1,255 @@ +/* -*- 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 <ooo/vba/word/WdFieldType.hpp> + +#include <sal/log.hxx> + +#include <doc.hxx> +#include <docsh.hxx> +#include <unotextrange.hxx> + +#include "vbaformfield.hxx" +#include "vbaformfieldcheckbox.hxx" +#include "vbaformfielddropdown.hxx" +#include "vbaformfieldtextinput.hxx" +#include "vbarange.hxx" +#include "wordvbahelper.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +/** + * FormFields are inline text objects that are only found in MS Word. + * They cannot be created in Excel or in Calc. + * + * There are three specific kinds of FormFields: CheckBox, DropDown, and TextInput. + */ +SwVbaFormField::SwVbaFormField(const uno::Reference<ooo::vba::XHelperInterface>& rParent, + const uno::Reference<uno::XComponentContext>& rContext, + const uno::Reference<text::XTextDocument>& xTextDocument, + sw::mark::IFieldmark& rFormField) + : SwVbaFormField_BASE(rParent, rContext) + , m_xTextDocument(xTextDocument) + , m_rFormField(rFormField) +{ +} + +SwVbaFormField::~SwVbaFormField() {} + +uno::Any SwVbaFormField::CheckBox() +{ + return uno::Any(uno::Reference<word::XCheckBox>( + new SwVbaFormFieldCheckBox(mxParent, mxContext, m_rFormField))); +} + +uno::Any SwVbaFormField::DropDown() +{ + return uno::Any(uno::Reference<word::XDropDown>( + new SwVbaFormFieldDropDown(mxParent, mxContext, m_rFormField))); +} + +uno::Any SwVbaFormField::TextInput() +{ + return uno::Any(uno::Reference<word::XTextInput>( + new SwVbaFormFieldTextInput(mxParent, mxContext, m_rFormField))); +} + +uno::Any SwVbaFormField::Previous() +{ + SwDoc* pDoc = word::getDocShell(m_xTextDocument)->GetDoc(); + if (!pDoc) + return uno::Any(); + + const IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + if (!pMarkAccess) + return uno::Any(); + + sw::mark::IFieldmark* pFieldMark = pMarkAccess->getFieldmarkBefore(m_rFormField.GetMarkPos(), + /*bLoop=*/false); + + // DateFields are a LO specialty, and do not exist natively in MS documents. Ignore if added... + auto pDateField = dynamic_cast<sw::mark::IDateFieldmark*>(pFieldMark); + while (pDateField) + { + pFieldMark = pMarkAccess->getFieldmarkBefore(pDateField->GetMarkPos(), /*bLoop=*/false); + pDateField = dynamic_cast<sw::mark::IDateFieldmark*>(pFieldMark); + } + + if (!pFieldMark) + return uno::Any(); + + return uno::Any(uno::Reference<word::XFormField>( + new SwVbaFormField(mxParent, mxContext, m_xTextDocument, *pFieldMark))); +} + +uno::Any SwVbaFormField::Next() +{ + SwDoc* pDoc = word::getDocShell(m_xTextDocument)->GetDoc(); + if (!pDoc) + return uno::Any(); + + const IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + if (!pMarkAccess) + return uno::Any(); + + sw::mark::IFieldmark* pFieldMark = pMarkAccess->getFieldmarkAfter(m_rFormField.GetMarkPos(), + /*bLoop=*/false); + + // DateFields are a LO specialty, and do not exist natively in MS documents. Ignore if added... + auto pDateField = dynamic_cast<sw::mark::IDateFieldmark*>(pFieldMark); + while (pDateField) + { + pFieldMark = pMarkAccess->getFieldmarkAfter(pDateField->GetMarkPos(), /*bLoop=*/false); + pDateField = dynamic_cast<sw::mark::IDateFieldmark*>(pFieldMark); + } + + if (!pFieldMark) + return uno::Any(); + + return uno::Any(uno::Reference<word::XFormField>( + new SwVbaFormField(mxParent, mxContext, m_xTextDocument, *pFieldMark))); +} + +uno::Reference<word::XRange> SwVbaFormField::Range() +{ + uno::Reference<word::XRange> xRet; + SwDoc* pDoc = word::getDocShell(m_xTextDocument)->GetDoc(); + if (pDoc) + { + rtl::Reference<SwXTextRange> xText(SwXTextRange::CreateXTextRange( + *pDoc, m_rFormField.GetMarkStart(), &m_rFormField.GetMarkEnd())); + if (xText.is()) + xRet = new SwVbaRange(mxParent, mxContext, m_xTextDocument, xText->getStart(), + xText->getEnd()); + } + return xRet; +} + +OUString SwVbaFormField::getDefaultPropertyName() { return "Type"; } + +sal_Int32 SwVbaFormField::getType() +{ + IDocumentMarkAccess::MarkType aType = IDocumentMarkAccess::GetType(m_rFormField); + if (aType == IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK) + return ooo::vba::word::WdFieldType::wdFieldFormCheckBox; + else if (aType == IDocumentMarkAccess::MarkType::TEXT_FIELDMARK) + return ooo::vba::word::WdFieldType::wdFieldFormTextInput; + return ooo::vba::word::WdFieldType::wdFieldFormDropDown; +} + +sal_Bool SwVbaFormField::getCalculateOnExit() +{ + SAL_INFO("sw.vba", "SwVbaFormField::getCalculateOnExit stub"); + return false; +} + +void SwVbaFormField::setCalculateOnExit(sal_Bool /*bSet*/) +{ + SAL_INFO("sw.vba", "SwVbaFormField::setCalculateOnExit stub"); +} + +sal_Bool SwVbaFormField::getEnabled() +{ + SAL_INFO("sw.vba", "SwVbaFormField::getEnabled stub"); + return true; +} + +void SwVbaFormField::setEnabled(sal_Bool /*bSet*/) +{ + SAL_INFO("sw.vba", "SwVbaFormField::setEnabled stub"); +} + +OUString SwVbaFormField::getEntryMacro() +{ + OUString sMacro; + (*m_rFormField.GetParameters())["EntryMacro"] >>= sMacro; + return sMacro; +} + +void SwVbaFormField::setEntryMacro(const OUString& rSet) +{ + (*m_rFormField.GetParameters())["EntryMacro"] <<= rSet; +} + +OUString SwVbaFormField::getExitMacro() +{ + OUString sMacro; + (*m_rFormField.GetParameters())["ExitMacro"] >>= sMacro; + return sMacro; +} + +void SwVbaFormField::setExitMacro(const OUString& rSet) +{ + (*m_rFormField.GetParameters())["ExitMacro"] <<= rSet; +} + +OUString SwVbaFormField::getHelpText() { return m_rFormField.GetFieldHelptext(); } + +void SwVbaFormField::setHelpText(const OUString& rSet) { m_rFormField.SetFieldHelptext(rSet); } + +sal_Bool SwVbaFormField::getOwnHelp() +{ + SAL_INFO("sw.vba", "SwVbaFormField::getOwnHelp stub"); + return true; +} + +void SwVbaFormField::setOwnHelp(sal_Bool /*bSet*/) +{ + SAL_INFO("sw.vba", "SwVbaFormField::setOwnHelp stub"); +} + +OUString SwVbaFormField::getName() { return m_rFormField.GetName(); } + +void SwVbaFormField::setName(const OUString& rSet) +{ + SAL_INFO("sw.vba", "SwVbaFormField::setName[" << rSet << "] stub"); +} + +OUString SwVbaFormField::getResult() { return m_rFormField.GetContent(); } + +void SwVbaFormField::setResult(const OUString& rSet) +{ + if (dynamic_cast<sw::mark::ICheckboxFieldmark*>(&m_rFormField)) + m_rFormField.ReplaceContent("false"); + else + m_rFormField.ReplaceContent(rSet); +} + +OUString SwVbaFormField::getStatusText() +{ + SAL_INFO("sw.vba", "SwVbaFormField::getStatusText stub"); + return OUString(); +} + +void SwVbaFormField::setStatusText(const OUString& rSet) +{ + SAL_INFO("sw.vba", "SwVbaFormField::setStatusText[" << rSet << "] stub"); +} + +sal_Bool SwVbaFormField::getOwnStatus() +{ + SAL_INFO("sw.vba", "SwVbaFormField::getOwnStatus stub"); + return true; +} + +void SwVbaFormField::setOwnStatus(sal_Bool /*bSet*/) +{ + SAL_INFO("sw.vba", "SwVbaFormField::setOwnStatus stub"); +} + +OUString SwVbaFormField::getServiceImplName() { return "SwVbaFormField"; } + +uno::Sequence<OUString> SwVbaFormField::getServiceNames() +{ + static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.FormField" }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfield.hxx b/sw/source/ui/vba/vbaformfield.hxx new file mode 100644 index 0000000000..260e790935 --- /dev/null +++ b/sw/source/ui/vba/vbaformfield.hxx @@ -0,0 +1,87 @@ +/* -*- 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/. + */ +#pragma once + +#include <com/sun/star/text/XTextDocument.hpp> +#include <ooo/vba/word/XFormField.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +#include <IDocumentMarkAccess.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XFormField> SwVbaFormField_BASE; + +class SwVbaFormField : public SwVbaFormField_BASE +{ +private: + css::uno::Reference<css::text::XTextDocument> m_xTextDocument; + sw::mark::IFieldmark& m_rFormField; + +public: + /// @throws css::uno::RuntimeException + SwVbaFormField(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext, + const uno::Reference<text::XTextDocument>& xTextDocument, + sw::mark::IFieldmark& rFormField); + ~SwVbaFormField() override; + + // XFormField Methods + OUString SAL_CALL getDefaultPropertyName() override; + + css::uno::Any SAL_CALL CheckBox() override; + css::uno::Any SAL_CALL DropDown() override; + css::uno::Any SAL_CALL TextInput() override; + css::uno::Any SAL_CALL Previous() override; + css::uno::Any SAL_CALL Next() override; + css::uno::Reference<ooo::vba::word::XRange> SAL_CALL Range() override; + + // Indicates which of the three form fields this is: oovbaapi/ooo/vba/word/WdFieldType.idl + sal_Int32 SAL_CALL getType() override; + // True if references to the specified form field + // are automatically updated whenever the field is exited + sal_Bool SAL_CALL getCalculateOnExit() override; + void SAL_CALL setCalculateOnExit(sal_Bool bSet) override; + sal_Bool SAL_CALL getEnabled() override; + void SAL_CALL setEnabled(sal_Bool bSet) override; + OUString SAL_CALL getEntryMacro() override; + void SAL_CALL setEntryMacro(const OUString& rSet) override; + OUString SAL_CALL getExitMacro() override; + void SAL_CALL setExitMacro(const OUString& rSet) override; + /* + * If the OwnHelp property is set to True, + * HelpText specifies the text string value. + * If OwnHelp is set to False, HelpText specifies the name of an AutoText entry + * that contains help text for the form field. + */ + OUString SAL_CALL getHelpText() override; + void SAL_CALL setHelpText(const OUString& rSet) override; + sal_Bool SAL_CALL getOwnHelp() override; + void SAL_CALL setOwnHelp(sal_Bool bSet) override; + + OUString SAL_CALL getName() override; + void SAL_CALL setName(const OUString& rSet) override; + OUString SAL_CALL getResult() override; + void SAL_CALL setResult(const OUString& rSet) override; + /* + * If the OwnStatus property is set to True, + * StatusText specifies the status bar value. + * If OwnStatus is set to False, StatusText specifies the name of an AutoText entry + * that contains status bar text for the form field. + */ + OUString SAL_CALL getStatusText() override; + void SAL_CALL setStatusText(const OUString& rSet) override; + sal_Bool SAL_CALL getOwnStatus() override; + void SAL_CALL setOwnStatus(sal_Bool bSet) override; + + // XHelperInterface + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfieldcheckbox.cxx b/sw/source/ui/vba/vbaformfieldcheckbox.cxx new file mode 100644 index 0000000000..5a32e7e426 --- /dev/null +++ b/sw/source/ui/vba/vbaformfieldcheckbox.cxx @@ -0,0 +1,117 @@ +/* -*- 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 <sal/log.hxx> + +#include "vbaformfieldcheckbox.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +/** + * CheckBoxes are inline text objects that are only found in MS Word. + * They cannot be created in Excel or in Calc. + * + * Note that VBA might call this a Checkbox, but it might not actually be one, + * so make good use of getValid() + */ +SwVbaFormFieldCheckBox::SwVbaFormFieldCheckBox( + const uno::Reference<ooo::vba::XHelperInterface>& rParent, + const uno::Reference<uno::XComponentContext>& rContext, sw::mark::IFieldmark& rFormField) + : SwVbaFormFieldCheckBox_BASE(rParent, rContext) + , m_pCheckBox(dynamic_cast<sw::mark::ICheckboxFieldmark*>(&rFormField)) +{ +} + +SwVbaFormFieldCheckBox::~SwVbaFormFieldCheckBox() {} + +OUString SwVbaFormFieldCheckBox::getDefaultPropertyName() { return "Valid"; } + +sal_Bool SwVbaFormFieldCheckBox::getValid() +{ + return m_pCheckBox + && IDocumentMarkAccess::GetType(*m_pCheckBox) + == IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK; +} + +sal_Bool SwVbaFormFieldCheckBox::getAutoSize() +{ + if (!getValid()) + return false; + + SAL_INFO("sw.vba", "SwVbaFormFieldCheckBox::getAutoSize stub"); + return true; +} + +void SwVbaFormFieldCheckBox::setAutoSize(sal_Bool /*bSet*/) +{ + if (!getValid()) + return; + + SAL_INFO("sw.vba", "SwVbaFormFieldCheckBox::setAutoSize stub"); +} + +sal_Bool SwVbaFormFieldCheckBox::getDefault() +{ + if (!getValid()) + return false; + + return getValue(); +} + +void SwVbaFormFieldCheckBox::setDefault(sal_Bool bSet) +{ + if (!getValid()) + return; + + // Hard to know what to do here, since LO doesn't have a default property for checkboxes. + // Setting this really only makes sense when macro-adding a checkbox. + // In that case, we want it to affect the actual checkbox. + // However, if the checkbox has already been set by the user, then this shouldn't do anything. + // Assuming this is only ever called when adding a checkbox seems the sanest approach. + setValue(bSet); +} + +// Returns the size of a check box, in points +sal_Int32 SwVbaFormFieldCheckBox::getSize() +{ + if (!getValid()) + return 0; + + SAL_INFO("sw.vba", "SwVbaFormFieldCheckBox::getSize stub"); + return 11; +} + +void SwVbaFormFieldCheckBox::setSize(sal_Int32 nSet) +{ + if (!getValid()) + return; + + SAL_INFO("sw.vba", "SwVbaFormFieldCheckBox::setSize[" << nSet << "] stub"); +} + +sal_Bool SwVbaFormFieldCheckBox::getValue() { return getValid() && m_pCheckBox->IsChecked(); } + +void SwVbaFormFieldCheckBox::setValue(sal_Bool bSet) +{ + if (!getValid() || !getValue() == !bSet) + return; + + m_pCheckBox->SetChecked(bSet); +} + +OUString SwVbaFormFieldCheckBox::getServiceImplName() { return "SwVbaFormFieldCheckBox"; } + +uno::Sequence<OUString> SwVbaFormFieldCheckBox::getServiceNames() +{ + static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.CheckBox" }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfieldcheckbox.hxx b/sw/source/ui/vba/vbaformfieldcheckbox.hxx new file mode 100644 index 0000000000..c62549585b --- /dev/null +++ b/sw/source/ui/vba/vbaformfieldcheckbox.hxx @@ -0,0 +1,54 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/word/XCheckBox.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +#include <IDocumentMarkAccess.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XCheckBox> SwVbaFormFieldCheckBox_BASE; + +class SwVbaFormFieldCheckBox : public SwVbaFormFieldCheckBox_BASE +{ +private: + sw::mark::ICheckboxFieldmark* m_pCheckBox; + +public: + /// @throws css::uno::RuntimeException + SwVbaFormFieldCheckBox(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext, + sw::mark::IFieldmark& rFormField); + ~SwVbaFormFieldCheckBox() override; + + // XCheckBox + OUString SAL_CALL getDefaultPropertyName() override; + + // Default member: True if the specified form field object is a valid check box form field + sal_Bool SAL_CALL getValid() override; + + sal_Bool SAL_CALL getAutoSize() override; + void SAL_CALL setAutoSize(sal_Bool bSet) override; + // Returns the default check box value + sal_Bool SAL_CALL getDefault() override; + void SAL_CALL setDefault(sal_Bool bSet) override; + // Returns the size of a check box, in points + sal_Int32 SAL_CALL getSize() override; + void SAL_CALL setSize(sal_Int32 nSet) override; + + sal_Bool SAL_CALL getValue() override; + void SAL_CALL setValue(sal_Bool bSet) override; + + // XHelperInterface + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfielddropdown.cxx b/sw/source/ui/vba/vbaformfielddropdown.cxx new file mode 100644 index 0000000000..f1edc81403 --- /dev/null +++ b/sw/source/ui/vba/vbaformfielddropdown.cxx @@ -0,0 +1,99 @@ +/* -*- 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 <ooo/vba/word/WdTextFormFieldType.hpp> + +#include "vbaformfielddropdown.hxx" +#include "vbaformfielddropdownlistentries.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +/** + * DropDown formfields are inline text objects that are only found in MS Word. + * They cannot be created in Excel or in Calc. + * + * Note that VBA might call this a DropDown, but it might not actually be one, + * so make good use of getValid() + */ +SwVbaFormFieldDropDown::SwVbaFormFieldDropDown( + const uno::Reference<ooo::vba::XHelperInterface>& rParent, + const uno::Reference<uno::XComponentContext>& rContext, ::sw::mark::IFieldmark& rFormField) + : SwVbaFormFieldDropDown_BASE(rParent, rContext) + , m_pDropDown(dynamic_cast<sw::mark::IDropdownFieldmark*>(&rFormField)) +{ +} + +SwVbaFormFieldDropDown::~SwVbaFormFieldDropDown() {} + +OUString SwVbaFormFieldDropDown::getDefaultPropertyName() { return "Valid"; } + +sal_Bool SwVbaFormFieldDropDown::getValid() +{ + return m_pDropDown + && IDocumentMarkAccess::GetType(*m_pDropDown) + == IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK; +} + +sal_Int32 SwVbaFormFieldDropDown::getDefault() { return getValue(); } + +void SwVbaFormFieldDropDown::setDefault(sal_Int32 nSet) +{ + // Hard to know what to do here, since LO doesn't have a default property for DropDowns. + // Setting this really only makes sense when macro-adding a DropDown. + // In that case, we want it to affect the actual text content. + // However, if an item has already been selected by the user, then this shouldn't do anything. + // Assuming this is only ever set when adding a DropDown seems the sanest approach. + setValue(nSet); +} + +sal_Int32 SwVbaFormFieldDropDown::getValue() +{ + sal_Int32 nRet = 0; + if (!getValid()) + return nRet; + + --nRet; // send -1, which requests being changed to the selected DropDown's zero-based index + m_pDropDown->GetContent(&nRet); + return nRet + 1; +} + +void SwVbaFormFieldDropDown::setValue(sal_Int32 nIndex) +{ + if (!getValid() || nIndex == getValue()) + return; + + // switch to zero-based index for implementation + --nIndex; + m_pDropDown->ReplaceContent(/*pText=*/nullptr, &nIndex); +} + +uno::Any SwVbaFormFieldDropDown::ListEntries(const uno::Any& rIndex) +{ + if (!getValid()) + return uno::Any(); + + uno::Reference<XCollection> xCol( + new SwVbaFormFieldDropDownListEntries(this, mxContext, *m_pDropDown)); + + if (rIndex.hasValue()) + return xCol->Item(rIndex, uno::Any()); + + return uno::Any(xCol); +} + +OUString SwVbaFormFieldDropDown::getServiceImplName() { return "SwVbaFormFieldDropDown"; } + +uno::Sequence<OUString> SwVbaFormFieldDropDown::getServiceNames() +{ + static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.DropDown" }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfielddropdown.hxx b/sw/source/ui/vba/vbaformfielddropdown.hxx new file mode 100644 index 0000000000..e92caa2f8e --- /dev/null +++ b/sw/source/ui/vba/vbaformfielddropdown.hxx @@ -0,0 +1,52 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/word/XDropDown.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +#include <IDocumentMarkAccess.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XDropDown> SwVbaFormFieldDropDown_BASE; + +class SwVbaFormFieldDropDown : public SwVbaFormFieldDropDown_BASE +{ +private: + sw::mark::IDropdownFieldmark* m_pDropDown; + +public: + /// @throws css::uno::RuntimeException + SwVbaFormFieldDropDown(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext, + sw::mark::IFieldmark& rFormField); + ~SwVbaFormFieldDropDown() override; + + // XDropDown + OUString SAL_CALL getDefaultPropertyName() override; + + // Default member: True if the specified form field object is a valid listbox field + sal_Bool SAL_CALL getValid() override; + + // Returns and sets the index for the default listbox entry + sal_Int32 SAL_CALL getDefault() override; + void SAL_CALL setDefault(sal_Int32 nSet) override; + // Returns and sets the index of the selected listbox entry + sal_Int32 SAL_CALL getValue() override; + void SAL_CALL setValue(sal_Int32 nIndex) override; + + // Returns a ListEntries collection that represents all the available entries + css::uno::Any SAL_CALL ListEntries(const css::uno::Any& rIndex) override; + + // XHelperInterface + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfielddropdownlistentries.cxx b/sw/source/ui/vba/vbaformfielddropdownlistentries.cxx new file mode 100644 index 0000000000..c167e16d78 --- /dev/null +++ b/sw/source/ui/vba/vbaformfielddropdownlistentries.cxx @@ -0,0 +1,162 @@ +/* -*- 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 <xmloff/odffields.hxx> + +#include "vbaformfielddropdownlistentries.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +static uno::Sequence<OUString> lcl_getListEntries(sw::mark::IDropdownFieldmark& rDropDown) +{ + uno::Sequence<OUString> aSeq; + (*rDropDown.GetParameters())[ODF_FORMDROPDOWN_LISTENTRY] >>= aSeq; + return aSeq; +} + +namespace +{ +class ListEntriesEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference<container::XIndexAccess> mxIndexAccess; + sal_Int32 mnIndex; + +public: + explicit ListEntriesEnumWrapper(uno::Reference<container::XIndexAccess> xIndexAccess) + : mxIndexAccess(xIndexAccess) + , mnIndex(0) + { + } + + sal_Bool SAL_CALL hasMoreElements() override { return (mnIndex < mxIndexAccess->getCount()); } + + uno::Any SAL_CALL nextElement() override + { + if (mnIndex < mxIndexAccess->getCount()) + { + return mxIndexAccess->getByIndex(mnIndex++); + } + throw container::NoSuchElementException(); + } +}; + +class ListEntryCollectionHelper + : public ::cppu::WeakImplHelper<container::XIndexAccess, container::XEnumerationAccess> +{ +private: + uno::Reference<XHelperInterface> mxParent; + uno::Reference<uno::XComponentContext> mxContext; + sw::mark::IDropdownFieldmark& m_rDropDown; + +public: + /// @throws css::uno::RuntimeException + ListEntryCollectionHelper(uno::Reference<ov::XHelperInterface> xParent, + uno::Reference<uno::XComponentContext> xContext, + sw::mark::IDropdownFieldmark& rFormField) + : mxParent(xParent) + , mxContext(xContext) + , m_rDropDown(rFormField) + { + } + + sal_Int32 SAL_CALL getCount() override { return lcl_getListEntries(m_rDropDown).getLength(); } + + uno::Any SAL_CALL getByIndex(sal_Int32 Index) override + { + if (Index < 0 || Index >= getCount()) + throw lang::IndexOutOfBoundsException(); + + return uno::Any(uno::Reference<word::XListEntry>( + new SwVbaFormFieldDropDownListEntry(mxParent, mxContext, m_rDropDown, Index))); + } + + uno::Type SAL_CALL getElementType() override { return cppu::UnoType<word::XListEntry>::get(); } + + sal_Bool SAL_CALL hasElements() override { return getCount() != 0; } + + // XEnumerationAccess + uno::Reference<container::XEnumeration> SAL_CALL createEnumeration() override + { + return new ListEntriesEnumWrapper(this); + } +}; +} + +SwVbaFormFieldDropDownListEntries::SwVbaFormFieldDropDownListEntries( + const uno::Reference<XHelperInterface>& xParent, + const uno::Reference<uno::XComponentContext>& xContext, + sw::mark::IDropdownFieldmark& rFormField) + : SwVbaFormFieldDropDownListEntries_BASE( + xParent, xContext, + uno::Reference<container::XIndexAccess>( + new ListEntryCollectionHelper(xParent, xContext, rFormField))) + , m_rDropDown(rFormField) +{ +} + +// XListEntries +uno::Reference<word::XListEntry> SwVbaFormFieldDropDownListEntries::Add(const OUString& rName, + const uno::Any& rIndex) +{ + sal_Int32 nZIndex = 0; + rIndex >>= nZIndex; + // rIndex is 1-based, nZIndex is 0-based. If rIndex is not given, then add as the last choice. + + // In testing with Word 2010, this gives a compile error: 'ListEntries.Add("Name", 2)' + // This compiles, but gets an unsupported runtime error: 'ListEntries.Add("Name", 2) = "Choice' + // So the only thing that actually works is to simply append: 'ListEntires.Add("Name")' + // but I'll still keep the expected implementation for the broken case. + if (!nZIndex) + nZIndex = SAL_MAX_INT32; + else + --nZIndex; + m_rDropDown.AddContent(rName + "__allowDuplicates", &nZIndex); + m_rDropDown.ReplaceContent(&rName, &nZIndex); + + return uno::Reference<word::XListEntry>( + new SwVbaFormFieldDropDownListEntry(mxParent, mxContext, m_rDropDown, nZIndex)); +} + +void SwVbaFormFieldDropDownListEntries::Clear() { m_rDropDown.DelContent(); } + +sal_Int32 SwVbaFormFieldDropDownListEntries::getCount() +{ + return lcl_getListEntries(m_rDropDown).getLength(); +} + +// XEnumerationAccess +uno::Type SwVbaFormFieldDropDownListEntries::getElementType() +{ + return cppu::UnoType<word::XListEntry>::get(); +} + +uno::Reference<container::XEnumeration> SwVbaFormFieldDropDownListEntries::createEnumeration() +{ + return new ListEntriesEnumWrapper(m_xIndexAccess); +} + +// SwVbadropDownListEntries_BASE +uno::Any SwVbaFormFieldDropDownListEntries::createCollectionObject(const uno::Any& aSource) +{ + return aSource; +} + +OUString SwVbaFormFieldDropDownListEntries::getServiceImplName() +{ + return "SwVbaFormFieldDropDownListEntries"; +} + +uno::Sequence<OUString> SwVbaFormFieldDropDownListEntries::getServiceNames() +{ + static uno::Sequence<OUString> const sNames{ "ooo.vba.word.ListEntries" }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfielddropdownlistentries.hxx b/sw/source/ui/vba/vbaformfielddropdownlistentries.hxx new file mode 100644 index 0000000000..ef13391270 --- /dev/null +++ b/sw/source/ui/vba/vbaformfielddropdownlistentries.hxx @@ -0,0 +1,49 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/word/XListEntries.hpp> +#include <ooo/vba/word/XListEntry.hpp> + +#include <vbahelper/vbacollectionimpl.hxx> + +#include "vbaformfielddropdownlistentries.hxx" +#include "vbaformfielddropdownlistentry.hxx" + +typedef CollTestImplHelper<ooo::vba::word::XListEntries> SwVbaFormFieldDropDownListEntries_BASE; + +class SwVbaFormFieldDropDownListEntries : public SwVbaFormFieldDropDownListEntries_BASE +{ +private: + sw::mark::IDropdownFieldmark& m_rDropDown; + +public: + /// @throws css::uno::RuntimeException + SwVbaFormFieldDropDownListEntries( + const css::uno::Reference<ov::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext, + sw::mark::IDropdownFieldmark& m_rDropDown); + + // XListEntries + css::uno::Reference<ooo::vba::word::XListEntry> + SAL_CALL Add(const OUString& rName, const css::uno::Any& rIndex) override; + void SAL_CALL Clear() override; + sal_Int32 SAL_CALL getCount() override; + + // XEnumerationAccess + css::uno::Type SAL_CALL getElementType() override; + css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override; + + // SwVbaFormFieldDropDownListEntries_BASE + css::uno::Any createCollectionObject(const css::uno::Any& aSource) override; + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfielddropdownlistentry.cxx b/sw/source/ui/vba/vbaformfielddropdownlistentry.cxx new file mode 100644 index 0000000000..bc02439ed5 --- /dev/null +++ b/sw/source/ui/vba/vbaformfielddropdownlistentry.cxx @@ -0,0 +1,56 @@ +/* -*- 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 "vbaformfielddropdownlistentry.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaFormFieldDropDownListEntry::SwVbaFormFieldDropDownListEntry( + const uno::Reference<ooo::vba::XHelperInterface>& rParent, + const uno::Reference<uno::XComponentContext>& rContext, + sw::mark::IDropdownFieldmark& rFormField, sal_Int32 nZIndex) + : SwVbaFormFieldDropDownListEntry_BASE(rParent, rContext) + , m_rDropDown(rFormField) + , m_nZIndex(nZIndex) +{ +} + +SwVbaFormFieldDropDownListEntry::~SwVbaFormFieldDropDownListEntry() {} + +// XListEntry +sal_Int32 SwVbaFormFieldDropDownListEntry::getIndex() { return m_nZIndex + 1; } + +OUString SwVbaFormFieldDropDownListEntry::getName() +{ + sal_Int32 nZIndex = m_nZIndex; + return m_rDropDown.GetContent(&nZIndex); +} + +void SwVbaFormFieldDropDownListEntry::setName(const OUString& rSet) +{ + sal_Int32 nZIndex = m_nZIndex; + m_rDropDown.ReplaceContent(&rSet, &nZIndex); +} + +void SwVbaFormFieldDropDownListEntry::Delete() { m_rDropDown.DelContent(m_nZIndex); } + +// XHelperInterface +OUString SwVbaFormFieldDropDownListEntry::getServiceImplName() +{ + return "SwVbaFormFieldDropDownListEntry"; +} + +uno::Sequence<OUString> SwVbaFormFieldDropDownListEntry::getServiceNames() +{ + static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.ListEntry" }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfielddropdownlistentry.hxx b/sw/source/ui/vba/vbaformfielddropdownlistentry.hxx new file mode 100644 index 0000000000..4ded080e63 --- /dev/null +++ b/sw/source/ui/vba/vbaformfielddropdownlistentry.hxx @@ -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/. + */ +#pragma once + +#include <ooo/vba/word/XListEntry.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +#include <IDocumentMarkAccess.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XListEntry> + SwVbaFormFieldDropDownListEntry_BASE; + +class SwVbaFormFieldDropDownListEntry : public SwVbaFormFieldDropDownListEntry_BASE +{ +private: + sw::mark::IDropdownFieldmark& m_rDropDown; + // All LO and internal UNO functions are 0-based. Convert to 1-based when sending to VBA + const sal_Int32 m_nZIndex; + +public: + /// @throws css::uno::RuntimeException + SwVbaFormFieldDropDownListEntry( + const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext, + sw::mark::IDropdownFieldmark& rFormField, sal_Int32 nZIndex); + ~SwVbaFormFieldDropDownListEntry() override; + + // XListEntry + sal_Int32 SAL_CALL getIndex() override; + + OUString SAL_CALL getName() override; + void SAL_CALL setName(const OUString& sSet) override; + + void SAL_CALL Delete() override; + + // XHelperInterface + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfields.cxx b/sw/source/ui/vba/vbaformfields.cxx new file mode 100644 index 0000000000..9c8af450d3 --- /dev/null +++ b/sw/source/ui/vba/vbaformfields.cxx @@ -0,0 +1,235 @@ +/* -*- 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 <comphelper/sequence.hxx> +#include <sal/log.hxx> + +#include <doc.hxx> +#include <docsh.hxx> +#include <IDocumentMarkAccess.hxx> + +#include "vbaformfield.hxx" +#include "vbaformfields.hxx" +#include "wordvbahelper.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +// Helper function to access the fieldmarks +// @param rIndex serves multiple purposes +// [in] -1 to indicate searching using the provided name, SAL_MAX_INT32 for totals +// [out] rIndex indicates the found index, or the total number of fieldmarks +static sw::mark::IFieldmark* lcl_getFieldmark(std::string_view rName, sal_Int32& rIndex, + const uno::Reference<frame::XModel>& xModel, + uno::Sequence<OUString>* pElementNames = nullptr) + +{ + SwDoc* pDoc = word::getDocShell(xModel)->GetDoc(); + if (!pDoc) + return nullptr; + + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + if (!pMarkAccess) + return nullptr; + + sal_Int32 nCounter = 0; + std::vector<OUString> vElementNames; + IDocumentMarkAccess::iterator aIter = pMarkAccess->getFieldmarksBegin(); + while (aIter != pMarkAccess->getFieldmarksEnd()) + { + switch (IDocumentMarkAccess::GetType(**aIter)) + { + case IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK: + case IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK: + case IDocumentMarkAccess::MarkType::TEXT_FIELDMARK: + { + if (rIndex < 0 + && (*aIter)->GetName().equalsIgnoreAsciiCase(OUString::fromUtf8(rName))) + { + rIndex = nCounter; + return dynamic_cast<sw::mark::IFieldmark*>(*aIter); + } + else if (rIndex == nCounter) + return dynamic_cast<sw::mark::IFieldmark*>(*aIter); + + ++nCounter; + if (pElementNames) + vElementNames.push_back((*aIter)->GetName()); + break; + } + default:; + } + aIter++; + } + rIndex = nCounter; + if (pElementNames) + *pElementNames = comphelper::containerToSequence(vElementNames); + return nullptr; +} + +namespace +{ +class FormFieldsEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference<container::XIndexAccess> mxIndexAccess; + sal_Int32 mnIndex; + +public: + explicit FormFieldsEnumWrapper(const uno::Reference<container::XIndexAccess>& xIndexAccess) + : mxIndexAccess(xIndexAccess) + , mnIndex(0) + { + } + sal_Bool SAL_CALL hasMoreElements() override { return (mnIndex < mxIndexAccess->getCount()); } + + uno::Any SAL_CALL nextElement() override + { + if (mnIndex < mxIndexAccess->getCount()) + { + return mxIndexAccess->getByIndex(mnIndex++); + } + throw container::NoSuchElementException(); + } +}; + +class FormFieldCollectionHelper + : public ::cppu::WeakImplHelper<container::XNameAccess, container::XIndexAccess, + container::XEnumerationAccess> +{ +private: + uno::Reference<XHelperInterface> mxParent; + uno::Reference<uno::XComponentContext> mxContext; + uno::Reference<text::XTextDocument> mxTextDocument; + sw::mark::IFieldmark* m_pCache; + +public: + /// @throws css::uno::RuntimeException + FormFieldCollectionHelper(uno::Reference<ov::XHelperInterface> xParent, + uno::Reference<uno::XComponentContext> xContext, + uno::Reference<text::XTextDocument> xTextDocument) + : mxParent(std::move(xParent)) + , mxContext(std::move(xContext)) + , mxTextDocument(std::move(xTextDocument)) + , m_pCache(nullptr) + { + } + + // XIndexAccess + sal_Int32 SAL_CALL getCount() override + { + sal_Int32 nCount = SAL_MAX_INT32; + lcl_getFieldmark("", nCount, mxTextDocument); + return nCount == SAL_MAX_INT32 ? 0 : nCount; + } + + uno::Any SAL_CALL getByIndex(sal_Int32 Index) override + { + m_pCache = lcl_getFieldmark("", Index, mxTextDocument); + if (!m_pCache) + throw lang::IndexOutOfBoundsException(); + + return uno::Any(uno::Reference<word::XFormField>( + new SwVbaFormField(mxParent, mxContext, mxTextDocument, *m_pCache))); + } + + // XNameAccess + uno::Sequence<OUString> SAL_CALL getElementNames() override + { + sal_Int32 nCount = SAL_MAX_INT32; + uno::Sequence<OUString> aSeq; + lcl_getFieldmark("", nCount, mxTextDocument, &aSeq); + return aSeq; + } + + uno::Any SAL_CALL getByName(const OUString& aName) override + { + if (!hasByName(aName)) + throw container::NoSuchElementException(); + + return uno::Any(uno::Reference<word::XFormField>( + new SwVbaFormField(mxParent, mxContext, mxTextDocument, *m_pCache))); + } + + sal_Bool SAL_CALL hasByName(const OUString& aName) override + { + sal_Int32 nCount = -1; + m_pCache = lcl_getFieldmark(aName.toUtf8(), nCount, mxTextDocument); + return m_pCache != nullptr; + } + + // XElementAccess + uno::Type SAL_CALL getElementType() override { return cppu::UnoType<word::XFormField>::get(); } + + sal_Bool SAL_CALL hasElements() override { return getCount() != 0; } + + // XEnumerationAccess + uno::Reference<container::XEnumeration> SAL_CALL createEnumeration() override + { + return new FormFieldsEnumWrapper(this); + } +}; +} + +SwVbaFormFields::SwVbaFormFields(const uno::Reference<XHelperInterface>& xParent, + const uno::Reference<uno::XComponentContext>& xContext, + const uno::Reference<text::XTextDocument>& xTextDocument) + : SwVbaFormFields_BASE(xParent, xContext, + uno::Reference<container::XIndexAccess>( + new FormFieldCollectionHelper(xParent, xContext, xTextDocument))) +{ +} + +sal_Bool SwVbaFormFields::getShaded() +{ + SAL_INFO("sw.vba", "SwVbaFormFields::getShaded stub"); + return false; +} + +void SwVbaFormFields::setShaded(sal_Bool /*bSet*/) +{ + SAL_INFO("sw.vba", "SwVbaFormFields::setShaded stub"); +} + +// uno::Reference<ooo::vba::word::XFormField> SwVbaFormFields::Add(const uno::Any& Range, +// sal_Int32 Type) +// { +// sw::mark::IFieldmark* pFieldmark = nullptr; +// switch (Type) +// { +// case ooo::vba::word::WdFieldType::wdFieldFormCheckBox: +// break; +// case ooo::vba::word::WdFieldType::wdFieldFormDropDown: +// break; +// case ooo::vba::word::WdFieldType::wdFieldFormTextInput: +// default:; +// } +// +// return uno::Reference<ooo::vba::word::XFormField>( +// new SwVbaFormField(mxParent, mxContext, m_xTextDocument, *pFieldmark)); +// } + +// XEnumerationAccess +uno::Type SwVbaFormFields::getElementType() { return cppu::UnoType<word::XFormField>::get(); } + +uno::Reference<container::XEnumeration> SwVbaFormFields::createEnumeration() +{ + return new FormFieldsEnumWrapper(m_xIndexAccess); +} + +uno::Any SwVbaFormFields::createCollectionObject(const uno::Any& aSource) { return aSource; } + +OUString SwVbaFormFields::getServiceImplName() { return "SwVbaFormFields"; } + +uno::Sequence<OUString> SwVbaFormFields::getServiceNames() +{ + static uno::Sequence<OUString> const sNames{ "ooo.vba.word.FormFields" }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfields.hxx b/sw/source/ui/vba/vbaformfields.hxx new file mode 100644 index 0000000000..2dfa9e76b0 --- /dev/null +++ b/sw/source/ui/vba/vbaformfields.hxx @@ -0,0 +1,41 @@ +/* -*- 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/. + */ +#pragma once + +#include <com/sun/star/text/XTextDocument.hpp> +#include <ooo/vba/word/XFormFields.hpp> + +#include <vbahelper/vbacollectionimpl.hxx> + +typedef CollTestImplHelper<ooo::vba::word::XFormFields> SwVbaFormFields_BASE; + +class SwVbaFormFields : public SwVbaFormFields_BASE +{ +public: + /// @throws css::uno::RuntimeException + SwVbaFormFields(const css::uno::Reference<ov::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext, + const css::uno::Reference<css::text::XTextDocument>& xTextDocument); + + // XFormFields + sal_Bool SAL_CALL getShaded() override; + void SAL_CALL setShaded(sal_Bool bSet) override; + //css::uno::Reference<ooo::vba::word::XFormField> SAL_CALL Add(const css::uno::Any& Range, sal_Int32 Type) override; + + // XEnumerationAccess + css::uno::Type SAL_CALL getElementType() override; + css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override; + + // SwVbaFormFields_BASE + css::uno::Any createCollectionObject(const css::uno::Any& aSource) override; + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfieldtextinput.cxx b/sw/source/ui/vba/vbaformfieldtextinput.cxx new file mode 100644 index 0000000000..4f78761f4e --- /dev/null +++ b/sw/source/ui/vba/vbaformfieldtextinput.cxx @@ -0,0 +1,130 @@ +/* -*- 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 <ooo/vba/word/WdTextFormFieldType.hpp> + +#include <sal/log.hxx> + +#include "vbaformfieldtextinput.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +/** + * TextInput formfields are inline text objects that are only found in MS Word. + * They cannot be created in Excel or in Calc. + * + * Note that VBA might call this a TextInput, but it might not actually be one, + * so make good use of getValid() + */ +SwVbaFormFieldTextInput::SwVbaFormFieldTextInput( + const uno::Reference<ooo::vba::XHelperInterface>& rParent, + const uno::Reference<uno::XComponentContext>& rContext, sw::mark::IFieldmark& rFormField) + : SwVbaFormFieldTextInput_BASE(rParent, rContext) + , m_rTextInput(rFormField) +{ +} + +SwVbaFormFieldTextInput::~SwVbaFormFieldTextInput() {} + +OUString SwVbaFormFieldTextInput::getDefaultPropertyName() { return "Valid"; } + +sal_Bool SwVbaFormFieldTextInput::getValid() +{ + return IDocumentMarkAccess::GetType(m_rTextInput) + == IDocumentMarkAccess::MarkType::TEXT_FIELDMARK; +} + +OUString SwVbaFormFieldTextInput::getDefault() +{ + if (!getValid()) + return OUString(); + + return m_rTextInput.GetContent(); +} + +void SwVbaFormFieldTextInput::setDefault(const OUString& sSet) +{ + // Hard to know what to do here, since LO doesn't have a default property for text input. + // This really only makes sense when macro-adding a text input. + // In that case, we want it to affect the actual text content. + // However, if the text has already been set by the user, then this shouldn't do anything. + // Assuming this is only ever set when adding a text input seems the sanest approach. + if (!getValid() || getDefault() == sSet) + return; + + m_rTextInput.ReplaceContent(sSet); +} + +OUString SwVbaFormFieldTextInput::getFormat() +{ + if (!getValid()) + return OUString(); + + SAL_INFO("sw.vba", "SwVbaFormFieldTextInput::getFormat stub"); + return OUString(); +} + +sal_Int32 SwVbaFormFieldTextInput::getType() +{ + if (!getValid()) + return word::WdTextFormFieldType::wdRegularText; + + SAL_INFO("sw.vba", "SwVbaFormFieldTextInput::getType stub"); + return word::WdTextFormFieldType::wdRegularText; +} + +sal_Int32 SwVbaFormFieldTextInput::getWidth() +{ + if (!getValid()) + return 0; + + SAL_INFO("sw.vba", "SwVbaFormFieldTextInput::getWidth stub"); + return 11 * 50; +} + +void SwVbaFormFieldTextInput::setWidth(sal_Int32 nWidth) +{ + if (!getValid()) + return; + + SAL_INFO("sw.vba", "SwVbaFormFieldTextInput::setWidth[" << nWidth << "] stub"); +} + +void SwVbaFormFieldTextInput::Clear() +{ + if (!getValid() || m_rTextInput.GetContent().isEmpty()) + return; + + m_rTextInput.ReplaceContent(""); +} + +void SwVbaFormFieldTextInput::EditType(sal_Int32 nType, const uno::Any& rDefault, + const uno::Any& rFormat, const uno::Any& rEnabled) +{ + OUString sDefault; + OUString sFormat; + bool bEnabled = true; + rDefault >>= sDefault; + rFormat >>= sFormat; + rEnabled >>= bEnabled; + SAL_INFO("sw.vba", "SwVbaFormFieldTextInput::EditType[" + << nType << "] sDefault[" << sDefault << "] sFormat[" << sFormat + << "] bEnabled[" << bEnabled << "] stub"); +} + +OUString SwVbaFormFieldTextInput::getServiceImplName() { return "SwVbaFormFieldTextInput"; } + +uno::Sequence<OUString> SwVbaFormFieldTextInput::getServiceNames() +{ + static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.TextInput" }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfieldtextinput.hxx b/sw/source/ui/vba/vbaformfieldtextinput.hxx new file mode 100644 index 0000000000..513cac64de --- /dev/null +++ b/sw/source/ui/vba/vbaformfieldtextinput.hxx @@ -0,0 +1,68 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/word/XTextInput.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +#include <IDocumentMarkAccess.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XTextInput> SwVbaFormFieldTextInput_BASE; + +class SwVbaFormFieldTextInput : public SwVbaFormFieldTextInput_BASE +{ +private: + sw::mark::IFieldmark& m_rTextInput; + +public: + /// @throws css::uno::RuntimeException + SwVbaFormFieldTextInput(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext, + sw::mark::IFieldmark& rFormField); + ~SwVbaFormFieldTextInput() override; + + // XTextInput + OUString SAL_CALL getDefaultPropertyName() override; + + // default member: True if the specified form field object is a valid text form field + sal_Bool SAL_CALL getValid() override; + + // Returns and sets the default text string of the input box + OUString SAL_CALL getDefault() override; + void SAL_CALL setDefault(const OUString& bSet) override; + // Returns the format string for the current text + OUString SAL_CALL getFormat() override; + /* + * Returns the type of text form field. + * Possible return values are: + * wdCalculationText - Calculation text field, + * wdCurrentDateText - Current date text field, + * wdCurrentTimeText - Current time text field, + * wdDateText - Date text field, + * wdNumberText - Number text field, + * wdRegularText - Regular text field. + */ + sal_Int32 SAL_CALL getType() override; + // Returns and sets the width, in points + sal_Int32 SAL_CALL getWidth() override; + void SAL_CALL setWidth(sal_Int32 nSet) override; + + // Deletes the text from the text form field. + void SAL_CALL Clear() override; + // Sets the type, default text string, format string, and enabled status + void SAL_CALL EditType(sal_Int32 nType, const css::uno::Any& rDefault, + const css::uno::Any& rFormat, const css::uno::Any& rEnabled) override; + + // XHelperInterface + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaframe.cxx b/sw/source/ui/vba/vbaframe.cxx new file mode 100644 index 0000000000..b3a0180fb1 --- /dev/null +++ b/sw/source/ui/vba/vbaframe.cxx @@ -0,0 +1,58 @@ +/* -*- 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 "vbaframe.hxx" +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaFrame::SwVbaFrame( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, css::uno::Reference< frame::XModel > xModel, css::uno::Reference< text::XTextFrame > xTextFrame ) : + SwVbaFrame_BASE( rParent, rContext ), mxModel(std::move( xModel )), mxTextFrame(std::move( xTextFrame )) +{ +} + +SwVbaFrame::~SwVbaFrame() +{ +} + +void SAL_CALL SwVbaFrame::Select() +{ + uno::Reference< view::XSelectionSupplier > xSelectSupp( mxModel->getCurrentController(), uno::UNO_QUERY_THROW ); + xSelectSupp->select( uno::Any( mxTextFrame ) ); +} + +OUString +SwVbaFrame::getServiceImplName() +{ + return "SwVbaFrame"; +} + +uno::Sequence< OUString > +SwVbaFrame::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Frame" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaframe.hxx b/sw/source/ui/vba/vbaframe.hxx new file mode 100644 index 0000000000..c24ba4617c --- /dev/null +++ b/sw/source/ui/vba/vbaframe.hxx @@ -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 . + */ +#ifndef INCLUDED_SW_SOURCE_UI_VBA_VBAFRAME_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAFRAME_HXX + +#include <ooo/vba/word/XFrame.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextFrame.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XFrame > SwVbaFrame_BASE; + +class SwVbaFrame : public SwVbaFrame_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::text::XTextFrame > mxTextFrame; + +public: + /// @throws css::uno::RuntimeException + SwVbaFrame( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::frame::XModel > xModel, css::uno::Reference< css::text::XTextFrame > xTextFrame ); + virtual ~SwVbaFrame() override; + + // Methods + virtual void SAL_CALL Select() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAFRAME_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaframes.cxx b/sw/source/ui/vba/vbaframes.cxx new file mode 100644 index 0000000000..376082054b --- /dev/null +++ b/sw/source/ui/vba/vbaframes.cxx @@ -0,0 +1,100 @@ +/* -*- 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 "vbaframes.hxx" +#include "vbaframe.hxx" +#include <com/sun/star/frame/XModel.hpp> +#include <cppuhelper/implbase.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +class FramesEnumeration : public ::cppu::WeakImplHelper< container::XEnumeration > +{ +private: + uno::Reference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< container::XIndexAccess> mxIndexAccess; + uno::Reference< frame::XModel > mxModel; + sal_Int32 mnCurrentPos; +public: + /// @throws uno::RuntimeException + FramesEnumeration( uno::Reference< XHelperInterface > xParent, uno::Reference< uno::XComponentContext > xContext, uno::Reference< container::XIndexAccess > xIndexAccess, uno::Reference< frame::XModel > xModel ) : mxParent(std::move( xParent )), mxContext(std::move( xContext)), mxIndexAccess(std::move( xIndexAccess )), mxModel(std::move( xModel )), mnCurrentPos(0) + { + } + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( mnCurrentPos < mxIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( !hasMoreElements() ) + throw container::NoSuchElementException(); + uno::Reference< text::XTextFrame > xTextFrame( mxIndexAccess->getByIndex( mnCurrentPos++ ), uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< word::XFrame > ( new SwVbaFrame( mxParent, mxContext, mxModel, xTextFrame ) ) ); + } + +}; + +} + +SwVbaFrames::SwVbaFrames( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< container::XIndexAccess >& xFrames, uno::Reference< frame::XModel > xModel ): SwVbaFrames_BASE( xParent, xContext, xFrames ), mxModel(std::move( xModel )) +{ + mxFramesSupplier.set( mxModel, uno::UNO_QUERY_THROW ); +} +// XEnumerationAccess +uno::Type +SwVbaFrames::getElementType() +{ + return cppu::UnoType<word::XFrame>::get(); +} + +uno::Reference< container::XEnumeration > +SwVbaFrames::createEnumeration() +{ + return new FramesEnumeration( this, mxContext,m_xIndexAccess, mxModel ); +} + +uno::Any +SwVbaFrames::createCollectionObject( const css::uno::Any& aSource ) +{ + uno::Reference< text::XTextFrame > xTextFrame( aSource, uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< word::XFrame > ( new SwVbaFrame( this, mxContext, mxModel, xTextFrame ) ) ); +} + +OUString +SwVbaFrames::getServiceImplName() +{ + return "SwVbaFrames"; +} + +css::uno::Sequence<OUString> +SwVbaFrames::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.Frames" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaframes.hxx b/sw/source/ui/vba/vbaframes.hxx new file mode 100644 index 0000000000..6a0c20c3db --- /dev/null +++ b/sw/source/ui/vba/vbaframes.hxx @@ -0,0 +1,50 @@ +/* -*- 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_VBA_VBAFRAMES_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAFRAMES_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XFrames.hpp> +#include <com/sun/star/text/XTextFramesSupplier.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XFrames > SwVbaFrames_BASE; + +class SwVbaFrames : public SwVbaFrames_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::text::XTextFramesSupplier > mxFramesSupplier; + +public: + SwVbaFrames( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::container::XIndexAccess >& xFrames, css::uno::Reference< css::frame::XModel > xModel ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaFrames_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAFRAMES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaglobals.cxx b/sw/source/ui/vba/vbaglobals.cxx new file mode 100644 index 0000000000..3e9f7dbefe --- /dev/null +++ b/sw/source/ui/vba/vbaglobals.cxx @@ -0,0 +1,224 @@ +/* -*- 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 "vbaglobals.hxx" +#include "vbawordbasic.hxx" +#include <sal/log.hxx> + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <comphelper/sequence.hxx> + +#include "vbaapplication.hxx" +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::ooo::vba; + +SwVbaGlobals::SwVbaGlobals( uno::Sequence< uno::Any > const& aArgs, uno::Reference< uno::XComponentContext >const& rxContext ) : SwVbaGlobals_BASE( uno::Reference< XHelperInterface >(), rxContext, "WordDocumentContext" ) +{ + SAL_INFO("sw.vba", "SwVbaGlobals::SwVbaGlobals()"); + uno::Sequence< beans::PropertyValue > aInitArgs( aArgs.hasElements() ? 2 : 1 ); + auto pInitArgs = aInitArgs.getArray(); + pInitArgs[ 0 ].Name = "Application"; + pInitArgs[ 0 ].Value <<= getApplication(); + if ( aArgs.hasElements() ) + { + pInitArgs[ 1 ].Name = "WordDocumentContext"; + pInitArgs[ 1 ].Value <<= getXSomethingFromArgs< frame::XModel >( aArgs, 0 ); + } + init( aInitArgs ); +} + +SwVbaGlobals::~SwVbaGlobals() +{ + SAL_INFO("sw.vba", "SwVbaGlobals::~SwVbaGlobals"); +} + +// XGlobals + +uno::Reference<word::XApplication > const & +SwVbaGlobals::getApplication() +{ + SAL_INFO("sw.vba", "In SwVbaGlobals::getApplication"); + if ( !mxApplication.is() ) + mxApplication.set( new SwVbaApplication( mxContext) ); + + return mxApplication; +} + +uno::Reference<word::XSystem > SAL_CALL +SwVbaGlobals::getSystem() +{ + return getApplication()->getSystem(); +} + +uno::Reference< word::XDocument > SAL_CALL +SwVbaGlobals::getActiveDocument() +{ + return getApplication()->getActiveDocument(); +} + +uno::Reference< word::XWindow > SAL_CALL +SwVbaGlobals::getActiveWindow() +{ + return getApplication()->getActiveWindow(); +} + +OUString SAL_CALL +SwVbaGlobals::getName() +{ + return getApplication()->getName(); +} + +uno::Reference<word::XOptions > SAL_CALL +SwVbaGlobals::getOptions() +{ + return getApplication()->getOptions(); +} + +uno::Any SAL_CALL +SwVbaGlobals::CommandBars( const uno::Any& aIndex ) +{ + return getApplication()->CommandBars( aIndex ); +} + +uno::Any SAL_CALL +SwVbaGlobals::Documents( const uno::Any& index ) +{ + return getApplication()->Documents( index ); +} + +uno::Any SAL_CALL +SwVbaGlobals::Addins( const uno::Any& index ) +{ + return getApplication()->Addins( index ); +} + +uno::Any SAL_CALL +SwVbaGlobals::Dialogs( const uno::Any& index ) +{ + return getApplication()->Dialogs( index ); +} + +uno::Any SAL_CALL +SwVbaGlobals::ListGalleries( const uno::Any& index ) +{ + return getApplication()->ListGalleries( index ); +} + +uno::Reference<word::XSelection > SAL_CALL +SwVbaGlobals::getSelection() +{ + return getApplication()->getSelection(); +} + +uno::Reference<word::XGlobals> SwVbaGlobals::getWord() +{ + return uno::Reference<word::XGlobals>(this); +} + +uno::Reference<word::XWordBasic> SAL_CALL SwVbaGlobals::getWordBasic() +{ + assert(dynamic_cast<SwVbaApplication*>(getApplication().get())); + SwVbaApplication* pVbaApp = static_cast<SwVbaApplication*>(getApplication().get()); + uno::Reference<word::XWordBasic> xWB(new SwWordBasic(pVbaApp)); + return xWB; +} + +float SAL_CALL SwVbaGlobals::CentimetersToPoints( float Centimeters ) +{ + return getApplication()->CentimetersToPoints( Centimeters ); +} + +float SAL_CALL SwVbaGlobals::PointsToCentimeters( float Points ) +{ + return getApplication()->PointsToCentimeters( Points ); +} + +float SAL_CALL SwVbaGlobals::PixelsToPoints( float Pixels, ::sal_Bool fVertical ) +{ + return getApplication()->PixelsToPoints( Pixels, fVertical ); +} + +float SAL_CALL SwVbaGlobals::PointsToPixels( float Points, ::sal_Bool fVertical ) +{ + return getApplication()->PointsToPixels( Points, fVertical ); +} + +float SAL_CALL SwVbaGlobals::InchesToPoints( float Inches ) +{ + return getApplication()->InchesToPoints( Inches ); +} + +float SAL_CALL SwVbaGlobals::PointsToInches( float Points ) +{ + return getApplication()->PointsToInches( Points ); +} + +float SAL_CALL SwVbaGlobals::MillimetersToPoints( float Millimeters ) +{ + return getApplication()->MillimetersToPoints( Millimeters ); +} + +float SAL_CALL SwVbaGlobals::PointsToMillimeters( float Points ) +{ + return getApplication()->PointsToMillimeters( Points ); +} + +float SAL_CALL SwVbaGlobals::PicasToPoints( float Picas ) +{ + return getApplication()->PicasToPoints( Picas ); +} + +float SAL_CALL SwVbaGlobals::PointsToPicas( float Points ) +{ + return getApplication()->PointsToPicas( Points ); +} + +OUString +SwVbaGlobals::getServiceImplName() +{ + return "SwVbaGlobals"; +} + +uno::Sequence< OUString > +SwVbaGlobals::getServiceNames() +{ + return { "ooo.vba.word.Globals" }; +} + +uno::Sequence< OUString > +SwVbaGlobals::getAvailableServiceNames( ) +{ + static const uno::Sequence<OUString> serviceNames = comphelper::concatSequences( + SwVbaGlobals_BASE::getAvailableServiceNames(), + uno::Sequence<OUString>{ "ooo.vba.word.Document", + // "ooo.vba.word.Globals", + // "ooo.vba.word.WrapFormat", + "com.sun.star.script.vba.VBATextEventProcessor" }); + return serviceNames; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Writer_SwVbaGlobals_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args) +{ + return cppu::acquire(new SwVbaGlobals(args, context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaglobals.hxx b/sw/source/ui/vba/vbaglobals.hxx new file mode 100644 index 0000000000..c1713502df --- /dev/null +++ b/sw/source/ui/vba/vbaglobals.hxx @@ -0,0 +1,80 @@ +/* -*- 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_VBA_VBAGLOBALS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAGLOBALS_HXX + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <ooo/vba/word/XGlobals.hpp> +#include <ooo/vba/word/XApplication.hpp> +#include <ooo/vba/word/XSystem.hpp> +#include <ooo/vba/word/XOptions.hpp> +#include <ooo/vba/word/XSelection.hpp> +#include <cppuhelper/implbase.hxx> +#include <vbahelper/vbaglobalbase.hxx> + +typedef ::cppu::ImplInheritanceHelper<VbaGlobalsBase, ov::word::XGlobals> SwVbaGlobals_BASE; + +class SwVbaGlobals : public SwVbaGlobals_BASE +{ +private: + css::uno::Reference<ooo::vba::word::XApplication> mxApplication; + + /// @throws css::uno::RuntimeException + css::uno::Reference<ooo::vba::word::XApplication> const& getApplication(); + +public: + SwVbaGlobals(css::uno::Sequence<css::uno::Any> const& aArgs, + css::uno::Reference<css::uno::XComponentContext> const& rxContext); + virtual ~SwVbaGlobals() override; + + // XGlobals + virtual OUString SAL_CALL getName() override; + virtual css::uno::Reference<ooo::vba::word::XSystem> SAL_CALL getSystem() override; + virtual css::uno::Reference<ov::word::XDocument> SAL_CALL getActiveDocument() override; + virtual css::uno::Reference<ov::word::XWindow> SAL_CALL getActiveWindow() override; + virtual css::uno::Reference<ooo::vba::word::XOptions> SAL_CALL getOptions() override; + virtual css::uno::Reference<ooo::vba::word::XSelection> SAL_CALL getSelection() override; + virtual css::uno::Reference<ooo::vba::word::XGlobals> SAL_CALL getWord() override; + virtual css::uno::Reference<ooo::vba::word::XWordBasic> SAL_CALL getWordBasic() override; + virtual css::uno::Any SAL_CALL CommandBars(const css::uno::Any& aIndex) override; + virtual css::uno::Any SAL_CALL Documents(const css::uno::Any& aIndex) override; + virtual css::uno::Any SAL_CALL Addins(const css::uno::Any& aIndex) override; + virtual css::uno::Any SAL_CALL Dialogs(const css::uno::Any& aIndex) override; + virtual css::uno::Any SAL_CALL ListGalleries(const css::uno::Any& aIndex) override; + virtual float SAL_CALL CentimetersToPoints(float Centimeters) override; + virtual float SAL_CALL PointsToCentimeters(float Points) override; + virtual float SAL_CALL PixelsToPoints(float Pixels, ::sal_Bool fVertical) override; + virtual float SAL_CALL PointsToPixels(float Pixels, ::sal_Bool fVertical) override; + virtual float SAL_CALL InchesToPoints(float Inches) override; + virtual float SAL_CALL PointsToInches(float Points) override; + virtual float SAL_CALL MillimetersToPoints(float Millimeters) override; + virtual float SAL_CALL PointsToMillimeters(float Points) override; + virtual float SAL_CALL PicasToPoints(float Picas) override; + virtual float SAL_CALL PointsToPicas(float Points) override; + + // XMultiServiceFactory + virtual css::uno::Sequence<OUString> SAL_CALL getAvailableServiceNames() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAGLOBALS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaheaderfooter.cxx b/sw/source/ui/vba/vbaheaderfooter.cxx new file mode 100644 index 0000000000..a031b0ecda --- /dev/null +++ b/sw/source/ui/vba/vbaheaderfooter.cxx @@ -0,0 +1,102 @@ +/* -*- 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 "vbaheaderfooter.hxx" +#include <ooo/vba/word/WdHeaderFooterIndex.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include "vbarange.hxx" +#include <utility> +#include <vbahelper/vbashapes.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaHeaderFooter::SwVbaHeaderFooter( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< frame::XModel > xModel, uno::Reference< beans::XPropertySet > xProps, bool isHeader, sal_Int32 index ) : SwVbaHeaderFooter_BASE( rParent, rContext ), mxModel(std::move( xModel )), mxPageStyleProps(std::move( xProps )), mbHeader( isHeader ), mnIndex( index ) +{ +} + +sal_Bool SAL_CALL SwVbaHeaderFooter::getIsHeader() +{ + return mbHeader; +} + +sal_Bool SAL_CALL SwVbaHeaderFooter::getLinkToPrevious() +{ + // seems always false + return false; +} + +void SAL_CALL SwVbaHeaderFooter::setLinkToPrevious( sal_Bool /*_linktoprevious*/ ) +{ + // not support in Writer +} + +uno::Reference< word::XRange > SAL_CALL SwVbaHeaderFooter::getRange() +{ + OUString sPropsNameText; + if( mbHeader ) + { + sPropsNameText = "HeaderText"; + } + else + { + sPropsNameText = "FooterText"; + } + if( mnIndex == word::WdHeaderFooterIndex::wdHeaderFooterEvenPages ) + { + sPropsNameText += "Left"; + } + + uno::Reference< text::XText > xText( mxPageStyleProps->getPropertyValue( sPropsNameText ), uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextDocument > xDocument( mxModel, uno::UNO_QUERY_THROW ); + return uno::Reference< word::XRange >( new SwVbaRange( this, mxContext, xDocument, xText->getStart(), xText->getEnd(), xText ) ); +} + +uno::Any SAL_CALL +SwVbaHeaderFooter::Shapes( const uno::Any& index ) +{ + // #FIXME: only get the shapes in the current header/footer + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( mxModel, uno::UNO_QUERY_THROW ); + //uno::Reference< drawing::XShapes > xShapes( xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xCol( new ScVbaShapes( this, mxContext, xIndexAccess, mxModel ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +OUString +SwVbaHeaderFooter::getServiceImplName() +{ + return "SwVbaHeaderFooter"; +} + +uno::Sequence< OUString > +SwVbaHeaderFooter::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Pane" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaheaderfooter.hxx b/sw/source/ui/vba/vbaheaderfooter.hxx new file mode 100644 index 0000000000..7425057b26 --- /dev/null +++ b/sw/source/ui/vba/vbaheaderfooter.hxx @@ -0,0 +1,53 @@ +/* -*- 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_VBA_VBAHEADERFOOTER_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAHEADERFOOTER_HXX + +#include <ooo/vba/word/XHeaderFooter.hpp> +#include <ooo/vba/word/XRange.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XHeaderFooter > SwVbaHeaderFooter_BASE; + +class SwVbaHeaderFooter : public SwVbaHeaderFooter_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::beans::XPropertySet > mxPageStyleProps; + bool mbHeader; + sal_Int32 mnIndex; + +public: + /// @throws css::uno::RuntimeException + SwVbaHeaderFooter( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::frame::XModel > xModel, css::uno::Reference< css::beans::XPropertySet > xProps, bool isHeader, sal_Int32 index ); + + // Attributes + virtual sal_Bool SAL_CALL getIsHeader() override; + virtual sal_Bool SAL_CALL getLinkToPrevious() override; + virtual void SAL_CALL setLinkToPrevious( sal_Bool _linktoprevious ) override; + virtual css::uno::Reference< ::ooo::vba::word::XRange > SAL_CALL getRange() override; + virtual css::uno::Any SAL_CALL Shapes( const css::uno::Any& aIndex ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAHEADERFOOTER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaheaderfooterhelper.cxx b/sw/source/ui/vba/vbaheaderfooterhelper.cxx new file mode 100644 index 0000000000..987088b6a5 --- /dev/null +++ b/sw/source/ui/vba/vbaheaderfooterhelper.cxx @@ -0,0 +1,174 @@ +/* -*- 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 "vbaheaderfooterhelper.hxx" +#include "wordvbahelper.hxx" +#include <com/sun/star/text/XTextRangeCompare.hpp> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/text/XPageCursor.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +#define FIRST_PAGE 1 + +// Class HeaderFooterHelper +bool HeaderFooterHelper::isHeaderFooter( const uno::Reference< frame::XModel >& xModel ) +{ + return isHeaderFooter( word::getCurrentXText( xModel ) ); +} + +bool HeaderFooterHelper::isHeaderFooter( const uno::Reference< text::XText >& xText ) +{ + uno::Reference< lang::XServiceInfo > xServiceInfo( xText, uno::UNO_QUERY_THROW ); + OUString aImplName = xServiceInfo->getImplementationName(); + return aImplName == "SwXHeadFootText"; +} + +bool HeaderFooterHelper::isHeader( const uno::Reference< frame::XModel >& xModel ) +{ + const uno::Reference< text::XText > xCurrentText = word::getCurrentXText( xModel ); + if( !isHeaderFooter( xCurrentText ) ) + return false; + + OUString aPropText = "HeaderText"; + uno::Reference< style::XStyle > xPageStyle = word::getCurrentPageStyle( xModel ); + uno::Reference< beans::XPropertySet > xPageProps( xPageStyle, uno::UNO_QUERY_THROW ); + bool isShared = true; + xPageProps->getPropertyValue( "HeaderIsShared" ) >>= isShared; + if( !isShared ) + { + uno::Reference< text::XPageCursor > xPageCursor( word::getXTextViewCursor( xModel ), uno::UNO_QUERY_THROW ); + if( 0 == xPageCursor->getPage() % 2 ) + aPropText = "HeaderTextLeft"; + else + aPropText = "HeaderTextRight"; + } + + uno::Reference< text::XText > xHeaderText( xPageProps->getPropertyValue( aPropText ), uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextRangeCompare > xTRC( xHeaderText, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextRange > xTR1( xCurrentText, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextRange > xTR2( xHeaderText, uno::UNO_QUERY_THROW ); + try + { + if( xTRC->compareRegionStarts( xTR1, xTR2 ) == 0 ) + return true; + } + catch (const lang::IllegalArgumentException&) + { + return false; + } + + return false; +} + +bool HeaderFooterHelper::isFirstPageHeader( const uno::Reference< frame::XModel >& xModel ) +{ + if( isHeader( xModel ) ) + { + uno::Reference< text::XPageCursor > xPageCursor( word::getXTextViewCursor( xModel ), uno::UNO_QUERY_THROW ); + // FIXME: getPage always returns 1 + sal_Int32 nPage = xPageCursor->getPage(); + return nPage == FIRST_PAGE; + } + return false; +} + +bool HeaderFooterHelper::isEvenPagesHeader( const uno::Reference< frame::XModel >& xModel ) +{ + if( isHeader( xModel ) ) + { + uno::Reference< beans::XPropertySet > xStyleProps( word::getCurrentPageStyle( xModel ), uno::UNO_QUERY_THROW ); + bool isShared = false; + xStyleProps->getPropertyValue("HeaderIsShared") >>= isShared; + if( !isShared ) + { + uno::Reference< text::XPageCursor > xPageCursor( word::getXTextViewCursor( xModel ), uno::UNO_QUERY_THROW ); + return ( 0 == xPageCursor->getPage() % 2 ); + } + } + return false; +} + +bool HeaderFooterHelper::isFooter( const uno::Reference< frame::XModel >& xModel ) +{ + const uno::Reference< text::XText > xCurrentText = word::getCurrentXText( xModel ); + if( !isHeaderFooter( xCurrentText ) ) + return false; + + OUString aPropText = "FooterText"; + uno::Reference< style::XStyle > xPageStyle = word::getCurrentPageStyle( xModel ); + uno::Reference< beans::XPropertySet > xPageProps( xPageStyle, uno::UNO_QUERY_THROW ); + bool isShared = true; + xPageProps->getPropertyValue( "FooterIsShared" ) >>= isShared; + if( !isShared ) + { + uno::Reference< text::XPageCursor > xPageCursor( word::getXTextViewCursor( xModel ), uno::UNO_QUERY_THROW ); + if( 0 == xPageCursor->getPage() % 2 ) + aPropText = "FooterTextLeft"; + else + aPropText = "FooterTextRight"; + } + + uno::Reference< text::XText > xFooterText( xPageProps->getPropertyValue( aPropText ), uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextRangeCompare > xTRC( xFooterText, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextRange > xTR1( xCurrentText, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextRange > xTR2( xFooterText, uno::UNO_QUERY_THROW ); + try + { + if( xTRC->compareRegionStarts( xTR1, xTR2 ) == 0 ) + return true; + } + catch (const lang::IllegalArgumentException&) + { + return false; + } + + return false; +} + +bool HeaderFooterHelper::isFirstPageFooter( const uno::Reference< frame::XModel >& xModel ) +{ + if( isFooter( xModel ) ) + { + uno::Reference< text::XPageCursor > xPageCursor( word::getXTextViewCursor( xModel ), uno::UNO_QUERY_THROW ); + sal_Int32 nPage = xPageCursor->getPage(); + return nPage == FIRST_PAGE; + } + return false; +} + +bool HeaderFooterHelper::isEvenPagesFooter( const uno::Reference< frame::XModel >& xModel ) +{ + if( isFooter( xModel ) ) + { + uno::Reference< beans::XPropertySet > xStyleProps( word::getCurrentPageStyle( xModel ), uno::UNO_QUERY_THROW ); + bool isShared = false; + xStyleProps->getPropertyValue("FooterIsShared") >>= isShared; + if( !isShared ) + { + uno::Reference< text::XPageCursor > xPageCursor( word::getXTextViewCursor( xModel ), uno::UNO_QUERY_THROW ); + return ( 0 == xPageCursor->getPage() % 2 ); + } + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaheaderfooterhelper.hxx b/sw/source/ui/vba/vbaheaderfooterhelper.hxx new file mode 100644 index 0000000000..ca66b208ad --- /dev/null +++ b/sw/source/ui/vba/vbaheaderfooterhelper.hxx @@ -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 . + */ +#ifndef INCLUDED_SW_SOURCE_UI_VBA_VBAHEADERFOOTERHELPER_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAHEADERFOOTERHELPER_HXX + +#include <vbahelper/vbahelper.hxx> +#include <com/sun/star/text/XText.hpp> + +class HeaderFooterHelper +{ +public: + /// @throws css::uno::RuntimeException + static bool isHeaderFooter(const css::uno::Reference<css::frame::XModel>& xModel); + /// @throws css::uno::RuntimeException + static bool isHeaderFooter(const css::uno::Reference<css::text::XText>& xText); + /// @throws css::uno::RuntimeException + static bool isHeader(const css::uno::Reference<css::frame::XModel>& xModel); + /// @throws css::uno::RuntimeException + static bool isFirstPageHeader(const css::uno::Reference<css::frame::XModel>& xModel); + /// @throws css::uno::RuntimeException + static bool isEvenPagesHeader(const css::uno::Reference<css::frame::XModel>& xModel); + /// @throws css::uno::RuntimeException + static bool isFooter(const css::uno::Reference<css::frame::XModel>& xModel); + /// @throws css::uno::RuntimeException + static bool isFirstPageFooter(const css::uno::Reference<css::frame::XModel>& xModel); + /// @throws css::uno::RuntimeException + static bool isEvenPagesFooter(const css::uno::Reference<css::frame::XModel>& xModel); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaheadersfooters.cxx b/sw/source/ui/vba/vbaheadersfooters.cxx new file mode 100644 index 0000000000..be205d8e13 --- /dev/null +++ b/sw/source/ui/vba/vbaheadersfooters.cxx @@ -0,0 +1,141 @@ +/* -*- 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 "vbaheadersfooters.hxx" +#include "vbaheaderfooter.hxx" +#include <cppuhelper/implbase.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +// I assume there is only one headersfooters in Writer +class HeadersFootersIndexAccess : public ::cppu::WeakImplHelper<container::XIndexAccess > +{ +private: + uno::Reference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< frame::XModel > mxModel; + uno::Reference< beans::XPropertySet > mxPageStyleProps; + bool mbHeader; + +public: + HeadersFootersIndexAccess( uno::Reference< XHelperInterface > xParent, uno::Reference< uno::XComponentContext > xContext, uno::Reference< frame::XModel > xModel, uno::Reference< beans::XPropertySet > xPageStyleProps, bool bHeader ) : mxParent(std::move( xParent )), mxContext(std::move( xContext )), mxModel(std::move( xModel )), mxPageStyleProps(std::move( xPageStyleProps )), mbHeader( bHeader ) {} + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount( ) override + { + // first page, even pages and primary page + return 3; + } + virtual uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override + { + if( Index < 1 || Index > 3 ) + throw lang::IndexOutOfBoundsException(); + return uno::Any( uno::Reference< word::XHeaderFooter >( new SwVbaHeaderFooter( mxParent, mxContext, mxModel, mxPageStyleProps, mbHeader, Index ) ) ); + } + virtual uno::Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<word::XHeaderFooter>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + return true; + } +}; + +class HeadersFootersEnumWrapper : public EnumerationHelper_BASE +{ + SwVbaHeadersFooters* m_pHeadersFooters; + sal_Int32 m_nIndex; +public: + explicit HeadersFootersEnumWrapper( SwVbaHeadersFooters* _pHeadersFooters ) : m_pHeadersFooters( _pHeadersFooters ), m_nIndex( 0 ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( m_nIndex < m_pHeadersFooters->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( m_nIndex < m_pHeadersFooters->getCount() ) + return m_pHeadersFooters->Item( uno::Any( ++m_nIndex ), uno::Any() ); + throw container::NoSuchElementException(); + } +}; + +} + +SwVbaHeadersFooters::SwVbaHeadersFooters( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< frame::XModel >& xModel, const uno::Reference< beans::XPropertySet >& xPageStyleProps, bool isHeader ): SwVbaHeadersFooters_BASE( xParent, xContext, new HeadersFootersIndexAccess( xParent, xContext, xModel, xPageStyleProps, isHeader ) ), mxModel( xModel ), mxPageStyleProps( xPageStyleProps ), mbHeader( isHeader ) +{ +} + +::sal_Int32 SAL_CALL SwVbaHeadersFooters::getCount() +{ + // wdHeaderFooterFirstPage, wdHeaderFooterPrimary and wdHeaderFooterEvenPages + return 3; +} + +uno::Any SAL_CALL SwVbaHeadersFooters::Item( const uno::Any& Index1, const uno::Any& ) +{ + sal_Int32 nIndex = 0; + Index1 >>= nIndex; + if( ( nIndex < 1 ) || ( nIndex > 3 ) ) + { + throw lang::IndexOutOfBoundsException(); + } + return uno::Any( uno::Reference< word::XHeaderFooter >( new SwVbaHeaderFooter( this, mxContext, mxModel, mxPageStyleProps, mbHeader, nIndex ) ) ); +} + +// XEnumerationAccess +uno::Type +SwVbaHeadersFooters::getElementType() +{ + return cppu::UnoType<word::XHeaderFooter>::get(); +} +uno::Reference< container::XEnumeration > + +SwVbaHeadersFooters::createEnumeration() +{ + return new HeadersFootersEnumWrapper( this ); +} + +uno::Any +SwVbaHeadersFooters::createCollectionObject( const uno::Any& aSource ) +{ + return aSource; +} + +OUString +SwVbaHeadersFooters::getServiceImplName() +{ + return "SwVbaHeadersFooters"; +} + +uno::Sequence<OUString> +SwVbaHeadersFooters::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.HeadersFooters" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaheadersfooters.hxx b/sw/source/ui/vba/vbaheadersfooters.hxx new file mode 100644 index 0000000000..44aa77cfde --- /dev/null +++ b/sw/source/ui/vba/vbaheadersfooters.hxx @@ -0,0 +1,51 @@ +/* -*- 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_VBA_VBAHEADERSFOOTERS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAHEADERSFOOTERS_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XHeadersFooters.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XHeadersFooters > SwVbaHeadersFooters_BASE; + +class SwVbaHeadersFooters : public SwVbaHeadersFooters_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::beans::XPropertySet > mxPageStyleProps; + bool mbHeader; + +public: + SwVbaHeadersFooters( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, const css::uno::Reference< css::frame::XModel >& xModel, const css::uno::Reference< css::beans::XPropertySet >& xProps, bool isHeader ); + + virtual ::sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index1, const css::uno::Any& ) override; + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaHeadersFooters_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAHEADERSFOOTERS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbainformationhelper.cxx b/sw/source/ui/vba/vbainformationhelper.cxx new file mode 100644 index 0000000000..9cda14b7b2 --- /dev/null +++ b/sw/source/ui/vba/vbainformationhelper.cxx @@ -0,0 +1,66 @@ +/* -*- 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 "vbainformationhelper.hxx" +#include <com/sun/star/text/XPageCursor.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <tools/UnitConversion.hxx> +#include "wordvbahelper.hxx" +#include <docsh.hxx> +#include <doc.hxx> +#include <vbahelper/vbahelper.hxx> +#include <viewsh.hxx> +#include <IDocumentLayoutAccess.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +const sal_Int32 DEFAULT_PAGE_DISTANCE = 500; + +sal_Int32 SwVbaInformationHelper::handleWdActiveEndPageNumber( const css::uno::Reference< css::text::XTextViewCursor >& xTVCursor ) +{ + uno::Reference< text::XPageCursor > xPageCursor( xTVCursor, uno::UNO_QUERY_THROW ); + return xPageCursor->getPage(); +} + +sal_Int32 SwVbaInformationHelper::handleWdNumberOfPagesInDocument( const css::uno::Reference< css::frame::XModel >& xModel ) +{ + return word::getPageCount( xModel ); +} + +double SwVbaInformationHelper::handleWdVerticalPositionRelativeToPage( const css::uno::Reference< css::frame::XModel >& xModel, const css::uno::Reference< css::text::XTextViewCursor >& xTVCursor ) +{ + xTVCursor->collapseToStart(); + uno::Reference< beans::XPropertySet > xStyleProps( word::getCurrentPageStyle( xModel ), uno::UNO_QUERY_THROW ); + sal_Int32 nTopMargin = 0; + xStyleProps->getPropertyValue( "TopMargin" ) >>= nTopMargin; + sal_Int32 nCurrentPos = xTVCursor->getPosition().Y; + + sal_Int32 nCurrentPage = handleWdActiveEndPageNumber( xTVCursor ); + SwDoc* pDoc = word::getDocShell( xModel )->GetDoc(); + SwViewShell* pViewSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell(); + sal_Int32 nPageHeight = pViewSh ? pViewSh->GetPageSize( nCurrentPage, false ).Height() : 0; + // FIXME: handle multiple page style + // it is very strange that the cursor position is incorrect when open Word file. + // e.g. if current cursor in the top left of the text body of the first page without header, + // the top value of current position should be 0, but is 201 when open a Word file. + nCurrentPos = nCurrentPos + nTopMargin - ( DEFAULT_PAGE_DISTANCE + convertTwipToMm100( nPageHeight ) ) * ( nCurrentPage - 1 ); + return Millimeter::getInPoints( nCurrentPos ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbainformationhelper.hxx b/sw/source/ui/vba/vbainformationhelper.hxx new file mode 100644 index 0000000000..c60b300cd4 --- /dev/null +++ b/sw/source/ui/vba/vbainformationhelper.hxx @@ -0,0 +1,42 @@ +/* -*- 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_VBA_VBAINFORMATIONHELPER_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAINFORMATIONHELPER_HXX + +#include <com/sun/star/text/XTextViewCursor.hpp> +#include <com/sun/star/frame/XModel.hpp> + +class SwVbaInformationHelper +{ +public: + /// @throws css::uno::RuntimeException + static sal_Int32 + handleWdActiveEndPageNumber(const css::uno::Reference<css::text::XTextViewCursor>& xTVCursor); + /// @throws css::uno::RuntimeException + static sal_Int32 + handleWdNumberOfPagesInDocument(const css::uno::Reference<css::frame::XModel>& xModel); + /// @throws css::uno::RuntimeException + static double handleWdVerticalPositionRelativeToPage( + const css::uno::Reference<css::frame::XModel>& xModel, + const css::uno::Reference<css::text::XTextViewCursor>& xTVCursor); + //static double verticalPositionRelativeToPageBoundary( const css::uno::Reference< css::frame::XModel >& xModel, const css::uno::Reference< css::text::XTextViewCursor >& xTVCursor, const css::uno::Reference< css::beans::XPropertySet >& xStyleProps ) throw( css::uno::RuntimeException ); +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAINFORMATIONHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalistformat.cxx b/sw/source/ui/vba/vbalistformat.cxx new file mode 100644 index 0000000000..efcbf2dbe8 --- /dev/null +++ b/sw/source/ui/vba/vbalistformat.cxx @@ -0,0 +1,328 @@ +/* -*- 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 "vbalistformat.hxx" +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include <ooo/vba/word/WdListApplyTo.hpp> +#include <ooo/vba/word/WdDefaultListBehavior.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/document/XUndoManagerSupplier.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/style/TabStop.hpp> +#include <com/sun/star/text/PositionAndSpaceMode.hpp> +#include <com/sun/star/text/XTextTable.hpp> +#include <com/sun/star/util/Color.hpp> +#include <comphelper/sequence.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <comphelper/scopeguard.hxx> +#include <editeng/numitem.hxx> +#include "vbalisttemplate.hxx" + +#include <vector> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaListFormat::SwVbaListFormat( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< text::XTextRange > xTextRange ) : SwVbaListFormat_BASE( rParent, rContext ), mxTextRange(std::move( xTextRange )) +{ +} + +SwVbaListFormat::~SwVbaListFormat() +{ +} + +void SAL_CALL SwVbaListFormat::ApplyListTemplate( const css::uno::Reference< word::XListTemplate >& ListTemplate, const css::uno::Any& ContinuePreviousList, const css::uno::Any& ApplyTo, const css::uno::Any& DefaultListBehavior ) +{ + bool bContinuePreviousList = true; + if( ContinuePreviousList.hasValue() ) + ContinuePreviousList >>= bContinuePreviousList; + + // "applyto" must be current selection + sal_Int32 bApplyTo = word::WdListApplyTo::wdListApplyToSelection; + if( ApplyTo.hasValue() ) + ApplyTo >>= bApplyTo; + if( bApplyTo != word::WdListApplyTo::wdListApplyToSelection ) + throw uno::RuntimeException(); + + // default behaviour must be wdWord8ListBehavior + sal_Int32 nDefaultListBehavior = word::WdDefaultListBehavior::wdWord8ListBehavior; + if( DefaultListBehavior.hasValue() ) + DefaultListBehavior >>= nDefaultListBehavior; + if( nDefaultListBehavior != word::WdDefaultListBehavior::wdWord8ListBehavior ) + throw uno::RuntimeException(); + + uno::Reference< container::XEnumerationAccess > xEnumAccess( mxTextRange, uno::UNO_QUERY_THROW ); + uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration(); + if (!xEnum->hasMoreElements()) + return; + + SwVbaListTemplate& rListTemplate = dynamic_cast<SwVbaListTemplate&>(*ListTemplate); + + bool isFirstElement = true; + do + { + uno::Reference< beans::XPropertySet > xProps( xEnum->nextElement(), uno::UNO_QUERY_THROW ); + if( isFirstElement ) + { + bool isNumberingRestart = !bContinuePreviousList; + xProps->setPropertyValue("ParaIsNumberingRestart", uno::Any( isNumberingRestart ) ); + if( isNumberingRestart ) + { + xProps->setPropertyValue("NumberingStartValue", uno::Any( sal_Int16(1) ) ); + } + isFirstElement = false; + } + else + { + xProps->setPropertyValue("ParaIsNumberingRestart", uno::Any( false ) ); + } + rListTemplate.applyListTemplate( xProps ); + } + while( xEnum->hasMoreElements() ); +} + +template <class Ref> +static void addParagraphsToList(const Ref& a, + std::vector<css::uno::Reference<css::beans::XPropertySet>>& rList) +{ + if (css::uno::Reference<css::lang::XServiceInfo> xInfo{ a, css::uno::UNO_QUERY }) + { + if (xInfo->supportsService("com.sun.star.text.Paragraph")) + { + rList.emplace_back(xInfo, css::uno::UNO_QUERY_THROW); + } + else if (xInfo->supportsService("com.sun.star.text.TextTable")) + { + css::uno::Reference<css::text::XTextTable> xTable(xInfo, css::uno::UNO_QUERY_THROW); + const auto aNames = xTable->getCellNames(); + for (const auto& rName : aNames) + { + addParagraphsToList(xTable->getCellByName(rName), rList); + } + } + } + if (css::uno::Reference<css::container::XEnumerationAccess> xEnumAccess{ a, + css::uno::UNO_QUERY }) + { + auto xEnum = xEnumAccess->createEnumeration(); + while (xEnum->hasMoreElements()) + addParagraphsToList(xEnum->nextElement(), rList); + } +} + +void SAL_CALL SwVbaListFormat::ConvertNumbersToText( ) +{ + css::uno::Reference<css::frame::XModel> xModel(getThisWordDoc(mxContext)); + css::uno::Reference<css::document::XUndoManagerSupplier> xUndoSupplier( + xModel, css::uno::UNO_QUERY_THROW); + css::uno::Reference<css::document::XUndoManager> xUndoManager(xUndoSupplier->getUndoManager()); + xUndoManager->enterUndoContext("ConvertNumbersToText"); + xModel->lockControllers(); + comphelper::ScopeGuard g([xModel, xUndoManager]() { + xModel->unlockControllers(); + xUndoManager->leaveUndoContext(); + }); + + std::vector<css::uno::Reference<css::beans::XPropertySet>> aParagraphs; + addParagraphsToList(mxTextRange, aParagraphs); + + // in reverse order, to get proper label strings + for (auto iter = aParagraphs.rbegin(); iter != aParagraphs.rend(); ++iter) + { + auto& rPropertySet = *iter; + if (bool bNumber; (rPropertySet->getPropertyValue("NumberingIsNumber") >>= bNumber) && bNumber) + { + css::uno::Reference<css::text::XTextRange> xRange(rPropertySet, css::uno::UNO_QUERY_THROW); + OUString sLabelString; + rPropertySet->getPropertyValue("ListLabelString") >>= sLabelString; + // sal_Int16 nAdjust = SAL_MAX_INT16; // TODO? + sal_Int16 nNumberingType = SAL_MAX_INT16; // css::style::NumberingType + sal_Int16 nPositionAndSpaceMode = SAL_MAX_INT16; + sal_Int16 nLabelFollowedBy = SAL_MAX_INT16; + sal_Int32 nListtabStopPosition = SAL_MAX_INT32; + sal_Int32 nFirstLineIndent = SAL_MAX_INT32; + sal_Int32 nIndentAt = SAL_MAX_INT32; + sal_Int32 nLeftMargin = SAL_MAX_INT32; + sal_Int32 nSymbolTextDistance = SAL_MAX_INT32; + sal_Int32 nFirstLineOffset = SAL_MAX_INT32; + OUString sCharStyleName, sBulletChar; + css::awt::FontDescriptor aBulletFont; + bool bHasFont; + css::util::Color aBulletColor = css::util::Color(COL_AUTO); + bool bHasColor; + + { + sal_uInt16 nLevel = SAL_MAX_UINT16; + rPropertySet->getPropertyValue("NumberingLevel") >>= nLevel; + css::uno::Reference<css::container::XIndexAccess> xNumberingRules; + rPropertySet->getPropertyValue("NumberingRules") >>= xNumberingRules; + comphelper::SequenceAsHashMap aLevelRule(xNumberingRules->getByIndex(nLevel)); + + // See offapi/com/sun/star/text/NumberingLevel.idl + aLevelRule["CharStyleName"] >>= sCharStyleName; + aLevelRule["NumberingType"] >>= nNumberingType; + // TODO: aLevelRule["Adjust"] >>= nAdjust; // HoriOrientation::LEFT/RIGHT/CENTER + aLevelRule["PositionAndSpaceMode"] >>= nPositionAndSpaceMode; + + // for css::text::PositionAndSpaceMode::LABEL_ALIGNMENT + aLevelRule["LabelFollowedBy"] >>= nLabelFollowedBy; + aLevelRule["ListtabStopPosition"] >>= nListtabStopPosition; + aLevelRule["FirstLineIndent"] >>= nFirstLineIndent; + aLevelRule["IndentAt"] >>= nIndentAt; + + // for css::text::PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION + aLevelRule["LeftMargin"] >>= nLeftMargin; + aLevelRule["SymbolTextDistance"] >>= nSymbolTextDistance; + aLevelRule["FirstLineOffset"] >>= nFirstLineOffset; + + aLevelRule["BulletChar"] >>= sBulletChar; + bHasFont = (aLevelRule["BulletFont"] >>= aBulletFont); + bHasColor = (aLevelRule["BulletColor"] >>= aBulletColor); + } + + if (nNumberingType != css::style::NumberingType::BITMAP) // TODO + { + if (nPositionAndSpaceMode + == css::text::PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION) + { + nIndentAt = nLeftMargin; + nFirstLineIndent = nFirstLineOffset; + nListtabStopPosition = nSymbolTextDistance; + nLabelFollowedBy = SvxNumberFormat::LabelFollowedBy::LISTTAB; + } + + switch (nLabelFollowedBy) + { + case SvxNumberFormat::LabelFollowedBy::LISTTAB: + sLabelString += "\t"; + break; + case SvxNumberFormat::LabelFollowedBy::SPACE: + sLabelString += " "; + break; + case SvxNumberFormat::LabelFollowedBy::NEWLINE: + sLabelString += "\n"; + break; + } + + css::uno::Reference<css::text::XTextRange> xNumberText(xRange->getStart()); + xNumberText->setString(sLabelString); + css::uno::Reference<css::beans::XPropertySet> xNumberProps( + xNumberText, css::uno::UNO_QUERY_THROW); + if (!sCharStyleName.isEmpty()) + xNumberProps->setPropertyValue("CharStyleName", css::uno::Any(sCharStyleName)); + + if (nNumberingType == css::style::NumberingType::CHAR_SPECIAL) + { + css::uno::Reference<css::text::XTextRange> xBulletText(xNumberText->getStart()); + xBulletText->setString(sBulletChar); + + std::unordered_map<OUString, css::uno::Any> aNameValues; + if (bHasFont) + { + aNameValues.insert({ + { "CharFontName", css::uno::Any(aBulletFont.Name) }, + { "CharFontStyleName", css::uno::Any(aBulletFont.StyleName) }, + { "CharFontFamily", css::uno::Any(aBulletFont.Family) }, + { "CharFontCharSet", css::uno::Any(aBulletFont.CharSet) }, + { "CharWeight", css::uno::Any(aBulletFont.Weight) }, + { "CharUnderline", css::uno::Any(aBulletFont.Underline) }, + { "CharStrikeout", css::uno::Any(aBulletFont.Strikeout) }, + { "CharAutoKerning", css::uno::Any(aBulletFont.Kerning) }, + { "CharFontPitch", css::uno::Any(aBulletFont.Pitch) }, + { "CharWordMode", css::uno::Any(aBulletFont.WordLineMode) }, + { "CharRotation", css::uno::Any(static_cast<sal_Int16>( + std::round(aBulletFont.Orientation * 10))) }, + }); + if (aBulletFont.Height) + aNameValues["CharHeight"] <<= aBulletFont.Height; + } + if (bHasColor) + { + aNameValues["CharColor"] <<= aBulletColor; + } + + if (css::uno::Reference<css::beans::XMultiPropertySet> xBulletMultiProps{ + xBulletText, css::uno::UNO_QUERY }) + { + xBulletMultiProps->setPropertyValues( + comphelper::mapKeysToSequence(aNameValues), + comphelper::mapValuesToSequence(aNameValues)); + } + else + { + css::uno::Reference<css::beans::XPropertySet> xBulletProps( + xBulletText, css::uno::UNO_QUERY_THROW); + for (const auto& [rName, rVal] : aNameValues) + xBulletProps->setPropertyValue(rName, rVal); + } + } + else + { + // TODO: css::style::NumberingType::BITMAP + } + + rPropertySet->setPropertyValue("ParaLeftMargin", css::uno::Any(nIndentAt)); + rPropertySet->setPropertyValue("ParaFirstLineIndent", css::uno::Any(nFirstLineIndent)); + if (nLabelFollowedBy == SvxNumberFormat::LabelFollowedBy::LISTTAB) + { + css::uno::Sequence<css::style::TabStop> stops; + rPropertySet->getPropertyValue("ParaTabStops") >>= stops; + css::style::TabStop tabStop{}; + tabStop.Position = nListtabStopPosition; + tabStop.Alignment = com::sun::star::style::TabAlign::TabAlign_LEFT; + tabStop.FillChar = ' '; + rPropertySet->setPropertyValue("ParaTabStops", + css::uno::Any(comphelper::combineSequences({ tabStop }, stops))); + // FIXME: What if added tap stop is greater than already defined ones? + } + } + else + { + continue; // for now, keep such lists as is + } + + // In case of higher outline levels, each assignment of empty value just sets level 1 + while (rPropertySet->getPropertyValue("NumberingRules") != css::uno::Any()) + { + rPropertySet->setPropertyValue("NumberingRules", css::uno::Any()); + } + } + } +} + +OUString +SwVbaListFormat::getServiceImplName() +{ + return "SwVbaListFormat"; +} + +uno::Sequence< OUString > +SwVbaListFormat::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.ListFormat" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalistformat.hxx b/sw/source/ui/vba/vbalistformat.hxx new file mode 100644 index 0000000000..378a42fd62 --- /dev/null +++ b/sw/source/ui/vba/vbalistformat.hxx @@ -0,0 +1,49 @@ +/* -*- 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_VBA_VBALISTFORMAT_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBALISTFORMAT_HXX + +#include <ooo/vba/word/XListFormat.hpp> +#include <ooo/vba/word/XListTemplate.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextRange.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XListFormat > SwVbaListFormat_BASE; + +class SwVbaListFormat : public SwVbaListFormat_BASE +{ +private: + css::uno::Reference< css::text::XTextRange > mxTextRange; + +public: + /// @throws css::uno::RuntimeException + SwVbaListFormat( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::text::XTextRange > xTextRange ); + virtual ~SwVbaListFormat() override; + + // Methods + virtual void SAL_CALL ApplyListTemplate( const css::uno::Reference< ::ooo::vba::word::XListTemplate >& ListTemplate, const css::uno::Any& ContinuePreviousList, const css::uno::Any& ApplyTo, const css::uno::Any& DefaultListBehavior ) override; + virtual void SAL_CALL ConvertNumbersToText( ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBALISTFORMAT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalistgalleries.cxx b/sw/source/ui/vba/vbalistgalleries.cxx new file mode 100644 index 0000000000..9c047b1b64 --- /dev/null +++ b/sw/source/ui/vba/vbalistgalleries.cxx @@ -0,0 +1,108 @@ +/* -*- 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 "vbalistgalleries.hxx" +#include "vbalistgallery.hxx" +#include <ooo/vba/word/WdListGalleryType.hpp> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +class ListGalleriesEnumWrapper : public EnumerationHelper_BASE +{ + SwVbaListGalleries* m_pListGalleries; + sal_Int32 m_nIndex; +public: + explicit ListGalleriesEnumWrapper( SwVbaListGalleries* pGalleries ) : m_pListGalleries( pGalleries ), m_nIndex( 1 ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( m_nIndex <= m_pListGalleries->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( m_nIndex <= m_pListGalleries->getCount() ) + return m_pListGalleries->Item( uno::Any( m_nIndex++ ), uno::Any() ); + throw container::NoSuchElementException(); + } +}; + +} + +SwVbaListGalleries::SwVbaListGalleries( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, uno::Reference< text::XTextDocument > xTextDoc ) : SwVbaListGalleries_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >() ), mxTextDocument(std::move( xTextDoc )) +{ +} + +::sal_Int32 SAL_CALL SwVbaListGalleries::getCount() +{ + // 3 types of list( bullet, numbered and outline ) + return 3; +} + +uno::Any SAL_CALL SwVbaListGalleries::Item( const uno::Any& Index1, const uno::Any& /*not processed in this base class*/ ) +{ + sal_Int32 nIndex = 0; + if( Index1 >>= nIndex ) + { + if( nIndex == word::WdListGalleryType::wdBulletGallery + || nIndex == word::WdListGalleryType::wdNumberGallery + || nIndex == word::WdListGalleryType::wdOutlineNumberGallery ) + return uno::Any( uno::Reference< word::XListGallery >( new SwVbaListGallery( this, mxContext, mxTextDocument, nIndex ) ) ); + } + throw uno::RuntimeException("Index out of bounds" ); +} + +// XEnumerationAccess +uno::Type +SwVbaListGalleries::getElementType() +{ + return cppu::UnoType<word::XListGallery>::get(); +} + +uno::Reference< container::XEnumeration > +SwVbaListGalleries::createEnumeration() +{ + return new ListGalleriesEnumWrapper( this ); +} + +uno::Any +SwVbaListGalleries::createCollectionObject( const css::uno::Any& aSource ) +{ + return aSource; +} + +OUString +SwVbaListGalleries::getServiceImplName() +{ + return "SwVbaListGalleries"; +} + +css::uno::Sequence<OUString> +SwVbaListGalleries::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.ListGalleries" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalistgalleries.hxx b/sw/source/ui/vba/vbalistgalleries.hxx new file mode 100644 index 0000000000..9eb8f58d93 --- /dev/null +++ b/sw/source/ui/vba/vbalistgalleries.hxx @@ -0,0 +1,51 @@ +/* -*- 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_VBA_VBALISTGALLERIES_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBALISTGALLERIES_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XListGalleries.hpp> +#include <com/sun/star/text/XTextDocument.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XListGalleries > SwVbaListGalleries_BASE; + +class SwVbaListGalleries : public SwVbaListGalleries_BASE +{ +private: + css::uno::Reference< css::text::XTextDocument > mxTextDocument; + +public: + /// @throws css::uno::RuntimeException + SwVbaListGalleries( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, css::uno::Reference< css::text::XTextDocument > xTextDoc ); + + virtual ::sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index1, const css::uno::Any& /*not processed in this base class*/ ) override; + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaListGalleries_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBALISTGALLERIES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalistgallery.cxx b/sw/source/ui/vba/vbalistgallery.cxx new file mode 100644 index 0000000000..8eae71df8e --- /dev/null +++ b/sw/source/ui/vba/vbalistgallery.cxx @@ -0,0 +1,60 @@ +/* -*- 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 <utility> + +#include "vbalistgallery.hxx" +#include "vbalisttemplates.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaListGallery::SwVbaListGallery( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< text::XTextDocument > xTextDoc, sal_Int32 nType ) : SwVbaListGallery_BASE( rParent, rContext ), mxTextDocument(std::move( xTextDoc )), mnType( nType ) +{ +} + +SwVbaListGallery::~SwVbaListGallery() +{ +} + +uno::Any SAL_CALL +SwVbaListGallery::ListTemplates( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaListTemplates( mxParent, mxContext, mxTextDocument, mnType ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +OUString +SwVbaListGallery::getServiceImplName() +{ + return "SwVbaListGallery"; +} + +uno::Sequence< OUString > +SwVbaListGallery::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.ListGallery" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalistgallery.hxx b/sw/source/ui/vba/vbalistgallery.hxx new file mode 100644 index 0000000000..2b288aa266 --- /dev/null +++ b/sw/source/ui/vba/vbalistgallery.hxx @@ -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 . + */ +#ifndef INCLUDED_SW_SOURCE_UI_VBA_VBALISTGALLERY_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBALISTGALLERY_HXX + +#include <ooo/vba/word/XListGallery.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextDocument.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XListGallery > SwVbaListGallery_BASE; + +class SwVbaListGallery : public SwVbaListGallery_BASE +{ +private: + css::uno::Reference< css::text::XTextDocument > mxTextDocument; + sal_Int32 mnType; + +public: + /// @throws css::uno::RuntimeException + SwVbaListGallery( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::text::XTextDocument > xTextDoc, sal_Int32 nType ); + virtual ~SwVbaListGallery() override; + + // Methods + virtual css::uno::Any SAL_CALL ListTemplates( const css::uno::Any& index ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBALISTGALLERY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalisthelper.cxx b/sw/source/ui/vba/vbalisthelper.cxx new file mode 100644 index 0000000000..4b3ca1304e --- /dev/null +++ b/sw/source/ui/vba/vbalisthelper.cxx @@ -0,0 +1,661 @@ +/* -*- 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 "vbalisthelper.hxx" +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include <sal/log.hxx> +#include <ooo/vba/word/WdListGalleryType.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +const sal_Int32 LIST_LEVEL_COUNT = 9; + +constexpr OUString UNO_NAME_PARENT_NUMBERING = u"ParentNumbering"_ustr; +constexpr OUString UNO_NAME_PREFIX = u"Prefix"_ustr; +constexpr OUString UNO_NAME_SUFFIX = u"Suffix"_ustr; +constexpr OUString UNO_NAME_CHAR_STYLE_NAME = u"CharStyleName"_ustr; +constexpr OUString UNO_NAME_NUMBERING_TYPE = u"NumberingType"_ustr; +constexpr OUString UNO_NAME_BULLET_CHAR = u"BulletChar"_ustr; + +constexpr OUString CHAR_CLOSED_DOT = u"\u2022"_ustr; +constexpr OUStringLiteral CHAR_EMPTY_DOT = u"o"; +constexpr OUString CHAR_SQUARE = u"\u2540"_ustr; +constexpr OUStringLiteral CHAR_STAR_SYMBOL = u"\u272A"; +constexpr OUString CHAR_FOUR_DIAMONDS = u"\u2756"_ustr; +constexpr OUStringLiteral CHAR_DIAMOND = u"\u2726"; +constexpr OUString CHAR_ARROW = u"\u27A2"_ustr; +constexpr OUStringLiteral CHAR_CHECK_MARK = u"\u2713"; + +SwVbaListHelper::SwVbaListHelper( css::uno::Reference< css::text::XTextDocument > xTextDoc, sal_Int32 nGalleryType, sal_Int32 nTemplateType ) : mxTextDocument(std::move( xTextDoc )), mnGalleryType( nGalleryType ), mnTemplateType( nTemplateType ) +{ + Init(); +} + +void SwVbaListHelper::Init() +{ + // set the numbering style name + switch( mnGalleryType ) + { + case word::WdListGalleryType::wdBulletGallery: + { + msStyleName = "WdBullet"; + break; + } + case word::WdListGalleryType::wdNumberGallery: + { + msStyleName = "WdNumber"; + break; + } + case word::WdListGalleryType::wdOutlineNumberGallery: + { + msStyleName = "WdOutlineNumber"; + break; + } + default: + { + throw uno::RuntimeException(); + } + } + msStyleName += OUString::number( mnTemplateType ); + + // get the numbering style + uno::Reference< style::XStyleFamiliesSupplier > xStyleSupplier( mxTextDocument, uno::UNO_QUERY_THROW ); + mxStyleFamily.set( xStyleSupplier->getStyleFamilies()->getByName("NumberingStyles"), uno::UNO_QUERY_THROW ); + SAL_INFO("sw.vba", "numbering style name: " << msStyleName ); + if( mxStyleFamily->hasByName( msStyleName ) ) + { + mxStyleProps.set( mxStyleFamily->getByName( msStyleName ), uno::UNO_QUERY_THROW ); + mxNumberingRules.set( mxStyleProps->getPropertyValue("NumberingRules"), uno::UNO_QUERY_THROW ); + } + else + { + // create new numbering style + uno::Reference< lang::XMultiServiceFactory > xDocMSF( mxTextDocument, uno::UNO_QUERY_THROW ); + mxStyleProps.set( xDocMSF->createInstance("com.sun.star.style.NumberingStyle"), uno::UNO_QUERY_THROW ); + // insert this style into style family, or the property NumberingRules doesn't exist. + mxStyleFamily->insertByName( msStyleName, uno::Any( mxStyleProps ) ); + mxStyleProps->getPropertyValue("NumberingRules") >>= mxNumberingRules; + + CreateListTemplate(); + + mxStyleProps->setPropertyValue("NumberingRules", uno::Any( mxNumberingRules ) ); + } +} + +void SwVbaListHelper::CreateListTemplate() +{ + switch( mnGalleryType ) + { + case word::WdListGalleryType::wdBulletGallery: + { + CreateBulletListTemplate(); + break; + } + case word::WdListGalleryType::wdNumberGallery: + { + CreateNumberListTemplate(); + break; + } + case word::WdListGalleryType::wdOutlineNumberGallery: + { + CreateOutlineNumberListTemplate(); + break; + } + default: + { + throw uno::RuntimeException(); + } + } +} + +void SwVbaListHelper::CreateBulletListTemplate() +{ + // there is only 1 level for each bullet list in MSWord + sal_Int32 nLevel = 0; + uno::Sequence< beans::PropertyValue > aPropertyValues; + mxNumberingRules->getByIndex( nLevel ) >>= aPropertyValues; + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_CHAR_STYLE_NAME, uno::Any( OUString( "Bullet Symbols" ) ) ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_NUMBERING_TYPE, uno::Any( sal_Int16(style::NumberingType::CHAR_SPECIAL) ) ); + + OUString aBulletChar; + switch( mnTemplateType ) + { + case 1: + { + aBulletChar = CHAR_CLOSED_DOT; + break; + } + case 2: + { + aBulletChar = CHAR_EMPTY_DOT; + break; + } + case 3: + { + aBulletChar = CHAR_SQUARE; + break; + } + case 4: + { + aBulletChar = CHAR_STAR_SYMBOL; + break; + } + case 5: + { + aBulletChar = CHAR_FOUR_DIAMONDS; + break; + } + case 6: + { + aBulletChar = CHAR_ARROW; + break; + } + case 7: + { + aBulletChar = CHAR_CHECK_MARK; + break; + } + default: + { + // we only support 7 types template now + throw css::uno::RuntimeException(); + } + } + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_BULLET_CHAR, uno::Any( aBulletChar ) ); + + mxNumberingRules->replaceByIndex( nLevel, uno::Any( aPropertyValues ) ); +} + +void SwVbaListHelper::CreateNumberListTemplate() +{ + // there is only 1 level for each bullet list in MSWord + sal_Int32 nLevel = 0; + uno::Sequence< beans::PropertyValue > aPropertyValues; + mxNumberingRules->getByIndex( nLevel ) >>= aPropertyValues; + + sal_Int16 nNumberingType = 0; + OUString sSuffix; + switch( mnTemplateType ) + { + case 1: + { + nNumberingType = style::NumberingType::ARABIC; + sSuffix = "."; + break; + } + case 2: + { + nNumberingType = style::NumberingType::ARABIC; + sSuffix = ")"; + break; + } + case 3: + { + nNumberingType = style::NumberingType::ROMAN_UPPER; + sSuffix = "."; + break; + } + case 4: + { + nNumberingType = style::NumberingType::CHARS_UPPER_LETTER; + sSuffix = "."; + break; + } + case 5: + { + nNumberingType = style::NumberingType::CHARS_LOWER_LETTER; + sSuffix = ")"; + break; + } + case 6: + { + nNumberingType = style::NumberingType::CHARS_LOWER_LETTER; + sSuffix = "."; + break; + } + case 7: + { + nNumberingType = style::NumberingType::ROMAN_LOWER; + sSuffix = "."; + break; + } + default: + { + // we only support 7 types template now + throw css::uno::RuntimeException(); + } + } + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_NUMBERING_TYPE, uno::Any( nNumberingType ) ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_SUFFIX, uno::Any( sSuffix ) ); + + mxNumberingRules->replaceByIndex( nLevel, uno::Any( aPropertyValues ) ); +} + +void SwVbaListHelper::CreateOutlineNumberListTemplate() +{ + switch( mnTemplateType ) + { + case 1: + { + CreateOutlineNumberForType1(); + break; + } + case 2: + { + CreateOutlineNumberForType2(); + break; + } + case 3: + { + CreateOutlineNumberForType3(); + break; + } + case 4: + { + CreateOutlineNumberForType4(); + break; + } + case 5: + { + CreateOutlineNumberForType5(); + break; + } + case 6: + { + CreateOutlineNumberForType6(); + break; + } + case 7: + { + CreateOutlineNumberForType7(); + break; + } + default: + { + // we only support 7 types template now + throw css::uno::RuntimeException(); + } + } +} + +void SwVbaListHelper::CreateOutlineNumberForType1() +{ + sal_Int16 nNumberingType = 0; + OUString sPrefix; + OUString sSuffix; + uno::Sequence< beans::PropertyValue > aPropertyValues; + + for( sal_Int32 nLevel = 0; nLevel < LIST_LEVEL_COUNT; nLevel++ ) + { + mxNumberingRules->getByIndex( nLevel ) >>= aPropertyValues; + switch( nLevel ) + { + case 0: + case 1: + { + nNumberingType = style::NumberingType::ARABIC; + sPrefix.clear(); + sSuffix = ")"; + break; + } + case 2: + { + nNumberingType = style::NumberingType::ROMAN_LOWER; + sPrefix.clear(); + sSuffix = ")"; + break; + } + case 3: + { + nNumberingType = style::NumberingType::ARABIC; + sPrefix = "("; + sSuffix = ")"; + break; + } + case 4: + { + nNumberingType = style::NumberingType::CHARS_LOWER_LETTER; + sPrefix = "("; + sSuffix = ")"; + break; + } + case 5: + { + nNumberingType = style::NumberingType::ROMAN_LOWER; + sPrefix = "("; + sSuffix = ")"; + break; + } + case 6: + { + nNumberingType = style::NumberingType::ARABIC; + sPrefix.clear(); + sSuffix = "."; + break; + } + case 7: + { + nNumberingType = style::NumberingType::CHARS_LOWER_LETTER; + sPrefix.clear(); + sSuffix = "."; + break; + } + case 8: + { + nNumberingType = style::NumberingType::ROMAN_LOWER; + sPrefix.clear(); + sSuffix = "."; + break; + } + } + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_NUMBERING_TYPE, uno::Any( nNumberingType ) ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_PREFIX, uno::Any( sPrefix ) ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_SUFFIX, uno::Any( sSuffix ) ); + mxNumberingRules->replaceByIndex( nLevel, uno::Any( aPropertyValues ) ); + } +} + +void SwVbaListHelper::CreateOutlineNumberForType2() +{ + sal_Int16 nParentNumbering = 0; + OUString sSuffix( '.' ); + uno::Sequence< beans::PropertyValue > aPropertyValues; + + for( sal_Int32 nLevel = 0; nLevel < LIST_LEVEL_COUNT; nLevel++ ) + { + mxNumberingRules->getByIndex( nLevel ) >>= aPropertyValues; + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_NUMBERING_TYPE, uno::Any( sal_Int16(style::NumberingType::ARABIC) ) ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_SUFFIX, uno::Any( sSuffix ) ); + if( nLevel != 0 ) + { + nParentNumbering = sal_Int16( nLevel - 1 ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_PARENT_NUMBERING, uno::Any( nParentNumbering ) ); + } + mxNumberingRules->replaceByIndex( nLevel, uno::Any( aPropertyValues ) ); + } +} + +void SwVbaListHelper::CreateOutlineNumberForType3() +{ + OUString aBulletChar; + uno::Sequence< beans::PropertyValue > aPropertyValues; + + for( sal_Int32 nLevel = 0; nLevel < LIST_LEVEL_COUNT; nLevel++ ) + { + mxNumberingRules->getByIndex( nLevel ) >>= aPropertyValues; + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_NUMBERING_TYPE, uno::Any( sal_Int16(style::NumberingType::CHAR_SPECIAL) ) ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_CHAR_STYLE_NAME, uno::Any( OUString("Bullet Symbols") ) ); + switch( nLevel ) + { + case 0: + { + aBulletChar = CHAR_FOUR_DIAMONDS; + break; + } + case 1: + case 5: + { + aBulletChar = CHAR_ARROW; + break; + } + case 2: + case 6: + { + aBulletChar = CHAR_SQUARE; + break; + } + case 3: + case 7: + { + aBulletChar = CHAR_CLOSED_DOT; + break; + } + case 4: + case 8: + { + aBulletChar = CHAR_DIAMOND; + break; + } + } + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_BULLET_CHAR, uno::Any( aBulletChar ) ); + mxNumberingRules->replaceByIndex( nLevel, uno::Any( aPropertyValues ) ); + } +} + +void SwVbaListHelper::CreateOutlineNumberForType4() +{ + sal_Int16 nNumberingType = 0; + OUString sPrefix; + OUString sSuffix; + uno::Sequence< beans::PropertyValue > aPropertyValues; + + for( sal_Int32 nLevel = 0; nLevel < LIST_LEVEL_COUNT; nLevel++ ) + { + mxNumberingRules->getByIndex( nLevel ) >>= aPropertyValues; + switch( nLevel ) + { + case 0: + { + nNumberingType = style::NumberingType::ROMAN_UPPER; + sPrefix.clear(); + sSuffix = "."; + break; + } + case 1: + { + nNumberingType = style::NumberingType::ARABIC; + sPrefix.clear(); + sSuffix = "."; + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_PARENT_NUMBERING, uno::Any( sal_Int16(0) ) ); + break; + } + case 2: + { + nNumberingType = style::NumberingType::CHARS_LOWER_LETTER; + sPrefix = "("; + sSuffix = ")"; + break; + } + case 3: + { + nNumberingType = style::NumberingType::ROMAN_LOWER; + sPrefix = "("; + sSuffix = ")"; + break; + } + case 4: + { + nNumberingType = style::NumberingType::ARABIC; + sPrefix.clear(); + sSuffix = ")"; + break; + } + case 5: + { + nNumberingType = style::NumberingType::CHARS_LOWER_LETTER; + sPrefix.clear(); + sSuffix = ")"; + break; + } + case 6: + { + nNumberingType = style::NumberingType::ROMAN_LOWER; + sPrefix.clear(); + sSuffix = ")"; + break; + } + case 7: + { + nNumberingType = style::NumberingType::CHARS_LOWER_LETTER; + sPrefix.clear(); + sSuffix = "."; + break; + } + case 8: + { + nNumberingType = style::NumberingType::ROMAN_LOWER; + sPrefix.clear(); + sSuffix = "."; + break; + } + } + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_NUMBERING_TYPE, uno::Any( nNumberingType ) ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_PREFIX, uno::Any( sPrefix ) ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_SUFFIX, uno::Any( sSuffix ) ); + mxNumberingRules->replaceByIndex( nLevel, uno::Any( aPropertyValues ) ); + } +} + +void SwVbaListHelper::CreateOutlineNumberForType5() +{ + sal_Int16 nParentNumbering = 0; + uno::Sequence< beans::PropertyValue > aPropertyValues; + + for( sal_Int32 nLevel = 0; nLevel < LIST_LEVEL_COUNT; nLevel++ ) + { + mxNumberingRules->getByIndex( nLevel ) >>= aPropertyValues; + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_NUMBERING_TYPE, uno::Any( sal_Int16(style::NumberingType::ARABIC) ) ); + if( nLevel != 0 ) + { + nParentNumbering = sal_Int16( nLevel - 1 ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_PARENT_NUMBERING, uno::Any( nParentNumbering ) ); + } + mxNumberingRules->replaceByIndex( nLevel, uno::Any( aPropertyValues ) ); + } +} + +void SwVbaListHelper::CreateOutlineNumberForType6() +{ + sal_Int16 nNumberingType = 0; + OUString sPrefix; + OUString sSuffix; + uno::Sequence< beans::PropertyValue > aPropertyValues; + + for( sal_Int32 nLevel = 0; nLevel < LIST_LEVEL_COUNT; nLevel++ ) + { + mxNumberingRules->getByIndex( nLevel ) >>= aPropertyValues; + switch( nLevel ) + { + case 0: + { + nNumberingType = style::NumberingType::ROMAN_UPPER; + sPrefix.clear(); + sSuffix = "."; + break; + } + case 1: + { + nNumberingType = style::NumberingType::CHARS_UPPER_LETTER; + sPrefix.clear(); + sSuffix = "."; + break; + } + case 2: + { + nNumberingType = style::NumberingType::ARABIC; + sPrefix.clear(); + sSuffix = ")"; + break; + } + case 3: + { + nNumberingType = style::NumberingType::CHARS_LOWER_LETTER; + sPrefix.clear(); + sSuffix = ")"; + break; + } + case 4: + { + nNumberingType = style::NumberingType::ARABIC; + sPrefix = "("; + sSuffix = ")"; + break; + } + case 5: + { + nNumberingType = style::NumberingType::CHARS_LOWER_LETTER; + sPrefix = "("; + sSuffix = ")"; + break; + } + case 6: + { + nNumberingType = style::NumberingType::ROMAN_LOWER; + sPrefix = "("; + sSuffix = ")"; + break; + } + case 7: + { + nNumberingType = style::NumberingType::CHARS_LOWER_LETTER; + sPrefix = "("; + sSuffix = "."; + break; + } + case 8: + { + nNumberingType = style::NumberingType::ROMAN_LOWER; + sPrefix = "("; + sSuffix = "."; + break; + } + } + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_NUMBERING_TYPE, uno::Any( nNumberingType ) ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_PREFIX, uno::Any( sPrefix ) ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_SUFFIX, uno::Any( sSuffix ) ); + mxNumberingRules->replaceByIndex( nLevel, uno::Any( aPropertyValues ) ); + } +} + +void SwVbaListHelper::CreateOutlineNumberForType7() +{ + uno::Sequence< beans::PropertyValue > aPropertyValues; + + for( sal_Int32 nLevel = 0; nLevel < LIST_LEVEL_COUNT; nLevel++ ) + { + mxNumberingRules->getByIndex( nLevel ) >>= aPropertyValues; + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_NUMBERING_TYPE, uno::Any( sal_Int16(style::NumberingType::ARABIC) ) ); + setOrAppendPropertyValue( aPropertyValues, UNO_NAME_PREFIX, uno::Any( OUString("Chapter ") ) ); + mxNumberingRules->replaceByIndex( nLevel, uno::Any( aPropertyValues ) ); + } +} + +uno::Any SwVbaListHelper::getPropertyValueWithNameAndLevel( sal_Int32 nLevel, const OUString& sName ) +{ + uno::Sequence< beans::PropertyValue > aPropertyValues; + mxNumberingRules->getByIndex( nLevel ) >>= aPropertyValues; + return getPropertyValue( aPropertyValues, sName ); +} + +void SwVbaListHelper::setPropertyValueWithNameAndLevel( sal_Int32 nLevel, const OUString& sName, const css::uno::Any& aValue ) +{ + uno::Sequence< beans::PropertyValue > aPropertyValues; + mxNumberingRules->getByIndex( nLevel ) >>= aPropertyValues; + setOrAppendPropertyValue( aPropertyValues, sName, aValue ); + mxNumberingRules->replaceByIndex( nLevel, uno::Any( aPropertyValues ) ); + mxStyleProps->setPropertyValue("NumberingRules", uno::Any( mxNumberingRules ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalisthelper.hxx b/sw/source/ui/vba/vbalisthelper.hxx new file mode 100644 index 0000000000..599e4f6864 --- /dev/null +++ b/sw/source/ui/vba/vbalisthelper.hxx @@ -0,0 +1,73 @@ +/* -*- 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/. + */ +#ifndef INCLUDED_SW_SOURCE_UI_VBA_VBALISTHELPER_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBALISTHELPER_HXX + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/text/XTextDocument.hpp> + +#include <memory> + +class SwVbaListHelper; +typedef std::shared_ptr< SwVbaListHelper > SwVbaListHelperRef; + +class SwVbaListHelper +{ +private: + css::uno::Reference< css::text::XTextDocument > mxTextDocument; + css::uno::Reference< css::container::XIndexReplace > mxNumberingRules; + css::uno::Reference< css::container::XNameContainer > mxStyleFamily; + css::uno::Reference< css::beans::XPropertySet > mxStyleProps; + sal_Int32 mnGalleryType; + sal_Int32 mnTemplateType; + OUString msStyleName; + + /// @throws css::uno::RuntimeException + void Init(); + /// @throws css::uno::RuntimeException + void CreateListTemplate(); + /// @throws css::uno::RuntimeException + void CreateBulletListTemplate(); + /// @throws css::uno::RuntimeException + void CreateNumberListTemplate(); + /// @throws css::uno::RuntimeException + void CreateOutlineNumberListTemplate(); + /// @throws css::uno::RuntimeException + void CreateOutlineNumberForType1(); + /// @throws css::uno::RuntimeException + void CreateOutlineNumberForType2(); + /// @throws css::uno::RuntimeException + void CreateOutlineNumberForType3(); + /// @throws css::uno::RuntimeException + void CreateOutlineNumberForType4(); + /// @throws css::uno::RuntimeException + void CreateOutlineNumberForType5(); + /// @throws css::uno::RuntimeException + void CreateOutlineNumberForType6(); + /// @throws css::uno::RuntimeException + void CreateOutlineNumberForType7(); + +public: + /// @throws css::uno::RuntimeException + SwVbaListHelper( css::uno::Reference< css::text::XTextDocument > xTextDoc, sal_Int32 nGalleryType, sal_Int32 nTemplateType ); + + sal_Int32 getGalleryType() const { return mnGalleryType; } + const css::uno::Reference< css::container::XIndexReplace >& getNumberingRules() const { return mxNumberingRules; } + /// @throws css::uno::RuntimeException + css::uno::Any getPropertyValueWithNameAndLevel( sal_Int32 nLevel, const OUString& sName ); + /// @throws css::uno::RuntimeException + void setPropertyValueWithNameAndLevel( sal_Int32 nLevel, const OUString& sName, const css::uno::Any& aValue ); + +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBALISTHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalistlevel.cxx b/sw/source/ui/vba/vbalistlevel.cxx new file mode 100644 index 0000000000..43f16e8524 --- /dev/null +++ b/sw/source/ui/vba/vbalistlevel.cxx @@ -0,0 +1,386 @@ +/* -*- 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 "vbalistlevel.hxx" +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include <com/sun/star/style/NumberingType.hpp> +#include <ooo/vba/word/WdListNumberStyle.hpp> +#include <com/sun/star/text/HoriOrientation.hpp> +#include <ooo/vba/word/WdListLevelAlignment.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaListLevel::SwVbaListLevel( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, SwVbaListHelperRef pHelper, sal_Int32 nLevel ) : SwVbaListLevel_BASE( rParent, rContext ), m_pListHelper(std::move( pHelper )), mnLevel( nLevel ) +{ +} + +SwVbaListLevel::~SwVbaListLevel() +{ +} + +::sal_Int32 SAL_CALL SwVbaListLevel::getAlignment() +{ + sal_Int16 nAlignment = 0; + m_pListHelper->getPropertyValueWithNameAndLevel( mnLevel, "Adjust" ) >>= nAlignment; + switch( nAlignment ) + { + case text::HoriOrientation::LEFT: + { + nAlignment = word::WdListLevelAlignment::wdListLevelAlignLeft; + break; + } + case text::HoriOrientation::RIGHT: + { + nAlignment = word::WdListLevelAlignment::wdListLevelAlignRight; + break; + } + case text::HoriOrientation::CENTER: + { + nAlignment = word::WdListLevelAlignment::wdListLevelAlignCenter; + break; + } + default: + { + throw uno::RuntimeException(); + } + } + return nAlignment; +} + +void SAL_CALL SwVbaListLevel::setAlignment( ::sal_Int32 _alignment ) +{ + sal_Int16 nAlignment = text::HoriOrientation::LEFT; + switch( _alignment ) + { + case word::WdListLevelAlignment::wdListLevelAlignLeft: + { + nAlignment = text::HoriOrientation::LEFT; + break; + } + case word::WdListLevelAlignment::wdListLevelAlignRight: + { + nAlignment = text::HoriOrientation::RIGHT; + break; + } + case word::WdListLevelAlignment::wdListLevelAlignCenter: + { + nAlignment = text::HoriOrientation::CENTER; + break; + } + default: + { + throw uno::RuntimeException(); + } + } + m_pListHelper->setPropertyValueWithNameAndLevel( mnLevel, "Adjust", uno::Any( nAlignment ) ); +} + +uno::Reference< ::ooo::vba::word::XFont > SAL_CALL SwVbaListLevel::getFont() +{ + throw uno::RuntimeException("Not implemented" ); +} + +void SAL_CALL SwVbaListLevel::setFont( const uno::Reference< ::ooo::vba::word::XFont >& /*_font*/ ) +{ + throw uno::RuntimeException("Not implemented" ); +} + +::sal_Int32 SAL_CALL SwVbaListLevel::getIndex() +{ + return mnLevel + 1; +} + +OUString SAL_CALL SwVbaListLevel::getLinkedStyle() +{ + // TODO: + return OUString(); +} + +void SAL_CALL SwVbaListLevel::setLinkedStyle( const OUString& /*_linkedstyle*/ ) +{ + // TODO: +} + +OUString SAL_CALL SwVbaListLevel::getNumberFormat() +{ + // TODO:: + return OUString(); +} + +void SAL_CALL SwVbaListLevel::setNumberFormat( const OUString& /*_numberformat*/ ) +{ + // TODO:: +} + +float SAL_CALL SwVbaListLevel::getNumberPosition() +{ + // indentAt + firstlineindent + sal_Int32 nIndentAt = 0; + sal_Int32 nFirstLineIndent = 0; + m_pListHelper->getPropertyValueWithNameAndLevel( mnLevel, "IndentAt" ) >>= nIndentAt; + m_pListHelper->getPropertyValueWithNameAndLevel( mnLevel, "FirstLineIndent" ) >>= nFirstLineIndent; + + sal_Int32 nResult = nIndentAt + nFirstLineIndent; + + return static_cast< float >( Millimeter::getInPoints( nResult ) ); +} + +void SAL_CALL SwVbaListLevel::setNumberPosition( float _numberposition ) +{ + sal_Int32 nNumberPosition = Millimeter::getInHundredthsOfOneMillimeter( _numberposition ); + + sal_Int32 nIndentAt = 0; + m_pListHelper->getPropertyValueWithNameAndLevel( mnLevel, "IndentAt" ) >>= nIndentAt; + + sal_Int32 nFirstLineIndent = nNumberPosition - nIndentAt; + m_pListHelper->setPropertyValueWithNameAndLevel( mnLevel, "FirstLineIndent", uno::Any( nFirstLineIndent ) ); +} + +::sal_Int32 SAL_CALL SwVbaListLevel::getNumberStyle() +{ + sal_Int16 nNumberingType = 0; + m_pListHelper->getPropertyValueWithNameAndLevel( mnLevel, "NumberingType" ) >>= nNumberingType; + switch( nNumberingType ) + { + case style::NumberingType::CHAR_SPECIAL: + { + nNumberingType = word::WdListNumberStyle::wdListNumberStyleBullet; + break; + } + case style::NumberingType::CHARS_UPPER_LETTER: + { + nNumberingType = word::WdListNumberStyle::wdListNumberStyleUppercaseLetter; + break; + } + case style::NumberingType::CHARS_LOWER_LETTER: + { + nNumberingType = word::WdListNumberStyle::wdListNumberStyleLowercaseLetter; + break; + } + case style::NumberingType::ROMAN_UPPER: + { + nNumberingType = word::WdListNumberStyle::wdListNumberStyleUppercaseRoman; + break; + } + case style::NumberingType::ROMAN_LOWER: + { + nNumberingType = word::WdListNumberStyle::wdListNumberStyleLowercaseRoman; + break; + } + case style::NumberingType::ARABIC: + { + nNumberingType = word::WdListNumberStyle::wdListNumberStyleArabic; + break; + } + case style::NumberingType::NUMBER_NONE: + { + nNumberingType = word::WdListNumberStyle::wdListNumberStyleNone; + break; + } + case style::NumberingType::FULLWIDTH_ARABIC: + { + nNumberingType = word::WdListNumberStyle::wdListNumberStyleArabicFullWidth; + break; + } + case style::NumberingType::CIRCLE_NUMBER: + { + nNumberingType = word::WdListNumberStyle::wdListNumberStyleNumberInCircle; + break; + } + case style::NumberingType::CHARS_ARABIC: + { + nNumberingType = word::WdListNumberStyle::wdListNumberStyleCardinalText; + break; + } + default: + { + throw uno::RuntimeException("Not implemented" ); + } + } + return nNumberingType; +} + +void SAL_CALL SwVbaListLevel::setNumberStyle( ::sal_Int32 _numberstyle ) +{ + sal_Int16 nNumberingType = 0; + switch( _numberstyle ) + { + case word::WdListNumberStyle::wdListNumberStyleBullet: + { + nNumberingType = style::NumberingType::CHAR_SPECIAL; + break; + } + case word::WdListNumberStyle::wdListNumberStyleUppercaseLetter: + { + nNumberingType = style::NumberingType::CHARS_UPPER_LETTER_N; + break; + } + case word::WdListNumberStyle::wdListNumberStyleLowercaseLetter: + { + nNumberingType = style::NumberingType::CHARS_LOWER_LETTER_N; + break; + } + case word::WdListNumberStyle::wdListNumberStyleUppercaseRoman: + { + nNumberingType = style::NumberingType::ROMAN_UPPER; + break; + } + case word::WdListNumberStyle::wdListNumberStyleLowercaseRoman: + { + nNumberingType = style::NumberingType::ROMAN_LOWER; + break; + } + case word::WdListNumberStyle::wdListNumberStyleArabic: + { + nNumberingType = style::NumberingType::ARABIC; + break; + } + case word::WdListNumberStyle::wdListNumberStyleNone: + { + nNumberingType = style::NumberingType::NUMBER_NONE; + break; + } + case word::WdListNumberStyle::wdListNumberStyleArabicFullWidth: + { + nNumberingType = style::NumberingType::FULLWIDTH_ARABIC; + break; + } + case word::WdListNumberStyle::wdListNumberStyleNumberInCircle: + { + nNumberingType = style::NumberingType::CIRCLE_NUMBER; + break; + } + case word::WdListNumberStyle::wdListNumberStyleCardinalText: + { + nNumberingType = style::NumberingType::CHARS_ARABIC; + break; + } + case word::WdListNumberStyle::wdListNumberStyleOrdinal: + case word::WdListNumberStyle::wdListNumberStyleOrdinalText: + case word::WdListNumberStyle::wdListNumberStyleKanji: + case word::WdListNumberStyle::wdListNumberStyleKanjiDigit: + case word::WdListNumberStyle::wdListNumberStyleAiueoHalfWidth: + case word::WdListNumberStyle::wdListNumberStyleIrohaHalfWidth: + { + nNumberingType = style::NumberingType::ARABIC; + break; + } + default: + { + throw uno::RuntimeException("Not implemented" ); + } + } + + m_pListHelper->setPropertyValueWithNameAndLevel( mnLevel, "NumberingType", uno::Any( nNumberingType ) ); +} + +::sal_Int32 SAL_CALL SwVbaListLevel::getResetOnHigher() +{ + //seems not support? + return 0; +} + +void SAL_CALL SwVbaListLevel::setResetOnHigher( ::sal_Int32 /*_resetonhigher*/ ) +{ + //seems not support? +} + +::sal_Int32 SAL_CALL SwVbaListLevel::getStartAt() +{ + sal_Int16 nStartWith = 0; + m_pListHelper->getPropertyValueWithNameAndLevel( mnLevel, "StartWith" ) >>= nStartWith; + return nStartWith; +} + +void SAL_CALL SwVbaListLevel::setStartAt( ::sal_Int32 _startat ) +{ + sal_Int16 nStartWith = static_cast<sal_Int16>(_startat); + m_pListHelper->setPropertyValueWithNameAndLevel( mnLevel, "StartWith", uno::Any( nStartWith ) ); +} + +float SAL_CALL SwVbaListLevel::getTabPosition() +{ + sal_Int32 nTabPosition = 0; + m_pListHelper->getPropertyValueWithNameAndLevel( mnLevel, "ListtabStopPosition" ) >>= nTabPosition; + + return static_cast< float >( Millimeter::getInPoints( nTabPosition ) ); +} + +void SAL_CALL SwVbaListLevel::setTabPosition( float _tabposition ) +{ + sal_Int32 nTabPosition = Millimeter::getInHundredthsOfOneMillimeter( _tabposition ); + m_pListHelper->setPropertyValueWithNameAndLevel( mnLevel, "ListtabStopPosition", uno::Any( nTabPosition ) ); +} + +float SAL_CALL SwVbaListLevel::getTextPosition() +{ + // indentAt + sal_Int32 nIndentAt = 0; + m_pListHelper->getPropertyValueWithNameAndLevel( mnLevel, "IndentAt" ) >>= nIndentAt; + + return static_cast< float >( Millimeter::getInPoints( nIndentAt ) ); +} + +void SAL_CALL SwVbaListLevel::setTextPosition( float _textposition ) +{ + sal_Int32 nIndentAt = 0; + sal_Int32 nFirstLineIndent = 0; + m_pListHelper->getPropertyValueWithNameAndLevel( mnLevel, "IndentAt" ) >>= nIndentAt; + m_pListHelper->getPropertyValueWithNameAndLevel( mnLevel, "FirstLineIndent" ) >>= nFirstLineIndent; + + sal_Int32 nAlignedAt = nIndentAt + nFirstLineIndent; + + nIndentAt = Millimeter::getInHundredthsOfOneMillimeter( _textposition ); + nFirstLineIndent = nAlignedAt - nIndentAt; + m_pListHelper->setPropertyValueWithNameAndLevel( mnLevel, "IndentAt", uno::Any( nIndentAt ) ); + m_pListHelper->setPropertyValueWithNameAndLevel( mnLevel, "FirstLineIndent", uno::Any( nFirstLineIndent ) ); +} + +::sal_Int32 SAL_CALL SwVbaListLevel::getTrailingCharacter() +{ + sal_Int16 nLabelFollowedBy= 0; + m_pListHelper->getPropertyValueWithNameAndLevel( mnLevel, "LabelFollowedBy" ) >>= nLabelFollowedBy; + + return nLabelFollowedBy; +} + +void SAL_CALL SwVbaListLevel::setTrailingCharacter( ::sal_Int32 _trailingcharacter ) +{ + sal_Int16 nLabelFollowedBy = static_cast<sal_Int16>(_trailingcharacter); + m_pListHelper->setPropertyValueWithNameAndLevel( mnLevel, "LabelFollowedBy", uno::Any( nLabelFollowedBy ) ); +} + +OUString +SwVbaListLevel::getServiceImplName() +{ + return "SwVbaListLevel"; +} + +uno::Sequence< OUString > +SwVbaListLevel::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.ListLevel" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalistlevel.hxx b/sw/source/ui/vba/vbalistlevel.hxx new file mode 100644 index 0000000000..e9a8e23e13 --- /dev/null +++ b/sw/source/ui/vba/vbalistlevel.hxx @@ -0,0 +1,70 @@ +/* -*- 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_VBA_VBALISTLEVEL_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBALISTLEVEL_HXX + +#include <ooo/vba/word/XListLevel.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include "vbalisthelper.hxx" + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XListLevel > SwVbaListLevel_BASE; + +class SwVbaListLevel : public SwVbaListLevel_BASE +{ +private: + SwVbaListHelperRef m_pListHelper; + sal_Int32 mnLevel; + +public: + /// @throws css::uno::RuntimeException + SwVbaListLevel( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, SwVbaListHelperRef pHelper, sal_Int32 nLevel ); + virtual ~SwVbaListLevel() override; + + // Attributes + virtual ::sal_Int32 SAL_CALL getAlignment() override; + virtual void SAL_CALL setAlignment( ::sal_Int32 _alignment ) override; + virtual css::uno::Reference< ::ooo::vba::word::XFont > SAL_CALL getFont() override; + virtual void SAL_CALL setFont( const css::uno::Reference< ::ooo::vba::word::XFont >& _font ) override; + virtual ::sal_Int32 SAL_CALL getIndex() override; + virtual OUString SAL_CALL getLinkedStyle() override; + virtual void SAL_CALL setLinkedStyle( const OUString& _linkedstyle ) override; + virtual OUString SAL_CALL getNumberFormat() override; + virtual void SAL_CALL setNumberFormat( const OUString& _numberformat ) override; + virtual float SAL_CALL getNumberPosition() override; + virtual void SAL_CALL setNumberPosition( float _numberposition ) override; + virtual ::sal_Int32 SAL_CALL getNumberStyle() override; + virtual void SAL_CALL setNumberStyle( ::sal_Int32 _numberstyle ) override; + virtual ::sal_Int32 SAL_CALL getResetOnHigher() override; + virtual void SAL_CALL setResetOnHigher( ::sal_Int32 _resetonhigher ) override; + virtual ::sal_Int32 SAL_CALL getStartAt() override; + virtual void SAL_CALL setStartAt( ::sal_Int32 _startat ) override; + virtual float SAL_CALL getTabPosition() override; + virtual void SAL_CALL setTabPosition( float _tabposition ) override; + virtual float SAL_CALL getTextPosition() override; + virtual void SAL_CALL setTextPosition( float _textposition ) override; + virtual ::sal_Int32 SAL_CALL getTrailingCharacter() override; + virtual void SAL_CALL setTrailingCharacter( ::sal_Int32 _trailingcharacter ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBALISTLEVEL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalistlevels.cxx b/sw/source/ui/vba/vbalistlevels.cxx new file mode 100644 index 0000000000..3f0d83e478 --- /dev/null +++ b/sw/source/ui/vba/vbalistlevels.cxx @@ -0,0 +1,111 @@ +/* -*- 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 "vbalistlevels.hxx" +#include "vbalistlevel.hxx" +#include <ooo/vba/word/WdListGalleryType.hpp> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +class ListLevelsEnumWrapper : public EnumerationHelper_BASE +{ + SwVbaListLevels* m_pListLevels; + sal_Int32 m_nIndex; +public: + explicit ListLevelsEnumWrapper( SwVbaListLevels* pLevels ) : m_pListLevels( pLevels ), m_nIndex( 1 ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( m_nIndex <= m_pListLevels->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( m_nIndex <= m_pListLevels->getCount() ) + return m_pListLevels->Item( uno::Any( m_nIndex++ ), uno::Any() ); + throw container::NoSuchElementException(); + } +}; + +} + +SwVbaListLevels::SwVbaListLevels( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, SwVbaListHelperRef pHelper ) : SwVbaListLevels_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >() ), m_pListHelper(std::move( pHelper )) +{ +} + +::sal_Int32 SAL_CALL SwVbaListLevels::getCount() +{ + sal_Int32 nGalleryType = m_pListHelper->getGalleryType(); + if( nGalleryType == word::WdListGalleryType::wdBulletGallery + || nGalleryType == word::WdListGalleryType::wdNumberGallery ) + return 1; + else if( nGalleryType == word::WdListGalleryType::wdOutlineNumberGallery ) + return 9; + return 0; +} + +uno::Any SAL_CALL SwVbaListLevels::Item( const uno::Any& Index1, const uno::Any& /*not processed in this base class*/ ) +{ + sal_Int32 nIndex = 0; + if( !( Index1 >>= nIndex ) ) + throw uno::RuntimeException(); + if( nIndex <=0 || nIndex > getCount() ) + throw uno::RuntimeException("Index out of bounds" ); + + return uno::Any( uno::Reference< word::XListLevel >( new SwVbaListLevel( this, mxContext, m_pListHelper, nIndex - 1 ) ) ); +} + +// XEnumerationAccess +uno::Type +SwVbaListLevels::getElementType() +{ + return cppu::UnoType<word::XListLevel>::get(); +} + +uno::Reference< container::XEnumeration > +SwVbaListLevels::createEnumeration() +{ + return new ListLevelsEnumWrapper( this ); +} + +uno::Any +SwVbaListLevels::createCollectionObject( const css::uno::Any& aSource ) +{ + return aSource; +} + +OUString +SwVbaListLevels::getServiceImplName() +{ + return "SwVbaListLevels"; +} + +css::uno::Sequence<OUString> +SwVbaListLevels::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.ListLevels" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalistlevels.hxx b/sw/source/ui/vba/vbalistlevels.hxx new file mode 100644 index 0000000000..2b3bb44d0f --- /dev/null +++ b/sw/source/ui/vba/vbalistlevels.hxx @@ -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 . + */ +#pragma once + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XListLevels.hpp> +#include "vbalisthelper.hxx" + +typedef CollTestImplHelper< ooo::vba::word::XListLevels > SwVbaListLevels_BASE; + +class SwVbaListLevels : public SwVbaListLevels_BASE +{ +private: + SwVbaListHelperRef m_pListHelper; + +public: + /// @throws css::uno::RuntimeException + SwVbaListLevels( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, SwVbaListHelperRef pHelper ); + + virtual ::sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index1, const css::uno::Any& /*not processed in this base class*/ ) override; + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaListLevels_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalisttemplate.cxx b/sw/source/ui/vba/vbalisttemplate.cxx new file mode 100644 index 0000000000..032bc98162 --- /dev/null +++ b/sw/source/ui/vba/vbalisttemplate.cxx @@ -0,0 +1,66 @@ +/* -*- 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 "vbalisttemplate.hxx" +#include "vbalistlevels.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaListTemplate::SwVbaListTemplate( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Reference< text::XTextDocument >& xTextDoc, sal_Int32 nGalleryType, sal_Int32 nTemplateType ) : SwVbaListTemplate_BASE( rParent, rContext ) +{ + m_pListHelper = std::make_shared<SwVbaListHelper>( xTextDoc, nGalleryType, nTemplateType ); +} + +SwVbaListTemplate::~SwVbaListTemplate() +{ +} + +uno::Any SAL_CALL +SwVbaListTemplate::ListLevels( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaListLevels( mxParent, mxContext, m_pListHelper ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +void SwVbaListTemplate::applyListTemplate( uno::Reference< beans::XPropertySet > const & xProps ) +{ + uno::Reference< container::XIndexReplace > xNumberingRules = m_pListHelper->getNumberingRules(); + xProps->setPropertyValue("NumberingRules", uno::Any( xNumberingRules ) ); +} + +OUString +SwVbaListTemplate::getServiceImplName() +{ + return "SwVbaListTemplate"; +} + +uno::Sequence< OUString > +SwVbaListTemplate::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.ListTemplate" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalisttemplate.hxx b/sw/source/ui/vba/vbalisttemplate.hxx new file mode 100644 index 0000000000..a690b6c820 --- /dev/null +++ b/sw/source/ui/vba/vbalisttemplate.hxx @@ -0,0 +1,51 @@ +/* -*- 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_VBA_VBALISTTEMPLATE_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBALISTTEMPLATE_HXX + +#include <ooo/vba/word/XListTemplate.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextDocument.hpp> +#include "vbalisthelper.hxx" + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XListTemplate > SwVbaListTemplate_BASE; + +class SwVbaListTemplate : public SwVbaListTemplate_BASE +{ +private: + SwVbaListHelperRef m_pListHelper; + +public: + /// @throws css::uno::RuntimeException + SwVbaListTemplate( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, const css::uno::Reference< css::text::XTextDocument >& xTextDoc, sal_Int32 nGalleryType, sal_Int32 nTemplateType ); + virtual ~SwVbaListTemplate() override; + + /// @throws css::uno::RuntimeException + void applyListTemplate( css::uno::Reference< css::beans::XPropertySet > const & xProps ); + + // Methods + virtual css::uno::Any SAL_CALL ListLevels( const css::uno::Any& index ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBALISTTEMPLATE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalisttemplates.cxx b/sw/source/ui/vba/vbalisttemplates.cxx new file mode 100644 index 0000000000..a9cc52d4bc --- /dev/null +++ b/sw/source/ui/vba/vbalisttemplates.cxx @@ -0,0 +1,106 @@ +/* -*- 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 <utility> + +#include "vbalisttemplates.hxx" +#include "vbalisttemplate.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +class ListTemplatesEnumWrapper : public EnumerationHelper_BASE +{ + SwVbaListTemplates* m_pListTemplates; + sal_Int32 m_nIndex; +public: + explicit ListTemplatesEnumWrapper( SwVbaListTemplates* pTemplates ) : m_pListTemplates( pTemplates ), m_nIndex( 1 ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( m_nIndex <= m_pListTemplates->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( m_nIndex <= m_pListTemplates->getCount() ) + return m_pListTemplates->Item( uno::Any( m_nIndex++ ), uno::Any() ); + throw container::NoSuchElementException(); + } +}; + +} + +SwVbaListTemplates::SwVbaListTemplates( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, uno::Reference< text::XTextDocument > xTextDoc, sal_Int32 nType ) : SwVbaListTemplates_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >() ), mxTextDocument(std::move( xTextDoc )), mnGalleryType( nType ) +{ +} + +::sal_Int32 SAL_CALL SwVbaListTemplates::getCount() +{ + // 3 types of list( bullet, numbered and outline ) + return 7; +} + +uno::Any SAL_CALL SwVbaListTemplates::Item( const uno::Any& Index1, const uno::Any& /*not processed in this base class*/ ) +{ + sal_Int32 nIndex = 0; + if( !( Index1 >>= nIndex ) ) + throw uno::RuntimeException(); + if( nIndex <=0 || nIndex > getCount() ) + throw uno::RuntimeException("Index out of bounds" ); + + return uno::Any( uno::Reference< word::XListTemplate >( new SwVbaListTemplate( this, mxContext, mxTextDocument, mnGalleryType, nIndex ) ) ); +} + +// XEnumerationAccess +uno::Type +SwVbaListTemplates::getElementType() +{ + return cppu::UnoType<word::XListTemplate>::get(); +} + +uno::Reference< container::XEnumeration > +SwVbaListTemplates::createEnumeration() +{ + return new ListTemplatesEnumWrapper( this ); +} + +uno::Any +SwVbaListTemplates::createCollectionObject( const css::uno::Any& aSource ) +{ + return aSource; +} + +OUString +SwVbaListTemplates::getServiceImplName() +{ + return "SwVbaListTemplates"; +} + +css::uno::Sequence<OUString> +SwVbaListTemplates::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.ListTemplates" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbalisttemplates.hxx b/sw/source/ui/vba/vbalisttemplates.hxx new file mode 100644 index 0000000000..bf5c34f6ee --- /dev/null +++ b/sw/source/ui/vba/vbalisttemplates.hxx @@ -0,0 +1,52 @@ +/* -*- 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_VBA_VBALISTTEMPLATES_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBALISTTEMPLATES_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XListTemplates.hpp> +#include <com/sun/star/text/XTextDocument.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XListTemplates > SwVbaListTemplates_BASE; + +class SwVbaListTemplates : public SwVbaListTemplates_BASE +{ +private: + css::uno::Reference< css::text::XTextDocument > mxTextDocument; + sal_Int32 mnGalleryType; + +public: + /// @throws css::uno::RuntimeException + SwVbaListTemplates( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, css::uno::Reference< css::text::XTextDocument > xTextDoc, sal_Int32 nType ); + + virtual ::sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index1, const css::uno::Any& /*not processed in this base class*/ ) override; + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaListTemplates_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBALISTTEMPLATES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbamailmerge.cxx b/sw/source/ui/vba/vbamailmerge.cxx new file mode 100644 index 0000000000..479f5dfd7d --- /dev/null +++ b/sw/source/ui/vba/vbamailmerge.cxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column:100 -*- */ +/* + * 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 "vbamailmerge.hxx" + +#include <ooo/vba/word/WdMailMergeMainDocType.hpp> + +SwVbaMailMerge::SwVbaMailMerge(const css::uno::Reference<ooo::vba::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext) + : SwVbaMailMerge_BASE(xParent, xContext) + , m_nMainDocType(ooo::vba::word::WdMailMergeMainDocType::wdNotAMergeDocument) +{ +} + +SwVbaMailMerge::~SwVbaMailMerge() {} + +rtl::Reference<SwVbaMailMerge> const& +SwVbaMailMerge::get(const css::uno::Reference<ooo::vba::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext) +{ + static rtl::Reference<SwVbaMailMerge> xInstance(new SwVbaMailMerge(xParent, xContext)); + + return xInstance; +} + +sal_Int32 SAL_CALL SwVbaMailMerge::getMainDocumentType() { return m_nMainDocType; } + +void SAL_CALL SwVbaMailMerge::setMainDocumentType(sal_Int32 _maindocumenttype) +{ + m_nMainDocType = _maindocumenttype; +} + +// Completely dummy, no-op. +void SAL_CALL SwVbaMailMerge::OpenDataSource( + const OUString&, const css::uno::Any&, const css::uno::Any&, const css::uno::Any&, + const css::uno::Any&, const css::uno::Any&, const css::uno::Any&, const css::uno::Any&, + const css::uno::Any&, const css::uno::Any&, const css::uno::Any&, const css::uno::Any&, + const css::uno::Any&, const css::uno::Any&, const css::uno::Any&, const css::uno::Any&) +{ +} + +OUString SwVbaMailMerge::getServiceImplName() { return "SwVbaMailMerge"; } + +css::uno::Sequence<OUString> SwVbaMailMerge::getServiceNames() +{ + static css::uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.MailMerge" }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbamailmerge.hxx b/sw/source/ui/vba/vbamailmerge.hxx new file mode 100644 index 0000000000..bfc28667d7 --- /dev/null +++ b/sw/source/ui/vba/vbamailmerge.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ +#ifndef INCLUDED_SW_SOURCE_UI_VBA_VBAMAILMERGE_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAMAILMERGE_HXX + +#include <ooo/vba/word/XMailMerge.hpp> +#include <rtl/ref.hxx> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XMailMerge> SwVbaMailMerge_BASE; + +// Singleton class. Get the single instance using the get() method. + +class SwVbaMailMerge : public SwVbaMailMerge_BASE +{ + sal_Int32 m_nMainDocType; + + SwVbaMailMerge(const css::uno::Reference<ooo::vba::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext); + +public: + virtual ~SwVbaMailMerge() override; + + static rtl::Reference<SwVbaMailMerge> const& + get(const css::uno::Reference<ooo::vba::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext); + + // XMailMerge + virtual sal_Int32 SAL_CALL getMainDocumentType() override; + virtual void SAL_CALL setMainDocumentType(sal_Int32 _maindocumenttype) override; + + virtual void SAL_CALL + OpenDataSource(const OUString& Name, const css::uno::Any& Format, + const css::uno::Any& ConfirmConversions, const css::uno::Any& ReadOnly, + const css::uno::Any& LinkToSource, const css::uno::Any& AddToRecentFiles, + const css::uno::Any& PasswordDocument, const css::uno::Any& PasswordTemplate, + const css::uno::Any& Revert, const css::uno::Any& WritePasswordDocument, + const css::uno::Any& WritePasswordTemplate, const css::uno::Any& Connection, + const css::uno::Any& SQLStatement, const css::uno::Any& SQLStatement1, + const css::uno::Any& OpenExclusive, const css::uno::Any& SubType) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAMAILMERGE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaoptions.cxx b/sw/source/ui/vba/vbaoptions.cxx new file mode 100644 index 0000000000..ef74dcd8a6 --- /dev/null +++ b/sw/source/ui/vba/vbaoptions.cxx @@ -0,0 +1,274 @@ +/* -*- 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 "vbaoptions.hxx" +#include <vbahelper/vbahelper.hxx> +#include <ooo/vba/word/WdDefaultFilePath.hpp> +#include <ooo/vba/word/WdLineStyle.hpp> +#include <ooo/vba/word/WdLineWidth.hpp> +#include <ooo/vba/word/WdColorIndex.hpp> +#include <com/sun/star/util/thePathSettings.hpp> +#include <comphelper/processfactory.hxx> +#include <basic/sberrors.hxx> +#include <osl/file.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaOptions::SwVbaOptions( uno::Reference<uno::XComponentContext > const & xContext ) : SwVbaOptions_BASE( uno::Reference< XHelperInterface >(), xContext ) +{ +} + +SwVbaOptions::~SwVbaOptions() +{ +} + +uno::Any SAL_CALL +SwVbaOptions::DefaultFilePath( sal_Int32 _path ) +{ + switch( _path ) + { + case word::WdDefaultFilePath::wdDocumentsPath: + { + msDefaultFilePath = "Work"; + break; + } + case word::WdDefaultFilePath::wdPicturesPath: + { + msDefaultFilePath = "Gallery"; + break; + } + case word::WdDefaultFilePath::wdUserTemplatesPath: + case word::WdDefaultFilePath::wdWorkgroupTemplatesPath: + { + msDefaultFilePath = "Template"; + break; + } + case word::WdDefaultFilePath::wdStartupPath: + { + msDefaultFilePath = "Addin"; + break; + } + case word::WdDefaultFilePath::wdUserOptionsPath: + { + msDefaultFilePath = "UserConfig"; + break; + } + case word::WdDefaultFilePath::wdToolsPath: + case word::WdDefaultFilePath::wdProgramPath: + { + msDefaultFilePath = "Module"; + break; + } + case word::WdDefaultFilePath::wdTempFilePath: + { + msDefaultFilePath = "Temp"; + break; + } + default: + { + DebugHelper::basicexception( ERRCODE_BASIC_NOT_IMPLEMENTED, {} ); + break; + } + } + return uno::Any( uno::Reference< XPropValue > ( new ScVbaPropValue( this ) ) ); +} + +void SwVbaOptions::setValueEvent( const uno::Any& value ) +{ + OUString sNewPath; + value >>= sNewPath; + OUString sNewPathUrl; + ::osl::File::getFileURLFromSystemPath( sNewPath, sNewPathUrl ); + uno::Reference< util::XPathSettings > xPathSettings = util::thePathSettings::get( comphelper::getProcessComponentContext() ); + OUString sOldPathUrl; + xPathSettings->getPropertyValue( msDefaultFilePath ) >>= sOldPathUrl; + // path could be a multipath, Microsoft doesn't support this feature in Word currently + // only the last path is from interest. + sal_Int32 nIndex = sOldPathUrl.lastIndexOf( ';' ); + if( nIndex != -1 ) + { + sNewPathUrl = sOldPathUrl.subView( 0, nIndex + 1 ) + sNewPathUrl; + } + xPathSettings->setPropertyValue( msDefaultFilePath, uno::Any( sNewPathUrl ) ); +} + +uno::Any SwVbaOptions::getValueEvent() +{ + uno::Reference< util::XPathSettings > xPathSettings = util::thePathSettings::get( comphelper::getProcessComponentContext() ); + OUString sPathUrl; + xPathSettings->getPropertyValue( msDefaultFilePath ) >>= sPathUrl; + // path could be a multipath, Microsoft doesn't support this feature in Word currently + // only the last path is from interest. + sal_Int32 nIndex = sPathUrl.lastIndexOf( ';' ); + if( nIndex != -1 ) + { + sPathUrl = sPathUrl.copy( nIndex + 1 ); + } + OUString sPath; + ::osl::File::getSystemPathFromFileURL( sPathUrl, sPath ); + return uno::Any( sPath ); +} + +sal_Int32 SAL_CALL SwVbaOptions::getDefaultBorderLineStyle() +{ + return word::WdLineStyle::wdLineStyleSingle; +} + +void SAL_CALL SwVbaOptions::setDefaultBorderLineStyle( ::sal_Int32 /*_defaultborderlinestyle*/ ) +{ + // not support in Writer +} + +sal_Int32 SAL_CALL SwVbaOptions::getDefaultBorderLineWidth() +{ + return word::WdLineWidth::wdLineWidth050pt; +} + +void SAL_CALL SwVbaOptions::setDefaultBorderLineWidth( ::sal_Int32 /*_defaultborderlinewidth*/ ) +{ + // not support in Writer +} + +sal_Int32 SAL_CALL SwVbaOptions::getDefaultBorderColorIndex() +{ + return word::WdColorIndex::wdAuto; +} + +void SAL_CALL SwVbaOptions::setDefaultBorderColorIndex( ::sal_Int32 /*_defaultbordercolorindex*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL SwVbaOptions::getReplaceSelection() +{ + return true; +} + +void SAL_CALL SwVbaOptions::setReplaceSelection( sal_Bool /*_replaceselection*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL SwVbaOptions::getMapPaperSize() +{ + return false; +} + +void SAL_CALL SwVbaOptions::setMapPaperSize( sal_Bool /*_mappapersize*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL SwVbaOptions::getAutoFormatAsYouTypeApplyHeadings() +{ + return false; +} + +void SAL_CALL SwVbaOptions::setAutoFormatAsYouTypeApplyHeadings( sal_Bool /*_autoformatasyoutypeapplyheadings*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL SwVbaOptions::getAutoFormatAsYouTypeApplyBulletedLists() +{ + return false; +} + +void SAL_CALL SwVbaOptions::setAutoFormatAsYouTypeApplyBulletedLists( sal_Bool /*_autoformatasyoutypeapplybulletedlists*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL SwVbaOptions::getAutoFormatAsYouTypeApplyNumberedLists() +{ + return false; +} + +void SAL_CALL SwVbaOptions::setAutoFormatAsYouTypeApplyNumberedLists( sal_Bool /*_autoformatasyoutypeapplynumberedlists*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL SwVbaOptions::getAutoFormatAsYouTypeFormatListItemBeginning() +{ + return false; +} + +void SAL_CALL SwVbaOptions::setAutoFormatAsYouTypeFormatListItemBeginning( sal_Bool /*_autoformatasyoutypeformatlistitembeginning*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL SwVbaOptions::getAutoFormatAsYouTypeDefineStyles() +{ + return false; +} + +void SAL_CALL SwVbaOptions::setAutoFormatAsYouTypeDefineStyles( sal_Bool /*_autoformatasyoutypedefinestyles*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL SwVbaOptions::getAutoFormatApplyHeadings() +{ + return false; +} + +void SAL_CALL SwVbaOptions::setAutoFormatApplyHeadings( sal_Bool /*_autoformatapplyheadings*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL SwVbaOptions::getAutoFormatApplyLists() +{ + return false; +} + +void SAL_CALL SwVbaOptions::setAutoFormatApplyLists( sal_Bool /*_autoformatapplylists*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL SwVbaOptions::getAutoFormatApplyBulletedLists() +{ + return false; +} + +void SAL_CALL SwVbaOptions::setAutoFormatApplyBulletedLists( sal_Bool /*_autoformatapplybulletedlists*/ ) +{ + // not support in Writer +} + +OUString +SwVbaOptions::getServiceImplName() +{ + return "SwVbaOptions"; +} + +uno::Sequence< OUString > +SwVbaOptions::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Options" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaoptions.hxx b/sw/source/ui/vba/vbaoptions.hxx new file mode 100644 index 0000000000..92994d5589 --- /dev/null +++ b/sw/source/ui/vba/vbaoptions.hxx @@ -0,0 +1,78 @@ +/* -*- 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_VBA_VBAOPTIONS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAOPTIONS_HXX + +#include <ooo/vba/word/XOptions.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <vbahelper/vbapropvalue.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XOptions > SwVbaOptions_BASE; + +class SwVbaOptions : public SwVbaOptions_BASE, + public PropListener +{ +private: + OUString msDefaultFilePath; +public: + explicit SwVbaOptions( css::uno::Reference< css::uno::XComponentContext > const & m_xContext ); + virtual ~SwVbaOptions() override; + + // Attributes + virtual ::sal_Int32 SAL_CALL getDefaultBorderLineStyle() override; + virtual void SAL_CALL setDefaultBorderLineStyle( ::sal_Int32 _defaultborderlinestyle ) override; + virtual ::sal_Int32 SAL_CALL getDefaultBorderLineWidth() override; + virtual void SAL_CALL setDefaultBorderLineWidth( ::sal_Int32 _defaultborderlinewidth ) override; + virtual ::sal_Int32 SAL_CALL getDefaultBorderColorIndex() override; + virtual void SAL_CALL setDefaultBorderColorIndex( ::sal_Int32 _defaultbordercolorindex ) override; + virtual sal_Bool SAL_CALL getReplaceSelection() override; + virtual void SAL_CALL setReplaceSelection( sal_Bool _replaceselection ) override; + virtual sal_Bool SAL_CALL getMapPaperSize() override; + virtual void SAL_CALL setMapPaperSize( sal_Bool _mappapersize ) override; + virtual sal_Bool SAL_CALL getAutoFormatAsYouTypeApplyHeadings() override; + virtual void SAL_CALL setAutoFormatAsYouTypeApplyHeadings( sal_Bool _autoformatasyoutypeapplyheadings ) override; + virtual sal_Bool SAL_CALL getAutoFormatAsYouTypeApplyBulletedLists() override; + virtual void SAL_CALL setAutoFormatAsYouTypeApplyBulletedLists( sal_Bool _autoformatasyoutypeapplybulletedlists ) override; + virtual sal_Bool SAL_CALL getAutoFormatAsYouTypeApplyNumberedLists() override; + virtual void SAL_CALL setAutoFormatAsYouTypeApplyNumberedLists( sal_Bool _autoformatasyoutypeapplynumberedlists ) override; + virtual sal_Bool SAL_CALL getAutoFormatAsYouTypeFormatListItemBeginning() override; + virtual void SAL_CALL setAutoFormatAsYouTypeFormatListItemBeginning( sal_Bool _autoformatasyoutypeformatlistitembeginning ) override; + virtual sal_Bool SAL_CALL getAutoFormatAsYouTypeDefineStyles() override; + virtual void SAL_CALL setAutoFormatAsYouTypeDefineStyles( sal_Bool _autoformatasyoutypedefinestyles ) override; + virtual sal_Bool SAL_CALL getAutoFormatApplyHeadings() override; + virtual void SAL_CALL setAutoFormatApplyHeadings( sal_Bool _autoformatapplyheadings ) override; + virtual sal_Bool SAL_CALL getAutoFormatApplyLists() override; + virtual void SAL_CALL setAutoFormatApplyLists( sal_Bool _autoformatapplylists ) override; + virtual sal_Bool SAL_CALL getAutoFormatApplyBulletedLists() override; + virtual void SAL_CALL setAutoFormatApplyBulletedLists( sal_Bool _autoformatapplybulletedlists ) override; + + // Methods + virtual css::uno::Any SAL_CALL DefaultFilePath( sal_Int32 _path ) override; + + //PropListener + virtual void setValueEvent( const css::uno::Any& value ) override; + virtual css::uno::Any getValueEvent() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAOPTIONS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbapagesetup.cxx b/sw/source/ui/vba/vbapagesetup.cxx new file mode 100644 index 0000000000..b22437dbd2 --- /dev/null +++ b/sw/source/ui/vba/vbapagesetup.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 "vbapagesetup.hxx" +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/text/XPageCursor.hpp> +#include <ooo/vba/word/WdSectionStart.hpp> +#include <ooo/vba/word/WdOrientation.hpp> +#include "wordvbahelper.hxx" + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +SwVbaPageSetup::SwVbaPageSetup(const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< frame::XModel >& xModel, + const uno::Reference< beans::XPropertySet >& xProps ): + SwVbaPageSetup_BASE( xParent, xContext ) +{ + mxModel.set( xModel, uno::UNO_SET_THROW ); + mxPageProps.set( xProps, uno::UNO_SET_THROW ); + mnOrientPortrait = word::WdOrientation::wdOrientPortrait; + mnOrientLandscape = word::WdOrientation::wdOrientLandscape; +} + +double SAL_CALL SwVbaPageSetup::getGutter() +{ + // not support in Writer + return 0; +} + +void SAL_CALL SwVbaPageSetup::setGutter( double _gutter ) +{ + // default add gutter into left margin + if( _gutter != 0 ) + { + double margin = VbaPageSetupBase::getLeftMargin() + _gutter; + VbaPageSetupBase::setLeftMargin( margin ); + } +} + +double SAL_CALL SwVbaPageSetup::getHeaderDistance() +{ + bool isHeaderOn = false; + mxPageProps->getPropertyValue("HeaderIsOn") >>= isHeaderOn; + if( !isHeaderOn ) + mxPageProps->setPropertyValue("HeaderIsOn", uno::Any( true ) ); + return VbaPageSetupBase::getHeaderMargin(); +} + + /** + * changes the value of TopMargin to the value of new MS-Word-HeaderDistance. Subtracts the difference + * between old TopMargin and the new headerDistance from the value of HeaderSpacing (which defines the + * space between the header and the body of the text). calculates the new HeaderHeight (= height of the + * header + headerBodyDistance). + * + * @param: headerDistance is the value that is set in MS Word for the distance from the top of the page + * to the header + */ +void SAL_CALL SwVbaPageSetup::setHeaderDistance( double _headerdistance ) +{ + sal_Int32 newHeaderDistance = Millimeter::getInHundredthsOfOneMillimeter( _headerdistance ); + bool isHeaderOn = false; + sal_Int32 currentTopMargin = 0; + sal_Int32 currentSpacing = 0; + sal_Int32 currentHeaderHeight = 0; + + mxPageProps->getPropertyValue("HeaderIsOn") >>= isHeaderOn; + if( !isHeaderOn ) + mxPageProps->setPropertyValue("HeaderIsOn", uno::Any( true ) ); + + mxPageProps->getPropertyValue("TopMargin") >>= currentTopMargin; + mxPageProps->getPropertyValue("HeaderBodyDistance") >>= currentSpacing; + mxPageProps->getPropertyValue("HeaderHeight") >>= currentHeaderHeight; + + sal_Int32 newSpacing = currentSpacing - ( newHeaderDistance - currentTopMargin ); + sal_Int32 height = currentHeaderHeight - currentSpacing; + sal_Int32 newHeaderHeight = newSpacing + height; + + mxPageProps->setPropertyValue("TopMargin", uno::Any( newHeaderDistance ) ); + mxPageProps->setPropertyValue("HeaderBodyDistance", uno::Any( newSpacing ) ); + mxPageProps->setPropertyValue("HeaderHeight", uno::Any( newHeaderHeight ) ); +} + +double SAL_CALL SwVbaPageSetup::getFooterDistance() +{ + bool isFooterOn = false; + mxPageProps->getPropertyValue("FooterIsOn") >>= isFooterOn; + if( !isFooterOn ) + mxPageProps->setPropertyValue("FooterIsOn", uno::Any( true ) ); + return VbaPageSetupBase::getFooterMargin(); +} + +void SAL_CALL SwVbaPageSetup::setFooterDistance( double _footerdistance ) +{ + sal_Int32 newFooterDistance = Millimeter::getInHundredthsOfOneMillimeter( _footerdistance ); + bool isFooterOn = false; + sal_Int32 currentBottomMargin = 0; + sal_Int32 currentSpacing = 0; + sal_Int32 currentFooterHeight = 0; + + mxPageProps->getPropertyValue("FooterIsOn") >>= isFooterOn; + if( !isFooterOn ) + mxPageProps->setPropertyValue("FooterIsOn", uno::Any( true ) ); + + mxPageProps->getPropertyValue("BottomMargin") >>= currentBottomMargin; + mxPageProps->getPropertyValue("FooterBodyDistance") >>= currentSpacing; + mxPageProps->getPropertyValue("FooterHeight") >>= currentFooterHeight; + + sal_Int32 newSpacing = currentSpacing - ( newFooterDistance - currentBottomMargin ); + sal_Int32 height = currentFooterHeight - currentSpacing; + sal_Int32 newFooterHeight = newSpacing + height; + + mxPageProps->setPropertyValue("BottomMargin", uno::Any( newFooterDistance ) ); + mxPageProps->setPropertyValue("FooterBodyDistance", uno::Any( newSpacing ) ); + mxPageProps->setPropertyValue("FooterHeight", uno::Any( newFooterHeight ) ); +} + +sal_Bool SAL_CALL SwVbaPageSetup::getDifferentFirstPageHeaderFooter() +{ + OUString pageStyle = getStyleOfFirstPage(); + if ( pageStyle == "First Page" ) + return true; + + return false; +} + +void SAL_CALL SwVbaPageSetup::setDifferentFirstPageHeaderFooter( sal_Bool status ) +{ + if( status == getDifferentFirstPageHeaderFooter() ) + return; + + OUString newStyle; + if( status ) + newStyle = "First Page"; + else + newStyle = "Standard"; + + uno::Reference< beans::XPropertySet > xStyleProps( word::getCurrentPageStyle( mxModel ), uno::UNO_QUERY_THROW ); + sal_Int32 nTopMargin = 0; + xStyleProps->getPropertyValue("TopMargin") >>= nTopMargin; + sal_Int32 nBottomMargin = 0; + xStyleProps->getPropertyValue("BottomMargin") >>= nBottomMargin; + sal_Int32 nLeftMargin = 0; + xStyleProps->getPropertyValue("LeftMargin") >>= nLeftMargin; + sal_Int32 nRightMargin = 0; + xStyleProps->getPropertyValue("RightMargin") >>= nRightMargin; + sal_Int32 nHeaderHeight = 0; + xStyleProps->getPropertyValue("HeaderHeight") >>= nHeaderHeight; + sal_Int32 nFooterHeight = 0; + xStyleProps->getPropertyValue("FooterHeight") >>= nFooterHeight; + + bool isHeaderOn = false; + xStyleProps->getPropertyValue("HeaderIsOn") >>= isHeaderOn; + if( isHeaderOn ) + { + nTopMargin += nHeaderHeight; + nBottomMargin += nFooterHeight; + xStyleProps->setPropertyValue("HeaderIsOn", uno::Any( false ) ); + xStyleProps->setPropertyValue("FooterIsOn", uno::Any( false ) ); + } + uno::Reference< text::XPageCursor > xPageCursor( word::getXTextViewCursor( mxModel ), uno::UNO_QUERY_THROW ); + if( xPageCursor->getPage() != 1 ) + { + xPageCursor->jumpToFirstPage(); + } + + uno::Reference< beans::XPropertySet > xCursorProps( xPageCursor, uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xTableProps( xCursorProps->getPropertyValue("TextTable"), uno::UNO_QUERY ); + if( xTableProps.is() ) + { + xTableProps->setPropertyValue("PageDescName", uno::Any( newStyle ) ); + } + else + { + xCursorProps->setPropertyValue("PageDescName", uno::Any( newStyle ) ); + } + + uno::Reference< beans::XPropertySet > xFirstPageProps( word::getCurrentPageStyle( mxModel ), uno::UNO_QUERY_THROW ); + xFirstPageProps->setPropertyValue("TopMargin", uno::Any( nTopMargin ) ); + xFirstPageProps->setPropertyValue("BottomMargin", uno::Any( nBottomMargin ) ); + xFirstPageProps->setPropertyValue("LeftMargin", uno::Any( nLeftMargin ) ); + xFirstPageProps->setPropertyValue("RightMargin", uno::Any( nRightMargin ) ); +} + +OUString SwVbaPageSetup::getStyleOfFirstPage() const +{ + OUString styleFirstPage; + uno::Reference< text::XPageCursor > xPageCursor( word::getXTextViewCursor( mxModel ), uno::UNO_QUERY_THROW ); + if( xPageCursor->getPage() != 1 ) + { + xPageCursor->jumpToFirstPage(); + } + + uno::Reference< beans::XPropertySet > xCursorProps( xPageCursor, uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xTableProps( xCursorProps->getPropertyValue("TextTable"), uno::UNO_QUERY ); + if( xTableProps.is() ) + { + xTableProps->getPropertyValue("PageDescName") >>= styleFirstPage; + } + else + { + xCursorProps->getPropertyValue("PageDescName") >>= styleFirstPage; + } + return styleFirstPage; +} + +::sal_Int32 SAL_CALL SwVbaPageSetup::getSectionStart() +{ + // FIXME: + sal_Int32 wdSectionStart = word::WdSectionStart::wdSectionNewPage; + uno::Reference< container::XNamed > xNamed( mxPageProps, uno::UNO_QUERY_THROW ); + OUString sStyleName = xNamed->getName(); + if ( sStyleName == "Left Page" ) + wdSectionStart = word::WdSectionStart::wdSectionEvenPage; + else if ( sStyleName == "Right Page" ) + wdSectionStart = word::WdSectionStart::wdSectionOddPage; + else + wdSectionStart = word::WdSectionStart::wdSectionNewPage; + return wdSectionStart; +} + +void SAL_CALL SwVbaPageSetup::setSectionStart( ::sal_Int32 /*_sectionstart*/ ) +{ + // fail to find corresponding feature in Writer + // #FIXME: +} + +OUString +SwVbaPageSetup::getServiceImplName() +{ + return "SwVbaPageSetup"; +} + +uno::Sequence< OUString > +SwVbaPageSetup::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.PageSetup" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbapagesetup.hxx b/sw/source/ui/vba/vbapagesetup.hxx new file mode 100644 index 0000000000..b6b9c01551 --- /dev/null +++ b/sw/source/ui/vba/vbapagesetup.hxx @@ -0,0 +1,62 @@ +/* -*- 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_VBA_VBAPAGESETUP_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAPAGESETUP_HXX + +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/word/XPageSetup.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <vbahelper/vbapagesetupbase.hxx> + +typedef cppu::ImplInheritanceHelper< VbaPageSetupBase, ooo::vba::word::XPageSetup > SwVbaPageSetup_BASE; + +class SwVbaPageSetup : public SwVbaPageSetup_BASE +{ +private: + /// @throws css::uno::RuntimeException + OUString getStyleOfFirstPage() const; + +public: + /// @throws css::uno::RuntimeException + SwVbaPageSetup( const css::uno::Reference< ooo::vba::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::frame::XModel >& xModel, + const css::uno::Reference< css::beans::XPropertySet >& xProps ); + + // Attributes + virtual double SAL_CALL getGutter() override; + virtual void SAL_CALL setGutter( double _gutter ) override; + virtual double SAL_CALL getHeaderDistance() override; + virtual void SAL_CALL setHeaderDistance( double _headerdistance ) override; + virtual double SAL_CALL getFooterDistance() override; + virtual void SAL_CALL setFooterDistance( double _footerdistance ) override; + virtual sal_Bool SAL_CALL getDifferentFirstPageHeaderFooter() override; + virtual void SAL_CALL setDifferentFirstPageHeaderFooter( sal_Bool status ) override; + virtual ::sal_Int32 SAL_CALL getSectionStart() override; + virtual void SAL_CALL setSectionStart( ::sal_Int32 _sectionstart ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbapalette.cxx b/sw/source/ui/vba/vbapalette.cxx new file mode 100644 index 0000000000..351f2711c5 --- /dev/null +++ b/sw/source/ui/vba/vbapalette.cxx @@ -0,0 +1,93 @@ +/* -*- 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 "vbapalette.hxx" +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <ooo/vba/word/WdColor.hpp> +#include <sal/macros.h> + +using namespace ::ooo::vba; +using namespace ::ooo::vba::word; +using namespace ::com::sun::star; + +const sal_Int32 ColorTable[] = +{ +WdColor::wdColorAutomatic, // 0 +WdColor::wdColorBlack, // 1 +WdColor::wdColorBlue, // 2 +WdColor::wdColorTurquoise, // 3 +WdColor::wdColorBrightGreen, // 4 +WdColor::wdColorPink, // 5 +WdColor::wdColorRed, // 6 +WdColor::wdColorYellow, // 7 +WdColor::wdColorWhite, // 8 +WdColor::wdColorDarkBlue, // 9 +WdColor::wdColorTeal, // 10 +WdColor::wdColorGreen, // 11 +WdColor::wdColorViolet, // 12 +WdColor::wdColorDarkRed, // 13 +WdColor::wdColorDarkYellow, // 14 +WdColor::wdColorGray50, // 15 +WdColor::wdColorGray25, // 16 +}; + +typedef ::cppu::WeakImplHelper< container::XIndexAccess > XIndexAccess_BASE; + +namespace { + +class DefaultPalette : public XIndexAccess_BASE +{ +public: + DefaultPalette(){} + + // Methods XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount() override + { + return SAL_N_ELEMENTS(ColorTable); + } + + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + if ( Index < 0 || Index >= getCount() ) + throw lang::IndexOutOfBoundsException(); + return uno::Any( sal_Int32( ColorTable[ Index ] ) ); + } + + // Methods XElementAccess + virtual uno::Type SAL_CALL getElementType() override + { + return ::cppu::UnoType<sal_Int32>::get(); + } + virtual sal_Bool SAL_CALL hasElements() override + { + return true; + } + +}; + +} + +VbaPalette::VbaPalette() + : mxPalette(new DefaultPalette()) +{ +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbapalette.hxx b/sw/source/ui/vba/vbapalette.hxx new file mode 100644 index 0000000000..cbf639301f --- /dev/null +++ b/sw/source/ui/vba/vbapalette.hxx @@ -0,0 +1,37 @@ +/* -*- 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_VBA_VBAPALETTE_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAPALETTE_HXX + +#include <com/sun/star/container/XIndexAccess.hpp> + +class VbaPalette +{ + css::uno::Reference< css::container::XIndexAccess > mxPalette; +public: + VbaPalette(); + // if no palette available e.g. because the document doesn't have a + // palette defined then a default palette will be returned. + const css::uno::Reference< css::container::XIndexAccess >& getPalette() const { return mxPalette;} +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbapane.cxx b/sw/source/ui/vba/vbapane.cxx new file mode 100644 index 0000000000..64a7c411c7 --- /dev/null +++ b/sw/source/ui/vba/vbapane.cxx @@ -0,0 +1,65 @@ +/* -*- 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 "vbapane.hxx" +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include "vbaview.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaPane::SwVbaPane( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, + uno::Reference< frame::XModel > xModel ) : + SwVbaPane_BASE( rParent, rContext ), mxModel(std::move( xModel )) +{ +} + +SwVbaPane::~SwVbaPane() +{ +} + +uno::Any SAL_CALL +SwVbaPane::View() +{ + return uno::Any( uno::Reference< word::XView >( new SwVbaView( this, mxContext, mxModel ) ) ); +} + +void SAL_CALL +SwVbaPane::Close( ) +{ + dispatchRequests( mxModel,".uno:CloseWin" ); +} + +OUString +SwVbaPane::getServiceImplName() +{ + return "SwVbaPane"; +} + +uno::Sequence< OUString > +SwVbaPane::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Pane" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbapane.hxx b/sw/source/ui/vba/vbapane.hxx new file mode 100644 index 0000000000..e0a81b9e0f --- /dev/null +++ b/sw/source/ui/vba/vbapane.hxx @@ -0,0 +1,49 @@ +/* -*- 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_VBA_VBAPANE_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAPANE_HXX + +#include <ooo/vba/word/XPane.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XPane> SwVbaPane_BASE; + +class SwVbaPane : public SwVbaPane_BASE +{ +private: + css::uno::Reference<css::frame::XModel> mxModel; + +public: + /// @throws css::uno::RuntimeException + SwVbaPane(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext, + css::uno::Reference<css::frame::XModel> xModel); + virtual ~SwVbaPane() override; + + // Methods + virtual css::uno::Any SAL_CALL View() override; + virtual void SAL_CALL Close() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAPANE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbapanes.cxx b/sw/source/ui/vba/vbapanes.cxx new file mode 100644 index 0000000000..05b288e290 --- /dev/null +++ b/sw/source/ui/vba/vbapanes.cxx @@ -0,0 +1,119 @@ +/* -*- 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 "vbapanes.hxx" +#include "vbapane.hxx" +#include <cppuhelper/implbase.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +// I assume there is only one pane in Writer +class PanesIndexAccess : public ::cppu::WeakImplHelper<container::XIndexAccess > +{ +private: + uno::Reference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< frame::XModel > mxModel; + +public: + PanesIndexAccess( uno::Reference< XHelperInterface > xParent, uno::Reference< uno::XComponentContext > xContext, uno::Reference< frame::XModel > xModel ) : mxParent(std::move( xParent )), mxContext(std::move( xContext )), mxModel(std::move( xModel )) {} + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount( ) override + { + return 1; + } + virtual uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override + { + if( Index != 0 ) + throw lang::IndexOutOfBoundsException(); + return uno::Any( uno::Reference< word::XPane >( new SwVbaPane( mxParent, mxContext, mxModel ) ) ); + } + virtual uno::Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<word::XPane>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + return true; + } +}; + +class PanesEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference<container::XIndexAccess > m_xIndexAccess; + sal_Int32 m_nIndex; +public: + explicit PanesEnumWrapper( uno::Reference< container::XIndexAccess > xIndexAccess ) : m_xIndexAccess(std::move( xIndexAccess )), m_nIndex( 0 ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( m_nIndex < m_xIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( m_nIndex < m_xIndexAccess->getCount() ) + return m_xIndexAccess->getByIndex( m_nIndex++ ); + throw container::NoSuchElementException(); + } +}; + +} + +SwVbaPanes::SwVbaPanes( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< frame::XModel >& xModel ): SwVbaPanes_BASE( xParent, xContext, new PanesIndexAccess( xParent, xContext, xModel ) ) +{ +} +// XEnumerationAccess +uno::Type +SwVbaPanes::getElementType() +{ + return cppu::UnoType<word::XPane>::get(); +} +uno::Reference< container::XEnumeration > +SwVbaPanes::createEnumeration() +{ + return new PanesEnumWrapper( m_xIndexAccess ); +} + +uno::Any +SwVbaPanes::createCollectionObject( const css::uno::Any& aSource ) +{ + return aSource; +} + +OUString +SwVbaPanes::getServiceImplName() +{ + return "SwVbaPanes"; +} + +css::uno::Sequence<OUString> +SwVbaPanes::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.Panes" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbapanes.hxx b/sw/source/ui/vba/vbapanes.hxx new file mode 100644 index 0000000000..27a6d65671 --- /dev/null +++ b/sw/source/ui/vba/vbapanes.hxx @@ -0,0 +1,41 @@ +/* -*- 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 . + */ +#pragma once + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XPanes.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XPanes > SwVbaPanes_BASE; + +class SwVbaPanes : public SwVbaPanes_BASE +{ +public: + SwVbaPanes( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xModel ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaPanes_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaparagraph.cxx b/sw/source/ui/vba/vbaparagraph.cxx new file mode 100644 index 0000000000..19a3127959 --- /dev/null +++ b/sw/source/ui/vba/vbaparagraph.cxx @@ -0,0 +1,179 @@ +/* -*- 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 "vbaparagraph.hxx" +#include "vbarange.hxx" +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/implbase.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaParagraph::SwVbaParagraph( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< text::XTextDocument > xDocument, uno::Reference< text::XTextRange > xTextRange ) : + SwVbaParagraph_BASE( rParent, rContext ), mxTextDocument(std::move( xDocument )), mxTextRange(std::move( xTextRange )) +{ +} + +SwVbaParagraph::~SwVbaParagraph() +{ +} + +uno::Reference< word::XRange > SAL_CALL +SwVbaParagraph::getRange( ) +{ + return uno::Reference< word::XRange >( new SwVbaRange( this, mxContext, mxTextDocument, mxTextRange->getStart(), mxTextRange->getEnd(), mxTextRange->getText() ) ); +} + +uno::Any SAL_CALL +SwVbaParagraph::getStyle( ) +{ + uno::Reference< word::XRange > xRange = getRange(); + return xRange->getStyle(); +} + +void SAL_CALL +SwVbaParagraph::setStyle( const uno::Any& style ) +{ + uno::Reference< word::XRange > xRange = getRange(); + xRange->setStyle( style ); +} + +OUString +SwVbaParagraph::getServiceImplName() +{ + return "SwVbaParagraph"; +} + +uno::Sequence< OUString > +SwVbaParagraph::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Paragraph" + }; + return aServiceNames; +} + +namespace { + +class ParagraphCollectionHelper : public ::cppu::WeakImplHelper< container::XIndexAccess, + container::XEnumerationAccess > +{ +private: + uno::Reference< text::XTextDocument > mxTextDocument; + + /// @throws uno::RuntimeException + uno::Reference< container::XEnumeration > getEnumeration() + { + uno::Reference< container::XEnumerationAccess > xParEnumAccess( mxTextDocument->getText(), uno::UNO_QUERY_THROW ); + return xParEnumAccess->createEnumeration(); + } + +public: + /// @throws uno::RuntimeException + explicit ParagraphCollectionHelper( uno::Reference< text::XTextDocument > xDocument ): mxTextDocument(std::move( xDocument )) + { + } + // XElementAccess + virtual uno::Type SAL_CALL getElementType( ) override { return cppu::UnoType<text::XTextRange>::get(); } + virtual sal_Bool SAL_CALL hasElements( ) override { return true; } + // XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount( ) override + { + sal_Int32 nCount = 0; + uno::Reference< container::XEnumeration > xParEnum = getEnumeration(); + while( xParEnum->hasMoreElements() ) + { + uno::Reference< lang::XServiceInfo > xServiceInfo( xParEnum->nextElement(), uno::UNO_QUERY_THROW ); + if( xServiceInfo->supportsService("com.sun.star.text.Paragraph") ) + { + nCount++; + } + } + return nCount; + } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + if( Index < getCount() ) + { + sal_Int32 nCount = 0; + uno::Reference< container::XEnumeration > xParEnum = getEnumeration(); + while( xParEnum->hasMoreElements() ) + { + uno::Reference< lang::XServiceInfo > xServiceInfo( xParEnum->nextElement(), uno::UNO_QUERY_THROW ); + if( xServiceInfo->supportsService("com.sun.star.text.Paragraph") ) + { + if( Index == nCount ) + return uno::Any( xServiceInfo ); + nCount++; + } + } + } + throw lang::IndexOutOfBoundsException(); + } + // XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + return getEnumeration(); + } +}; + +} + +SwVbaParagraphs::SwVbaParagraphs( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext > & xContext, const uno::Reference< text::XTextDocument >& xDocument ) : SwVbaParagraphs_BASE( xParent, xContext, new ParagraphCollectionHelper( xDocument ) ), mxTextDocument( xDocument ) +{ +} + +// XEnumerationAccess +uno::Type +SwVbaParagraphs::getElementType() +{ + return cppu::UnoType<word::XParagraph>::get(); +} +uno::Reference< container::XEnumeration > +SwVbaParagraphs::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumerationAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return xEnumerationAccess->createEnumeration(); +} + +uno::Any +SwVbaParagraphs::createCollectionObject( const css::uno::Any& aSource ) +{ + uno::Reference< text::XTextRange > xTextRange( aSource, uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< word::XParagraph >( new SwVbaParagraph( this, mxContext, mxTextDocument, xTextRange ) ) ); +} + +OUString +SwVbaParagraphs::getServiceImplName() +{ + return "SwVbaParagraphs"; +} + +css::uno::Sequence<OUString> +SwVbaParagraphs::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.Paragraphs" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaparagraph.hxx b/sw/source/ui/vba/vbaparagraph.hxx new file mode 100644 index 0000000000..6c35455614 --- /dev/null +++ b/sw/source/ui/vba/vbaparagraph.hxx @@ -0,0 +1,74 @@ +/* -*- 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_VBA_VBAPARAGRAPH_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAPARAGRAPH_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XParagraphs.hpp> +#include <ooo/vba/word/XParagraph.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/text/XTextDocument.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XParagraph > SwVbaParagraph_BASE; + +class SwVbaParagraph : public SwVbaParagraph_BASE +{ +private: + css::uno::Reference< css::text::XTextDocument > mxTextDocument; + css::uno::Reference< css::text::XTextRange > mxTextRange; + +public: + /// @throws css::uno::RuntimeException + SwVbaParagraph( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::text::XTextDocument > xDocument, css::uno::Reference< css::text::XTextRange > xTextRange ); + virtual ~SwVbaParagraph() override; + + // XParagraph + virtual css::uno::Reference< ooo::vba::word::XRange > SAL_CALL getRange() override; + virtual css::uno::Any SAL_CALL getStyle() override; + virtual void SAL_CALL setStyle( const css::uno::Any& style ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +typedef CollTestImplHelper< ooo::vba::word::XParagraphs > SwVbaParagraphs_BASE; + +class SwVbaParagraphs : public SwVbaParagraphs_BASE +{ +private: + css::uno::Reference< css::text::XTextDocument > mxTextDocument; +public: + /// @throws css::uno::RuntimeException + SwVbaParagraphs( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::text::XTextDocument >& xDocument ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaParagraphs_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAPARAGRAPH_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaparagraphformat.cxx b/sw/source/ui/vba/vbaparagraphformat.cxx new file mode 100644 index 0000000000..4e5a61fdeb --- /dev/null +++ b/sw/source/ui/vba/vbaparagraphformat.cxx @@ -0,0 +1,567 @@ +/* -*- 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 "vbaparagraphformat.hxx" +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include <basic/sberrors.hxx> +#include <com/sun/star/style/LineSpacingMode.hpp> +#include <ooo/vba/word/WdLineSpacing.hpp> +#include <ooo/vba/word/WdParagraphAlignment.hpp> +#include <ooo/vba/word/WdOutlineLevel.hpp> +#include <com/sun/star/style/ParagraphAdjust.hpp> +#include <com/sun/star/style/BreakType.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include "vbatabstops.hxx" +#include <o3tl/string_view.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +const sal_Int16 CHARACTER_INDENT_FACTOR = 12; +const sal_Int16 PERCENT100 = 100; +const sal_Int16 PERCENT150 = 150; +const sal_Int16 PERCENT200 = 200; + +SwVbaParagraphFormat::SwVbaParagraphFormat( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< beans::XPropertySet > xParaProps ) : SwVbaParagraphFormat_BASE( rParent, rContext ), mxParaProps(std::move( xParaProps )) +{ +} + +SwVbaParagraphFormat::~SwVbaParagraphFormat() +{ +} + +sal_Int32 SAL_CALL SwVbaParagraphFormat::getAlignment() +{ + style::ParagraphAdjust aParaAdjust = style::ParagraphAdjust_LEFT; + mxParaProps->getPropertyValue("ParaAdjust") >>= aParaAdjust; + return getMSWordAlignment( aParaAdjust ); +} + +void SAL_CALL SwVbaParagraphFormat::setAlignment( sal_Int32 _alignment ) +{ + style::ParagraphAdjust aParaAdjust = getOOoAlignment( _alignment ); + mxParaProps->setPropertyValue("ParaAdjust", uno::Any( aParaAdjust ) ); +} + +float SAL_CALL SwVbaParagraphFormat::getFirstLineIndent() +{ + sal_Int32 indent = 0; + mxParaProps->getPropertyValue("ParaFirstLineIndent") >>= indent; + return static_cast<float>( Millimeter::getInPoints( indent ) ); +} + +void SAL_CALL SwVbaParagraphFormat::setFirstLineIndent( float _firstlineindent ) +{ + sal_Int32 indent = Millimeter::getInHundredthsOfOneMillimeter( _firstlineindent ); + mxParaProps->setPropertyValue("ParaFirstLineIndent", uno::Any( indent ) ); +} + +uno::Any SAL_CALL SwVbaParagraphFormat::getKeepTogether() +{ + bool bKeep = false; + mxParaProps->getPropertyValue("ParaKeepTogether") >>= bKeep; + return uno::Any ( bKeep ); +} + +void SAL_CALL SwVbaParagraphFormat::setKeepTogether( const uno::Any& _keeptogether ) +{ + bool bKeep = false; + if( _keeptogether >>= bKeep ) + { + mxParaProps->setPropertyValue("ParaKeepTogether", uno::Any( bKeep ) ); + } + else + { + DebugHelper::runtimeexception( ERRCODE_BASIC_BAD_PARAMETER ); + } +} + +uno::Any SAL_CALL SwVbaParagraphFormat::getKeepWithNext() +{ + bool bKeep = false; + mxParaProps->getPropertyValue("ParaSplit") >>= bKeep; + return uno::Any ( bKeep ); +} + +void SAL_CALL SwVbaParagraphFormat::setKeepWithNext( const uno::Any& _keepwithnext ) +{ + bool bKeep = false; + if( _keepwithnext >>= bKeep ) + { + mxParaProps->setPropertyValue("ParaSplit", uno::Any( bKeep ) ); + } + else + { + DebugHelper::runtimeexception( ERRCODE_BASIC_BAD_PARAMETER ); + } +} + +uno::Any SAL_CALL SwVbaParagraphFormat::getHyphenation() +{ + bool bHypn = false; + mxParaProps->getPropertyValue("ParaIsHyphenation") >>= bHypn; + return uno::Any ( bHypn ); +} + +void SAL_CALL SwVbaParagraphFormat::setHyphenation( const uno::Any& _hyphenation ) +{ + bool bHypn = false; + if( _hyphenation >>= bHypn ) + { + mxParaProps->setPropertyValue("ParaIsHyphenation", uno::Any( bHypn ) ); + } + else + { + DebugHelper::runtimeexception( ERRCODE_BASIC_BAD_PARAMETER ); + } +} + +float SAL_CALL SwVbaParagraphFormat::getLineSpacing() +{ + style::LineSpacing aLineSpacing; + mxParaProps->getPropertyValue("ParaLineSpacing") >>= aLineSpacing; + return getMSWordLineSpacing( aLineSpacing ); +} + +void SAL_CALL SwVbaParagraphFormat::setLineSpacing( float _linespacing ) +{ + style::LineSpacing aLineSpacing; + mxParaProps->getPropertyValue("ParaLineSpacing") >>= aLineSpacing; + aLineSpacing = getOOoLineSpacing( _linespacing, aLineSpacing.Mode ); + mxParaProps->setPropertyValue("ParaLineSpacing", uno::Any( aLineSpacing ) ); +} + +sal_Int32 SAL_CALL SwVbaParagraphFormat::getLineSpacingRule() +{ + style::LineSpacing aLineSpacing; + mxParaProps->getPropertyValue("ParaLineSpacing") >>= aLineSpacing; + return getMSWordLineSpacingRule( aLineSpacing ); +} + +void SAL_CALL SwVbaParagraphFormat::setLineSpacingRule( sal_Int32 _linespacingrule ) +{ + style::LineSpacing aLineSpacing = getOOoLineSpacingFromRule( _linespacingrule ); + mxParaProps->setPropertyValue("ParaLineSpacing", uno::Any( aLineSpacing ) ); +} + +uno::Any SAL_CALL SwVbaParagraphFormat::getNoLineNumber() +{ + bool noLineNum = false; + mxParaProps->getPropertyValue("ParaLineNumberCount") >>= noLineNum; + return uno::Any ( noLineNum ); +} + +void SAL_CALL SwVbaParagraphFormat::setNoLineNumber( const uno::Any& _nolinenumber ) +{ + bool noLineNum = false; + if( _nolinenumber >>= noLineNum ) + { + mxParaProps->setPropertyValue("ParaLineNumberCount", uno::Any( noLineNum ) ); + } + else + { + DebugHelper::runtimeexception( ERRCODE_BASIC_BAD_PARAMETER ); + } +} + +sal_Int32 SAL_CALL SwVbaParagraphFormat::getOutlineLevel() +{ + sal_Int32 nLevel = word::WdOutlineLevel::wdOutlineLevelBodyText; + OUString aHeading; + static constexpr OUString HEADING = u"Heading"_ustr; + mxParaProps->getPropertyValue("ParaStyleName") >>= aHeading; + if( aHeading.startsWith( HEADING ) ) + { + // get the sub string after "Heading" + nLevel = o3tl::toInt32(aHeading.subView( HEADING.getLength() )); + } + return nLevel; +} + +void SAL_CALL SwVbaParagraphFormat::setOutlineLevel( sal_Int32 _outlinelevel ) +{ + if( _outlinelevel != getOutlineLevel() ) + { + // TODO: in my test in msword, there is no effect for this function. + } +} + +uno::Any SAL_CALL SwVbaParagraphFormat::getPageBreakBefore() +{ + style::BreakType aBreakType; + mxParaProps->getPropertyValue("BreakType") >>= aBreakType; + bool bBreakBefore = ( aBreakType == style::BreakType_PAGE_BEFORE || aBreakType == style::BreakType_PAGE_BOTH ); + return uno::Any( bBreakBefore ); +} + +void SAL_CALL SwVbaParagraphFormat::setPageBreakBefore( const uno::Any& _breakbefore ) +{ + bool bBreakBefore = false; + if( _breakbefore >>= bBreakBefore ) + { + style::BreakType aBreakType; + mxParaProps->getPropertyValue("BreakType") >>= aBreakType; + if( bBreakBefore ) + { + if( aBreakType == style::BreakType_NONE ) + aBreakType = style::BreakType_PAGE_BEFORE; + else if ( aBreakType == style::BreakType_PAGE_AFTER ) + aBreakType = style::BreakType_PAGE_BOTH; + } + else + { + if( aBreakType == style::BreakType_PAGE_BOTH ) + aBreakType = style::BreakType_PAGE_AFTER; + else if ( aBreakType == style::BreakType_PAGE_BEFORE ) + aBreakType = style::BreakType_PAGE_AFTER; + } + mxParaProps->setPropertyValue("BreakType", uno::Any( aBreakType ) ); + } + else + { + DebugHelper::runtimeexception( ERRCODE_BASIC_BAD_PARAMETER ); + } +} + +float SAL_CALL SwVbaParagraphFormat::getSpaceBefore() +{ + sal_Int32 nSpace = 0; + mxParaProps->getPropertyValue("ParaTopMargin") >>= nSpace; + return static_cast<float>( Millimeter::getInPoints( nSpace ) ); +} + +void SAL_CALL SwVbaParagraphFormat::setSpaceBefore( float _space ) +{ + sal_Int32 nSpace = Millimeter::getInHundredthsOfOneMillimeter( _space ); + mxParaProps->setPropertyValue("ParaTopMargin", uno::Any( nSpace ) ); +} + +float SAL_CALL SwVbaParagraphFormat::getSpaceAfter() +{ + sal_Int32 nSpace = 0; + mxParaProps->getPropertyValue("ParaBottomMargin") >>= nSpace; + return static_cast<float>( Millimeter::getInPoints( nSpace ) ); +} + +void SAL_CALL SwVbaParagraphFormat::setSpaceAfter( float _space ) +{ + sal_Int32 nSpace = Millimeter::getInHundredthsOfOneMillimeter( _space ); + mxParaProps->setPropertyValue("ParaBottomMargin", uno::Any( nSpace ) ); +} + +float SAL_CALL SwVbaParagraphFormat::getLeftIndent() +{ + sal_Int32 nIndent = 0; + mxParaProps->getPropertyValue("ParaLeftMargin") >>= nIndent; + return static_cast<float>( Millimeter::getInPoints( nIndent ) ); +} + +void SAL_CALL SwVbaParagraphFormat::setLeftIndent( float _leftindent ) +{ + sal_Int32 nIndent = Millimeter::getInHundredthsOfOneMillimeter( _leftindent ); + mxParaProps->setPropertyValue("ParaLeftMargin", uno::Any( nIndent ) ); +} + +float SAL_CALL SwVbaParagraphFormat::getRightIndent() +{ + sal_Int32 nIndent = 0; + mxParaProps->getPropertyValue("ParaRightMargin") >>= nIndent; + return static_cast<float>( Millimeter::getInPoints( nIndent ) ); +} + +void SAL_CALL SwVbaParagraphFormat::setRightIndent( float _rightindent ) +{ + sal_Int32 nIndent = Millimeter::getInHundredthsOfOneMillimeter( _rightindent ); + mxParaProps->setPropertyValue("ParaRightMargin", uno::Any( nIndent ) ); +} + +uno::Any SAL_CALL SwVbaParagraphFormat::getTabStops() +{ + return uno::Any( uno::Reference< word::XTabStops >( new SwVbaTabStops( this, mxContext, mxParaProps ) ) ); +} + +void SAL_CALL SwVbaParagraphFormat::setTabStops( const uno::Any& /*_tabstops*/ ) +{ + throw uno::RuntimeException("Not implemented" ); +} + +uno::Any SAL_CALL SwVbaParagraphFormat::getWidowControl() +{ + sal_Int8 nWidow = 0; + mxParaProps->getPropertyValue("ParaWidows") >>= nWidow; + sal_Int8 nOrphan = 0; + mxParaProps->getPropertyValue("ParaOrphans") >>= nOrphan; + // if the amount of single lines on one page > 1 and the same of start and end of the paragraph, + // true is returned. + bool bWidow = ( nWidow > 1 && nOrphan == nWidow ); + return uno::Any( bWidow ); +} + +void SAL_CALL SwVbaParagraphFormat::setWidowControl( const uno::Any& _widowcontrol ) +{ + // if we get true, the part of the paragraph on one page has to be + // at least two lines + bool bWidow = false; + if( _widowcontrol >>= bWidow ) + { + sal_Int8 nControl = bWidow? 2:1; + mxParaProps->setPropertyValue("ParaWidows", uno::Any( nControl ) ); + mxParaProps->setPropertyValue("ParaOrphans", uno::Any( nControl ) ); + } + else + { + DebugHelper::runtimeexception( ERRCODE_BASIC_BAD_PARAMETER ); + } +} + +style::LineSpacing SwVbaParagraphFormat::getOOoLineSpacing( float _lineSpace, sal_Int16 mode ) +{ + style::LineSpacing aLineSpacing; + if( mode != style::LineSpacingMode::MINIMUM && mode != style::LineSpacingMode::FIX ) + { + // special behaviour of word: if the space is set to these values, the rule and + // the height are changed accordingly + if( _lineSpace == CHARACTER_INDENT_FACTOR ) + { + aLineSpacing.Mode = style::LineSpacingMode::PROP; + aLineSpacing.Height = PERCENT100; + } + else if( _lineSpace == CHARACTER_INDENT_FACTOR * 1.5 ) // no rounding issues, == 18 + { + aLineSpacing.Mode = style::LineSpacingMode::PROP; + aLineSpacing.Height = PERCENT150; + } + else if( _lineSpace == CHARACTER_INDENT_FACTOR * 2 ) + { + aLineSpacing.Mode = style::LineSpacingMode::PROP; + aLineSpacing.Height = PERCENT200; + } + else + { + aLineSpacing.Mode = style::LineSpacingMode::FIX; + aLineSpacing.Height = static_cast<sal_Int16>( Millimeter::getInHundredthsOfOneMillimeter( _lineSpace ) ); + } + } + else + { + aLineSpacing.Mode = mode; + aLineSpacing.Height = static_cast<sal_Int16>( Millimeter::getInHundredthsOfOneMillimeter( _lineSpace ) ); + } + return aLineSpacing; +} + +style::LineSpacing SwVbaParagraphFormat::getOOoLineSpacingFromRule( sal_Int32 _linespacingrule ) +{ + style::LineSpacing aLineSpacing; + switch( _linespacingrule ) + { + case word::WdLineSpacing::wdLineSpace1pt5: + { + aLineSpacing.Mode = style::LineSpacingMode::PROP; + aLineSpacing.Height = PERCENT150; + break; + } + case word::WdLineSpacing::wdLineSpaceAtLeast: + { + aLineSpacing.Mode = style::LineSpacingMode::MINIMUM; + aLineSpacing.Height = getCharHeight(); + break; + } + case word::WdLineSpacing::wdLineSpaceDouble: + { + aLineSpacing.Mode = style::LineSpacingMode::PROP; + aLineSpacing.Height = getCharHeight(); + break; + } + case word::WdLineSpacing::wdLineSpaceExactly: + case word::WdLineSpacing::wdLineSpaceMultiple: + { + aLineSpacing.Mode = style::LineSpacingMode::FIX; + aLineSpacing.Height = getCharHeight(); + break; + } + case word::WdLineSpacing::wdLineSpaceSingle: + { + aLineSpacing.Mode = style::LineSpacingMode::PROP; + aLineSpacing.Height = PERCENT100; + break; + } + default: + { + DebugHelper::runtimeexception( ERRCODE_BASIC_BAD_PARAMETER ); + break; + } + } + return aLineSpacing; +} + +float SwVbaParagraphFormat::getMSWordLineSpacing( style::LineSpacing const & rLineSpacing ) +{ + float wdLineSpacing = 0; + if( rLineSpacing.Mode != style::LineSpacingMode::PROP ) + { + wdLineSpacing = static_cast<float>( Millimeter::getInPoints( rLineSpacing.Height ) ); + } + else + { + wdLineSpacing = static_cast<float>( CHARACTER_INDENT_FACTOR * rLineSpacing.Height ) / PERCENT100; + } + return wdLineSpacing; +} + +sal_Int32 SwVbaParagraphFormat::getMSWordLineSpacingRule( style::LineSpacing const & rLineSpacing ) +{ + sal_Int32 wdLineSpacing = word::WdLineSpacing::wdLineSpaceSingle; + switch( rLineSpacing.Mode ) + { + case style::LineSpacingMode::PROP: + { + switch( rLineSpacing.Height ) + { + case PERCENT100: + { + wdLineSpacing = word::WdLineSpacing::wdLineSpaceSingle; + break; + } + case PERCENT150: + { + wdLineSpacing = word::WdLineSpacing::wdLineSpace1pt5; + break; + } + case PERCENT200: + { + wdLineSpacing = word::WdLineSpacing::wdLineSpaceDouble; + break; + } + default: + { + wdLineSpacing = word::WdLineSpacing::wdLineSpaceMultiple; + } + } + break; + } + case style::LineSpacingMode::MINIMUM: + { + wdLineSpacing = word::WdLineSpacing::wdLineSpaceAtLeast; + break; + } + case style::LineSpacingMode::FIX: + case style::LineSpacingMode::LEADING: + { + wdLineSpacing = word::WdLineSpacing::wdLineSpaceExactly; + break; + } + default: + { + DebugHelper::runtimeexception( ERRCODE_BASIC_BAD_PARAMETER ); + } + } + return wdLineSpacing; +} + +sal_Int16 SwVbaParagraphFormat::getCharHeight() +{ + float fCharHeight = 0.0; + mxParaProps->getPropertyValue("CharHeight") >>= fCharHeight; + return static_cast<sal_Int16>( Millimeter::getInHundredthsOfOneMillimeter( fCharHeight ) ); +} + +style::ParagraphAdjust SwVbaParagraphFormat::getOOoAlignment( sal_Int32 _alignment ) +{ + style::ParagraphAdjust nParaAjust = style::ParagraphAdjust_LEFT; + switch( _alignment ) + { + case word::WdParagraphAlignment::wdAlignParagraphCenter: + { + nParaAjust = style::ParagraphAdjust_CENTER; + break; + } + case word::WdParagraphAlignment::wdAlignParagraphJustify: + { + nParaAjust = style::ParagraphAdjust_BLOCK; + break; + } + case word::WdParagraphAlignment::wdAlignParagraphLeft: + { + nParaAjust = style::ParagraphAdjust_LEFT; + break; + } + case word::WdParagraphAlignment::wdAlignParagraphRight: + { + nParaAjust = style::ParagraphAdjust_RIGHT; + break; + } + default: + { + DebugHelper::runtimeexception( ERRCODE_BASIC_BAD_PARAMETER ); + } + } + return nParaAjust; +} + +sal_Int32 SwVbaParagraphFormat::getMSWordAlignment( style::ParagraphAdjust _alignment ) +{ + sal_Int32 wdAlignment = word::WdParagraphAlignment::wdAlignParagraphLeft; + switch( _alignment ) + { + case style::ParagraphAdjust_CENTER: + { + wdAlignment = word::WdParagraphAlignment::wdAlignParagraphCenter; + break; + } + case style::ParagraphAdjust_LEFT: + { + wdAlignment = word::WdParagraphAlignment::wdAlignParagraphLeft; + break; + } + case style::ParagraphAdjust_BLOCK: + { + wdAlignment = word::WdParagraphAlignment::wdAlignParagraphJustify; + break; + } + case style::ParagraphAdjust_RIGHT: + { + wdAlignment = word::WdParagraphAlignment::wdAlignParagraphRight; + break; + } + default: + { + DebugHelper::basicexception( ERRCODE_BASIC_BAD_PARAMETER, {} ); + } + } + return wdAlignment; +} + +OUString +SwVbaParagraphFormat::getServiceImplName() +{ + return "SwVbaParagraphFormat"; +} + +uno::Sequence< OUString > +SwVbaParagraphFormat::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.ParagraphFormat" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaparagraphformat.hxx b/sw/source/ui/vba/vbaparagraphformat.hxx new file mode 100644 index 0000000000..a80c21e1b1 --- /dev/null +++ b/sw/source/ui/vba/vbaparagraphformat.hxx @@ -0,0 +1,88 @@ +/* -*- 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_VBA_VBAPARAGRAPHFORMAT_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAPARAGRAPHFORMAT_HXX + +#include <ooo/vba/word/XParagraphFormat.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/style/LineSpacing.hpp> +#include <com/sun/star/style/ParagraphAdjust.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XParagraphFormat > SwVbaParagraphFormat_BASE; + +class SwVbaParagraphFormat : public SwVbaParagraphFormat_BASE +{ +private: + css::uno::Reference< css::beans::XPropertySet > mxParaProps; + +private: + static css::style::LineSpacing getOOoLineSpacing( float _lineSpace, sal_Int16 mode ); + css::style::LineSpacing getOOoLineSpacingFromRule( sal_Int32 _linespacingrule ); + static float getMSWordLineSpacing( css::style::LineSpacing const & rLineSpacing ); + static sal_Int32 getMSWordLineSpacingRule( css::style::LineSpacing const & rLineSpacing ); + /// @throws css::uno::RuntimeException + sal_Int16 getCharHeight(); + static css::style::ParagraphAdjust getOOoAlignment( sal_Int32 _alignment ); + static sal_Int32 getMSWordAlignment( css::style::ParagraphAdjust _alignment ); + +public: + SwVbaParagraphFormat( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::beans::XPropertySet > xParaProps ); + virtual ~SwVbaParagraphFormat() override; + + // Attributes + virtual ::sal_Int32 SAL_CALL getAlignment() override; + virtual void SAL_CALL setAlignment( ::sal_Int32 _alignment ) override; + virtual float SAL_CALL getFirstLineIndent() override; + virtual void SAL_CALL setFirstLineIndent( float _firstlineindent ) override; + virtual css::uno::Any SAL_CALL getKeepTogether() override; + virtual void SAL_CALL setKeepTogether( const css::uno::Any& _keeptogether ) override; + virtual css::uno::Any SAL_CALL getKeepWithNext() override; + virtual void SAL_CALL setKeepWithNext( const css::uno::Any& _keepwithnext ) override; + virtual css::uno::Any SAL_CALL getHyphenation() override; + virtual void SAL_CALL setHyphenation( const css::uno::Any& _hyphenation ) override; + virtual float SAL_CALL getLineSpacing() override; + virtual void SAL_CALL setLineSpacing( float _linespacing ) override; + virtual ::sal_Int32 SAL_CALL getLineSpacingRule() override; + virtual void SAL_CALL setLineSpacingRule( ::sal_Int32 _linespacingrule ) override; + virtual css::uno::Any SAL_CALL getNoLineNumber() override; + virtual void SAL_CALL setNoLineNumber( const css::uno::Any& _nolinenumber ) override; + virtual ::sal_Int32 SAL_CALL getOutlineLevel() override; + virtual void SAL_CALL setOutlineLevel( ::sal_Int32 _outlinelevel ) override; + virtual css::uno::Any SAL_CALL getPageBreakBefore() override; + virtual void SAL_CALL setPageBreakBefore( const css::uno::Any& _pagebreakbefore ) override; + virtual float SAL_CALL getSpaceBefore() override; + virtual void SAL_CALL setSpaceBefore( float _spacebefore ) override; + virtual float SAL_CALL getSpaceAfter() override; + virtual void SAL_CALL setSpaceAfter( float _spaceafter ) override; + virtual float SAL_CALL getLeftIndent() override; + virtual void SAL_CALL setLeftIndent( float _leftindent ) override; + virtual float SAL_CALL getRightIndent() override; + virtual void SAL_CALL setRightIndent( float _rightindent ) override; + virtual css::uno::Any SAL_CALL getTabStops() override; + virtual void SAL_CALL setTabStops( const css::uno::Any& _tabstops ) override; + virtual css::uno::Any SAL_CALL getWidowControl() override; + virtual void SAL_CALL setWidowControl( const css::uno::Any& _widowcontrol ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAPARAGRAPHFORMAT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbarange.cxx b/sw/source/ui/vba/vbarange.cxx new file mode 100644 index 0000000000..c48dd6193c --- /dev/null +++ b/sw/source/ui/vba/vbarange.cxx @@ -0,0 +1,434 @@ +/* -*- 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 "vbarange.hxx" +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include <basic/sberrors.hxx> +#include "vbarangehelper.hxx" +#include <ooo/vba/word/WdBreakType.hpp> +#include <com/sun/star/style/BreakType.hpp> +#include <com/sun/star/text/ControlCharacter.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/text/XTextRangeCompare.hpp> +#include <com/sun/star/text/XTextViewCursor.hpp> +#include "vbaparagraphformat.hxx" +#include "vbastyle.hxx" +#include "vbafont.hxx" +#include "vbafind.hxx" +#include "vbapalette.hxx" +#include "vbapagesetup.hxx" +#include "vbalistformat.hxx" +#include "vbarevisions.hxx" +#include "vbabookmarks.hxx" +#include "vbasections.hxx" +#include "vbafield.hxx" +#include "wordvbahelper.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaRange::SwVbaRange( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< text::XTextDocument > xTextDocument, const uno::Reference< text::XTextRange >& rStart ) : SwVbaRange_BASE( rParent, rContext ), mxTextDocument(std::move( xTextDocument )) +{ + uno::Reference< text::XTextRange > xEnd; + initialize( rStart, xEnd ); +} + +SwVbaRange::SwVbaRange( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< text::XTextDocument > xTextDocument, const uno::Reference< text::XTextRange >& rStart, const uno::Reference< text::XTextRange >& rEnd ) : SwVbaRange_BASE( rParent, rContext ), mxTextDocument(std::move( xTextDocument )) +{ + initialize( rStart, rEnd ); +} + +SwVbaRange::SwVbaRange( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< text::XTextDocument > xTextDocument, const uno::Reference< text::XTextRange >& rStart, const uno::Reference< text::XTextRange >& rEnd, uno::Reference< text::XText > xText ) : SwVbaRange_BASE( rParent, rContext ),mxTextDocument(std::move( xTextDocument )), mxText(std::move( xText )) +{ + initialize( rStart, rEnd ); +} + +SwVbaRange::~SwVbaRange() +{ +} + +void SwVbaRange::initialize( const uno::Reference< text::XTextRange >& rStart, const uno::Reference< text::XTextRange >& rEnd ) +{ + if( !mxText.is() ) + { + mxText = mxTextDocument->getText(); + } + + mxTextCursor = SwVbaRangeHelper::initCursor( rStart, mxText ); + if( !mxTextCursor.is() ) + throw uno::RuntimeException("Fails to create text cursor" ); + mxTextCursor->collapseToStart(); + + if( rEnd.is() ) + mxTextCursor->gotoRange( rEnd, true ); + else + mxTextCursor->gotoEnd( true ); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwVbaRange::getXTextRange() +{ + uno::Reference< text::XTextRange > xTextRange( mxTextCursor, uno::UNO_QUERY_THROW ); + return xTextRange; +} + +/** +* The complexity in this method is because we need to workaround +* an issue that the last paragraph in a document does not have a trailing CRLF. +* @return +*/ +OUString SAL_CALL +SwVbaRange::getText() +{ + OUString aText = mxTextCursor->getString(); + sal_Int32 nLen = aText.getLength(); + + // FIXME: should add a line separator if the range includes the last paragraph + if( nLen == 0 ) + { + if( mxTextCursor->isCollapsed() ) + { + mxTextCursor->goRight( 1, true ); + aText = mxTextCursor->getString(); + mxTextCursor->collapseToStart(); + } + else + { + uno::Reference< text::XTextRange > xStart = mxTextCursor->getStart(); + uno::Reference< text::XTextRange > xEnd = mxTextCursor->getEnd(); + mxTextCursor->collapseToEnd(); + mxTextCursor->goRight( 1, true ); + mxTextCursor->gotoRange( xStart, false ); + mxTextCursor->gotoRange( xEnd, true ); + } + } + + return aText; +} + +void SAL_CALL +SwVbaRange::setText( const OUString& rText ) +{ + // Emulate the MSWord behavior, Don't delete the bookmark + // which contains no text string in current inserting position, + OUString sName; + uno::Reference< text::XTextRange > xRange( mxTextCursor, uno::UNO_QUERY_THROW ); + try + { + uno::Reference< text::XTextContent > xBookmark = SwVbaRangeHelper::findBookmarkByPosition( mxTextDocument, xRange->getStart() ); + if( xBookmark.is() ) + { + uno::Reference< container::XNamed > xNamed( xBookmark, uno::UNO_QUERY_THROW ); + sName = xNamed->getName(); + } + } + catch (const uno::Exception&) + { + // do nothing + } + + if( rText.indexOf( '\n' ) != -1 ) + { + mxTextCursor->setString( OUString() ); + // process CR in strings + SwVbaRangeHelper::insertString( xRange, mxText, rText, true ); + } + else + { + mxTextCursor->setString( rText ); + } + + // insert the bookmark if the bookmark is deleted during setting text string + if( !sName.isEmpty() ) + { + uno::Reference< text::XBookmarksSupplier > xBookmarksSupplier( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xNameAccess( xBookmarksSupplier->getBookmarks(), uno::UNO_SET_THROW ); + if( !xNameAccess->hasByName( sName ) ) + { + uno::Reference< frame::XModel > xModel( mxTextDocument, uno::UNO_QUERY_THROW ); + SwVbaBookmarks::addBookmarkByName( xModel, sName, xRange->getStart() ); + } + } +} + +// FIXME: test is not pass +void SAL_CALL SwVbaRange::InsertBreak(const uno::Any& _breakType) +{ + // default type is wdPageBreak; + sal_Int32 nBreakType = word::WdBreakType::wdPageBreak; + if( _breakType.hasValue() ) + _breakType >>= nBreakType; + + style::BreakType eBreakType = style::BreakType_NONE; + switch( nBreakType ) + { + case word::WdBreakType::wdPageBreak: + eBreakType = style::BreakType_PAGE_BEFORE; + break; + case word::WdBreakType::wdColumnBreak: + eBreakType = style::BreakType_COLUMN_AFTER; + break; + case word::WdBreakType::wdLineBreak: + case word::WdBreakType::wdLineBreakClearLeft: + case word::WdBreakType::wdLineBreakClearRight: + case word::WdBreakType::wdSectionBreakContinuous: + case word::WdBreakType::wdSectionBreakEvenPage: + case word::WdBreakType::wdSectionBreakNextPage: + case word::WdBreakType::wdSectionBreakOddPage: + case word::WdBreakType::wdTextWrappingBreak: + DebugHelper::basicexception( ERRCODE_BASIC_NOT_IMPLEMENTED, {} ); + break; + default: + DebugHelper::basicexception( ERRCODE_BASIC_BAD_PARAMETER, {} ); + } + + if( eBreakType != style::BreakType_NONE ) + { + if( !mxTextCursor->isCollapsed() ) + { + mxTextCursor->setString( OUString() ); + mxTextCursor->collapseToStart(); + } + + uno::Reference< beans::XPropertySet > xProp( mxTextCursor, uno::UNO_QUERY_THROW ); + xProp->setPropertyValue("BreakType", uno::Any( eBreakType ) ); + } +} + +void SAL_CALL +SwVbaRange::Select() +{ + uno::Reference< frame::XModel > xModel( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextViewCursor > xTextViewCursor = word::getXTextViewCursor( xModel ); + xTextViewCursor->gotoRange( mxTextCursor->getStart(), false ); + xTextViewCursor->gotoRange( mxTextCursor->getEnd(), true ); +} + +void SAL_CALL +SwVbaRange::InsertParagraph() +{ + mxTextCursor->setString( "" ); + InsertParagraphBefore(); +} + +void SAL_CALL +SwVbaRange::InsertParagraphBefore() +{ + uno::Reference< text::XTextRange > xTextRange = mxTextCursor->getStart(); + mxText->insertControlCharacter( xTextRange, text::ControlCharacter::PARAGRAPH_BREAK, true ); + mxTextCursor->gotoRange( xTextRange, true ); +} + +void SAL_CALL +SwVbaRange::InsertParagraphAfter() +{ + uno::Reference< text::XTextRange > xTextRange = mxTextCursor->getEnd(); + mxText->insertControlCharacter( xTextRange, text::ControlCharacter::PARAGRAPH_BREAK, true ); +} + +uno::Reference< word::XParagraphFormat > SAL_CALL +SwVbaRange::getParagraphFormat() +{ + uno::Reference< beans::XPropertySet > xParaProps( mxTextCursor, uno::UNO_QUERY_THROW ); + return uno::Reference< word::XParagraphFormat >( new SwVbaParagraphFormat( this, mxContext, xParaProps ) ); +} + +void SAL_CALL +SwVbaRange::setParagraphFormat( const uno::Reference< word::XParagraphFormat >& /*rParagraphFormat*/ ) +{ + throw uno::RuntimeException("Not implemented" ); +} + +void SwVbaRange::GetStyleInfo(OUString& aStyleName, OUString& aStyleType ) +{ + uno::Reference< beans::XPropertySet > xProp( mxTextCursor, uno::UNO_QUERY_THROW ); + if( ( xProp->getPropertyValue("CharStyleName") >>= aStyleName ) && !aStyleName.isEmpty() ) + { + aStyleType = "CharacterStyles"; + } + else if( ( xProp->getPropertyValue("ParaStyleName") >>= aStyleName ) && !aStyleName.isEmpty() ) + { + aStyleType = "ParagraphStyles"; + } + if( aStyleType.isEmpty() ) + { + DebugHelper::runtimeexception( ERRCODE_BASIC_INTERNAL_ERROR ); + } +} + +uno::Any SAL_CALL +SwVbaRange::getStyle() +{ + OUString aStyleName; + OUString aStyleType; + GetStyleInfo( aStyleName, aStyleType ); + uno::Reference< style::XStyleFamiliesSupplier > xStyleSupplier( mxTextDocument, uno::UNO_QUERY_THROW); + uno::Reference< container::XNameAccess > xStylesAccess( xStyleSupplier->getStyleFamilies()->getByName( aStyleType ), uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xStyleProps( xStylesAccess->getByName( aStyleName ), uno::UNO_QUERY_THROW ); + uno::Reference< frame::XModel > xModel( mxTextDocument, uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< word::XStyle >( new SwVbaStyle( this, mxContext, xModel, xStyleProps ) ) ); +} + +void SAL_CALL +SwVbaRange::setStyle( const uno::Any& rStyle ) +{ + uno::Reference< beans::XPropertySet > xParaProps( mxTextCursor, uno::UNO_QUERY_THROW ); + SwVbaStyle::setStyle( xParaProps, rStyle ); +} + +uno::Reference< word::XFont > SAL_CALL +SwVbaRange::getFont() +{ + VbaPalette aColors; + return new SwVbaFont( mxParent, mxContext, aColors.getPalette(), uno::Reference< beans::XPropertySet >( getXTextRange(), uno::UNO_QUERY_THROW ) ); +} + +uno::Reference< word::XFind > SAL_CALL +SwVbaRange::getFind() +{ + uno::Reference< text::XTextRange > xTextRange = getXTextRange(); + uno::Reference< frame::XModel > xModel( mxTextDocument, uno::UNO_QUERY_THROW ); + return SwVbaFind::GetOrCreateFind(this, mxContext, xModel, xTextRange); +} + +uno::Reference< word::XListFormat > SAL_CALL +SwVbaRange::getListFormat() +{ + return uno::Reference< word::XListFormat >( new SwVbaListFormat( this, mxContext, getXTextRange() ) ); +} + +::sal_Int32 SAL_CALL SwVbaRange::getLanguageID() +{ + uno::Reference< beans::XPropertySet > xParaProps( mxTextCursor, uno::UNO_QUERY_THROW ); + return static_cast<sal_uInt16>(SwVbaStyle::getLanguageID( xParaProps )); +} + +void SAL_CALL SwVbaRange::setLanguageID( ::sal_Int32 _languageid ) +{ + uno::Reference< beans::XPropertySet > xParaProps( mxTextCursor, uno::UNO_QUERY_THROW ); + SwVbaStyle::setLanguageID( xParaProps, LanguageType(_languageid) ); +} + +uno::Any SAL_CALL +SwVbaRange::PageSetup( ) +{ + uno::Reference< beans::XPropertySet > xParaProps( mxTextCursor, uno::UNO_QUERY_THROW ); + uno::Reference< frame::XModel > xModel( mxTextDocument, uno::UNO_QUERY_THROW ); + OUString aPageStyleName; + xParaProps->getPropertyValue("PageStyleName") >>= aPageStyleName; + uno::Reference< style::XStyleFamiliesSupplier > xSytleFamSupp( xModel, uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xSytleFamNames( xSytleFamSupp->getStyleFamilies(), uno::UNO_SET_THROW ); + uno::Reference< container::XNameAccess > xPageStyles( xSytleFamNames->getByName("PageStyles"), uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xPageProps( xPageStyles->getByName( aPageStyleName ), uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< word::XPageSetup >( new SwVbaPageSetup( this, mxContext, xModel, xPageProps ) ) ); +} + +::sal_Int32 SAL_CALL SwVbaRange::getStart() +{ + uno::Reference< text::XText > xText = mxTextDocument->getText(); + return SwVbaRangeHelper::getPosition( xText, mxTextCursor->getStart() ); +} + +void SAL_CALL SwVbaRange::setStart( ::sal_Int32 _start ) +{ + uno::Reference< text::XText > xText = mxTextDocument->getText(); + uno::Reference< text::XTextRange > xStart = SwVbaRangeHelper::getRangeByPosition( xText, _start ); + uno::Reference< text::XTextRange > xEnd = mxTextCursor->getEnd(); + + mxTextCursor->gotoRange( xStart, false ); + mxTextCursor->gotoRange( xEnd, true ); +} + +::sal_Int32 SAL_CALL SwVbaRange::getEnd() +{ + uno::Reference< text::XText > xText = mxTextDocument->getText(); + return SwVbaRangeHelper::getPosition( xText, mxTextCursor->getEnd() ); +} + +void SAL_CALL SwVbaRange::setEnd( ::sal_Int32 _end ) +{ + uno::Reference< text::XText > xText = mxTextDocument->getText(); + uno::Reference< text::XTextRange > xEnd = SwVbaRangeHelper::getRangeByPosition( xText, _end ); + + mxTextCursor->collapseToStart(); + mxTextCursor->gotoRange( xEnd, true ); +} + +sal_Bool SAL_CALL SwVbaRange::InRange( const uno::Reference< ::ooo::vba::word::XRange >& Range ) +{ + SwVbaRange* pRange = dynamic_cast< SwVbaRange* >( Range.get() ); + if( !pRange ) + throw uno::RuntimeException(); + uno::Reference< text::XTextRange > xTextRange = pRange->getXTextRange(); + uno::Reference< text::XTextRangeCompare > xTRC( mxTextCursor->getText(), uno::UNO_QUERY_THROW ); + if( xTRC->compareRegionStarts( xTextRange, getXTextRange() ) >= 0 && xTRC->compareRegionEnds( xTextRange, getXTextRange() ) <= 0 ) + return true; + return false; +} + +uno::Any SAL_CALL +SwVbaRange::Revisions( const uno::Any& index ) +{ + uno::Reference< text::XTextRange > xTextRange = getXTextRange(); + uno::Reference< frame::XModel > xModel( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xCol( new SwVbaRevisions( mxParent, mxContext, xModel, xTextRange ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaRange::Sections( const uno::Any& index ) +{ + uno::Reference< text::XTextRange > xTextRange = getXTextRange(); + uno::Reference< frame::XModel > xModel( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xCol( new SwVbaSections( mxParent, mxContext, xModel, xTextRange ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaRange::Fields( const uno::Any& index ) +{ + //FIXME: should be get the field in current range + uno::Reference< frame::XModel > xModel( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< XCollection > xCol( new SwVbaFields( mxParent, mxContext, xModel ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +OUString +SwVbaRange::getServiceImplName() +{ + return "SwVbaRange"; +} + +uno::Sequence< OUString > +SwVbaRange::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Range" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbarange.hxx b/sw/source/ui/vba/vbarange.hxx new file mode 100644 index 0000000000..f0dd156350 --- /dev/null +++ b/sw/source/ui/vba/vbarange.hxx @@ -0,0 +1,101 @@ +/* -*- 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_VBA_VBARANGE_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBARANGE_HXX + +#include <ooo/vba/word/XRange.hpp> +#include <ooo/vba/word/XParagraphFormat.hpp> +#include <ooo/vba/word/XFont.hpp> +#include <ooo/vba/word/XFind.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <ooo/vba/word/XListFormat.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XRange > SwVbaRange_BASE; + +class SwVbaRange : public SwVbaRange_BASE +{ +private: + css::uno::Reference< css::text::XTextDocument > mxTextDocument; + css::uno::Reference< css::text::XTextCursor > mxTextCursor; + css::uno::Reference< css::text::XText > mxText; + +private: + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + void initialize( const css::uno::Reference< css::text::XTextRange >& rStart, const css::uno::Reference< css::text::XTextRange >& rEnd ); + /// @throws css::uno::RuntimeException + void GetStyleInfo(OUString& aStyleName, OUString& aStyleType ); +public: + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + SwVbaRange( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::text::XTextDocument > xTextDocument, const css::uno::Reference< css::text::XTextRange >& rStart); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + SwVbaRange( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::text::XTextDocument > xTextDocument, const css::uno::Reference< css::text::XTextRange >& rStart, const css::uno::Reference< css::text::XTextRange >& rEnd ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + SwVbaRange( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::text::XTextDocument > xTextDocument, const css::uno::Reference< css::text::XTextRange >& rStart, const css::uno::Reference< css::text::XTextRange >& rEnd, css::uno::Reference< css::text::XText > xText); + virtual ~SwVbaRange() override; + const css::uno::Reference< css::text::XTextDocument >& getDocument() const { return mxTextDocument; } + + virtual css::uno::Reference< css::text::XTextRange > SAL_CALL getXTextRange() override; + const css::uno::Reference< css::text::XText >& getXText() const { return mxText; } + void setXTextCursor( const css::uno::Reference< css::text::XTextCursor >& xTextCursor ) { mxTextCursor = xTextCursor; } + + // Attribute + virtual OUString SAL_CALL getText() override; + virtual void SAL_CALL setText( const OUString& rText ) override; + virtual css::uno::Reference< ooo::vba::word::XParagraphFormat > SAL_CALL getParagraphFormat() override; + virtual void SAL_CALL setParagraphFormat( const css::uno::Reference< ooo::vba::word::XParagraphFormat >& rParagraphFormat ) override; + virtual css::uno::Any SAL_CALL getStyle() override; + virtual void SAL_CALL setStyle( const css::uno::Any& _xStyle ) override; + virtual css::uno::Reference< ooo::vba::word::XFont > SAL_CALL getFont() override; + virtual css::uno::Reference< ooo::vba::word::XFind > SAL_CALL getFind() override; + virtual css::uno::Reference< ooo::vba::word::XListFormat > SAL_CALL getListFormat() override; + + //XDefaultProperty + virtual OUString SAL_CALL getDefaultPropertyName() override { return "Text"; } + + // Methods + virtual void SAL_CALL InsertBreak(const css::uno::Any& _breakType) override; + virtual void SAL_CALL Select() override; + virtual void SAL_CALL InsertParagraph() override; + virtual void SAL_CALL InsertParagraphBefore() override; + virtual void SAL_CALL InsertParagraphAfter() override; + virtual ::sal_Int32 SAL_CALL getLanguageID() override; + virtual void SAL_CALL setLanguageID( ::sal_Int32 _languageid ) override; + virtual css::uno::Any SAL_CALL PageSetup() override; + virtual ::sal_Int32 SAL_CALL getStart() override; + virtual void SAL_CALL setStart( ::sal_Int32 _start ) override; + virtual ::sal_Int32 SAL_CALL getEnd() override; + virtual void SAL_CALL setEnd( ::sal_Int32 _end ) override; + virtual sal_Bool SAL_CALL InRange( const css::uno::Reference< ::ooo::vba::word::XRange >& Range ) override; + virtual css::uno::Any SAL_CALL Revisions( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Sections( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Fields( const css::uno::Any& aIndex ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBARANGE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbarangehelper.cxx b/sw/source/ui/vba/vbarangehelper.cxx new file mode 100644 index 0000000000..1760d0f985 --- /dev/null +++ b/sw/source/ui/vba/vbarangehelper.cxx @@ -0,0 +1,191 @@ +/* -*- 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 "vbarangehelper.hxx" +#include <vbahelper/vbahelper.hxx> +#include <com/sun/star/text/ControlCharacter.hpp> +#include <com/sun/star/text/XTextRangeCompare.hpp> +#include <com/sun/star/text/XBookmarksSupplier.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +/** + * get a range in a xText by creating + * a cursor that iterates over the text. If the iterating cursor is + * equal to the desired position, the range equivalent is returned. + * Some special cases are tables that are inside of the text, because the + * position has to be adjusted. + * @param xText a text where a range position is searched + * @param position a position inside o the text + * @return a range for the position; null is returned if no range can be + * constructed. + */ +uno::Reference< text::XTextRange > SwVbaRangeHelper::getRangeByPosition( const uno::Reference< text::XText >& rText, sal_Int32 _position ) +{ + uno::Reference< text::XTextRange > xRange; + if( rText.is() ) + { + sal_Int32 nPos = 0; + uno::Reference< text::XTextCursor > xCursor = rText->createTextCursor(); + xCursor->collapseToStart(); + bool bCanGo = true; + while( !xRange.is() && bCanGo ) + { + if( _position == nPos ) + { + xRange = xCursor->getStart(); + } + else + { + bCanGo = xCursor->goRight( 1, false ); + nPos++; + } + } + } + return xRange; +} + +void SwVbaRangeHelper::insertString( uno::Reference< text::XTextRange > const & rTextRange, uno::Reference< text::XText > const & rText, std::u16string_view aStr, bool _bAbsorb ) +{ + size_t nlastIndex = 0; + size_t nIndex = 0; + uno::Reference< text::XTextRange > xRange = rTextRange; + + while( ( nIndex = aStr.find('\n', nlastIndex)) != std::u16string_view::npos ) + { + xRange = xRange->getEnd(); + if( nlastIndex < ( nIndex - 1 ) ) + { + rText->insertString( xRange, OUString(aStr.substr( nlastIndex, ( nIndex - 1 - nlastIndex ) )), _bAbsorb ); + xRange = xRange->getEnd(); + } + + rText->insertControlCharacter( xRange, text::ControlCharacter::PARAGRAPH_BREAK, _bAbsorb ); + nlastIndex = nIndex + 1; + } + + if( nlastIndex < aStr.size() ) + { + xRange = xRange->getEnd(); + + OUString aWatt( aStr.substr( nlastIndex ) ); + rText->insertString( xRange, aWatt, _bAbsorb ); + } +} + +uno::Reference< text::XTextCursor > SwVbaRangeHelper::initCursor( const uno::Reference< text::XTextRange >& rTextRange, + const uno::Reference< text::XText >& rText ) +{ + uno::Reference< text::XTextCursor > xTextCursor; + bool bGotTextCursor = false; + + try + { + xTextCursor = rText->createTextCursorByRange( rTextRange ); + bGotTextCursor = true; + } + catch (const uno::Exception& e) + { + DebugHelper::basicexception(e); + } + + if( !bGotTextCursor || !xTextCursor.is() ) + { + try + { + uno::Reference< text::XText > xText = rTextRange->getText(); + xTextCursor = xText->createTextCursor(); + bGotTextCursor = true; + } + catch (const uno::Exception& e) + { + DebugHelper::basicexception(e); + } + } + + if( !bGotTextCursor || !xTextCursor.is() ) + { + try + { + xTextCursor = rText->createTextCursor(); + } + catch (const uno::Exception& e) + { + DebugHelper::basicexception(e); + } + } + return xTextCursor; +} + +sal_Int32 SwVbaRangeHelper::getPosition( const uno::Reference< text::XText >& rText, const uno::Reference< text::XTextRange >& rTextRange ) +{ + sal_Int32 nPosition = -1; + if( rText.is() && rTextRange.is() ) + { + nPosition = 0; + uno::Reference< text::XTextCursor > xCursor = rText->createTextCursor(); + xCursor->collapseToStart(); + uno::Reference< text::XTextRangeCompare > xCompare( rText, uno::UNO_QUERY_THROW ); + // compareValue is 0 if the ranges are equal + sal_Int32 nCompareValue = xCompare->compareRegionStarts( xCursor->getStart(), rTextRange ); + bool canGo = true; + + while( nCompareValue !=0 && canGo ) + { + canGo = xCursor->goRight( 1, false ); + nCompareValue = xCompare->compareRegionStarts( xCursor->getStart(), rTextRange ); + nPosition++; + } + + // check fails: no correct position found + if( !canGo && nCompareValue != 0 ) + { + nPosition = -1; + } + } + + return nPosition; +} + +uno::Reference< text::XTextContent > SwVbaRangeHelper::findBookmarkByPosition( const uno::Reference< text::XTextDocument >& xTextDoc, const uno::Reference< text::XTextRange >& xTextRange ) +{ + uno::Reference< text::XBookmarksSupplier > xBookmarksSupplier( xTextDoc, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndexAccess( xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY_THROW ); + for( sal_Int32 index = 0; index < xIndexAccess->getCount(); index++ ) + { + uno::Reference< text::XTextContent > xBookmark( xIndexAccess->getByIndex( index ), uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextRange > xBkAnchor = xBookmark->getAnchor(); + uno::Reference< text::XTextRangeCompare > xCompare( xBkAnchor->getText(), uno::UNO_QUERY_THROW ); + if( xCompare->compareRegionStarts( xBkAnchor->getStart(), xBkAnchor->getEnd() ) == 0 ) + { + try + { + if( xCompare->compareRegionStarts( xTextRange, xBkAnchor->getStart() ) == 0 ) + return xBookmark; + } + catch (const uno::Exception&) + { + continue; + } + } + } + return uno::Reference< text::XTextContent >(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbarangehelper.hxx b/sw/source/ui/vba/vbarangehelper.hxx new file mode 100644 index 0000000000..af3f885e4a --- /dev/null +++ b/sw/source/ui/vba/vbarangehelper.hxx @@ -0,0 +1,44 @@ +/* -*- 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_VBA_VBARANGEHELPER_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBARANGEHELPER_HXX + +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/text/XTextDocument.hpp> + +class SwVbaRangeHelper +{ +public: + /// @throws css::uno::RuntimeException + static css::uno::Reference< css::text::XTextRange > getRangeByPosition( const css::uno::Reference< css::text::XText >& rText, sal_Int32 _position ); + /// @throws css::uno::RuntimeException + static void insertString( css::uno::Reference< css::text::XTextRange > const & rTextRange, css::uno::Reference< css::text::XText > const & rText, std::u16string_view aStr, bool _bAbsorb ); + /// @throws css::uno::RuntimeException + /// @throws css::script::BasicErrorException + static css::uno::Reference< css::text::XTextCursor > initCursor( const css::uno::Reference< css::text::XTextRange >& rTextRange, const css::uno::Reference< css::text::XText >& rText ); + /// @throws css::uno::RuntimeException + static sal_Int32 getPosition( const css::uno::Reference< css::text::XText >& rText, const css::uno::Reference< css::text::XTextRange >& rTextRange ); + /// @throws css::uno::RuntimeException + static css::uno::Reference< css::text::XTextContent > findBookmarkByPosition( const css::uno::Reference< css::text::XTextDocument >& xTextDoc, const css::uno::Reference< css::text::XTextRange >& xTextRange ); + +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBARANGEHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbareplacement.cxx b/sw/source/ui/vba/vbareplacement.cxx new file mode 100644 index 0000000000..bed7aee8d7 --- /dev/null +++ b/sw/source/ui/vba/vbareplacement.cxx @@ -0,0 +1,67 @@ +/* -*- 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 <utility> + +#include "vbareplacement.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaReplacement::SwVbaReplacement( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< util::XPropertyReplace > xPropertyReplace ) : + SwVbaReplacement_BASE( rParent, rContext ), mxPropertyReplace(std::move( xPropertyReplace )) +{ +} + +SwVbaReplacement::~SwVbaReplacement() +{ +} + +OUString SAL_CALL SwVbaReplacement::getText() +{ + return mxPropertyReplace->getReplaceString(); +} + +void SAL_CALL SwVbaReplacement::setText( const OUString& _text ) +{ + mxPropertyReplace->setReplaceString( _text ); +} + +void SAL_CALL SwVbaReplacement::ClearFormatting( ) +{ + uno::Sequence< beans::PropertyValue > aPropValues; + mxPropertyReplace->setReplaceAttributes( aPropValues ); +} + +OUString +SwVbaReplacement::getServiceImplName() +{ + return "SwVbaReplacement"; +} + +uno::Sequence< OUString > +SwVbaReplacement::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Replacement" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbareplacement.hxx b/sw/source/ui/vba/vbareplacement.hxx new file mode 100644 index 0000000000..6c6ee89422 --- /dev/null +++ b/sw/source/ui/vba/vbareplacement.hxx @@ -0,0 +1,51 @@ +/* -*- 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_VBA_VBAREPLACEMENT_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAREPLACEMENT_HXX + +#include <ooo/vba/word/XReplacement.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/util/XPropertyReplace.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XReplacement > SwVbaReplacement_BASE; + +class SwVbaReplacement : public SwVbaReplacement_BASE +{ +private: + css::uno::Reference< css::util::XPropertyReplace> mxPropertyReplace; + +public: + /// @throws css::uno::RuntimeException + SwVbaReplacement( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::util::XPropertyReplace > xPropertyReplace ); + virtual ~SwVbaReplacement() override; + + // Attributes + virtual OUString SAL_CALL getText() override; + virtual void SAL_CALL setText( const OUString& _text ) override; + + //Methods + virtual void SAL_CALL ClearFormatting() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAREPLACEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbarevision.cxx b/sw/source/ui/vba/vbarevision.cxx new file mode 100644 index 0000000000..f8b1c5978d --- /dev/null +++ b/sw/source/ui/vba/vbarevision.cxx @@ -0,0 +1,95 @@ +/* -*- 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 "vbarevision.hxx" +#include <sal/log.hxx> +#include <com/sun/star/document/XRedlinesSupplier.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include "wordvbahelper.hxx" +#include <docsh.hxx> +#include <doc.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaRevision::SwVbaRevision( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< frame::XModel > xModel, uno::Reference< beans::XPropertySet > xRedlineProps ) : SwVbaRevision_BASE( rParent, rContext ), mxModel(std::move( xModel )), mxRedlineProps(std::move( xRedlineProps )) +{ +} + +SwVbaRevision::~SwVbaRevision() +{ +} + +sal_Int32 SwVbaRevision::GetPosition() +{ + sal_Int32 nPos = -1; + uno::Reference< document::XRedlinesSupplier > xRedlinesSupp( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xRedlines( xRedlinesSupp->getRedlines(), uno::UNO_QUERY_THROW ); + sal_Int32 nCount = xRedlines->getCount(); + for( sal_Int32 i = 0; i < nCount; i++ ) + { + uno::Reference< beans::XPropertySet > xProps( xRedlines->getByIndex( i ), uno::UNO_QUERY_THROW ); + if( xProps == mxRedlineProps ) + { + nPos = i; + SAL_INFO("sw.ui", "the redline position is " << nPos); + break; + } + } + if( nPos == -1 ) + throw uno::RuntimeException(); + + return nPos; +} + +void SAL_CALL +SwVbaRevision::Accept() +{ + SwDoc* pDoc = word::getDocShell( mxModel )->GetDoc(); + if( pDoc ) + pDoc->getIDocumentRedlineAccess().AcceptRedline( GetPosition(), true ); +} + +void SAL_CALL +SwVbaRevision::Reject( ) +{ + SwDoc* pDoc = word::getDocShell( mxModel )->GetDoc(); + if( pDoc ) + pDoc->getIDocumentRedlineAccess().RejectRedline( GetPosition(), true ); +} + +OUString +SwVbaRevision::getServiceImplName() +{ + return "SwVbaRevision"; +} + +uno::Sequence< OUString > +SwVbaRevision::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Revision" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbarevision.hxx b/sw/source/ui/vba/vbarevision.hxx new file mode 100644 index 0000000000..c483f6578f --- /dev/null +++ b/sw/source/ui/vba/vbarevision.hxx @@ -0,0 +1,52 @@ +/* -*- 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_VBA_VBAREVISION_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAREVISION_HXX + +#include <ooo/vba/word/XRevision.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XRevision > SwVbaRevision_BASE; + +class SwVbaRevision : public SwVbaRevision_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::beans::XPropertySet > mxRedlineProps; + +private: + /// @throws css::uno::RuntimeException + sal_Int32 GetPosition(); + +public: + /// @throws css::uno::RuntimeException + SwVbaRevision( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::frame::XModel > xModel, css::uno::Reference< css::beans::XPropertySet > xRedlineProps ); + virtual ~SwVbaRevision() override; + + // Methods + virtual void SAL_CALL Accept( ) override; + virtual void SAL_CALL Reject( ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAREVISION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbarevisions.cxx b/sw/source/ui/vba/vbarevisions.cxx new file mode 100644 index 0000000000..bfd8c68eae --- /dev/null +++ b/sw/source/ui/vba/vbarevisions.cxx @@ -0,0 +1,185 @@ +/* -*- 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 "vbarevisions.hxx" +#include "vbarevision.hxx" +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/XRedlinesSupplier.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/text/XTextRangeCompare.hpp> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +typedef std::vector< uno::Reference< beans::XPropertySet > > RevisionMap; + +namespace { + +class RedlinesEnumeration : public ::cppu::WeakImplHelper< container::XEnumeration > +{ + RevisionMap mRevisionMap; + RevisionMap::iterator mIt; +public: + explicit RedlinesEnumeration( RevisionMap&& sMap ) : mRevisionMap( std::move(sMap) ), mIt( mRevisionMap.begin() ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( mIt != mRevisionMap.end() ); + } + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( !hasMoreElements() ) + throw container::NoSuchElementException(); + uno::Reference< beans::XPropertySet > xRevision( *mIt++ ); + return uno::Any( xRevision ) ; + } +}; + +class RevisionCollectionHelper : public ::cppu::WeakImplHelper< container::XIndexAccess, + container::XEnumerationAccess > +{ + RevisionMap mRevisionMap; +public: +/// @throws css::uno::RuntimeException +RevisionCollectionHelper( const uno::Reference< frame::XModel >& xModel, const uno::Reference< text::XTextRange >& xTextRange ); + + // XElementAccess + virtual uno::Type SAL_CALL getElementType( ) override { return cppu::UnoType<beans::XPropertySet>::get(); } + virtual sal_Bool SAL_CALL hasElements( ) override { return ( !mRevisionMap.empty() ); } + // XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount( ) override { return mRevisionMap.size(); } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + if ( Index < 0 || Index >= getCount() ) + throw lang::IndexOutOfBoundsException(); + + return uno::Any( mRevisionMap[ Index ] ); + + } + // XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + return new RedlinesEnumeration( std::vector(mRevisionMap) ); + } +}; + +} + +RevisionCollectionHelper::RevisionCollectionHelper( const uno::Reference< frame::XModel >& xModel, const uno::Reference< text::XTextRange >& xTextRange ) + { + uno::Reference< text::XTextRangeCompare > xTRC( xTextRange->getText(), uno::UNO_QUERY_THROW ); + uno::Reference< document::XRedlinesSupplier > xRedlinesSupp( xModel, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xRedlines( xRedlinesSupp->getRedlines(), uno::UNO_QUERY_THROW ); + sal_Int32 nCount = xRedlines->getCount(); + for( sal_Int32 index = 0; index < nCount; index++ ) + { + uno::Reference< text::XTextRange > xRedlineRange( xRedlines->getByIndex( index ), uno::UNO_QUERY_THROW ); + if( xTRC->compareRegionStarts( xTextRange, xRedlineRange ) >= 0 && xTRC->compareRegionEnds( xTextRange, xRedlineRange ) <= 0 ) + { + uno::Reference< beans::XPropertySet > xRedlineProps( xRedlineRange, uno::UNO_QUERY_THROW ); + mRevisionMap.push_back( xRedlineProps ); + } + } + } + +namespace { + +class RevisionsEnumeration : public EnumerationHelperImpl +{ + uno::Reference< frame::XModel > m_xModel; +public: + /// @throws uno::RuntimeException + RevisionsEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, uno::Reference< frame::XModel > xModel ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ), m_xModel(std::move( xModel )) {} + + virtual uno::Any SAL_CALL nextElement( ) override + { + uno::Reference< beans::XPropertySet > xRevision( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< word::XRevision > ( new SwVbaRevision( m_xParent, m_xContext, m_xModel, xRevision ) ) ); + } + +}; + +} + +SwVbaRevisions::SwVbaRevisions( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< frame::XModel >& xModel, const uno::Reference< text::XTextRange >& xTextRange ): SwVbaRevisions_BASE( xParent, xContext, new RevisionCollectionHelper( xModel, xTextRange ) ), mxModel( xModel ) +{ +} + +SwVbaRevisions::SwVbaRevisions( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, uno::Reference< frame::XModel > xModel, const uno::Reference< container::XIndexAccess >& xIndexAccess ): SwVbaRevisions_BASE( xParent, xContext, xIndexAccess ), mxModel(std::move( xModel )) +{ +} + +// XEnumerationAccess +uno::Type +SwVbaRevisions::getElementType() +{ + return cppu::UnoType<word::XRevision>::get(); +} +uno::Reference< container::XEnumeration > +SwVbaRevisions::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return new RevisionsEnumeration( this, mxContext, xEnumAccess->createEnumeration(), mxModel ); +} + +uno::Any +SwVbaRevisions::createCollectionObject( const css::uno::Any& aSource ) +{ + uno::Reference< beans::XPropertySet > xRevision( aSource, uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< word::XRevision > ( new SwVbaRevision( this, mxContext, mxModel, xRevision ) ) ); +} + +void SAL_CALL SwVbaRevisions::AcceptAll( ) +{ + // First we need to put all the redline into a vector, because if the redline is accepted, + // it will auto delete in the document. + std::vector< uno::Reference< word::XRevision > > aRevisions; + uno::Reference< container::XEnumeration > xEnumeration = createEnumeration(); + while( xEnumeration->hasMoreElements() ) + { + uno::Reference< word::XRevision > xRevision( xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); + aRevisions.push_back( xRevision ); + } + + for( const auto& xRevision : aRevisions ) + xRevision->Accept(); +} + +void SAL_CALL SwVbaRevisions::RejectAll( ) +{ + throw uno::RuntimeException(); +} + +OUString +SwVbaRevisions::getServiceImplName() +{ + return "SwVbaRevisions"; +} + +css::uno::Sequence<OUString> +SwVbaRevisions::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.Revisions" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbarevisions.hxx b/sw/source/ui/vba/vbarevisions.hxx new file mode 100644 index 0000000000..a3fe79108a --- /dev/null +++ b/sw/source/ui/vba/vbarevisions.hxx @@ -0,0 +1,54 @@ +/* -*- 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_VBA_VBAREVISIONS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAREVISIONS_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XRevisions.hpp> +#include <com/sun/star/text/XTextRange.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XRevisions > SwVbaRevisions_BASE; + +class SwVbaRevisions : public SwVbaRevisions_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + +public: + SwVbaRevisions( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xModel, const css::uno::Reference< css::text::XTextRange >& xTextRange ); + + SwVbaRevisions( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, css::uno::Reference< css::frame::XModel > xModel, const css::uno::Reference< css::container::XIndexAccess >& xIndexAccess ); + + // Methods + virtual void SAL_CALL AcceptAll( ) override; + virtual void SAL_CALL RejectAll( ) override; + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaRevisions_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAREVISIONS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbarow.cxx b/sw/source/ui/vba/vbarow.cxx new file mode 100644 index 0000000000..aa4f7701fd --- /dev/null +++ b/sw/source/ui/vba/vbarow.cxx @@ -0,0 +1,121 @@ +/* -*- 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 "vbarow.hxx" +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <ooo/vba/word/WdRowHeightRule.hpp> +#include <ooo/vba/word/WdConstants.hpp> +#include "vbatablehelper.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaRow::SwVbaRow( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext,uno::Reference< text::XTextTable > xTextTable, sal_Int32 nIndex ) : + SwVbaRow_BASE( rParent, rContext ), mxTextTable(std::move( xTextTable )), mnIndex( nIndex ) +{ + mxTableRows = mxTextTable->getRows(); + mxRowProps.set( mxTableRows->getByIndex( mnIndex ), uno::UNO_QUERY_THROW ); +} + +SwVbaRow::~SwVbaRow() +{ +} + +uno::Any SAL_CALL SwVbaRow::getHeight() +{ + if( getHeightRule() == word::WdRowHeightRule::wdRowHeightAuto ) + return uno::Any( sal_Int32( word::WdConstants::wdUndefined ) ); + + sal_Int32 nHeight = 0; + mxRowProps->getPropertyValue("Height") >>= nHeight; + return uno::Any( static_cast<float>(Millimeter::getInPoints( nHeight )) ); +} + +void SAL_CALL SwVbaRow::setHeight( const uno::Any& _height ) +{ + float height = 0; + _height >>= height; + + sal_Int32 nHeight = Millimeter::getInHundredthsOfOneMillimeter( height ); + mxRowProps->setPropertyValue("Height", uno::Any( nHeight ) ); +} + +::sal_Int32 SAL_CALL SwVbaRow::getHeightRule() +{ + bool isAutoHeight = false; + mxRowProps->getPropertyValue("IsAutoHeight") >>= isAutoHeight; + return isAutoHeight ? word::WdRowHeightRule::wdRowHeightAuto : word::WdRowHeightRule::wdRowHeightExactly; +} + +void SAL_CALL SwVbaRow::setHeightRule( ::sal_Int32 _heightrule ) +{ + bool isAutoHeight = ( _heightrule == word::WdRowHeightRule::wdRowHeightAuto ); + mxRowProps->setPropertyValue("IsAutoHeight", uno::Any( isAutoHeight ) ); +} + +void SAL_CALL +SwVbaRow::Select( ) +{ + SelectRow( getCurrentWordDoc(mxContext), mxTextTable, mnIndex, mnIndex ); +} + +void SwVbaRow::SelectRow( const uno::Reference< frame::XModel >& xModel, const uno::Reference< text::XTextTable >& xTextTable, sal_Int32 nStartRow, sal_Int32 nEndRow ) +{ + OUString sRangeName = "A" + OUString::number(nStartRow + 1); + SwVbaTableHelper aTableHelper( xTextTable ); + sal_Int32 nColCount = aTableHelper.getTabColumnsCount( nEndRow ); + // FIXME: the column count > 26 + //char cCol = 'A' + nColCount - 1; + OUString sCol = SwVbaTableHelper::getColumnStr( nColCount - 1); + sRangeName += ":" + sCol + OUString::number(nEndRow + 1); + + uno::Reference< table::XCellRange > xCellRange( xTextTable, uno::UNO_QUERY_THROW ); + uno::Reference< table::XCellRange > xSelRange = xCellRange->getCellRangeByName( sRangeName ); + + uno::Reference< view::XSelectionSupplier > xSelection( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); + xSelection->select( uno::Any( xSelRange ) ); +} + +void SAL_CALL SwVbaRow::SetHeight( float height, sal_Int32 heightrule ) +{ + setHeightRule( heightrule ); + setHeight( uno::Any( height ) ); +} + +OUString +SwVbaRow::getServiceImplName() +{ + return "SwVbaRow"; +} + +uno::Sequence< OUString > +SwVbaRow::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Row" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbarow.hxx b/sw/source/ui/vba/vbarow.hxx new file mode 100644 index 0000000000..40abaee2ee --- /dev/null +++ b/sw/source/ui/vba/vbarow.hxx @@ -0,0 +1,61 @@ +/* -*- 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_VBA_VBAROW_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAROW_HXX + +#include <ooo/vba/word/XRow.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/table/XTableRows.hpp> +#include <com/sun/star/text/XTextTable.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XRow > SwVbaRow_BASE; + +class SwVbaRow : public SwVbaRow_BASE +{ +private: + css::uno::Reference< css::text::XTextTable > mxTextTable; + css::uno::Reference< css::table::XTableRows > mxTableRows; + css::uno::Reference< css::beans::XPropertySet > mxRowProps; + sal_Int32 mnIndex; + +public: + /// @throws css::uno::RuntimeException + SwVbaRow( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::text::XTextTable > xTextTable, sal_Int32 nIndex ); + virtual ~SwVbaRow() override; + + // Attributes + virtual css::uno::Any SAL_CALL getHeight() override; + virtual void SAL_CALL setHeight( const css::uno::Any& _height ) override; + virtual ::sal_Int32 SAL_CALL getHeightRule() override; + virtual void SAL_CALL setHeightRule( ::sal_Int32 _heightrule ) override; + + // Methods + virtual void SAL_CALL Select( ) override; + virtual void SAL_CALL SetHeight( float height, sal_Int32 heightrule ) override; + + /// @throws css::uno::RuntimeException + static void SelectRow( const css::uno::Reference< css::frame::XModel >& xModel, const css::uno::Reference< css::text::XTextTable >& xTextTable, sal_Int32 nStartRow, sal_Int32 nEndRow ); + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAROW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbarows.cxx b/sw/source/ui/vba/vbarows.cxx new file mode 100644 index 0000000000..2b757ff31f --- /dev/null +++ b/sw/source/ui/vba/vbarows.cxx @@ -0,0 +1,370 @@ +/* -*- 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 "vbarows.hxx" +#include "vbarow.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <ooo/vba/word/WdRowAlignment.hpp> +#include <ooo/vba/word/WdConstants.hpp> +#include <ooo/vba/word/WdRulerStyle.hpp> +#include <basic/sberrors.hxx> +#include <utility> +#include "vbacolumns.hxx" +#include "vbatablehelper.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +class RowsEnumWrapper : public EnumerationHelper_BASE +{ + uno::WeakReference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< text::XTextTable > mxTextTable; + uno::Reference< container::XIndexAccess > mxIndexAccess; + sal_Int32 m_nIndex; + +public: + RowsEnumWrapper( const uno::Reference< XHelperInterface >& xParent, uno::Reference< uno::XComponentContext > xContext, uno::Reference< text::XTextTable > xTextTable ) : mxParent( xParent ), mxContext(std::move( xContext )), mxTextTable(std::move( xTextTable )), m_nIndex( 0 ) + { + mxIndexAccess = mxTextTable->getRows(); + } + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( m_nIndex < mxIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if( m_nIndex < mxIndexAccess->getCount() ) + { + return uno::Any( uno::Reference< word::XRow > ( new SwVbaRow( mxParent, mxContext, mxTextTable, m_nIndex++ ) ) ); + } + throw container::NoSuchElementException(); + } +}; + +} + +SwVbaRows::SwVbaRows( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, uno::Reference< text::XTextTable > xTextTable, const uno::Reference< table::XTableRows >& xTableRows ) : SwVbaRows_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( xTableRows, uno::UNO_QUERY_THROW ) ), mxTextTable(std::move( xTextTable )), mxTableRows( xTableRows ) +{ + mnStartRowIndex = 0; + mnEndRowIndex = m_xIndexAccess->getCount() - 1; +} + +SwVbaRows::SwVbaRows( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, uno::Reference< text::XTextTable > xTextTable, const uno::Reference< table::XTableRows >& xTableRows, sal_Int32 nStarIndex, sal_Int32 nEndIndex ) : SwVbaRows_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( xTableRows, uno::UNO_QUERY_THROW ) ), mxTextTable(std::move( xTextTable )), mxTableRows( xTableRows ), mnStartRowIndex( nStarIndex ), mnEndRowIndex( nEndIndex ) +{ + if( mnEndRowIndex < mnStartRowIndex ) + throw uno::RuntimeException(); +} + +/** + * get the alignment of the rows: SO format com.sun.star.text.HoriOrientation + * is mapped to WdRowAlignment in Word + * @return the alignment + */ +::sal_Int32 SAL_CALL SwVbaRows::getAlignment() +{ + sal_Int16 nAlignment = text::HoriOrientation::LEFT; + uno::Reference< beans::XPropertySet > xTableProps( mxTextTable, uno::UNO_QUERY_THROW ); + xTableProps->getPropertyValue("HoriOrient") >>= nAlignment; + sal_Int32 nRet = 0; + switch( nAlignment ) + { + case text::HoriOrientation::CENTER: + { + nRet = word::WdRowAlignment::wdAlignRowCenter; + break; + } + case text::HoriOrientation::RIGHT: + { + nRet = word::WdRowAlignment::wdAlignRowRight; + break; + } + default: + { + nRet = word::WdRowAlignment::wdAlignRowLeft; + } + } + return nRet; +} + +void SAL_CALL SwVbaRows::setAlignment( ::sal_Int32 _alignment ) +{ + sal_Int16 nAlignment = text::HoriOrientation::LEFT; + switch( _alignment ) + { + case word::WdRowAlignment::wdAlignRowCenter: + { + nAlignment = text::HoriOrientation::CENTER; + break; + } + case word::WdRowAlignment::wdAlignRowRight: + { + nAlignment = text::HoriOrientation::RIGHT; + break; + } + default: + { + nAlignment = text::HoriOrientation::LEFT; + } + } + uno::Reference< beans::XPropertySet > xTableProps( mxTextTable, uno::UNO_QUERY_THROW ); + xTableProps->setPropertyValue("HoriOrient", uno::Any( nAlignment ) ); +} + +uno::Any SAL_CALL SwVbaRows::getAllowBreakAcrossPages() +{ + bool bAllowBreak = false; + uno::Reference< container::XIndexAccess > xRowsAccess( mxTableRows, uno::UNO_QUERY_THROW ); + for( sal_Int32 index = mnStartRowIndex; index <= mnEndRowIndex; ++index ) + { + uno::Reference< beans::XPropertySet > xRowProps( xRowsAccess->getByIndex( index ), uno::UNO_QUERY_THROW ); + bool bSplit = false; + xRowProps->getPropertyValue("IsSplitAllowed") >>= bSplit; + if( index == 0 ) + { + bAllowBreak = bSplit; + } + if( bSplit != bAllowBreak ) + { + return uno::Any( sal_Int32(word::WdConstants::wdUndefined) ); + } + } + return uno::Any( bAllowBreak ); +} + +void SAL_CALL SwVbaRows::setAllowBreakAcrossPages( const uno::Any& _allowbreakacrosspages ) +{ + bool bAllowBreak = false; + _allowbreakacrosspages >>= bAllowBreak; + uno::Reference< container::XIndexAccess > xRowsAccess( mxTableRows, uno::UNO_QUERY_THROW ); + for( sal_Int32 index = mnStartRowIndex; index <= mnEndRowIndex; ++index ) + { + uno::Reference< beans::XPropertySet > xRowProps( xRowsAccess->getByIndex( index ), uno::UNO_QUERY_THROW ); + xRowProps->setPropertyValue("IsSplitAllowed", uno::Any( bAllowBreak ) ); + } +} + +float SAL_CALL SwVbaRows::getSpaceBetweenColumns() +{ + // just get the first spacing of the first cell + uno::Reference< table::XCellRange > xCellRange( mxTextTable, uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xCellProps( xCellRange->getCellByPosition( 0, mnStartRowIndex ), uno::UNO_QUERY_THROW ); + sal_Int32 nLeftBorderDistance = 0; + sal_Int32 nRightBorderDistance = 0; + xCellProps->getPropertyValue("LeftBorderDistance") >>= nLeftBorderDistance; + xCellProps->getPropertyValue("RightBorderDistance") >>= nRightBorderDistance; + return static_cast< float >( Millimeter::getInPoints( nLeftBorderDistance + nRightBorderDistance ) ); +} + +void SAL_CALL SwVbaRows::setSpaceBetweenColumns( float _spacebetweencolumns ) +{ + sal_Int32 nSpace = Millimeter::getInHundredthsOfOneMillimeter( _spacebetweencolumns ) / 2; + uno::Reference< container::XIndexAccess > xColumnAccess( mxTextTable->getColumns(), uno::UNO_QUERY_THROW ); + uno::Reference< table::XCellRange > xCellRange( mxTextTable, uno::UNO_QUERY_THROW ); + SwVbaTableHelper aTableHelper( mxTextTable ); + for( sal_Int32 row = mnStartRowIndex; row <= mnEndRowIndex; ++row ) + { + sal_Int32 nColumns = aTableHelper.getTabColumnsCount( row ); + for( sal_Int32 column = 0; column < nColumns; ++column ) + { + uno::Reference< beans::XPropertySet > xCellProps( xCellRange->getCellByPosition( column, row ), uno::UNO_QUERY_THROW ); + xCellProps->setPropertyValue("LeftBorderDistance", uno::Any( nSpace ) ); + xCellProps->setPropertyValue("RightBorderDistance", uno::Any( nSpace ) ); + } + } +} + +void SAL_CALL SwVbaRows::Delete( ) +{ + mxTableRows->removeByIndex( mnStartRowIndex, getCount() ); +} + +void SAL_CALL SwVbaRows::SetLeftIndent( float LeftIndent, ::sal_Int32 RulerStyle ) +{ + uno::Reference< word::XColumns > xColumns( new SwVbaColumns( getParent(), mxContext, mxTextTable, mxTextTable->getColumns() ) ); + sal_Int32 nIndent = static_cast<sal_Int32>(LeftIndent); + switch( RulerStyle ) + { + case word::WdRulerStyle::wdAdjustFirstColumn: + { + setIndentWithAdjustFirstColumn( xColumns, nIndent ); + break; + } + case word::WdRulerStyle::wdAdjustNone: + { + setIndentWithAdjustNone( nIndent ); + break; + } + case word::WdRulerStyle::wdAdjustProportional: + { + setIndentWithAdjustProportional( xColumns, nIndent ); + break; + } + case word::WdRulerStyle::wdAdjustSameWidth: + { + setIndentWithAdjustSameWidth( xColumns, nIndent ); + break; + } + default: + { + DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_ARGUMENT); + } + } +} + +void SwVbaRows::setIndentWithAdjustNone( sal_Int32 indent ) +{ + uno::Reference< beans::XPropertySet > xTableProps( mxTextTable, uno::UNO_QUERY_THROW ); + sal_Int32 nMargin = 0; + xTableProps->getPropertyValue("LeftMargin") >>= nMargin; + nMargin += indent; + xTableProps->setPropertyValue("LeftMargin", uno::Any( nMargin ) ); +} + + void SwVbaRows::setIndentWithAdjustFirstColumn( const uno::Reference< word::XColumns >& xColumns, sal_Int32 indent ) + { + uno::Reference< XCollection > xCol( xColumns, uno::UNO_QUERY_THROW ); + uno::Reference< word::XColumn > xColumn( xCol->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); + sal_Int32 nWidth = xColumn->getWidth(); + nWidth -= indent; + xColumn->setWidth( nWidth ); + setIndentWithAdjustNone( indent ); + } + + void SwVbaRows::setIndentWithAdjustProportional( + const uno::Reference< word::XColumns >& xColumns, + sal_Int32 indent +) + { + // calculate the new width and get the proportion between old and new + uno::Reference< beans::XPropertySet > xTableProps( mxTextTable, uno::UNO_QUERY_THROW ); + sal_Int32 nWidth = 0; + xTableProps->getPropertyValue("Width") >>= nWidth; + sal_Int32 nNewWidth = nWidth - indent; + if ((nNewWidth <= 0) || (nWidth <= 0)) + { + throw uno::RuntimeException( + "Pb with width, in SwVbaRows::setIndentWithAdjustProportional " + "(nNewWidth <= 0) || (nWidth <= 0)" + ); + } + double propFactor = static_cast<double>(nNewWidth)/static_cast<double>(nWidth); + + // get all columns, calculate and set the new width of the columns + uno::Reference< XCollection > xCol( xColumns, uno::UNO_QUERY_THROW ); + sal_Int32 nColCount = xCol->getCount(); + for( sal_Int32 i = 0; i < nColCount; i++ ) + { + uno::Reference< word::XColumn > xColumn( xCol->Item( uno::Any( i ), uno::Any() ), uno::UNO_QUERY_THROW ); + sal_Int32 nColWidth = xColumn->getWidth(); + sal_Int32 nNewColWidth = static_cast<sal_Int32>( propFactor * nColWidth ); + xColumn->setWidth( nNewColWidth ); + } + + // set the width and position of the table + setIndentWithAdjustNone( indent ); + xTableProps->setPropertyValue("Width", uno::Any( nNewWidth ) ); + } + + void SwVbaRows::setIndentWithAdjustSameWidth( const uno::Reference< word::XColumns >& xColumns, sal_Int32 indent ) + { + // calculate the new width and get the width of all columns + uno::Reference< beans::XPropertySet > xTableProps( mxTextTable, uno::UNO_QUERY_THROW ); + sal_Int32 nWidth = 0; + xTableProps->getPropertyValue("Width") >>= nWidth; + sal_Int32 nNewWidth = nWidth - indent; + + // get all columns, calculate and set the new width of the columns + uno::Reference< XCollection > xCol( xColumns, uno::UNO_QUERY_THROW ); + sal_Int32 nColCount = xCol->getCount(); + sal_Int32 nNewColWidth = static_cast<sal_Int32>( double( nNewWidth )/nColCount ); + for( sal_Int32 i = 0; i < nColCount; i++ ) + { + uno::Reference< word::XColumn > xColumn( xCol->Item( uno::Any( i ), uno::Any() ), uno::UNO_QUERY_THROW ); + xColumn->setWidth( nNewColWidth ); + } + + // set the width and position of the table + setIndentWithAdjustNone( indent ); + xTableProps->setPropertyValue("Width", uno::Any( nNewWidth ) ); + } + +void SAL_CALL SwVbaRows::Select( ) +{ + SwVbaRow::SelectRow( getCurrentWordDoc(mxContext), mxTextTable, mnStartRowIndex, mnEndRowIndex ); +} + +::sal_Int32 SAL_CALL SwVbaRows::getCount() +{ + return ( mnEndRowIndex - mnStartRowIndex + 1 ); +} + +uno::Any SAL_CALL SwVbaRows::Item( const uno::Any& Index1, const uno::Any& /*not processed in this base class*/ ) +{ + sal_Int32 nIndex = 0; + if( Index1 >>= nIndex ) + { + if( nIndex <= 0 || nIndex > getCount() ) + { + throw lang::IndexOutOfBoundsException("Index out of bounds" ); + } + return uno::Any( uno::Reference< word::XRow >( new SwVbaRow( this, mxContext, mxTextTable, nIndex - 1 ) ) ); + } + throw uno::RuntimeException("Index out of bounds" ); +} + +// XEnumerationAccess +uno::Type +SwVbaRows::getElementType() +{ + return cppu::UnoType<word::XRow>::get(); +} +uno::Reference< container::XEnumeration > +SwVbaRows::createEnumeration() +{ + return new RowsEnumWrapper( this, mxContext, mxTextTable ); +} + +uno::Any +SwVbaRows::createCollectionObject( const uno::Any& aSource ) +{ + return aSource; +} + +OUString +SwVbaRows::getServiceImplName() +{ + return "SwVbaRows"; +} + +uno::Sequence<OUString> +SwVbaRows::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.Rows" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbarows.hxx b/sw/source/ui/vba/vbarows.hxx new file mode 100644 index 0000000000..98a1069fa8 --- /dev/null +++ b/sw/source/ui/vba/vbarows.hxx @@ -0,0 +1,82 @@ +/* -*- 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_VBA_VBAROWS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAROWS_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XRows.hpp> +#include <ooo/vba/word/XColumns.hpp> +#include <com/sun/star/table/XTableRows.hpp> +#include <com/sun/star/text/XTextTable.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XRows > SwVbaRows_BASE; + +class SwVbaRows : public SwVbaRows_BASE +{ +private: + css::uno::Reference< css::text::XTextTable > mxTextTable; + css::uno::Reference< css::table::XTableRows > mxTableRows; + sal_Int32 mnStartRowIndex; + sal_Int32 mnEndRowIndex; + +private: + /// @throws css::uno::RuntimeException + void setIndentWithAdjustNone( sal_Int32 indent ); + /// @throws css::uno::RuntimeException + void setIndentWithAdjustFirstColumn( const css::uno::Reference< ooo::vba::word::XColumns >& xColumns, sal_Int32 indent ); + /// @throws css::uno::RuntimeException + void setIndentWithAdjustProportional( const css::uno::Reference< ooo::vba::word::XColumns >& xColumns, sal_Int32 indent ); + /// @throws css::uno::RuntimeException + void setIndentWithAdjustSameWidth( const css::uno::Reference< ooo::vba::word::XColumns >& xColumns, sal_Int32 indent ); + +public: + /// @throws css::uno::RuntimeException + SwVbaRows( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, css::uno::Reference< css::text::XTextTable > xTextTable, const css::uno::Reference< css::table::XTableRows >& xTableRows ); + /// @throws css::uno::RuntimeException + SwVbaRows( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, css::uno::Reference< css::text::XTextTable > xTextTable, const css::uno::Reference< css::table::XTableRows >& xTableRows, sal_Int32 nStarIndex, sal_Int32 nEndIndex ); + + // Attributes + virtual ::sal_Int32 SAL_CALL getAlignment() override; + virtual void SAL_CALL setAlignment( ::sal_Int32 _alignment ) override; + virtual css::uno::Any SAL_CALL getAllowBreakAcrossPages() override; + virtual void SAL_CALL setAllowBreakAcrossPages( const css::uno::Any& _allowbreakacrosspages ) override; + virtual float SAL_CALL getSpaceBetweenColumns() override; + virtual void SAL_CALL setSpaceBetweenColumns( float _spacebetweencolumns ) override; + + // Methods + virtual void SAL_CALL Delete( ) override; + virtual void SAL_CALL SetLeftIndent( float LeftIndent, ::sal_Int32 RulerStyle ) override; + virtual void SAL_CALL Select( ) override; + + //XCollection + virtual ::sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index1, const css::uno::Any& /*not processed in this base class*/ ) override; + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaRows_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAROWS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbasection.cxx b/sw/source/ui/vba/vbasection.cxx new file mode 100644 index 0000000000..40ecdaabd5 --- /dev/null +++ b/sw/source/ui/vba/vbasection.cxx @@ -0,0 +1,84 @@ +/* -*- 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 "vbasection.hxx" +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include "vbapagesetup.hxx" +#include "vbaheadersfooters.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaSection::SwVbaSection( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< frame::XModel > xModel, uno::Reference< beans::XPropertySet > xProps ) : + SwVbaSection_BASE( rParent, rContext ), mxModel(std::move( xModel )), mxPageProps(std::move( xProps )) +{ +} + +SwVbaSection::~SwVbaSection() +{ +} + +sal_Bool SAL_CALL SwVbaSection::getProtectedForForms() +{ + return false; +} + +void SAL_CALL SwVbaSection::setProtectedForForms( sal_Bool /*_protectedforforms*/ ) +{ +} + +uno::Any SAL_CALL SwVbaSection::Headers( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaHeadersFooters( this, mxContext, mxModel, mxPageProps, true ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL SwVbaSection::Footers( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaHeadersFooters( this, mxContext, mxModel, mxPageProps, false ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaSection::PageSetup( ) +{ + return uno::Any( uno::Reference< word::XPageSetup >( new SwVbaPageSetup( this, mxContext, mxModel, mxPageProps ) ) ); +} + +OUString +SwVbaSection::getServiceImplName() +{ + return "SwVbaSection"; +} + +uno::Sequence< OUString > +SwVbaSection::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Section" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbasection.hxx b/sw/source/ui/vba/vbasection.hxx new file mode 100644 index 0000000000..9a1b927424 --- /dev/null +++ b/sw/source/ui/vba/vbasection.hxx @@ -0,0 +1,53 @@ +/* -*- 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_VBA_VBASECTION_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBASECTION_HXX + +#include <ooo/vba/word/XSection.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XSection > SwVbaSection_BASE; + +class SwVbaSection : public SwVbaSection_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::beans::XPropertySet > mxPageProps; + +public: + /// @throws css::uno::RuntimeException + SwVbaSection( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::frame::XModel > xModel, css::uno::Reference< css::beans::XPropertySet > xProps ); + virtual ~SwVbaSection() override; + + // Attributes + virtual sal_Bool SAL_CALL getProtectedForForms() override; + virtual void SAL_CALL setProtectedForForms( sal_Bool _protectedforforms ) override; + + // Methods + virtual css::uno::Any SAL_CALL Headers( const css::uno::Any& index ) override; + virtual css::uno::Any SAL_CALL Footers( const css::uno::Any& index ) override; + virtual css::uno::Any SAL_CALL PageSetup( ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBASECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbasections.cxx b/sw/source/ui/vba/vbasections.cxx new file mode 100644 index 0000000000..fe9315ebf6 --- /dev/null +++ b/sw/source/ui/vba/vbasections.cxx @@ -0,0 +1,195 @@ +/* -*- 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 "vbasections.hxx" +#include "vbasection.hxx" +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include "wordvbahelper.hxx" +#include <cppuhelper/implbase.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +typedef std::vector< uno::Reference< beans::XPropertySet > > XSectionVec; + +namespace { + +class SectionEnumeration : public ::cppu::WeakImplHelper< container::XEnumeration > +{ + XSectionVec mxSections; + XSectionVec::iterator mIt; + +public: + explicit SectionEnumeration( XSectionVec&& rVec ) : mxSections( std::move(rVec) ), mIt( mxSections.begin() ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( mIt != mxSections.end() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( hasMoreElements() ) + return uno::Any( *mIt++ ); + throw container::NoSuchElementException(); + } +}; + +// here I regard pagestyle as section +class SectionCollectionHelper : public ::cppu::WeakImplHelper< container::XIndexAccess, + container::XEnumerationAccess > +{ +private: + uno::Reference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< frame::XModel > mxModel; + XSectionVec mxSections; + +public: + /// @throws uno::RuntimeException + SectionCollectionHelper( uno::Reference< XHelperInterface > xParent, uno::Reference< uno::XComponentContext > xContext, uno::Reference< frame::XModel > xModel ) : mxParent(std::move( xParent )), mxContext(std::move( xContext )), mxModel(std::move( xModel )) + { + uno::Reference< style::XStyleFamiliesSupplier > xSytleFamSupp( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xSytleFamNames( xSytleFamSupp->getStyleFamilies(), uno::UNO_SET_THROW ); + uno::Reference< container::XIndexAccess > xPageStyles( xSytleFamNames->getByName("PageStyles"), uno::UNO_QUERY_THROW ); + sal_Int32 nCount = xPageStyles->getCount(); + for( sal_Int32 index = 0; index < nCount; ++index ) + { + uno::Reference< style::XStyle > xStyle( xPageStyles->getByIndex( index ), uno::UNO_QUERY_THROW ); + // only the pagestyles in using are considered + if( xStyle->isInUse( ) ) + { + uno::Reference< beans::XPropertySet > xPageProps( xStyle, uno::UNO_QUERY_THROW ); + mxSections.push_back( xPageProps ); + } + } + } + + /// @throws uno::RuntimeException + SectionCollectionHelper( uno::Reference< XHelperInterface > xParent, uno::Reference< uno::XComponentContext > xContext, uno::Reference< frame::XModel > xModel, const uno::Reference< text::XTextRange >& xTextRange ) : mxParent(std::move( xParent )), mxContext(std::move( xContext )), mxModel(std::move( xModel )) + { + // Hacky implementation of Range.Sections, only support 1 section + uno::Reference< beans::XPropertySet > xRangeProps( xTextRange, uno::UNO_QUERY_THROW ); + uno::Reference< style::XStyle > xStyle = word::getCurrentPageStyle( mxModel, xRangeProps ); + uno::Reference< beans::XPropertySet > xPageProps( xStyle, uno::UNO_QUERY_THROW ); + mxSections.push_back( xPageProps ); + } + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount( ) override + { + return mxSections.size(); + } + virtual uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override + { + if ( Index < 0 || Index >= getCount() ) + throw css::lang::IndexOutOfBoundsException(); + + uno::Reference< beans::XPropertySet > xPageProps( mxSections[ Index ], uno::UNO_SET_THROW ); + return uno::Any( uno::Reference< word::XSection >( new SwVbaSection( mxParent, mxContext, mxModel, xPageProps ) ) ); + } + virtual uno::Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<word::XSection>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + return true; + } + // XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + return new SectionEnumeration( std::vector(mxSections) ); + } +}; + +class SectionsEnumWrapper : public EnumerationHelperImpl +{ + uno::Reference< frame::XModel > mxModel; +public: + /// @throws uno::RuntimeException + SectionsEnumWrapper( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, uno::Reference< frame::XModel > xModel ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ), mxModel(std::move( xModel )){} + + virtual uno::Any SAL_CALL nextElement( ) override + { + uno::Reference< beans::XPropertySet > xPageProps( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< word::XSection > ( new SwVbaSection( m_xParent, m_xContext, mxModel, xPageProps ) ) ); + } +}; + +} + +SwVbaSections::SwVbaSections( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< frame::XModel >& xModel ): SwVbaSections_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( new SectionCollectionHelper( xParent, xContext, xModel ) ) ), mxModel( xModel ) +{ +} + +SwVbaSections::SwVbaSections( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< frame::XModel >& xModel, const uno::Reference< text::XTextRange >& xTextRange ): SwVbaSections_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( new SectionCollectionHelper( xParent, xContext, xModel, xTextRange ) ) ), mxModel( xModel ) +{ +} + +uno::Any SAL_CALL +SwVbaSections::PageSetup( ) +{ + if( m_xIndexAccess->getCount() ) + { + // check if the first section is our want + uno::Reference< word::XSection > xSection( m_xIndexAccess->getByIndex( 0 ), uno::UNO_QUERY_THROW ); + return xSection->PageSetup(); + } + throw uno::RuntimeException("There is no section" ); +} + +// XEnumerationAccess +uno::Type SAL_CALL +SwVbaSections::getElementType() +{ + return cppu::UnoType<word::XSection>::get(); +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwVbaSections::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return new SectionsEnumWrapper( this, mxContext, xEnumAccess->createEnumeration(), mxModel ); +} + +uno::Any +SwVbaSections::createCollectionObject( const css::uno::Any& aSource ) +{ + return aSource; +} + +OUString +SwVbaSections::getServiceImplName() +{ + return "SwVbaSections"; +} + +css::uno::Sequence<OUString> +SwVbaSections::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.Sections" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbasections.hxx b/sw/source/ui/vba/vbasections.hxx new file mode 100644 index 0000000000..3bf3ab4ca3 --- /dev/null +++ b/sw/source/ui/vba/vbasections.hxx @@ -0,0 +1,51 @@ +/* -*- 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_VBA_VBASECTIONS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBASECTIONS_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XSections.hpp> +#include <com/sun/star/text/XTextRange.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XSections > SwVbaSections_BASE; + +class SwVbaSections : public SwVbaSections_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + +public: + SwVbaSections( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xModel ); + SwVbaSections( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xModel, const css::uno::Reference< css::text::XTextRange >& xTextRange ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + virtual css::uno::Any SAL_CALL PageSetup( ) override; + + // SwVbaSections_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBASECTIONS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaselection.cxx b/sw/source/ui/vba/vbaselection.cxx new file mode 100644 index 0000000000..d983bd2bd2 --- /dev/null +++ b/sw/source/ui/vba/vbaselection.cxx @@ -0,0 +1,1169 @@ +/* -*- 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 "vbaselection.hxx" +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include "vbarange.hxx" +#include "vbafind.hxx" +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/text/XTextTable.hpp> +#include <com/sun/star/text/XTextTableCursor.hpp> +#include <com/sun/star/table/XCell.hpp> +#include <basic/sberrors.hxx> +#include <ooo/vba/word/WdUnits.hpp> +#include <ooo/vba/word/WdMovementType.hpp> +#include <ooo/vba/word/WdGoToItem.hpp> +#include <ooo/vba/word/WdGoToDirection.hpp> +#include <ooo/vba/word/XBookmark.hpp> +#include <ooo/vba/word/XApplication.hpp> +#include <ooo/vba/word/WdCollapseDirection.hpp> +#include <com/sun/star/text/XPageCursor.hpp> +#include <unotbl.hxx> +#include <unocoll.hxx> +#include "vbatable.hxx" +#include <com/sun/star/view/XViewCursor.hpp> +#include <com/sun/star/view/XLineCursor.hpp> +#include <com/sun/star/text/XWordCursor.hpp> +#include <com/sun/star/text/XParagraphCursor.hpp> +#include <ooo/vba/word/WdInformation.hpp> +#include <ooo/vba/word/WdHeaderFooterIndex.hpp> +#include <ooo/vba/word/WdSeekView.hpp> +#include "vbainformationhelper.hxx" +#include "vbafield.hxx" +#include "vbaheaderfooter.hxx" +#include "vbaheaderfooterhelper.hxx" +#include <vbahelper/vbashaperange.hxx> +#include <com/sun/star/drawing/ShapeCollection.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include "vbarows.hxx" +#include "vbacolumns.hxx" +#include "vbatablehelper.hxx" +#include "vbacells.hxx" +#include "vbaview.hxx" +#include "vbaparagraph.hxx" +#include "vbastyle.hxx" +#include <docsh.hxx> +#include <tblenum.hxx> +#include <sal/log.hxx> +#include <fesh.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaSelection::SwVbaSelection( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< frame::XModel > xModel ) : SwVbaSelection_BASE( rParent, rContext ), mxModel(std::move( xModel )) +{ + mxTextViewCursor = word::getXTextViewCursor( mxModel ); +} + +SwVbaSelection::~SwVbaSelection() +{ +} + +uno::Reference< text::XTextRange > SwVbaSelection::GetSelectedRange() +{ + uno::Reference< text::XTextRange > xTextRange; + uno::Reference< lang::XServiceInfo > xServiceInfo( mxModel->getCurrentSelection(), uno::UNO_QUERY_THROW ); + if( !xServiceInfo->supportsService("com.sun.star.text.TextRanges") ) + { + throw uno::RuntimeException("Not implemented" ); + } + + uno::Reference< container::XIndexAccess > xTextRanges( xServiceInfo, uno::UNO_QUERY_THROW ); + if( xTextRanges->getCount() > 0 ) + { + // if there are multiple selection, just return the last selected Range. + xTextRange.set( xTextRanges->getByIndex( xTextRanges->getCount()-1 ), uno::UNO_QUERY_THROW ); + } + + return xTextRange; +} + +uno::Reference< word::XRange > SAL_CALL +SwVbaSelection::getRange() +{ + uno::Reference< text::XTextRange > xTextRange = GetSelectedRange(); + uno::Reference< text::XTextDocument > xDocument( mxModel, uno::UNO_QUERY_THROW ); + return uno::Reference< word::XRange >( new SwVbaRange( this, mxContext, xDocument, xTextRange->getStart(), xTextRange->getEnd(), mxTextViewCursor->getText() ) ); +} + +OUString SAL_CALL +SwVbaSelection::getText() +{ + return getRange()->getText(); +} + +void SAL_CALL +SwVbaSelection::setText( const OUString& rText ) +{ + getRange()->setText( rText ); +} + +void SAL_CALL +SwVbaSelection::TypeText( const OUString& rText ) +{ + // FIXME: handle the property Options.ReplaceSelection, the default value is true + setText( rText ); +} + +void SAL_CALL +SwVbaSelection::HomeKey( const uno::Any& _unit, const uno::Any& _extend ) +{ + sal_Int32 nUnit = word::WdUnits::wdLine; + sal_Int32 nExtend = word::WdMovementType::wdMove; + _unit >>= nUnit; + _extend >>= nExtend; + bool bExtend = nExtend == word::WdMovementType::wdExtend; + + switch( nUnit ) + { + case word::WdUnits::wdStory: + { + // go to the valid text first so that the current view cursor is valid to call gotoRange. + word::gotoSelectedObjectAnchor(mxModel); + // go to the begin of the document + uno::Reference< text::XText > xCurrentText = word::getCurrentXText( mxModel ); + uno::Reference< text::XTextRange > xFirstRange = word::getFirstObjectPosition( xCurrentText ); + mxTextViewCursor->gotoRange( xFirstRange, bExtend ); + break; + } + case word::WdUnits::wdLine: + { + // go to the begin of the Line + uno::Reference< view::XLineCursor > xLineCursor( mxTextViewCursor, uno::UNO_QUERY_THROW ); + xLineCursor->gotoStartOfLine( bExtend ); + break; + } + default: + { + throw uno::RuntimeException("Not implemented" ); + } + } +} + +void SAL_CALL +SwVbaSelection::EndKey( const uno::Any& _unit, const uno::Any& _extend ) +{ + sal_Int32 nUnit = word::WdUnits::wdLine; + sal_Int32 nExtend = word::WdMovementType::wdMove; + _unit >>= nUnit; + _extend >>= nExtend; + bool bExtend = nExtend == word::WdMovementType::wdExtend; + + switch( nUnit ) + { + case word::WdUnits::wdStory: + { + // go to the valid text first so that the current view cursor is valid to call gotoRange. + word::gotoSelectedObjectAnchor(mxModel); + // go to the end of the document + uno::Reference< text::XText > xCurrentText = word::getCurrentXText( mxModel ); + uno::Reference< text::XTextRange > xEnd = xCurrentText->getEnd(); + mxTextViewCursor->gotoRange( xEnd, bExtend ); + break; + } + case word::WdUnits::wdLine: + { + // go to the end of the Line + uno::Reference< view::XLineCursor > xLineCursor( mxTextViewCursor, uno::UNO_QUERY_THROW ); + xLineCursor->gotoEndOfLine( bExtend ); + break; + } + default: + { + throw uno::RuntimeException("Not implemented" ); + } + } +} + +void SAL_CALL +SwVbaSelection::Delete( const uno::Any& _unit, const uno::Any& _count ) +{ + sal_Int32 nUnit = word::WdUnits::wdLine; + sal_Int32 nCount = 0; + if( _count.hasValue() ) + _count >>= nCount; + if( _unit.hasValue() && ( nCount > 0 ) ) + { + _unit >>= nUnit; + switch( nUnit ) + { + case word::WdUnits::wdCharacter: + { + if( HasSelection() ) + nCount--; + mxTextViewCursor->goRight( nCount, true ); + break; + } + default: + { + throw uno::RuntimeException("Not implemented" ); + } + } + } + dispatchRequests( mxModel,".uno:Delete" ); +} + +void +SwVbaSelection::Move( const uno::Any& _unit, const uno::Any& _count, const uno::Any& _extend, word::E_DIRECTION eDirection ) +{ + sal_Int32 nUnit = word::WdUnits::wdCharacter; + sal_Int32 nCount = 1; + sal_Int32 nExtend = word::WdMovementType::wdMove; + + if( _unit.hasValue() ) + _unit >>= nUnit; + if( _count.hasValue() ) + _count >>= nCount; + if( _extend.hasValue() ) + _extend >>= nExtend; + + if( nCount == 0 ) + return; + + bool bExpand = nExtend != word::WdMovementType::wdMove; + + switch( nUnit ) + { + case word::WdUnits::wdCell: + { + if( nExtend == word::WdMovementType::wdExtend ) + { + DebugHelper::basicexception(ERRCODE_BASIC_BAD_ARGUMENT, {}); + return; + } + NextCell( nCount, eDirection ); + break; + } + case word::WdUnits::wdLine: + { + if( eDirection == word::MOVE_LEFT || eDirection == word::MOVE_RIGHT ) + { + throw uno::RuntimeException("Not implemented" ); + } + uno::Reference< view::XViewCursor > xViewCursor( mxTextViewCursor, uno::UNO_QUERY_THROW ); + if( eDirection == word::MOVE_UP ) + xViewCursor->goUp( nCount, bExpand ); + else if( eDirection == word::MOVE_DOWN ) + xViewCursor->goDown( nCount, bExpand ); + break; + } + case word::WdUnits::wdCharacter: + { + if( eDirection == word::MOVE_UP || eDirection == word::MOVE_DOWN ) + { + throw uno::RuntimeException("Not implemented" ); + } + if( word::gotoSelectedObjectAnchor( mxModel ) ) + { + nCount--; + } + uno::Reference< view::XViewCursor > xViewCursor( mxTextViewCursor, uno::UNO_QUERY_THROW ); + if( eDirection == word::MOVE_LEFT ) + { + // if current select is a cellrange or table, + // the first count of move should move to the first selected cell. + uno::Reference< text::XTextTableCursor > xTextTableCursor( mxModel->getCurrentSelection(), uno::UNO_QUERY ); + if ( xTextTableCursor.is() ) + { + uno::Reference< beans::XPropertySet > xCursorProps( mxTextViewCursor, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextTable > xTextTable; + xCursorProps->getPropertyValue("TextTable") >>= xTextTable; + if( xTextTable.is() ) + { + uno::Reference< text::XTextRange > xRange( xTextTable->getCellByName( xTextTableCursor->getRangeName()), uno::UNO_QUERY_THROW ); + mxTextViewCursor->gotoRange( xRange->getStart(), bExpand ); + nCount--; + } + } + xViewCursor->goLeft( nCount, bExpand ); + } + else if( eDirection == word::MOVE_RIGHT ) + xViewCursor->goRight( nCount, bExpand ); + break; + } + case word::WdUnits::wdWord: + case word::WdUnits::wdParagraph: + { + uno::Reference< text::XTextRange > xRange = GetSelectedRange(); + uno::Reference< text::XText > xText = xRange->getText(); + uno::Reference< text::XTextCursor > xTextCursor = xText->createTextCursorByRange( xRange ); + if( nUnit == word::WdUnits::wdParagraph ) + { + if( eDirection == word::MOVE_LEFT || eDirection == word::MOVE_RIGHT ) + { + throw uno::RuntimeException("Not implemented" ); + } + uno::Reference< text::XParagraphCursor > xParagraphCursor( xTextCursor, uno::UNO_QUERY_THROW ); + for( sal_Int32 i=0; i<nCount; i++ ) + { + if( ( eDirection == word::MOVE_UP ) && !xParagraphCursor->gotoPreviousParagraph( bExpand ) ) + break; + else if( ( eDirection == word::MOVE_DOWN ) && !xParagraphCursor->gotoNextParagraph( bExpand ) ) + break; + } + } + else if( nUnit == word::WdUnits::wdWord ) + { + if( eDirection == word::MOVE_UP || eDirection == word::MOVE_DOWN ) + { + throw uno::RuntimeException("Not implemented" ); + } + uno::Reference< text::XWordCursor > xWordCursor( xTextCursor, uno::UNO_QUERY_THROW ); + for( sal_Int32 i=0; i<nCount; i++ ) + { + if( (eDirection == word::MOVE_LEFT ) && !xWordCursor->gotoPreviousWord( bExpand ) ) + break; + else if( ( eDirection == word::MOVE_RIGHT ) && !xWordCursor->gotoNextWord( bExpand ) ) + break; + } + } + mxTextViewCursor->gotoRange( xTextCursor->getStart(), false ); + mxTextViewCursor->gotoRange( xTextCursor->getEnd(), true ); + break; + } + default: + { + throw uno::RuntimeException("Not implemented" ); + } + } +} + +void SwVbaSelection::NextCell(sal_Int32 nCount, word::E_DIRECTION eDirection) +{ + uno::Reference< beans::XPropertySet > xCursorProps( mxTextViewCursor, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextTable > xTextTable; + uno::Reference< table::XCell > xCell; + xCursorProps->getPropertyValue("TextTable") >>= xTextTable; + xCursorProps->getPropertyValue("Cell") >>= xCell; + if( !xTextTable.is() || !xCell.is() ) + { + DebugHelper::basicexception(ERRCODE_BASIC_BAD_ARGUMENT, {}); + return; + } + uno::Reference< beans::XPropertySet > xCellProps( xCell, uno::UNO_QUERY_THROW ); + OUString aCellName; + xCellProps->getPropertyValue("CellName") >>= aCellName; + uno::Reference< text::XTextTableCursor > xTextTableCursor = xTextTable->createCursorByCellName( aCellName ); + // move the table cursor + switch( eDirection ) + { + case word::MOVE_LEFT: + { + xTextTableCursor->goLeft( nCount, false ); + break; + } + case word::MOVE_RIGHT: + { + xTextTableCursor->goRight( nCount, false ); + break; + } + case word::MOVE_UP: + { + xTextTableCursor->goUp( nCount, false ); + break; + } + case word::MOVE_DOWN: + { + xTextTableCursor->goDown( nCount, false ); + break; + } + default: + { + DebugHelper::basicexception(ERRCODE_BASIC_BAD_ARGUMENT, {}); + return; + } + } + // move the view cursor + xCell = xTextTable->getCellByName( xTextTableCursor->getRangeName() ); + mxTextViewCursor->gotoRange( uno::Reference< text::XTextRange >( xCell, uno::UNO_QUERY_THROW ), false ); +} + +void SAL_CALL +SwVbaSelection::MoveRight(const uno::Any& _unit, const uno::Any& _count, const uno::Any& _extend) +{ + sal_Int32 nCount = 1; + + if( _count.hasValue() ) + _count >>= nCount; + + if( nCount == 0 ) + return; + + if( nCount < 0 ) + { + MoveLeft( _unit, uno::Any( -nCount ), _extend ); + return; + } + + Move( _unit, _count, _extend, word::MOVE_RIGHT ); +} + +void SAL_CALL +SwVbaSelection::MoveLeft(const uno::Any& _unit, const uno::Any& _count, const uno::Any& _extend) +{ + sal_Int32 nCount = 1; + if( _count.hasValue() ) + _count >>= nCount; + + if( nCount == 0 ) + return; + + if( nCount < 0 ) + { + MoveRight( _unit, uno::Any( -nCount ), _extend ); + return; + } + + Move( _unit, _count, _extend, word::MOVE_LEFT ); +} + +void SAL_CALL +SwVbaSelection::MoveDown(const uno::Any& _unit, const uno::Any& _count, const uno::Any& _extend) +{ + sal_Int32 nCount = 1; + + if( _count.hasValue() ) + _count >>= nCount; + + if( nCount == 0 ) + return; + + if( nCount < 0 ) + { + MoveUp( _unit, uno::Any( -nCount ), _extend ); + return; + } + + Move( _unit, _count, _extend, word::MOVE_DOWN ); +} + +void SAL_CALL +SwVbaSelection::MoveUp(const uno::Any& _unit, const uno::Any& _count, const uno::Any& _extend) +{ + sal_Int32 nCount = 1; + + if( _count.hasValue() ) + _count >>= nCount; + + if( nCount == 0 ) + return; + + if( nCount < 0 ) + { + MoveDown( _unit, uno::Any( -nCount ), _extend ); + return; + } + + Move( _unit, _count, _extend, word::MOVE_UP ); +} + +void SAL_CALL +SwVbaSelection::TypeParagraph() +{ + // #FIXME: if the selection is an entire paragraph, it's replaced + // by the new paragraph + bool isCollapsed = mxTextViewCursor->isCollapsed(); + InsertParagraph(); + if( isCollapsed ) + mxTextViewCursor->collapseToStart(); +} + +void SAL_CALL +SwVbaSelection::InsertParagraph() +{ + // #FIXME: the selection should include the new paragraph. + getRange()->InsertParagraph(); +} + +void SAL_CALL +SwVbaSelection::InsertParagraphBefore() +{ + getRange()->InsertParagraphBefore(); +} + +void SAL_CALL +SwVbaSelection::InsertParagraphAfter() +{ + getRange()->InsertParagraphAfter(); +} + +uno::Reference< word::XParagraphFormat > SAL_CALL +SwVbaSelection::getParagraphFormat() +{ + return getRange()->getParagraphFormat(); +} + +void SAL_CALL +SwVbaSelection::setParagraphFormat( const uno::Reference< word::XParagraphFormat >& rParagraphFormat ) +{ + return getRange()->setParagraphFormat( rParagraphFormat ); +} + +uno::Reference< word::XFind > SAL_CALL +SwVbaSelection::getFind() +{ + uno::Reference< text::XTextRange > xTextRange = GetSelectedRange(); + uno::Reference< text::XTextRange > xStart = xTextRange->getStart(); + uno::Reference< text::XTextRange > xEnd = xTextRange->getEnd(); + uno::Reference< text::XTextRangeCompare > xTRC( xTextRange->getText(), uno::UNO_QUERY_THROW ); + int n = xTRC->compareRegionStarts( xStart, xEnd); + if( n == 0 ) + { + WholeStory(); + xTextRange = GetSelectedRange(); + } + return SwVbaFind::GetOrCreateFind(this, mxContext, mxModel, xTextRange); +} + +uno::Any SAL_CALL +SwVbaSelection::getStyle() +{ + return getRange()->getStyle(); +} + +void SAL_CALL +SwVbaSelection::setStyle( const uno::Any& rStyle ) +{ + uno::Reference< beans::XPropertySet > xParaProps( mxTextViewCursor, uno::UNO_QUERY_THROW ); + return SwVbaStyle::setStyle( xParaProps, rStyle ); +} + +uno::Reference< word::XFont > SAL_CALL +SwVbaSelection::getFont() +{ + return getRange()->getFont(); +} + +void SAL_CALL +SwVbaSelection::TypeBackspace() +{ + dispatchRequests( mxModel,".uno:SwBackspace" ); +} + +uno::Reference< word::XRange > SAL_CALL SwVbaSelection::GoTo( const uno::Any& _what, const uno::Any& _which, const uno::Any& _count, const uno::Any& _name ) +{ + sal_Int32 nWhat = 0; + if( !( _what >>= nWhat ) ) + DebugHelper::basicexception(ERRCODE_BASIC_BAD_ARGUMENT, {}); + switch( nWhat ) + { + case word::WdGoToItem::wdGoToBookmark: + { + uno::Reference< word::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); + uno::Reference< word::XBookmark > xBookmark( xApplication->getActiveDocument()->Bookmarks(_name), uno::UNO_QUERY_THROW ); + xBookmark->Select(); + break; + } + case word::WdGoToItem::wdGoToPage: + { + uno::Reference< text::XPageCursor > xPageCursor( mxTextViewCursor, uno::UNO_QUERY_THROW ); + sal_Int32 nCurrPage = xPageCursor->getPage(); + sal_Int32 nLastPage = word::getPageCount( mxModel ); + sal_Int32 nCount = 0; + if( _count.hasValue() ) + _count >>= nCount; + sal_Int32 nWhich = 0; + if( _which.hasValue() ) + _which >>= nWhich; + sal_Int32 nPage = 0; + switch( nWhich ) + { + case word::WdGoToDirection::wdGoToLast: + { + nPage = nLastPage; + break; + } + case word::WdGoToDirection::wdGoToNext: + { + if( nCount !=0 ) + nPage = nCurrPage + nCount; + else + nPage = nCurrPage + 1; + break; + } + case word::WdGoToDirection::wdGoToPrevious: + { + if( nCount !=0 ) + nPage = nCurrPage - nCount; + else + nPage = nCurrPage - 1; + break; + } + default: + { + nPage = nCount; + } + } + if( _name.hasValue() ) + { + OUString sName; + _name >>= sName; + sal_Int32 nName = sName.toInt32(); + if( nName !=0 ) + nPage = nName; + } + if( nPage <= 0 ) + nPage = 1; + if( nPage > nLastPage ) + nPage = nLastPage; + xPageCursor->jumpToPage( static_cast<sal_Int16>(nPage) ); + break; + } + case word::WdGoToItem::wdGoToSection: + { + uno::Reference< text::XPageCursor > xPageCursor( mxTextViewCursor, uno::UNO_QUERY_THROW ); + sal_Int32 nCount = 0; + if( _count.hasValue() ) + _count >>= nCount; + sal_Int32 nWhich = 0; + if( _which.hasValue() ) + _which >>= nWhich; + sal_Int32 nPage = 0; + switch( nWhich ) + { + case word::WdGoToDirection::wdGoToAbsolute: + { + // currently only support this type + if( nCount == 1 ) + nPage = 1; + break; + } + default: + { + nPage = 0; + } + } + if( nPage == 0 ) + throw uno::RuntimeException("Not implemented" ); + xPageCursor->jumpToPage( static_cast<sal_Int16>(nPage) ); + break; + } + default: + throw uno::RuntimeException("Not implemented" ); + } + return getRange(); +} + +::sal_Int32 SAL_CALL SwVbaSelection::getLanguageID() +{ + return getRange()->getLanguageID(); +} + +void SAL_CALL SwVbaSelection::setLanguageID( ::sal_Int32 _languageid ) +{ + getRange()->setLanguageID( _languageid ); +} + +uno::Any SAL_CALL SwVbaSelection::Information( sal_Int32 _type ) +{ + uno::Any result; + switch( _type ) + { + case word::WdInformation::wdActiveEndPageNumber: + { + result <<= SwVbaInformationHelper::handleWdActiveEndPageNumber( mxTextViewCursor ); + break; + } + case word::WdInformation::wdNumberOfPagesInDocument: + { + result <<= SwVbaInformationHelper::handleWdNumberOfPagesInDocument( mxModel ); + break; + } + case word::WdInformation::wdVerticalPositionRelativeToPage: + { + result <<= SwVbaInformationHelper::handleWdVerticalPositionRelativeToPage( mxModel, mxTextViewCursor ); + break; + } + case word::WdInformation::wdWithInTable: + { + uno::Reference< beans::XPropertySet > xCursorProps( mxTextViewCursor, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextTable > xTextTable; + xCursorProps->getPropertyValue("TextTable") >>= xTextTable; + result <<= xTextTable.is(); + break; + } + case word::WdInformation::wdHeaderFooterType: + { + uno::Reference< word::XView > xView( new SwVbaView( this, mxContext, mxModel ) ); + sal_Int32 nView = xView->getSeekView(); + sal_Int32 nHeaderFooterType = 0; + switch( nView ) + { + case word::WdSeekView::wdSeekMainDocument: + { + nHeaderFooterType = -1; // not in a header or footer + break; + } + case word::WdSeekView::wdSeekEvenPagesHeader: + { + nHeaderFooterType = 0; // even page header + break; + } + case word::WdSeekView::wdSeekPrimaryHeader: + { + nHeaderFooterType = 1; // odd page header + break; + } + case word::WdSeekView::wdSeekEvenPagesFooter: + { + nHeaderFooterType = 2; // even page footer + break; + } + case word::WdSeekView::wdSeekPrimaryFooter: + { + nHeaderFooterType = 3; // odd page footer + break; + } + case word::WdSeekView::wdSeekFirstPageHeader: + case word::WdSeekView::wdSeekFirstPageFooter: + { + uno::Reference< beans::XPropertySet > xCursorProps( mxTextViewCursor, uno::UNO_QUERY_THROW ); + OUString aPageStyleName; + xCursorProps->getPropertyValue("PageStyleName") >>= aPageStyleName; + bool bFirstPage = false; + if ( aPageStyleName == "First Page" ) + bFirstPage = true; + if( nView == word::WdSeekView::wdSeekFirstPageHeader ) + { + if( bFirstPage ) + nHeaderFooterType = 4; + else + nHeaderFooterType = 1; + } + else + { + if( bFirstPage ) + nHeaderFooterType = 5; + else + nHeaderFooterType = 3; + } + break; + } + default: + { + nHeaderFooterType = -1; + } + } + result <<= nHeaderFooterType; + break; + } + default: + throw uno::RuntimeException("Not implemented" ); + } + return result; +} + +void SAL_CALL SwVbaSelection::InsertBreak( const uno::Any& _breakType ) +{ + getRange()->InsertBreak( _breakType ); +} + +uno::Any SAL_CALL +SwVbaSelection::Tables( const uno::Any& aIndex ) +{ + // Hacky implementation due to missing api ( and lack of knowledge ) + // we can only support a selection that is a single table + if ( !aIndex.hasValue() ) // currently we can't support multiple tables in a selection + throw uno::RuntimeException(); + + sal_Int32 nIndex = 0; + aIndex >>= nIndex; + + uno::Any aRet; + + if ( nIndex != 1 ) + throw uno::RuntimeException(); + + uno::Reference< beans::XPropertySet > xCursorProps( mxTextViewCursor, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextTable > xTextTable; + xCursorProps->getPropertyValue("TextTable") >>= xTextTable; + if( xTextTable.is() ) + { + uno::Reference< css::text::XTextDocument > xTextDoc( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< word::XTable > xVBATable = new SwVbaTable( mxParent, mxContext, xTextDoc, xTextTable ); + aRet <<= xVBATable; + return aRet; + } + + // if the current selection is a XTextTableCursor and the index is 1 then we can service this request, otherwise we just have to throw + uno::Reference< text::XTextTableCursor > xTextTableCursor( mxModel->getCurrentSelection(), uno::UNO_QUERY_THROW ); + SwXTextTableCursor* pTTCursor = dynamic_cast< SwXTextTableCursor* >( xTextTableCursor.get() ); + if ( pTTCursor ) + { + SwFrameFormat* pFormat = pTTCursor->GetFrameFormat(); + if ( pFormat ) + { + uno::Reference< text::XTextTable > xTable = SwXTextTables::GetObject(*pFormat); + uno::Reference< css::text::XTextDocument > xTextDoc( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< word::XTable > xVBATable = new SwVbaTable( mxParent, mxContext, xTextDoc, xTable ); + aRet <<= xVBATable; + } + } + return aRet; + +} + +uno::Any SAL_CALL +SwVbaSelection::Fields( const uno::Any& index ) +{ + uno::Reference< XCollection > xCol( new SwVbaFields( mxParent, mxContext, mxModel ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Reference< word::XHeaderFooter > SAL_CALL +SwVbaSelection::getHeaderFooter() +{ + if( HeaderFooterHelper::isHeaderFooter( mxModel ) ) + { + uno::Reference< beans::XPropertySet > xPageStyleProps( word::getCurrentPageStyle( mxModel ), uno::UNO_QUERY_THROW ); + sal_Int32 nIndex = word::WdHeaderFooterIndex::wdHeaderFooterPrimary; + bool isHeader = HeaderFooterHelper::isHeader( mxModel ); + if( HeaderFooterHelper::isEvenPagesHeader( mxModel ) || HeaderFooterHelper::isEvenPagesFooter( mxModel ) ) + nIndex = word::WdHeaderFooterIndex::wdHeaderFooterEvenPages; + else if( HeaderFooterHelper::isFirstPageHeader( mxModel ) || HeaderFooterHelper::isFirstPageFooter( mxModel ) ) + nIndex = word::WdHeaderFooterIndex::wdHeaderFooterFirstPage; + + return uno::Reference< word::XHeaderFooter >( new SwVbaHeaderFooter( this, mxContext, mxModel, xPageStyleProps, isHeader, nIndex ) ); + + } + return uno::Reference< word::XHeaderFooter >(); +} + +uno::Any SAL_CALL +SwVbaSelection::ShapeRange( ) +{ + uno::Reference< drawing::XShapes > xShapes( mxModel->getCurrentSelection(), uno::UNO_QUERY ); + if ( !xShapes.is() ) + { + uno::Reference< drawing::XShape > xShape( mxModel->getCurrentSelection(), uno::UNO_QUERY_THROW ); + xShapes.set( drawing::ShapeCollection::create(mxContext) ); + xShapes->add( xShape ); + } + + uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< drawing::XDrawPage > xDrawPage = xDrawPageSupplier->getDrawPage(); + uno::Reference< container::XIndexAccess > xShapesAccess( xShapes, uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< msforms::XShapeRange >( new ScVbaShapeRange( this, mxContext, xShapesAccess, xDrawPage, mxModel ) ) ); +} + +::sal_Int32 SAL_CALL SwVbaSelection::getStart() +{ + return getRange()->getStart(); +} + +void SAL_CALL SwVbaSelection::setStart( ::sal_Int32 _start ) +{ + getRange()->setStart( _start ); +} +::sal_Int32 SAL_CALL SwVbaSelection::getEnd() +{ + return getRange()->getEnd(); +} + +void SAL_CALL SwVbaSelection::setEnd( ::sal_Int32 _end ) +{ + getRange()->setEnd( _end ); +} + +void SAL_CALL SwVbaSelection::SelectRow() +{ + uno::Reference< word::XRows > xRows( Rows( uno::Any() ), uno::UNO_QUERY_THROW ); + xRows->Select(); +} + +void SAL_CALL SwVbaSelection::SelectColumn() +{ + uno::Reference< word::XColumns > xColumns( Columns( uno::Any() ), uno::UNO_QUERY_THROW ); + xColumns->Select(); +} + +uno::Any SAL_CALL SwVbaSelection::Rows( const uno::Any& index ) +{ + OUString sTLName; + OUString sBRName; + GetSelectedCellRange( sTLName, sBRName ); + + sal_Int32 nStartRow = 0; + sal_Int32 nEndRow = 0; + uno::Reference< text::XTextTable > xTextTable = GetXTextTable(); + SwVbaTableHelper aTableHelper( xTextTable ); + nStartRow = aTableHelper.getTabRowIndex( sTLName ); + if( !sBRName.isEmpty() ) + { + nEndRow = aTableHelper.getTabRowIndex( sBRName ); + } + else + { + nEndRow = nStartRow; + } + + uno::Reference< XCollection > xCol( new SwVbaRows( this, mxContext, xTextTable, xTextTable->getRows(), nStartRow, nEndRow ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL SwVbaSelection::Columns( const uno::Any& index ) +{ + OUString sTLName; + OUString sBRName; + GetSelectedCellRange( sTLName, sBRName ); + sal_Int32 nStartColumn = 0; + sal_Int32 nEndColumn = 0; + + uno::Reference< text::XTextTable > xTextTable = GetXTextTable(); + SwVbaTableHelper aTableHelper( xTextTable ); + nStartColumn = aTableHelper.getTabColIndex( sTLName ); + if( !sBRName.isEmpty() ) + { + nEndColumn = aTableHelper.getTabColIndex( sBRName ); + } + else + { + nEndColumn = nStartColumn; + } + + uno::Reference< XCollection > xCol( new SwVbaColumns( this, mxContext, xTextTable, xTextTable->getColumns(), nStartColumn, nEndColumn ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Reference< text::XTextTable > SwVbaSelection::GetXTextTable() const +{ + uno::Reference< beans::XPropertySet > xCursorProps( mxTextViewCursor, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextTable > xTextTable; + xCursorProps->getPropertyValue("TextTable") >>= xTextTable; + return xTextTable; +} + +bool SwVbaSelection::IsInTable() const +{ + uno::Reference< text::XTextTable > xTextTable = GetXTextTable(); + return xTextTable.is(); +} + +bool SwVbaSelection::HasSelection() +{ + uno::Reference< text::XTextRange > xStart = mxTextViewCursor->getStart(); + uno::Reference< text::XTextRange > xEnd = mxTextViewCursor->getEnd(); + uno::Reference< text::XTextRangeCompare > xTRC( mxTextViewCursor->getText(), uno::UNO_QUERY_THROW ); + return xTRC->compareRegionStarts( xStart, xEnd ) != 0 || xTRC->compareRegionEnds( xStart, xEnd ) != 0; +} + +void SwVbaSelection::GetSelectedCellRange( OUString& sTLName, OUString& sBRName ) +{ + uno::Reference< beans::XPropertySet > xCursorProps( mxTextViewCursor, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextTable > xTextTable; + xCursorProps->getPropertyValue("TextTable") >>= xTextTable; + if( !xTextTable.is() ) + throw uno::RuntimeException( ); + + uno::Reference< text::XTextTableCursor > xTextTableCursor( mxModel->getCurrentSelection(), uno::UNO_QUERY ); + if( xTextTableCursor.is() ) + { + const OUString sRange( xTextTableCursor->getRangeName() ); + if (!sRange.isEmpty()) + { + sal_Int32 nIdx{0}; + sTLName = sRange.getToken(0, ':', nIdx); + sBRName = sRange.getToken(0, ':', nIdx); + } + } + if( sTLName.isEmpty() ) + { + uno::Reference< table::XCell > xCell; + xCursorProps->getPropertyValue("Cell") >>= xCell; + if( !xCell.is() ) + { + throw uno::RuntimeException( ); + } + uno::Reference< beans::XPropertySet > xCellProps( xCell, uno::UNO_QUERY_THROW ); + xCellProps->getPropertyValue("CellName") >>= sTLName; + } +} + +uno::Any SAL_CALL SwVbaSelection::Cells( const uno::Any& index ) +{ + OUString sTLName; + OUString sBRName; + GetSelectedCellRange( sTLName, sBRName ); + sal_Int32 nLeft = 0; + sal_Int32 nTop = 0; + sal_Int32 nRight = 0; + sal_Int32 nBottom = 0; + + uno::Reference< text::XTextTable > xTextTable = GetXTextTable(); + SwVbaTableHelper aTableHelper( xTextTable ); + nLeft = aTableHelper.getTabColIndex( sTLName ); + nTop = aTableHelper.getTabRowIndex( sTLName ); + if( !sBRName.isEmpty() ) + { + nRight = aTableHelper.getTabColIndex( sBRName ); + nBottom = aTableHelper.getTabRowIndex( sBRName ); + } + else + { + nRight = nLeft; + nBottom = nTop; + } + + uno::Reference< XCollection > xCol( new SwVbaCells( this, mxContext, xTextTable, nLeft, nTop, nRight, nBottom ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +void SAL_CALL SwVbaSelection::Copy( ) +{ + dispatchRequests( mxModel,".uno:Copy" ); +} + +void SAL_CALL SwVbaSelection::CopyAsPicture( ) +{ + // seems not support in Writer + Copy(); +} + +void SAL_CALL SwVbaSelection::Paste( ) +{ + dispatchRequests( mxModel,".uno:Paste" ); +} + +void SAL_CALL SwVbaSelection::Collapse( const uno::Any& Direction ) +{ + if( word::gotoSelectedObjectAnchor( mxModel ) ) + return; + + sal_Int32 nDirection = word::WdCollapseDirection::wdCollapseStart; + if( Direction.hasValue() ) + Direction >>= nDirection; + + uno::Reference< text::XTextViewCursor > xTextViewCursor = word::getXTextViewCursor( mxModel ); + if( nDirection == word::WdCollapseDirection::wdCollapseStart ) + { + // it is inaccurate if current selection is multiple cells, so it needs to go to start + uno::Reference< text::XTextRange > xTextRange = mxTextViewCursor->getStart(); + xTextViewCursor->gotoRange( xTextRange, false ); + xTextViewCursor->collapseToStart(); + } + else if( nDirection == word::WdCollapseDirection::wdCollapseEnd ) + { + uno::Reference< text::XTextRange > xTextRange = mxTextViewCursor->getEnd(); + xTextViewCursor->gotoRange( xTextRange, false ); + xTextViewCursor->collapseToEnd(); + } + else + { + throw uno::RuntimeException(); + } +} + +void SAL_CALL SwVbaSelection::WholeStory( ) +{ + uno::Reference< text::XText > xText = word::getCurrentXText( mxModel ); + // FIXME: for i#7747,if the first line is a table, it fails to select all the contents in the story. + // Temporary solution, insert an empty line before the table so that it could select all the contents. + uno::Reference< container::XEnumerationAccess > xParaAccess( xText, uno::UNO_QUERY_THROW ); + uno::Reference< container::XEnumeration> xParaEnum = xParaAccess->createEnumeration(); + if( xParaEnum->hasMoreElements() ) + { + uno::Reference< text::XTextTable > xTextTable( xParaEnum->nextElement(), uno::UNO_QUERY ); + if( xTextTable.is() ) + { + // insert an empty line + uno::Reference< text::XTextRange > xFirstCellRange = word::getFirstObjectPosition( xText ); + mxTextViewCursor->gotoRange( xFirstCellRange, false ); + dispatchRequests( mxModel,".uno:InsertPara" ); + } + } + uno::Reference< text::XTextRange > xStart = xText->getStart(); + uno::Reference< text::XTextRange > xEnd = xText->getEnd(); + mxTextViewCursor->gotoRange( xStart, false ); + mxTextViewCursor->gotoRange( xEnd, true ); +} + +sal_Bool SAL_CALL SwVbaSelection::InRange( const uno::Reference< ::ooo::vba::word::XRange >& Range ) +{ + return getRange()->InRange( Range ); +} + +void SAL_CALL SwVbaSelection::SplitTable() +{ + if( !IsInTable() ) + throw uno::RuntimeException(); + + SwDocShell* pDocShell = word::getDocShell( mxModel ); + if( pDocShell ) + { + if (SwFEShell* pFEShell = pDocShell->GetFEShell()) + pFEShell->SplitTable( SplitTable_HeadlineOption::ContentCopy ); + } +} + +uno::Any SAL_CALL +SwVbaSelection::Paragraphs( const uno::Any& aIndex ) +{ + // Hacky implementation due to missing api ( and lack of knowledge ) + // we can only support a selection that is a single paragraph + if ( !aIndex.hasValue() ) // currently we can't support multiple paragraphs in a selection + throw uno::RuntimeException(); + + sal_Int32 nIndex = 0; + aIndex >>= nIndex; + + uno::Any aRet; + + if ( nIndex != 1 ) + throw uno::RuntimeException(); + + uno::Reference< text::XTextRange > xTextRange = mxTextViewCursor->getStart(); + uno::Reference< text::XText > xText = xTextRange->getText(); + uno::Reference< text::XParagraphCursor > xParaCursor( xText->createTextCursor(), uno::UNO_QUERY_THROW ); + xParaCursor->gotoStartOfParagraph( false ); + xParaCursor->gotoStartOfParagraph( true ); + + uno::Reference< text::XTextDocument > xTextDoc( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextRange > xParaRange( xParaCursor, uno::UNO_QUERY_THROW ); + uno::Reference< word::XParagraph > xParagraph = new SwVbaParagraph( mxParent, mxContext, xTextDoc, xParaRange ); + + aRet <<= xParagraph; + return aRet; +} + +OUString +SwVbaSelection::getServiceImplName() +{ + return "SwVbaSelection"; +} + +uno::Sequence< OUString > +SwVbaSelection::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Selection" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaselection.hxx b/sw/source/ui/vba/vbaselection.hxx new file mode 100644 index 0000000000..0dba75b729 --- /dev/null +++ b/sw/source/ui/vba/vbaselection.hxx @@ -0,0 +1,120 @@ +/* -*- 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_VBA_VBASELECTION_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBASELECTION_HXX + +#include <ooo/vba/word/XSelection.hpp> +#include <ooo/vba/word/XRange.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextViewCursor.hpp> +#include <com/sun/star/text/XTextTable.hpp> +#include <ooo/vba/word/XParagraphFormat.hpp> +#include <ooo/vba/word/XFind.hpp> +#include <ooo/vba/word/XFont.hpp> +#include <ooo/vba/word/XHeaderFooter.hpp> +#include "wordvbahelper.hxx" + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XSelection > SwVbaSelection_BASE; + +class SwVbaSelection : public SwVbaSelection_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::text::XTextViewCursor > mxTextViewCursor; + +private: + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + void Move( const css::uno::Any& _unit, const css::uno::Any& _count, const css::uno::Any& _extend, ooo::vba::word::E_DIRECTION eDirection ); + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + void NextCell( sal_Int32 nCount, ooo::vba::word::E_DIRECTION eDirection ); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::text::XTextRange > GetSelectedRange(); + /// @throws css::uno::RuntimeException + void GetSelectedCellRange( OUString& sTLName, OUString& sBRName ); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::text::XTextTable > GetXTextTable() const; + /// @throws css::uno::RuntimeException + bool IsInTable() const; + /// @throws css::uno::RuntimeException + bool HasSelection(); + +public: + /// @throws css::uno::RuntimeException + SwVbaSelection( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::frame::XModel > xModel ); + virtual ~SwVbaSelection() override; + + // Attribute + virtual OUString SAL_CALL getText() override; + virtual void SAL_CALL setText( const OUString& rText ) override; + virtual css::uno::Reference< ooo::vba::word::XRange > SAL_CALL getRange() override; + virtual void SAL_CALL HomeKey( const css::uno::Any& _unit, const css::uno::Any& _extend ) override; + virtual void SAL_CALL EndKey( const css::uno::Any& _unit, const css::uno::Any& _extend ) override; + virtual void SAL_CALL TypeText( const OUString& rText ) override; + virtual void SAL_CALL Delete( const css::uno::Any& _unit, const css::uno::Any& _count ) override; + virtual void SAL_CALL MoveRight( const css::uno::Any& _unit, const css::uno::Any& _count, const css::uno::Any& _extend ) override; + virtual void SAL_CALL MoveLeft( const css::uno::Any& _unit, const css::uno::Any& _count, const css::uno::Any& _extend ) override; + virtual void SAL_CALL MoveDown( const css::uno::Any& _unit, const css::uno::Any& _count, const css::uno::Any& _extend ) override; + virtual void SAL_CALL MoveUp( const css::uno::Any& _unit, const css::uno::Any& _count, const css::uno::Any& _extend ) override; + virtual void SAL_CALL TypeParagraph() override; + virtual void SAL_CALL InsertParagraph() override; + virtual void SAL_CALL InsertParagraphBefore() override; + virtual void SAL_CALL InsertParagraphAfter() override; + virtual css::uno::Reference< ooo::vba::word::XParagraphFormat > SAL_CALL getParagraphFormat() override; + virtual void SAL_CALL setParagraphFormat( const css::uno::Reference< ooo::vba::word::XParagraphFormat >& rParagraphFormat ) override; + virtual css::uno::Reference< ooo::vba::word::XFind > SAL_CALL getFind() override; + virtual css::uno::Any SAL_CALL getStyle() override; + virtual void SAL_CALL setStyle( const css::uno::Any& _xStyle ) override; + virtual css::uno::Reference< ooo::vba::word::XFont > SAL_CALL getFont() override; + virtual void SAL_CALL TypeBackspace() override; + virtual css::uno::Reference< ooo::vba::word::XRange > SAL_CALL GoTo( const css::uno::Any& _what, const css::uno::Any& _which, const css::uno::Any& _count, const css::uno::Any& _name ) override; + virtual ::sal_Int32 SAL_CALL getLanguageID( ) override; + virtual void SAL_CALL setLanguageID( ::sal_Int32 _languageid ) override; + virtual css::uno::Any SAL_CALL Information( sal_Int32 _type ) override; + virtual void SAL_CALL InsertBreak( const css::uno::Any& _breakType ) override; + virtual css::uno::Any SAL_CALL Tables( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Fields( const css::uno::Any& aIndex ) override; + virtual css::uno::Reference< ooo::vba::word::XHeaderFooter > SAL_CALL getHeaderFooter() override; + virtual css::uno::Any SAL_CALL ShapeRange( ) override; + virtual ::sal_Int32 SAL_CALL getStart() override; + virtual void SAL_CALL setStart( ::sal_Int32 _start ) override; + virtual ::sal_Int32 SAL_CALL getEnd() override; + virtual void SAL_CALL setEnd( ::sal_Int32 _end ) override; + virtual void SAL_CALL SelectRow() override; + virtual void SAL_CALL SelectColumn() override; + virtual css::uno::Any SAL_CALL Rows( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Columns( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Cells( const css::uno::Any& aIndex ) override; + virtual void SAL_CALL Copy( ) override; + virtual void SAL_CALL CopyAsPicture( ) override; + virtual void SAL_CALL Paste( ) override; + virtual void SAL_CALL Collapse( const css::uno::Any& Direction ) override; + virtual void SAL_CALL WholeStory( ) override; + virtual sal_Bool SAL_CALL InRange( const css::uno::Reference< ::ooo::vba::word::XRange >& Range ) override; + virtual void SAL_CALL SplitTable() override; + virtual css::uno::Any SAL_CALL Paragraphs( const css::uno::Any& aIndex ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBASELECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbastyle.cxx b/sw/source/ui/vba/vbastyle.cxx new file mode 100644 index 0000000000..771e03ae33 --- /dev/null +++ b/sw/source/ui/vba/vbastyle.cxx @@ -0,0 +1,228 @@ +/* -*- 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 "vbastyle.hxx" +#include <ooo/vba/word/WdStyleType.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <i18nlangtag/languagetag.hxx> +#include <utility> +#include "vbafont.hxx" +#include "vbapalette.hxx" +#include "vbaparagraphformat.hxx" +#include "vbastyles.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaStyle::SwVbaStyle( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, uno::Reference< frame::XModel> xModel, const uno::Reference< beans::XPropertySet >& _xPropertySet ) : SwVbaStyle_BASE( xParent, xContext ) , mxModel(std::move( xModel )), mxStyleProps( _xPropertySet ) +{ + mxStyle.set( _xPropertySet, uno::UNO_QUERY_THROW ); +} + +void SAL_CALL +SwVbaStyle::setName( const OUString& Name ) +{ + mxStyle->setName(Name); +} + +OUString SAL_CALL +SwVbaStyle::getName() +{ + return mxStyle->getName(); +} + +LanguageType SwVbaStyle::getLanguageID( const uno::Reference< beans::XPropertySet >& xTCProps ) +{ + lang::Locale aLocale; + xTCProps->getPropertyValue("CharLocale") >>= aLocale; + return LanguageTag::convertToLanguageType( aLocale, false); +} + +void SwVbaStyle::setLanguageID( const uno::Reference< beans::XPropertySet >& xTCProps, LanguageType _languageid ) +{ + lang::Locale aLocale = LanguageTag( _languageid ).getLocale(); + xTCProps->setPropertyValue("CharLocale", uno::Any( aLocale ) ) ; +} + +::sal_Int32 SAL_CALL SwVbaStyle::getLanguageID() +{ + return static_cast<sal_uInt16>(getLanguageID( mxStyleProps )); +} + +void SAL_CALL SwVbaStyle::setLanguageID( ::sal_Int32 _languageid ) +{ + setLanguageID( mxStyleProps, LanguageType(_languageid) ); +} + +::sal_Int32 SAL_CALL SwVbaStyle::getType() +{ + sal_Int32 nType = word::WdStyleType::wdStyleTypeParagraph; + uno::Reference< lang::XServiceInfo > xServiceInfo( mxStyle, uno::UNO_QUERY_THROW ); + if( xServiceInfo->supportsService("com.sun.star.style.ParagraphStyle") ) + nType = word::WdStyleType::wdStyleTypeParagraph; + else if( xServiceInfo->supportsService("com.sun.star.style.CharacterStyle") ) + nType = word::WdStyleType::wdStyleTypeCharacter; + else + nType = word::WdStyleType::wdStyleTypeList; + return nType; +} + +uno::Reference< word::XFont > SAL_CALL +SwVbaStyle::getFont() +{ + VbaPalette aColors; + return new SwVbaFont( mxParent, mxContext, aColors.getPalette(), mxStyleProps ); +} + +void SwVbaStyle::setStyle( const uno::Reference< beans::XPropertySet >& xParaProps, const uno::Any& rStyle ) +{ + OUString sStyle; + uno::Reference< word::XStyle > xStyle; + if( rStyle >>= xStyle ) + { + sStyle = xStyle->getName(); + } + else + { + rStyle >>= sStyle; + } + + if( !sStyle.isEmpty() ) + { + xParaProps->setPropertyValue("ParaStyleName", uno::Any( sStyle ) ); + return; + } + + throw uno::RuntimeException(); +} + +OUString SAL_CALL SwVbaStyle::getNameLocal() +{ + OUString sNameLocal; + mxStyleProps->getPropertyValue("DisplayName") >>= sNameLocal; + return sNameLocal; +} + +void SAL_CALL SwVbaStyle::setNameLocal( const OUString& _namelocal ) +{ + mxStyleProps->setPropertyValue("DisplayName", uno::Any( _namelocal ) ); +} + +uno::Reference< word::XParagraphFormat > SAL_CALL SwVbaStyle::getParagraphFormat() +{ + if( word::WdStyleType::wdStyleTypeParagraph != getType() ) + { + throw uno::RuntimeException(); + } + + uno::Reference< text::XTextDocument > xTextDocument( mxModel, uno::UNO_QUERY_THROW ); + return uno::Reference< word::XParagraphFormat >( new SwVbaParagraphFormat( this, mxContext, mxStyleProps ) ); +} + +sal_Bool SAL_CALL SwVbaStyle::getAutomaticallyUpdate() +{ + bool isAutoUpdate = false; + mxStyleProps->getPropertyValue("IsAutoUpdate") >>= isAutoUpdate; + return isAutoUpdate; +} + +void SAL_CALL SwVbaStyle::setAutomaticallyUpdate( sal_Bool _automaticallyupdate ) +{ + mxStyleProps->setPropertyValue("IsAutoUpdate", uno::Any( _automaticallyupdate ) ); +} + +uno::Any SAL_CALL SwVbaStyle::getBaseStyle() +{ + // ParentStyle + OUString sBaseStyle; + mxStyleProps->getPropertyValue("ParentStyle") >>= sBaseStyle; + if( sBaseStyle.isEmpty() ) + { + throw uno::RuntimeException(); + } + + uno::Reference< XCollection > xCol( new SwVbaStyles( this, mxContext, mxModel ) ); + return xCol->Item( uno::Any( sBaseStyle ), uno::Any() ); +} + +void SAL_CALL SwVbaStyle::setBaseStyle( const uno::Any& _basestyle ) +{ + uno::Reference< word::XStyle > xStyle; + _basestyle >>= xStyle; + if( !xStyle.is() ) + { + throw uno::RuntimeException(); + } + + OUString sBaseStyle = xStyle->getName(); + mxStyleProps->setPropertyValue("ParentStyle", uno::Any( sBaseStyle ) ); +} + +uno::Any SAL_CALL SwVbaStyle::getNextParagraphStyle() +{ + //FollowStyle + OUString sFollowStyle; + mxStyleProps->getPropertyValue("FollowStyle") >>= sFollowStyle; + if( sFollowStyle.isEmpty() ) + { + throw uno::RuntimeException(); + } + + uno::Reference< XCollection > xCol( new SwVbaStyles( this, mxContext, mxModel ) ); + return xCol->Item( uno::Any( sFollowStyle ), uno::Any() ); +} + +void SAL_CALL SwVbaStyle::setNextParagraphStyle( const uno::Any& _nextparagraphstyle ) +{ + uno::Reference< word::XStyle > xStyle; + _nextparagraphstyle >>= xStyle; + if( !xStyle.is() ) + { + throw uno::RuntimeException(); + } + + OUString sFollowStyle = xStyle->getName(); + mxStyleProps->setPropertyValue("FollowStyle", uno::Any( sFollowStyle ) ); +} + +::sal_Int32 SAL_CALL SwVbaStyle::getListLevelNumber() +{ + sal_Int16 nNumberingLevel = 0; + mxStyleProps->getPropertyValue("NumberingLevel") >>= nNumberingLevel; + return nNumberingLevel; +} + +OUString +SwVbaStyle::getServiceImplName() +{ + return "SwVbaStyle"; +} + +uno::Sequence< OUString > +SwVbaStyle::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.XStyle" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbastyle.hxx b/sw/source/ui/vba/vbastyle.hxx new file mode 100644 index 0000000000..dc7ae051f1 --- /dev/null +++ b/sw/source/ui/vba/vbastyle.hxx @@ -0,0 +1,78 @@ +/* -*- 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_VBA_VBASTYLE_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBASTYLE_HXX + +#include <ooo/vba/word/XStyle.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <i18nlangtag/lang.h> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <ooo/vba/word/XFont.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XStyle > SwVbaStyle_BASE; + +class SwVbaStyle : public SwVbaStyle_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::beans::XPropertySet > mxStyleProps; + css::uno::Reference< css::style::XStyle > mxStyle; +public: + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + SwVbaStyle( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, css::uno::Reference< css::frame::XModel > xModel, const css::uno::Reference< css::beans::XPropertySet >& _xPropertySet ); + + /// @throws css::uno::RuntimeException + static void setStyle( const css::uno::Reference< css::beans::XPropertySet >& xParaProps, const css::uno::Any& xStyle ); + /// @throws css::uno::RuntimeException + static LanguageType getLanguageID( const css::uno::Reference< css::beans::XPropertySet >& xTCProps ); + /// @throws css::uno::RuntimeException + static void setLanguageID( const css::uno::Reference< css::beans::XPropertySet >& xTCProps, LanguageType _languageid ); + + // Attributes + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName( const OUString& Name ) override; + virtual ::sal_Int32 SAL_CALL getLanguageID( ) override; + virtual void SAL_CALL setLanguageID( ::sal_Int32 _languageid ) override; + virtual ::sal_Int32 SAL_CALL getType() override; + virtual css::uno::Reference< ooo::vba::word::XFont > SAL_CALL getFont() override; + virtual OUString SAL_CALL getNameLocal() override; + virtual void SAL_CALL setNameLocal( const OUString& _namelocal ) override; + virtual css::uno::Reference< ::ooo::vba::word::XParagraphFormat > SAL_CALL getParagraphFormat() override; + virtual sal_Bool SAL_CALL getAutomaticallyUpdate() override; + virtual void SAL_CALL setAutomaticallyUpdate( sal_Bool _automaticallyupdate ) override; + virtual css::uno::Any SAL_CALL getBaseStyle() override; + virtual void SAL_CALL setBaseStyle( const css::uno::Any& _basestyle ) override; + virtual css::uno::Any SAL_CALL getNextParagraphStyle() override; + virtual void SAL_CALL setNextParagraphStyle( const css::uno::Any& _nextparagraphstyle ) override; + virtual ::sal_Int32 SAL_CALL getListLevelNumber() override; + + //XDefaultProperty + virtual OUString SAL_CALL getDefaultPropertyName( ) override { return "Name"; } + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif //SW_VBA_AXIS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbastyles.cxx b/sw/source/ui/vba/vbastyles.cxx new file mode 100644 index 0000000000..5e9ce270ff --- /dev/null +++ b/sw/source/ui/vba/vbastyles.cxx @@ -0,0 +1,378 @@ +/* -*- 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 "vbastyles.hxx" +#include "vbastyle.hxx" +#include <basic/sberrors.hxx> +#include <cppuhelper/implbase.hxx> +#include <sal/log.hxx> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <ooo/vba/word/WdBuiltinStyle.hpp> +#include <ooo/vba/word/WdStyleType.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +struct BuiltinStyleTable +{ + sal_Int32 wdBuiltinStyle; + const char* pOOoStyleName; + sal_Int32 wdStyleType; +}; + +} + +const BuiltinStyleTable aBuiltinStyleTable[] = +{ + { word::WdBuiltinStyle::wdStyleBlockQuotation, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleBodyText, "Text body", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleBodyText2, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleBodyText3, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleBodyTextFirstIndent, "First line indent", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleBodyTextFirstIndent2, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleBodyTextIndent, "Text body indent", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleBodyTextIndent2, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleBodyTextIndent3, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleCaption, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleClosing, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleCommentReference, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleCommentText, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleDate, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleDefaultParagraphFont, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleEmphasis, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleEndnoteReference, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleEndnoteText, "Endnote", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleEnvelopeAddress, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleEnvelopeReturn, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleFooter, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleFootnoteReference, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleFootnoteText, "Footnote", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHeader, "Header", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHeading1, "Heading 1", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHeading2, "Heading 2", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHeading3, "Heading 3", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHeading4, "Heading 4", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHeading5, "Heading 5", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHeading6, "Heading 6", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHeading7, "Heading 7", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHeading8, "Heading 8", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHeading9, "Heading 9", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHtmlAcronym, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHtmlAddress, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHtmlCite, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHtmlCode, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHtmlDfn, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHtmlKbd, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHtmlNormal, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHtmlPre, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHtmlSamp, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHtmlTt, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHtmlVar, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHyperlink, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleHyperlinkFollowed, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleIndex1, "Index 1", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleIndex2, "Index 2", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleIndex3, "Index 3", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleIndex4, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleIndex5, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleIndex6, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleIndex7, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleIndex8, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleIndex9, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleIndexHeading, "Index Heading", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleLineNumber, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleList, "List", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleList2, "List 2", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleList3, "List 3", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleList4, "List 4", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleList5, "List 5", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleListBullet, "List 1", word::WdStyleType::wdStyleTypeList }, + { word::WdBuiltinStyle::wdStyleListBullet2, "List 2", word::WdStyleType::wdStyleTypeList }, + { word::WdBuiltinStyle::wdStyleListBullet3, "List 3", word::WdStyleType::wdStyleTypeList }, + { word::WdBuiltinStyle::wdStyleListBullet4, "List 4", word::WdStyleType::wdStyleTypeList }, + { word::WdBuiltinStyle::wdStyleListBullet5, "List 5", word::WdStyleType::wdStyleTypeList }, + { word::WdBuiltinStyle::wdStyleListContinue, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleListContinue2, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleListContinue3, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleListContinue4, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleListContinue5, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleListNumber, "Numbering 123", word::WdStyleType::wdStyleTypeList }, + { word::WdBuiltinStyle::wdStyleListNumber2, "Numbering ABC", word::WdStyleType::wdStyleTypeList }, + { word::WdBuiltinStyle::wdStyleListNumber3, "Numbering abc", word::WdStyleType::wdStyleTypeList }, + { word::WdBuiltinStyle::wdStyleListNumber4, "Numbering IVX", word::WdStyleType::wdStyleTypeList }, + { word::WdBuiltinStyle::wdStyleListNumber5, "Numbering ivx", word::WdStyleType::wdStyleTypeList }, + { word::WdBuiltinStyle::wdStyleMacroText, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleMessageHeader, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleNavPane, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleNormal, "Default", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleNormalIndent, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleNormalTable, "Table", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleNoteHeading, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStylePageNumber, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStylePlainText, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleSalutation, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleSignature, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleStrong, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleSubtitle, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTableOfAuthorities, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTableOfFigures, "", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTitle, "Title", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTOAHeading, "Contents Heading", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTOC1, "Contents 1", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTOC2, "Contents 2", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTOC3, "Contents 3", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTOC4, "Contents 4", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTOC5, "Contents 5", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTOC6, "Contents 6", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTOC7, "Contents 7", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTOC8, "Contents 8", word::WdStyleType::wdStyleTypeParagraph }, + { word::WdBuiltinStyle::wdStyleTOC9, "Contents 9", word::WdStyleType::wdStyleTypeParagraph }, + { 0, nullptr, 0 } +}; + +namespace { + +struct MSOStyleNameTable +{ + const char* pMSOStyleName; + const char* pOOoStyleName; +}; + +} + +const MSOStyleNameTable aMSOStyleNameTable[] = +{ + { "Normal", "Default" }, + { nullptr, nullptr } +}; + +namespace { + +class StyleCollectionHelper : public ::cppu::WeakImplHelper< container::XNameAccess, + container::XIndexAccess, + container::XEnumerationAccess > +{ +private: + uno::Reference< container::XNameAccess > mxParaStyles; + uno::Any m_cachePos; +public: + explicit StyleCollectionHelper( const uno::Reference< frame::XModel >& _xModel ) + { + // we only concern about the Paragraph styles + uno::Reference< style::XStyleFamiliesSupplier > xStyleSupplier( _xModel, uno::UNO_QUERY_THROW); + uno::Reference< container::XNameAccess > xStyleFamilies = xStyleSupplier->getStyleFamilies(); + mxParaStyles.set( xStyleFamilies->getByName("ParagraphStyles"), uno::UNO_QUERY_THROW ); + } + // XElementAccess + virtual uno::Type SAL_CALL getElementType( ) override { return cppu::UnoType<style::XStyle>::get(); } + virtual sal_Bool SAL_CALL hasElements( ) override { return getCount() > 0; } + // XNameAccess + virtual uno::Any SAL_CALL getByName( const OUString& aName ) override + { + if ( !hasByName(aName) ) + throw container::NoSuchElementException(); + return m_cachePos; + } + virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override + { + return mxParaStyles->getElementNames(); + } + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { + // search in the MSOStyleName table first + for( const MSOStyleNameTable* pTable = aMSOStyleNameTable; pTable->pMSOStyleName != nullptr; pTable++ ) + { + if( aName.equalsIgnoreAsciiCaseAscii( pTable->pMSOStyleName ) ) + { + //Found it + OUString sStyleName = OUString::createFromAscii( pTable->pOOoStyleName ); + if( mxParaStyles->hasByName( sStyleName ) ) + { + m_cachePos = mxParaStyles->getByName( sStyleName ); + return true; + } + return false; + } + } + + if( mxParaStyles->hasByName( aName ) ) + { + m_cachePos = mxParaStyles->getByName( aName ); + return true; + } + else + { + const uno::Sequence< OUString > sElementNames = mxParaStyles->getElementNames(); + auto pStyleName = std::find_if(sElementNames.begin(), sElementNames.end(), + [&aName](const OUString& rStyleName) { return rStyleName.equalsIgnoreAsciiCase( aName ); }); + if (pStyleName != sElementNames.end()) + { + m_cachePos = mxParaStyles->getByName( *pStyleName ); + return true; + } + } + return false; + } + + // XIndexAccess + virtual ::sal_Int32 SAL_CALL getCount( ) override + { + uno::Reference< container::XIndexAccess > xIndexAccess( mxParaStyles, uno::UNO_QUERY_THROW ); + return xIndexAccess->getCount(); + } + virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override + { + if ( Index < 0 || Index >= getCount() ) + throw lang::IndexOutOfBoundsException(); + + uno::Reference< container::XIndexAccess > xIndexAccess( mxParaStyles, uno::UNO_QUERY_THROW ); + return xIndexAccess->getByIndex( Index ); + } + // XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + throw uno::RuntimeException("Not implemented" ); + } +}; + +class StylesEnumWrapper : public EnumerationHelper_BASE +{ + SwVbaStyles* m_pStyles; + sal_Int32 m_nIndex; +public: + explicit StylesEnumWrapper( SwVbaStyles* _pStyles ) : m_pStyles( _pStyles ), m_nIndex( 1 ) {} + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( m_nIndex <= m_pStyles->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( m_nIndex <= m_pStyles->getCount() ) + return m_pStyles->Item( uno::Any( m_nIndex++ ), uno::Any() ); + throw container::NoSuchElementException(); + } +}; + +} + +SwVbaStyles::SwVbaStyles( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext > & xContext, const uno::Reference< frame::XModel >& xModel ) + : SwVbaStyles_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( new StyleCollectionHelper( xModel ) ) ), mxModel( xModel ) +{ + mxMSF.set( mxModel, uno::UNO_QUERY_THROW ); +} + +uno::Any +SwVbaStyles::createCollectionObject(const uno::Any& aObject) +{ + uno::Reference< beans::XPropertySet > xStyleProp( aObject, uno::UNO_QUERY_THROW ); + return uno::Any( uno::Reference< word::XStyle >( new SwVbaStyle( this, mxContext, mxModel, xStyleProp ) ) ); +} + +uno::Type SAL_CALL +SwVbaStyles::getElementType() +{ + return cppu::UnoType<word::XStyle>::get(); +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwVbaStyles::createEnumeration() +{ + return new StylesEnumWrapper( this ); +} + +uno::Any SAL_CALL +SwVbaStyles::Item( const uno::Any& Index1, const uno::Any& Index2 ) +{ + //handle WdBuiltinStyle + sal_Int32 nIndex = 0; + if( ( Index1 >>= nIndex ) && ( nIndex < 0 ) ) + { + for( const BuiltinStyleTable* pTable = aBuiltinStyleTable; pTable != nullptr; pTable++ ) + { + if( nIndex == pTable->wdBuiltinStyle ) + { + OUString aStyleName = OUString::createFromAscii( pTable->pOOoStyleName ); + if( !aStyleName.isEmpty() ) + { + OUString aStyleType; + switch( pTable->wdStyleType ) + { + case word::WdStyleType::wdStyleTypeParagraph: + case word::WdStyleType::wdStyleTypeTable: + { + aStyleType = "ParagraphStyles"; + break; + } + case word::WdStyleType::wdStyleTypeCharacter: + { + aStyleType = "CharacterStyles"; + break; + } + case word::WdStyleType::wdStyleTypeList: + { + // should use Paragraph style and set the property "NumberingStyleName" + aStyleType = "ParagraphStyles"; + break; + } + default: + DebugHelper::basicexception( ERRCODE_BASIC_INTERNAL_ERROR, {} ); + } + uno::Reference< style::XStyleFamiliesSupplier > xStyleSupplier( mxModel, uno::UNO_QUERY_THROW); + uno::Reference< container::XNameAccess > xStylesAccess( xStyleSupplier->getStyleFamilies()->getByName( aStyleType ), uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xStyleProps( xStylesAccess->getByName( aStyleName ), uno::UNO_QUERY_THROW ); + // set the property "NumberingStyleName" if it is a listbullet + if( pTable->wdStyleType == word::WdStyleType::wdStyleTypeList ) + { + xStyleProps->setPropertyValue("NumberingStyleName", uno::Any( aStyleName ) ); + } + return uno::Any( uno::Reference< word::XStyle >( new SwVbaStyle( this, mxContext, mxModel, xStyleProps ) ) ); + } + else + { + SAL_WARN("sw.vba", "the builtin style type is not implemented"); + throw uno::RuntimeException("Not implemented" ); + } + } + } + } + return SwVbaStyles_BASE::Item( Index1, Index2 ); +} + +OUString +SwVbaStyles::getServiceImplName() +{ + return "SwVbaStyles"; +} + +uno::Sequence< OUString > +SwVbaStyles::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.XStyles" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbastyles.hxx b/sw/source/ui/vba/vbastyles.hxx new file mode 100644 index 0000000000..390225cd08 --- /dev/null +++ b/sw/source/ui/vba/vbastyles.hxx @@ -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 . + */ +#ifndef INCLUDED_SW_SOURCE_UI_VBA_VBASTYLES_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBASTYLES_HXX + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <ooo/vba/word/XStyles.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +typedef CollTestImplHelper< ooo::vba::word::XStyles > SwVbaStyles_BASE; +class SwVbaStyles: public SwVbaStyles_BASE +{ + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::lang::XMultiServiceFactory > mxMSF; +public: + /// @throws css::script::BasicErrorException + /// @throws css::uno::RuntimeException + SwVbaStyles( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xModel ); + + virtual css::uno::Any SAL_CALL Item(const css::uno::Any& Index1, const css::uno::Any& Index2) override; + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + virtual css::uno::Any createCollectionObject(const css::uno::Any&) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbasystem.cxx b/sw/source/ui/vba/vbasystem.cxx new file mode 100644 index 0000000000..e09c89554e --- /dev/null +++ b/sw/source/ui/vba/vbasystem.cxx @@ -0,0 +1,275 @@ +/* -*- 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 "vbasystem.hxx" + +#include <ooo/vba/word/WdCursorType.hpp> +#include <tools/config.hxx> +#include <osl/file.hxx> +#include <tools/urlobj.hxx> +#include <o3tl/char16_t2wchar_t.hxx> + +#ifdef _WIN32 +#include <cstddef> +#include <string_view> +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#endif + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +PrivateProfileStringListener::~PrivateProfileStringListener() +{ +} + +void PrivateProfileStringListener::Initialize( const OUString& rFileName, const OString& rGroupName, const OString& rKey ) +{ + maFileName = rFileName; + maGroupName = rGroupName; + maKey = rKey; +} +#ifdef _WIN32 +static void lcl_getRegKeyInfo( std::string_view sKeyInfo, HKEY& hBaseKey, OString& sSubKey ) +{ + std::size_t nBaseKeyIndex = sKeyInfo.find('\\'); + if( nBaseKeyIndex != std::string_view::npos ) + { + std::string_view sBaseKey = sKeyInfo.substr( 0, nBaseKeyIndex ); + sSubKey = OString(sKeyInfo.substr( nBaseKeyIndex + 1 )); + if( sBaseKey == "HKEY_CURRENT_USER" ) + { + hBaseKey = HKEY_CURRENT_USER; + } + else if( sBaseKey == "HKEY_LOCAL_MACHINE" ) + { + hBaseKey = HKEY_LOCAL_MACHINE; + } + else if( sBaseKey == "HKEY_CLASSES_ROOT" ) + { + hBaseKey = HKEY_CLASSES_ROOT; + } + else if( sBaseKey == "HKEY_USERS" ) + { + hBaseKey = HKEY_USERS; + } + else if( sBaseKey == "HKEY_CURRENT_CONFIG" ) + { + hBaseKey = HKEY_CURRENT_CONFIG; + } + } +} +#endif + +uno::Any PrivateProfileStringListener::getValueEvent() +{ + // get the private profile string + OUString sValue; + if(maFileName.isEmpty()) + { + // get key/value from Windows registry +#ifdef _WIN32 + HKEY hBaseKey = nullptr; + OString sSubKey; + lcl_getRegKeyInfo( maGroupName, hBaseKey, sSubKey ); + if( hBaseKey != nullptr ) + { + HKEY hKey = nullptr; + LPCSTR lpSubKey = sSubKey.getStr(); + // We use RegOpenKeyExA here for convenience, because we already have subkey name as 8-bit string + LONG lResult = RegOpenKeyExA( hBaseKey, lpSubKey, 0, KEY_QUERY_VALUE, &hKey ); + if( ERROR_SUCCESS == lResult ) + { + OUString sUValName = OStringToOUString(maKey, RTL_TEXTENCODING_DONTKNOW); + LPCWSTR lpValueName = o3tl::toW(sUValName.getStr()); + WCHAR szBuffer[1024]; + DWORD cbData = sizeof(szBuffer); + lResult = RegQueryValueExW( hKey, lpValueName, nullptr, nullptr, reinterpret_cast<LPBYTE>(szBuffer), &cbData ); + RegCloseKey( hKey ); + // https://msdn.microsoft.com/en-us/ms724911 mentions that + // "the string may not have been stored with the proper terminating null characters" + szBuffer[std::min(size_t(cbData / sizeof(szBuffer[0])), SAL_N_ELEMENTS(szBuffer)-1)] = 0; + sValue = o3tl::toU(szBuffer); + } + } +#else + throw uno::RuntimeException("Only support on Windows" ); +#endif + } + + // get key/value from a file + Config aCfg( maFileName ); + aCfg.SetGroup( maGroupName ); + sValue = OStringToOUString(aCfg.ReadKey(maKey), RTL_TEXTENCODING_DONTKNOW); + + + return uno::Any( sValue ); +} + +void PrivateProfileStringListener::setValueEvent( const css::uno::Any& value ) +{ + // set the private profile string + OUString aValue; + value >>= aValue; + if(maFileName.isEmpty()) + { + //set value into Windows registry +#ifdef _WIN32 + HKEY hBaseKey = nullptr; + OString sSubKey; + lcl_getRegKeyInfo( maGroupName, hBaseKey, sSubKey ); + if( hBaseKey != nullptr ) + { + HKEY hKey = nullptr; + LPCSTR lpSubKey = sSubKey.getStr(); + // We use RegCreateKeyExA here for convenience, because we already have subkey name as 8-bit string + LONG lResult = RegCreateKeyExA( hBaseKey, lpSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nullptr, &hKey, nullptr ); + if( ERROR_SUCCESS == lResult ) + { + DWORD cbData = sizeof(WCHAR) * (aValue.getLength() + 1); + OUString sUValName = OStringToOUString(maKey, RTL_TEXTENCODING_DONTKNOW); + LPCWSTR lpValueName = o3tl::toW(sUValName.getStr()); + lResult = RegSetValueExW( hKey, lpValueName, 0 /* Reserved */, REG_SZ, reinterpret_cast<BYTE const *>(aValue.getStr()), cbData ); + RegCloseKey( hKey ); + } + } + return; +#else + throw uno::RuntimeException("Not implemented" ); +#endif + } + + // set value into a file + Config aCfg( maFileName ); + aCfg.SetGroup( maGroupName ); + aCfg.WriteKey( maKey, OUStringToOString(aValue, RTL_TEXTENCODING_DONTKNOW) ); + + +} + +SwVbaSystem::SwVbaSystem( uno::Reference<uno::XComponentContext > const & xContext ): SwVbaSystem_BASE( uno::Reference< XHelperInterface >(), xContext ) +{ +} + +SwVbaSystem::~SwVbaSystem() +{ +} + +sal_Int32 SAL_CALL +SwVbaSystem::getCursor() +{ + PointerStyle nPointerStyle = getPointerStyle( getCurrentWordDoc(mxContext) ); + + switch( nPointerStyle ) + { + case PointerStyle::Arrow: + return word::WdCursorType::wdCursorNorthwestArrow; + case PointerStyle::Null: + return word::WdCursorType::wdCursorNormal; + case PointerStyle::Wait: + return word::WdCursorType::wdCursorWait; + case PointerStyle::Text: + return word::WdCursorType::wdCursorIBeam; + default: + return word::WdCursorType::wdCursorNormal; + } +} + +void SAL_CALL +SwVbaSystem::setCursor( sal_Int32 _cursor ) +{ + try + { + switch( _cursor ) + { + case word::WdCursorType::wdCursorNorthwestArrow: + { + setCursorHelper( getCurrentWordDoc(mxContext), PointerStyle::Arrow, false ); + break; + } + case word::WdCursorType::wdCursorWait: + { + //It will set the edit window, toobar and statusbar's mouse pointer. + setCursorHelper( getCurrentWordDoc(mxContext), PointerStyle::Wait, true ); + break; + } + case word::WdCursorType::wdCursorIBeam: + { + //It will set the edit window, toobar and statusbar's mouse pointer. + setCursorHelper( getCurrentWordDoc( mxContext ), PointerStyle::Text, true ); + break; + } + case word::WdCursorType::wdCursorNormal: + { + setCursorHelper( getCurrentWordDoc( mxContext ), PointerStyle::Null, false ); + break; + } + default: + throw uno::RuntimeException("Unknown value for Cursor pointer" ); + // TODO: isn't this a flaw in the API? It should be allowed to throw an + // IllegalArgumentException, or so + } + } + catch( const uno::Exception& ) + { + } +} + +uno::Any SAL_CALL +SwVbaSystem::PrivateProfileString( const OUString& rFilename, const OUString& rSection, const OUString& rKey ) +{ + // FIXME: need to detect whether it is a relative file path + // we need to detect if this is a URL, if not then assume it's a file path + OUString sFileUrl; + if( !rFilename.isEmpty() ) + { + INetURLObject aObj; + aObj.SetURL( rFilename ); + bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid; + if ( bIsURL ) + sFileUrl = rFilename; + else + osl::FileBase::getFileURLFromSystemPath( rFilename, sFileUrl); + } + + OString aGroupName(OUStringToOString(rSection, RTL_TEXTENCODING_DONTKNOW)); + OString aKey(OUStringToOString(rKey, RTL_TEXTENCODING_DONTKNOW)); + maPrivateProfileStringListener.Initialize( sFileUrl, aGroupName, aKey ); + + return uno::Any( uno::Reference< XPropValue > ( new ScVbaPropValue( &maPrivateProfileStringListener ) ) ); +} + +OUString +SwVbaSystem::getServiceImplName() +{ + return "SwVbaSystem"; +} + +uno::Sequence< OUString > +SwVbaSystem::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.System" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbasystem.hxx b/sw/source/ui/vba/vbasystem.hxx new file mode 100644 index 0000000000..c0acb2ad49 --- /dev/null +++ b/sw/source/ui/vba/vbasystem.hxx @@ -0,0 +1,64 @@ +/* -*- 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_VBA_VBASYSTEM_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBASYSTEM_HXX + +#include <ooo/vba/word/XSystem.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <vbahelper/vbapropvalue.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XSystem > SwVbaSystem_BASE; + +class PrivateProfileStringListener : public PropListener +{ +private: + OUString maFileName; + OString maGroupName; + OString maKey; +public: + PrivateProfileStringListener(){}; + virtual ~PrivateProfileStringListener(); + void Initialize( const OUString& rFileName, const OString& rGroupName, const OString& rKey ); + + //PropListener + virtual void setValueEvent( const css::uno::Any& value ) override; + virtual css::uno::Any getValueEvent() override; +}; + +class SwVbaSystem : public SwVbaSystem_BASE +{ +private: + PrivateProfileStringListener maPrivateProfileStringListener; + +public: + explicit SwVbaSystem( css::uno::Reference< css::uno::XComponentContext > const & m_xContext ); + virtual ~SwVbaSystem() override; + + // XSystem + virtual sal_Int32 SAL_CALL getCursor() override; + virtual void SAL_CALL setCursor( sal_Int32 _cursor ) override; + virtual css::uno::Any SAL_CALL PrivateProfileString( const OUString& rFilename, const OUString& rSection, const OUString& rKey ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBASYSTEM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatable.cxx b/sw/source/ui/vba/vbatable.cxx new file mode 100644 index 0000000000..25e370a1c5 --- /dev/null +++ b/sw/source/ui/vba/vbatable.cxx @@ -0,0 +1,211 @@ +/* -*- 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 "vbatable.hxx" +#include "vbarange.hxx" +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/text/XTextViewCursorSupplier.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/text/XTextTable.hpp> +#include <com/sun/star/table/XTableRows.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/table/TableBorderDistances.hpp> +#include <utility> +#include "vbaborders.hxx" +#include "vbapalette.hxx" +#include "vbarows.hxx" +#include "vbacolumns.hxx" +#include "vbaapplication.hxx" + +#include <tools/UnitConversion.hxx> + +#include <sal/log.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaTable::SwVbaTable( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< text::XTextDocument > xDocument, const uno::Reference< text::XTextTable >& xTextTable) : SwVbaTable_BASE( rParent, rContext ), mxTextDocument(std::move( xDocument )) +{ + mxTextTable.set( xTextTable, uno::UNO_SET_THROW ); +} + +uno::Reference< word::XRange > SAL_CALL +SwVbaTable::Range( ) +{ + return new SwVbaRange( mxParent, mxContext, mxTextDocument, mxTextTable->getAnchor() ); +} + +void SAL_CALL +SwVbaTable::Select( ) +{ + uno::Reference< frame::XModel > xModel( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< frame::XController > xController = xModel->getCurrentController(); + + uno::Reference< text::XTextViewCursorSupplier > xViewCursorSupplier( xController, uno::UNO_QUERY_THROW ); + uno::Reference< view::XSelectionSupplier > xSelectionSupplier( xController, uno::UNO_QUERY_THROW ); + + // set the view cursor to the start of the table. + xSelectionSupplier->select( uno::Any( mxTextTable ) ); + + // go to the end of the table and span the view + uno::Reference< text::XTextViewCursor > xCursor = xViewCursorSupplier->getViewCursor(); + xCursor->gotoEnd(true); + +} + +void SAL_CALL +SwVbaTable::Delete( ) +{ + uno::Reference< table::XTableRows > xRows( mxTextTable->getRows() ); + xRows->removeByIndex( 0, xRows->getCount() ); +} + +OUString SAL_CALL +SwVbaTable::getName( ) +{ + uno::Reference< container::XNamed > xNamed( mxTextTable, uno::UNO_QUERY_THROW ); + return xNamed->getName(); +} + +uno::Any SAL_CALL +SwVbaTable::Borders( const uno::Any& index ) +{ + uno::Reference< table::XCellRange > aCellRange( mxTextTable, uno::UNO_QUERY_THROW ); + VbaPalette aPalette; + uno::Reference< XCollection > xCol( new SwVbaBorders( this, mxContext, aCellRange, aPalette ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +double SAL_CALL +SwVbaTable::getBottomPadding() +{ + uno::Reference< beans::XPropertySet > xPropertySet( mxTextTable, uno::UNO_QUERY_THROW); + table::TableBorderDistances aTableBorderDistances; + xPropertySet->getPropertyValue("TableBorderDistances") >>= aTableBorderDistances; + return convertMm100ToPoint(aTableBorderDistances.BottomDistance); +} + +void SAL_CALL +SwVbaTable::setBottomPadding( double fValue ) +{ + uno::Reference< beans::XPropertySet > xPropertySet( mxTextTable, uno::UNO_QUERY_THROW); + table::TableBorderDistances aTableBorderDistances; + aTableBorderDistances.IsBottomDistanceValid = true; + aTableBorderDistances.BottomDistance = convertPointToMm100(fValue); + xPropertySet->setPropertyValue( "TableBorderDistances", uno::Any( aTableBorderDistances ) ); +} + +double SAL_CALL +SwVbaTable::getLeftPadding() +{ + uno::Reference< beans::XPropertySet > xPropertySet( mxTextTable, uno::UNO_QUERY_THROW); + table::TableBorderDistances aTableBorderDistances; + xPropertySet->getPropertyValue("TableBorderDistances") >>= aTableBorderDistances; + return convertMm100ToPoint(aTableBorderDistances.LeftDistance); +} + +void SAL_CALL +SwVbaTable::setLeftPadding( double fValue ) +{ + uno::Reference< beans::XPropertySet > xPropertySet( mxTextTable, uno::UNO_QUERY_THROW); + table::TableBorderDistances aTableBorderDistances; + aTableBorderDistances.IsLeftDistanceValid = true; + aTableBorderDistances.LeftDistance = convertPointToMm100(fValue); + xPropertySet->setPropertyValue( "TableBorderDistances", uno::Any( aTableBorderDistances ) ); +} + +double SAL_CALL +SwVbaTable::getRightPadding() +{ + uno::Reference< beans::XPropertySet > xPropertySet( mxTextTable, uno::UNO_QUERY_THROW); + table::TableBorderDistances aTableBorderDistances; + xPropertySet->getPropertyValue("TableBorderDistances") >>= aTableBorderDistances; + return convertMm100ToPoint(aTableBorderDistances.RightDistance); +} + +void SAL_CALL +SwVbaTable::setRightPadding( double fValue ) +{ + uno::Reference< beans::XPropertySet > xPropertySet( mxTextTable, uno::UNO_QUERY_THROW); + table::TableBorderDistances aTableBorderDistances; + aTableBorderDistances.IsRightDistanceValid = true; + aTableBorderDistances.RightDistance = convertPointToMm100(fValue); + xPropertySet->setPropertyValue( "TableBorderDistances", uno::Any( aTableBorderDistances ) ); +} + +double SAL_CALL +SwVbaTable::getTopPadding() +{ + uno::Reference< beans::XPropertySet > xPropertySet( mxTextTable, uno::UNO_QUERY_THROW); + table::TableBorderDistances aTableBorderDistances; + xPropertySet->getPropertyValue("TableBorderDistances") >>= aTableBorderDistances; + return convertMm100ToPoint(aTableBorderDistances.TopDistance); +} + +void SAL_CALL +SwVbaTable::setTopPadding( double fValue ) +{ + uno::Reference< beans::XPropertySet > xPropertySet( mxTextTable, uno::UNO_QUERY_THROW); + table::TableBorderDistances aTableBorderDistances; + aTableBorderDistances.IsTopDistanceValid = true; + aTableBorderDistances.TopDistance = convertPointToMm100(fValue); + xPropertySet->setPropertyValue( "TableBorderDistances", uno::Any( aTableBorderDistances ) ); +} + +uno::Any SAL_CALL +SwVbaTable::Rows( const uno::Any& index ) +{ + uno::Reference< table::XTableRows > xTableRows( mxTextTable->getRows(), uno::UNO_SET_THROW ); + uno::Reference< XCollection > xCol( new SwVbaRows( this, mxContext, mxTextTable, xTableRows ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +uno::Any SAL_CALL +SwVbaTable::Columns( const uno::Any& index ) +{ + uno::Reference< table::XTableColumns > xTableColumns( mxTextTable->getColumns(), uno::UNO_SET_THROW ); + uno::Reference< XCollection > xCol( new SwVbaColumns( this, mxContext, mxTextTable, xTableColumns ) ); + if ( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +// XHelperInterface +OUString +SwVbaTable::getServiceImplName() +{ + return "SwVbaTable"; +} + +uno::Sequence<OUString> +SwVbaTable::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Table" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatable.hxx b/sw/source/ui/vba/vbatable.hxx new file mode 100644 index 0000000000..2bb802b5c6 --- /dev/null +++ b/sw/source/ui/vba/vbatable.hxx @@ -0,0 +1,59 @@ +/* -*- 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_VBA_VBATABLE_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBATABLE_HXX +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/text/XTextTable.hpp> +#include <ooo/vba/word/XRange.hpp> +#include <ooo/vba/word/XTable.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XTable > SwVbaTable_BASE; + +class SwVbaTable : public SwVbaTable_BASE +{ + css::uno::Reference< css::text::XTextDocument > mxTextDocument; + css::uno::Reference< css::text::XTextTable > mxTextTable; +public: + /// @throws css::uno::RuntimeException + SwVbaTable( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::text::XTextDocument > xDocument, const css::uno::Reference< css::text::XTextTable >& xTextTable); + virtual css::uno::Reference< ::ooo::vba::word::XRange > SAL_CALL Range( ) override; + virtual void SAL_CALL Select( ) override; + virtual void SAL_CALL Delete( ) override; + virtual OUString SAL_CALL getName( ) override; + virtual css::uno::Any SAL_CALL Borders( const css::uno::Any& aIndex ) override; + virtual double SAL_CALL getBottomPadding( ) override; + virtual void SAL_CALL setBottomPadding( double fValue ) override; + virtual double SAL_CALL getLeftPadding( ) override; + virtual void SAL_CALL setLeftPadding( double fValue ) override; + virtual double SAL_CALL getRightPadding( ) override; + virtual void SAL_CALL setRightPadding( double fValue ) override; + virtual double SAL_CALL getTopPadding( ) override; + virtual void SAL_CALL setTopPadding( double fValue ) override; + virtual css::uno::Any SAL_CALL Rows( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL Columns( const css::uno::Any& aIndex ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatablehelper.cxx b/sw/source/ui/vba/vbatablehelper.cxx new file mode 100644 index 0000000000..2d7a1b393e --- /dev/null +++ b/sw/source/ui/vba/vbatablehelper.cxx @@ -0,0 +1,276 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <comphelper/servicehelper.hxx> +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include "vbatablehelper.hxx" +#include <swtable.hxx> +#include <unotbl.hxx> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +#define UNO_TABLE_COLUMN_SUM 10000 + +SwVbaTableHelper::SwVbaTableHelper( uno::Reference< text::XTextTable > xTextTable ) : mxTextTable(std::move( xTextTable )) +{ + m_pTable = GetSwTable( mxTextTable ); +} + +SwTable* SwVbaTableHelper::GetSwTable( const uno::Reference< text::XTextTable >& xTextTable ) +{ + SwXTextTable* pXTextTable = dynamic_cast<SwXTextTable*>(xTextTable.get()); + if( !pXTextTable ) + throw uno::RuntimeException(); + + SwFrameFormat* pFrameFormat = pXTextTable->GetFrameFormat(); + if( !pFrameFormat ) + throw uno::RuntimeException(); + + SwTable* pTable = SwTable::FindTable( pFrameFormat ); + return pTable; +} + +sal_Int32 SwVbaTableHelper::getTabColumnsCount( sal_Int32 nRowIndex ) +{ + sal_Int32 nRet = 0; + if(!m_pTable->IsTableComplex()) + { + SwTableLines& rLines = m_pTable->GetTabLines(); + SwTableLine* pLine = rLines[ nRowIndex ]; + nRet = pLine->GetTabBoxes().size(); + } + return nRet; +} + +sal_Int32 SwVbaTableHelper::getTabColumnsMaxCount( ) +{ + sal_Int32 nRet = 0; + sal_Int32 nRowCount = m_pTable->GetTabLines().size(); + for( sal_Int32 index = 0; index < nRowCount; index++ ) + { + sal_Int32 nColCount = getTabColumnsCount( index ); + if( nRet < nColCount ) + nRet = nColCount; + } + return nRet; +} + +sal_Int32 SwVbaTableHelper::getTabRowIndex( const OUString& rCellName ) +{ + sal_Int32 nRet = 0; + SwTableBox* pBox = const_cast<SwTableBox*>(m_pTable->GetTableBox( rCellName )); + if( !pBox ) + throw uno::RuntimeException(); + + const SwTableLine* pLine = pBox->GetUpper(); + const SwTableLines* pLines = pLine->GetUpper() + ? &pLine->GetUpper()->GetTabLines() : &m_pTable->GetTabLines(); + nRet = pLines->GetPos( pLine ); + return nRet; +} + +sal_Int32 SwVbaTableHelper::getTabColIndex( const OUString& rCellName ) +{ + const SwTableBox* pBox = m_pTable->GetTableBox( rCellName ); + if( !pBox ) + throw uno::RuntimeException(); + return pBox->GetUpper()->GetBoxPos( pBox ); +} + +OUString SwVbaTableHelper::getColumnStr( sal_Int32 nCol ) +{ + const sal_Int32 coDiff = 52; // 'A'-'Z' 'a' - 'z' + sal_Int32 nCalc = 0; + + OUString sRet; + do{ + nCalc = nCol % coDiff; + if( nCalc >= 26 ) + sRet = OUStringChar( sal_Unicode('a' - 26 + nCalc) ) + sRet; + else + sRet = OUStringChar( sal_Unicode('A' + nCalc) ) + sRet; + + nCol = nCol - nCalc; + if( 0 == nCol ) + break; + nCol /= coDiff; + --nCol; + }while(true); + return sRet; +} + +sal_Int32 SwVbaTableHelper::getTableWidth( ) const +{ + sal_Int32 nWidth = 0; + bool isWidthRelatvie = false; + uno::Reference< beans::XPropertySet > xTableProps( mxTextTable, uno::UNO_QUERY_THROW ); + xTableProps->getPropertyValue("IsWidthRelative") >>= isWidthRelatvie; + if( isWidthRelatvie ) + { + xTableProps->getPropertyValue("RelativeWidth") >>= nWidth; + } + else + { + xTableProps->getPropertyValue("Width") >>= nWidth; + } + return nWidth; +} + +SwTableBox* SwVbaTableHelper::GetTabBox( sal_Int32 nCol, sal_Int32 nRow ) +{ + SwTableLines& rLines = m_pTable->GetTabLines(); + sal_Int32 nRowCount = rLines.size(); + if (nRow < 0 || nRow >= nRowCount) + throw uno::RuntimeException(); + + SwTableLine* pLine = rLines[ nRow ]; + sal_Int32 nColCount = pLine->GetTabBoxes().size(); + if (nCol < 0 || nCol >= nColCount) + throw uno::RuntimeException(); + + SwTableBox* pStart = pLine->GetTabBoxes()[ nCol ]; + + if( !pStart ) + throw uno::RuntimeException(); + + return pStart; +} + +void SwVbaTableHelper::InitTabCols( SwTabCols& rCols, const SwTableBox *pStart ) +{ + rCols.SetLeftMin ( 0 ); + rCols.SetLeft ( 0 ); + rCols.SetRight ( UNO_TABLE_COLUMN_SUM ); + rCols.SetRightMax( UNO_TABLE_COLUMN_SUM ); + m_pTable->GetTabCols( rCols, pStart ); +} + +sal_Int32 SwVbaTableHelper::GetColCount( SwTabCols const & rCols ) +{ + sal_Int32 nCount = 0; + for( size_t i = 0; i < rCols.Count(); ++i ) + if(rCols.IsHidden(i)) + nCount ++; + return rCols.Count() - nCount; +} + +sal_Int32 SwVbaTableHelper::GetRightSeparator( SwTabCols const & rCols, sal_Int32 nNum) +{ + OSL_ENSURE( nNum < GetColCount( rCols ) ,"Index out of range"); + sal_Int32 i = 0; + while( nNum >= 0 ) + { + if( !rCols.IsHidden(i) ) + nNum--; + i++; + } + return i - 1; +} + +sal_Int32 SwVbaTableHelper::GetColWidth( sal_Int32 nCol, sal_Int32 nRow ) +{ + SwTableBox* pStart = GetTabBox( nCol, nRow ); + SwTabCols aCols; + InitTabCols( aCols, pStart ); + sal_Int32 nWidth = GetColWidth( aCols, nCol ); + + sal_Int32 nTableWidth = getTableWidth( ); + double dAbsWidth = ( static_cast<double>(nWidth) / UNO_TABLE_COLUMN_SUM ) * static_cast<double>(nTableWidth); + return static_cast<sal_Int32>(Millimeter::getInPoints( static_cast<int>(dAbsWidth) )); +} + +sal_Int32 SwVbaTableHelper::GetColWidth( SwTabCols& rCols, sal_Int32 nNum ) +{ + SwTwips nWidth = 0; + + if( rCols.Count() > 0 ) + { + if(rCols.Count() == static_cast<size_t>(GetColCount( rCols ))) + { + if(static_cast<size_t>(nNum) == rCols.Count()) + nWidth = rCols.GetRight() - rCols[nNum-1]; + else + { + nWidth = rCols[nNum]; + if(nNum == 0) + nWidth -= rCols.GetLeft(); + else + nWidth -= rCols[nNum-1]; + } + } + else + { + SwTwips nRValid = nNum < GetColCount( rCols ) ? + rCols[GetRightSeparator( rCols, nNum )]: + rCols.GetRight(); + SwTwips nLValid = nNum ? + rCols[GetRightSeparator( rCols, nNum - 1 )]: + rCols.GetLeft(); + nWidth = nRValid - nLValid; + } + } + else + nWidth = rCols.GetRight(); + + return nWidth; +} + +void SwVbaTableHelper::SetColWidth( sal_Int32 _width, sal_Int32 nCol, sal_Int32 nRow, bool bCurRowOnly ) +{ + double dAbsWidth = Millimeter::getInHundredthsOfOneMillimeter( _width ); + sal_Int32 nTableWidth = getTableWidth( ); + if (!nTableWidth) + throw uno::RuntimeException(); + sal_Int32 nNewWidth = dAbsWidth/nTableWidth * UNO_TABLE_COLUMN_SUM; + + SwTableBox* pStart = GetTabBox( nCol, nRow ); + SwTabCols aOldCols; + InitTabCols( aOldCols, pStart ); + + SwTabCols aCols( aOldCols ); + if ( aCols.Count() > 0 ) + { + SwTwips nWidth = GetColWidth( aCols, nCol); + + int nDiff = nNewWidth - nWidth; + if( !nCol ) + aCols[ GetRightSeparator(aCols, 0) ] += nDiff; + else if( nCol < GetColCount( aCols ) ) + { + if(nDiff < GetColWidth( aCols, nCol + 1) - MINLAY) + aCols[ GetRightSeparator( aCols, nCol ) ] += nDiff; + else + { + int nDiffLeft = nDiff - static_cast<int>(GetColWidth( aCols, nCol + 1)) + int(MINLAY); + aCols[ GetRightSeparator( aCols, nCol ) ] += (nDiff - nDiffLeft); + aCols[ GetRightSeparator( aCols, nCol - 1 ) ] -= nDiffLeft; + } + } + else + aCols[ GetRightSeparator( aCols, nCol-1 ) ] -= nDiff; + } + else + aCols.SetRight( std::min( static_cast<tools::Long>(nNewWidth), aCols.GetRightMax()) ); + + m_pTable->SetTabCols(aCols, aOldCols, pStart, bCurRowOnly ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatablehelper.hxx b/sw/source/ui/vba/vbatablehelper.hxx new file mode 100644 index 0000000000..b3b48dc005 --- /dev/null +++ b/sw/source/ui/vba/vbatablehelper.hxx @@ -0,0 +1,67 @@ +/* -*- 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_VBA_VBATABLEHELPER_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBATABLEHELPER_HXX + +#include <com/sun/star/text/XTextTable.hpp> +#include <swtable.hxx> +#include <tabcol.hxx> + +class SwVbaTableHelper +{ +private: + css::uno::Reference< css::text::XTextTable > mxTextTable; + SwTable* m_pTable; + +private: + /// @throws css::uno::RuntimeException + SwTableBox* GetTabBox( sal_Int32 nCol, sal_Int32 nRow ); + void InitTabCols( SwTabCols& rCols, const SwTableBox *pStart ); + static sal_Int32 GetRightSeparator( SwTabCols const & rCols, sal_Int32 nNum); + static sal_Int32 GetColCount( SwTabCols const & rCols ); + /// @throws css::uno::RuntimeException + static sal_Int32 GetColWidth( SwTabCols& rCols, sal_Int32 nNum ); + +public: + /// @throws css::uno::RuntimeException + explicit SwVbaTableHelper( css::uno::Reference< css::text::XTextTable > xTextTable ); + /// @throws css::uno::RuntimeException + sal_Int32 getTabColumnsCount( sal_Int32 nRowIndex ); + /// @throws css::uno::RuntimeException + sal_Int32 getTabColumnsMaxCount( ); + /// @throws css::uno::RuntimeException + sal_Int32 getTabRowIndex( const OUString& sCellName ); + /// @throws css::uno::RuntimeException + sal_Int32 getTabColIndex( const OUString& sCellName ); + /// @throws css::uno::RuntimeException + sal_Int32 getTableWidth( ) const; + + /// @throws css::uno::RuntimeException + sal_Int32 GetColWidth( sal_Int32 nCol, sal_Int32 nRow = 0 ); + /// @throws css::uno::RuntimeException + void SetColWidth( sal_Int32 _width, sal_Int32 nCol, sal_Int32 nRow = 0, bool bCurRowOnly = false ); + + /// @throws css::uno::RuntimeException + static SwTable* GetSwTable( const css::uno::Reference< css::text::XTextTable >& xTextTable ); + static OUString getColumnStr( sal_Int32 nCol ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatableofcontents.cxx b/sw/source/ui/vba/vbatableofcontents.cxx new file mode 100644 index 0000000000..e0d80cfb1c --- /dev/null +++ b/sw/source/ui/vba/vbatableofcontents.cxx @@ -0,0 +1,111 @@ +/* -*- 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 "vbatableofcontents.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <ooo/vba/word/WdTabLeader.hpp> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaTableOfContents::SwVbaTableOfContents( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, uno::Reference< text::XTextDocument > xDoc, uno::Reference< text::XDocumentIndex > xDocumentIndex ) : + SwVbaTableOfContents_BASE( rParent, rContext ), mxTextDocument(std::move( xDoc )), mxDocumentIndex(std::move( xDocumentIndex )) +{ + mxTocProps.set( mxDocumentIndex, uno::UNO_QUERY_THROW ); +} + +SwVbaTableOfContents::~SwVbaTableOfContents() +{ +} + +::sal_Int32 SAL_CALL SwVbaTableOfContents::getLowerHeadingLevel() +{ + sal_Int16 nLevel = 0; + mxTocProps->getPropertyValue("Level") >>= nLevel; + return nLevel; +} + +void SAL_CALL SwVbaTableOfContents::setLowerHeadingLevel( ::sal_Int32 _lowerheadinglevel ) +{ + mxTocProps->setPropertyValue("Level", uno::Any( sal_Int8( _lowerheadinglevel ) ) ); +} + +::sal_Int32 SAL_CALL SwVbaTableOfContents::getTabLeader() +{ + // not support in Writer + return word::WdTabLeader::wdTabLeaderDots; +} + +void SAL_CALL SwVbaTableOfContents::setTabLeader( ::sal_Int32 /*_tableader*/ ) +{ + // not support in Writer +} + +sal_Bool SAL_CALL SwVbaTableOfContents::getUseFields() +{ + bool bUseFields = false; + mxTocProps->getPropertyValue("CreateFromMarks") >>= bUseFields; + return bUseFields; +} + +void SAL_CALL SwVbaTableOfContents::setUseFields( sal_Bool _useFields ) +{ + mxTocProps->setPropertyValue("CreateFromMarks", uno::Any( _useFields ) ); +} + +sal_Bool SAL_CALL SwVbaTableOfContents::getUseOutlineLevels() +{ + bool bUseOutlineLevels = false; + mxTocProps->getPropertyValue("CreateFromOutline") >>= bUseOutlineLevels; + return bUseOutlineLevels; +} + +void SAL_CALL SwVbaTableOfContents::setUseOutlineLevels( sal_Bool _useOutlineLevels ) +{ + mxTocProps->setPropertyValue("CreateFromOutline", uno::Any( _useOutlineLevels ) ); +} + +void SAL_CALL SwVbaTableOfContents::Delete( ) +{ + uno::Reference< text::XTextContent > xTextContent( mxDocumentIndex, uno::UNO_QUERY_THROW ); + mxTextDocument->getText()->removeTextContent( xTextContent ); +} + +void SAL_CALL SwVbaTableOfContents::Update( ) +{ + mxDocumentIndex->update(); +} + +OUString +SwVbaTableOfContents::getServiceImplName() +{ + return "SwVbaTableOfContents"; +} + +uno::Sequence< OUString > +SwVbaTableOfContents::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.TableOfContents" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatableofcontents.hxx b/sw/source/ui/vba/vbatableofcontents.hxx new file mode 100644 index 0000000000..69ccd9394f --- /dev/null +++ b/sw/source/ui/vba/vbatableofcontents.hxx @@ -0,0 +1,61 @@ +/* -*- 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_VBA_VBATABLEOFCONTENTS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBATABLEOFCONTENTS_HXX + +#include <ooo/vba/word/XTableOfContents.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/text/XDocumentIndex.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XTableOfContents > SwVbaTableOfContents_BASE; + +class SwVbaTableOfContents : public SwVbaTableOfContents_BASE +{ +private: + css::uno::Reference< css::text::XTextDocument > mxTextDocument; + css::uno::Reference< css::text::XDocumentIndex > mxDocumentIndex; + css::uno::Reference< css::beans::XPropertySet > mxTocProps; + +public: + /// @throws css::uno::RuntimeException + SwVbaTableOfContents( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, css::uno::Reference< css::text::XTextDocument > xDoc, css::uno::Reference< css::text::XDocumentIndex > xDocumentIndex ); + virtual ~SwVbaTableOfContents() override; + + // Attributes + virtual ::sal_Int32 SAL_CALL getLowerHeadingLevel() override; + virtual void SAL_CALL setLowerHeadingLevel( ::sal_Int32 _lowerheadinglevel ) override; + virtual ::sal_Int32 SAL_CALL getTabLeader() override; + virtual void SAL_CALL setTabLeader( ::sal_Int32 _tableader ) override; + virtual sal_Bool SAL_CALL getUseFields() override; + virtual void SAL_CALL setUseFields( sal_Bool _useFields ) override; + virtual sal_Bool SAL_CALL getUseOutlineLevels() override; + virtual void SAL_CALL setUseOutlineLevels( sal_Bool _useOutlineLevels ) override; + + // Methods + virtual void SAL_CALL Delete( ) override; + virtual void SAL_CALL Update( ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBATABLEOFCONTENTS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatables.cxx b/sw/source/ui/vba/vbatables.cxx new file mode 100644 index 0000000000..b7aa4cadda --- /dev/null +++ b/sw/source/ui/vba/vbatables.cxx @@ -0,0 +1,239 @@ +/* -*- 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 "vbatables.hxx" +#include "vbatable.hxx" +#include "vbarange.hxx" +#include "wordvbahelper.hxx" +#include <com/sun/star/text/XTextTable.hpp> +#include <com/sun/star/text/XTextTablesSupplier.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <cppuhelper/implbase.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace css; + +static uno::Reference< container::XIndexAccess > lcl_getTables( const uno::Reference< frame::XModel >& xDoc ) +{ + uno::Reference< container::XIndexAccess > xTables; + uno::Reference< text::XTextTablesSupplier > xSupp( xDoc, uno::UNO_QUERY ); + if ( xSupp.is() ) + xTables.set( xSupp->getTextTables(), uno::UNO_QUERY_THROW ); + return xTables; +} + +static uno::Any lcl_createTable( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< frame::XModel >& xDocument, const uno::Any& aSource ) +{ + uno::Reference< text::XTextTable > xTextTable( aSource, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextDocument > xTextDocument( xDocument, uno::UNO_QUERY_THROW ); + uno::Reference< word::XTable > xTable( new SwVbaTable( xParent, xContext, xTextDocument, xTextTable ) ); + return uno::Any( xTable ); +} + +static bool lcl_isInHeaderFooter( const uno::Reference< text::XTextTable >& xTable ) +{ + uno::Reference< text::XTextContent > xTextContent( xTable, uno::UNO_QUERY_THROW ); + uno::Reference< text::XText > xText = xTextContent->getAnchor()->getText(); + uno::Reference< lang::XServiceInfo > xServiceInfo( xText, uno::UNO_QUERY ); + if ( !xServiceInfo ) + return false; + OUString aImplName = xServiceInfo->getImplementationName(); + return aImplName == "SwXHeadFootText"; +} + +typedef std::vector< uno::Reference< text::XTextTable > > XTextTableVec; + +namespace { + +class TableCollectionHelper : public ::cppu::WeakImplHelper< container::XIndexAccess, + container::XNameAccess > +{ + XTextTableVec mxTables; + XTextTableVec::iterator m_cachePos; + +public: + explicit TableCollectionHelper( const uno::Reference< frame::XModel >& xDocument ) + { + // only count the tables in the body text, not in the header/footer + uno::Reference< container::XIndexAccess > xTables = lcl_getTables( xDocument ); + sal_Int32 nCount = xTables->getCount(); + for( sal_Int32 i = 0; i < nCount; i++ ) + { + uno::Reference< text::XTextTable > xTable( xTables->getByIndex( i ) , uno::UNO_QUERY_THROW ); + if( !lcl_isInHeaderFooter( xTable ) ) + mxTables.push_back( xTable ); + } + m_cachePos = mxTables.begin(); + } + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount( ) override + { + return mxTables.size(); + } + virtual uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override + { + if ( Index < 0 || Index >= getCount() ) + throw lang::IndexOutOfBoundsException(); + uno::Reference< text::XTextTable > xTable( mxTables[ Index ], uno::UNO_SET_THROW ); + return uno::Any( xTable ); + } + // XElementAccess + virtual uno::Type SAL_CALL getElementType( ) override { return cppu::UnoType<text::XTextTable>::get(); } + virtual sal_Bool SAL_CALL hasElements( ) override { return getCount() > 0 ; } + // XNameAccess + virtual uno::Any SAL_CALL getByName( const OUString& aName ) override + { + if ( !hasByName(aName) ) + throw container::NoSuchElementException(); + uno::Reference< text::XTextTable > xTable( *m_cachePos, uno::UNO_SET_THROW ); + return uno::Any( xTable ); + } + virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override + { + uno::Sequence< OUString > sNames( mxTables.size() ); + OUString* pString = sNames.getArray(); + for ( const auto& rxTable : mxTables ) + { + uno::Reference< container::XNamed > xName( rxTable, uno::UNO_QUERY_THROW ); + *pString = xName->getName(); + ++pString; + } + return sNames; + } + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { + m_cachePos = mxTables.begin(); + XTextTableVec::iterator it_end = mxTables.end(); + for ( ; m_cachePos != it_end; ++m_cachePos ) + { + uno::Reference< container::XNamed > xName( *m_cachePos, uno::UNO_QUERY_THROW ); + if ( aName.equalsIgnoreAsciiCase( xName->getName() ) ) + break; + } + return ( m_cachePos != it_end ); + } +}; + +class TableEnumerationImpl : public ::cppu::WeakImplHelper< css::container::XEnumeration > +{ + uno::Reference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< frame::XModel > mxDocument; + uno::Reference< container::XIndexAccess > mxIndexAccess; + sal_Int32 mnCurIndex; +public: + TableEnumerationImpl( uno::Reference< XHelperInterface > xParent, uno::Reference< uno::XComponentContext > xContext, uno::Reference< frame::XModel > xDocument, uno::Reference< container::XIndexAccess > xIndexAccess ) : mxParent(std::move( xParent )), mxContext(std::move( xContext )), mxDocument(std::move( xDocument )), mxIndexAccess(std::move( xIndexAccess )), mnCurIndex(0) + { + } + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( mnCurIndex < mxIndexAccess->getCount() ); + } + virtual uno::Any SAL_CALL nextElement( ) override + { + if ( !hasMoreElements() ) + throw container::NoSuchElementException(); + return lcl_createTable( mxParent, mxContext, mxDocument, mxIndexAccess->getByIndex( mnCurIndex++ ) ); + } + +}; + +} + +SwVbaTables::SwVbaTables( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< frame::XModel >& xDocument ) : SwVbaTables_BASE( xParent, xContext , uno::Reference< container::XIndexAccess >( new TableCollectionHelper( xDocument ) ) ), mxDocument( xDocument ) +{ +} + +uno::Reference< word::XTable > SAL_CALL +SwVbaTables::Add( const uno::Reference< word::XRange >& Range, const uno::Any& NumRows, const uno::Any& NumColumns, const uno::Any& /*DefaultTableBehavior*/, const uno::Any& /*AutoFitBehavior*/ ) +{ + sal_Int32 nCols = 0; + sal_Int32 nRows = 0; + SwVbaRange* pVbaRange = dynamic_cast< SwVbaRange* >( Range.get() ); + // Preconditions + if ( !( pVbaRange && ( NumRows >>= nRows ) && ( NumColumns >>= nCols ) ) ) + throw uno::RuntimeException(); // #FIXME better exception?? + if ( nCols <= 0 || nRows <= 0 ) + throw uno::RuntimeException(); // #FIXME better exception?? + + uno::Reference< frame::XModel > xModel( pVbaRange->getDocument(), uno::UNO_QUERY_THROW ); + uno::Reference< lang::XMultiServiceFactory > xMsf( xModel, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextRange > xTextRange = pVbaRange->getXTextRange(); + + uno::Reference< text::XTextTable > xTable; + xTable.set( xMsf->createInstance("com.sun.star.text.TextTable"), uno::UNO_QUERY_THROW ); + + xTable->initialize( nRows, nCols ); + uno::Reference< text::XText > xText = xTextRange->getText(); + uno::Reference< text::XTextContent > xContext( xTable, uno::UNO_QUERY_THROW ); + + xText->insertTextContent( xTextRange, xContext, true ); + + // move the current cursor to the first table cell + uno::Reference< table::XCellRange > xCellRange( xTable, uno::UNO_QUERY_THROW ); + uno::Reference< text::XText> xFirstCellText( xCellRange->getCellByPosition(0, 0), uno::UNO_QUERY_THROW ); + word::getXTextViewCursor( mxDocument )->gotoRange( xFirstCellText->getStart(), false ); + + uno::Reference< word::XTable > xVBATable( new SwVbaTable( mxParent, mxContext, pVbaRange->getDocument(), xTable ) ); + return xVBATable; +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwVbaTables::createEnumeration() +{ + return new TableEnumerationImpl( mxParent, mxContext, mxDocument, m_xIndexAccess ); +} + +// ScVbaCollectionBaseImpl +uno::Any +SwVbaTables::createCollectionObject( const uno::Any& aSource ) +{ + return lcl_createTable( mxParent, mxContext, mxDocument, aSource ); +} + +// XHelperInterface +OUString +SwVbaTables::getServiceImplName() +{ + return "SwVbaTables"; +} + +// XEnumerationAccess +uno::Type SAL_CALL +SwVbaTables::getElementType() +{ + return cppu::UnoType<word::XTable>::get(); +} + +uno::Sequence<OUString> +SwVbaTables::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Tables" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatables.hxx b/sw/source/ui/vba/vbatables.hxx new file mode 100644 index 0000000000..ae7de0b00c --- /dev/null +++ b/sw/source/ui/vba/vbatables.hxx @@ -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 . + */ + +#ifndef INCLUDED_SW_SOURCE_UI_VBA_VBATABLES_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBATABLES_HXX + +#include <ooo/vba/word/XTables.hpp> +#include <vbahelper/vbacollectionimpl.hxx> + +typedef CollTestImplHelper< ov::word::XTables > SwVbaTables_BASE; + +class SwVbaTables : public SwVbaTables_BASE +{ + css::uno::Reference< css::frame::XModel > mxDocument; +public: + SwVbaTables( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xDocument ); + // XTables + virtual css::uno::Reference< ov::word::XTable > SAL_CALL Add( const css::uno::Reference< ::ooo::vba::word::XRange >& Range, const css::uno::Any& NumRows, const css::uno::Any& NumColumns, const css::uno::Any& DefaultTableBehavior, const css::uno::Any& AutoFitBehavior ) override; + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + // ScVbaCollectionBaseImpl + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatablesofcontents.cxx b/sw/source/ui/vba/vbatablesofcontents.cxx new file mode 100644 index 0000000000..8df156fecf --- /dev/null +++ b/sw/source/ui/vba/vbatablesofcontents.cxx @@ -0,0 +1,186 @@ +/* -*- 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 "vbatablesofcontents.hxx" +#include "vbatableofcontents.hxx" +#include "vbarange.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/text/XDocumentIndexesSupplier.hpp> +#include <cppuhelper/implbase.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +namespace { + +class TablesOfContentsEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference< container::XIndexAccess > mxIndexAccess; + sal_Int32 m_nIndex; + +public: + explicit TablesOfContentsEnumWrapper( uno::Reference< container::XIndexAccess > xIndexAccess ) : mxIndexAccess(std::move( xIndexAccess )), m_nIndex( 0 ) + { + } + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( m_nIndex < mxIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if( m_nIndex < mxIndexAccess->getCount() ) + { + return mxIndexAccess->getByIndex( m_nIndex++ ); + } + throw container::NoSuchElementException(); + } +}; + +class TableOfContentsCollectionHelper : public ::cppu::WeakImplHelper< container::XIndexAccess, + container::XEnumerationAccess > +{ +private: + uno::Reference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + uno::Reference< text::XTextDocument > mxTextDocument; + std::vector< uno::Reference< text::XDocumentIndex > > maToc; + +public: + /// @throws uno::RuntimeException + TableOfContentsCollectionHelper( uno::Reference< ov::XHelperInterface > xParent, uno::Reference< uno::XComponentContext > xContext, uno::Reference< text::XTextDocument > xDoc ): mxParent(std::move( xParent )), mxContext(std::move( xContext )), mxTextDocument(std::move( xDoc )) + { + uno::Reference< text::XDocumentIndexesSupplier > xDocIndexSupp( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xDocIndexes = xDocIndexSupp->getDocumentIndexes(); + sal_Int32 nCount = xDocIndexes->getCount(); + for( sal_Int32 i = 0; i < nCount; i++ ) + { + uno::Reference< text::XDocumentIndex > xToc( xDocIndexes->getByIndex(i), uno::UNO_QUERY_THROW ); + if( xToc->getServiceName() == "com.sun.star.text.ContentIndex" ) + { + maToc.push_back( xToc ); + } + } + } + + virtual sal_Int32 SAL_CALL getCount( ) override + { + return maToc.size(); + } + virtual uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override + { + if ( Index < 0 || Index >= getCount() ) + throw lang::IndexOutOfBoundsException(); + + uno::Reference< text::XDocumentIndex > xToc( maToc[Index], uno::UNO_SET_THROW ); + return uno::Any( uno::Reference< word::XTableOfContents >( new SwVbaTableOfContents( mxParent, mxContext, mxTextDocument, xToc ) ) ); + } + virtual uno::Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<word::XTableOfContents>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + return true; + } + // XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + return new TablesOfContentsEnumWrapper( this ); + } +}; + +} + +SwVbaTablesOfContents::SwVbaTablesOfContents( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< text::XTextDocument >& xDoc ) : SwVbaTablesOfContents_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( new TableOfContentsCollectionHelper( xParent, xContext, xDoc ) ) ), mxTextDocument( xDoc ) +{ +} + +uno::Reference< word::XTableOfContents > SAL_CALL +SwVbaTablesOfContents::Add( const uno::Reference< word::XRange >& Range, const uno::Any& /*UseHeadingStyles*/, const uno::Any& /*UpperHeadingLevel*/, const uno::Any& LowerHeadingLevel, const uno::Any& UseFields, const uno::Any& /*TableID*/, const uno::Any& /*RightAlignPageNumbers*/, const uno::Any& /*IncludePageNumbers*/, const uno::Any& /*AddedStyles*/, const uno::Any& /*UseHyperlinks*/, const uno::Any& /*HidePageNumbersInWeb*/, const uno::Any& /*UseOutlineLevels*/ ) +{ + uno::Reference< lang::XMultiServiceFactory > xDocMSF( mxTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< text::XDocumentIndex > xDocumentIndex( xDocMSF->createInstance("com.sun.star.text.ContentIndex"), uno::UNO_QUERY_THROW ); + + uno::Reference< beans::XPropertySet > xTocProps( xDocumentIndex, uno::UNO_QUERY_THROW ); + xTocProps->setPropertyValue("IsProtected", uno::Any( false ) ); + + uno::Reference< word::XTableOfContents > xToc( new SwVbaTableOfContents( this, mxContext, mxTextDocument, xDocumentIndex ) ); + + sal_Int32 nLowerHeadingLevel = 9; + if( LowerHeadingLevel.hasValue() ) + LowerHeadingLevel >>= nLowerHeadingLevel; + xToc->setLowerHeadingLevel( nLowerHeadingLevel ); + + bool bUseFields = false; + if( UseFields.hasValue() ) + UseFields >>= bUseFields; + xToc->setUseFields( bUseFields ); + + xToc->setUseOutlineLevels( true ); + + SwVbaRange* pVbaRange = dynamic_cast<SwVbaRange*>( Range.get() ); + if( !pVbaRange ) + throw uno::RuntimeException(); + + uno::Reference< text::XTextRange > xTextRange = pVbaRange->getXTextRange(); + uno::Reference< text::XText > xText = pVbaRange->getXText(); + uno::Reference< text::XTextContent > xTextContent( xDocumentIndex, uno::UNO_QUERY_THROW ); + xText->insertTextContent( xTextRange, xTextContent, false ); + xToc->Update(); + + return xToc; +} + +// XEnumerationAccess +uno::Type +SwVbaTablesOfContents::getElementType() +{ + return cppu::UnoType<word::XTableOfContents>::get(); +} +uno::Reference< container::XEnumeration > +SwVbaTablesOfContents::createEnumeration() +{ + return new TablesOfContentsEnumWrapper( m_xIndexAccess ); +} + +uno::Any +SwVbaTablesOfContents::createCollectionObject( const uno::Any& aSource ) +{ + return aSource; +} + +OUString +SwVbaTablesOfContents::getServiceImplName() +{ + return "SwVbaTablesOfContents"; +} + +uno::Sequence<OUString> +SwVbaTablesOfContents::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.TablesOfContents" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatablesofcontents.hxx b/sw/source/ui/vba/vbatablesofcontents.hxx new file mode 100644 index 0000000000..37048ae1bc --- /dev/null +++ b/sw/source/ui/vba/vbatablesofcontents.hxx @@ -0,0 +1,54 @@ +/* -*- 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_VBA_VBATABLESOFCONTENTS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBATABLESOFCONTENTS_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XTablesOfContents.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <ooo/vba/word/XTableOfContents.hpp> +#include <ooo/vba/word/XRange.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XTablesOfContents > SwVbaTablesOfContents_BASE; + +class SwVbaTablesOfContents : public SwVbaTablesOfContents_BASE +{ +private: + css::uno::Reference< css::text::XTextDocument > mxTextDocument; + +public: + /// @throws css::uno::RuntimeException + SwVbaTablesOfContents( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::text::XTextDocument >& xDoc ); + + // Methods + virtual css::uno::Reference< ::ooo::vba::word::XTableOfContents > SAL_CALL Add( const css::uno::Reference< ::ooo::vba::word::XRange >& Range, const css::uno::Any& UseHeadingStyles, const css::uno::Any& UpperHeadingLevel, const css::uno::Any& LowerHeadingLevel, const css::uno::Any& UseFields, const css::uno::Any& TableID, const css::uno::Any& RightAlignPageNumbers, const css::uno::Any& IncludePageNumbers, const css::uno::Any& AddedStyles, const css::uno::Any& UseHyperlinks, const css::uno::Any& HidePageNumbersInWeb, const css::uno::Any& UseOutlineLevels ) override; + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaTablesOfContents_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBATABLESOFCONTENTS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatabstop.cxx b/sw/source/ui/vba/vbatabstop.cxx new file mode 100644 index 0000000000..8ebfdfa421 --- /dev/null +++ b/sw/source/ui/vba/vbatabstop.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 "vbatabstop.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaTabStop::SwVbaTabStop( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext ) : SwVbaTabStop_BASE( rParent, rContext ) +{ +} + +SwVbaTabStop::~SwVbaTabStop() +{ +} + +OUString +SwVbaTabStop::getServiceImplName() +{ + return "SwVbaTabStop"; +} + +uno::Sequence< OUString > +SwVbaTabStop::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.TabStop" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatabstop.hxx b/sw/source/ui/vba/vbatabstop.hxx new file mode 100644 index 0000000000..3be2c29e47 --- /dev/null +++ b/sw/source/ui/vba/vbatabstop.hxx @@ -0,0 +1,41 @@ +/* -*- 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_VBA_VBATABSTOP_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBATABSTOP_HXX + +#include <ooo/vba/word/XTabStop.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XTabStop> SwVbaTabStop_BASE; + +class SwVbaTabStop : public SwVbaTabStop_BASE +{ +public: + /// @throws css::uno::RuntimeException + SwVbaTabStop(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext); + virtual ~SwVbaTabStop() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBATABSTOP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatabstops.cxx b/sw/source/ui/vba/vbatabstops.cxx new file mode 100644 index 0000000000..7d2d86824a --- /dev/null +++ b/sw/source/ui/vba/vbatabstops.cxx @@ -0,0 +1,270 @@ +/* -*- 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 "vbatabstops.hxx" +#include "vbatabstop.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/style/TabAlign.hpp> +#include <com/sun/star/style/TabStop.hpp> +#include <ooo/vba/word/WdTabLeader.hpp> +#include <ooo/vba/word/WdTabAlignment.hpp> +#include <basic/sberrors.hxx> +#include <cppuhelper/implbase.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +/// @throws uno::RuntimeException +static uno::Sequence< style::TabStop > lcl_getTabStops( const uno::Reference< beans::XPropertySet >& xParaProps ) +{ + uno::Sequence< style::TabStop > aSeq; + xParaProps->getPropertyValue("ParaTabStops") >>= aSeq; + return aSeq; +} + +/// @throws uno::RuntimeException +static void lcl_setTabStops( const uno::Reference< beans::XPropertySet >& xParaProps, const uno::Sequence< style::TabStop >& aSeq ) +{ + xParaProps->setPropertyValue("ParaTabStops", uno::Any( aSeq ) ); +} + +namespace { + +class TabStopsEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference< container::XIndexAccess > mxIndexAccess; + sal_Int32 m_nIndex; + +public: + explicit TabStopsEnumWrapper( uno::Reference< container::XIndexAccess > xIndexAccess ) : mxIndexAccess(std::move( xIndexAccess )), m_nIndex( 0 ) + { + } + virtual sal_Bool SAL_CALL hasMoreElements( ) override + { + return ( m_nIndex < mxIndexAccess->getCount() ); + } + + virtual uno::Any SAL_CALL nextElement( ) override + { + if( m_nIndex < mxIndexAccess->getCount() ) + { + return mxIndexAccess->getByIndex( m_nIndex++ ); + } + throw container::NoSuchElementException(); + } +}; + +class TabStopCollectionHelper : public ::cppu::WeakImplHelper< container::XIndexAccess, + container::XEnumerationAccess > +{ +private: + uno::Reference< XHelperInterface > mxParent; + uno::Reference< uno::XComponentContext > mxContext; + sal_Int32 mnTabStops; + +public: + /// @throws css::uno::RuntimeException + TabStopCollectionHelper( css::uno::Reference< ov::XHelperInterface > xParent, css::uno::Reference< css::uno::XComponentContext > xContext, const css::uno::Reference< css::beans::XPropertySet >& xParaProps ): mxParent(std::move( xParent )), mxContext(std::move( xContext )), mnTabStops(lcl_getTabStops( xParaProps ).getLength()) + { + } + + virtual sal_Int32 SAL_CALL getCount( ) override + { + return mnTabStops; + } + virtual uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override + { + if ( Index < 0 || Index >= getCount() ) + throw css::lang::IndexOutOfBoundsException(); + + return uno::Any( uno::Reference< word::XTabStop >( new SwVbaTabStop( mxParent, mxContext ) ) ); + } + virtual uno::Type SAL_CALL getElementType( ) override + { + return cppu::UnoType<word::XTabStop>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + return true; + } + // XEnumerationAccess + virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override + { + return new TabStopsEnumWrapper( this ); + } +}; + +} + +SwVbaTabStops::SwVbaTabStops( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< beans::XPropertySet >& xParaProps ) : SwVbaTabStops_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( new TabStopCollectionHelper( xParent, xContext, xParaProps ) ) ), mxParaProps( xParaProps ) +{ +} + +uno::Reference< word::XTabStop > SAL_CALL SwVbaTabStops::Add( float Position, const uno::Any& Alignment, const uno::Any& Leader ) +{ + sal_Int32 nPosition = Millimeter::getInHundredthsOfOneMillimeter( Position ); + + style::TabAlign nAlign = style::TabAlign_LEFT; + if( Alignment.hasValue() ) + { + sal_Int32 wdAlign = word::WdTabAlignment::wdAlignTabLeft; + Alignment >>= wdAlign; + switch( wdAlign ) + { + case word::WdTabAlignment::wdAlignTabLeft: + { + nAlign = style::TabAlign_LEFT; + break; + } + case word::WdTabAlignment::wdAlignTabRight: + { + nAlign = style::TabAlign_RIGHT; + break; + } + case word::WdTabAlignment::wdAlignTabCenter: + { + nAlign = style::TabAlign_CENTER; + break; + } + case word::WdTabAlignment::wdAlignTabDecimal: + { + nAlign = style::TabAlign_DECIMAL; + break; + } + case word::WdTabAlignment::wdAlignTabBar: + case word::WdTabAlignment::wdAlignTabList: + { + DebugHelper::basicexception( ERRCODE_BASIC_NOT_IMPLEMENTED, {} ); + break; + } + default: + { + //left + } + } + } + + sal_Unicode cLeader = ' '; // default is space + if( Leader.hasValue() ) + { + sal_Int32 wdLeader = word::WdTabLeader::wdTabLeaderSpaces; + Leader >>= wdLeader; + switch( wdLeader ) + { + case word::WdTabLeader::wdTabLeaderSpaces: + { + cLeader = ' '; + break; + } + case word::WdTabLeader::wdTabLeaderMiddleDot: + { + cLeader = 183; // U+00B7 MIDDLE DOT + break; + } + case word::WdTabLeader::wdTabLeaderDots: + { + cLeader = '.'; + break; + } + case word::WdTabLeader::wdTabLeaderDashes: + case word::WdTabLeader::wdTabLeaderHeavy: + case word::WdTabLeader::wdTabLeaderLines: + { + cLeader = '_'; + break; + } + default: + { + //left + } + } + } + + style::TabStop aTab; + aTab.Position = nPosition; + aTab.Alignment = nAlign; + aTab.DecimalChar = '.'; // default value + aTab.FillChar = cLeader; + + uno::Sequence< style::TabStop > aOldTabs = lcl_getTabStops( mxParaProps ); + auto [begin, end] = asNonConstRange(aOldTabs); + + style::TabStop* pOldTab = std::find_if(begin, end, + [nPosition](const style::TabStop& rTab) { return rTab.Position == nPosition; }); + bool bOverWriter = pOldTab != end; + if( bOverWriter ) + { + *pOldTab = aTab; + lcl_setTabStops( mxParaProps, aOldTabs ); + } + else + { + sal_Int32 nTabs = aOldTabs.getLength(); + uno::Sequence< style::TabStop > aNewTabs( nTabs + 1 ); + + auto it = aNewTabs.getArray(); + *it = aTab; + std::copy(begin, end, std::next(it)); + lcl_setTabStops( mxParaProps, aNewTabs ); + } + + return uno::Reference< word::XTabStop >( new SwVbaTabStop( this, mxContext ) ); +} + +void SAL_CALL SwVbaTabStops::ClearAll() +{ + uno::Sequence< style::TabStop > aSeq; + lcl_setTabStops( mxParaProps, aSeq ); +} + +// XEnumerationAccess +uno::Type +SwVbaTabStops::getElementType() +{ + return cppu::UnoType<word::XTabStop>::get(); +} +uno::Reference< container::XEnumeration > +SwVbaTabStops::createEnumeration() +{ + return new TabStopsEnumWrapper( m_xIndexAccess ); +} + +uno::Any +SwVbaTabStops::createCollectionObject( const css::uno::Any& aSource ) +{ + return aSource; +} + +OUString +SwVbaTabStops::getServiceImplName() +{ + return "SwVbaTabStops"; +} + +css::uno::Sequence<OUString> +SwVbaTabStops::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.TabStops" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatabstops.hxx b/sw/source/ui/vba/vbatabstops.hxx new file mode 100644 index 0000000000..66a163d492 --- /dev/null +++ b/sw/source/ui/vba/vbatabstops.hxx @@ -0,0 +1,53 @@ +/* -*- 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_VBA_VBATABSTOPS_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBATABSTOPS_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XTabStops.hpp> +#include <ooo/vba/word/XTabStop.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XTabStops > SwVbaTabStops_BASE; + +class SwVbaTabStops : public SwVbaTabStops_BASE +{ +private: + css::uno::Reference< css::beans::XPropertySet > mxParaProps; + +public: + /// @throws css::uno::RuntimeException + SwVbaTabStops( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::beans::XPropertySet >& xParaProps ); + + // Methods + virtual css::uno::Reference< ::ooo::vba::word::XTabStop > SAL_CALL Add( float Position, const css::uno::Any& Alignment, const css::uno::Any& Leader ) override; + virtual void SAL_CALL ClearAll( ) override; + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaTabStops_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBATABSTOPS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatemplate.cxx b/sw/source/ui/vba/vbatemplate.cxx new file mode 100644 index 0000000000..f05b699187 --- /dev/null +++ b/sw/source/ui/vba/vbatemplate.cxx @@ -0,0 +1,129 @@ +/* -*- 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 "vbatemplate.hxx" +#include "vbaautotextentry.hxx" +#include <com/sun/star/text/AutoTextContainer.hpp> +#include <comphelper/processfactory.hxx> +#include <tools/urlobj.hxx> +#include <rtl/character.hxx> +#include <osl/file.hxx> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +static OUString lcl_CheckGroupName( std::u16string_view aGroupName ) +{ + OUStringBuffer sRet(aGroupName.size()); + //group name should contain only A-Z and a-z and spaces + for( size_t i = 0; i < aGroupName.size(); i++ ) + { + sal_Unicode cChar = aGroupName[i]; + if (rtl::isAsciiAlphanumeric(cChar) || + cChar == '_' || cChar == 0x20) + { + sRet.append(cChar); + } + } + sRet.strip(' '); + return sRet.makeStringAndClear(); +} + +SwVbaTemplate::SwVbaTemplate( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, OUString aFullUrl ) + : SwVbaTemplate_BASE( rParent, rContext ), msFullUrl(std::move( aFullUrl )) +{ +} + +SwVbaTemplate::~SwVbaTemplate() +{ +} + +OUString +SwVbaTemplate::getName() +{ + OUString sName; + if( !msFullUrl.isEmpty() ) + { + INetURLObject aURL( msFullUrl ); + ::osl::File::getSystemPathFromFileURL( aURL.GetLastName(), sName ); + } + return sName; +} + +OUString +SwVbaTemplate::getPath() +{ + OUString sPath; + if( !msFullUrl.isEmpty() ) + { + INetURLObject aURL( msFullUrl ); + OUString sURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ) ); + sURL = sURL.copy( 0, sURL.getLength() - aURL.GetLastName().getLength() - 1 ); + ::osl::File::getSystemPathFromFileURL( sURL, sPath ); + } + return sPath; +} + +uno::Any SAL_CALL +SwVbaTemplate::AutoTextEntries( const uno::Any& index ) +{ + uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); + uno::Reference< text::XAutoTextContainer2 > xAutoTextContainer = text::AutoTextContainer::create( xContext ); + + // the default template is "Normal.dot" in Word. + OUString sGroup("Normal"); + OUString sName = getName(); + sal_Int32 nIndex = sName.lastIndexOf( '.' ); + if( nIndex > 0 ) + { + sGroup = sName.copy( 0, sName.lastIndexOf( '.' ) ); + } + OUString sNewGroup = lcl_CheckGroupName( sGroup ); + + uno::Reference< container::XIndexAccess > xGroup; + if( !xAutoTextContainer->hasByName( sNewGroup ) ) + { + throw uno::RuntimeException("Auto Text Entry doesn't exist" ); + } + + xGroup.set( xAutoTextContainer->getByName( sNewGroup ), uno::UNO_QUERY_THROW ); + + uno::Reference< XCollection > xCol( new SwVbaAutoTextEntries( this, mxContext, xGroup ) ); + if( index.hasValue() ) + return xCol->Item( index, uno::Any() ); + return uno::Any( xCol ); +} + +OUString +SwVbaTemplate::getServiceImplName() +{ + return "SwVbaTemplate"; +} + +uno::Sequence< OUString > +SwVbaTemplate::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Template" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbatemplate.hxx b/sw/source/ui/vba/vbatemplate.hxx new file mode 100644 index 0000000000..146684b18c --- /dev/null +++ b/sw/source/ui/vba/vbatemplate.hxx @@ -0,0 +1,46 @@ +/* -*- 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_VBA_VBATEMPLATE_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBATEMPLATE_HXX + +#include <ooo/vba/word/XTemplate.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XTemplate > SwVbaTemplate_BASE; + +class SwVbaTemplate : public SwVbaTemplate_BASE +{ +private: + OUString msFullUrl; +public: + SwVbaTemplate( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, + OUString ); + virtual ~SwVbaTemplate() override; + + // XTemplate + virtual OUString SAL_CALL getName() override; + virtual OUString SAL_CALL getPath() override; + virtual css::uno::Any SAL_CALL AutoTextEntries( const css::uno::Any& index ) override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBATEMPLATE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbavariable.cxx b/sw/source/ui/vba/vbavariable.cxx new file mode 100644 index 0000000000..dea82686e1 --- /dev/null +++ b/sw/source/ui/vba/vbavariable.cxx @@ -0,0 +1,92 @@ +/* -*- 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 "vbavariable.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <utility> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaVariable::SwVbaVariable( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, + uno::Reference< beans::XPropertyAccess > xUserDefined, OUString aVariableName ) : + SwVbaVariable_BASE( rParent, rContext ), mxUserDefined(std::move( xUserDefined )), maVariableName(std::move( aVariableName )) +{ +} + +SwVbaVariable::~SwVbaVariable() +{ +} + +OUString SAL_CALL +SwVbaVariable::getName() +{ + return maVariableName; +} + +void SAL_CALL +SwVbaVariable::setName( const OUString& ) +{ + throw uno::RuntimeException(" Fail to set name" ); +} + +uno::Any SAL_CALL +SwVbaVariable::getValue() +{ + uno::Reference< beans::XPropertySet > xProp( mxUserDefined, uno::UNO_QUERY_THROW ); + return xProp->getPropertyValue( maVariableName ); +} + +void SAL_CALL +SwVbaVariable::setValue( const uno::Any& rValue ) +{ + // FIXME: fail to set the value if the new type of value is different from the original one. + uno::Reference< beans::XPropertySet > xProp( mxUserDefined, uno::UNO_QUERY_THROW ); + xProp->setPropertyValue( maVariableName, rValue ); +} + +sal_Int32 SAL_CALL +SwVbaVariable::getIndex() +{ + const uno::Sequence< beans::PropertyValue > props = mxUserDefined->getPropertyValues(); + auto pProp = std::find_if(props.begin(), props.end(), + [this](const beans::PropertyValue& rProp) { return rProp.Name == maVariableName; }); + if (pProp != props.end()) + return static_cast<sal_Int32>(std::distance(props.begin(), pProp)) + 1; + + return 0; +} + +OUString +SwVbaVariable::getServiceImplName() +{ + return "SwVbaVariable"; +} + +uno::Sequence< OUString > +SwVbaVariable::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Variable" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbavariable.hxx b/sw/source/ui/vba/vbavariable.hxx new file mode 100644 index 0000000000..6b3ab37c78 --- /dev/null +++ b/sw/source/ui/vba/vbavariable.hxx @@ -0,0 +1,53 @@ +/* -*- 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_VBA_VBAVARIABLE_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAVARIABLE_HXX + +#include <ooo/vba/word/XVariable.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/beans/XPropertyAccess.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XVariable > SwVbaVariable_BASE; + +class SwVbaVariable : public SwVbaVariable_BASE +{ +private: + css::uno::Reference< css::beans::XPropertyAccess > mxUserDefined; + OUString maVariableName; + +public: + /// @throws css::uno::RuntimeException + SwVbaVariable( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, + css::uno::Reference< css::beans::XPropertyAccess > xUserDefined, OUString aName ); + virtual ~SwVbaVariable() override; + + // XVariable + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName( const OUString& ) override; + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& rValue ) override; + virtual sal_Int32 SAL_CALL getIndex() override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAVARIABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbavariables.cxx b/sw/source/ui/vba/vbavariables.cxx new file mode 100644 index 0000000000..6505eb23e0 --- /dev/null +++ b/sw/source/ui/vba/vbavariables.cxx @@ -0,0 +1,95 @@ +/* -*- 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 "vbavariables.hxx" +#include "vbavariable.hxx" +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +/// @throws uno::RuntimeException +static uno::Reference< container::XIndexAccess > createVariablesAccess( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< beans::XPropertyAccess >& xUserDefined ) +{ + // FIXME: the performance is poor? + XNamedObjectCollectionHelper< word::XVariable >::XNamedVec aVariables; + const uno::Sequence< beans::PropertyValue > props = xUserDefined->getPropertyValues(); + sal_Int32 nCount = props.getLength(); + aVariables.reserve( nCount ); + std::transform(props.begin(), props.end(), std::back_inserter(aVariables), + [&xParent, &xContext, &xUserDefined](const beans::PropertyValue& rProp) -> uno::Reference< word::XVariable > { + return uno::Reference< word::XVariable > ( new SwVbaVariable( xParent, xContext, xUserDefined, rProp.Name ) ); }); + + uno::Reference< container::XIndexAccess > xVariables( new XNamedObjectCollectionHelper< word::XVariable >( std::move(aVariables) ) ); + return xVariables; +} + +SwVbaVariables::SwVbaVariables( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext > & xContext, const uno::Reference< beans::XPropertyAccess >& rUserDefined ): SwVbaVariables_BASE( xParent, xContext, createVariablesAccess( xParent, xContext, rUserDefined ) ), mxUserDefined( rUserDefined ) +{ +} +// XEnumerationAccess +uno::Type +SwVbaVariables::getElementType() +{ + return cppu::UnoType<word::XVariable>::get(); +} +uno::Reference< container::XEnumeration > +SwVbaVariables::createEnumeration() +{ + uno::Reference< container::XEnumerationAccess > xEnumerationAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); + return xEnumerationAccess->createEnumeration(); +} + +uno::Any +SwVbaVariables::createCollectionObject( const css::uno::Any& aSource ) +{ + return aSource; +} + +uno::Any SAL_CALL +SwVbaVariables::Add( const OUString& rName, const uno::Any& rValue ) +{ + uno::Any aValue; + if( rValue.hasValue() ) + aValue = rValue; + else + aValue <<= OUString(); + uno::Reference< beans::XPropertyContainer > xPropertyContainer( mxUserDefined, uno::UNO_QUERY_THROW ); + xPropertyContainer->addProperty( rName, beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::REMOVABLE, aValue ); + + return uno::Any( uno::Reference< word::XVariable >( new SwVbaVariable( getParent(), mxContext, mxUserDefined, rName ) ) ); +} + +OUString +SwVbaVariables::getServiceImplName() +{ + return "SwVbaVariables"; +} + +css::uno::Sequence<OUString> +SwVbaVariables::getServiceNames() +{ + static uno::Sequence< OUString > const sNames + { + "ooo.vba.word.Variables" + }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbavariables.hxx b/sw/source/ui/vba/vbavariables.hxx new file mode 100644 index 0000000000..639c54a33e --- /dev/null +++ b/sw/source/ui/vba/vbavariables.hxx @@ -0,0 +1,51 @@ +/* -*- 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_VBA_VBAVARIABLES_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAVARIABLES_HXX + +#include <vbahelper/vbacollectionimpl.hxx> +#include <ooo/vba/word/XVariables.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> + +typedef CollTestImplHelper< ooo::vba::word::XVariables > SwVbaVariables_BASE; + +class SwVbaVariables : public SwVbaVariables_BASE +{ +private: + css::uno::Reference< css::beans::XPropertyAccess > mxUserDefined; + +public: + SwVbaVariables( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::beans::XPropertyAccess >& rUserDefined ); + + // XEnumerationAccess + virtual css::uno::Type SAL_CALL getElementType() override; + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // SwVbaVariables_BASE + virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override; + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; + + // XVariables + virtual css::uno::Any SAL_CALL Add( const OUString& rName, const css::uno::Any& rValue ) override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAVARIABLES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaview.cxx b/sw/source/ui/vba/vbaview.cxx new file mode 100644 index 0000000000..822c4f93e5 --- /dev/null +++ b/sw/source/ui/vba/vbaview.cxx @@ -0,0 +1,399 @@ +/* -*- 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 "vbaview.hxx" +#include <utility> +#include <vbahelper/vbahelper.hxx> +#include <basic/sberrors.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/view/XViewSettingsSupplier.hpp> +#include <com/sun/star/text/XTextViewCursorSupplier.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/text/XFootnotesSupplier.hpp> +#include <com/sun/star/text/XEndnotesSupplier.hpp> +#include <com/sun/star/text/XPageCursor.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <ooo/vba/word/WdSpecialPane.hpp> +#include <ooo/vba/word/WdViewType.hpp> +#include <ooo/vba/word/WdSeekView.hpp> + +#include "wordvbahelper.hxx" +#include "vbaheaderfooterhelper.hxx" +#include <view.hxx> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +const sal_Int32 DEFAULT_BODY_DISTANCE = 500; + +SwVbaView::SwVbaView( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, + uno::Reference< frame::XModel > xModel ) : + SwVbaView_BASE( rParent, rContext ), mxModel(std::move( xModel )) +{ + uno::Reference< frame::XController > xController = mxModel->getCurrentController(); + + uno::Reference< text::XTextViewCursorSupplier > xTextViewCursorSupp( xController, uno::UNO_QUERY_THROW ); + mxViewCursor = xTextViewCursorSupp->getViewCursor(); + + uno::Reference< view::XViewSettingsSupplier > xViewSettingSupp( xController, uno::UNO_QUERY_THROW ); + mxViewSettings.set( xViewSettingSupp->getViewSettings(), uno::UNO_SET_THROW ); +} + +SwVbaView::~SwVbaView() +{ +} + +sal_Bool SwVbaView::getShowAll() +{ + bool bShowFormattingMarks = false; + mxViewSettings->getPropertyValue("ShowNonprintingCharacters") >>= bShowFormattingMarks; + return bShowFormattingMarks; +} + +void SwVbaView::setShowAll(sal_Bool bSet) +{ + mxViewSettings->setPropertyValue("ShowNonprintingCharacters", uno::Any(bSet)); +} + +::sal_Int32 SAL_CALL +SwVbaView::getSeekView() +{ + // FIXME: if the view cursor is in table, field, section and frame + // handle if the cursor is in table + uno::Reference< text::XText > xCurrentText = mxViewCursor->getText(); + uno::Reference< beans::XPropertySet > xCursorProps( mxViewCursor, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextContent > xTextContent; + while( xCursorProps->getPropertyValue("TextTable") >>= xTextContent ) + { + xCurrentText = xTextContent->getAnchor()->getText(); + xCursorProps.set( xCurrentText->createTextCursor(), uno::UNO_QUERY_THROW ); + } + uno::Reference< lang::XServiceInfo > xServiceInfo( xCurrentText, uno::UNO_QUERY_THROW ); + OUString aImplName = xServiceInfo->getImplementationName(); + if ( aImplName == "SwXBodyText" ) + { + return word::WdSeekView::wdSeekMainDocument; + } + else if ( aImplName == "SwXHeadFootText" ) + { + if( HeaderFooterHelper::isHeader( mxModel ) ) + { + if( HeaderFooterHelper::isFirstPageHeader( mxModel ) ) + return word::WdSeekView::wdSeekFirstPageHeader; + else if( HeaderFooterHelper::isEvenPagesHeader( mxModel ) ) + return word::WdSeekView::wdSeekEvenPagesHeader; + else + return word::WdSeekView::wdSeekPrimaryHeader; + } + else + { + if( HeaderFooterHelper::isFirstPageFooter( mxModel ) ) + return word::WdSeekView::wdSeekFirstPageFooter; + else if( HeaderFooterHelper::isEvenPagesFooter( mxModel ) ) + return word::WdSeekView::wdSeekEvenPagesFooter; + else + return word::WdSeekView::wdSeekPrimaryFooter; + } + } + else if ( aImplName == "SwXFootnote" ) + { + if( xServiceInfo->supportsService("com.sun.star.text.Endnote") ) + return word::WdSeekView::wdSeekEndnotes; + else + return word::WdSeekView::wdSeekFootnotes; + } + + return word::WdSeekView::wdSeekMainDocument; +} + +void SAL_CALL +SwVbaView::setSeekView( ::sal_Int32 _seekview ) +{ + // FIXME: save the current cursor position, if the cursor is in the main + // document, so we can jump back to this position, if the macro sets + // the ViewMode back to wdSeekMainDocument + + word::gotoSelectedObjectAnchor( mxModel ); + switch( _seekview ) + { + case word::WdSeekView::wdSeekFirstPageFooter: + case word::WdSeekView::wdSeekFirstPageHeader: + case word::WdSeekView::wdSeekCurrentPageFooter: + case word::WdSeekView::wdSeekCurrentPageHeader: + case word::WdSeekView::wdSeekPrimaryFooter: + case word::WdSeekView::wdSeekPrimaryHeader: + case word::WdSeekView::wdSeekEvenPagesFooter: + case word::WdSeekView::wdSeekEvenPagesHeader: + { + // need to test + mxViewCursor->gotoRange( getHFTextRange( _seekview ), false ); + break; + } + case word::WdSeekView::wdSeekFootnotes: + { + uno::Reference< text::XFootnotesSupplier > xFootnotesSupp( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xFootnotes( xFootnotesSupp->getFootnotes(), uno::UNO_SET_THROW ); + if( xFootnotes->getCount() > 0 ) + { + uno::Reference< text::XText > xText( xFootnotes->getByIndex(0), uno::UNO_QUERY_THROW ); + mxViewCursor->gotoRange( xText->getStart(), false ); + } + else + { + DebugHelper::runtimeexception( ERRCODE_BASIC_NO_ACTIVE_OBJECT ); + } + break; + } + case word::WdSeekView::wdSeekEndnotes: + { + uno::Reference< text::XEndnotesSupplier > xEndnotesSupp( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xEndnotes( xEndnotesSupp->getEndnotes(), uno::UNO_SET_THROW ); + if( xEndnotes->getCount() > 0 ) + { + uno::Reference< text::XText > xText( xEndnotes->getByIndex(0), uno::UNO_QUERY_THROW ); + mxViewCursor->gotoRange( xText->getStart(), false ); + } + else + { + DebugHelper::runtimeexception( ERRCODE_BASIC_NO_ACTIVE_OBJECT ); + } + break; + } + case word::WdSeekView::wdSeekMainDocument: + { + uno::Reference< text::XTextDocument > xTextDocument( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< text::XText > xText = xTextDocument->getText(); + mxViewCursor->gotoRange( word::getFirstObjectPosition( xText ), false ); + break; + } + } +} + +::sal_Int32 SAL_CALL +SwVbaView::getSplitSpecial() +{ + return word::WdSpecialPane::wdPaneNone; +} + +void SAL_CALL +SwVbaView::setSplitSpecial( ::sal_Int32/* _splitspecial */) +{ + // not support in Writer +} + +sal_Bool SAL_CALL +SwVbaView::getTableGridLines() +{ + bool bShowTableGridLine = false; + mxViewSettings->getPropertyValue("ShowTableBoundaries") >>= bShowTableGridLine; + return bShowTableGridLine; +} + +void SAL_CALL +SwVbaView::setTableGridLines( sal_Bool _tablegridlines ) +{ + mxViewSettings->setPropertyValue("ShowTableBoundaries", uno::Any( _tablegridlines ) ); +} + +::sal_Int32 SAL_CALL +SwVbaView::getType() +{ + // FIXME: handle wdPrintPreview type + bool bOnlineLayout = false; + mxViewSettings->getPropertyValue("ShowOnlineLayout") >>= bOnlineLayout; + return bOnlineLayout ? word::WdViewType::wdWebView : word::WdViewType::wdPrintView; +} + +void SAL_CALL +SwVbaView::setType( ::sal_Int32 _type ) +{ + // FIXME: handle wdPrintPreview type + switch( _type ) + { + case word::WdViewType::wdPrintView: + case word::WdViewType::wdNormalView: + { + mxViewSettings->setPropertyValue("ShowOnlineLayout", uno::Any( false ) ); + break; + } + case word::WdViewType::wdWebView: + { + mxViewSettings->setPropertyValue("ShowOnlineLayout", uno::Any( true ) ); + break; + } + case word::WdViewType::wdPrintPreview: + { + PrintPreviewHelper( uno::Any(),word::getView( mxModel ) ); + break; + } + default: + DebugHelper::runtimeexception( ERRCODE_BASIC_NOT_IMPLEMENTED ); + + } +} + +uno::Reference< text::XTextRange > SwVbaView::getHFTextRange( sal_Int32 nType ) +{ + mxModel->lockControllers(); + + OUString aPropIsOn; + OUString aPropIsShared; + OUString aPropBodyDistance; + OUString aPropText; + + switch( nType ) + { + case word::WdSeekView::wdSeekCurrentPageFooter: + case word::WdSeekView::wdSeekFirstPageFooter: + case word::WdSeekView::wdSeekPrimaryFooter: + case word::WdSeekView::wdSeekEvenPagesFooter: + { + aPropIsOn = "FooterIsOn"; + aPropIsShared = "FooterIsShared"; + aPropBodyDistance = "FooterBodyDistance"; + aPropText = "FooterText"; + break; + } + case word::WdSeekView::wdSeekCurrentPageHeader: + case word::WdSeekView::wdSeekFirstPageHeader: + case word::WdSeekView::wdSeekPrimaryHeader: + case word::WdSeekView::wdSeekEvenPagesHeader: + { + aPropIsOn = "HeaderIsOn"; + aPropIsShared = "HeaderIsShared"; + aPropBodyDistance = "HeaderBodyDistance"; + aPropText = "HeaderText"; + break; + } + } + + uno::Reference< text::XPageCursor > xPageCursor( mxViewCursor, uno::UNO_QUERY_THROW ); + + if( nType == word::WdSeekView::wdSeekFirstPageFooter + || nType == word::WdSeekView::wdSeekFirstPageHeader ) + { + xPageCursor->jumpToFirstPage(); + } + + uno::Reference< style::XStyle > xStyle; + uno::Reference< text::XText > xText; + switch( nType ) + { + case word::WdSeekView::wdSeekPrimaryFooter: + case word::WdSeekView::wdSeekPrimaryHeader: + case word::WdSeekView::wdSeekEvenPagesFooter: + case word::WdSeekView::wdSeekEvenPagesHeader: + { + // The primary header is the first header of the section. + // If the header is not shared between odd and even pages + // the odd page's header is the primary header. If the + // first page's header is different from the rest of the + // document, it is NOT the primary header ( the next primary + // header would be on page 3 ) + // The even pages' header is only available if the header is + // not shared and the current style is applied to a page with + // an even page number + uno::Reference< beans::XPropertySet > xCursorProps( mxViewCursor, uno::UNO_QUERY_THROW ); + OUString aPageStyleName; + xCursorProps->getPropertyValue("PageStyleName") >>= aPageStyleName; + if ( aPageStyleName == "First Page" ) + { + // go to the beginning of where the next style is used + bool hasNextPage = false; + xStyle = word::getCurrentPageStyle( mxModel ); + do + { + hasNextPage = xPageCursor->jumpToNextPage(); + } + while( hasNextPage && ( xStyle == word::getCurrentPageStyle( mxModel ) ) ); + + if( !hasNextPage ) + DebugHelper::basicexception( ERRCODE_BASIC_BAD_ACTION, {} ); + } + break; + } + default: + { + break; + } + } + + xStyle = word::getCurrentPageStyle( mxModel ); + uno::Reference< beans::XPropertySet > xPageProps( xStyle, uno::UNO_QUERY_THROW ); + bool isOn = false; + xPageProps->getPropertyValue( aPropIsOn ) >>= isOn; + bool isShared = false; + xPageProps->getPropertyValue( aPropIsShared ) >>= isShared; + if( !isOn ) + { + xPageProps->setPropertyValue( aPropIsOn, uno::Any( true ) ); + xPageProps->setPropertyValue( aPropBodyDistance, uno::Any( DEFAULT_BODY_DISTANCE ) ); + } + if( !isShared ) + { + OUString aTempPropText = aPropText; + if( nType == word::WdSeekView::wdSeekEvenPagesFooter + || nType == word::WdSeekView::wdSeekEvenPagesHeader ) + { + aTempPropText += "Left"; + } + else + { + aTempPropText += "Right"; + } + xText.set( xPageProps->getPropertyValue( aTempPropText), uno::UNO_QUERY_THROW ); + } + else + { + if( nType == word::WdSeekView::wdSeekEvenPagesFooter + || nType == word::WdSeekView::wdSeekEvenPagesHeader ) + { + DebugHelper::basicexception( ERRCODE_BASIC_BAD_ACTION, {} ); + } + xText.set( xPageProps->getPropertyValue( aPropText ), uno::UNO_QUERY_THROW ); + } + + mxModel->unlockControllers(); + if( !xText.is() ) + { + DebugHelper::basicexception( ERRCODE_BASIC_INTERNAL_ERROR, {} ); + } + uno::Reference< text::XTextRange > xTextRange = word::getFirstObjectPosition( xText ); + return xTextRange; +} + +OUString +SwVbaView::getServiceImplName() +{ + return "SwVbaView"; +} + +uno::Sequence< OUString > +SwVbaView::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.View" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaview.hxx b/sw/source/ui/vba/vbaview.hxx new file mode 100644 index 0000000000..66cd0db612 --- /dev/null +++ b/sw/source/ui/vba/vbaview.hxx @@ -0,0 +1,63 @@ +/* -*- 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 . + */ +#pragma once + +#include <ooo/vba/word/XView.hpp> +#include <vbahelper/vbahelperinterface.hxx> +#include <com/sun/star/text/XTextViewCursor.hpp> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XView > SwVbaView_BASE; + +class SwVbaView : public SwVbaView_BASE +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + css::uno::Reference< css::text::XTextViewCursor > mxViewCursor; + css::uno::Reference< css::beans::XPropertySet > mxViewSettings; + + /// @throws css::uno::RuntimeException + /// @throws css::script::BasicErrorException + css::uno::Reference< css::text::XTextRange > getHFTextRange( sal_Int32 nType ); + +public: + /// @throws css::uno::RuntimeException + SwVbaView( const css::uno::Reference< ooo::vba::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, + css::uno::Reference< css::frame::XModel > xModel ); + virtual ~SwVbaView() override; + + // XView + sal_Bool SAL_CALL getShowAll() override; + void SAL_CALL setShowAll(sal_Bool bSet) override; + virtual ::sal_Int32 SAL_CALL getSeekView() override; + virtual void SAL_CALL setSeekView( ::sal_Int32 _seekview ) override; + virtual ::sal_Int32 SAL_CALL getSplitSpecial() override; + virtual void SAL_CALL setSplitSpecial( ::sal_Int32 _splitspecial ) override; + virtual sal_Bool SAL_CALL getTableGridLines() override; + virtual void SAL_CALL setTableGridLines( sal_Bool _tablegridlines ) override; + virtual ::sal_Int32 SAL_CALL getType() override; + virtual void SAL_CALL setType( ::sal_Int32 _type ) override; + + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbawindow.cxx b/sw/source/ui/vba/vbawindow.cxx new file mode 100644 index 0000000000..9114f4b8d4 --- /dev/null +++ b/sw/source/ui/vba/vbawindow.cxx @@ -0,0 +1,179 @@ +/* -*- 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 <ooo/vba/word/WdWindowState.hpp> +#include <sal/log.hxx> +#include <sfx2/viewfrm.hxx> +#include <vcl/wrkwin.hxx> + +#include "vbawindow.hxx" +#include "vbadocument.hxx" +#include "vbaview.hxx" +#include "vbapanes.hxx" +#include "vbapane.hxx" +#include "wordvbahelper.hxx" +#include <view.hxx> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +SwVbaWindow::SwVbaWindow( + const uno::Reference< XHelperInterface >& xParent, + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< frame::XModel >& xModel, + const uno::Reference< frame::XController >& xController ) : + WindowImpl_BASE( xParent, xContext, xModel, xController ) +{ +} + +void +SwVbaWindow::Activate() +{ + rtl::Reference<SwVbaDocument> document( new SwVbaDocument(uno::Reference< XHelperInterface >( Application(), uno::UNO_QUERY_THROW ), mxContext, m_xModel) ); + + document->Activate(); +} + +void +SwVbaWindow::Close( const uno::Any& SaveChanges, const uno::Any& RouteDocument ) +{ + // FIXME: it is incorrect when there are more than 1 windows + rtl::Reference<SwVbaDocument> document( new SwVbaDocument(uno::Reference< XHelperInterface >( Application(), uno::UNO_QUERY_THROW ), mxContext, m_xModel) ); + uno::Any FileName; + document->Close(SaveChanges, FileName, RouteDocument ); +} + +uno::Any SAL_CALL +SwVbaWindow::getView() +{ + return uno::Any( uno::Reference< word::XView >( new SwVbaView( this, mxContext, m_xModel ) ) ); +} + +void SAL_CALL SwVbaWindow::setView( const uno::Any& _view ) +{ + sal_Int32 nType = 0; + if( _view >>= nType ) + { + rtl::Reference<SwVbaView> view( new SwVbaView(this, mxContext, m_xModel) ); + view->setType( nType ); + } +} + +uno::Any SAL_CALL +SwVbaWindow::getWindowState() +{ + sal_Int32 nwindowState = word::WdWindowState::wdWindowStateNormal; + SwView* pView = word::getView( m_xModel ); + SfxViewFrame& rViewFrame = pView->GetViewFrame(); + WorkWindow* pWork = static_cast<WorkWindow*>( rViewFrame.GetFrame().GetSystemWindow() ); + if ( pWork ) + { + if ( pWork -> IsMaximized()) + nwindowState = word::WdWindowState::wdWindowStateMaximize; + else if (pWork -> IsMinimized()) + nwindowState = word::WdWindowState::wdWindowStateMinimize; + } + return uno::Any( nwindowState ); +} + +void SAL_CALL +SwVbaWindow::setWindowState( const uno::Any& _windowstate ) +{ + sal_Int32 nwindowState = word::WdWindowState::wdWindowStateMaximize; + _windowstate >>= nwindowState; + SwView* pView = word::getView( m_xModel ); + SfxViewFrame& rViewFrame = pView->GetViewFrame(); + WorkWindow* pWork = static_cast<WorkWindow*>( rViewFrame.GetFrame().GetSystemWindow() ); + if ( pWork ) + { + if ( nwindowState == word::WdWindowState::wdWindowStateMaximize ) + pWork -> Maximize(); + else if (nwindowState == word::WdWindowState::wdWindowStateMinimize) + pWork -> Minimize(); + else if (nwindowState == word::WdWindowState::wdWindowStateNormal) + pWork -> Restore(); + else + SAL_WARN("sw.vba", "Unhandled window state " << nwindowState); + } +} + +OUString SAL_CALL +SwVbaWindow::getCaption() +{ + SwView* pView = word::getView( m_xModel ); + if( !pView ) + return ""; + + uno::Reference< css::beans::XPropertySet > xFrameProps( pView->GetViewFrame().GetFrame().GetFrameInterface()->getController()->getFrame(), uno::UNO_QUERY ); + if( !xFrameProps.is() ) + return ""; + + OUString sTitle; + xFrameProps->getPropertyValue( "Title" ) >>= sTitle; + + return sTitle; +} + +void SAL_CALL +SwVbaWindow::setCaption( const OUString& _caption ) +{ + SwView* pView = word::getView( m_xModel ); + if( !pView ) + return; + + uno::Reference< css::beans::XPropertySet > xFrameProps( pView->GetViewFrame().GetFrame().GetFrameInterface()->getController()->getFrame(), uno::UNO_QUERY ); + if( !xFrameProps.is() ) + return; + + xFrameProps->setPropertyValue( "Title", uno::Any( _caption ) ); +} + +uno::Any SAL_CALL +SwVbaWindow::Panes( const uno::Any& aIndex ) +{ + uno::Reference< XCollection > xPanes( new SwVbaPanes( this, mxContext, m_xModel ) ); + if( aIndex.getValueTypeClass() == uno::TypeClass_VOID ) + return uno::Any( xPanes ); + + return xPanes->Item( aIndex, uno::Any() ); +} + +uno::Any SAL_CALL +SwVbaWindow::ActivePane() +{ + return uno::Any( uno::Reference< word::XPane >( new SwVbaPane( this, mxContext, m_xModel ) ) ); +} + +OUString +SwVbaWindow::getServiceImplName() +{ + return "SwVbaWindow"; +} + +uno::Sequence< OUString > +SwVbaWindow::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.Window" + }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbawindow.hxx b/sw/source/ui/vba/vbawindow.hxx new file mode 100644 index 0000000000..ee435b1505 --- /dev/null +++ b/sw/source/ui/vba/vbawindow.hxx @@ -0,0 +1,59 @@ +/* -*- 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_VBA_VBAWINDOW_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAWINDOW_HXX +#include <cppuhelper/implbase.hxx> +#include <ooo/vba/word/XWindow.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <vbahelper/vbahelperinterface.hxx> +#include <vbahelper/vbawindowbase.hxx> + +typedef cppu::ImplInheritanceHelper< VbaWindowBase, ov::word::XWindow > WindowImpl_BASE; + +class SwVbaWindow : public WindowImpl_BASE +{ +public: + /// @throws css::uno::RuntimeException + SwVbaWindow( + const css::uno::Reference< ov::XHelperInterface >& xParent, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const css::uno::Reference< css::frame::XModel >& xModel, + const css::uno::Reference< css::frame::XController >& xController ); + + // Attributes + virtual css::uno::Any SAL_CALL getView() override; + virtual void SAL_CALL setView( const css::uno::Any& _view ) override; + virtual css::uno::Any SAL_CALL getWindowState() override; + virtual void SAL_CALL setWindowState( const css::uno::Any& _windowstate ) override; + virtual OUString SAL_CALL getCaption() override; + virtual void SAL_CALL setCaption( const OUString& _caption ) override; + // Methods + virtual void SAL_CALL Activate( ) override; + virtual void SAL_CALL Close( const css::uno::Any& SaveChanges, const css::uno::Any& RouteDocument ) override; + virtual css::uno::Any SAL_CALL Panes( const css::uno::Any& aIndex ) override; + virtual css::uno::Any SAL_CALL ActivePane() override; + // XHelperInterface + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAWINDOW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbawordbasic.cxx b/sw/source/ui/vba/vbawordbasic.cxx new file mode 100644 index 0000000000..f08ed4e0da --- /dev/null +++ b/sw/source/ui/vba/vbawordbasic.cxx @@ -0,0 +1,265 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column:100 -*- */ +/* + * 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 "vbaapplication.hxx" +#include "vbafilterpropsfromformat.hxx" +#include "vbamailmerge.hxx" +#include "vbawordbasic.hxx" + +#include <basic/sbx.hxx> +#include <basic/sbxvar.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> +#include <osl/file.hxx> +#include <sal/log.hxx> +#include <tools/urlobj.hxx> + +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/util/thePathSettings.hpp> +#include <ooo/vba/word/XBookmarks.hpp> +#include <ooo/vba/word/XDocuments.hpp> + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwWordBasic::SwWordBasic(SwVbaApplication* pApp) + : mpApp(pApp) +{ +} + +sal_Int32 SAL_CALL SwWordBasic::getMailMergeMainDocumentType() +{ + return SwVbaMailMerge::get(mpApp->getParent(), mpApp->getContext())->getMainDocumentType(); +} + +void SAL_CALL SwWordBasic::setMailMergeMainDocumentType(sal_Int32 _mailmergemaindocumenttype) +{ + SwVbaMailMerge::get(mpApp->getParent(), mpApp->getContext()) + ->setMainDocumentType(_mailmergemaindocumenttype); +} + +void SAL_CALL SwWordBasic::FileOpen(const OUString& Name, const uno::Any& ConfirmConversions, + const uno::Any& ReadOnly, const uno::Any& AddToMru, + const uno::Any& PasswordDoc, const uno::Any& PasswordDot, + const uno::Any& Revert, const uno::Any& WritePasswordDoc, + const uno::Any& WritePasswordDot) +{ + uno::Any aDocuments = mpApp->Documents(uno::Any()); + + uno::Reference<word::XDocuments> rDocuments; + + if (aDocuments >>= rDocuments) + rDocuments->Open(Name, ConfirmConversions, ReadOnly, AddToMru, PasswordDoc, PasswordDot, + Revert, WritePasswordDoc, WritePasswordDot, uno::Any(), uno::Any(), + uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any()); +} + +void SAL_CALL SwWordBasic::FileSave() +{ + uno::Reference<frame::XModel> xModel(mpApp->getCurrentDocument(), uno::UNO_SET_THROW); + dispatchRequests(xModel, ".uno:Save"); +} + +void SAL_CALL SwWordBasic::FileSaveAs( + const css::uno::Any& Name, const css::uno::Any& Format, const css::uno::Any& /*LockAnnot*/, + const css::uno::Any& /*Password*/, const css::uno::Any& /*AddToMru*/, + const css::uno::Any& /*WritePassword*/, const css::uno::Any& /*RecommendReadOnly*/, + const css::uno::Any& /*EmbedFonts*/, const css::uno::Any& /*NativePictureFormat*/, + const css::uno::Any& /*FormsData*/, const css::uno::Any& /*SaveAsAOCELetter*/) +{ + SAL_INFO("sw.vba", "WordBasic.FileSaveAs(Name:=" << Name << ",Format:=" << Format << ")"); + + uno::Reference<frame::XModel> xModel(mpApp->getCurrentDocument(), uno::UNO_SET_THROW); + + // Based on SwVbaDocument::SaveAs2000. + + OUString sFileName; + Name >>= sFileName; + + OUString sURL; + osl::FileBase::getFileURLFromSystemPath(sFileName, sURL); + + // Detect if there is no path then we need to use the current folder. + INetURLObject aURL(sURL); + sURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri); + if (sURL.isEmpty()) + { + // Need to add cur dir ( of this document ) or else the 'Work' dir + sURL = xModel->getURL(); + + if (sURL.isEmpty()) + { + // Not path available from 'this' document. Need to add the 'document'/work directory then. + // Based on SwVbaOptions::getValueEvent() + uno::Reference<util::XPathSettings> xPathSettings + = util::thePathSettings::get(comphelper::getProcessComponentContext()); + OUString sPathUrl; + xPathSettings->getPropertyValue("Work") >>= sPathUrl; + // Path could be a multipath, Microsoft doesn't support this feature in Word currently. + // Only the last path is from interest. + // No idea if this crack is relevant for WordBasic or not. + sal_Int32 nIndex = sPathUrl.lastIndexOf(';'); + if (nIndex != -1) + { + sPathUrl = sPathUrl.copy(nIndex + 1); + } + + aURL.SetURL(sPathUrl); + } + else + { + aURL.SetURL(sURL); + aURL.Append(sFileName); + } + sURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri); + } + sal_Int32 nFileFormat = word::WdSaveFormat::wdFormatDocument; + Format >>= nFileFormat; + + uno::Sequence aProps{ comphelper::makePropertyValue("FilterName", css::uno::Any()), + comphelper::makePropertyValue("FileName", sURL) }; + + setFilterPropsFromFormat(nFileFormat, aProps); + + dispatchRequests(xModel, ".uno:SaveAs", aProps); +} + +void SAL_CALL SwWordBasic::FileClose(const css::uno::Any& Save) +{ + uno::Reference<frame::XModel> xModel(mpApp->getCurrentDocument(), uno::UNO_SET_THROW); + + sal_Int16 nSave = 0; + if (Save.hasValue() && (Save >>= nSave) && (nSave == 0 || nSave == 1)) + FileSave(); + + // FIXME: Here I would much prefer to call VbaDocumentBase::Close() but not sure how to get at + // the VbaDocumentBase of the current document. (Probably it is easy and I haven't looked hard + // enough.) + // + // FIXME: Error handling. If there is no current document, return some kind of error? But for + // now, just ignore errors. This code is written to work for a very specific customer use case + // anyway, not for an arbitrary sequence of COM calls to the "VBA" API. + dispatchRequests(xModel, ".uno:CloseDoc"); +} + +void SAL_CALL SwWordBasic::ToolsOptionsView( + const css::uno::Any& DraftFont, const css::uno::Any& WrapToWindow, + const css::uno::Any& PicturePlaceHolders, const css::uno::Any& FieldCodes, + const css::uno::Any& BookMarks, const css::uno::Any& FieldShading, + const css::uno::Any& StatusBar, const css::uno::Any& HScroll, const css::uno::Any& VScroll, + const css::uno::Any& StyleAreaWidth, const css::uno::Any& Tabs, const css::uno::Any& Spaces, + const css::uno::Any& Paras, const css::uno::Any& Hyphens, const css::uno::Any& Hidden, + const css::uno::Any& ShowAll, const css::uno::Any& Drawings, const css::uno::Any& Anchors, + const css::uno::Any& TextBoundaries, const css::uno::Any& VRuler, + const css::uno::Any& Highlight) +{ + SAL_INFO("sw.vba", "WordBasic.ToolsOptionsView(" + "DraftFont:=" + << DraftFont << ", WrapToWindow:=" << WrapToWindow + << ", PicturePlaceHolders:=" << PicturePlaceHolders + << ", FieldCodes:=" << FieldCodes << ", BookMarks:=" << BookMarks + << ", FieldShading:=" << FieldShading << ", StatusBar:=" << StatusBar + << ", HScroll:=" << HScroll << ", VScroll:=" << VScroll + << ", StyleAreaWidth:=" << StyleAreaWidth << ", Tabs:=" << Tabs + << ", Spaces:=" << Spaces << ", Paras:=" << Paras + << ", Hyphens:=" << Hyphens << ", Hidden:=" << Hidden + << ", ShowAll:=" << ShowAll << ", Drawings:=" << Drawings + << ", Anchors:=" << Anchors << ", TextBoundaries:=" << TextBoundaries + << ", VRuler:=" << VRuler << ", Highlight:=" << Highlight << ")"); +} + +css::uno::Any SAL_CALL SwWordBasic::WindowName(const css::uno::Any& /*Number*/) +{ + return css::uno::Any(mpApp->getActiveSwVbaWindow()->getCaption()); +} + +css::uno::Any SAL_CALL SwWordBasic::ExistingBookmark(const OUString& Name) +{ + uno::Reference<word::XBookmarks> xBookmarks(mpApp->getActiveDocument()->Bookmarks(uno::Any()), + uno::UNO_QUERY); + return css::uno::Any(xBookmarks.is() && xBookmarks->Exists(Name)); +} + +void SAL_CALL SwWordBasic::MailMergeOpenDataSource( + const OUString& Name, const css::uno::Any& Format, const css::uno::Any& ConfirmConversions, + const css::uno::Any& ReadOnly, const css::uno::Any& LinkToSource, + const css::uno::Any& AddToRecentFiles, const css::uno::Any& PasswordDocument, + const css::uno::Any& PasswordTemplate, const css::uno::Any& Revert, + const css::uno::Any& WritePasswordDocument, const css::uno::Any& WritePasswordTemplate, + const css::uno::Any& Connection, const css::uno::Any& SQLStatement, + const css::uno::Any& SQLStatement1, const css::uno::Any& OpenExclusive, + const css::uno::Any& SubType) +{ + mpApp->getActiveDocument()->getMailMerge()->OpenDataSource( + Name, Format, ConfirmConversions, ReadOnly, LinkToSource, AddToRecentFiles, + PasswordDocument, PasswordTemplate, Revert, WritePasswordDocument, WritePasswordTemplate, + Connection, SQLStatement, SQLStatement1, OpenExclusive, SubType); +} + +css::uno::Any SAL_CALL SwWordBasic::AppMaximize(const css::uno::Any& WindowName, + const css::uno::Any& State) +{ + SAL_INFO("sw.vba", "WordBasic.AppMaximize( WindowName:=" << WindowName << ", State:=" << State); + + // FIXME: Implement if necessary + return css::uno::Any(sal_Int32(0)); +} + +css::uno::Any SAL_CALL SwWordBasic::DocMaximize(const css::uno::Any& State) +{ + SAL_INFO("sw.vba", "WordBasic.DocMaximize(State:=" << State << ")"); + + // FIXME: Implement if necessary + return css::uno::Any(sal_Int32(0)); +} + +void SAL_CALL SwWordBasic::AppShow(const css::uno::Any& WindowName) +{ + SAL_INFO("sw.vba", "WordBasic.AppShow(WindowName:=" << WindowName << ")"); + + // FIXME: Implement if necessary +} + +css::uno::Any SAL_CALL SwWordBasic::AppCount() +{ + SAL_INFO("sw.vba", "WordBasic.AppCount()"); + + // FIXME: Implement if necessary. Return a random number for now. + return css::uno::Any(sal_Int32(2)); +} + +void SAL_CALL SwWordBasic::MsgBox(const OUString& sPrompt) +{ + SbxArrayRef pArgs = new SbxArray; + SbxVariable* pVar = new SbxVariable(); + pVar->PutString(sPrompt); + pArgs->Put(pVar, 1); + + if (!executeRunTimeLibrary(u"MsgBox", pArgs.get())) + SAL_WARN("sw.vba", "failed to execute runtime library function MsgBox (" << sPrompt << ")"); +} + +void SAL_CALL SwWordBasic::ScreenUpdating(const uno::Any& On) +{ + sal_Int32 nOn; + if (On >>= nOn) + mpApp->setScreenUpdating(nOn != 0); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbawordbasic.hxx b/sw/source/ui/vba/vbawordbasic.hxx new file mode 100644 index 0000000000..05589f0c58 --- /dev/null +++ b/sw/source/ui/vba/vbawordbasic.hxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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_VBA_VBAWORDBASIC_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAWORDBASIC_HXX + +class SwVbaApplication; + +/** + * This is a representation of the WordBasic statements and functions + * that were available in Word version 6.0 and Word for Windows 95. + * + * It can be specified as "Application.WordBasic." or "WordBasic.". + * + * Starting with Word 2000, old macros were automatically converted + * into Visual Basic modules, and the WordBasic prefix was added where + * no VBA methods precisely corresponded. + * + * In other words, it is a compatibility shim. + */ +class SwWordBasic : public cppu::WeakImplHelper<ooo::vba::word::XWordBasic> +{ +private: + SwVbaApplication* mpApp; + +public: + SwWordBasic(SwVbaApplication* pApp); + + // XWordBasic + virtual sal_Int32 SAL_CALL getMailMergeMainDocumentType() override; + virtual void SAL_CALL + setMailMergeMainDocumentType(sal_Int32 _mailmergemaindocumenttype) override; + + virtual void SAL_CALL FileOpen(const OUString& Name, const css::uno::Any& ConfirmConversions, + const css::uno::Any& ReadOnly, const css::uno::Any& AddToMru, + const css::uno::Any& PasswordDoc, + const css::uno::Any& PasswordDot, const css::uno::Any& Revert, + const css::uno::Any& WritePasswordDoc, + const css::uno::Any& WritePasswordDot) override; + virtual void SAL_CALL FileSave() override; + virtual void SAL_CALL FileSaveAs( + const css::uno::Any& Name, const css::uno::Any& Format, const css::uno::Any& LockAnnot, + const css::uno::Any& Password, const css::uno::Any& AddToMru, + const css::uno::Any& WritePassword, const css::uno::Any& RecommendReadOnly, + const css::uno::Any& EmbedFonts, const css::uno::Any& NativePictureFormat, + const css::uno::Any& FormsData, const css::uno::Any& SaveAsAOCELetter) override; + virtual void SAL_CALL FileClose(const css::uno::Any& Save) override; + virtual void SAL_CALL ToolsOptionsView( + const css::uno::Any& DraftFont, const css::uno::Any& WrapToWindow, + const css::uno::Any& PicturePlaceHolders, const css::uno::Any& FieldCodes, + const css::uno::Any& BookMarks, const css::uno::Any& FieldShading, + const css::uno::Any& StatusBar, const css::uno::Any& HScroll, const css::uno::Any& VScroll, + const css::uno::Any& StyleAreaWidth, const css::uno::Any& Tabs, const css::uno::Any& Spaces, + const css::uno::Any& Paras, const css::uno::Any& Hyphens, const css::uno::Any& Hidden, + const css::uno::Any& ShowAll, const css::uno::Any& Drawings, const css::uno::Any& Anchors, + const css::uno::Any& TextBoundaries, const css::uno::Any& VRuler, + const css::uno::Any& Highlight) override; + virtual css::uno::Any SAL_CALL WindowName(const css::uno::Any& Number) override; + virtual css::uno::Any SAL_CALL ExistingBookmark(const OUString& Name) override; + virtual void SAL_CALL MailMergeOpenDataSource( + const OUString& Name, const css::uno::Any& Format, const css::uno::Any& ConfirmConversions, + const css::uno::Any& ReadOnly, const css::uno::Any& LinkToSource, + const css::uno::Any& AddToRecentFiles, const css::uno::Any& PasswordDocument, + const css::uno::Any& PasswordTemplate, const css::uno::Any& Revert, + const css::uno::Any& WritePasswordDocument, const css::uno::Any& WritePasswordTemplate, + const css::uno::Any& Connection, const css::uno::Any& SQLStatement, + const css::uno::Any& SQLStatement1, const css::uno::Any& OpenExclusive, + const css::uno::Any& SubType) override; + virtual css::uno::Any SAL_CALL AppMaximize(const css::uno::Any& WindowName, + const css::uno::Any& State) override; + virtual css::uno::Any SAL_CALL DocMaximize(const css::uno::Any& State) override; + virtual void SAL_CALL AppShow(const css::uno::Any& WindowName) override; + virtual css::uno::Any SAL_CALL AppCount() override; + virtual void SAL_CALL MsgBox(const OUString& sPrompt) override; + virtual void SAL_CALL ScreenUpdating(const css::uno::Any& On) override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAWORDBASIC_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbawrapformat.cxx b/sw/source/ui/vba/vbawrapformat.cxx new file mode 100644 index 0000000000..2aef0523b4 --- /dev/null +++ b/sw/source/ui/vba/vbawrapformat.cxx @@ -0,0 +1,243 @@ +/* -*- 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 <sal/config.h> + +#include "vbawrapformat.hxx" +#include <ooo/vba/word/WdWrapSideType.hpp> +#include <ooo/vba/word/WdWrapType.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <basic/sberrors.hxx> +#include <vbahelper/vbahelper.hxx> + +using namespace ooo::vba; +using namespace com::sun::star; + +SwVbaWrapFormat::SwVbaWrapFormat( uno::Sequence< uno::Any > const& aArgs, uno::Reference< uno::XComponentContext >const& xContext ) : SwVbaWrapFormat_BASE( getXSomethingFromArgs< XHelperInterface >( aArgs, 0 ), xContext ), m_xShape( getXSomethingFromArgs< drawing::XShape >( aArgs, 1, false ) ), mnWrapFormatType( 0 ), mnSide( word::WdWrapSideType::wdWrapBoth ) +{ + m_xPropertySet.set( m_xShape, uno::UNO_QUERY_THROW ); +} + +void SwVbaWrapFormat::makeWrap() +{ + text::WrapTextMode eTextMode = text::WrapTextMode_NONE; + if( mnSide == word::WdWrapSideType::wdWrapLeft ) + { + eTextMode = text::WrapTextMode_LEFT; + } + else if( mnSide == word::WdWrapSideType::wdWrapRight ) + { + eTextMode = text::WrapTextMode_RIGHT; + } + else if( mnSide == word::WdWrapSideType::wdWrapBoth || + mnSide == word::WdWrapSideType::wdWrapLargest ) + { + switch( mnWrapFormatType ) + { + case word::WdWrapType::wdWrapNone: + case word::WdWrapType::wdWrapThrough: + { + eTextMode = text::WrapTextMode_THROUGH; + break; + } + case word::WdWrapType::wdWrapInline: + case word::WdWrapType::wdWrapTopBottom: + { + eTextMode = text::WrapTextMode_NONE; + break; + } + case word::WdWrapType::wdWrapSquare: + { + eTextMode = text::WrapTextMode_PARALLEL; + m_xPropertySet->setPropertyValue("SurroundContour", uno::Any( false ) ); + break; + } + case word::WdWrapType::wdWrapTight: + { + eTextMode = text::WrapTextMode_PARALLEL; + m_xPropertySet->setPropertyValue("SurroundContour", uno::Any( true ) ); + break; + } + default: + { + DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_ARGUMENT); + } + } + } + m_xPropertySet->setPropertyValue("TextWrap", uno::Any( eTextMode ) ); +} + +::sal_Int32 SAL_CALL SwVbaWrapFormat::getType() +{ + sal_Int32 nType = word::WdWrapType::wdWrapSquare; + text::WrapTextMode eTextMode; + m_xPropertySet->getPropertyValue("TextWrap") >>= eTextMode; + switch( eTextMode ) + { + case text::WrapTextMode_NONE: + { + nType = word::WdWrapType::wdWrapTopBottom; + break; + } + case text::WrapTextMode_THROUGH: + { + nType = word::WdWrapType::wdWrapNone; + break; + } + case text::WrapTextMode_PARALLEL: + { + bool bContour = false; + m_xPropertySet->getPropertyValue("SurroundContour") >>= bContour; + if( bContour ) + nType = word::WdWrapType::wdWrapTight; + else + nType = word::WdWrapType::wdWrapSquare; + break; + } + case text::WrapTextMode_DYNAMIC: + case text::WrapTextMode_LEFT: + case text::WrapTextMode_RIGHT: + { + nType = word::WdWrapType::wdWrapThrough; + break; + } + default: + { + nType = word::WdWrapType::wdWrapSquare; + } + } + return nType; +} + +void SAL_CALL SwVbaWrapFormat::setType( ::sal_Int32 _type ) +{ + mnWrapFormatType = _type; + makeWrap(); +} + +::sal_Int32 SAL_CALL SwVbaWrapFormat::getSide() +{ + sal_Int32 nSide = word::WdWrapSideType::wdWrapBoth; + text::WrapTextMode eTextMode; + m_xPropertySet->getPropertyValue("TextWrap") >>= eTextMode; + switch( eTextMode ) + { + case text::WrapTextMode_LEFT: + { + nSide = word::WdWrapSideType::wdWrapLeft; + break; + } + case text::WrapTextMode_RIGHT: + { + nSide = word::WdWrapSideType::wdWrapRight; + break; + } + default: + { + nSide = word::WdWrapSideType::wdWrapBoth; + } + } + return nSide; +} + +void SAL_CALL SwVbaWrapFormat::setSide( ::sal_Int32 _side ) +{ + mnSide = _side; + makeWrap(); +} + +float SwVbaWrapFormat::getDistance( const OUString& sName ) +{ + sal_Int32 nDistance = 0; + m_xPropertySet->getPropertyValue( sName ) >>= nDistance; + return static_cast< float >( Millimeter::getInPoints( nDistance ) ); +} + +void SwVbaWrapFormat::setDistance( const OUString& sName, float _distance ) +{ + sal_Int32 nDistance = Millimeter::getInHundredthsOfOneMillimeter( _distance ); + m_xPropertySet->setPropertyValue( sName, uno::Any( nDistance ) ); +} + +float SAL_CALL SwVbaWrapFormat::getDistanceTop() +{ + return getDistance( "TopMargin" ); +} + +void SAL_CALL SwVbaWrapFormat::setDistanceTop( float _distancetop ) +{ + setDistance( "TopMargin", _distancetop ); +} + +float SAL_CALL SwVbaWrapFormat::getDistanceBottom() +{ + return getDistance( "BottomMargin" ); +} + +void SAL_CALL SwVbaWrapFormat::setDistanceBottom( float _distancebottom ) +{ + setDistance( "BottomMargin", _distancebottom ); +} + +float SAL_CALL SwVbaWrapFormat::getDistanceLeft() +{ + return getDistance( "LeftMargin" ); +} + +void SAL_CALL SwVbaWrapFormat::setDistanceLeft( float _distanceleft ) +{ + setDistance( "LeftMargin", _distanceleft ); +} + +float SAL_CALL SwVbaWrapFormat::getDistanceRight() +{ + return getDistance( "RightMargin" ); +} + +void SAL_CALL SwVbaWrapFormat::setDistanceRight( float _distanceright ) +{ + setDistance( "RightMargin", _distanceright ); +} + +OUString +SwVbaWrapFormat::getServiceImplName() +{ + return "SwVbaWrapFormat"; +} + +uno::Sequence< OUString > +SwVbaWrapFormat::getServiceNames() +{ + static uno::Sequence< OUString > const aServiceNames + { + "ooo.vba.word.WrapFormat" + }; + return aServiceNames; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Writer_SwVbaWrapFormat_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args) +{ + return cppu::acquire(new SwVbaWrapFormat(args, context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbawrapformat.hxx b/sw/source/ui/vba/vbawrapformat.hxx new file mode 100644 index 0000000000..ef28118ed9 --- /dev/null +++ b/sw/source/ui/vba/vbawrapformat.hxx @@ -0,0 +1,66 @@ +/* -*- 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_VBA_VBAWRAPFORMAT_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_VBAWRAPFORMAT_HXX + +#include <com/sun/star/drawing/XShape.hpp> +#include <ooo/vba/word/XWrapFormat.hpp> +#include <vbahelper/vbahelperinterface.hxx> + +typedef InheritedHelperInterfaceWeakImpl< ooo::vba::word::XWrapFormat > SwVbaWrapFormat_BASE; + +class SwVbaWrapFormat : public SwVbaWrapFormat_BASE +{ +private: + css::uno::Reference< css::drawing::XShape > m_xShape; + css::uno::Reference< css::beans::XPropertySet > m_xPropertySet; + sal_Int32 mnWrapFormatType; + sal_Int32 mnSide; + +private: + /// @throws css::uno::RuntimeException + void makeWrap(); + /// @throws css::uno::RuntimeException + float getDistance( const OUString& sName ); + /// @throws css::uno::RuntimeException + void setDistance( const OUString& sName, float _distance ); + +public: + SwVbaWrapFormat( css::uno::Sequence< css::uno::Any > const& aArgs, css::uno::Reference< css::uno::XComponentContext >const& xContext ); + + virtual ::sal_Int32 SAL_CALL getType() override; + virtual void SAL_CALL setType( ::sal_Int32 _type ) override; + virtual ::sal_Int32 SAL_CALL getSide() override; + virtual void SAL_CALL setSide( ::sal_Int32 _side ) override; + virtual float SAL_CALL getDistanceTop() override; + virtual void SAL_CALL setDistanceTop( float _distancetop ) override; + virtual float SAL_CALL getDistanceBottom() override; + virtual void SAL_CALL setDistanceBottom( float _distancebottom ) override; + virtual float SAL_CALL getDistanceLeft() override; + virtual void SAL_CALL setDistanceLeft( float _distanceleft ) override; + virtual float SAL_CALL getDistanceRight() override; + virtual void SAL_CALL setDistanceRight( float _distanceright ) override; + + virtual OUString getServiceImplName() override; + virtual css::uno::Sequence<OUString> getServiceNames() override; +}; + +#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAWRAPFORMAT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/wordvbahelper.cxx b/sw/source/ui/vba/wordvbahelper.cxx new file mode 100644 index 0000000000..5bf7e26c77 --- /dev/null +++ b/sw/source/ui/vba/wordvbahelper.cxx @@ -0,0 +1,176 @@ +/* -*- 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 <docsh.hxx> +#include "wordvbahelper.hxx" +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/text/XTextViewCursorSupplier.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <unotxdoc.hxx> +#include <doc.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <view.hxx> +#include <viewsh.hxx> +#include <comphelper/servicehelper.hxx> + +using namespace ::com::sun::star; +using namespace ::ooo::vba; + +namespace ooo::vba::word +{ + +SwDocShell* getDocShell( const uno::Reference< frame::XModel>& xModel ) +{ + uno::Reference< lang::XUnoTunnel > xTunnel( xModel, uno::UNO_QUERY_THROW ); + SwXTextDocument* pXDoc = comphelper::getFromUnoTunnel<SwXTextDocument>(xTunnel); + return pXDoc ? pXDoc->GetDocShell() : nullptr; +} + +SwView* getView( const uno::Reference< frame::XModel>& xModel ) +{ + SwDocShell* pDocShell = getDocShell( xModel ); + return pDocShell? pDocShell->GetView() : nullptr; +} + +uno::Reference< text::XTextViewCursor > getXTextViewCursor( const uno::Reference< frame::XModel >& xModel ) +{ + uno::Reference< frame::XController > xController = xModel->getCurrentController(); + uno::Reference< text::XTextViewCursorSupplier > xTextViewCursorSupp( xController, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextViewCursor > xTextViewCursor = xTextViewCursorSupp->getViewCursor(); + return xTextViewCursor; +} + +uno::Reference< style::XStyle > getCurrentPageStyle( const uno::Reference< frame::XModel >& xModel ) +{ + uno::Reference< beans::XPropertySet > xCursorProps( getXTextViewCursor( xModel ), uno::UNO_QUERY_THROW ); + return getCurrentPageStyle( xModel, xCursorProps ); +} + +uno::Reference< style::XStyle > getCurrentPageStyle( const uno::Reference< frame::XModel >& xModel, const uno::Reference< beans::XPropertySet >& xProps ) +{ + OUString aPageStyleName; + xProps->getPropertyValue("PageStyleName") >>= aPageStyleName; + uno::Reference< style::XStyleFamiliesSupplier > xSytleFamSupp( xModel, uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xSytleFamNames( xSytleFamSupp->getStyleFamilies(), uno::UNO_SET_THROW ); + uno::Reference< container::XNameAccess > xPageStyles( xSytleFamNames->getByName("PageStyles"), uno::UNO_QUERY_THROW ); + uno::Reference< style::XStyle > xStyle( xPageStyles->getByName( aPageStyleName ), uno::UNO_QUERY_THROW ); + + return xStyle; +} + +sal_Int32 getPageCount( const uno::Reference< frame::XModel>& xModel ) +{ + SwDocShell* pDocShell = getDocShell( xModel ); + SwViewShell* pViewSh = pDocShell ? pDocShell->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell() : nullptr; + return pViewSh ? pViewSh->GetPageCount() : 0; +} + +uno::Reference< style::XStyle > getDefaultParagraphStyle( const uno::Reference< frame::XModel >& xModel ) +{ + uno::Reference< style::XStyleFamiliesSupplier > xSytleFamSupp( xModel, uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xSytleFamNames( xSytleFamSupp->getStyleFamilies(), uno::UNO_SET_THROW ); + uno::Reference< container::XNameAccess > xParaStyles( xSytleFamNames->getByName("ParagraphStyles"), uno::UNO_QUERY_THROW ); + uno::Reference< style::XStyle > xStyle( xParaStyles->getByName("Standard"), uno::UNO_QUERY_THROW ); + + return xStyle; +} + +uno::Reference< text::XTextRange > getFirstObjectPosition( const uno::Reference< text::XText >& xText ) +{ + // if the first object is table, get the position of first cell + uno::Reference< text::XTextRange > xTextRange; + uno::Reference< container::XEnumerationAccess > xParaAccess( xText, uno::UNO_QUERY_THROW ); + uno::Reference< container::XEnumeration> xParaEnum = xParaAccess->createEnumeration(); + if( xParaEnum->hasMoreElements() ) + { + uno::Reference< lang::XServiceInfo > xServiceInfo( xParaEnum->nextElement(), uno::UNO_QUERY_THROW ); + if( xServiceInfo->supportsService("com.sun.star.text.TextTable") ) + { + uno::Reference< table::XCellRange > xCellRange( xServiceInfo, uno::UNO_QUERY_THROW ); + uno::Reference< text::XText> xFirstCellText( xCellRange->getCellByPosition(0, 0), uno::UNO_QUERY_THROW ); + xTextRange = xFirstCellText->getStart(); + } + } + if( !xTextRange.is() ) + xTextRange = xText->getStart(); + return xTextRange; +} + +uno::Reference< text::XText > getCurrentXText( const uno::Reference< frame::XModel >& xModel ) +{ + uno::Reference< text::XTextRange > xTextRange; + uno::Reference< text::XTextContent > xTextContent( xModel->getCurrentSelection(), uno::UNO_QUERY ); + if( !xTextContent.is() ) + { + uno::Reference< container::XIndexAccess > xIndexAccess( xModel->getCurrentSelection(), uno::UNO_QUERY ); + if( xIndexAccess.is() ) + { + xTextContent.set( xIndexAccess->getByIndex(0), uno::UNO_QUERY ); + } + } + + if( xTextContent.is() ) + xTextRange = xTextContent->getAnchor(); + + if( !xTextRange.is() ) + xTextRange.set( getXTextViewCursor( xModel ), uno::UNO_QUERY_THROW ); + + uno::Reference< text::XText > xText; + try + { + xText = xTextRange->getText(); + } + catch (const uno::RuntimeException&) + { + //catch exception "no text selection" + } + uno::Reference< beans::XPropertySet > xVCProps( xTextRange, uno::UNO_QUERY_THROW ); + while( xVCProps->getPropertyValue("TextTable") >>= xTextContent ) + { + xText = xTextContent->getAnchor()->getText(); + xVCProps.set( xText->createTextCursor(), uno::UNO_QUERY_THROW ); + } + + if( !xText.is() ) + throw uno::RuntimeException("no text selection" ); + + return xText; +} + +bool gotoSelectedObjectAnchor( const uno::Reference< frame::XModel>& xModel ) +{ + bool isObjectSelected = false; + uno::Reference< text::XTextContent > xTextContent( xModel->getCurrentSelection(), uno::UNO_QUERY ); + if( xTextContent.is() ) + { + uno::Reference< text::XTextRange > xTextRange( xTextContent->getAnchor(), uno::UNO_SET_THROW ); + uno::Reference< view::XSelectionSupplier > xSelectSupp( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); + xSelectSupp->select( uno::Any( xTextRange ) ); + isObjectSelected = true; + } + return isObjectSelected; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/wordvbahelper.hxx b/sw/source/ui/vba/wordvbahelper.hxx new file mode 100644 index 0000000000..ba8f77885c --- /dev/null +++ b/sw/source/ui/vba/wordvbahelper.hxx @@ -0,0 +1,63 @@ +/* -*- 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_VBA_WORDVBAHELPER_HXX +#define INCLUDED_SW_SOURCE_UI_VBA_WORDVBAHELPER_HXX + +#include <vbahelper/vbahelper.hxx> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XTextViewCursor.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +class SwDocShell; +class SwView; +namespace ooo::vba::word + { + //css::uno::Reference< css::frame::XModel > getCurrentDocument() throw (css::uno::RuntimeException); + SwDocShell* getDocShell( const css::uno::Reference< css::frame::XModel>& xModel ); + SwView* getView( const css::uno::Reference< css::frame::XModel>& xModel ); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::text::XTextViewCursor > getXTextViewCursor( const css::uno::Reference< css::frame::XModel >& xModel ); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::style::XStyle > getCurrentPageStyle( const css::uno::Reference< css::frame::XModel >& xModel ); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::style::XStyle > getCurrentPageStyle( const css::uno::Reference< css::frame::XModel>& xModel, const css::uno::Reference< css::beans::XPropertySet >& xProps ); + /// @throws css::uno::RuntimeException + sal_Int32 getPageCount( const css::uno::Reference< css::frame::XModel>& xModel ); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::style::XStyle > getDefaultParagraphStyle( const css::uno::Reference< css::frame::XModel >& xModel ); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::text::XTextRange > getFirstObjectPosition( const css::uno::Reference< css::text::XText >& xText ); + /// @throws css::uno::RuntimeException + css::uno::Reference< css::text::XText > getCurrentXText( const css::uno::Reference< css::frame::XModel>& xModel ); + /// @throws css::uno::RuntimeException + bool gotoSelectedObjectAnchor( const css::uno::Reference< css::frame::XModel>& xModel ); + + enum E_DIRECTION + { + MOVE_LEFT = 1, + MOVE_RIGHT, + MOVE_UP, + MOVE_DOWN + }; + +} // ooo::vba::word +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |