tdf#86790: Add support for a word-style styleref

STYLEREF is a field type in Word which changes its content based on
nearby paragraphs. For example, upon creating a styleref referencing
"Heading 1" you will see the text of the nearest "Heading 1"-styled
paragraph that is above the field.

This patch implements STYLEREF in Writer as a cross-reference. By using
"insert>cross-reference>styles" you'll be presented with a list of
styles. Selecting one and clicking "insert" will create a field which
has text from the "most relevant" instance of the style. To find the
most relevant instance we first search up for paragraphs with the style,
and if there are any we take the closest. If there weren't any, we
search down for paragraphs with the style.

This patch also updates our use of STYLEREF for chapters exported to
docx by using it for all chapters not only those in headers and footers.
This allows us to approximate more chapter field functionality even when
moving between Writer and Word.

Finally, this patch adds some tests for STYLEREF:
- testTdf86790 tests that the "sample file with STYLEREF" document from
  tdf#86790 has the correct fields
- testStyleRefSearchUp tests that the STYLEREF searches up when there
  are bits of text both above and below it
- testStyleRefSearchDown tests that the STYLEREF searches down when
  there are bits of text below it only
- testMarginalStyleRef tests that the STYLEREF searches from the page
  top when it is placed in a footer
- testFootnotetyleRef tests that the STYLEREF searches from the
  reference mark when it is placed in a footnote

Still TODO:
- [  ] Update documentation
- [  ] Implement reverse-searching (\l) and nondelimiter
       suppression (\t)
       - Probably these 2 will be in a followup patch

Change-Id: I25dd7a6940abee5651a784b9059fe23b32547d6c
Signed-off-by: Skyler Grey <skyler.grey@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157456
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
This commit is contained in:
Skyler Grey
2023-10-20 08:53:34 +02:00
committed by Miklos Vajna
parent d52982f4b3
commit 32c588dd11
28 changed files with 921 additions and 151 deletions
+1
View File
@@ -1902,6 +1902,7 @@ namespace xmloff::token {
XML_STRUCTURE_PROTECTED,
XML_STYLE,
XML_STYLE_NAME,
XML_STYLE_REF,
XML_STYLES,
XML_STYLESHEET,
XML_SUB_TABLE,
@@ -44,6 +44,11 @@ published constants ReferenceFieldSource
/** The source is an endnote.
*/
const short ENDNOTE = 4;
/** The source is a style.
@since LibreOffice 24.2
*/
const short STYLE = 5;
};
@@ -2179,6 +2179,29 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
</rng:element>
</rng:define>
<!-- TODO no proposal -->
<rng:define name="loext-style-reference">
<rng:element name="loext:style-ref">
<rng:interleave>
<rng:ref name="text-common-ref-content"/>
<rng:optional>
<rng:attribute name="text:reference-format">
<rng:choice>
<rng:value>text</rng:value>
<rng:value>direction</rng:value>
<rng:value>number</rng:value>
<rng:value>number-no-superior</rng:value>
<rng:value>number-all-superior</rng:value>
</rng:choice>
</rng:attribute>
</rng:optional>
</rng:interleave>
</rng:element>
</rng:define>
<rng:define name="paragraph-content" combine="choice">
<rng:ref name="loext-style-reference"/>
</rng:define>
<rng:define name="loext-qrcode">
<rng:element name="loext:qrcode">
<rng:attribute name="office:string-value">
+1
View File
@@ -31,6 +31,7 @@ const TranslateId FLD_REF_PAGE_TYPES[] =
NC_("fldrefpage|liststore1", "Endnotes"),
NC_("fldrefpage|liststore1", "Headings"),
NC_("fldrefpage|liststore1", "Numbered Paragraphs"),
NC_("fldrefpage|liststore1", "Styles"),
};
#endif
+15 -7
View File
@@ -26,8 +26,10 @@
class SfxPoolItem;
class SwDoc;
class SwTextNode;
class SwContentFrame;
class SwTextField;
class SwRootFrame;
class SwFrame;
bool IsFrameBehind( const SwTextNode& rMyNd, sal_Int32 nMySttPos,
const SwTextNode& rBehindNd, sal_Int32 nSttPos );
@@ -39,7 +41,8 @@ enum REFERENCESUBTYPE
REF_BOOKMARK,
REF_OUTLINE,
REF_FOOTNOTE,
REF_ENDNOTE
REF_ENDNOTE,
REF_STYLE
};
enum REFERENCEMARK
@@ -80,7 +83,8 @@ public:
static SwTextNode* FindAnchor( SwDoc* pDoc, const OUString& rRefMark,
sal_uInt16 nSubType, sal_uInt16 nSeqNo,
sal_Int32* pStt, sal_Int32* pEnd = nullptr,
SwRootFrame const* pLayout = nullptr);
SwRootFrame const* pLayout = nullptr,
SwTextNode* pSelf = nullptr, SwFrame* pFrame = nullptr);
void UpdateGetReferences();
};
@@ -111,11 +115,13 @@ public:
// #i81002#
/** The <SwTextField> instance, which represents the text attribute for the
<SwGetRefField> instance, has to be passed to the method.
This <SwTextField> instance is needed for the reference format type REF_UPDOWN
and REF_NUMBER.
This <SwTextField> instance is needed for the reference format type REF_UPDOWN, REF_NUMBER
and REF_STYLE.
Note: This instance may be NULL (field in Undo/Redo). This will cause
no update for these reference format types. */
void UpdateField( const SwTextField* pFieldTextAttr );
void UpdateField( const SwTextField* pFieldTextAttr, SwFrame* pFrame );
void UpdateField( const SwTextField* pFieldTextAttr, SwFrame* pFrame,
const SwRootFrame* const pLayout, OUString& rText );
void SetExpand( const OUString& rStr );
@@ -126,9 +132,9 @@ public:
// --> #i81002#
bool IsRefToHeadingCrossRefBookmark() const;
bool IsRefToNumItemCrossRefBookmark() const;
const SwTextNode* GetReferencedTextNode() const;
const SwTextNode* GetReferencedTextNode(SwTextNode* pTextNode, SwFrame* pFrame) const;
// #i85090#
OUString GetExpandedTextOfReferencedTextNode(SwRootFrame const& rLayout) const;
OUString GetExpandedTextOfReferencedTextNode(SwRootFrame const& rLayout, SwTextNode* pTextNode, SwFrame* pFrame) const;
/// Get/set SequenceNo (of interest only for REF_SEQUENCEFLD).
sal_uInt16 GetSeqNo() const { return m_nSeqNo; }
@@ -138,6 +144,8 @@ public:
virtual OUString GetPar1() const override;
virtual void SetPar1(const OUString& rStr) override;
void SetText(OUString sText, SwRootFrame* pLayout);
virtual OUString GetPar2() const override;
virtual bool QueryValue( css::uno::Any& rVal, sal_uInt16 nWhichId ) const override;
virtual bool PutValue( const css::uno::Any& rVal, sal_uInt16 nWhichId ) override;
Binary file not shown.
+228
View File
@@ -7,6 +7,36 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/text/ControlCharacter.hpp>
#include <com/sun/star/text/ReferenceFieldPart.hpp>
#include <com/sun/star/text/ReferenceFieldSource.hpp>
#include <com/sun/star/text/XFootnote.hpp>
#include <com/sun/star/text/XFootnotesSupplier.hpp>
#include <com/sun/star/text/XSimpleText.hpp>
#include <com/sun/star/text/XTextField.hpp>
#include <com/sun/star/text/XTextRange.hpp>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/text/XPageCursor.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
#include <com/sun/star/text/XSimpleText.hpp>
#include <com/sun/star/text/XText.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/text/XPageCursor.hpp>
#include <com/sun/star/text/XTextCursor.hpp>
#include <com/sun/star/uno/Any.h>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/uno/Sequence.h>
#include <cppunit/TestAssert.h>
#include <cppunit/extensions/HelperMacros.h>
#include <rtl/ustring.hxx>
#include <sal/types.h>
#include <swmodeltestbase.hxx>
#include <com/sun/star/text/XTextDocument.hpp>
@@ -132,6 +162,204 @@ CPPUNIT_TEST_FIXTURE(Test, testChapterFieldsFollowedBy)
CPPUNIT_ASSERT_EQUAL(sValue, xField->getPresentation(false));
}
}
CPPUNIT_TEST_FIXTURE(Test, testTdf86790)
{
loadFromURL(u"tdf86790.docx");
uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<container::XEnumerationAccess> xFieldsAccess(
xTextFieldsSupplier->getTextFields());
uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
// Similarly to testChapterFieldsFollowedBy, the fields are enumerated with #1 first and everything else in reverse order
std::vector<std::pair<OUString, OUString>> aFieldValues = {
{ " Heading 1", "1" }, // #1
{ " foobar", "22.2" }, // #5
{ " foobar", "4" }, // #4
{ " Heading 2", "1.1" }, // #3
{ " Heading 2", "1.1" }, // #2
};
for (const auto& sValue : aFieldValues)
{
CPPUNIT_ASSERT(xFields->hasMoreElements());
uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(sValue.first, xField->getPresentation(true));
CPPUNIT_ASSERT_EQUAL(sValue.second, xField->getPresentation(false));
}
}
/// If there is referenced text both above and below, STYLEREF searches up
CPPUNIT_TEST_FIXTURE(Test, testStyleRefSearchUp)
{
createSwDoc();
uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
uno::Reference<text::XText> xText = xTextDocument->getText();
uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
uno::Reference<beans::XPropertySet> xCursorPropertySet(xCursor, uno::UNO_QUERY);
xCursorPropertySet->setPropertyValue("ParaStyleName", uno::Any(OUString("Heading 1")));
xText->insertString(xCursor, "Heading far above field", false);
xText->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
xCursorPropertySet->setPropertyValue("ParaStyleName", uno::Any(OUString("Heading 1")));
xText->insertString(xCursor, "Heading above field", false);
xText->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
uno::Reference<text::XTextField> xField(
xFactory->createInstance("com.sun.star.text.TextField.GetReference"), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xFieldPropertySet(xField, uno::UNO_QUERY);
xFieldPropertySet->setPropertyValue("ReferenceFieldSource",
uno::Any(sal_Int16(text::ReferenceFieldSource::STYLE)));
xFieldPropertySet->setPropertyValue("ReferenceFieldPart",
uno::Any(sal_Int16(text::ReferenceFieldPart::TEXT)));
xFieldPropertySet->setPropertyValue("SourceName", uno::Any(OUString("Heading 1")));
uno::Reference<text::XTextCursor> xFieldCursor = xText->createTextCursor();
xText->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
xCursorPropertySet->setPropertyValue("ParaStyleName", uno::Any(OUString("Heading 1")));
xText->insertString(xCursor, "Heading below field", false);
xField->attach(xFieldCursor);
CPPUNIT_ASSERT_EQUAL(OUString("Heading above field"), xField->getPresentation(false));
}
/// If there is referenced text both above and below, STYLEREF searches down
CPPUNIT_TEST_FIXTURE(Test, testStyleRefSearchDown)
{
createSwDoc();
uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
uno::Reference<text::XText> xText = xTextDocument->getText();
uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
uno::Reference<beans::XPropertySet> xCursorPropertySet(xCursor, uno::UNO_QUERY);
uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
uno::Reference<text::XTextField> xField(
xFactory->createInstance("com.sun.star.text.TextField.GetReference"), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xFieldPropertySet(xField, uno::UNO_QUERY);
xFieldPropertySet->setPropertyValue("ReferenceFieldSource",
uno::Any(sal_Int16(text::ReferenceFieldSource::STYLE)));
xFieldPropertySet->setPropertyValue("ReferenceFieldPart",
uno::Any(sal_Int16(text::ReferenceFieldPart::TEXT)));
xFieldPropertySet->setPropertyValue("SourceName", uno::Any(OUString("Heading 1")));
uno::Reference<text::XTextCursor> xFieldCursor = xText->createTextCursor();
xText->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
xCursorPropertySet->setPropertyValue("ParaStyleName", uno::Any(OUString("Heading 1")));
xText->insertString(xCursor, "Heading below field", false);
xText->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
xCursorPropertySet->setPropertyValue("ParaStyleName", uno::Any(OUString("Heading 1")));
xText->insertString(xCursor, "Heading far below field", false);
xField->attach(xFieldCursor);
CPPUNIT_ASSERT_EQUAL(OUString("Heading below field"), xField->getPresentation(false));
}
/// STYLEREFs in marginals (headers or footers) should search in the page they are on first, regardless if there is anything above them
CPPUNIT_TEST_FIXTURE(Test, testMarginalStyleRef)
{
createSwDoc();
uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
uno::Reference<text::XText> xText = xTextDocument->getText();
uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
uno::Reference<beans::XPropertySet> xCursorPropertySet(xCursor, uno::UNO_QUERY);
xCursorPropertySet->setPropertyValue("ParaStyleName", uno::Any(OUString("Heading 1")));
xText->insertString(xCursor, "Top heading on page", false);
xText->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
xCursorPropertySet->setPropertyValue("ParaStyleName", uno::Any(OUString("Heading 1")));
xText->insertString(xCursor, "Bottom heading on page", false);
xText->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
uno::Reference<text::XTextField> xField(
xFactory->createInstance("com.sun.star.text.TextField.GetReference"), uno::UNO_QUERY);
uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(mxComponent,
uno::UNO_QUERY);
uno::Reference<container::XNameContainer> xParagraphStylesContainer(
xStyleFamiliesSupplier->getStyleFamilies()->getByName("PageStyles"), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xPagePropertySet(
xParagraphStylesContainer->getByName("Standard"), uno::UNO_QUERY);
xPagePropertySet->setPropertyValue("FooterIsOn", uno::Any(true));
uno::Reference<text::XText> xFooterText(xPagePropertySet->getPropertyValue("FooterText"),
uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xFieldPropertySet(xField, uno::UNO_QUERY);
xFieldPropertySet->setPropertyValue("ReferenceFieldSource",
uno::Any(sal_Int16(text::ReferenceFieldSource::STYLE)));
xFieldPropertySet->setPropertyValue("ReferenceFieldPart",
uno::Any(sal_Int16(text::ReferenceFieldPart::TEXT)));
xFieldPropertySet->setPropertyValue("SourceName", uno::Any(OUString("Heading 1")));
uno::Reference<text::XTextRange> xFooterCursor = xFooterText->createTextCursor();
xField->attach(xFooterCursor);
CPPUNIT_ASSERT_EQUAL(OUString("Top heading on page"), xField->getPresentation(false));
}
/// STYLEREFs in footnotes should search from the point of the reference mark
CPPUNIT_TEST_FIXTURE(Test, testFootnoteStyleRef)
{
createSwDoc();
uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
uno::Reference<text::XText> xText = xTextDocument->getText();
uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
uno::Reference<beans::XPropertySet> xCursorPropertySet(xCursor, uno::UNO_QUERY);
xCursorPropertySet->setPropertyValue("ParaStyleName", uno::Any(OUString("Heading 1")));
xText->insertString(xCursor, "Heading far above reference mark", false);
xText->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
xCursorPropertySet->setPropertyValue("ParaStyleName", uno::Any(OUString("Heading 1")));
xText->insertString(xCursor, "Heading above reference mark", false);
xText->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
uno::Reference<text::XFootnote> xFootnote(
xFactory->createInstance("com.sun.star.text.Footnote"), uno::UNO_QUERY);
xFootnote->setLabel("Style reference mark");
xText->insertTextContent(xCursor, xFootnote, false);
xText->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
xCursorPropertySet->setPropertyValue("ParaStyleName", uno::Any(OUString("Heading 1")));
xText->insertString(xCursor, "Heading below reference mark", false);
uno::Reference<text::XTextField> xField(
xFactory->createInstance("com.sun.star.text.TextField.GetReference"), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xFieldPropertySet(xField, uno::UNO_QUERY);
xFieldPropertySet->setPropertyValue("ReferenceFieldSource",
uno::Any(sal_Int16(text::ReferenceFieldSource::STYLE)));
xFieldPropertySet->setPropertyValue("ReferenceFieldPart",
uno::Any(sal_Int16(text::ReferenceFieldPart::TEXT)));
xFieldPropertySet->setPropertyValue("SourceName", uno::Any(OUString("Heading 1")));
uno::Reference<text::XSimpleText> xFootnoteText(xFootnote, uno::UNO_QUERY);
uno::Reference<text::XTextRange> xFootnoteCursor = xFootnoteText->createTextCursor();
xField->attach(xFootnoteCursor);
CPPUNIT_ASSERT_EQUAL(OUString("Heading above reference mark"), xField->getPresentation(false));
}
}
CPPUNIT_PLUGIN_IMPLEMENT();
+1 -1
View File
@@ -582,7 +582,7 @@ DECLARE_OOXMLEXPORT_TEST(testMultiPageToc, "multi-page-toc.docx")
CPPUNIT_ASSERT_EQUAL(OUString("Table of Contents1"), xTextSection->getName());
// There should be a field in the header as well.
uno::Reference<text::XText> xHeaderText = getProperty< uno::Reference<text::XText> >(getStyles("PageStyles")->getByName("Standard"), "HeaderText");
CPPUNIT_ASSERT_EQUAL(OUString("TextFieldStart"), getProperty<OUString>(getRun(getParagraphOfText(1, xHeaderText), 1), "TextPortionType"));
CPPUNIT_ASSERT_EQUAL(OUString("TextField"), getProperty<OUString>(getRun(getParagraphOfText(1, xHeaderText), 1), "TextPortionType"));
}
DECLARE_OOXMLEXPORT_TEST(testTextboxTable, "textbox-table.docx")
+3 -3
View File
@@ -2454,9 +2454,9 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf128106)
CPPUNIT_ASSERT_EQUAL(sal_uInt16(REF_BOOKMARK), fields[0]->GetField()->GetSubType());
CPPUNIT_ASSERT_EQUAL(OUString("bookmarkchapter1_text"),
static_cast<SwGetRefField const*>(fields[0]->GetField())->GetSetRefName());
CPPUNIT_ASSERT_EQUAL(OUString("Text"),
static_cast<SwGetRefField const*>(fields[0]->GetField())
->GetExpandedTextOfReferencedTextNode(*pWrtShell->GetLayout()));
CPPUNIT_ASSERT_EQUAL(OUString("Text"), static_cast<SwGetRefField const*>(fields[0]->GetField())
->GetExpandedTextOfReferencedTextNode(
*pWrtShell->GetLayout(), nullptr, nullptr));
CPPUNIT_ASSERT_EQUAL(sal_uInt16(REF_BOOKMARK), fields[1]->GetField()->GetSubType());
CPPUNIT_ASSERT(
static_cast<SwGetRefField const*>(fields[1]->GetField())->IsRefToHeadingCrossRefBookmark());
+3
View File
@@ -1228,6 +1228,9 @@ OUString SwAccessibleParagraph::GetFieldTypeNameAtIndex(sal_Int32 nIndex)
case REF_SEQUENCEFLD:
sEntry = static_cast<const SwGetRefField*>(pField)->GetSetRefName();
break;
case REF_STYLE:
sEntry = "StyleRef";
break;
}
//Get format string
strTypeName = sEntry;
+8 -2
View File
@@ -1409,8 +1409,14 @@ bool SwCursorShell::GotoRefMark( const OUString& rRefMark, sal_uInt16 nSubType,
SwCursorSaveState aSaveState( *m_pCurrentCursor );
sal_Int32 nPos = -1;
SwTextNode* pTextNd = SwGetRefFieldType::FindAnchor( GetDoc(), rRefMark,
nSubType, nSeqNo, &nPos, nullptr, GetLayout());
SwPaM* pCursor = GetCursor();
SwPosition* pPos = pCursor->GetPoint();
SwTextNode* pRefTextNd = pPos->GetNode().GetTextNode();
SwContentFrame* pRefFrame = GetCurrFrame();
SwTextNode* pTextNd = SwGetRefFieldType::FindAnchor(GetDoc(), rRefMark,
nSubType, nSeqNo, &nPos, nullptr, GetLayout(), pRefTextNd, pRefFrame);
if( !pTextNd || !pTextNd->GetNodes().IsDocNodes() )
return false;
+390 -96
View File
@@ -42,6 +42,7 @@
#include <reffld.hxx>
#include <expfld.hxx>
#include <txtfrm.hxx>
#include <notxtfrm.hxx>
#include <flyfrm.hxx>
#include <pagedesc.hxx>
#include <IMark.hxx>
@@ -65,6 +66,7 @@
#include <string_view>
#include <map>
#include <algorithm>
#include <deque>
using namespace ::com::sun::star;
using namespace ::com::sun::star::text;
@@ -349,11 +351,11 @@ static void lcl_formatReferenceLanguage( OUString& rRefText,
SwGetRefField::SwGetRefField( SwGetRefFieldType* pFieldType,
OUString aSetRef, OUString aSetReferenceLanguage, sal_uInt16 nSubTyp,
sal_uInt16 nSequenceNo, sal_uLong nFormat )
: SwField( pFieldType, nFormat ),
m_sSetRefName( std::move(aSetRef) ),
m_sSetReferenceLanguage( std::move(aSetReferenceLanguage) ),
m_nSubType( nSubTyp ),
m_nSeqNo( nSequenceNo )
: SwField(pFieldType, nFormat),
m_sSetRefName(std::move(aSetRef)),
m_sSetReferenceLanguage(std::move(aSetReferenceLanguage)),
m_nSubType(nSubTyp),
m_nSeqNo(nSequenceNo)
{
}
@@ -361,6 +363,18 @@ SwGetRefField::~SwGetRefField()
{
}
void SwGetRefField::SetText(OUString sText, SwRootFrame* pLayout)
{
if (pLayout->IsHideRedlines())
{
m_sTextRLHidden = sText;
}
else
{
m_sText = sText;
}
}
OUString SwGetRefField::GetDescription() const
{
return SwResId(STR_REFERENCE);
@@ -389,13 +403,14 @@ bool SwGetRefField::IsRefToNumItemCrossRefBookmark() const
::sw::mark::CrossRefNumItemBookmark::IsLegalName(m_sSetRefName);
}
const SwTextNode* SwGetRefField::GetReferencedTextNode() const
const SwTextNode* SwGetRefField::GetReferencedTextNode(SwTextNode* pTextNode, SwFrame* pFrame) const
{
SwGetRefFieldType *pTyp = dynamic_cast<SwGetRefFieldType*>(GetTyp());
if (!pTyp)
return nullptr;
sal_Int32 nDummy = -1;
return SwGetRefFieldType::FindAnchor( &pTyp->GetDoc(), m_sSetRefName, m_nSubType, m_nSeqNo, &nDummy );
return SwGetRefFieldType::FindAnchor( &pTyp->GetDoc(), m_sSetRefName, m_nSubType, m_nSeqNo, &nDummy,
nullptr, nullptr, pTextNode, pFrame );
}
// strikethrough for tooltips using Unicode combining character
@@ -411,9 +426,9 @@ static OUString lcl_formatStringByCombiningCharacter(std::u16string_view sText,
// #i85090#
OUString SwGetRefField::GetExpandedTextOfReferencedTextNode(
SwRootFrame const& rLayout) const
SwRootFrame const& rLayout, SwTextNode* pTextNode, SwFrame* pFrame) const
{
const SwTextNode* pReferencedTextNode( GetReferencedTextNode() );
const SwTextNode* pReferencedTextNode( GetReferencedTextNode(pTextNode, pFrame) );
if ( !pReferencedTextNode )
return OUString();
@@ -481,38 +496,43 @@ static void FilterText(OUString & rText, LanguageType const eLang,
}
// #i81002# - parameter <pFieldTextAttr> added
void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr )
void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr, SwFrame* pFrame )
{
m_sText.clear();
m_sTextRLHidden.clear();
SwDoc& rDoc = static_cast<SwGetRefFieldType*>(GetTyp())->GetDoc();
for (SwRootFrame const* const pLay : rDoc.GetAllLayouts())
{
if (pLay->IsHideRedlines())
{
UpdateField(pFieldTextAttr, pFrame, pLay, m_sTextRLHidden);
}
else
{
UpdateField(pFieldTextAttr, pFrame, pLay, m_sText);
}
}
}
void SwGetRefField::UpdateField(const SwTextField* pFieldTextAttr, SwFrame* pFrameContainingField,
const SwRootFrame* const pLayout, OUString& rText)
{
SwDoc& rDoc = static_cast<SwGetRefFieldType*>(GetTyp())->GetDoc();
rText.clear();
// finding the reference target (the number)
sal_Int32 nNumStart = -1;
sal_Int32 nNumEnd = -1;
SwTextNode* pTextNd = SwGetRefFieldType::FindAnchor(
&rDoc, m_sSetRefName, m_nSubType, m_nSeqNo, &nNumStart, &nNumEnd
&rDoc, m_sSetRefName, m_nSubType, m_nSeqNo, &nNumStart, &nNumEnd,
pLayout, pFieldTextAttr ? pFieldTextAttr->GetpTextNode() : nullptr, pFrameContainingField
);
// not found?
if ( !pTextNd )
{
m_sText = SwViewShell::GetShellRes()->aGetRefField_RefItemNotFound;
m_sTextRLHidden = m_sText;
return ;
}
rText = SwViewShell::GetShellRes()->aGetRefField_RefItemNotFound;
SwRootFrame const* pLayout(nullptr);
SwRootFrame const* pLayoutRLHidden(nullptr);
for (SwRootFrame const*const pLay : rDoc.GetAllLayouts())
{
if (pLay->IsHideRedlines())
{
pLayoutRLHidden = pLay;
}
else
{
pLayout = pLay;
}
return;
}
// where is the category name (e.g. "Illustration")?
@@ -607,18 +627,21 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr )
SwTextFootnote* const pFootnoteIdx = rDoc.GetFootnoteIdxs()[i];
if( m_nSeqNo == pFootnoteIdx->GetSeqRefNo() )
{
m_sText = pFootnoteIdx->GetFootnote().GetViewNumStr(rDoc, nullptr);
m_sTextRLHidden = pFootnoteIdx->GetFootnote().GetViewNumStr(rDoc, pLayoutRLHidden);
rText = pFootnoteIdx->GetFootnote().GetViewNumStr(rDoc, pLayout);
if (!m_sSetReferenceLanguage.isEmpty())
{
lcl_formatReferenceLanguage(m_sText, false, GetLanguage(), m_sSetReferenceLanguage);
lcl_formatReferenceLanguage(m_sTextRLHidden, false, GetLanguage(), m_sSetReferenceLanguage);
lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
}
break;
}
}
return;
case REF_STYLE:
nStart = 0;
nEnd = nLen;
break;
case REF_SETREFATTR:
nStart = nNumStart;
nEnd = nNumEnd;
@@ -630,26 +653,32 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr )
if( nStart != nEnd ) // a section?
{
m_sText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false, false, ExpandMode::HideDeletions);
// show the referenced text without the deletions, but if the whole text was
// deleted, show the original text for the sake of the comfortable reviewing
// (with strikethrough in tooltip, see GetExpandedTextOfReferencedTextNode())
if ( m_sText.isEmpty() )
m_sText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false, false, ExpandMode(0));
if (m_nSubType == REF_OUTLINE
|| (m_nSubType == REF_SEQUENCEFLD && REF_CONTENT == GetFormat()))
if (pLayout->IsHideRedlines())
{
m_sTextRLHidden = sw::GetExpandTextMerged(
pLayoutRLHidden, *pTextNd, false, false, ExpandMode(0));
if (m_nSubType == REF_OUTLINE
|| (m_nSubType == REF_SEQUENCEFLD && REF_CONTENT == GetFormat()))
{
rText = sw::GetExpandTextMerged(pLayout, *pTextNd, false, false,
ExpandMode(0));
}
else
{
rText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false,
false, ExpandMode::HideDeletions);
}
}
else
{
m_sTextRLHidden = pTextNd->GetExpandText(pLayoutRLHidden,
nStart, nEnd - nStart, false, false, false, ExpandMode::HideDeletions);
rText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false,
false, ExpandMode::HideDeletions);
// show the referenced text without the deletions, but if the whole text was
// deleted, show the original text for the sake of the comfortable reviewing
// (with strikethrough in tooltip, see GetExpandedTextOfReferencedTextNode())
if (rText.isEmpty())
rText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false,
false, ExpandMode(0));
}
FilterText(m_sText, GetLanguage(), m_sSetReferenceLanguage);
FilterText(m_sTextRLHidden, GetLanguage(), m_sSetReferenceLanguage);
}
}
break;
@@ -657,10 +686,7 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr )
case REF_PAGE:
case REF_PAGE_PGDESC:
{
auto const func =
[this, pTextNd, nNumStart](OUString & rText, SwRootFrame const*const pLay)
{
SwTextFrame const* pFrame = static_cast<SwTextFrame*>(pTextNd->getLayoutFrame(pLay, nullptr, nullptr));
SwTextFrame const* pFrame = static_cast<SwTextFrame*>(pTextNd->getLayoutFrame(pLayout, nullptr, nullptr));
SwTextFrame const*const pSave = pFrame;
if (pFrame)
{
@@ -687,35 +713,25 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr )
if (!m_sSetReferenceLanguage.isEmpty())
lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
}
};
// sw_redlinehide: currently only one of these layouts will exist,
// so the getLayoutFrame will use the same frame in both cases
func(m_sText, pLayout);
func(m_sTextRLHidden, pLayoutRLHidden);
}
break;
case REF_CHAPTER:
{
// a bit tricky: search any frame
SwFrame const* const pFrame = pTextNd->getLayoutFrame(pLayout);
if (pFrame)
{
auto const func =
[this, pTextNd](OUString & rText, SwRootFrame const*const pLay)
{
// a bit tricky: search any frame
SwFrame const*const pFrame = pTextNd->getLayoutFrame(pLay);
if( pFrame )
{
SwChapterFieldType aFieldTyp;
SwChapterField aField( &aFieldTyp, 0 );
aField.SetLevel( MAXLEVEL - 1 );
aField.ChangeExpansion( *pFrame, pTextNd, true );
rText = aField.GetNumber(pLay);
SwChapterFieldType aFieldTyp;
SwChapterField aField(&aFieldTyp, 0);
aField.SetLevel(MAXLEVEL - 1);
aField.ChangeExpansion(*pFrame, pTextNd, true);
if (!m_sSetReferenceLanguage.isEmpty())
lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
}
};
func(m_sText, pLayout);
func(m_sTextRLHidden, pLayoutRLHidden);
rText = aField.GetNumber(pLayout);
if (!m_sSetReferenceLanguage.isEmpty())
lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
}
}
break;
@@ -731,22 +747,19 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr )
// first a "short" test - in case both are in the same node
if( pFieldTextAttr->GetpTextNode() == pTextNd )
{
m_sText = nNumStart < pFieldTextAttr->GetStart()
rText = nNumStart < pFieldTextAttr->GetStart()
? aLocaleData.getAboveWord()
: aLocaleData.getBelowWord();
m_sTextRLHidden = m_sText;
break;
}
m_sText = ::IsFrameBehind( *pFieldTextAttr->GetpTextNode(), pFieldTextAttr->GetStart(),
rText = ::IsFrameBehind( *pFieldTextAttr->GetpTextNode(), pFieldTextAttr->GetStart(),
*pTextNd, nNumStart )
? aLocaleData.getAboveWord()
: aLocaleData.getBelowWord();
if (!m_sSetReferenceLanguage.isEmpty())
lcl_formatReferenceLanguage(m_sText, false, GetLanguage(), m_sSetReferenceLanguage);
m_sTextRLHidden = m_sText;
lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
}
break;
// #i81002#
@@ -758,20 +771,12 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr )
{
auto result =
MakeRefNumStr(pLayout, pFieldTextAttr->GetTextNode(), *pTextNd, GetFormat());
m_sText = result.first;
rText = result.first;
// for differentiation of Roman numbers and letters in Hungarian article handling
bool bClosingParenthesis = result.second;
if (!m_sSetReferenceLanguage.isEmpty())
{
lcl_formatReferenceLanguage(m_sText, bClosingParenthesis, GetLanguage(), m_sSetReferenceLanguage);
}
result =
MakeRefNumStr(pLayoutRLHidden, pFieldTextAttr->GetTextNode(), *pTextNd, GetFormat());
m_sTextRLHidden = result.first;
bClosingParenthesis = result.second;
if (!m_sSetReferenceLanguage.isEmpty())
{
lcl_formatReferenceLanguage(m_sTextRLHidden, bClosingParenthesis, GetLanguage(), m_sSetReferenceLanguage);
lcl_formatReferenceLanguage(rText, bClosingParenthesis, GetLanguage(), m_sSetReferenceLanguage);
}
}
}
@@ -934,6 +939,7 @@ bool SwGetRefField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
case REF_OUTLINE : OSL_FAIL("not implemented"); break;
case REF_FOOTNOTE : nSource = ReferenceFieldSource::FOOTNOTE; break;
case REF_ENDNOTE : nSource = ReferenceFieldSource::ENDNOTE; break;
case REF_STYLE : nSource = ReferenceFieldSource::STYLE; break;
}
rAny <<= nSource;
}
@@ -1018,6 +1024,7 @@ bool SwGetRefField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
case ReferenceFieldSource::BOOKMARK : m_nSubType = REF_BOOKMARK ; break;
case ReferenceFieldSource::FOOTNOTE : m_nSubType = REF_FOOTNOTE ; break;
case ReferenceFieldSource::ENDNOTE : m_nSubType = REF_ENDNOTE ; break;
case ReferenceFieldSource::STYLE : m_nSubType = REF_STYLE ; break;
}
}
break;
@@ -1115,7 +1122,7 @@ void SwGetRefFieldType::UpdateGetReferences()
}
// #i81002#
pGRef->UpdateField(pFormatField->GetTextField());
pGRef->UpdateField(pFormatField->GetTextField(), nullptr);
}
CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
}
@@ -1166,10 +1173,53 @@ bool IsMarkHintHidden(SwRootFrame const& rLayout,
} // namespace sw
SwTextNode* SwGetRefFieldType::FindAnchor( SwDoc* pDoc, const OUString& rRefMark,
sal_uInt16 nSubType, sal_uInt16 nSeqNo,
sal_Int32* pStt, sal_Int32* pEnd,
SwRootFrame const*const pLayout)
namespace
{
enum StyleRefElementType
{
Default,
Reference, /* e.g. footnotes, endnotes */
Marginal, /* headers, footers */
};
/// Picks the first text node with a matching style from a double ended queue, starting at the front
/// This allows us to use the deque either as a stack or as a queue depending on whether we want to search up or down
SwTextNode* SearchForStyleAnchor(SwTextNode* pSelf, const std::deque<SwNode*>& pToSearch,
std::u16string_view rStyleName, bool bCaseSensitive = true)
{
std::deque<SwNode*> pSearching(pToSearch);
while (!pSearching.empty())
{
SwNode* pCurrent = pSearching.front();
pSearching.pop_front();
if (*pCurrent == *pSelf)
continue;
SwTextNode* pTextNode = pCurrent->GetTextNode();
if (!pTextNode)
continue;
if (bCaseSensitive)
{
if (pTextNode->GetFormatColl()->GetName() == rStyleName)
return pTextNode;
}
else
{
if (pTextNode->GetFormatColl()->GetName().equalsIgnoreAsciiCase(rStyleName))
return pTextNode;
}
}
return nullptr;
}
}
SwTextNode* SwGetRefFieldType::FindAnchor(SwDoc* pDoc, const OUString& rRefMark,
sal_uInt16 nSubType, sal_uInt16 nSeqNo, sal_Int32* pStt,
sal_Int32* pEnd, SwRootFrame const* const pLayout,
SwTextNode* pSelf, SwFrame* pContentFrame)
{
OSL_ENSURE( pStt, "Why did no one check the StartPos?" );
@@ -1284,6 +1334,250 @@ SwTextNode* SwGetRefFieldType::FindAnchor( SwDoc* pDoc, const OUString& rRefMark
}
}
break;
case REF_STYLE:
if (!pSelf) break;
const SwNodes& nodes = pDoc->GetNodes();
StyleRefElementType elementType = StyleRefElementType::Default;
const SwTextNode* pReference = nullptr;
{ /* Check if we're a footnote/endnote */
for (SwTextFootnote* pFootnoteIdx : pDoc->GetFootnoteIdxs())
{
if (pLayout && pLayout->IsHideRedlines()
&& sw::IsFootnoteDeleted(rIDRA, *pFootnoteIdx))
{
continue;
}
const SwNodeIndex* pIdx = pFootnoteIdx->GetStartNode();
if (pIdx)
{
SwNodeIndex aIdx(*pIdx, 1);
SwTextNode* pFootnoteNode = aIdx.GetNode().GetTextNode();
if (nullptr == pFootnoteNode)
pFootnoteNode
= static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
if (*pSelf == *pFootnoteNode)
{
elementType = StyleRefElementType::Reference;
pReference = &pFootnoteIdx->GetTextNode();
}
}
}
}
if (pDoc->IsInHeaderFooter(*pSelf))
{
elementType = StyleRefElementType::Marginal;
}
if (pReference == nullptr)
{
pReference = pSelf;
}
switch (elementType)
{
case Marginal:
{
// For marginals, styleref tries to act on the current page first
// 1. Get the page we're on, search it from top to bottom
Point aPt;
std::pair<Point, bool> const tmp(aPt, false);
if (!pContentFrame) SAL_WARN("xmloff.text", "<SwGetRefFieldType::FindAnchor(..)>: Missing content frame for marginal styleref");
const SwPageFrame* pPageFrame = nullptr;
if (pContentFrame)
pPageFrame = pContentFrame->FindPageFrame();
const SwNode* pPageStart(nullptr);
const SwNode* pPageEnd(nullptr);
if (pPageFrame)
{
const SwContentFrame* pPageStartFrame = pPageFrame->FindFirstBodyContent();
const SwContentFrame* pPageEndFrame = pPageFrame->FindLastBodyContent();
if (pPageStartFrame) {
if (pPageStartFrame->IsTextFrame())
{
pPageStart = static_cast<const SwTextFrame*>(pPageStartFrame)
->GetTextNodeFirst();
}
else
{
pPageStart
= static_cast<const SwNoTextFrame*>(pPageStartFrame)->GetNode();
}
}
if (pPageEndFrame) {
if (pPageEndFrame->IsTextFrame())
{
pPageEnd = static_cast<const SwTextFrame*>(pPageEndFrame)
->GetTextNodeFirst();
}
else
{
pPageEnd = static_cast<const SwNoTextFrame*>(pPageEndFrame)->GetNode();
}
}
}
if (!pPageStart || !pPageEnd)
{
pPageStart = pReference;
pPageEnd = pReference;
}
std::deque<SwNode*> pAbovePage;
std::deque<SwNode*> pInPage;
std::deque<SwNode*> pBelowPage;
bool beforeStart = true;
bool beforeEnd = true;
for (SwNodeOffset n(0); n < nodes.Count(); n++)
{
if (beforeStart && *pPageStart == *nodes[n])
{
beforeStart = false;
}
if (beforeStart)
{
pAbovePage.push_front(nodes[n]);
}
else if (beforeEnd)
{
pInPage.push_back(nodes[n]);
if (*pPageEnd == *nodes[n])
{
beforeEnd = false;
}
}
else
{
pBelowPage.push_back(nodes[n]);
}
}
pTextNd = SearchForStyleAnchor(pSelf, pInPage, rRefMark);
if (pTextNd)
{
break;
}
// 2. Search up from the top of the page
pTextNd = SearchForStyleAnchor(pSelf, pAbovePage, rRefMark);
if (pTextNd)
{
break;
}
// 3. Search down from the bottom of the page
pTextNd = SearchForStyleAnchor(pSelf, pBelowPage, rRefMark);
if (pTextNd)
{
break;
}
// Word has case insensitive styles. LO has case sensitive styles. If we didn't find
// it yet, maybe we could with a case insensitive search. Let's do that
pTextNd = SearchForStyleAnchor(pSelf, pInPage, rRefMark,
false /* bCaseSensitive */);
if (pTextNd)
{
break;
}
pTextNd = SearchForStyleAnchor(pSelf, pAbovePage, rRefMark,
false /* bCaseSensitive */);
if (pTextNd)
{
break;
}
pTextNd = SearchForStyleAnchor(pSelf, pBelowPage, rRefMark,
false /* bCaseSensitive */);
break;
}
case Reference:
case Default:
{
// Normally, styleref does searches around the field position
// For references, styleref acts from the position of the reference not the field
// Happily, the previous code saves either one into pReference, so the following is generic for both
std::deque<SwNode*> pNotBelowElement;
std::deque<SwNode*> pBelowElement;
bool beforeElement = true;
for (SwNodeOffset n(0); n < nodes.Count(); n++)
{
if (beforeElement)
{
pNotBelowElement.push_front(nodes[n]);
if (*pReference == *nodes[n])
{
beforeElement = false;
}
}
else
{
pBelowElement.push_back(nodes[n]);
}
}
// 1. Search up until we hit the top of the document
pTextNd = SearchForStyleAnchor(pSelf, pNotBelowElement, rRefMark);
if (pTextNd)
{
break;
}
// 2. Search down until we hit the bottom of the document
pTextNd = SearchForStyleAnchor(pSelf, pBelowElement, rRefMark);
if (pTextNd)
{
break;
}
// Again, we need to remember that Word styles are not case sensitive
pTextNd = SearchForStyleAnchor(pSelf, pNotBelowElement, rRefMark,
false /* bCaseSensitive */);
if (pTextNd)
{
break;
}
pTextNd = SearchForStyleAnchor(pSelf, pBelowElement, rRefMark,
false /* bCaseSensitive */);
break;
}
default:
OSL_FAIL("<SwGetRefFieldType::FindAnchor(..)> - unknown getref element type");
}
if (pTextNd)
{
*pStt = 0;
if (pEnd)
*pEnd = pTextNd->GetText().getLength();
}
break;
}
return pTextNd;
+9 -1
View File
@@ -240,7 +240,14 @@ SwExpandPortion *SwTextFormatter::NewFieldPortion( SwTextFormatInfo &rInf,
bPlaceHolder = true;
break;
case SwFieldIds::GetRef:
{
subType = static_cast<SwGetRefField*>(pField)->GetSubType();
if (!bName && subType == REF_STYLE)
{
static_cast<SwGetRefField*>(pField)->UpdateField(
static_txtattr_cast<SwTextField const*>(pHint), pFrame);
}
{
OUString const str( bName
? pField->GetFieldName()
@@ -251,7 +258,8 @@ SwExpandPortion *SwTextFormatter::NewFieldPortion( SwTextFormatInfo &rInf,
static_cast<SwFieldPortion*>(pRet)->m_nAttrFieldType = ATTR_BOOKMARKFLD;
else if( subType == REF_SETREFATTR )
static_cast<SwFieldPortion*>(pRet)->m_nAttrFieldType = ATTR_SETREFATTRFLD;
break;
}
break;
case SwFieldIds::DateTime:
subType = static_cast<SwDateTimeField*>(pField)->GetSubType();
{
+3
View File
@@ -642,6 +642,9 @@ public:
/// Find the bookmark name.
OUString GetBookmarkName( sal_uInt16 nTyp, const OUString* pName, sal_uInt16 nSeqNo );
/// Find out which style we should use in OOXML
OUString GetStyleRefName(const OUString& rName);
/// Use OutputItem() on an item set according to the parameters.
void OutputItemSet( const SfxItemSet& rSet, bool bPapFormat, bool bChpFormat, sal_uInt16 nScript, bool bExportParentItemSet );
+66 -21
View File
@@ -128,6 +128,7 @@
#include <fmthdft.hxx>
#include <authfld.hxx>
#include <dbfld.hxx>
#include <docsh.hxx>
#include "sprmids.hxx"
@@ -1071,6 +1072,18 @@ OUString MSWordExportBase::GetBookmarkName( sal_uInt16 nTyp, const OUString* pNa
return BookmarkToWord( sRet ); // #i43956# - encode bookmark accordingly
}
OUString MSWordExportBase::GetStyleRefName(const OUString& rName)
{
SwTextFormatColls* pTextFormatColls = m_rDoc.GetTextFormatColls();
SwTextFormatColl* pTextFormat = pTextFormatColls->FindFormatByName(rName);
if (pTextFormat == nullptr)
return "\"" + rName + "\"";
// Didn't find the style, just keep the original name
return "\"" + m_pStyles->GetStyleWWName(pTextFormat) + "\"";
}
/* File CHRATR.HXX: */
void WW8AttributeOutput::RTLAndCJKState( bool bIsRTL, sal_uInt16 nScript )
{
@@ -3319,26 +3332,45 @@ void AttributeOutputBase::TextField( const SwFormatField& rField )
sStr = FieldString(eField)
+ GetExport().GetBookmarkName(nSubType, nullptr, rRField.GetSeqNo());
break;
case REF_STYLE:
sStr = FieldString(ww::eSTYLEREF)
+ GetExport().GetStyleRefName(pField->GetPar1());
eField = ww::eSTYLEREF;
break;
}
if (eField != ww::eNONE)
OUString sExtraFlags = "\\h "; // by default, include a hyperlink
switch (eField)
{
switch (pField->GetFormat())
{
case REF_UPDOWN:
sStr += " \\p \\h "; // with hyperlink
break;
case REF_CHAPTER:
sStr += " \\n \\h "; // with hyperlink
break;
default:
sStr += " \\h "; // insert hyperlink
break;
}
GetExport().OutputField(pField, eField, sStr);
case ww::eNONE:
bWriteExpand = true;
break;
case ww::eSTYLEREF:
sExtraFlags = ""; // styleref fields do not work if they have a hyperlink
[[fallthrough]];
default:
switch (pField->GetFormat())
{
case REF_NUMBER:
sStr += " \\r " + sExtraFlags;
break;
case REF_NUMBER_FULL_CONTEXT:
sStr += " \\w " + sExtraFlags;
break;
case REF_UPDOWN:
sStr += " \\p " + sExtraFlags;
break;
case REF_NUMBER_NO_CONTEXT:
case REF_CHAPTER:
sStr += " \\n " + sExtraFlags;
break;
default:
sStr += " " + sExtraFlags;
break;
}
GetExport().OutputField(pField, eField, sStr);
}
else
bWriteExpand = true;
}
break;
case SwFieldIds::CombinedChars:
@@ -3388,7 +3420,8 @@ void AttributeOutputBase::TextField( const SwFormatField& rField )
break;
case SwFieldIds::Chapter:
bWriteExpand = true;
if (GetExport().m_bOutKF && rField.GetTextField())
if (rField.GetTextField())
{
const SwTextNode *pTextNd = GetExport().GetHdFtPageRoot();
if (!pTextNd)
@@ -3400,10 +3433,22 @@ void AttributeOutputBase::TextField( const SwFormatField& rField )
{
SwChapterField aCopy(*static_cast<const SwChapterField*>(pField));
aCopy.ChangeExpansion(*pTextNd, false);
const OUString sStr = FieldString(ww::eSTYLEREF)
+ " "
+ OUString::number(aCopy.GetLevel() + 1)
+ " \\* MERGEFORMAT ";
OUString sStr;
if (GetExport().m_bOutKF) {
// In headers and footers, use the chapter number as the style name
sStr = FieldString(ww::eSTYLEREF)
+ " "
+ OUString::number(aCopy.GetLevel() + 1)
+ " \\* MERGEFORMAT ";
} else {
// Otherwise, get the style of the text and use it as the style name
const SwTextNode* pOutlineNd = pTextNd->FindOutlineNodeOfLevel(aCopy.GetLevel());
sStr = FieldString(ww::eSTYLEREF)
+ GetExport().GetStyleRefName(pOutlineNd->GetFormatColl()->GetName());
}
GetExport().OutputField(pField, ww::eSTYLEREF, sStr);
bWriteExpand = false;
}
+3 -4
View File
@@ -969,8 +969,7 @@ tools::Long SwWW8ImplReader::Read_Field(WW8PLCFManResult* pRes)
bool bHasHandler = aWW8FieldTab[aF.nId] != nullptr;
if (aF.nId == 10) // STYLEREF
{
// STYLEREF, by default these are not handled.
bHasHandler = false;
bool bHandledByChapter = false;
sal_uInt64 nOldPos = m_pStrm->Tell();
OUString aStr;
aF.nLCode = m_xSBase->WW8ReadString(*m_pStrm, aStr, m_xPlcxMan->GetCpOfs() + aF.nSCode, aF.nLCode, m_eTextCharSet);
@@ -980,9 +979,9 @@ tools::Long SwWW8ImplReader::Read_Field(WW8PLCFManResult* pRes)
sal_Int32 nRet = aReadParam.SkipToNextToken();
if (nRet == -2 && !aReadParam.GetResult().isEmpty())
// Single numeric argument: this can be handled by SwChapterField.
bHasHandler = rtl::isAsciiDigit(aReadParam.GetResult()[0]);
bHandledByChapter = rtl::isAsciiDigit(aReadParam.GetResult()[0]);
if (bHasHandler)
if (bHandledByChapter)
{
nRet = aReadParam.SkipToNextToken();
// Handle using SwChapterField only in case there is no \[a-z]
+66 -4
View File
@@ -47,6 +47,9 @@
// #i83479#
#define REFFLDFLAG_HEADING 0x7100
#define REFFLDFLAG_NUMITEM 0x7200
#define REFFLDFLAG_STYLE 0xc000
/* we skip past 0x8000, 0x9000, 0xa000 and 0xb000 as when we bitwise 'and'
with REFFLDFLAG they are false */
static sal_uInt16 nFieldDlgFormatSel = 0;
@@ -82,6 +85,7 @@ SwFieldRefPage::SwFieldRefPage(weld::Container* pPage, weld::DialogController* p
// #i83479#
m_sHeadingText = m_xTypeLB->get_text(3);
m_sNumItemText = m_xTypeLB->get_text(4);
m_sStyleText = m_xTypeLB->get_text(5);
auto nHeight = m_xTypeLB->get_height_rows(8);
auto nWidth = m_xTypeLB->get_approximate_digit_width() * FIELD_COLUMN_WIDTH;
@@ -239,6 +243,9 @@ void SwFieldRefPage::Reset(const SfxItemSet* )
m_xTypeLB->append(OUString::number(REFFLDFLAG_ENDNOTE), m_sEndnoteText);
}
// stylerefs
m_xTypeLB->append(OUString::number(REFFLDFLAG_STYLE), m_sStyleText);
m_xTypeLB->thaw();
// select old Pos
@@ -274,7 +281,7 @@ void SwFieldRefPage::Reset(const SfxItemSet* )
}
}
TypeHdl(*m_xTypeLB);
if (nFormatBoxPosition < m_xFormatLB->n_children())
if (!IsFieldEdit() && nFormatBoxPosition < m_xFormatLB->n_children())
{
m_xFormatLB->select(nFormatBoxPosition);
}
@@ -356,6 +363,17 @@ IMPL_LINK_NOARG(SwFieldRefPage, TypeHdl, weld::TreeView&, void)
nFlag = REFFLDFLAG;
break;
}
case REF_STYLE:
{
SwGetRefField const*const pRefField(dynamic_cast<SwGetRefField*>(GetCurField()));
if (pRefField)
{
sName = pRefField->GetPar1();
}
nFlag = REFFLDFLAG_STYLE;
break;
}
}
if (m_xTypeLB->find_text(sName) == -1) // reference to deleted mark
@@ -610,7 +628,7 @@ void SwFieldRefPage::UpdateSubType(const OUString& filterString)
m_xSelectionToolTipLB->append(sId,
pIDoc->getOutlineText(nOutlIdx, pSh->GetLayout(), true, true, false));
if ((IsFieldEdit() && pRefField
&& pRefField->GetReferencedTextNode() == maOutlineNodes[nOutlIdx])
&& pRefField->GetReferencedTextNode(nullptr, nullptr) == maOutlineNodes[nOutlIdx])
|| mpSavedSelectedTextNode == maOutlineNodes[nOutlIdx])
{
m_sSelectionToolTipLBId = sId;
@@ -645,7 +663,7 @@ void SwFieldRefPage::UpdateSubType(const OUString& filterString)
m_xSelectionToolTipLB->append(sId,
pIDoc->getListItemText(*maNumItems[nNumItemIdx], *pSh->GetLayout()));
if ((IsFieldEdit() && pRefField
&& pRefField->GetReferencedTextNode() == maNumItems[nNumItemIdx]->GetTextNode())
&& pRefField->GetReferencedTextNode(nullptr, nullptr) == maNumItems[nNumItemIdx]->GetTextNode())
|| mpSavedSelectedTextNode == maNumItems[nNumItemIdx]->GetTextNode())
{
m_sSelectionToolTipLBId = sId;
@@ -660,6 +678,32 @@ void SwFieldRefPage::UpdateSubType(const OUString& filterString)
}
}
}
else if (nTypeId == REFFLDFLAG_STYLE)
{
const IDocumentOutlineNodes* pIDoc(pSh->getIDocumentOutlineNodesAccess());
pIDoc->getOutlineNodes(maOutlineNodes);
SfxStyleSheetBasePool* pStyleSheetPool
= pSh->GetDoc()->GetDocShell()->GetStyleSheetPool();
auto stylesheetIterator
= pStyleSheetPool->CreateIterator(SfxStyleFamily::Para, SfxStyleSearchBits::Used);
SfxStyleSheetBase* pStyle = stylesheetIterator->First();
while (pStyle != nullptr)
{
bool isSubstring = MatchSubstring(pStyle->GetName(), filterString);
if (isSubstring)
{
m_xSelectionLB->append_text(pStyle->GetName());
}
pStyle = stylesheetIterator->Next();
}
if (IsFieldEdit() && pRefField)
sOldSel = pRefField->GetPar1();
}
else
{
// get the fields to Seq-FieldType:
@@ -803,6 +847,7 @@ sal_Int32 SwFieldRefPage::FillFormatLB(sal_uInt16 nTypeId)
// reference has less that the annotation
sal_uInt16 nSize( 0 );
sal_uInt16 nOffset( 0 );
bool bAddCrossRefFormats( false );
switch (nTypeId)
{
@@ -818,6 +863,11 @@ sal_Int32 SwFieldRefPage::FillFormatLB(sal_uInt16 nTypeId)
case REFFLDFLAG_ENDNOTE:
nSize = FMT_REF_PAGE_PGDSC_IDX + 1;
break;
case REFFLDFLAG_STYLE:
nOffset = FMT_REF_TEXT_IDX;
nSize = FMT_REF_UPDOWN_IDX + 1 - nOffset;
bAddCrossRefFormats = true;
break;
default:
// #i83479#
@@ -837,7 +887,7 @@ sal_Int32 SwFieldRefPage::FillFormatLB(sal_uInt16 nTypeId)
nTypeId = static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef);
SwFieldTypesEnum nFieldType = static_cast<SwFieldTypesEnum>(nTypeId);
for (sal_uInt16 i = 0; i < nSize; i++)
for (sal_uInt16 i = nOffset; i < nSize + nOffset; i++)
{
OUString sId(OUString::number(GetFieldMgr().GetFormatId( nFieldType, i )));
m_xFormatLB->append(sId, GetFieldMgr().GetFormatStr(nFieldType, i));
@@ -1077,6 +1127,18 @@ bool SwFieldRefPage::FillItemSet(SfxItemSet* )
}
}
}
else if (nTypeId == REFFLDFLAG_STYLE)
{
int nEntry = m_xSelectionLB->get_selected_index();
if (nEntry != -1)
{
aName = m_xSelectionLB->get_text(nEntry);
nTypeId = static_cast<sal_uInt16>(SwFieldTypesEnum::GetRef);
nSubType = REF_STYLE;
} else {
SAL_WARN("sw.ui", "<SwFieldRefPage::FillItemSet(..)> no entry selected in selection listbox!");
}
}
else // SequenceFields
{
// get fields for Seq-FieldType:
+1
View File
@@ -34,6 +34,7 @@ class SwFieldRefPage : public SwFieldPage
// #i83479#
OUString m_sHeadingText;
OUString m_sNumItemText;
OUString m_sStyleText;
IDocumentOutlineNodes::tSortedOutlineNodeList maOutlineNodes;
IDocumentListItems::tSortedNodeNumList maNumItems;
+1 -1
View File
@@ -567,7 +567,7 @@ void SwEditWin::RequestHelp(const HelpEvent &rEvt)
if ( pRefField->IsRefToHeadingCrossRefBookmark() ||
pRefField->IsRefToNumItemCrossRefBookmark() )
{
sText = pRefField->GetExpandedTextOfReferencedTextNode(*rSh.GetLayout());
sText = pRefField->GetExpandedTextOfReferencedTextNode(*rSh.GetLayout(), nullptr, nullptr);
if ( sText.getLength() > 80 )
{
sText = OUString::Concat(sText.subView(0, 80)) + "...";
+3
View File
@@ -66,6 +66,8 @@
#include <authfld.hxx>
#include <flddat.hxx>
#include <fldmgr.hxx>
#include <ndtxt.hxx>
#include <cntfrm.hxx>
#include <flddropdown.hxx>
#include <strings.hrc>
#include <tox.hxx>
@@ -1132,6 +1134,7 @@ bool SwFieldMgr::InsertField(
}
nFormatId %= SAL_N_ELEMENTS(FMT_REF_ARY);
}
pField.reset(new SwGetRefField(pTyp, rData.m_sPar1, sReferenceLanguage, nSubType, nSeqNo, nFormatId));
bExp = true;
break;
+1 -1
View File
@@ -707,7 +707,7 @@ void SwContentType::FillMemberList(bool* pbContentChanged)
{
OUString sExpandedTextOfReferencedTextNode =
pRefField->GetExpandedTextOfReferencedTextNode(
*m_pWrtShell->GetLayout());
*m_pWrtShell->GetLayout(), nullptr, nullptr);
if (sExpandedTextOfReferencedTextNode.getLength() > 80)
{
sExpandedTextOfReferencedTextNode = OUString::Concat(
@@ -5829,7 +5829,7 @@ static const FieldConversionMap_t & lcl_GetFieldConversion()
{"SEQ", {"SetExpression", FIELD_SEQ }},
{"SET", {"SetExpression", FIELD_SET }},
// {"SKIPIF", {"", FIELD_SKIPIF }},
// {"STYLEREF", {"", FIELD_STYLEREF }},
{"STYLEREF", {"GetReference", FIELD_STYLEREF }},
{"SUBJECT", {"DocInfo.Subject", FIELD_SUBJECT }},
{"SYMBOL", {"", FIELD_SYMBOL }},
{"TEMPLATE", {"TemplateName", FIELD_TEMPLATE }},
@@ -7519,9 +7519,11 @@ void DomainMapper_Impl::CloseFieldCommand()
break;
case FIELD_PAGEREF:
case FIELD_REF:
case FIELD_STYLEREF:
if (xFieldProperties.is() && !IsInTOC())
{
bool bPageRef = aIt->second.eFieldId == FIELD_PAGEREF;
bool bStyleRef = aIt->second.eFieldId == FIELD_STYLEREF;
// Do we need a GetReference (default) or a GetExpression field?
uno::Reference< text::XTextFieldsSupplier > xFieldsSupplier( GetTextDocument(), uno::UNO_QUERY );
@@ -7531,12 +7533,50 @@ void DomainMapper_Impl::CloseFieldCommand()
"com.sun.star.text.FieldMaster.SetExpression."
+ sFirstParam))
{
xFieldProperties->setPropertyValue(
getPropertyName(PROP_REFERENCE_FIELD_SOURCE),
uno::Any( sal_Int16(text::ReferenceFieldSource::BOOKMARK)) );
xFieldProperties->setPropertyValue(
getPropertyName(PROP_SOURCE_NAME),
uno::Any(sFirstParam) );
if (bStyleRef)
{
xFieldProperties->setPropertyValue(
getPropertyName(PROP_REFERENCE_FIELD_SOURCE),
uno::Any(sal_Int16(text::ReferenceFieldSource::STYLE)));
OUString sStyleSheetName
= GetStyleSheetTable()->ConvertStyleName(sFirstParam, true);
uno::Any aStyleDisplayName;
uno::Reference<style::XStyleFamiliesSupplier> xStylesSupplier(
GetTextDocument(), uno::UNO_QUERY_THROW);
uno::Reference<container::XNameAccess> xStyleFamilies
= xStylesSupplier->getStyleFamilies();
uno::Reference<container::XNameAccess> xStyles;
xStyleFamilies->getByName(getPropertyName(PROP_PARAGRAPH_STYLES))
>>= xStyles;
uno::Reference<css::beans::XPropertySet> xStyle;
try
{
xStyles->getByName(sStyleSheetName) >>= xStyle;
aStyleDisplayName = xStyle->getPropertyValue("DisplayName");
}
catch (css::container::NoSuchElementException)
{
aStyleDisplayName <<= sStyleSheetName;
}
xFieldProperties->setPropertyValue(
getPropertyName(PROP_SOURCE_NAME), aStyleDisplayName);
}
else
{
xFieldProperties->setPropertyValue(
getPropertyName(PROP_REFERENCE_FIELD_SOURCE),
uno::Any( sal_Int16(text::ReferenceFieldSource::BOOKMARK)) );
xFieldProperties->setPropertyValue(
getPropertyName(PROP_SOURCE_NAME),
uno::Any(sFirstParam));
}
sal_Int16 nFieldPart = (bPageRef ? text::ReferenceFieldPart::PAGE : text::ReferenceFieldPart::TEXT);
OUString sValue;
if( lcl_FindInCommand( pContext->GetCommand(), 'p', sValue ))
@@ -7631,7 +7671,6 @@ void DomainMapper_Impl::CloseFieldCommand()
handleFieldSet(pContext, xFieldInterface, xFieldProperties);
break;
case FIELD_SKIPIF : break;
case FIELD_STYLEREF : break;
case FIELD_SUBJECT :
{
if (!sFirstParam.isEmpty())
+3 -2
View File
@@ -209,8 +209,9 @@ enum FieldId
*/
,FIELD_SKIPIF
/* STYLEREF stylename \* MERGEFORMAT ->
not imported in old ww8 filter
todo: add an equivalent field type
implemented using GetReference, but some switches are not implemented yet
\l isn't implemented
\t isn't implemented
*/
,FIELD_STYLEREF
/* SUBJECT subject \* Defaultswitch \* MERGEFORMAT ->
+1
View File
@@ -119,6 +119,7 @@ enum FieldIdEnum {
FIELD_ID_REF_BOOKMARK, // get reference field (bookmark)
FIELD_ID_REF_FOOTNOTE, // get reference field (footnote)
FIELD_ID_REF_ENDNOTE, // get reference field (endnote)
FIELD_ID_REF_STYLE, // styleref field
FIELD_ID_DDE, // DDE field
FIELD_ID_BIBLIOGRAPHY, // bibliography index entry
+1
View File
@@ -1915,6 +1915,7 @@ namespace xmloff::token {
TOKEN( "structure-protected", XML_STRUCTURE_PROTECTED ),
TOKEN( "style", XML_STYLE ),
TOKEN( "style-name", XML_STYLE_NAME ),
TOKEN( "style-ref", XML_STYLE_REF ),
TOKEN( "styles", XML_STYLES ),
TOKEN( "stylesheet", XML_STYLESHEET ),
TOKEN( "sub-table", XML_SUB_TABLE ),
+32
View File
@@ -563,6 +563,9 @@ enum FieldIdEnum XMLTextFieldExport::MapFieldName(
case ReferenceFieldSource::ENDNOTE:
nToken = FIELD_ID_REF_ENDNOTE;
break;
case ReferenceFieldSource::STYLE:
nToken = FIELD_ID_REF_STYLE;
break;
default:
nToken = FIELD_ID_UNKNOWN;
break;
@@ -703,6 +706,7 @@ bool XMLTextFieldExport::IsStringField(
case FIELD_ID_REF_BOOKMARK:
case FIELD_ID_REF_FOOTNOTE:
case FIELD_ID_REF_ENDNOTE:
case FIELD_ID_REF_STYLE:
case FIELD_ID_MACRO:
case FIELD_ID_TEMPLATE_NAME:
case FIELD_ID_CHAPTER:
@@ -914,6 +918,7 @@ void XMLTextFieldExport::ExportFieldAutoStyle(
case FIELD_ID_REF_BOOKMARK:
case FIELD_ID_REF_FOOTNOTE:
case FIELD_ID_REF_ENDNOTE:
case FIELD_ID_REF_STYLE:
case FIELD_ID_MACRO:
case FIELD_ID_REFPAGE_SET:
case FIELD_ID_REFPAGE_GET:
@@ -1646,6 +1651,30 @@ void XMLTextFieldExport::ExportFieldHelper(
sPresentation);
break;
case FIELD_ID_REF_STYLE:
{
ProcessString(XML_REFERENCE_FORMAT,
MapReferenceType(GetInt16Property(gsPropertyReferenceFieldPart, rPropSet)),
XML_TEMPLATE);
ProcessString(XML_REF_NAME, GetStringProperty(gsPropertySourceName, rPropSet));
if (xPropSetInfo->hasPropertyByName(gsPropertyReferenceFieldLanguage)
&& GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
{
// export text:reference-language attribute, if not empty
ProcessString(XML_REFERENCE_LANGUAGE,
GetStringProperty(gsPropertyReferenceFieldLanguage, rPropSet), true,
XML_NAMESPACE_LO_EXT);
}
SvXMLElementExport aElem(
GetExport(),
XML_NAMESPACE_LO_EXT,
MapReferenceSource(GetInt16Property(gsPropertyReferenceFieldSource, rPropSet)),
false,
false);
GetExport().Characters(sPresentation);
break;
}
case FIELD_ID_DDE:
// name from field master
ProcessString(XML_CONNECTION_NAME,
@@ -3160,6 +3189,9 @@ enum XMLTokenEnum XMLTextFieldExport::MapReferenceSource(sal_Int16 nType)
case ReferenceFieldSource::ENDNOTE:
eElement = XML_NOTE_REF;
break;
case ReferenceFieldSource::STYLE:
eElement = XML_STYLE_REF;
break;
default:
OSL_FAIL("unknown reference source");
break;
+5
View File
@@ -407,6 +407,7 @@ XMLTextFieldImportContext::CreateTextFieldImportContext(
case XML_ELEMENT(TEXT, XML_BOOKMARK_REF):
case XML_ELEMENT(TEXT, XML_NOTE_REF):
case XML_ELEMENT(TEXT, XML_SEQUENCE_REF):
case XML_ELEMENT(LO_EXT, XML_STYLE_REF):
pContext = new XMLReferenceFieldImportContext( rImport, rHlp, nToken );
break;
@@ -2509,6 +2510,9 @@ void XMLReferenceFieldImportContext::startFastElement(
case XML_ELEMENT(TEXT, XML_SEQUENCE_REF):
nSource = ReferenceFieldSource::SEQUENCE_FIELD;
break;
case XML_ELEMENT(LO_EXT, XML_STYLE_REF):
nSource = ReferenceFieldSource::STYLE;
break;
default:
XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElementToken);
bTypeOK = false;
@@ -2577,6 +2581,7 @@ void XMLReferenceFieldImportContext::PrepareField(
{
case XML_ELEMENT(TEXT, XML_REFERENCE_REF):
case XML_ELEMENT(TEXT, XML_BOOKMARK_REF):
case XML_ELEMENT(LO_EXT, XML_STYLE_REF):
xPropertySet->setPropertyValue("SourceName", Any(sName));
break;
+1
View File
@@ -1815,6 +1815,7 @@ stroke-width
structure-protected
style
style-name
style-ref
styles
stylesheet
sub-table