include/xmloff/xmltoken.hxx | 1 offapi/com/sun/star/text/textfield/PageCuontRange.idl | 40 ++++ officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu | 8 schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng | 11 + sw/inc/cmdid.h | 1 sw/inc/docufld.hxx | 13 - sw/inc/strings.hrc | 1 sw/inc/swabstdlg.hxx | 1 sw/inc/unocoll.hxx | 2 sw/inc/unoprnms.hxx | 1 sw/qa/extras/odfexport/data/tdf71583.odt |binary sw/qa/extras/odfexport/odfexport2.cxx | 10 + sw/qa/extras/uiwriter/uiwriter9.cxx | 83 ++++++++ sw/sdi/_textsh.sdi | 16 + sw/sdi/swriter.sdi | 34 +++ sw/source/core/doc/DocumentFieldsManager.cxx | 11 + sw/source/core/doc/fmtcol.cxx | 3 sw/source/core/fields/docufld.cxx | 66 +++++- sw/source/core/inc/frame.hxx | 1 sw/source/core/layout/trvlfrm.cxx | 100 ++++++---- sw/source/core/text/txtfld.cxx | 6 sw/source/core/unocore/unocoll.cxx | 4 sw/source/core/unocore/unofield.cxx | 7 sw/source/ui/dialog/swdlgfact.cxx | 5 sw/source/ui/dialog/swdlgfact.hxx | 1 sw/source/ui/misc/pagenumberdlg.cxx | 19 + sw/source/uibase/docvw/HeaderFooterWin.cxx | 5 sw/source/uibase/fldui/fldmgr.cxx | 1 sw/source/uibase/inc/pagenumberdlg.hxx | 3 sw/source/uibase/shells/textfld.cxx | 13 - sw/uiconfig/sglobal/popupmenu/insertfield.xml | 1 sw/uiconfig/swform/popupmenu/insertfield.xml | 1 sw/uiconfig/swreport/popupmenu/insertfield.xml | 1 sw/uiconfig/swriter/popupmenu/insertfield.xml | 1 sw/uiconfig/swriter/ui/hfmenubutton.ui | 10 - sw/uiconfig/swriter/ui/pagenumberdlg.ui | 26 ++ sw/uiconfig/swxform/popupmenu/insertfield.xml | 1 xmloff/inc/txtflde.hxx | 5 xmloff/source/core/xmltoken.cxx | 1 xmloff/source/text/txtflde.cxx | 30 ++- xmloff/source/text/txtfldi.cxx | 4 xmloff/source/token/tokens.txt | 1 42 files changed, 487 insertions(+), 62 deletions(-)
New commits: commit 6bee59854b7deddc1c76f339f93974131e6701e7 Author: Oliver Specht <oliver.spe...@cib.de> AuthorDate: Mon Dec 9 13:10:22 2024 +0100 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Sat Mar 8 14:59:31 2025 +0100 tdf#71583 Add page count of ranges with consecutive page numbering Adds a field that counts the pages in ranges defined by page number restarts Change-Id: Ie0727ab20c81464918ad5fb9aa42046bf00aa63c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/178714 Tested-by: allotropia jenkins <jenk...@allotropia.de> Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de> diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index e3b54f961206..1a17b9176d9d 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -1484,6 +1484,7 @@ namespace xmloff::token { XML_PAGE_CONTENT, XML_PAGE_CONTINUATION_STRING, XML_PAGE_COUNT, + XML_PAGE_COUNT_RANGE, XML_PAGE_END_MARGIN, XML_PAGE_HEIGHT, XML_PAGE_MASTER, diff --git a/offapi/com/sun/star/text/textfield/PageCuontRange.idl b/offapi/com/sun/star/text/textfield/PageCuontRange.idl new file mode 100755 index 000000000000..0a74540082c6 --- /dev/null +++ b/offapi/com/sun/star/text/textfield/PageCuontRange.idl @@ -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 . + */ + + +module com { module sun { module star { module text { module textfield { + +/** specifies service of a text field that displays the number of pages + in the current range of pages with consecutive page numbering + @see com::sun::star::text::TextField +*/ +published service PageCountRange +{ + service com::sun::star::text::TextField; + + /** specifies the type of the numbering as + com::sun::star::style::NumberingType + */ + [property]short NumberingType; +}; + + +}; }; }; }; }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu index 0db0891e8594..67c0b473f7ab 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu @@ -1158,6 +1158,14 @@ <value>1</value> </prop> </node> + <node oor:name=".uno:InsertPageCountInRangeField" oor:op="replace"> + <prop oor:name="Label" oor:type="xs:string"> + <value xml:lang="en-US">Page Count In ~Range</value> + </prop> + <prop oor:name="Properties" oor:type="xs:int"> + <value>1</value> + </prop> + </node> <node oor:name=".uno:InsertTopicField" oor:op="replace"> <prop oor:name="Label" oor:type="xs:string"> <value xml:lang="en-US">~Subject</value> diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng index c9d41d0778cd..779b502ae3ef 100644 --- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng @@ -3973,4 +3973,15 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. </rng:attribute> </rng:optional> </rng:define> + + <!-- tdf#71583 --> + <rng:define name="paragraph-content" combine="choice"> + <rng:element> + <rng:choice> + <rng:name>loext:page-count-range</rng:name> + </rng:choice> + <rng:ref name="common-field-num-format-attlist"/> + <rng:text/> + </rng:element> + </rng:define> </rng:grammar> diff --git a/sw/inc/cmdid.h b/sw/inc/cmdid.h index 6f5ea775dfa0..a53633b46e0f 100644 --- a/sw/inc/cmdid.h +++ b/sw/inc/cmdid.h @@ -335,6 +335,7 @@ class SwUINumRuleItem; #define FN_DELETE_BOOKMARKS (FN_INSERT2 + 39) #define FN_DELETE_FIELDS (FN_INSERT2 + 40) #define FN_DELETE_SECTIONS (FN_INSERT2 + 41) +#define FN_INSERT_FLD_RANGE_PGCOUNT (FN_INSERT2 + 43) /*insert field page count in range*/ // Region: Format #define FN_AUTOFORMAT_APPLY (FN_FORMAT + 1 ) /* apply autoformat options */ diff --git a/sw/inc/docufld.hxx b/sw/inc/docufld.hxx index 71096d5758b0..8369afaf5653 100644 --- a/sw/inc/docufld.hxx +++ b/sw/inc/docufld.hxx @@ -52,12 +52,14 @@ enum SwDocStatSubType { DS_BEGIN, DS_PAGE = DS_BEGIN, + // page count in current range + DS_PAGE_RANGE, DS_PARA, DS_WORD, DS_CHAR, DS_TBL, DS_GRF, - DS_OLE, + DS_OLE }; typedef sal_uInt16 SwDocInfoSubType; @@ -256,21 +258,24 @@ class SAL_DLLPUBLIC_RTTI SwDocStatFieldType final : public SwFieldType public: SwDocStatFieldType(SwDoc&); - OUString Expand(sal_uInt16 nSubType, SvxNumType nFormat) const; + OUString Expand(sal_uInt16 nSubType, SvxNumType nFormat, + sal_uInt16 nVirtPageCount) const; virtual std::unique_ptr<SwFieldType> Copy() const override; void SetNumFormat( SvxNumType eFormat ) { m_nNumberingType = eFormat; } + void UpdateRangeFields(SwRootFrame const*const pLayout); }; class SW_DLLPUBLIC SwDocStatField final : public SwField { sal_uInt16 m_nSubType; + sal_uInt16 m_nVirtPageCount; public: SwDocStatField( SwDocStatFieldType*, - sal_uInt16 nSubType, sal_uInt32 nFormat); + sal_uInt16 nSubType, sal_uInt32 nFormat, sal_uInt16 nVirtPageCount = 0); - void ChangeExpansion( const SwFrame* pFrame ); + void ChangeExpansion( const SwFrame* pFrame, sal_uInt16 nVirtPageCount); virtual OUString ExpandImpl(SwRootFrame const* pLayout) const override; virtual std::unique_ptr<SwField> Copy() const override; diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc index 2d21be7daedc..07e5f2b8fc55 100644 --- a/sw/inc/strings.hrc +++ b/sw/inc/strings.hrc @@ -977,6 +977,7 @@ #define FLD_STAT_GRF NC_("FLD_STAT_GRF", "Image") #define FLD_STAT_OBJ NC_("FLD_STAT_OBJ", "OLE objects") #define FLD_STAT_PAGE NC_("FLD_STAT_PAGE", "Pages") +#define FLD_STAT_PAGE_SECTION NC_("FLD_STAT_PAGE", "Pages in range") // SubCmd DDETypes #define FMT_DDE_HOT NC_("FMT_DDE_HOT", "DDE automatic") #define FMT_DDE_NORMAL NC_("FMT_DDE_NORMAL", "DDE manual") diff --git a/sw/inc/swabstdlg.hxx b/sw/inc/swabstdlg.hxx index 2426e5f25e16..327421466233 100644 --- a/sw/inc/swabstdlg.hxx +++ b/sw/inc/swabstdlg.hxx @@ -241,6 +241,7 @@ public: virtual int GetPageNumberAlignment() const = 0; virtual bool GetMirrorOnEvenPages() const = 0; virtual bool GetIncludePageTotal() const = 0; + virtual bool GetIncludePageRangeTotal() const = 0; virtual SvxNumType GetPageNumberType() const = 0; virtual void SetPageNumberType(SvxNumType nSet) = 0; }; diff --git a/sw/inc/unocoll.hxx b/sw/inc/unocoll.hxx index 0ecca6fb45c2..898b8f122ffa 100644 --- a/sw/inc/unocoll.hxx +++ b/sw/inc/unocoll.hxx @@ -126,6 +126,7 @@ enum class SwServiceType { FieldTypeDocInfoDescription = 59, FieldTypeDocInfoCreateAuthor = 60, FieldTypeDocInfoCreateDateTime = 61, + FieldTypePageCountRange = 62, FieldTypeDummy1 = 63, FieldTypeDummy2 = 64, FieldTypeDummy3 = 65, @@ -215,6 +216,7 @@ enum class SwServiceType { #define CSS_TEXT_TEXTFIELD_DATABASE_NAME "com.sun.star.text.textfield.DatabaseName" #define CSS_TEXT_TEXTFIELD_TABLE_FORMULA "com.sun.star.text.textfield.TableFormula" #define CSS_TEXT_TEXTFIELD_PAGE_COUNT "com.sun.star.text.textfield.PageCount" +#define CSS_TEXT_TEXTFIELD_PAGE_COUNT_RANGE "com.sun.star.text.textfield.PageCountRange" #define CSS_TEXT_TEXTFIELD_PARAGRAPH_COUNT "com.sun.star.text.textfield.ParagraphCount" #define CSS_TEXT_TEXTFIELD_WORD_COUNT "com.sun.star.text.textfield.WordCount" #define CSS_TEXT_TEXTFIELD_CHARACTER_COUNT "com.sun.star.text.textfield.CharacterCount" diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx index 836294a98a3f..c16ba484c57e 100644 --- a/sw/inc/unoprnms.hxx +++ b/sw/inc/unoprnms.hxx @@ -306,6 +306,7 @@ inline constexpr OUString UNO_NAME_NUMBERING_TYPE = u"NumberingType"_ustr; inline constexpr OUString UNO_NAME_OFFSET = u"Offset"_ustr; inline constexpr OUString UNO_NAME_ON = u"On"_ustr; inline constexpr OUString UNO_NAME_OPAQUE = u"Opaque"_ustr; +inline constexpr OUString UNO_NAME_PAGE_COUNT_RANGE = u"PageCountRange"_ustr; inline constexpr OUString UNO_NAME_PAGE_TOGGLE = u"PageToggle"_ustr; inline constexpr OUString UNO_NAME_PAGE_DESC_NAME = u"PageDescName"_ustr; inline constexpr OUString UNO_NAME_PAGE_NUMBER_OFFSET = u"PageNumberOffset"_ustr; diff --git a/sw/qa/extras/odfexport/data/tdf71583.odt b/sw/qa/extras/odfexport/data/tdf71583.odt new file mode 100644 index 000000000000..034d4fa536c8 Binary files /dev/null and b/sw/qa/extras/odfexport/data/tdf71583.odt differ diff --git a/sw/qa/extras/odfexport/odfexport2.cxx b/sw/qa/extras/odfexport/odfexport2.cxx index 219561f30287..98dcee80ffb8 100644 --- a/sw/qa/extras/odfexport/odfexport2.cxx +++ b/sw/qa/extras/odfexport/odfexport2.cxx @@ -1754,6 +1754,16 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf163703) CPPUNIT_ASSERT_EQUAL(css::awt::FontSlant_NONE, getProperty<css::awt::FontSlant>(x3rdRun, u"CharPosture"_ustr)); } + +CPPUNIT_TEST_FIXTURE(Test, testTdf71583) +{ + // Verifies that loext:text-indent correctly round-trips + loadAndReload("tdf71583.odt"); + xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr); + assertXPathNodeName(pXmlDoc, "//office:body/office:text/text:p/*[1]", + "page-count-range"); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/qa/extras/uiwriter/uiwriter9.cxx b/sw/qa/extras/uiwriter/uiwriter9.cxx index c8d145e3a034..23285b2c8788 100644 --- a/sw/qa/extras/uiwriter/uiwriter9.cxx +++ b/sw/qa/extras/uiwriter/uiwriter9.cxx @@ -19,11 +19,13 @@ #include <com/sun/star/awt/FontSlant.hpp> #include <com/sun/star/table/TableBorder2.hpp> #include <com/sun/star/text/XDocumentIndex.hpp> +#include <com/sun/star/text/XTextField.hpp> #include <com/sun/star/text/XTextFrame.hpp> #include <com/sun/star/text/XTextTable.hpp> #include <com/sun/star/text/XTextViewCursorSupplier.hpp> #include <com/sun/star/text/XPageCursor.hpp> #include <com/sun/star/text/XParagraphCursor.hpp> + #include <com/sun/star/view/XSelectionSupplier.hpp> #include <comphelper/lok.hxx> @@ -889,6 +891,87 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf162195) xTables->getAnchor()->getString()); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf71583) +{ + //create a document, multiple pages, some restart page counting + // insert page count in range fields and check the calculated + // values + + auto insertParagraphAndBreak = [](sal_Int32& nParagraph, SwWrtShell& rWrtSh, + uno::Reference<lang::XComponent> xComponent, + const sal_uInt16 nPages) { + for (sal_uInt16 nPage = 0; nPage < nPages; ++nPage) + { + rWrtSh.Insert(u"Paragraph "_ustr); + rWrtSh.Insert(OUString::number(nParagraph)); + ++nParagraph; + auto xModel(xComponent.queryThrow<frame::XModel>()); + auto xFactory(xComponent.queryThrow<lang::XMultiServiceFactory>()); + auto xTextViewCursorSupplier( + xModel->getCurrentController().queryThrow<text::XTextViewCursorSupplier>()); + auto xTextRangeCursor( + xTextViewCursorSupplier->getViewCursor().queryThrow<text::XTextRange>()); + + uno::Reference<text::XTextField> xTextField( + xFactory->createInstance(u"com.sun.star.text.TextField.PageCountRange"_ustr), + uno::UNO_QUERY); + xTextRangeCursor->getText()->insertTextContent(xTextRangeCursor, xTextField, false); + + rWrtSh.SttEndDoc(false); + rWrtSh.SplitNode(); + if (nPage < nPages - 1) + rWrtSh.InsertPageBreak(); + else + { + std::optional<sal_uInt16> oPageNumber = 1; + OUString sPageStyle(u"Default Page Style"_ustr); + rWrtSh.InsertPageBreak(&sPageStyle, oPageNumber); + } + } + }; + + auto checkDocument = [this]() { + auto checkFieldContent = [this](uno::Reference<text::XText>& xBodyText, sal_uInt16 nPara, + rtl::OUString sSymbol) { + uno::Reference<text::XTextRange> xPara(getParagraphOfText(nPara, xBodyText)); + const uno::Reference<text::XTextRange> xRun = getRun(xPara, 2); + uno::Reference<text::XTextField> xTextField + = getProperty<uno::Reference<text::XTextField>>(xRun, u"TextField"_ustr); + OUString sPresentation = xTextField->getPresentation(false); + CPPUNIT_ASSERT_EQUAL(sSymbol, sPresentation); + }; + + auto xModel(mxComponent.queryThrow<text::XTextDocument>()); + uno::Reference<text::XText> xBodyText = xModel->getText(); + OUString sCompare = u"B"_ustr; + + for (sal_uInt16 nPara = 1; nPara < 25; nPara += 2) + { + if (nPara == 5) + sCompare = u"D"_ustr; + if (nPara == 13) + sCompare = u"F"_ustr; + checkFieldContent(xBodyText, nPara, sCompare); + } + }; + createSwDoc(); + SwWrtShell* pWrtShell = nullptr; + { + pWrtShell = getSwDocShell()->GetWrtShell(); + CPPUNIT_ASSERT(pWrtShell); + + sal_Int32 nParagraph = 0; + for (int i = 1; i <= 3; ++i) + insertParagraphAndBreak(nParagraph, *pWrtShell, mxComponent, i * 2); + checkDocument(); + } + + { + saveAndReload(u"writer8"_ustr); + checkDocument(); + } +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/sdi/_textsh.sdi b/sw/sdi/_textsh.sdi index 9c30229795a4..7834d019e17a 100644 --- a/sw/sdi/_textsh.sdi +++ b/sw/sdi/_textsh.sdi @@ -956,6 +956,22 @@ interface BaseText ReadOnlyDoc = FALSE ; ] + FN_INSERT_FLD_RANGE_PGCOUNT + [ + ExecMethod = ExecField ; + StateMethod = StateField ; + DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; + ReadOnlyDoc = FALSE ; + ] + + FN_INSERT_FLD_RANGE_PGCOUNT + [ + ExecMethod = ExecField ; + StateMethod = StateField ; + DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; + ReadOnlyDoc = FALSE ; + ] + FN_INSERT_FLD_TITLE [ ExecMethod = ExecField ; diff --git a/sw/sdi/swriter.sdi b/sw/sdi/swriter.sdi index d6e0e703fb8b..6f6f619a17b4 100644 --- a/sw/sdi/swriter.sdi +++ b/sw/sdi/swriter.sdi @@ -3443,6 +3443,40 @@ SfxVoidItem InsertPageCountField FN_INSERT_FLD_PGCOUNT GroupId = SfxGroupId::Insert; ] +SfxVoidItem InsertPageCountInRangeField FN_INSERT_FLD_RANGE_PGCOUNT +() +[ + AutoUpdate = FALSE, + FastCall = FALSE, + ReadOnlyDoc = FALSE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + + AccelConfig = TRUE, + MenuConfig = TRUE, + ToolBoxConfig = TRUE, + GroupId = SfxGroupId::Insert; +] + +SfxVoidItem InsertPageCountInRangeField FN_INSERT_FLD_RANGE_PGCOUNT +() +[ + AutoUpdate = FALSE, + FastCall = FALSE, + ReadOnlyDoc = FALSE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + + AccelConfig = TRUE, + MenuConfig = TRUE, + ToolBoxConfig = TRUE, + GroupId = SfxGroupId::Insert; +] + SfxObjectShellItem InsertPageFooter FN_INSERT_PAGEFOOTER (SfxStringItem PageStyle FN_INSERT_PAGEFOOTER,SfxBoolItem On FN_PARAM_1) [ diff --git a/sw/source/core/doc/DocumentFieldsManager.cxx b/sw/source/core/doc/DocumentFieldsManager.cxx index a5594aa1f86d..2b17d85e27e2 100644 --- a/sw/source/core/doc/DocumentFieldsManager.cxx +++ b/sw/source/core/doc/DocumentFieldsManager.cxx @@ -1281,8 +1281,17 @@ void DocumentFieldsManager::UpdatePageFields(const SwTwips nDocPos) pFieldType->UpdateDocPos(nDocPos); break; case SwFieldIds::DocStat: + { pFieldType->CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr)); - break; + SwRootFrame const* pLayout(nullptr); + for (SwRootFrame const*const pLay : m_rDoc.GetAllLayouts()) + { + if (!pLay->IsHideRedlines()) + pLayout = pLay; + } + static_cast<SwDocStatFieldType*>(pFieldType)->UpdateRangeFields(pLayout); + } + break; case SwFieldIds::GetRef: static_cast<SwGetRefFieldType*>(pFieldType)->UpdateStyleReferences(); // Style references can vary across different pages (e.g. in header/footer) diff --git a/sw/source/core/doc/fmtcol.cxx b/sw/source/core/doc/fmtcol.cxx index f3523a544e97..408b282f217d 100644 --- a/sw/source/core/doc/fmtcol.cxx +++ b/sw/source/core/doc/fmtcol.cxx @@ -133,7 +133,8 @@ void SwTextFormatColl::SwClientNotify(const SwModify& rModify, const SfxHint& rH CallSwClientNotify(rHint); return; } - else if (rHint.GetId() == SfxHintId::SwVirtPageNumHint) + else if (rHint.GetId() == SfxHintId::SwVirtPageNumHint)// || + //rHint.GetId() == SfxHintId::SwVirtPageCountHint) { CallSwClientNotify(rHint); return; diff --git a/sw/source/core/fields/docufld.cxx b/sw/source/core/fields/docufld.cxx index 376820d45d76..cf70bbe29e36 100644 --- a/sw/source/core/fields/docufld.cxx +++ b/sw/source/core/fields/docufld.cxx @@ -733,7 +733,8 @@ SwDocStatFieldType::SwDocStatFieldType(SwDoc& rDocument) { } -OUString SwDocStatFieldType::Expand(sal_uInt16 nSubType, SvxNumType nFormat) const +OUString SwDocStatFieldType::Expand(sal_uInt16 nSubType, + SvxNumType nFormat, sal_uInt16 nVirtPageCount) const { sal_uInt32 nVal = 0; const SwDocStat& rDStat = m_rDoc.getIDocumentStatistics().GetDocStat(); @@ -752,6 +753,11 @@ OUString SwDocStatFieldType::Expand(sal_uInt16 nSubType, SvxNumType nFormat) con if( SVX_NUM_PAGEDESC == nFormat ) nFormat = m_nNumberingType; break; + case DS_PAGE_RANGE: + nVal = nVirtPageCount; + if( SVX_NUM_PAGEDESC == nFormat ) + nFormat = m_nNumberingType; + break; default: OSL_FAIL( "SwDocStatFieldType::Expand: unknown SubType" ); } @@ -766,26 +772,56 @@ std::unique_ptr<SwFieldType> SwDocStatFieldType::Copy() const { return std::make_unique<SwDocStatFieldType>(m_rDoc); } +void SwDocStatFieldType::UpdateRangeFields(SwRootFrame const*const pLayout) +{ + std::vector<SwFormatField*> vFields; + GatherFields(vFields); + for(auto pFormatField: vFields) + { + SwDocStatField* pDocStatField = static_cast<SwDocStatField*>(pFormatField->GetField()); + if (pDocStatField->GetSubType() == DS_PAGE_RANGE) + { + SwTextField* pTField = pFormatField->GetTextField(); + const SwTextNode& rTextNd = pTField->GetTextNode(); + // Always the first! (in Tab-Headline, header/footer ) + Point aPt; + std::pair<Point, bool> const tmp(aPt, false); + const SwContentFrame *const pFrame = rTextNd.getLayoutFrame( + pLayout, nullptr, &tmp); + + if (pFrame && + pFrame->IsInDocBody() && + pFrame->FindPageFrame()) + { + pDocStatField->ChangeExpansion(pFrame, pFrame->GetVirtPageCount()); + } + } + } +} /** * @param pTyp * @param nSub SubType * @param nFormat */ -SwDocStatField::SwDocStatField(SwDocStatFieldType* pTyp, sal_uInt16 nSub, sal_uInt32 nFormat) +SwDocStatField::SwDocStatField(SwDocStatFieldType* pTyp, sal_uInt16 nSub, + sal_uInt32 nFormat, sal_uInt16 nVirtPageCount) : SwField(pTyp, nFormat), - m_nSubType(nSub) -{} + m_nSubType(nSub), + m_nVirtPageCount(nVirtPageCount) +{ +} OUString SwDocStatField::ExpandImpl(SwRootFrame const*const) const { - return static_cast<SwDocStatFieldType*>(GetTyp())->Expand(m_nSubType, static_cast<SvxNumType>(GetFormat())); + return static_cast<SwDocStatFieldType*>(GetTyp()) + ->Expand(m_nSubType, static_cast<SvxNumType>(GetFormat()), m_nVirtPageCount); } std::unique_ptr<SwField> SwDocStatField::Copy() const { return std::make_unique<SwDocStatField>( - static_cast<SwDocStatFieldType*>(GetTyp()), m_nSubType, GetFormat() ); + static_cast<SwDocStatFieldType*>(GetTyp()), m_nSubType, GetFormat(), m_nVirtPageCount ); } sal_uInt16 SwDocStatField::GetSubType() const @@ -798,11 +834,13 @@ void SwDocStatField::SetSubType(sal_uInt16 nSub) m_nSubType = nSub; } -void SwDocStatField::ChangeExpansion( const SwFrame* pFrame ) +void SwDocStatField::ChangeExpansion(const SwFrame* pFrame, sal_uInt16 nVirtPageCount) { if( DS_PAGE == m_nSubType && SVX_NUM_PAGEDESC == GetFormat() ) static_cast<SwDocStatFieldType*>(GetTyp())->SetNumFormat( pFrame->FindPageFrame()->GetPageDesc()->GetNumType().GetNumberingType() ); + else if (nVirtPageCount && DS_PAGE_RANGE == m_nSubType) + m_nVirtPageCount = nVirtPageCount; } bool SwDocStatField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const @@ -812,6 +850,9 @@ bool SwDocStatField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const case FIELD_PROP_USHORT2: rAny <<= static_cast<sal_Int16>(GetFormat()); break; + case FIELD_PROP_USHORT1: + rAny <<= static_cast<sal_Int32>(m_nVirtPageCount); + break; default: assert(false); @@ -837,6 +878,17 @@ bool SwDocStatField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId ) } } break; + case FIELD_PROP_USHORT1: + { + sal_Int32 nSet = 0; + rAny >>= nSet; + if (nSet >= 0 && nSet < USHRT_MAX) + { + m_nVirtPageCount = static_cast<sal_uInt16>(nSet); + bRet = true; + } + } + break; default: assert(false); diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx index f43a731244ea..5b4b662346ba 100644 --- a/sw/source/core/inc/frame.hxx +++ b/sw/source/core/inc/frame.hxx @@ -742,6 +742,7 @@ public: sal_uInt16 GetPhyPageNum() const; // page number without offset SW_DLLPUBLIC sal_uInt16 GetVirtPageNum() const; // page number with offset + SW_DLLPUBLIC sal_uInt16 GetVirtPageCount() const; // page count between offsets bool OnRightPage() const { return 0 != GetPhyPageNum() % 2; }; bool WannaRightPage() const; bool OnFirstPage() const; diff --git a/sw/source/core/layout/trvlfrm.cxx b/sw/source/core/layout/trvlfrm.cxx index 0b46e6553576..ba6fbde7ec1d 100644 --- a/sw/source/core/layout/trvlfrm.cxx +++ b/sw/source/core/layout/trvlfrm.cxx @@ -1859,6 +1859,31 @@ Point SwFrame::GetRelPos() const return aRet; } +static const SwFrame* lcl_FindStartOfVirtualPages(const SwPageFrame *pPage) +{ + const SwPageFrame* pPageFrameIter = pPage; + while (pPageFrameIter) + { + const SwContentFrame* pContentFrame = pPageFrameIter->FindFirstBodyContent(); + if (pContentFrame) + { + const SwFormatPageDesc& rFormatPageDesc = pContentFrame->GetPageDescItem(); + + if ( rFormatPageDesc.GetNumOffset() && rFormatPageDesc.GetDefinedIn() ) + { + const sw::BroadcastingModify* pMod = rFormatPageDesc.GetDefinedIn(); + sw::VirtPageNumHint aHint(pPage); + pMod->CallSwClientNotify(aHint); + if(aHint.GetPage()) + { + return aHint.GetFrame(); + } + } + } + pPageFrameIter = static_cast<const SwPageFrame*>(pPageFrameIter->GetPrev()); + } + return nullptr; +} /** @return the virtual page number with the offset. */ sal_uInt16 SwFrame::GetVirtPageNum() const { @@ -1867,54 +1892,61 @@ sal_uInt16 SwFrame::GetVirtPageNum() const return 0; sal_uInt16 nPhyPage = pPage->GetPhyPageNum(); - if ( !static_cast<const SwRootFrame*>(pPage->GetUpper())->IsVirtPageNum() ) + const SwRootFrame* pRootFrame = static_cast<const SwRootFrame*>(pPage->GetUpper()); + if ( !pRootFrame->IsVirtPageNum() ) return nPhyPage; //Search the nearest section using the virtual page number. - //Because searching backwards needs a lot of time we search specific using - //the dependencies. From the PageDescs we get the attributes and from the - //attributes we get the sections. - const SwPageFrame *pVirtPage = nullptr; - const SwFrame *pFrame = nullptr; - const SfxItemPool &rPool = pPage->GetFormat()->GetDoc()->GetAttrPool(); - ItemSurrogates aSurrogates; - rPool.GetItemSurrogates(aSurrogates, RES_PAGEDESC); - for (const SfxPoolItem* pItem : aSurrogates) - { - const SwFormatPageDesc *pDesc = dynamic_cast<const SwFormatPageDesc*>(pItem); - if ( !pDesc ) - continue; - - if ( pDesc->GetNumOffset() && pDesc->GetDefinedIn() ) - { - auto pMod = pDesc->GetDefinedIn(); - sw::VirtPageNumHint aHint(pPage); - pMod->CallSwClientNotify(aHint); - if(aHint.GetPage()) - { - if(!pVirtPage || aHint.GetPage()->GetPhyPageNum() > pVirtPage->GetPhyPageNum()) - { - pVirtPage = aHint.GetPage(); - pFrame = aHint.GetFrame(); - } - } - } - } - if ( pFrame ) + const SwFrame *pFoundFrame = lcl_FindStartOfVirtualPages(pPage); + if ( pFoundFrame ) { - ::std::optional<sal_uInt16> oNumOffset = pFrame->GetPageDescItem().GetNumOffset(); + ::std::optional<sal_uInt16> oNumOffset = pFoundFrame->GetPageDescItem().GetNumOffset(); if (oNumOffset) { - return nPhyPage - pFrame->GetPhyPageNum() + *oNumOffset; + return nPhyPage - pFoundFrame->GetPhyPageNum() + *oNumOffset; } else { - return nPhyPage - pFrame->GetPhyPageNum(); + return nPhyPage - pFoundFrame->GetPhyPageNum(); } } return nPhyPage; } +sal_uInt16 SwFrame::GetVirtPageCount() const +{ + const SwPageFrame *pPage = FindPageFrame(); + if ( !pPage || !pPage->GetUpper() ) + return 0; + + const SwRootFrame* pRootFrame = static_cast<const SwRootFrame*>(pPage->GetUpper()); + if ( !pRootFrame->IsVirtPageNum() ) + return pRootFrame->GetPageNum(); + + //Search the nearest section using the virtual page number and the nearest + //follower without a virtual page number. + const SwFrame *pFoundFrame = lcl_FindStartOfVirtualPages(pPage); + const SwPageFrame* pEndPage = pPage; + const SwPageFrame* pPageFrameIter = static_cast<const SwPageFrame*>(pPage->GetNext());; + while (pPageFrameIter) + { + const SwContentFrame* pContentFrame = pPageFrameIter->FindFirstBodyContent(); + if (pContentFrame) + { + const SwFormatPageDesc& rFormatPageDesc = pContentFrame->GetPageDescItem(); + + if ( rFormatPageDesc.GetNumOffset() && rFormatPageDesc.GetDefinedIn() ) + break; + else + pEndPage = pPageFrameIter; + } + pPageFrameIter = static_cast<const SwPageFrame*>(pPageFrameIter->GetNext()); + } + sal_uInt16 nStartPage = pFoundFrame ? pFoundFrame->GetPhyPageNum() : 1; + return pEndPage->GetPhyPageNum() - nStartPage + 1; + return 1; +} + /** Determines and sets those cells which are enclosed by the selection. */ bool SwRootFrame::MakeTableCursors( SwTableCursor& rTableCursor ) { diff --git a/sw/source/core/text/txtfld.cxx b/sw/source/core/text/txtfld.cxx index e522f4e08929..9d5952c14fd9 100644 --- a/sw/source/core/text/txtfld.cxx +++ b/sw/source/core/text/txtfld.cxx @@ -116,7 +116,11 @@ SwExpandPortion *SwTextFormatter::NewFieldPortion( SwTextFormatInfo &rInf, case SwFieldIds::DocStat: if (!bName && pSh && !pSh->Imp()->IsUpdateExpFields()) { - static_cast<SwDocStatField*>(pField)->ChangeExpansion(m_pFrame); + SwDocStatField* pDocStatField = static_cast<SwDocStatField*>(pField); + sal_uInt16 nVirtPageCount = 0; + if (pDocStatField->GetSubType() == SwDocStatSubType::DS_PAGE_RANGE) + nVirtPageCount = m_pFrame->GetVirtPageCount(); + pDocStatField->ChangeExpansion(m_pFrame, nVirtPageCount); } break; case SwFieldIds::PageNumber: diff --git a/sw/source/core/unocore/unocoll.cxx b/sw/source/core/unocore/unocoll.cxx index e00fa835f16a..cf790b34e6b9 100644 --- a/sw/source/core/unocore/unocoll.cxx +++ b/sw/source/core/unocore/unocoll.cxx @@ -346,7 +346,7 @@ const ProvNamesId_Type aProvNamesId[] = { "com.sun.star.text.TextField.DocInfo.Description", SwServiceType::FieldTypeDocInfoDescription }, { "com.sun.star.text.TextField.DocInfo.CreateAuthor", SwServiceType::FieldTypeDocInfoCreateAuthor }, { "com.sun.star.text.TextField.DocInfo.CreateDateTime", SwServiceType::FieldTypeDocInfoCreateDateTime }, - { "", SwServiceType::FieldTypeDummy0 }, + { "com.sun.star.text.TextField.PageCountRange", SwServiceType::FieldTypePageCountRange }, { "", SwServiceType::FieldTypeDummy1 }, { "", SwServiceType::FieldTypeDummy2 }, { "", SwServiceType::FieldTypeDummy3 }, @@ -428,6 +428,7 @@ const ProvNamesId_Type aProvNamesId[] = { CSS_TEXT_TEXTFIELD_DATABASE_NAME, SwServiceType::FieldTypeDatabaseName }, { CSS_TEXT_TEXTFIELD_TABLE_FORMULA, SwServiceType::FieldTypeTableFormula }, { CSS_TEXT_TEXTFIELD_PAGE_COUNT, SwServiceType::FieldTypePageCount }, + { CSS_TEXT_TEXTFIELD_PAGE_COUNT_RANGE, SwServiceType::FieldTypePageCountRange }, { CSS_TEXT_TEXTFIELD_PARAGRAPH_COUNT, SwServiceType::FieldTypeParagraphCount }, { CSS_TEXT_TEXTFIELD_WORD_COUNT, SwServiceType::FieldTypeWordCount }, { CSS_TEXT_TEXTFIELD_CHARACTER_COUNT, SwServiceType::FieldTypeCharacterCount }, @@ -731,6 +732,7 @@ SwXServiceProvider::MakeInstance(SwServiceType nObjectType, SwDoc & rDoc) case SwServiceType::FieldTypeDatabase: case SwServiceType::FieldTypeDatabaseName: case SwServiceType::FieldTypePageCount: + case SwServiceType::FieldTypePageCountRange: case SwServiceType::FieldTypeParagraphCount: case SwServiceType::FieldTypeWordCount: case SwServiceType::FieldTypeCharacterCount: diff --git a/sw/source/core/unocore/unofield.cxx b/sw/source/core/unocore/unofield.cxx index aab9b5193646..6f417002ed82 100644 --- a/sw/source/core/unocore/unofield.cxx +++ b/sw/source/core/unocore/unofield.cxx @@ -155,6 +155,7 @@ const ServiceIdResId aServiceToRes[] = {SwFieldIds::Database, SwServiceType::FieldTypeDatabase }, {SwFieldIds::DatabaseName, SwServiceType::FieldTypeDatabaseName }, {SwFieldIds::DocStat, SwServiceType::FieldTypePageCount }, + {SwFieldIds::DocStat, SwServiceType::FieldTypePageCountRange }, {SwFieldIds::DocStat, SwServiceType::FieldTypeParagraphCount }, {SwFieldIds::DocStat, SwServiceType::FieldTypeWordCount }, {SwFieldIds::DocStat, SwServiceType::FieldTypeCharacterCount }, @@ -245,6 +246,7 @@ static SwServiceType lcl_GetServiceForField( const SwField& rField ) { switch( rField.GetSubType() ) { + case DS_PAGE_RANGE:nSrvId = SwServiceType::FieldTypePageCountRange; break; case DS_PAGE: nSrvId = SwServiceType::FieldTypePageCount; break; case DS_PARA: nSrvId = SwServiceType::FieldTypeParagraphCount; break; case DS_WORD: nSrvId = SwServiceType::FieldTypeWordCount ; break; @@ -355,6 +357,7 @@ static sal_uInt16 lcl_GetPropertyMapOfService( SwServiceType nServiceId ) case SwServiceType::FieldTypeDatabase: nRet = PROPERTY_MAP_FLDTYP_DATABASE; break; case SwServiceType::FieldTypeDatabaseName: nRet = PROPERTY_MAP_FLDTYP_DATABASE_NAME; break; case SwServiceType::FieldTypeTableFormula: nRet = PROPERTY_MAP_FLDTYP_TABLE_FORMULA; break; + case SwServiceType::FieldTypePageCountRange: case SwServiceType::FieldTypePageCount: case SwServiceType::FieldTypeParagraphCount: case SwServiceType::FieldTypeWordCount: @@ -1857,6 +1860,7 @@ void SAL_CALL SwXTextField::attach( } break; case SwServiceType::FieldTypePageCount: + case SwServiceType::FieldTypePageCountRange: case SwServiceType::FieldTypeParagraphCount: case SwServiceType::FieldTypeWordCount: case SwServiceType::FieldTypeCharacterCount: @@ -1873,12 +1877,13 @@ void SAL_CALL SwXTextField::attach( case SwServiceType::FieldTypeTableCount : nSubType = DS_TBL; break; case SwServiceType::FieldTypeGraphicObjectCount : nSubType = DS_GRF; break; case SwServiceType::FieldTypeEmbeddedObjectCount : nSubType = DS_OLE; break; + case SwServiceType::FieldTypePageCountRange : nSubType = DS_PAGE_RANGE; break; default: break; } SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DocStat); xField.reset(new SwDocStatField( static_cast<SwDocStatFieldType*>(pFieldType), - nSubType, m_pImpl->m_pProps->nUSHORT2)); + nSubType, m_pImpl->m_pProps->nUSHORT2, m_pImpl->m_pProps->nUSHORT1)); } break; case SwServiceType::FieldTypeBibliography: diff --git a/sw/source/ui/dialog/swdlgfact.cxx b/sw/source/ui/dialog/swdlgfact.cxx index d7ef3643318d..7ad39bdfcde7 100644 --- a/sw/source/ui/dialog/swdlgfact.cxx +++ b/sw/source/ui/dialog/swdlgfact.cxx @@ -780,6 +780,11 @@ bool AbstractSwPageNumberDlg_Impl::GetIncludePageTotal() const return m_xDlg->GetIncludePageTotal(); } +bool AbstractSwPageNumberDlg_Impl::GetIncludePageRangeTotal() const +{ + return m_xDlg->GetIncludePageRangeTotal(); +} + SvxNumType AbstractSwPageNumberDlg_Impl::GetPageNumberType() const { return m_xDlg->GetPageNumberType(); diff --git a/sw/source/ui/dialog/swdlgfact.hxx b/sw/source/ui/dialog/swdlgfact.hxx index a7240fe862b8..57fce058d69d 100644 --- a/sw/source/ui/dialog/swdlgfact.hxx +++ b/sw/source/ui/dialog/swdlgfact.hxx @@ -172,6 +172,7 @@ public: virtual int GetPageNumberAlignment() const override; bool GetMirrorOnEvenPages() const override; bool GetIncludePageTotal() const override; + bool GetIncludePageRangeTotal() const override; SvxNumType GetPageNumberType() const override; void SetPageNumberType(SvxNumType nSet) override; }; diff --git a/sw/source/ui/misc/pagenumberdlg.cxx b/sw/source/ui/misc/pagenumberdlg.cxx index d812cfaee60f..f384947c9894 100644 --- a/sw/source/ui/misc/pagenumberdlg.cxx +++ b/sw/source/ui/misc/pagenumberdlg.cxx @@ -34,6 +34,7 @@ SwPageNumberDlg::SwPageNumberDlg(weld::Window* pParent) , m_xPageNumberAlignment(m_xBuilder->weld_combo_box(u"alignmentCombo"_ustr)) , m_xMirrorOnEvenPages(m_xBuilder->weld_check_button(u"mirrorCheckbox"_ustr)) , m_xIncludePageTotal(m_xBuilder->weld_check_button(u"pagetotalCheckbox"_ustr)) + , m_xIncludePageRangeTotal(m_xBuilder->weld_check_button(u"pagerangetotalCheckbox"_ustr)) , m_xPageNumberTypeLB(new SvxPageNumberListBox(m_xBuilder->weld_combo_box(u"numfmtlb"_ustr))) , m_xPreviewImage(m_xBuilder->weld_image(u"previewImage"_ustr)) , m_aPageNumberPosition(1) // bottom @@ -48,10 +49,13 @@ SwPageNumberDlg::SwPageNumberDlg(weld::Window* pParent) m_xMirrorOnEvenPages->set_sensitive(false); m_xMirrorOnEvenPages->set_state(TRISTATE_TRUE); m_xIncludePageTotal->set_state(TRISTATE_FALSE); + m_xIncludePageRangeTotal->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)); + m_xIncludePageRangeTotal->connect_toggled( + LINK(this, SwPageNumberDlg, IncludePageRangeTotalChangeHdl)); updateImage(); } @@ -81,6 +85,13 @@ IMPL_LINK_NOARG(SwPageNumberDlg, NumberTypeSelectHdl, weld::ComboBox&, void) IMPL_LINK_NOARG(SwPageNumberDlg, IncludePageTotalChangeHdl, weld::Toggleable&, void) { + m_xIncludePageRangeTotal->set_sensitive(m_xIncludePageTotal->get_state() != TRISTATE_TRUE); + updateImage(); +} + +IMPL_LINK_NOARG(SwPageNumberDlg, IncludePageRangeTotalChangeHdl, weld::Toggleable&, void) +{ + m_xIncludePageTotal->set_sensitive(m_xIncludePageRangeTotal->get_state() != TRISTATE_TRUE); updateImage(); } @@ -95,6 +106,11 @@ bool SwPageNumberDlg::GetIncludePageTotal() return m_xIncludePageTotal->get_state() == TRISTATE_TRUE; } +bool SwPageNumberDlg::GetIncludePageRangeTotal() const +{ + return m_xIncludePageRangeTotal->get_state() == TRISTATE_TRUE; +} + void SwPageNumberDlg::SetPageNumberType(SvxNumType nSet) { m_nPageNumberType = nSet; @@ -116,7 +132,8 @@ void SwPageNumberDlg::updateImage() OUString sText = u"#"_ustr; - if (m_xIncludePageTotal->get_state() == TRISTATE_TRUE) + if (m_xIncludePageTotal->get_state() == TRISTATE_TRUE + || m_xIncludePageRangeTotal->get_state() == TRISTATE_TRUE) { sText += " / #"; } diff --git a/sw/source/uibase/docvw/HeaderFooterWin.cxx b/sw/source/uibase/docvw/HeaderFooterWin.cxx index c20c39dcb6e4..b96e31880e76 100644 --- a/sw/source/uibase/docvw/HeaderFooterWin.cxx +++ b/sw/source/uibase/docvw/HeaderFooterWin.cxx @@ -537,6 +537,11 @@ void SwHeaderFooterWin::ExecuteCommand(std::u16string_view rIdent) SfxViewFrame& rVFrame = rSh.GetView().GetViewFrame(); rVFrame.GetBindings().Execute(FN_INSERT_FLD_PGCOUNT); } + else if (rIdent == u"insert_pagecount_in_range") + { + SfxViewFrame& rVFrame = rSh.GetView().GetViewFrame(); + rVFrame.GetBindings().Execute(FN_INSERT_FLD_RANGE_PGCOUNT); + } } IMPL_LINK_NOARG(SwHeaderFooterWin, ClickHdl, weld::Button&, void) diff --git a/sw/source/uibase/fldui/fldmgr.cxx b/sw/source/uibase/fldui/fldmgr.cxx index c23c8eb8c93c..ddd4b57bba8a 100644 --- a/sw/source/uibase/fldui/fldmgr.cxx +++ b/sw/source/uibase/fldui/fldmgr.cxx @@ -196,6 +196,7 @@ const TranslateId FMT_FF_ARY[] = const TranslateId FLD_STAT_ARY[] = { FLD_STAT_PAGE, + FLD_STAT_PAGE_SECTION, FLD_STAT_PARA, FLD_STAT_WORD, FLD_STAT_CHAR, diff --git a/sw/source/uibase/inc/pagenumberdlg.hxx b/sw/source/uibase/inc/pagenumberdlg.hxx index 169c9209dbf5..16a94e28eefc 100644 --- a/sw/source/uibase/inc/pagenumberdlg.hxx +++ b/sw/source/uibase/inc/pagenumberdlg.hxx @@ -33,6 +33,7 @@ class SwPageNumberDlg final : public SfxDialogController std::unique_ptr<weld::ComboBox> m_xPageNumberAlignment; std::unique_ptr<weld::CheckButton> m_xMirrorOnEvenPages; std::unique_ptr<weld::CheckButton> m_xIncludePageTotal; + std::unique_ptr<weld::CheckButton> m_xIncludePageRangeTotal; std::unique_ptr<SvxPageNumberListBox> m_xPageNumberTypeLB; std::unique_ptr<weld::Image> m_xPreviewImage; @@ -43,6 +44,7 @@ class SwPageNumberDlg final : public SfxDialogController DECL_LINK(OkHdl, weld::Button&, void); DECL_LINK(IncludePageTotalChangeHdl, weld::Toggleable&, void); + DECL_LINK(IncludePageRangeTotalChangeHdl, weld::Toggleable&, void); DECL_LINK(PositionSelectHdl, weld::ComboBox&, void); DECL_LINK(AlignmentSelectHdl, weld::ComboBox&, void); DECL_LINK(NumberTypeSelectHdl, weld::ComboBox&, void); @@ -55,6 +57,7 @@ public: int GetPageNumberAlignment() const { return m_aPageNumberAlignment; } bool GetMirrorOnEvenPages(); bool GetIncludePageTotal(); + bool GetIncludePageRangeTotal() const; SvxNumType GetPageNumberType() const { return m_nPageNumberType; } void SetPageNumberType(SvxNumType nSet); }; diff --git a/sw/source/uibase/shells/textfld.cxx b/sw/source/uibase/shells/textfld.cxx index 1b07a0708693..811339905f77 100644 --- a/sw/source/uibase/shells/textfld.cxx +++ b/sw/source/uibase/shells/textfld.cxx @@ -761,8 +761,9 @@ void SwTextShell::ExecField(SfxRequest &rReq) bIsText = false; goto FIELD_INSERT; case FN_INSERT_FLD_PGCOUNT : + case FN_INSERT_FLD_RANGE_PGCOUNT: nInsertType = SwFieldTypesEnum::DocumentStatistics; - nInsertSubType = 0; + nInsertSubType = FN_INSERT_FLD_RANGE_PGCOUNT == nSlot ? 1 : 0; bIsText = false; nInsertFormat = SVX_NUM_PAGEDESC; goto FIELD_INSERT; @@ -1306,11 +1307,14 @@ FIELD_INSERT: SwInsertField_Data aData(SwFieldTypesEnum::PageNumber, 0, OUString(), OUString(), SVX_NUM_PAGEDESC); aMgr.InsertField(aData); - if (pDlg->GetIncludePageTotal()) + if (pDlg->GetIncludePageTotal() || + pDlg->GetIncludePageRangeTotal()) { rDoc->getIDocumentContentOperations().InsertString(*rSh.GetCursor(), u" / "_ustr); - SwInsertField_Data aPageTotalData(SwFieldTypesEnum::DocumentStatistics, DS_PAGE, - OUString(), OUString(), SVX_NUM_PAGEDESC); + SwInsertField_Data aPageTotalData(SwFieldTypesEnum::DocumentStatistics, + pDlg->GetIncludePageTotal() ? DS_PAGE : DS_PAGE_RANGE, + OUString(), OUString(), SVX_NUM_PAGEDESC); + aMgr.InsertField(aPageTotalData); } @@ -1641,6 +1645,7 @@ void SwTextShell::StateField( SfxItemSet &rSet ) case FN_INSERT_FLD_AUTHOR: case FN_INSERT_FLD_DATE: case FN_INSERT_FLD_PGCOUNT: + case FN_INSERT_FLD_RANGE_PGCOUNT: case FN_INSERT_FLD_PGNUMBER: case FN_INSERT_FLD_TIME: case FN_INSERT_FLD_TITLE: diff --git a/sw/uiconfig/sglobal/popupmenu/insertfield.xml b/sw/uiconfig/sglobal/popupmenu/insertfield.xml index 48e9ae5370d3..f063065ff96c 100644 --- a/sw/uiconfig/sglobal/popupmenu/insertfield.xml +++ b/sw/uiconfig/sglobal/popupmenu/insertfield.xml @@ -10,6 +10,7 @@ <menu:menupopup xmlns:menu="http://openoffice.org/2001/menu"> <menu:menuitem menu:id=".uno:InsertPageNumberField"/> <menu:menuitem menu:id=".uno:InsertPageCountField"/> + <menu:menuitem menu:id=".uno:InsertPageCountInRangeField"/> <menu:menuitem menu:id=".uno:InsertDateField"/> <menu:menuitem menu:id=".uno:InsertDateFieldVar"/> <menu:menuitem menu:id=".uno:InsertTimeField"/> diff --git a/sw/uiconfig/swform/popupmenu/insertfield.xml b/sw/uiconfig/swform/popupmenu/insertfield.xml index 48e9ae5370d3..f063065ff96c 100644 --- a/sw/uiconfig/swform/popupmenu/insertfield.xml +++ b/sw/uiconfig/swform/popupmenu/insertfield.xml @@ -10,6 +10,7 @@ <menu:menupopup xmlns:menu="http://openoffice.org/2001/menu"> <menu:menuitem menu:id=".uno:InsertPageNumberField"/> <menu:menuitem menu:id=".uno:InsertPageCountField"/> + <menu:menuitem menu:id=".uno:InsertPageCountInRangeField"/> <menu:menuitem menu:id=".uno:InsertDateField"/> <menu:menuitem menu:id=".uno:InsertDateFieldVar"/> <menu:menuitem menu:id=".uno:InsertTimeField"/> diff --git a/sw/uiconfig/swreport/popupmenu/insertfield.xml b/sw/uiconfig/swreport/popupmenu/insertfield.xml index 48e9ae5370d3..f063065ff96c 100644 --- a/sw/uiconfig/swreport/popupmenu/insertfield.xml +++ b/sw/uiconfig/swreport/popupmenu/insertfield.xml @@ -10,6 +10,7 @@ <menu:menupopup xmlns:menu="http://openoffice.org/2001/menu"> <menu:menuitem menu:id=".uno:InsertPageNumberField"/> <menu:menuitem menu:id=".uno:InsertPageCountField"/> + <menu:menuitem menu:id=".uno:InsertPageCountInRangeField"/> <menu:menuitem menu:id=".uno:InsertDateField"/> <menu:menuitem menu:id=".uno:InsertDateFieldVar"/> <menu:menuitem menu:id=".uno:InsertTimeField"/> diff --git a/sw/uiconfig/swriter/popupmenu/insertfield.xml b/sw/uiconfig/swriter/popupmenu/insertfield.xml index 48e9ae5370d3..f063065ff96c 100644 --- a/sw/uiconfig/swriter/popupmenu/insertfield.xml +++ b/sw/uiconfig/swriter/popupmenu/insertfield.xml @@ -10,6 +10,7 @@ <menu:menupopup xmlns:menu="http://openoffice.org/2001/menu"> <menu:menuitem menu:id=".uno:InsertPageNumberField"/> <menu:menuitem menu:id=".uno:InsertPageCountField"/> + <menu:menuitem menu:id=".uno:InsertPageCountInRangeField"/> <menu:menuitem menu:id=".uno:InsertDateField"/> <menu:menuitem menu:id=".uno:InsertDateFieldVar"/> <menu:menuitem menu:id=".uno:InsertTimeField"/> diff --git a/sw/uiconfig/swriter/ui/hfmenubutton.ui b/sw/uiconfig/swriter/ui/hfmenubutton.ui index a41efba005ec..97486327bde8 100644 --- a/sw/uiconfig/swriter/ui/hfmenubutton.ui +++ b/sw/uiconfig/swriter/ui/hfmenubutton.ui @@ -40,7 +40,7 @@ <property name="use-underline">True</property> </object> </child> - <child> + <child> <object class="GtkMenuItem" id="insert_pagecount"> <property name="visible">True</property> <property name="can-focus">False</property> @@ -48,6 +48,14 @@ <property name="use-underline">True</property> </object> </child> + <child> + <object class="GtkMenuItem" id="insert_pagecount_in_range"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes" context="headerfootermenu|insert_pagecount_in_range">Insert Page Count In Range</property> + <property name="use-underline">True</property> + </object> + </child> </object> <object class="GtkBox" id="HFMenuButton"> <property name="visible">True</property> diff --git a/sw/uiconfig/swriter/ui/pagenumberdlg.ui b/sw/uiconfig/swriter/ui/pagenumberdlg.ui index f014545da429..9651dca4a235 100644 --- a/sw/uiconfig/swriter/ui/pagenumberdlg.ui +++ b/sw/uiconfig/swriter/ui/pagenumberdlg.ui @@ -212,6 +212,28 @@ </packing> </child> <child> + <object class="GtkCheckButton" id="pagerangetotalCheckbox"> + <property name="label" translatable="yes" context="pagenumberdlg|pagerangetotalCheckbox">Include page total in range</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">False</property> + <property name="margin-start">18</property> + <property name="margin-top">3</property> + <property name="use-underline">True</property> + <property name="draw-indicator">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="pagerangetotalCheckbox-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="pagenumberdlg|extended_tip|pagerangetotalCheckbox">Also insert the total number of pages in range</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">6</property> + </packing> + </child> + <child> <object class="GtkLabel" id="numfmtLabel"> <property name="visible">True</property> <property name="can-focus">False</property> @@ -232,7 +254,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">6</property> + <property name="position">7</property> </packing> </child> <child> @@ -251,7 +273,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">7</property> + <property name="position">8</property> </packing> </child> </object> diff --git a/sw/uiconfig/swxform/popupmenu/insertfield.xml b/sw/uiconfig/swxform/popupmenu/insertfield.xml index 48e9ae5370d3..f063065ff96c 100644 --- a/sw/uiconfig/swxform/popupmenu/insertfield.xml +++ b/sw/uiconfig/swxform/popupmenu/insertfield.xml @@ -10,6 +10,7 @@ <menu:menupopup xmlns:menu="http://openoffice.org/2001/menu"> <menu:menuitem menu:id=".uno:InsertPageNumberField"/> <menu:menuitem menu:id=".uno:InsertPageCountField"/> + <menu:menuitem menu:id=".uno:InsertPageCountInRangeField"/> <menu:menuitem menu:id=".uno:InsertDateField"/> <menu:menuitem menu:id=".uno:InsertDateFieldVar"/> <menu:menuitem menu:id=".uno:InsertTimeField"/> diff --git a/xmloff/inc/txtflde.hxx b/xmloff/inc/txtflde.hxx index 06d5edcaa2b4..32f6142bc7bb 100644 --- a/xmloff/inc/txtflde.hxx +++ b/xmloff/inc/txtflde.hxx @@ -108,6 +108,8 @@ enum FieldIdEnum { FIELD_ID_COUNT_WORDS, // - words FIELD_ID_COUNT_CHARACTERS, // - chars FIELD_ID_COUNT_PAGES, // - pages + FIELD_ID_COUNT_PAGES_RANGE, // - pages in range + FIELD_ID_COUNT_TABLES, // - tables FIELD_ID_COUNT_GRAPHICS, // - graphics FIELD_ID_COUNT_OBJECTS, // - objects @@ -227,7 +229,8 @@ private: /// export an element with string content void ExportElement(enum ::xmloff::token::XMLTokenEnum eElement, /// element token - const OUString& sContent); /// element content + const OUString& sContent, + sal_uInt16 nNamespace = XML_NAMESPACE_TEXT); /// element content /// export a macro (as used in the macro field) void ExportMacro( const css::uno::Reference< css::beans::XPropertySet> & rPropSet, diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 171c38c9ac45..b3b4695e4918 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -1497,6 +1497,7 @@ namespace xmloff::token { TOKEN( "page-content", XML_PAGE_CONTENT ), TOKEN( "page-continuation-string", XML_PAGE_CONTINUATION_STRING ), TOKEN( "page-count", XML_PAGE_COUNT ), + TOKEN( "page-count-range", XML_PAGE_COUNT_RANGE ), TOKEN( "page-end-margin", XML_PAGE_END_MARGIN ), TOKEN( "page-height", XML_PAGE_HEIGHT ), TOKEN( "page-master", XML_PAGE_MASTER ), diff --git a/xmloff/source/text/txtflde.cxx b/xmloff/source/text/txtflde.cxx index 1c8d9fb56847..6f348cfd3085 100644 --- a/xmloff/source/text/txtflde.cxx +++ b/xmloff/source/text/txtflde.cxx @@ -130,6 +130,7 @@ char const FIELD_SERVICE_FILE_NAME[] = "FileName"; char const FIELD_SERVICE_CHAPTER[] = "Chapter"; char const FIELD_SERVICE_TEMPLATE_NAME[] = "TemplateName"; char const FIELD_SERVICE_PAGE_COUNT[] = "PageCount"; +char const FIELD_SERVICE_PAGE_COUNT_RANGE[] = "PageCountRange"; char const FIELD_SERVICE_PARAGRAPH_COUNT[] = "ParagraphCount"; char const FIELD_SERVICE_WORD_COUNT[] = "WordCount"; char const FIELD_SERVICE_CHARACTER_COUNT[] = "CharacterCount"; @@ -249,6 +250,7 @@ SvXMLEnumStringMapEntry<FieldIdEnum> const aFieldServiceNameMapping[] = ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_TEMPLATE_NAME, FIELD_ID_TEMPLATE_NAME ), ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_PAGE_COUNT, FIELD_ID_COUNT_PAGES ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_PAGE_COUNT_RANGE, FIELD_ID_COUNT_PAGES_RANGE ), ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_PARAGRAPH_COUNT, FIELD_ID_COUNT_PARAGRAPHS ), ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_WORD_COUNT, FIELD_ID_COUNT_WORDS ), ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_CHARACTER_COUNT, FIELD_ID_COUNT_CHARACTERS ), @@ -592,6 +594,7 @@ enum FieldIdEnum XMLTextFieldExport::MapFieldName( case FIELD_ID_REFPAGE_SET: case FIELD_ID_REFPAGE_GET: case FIELD_ID_COUNT_PAGES: + case FIELD_ID_COUNT_PAGES_RANGE: case FIELD_ID_COUNT_PARAGRAPHS: case FIELD_ID_COUNT_WORDS: case FIELD_ID_COUNT_CHARACTERS: @@ -683,6 +686,7 @@ bool XMLTextFieldExport::IsStringField( return false; case FIELD_ID_COUNT_PAGES: + case FIELD_ID_COUNT_PAGES_RANGE: case FIELD_ID_COUNT_PARAGRAPHS: case FIELD_ID_COUNT_WORDS: case FIELD_ID_COUNT_CHARACTERS: @@ -938,6 +942,7 @@ void XMLTextFieldExport::ExportFieldAutoStyle( case FIELD_ID_REFPAGE_SET: case FIELD_ID_REFPAGE_GET: case FIELD_ID_COUNT_PAGES: + case FIELD_ID_COUNT_PAGES_RANGE: case FIELD_ID_COUNT_PARAGRAPHS: case FIELD_ID_COUNT_WORDS: case FIELD_ID_COUNT_CHARACTERS: @@ -1503,9 +1508,24 @@ void XMLTextFieldExport::ExportFieldHelper( ProcessNumberingType(GetInt16Property(gsPropertyNumberingType, rPropSet)); } - ExportElement(MapCountFieldName(nToken), sPresentation); + ExportElement(MapCountFieldName(nToken), sPresentation, XML_NAMESPACE_TEXT); break; + case FIELD_ID_COUNT_PAGES_RANGE: + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + if (xPropSetInfo->hasPropertyByName(gsPropertyNumberingType)) + { + ProcessNumberingType(GetInt16Property(gsPropertyNumberingType, + rPropSet)); + } + ExportElement(MapCountFieldName(nToken), sPresentation, XML_NAMESPACE_LO_EXT); + } + else + { + GetExport().Characters(sPresentation); + } + break; case FIELD_ID_CONDITIONAL_TEXT: ProcessString(XML_CONDITION, XML_NAMESPACE_OOOW, GetStringProperty(gsPropertyCondition, rPropSet)); @@ -2280,13 +2300,14 @@ void XMLTextFieldExport::ExportElement(enum XMLTokenEnum eElementName, } void XMLTextFieldExport::ExportElement(enum XMLTokenEnum eElementName, - const OUString& sContent) + const OUString& sContent, + sal_uInt16 nNamespace) { DBG_ASSERT(eElementName != XML_TOKEN_INVALID, "invalid element name!"); if (eElementName != XML_TOKEN_INVALID) { // Element - SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + SvXMLElementExport aElem( GetExport(), nNamespace, eElementName, false, false ); // export content GetExport().Characters(sContent); @@ -3059,6 +3080,9 @@ enum XMLTokenEnum XMLTextFieldExport::MapCountFieldName(FieldIdEnum nToken) case FIELD_ID_COUNT_PAGES: eElement = XML_PAGE_COUNT; break; + case FIELD_ID_COUNT_PAGES_RANGE: + eElement = XML_PAGE_COUNT_RANGE; + break; case FIELD_ID_COUNT_PARAGRAPHS: eElement = XML_PARAGRAPH_COUNT; break; diff --git a/xmloff/source/text/txtfldi.cxx b/xmloff/source/text/txtfldi.cxx index a4a602b63665..78a8610f4d0e 100644 --- a/xmloff/source/text/txtfldi.cxx +++ b/xmloff/source/text/txtfldi.cxx @@ -382,6 +382,7 @@ XMLTextFieldImportContext::CreateTextFieldImportContext( case XML_ELEMENT(TEXT, XML_IMAGE_COUNT): case XML_ELEMENT(TEXT, XML_OBJECT_COUNT): case XML_ELEMENT(TEXT, XML_PAGE_COUNT): + case XML_ELEMENT(LO_EXT, XML_PAGE_COUNT_RANGE): pContext = new XMLCountFieldImportContext( rImport, rHlp, nToken); break; @@ -2237,6 +2238,9 @@ OUString XMLCountFieldImportContext::MapTokenToServiceName( case XML_ELEMENT(TEXT, XML_PAGE_COUNT): pServiceName = "PageCount"; break; + case XML_ELEMENT(LO_EXT, XML_PAGE_COUNT_RANGE): + pServiceName = "PageCountRange"; + break; default: XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); assert(false); diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index 9bfe5dda2b8c..359523ef6863 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -1397,6 +1397,7 @@ page-breaks-on-group-change page-content page-continuation-string page-count +page-count-range page-end-margin page-height page-master