include/xmloff/xmltoken.hxx | 1 offapi/com/sun/star/text/textfield/PageCountRange.idl | 40 ++++ officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu | 8 schema/libreoffice/OpenDocument-v1.4+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 | 9 + sw/qa/extras/uiwriter/uiwriter9.cxx | 83 ++++++++++ sw/sdi/_textsh.sdi | 8 sw/sdi/swriter.sdi | 17 ++ sw/source/core/doc/DocumentFieldsManager.cxx | 11 + sw/source/core/fields/docufld.cxx | 66 +++++++ sw/source/core/inc/frame.hxx | 1 sw/source/core/layout/trvlfrm.cxx | 66 ++++++- 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 | 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 | 12 - 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 | 8 sw/uiconfig/swriter/ui/pagenumberdlg.ui | 28 +++ 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 40 files changed, 437 insertions(+), 43 deletions(-)
New commits: commit 554d2769d1c8c5b2fa03d2c72e91c92a94fb3cd8 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:16 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/+/178141 Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de> Tested-by: Gabor Kelemen <gabor.kelemen.ext...@allotropia.de> Tested-by: Jenkins diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index e6a82d4021c2..3dadf9fa10fe 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -1489,6 +1489,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/PageCountRange.idl b/offapi/com/sun/star/text/textfield/PageCountRange.idl new file mode 100755 index 000000000000..0a74540082c6 --- /dev/null +++ b/offapi/com/sun/star/text/textfield/PageCountRange.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 bcacf991e058..9686cdb09823 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu @@ -1188,6 +1188,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.4+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng index 50a5fa96e5b3..dfc2bba4af45 100644 --- a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng @@ -4033,7 +4033,6 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. </rng:attribute> </rng:optional> </rng:define> - <!-- TODO no proposal for page number on multipage formats --> <rng:define name="draw-image-attlist" combine="interleave"> <rng:optional> @@ -4042,4 +4041,14 @@ 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 5c7cda8f44af..abfe12fa9e78 100644 --- a/sw/inc/cmdid.h +++ b/sw/inc/cmdid.h @@ -341,6 +341,7 @@ class SwUINumRuleItem; #define FN_DELETE_FIELDS (FN_INSERT2 + 40) #define FN_DELETE_SECTIONS (FN_INSERT2 + 41) #define FN_DELETE_CONTENT_CONTROL (FN_INSERT2 + 42) /* Delete content control formatting */ +#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 83986b735ae3..2e762987b01a 100644 --- a/sw/inc/docufld.hxx +++ b/sw/inc/docufld.hxx @@ -51,12 +51,14 @@ enum SwDocStatSubType { DS_BEGIN, DS_PAGE = DS_BEGIN, + // page count in current section + DS_PAGE_RANGE, DS_PARA, DS_WORD, DS_CHAR, DS_TBL, DS_GRF, - DS_OLE, + DS_OLE }; typedef sal_uInt16 SwDocInfoSubType; @@ -255,21 +257,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 18a66de7b251..526c1f3ab8f6 100644 --- a/sw/inc/strings.hrc +++ b/sw/inc/strings.hrc @@ -1012,6 +1012,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_RANGE 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 59768a69aa55..3f4e1cd5b10d 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 bool GetFitIntoExistingMargins() 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 b190f3e4ca1f..5bc0f5c0726a 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 8408c0f13fd7..82bd0b806c93 100644 --- a/sw/inc/unoprnms.hxx +++ b/sw/inc/unoprnms.hxx @@ -310,6 +310,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 f43067922976..41a95a022b10 100644 --- a/sw/qa/extras/odfexport/odfexport2.cxx +++ b/sw/qa/extras/odfexport/odfexport2.cxx @@ -2044,6 +2044,15 @@ CPPUNIT_TEST_FIXTURE(Test, testMsWordUlTrailSpace) } } +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 8e92bcc8d67c..d42c7fc06ee7 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> @@ -1184,6 +1186,87 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf164140) CPPUNIT_ASSERT_EQUAL(size_t(0), stAfterKashida.size()); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf71583) +{ + //create a document, multiple pages, some restart page counting + // insert page count in section 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 a0f257d916a3..b385e798ad9b 100644 --- a/sw/sdi/_textsh.sdi +++ b/sw/sdi/_textsh.sdi @@ -960,6 +960,14 @@ interface BaseText 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 b2856ba521c0..2268643f4575 100644 --- a/sw/sdi/swriter.sdi +++ b/sw/sdi/swriter.sdi @@ -3478,6 +3478,23 @@ 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; +] + 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 9180ca187767..1af75789e2af 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/fields/docufld.cxx b/sw/source/core/fields/docufld.cxx index fc9141f67f03..68576689f1ac 100644 --- a/sw/source/core/fields/docufld.cxx +++ b/sw/source/core/fields/docufld.cxx @@ -740,7 +740,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(); @@ -759,6 +760,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" ); } @@ -773,26 +779,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 @@ -805,11 +841,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 @@ -819,6 +857,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); @@ -844,6 +885,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 3ef9f4c15901..df6adf0a5e38 100644 --- a/sw/source/core/inc/frame.hxx +++ b/sw/source/core/inc/frame.hxx @@ -755,6 +755,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 0b4f2d2a8eb0..865878b51822 100644 --- a/sw/source/core/layout/trvlfrm.cxx +++ b/sw/source/core/layout/trvlfrm.cxx @@ -1866,20 +1866,8 @@ Point SwFrame::GetRelPos() const return aRet; } -/** @return the virtual page number with the offset. */ -sal_uInt16 SwFrame::GetVirtPageNum() const +static const SwFrame* lcl_FindStartOfVirtualPages(const SwPageFrame *pPage) { - const SwPageFrame *pPage = FindPageFrame(); - if ( !pPage || !pPage->GetUpper() ) - return 0; - - sal_uInt16 nPhyPage = pPage->GetPhyPageNum(); - const SwRootFrame* pRootFrame = static_cast<const SwRootFrame*>(pPage->GetUpper()); - if ( !pRootFrame->IsVirtPageNum() ) - return nPhyPage; - - //Search the nearest section using the virtual page number. - const SwFrame *pFoundFrame = nullptr; const SwPageFrame* pPageFrameIter = pPage; while (pPageFrameIter) { @@ -1895,13 +1883,28 @@ sal_uInt16 SwFrame::GetVirtPageNum() const pMod->CallSwClientNotify(aHint); if(aHint.GetPage()) { - pFoundFrame = aHint.GetFrame(); - break; + 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 +{ + const SwPageFrame *pPage = FindPageFrame(); + if ( !pPage || !pPage->GetUpper() ) + return 0; + + sal_uInt16 nPhyPage = pPage->GetPhyPageNum(); + const SwRootFrame* pRootFrame = static_cast<const SwRootFrame*>(pPage->GetUpper()); + if ( !pRootFrame->IsVirtPageNum() ) + return nPhyPage; + + //Search the nearest section using the virtual page number. + const SwFrame *pFoundFrame = lcl_FindStartOfVirtualPages(pPage); if ( pFoundFrame ) { ::std::optional<sal_uInt16> oNumOffset = pFoundFrame->GetPageDescItem().GetNumOffset(); @@ -1917,6 +1920,39 @@ sal_uInt16 SwFrame::GetVirtPageNum() const 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; +} + /** 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 77abcff7e344..18d102f40319 100644 --- a/sw/source/core/text/txtfld.cxx +++ b/sw/source/core/text/txtfld.cxx @@ -117,7 +117,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 342d2913f74a..8d12d8aea92c 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 }, @@ -734,6 +735,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 da961728d8cc..57c4d881472d 100644 --- a/sw/source/core/unocore/unofield.cxx +++ b/sw/source/core/unocore/unofield.cxx @@ -157,6 +157,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 }, @@ -247,6 +248,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; @@ -357,6 +359,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: @@ -1856,6 +1859,7 @@ void SAL_CALL SwXTextField::attach( } break; case SwServiceType::FieldTypePageCount: + case SwServiceType::FieldTypePageCountRange: case SwServiceType::FieldTypeParagraphCount: case SwServiceType::FieldTypeWordCount: case SwServiceType::FieldTypeCharacterCount: @@ -1872,12 +1876,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 ea4e0ffa3daa..66608b9427b1 100644 --- a/sw/source/ui/dialog/swdlgfact.cxx +++ b/sw/source/ui/dialog/swdlgfact.cxx @@ -788,6 +788,7 @@ public: int GetPageNumberAlignment() const override { return m_pDlg->GetPageNumberAlignment(); } bool GetMirrorOnEvenPages() const override { return m_pDlg->GetMirrorOnEvenPages(); } bool GetIncludePageTotal() const override { return m_pDlg->GetIncludePageTotal(); } + bool GetIncludePageRangeTotal() const override { return m_pDlg->GetIncludePageRangeTotal(); } bool GetFitIntoExistingMargins() const override { return m_pDlg->GetFitIntoExistingMargins(); } SvxNumType GetPageNumberType() const override { return m_pDlg->GetPageNumberType(); } void SetPageNumberType(SvxNumType nSet) override { m_pDlg->SetPageNumberType(nSet); } diff --git a/sw/source/ui/misc/pagenumberdlg.cxx b/sw/source/ui/misc/pagenumberdlg.cxx index bc3cadb701e8..812ef0bdcc1a 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_xFitIntoExistingMargins( m_xBuilder->weld_check_button(u"fitintoexistingmarginsCheckbox"_ustr)) , m_xPageNumberTypeLB(new SvxPageNumberListBox(m_xBuilder->weld_combo_box(u"numfmtlb"_ustr))) @@ -50,11 +51,14 @@ 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); m_xFitIntoExistingMargins->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(); } @@ -84,6 +88,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(); } @@ -98,6 +109,11 @@ bool SwPageNumberDlg::GetIncludePageTotal() const return m_xIncludePageTotal->get_state() == TRISTATE_TRUE; } +bool SwPageNumberDlg::GetIncludePageRangeTotal() const +{ + return m_xIncludePageRangeTotal->get_state() == TRISTATE_TRUE; +} + bool SwPageNumberDlg::GetFitIntoExistingMargins() const { return m_xFitIntoExistingMargins->get_state() == TRISTATE_TRUE; @@ -124,7 +140,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 7d4d4e251b67..cfef4e3e7bf5 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_RANGE, 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 f097509b5a68..c5371fa01f1a 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<weld::CheckButton> m_xFitIntoExistingMargins; std::unique_ptr<SvxPageNumberListBox> m_xPageNumberTypeLB; @@ -44,6 +45,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); @@ -56,6 +58,7 @@ public: int GetPageNumberAlignment() const { return m_aPageNumberAlignment; } bool GetMirrorOnEvenPages() const; bool GetIncludePageTotal() const; + bool GetIncludePageRangeTotal() const; bool GetFitIntoExistingMargins() 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 ea69fe7e8064..4a9a11eba7f2 100644 --- a/sw/source/uibase/shells/textfld.cxx +++ b/sw/source/uibase/shells/textfld.cxx @@ -790,8 +790,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; @@ -1401,11 +1402,13 @@ 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); } @@ -1731,6 +1734,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..ce4e22de1e87 100644 --- a/sw/uiconfig/swriter/ui/hfmenubutton.ui +++ b/sw/uiconfig/swriter/ui/hfmenubutton.ui @@ -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 e876594c05c5..e5ef0d86e9bf 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="GtkCheckButton" id="fitintoexistingmarginsCheckbox"> <property name="label" translatable="yes" context="pagenumberdlg|fitintoexistingmarginsCheckbox">Fit into existing margins</property> <property name="visible">True</property> @@ -230,7 +252,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> @@ -254,7 +276,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">7</property> + <property name="position">8</property> </packing> </child> <child> @@ -273,7 +295,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">8</property> + <property name="position">9</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 60065d90095b..30ed2d6ae71e 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 section/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 b0fc6e028c2f..aa5b24961ba8 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -1502,6 +1502,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 3f2ac6b452f3..c0fb7aaac850 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: @@ -929,6 +933,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: @@ -1494,9 +1499,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)); @@ -2271,13 +2291,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); @@ -3050,6 +3071,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 fcaf900b8f41..ed14e1edb1a8 100644 --- a/xmloff/source/text/txtfldi.cxx +++ b/xmloff/source/text/txtfldi.cxx @@ -383,6 +383,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; @@ -2238,6 +2239,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 004243725964..d11a6d02e77c 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -1402,6 +1402,7 @@ page-breaks-on-group-change page-content page-continuation-string page-count +page-count-range page-end-margin page-height page-master