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("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY
);
38 uno::Sequence
<beans::PropertyValue
> aFields
= {
39 comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW
),
40 comphelper::makePropertyValue("Identifier", OUString("ARJ00")),
41 comphelper::makePropertyValue("Author", OUString("Ar, J")),
42 comphelper::makePropertyValue("Title", OUString("mytitle")),
43 comphelper::makePropertyValue("Year", OUString("2020")),
44 comphelper::makePropertyValue("URL", OUString("http://www.example.com/test.pdf")),
46 xField
->setPropertyValue("Fields", 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("com.sun.star.text.Bibliography"), 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), "HyperLinkURL");
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(OUString("http://www.example.com/test.pdf"), 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("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY
);
80 uno::Sequence
<beans::PropertyValue
> aFields
= {
81 comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW
),
82 comphelper::makePropertyValue("Identifier", OUString("AT")),
83 comphelper::makePropertyValue("Author", OUString("Author")),
84 comphelper::makePropertyValue("Title", OUString("Title")),
85 comphelper::makePropertyValue("URL", OUString("http://www.example.com/test.pdf#page=1")),
87 xField
->setPropertyValue("Fields", 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("com.sun.star.text.Bibliography"), 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), "HyperLinkURL");
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(OUString("http://www.example.com/test.pdf"), 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("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY
);
126 uno::Sequence
<beans::PropertyValue
> aFields
= {
127 comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW
),
128 comphelper::makePropertyValue("Identifier", OUString("AT")),
129 comphelper::makePropertyValue("Author", OUString("Author")),
130 comphelper::makePropertyValue("Title", OUString("Title")),
131 comphelper::makePropertyValue("URL", OUString("http://www.example.com/test.pdf#page=1")),
133 xField
->setPropertyValue("Fields", 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("FilterName", OUString("writer8")),
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("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY
);
175 uno::Sequence
<beans::PropertyValue
> aFields
= {
176 comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW
),
177 comphelper::makePropertyValue("Identifier", OUString("AT")),
178 comphelper::makePropertyValue("Author", OUString("Author")),
179 comphelper::makePropertyValue("Title", OUString("Title")),
180 comphelper::makePropertyValue("URL", OUString("test.pdf#page=1")),
182 xField
->setPropertyValue("Fields", 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("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY
);
221 uno::Sequence
<beans::PropertyValue
> aFields
= {
222 comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW
),
223 comphelper::makePropertyValue("Identifier", OUString("AT")),
224 comphelper::makePropertyValue("Author", OUString("Author")),
225 comphelper::makePropertyValue("Title", OUString("Title")),
226 comphelper::makePropertyValue("URL", OUString(rURL
)),
228 xField
->setPropertyValue("Fields", uno::Any(aFields
));
229 uno::Reference
<text::XTextContent
> xContent(xField
, uno::UNO_QUERY
);
230 xText
->insertTextContent(xCursor
, xContent
, /*bAbsorb=*/false);
232 // Create a bibliography table.
233 uno::Reference
<text::XTextContent
> xTable(
234 xFactory
->createInstance("com.sun.star.text.Bibliography"), uno::UNO_QUERY
);
235 xCursor
->gotoEnd(/*bExpand=*/false);
236 xText
->insertControlCharacter(xCursor
, text::ControlCharacter::APPEND_PARAGRAPH
,
238 xText
->insertTextContent(xCursor
, xTable
, /*bAbsorb=*/false);
240 // When updating that table:
241 uno::Reference
<text::XDocumentIndex
> xTableIndex(xTable
, uno::UNO_QUERY
);
242 xTableIndex
->update();
244 // Then the first two fields should be merged to a single source, but not the third.
245 CPPUNIT_ASSERT_EQUAL(OUString("AT: Author, Title, , http://www.example.com/test.pdf"),
246 getParagraph(3)->getString());
247 // Without the accompanying fix in place, this test would have failed with:
248 // - Expected: AT: Author, Title, , http://www.example.com/test2.pdf
249 // - Actual : AT: Author, Title, , http://www.example.com/test.pdf
250 // i.e. test.pdf was mentioned twice, without deduplication.
251 CPPUNIT_ASSERT_EQUAL(OUString("AT: Author, Title, , http://www.example.com/test2.pdf"),
252 getParagraph(4)->getString());
256 CPPUNIT_PLUGIN_IMPLEMENT();
258 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */