tdf#30709 sw Style Inspector: show section and parent metadata
Show text:section RDF metadata under the node "Sections"
in the Style Inspector. Also show parent metadata of nested
annotated text ranges (and sections) at the cursor
position, not only metadata of the innermost.
Show metadata fields (text:meta-field) and annotated text
ranges (text:meta) under the new category "Fields" instead
of at "Character Direct Formatting".
Put section and other metadata in front of the other style
settings text. Hide their empty categories "Sections",
"Bookmarks" and "Fields", if there is no associated RDF
metadata.
Follow-up of commit db7ef0a9ed21b0271345249b97a7a10d60d259e6
"tdf#30709 sw Style Inspector: show bookmark data".
Change-Id: Ibfd2c5dfb1597afaa8038b497977505914bed76d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126065
Tested-by: Jenkins
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/include/svx/sidebar/InspectorTextPanel.hxx b/include/svx/sidebar/InspectorTextPanel.hxx
index ce4eecf..f6ef023 100644
--- a/include/svx/sidebar/InspectorTextPanel.hxx
+++ b/include/svx/sidebar/InspectorTextPanel.hxx
@@ -50,7 +50,7 @@ public:
InspectorTextPanel(weld::Widget* pParent);
void updateEntries(const std::vector<TreeNode>& rStore);
void updateEntries(const std::vector<TreeNode>& rStore, const sal_Int32 nParIdx);
private:
std::unique_ptr<weld::TreeView> mpListBoxStyles;
diff --git a/svx/source/sidebar/inspector/InspectorTextPanel.cxx b/svx/source/sidebar/inspector/InspectorTextPanel.cxx
index bdd87ee..69ed0f0 100644
--- a/svx/source/sidebar/inspector/InspectorTextPanel.cxx
+++ b/svx/source/sidebar/inspector/InspectorTextPanel.cxx
@@ -132,7 +132,7 @@ static void FillBox_Impl(weld::TreeView& rListBoxStyles, const TreeNode& rCurren
FillBox_Impl(rListBoxStyles, rChildNode, pResult.get());
}
void InspectorTextPanel::updateEntries(const std::vector<TreeNode>& rStore)
void InspectorTextPanel::updateEntries(const std::vector<TreeNode>& rStore, const sal_Int32 nParIdx)
{
mpListBoxStyles->freeze();
mpListBoxStyles->clear();
@@ -149,12 +149,21 @@ void InspectorTextPanel::updateEntries(const std::vector<TreeNode>& rStore)
return false;
});
// Collapse "Default Paragraph Style"
std::unique_ptr<weld::TreeIter> pEntry = mpListBoxStyles->make_iterator();
if (!mpListBoxStyles->get_iter_first(*pEntry))
return;
// skip the optional metadata items before "Default Paragraph Style"
for (sal_Int32 i = 0; i < nParIdx; ++i)
{
if (!mpListBoxStyles->iter_next_sibling(*pEntry))
return;
}
if (!mpListBoxStyles->iter_next(*pEntry))
return;
mpListBoxStyles->collapse_row(*pEntry); // Collapse "Default Paragraph Style"
mpListBoxStyles->collapse_row(*pEntry);
}
InspectorTextPanel::~InspectorTextPanel() {}
diff --git a/sw/qa/uitest/styleInspector/styleInspector.py b/sw/qa/uitest/styleInspector/styleInspector.py
index f95ca9b..7cfabce 100644
--- a/sw/qa/uitest/styleInspector/styleInspector.py
+++ b/sw/qa/uitest/styleInspector/styleInspector.py
@@ -171,10 +171,10 @@ class styleNavigator(UITestCase):
self.xUITest.executeCommand(".uno:GoRight")
# The cursor is on text with annotated text range
xDirFormatting = xListBox.getChild('3')
self.assertEqual(2, len(xDirFormatting.getChildren()))
xDirFormatting = xListBox.getChild('0')
self.assertEqual("Fields\t", get_state_as_dict(xListBox.getChild('0'))['Text'])
self.assertEqual(1, len(xDirFormatting.getChildren()))
self.assertEqual("Metadata Reference\t", get_state_as_dict(xDirFormatting.getChild('0'))['Text'])
self.assertEqual("Nested Text Content\tAnnotated text range", get_state_as_dict(xDirFormatting.getChild('1'))['Text'])
xMetadata = xDirFormatting.getChild('0')
self.assertEqual(4, len(xMetadata.getChildren()))
@@ -183,8 +183,12 @@ class styleNavigator(UITestCase):
self.assertEqual("http://www.w3.org/2000/01/rdf-schema#comment\tComment...", get_state_as_dict(xMetadata.getChild('2'))['Text'])
self.assertEqual("http://www.w3.org/2000/01/rdf-schema#label\tAnnotated paragraph portion", get_state_as_dict(xMetadata.getChild('3'))['Text'])
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
xDirFormatting = xListBox.getChild('4')
self.assertEqual(1, len(xDirFormatting.getChildren()))
self.assertEqual("Nested Text Content\tAnnotated text range", get_state_as_dict(xDirFormatting.getChild('0'))['Text'])
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
self.assertEqual(0, len(xListBox.getChild('3').getChildren()))
self.xUITest.executeCommand(".uno:Sidebar")
@@ -209,19 +213,20 @@ class styleNavigator(UITestCase):
self.xUITest.executeCommand(".uno:GoDown")
# The cursor is on text with paragraph metadata showed under direct paragraph formatting
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
self.assertEqual(137, len(xListBox.getChild('0').getChild('0').getChildren()))
self.assertEqual(1, len(xListBox.getChild('1').getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xListBox.getChild('1').getChild('0'))['Text'])
self.assertEqual(137, len(xListBox.getChild('1').getChild('0').getChildren()))
# Outer bookmark
xBookmarkFormatting = xListBox.getChild('4')
xBookmarkFormatting = xListBox.getChild('0')
self.assertEqual("Bookmarks\t", get_state_as_dict(xBookmarkFormatting)['Text'])
self.assertEqual(1, len(xBookmarkFormatting.getChildren()))
self.assertEqual("Bookmark 1\t", get_state_as_dict(xBookmarkFormatting.getChild('0'))['Text'])
self.xUITest.executeCommand(".uno:GoDown")
# Inner bookmark
xBookmarkFormatting = xListBox.getChild('4')
xBookmarkFormatting = xListBox.getChild('0')
self.assertEqual(2, len(xBookmarkFormatting.getChildren()))
self.assertEqual("Bookmark 1\t", get_state_as_dict(xBookmarkFormatting.getChild('0'))['Text'])
@@ -238,7 +243,7 @@ class styleNavigator(UITestCase):
# Only in outer bookmark again
self.xUITest.executeCommand(".uno:GoDown")
xBookmarkFormatting = xListBox.getChild('4')
xBookmarkFormatting = xListBox.getChild('0')
self.assertEqual(1, len(xBookmarkFormatting.getChildren()))
self.assertEqual("Bookmark 1\t", get_state_as_dict(xBookmarkFormatting.getChild('0'))['Text'])
@@ -270,10 +275,10 @@ class styleNavigator(UITestCase):
self.xUITest.executeCommand(".uno:GoRight")
# The cursor is on text with annotated text range
xDirFormatting = xListBox.getChild('3')
self.assertEqual(2, len(xDirFormatting.getChildren()))
xDirFormatting = xListBox.getChild('0')
self.assertEqual(1, len(xDirFormatting.getChildren()))
self.assertEqual("Metadata Reference\t", get_state_as_dict(xDirFormatting.getChild('0'))['Text'])
self.assertEqual("Nested Text Content\tipsum", get_state_as_dict(xDirFormatting.getChild('1'))['Text'])
self.assertEqual("Nested Text Content\tipsum", get_state_as_dict(xListBox.getChild(4).getChild('0'))['Text'])
xMetadata = xDirFormatting.getChild('0')
self.assertEqual(2, len(xMetadata.getChildren()))
@@ -281,8 +286,8 @@ class styleNavigator(UITestCase):
# RGB code of the custom shading color of the annotated text range is FFB7E9
self.assertEqual("urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0odf#shading\tFFB7E9", get_state_as_dict(xMetadata.getChild('1'))['Text'])
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
self.assertEqual(0, len(xListBox.getChild('3').getChildren()))
# go to next word with RDF annotation
self.xUITest.executeCommand(".uno:GoToNextWord")
@@ -291,10 +296,10 @@ class styleNavigator(UITestCase):
self.xUITest.executeCommand(".uno:GoRight")
# The cursor is on text with annotated text range
xDirFormatting = xListBox.getChild('3')
self.assertEqual(2, len(xDirFormatting.getChildren()))
xDirFormatting = xListBox.getChild('0')
self.assertEqual(1, len(xDirFormatting.getChildren()))
self.assertEqual("Metadata Reference\t", get_state_as_dict(xDirFormatting.getChild('0'))['Text'])
self.assertEqual("Nested Text Content\tames", get_state_as_dict(xDirFormatting.getChild('1'))['Text'])
self.assertEqual("Nested Text Content\tames", get_state_as_dict(xListBox.getChild(4).getChild('0'))['Text'])
xMetadata = xDirFormatting.getChild('0')
self.assertEqual(2, len(xMetadata.getChildren()))
@@ -302,8 +307,8 @@ class styleNavigator(UITestCase):
# RGB code of the custom shading color of the annotated text range is 97E1E9 (the code can be lower case, see STRtoRGB)
self.assertEqual("urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0odf#shading\t97e1e9", get_state_as_dict(xMetadata.getChild('1'))['Text'])
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
self.assertEqual(0, len(xListBox.getChild('3').getChildren()))
# add a new annotated text range and check it in the Style Inspector
self.xUITest.executeCommand(".uno:GoToStartOfDoc")
@@ -337,7 +342,7 @@ class styleNavigator(UITestCase):
self.xUITest.executeCommand(".uno:Undo")
xDirFormatting = xListBox.getChild('3')
xDirFormatting = xListBox.getChild('0')
xMetadata = xDirFormatting.getChild('0')
self.assertEqual(2, len(xMetadata.getChildren()))
# RGB code of the custom shading color of the annotated text range is BBFF88
diff --git a/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx b/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
index b0a0258..33d2ae6 100644
--- a/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
+++ b/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
@@ -26,6 +26,7 @@
#include <unoprnms.hxx>
#include <editeng/unoprnms.hxx>
#include <com/sun/star/text/XBookmarksSupplier.hpp>
#include <com/sun/star/text/XTextSectionsSupplier.hpp>
#include <com/sun/star/text/XTextRange.hpp>
#include <com/sun/star/text/XTextRangeCompare.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
@@ -36,6 +37,7 @@
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <com/sun/star/rdf/XMetadatable.hpp>
#include <com/sun/star/rdf/XDocumentMetadataAccess.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <unotextrange.hxx>
#include <comphelper/string.hxx>
@@ -48,7 +50,8 @@
namespace sw::sidebar
{
static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>& aStore);
static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>& aStore,
sal_Int32& rParIdx);
std::unique_ptr<PanelLayout> WriterInspectorTextPanel::Create(weld::Widget* pParent)
{
@@ -60,6 +63,7 @@ std::unique_ptr<PanelLayout> WriterInspectorTextPanel::Create(weld::Widget* pPar
WriterInspectorTextPanel::WriterInspectorTextPanel(weld::Widget* pParent)
: InspectorTextPanel(pParent)
, m_nParIdx(0)
{
SwDocShell* pDocSh = static_cast<SwDocShell*>(SfxObjectShell::Current());
m_pShell = pDocSh ? pDocSh->GetWrtShell() : nullptr;
@@ -72,8 +76,8 @@ WriterInspectorTextPanel::WriterInspectorTextPanel(weld::Widget* pParent)
// Update panel on start
std::vector<svx::sidebar::TreeNode> aStore;
if (pDocSh && pDocSh->GetDoc()->GetEditShell()->GetCursor()->GetNode().GetTextNode())
UpdateTree(pDocSh, aStore);
updateEntries(aStore);
UpdateTree(pDocSh, aStore, m_nParIdx);
updateEntries(aStore, m_nParIdx);
}
WriterInspectorTextPanel::~WriterInspectorTextPanel() { m_pShell->SetChgLnk(m_oldLink); }
@@ -390,6 +394,16 @@ static void MetadataToTreeNode(const css::uno::Reference<css::uno::XInterface>&
if (!xMeta.is() || xMeta->getMetadataReference().Second.isEmpty())
return;
// add metadata of parents for nested annotated text ranges
uno::Reference<container::XChild> xChild(rSource, uno::UNO_QUERY);
if (xChild.is())
{
uno::Reference<container::XEnumerationAccess> xParentMeta(xChild->getParent(),
uno::UNO_QUERY);
if (xParentMeta.is())
MetadataToTreeNode(xParentMeta, rNode);
}
svx::sidebar::TreeNode aCurNode;
aCurNode.sNodeName = PropertyNametoRID("MetadataReference");
aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
@@ -449,7 +463,8 @@ PropertyToTreeNode(const css::beans::Property& rProperty,
static void InsertValues(const css::uno::Reference<css::uno::XInterface>& rSource,
std::unordered_map<OUString, bool>& rIsDefined,
svx::sidebar::TreeNode& rNode, const bool isRoot,
const std::vector<OUString>& rHiddenProperty)
const std::vector<OUString>& rHiddenProperty,
svx::sidebar::TreeNode& rFieldsNode)
{
uno::Reference<beans::XPropertySet> xPropertiesSet(rSource, uno::UNO_QUERY_THROW);
uno::Reference<beans::XPropertyState> xPropertiesState(rSource, uno::UNO_QUERY_THROW);
@@ -476,7 +491,7 @@ static void InsertValues(const css::uno::Reference<css::uno::XInterface>& rSourc
{
uno::Reference<container::XEnumerationAccess> xMeta;
if (aCurNode.aValue >>= xMeta)
MetadataToTreeNode(xMeta, rNode);
MetadataToTreeNode(xMeta, rFieldsNode);
aCurNode.aValue <<= NestedTextContentToText(aCurNode.aValue);
}
@@ -495,7 +510,8 @@ static void InsertValues(const css::uno::Reference<css::uno::XInterface>& rSourc
});
}
static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>& aStore)
static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>& aStore,
sal_Int32& rParIdx)
{
SwDoc* pDoc = pDocSh->GetDoc();
SwPaM* pCursor = pDoc->GetEditShell()->GetCursor();
@@ -504,17 +520,23 @@ static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>&
svx::sidebar::TreeNode aParaNode;
svx::sidebar::TreeNode aParaDFNode;
svx::sidebar::TreeNode aBookmarksNode;
svx::sidebar::TreeNode aFieldsNode;
svx::sidebar::TreeNode aTextSectionsNode;
aCharNode.sNodeName = SwResId(STR_CHARACTERSTYLEFAMILY);
aParaNode.sNodeName = SwResId(STR_PARAGRAPHSTYLEFAMILY);
aCharDFNode.sNodeName = SwResId(RID_CHAR_DIRECTFORMAT);
aParaDFNode.sNodeName = SwResId(RID_PARA_DIRECTFORMAT);
aBookmarksNode.sNodeName = SwResId(STR_CONTENT_TYPE_BOOKMARK);
aFieldsNode.sNodeName = SwResId(STR_CONTENT_TYPE_TEXTFIELD);
aTextSectionsNode.sNodeName = SwResId(STR_CONTENT_TYPE_REGION);
aCharDFNode.NodeType = svx::sidebar::TreeNode::Category;
aCharNode.NodeType = svx::sidebar::TreeNode::Category;
aParaNode.NodeType = svx::sidebar::TreeNode::Category;
aParaDFNode.NodeType = svx::sidebar::TreeNode::Category;
aBookmarksNode.NodeType = svx::sidebar::TreeNode::Category;
aFieldsNode.NodeType = svx::sidebar::TreeNode::Category;
aTextSectionsNode.NodeType = svx::sidebar::TreeNode::Category;
uno::Reference<text::XTextRange> xRange(
SwXTextRange::CreateXTextRange(*pDoc, *pCursor->GetPoint(), nullptr));
@@ -533,7 +555,7 @@ static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>&
UNO_NAME_NUMBERING_LEVEL,
UNO_NAME_PARRSID };
InsertValues(xRange, aIsDefined, aCharDFNode, false, aHiddenProperties);
InsertValues(xRange, aIsDefined, aCharDFNode, false, aHiddenProperties, aFieldsNode);
uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(pDocSh->GetBaseModel(),
uno::UNO_QUERY);
@@ -554,7 +576,7 @@ static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>&
aCurrentChild.sNodeName = sDisplayName;
aCurrentChild.NodeType = svx::sidebar::TreeNode::ComplexProperty;
InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, false, {});
InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, false, {}, aFieldsNode);
aCharNode.children.push_back(aCurrentChild);
}
@@ -567,7 +589,8 @@ static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>&
{
// Collect metadata of the current paragraph
MetadataToTreeNode(xThisParagraphRange, aParaDFNode);
InsertValues(xThisParagraphRange, aIsDefined, aParaDFNode, false, aHiddenProperties);
InsertValues(xThisParagraphRange, aIsDefined, aParaDFNode, false, aHiddenProperties,
aFieldsNode);
}
xStyleFamily.set(xStyleFamilies->getByName("ParagraphStyles"), uno::UNO_QUERY_THROW);
@@ -583,7 +606,8 @@ static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>&
aCurrentChild.sNodeName = sDisplayName;
aCurrentChild.NodeType = svx::sidebar::TreeNode::ComplexProperty;
InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, aParentParaStyle.isEmpty(), {});
InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, aParentParaStyle.isEmpty(), {},
aFieldsNode);
aParaNode.children.push_back(aCurrentChild);
sCurrentParaStyle = aParentParaStyle;
@@ -618,7 +642,45 @@ static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>&
aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
MetadataToTreeNode(xBookmark, aCurNode);
aBookmarksNode.children.push_back(aCurNode);
// show bookmark only if it has RDF metadata
if (aCurNode.children.size() > 0)
aBookmarksNode.children.push_back(aCurNode);
}
}
catch (const lang::IllegalArgumentException&)
{
}
}
// Collect sections at character position
uno::Reference<text::XTextSectionsSupplier> xTextSectionsSupplier(pDocSh->GetBaseModel(),
uno::UNO_QUERY);
uno::Reference<container::XIndexAccess> xTextSections(xTextSectionsSupplier->getTextSections(),
uno::UNO_QUERY);
for (sal_Int32 i = 0; i < xTextSections->getCount(); ++i)
{
svx::sidebar::TreeNode aCurNode;
uno::Reference<text::XTextContent> section;
xTextSections->getByIndex(i) >>= section;
uno::Reference<container::XNamed> xTextSection(section, uno::UNO_QUERY);
try
{
uno::Reference<text::XTextRange> sectionRange = section->getAnchor();
uno::Reference<text::XTextRangeCompare> xTextRangeCompare(xRange->getText(),
uno::UNO_QUERY);
if (xTextRangeCompare.is()
&& xTextRangeCompare->compareRegionStarts(sectionRange, xRange) != -1
&& xTextRangeCompare->compareRegionEnds(xRange, sectionRange) != -1)
{
aCurNode.sNodeName = xTextSection->getName();
aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
MetadataToTreeNode(xTextSection, aCurNode);
// show section only if it has RDF metadata
if (aCurNode.children.size() > 0)
aTextSectionsNode.children.push_back(aCurNode);
}
}
catch (const lang::IllegalArgumentException&)
@@ -628,18 +690,35 @@ static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>&
/*
Display Order :-
SECTIONS with RDF metadata (optional)
BOOKMARKS with RDF metadata (optional)
FIELDS with RDF metadata (optional)
PARAGRAPH STYLE
PARAGRAPH DIRECT FORMATTING
CHARACTER STYLE
DIRECT FORMATTING
BOOKMARKS
*/
rParIdx = 0;
// show sections, bookmarks and fields only if they have RDF metadata
if (aTextSectionsNode.children.size() > 0)
{
aStore.push_back(aTextSectionsNode);
rParIdx++;
}
if (aBookmarksNode.children.size() > 0)
{
aStore.push_back(aBookmarksNode);
rParIdx++;
}
if (aFieldsNode.children.size() > 0)
{
aStore.push_back(aFieldsNode);
rParIdx++;
}
aStore.push_back(aParaNode);
aStore.push_back(aParaDFNode);
aStore.push_back(aCharNode);
aStore.push_back(aCharDFNode);
if (aBookmarksNode.children.size() > 0)
aStore.push_back(aBookmarksNode);
}
IMPL_LINK(WriterInspectorTextPanel, AttrChangedNotify, LinkParamNone*, pLink, void)
@@ -651,9 +730,9 @@ IMPL_LINK(WriterInspectorTextPanel, AttrChangedNotify, LinkParamNone*, pLink, vo
std::vector<svx::sidebar::TreeNode> aStore;
if (pDocSh && pDocSh->GetDoc()->GetEditShell()->GetCursor()->GetNode().GetTextNode())
UpdateTree(pDocSh, aStore);
UpdateTree(pDocSh, aStore, m_nParIdx);
updateEntries(aStore);
updateEntries(aStore, m_nParIdx);
}
} // end of namespace svx::sidebar
diff --git a/sw/source/uibase/sidebar/WriterInspectorTextPanel.hxx b/sw/source/uibase/sidebar/WriterInspectorTextPanel.hxx
index 2f72c63..fae6190 100644
--- a/sw/source/uibase/sidebar/WriterInspectorTextPanel.hxx
+++ b/sw/source/uibase/sidebar/WriterInspectorTextPanel.hxx
@@ -36,6 +36,7 @@ public:
private:
SwWrtShell* m_pShell;
Link<LinkParamNone*, void> m_oldLink;
sal_Int32 m_nParIdx; // count optional metadata tree items to collapse default paragraph styles
// attributes have changed
DECL_LINK(AttrChangedNotify, LinkParamNone*, void);