summaryrefslogtreecommitdiffstats
path: root/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx')
-rw-r--r--sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx768
1 files changed, 768 insertions, 0 deletions
diff --git a/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx b/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
new file mode 100644
index 000000000..2f9e305f1
--- /dev/null
+++ b/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
@@ -0,0 +1,768 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "WriterInspectorTextPanel.hxx"
+
+#include <doc.hxx>
+#include <ndtxt.hxx>
+#include <docsh.hxx>
+#include <wrtsh.hxx>
+#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>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#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>
+#include <comphelper/processfactory.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <vcl/settings.hxx>
+#include <inspectorproperties.hrc>
+#include <strings.hrc>
+#include <rdfhelper.hxx>
+
+namespace sw::sidebar
+{
+static void UpdateTree(SwDocShell& rDocSh, SwEditShell& rEditSh,
+ std::vector<svx::sidebar::TreeNode>& aStore, sal_Int32& rParIdx);
+
+std::unique_ptr<PanelLayout> WriterInspectorTextPanel::Create(weld::Widget* pParent)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException(
+ "no parent Window given to WriterInspectorTextPanel::Create", nullptr, 0);
+ return std::make_unique<WriterInspectorTextPanel>(pParent);
+}
+
+WriterInspectorTextPanel::WriterInspectorTextPanel(weld::Widget* pParent)
+ : InspectorTextPanel(pParent)
+ , m_nParIdx(0)
+{
+ SwDocShell* pDocSh = dynamic_cast<SwDocShell*>(SfxObjectShell::Current());
+ m_pShell = pDocSh ? pDocSh->GetWrtShell() : nullptr;
+ if (m_pShell)
+ {
+ m_oldLink = m_pShell->GetChgLnk();
+ m_pShell->SetChgLnk(LINK(this, WriterInspectorTextPanel, AttrChangedNotify));
+
+ // tdf#154629 listen to know if the shell destructs before this panel does,
+ // which can happen on entering print preview
+ m_pShell->Add(this);
+ }
+
+ // Update panel on start
+ std::vector<svx::sidebar::TreeNode> aStore;
+ SwEditShell* pEditSh = pDocSh ? pDocSh->GetDoc()->GetEditShell() : nullptr;
+ if (pEditSh && pEditSh->GetCursor()->GetNode().GetTextNode())
+ UpdateTree(*pDocSh, *pEditSh, aStore, m_nParIdx);
+ updateEntries(aStore, m_nParIdx);
+}
+
+void WriterInspectorTextPanel::SwClientNotify(const SwModify& rModify, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::SwLegacyModify)
+ {
+ const sw::LegacyModifyHint& rLegacy = static_cast<const sw::LegacyModifyHint&>(rHint);
+ if (rLegacy.GetWhich() == RES_OBJECTDYING)
+ m_pShell = nullptr;
+ }
+ SwClient::SwClientNotify(rModify, rHint);
+}
+
+WriterInspectorTextPanel::~WriterInspectorTextPanel()
+{
+ if (m_pShell)
+ {
+ m_pShell->SetChgLnk(m_oldLink);
+ m_pShell->Remove(this);
+ }
+}
+
+static OUString PropertyNametoRID(const OUString& rName)
+{
+ static const std::map<OUString, TranslateId> aNameToRID = {
+ { "BorderDistance", RID_BORDER_DISTANCE },
+ { "BottomBorder", RID_BOTTOM_BORDER },
+ { "BottomBorderDistance", RID_BOTTOM_BORDER_DISTANCE },
+ { "BreakType", RID_BREAK_TYPE },
+ { "Category", RID_CATEGORY },
+ { "Cell", RID_CELL },
+ { "CharAutoEscapement", RID_CHAR_AUTO_ESCAPEMENT },
+ { "CharAutoKerning", RID_CHAR_AUTO_KERNING },
+ { "CharAutoStyleName", RID_CHAR_AUTO_STYLE_NAME },
+ { "CharBackColor", RID_CHAR_BACK_COLOR },
+ { "CharBackTransparent", RID_CHAR_BACK_TRANSPARENT },
+ { "CharBorderDistance", RID_CHAR_BORDER_DISTANCE },
+ { "CharBottomBorder", RID_CHAR_BOTTOM_BORDER },
+ { "CharBottomBorderDistance", RID_CHAR_BOTTOM_BORDER_DISTANCE },
+ { "CharCaseMap", RID_CHAR_CASE_MAP },
+ { "CharColor", RID_CHAR_COLOR },
+ { "CharCombineIsOn", RID_CHAR_COMBINE_IS_ON },
+ { "CharCombinePrefix", RID_CHAR_COMBINE_PREFIX },
+ { "CharCombineSuffix", RID_CHAR_COMBINE_SUFFIX },
+ { "CharContoured", RID_CHAR_CONTOURED },
+ { "CharCrossedOut", RID_CHAR_CROSSED_OUT },
+ { "CharDiffHeight", RID_CHAR_DIFF_HEIGHT },
+ { "CharDiffHeightAsian", RID_CHAR_DIFF_HEIGHT_ASIAN },
+ { "CharDiffHeightComplex", RID_CHAR_DIFF_HEIGHT_COMPLEX },
+ { "CharEmphasis", RID_CHAR_EMPHASIS },
+ { "CharEscapement", RID_CHAR_ESCAPEMENT },
+ { "CharEscapementHeight", RID_CHAR_ESCAPEMENT_HEIGHT },
+ { "CharFlash", RID_CHAR_FLASH },
+ { "CharFontCharSet", RID_CHAR_FONT_CHAR_SET },
+ { "CharFontCharSetAsian", RID_CHAR_FONT_CHAR_SET_ASIAN },
+ { "CharFontCharSetComplex", RID_CHAR_FONT_CHAR_SET_COMPLEX },
+ { "CharFontFamily", RID_CHAR_FONT_FAMILY },
+ { "CharFontFamilyAsian", RID_CHAR_FONT_FAMILY_ASIAN },
+ { "CharFontFamilyComplex", RID_CHAR_FONT_FAMILY_COMPLEX },
+ { "CharFontName", RID_CHAR_FONT_NAME },
+ { "CharFontNameAsian", RID_CHAR_FONT_NAME_ASIAN },
+ { "CharFontNameComplex", RID_CHAR_FONT_NAME_COMPLEX },
+ { "CharFontPitch", RID_CHAR_FONT_PITCH },
+ { "CharFontPitchAsian", RID_CHAR_FONT_PITCH_ASIAN },
+ { "CharFontPitchComplex", RID_CHAR_FONT_PITCH_COMPLEX },
+ { "CharFontStyleName", RID_CHAR_FONT_STYLE_NAME },
+ { "CharFontStyleNameAsian", RID_CHAR_FONT_STYLE_NAME_ASIAN },
+ { "CharFontStyleNameComplex", RID_CHAR_FONT_STYLE_NAME_COMPLEX },
+ { "CharHeight", RID_CHAR_HEIGHT },
+ { "CharHeightAsian", RID_CHAR_HEIGHT_ASIAN },
+ { "CharHeightComplex", RID_CHAR_HEIGHT_COMPLEX },
+ { "CharHidden", RID_CHAR_HIDDEN },
+ { "CharHighlight", RID_CHAR_HIGHLIGHT },
+ { "CharInteropGrabBag", RID_CHAR_INTEROP_GRAB_BAG },
+ { "CharKerning", RID_CHAR_KERNING },
+ { "CharLeftBorder", RID_CHAR_LEFT_BORDER },
+ { "CharLeftBorderDistance", RID_CHAR_LEFT_BORDER_DISTANCE },
+ { "CharLocale", RID_CHAR_LOCALE },
+ { "CharLocaleAsian", RID_CHAR_LOCALE_ASIAN },
+ { "CharLocaleComplex", RID_CHAR_LOCALE_COMPLEX },
+ { "CharNoHyphenation", RID_CHAR_NO_HYPHENATION },
+ { "CharOverline", RID_CHAR_OVERLINE },
+ { "CharOverlineColor", RID_CHAR_OVERLINE_COLOR },
+ { "CharOverlineHasColor", RID_CHAR_OVERLINE_HAS_COLOR },
+ { "CharPosture", RID_CHAR_POSTURE },
+ { "CharPostureAsian", RID_CHAR_POSTURE_ASIAN },
+ { "CharPostureComplex", RID_CHAR_POSTURE_COMPLEX },
+ { "CharPropHeight", RID_CHAR_PROP_HEIGHT },
+ { "CharPropHeightAsian", RID_CHAR_PROP_HEIGHT_ASIAN },
+ { "CharPropHeightComplex", RID_CHAR_PROP_HEIGHT_COMPLEX },
+ { "CharRelief", RID_CHAR_RELIEF },
+ { "CharRightBorder", RID_CHAR_RIGHT_BORDER },
+ { "CharRightBorderDistance", RID_CHAR_RIGHT_BORDER_DISTANCE },
+ { "CharRotation", RID_CHAR_ROTATION },
+ { "CharRotationIsFitToLine", RID_CHAR_ROTATION_IS_FIT_TO_LINE },
+ { "CharScaleWidth", RID_CHAR_SCALE_WIDTH },
+ { "CharShadingValue", RID_CHAR_SHADING_VALUE },
+ { "CharShadowFormat", RID_CHAR_SHADOW_FORMAT },
+ { "CharShadowed", RID_CHAR_SHADOWED },
+ { "CharStrikeout", RID_CHAR_STRIKEOUT },
+ { "CharStyleName", RID_CHAR_STYLE_NAME },
+ { "CharStyleNames", RID_CHAR_STYLE_NAMES },
+ { "CharTopBorder", RID_CHAR_TOP_BORDER },
+ { "CharTopBorderDistance", RID_CHAR_TOP_BORDER_DISTANCE },
+ { "CharTransparence", RID_CHAR_TRANSPARENCE },
+ { "CharUnderline", RID_CHAR_UNDERLINE },
+ { "CharUnderlineColor", RID_CHAR_UNDERLINE_COLOR },
+ { "CharUnderlineHasColor", RID_CHAR_UNDERLINE_HAS_COLOR },
+ { "CharWeight", RID_CHAR_WEIGHT },
+ { "CharWeightAsian", RID_CHAR_WEIGHT_ASIAN },
+ { "CharWeightComplex", RID_CHAR_WEIGHT_COMPLEX },
+ { "CharWordMode", RID_CHAR_WORD_MODE },
+ { "ContinueingPreviousSubTree", RID_CONTINUING_PREVIOUS_SUB_TREE },
+ { "DisplayName", RID_DISPLAY_NAME },
+ { "DocumentIndex", RID_DOCUMENT_INDEX },
+ { "DocumentIndexMark", RID_DOCUMENT_INDEX_MARK },
+ { "DropCapCharStyleName", RID_DROP_CAP_CHAR_STYLE_NAME },
+ { "DropCapFormat", RID_DROP_CAP_FORMAT },
+ { "DropCapWholeWord", RID_DROP_CAP_WHOLE_WORD },
+ { "Endnote", RID_ENDNOTE },
+ { "FillBackground", RID_FILL_BACKGROUND },
+ { "FillBitmap", RID_FILL_BITMAP },
+ { "FillBitmapLogicalSize", RID_FILL_BITMAP_LOGICAL_SIZE },
+ { "FillBitmapMode", RID_FILL_BITMAP_MODE },
+ { "FillBitmapName", RID_FILL_BITMAP_NAME },
+ { "FillBitmapOffsetX", RID_FILL_BITMAP_OFFSET_X },
+ { "FillBitmapOffsetY", RID_FILL_BITMAP_OFFSET_Y },
+ { "FillBitmapPositionOffsetX", RID_FILL_BITMAP_POSITION_OFFSET_X },
+ { "FillBitmapPositionOffsetY", RID_FILL_BITMAP_POSITION_OFFSET_Y },
+ { "FillBitmapRectanglePoint", RID_FILL_BITMAP_RECTANGLE_POINT },
+ { "FillBitmapSizeX", RID_FILL_BITMAP_SIZE_X },
+ { "FillBitmapSizeY", RID_FILL_BITMAP_SIZE_Y },
+ { "FillBitmapStretch", RID_FILL_BITMAP_STRETCH },
+ { "FillBitmapTile", RID_FILL_BITMAP_TILE },
+ { "FillBitmapURL", RID_FILL_BITMAP_URL },
+ { "FillColor", RID_FILL_COLOR },
+ { "FillColor2", RID_FILL_COLOR2 },
+ { "FillGradient", RID_FILL_GRADIENT },
+ { "FillGradientName", RID_FILL_GRADIENT_NAME },
+ { "FillGradientStepCount", RID_FILL_GRADIENT_STEP_COUNT },
+ { "FillHatch", RID_FILL_HATCH },
+ { "FillHatchName", RID_FILL_HATCH_NAME },
+ { "FillStyle", RID_FILL_STYLE },
+ { "FillTransparence", RID_FILL_TRANSPARENCE },
+ { "FillTransparenceGradient", RID_FILL_TRANSPARENCE_GRADIENT },
+ { "FillTransparenceGradientName", RID_FILL_TRANSPARENCE_GRADIENT_NAME },
+ { "FollowStyle", RID_FOLLOW_STYLE },
+ { "Footnote", RID_FOOTNOTE },
+ { "Hidden", RID_HIDDEN },
+ { "HyperLinkEvents", RID_HYPERLINK_EVENTS },
+ { "HyperLinkName", RID_HYPERLINK_NAME },
+ { "HyperLinkTarget", RID_HYPERLINK_TARGET },
+ { "HyperLinkURL", RID_HYPERLINK_URL },
+ { "IsAutoUpdate", RID_IS_AUTO_UPDATE },
+ { "IsPhysical", RID_IS_PHYSICAL },
+ { "LeftBorder", RID_LEFT_BORDER },
+ { "LeftBorderDistance", RID_LEFT_BORDER_DISTANCE },
+ { "ListAutoFormat", RID_LIST_AUTO_FORMAT },
+ { "ListId", RID_LIST_ID },
+ { "ListLabelString", RID_LIST_LABEL_STRING },
+ { "MetadataReference", RID_METADATA_REFERENCE },
+ { "NestedTextContent", RID_NESTED_TEXT_CONTENT },
+ { "NumberingIsNumber", RID_NUMBERING_IS_NUMBER },
+ { "NumberingLevel", RID_NUMBERING_LEVEL },
+ { "NumberingRules", RID_NUMBERING_RULES },
+ { "NumberingStartValue", RID_NUMBERING_START_VALUE },
+ { "NumberingStyleName", RID_NUMBERING_STYLE_NAME },
+ { "OutlineContentVisible", RID_OUTLINE_CONTENT_VISIBLE },
+ { "OutlineLevel", RID_OUTLINE_LEVEL },
+ { "PageDescName", RID_PAGE_DESC_NAME },
+ { "PageNumberOffset", RID_PAGE_NUMBER_OFFSET },
+ { "PageStyleName", RID_PAGE_STYLE_NAME },
+ { "ParRsid", RID_PAR_RSID },
+ { "ParaAdjust", RID_PARA_ADJUST },
+ { "ParaAutoStyleName", RID_PARA_AUTO_STYLE_NAME },
+ { "ParaBackColor", RID_PARA_BACK_COLOR },
+ { "ParaBackGraphic", RID_PARA_BACK_GRAPHIC },
+ { "ParaBackGraphicFilter", RID_PARA_BACK_GRAPHIC_FILTER },
+ { "ParaBackGraphicLocation", RID_PARA_BACK_GRAPHIC_LOCATION },
+ { "ParaBackGraphicURL", RID_PARA_BACK_GRAPHIC_URL },
+ { "ParaBackTransparent", RID_PARA_BACK_TRANSPARENT },
+ { "ParaBottomMargin", RID_PARA_BOTTOM_MARGIN },
+ { "ParaBottomMarginRelative", RID_PARA_BOTTOM_MARGIN_RELATIVE },
+ { "ParaChapterNumberingLevel", RID_PARA_CHAPTER_NUMBERING_LEVEL },
+ { "ParaConditionalStyleName", RID_PARA_CONDITIONAL_STYLE_NAME },
+ { "ParaContextMargin", RID_PARA_CONTEXT_MARGIN },
+ { "ParaExpandSingleWord", RID_PARA_EXPAND_SINGLE_WORD },
+ { "ParaFirstLineIndent", RID_PARA_FIRST_LINE_INDENT },
+ { "ParaFirstLineIndentRelative", RID_PARA_FIRST_LINE_INDENT_RELATIVE },
+ { "ParaHyphenationMaxHyphens", RID_PARA_HYPHENATION_MAX_HYPHENS },
+ { "ParaHyphenationMaxLeadingChars", RID_PARA_HYPHENATION_MAX_LEADING_CHARS },
+ { "ParaHyphenationMaxTrailingChars", RID_PARA_HYPHENATION_MAX_TRAILING_CHARS },
+ { "ParaHyphenationNoCaps", RID_PARA_HYPHENATION_NO_CAPS },
+ { "ParaHyphenationNoLastWord", RID_PARA_HYPHENATION_NO_LAST_WORD },
+ { "ParaHyphenationMinWordLength", RID_PARA_HYPHENATION_MIN_WORD_LENGTH },
+ { "ParaHyphenationZone", RID_PARA_HYPHENATION_ZONE },
+ { "ParaInteropGrabBag", RID_PARA_INTEROP_GRAB_BAG },
+ { "ParaIsAutoFirstLineIndent", RID_PARA_IS_AUTO_FIRST_LINE_INDENT },
+ { "ParaIsCharacterDistance", RID_PARA_IS_CHARACTER_DISTANCE },
+ { "ParaIsConnectBorder", RID_PARA_IS_CONNECT_BORDER },
+ { "ParaIsForbiddenRules", RID_PARA_IS_FORBIDDEN_RULES },
+ { "ParaIsHangingPunctuation", RID_PARA_IS_HANGING_PUNCTUATION },
+ { "ParaIsHyphenation", RID_PARA_IS_HYPHENATION },
+ { "ParaIsNumberingRestart", RID_PARA_IS_NUMBERING_RESTART },
+ { "ParaKeepTogether", RID_PARA_KEEP_TOGETHER },
+ { "ParaLastLineAdjust", RID_PARA_LAST_LINE_ADJUST },
+ { "ParaLeftMargin", RID_PARA_LEFT_MARGIN },
+ { "ParaLeftMarginRelative", RID_PARA_LEFT_MARGIN_RELATIVE },
+ { "ParaLineNumberCount", RID_PARA_LINE_NUMBER_COUNT },
+ { "ParaLineNumberStartValue", RID_PARA_LINE_NUMBER_START_VALUE },
+ { "ParaLineSpacing", RID_PARA_LINE_SPACING },
+ { "ParaOrphans", RID_PARA_ORPHANS },
+ { "ParaRegisterModeActive", RID_PARA_REGISTER_MODE_ACTIVE },
+ { "ParaRightMargin", RID_PARA_RIGHT_MARGIN },
+ { "ParaRightMarginRelative", RID_PARA_RIGHT_MARGIN_RELATIVE },
+ { "ParaShadowFormat", RID_PARA_SHADOW_FORMAT },
+ { "ParaSplit", RID_PARA_SPLIT },
+ { "ParaStyleName", RID_PARA_STYLE_NAME },
+ { "ParaTabStops", RID_PARA_TAB_STOPS },
+ { "ParaTopMargin", RID_PARA_TOP_MARGIN },
+ { "ParaTopMarginRelative", RID_PARA_TOP_MARGIN_RELATIVE },
+ { "ParaUserDefinedAttributes", RID_PARA_USER_DEFINED_ATTRIBUTES },
+ { "ParaVertAlignment", RID_PARA_VERT_ALIGNMENT },
+ { "ParaWidows", RID_PARA_WIDOWS },
+ { "ReferenceMark", RID_REFERENCE_MARK },
+ { "RightBorder", RID_RIGHT_BORDER },
+ { "RightBorderDistance", RID_RIGHT_BORDER_DISTANCE },
+ { "Rsid", RID_RSID },
+ { "RubyAdjust", RID_RUBY_ADJUST },
+ { "RubyCharStyleName", RID_RUBY_CHAR_STYLE_NAME },
+ { "RubyIsAbove", RID_RUBY_IS_ABOVE },
+ { "RubyPosition", RID_RUBY_POSITION },
+ { "RubyText", RID_RUBY_TEXT },
+ { "SnapToGrid", RID_SNAP_TO_GRID },
+ { "StyleInteropGrabBag", RID_STYLE_INTEROP_GRAB_BAG },
+ { "TextField", RID_TEXT_FIELD },
+ { "TextFrame", RID_TEXT_FRAME },
+ { "TextParagraph", RID_TEXT_PARAGRAPH },
+ { "TextSection", RID_TEXT_SECTION },
+ { "TextTable", RID_TEXT_TABLE },
+ { "TextUserDefinedAttributes", RID_TEXT_USER_DEFINED_ATTRIBUTES },
+ { "TopBorder", RID_TOP_BORDER },
+ { "TopBorderDistance", RID_TOP_BORDER_DISTANCE },
+ { "UnvisitedCharStyleName", RID_UNVISITED_CHAR_STYLE_NAME },
+ { "VisitedCharStyleName", RID_VISITED_CHAR_STYLE_NAME },
+ { "WritingMode", RID_WRITING_MODE },
+ { "BorderColor", RID_BORDER_COLOR },
+ { "BorderInnerLineWidth", RID_BORDER_INNER_LINE_WIDTH },
+ { "BorderLineDistance", RID_BORDER_LINE_DISTANCE },
+ { "BorderLineStyle", RID_BORDER_LINE_STYLE },
+ { "BorderLineWidth", RID_BORDER_LINE_WIDTH },
+ { "BorderOuterLineWidth", RID_BORDER_OUTER_LINE_WIDTH },
+ };
+
+ auto itr = aNameToRID.find(rName);
+ if (itr != aNameToRID.end())
+ return SwResId(itr->second);
+ return rName;
+}
+
+static svx::sidebar::TreeNode SimplePropToTreeNode(const OUString& rName, const css::uno::Any& rVal)
+{
+ svx::sidebar::TreeNode aCurNode;
+ aCurNode.sNodeName = PropertyNametoRID(rName);
+ aCurNode.aValue = rVal;
+
+ return aCurNode;
+}
+
+static svx::sidebar::TreeNode BorderToTreeNode(const OUString& rName, const css::uno::Any& rVal)
+{
+ table::BorderLine2 aBorder;
+ rVal >>= aBorder;
+ svx::sidebar::TreeNode aCurNode;
+ aCurNode.sNodeName = PropertyNametoRID(rName);
+ aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
+
+ aCurNode.children.push_back(SimplePropToTreeNode("BorderColor", css::uno::Any(aBorder.Color)));
+ aCurNode.children.push_back(
+ SimplePropToTreeNode("BorderLineWidth", css::uno::Any(aBorder.LineWidth)));
+ aCurNode.children.push_back(
+ SimplePropToTreeNode("BorderLineStyle", css::uno::Any(aBorder.LineStyle)));
+ aCurNode.children.push_back(
+ SimplePropToTreeNode("BorderLineDistance", css::uno::Any(aBorder.LineDistance)));
+ aCurNode.children.push_back(
+ SimplePropToTreeNode("BorderInnerLineWidth", css::uno::Any(aBorder.InnerLineWidth)));
+ aCurNode.children.push_back(
+ SimplePropToTreeNode("BorderOuterLineWidth", css::uno::Any(aBorder.OuterLineWidth)));
+
+ return aCurNode;
+}
+
+static svx::sidebar::TreeNode LocaleToTreeNode(const OUString& rName, const css::uno::Any& rVal)
+{
+ svx::sidebar::TreeNode aCurNode;
+ aCurNode.sNodeName = PropertyNametoRID(rName);
+ lang::Locale aLocale;
+ rVal >>= aLocale;
+ OUString aLocaleText(aLocale.Language + "-" + aLocale.Country);
+ if (!aLocale.Variant.isEmpty())
+ aLocaleText += " (" + aLocale.Variant + ")";
+ aCurNode.aValue <<= aLocaleText;
+
+ return aCurNode;
+}
+
+// Collect text of the current level of the annotated text
+// ranges (InContentMetadata) and metadata fields (MetadataField)
+static OUString NestedTextContentToText(const css::uno::Any& rVal)
+{
+ uno::Reference<container::XEnumerationAccess> xMeta;
+ if (rVal >>= xMeta)
+ {
+ uno::Reference<container::XEnumeration> xMetaPortions = xMeta->createEnumeration();
+
+ OUStringBuffer aBuf;
+ while (xMetaPortions->hasMoreElements())
+ {
+ uno::Reference<css::text::XTextRange> xRng(xMetaPortions->nextElement(),
+ uno::UNO_QUERY);
+ aBuf.append(xRng->getString());
+ }
+ return aBuf.makeStringAndClear();
+ }
+
+ return OUString();
+}
+
+// List metadata associated to the paragraph or character range
+static void MetadataToTreeNode(const css::uno::Reference<css::uno::XInterface>& rSource,
+ svx::sidebar::TreeNode& rNode)
+{
+ uno::Reference<rdf::XMetadatable> xMeta(rSource, uno::UNO_QUERY_THROW);
+ // don't add tree node "Metadata Reference", if there is no xml:id
+ 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;
+
+ aCurNode.children.push_back(
+ SimplePropToTreeNode("xml:id", uno::Any(xMeta->getMetadataReference().Second)));
+
+ // list associated (predicate, object) pairs of the actual subject
+ // under the tree node "Metadata Reference"
+ if (SwDocShell* pDocSh = static_cast<SwDocShell*>(SfxObjectShell::Current()))
+ {
+ uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(pDocSh->GetBaseModel(),
+ uno::UNO_QUERY);
+ const uno::Reference<rdf::XRepository>& xRepo = xDocumentMetadataAccess->getRDFRepository();
+ const css::uno::Reference<css::rdf::XResource> xSubject(rSource, uno::UNO_QUERY);
+ std::map<OUString, OUString> xStatements
+ = SwRDFHelper::getStatements(pDocSh->GetBaseModel(), xRepo->getGraphNames(), xSubject);
+ for (const auto& pair : xStatements)
+ aCurNode.children.push_back(SimplePropToTreeNode(pair.first, uno::Any(pair.second)));
+ }
+
+ rNode.children.push_back(aCurNode);
+}
+
+static svx::sidebar::TreeNode
+PropertyToTreeNode(const css::beans::Property& rProperty,
+ const uno::Reference<beans::XPropertySet>& xPropertiesSet, const bool rIsGrey)
+{
+ const OUString& rPropName = rProperty.Name;
+ svx::sidebar::TreeNode aCurNode;
+ const uno::Any aAny = xPropertiesSet->getPropertyValue(rPropName);
+ aCurNode.sNodeName = PropertyNametoRID(rPropName);
+
+ // These properties are handled separately as they are stored in STRUCT and not in single data members
+ if (rPropName == "CharTopBorder" || rPropName == "CharBottomBorder"
+ || rPropName == "CharLeftBorder" || rPropName == "CharRightBorder"
+ || rPropName == "TopBorder" || rPropName == "BottomBorder" || rPropName == "LeftBorder"
+ || rPropName == "RightBorder")
+ {
+ aCurNode = BorderToTreeNode(rPropName, aAny);
+ }
+ else if (rPropName == "CharLocale")
+ {
+ aCurNode = LocaleToTreeNode(rPropName, aAny);
+ }
+ else
+ aCurNode = SimplePropToTreeNode(rPropName, aAny);
+
+ if (rIsGrey)
+ {
+ aCurNode.isGrey = true;
+ for (svx::sidebar::TreeNode& rChildNode : aCurNode.children)
+ rChildNode.isGrey = true; // grey out all the children nodes
+ }
+
+ return aCurNode;
+}
+
+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,
+ svx::sidebar::TreeNode& rFieldsNode)
+{
+ uno::Reference<beans::XPropertySet> xPropertiesSet(rSource, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertyState> xPropertiesState(rSource, uno::UNO_QUERY_THROW);
+ const uno::Sequence<beans::Property> aProperties
+ = xPropertiesSet->getPropertySetInfo()->getProperties();
+
+ for (const beans::Property& rProperty : aProperties)
+ {
+ const OUString& rPropName = rProperty.Name;
+ if (std::find(rHiddenProperty.begin(), rHiddenProperty.end(), rPropName)
+ != rHiddenProperty.end())
+ continue;
+
+ if (isRoot
+ || xPropertiesState->getPropertyState(rPropName) == beans::PropertyState_DIRECT_VALUE)
+ {
+ svx::sidebar::TreeNode aCurNode
+ = PropertyToTreeNode(rProperty, xPropertiesSet, rIsDefined[rPropName]);
+ rIsDefined[rPropName] = true;
+
+ // process NestedTextContent and show associated metadata
+ // under the tree node "Metadata Reference", if they exist
+ if (rPropName == "NestedTextContent")
+ {
+ uno::Reference<container::XEnumerationAccess> xMeta;
+ if (aCurNode.aValue >>= xMeta)
+ MetadataToTreeNode(xMeta, rFieldsNode);
+ aCurNode.aValue <<= NestedTextContentToText(aCurNode.aValue);
+ }
+
+ rNode.children.push_back(aCurNode);
+ }
+ }
+
+ const comphelper::string::NaturalStringSorter aSorter(
+ comphelper::getProcessComponentContext(),
+ Application::GetSettings().GetUILanguageTag().getLocale());
+
+ std::sort(
+ rNode.children.begin(), rNode.children.end(),
+ [&aSorter](svx::sidebar::TreeNode const& rEntry1, svx::sidebar::TreeNode const& rEntry2) {
+ return aSorter.compare(rEntry1.sNodeName, rEntry2.sNodeName) < 0;
+ });
+}
+
+static void UpdateTree(SwDocShell& rDocSh, SwEditShell& rEditSh,
+ std::vector<svx::sidebar::TreeNode>& aStore, sal_Int32& rParIdx)
+{
+ SwDoc* pDoc = rDocSh.GetDoc();
+ SwPaM* pCursor = rEditSh.GetCursor();
+ svx::sidebar::TreeNode aCharDFNode;
+ svx::sidebar::TreeNode aCharNode;
+ 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));
+ uno::Reference<beans::XPropertySet> xPropertiesSet(xRange, uno::UNO_QUERY_THROW);
+ std::unordered_map<OUString, bool> aIsDefined;
+
+ const std::vector<OUString> aHiddenProperties{ UNO_NAME_RSID,
+ UNO_NAME_PARA_IS_NUMBERING_RESTART,
+ UNO_NAME_PARA_STYLE_NAME,
+ UNO_NAME_PARA_CONDITIONAL_STYLE_NAME,
+ UNO_NAME_PAGE_STYLE_NAME,
+ UNO_NAME_NUMBERING_START_VALUE,
+ UNO_NAME_NUMBERING_IS_NUMBER,
+ UNO_NAME_PARA_CONTINUEING_PREVIOUS_SUB_TREE,
+ UNO_NAME_CHAR_STYLE_NAME,
+ UNO_NAME_NUMBERING_LEVEL,
+ UNO_NAME_PARRSID };
+
+ InsertValues(xRange, aIsDefined, aCharDFNode, false, aHiddenProperties, aFieldsNode);
+
+ uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(rDocSh.GetBaseModel(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xStyleFamilies
+ = xStyleFamiliesSupplier->getStyleFamilies();
+ OUString sCurrentCharStyle, sCurrentParaStyle, sDisplayName;
+
+ uno::Reference<container::XNameAccess> xStyleFamily(
+ xStyleFamilies->getByName("CharacterStyles"), uno::UNO_QUERY_THROW);
+ xPropertiesSet->getPropertyValue("CharStyleName") >>= sCurrentCharStyle;
+ xPropertiesSet->getPropertyValue("ParaStyleName") >>= sCurrentParaStyle;
+
+ if (!sCurrentCharStyle.isEmpty())
+ {
+ xPropertiesSet.set(xStyleFamily->getByName(sCurrentCharStyle), css::uno::UNO_QUERY_THROW);
+ xPropertiesSet->getPropertyValue("DisplayName") >>= sDisplayName;
+ svx::sidebar::TreeNode aCurrentChild;
+ aCurrentChild.sNodeName = sDisplayName;
+ aCurrentChild.NodeType = svx::sidebar::TreeNode::ComplexProperty;
+
+ InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, false, {}, aFieldsNode);
+
+ aCharNode.children.push_back(aCurrentChild);
+ }
+
+ // Collect paragraph direct formatting
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xRange, uno::UNO_QUERY_THROW);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<text::XTextRange> xThisParagraphRange(xParaEnum->nextElement(), uno::UNO_QUERY);
+ if (xThisParagraphRange.is())
+ {
+ // Collect metadata of the current paragraph
+ MetadataToTreeNode(xThisParagraphRange, aParaDFNode);
+ InsertValues(xThisParagraphRange, aIsDefined, aParaDFNode, false, aHiddenProperties,
+ aFieldsNode);
+ }
+
+ xStyleFamily.set(xStyleFamilies->getByName("ParagraphStyles"), uno::UNO_QUERY_THROW);
+
+ while (!sCurrentParaStyle.isEmpty())
+ {
+ uno::Reference<style::XStyle> xPropertiesStyle(xStyleFamily->getByName(sCurrentParaStyle),
+ uno::UNO_QUERY_THROW);
+ xPropertiesSet.set(xPropertiesStyle, css::uno::UNO_QUERY_THROW);
+ xPropertiesSet->getPropertyValue("DisplayName") >>= sDisplayName;
+ OUString aParentParaStyle = xPropertiesStyle->getParentStyle();
+ svx::sidebar::TreeNode aCurrentChild;
+ aCurrentChild.sNodeName = sDisplayName;
+ aCurrentChild.NodeType = svx::sidebar::TreeNode::ComplexProperty;
+
+ InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, aParentParaStyle.isEmpty(), {},
+ aFieldsNode);
+
+ aParaNode.children.push_back(aCurrentChild);
+ sCurrentParaStyle = aParentParaStyle;
+ }
+
+ std::reverse(aParaNode.children.begin(),
+ aParaNode.children.end()); // Parent style should be first then children
+
+ // Collect bookmarks at character position
+ uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(rDocSh.GetBaseModel(),
+ uno::UNO_QUERY);
+
+ uno::Reference<container::XIndexAccess> xBookmarks(xBookmarksSupplier->getBookmarks(),
+ uno::UNO_QUERY);
+ for (sal_Int32 i = 0; i < xBookmarks->getCount(); ++i)
+ {
+ svx::sidebar::TreeNode aCurNode;
+ uno::Reference<text::XTextContent> bookmark;
+ xBookmarks->getByIndex(i) >>= bookmark;
+ uno::Reference<container::XNamed> xBookmark(bookmark, uno::UNO_QUERY);
+
+ try
+ {
+ uno::Reference<text::XTextRange> bookmarkRange = bookmark->getAnchor();
+ uno::Reference<text::XTextRangeCompare> xTextRangeCompare(xRange->getText(),
+ uno::UNO_QUERY);
+ if (xTextRangeCompare.is()
+ && xTextRangeCompare->compareRegionStarts(bookmarkRange, xRange) != -1
+ && xTextRangeCompare->compareRegionEnds(xRange, bookmarkRange) != -1)
+ {
+ aCurNode.sNodeName = xBookmark->getName();
+ aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
+
+ MetadataToTreeNode(xBookmark, 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(rDocSh.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&)
+ {
+ }
+ }
+
+ /*
+ 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
+ */
+ 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);
+}
+
+IMPL_LINK(WriterInspectorTextPanel, AttrChangedNotify, LinkParamNone*, pLink, void)
+{
+ if (m_oldLink.IsSet())
+ m_oldLink.Call(pLink);
+
+ SwDocShell* pDocSh = m_pShell->GetDoc()->GetDocShell();
+ std::vector<svx::sidebar::TreeNode> aStore;
+
+ SwEditShell* pEditSh = pDocSh ? pDocSh->GetDoc()->GetEditShell() : nullptr;
+ if (pEditSh && pEditSh->GetCursor()->GetNode().GetTextNode())
+ UpdateTree(*pDocSh, *pEditSh, aStore, m_nParIdx);
+
+ updateEntries(aStore, m_nParIdx);
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */