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:
Vojtěch Doležal
2023-03-07 07:12:31 +00:00
committed by Miklos Vajna
parent cc45d748e2
commit 7b99871635
21 changed files with 502 additions and 57 deletions
+2
View File
@@ -3465,6 +3465,8 @@ namespace xmloff::token {
XML_MARGIN_GUTTER,
XML_LOCAL_URL,
XML_TARGET_URL,
XML_USE_TARGET_URL,
// Math ml
XML_DIR,
+5
View File
@@ -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)
+2
View File
@@ -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";
+2
View File
@@ -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")
+2
View File
@@ -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
};
+154
View File
@@ -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");
+27 -3
View File
@@ -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))
{
+2 -8
View File
@@ -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;
+130 -27
View File
@@ -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();
}
}
}
+2
View File
@@ -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,
};
}
+34
View File
@@ -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];
+8 -2
View File
@@ -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;
}
+12 -2
View File
@@ -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)
+2
View File
@@ -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,
};
}
+68 -12
View File
@@ -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(),
+24
View File
@@ -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>
+6 -1
View File
@@ -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
+2
View File
@@ -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 ),
+9 -1
View File
@@ -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");
+7 -1
View File
@@ -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;
+2
View File
@@ -3216,6 +3216,8 @@ page-content-top
page-content-bottom
margin-gutter
local-url
target-url
use-target-url
dir
displaystyle
infinity