summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/xmloff/xmltoken.hxx2
-rw-r--r--sw/inc/authfld.hxx5
-rw-r--r--sw/inc/helpids.h2
-rw-r--r--sw/inc/strings.hrc2
-rw-r--r--sw/inc/toxe.hxx2
-rw-r--r--sw/qa/core/text/text.cxx154
-rw-r--r--sw/source/core/fields/authfld.cxx30
-rw-r--r--sw/source/core/fields/fldbas.cxx10
-rw-r--r--sw/source/core/text/EnhancedPDFExportHelper.cxx149
-rw-r--r--sw/source/ui/index/cnttab.cxx2
-rw-r--r--sw/source/ui/index/swuiidxmrk.cxx34
-rw-r--r--sw/source/uibase/docvw/edtwin2.cxx10
-rw-r--r--sw/source/uibase/shells/textsh1.cxx14
-rw-r--r--sw/source/uibase/utlui/initui.cxx2
-rw-r--r--sw/source/uibase/wrtsh/wrtsh2.cxx74
-rw-r--r--sw/uiconfig/swriter/ui/bibliofragment.ui24
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx7
-rw-r--r--xmloff/source/core/xmltoken.cxx2
-rw-r--r--xmloff/source/text/txtflde.cxx10
-rw-r--r--xmloff/source/text/txtfldi.cxx8
-rw-r--r--xmloff/source/token/tokens.txt2
21 files changed, 495 insertions, 50 deletions
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index 7c6cea0482d3..5262f3b3ab5e 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -3465,6 +3465,8 @@ namespace xmloff::token {
XML_MARGIN_GUTTER,
XML_LOCAL_URL,
+ XML_TARGET_URL,
+ XML_USE_TARGET_URL,
// Math ml
XML_DIR,
diff --git a/sw/inc/authfld.hxx b/sw/inc/authfld.hxx
index def78f913e14..26e4843a6ad2 100644
--- a/sw/inc/authfld.hxx
+++ b/sw/inc/authfld.hxx
@@ -199,8 +199,13 @@ public:
OUString GetAuthority(const SwRootFrame *pLayout,
const SwForm *pTOX = nullptr) const;
+ bool UseTargetURL() const;
+
bool HasURL() const;
OUString GetAbsoluteURL() const;
+
+ bool HasTargetURL() const;
+ OUString GetAbsoluteTargetURL() const;
/**
* Returns full URI for the URL, relative if specified
* \param bRelative whether the path should be relative (when dealing with local files)
diff --git a/sw/inc/helpids.h b/sw/inc/helpids.h
index 65c49e22f311..78f52fd436ea 100644
--- a/sw/inc/helpids.h
+++ b/sw/inc/helpids.h
@@ -76,6 +76,8 @@ inline constexpr OStringLiteral HID_EDIT_FORMULA = "SW_HID_EDIT_FORMULA";
#define HID_AUTH_FIELD_CUSTOM5 "SW_HID_AUTH_FIELD_CUSTOM5"
#define HID_AUTH_FIELD_ISBN "SW_HID_AUTH_FIELD_ISBN"
#define HID_AUTH_FIELD_LOCAL_URL "SW_HID_AUTH_FIELD_LOCAL_URL"
+#define HID_AUTH_FIELD_TARGET_URL "SW_HID_AUTH_FIELD_TARGET_URL"
+#define HID_AUTH_FIELD_USE_TARGET_URL "SW_HID_AUTH_FIELD_USE_TARGET_URL"
inline constexpr OStringLiteral HID_BUSINESS_FMT_PAGE = "SW_HID_BUSINESS_FMT_PAGE";
inline constexpr OStringLiteral HID_BUSINESS_FMT_PAGE_CONT = "SW_HID_BUSINESS_FMT_PAGE_CONT";
diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc
index 96e58d395164..8af6eef01a4d 100644
--- a/sw/inc/strings.hrc
+++ b/sw/inc/strings.hrc
@@ -816,6 +816,8 @@
#define STR_AUTH_FIELD_CUSTOM5 NC_("STR_AUTH_FIELD_CUSTOM5", "User-defined5")
#define STR_AUTH_FIELD_ISBN NC_("STR_AUTH_FIELD_ISBN", "ISBN")
#define STR_AUTH_FIELD_LOCAL_URL NC_("STR_AUTH_FIELD_LOCAL_URL", "Local copy")
+#define STR_AUTH_FIELD_TARGET_URL NC_("STR_AUTH_FIELD_TARGET_URL", "Target URL")
+#define STR_AUTH_FIELD_USE_TARGET_URL NC_("STR_AUTH_FIELD_USE_TARGET_URL", "Use Target URL as hyperlink")
#define STR_IDXMRK_EDIT NC_("STR_IDXMRK_EDIT", "Edit Index Entry")
#define STR_IDXMRK_INSERT NC_("STR_IDXMRK_INSERT", "Insert Index Entry")
diff --git a/sw/inc/toxe.hxx b/sw/inc/toxe.hxx
index b2f08e66c320..05084c84c2e8 100644
--- a/sw/inc/toxe.hxx
+++ b/sw/inc/toxe.hxx
@@ -115,6 +115,8 @@ enum ToxAuthorityField
AUTH_FIELD_CUSTOM5,
AUTH_FIELD_ISBN,
AUTH_FIELD_LOCAL_URL,
+ AUTH_FIELD_TARGET_URL,
+ AUTH_FIELD_USE_TARGET_URL,
AUTH_FIELD_END
};
diff --git a/sw/qa/core/text/text.cxx b/sw/qa/core/text/text.cxx
index d16e7b324656..7ace4df111c6 100644
--- a/sw/qa/core/text/text.cxx
+++ b/sw/qa/core/text/text.cxx
@@ -12,7 +12,9 @@
#include <memory>
#include <com/sun/star/text/BibliographyDataType.hpp>
+#include <com/sun/star/text/ControlCharacter.hpp>
#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/XDocumentIndex.hpp>
#include <vcl/gdimtf.hxx>
#include <vcl/filter/PDFiumLibrary.hxx>
@@ -135,6 +137,158 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testBibliographyUrlPdfExport)
CPPUNIT_ASSERT(pPdfPage->hasLinks());
}
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testBibliographyUrlPdfExport2)
+{
+ // Given a document with a bibliography entry field:
+ std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
+ if (!pPDFium)
+ {
+ return;
+ }
+ createSwDoc();
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xField(
+ xFactory->createInstance("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aFields = {
+ comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW),
+ comphelper::makePropertyValue("Identifier", OUString("AT")),
+ comphelper::makePropertyValue("Author", OUString("Author")),
+ comphelper::makePropertyValue("Title", OUString("Title")),
+ comphelper::makePropertyValue("URL", OUString("#page=1")),
+ };
+ xField->setPropertyValue("Fields", uno::Any(aFields));
+ 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<text::XTextContent> xContent(xField, uno::UNO_QUERY);
+ xText->insertTextContent(xCursor, xContent, /*bAbsorb=*/false);
+
+ // When exporting to PDF:
+ save("writer_pdf_Export");
+
+ // Then make sure the field links when the Target URL is set
+ // (this test is important, isn't the same as the one above)
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0);
+ CPPUNIT_ASSERT(pPdfPage->hasLinks());
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testBibliographyUrlPdfExport3)
+{
+ // Given a document with a bibliography entry field:
+ std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
+ if (!pPDFium)
+ {
+ return;
+ }
+ createSwDoc();
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xField(
+ xFactory->createInstance("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aFields = {
+ comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW),
+ comphelper::makePropertyValue("Identifier", OUString("AT")),
+ comphelper::makePropertyValue("Author", OUString("Author")),
+ comphelper::makePropertyValue("Title", OUString("Title")),
+ comphelper::makePropertyValue("TargetURL", OUString("#page=1")),
+ };
+ xField->setPropertyValue("Fields", uno::Any(aFields));
+ 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<text::XTextContent> xContent(xField, uno::UNO_QUERY);
+ xText->insertTextContent(xCursor, xContent, /*bAbsorb=*/false);
+
+ // When exporting to PDF:
+ save("writer_pdf_Export");
+
+ // Then make sure there are no links since UseTargetURL is not set
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0);
+ CPPUNIT_ASSERT(!pPdfPage->hasLinks());
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testBibliographyUrlPdfExport4)
+{
+ // Given a document with a bibliography entry field:
+ std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
+ if (!pPDFium)
+ {
+ return;
+ }
+ createSwDoc();
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xField(
+ xFactory->createInstance("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aFields = {
+ comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW),
+ comphelper::makePropertyValue("Identifier", OUString("AT")),
+ comphelper::makePropertyValue("Author", OUString("Author")),
+ comphelper::makePropertyValue("Title", OUString("Title")),
+ comphelper::makePropertyValue("TargetURL", OUString("#page=1")),
+ comphelper::makePropertyValue("UseTargetURL", OUString("true")),
+ };
+ xField->setPropertyValue("Fields", uno::Any(aFields));
+ 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<text::XTextContent> xContent(xField, uno::UNO_QUERY);
+ xText->insertTextContent(xCursor, xContent, /*bAbsorb=*/false);
+
+ // When exporting to PDF:
+ save("writer_pdf_Export");
+
+ // Then make sure the field links when the Target URL is set
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0);
+ CPPUNIT_ASSERT(pPdfPage->hasLinks());
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testBibliographyUrlPdfExport5)
+{
+ // Given a document with a bibliography entry field:
+ std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
+ if (!pPDFium)
+ {
+ return;
+ }
+ createSwDoc();
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xField(
+ xFactory->createInstance("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aFields = {
+ comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW),
+ comphelper::makePropertyValue("Identifier", OUString("AT")),
+ comphelper::makePropertyValue("Author", OUString("Author")),
+ comphelper::makePropertyValue("Title", OUString("Title")),
+ comphelper::makePropertyValue("UseTargetURL", OUString("true")),
+ };
+ xField->setPropertyValue("Fields", uno::Any(aFields));
+ 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<text::XTextContent> xContent(xField, uno::UNO_QUERY);
+ xText->insertTextContent(xCursor, xContent, /*bAbsorb=*/false);
+ // Create a bibliography table.
+ uno::Reference<text::XTextContent> xTable(
+ xFactory->createInstance("com.sun.star.text.Bibliography"), uno::UNO_QUERY);
+ xCursor->gotoEnd(/*bExpand=*/false);
+ xText->insertControlCharacter(xCursor, text::ControlCharacter::APPEND_PARAGRAPH,
+ /*bAbsorb=*/false);
+ xText->insertTextContent(xCursor, xTable, /*bAbsorb=*/false);
+ // Update the table
+ uno::Reference<text::XDocumentIndex> xTableIndex(xTable, uno::UNO_QUERY);
+ xTableIndex->update();
+
+ // When exporting to PDF:
+ save("writer_pdf_Export");
+
+ // Then make sure the mark links to the table when table is present
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0);
+ CPPUNIT_ASSERT(pPdfPage->hasLinks());
+}
+
CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testTabOverMarginSection)
{
createSwDoc("tabovermargin-section.fodt");
diff --git a/sw/source/core/fields/authfld.cxx b/sw/source/core/fields/authfld.cxx
index 44d1e39dd3ae..d1d50506d741 100644
--- a/sw/source/core/fields/authfld.cxx
+++ b/sw/source/core/fields/authfld.cxx
@@ -634,6 +634,12 @@ OUString SwAuthorityField::GetAuthority(const SwRootFrame* pLayout, const SwForm
return aText;
}
+bool SwAuthorityField::UseTargetURL() const
+{
+ const OUString& rValue = GetAuthEntry()->GetAuthorField(AUTH_FIELD_USE_TARGET_URL);
+ return rValue.toAsciiLowerCase() == "true";
+}
+
bool SwAuthorityField::HasURL() const
{
const OUString& rURL = GetAuthEntry()->GetAuthorField(AUTH_FIELD_URL);
@@ -650,6 +656,22 @@ OUString SwAuthorityField::GetAbsoluteURL() const
INetURLObject::DecodeMechanism::WithCharset);
}
+bool SwAuthorityField::HasTargetURL() const
+{
+ const OUString& rURL = GetAuthEntry()->GetAuthorField(AUTH_FIELD_TARGET_URL);
+ return !rURL.isEmpty();
+}
+
+OUString SwAuthorityField::GetAbsoluteTargetURL() const
+{
+ const OUString& rURL = GetAuthEntry()->GetAuthorField(AUTH_FIELD_TARGET_URL);
+ SwDoc* pDoc = static_cast<SwAuthorityFieldType*>(GetTyp())->GetDoc();
+ SwDocShell* pDocShell = pDoc->GetDocShell();
+ OUString aBasePath = pDocShell->getDocumentBaseURL();
+ return INetURLObject::GetAbsURL(aBasePath, rURL, INetURLObject::EncodeMechanism::WasEncoded,
+ INetURLObject::DecodeMechanism::WithCharset);
+}
+
OUString SwAuthorityField::GetURI(bool bRelative) const
{
OUString sTmp = GetFieldText(AUTH_FIELD_URL);
@@ -751,7 +773,9 @@ const char* const aFieldNames[] =
"Custom4",
"Custom5",
"ISBN",
- "LocalURL"
+ "LocalURL",
+ "TargetURL",
+ "UseTargetURL"
};
void SwAuthEntry::dumpAsXml(xmlTextWriterPtr pWriter) const
@@ -808,8 +832,8 @@ bool SwAuthorityField::PutValue( const Any& rAny, sal_uInt16 /*nWhichId*/ )
if(!(rAny >>= aParam))
return false;
- OUStringBuffer sBuf(+AUTH_FIELD_LOCAL_URL);
- comphelper::string::padToLength(sBuf, AUTH_FIELD_LOCAL_URL, TOX_STYLE_DELIMITER);
+ OUStringBuffer sBuf(+(AUTH_FIELD_END - 1));
+ comphelper::string::padToLength(sBuf, (AUTH_FIELD_END - 1), TOX_STYLE_DELIMITER);
OUString sToSet(sBuf.makeStringAndClear());
for(const PropertyValue& rParam : std::as_const(aParam))
{
diff --git a/sw/source/core/fields/fldbas.cxx b/sw/source/core/fields/fldbas.cxx
index 71afe0d7e425..80ae487f93fe 100644
--- a/sw/source/core/fields/fldbas.cxx
+++ b/sw/source/core/fields/fldbas.cxx
@@ -423,7 +423,8 @@ bool SwField::HasClickHdl() const
case SwFieldIds::GetRef:
case SwFieldIds::Macro:
case SwFieldIds::Input:
- case SwFieldIds::Dropdown :
+ case SwFieldIds::Dropdown:
+ case SwFieldIds::TableOfAuthorities:
bRet = true;
break;
@@ -431,13 +432,6 @@ bool SwField::HasClickHdl() const
bRet = static_cast<const SwSetExpField*>(this)->GetInputFlag();
break;
- case SwFieldIds::TableOfAuthorities:
- {
- const auto pAuthorityField = static_cast<const SwAuthorityField*>(this);
- bRet = pAuthorityField->HasURL();
- break;
- }
-
default: break;
}
return bRet;
diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx b/sw/source/core/text/EnhancedPDFExportHelper.cxx
index 053b67990eda..1dde77106624 100644
--- a/sw/source/core/text/EnhancedPDFExportHelper.cxx
+++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx
@@ -803,6 +803,13 @@ void SwTaggedPDFHelper::SetAttributes( vcl::PDFWriter::StructElement eType )
bLanguage = true;
break;
+ case vcl::PDFWriter::BibEntry :
+ bTextDecorationType =
+ bBaselineShift =
+ bLinkAttribute =
+ bLanguage = true;
+ break;
+
default:
break;
}
@@ -2246,6 +2253,50 @@ void SwEnhancedPDFExportHelper::ExportAuthorityEntryLinks()
return;
}
+ // Create PDF destinations for bibliography table entries
+ std::vector<std::tuple<const SwTOXBase*, const OUString*, sal_Int32>> vDestinations;
+ // string is the row node text, sal_Int32 is number of the destination
+ // Note: This way of iterating doesn't seem to take into account TOXes
+ // that are in a frame, probably in some other cases too
+ {
+ mrSh.GotoPage(1);
+ while (mrSh.GotoNextTOXBase())
+ {
+ const SwTOXBase* pIteratedTOX = nullptr;
+ while ((pIteratedTOX = mrSh.GetCurTOX()) != nullptr
+ && pIteratedTOX->GetType() == TOX_AUTHORITIES)
+ {
+ if (const SwNode& rCurrentNode = mrSh.GetCursor()->GetPoint()->GetNode();
+ rCurrentNode.GetNodeType() == SwNodeType::Text)
+ {
+ if (mrSh.GetCursor()->GetPoint()->GetNode().FindSectionNode()->GetSection().GetType()
+ == SectionType::ToxContent) // this checks it's not a heading
+ {
+ // Destination Rectangle
+ const SwRect& rDestRect = mrSh.GetCharRect();
+
+ const SwPageFrame* pCurrPage =
+ static_cast<const SwPageFrame*>( mrSh.GetLayout()->Lower() );
+
+ // Destination PageNum
+ const sal_Int32 nDestPageNum = CalcOutputPageNum( rDestRect );
+
+ // Destination Export
+ if ( -1 != nDestPageNum )
+ {
+ tools::Rectangle aRect(SwRectToPDFRect(pCurrPage, rDestRect.SVRect()));
+ const sal_Int32 nDestId = pPDFExtOutDevData->CreateDest(aRect, nDestPageNum);
+ const OUString* vNodeText = &static_cast<const SwTextNode*>(&rCurrentNode)->GetText();
+ vDestinations.emplace_back(pIteratedTOX, vNodeText, nDestId);
+ }
+ }
+ }
+ mrSh.MovePara(GoNextPara, fnParaStart);
+ }
+ }
+ }
+
+ // Generate links to matching entries in the bibliography tables
std::vector<SwFormatField*> aFields;
SwFieldType* pType = mrSh.GetFieldType(SwFieldIds::TableOfAuthorities, OUString());
if (!pType)
@@ -2264,38 +2315,90 @@ void SwEnhancedPDFExportHelper::ExportAuthorityEntryLinks()
const auto& rAuthorityField
= *static_cast<const SwAuthorityField*>(pFormatField->GetField());
- if (!rAuthorityField.HasURL())
- {
- continue;
- }
- const OUString& rURL = rAuthorityField.GetAuthEntry()->GetAuthorField(AUTH_FIELD_URL);
- const SwTextNode& rTextNode = pFormatField->GetTextField()->GetTextNode();
- if (!lcl_TryMoveToNonHiddenField(mrSh, rTextNode, *pFormatField))
+ if ((!rAuthorityField.UseTargetURL() && rAuthorityField.HasURL())
+ || (rAuthorityField.UseTargetURL() && rAuthorityField.HasTargetURL()))
{
- continue;
- }
+ // Since the conditions indicate usage of a URL link to it
+ const OUString& rURL = rAuthorityField.GetAuthEntry()->GetAuthorField(
+ rAuthorityField.UseTargetURL() ? AUTH_FIELD_TARGET_URL : AUTH_FIELD_URL);
- OUString const content(rAuthorityField.ExpandField(true, mrSh.GetLayout()));
+ const SwTextNode& rTextNode = pFormatField->GetTextField()->GetTextNode();
+ if (!lcl_TryMoveToNonHiddenField(mrSh, rTextNode, *pFormatField))
+ {
+ continue;
+ }
- // Select the field.
- mrSh.SwCursorShell::SetMark();
- mrSh.SwCursorShell::Right(1, SwCursorSkipMode::Chars);
+ OUString const content(rAuthorityField.ExpandField(true, mrSh.GetLayout()));
- // Create the links.
- for (const auto& rLinkRect : *mrSh.SwCursorShell::GetCursor_())
- {
- for (const auto& rLinkPageNum : CalcOutputPageNums(rLinkRect))
+ // Select the field.
+ mrSh.SwCursorShell::SetMark();
+ mrSh.SwCursorShell::Right(1, SwCursorSkipMode::Chars);
+
+ // Create the links.
+ for (const auto& rLinkRect : *mrSh.SwCursorShell::GetCursor_())
{
- tools::Rectangle aRect(SwRectToPDFRect(pPageFrame, rLinkRect.SVRect()));
- sal_Int32 nLinkId = pPDFExtOutDevData->CreateLink(aRect, content, rLinkPageNum);
- IdMapEntry aLinkEntry(rLinkRect, nLinkId);
- s_aLinkIdMap.push_back(aLinkEntry);
- pPDFExtOutDevData->SetLinkURL(nLinkId, rURL);
+ for (const auto& rLinkPageNum : CalcOutputPageNums(rLinkRect))
+ {
+ tools::Rectangle aRect(SwRectToPDFRect(pPageFrame, rLinkRect.SVRect()));
+ sal_Int32 nLinkId = pPDFExtOutDevData->CreateLink(aRect, content, rLinkPageNum);
+ IdMapEntry aLinkEntry(rLinkRect, nLinkId);
+ s_aLinkIdMap.push_back(aLinkEntry);
+ pPDFExtOutDevData->SetLinkURL(nLinkId, rURL);
+ }
}
+ mrSh.SwCursorShell::ClearMark();
}
+ else if (rAuthorityField.UseTargetURL())
+ {
+ // Since the bibliography mark doesn't have target URL, try linking to a bibliography table
+ sal_Int32 nDestId = -1;
+
+ std::unordered_map<const SwTOXBase*, OUString> vFormattedFieldStrings;
+ for (const auto& rDestinationTuple : vDestinations)
+ {
+ if (vFormattedFieldStrings.find(std::get<0>(rDestinationTuple))
+ == vFormattedFieldStrings.end())
+ vFormattedFieldStrings.emplace(std::get<0>(rDestinationTuple),
+ rAuthorityField.GetAuthority(mrSh.GetLayout(),
+ &std::get<0>(rDestinationTuple)->GetTOXForm()));
+
+ if (vFormattedFieldStrings.at(std::get<0>(rDestinationTuple)) == *std::get<1>(rDestinationTuple))
+ {
+ nDestId = std::get<2>(rDestinationTuple);
+ break;
+ }
+ }
+
+ if (nDestId == -1)
+ continue;
+
+ const SwTextNode& rTextNode = pFormatField->GetTextField()->GetTextNode();
+ if (!lcl_TryMoveToNonHiddenField(mrSh, rTextNode, *pFormatField))
+ {
+ continue;
+ }
+
+ OUString const content(rAuthorityField.ExpandField(true, mrSh.GetLayout()));
- mrSh.SwCursorShell::ClearMark();
+ // Select the field.
+ mrSh.SwCursorShell::SetMark();
+ mrSh.SwCursorShell::Right(1, SwCursorSkipMode::Chars);
+
+ // Create the links.
+ for (const auto& rLinkRect : *mrSh.SwCursorShell::GetCursor_())
+ {
+ for (const auto& rLinkPageNum : CalcOutputPageNums(rLinkRect))
+ {
+ tools::Rectangle aRect(SwRectToPDFRect(pPageFrame, rLinkRect.SVRect()));
+ sal_Int32 nLinkId = pPDFExtOutDevData->CreateLink(aRect, content, rLinkPageNum);
+ IdMapEntry aLinkEntry(rLinkRect, nLinkId);
+ s_aLinkIdMap.push_back(aLinkEntry);
+ pPDFExtOutDevData->SetLinkDest(nLinkId, nDestId);
+ }
+ }
+ mrSh.SwCursorShell::ClearMark();
+ }
}
}
diff --git a/sw/source/ui/index/cnttab.cxx b/sw/source/ui/index/cnttab.cxx
index 9955a85cd3d3..ce234a14f293 100644
--- a/sw/source/ui/index/cnttab.cxx
+++ b/sw/source/ui/index/cnttab.cxx
@@ -1899,6 +1899,8 @@ namespace
STR_AUTH_FIELD_CUSTOM5,
STR_AUTH_FIELD_ISBN,
STR_AUTH_FIELD_LOCAL_URL,
+ STR_AUTH_FIELD_TARGET_URL,
+ STR_AUTH_FIELD_USE_TARGET_URL,
};
}
diff --git a/sw/source/ui/index/swuiidxmrk.cxx b/sw/source/ui/index/swuiidxmrk.cxx
index 656eacedae02..4c9ea292bee7 100644
--- a/sw/source/ui/index/swuiidxmrk.cxx
+++ b/sw/source/ui/index/swuiidxmrk.cxx
@@ -1091,6 +1091,7 @@ class SwCreateAuthEntryDlg_Impl : public weld::GenericDialogController
std::unique_ptr<weld::Button> m_xLocalBrowseButton;
std::unique_ptr<weld::CheckButton> m_xLocalPageCB;
std::unique_ptr<weld::SpinButton> m_xLocalPageSB;
+ std::unique_ptr<weld::CheckButton> m_xUseTargetURLCB;
DECL_LINK(IdentifierHdl, weld::ComboBox&, void);
DECL_LINK(ShortNameHdl, weld::Entry&, void);
@@ -1147,6 +1148,8 @@ const TextInfo aTextInfoArr[] =
{AUTH_FIELD_ANNOTE, HID_AUTH_FIELD_ANNOTE },
{AUTH_FIELD_NOTE, HID_AUTH_FIELD_NOTE },
{AUTH_FIELD_URL, HID_AUTH_FIELD_URL },
+ {AUTH_FIELD_USE_TARGET_URL, HID_AUTH_FIELD_USE_TARGET_URL },
+ {AUTH_FIELD_TARGET_URL, HID_AUTH_FIELD_TARGET_URL },
{AUTH_FIELD_LOCAL_URL, HID_AUTH_FIELD_LOCAL_URL },
{AUTH_FIELD_CUSTOM1, HID_AUTH_FIELD_CUSTOM1 },
{AUTH_FIELD_CUSTOM2, HID_AUTH_FIELD_CUSTOM2 },
@@ -1567,6 +1570,8 @@ namespace
STR_AUTH_FIELD_CUSTOM5,
STR_AUTH_FIELD_ISBN,
STR_AUTH_FIELD_LOCAL_URL,
+ STR_AUTH_FIELD_TARGET_URL,
+ STR_AUTH_FIELD_USE_TARGET_URL,
};
}
@@ -1655,6 +1660,29 @@ SwCreateAuthEntryDlg_Impl::SwCreateAuthEntryDlg_Impl(weld::Window* pParent,
m_xIdentifierBox->set_help_id(aCurInfo.pHelpId);
m_aFixedTexts.back()->set_mnemonic_widget(m_xIdentifierBox.get());
}
+ else if (AUTH_FIELD_USE_TARGET_URL == aCurInfo.nToxField)
+ {
+ m_pBoxes[nIndex] = m_aBuilders.back()->weld_box("togglebox");
+
+ if (bLeft)
+ m_aOrigContainers.back()->move(m_pBoxes[nIndex].get(), m_xLeft.get());
+ else
+ m_aOrigContainers.back()->move(m_pBoxes[nIndex].get(), m_xRight.get());
+
+ m_pBoxes[nIndex]->set_grid_left_attach(1);
+ m_pBoxes[nIndex]->set_grid_top_attach(bLeft ? nLeftRow : nRightRow);
+ m_pBoxes[nIndex]->set_hexpand(true);
+
+ m_xUseTargetURLCB = m_aBuilders.back()->weld_check_button("usetargeturlcb");
+ m_xUseTargetURLCB->set_active(m_bNewEntryMode
+ || pFields[aCurInfo.nToxField].toAsciiLowerCase() == "true");
+ m_xUseTargetURLCB->set_grid_left_attach(1);
+ m_xUseTargetURLCB->set_grid_top_attach(bLeft ? nLeftRow : nRightRow);
+ m_xUseTargetURLCB->set_hexpand(true);
+ m_xUseTargetURLCB->show();
+ m_xUseTargetURLCB->set_help_id(aCurInfo.pHelpId);
+ m_aFixedTexts.back()->set_mnemonic_widget(m_xUseTargetURLCB.get());
+ }
else
{
m_pBoxes[nIndex] = m_aBuilders.back()->weld_box("vbox");
@@ -1747,6 +1775,12 @@ OUString SwCreateAuthEntryDlg_Impl::GetEntryText(ToxAuthorityField eField) cons
return m_xIdentifierBox->get_active_text();
}
+ if (AUTH_FIELD_USE_TARGET_URL == eField)
+ {
+ assert(m_xUseTargetURLCB && "No UseTargetURL");
+ return (m_xUseTargetURLCB->get_active() ? OUString("true") : OUString("false"));
+ }
+
for(int nIndex = 0; nIndex < AUTH_FIELD_END; nIndex++)
{
const TextInfo aCurInfo = aTextInfoArr[nIndex];
diff --git a/sw/source/uibase/docvw/edtwin2.cxx b/sw/source/uibase/docvw/edtwin2.cxx
index 573b08dc4f47..01c668be4586 100644
--- a/sw/source/uibase/docvw/edtwin2.cxx
+++ b/sw/source/uibase/docvw/edtwin2.cxx
@@ -375,11 +375,17 @@ void SwEditWin::RequestHelp(const HelpEvent &rEvt)
const auto pAuthorityField = static_cast<const SwAuthorityField*>(pField);
sText = pAuthorityField->GetAuthority(rSh.GetLayout());
- if (pAuthorityField->HasURL())
+ if (!pAuthorityField->UseTargetURL() && pAuthorityField->HasURL())
{
- const OUString& rURL = pAuthorityField->GetURI(false);
+ const OUString& rURL = pAuthorityField->GetAbsoluteURL();
sText += "\n" + SfxHelp::GetURLHelpText(rURL);
}
+ else if (pAuthorityField->UseTargetURL() && pAuthorityField->HasTargetURL())
+ {
+ const OUString& rURL = pAuthorityField->GetAbsoluteTargetURL();
+ sText += "\n" + SfxHelp::GetURLHelpText(rURL);
+ }
+
break;
}
diff --git a/sw/source/uibase/shells/textsh1.cxx b/sw/source/uibase/shells/textsh1.cxx
index 156572854c19..f1d9522a89f7 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -1821,13 +1821,20 @@ void SwTextShell::Execute(SfxRequest &rReq)
if (pField && pField->GetTyp()->Which() == SwFieldIds::TableOfAuthorities)
{
const auto& rAuthorityField = *static_cast<const SwAuthorityField*>(pField);
- if (rAuthorityField.HasURL())
+ if (!rAuthorityField.UseTargetURL() && rAuthorityField.HasURL())
{
// Bibliography entry with URL also provides a hyperlink.
const OUString& rURL
= rAuthorityField.GetAuthEntry()->GetAuthorField(AUTH_FIELD_URL);
::LoadURL(rWrtSh, rURL, LoadUrlFlags::NewView, /*rTargetFrameName=*/OUString());
}
+ else if (rAuthorityField.UseTargetURL() && rAuthorityField.HasTargetURL())
+ {
+ // Bibliography entry with URL also provides a hyperlink.
+ const OUString& rURL
+ = rAuthorityField.GetAuthEntry()->GetAuthorField(AUTH_FIELD_TARGET_URL);
+ ::LoadURL(rWrtSh, rURL, LoadUrlFlags::NewView, /*rTargetFrameName=*/OUString());
+ }
}
}
}
@@ -2552,7 +2559,10 @@ void SwTextShell::GetState( SfxItemSet &rSet )
{
// Bibliography entry with URL also provides a hyperlink.
const auto& rAuthorityField = *static_cast<const SwAuthorityField*>(pField);
- bAuthorityFieldURL = rAuthorityField.HasURL();
+ if (!rAuthorityField.UseTargetURL())
+ bAuthorityFieldURL = rAuthorityField.HasURL();
+ else
+ bAuthorityFieldURL = rAuthorityField.HasTargetURL();
}
if (SfxItemState::SET > aSet.GetItemState(RES_TXTATR_INETFMT, false)
&& !bAuthorityFieldURL)
diff --git a/sw/source/uibase/utlui/initui.cxx b/sw/source/uibase/utlui/initui.cxx
index 4438935585b9..51e2b8e8894e 100644
--- a/sw/source/uibase/utlui/initui.cxx
+++ b/sw/source/uibase/utlui/initui.cxx
@@ -236,6 +236,8 @@ namespace
STR_AUTH_FIELD_CUSTOM5,
STR_AUTH_FIELD_ISBN,
STR_AUTH_FIELD_LOCAL_URL,
+ STR_AUTH_FIELD_TARGET_URL,
+ STR_AUTH_FIELD_USE_TARGET_URL,
};
}
diff --git a/sw/source/uibase/wrtsh/wrtsh2.cxx b/sw/source/uibase/wrtsh/wrtsh2.cxx
index b9995c0922b4..3249b39e86eb 100644
--- a/sw/source/uibase/wrtsh/wrtsh2.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh2.cxx
@@ -49,6 +49,7 @@
#include <swabstdlg.hxx>
#include <SwRewriter.hxx>
#include <authfld.hxx>
+#include <ndtxt.hxx>
#include <com/sun/star/document/XDocumentProperties.hpp>
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
@@ -342,8 +343,11 @@ void SwWrtShell::ClickToField(const SwField& rField, bool bExecHyperlinks)
{
addCurrentPosition();
- // cross reference field must not be selected because it moves the cursor
- if (SwFieldIds::GetRef != rField.GetTyp()->Which())
+ // Since the cross reference and bibliography mark move the cursor,
+ // only select the field if it's not a Ctrl+Click
+ if (!bExecHyperlinks
+ || (SwFieldIds::GetRef != rField.GetTyp()->Which()
+ && SwFieldIds::TableOfAuthorities != rField.GetTyp()->Which()))
{
StartAllAction();
Right( SwCursorSkipMode::Chars, true, 1, false ); // Select the field.
@@ -405,22 +409,74 @@ void SwWrtShell::ClickToField(const SwField& rField, bool bExecHyperlinks)
case SwFieldIds::TableOfAuthorities:
{
if (!bExecHyperlinks)
+ break; // Since it's not a Ctrl+Click, do not jump anywhere
+
+ Point vStartPoint = GetCursor_()->GetPtPos();
+ const SwAuthorityField* pField = static_cast<const SwAuthorityField*>(&rField);
+
+ if (!pField->UseTargetURL() && pField->HasURL())
{
- break;
- }
+ // Since user didn't opt in to use Target URL, open standard URL
- auto pField = static_cast<const SwAuthorityField*>(&rField);
- if (!pField->HasURL())
+ const OUString& rURL = pField->GetAbsoluteURL();
+ ::LoadURL(*this, rURL, LoadUrlFlags::NewView, /*rTargetFrameName=*/OUString());
+ }
+ else if (pField->UseTargetURL() && pField->HasTargetURL())
{
- break;
+ // Since user opted in to use Target URL and field has Target URL, use it
+
+ const OUString& rURL = pField->GetAbsoluteTargetURL();
+ ::LoadURL(*this, rURL, LoadUrlFlags::NewView, /*rTargetFrameName=*/OUString());
}
+ else if (pField->UseTargetURL())
+ {
+ // Since user opted in to use Target URL but the field doesn't have Target URL,
+ // try finding matching bibliography table line
+
+ const bool bWasViewLocked = IsViewLocked();
+ LockView(true);
- const OUString& rURL = pField->GetAbsoluteURL();
- ::LoadURL(*this, rURL, LoadUrlFlags::NewView, /*rTargetFrameName=*/OUString());
+ // Note: This way of iterating doesn't seem to take into account TOXes
+ // that are in a frame, probably in some other cases too
+ GotoPage(1);
+ while (GotoNextTOXBase())
+ {
+ const SwTOXBase* pIteratedTOX = nullptr;
+ const SwTOXBase* pPreviousTOX = nullptr;
+ OUString vFieldText;
+ while ((pIteratedTOX = GetCurTOX()) != nullptr
+ && pIteratedTOX->GetType() == TOX_AUTHORITIES)
+ {
+ if (pIteratedTOX != pPreviousTOX)
+ vFieldText = pField->GetAuthority(GetLayout(), &pIteratedTOX->GetTOXForm());
+
+ if (const SwNode& rCurrentNode = GetCursor()->GetPoint()->GetNode();
+ rCurrentNode.GetNodeType() == SwNodeType::Text
+ && (GetCursor()->GetPoint()->GetNode().FindSectionNode()->GetSection().GetType()
+ == SectionType::ToxContent) // this checks it's not a heading
+ && static_cast<const SwTextNode*>(&rCurrentNode)->GetText() == vFieldText)
+ {
+ // Since a node has been found that is a text node, isn't a heading,
+ // and has text matching to text generated by the field, jump to it
+ LockView(bWasViewLocked);
+ ShowCursor();
+ return;
+ }
+ pPreviousTOX = pIteratedTOX;
+ FwdPara();
+ }
+ }
+ // Since a matching node has not been found, return to original position
+ SetCursor(&vStartPoint);
+ LockView(bWasViewLocked);
+ }
}
break;
case SwFieldIds::GetRef:
+ if (!bExecHyperlinks)
+ break;
+
StartAllAction();
SwCursorShell::GotoRefMark( static_cast<const SwGetRefField&>(rField).GetSetRefName(),
static_cast<const SwGetRefField&>(rField).GetSubType(),
diff --git a/sw/uiconfig/swriter/ui/bibliofragment.ui b/sw/uiconfig/swriter/ui/bibliofragment.ui
index f35db697e1e7..2652711b4472 100644
--- a/sw/uiconfig/swriter/ui/bibliofragment.ui
+++ b/sw/uiconfig/swriter/ui/bibliofragment.ui
@@ -109,6 +109,30 @@
</packing>
</child>
<child>
+ <object class="GtkBox" id="togglebox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkCheckButton" id="usetargeturlcb">
+ <property name="label" translatable="yes" context=""></property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkComboBoxText" id="listbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 8b1a8b6287da..2b17a18dd33b 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -3631,7 +3631,12 @@ we check in the following sequence:
}
else
{
- INetURLObject aNewURL(rtl::Uri::convertRelToAbs(m_aContext.BaseURL, url));
+ INetURLObject aNewURL(rtl::Uri::convertRelToAbs(
+ (m_aContext.BaseURL.getLength() > 0 ?
+ m_aContext.BaseURL :
+ //use dummy location if empty
+ u"http://ahost.ax"),
+ url));
aTargetURL = aNewURL; //reassign the new target URL
//recompute the target protocol, with the new URL
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 7eb6f14eee54..daa658011ae3 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -3469,6 +3469,8 @@ namespace xmloff::token {
TOKEN("margin-gutter", XML_MARGIN_GUTTER),
TOKEN("local-url", XML_LOCAL_URL),
+ TOKEN("target-url", XML_TARGET_URL),
+ TOKEN("use-target-url", XML_USE_TARGET_URL),
TOKEN("dir", XML_DIR ),
TOKEN("displaystyle", XML_DISPLAYSTYLE ),
diff --git a/xmloff/source/text/txtflde.cxx b/xmloff/source/text/txtflde.cxx
index 58ad8604f0a1..71093e61420a 100644
--- a/xmloff/source/text/txtflde.cxx
+++ b/xmloff/source/text/txtflde.cxx
@@ -2708,7 +2708,7 @@ void XMLTextFieldExport::ProcessBibliographyData(
if (!sStr.isEmpty())
{
XMLTokenEnum eElement = MapBibliographyFieldName(rProp.Name);
- if (eElement == XML_URL || eElement == XML_LOCAL_URL)
+ if (eElement == XML_URL || eElement == XML_LOCAL_URL || eElement == XML_TARGET_URL)
{
sStr = GetExport().GetRelativeReference(sStr);
}
@@ -3414,6 +3414,14 @@ enum XMLTokenEnum XMLTextFieldExport::MapBibliographyFieldName(std::u16string_vi
{
eName = XML_LOCAL_URL;
}
+ else if (sName == u"TargetURL")
+ {
+ eName = XML_TARGET_URL;
+ }
+ else if (sName == u"UseTargetURL")
+ {
+ eName = XML_USE_TARGET_URL;
+ }
else
{
SAL_WARN("xmloff.text", "Unknown bibliography info data");
diff --git a/xmloff/source/text/txtfldi.cxx b/xmloff/source/text/txtfldi.cxx
index af2bd8aa2ac1..e2fad89cac9d 100644
--- a/xmloff/source/text/txtfldi.cxx
+++ b/xmloff/source/text/txtfldi.cxx
@@ -2969,7 +2969,7 @@ void XMLBibliographyFieldImportContext::startFastElement(
else
{
OUString aStringValue = aIter.toString();
- if (nToken == XML_URL || nToken == XML_LOCAL_URL)
+ if (nToken == XML_URL || nToken == XML_LOCAL_URL || nToken == XML_TARGET_URL)
{
aStringValue = GetImport().GetAbsoluteReference(aStringValue);
}
@@ -3113,6 +3113,12 @@ const char* XMLBibliographyFieldImportContext::MapBibliographyFieldName(
case XML_LOCAL_URL:
pName = "LocalURL";
break;
+ case XML_TARGET_URL:
+ pName = "TargetURL";
+ break;
+ case XML_USE_TARGET_URL:
+ pName = "UseTargetURL";
+ break;
default:
assert(false && "Unknown bibliography info data");
pName = nullptr;
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index 576efe9b8bd5..098d8dd4c501 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -3216,6 +3216,8 @@ page-content-top
page-content-bottom
margin-gutter
local-url
+target-url
+use-target-url
dir
displaystyle
infinity