tdf#153396 - Bibliography marks improvements
Adds option to separate function of "URL" into (listed) "URL" and "Target URL" to allow for more flexibility (in that case if target URL is empty, bibliography mark hyperlink leads to bibliography table row if possible) When writing tests also found and fixed bug where exporting new file with anchor link bibliography mark crashes LO. Change-Id: Ic1b5c8c9590c0338dcfc4fa3a981142bddae0113 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147868 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
This commit is contained in:
committed by
Miklos Vajna
parent
cc45d748e2
commit
7b99871635
@@ -3465,6 +3465,8 @@ namespace xmloff::token {
|
||||
XML_MARGIN_GUTTER,
|
||||
|
||||
XML_LOCAL_URL,
|
||||
XML_TARGET_URL,
|
||||
XML_USE_TARGET_URL,
|
||||
|
||||
// Math ml
|
||||
XML_DIR,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
|
||||
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);
|
||||
|
||||
const OUString& rURL = rAuthorityField.GetAuthEntry()->GetAuthorField(AUTH_FIELD_URL);
|
||||
const SwTextNode& rTextNode = pFormatField->GetTextField()->GetTextNode();
|
||||
if (!lcl_TryMoveToNonHiddenField(mrSh, rTextNode, *pFormatField))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
OUString const content(rAuthorityField.ExpandField(true, mrSh.GetLayout()));
|
||||
|
||||
// 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))
|
||||
const SwTextNode& rTextNode = pFormatField->GetTextField()->GetTextNode();
|
||||
if (!lcl_TryMoveToNonHiddenField(mrSh, rTextNode, *pFormatField))
|
||||
{
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
mrSh.SwCursorShell::ClearMark();
|
||||
OUString const content(rAuthorityField.ExpandField(true, mrSh.GetLayout()));
|
||||
|
||||
// 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->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()));
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
break; // Since it's not a Ctrl+Click, do not jump anywhere
|
||||
|
||||
auto pField = static_cast<const SwAuthorityField*>(&rField);
|
||||
if (!pField->HasURL())
|
||||
{
|
||||
break;
|
||||
}
|
||||
Point vStartPoint = GetCursor_()->GetPtPos();
|
||||
const SwAuthorityField* pField = static_cast<const SwAuthorityField*>(&rField);
|
||||
|
||||
const OUString& rURL = pField->GetAbsoluteURL();
|
||||
::LoadURL(*this, rURL, LoadUrlFlags::NewView, /*rTargetFrameName=*/OUString());
|
||||
if (!pField->UseTargetURL() && pField->HasURL())
|
||||
{
|
||||
// Since user didn't opt in to use Target URL, open standard URL
|
||||
|
||||
const OUString& rURL = pField->GetAbsoluteURL();
|
||||
::LoadURL(*this, rURL, LoadUrlFlags::NewView, /*rTargetFrameName=*/OUString());
|
||||
}
|
||||
else if (pField->UseTargetURL() && pField->HasTargetURL())
|
||||
{
|
||||
// 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);
|
||||
|
||||
// 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(),
|
||||
|
||||
@@ -108,6 +108,30 @@
|
||||
<property name="top_attach">0</property>
|
||||
</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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ),
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3216,6 +3216,8 @@ page-content-top
|
||||
page-content-bottom
|
||||
margin-gutter
|
||||
local-url
|
||||
target-url
|
||||
use-target-url
|
||||
dir
|
||||
displaystyle
|
||||
infinity
|
||||
|
||||
Reference in New Issue
Block a user