1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <swmodeltestbase.hxx>
12 #include <com/sun/star/frame/XStorable.hpp>
13 #include <com/sun/star/text/BibliographyDataType.hpp>
14 #include <com/sun/star/text/ControlCharacter.hpp>
15 #include <com/sun/star/text/XDocumentIndex.hpp>
16 #include <com/sun/star/text/XTextDocument.hpp>
18 #include <comphelper/propertyvalue.hxx>
20 #include <IDocumentFieldsAccess.hxx>
21 #include <authfld.hxx>
26 /// Covers sw/source/core/tox/ fixes.
27 class Test
: public SwModelTestBase
31 CPPUNIT_TEST_FIXTURE(Test
, testAuthorityLinkClick
)
33 // Create a document with a bibliography reference (of type WWW) in it.
35 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
36 uno::Reference
<beans::XPropertySet
> xField(
37 xFactory
->createInstance(u
"com.sun.star.text.TextField.Bibliography"_ustr
), uno::UNO_QUERY
);
38 uno::Sequence
<beans::PropertyValue
> aFields
= {
39 comphelper::makePropertyValue(u
"BibiliographicType"_ustr
, text::BibliographyDataType::WWW
),
40 comphelper::makePropertyValue(u
"Identifier"_ustr
, u
"ARJ00"_ustr
),
41 comphelper::makePropertyValue(u
"Author"_ustr
, u
"Ar, J"_ustr
),
42 comphelper::makePropertyValue(u
"Title"_ustr
, u
"mytitle"_ustr
),
43 comphelper::makePropertyValue(u
"Year"_ustr
, u
"2020"_ustr
),
44 comphelper::makePropertyValue(u
"URL"_ustr
, u
"http://www.example.com/test.pdf"_ustr
),
46 xField
->setPropertyValue(u
"Fields"_ustr
, uno::Any(aFields
));
47 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
48 uno::Reference
<text::XText
> xText
= xTextDocument
->getText();
49 uno::Reference
<text::XTextCursor
> xCursor
= xText
->createTextCursor();
50 uno::Reference
<text::XTextContent
> xContent(xField
, uno::UNO_QUERY
);
51 xText
->insertTextContent(xCursor
, xContent
, /*bAbsorb=*/false);
52 // Create a bibliography table.
53 uno::Reference
<text::XTextContent
> xTable(
54 xFactory
->createInstance(u
"com.sun.star.text.Bibliography"_ustr
), uno::UNO_QUERY
);
55 xCursor
->gotoEnd(/*bExpand=*/false);
56 xText
->insertControlCharacter(xCursor
, text::ControlCharacter::APPEND_PARAGRAPH
,
58 xText
->insertTextContent(xCursor
, xTable
, /*bAbsorb=*/false);
61 uno::Reference
<text::XDocumentIndex
> xTableIndex(xTable
, uno::UNO_QUERY
);
62 xTableIndex
->update();
64 // Paragraph index: Reference, table header, table row.
65 // Portion index: ID, etc; then the URL.
66 auto aActual
= getProperty
<OUString
>(getRun(getParagraph(3), 2), u
"HyperLinkURL"_ustr
);
67 // Without the accompanying fix in place, this test would have failed with:
68 // An uncaught exception of type com.sun.star.container.NoSuchElementException
69 // i.e. the URL was not clickable and the table row was a single text portion.
70 CPPUNIT_ASSERT_EQUAL(u
"http://www.example.com/test.pdf"_ustr
, aActual
);
73 CPPUNIT_TEST_FIXTURE(Test
, testAuthorityTableEntryURL
)
75 // Given a document with a bibliography reference (of type WWW) in it:
77 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
78 uno::Reference
<beans::XPropertySet
> xField(
79 xFactory
->createInstance(u
"com.sun.star.text.TextField.Bibliography"_ustr
), uno::UNO_QUERY
);
80 uno::Sequence
<beans::PropertyValue
> aFields
= {
81 comphelper::makePropertyValue(u
"BibiliographicType"_ustr
, text::BibliographyDataType::WWW
),
82 comphelper::makePropertyValue(u
"Identifier"_ustr
, u
"AT"_ustr
),
83 comphelper::makePropertyValue(u
"Author"_ustr
, u
"Author"_ustr
),
84 comphelper::makePropertyValue(u
"Title"_ustr
, u
"Title"_ustr
),
85 comphelper::makePropertyValue(u
"URL"_ustr
, u
"http://www.example.com/test.pdf#page=1"_ustr
),
87 xField
->setPropertyValue(u
"Fields"_ustr
, uno::Any(aFields
));
88 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
89 uno::Reference
<text::XText
> xText
= xTextDocument
->getText();
90 uno::Reference
<text::XTextCursor
> xCursor
= xText
->createTextCursor();
91 uno::Reference
<text::XTextContent
> xContent(xField
, uno::UNO_QUERY
);
92 xText
->insertTextContent(xCursor
, xContent
, /*bAbsorb=*/false);
93 // Create a bibliography table.
94 uno::Reference
<text::XTextContent
> xTable(
95 xFactory
->createInstance(u
"com.sun.star.text.Bibliography"_ustr
), uno::UNO_QUERY
);
96 xCursor
->gotoEnd(/*bExpand=*/false);
97 xText
->insertControlCharacter(xCursor
, text::ControlCharacter::APPEND_PARAGRAPH
,
99 xText
->insertTextContent(xCursor
, xTable
, /*bAbsorb=*/false);
101 // When updating that table:
102 uno::Reference
<text::XDocumentIndex
> xTableIndex(xTable
, uno::UNO_QUERY
);
103 xTableIndex
->update();
105 // Then the page number from the source's URL should be stripped:
106 // Paragraph index: Reference, table header, table row.
107 // Portion index: ID, etc; then the URL.
108 auto aActual
= getProperty
<OUString
>(getRun(getParagraph(3), 2), u
"HyperLinkURL"_ustr
);
109 // Without the accompanying fix in place, this test would have failed with:
110 // - Expected: http://www.example.com/test.pdf
111 // - Actual : http://www.example.com/test.pdf#page=1
112 // i.e. the page number was still part of the bibliography table.
113 CPPUNIT_ASSERT_EQUAL(u
"http://www.example.com/test.pdf"_ustr
, aActual
);
116 CPPUNIT_TEST_FIXTURE(Test
, testAuthorityTableEntryClick
)
118 // Given an empty document:
120 SwDoc
* pDoc
= getSwDoc();
122 // When inserting a biblio entry field with an URL:
123 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
124 uno::Reference
<beans::XPropertySet
> xField(
125 xFactory
->createInstance(u
"com.sun.star.text.TextField.Bibliography"_ustr
), uno::UNO_QUERY
);
126 uno::Sequence
<beans::PropertyValue
> aFields
= {
127 comphelper::makePropertyValue(u
"BibiliographicType"_ustr
, text::BibliographyDataType::WWW
),
128 comphelper::makePropertyValue(u
"Identifier"_ustr
, u
"AT"_ustr
),
129 comphelper::makePropertyValue(u
"Author"_ustr
, u
"Author"_ustr
),
130 comphelper::makePropertyValue(u
"Title"_ustr
, u
"Title"_ustr
),
131 comphelper::makePropertyValue(u
"URL"_ustr
, u
"http://www.example.com/test.pdf#page=1"_ustr
),
133 xField
->setPropertyValue(u
"Fields"_ustr
, uno::Any(aFields
));
134 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
135 uno::Reference
<text::XText
> xText
= xTextDocument
->getText();
136 uno::Reference
<text::XTextCursor
> xCursor
= xText
->createTextCursor();
137 uno::Reference
<text::XTextContent
> xContent(xField
, uno::UNO_QUERY
);
138 xText
->insertTextContent(xCursor
, xContent
, /*bAbsorb=*/false);
140 // Then make sure that the field is clickable, since the page part will not be part of the
141 // bibliography table:
142 const SwFieldTypes
* pTypes
= pDoc
->getIDocumentFieldsAccess().GetFieldTypes();
143 auto it
= std::find_if(pTypes
->begin(), pTypes
->end(),
144 [](const std::unique_ptr
<SwFieldType
>& pType
) {
145 return pType
->Which() == SwFieldIds::TableOfAuthorities
;
147 CPPUNIT_ASSERT(it
!= pTypes
->end());
148 const SwFieldType
* pType
= it
->get();
149 std::vector
<SwFormatField
*> aFormatFields
;
150 pType
->GatherFields(aFormatFields
);
151 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aFormatFields
.size());
152 SwField
* pField
= aFormatFields
[0]->GetField();
153 // Without the accompanying fix in place, this test would have failed, as the field was not
155 CPPUNIT_ASSERT(pField
->IsClickable());
156 // This is needed, so the mouse has the correct RefHand pointer style.
157 CPPUNIT_ASSERT(pField
->HasClickHdl());
160 CPPUNIT_TEST_FIXTURE(Test
, testAuthorityTableEntryRelClick
)
162 // Given an empty document with a file:// base URL:
164 SwDoc
* pDoc
= getSwDoc();
165 uno::Reference
<frame::XStorable
> xStorable(mxComponent
, uno::UNO_QUERY
);
166 uno::Sequence
<beans::PropertyValue
> aArgs
= {
167 comphelper::makePropertyValue(u
"FilterName"_ustr
, u
"writer8"_ustr
),
169 xStorable
->storeAsURL(maTempFile
.GetURL(), aArgs
);
171 // When inserting a biblio entry field with a relative URL:
172 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
173 uno::Reference
<beans::XPropertySet
> xField(
174 xFactory
->createInstance(u
"com.sun.star.text.TextField.Bibliography"_ustr
), uno::UNO_QUERY
);
175 uno::Sequence
<beans::PropertyValue
> aFields
= {
176 comphelper::makePropertyValue(u
"BibiliographicType"_ustr
, text::BibliographyDataType::WWW
),
177 comphelper::makePropertyValue(u
"Identifier"_ustr
, u
"AT"_ustr
),
178 comphelper::makePropertyValue(u
"Author"_ustr
, u
"Author"_ustr
),
179 comphelper::makePropertyValue(u
"Title"_ustr
, u
"Title"_ustr
),
180 comphelper::makePropertyValue(u
"URL"_ustr
, u
"test.pdf#page=1"_ustr
),
182 xField
->setPropertyValue(u
"Fields"_ustr
, uno::Any(aFields
));
183 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
184 uno::Reference
<text::XText
> xText
= xTextDocument
->getText();
185 uno::Reference
<text::XTextCursor
> xCursor
= xText
->createTextCursor();
186 uno::Reference
<text::XTextContent
> xContent(xField
, uno::UNO_QUERY
);
187 xText
->insertTextContent(xCursor
, xContent
, /*bAbsorb=*/false);
189 // Then make sure that the field is clickable:
190 const SwFieldTypes
* pTypes
= pDoc
->getIDocumentFieldsAccess().GetFieldTypes();
191 auto it
= std::find_if(pTypes
->begin(), pTypes
->end(),
192 [](const std::unique_ptr
<SwFieldType
>& pType
) {
193 return pType
->Which() == SwFieldIds::TableOfAuthorities
;
195 CPPUNIT_ASSERT(it
!= pTypes
->end());
196 const SwFieldType
* pType
= it
->get();
197 std::vector
<SwFormatField
*> aFormatFields
;
198 pType
->GatherFields(aFormatFields
);
199 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aFormatFields
.size());
200 auto pField
= static_cast<SwAuthorityField
*>(aFormatFields
[0]->GetField());
201 CPPUNIT_ASSERT(pField
->GetAbsoluteURL().startsWith("file://"));
204 CPPUNIT_TEST_FIXTURE(Test
, testAuthorityTableURLDeduplication
)
206 // Given a document with 3 bibliography references (of type WWW) in it:
207 static const std::initializer_list
<std::u16string_view
> aURLs
= {
208 u
"http://www.example.com/test.pdf#page=1",
209 u
"http://www.example.com/test.pdf#page=2",
210 u
"http://www.example.com/test2.pdf",
213 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
214 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
215 uno::Reference
<text::XText
> xText
= xTextDocument
->getText();
216 uno::Reference
<text::XTextCursor
> xCursor
= xText
->createTextCursor();
217 for (const auto& rURL
: aURLs
)
219 uno::Reference
<beans::XPropertySet
> xField(
220 xFactory
->createInstance(u
"com.sun.star.text.TextField.Bibliography"_ustr
),
222 uno::Sequence
<beans::PropertyValue
> aFields
= {
223 comphelper::makePropertyValue(u
"BibiliographicType"_ustr
,
224 text::BibliographyDataType::WWW
),
225 comphelper::makePropertyValue(u
"Identifier"_ustr
, u
"AT"_ustr
),
226 comphelper::makePropertyValue(u
"Author"_ustr
, u
"Author"_ustr
),
227 comphelper::makePropertyValue(u
"Title"_ustr
, u
"Title"_ustr
),
228 comphelper::makePropertyValue(u
"URL"_ustr
, OUString(rURL
)),
230 xField
->setPropertyValue(u
"Fields"_ustr
, uno::Any(aFields
));
231 uno::Reference
<text::XTextContent
> xContent(xField
, uno::UNO_QUERY
);
232 xText
->insertTextContent(xCursor
, xContent
, /*bAbsorb=*/false);
234 // Create a bibliography table.
235 uno::Reference
<text::XTextContent
> xTable(
236 xFactory
->createInstance(u
"com.sun.star.text.Bibliography"_ustr
), uno::UNO_QUERY
);
237 xCursor
->gotoEnd(/*bExpand=*/false);
238 xText
->insertControlCharacter(xCursor
, text::ControlCharacter::APPEND_PARAGRAPH
,
240 xText
->insertTextContent(xCursor
, xTable
, /*bAbsorb=*/false);
242 // When updating that table:
243 uno::Reference
<text::XDocumentIndex
> xTableIndex(xTable
, uno::UNO_QUERY
);
244 xTableIndex
->update();
246 // Then the first two fields should be merged to a single source, but not the third.
247 CPPUNIT_ASSERT_EQUAL(u
"AT: Author, Title, , http://www.example.com/test.pdf"_ustr
,
248 getParagraph(3)->getString());
249 // Without the accompanying fix in place, this test would have failed with:
250 // - Expected: AT: Author, Title, , http://www.example.com/test2.pdf
251 // - Actual : AT: Author, Title, , http://www.example.com/test.pdf
252 // i.e. test.pdf was mentioned twice, without deduplication.
253 CPPUNIT_ASSERT_EQUAL(u
"AT: Author, Title, , http://www.example.com/test2.pdf"_ustr
,
254 getParagraph(4)->getString());
258 CPPUNIT_PLUGIN_IMPLEMENT();
260 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */