Add a comment to clarify what kind of inputs the class handles
[LibreOffice.git] / sw / source / uibase / sidebar / WriterInspectorTextPanel.cxx
blobfe1b5e58042d0eb998ea97a6128880e2b9fc28a6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "WriterInspectorTextPanel.hxx"
22 #include <doc.hxx>
23 #include <ndtxt.hxx>
24 #include <docsh.hxx>
25 #include <wrtsh.hxx>
26 #include <unoprnms.hxx>
27 #include <editeng/unoprnms.hxx>
28 #include <com/sun/star/text/XBookmarksSupplier.hpp>
29 #include <com/sun/star/text/XTextSectionsSupplier.hpp>
30 #include <com/sun/star/text/XTextRange.hpp>
31 #include <com/sun/star/text/XTextRangeCompare.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/beans/XPropertyState.hpp>
34 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
35 #include <com/sun/star/table/BorderLine2.hpp>
36 #include <com/sun/star/lang/IllegalArgumentException.hpp>
37 #include <com/sun/star/rdf/XMetadatable.hpp>
38 #include <com/sun/star/rdf/XDocumentMetadataAccess.hpp>
39 #include <com/sun/star/container/XChild.hpp>
41 #include <unotextrange.hxx>
42 #include <comphelper/string.hxx>
43 #include <comphelper/processfactory.hxx>
44 #include <i18nlangtag/languagetag.hxx>
45 #include <vcl/settings.hxx>
46 #include <inspectorproperties.hrc>
47 #include <strings.hrc>
48 #include <rdfhelper.hxx>
49 #include <unotxdoc.hxx>
51 namespace sw::sidebar
53 static void UpdateTree(SwDocShell& rDocSh, SwEditShell& rEditSh,
54 std::vector<svx::sidebar::TreeNode>& aStore, sal_Int32& rParIdx);
56 std::unique_ptr<PanelLayout> WriterInspectorTextPanel::Create(weld::Widget* pParent)
58 if (pParent == nullptr)
59 throw lang::IllegalArgumentException(
60 u"no parent Window given to WriterInspectorTextPanel::Create"_ustr, nullptr, 0);
61 return std::make_unique<WriterInspectorTextPanel>(pParent);
64 WriterInspectorTextPanel::WriterInspectorTextPanel(weld::Widget* pParent)
65 : InspectorTextPanel(pParent)
66 , m_nParIdx(0)
68 SwDocShell* pDocSh = dynamic_cast<SwDocShell*>(SfxObjectShell::Current());
69 m_pShell = pDocSh ? pDocSh->GetWrtShell() : nullptr;
70 if (m_pShell)
72 m_oldLink = m_pShell->GetChgLnk();
73 m_pShell->SetChgLnk(LINK(this, WriterInspectorTextPanel, AttrChangedNotify));
75 // tdf#154629 listen to know if the shell destructs before this panel does,
76 // which can happen on entering print preview
77 m_pShell->Add(*this);
80 // Update panel on start
81 std::vector<svx::sidebar::TreeNode> aStore;
82 SwEditShell* pEditSh = pDocSh ? pDocSh->GetDoc()->GetEditShell() : nullptr;
83 if (pEditSh && pEditSh->GetCursor()->GetPointNode().GetTextNode())
84 UpdateTree(*pDocSh, *pEditSh, aStore, m_nParIdx);
85 updateEntries(aStore, m_nParIdx);
88 void WriterInspectorTextPanel::SwClientNotify(const SwModify& rModify, const SfxHint& rHint)
90 if (rHint.GetId() == SfxHintId::SwObjectDying)
91 m_pShell = nullptr;
92 SwClient::SwClientNotify(rModify, rHint);
95 WriterInspectorTextPanel::~WriterInspectorTextPanel()
97 if (m_pShell)
99 m_pShell->SetChgLnk(m_oldLink);
100 m_pShell->Remove(*this);
104 static OUString PropertyNametoRID(const OUString& rName)
106 static const std::map<OUString, TranslateId> aNameToRID = {
107 { "BorderDistance", RID_BORDER_DISTANCE },
108 { "BottomBorder", RID_BOTTOM_BORDER },
109 { "BottomBorderDistance", RID_BOTTOM_BORDER_DISTANCE },
110 { "BreakType", RID_BREAK_TYPE },
111 { "Category", RID_CATEGORY },
112 { "Cell", RID_CELL },
113 { "CharAutoEscapement", RID_CHAR_AUTO_ESCAPEMENT },
114 { "CharAutoKerning", RID_CHAR_AUTO_KERNING },
115 { "CharAutoStyleName", RID_CHAR_AUTO_STYLE_NAME },
116 { "CharBackColor", RID_CHAR_BACK_COLOR },
117 { "CharBackTransparent", RID_CHAR_BACK_TRANSPARENT },
118 { "CharBorderDistance", RID_CHAR_BORDER_DISTANCE },
119 { "CharBottomBorder", RID_CHAR_BOTTOM_BORDER },
120 { "CharBottomBorderDistance", RID_CHAR_BOTTOM_BORDER_DISTANCE },
121 { "CharCaseMap", RID_CHAR_CASE_MAP },
122 { "CharColor", RID_CHAR_COLOR },
123 { "CharCombineIsOn", RID_CHAR_COMBINE_IS_ON },
124 { "CharCombinePrefix", RID_CHAR_COMBINE_PREFIX },
125 { "CharCombineSuffix", RID_CHAR_COMBINE_SUFFIX },
126 { "CharContoured", RID_CHAR_CONTOURED },
127 { "CharCrossedOut", RID_CHAR_CROSSED_OUT },
128 { "CharDiffHeight", RID_CHAR_DIFF_HEIGHT },
129 { "CharDiffHeightAsian", RID_CHAR_DIFF_HEIGHT_ASIAN },
130 { "CharDiffHeightComplex", RID_CHAR_DIFF_HEIGHT_COMPLEX },
131 { "CharEmphasis", RID_CHAR_EMPHASIS },
132 { "CharEscapement", RID_CHAR_ESCAPEMENT },
133 { "CharEscapementHeight", RID_CHAR_ESCAPEMENT_HEIGHT },
134 { "CharFlash", RID_CHAR_FLASH },
135 { "CharFontCharSet", RID_CHAR_FONT_CHAR_SET },
136 { "CharFontCharSetAsian", RID_CHAR_FONT_CHAR_SET_ASIAN },
137 { "CharFontCharSetComplex", RID_CHAR_FONT_CHAR_SET_COMPLEX },
138 { "CharFontFamily", RID_CHAR_FONT_FAMILY },
139 { "CharFontFamilyAsian", RID_CHAR_FONT_FAMILY_ASIAN },
140 { "CharFontFamilyComplex", RID_CHAR_FONT_FAMILY_COMPLEX },
141 { "CharFontName", RID_CHAR_FONT_NAME },
142 { "CharFontNameAsian", RID_CHAR_FONT_NAME_ASIAN },
143 { "CharFontNameComplex", RID_CHAR_FONT_NAME_COMPLEX },
144 { "CharFontPitch", RID_CHAR_FONT_PITCH },
145 { "CharFontPitchAsian", RID_CHAR_FONT_PITCH_ASIAN },
146 { "CharFontPitchComplex", RID_CHAR_FONT_PITCH_COMPLEX },
147 { "CharFontStyleName", RID_CHAR_FONT_STYLE_NAME },
148 { "CharFontStyleNameAsian", RID_CHAR_FONT_STYLE_NAME_ASIAN },
149 { "CharFontStyleNameComplex", RID_CHAR_FONT_STYLE_NAME_COMPLEX },
150 { "CharHeight", RID_CHAR_HEIGHT },
151 { "CharHeightAsian", RID_CHAR_HEIGHT_ASIAN },
152 { "CharHeightComplex", RID_CHAR_HEIGHT_COMPLEX },
153 { "CharHidden", RID_CHAR_HIDDEN },
154 { "CharHighlight", RID_CHAR_HIGHLIGHT },
155 { "CharInteropGrabBag", RID_CHAR_INTEROP_GRAB_BAG },
156 { "CharKerning", RID_CHAR_KERNING },
157 { "CharLeftBorder", RID_CHAR_LEFT_BORDER },
158 { "CharLeftBorderDistance", RID_CHAR_LEFT_BORDER_DISTANCE },
159 { "CharLocale", RID_CHAR_LOCALE },
160 { "CharLocaleAsian", RID_CHAR_LOCALE_ASIAN },
161 { "CharLocaleComplex", RID_CHAR_LOCALE_COMPLEX },
162 { "CharNoHyphenation", RID_CHAR_NO_HYPHENATION },
163 { "CharOverline", RID_CHAR_OVERLINE },
164 { "CharOverlineColor", RID_CHAR_OVERLINE_COLOR },
165 { "CharOverlineHasColor", RID_CHAR_OVERLINE_HAS_COLOR },
166 { "CharPosture", RID_CHAR_POSTURE },
167 { "CharPostureAsian", RID_CHAR_POSTURE_ASIAN },
168 { "CharPostureComplex", RID_CHAR_POSTURE_COMPLEX },
169 { "CharPropHeight", RID_CHAR_PROP_HEIGHT },
170 { "CharPropHeightAsian", RID_CHAR_PROP_HEIGHT_ASIAN },
171 { "CharPropHeightComplex", RID_CHAR_PROP_HEIGHT_COMPLEX },
172 { "CharRelief", RID_CHAR_RELIEF },
173 { "CharRightBorder", RID_CHAR_RIGHT_BORDER },
174 { "CharRightBorderDistance", RID_CHAR_RIGHT_BORDER_DISTANCE },
175 { "CharRotation", RID_CHAR_ROTATION },
176 { "CharRotationIsFitToLine", RID_CHAR_ROTATION_IS_FIT_TO_LINE },
177 { "CharScaleWidth", RID_CHAR_SCALE_WIDTH },
178 { "CharShadingValue", RID_CHAR_SHADING_VALUE },
179 { "CharShadowFormat", RID_CHAR_SHADOW_FORMAT },
180 { "CharShadowed", RID_CHAR_SHADOWED },
181 { "CharStrikeout", RID_CHAR_STRIKEOUT },
182 { "CharStyleName", RID_CHAR_STYLE_NAME },
183 { "CharStyleNames", RID_CHAR_STYLE_NAMES },
184 { "CharTopBorder", RID_CHAR_TOP_BORDER },
185 { "CharTopBorderDistance", RID_CHAR_TOP_BORDER_DISTANCE },
186 { "CharTransparence", RID_CHAR_TRANSPARENCE },
187 { "CharUnderline", RID_CHAR_UNDERLINE },
188 { "CharUnderlineColor", RID_CHAR_UNDERLINE_COLOR },
189 { "CharUnderlineHasColor", RID_CHAR_UNDERLINE_HAS_COLOR },
190 { "CharWeight", RID_CHAR_WEIGHT },
191 { "CharWeightAsian", RID_CHAR_WEIGHT_ASIAN },
192 { "CharWeightComplex", RID_CHAR_WEIGHT_COMPLEX },
193 { "CharWordMode", RID_CHAR_WORD_MODE },
194 { "ContinueingPreviousSubTree", RID_CONTINUING_PREVIOUS_SUB_TREE },
195 { "DisplayName", RID_DISPLAY_NAME },
196 { "DocumentIndex", RID_DOCUMENT_INDEX },
197 { "DocumentIndexMark", RID_DOCUMENT_INDEX_MARK },
198 { "DropCapCharStyleName", RID_DROP_CAP_CHAR_STYLE_NAME },
199 { "DropCapFormat", RID_DROP_CAP_FORMAT },
200 { "DropCapWholeWord", RID_DROP_CAP_WHOLE_WORD },
201 { "Endnote", RID_ENDNOTE },
202 { "FillBackground", RID_FILL_BACKGROUND },
203 { "FillBitmap", RID_FILL_BITMAP },
204 { "FillBitmapLogicalSize", RID_FILL_BITMAP_LOGICAL_SIZE },
205 { "FillBitmapMode", RID_FILL_BITMAP_MODE },
206 { "FillBitmapName", RID_FILL_BITMAP_NAME },
207 { "FillBitmapOffsetX", RID_FILL_BITMAP_OFFSET_X },
208 { "FillBitmapOffsetY", RID_FILL_BITMAP_OFFSET_Y },
209 { "FillBitmapPositionOffsetX", RID_FILL_BITMAP_POSITION_OFFSET_X },
210 { "FillBitmapPositionOffsetY", RID_FILL_BITMAP_POSITION_OFFSET_Y },
211 { "FillBitmapRectanglePoint", RID_FILL_BITMAP_RECTANGLE_POINT },
212 { "FillBitmapSizeX", RID_FILL_BITMAP_SIZE_X },
213 { "FillBitmapSizeY", RID_FILL_BITMAP_SIZE_Y },
214 { "FillBitmapStretch", RID_FILL_BITMAP_STRETCH },
215 { "FillBitmapTile", RID_FILL_BITMAP_TILE },
216 { "FillBitmapURL", RID_FILL_BITMAP_URL },
217 { "FillColor", RID_FILL_COLOR },
218 { "FillColor2", RID_FILL_COLOR2 },
219 { "FillGradient", RID_FILL_GRADIENT },
220 { "FillGradientName", RID_FILL_GRADIENT_NAME },
221 { "FillGradientStepCount", RID_FILL_GRADIENT_STEP_COUNT },
222 { "FillHatch", RID_FILL_HATCH },
223 { "FillHatchName", RID_FILL_HATCH_NAME },
224 { "FillStyle", RID_FILL_STYLE },
225 { "FillTransparence", RID_FILL_TRANSPARENCE },
226 { "FillTransparenceGradient", RID_FILL_TRANSPARENCE_GRADIENT },
227 { "FillTransparenceGradientName", RID_FILL_TRANSPARENCE_GRADIENT_NAME },
228 { "FollowStyle", RID_FOLLOW_STYLE },
229 { "Footnote", RID_FOOTNOTE },
230 { "Hidden", RID_HIDDEN },
231 { "HyperLinkEvents", RID_HYPERLINK_EVENTS },
232 { "HyperLinkName", RID_HYPERLINK_NAME },
233 { "HyperLinkTarget", RID_HYPERLINK_TARGET },
234 { "HyperLinkURL", RID_HYPERLINK_URL },
235 { "IsAutoUpdate", RID_IS_AUTO_UPDATE },
236 { "IsPhysical", RID_IS_PHYSICAL },
237 { "LeftBorder", RID_LEFT_BORDER },
238 { "LeftBorderDistance", RID_LEFT_BORDER_DISTANCE },
239 { "ListAutoFormat", RID_LIST_AUTO_FORMAT },
240 { "ListId", RID_LIST_ID },
241 { "ListLabelString", RID_LIST_LABEL_STRING },
242 { "MetadataReference", RID_METADATA_REFERENCE },
243 { "NestedTextContent", RID_NESTED_TEXT_CONTENT },
244 { "NumberingIsNumber", RID_NUMBERING_IS_NUMBER },
245 { "NumberingLevel", RID_NUMBERING_LEVEL },
246 { "NumberingRules", RID_NUMBERING_RULES },
247 { "NumberingStartValue", RID_NUMBERING_START_VALUE },
248 { "NumberingStyleName", RID_NUMBERING_STYLE_NAME },
249 { "OutlineContentVisible", RID_OUTLINE_CONTENT_VISIBLE },
250 { "OutlineLevel", RID_OUTLINE_LEVEL },
251 { "PageDescName", RID_PAGE_DESC_NAME },
252 { "PageNumberOffset", RID_PAGE_NUMBER_OFFSET },
253 { "PageStyleName", RID_PAGE_STYLE_NAME },
254 { "ParRsid", RID_PAR_RSID },
255 { "ParaAdjust", RID_PARA_ADJUST },
256 { "ParaAutoStyleName", RID_PARA_AUTO_STYLE_NAME },
257 { "ParaBackColor", RID_PARA_BACK_COLOR },
258 { "ParaBackGraphic", RID_PARA_BACK_GRAPHIC },
259 { "ParaBackGraphicFilter", RID_PARA_BACK_GRAPHIC_FILTER },
260 { "ParaBackGraphicLocation", RID_PARA_BACK_GRAPHIC_LOCATION },
261 { "ParaBackGraphicURL", RID_PARA_BACK_GRAPHIC_URL },
262 { "ParaBackTransparent", RID_PARA_BACK_TRANSPARENT },
263 { "ParaBottomMargin", RID_PARA_BOTTOM_MARGIN },
264 { "ParaBottomMarginRelative", RID_PARA_BOTTOM_MARGIN_RELATIVE },
265 { "ParaChapterNumberingLevel", RID_PARA_CHAPTER_NUMBERING_LEVEL },
266 { "ParaConditionalStyleName", RID_PARA_CONDITIONAL_STYLE_NAME },
267 { "ParaContextMargin", RID_PARA_CONTEXT_MARGIN },
268 { "ParaExpandSingleWord", RID_PARA_EXPAND_SINGLE_WORD },
269 { "ParaFirstLineIndent", RID_PARA_FIRST_LINE_INDENT },
270 { "ParaFirstLineIndentRelative", RID_PARA_FIRST_LINE_INDENT_RELATIVE },
271 { "ParaHyphenationMaxHyphens", RID_PARA_HYPHENATION_MAX_HYPHENS },
272 { "ParaHyphenationMaxLeadingChars", RID_PARA_HYPHENATION_MAX_LEADING_CHARS },
273 { "ParaHyphenationMaxTrailingChars", RID_PARA_HYPHENATION_MAX_TRAILING_CHARS },
274 { "ParaHyphenationCompoundMinLeadingChars",
275 RID_PARA_HYPHENATION_COMPOUND_MIN_LEADING_CHARS },
276 { "ParaHyphenationNoCaps", RID_PARA_HYPHENATION_NO_CAPS },
277 { "ParaHyphenationNoLastWord", RID_PARA_HYPHENATION_NO_LAST_WORD },
278 { "ParaHyphenationMinWordLength", RID_PARA_HYPHENATION_MIN_WORD_LENGTH },
279 { "ParaHyphenationZone", RID_PARA_HYPHENATION_ZONE },
280 { "ParaHyphenationKeep", RID_PARA_HYPHENATION_KEEP },
281 { "ParaHyphenationKeepType", RID_PARA_HYPHENATION_KEEP_TYPE },
282 { "ParaInteropGrabBag", RID_PARA_INTEROP_GRAB_BAG },
283 { "ParaIsAutoFirstLineIndent", RID_PARA_IS_AUTO_FIRST_LINE_INDENT },
284 { "ParaIsCharacterDistance", RID_PARA_IS_CHARACTER_DISTANCE },
285 { "ParaIsConnectBorder", RID_PARA_IS_CONNECT_BORDER },
286 { "ParaIsForbiddenRules", RID_PARA_IS_FORBIDDEN_RULES },
287 { "ParaIsHangingPunctuation", RID_PARA_IS_HANGING_PUNCTUATION },
288 { "ParaIsHyphenation", RID_PARA_IS_HYPHENATION },
289 { "ParaIsNumberingRestart", RID_PARA_IS_NUMBERING_RESTART },
290 { "ParaKeepTogether", RID_PARA_KEEP_TOGETHER },
291 { "ParaLastLineAdjust", RID_PARA_LAST_LINE_ADJUST },
292 { "ParaLeftMargin", RID_PARA_LEFT_MARGIN },
293 { "ParaLeftMarginRelative", RID_PARA_LEFT_MARGIN_RELATIVE },
294 { "ParaLineNumberCount", RID_PARA_LINE_NUMBER_COUNT },
295 { "ParaLineNumberStartValue", RID_PARA_LINE_NUMBER_START_VALUE },
296 { "ParaLineSpacing", RID_PARA_LINE_SPACING },
297 { "ParaOrphans", RID_PARA_ORPHANS },
298 { "ParaRegisterModeActive", RID_PARA_REGISTER_MODE_ACTIVE },
299 { "ParaRightMargin", RID_PARA_RIGHT_MARGIN },
300 { "ParaRightMarginRelative", RID_PARA_RIGHT_MARGIN_RELATIVE },
301 { "ParaShadowFormat", RID_PARA_SHADOW_FORMAT },
302 { "ParaSplit", RID_PARA_SPLIT },
303 { "ParaStyleName", RID_PARA_STYLE_NAME },
304 { "ParaTabStops", RID_PARA_TAB_STOPS },
305 { "ParaTopMargin", RID_PARA_TOP_MARGIN },
306 { "ParaTopMarginRelative", RID_PARA_TOP_MARGIN_RELATIVE },
307 { "ParaUserDefinedAttributes", RID_PARA_USER_DEFINED_ATTRIBUTES },
308 { "ParaVertAlignment", RID_PARA_VERT_ALIGNMENT },
309 { "ParaWidows", RID_PARA_WIDOWS },
310 { "ReferenceMark", RID_REFERENCE_MARK },
311 { "RightBorder", RID_RIGHT_BORDER },
312 { "RightBorderDistance", RID_RIGHT_BORDER_DISTANCE },
313 { "Rsid", RID_RSID },
314 { "RubyAdjust", RID_RUBY_ADJUST },
315 { "RubyCharStyleName", RID_RUBY_CHAR_STYLE_NAME },
316 { "RubyIsAbove", RID_RUBY_IS_ABOVE },
317 { "RubyPosition", RID_RUBY_POSITION },
318 { "RubyText", RID_RUBY_TEXT },
319 { "SnapToGrid", RID_SNAP_TO_GRID },
320 { "StyleInteropGrabBag", RID_STYLE_INTEROP_GRAB_BAG },
321 { "TextField", RID_TEXT_FIELD },
322 { "TextFrame", RID_TEXT_FRAME },
323 { "TextParagraph", RID_TEXT_PARAGRAPH },
324 { "TextSection", RID_TEXT_SECTION },
325 { "TextTable", RID_TEXT_TABLE },
326 { "TextUserDefinedAttributes", RID_TEXT_USER_DEFINED_ATTRIBUTES },
327 { "TopBorder", RID_TOP_BORDER },
328 { "TopBorderDistance", RID_TOP_BORDER_DISTANCE },
329 { "UnvisitedCharStyleName", RID_UNVISITED_CHAR_STYLE_NAME },
330 { "VisitedCharStyleName", RID_VISITED_CHAR_STYLE_NAME },
331 { "WritingMode", RID_WRITING_MODE },
332 { "BorderColor", RID_BORDER_COLOR },
333 { "BorderInnerLineWidth", RID_BORDER_INNER_LINE_WIDTH },
334 { "BorderLineDistance", RID_BORDER_LINE_DISTANCE },
335 { "BorderLineStyle", RID_BORDER_LINE_STYLE },
336 { "BorderLineWidth", RID_BORDER_LINE_WIDTH },
337 { "BorderOuterLineWidth", RID_BORDER_OUTER_LINE_WIDTH },
340 auto itr = aNameToRID.find(rName);
341 if (itr != aNameToRID.end())
342 return SwResId(itr->second);
343 return rName;
346 static svx::sidebar::TreeNode SimplePropToTreeNode(const OUString& rName, const css::uno::Any& rVal)
348 svx::sidebar::TreeNode aCurNode;
349 aCurNode.sNodeName = PropertyNametoRID(rName);
350 aCurNode.aValue = rVal;
352 return aCurNode;
355 static svx::sidebar::TreeNode BorderToTreeNode(const OUString& rName, const css::uno::Any& rVal)
357 table::BorderLine2 aBorder;
358 rVal >>= aBorder;
359 svx::sidebar::TreeNode aCurNode;
360 aCurNode.sNodeName = PropertyNametoRID(rName);
361 aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
363 aCurNode.children = {
364 SimplePropToTreeNode(u"BorderColor"_ustr, css::uno::Any(aBorder.Color)),
365 SimplePropToTreeNode(u"BorderLineWidth"_ustr, css::uno::Any(aBorder.LineWidth)),
366 SimplePropToTreeNode(u"BorderLineStyle"_ustr, css::uno::Any(aBorder.LineStyle)),
367 SimplePropToTreeNode(u"BorderLineDistance"_ustr, css::uno::Any(aBorder.LineDistance)),
368 SimplePropToTreeNode(u"BorderInnerLineWidth"_ustr, css::uno::Any(aBorder.InnerLineWidth)),
369 SimplePropToTreeNode(u"BorderOuterLineWidth"_ustr, css::uno::Any(aBorder.OuterLineWidth))
371 return aCurNode;
374 static svx::sidebar::TreeNode LocaleToTreeNode(const OUString& rName, const css::uno::Any& rVal)
376 svx::sidebar::TreeNode aCurNode;
377 aCurNode.sNodeName = PropertyNametoRID(rName);
378 lang::Locale aLocale;
379 rVal >>= aLocale;
380 OUString aLocaleText(aLocale.Language + "-" + aLocale.Country);
381 if (!aLocale.Variant.isEmpty())
382 aLocaleText += " (" + aLocale.Variant + ")";
383 aCurNode.aValue <<= aLocaleText;
385 return aCurNode;
388 // Collect text of the current level of the annotated text
389 // ranges (InContentMetadata) and metadata fields (MetadataField)
390 static OUString NestedTextContentToText(const css::uno::Any& rVal)
392 uno::Reference<container::XEnumerationAccess> xMeta;
393 if (rVal >>= xMeta)
395 uno::Reference<container::XEnumeration> xMetaPortions = xMeta->createEnumeration();
397 OUStringBuffer aBuf;
398 while (xMetaPortions->hasMoreElements())
400 uno::Reference<css::text::XTextRange> xRng(xMetaPortions->nextElement(),
401 uno::UNO_QUERY);
402 aBuf.append(xRng->getString());
404 return aBuf.makeStringAndClear();
407 return OUString();
410 // List metadata associated to the paragraph or character range
411 static void MetadataToTreeNode(const css::uno::Reference<css::uno::XInterface>& rSource,
412 svx::sidebar::TreeNode& rNode)
414 uno::Reference<rdf::XMetadatable> xMeta(rSource, uno::UNO_QUERY_THROW);
415 // don't add tree node "Metadata Reference", if there is no xml:id
416 if (!xMeta.is() || xMeta->getMetadataReference().Second.isEmpty())
417 return;
419 // add metadata of parents for nested annotated text ranges
420 uno::Reference<container::XChild> xChild(rSource, uno::UNO_QUERY);
421 if (xChild.is())
423 uno::Reference<container::XEnumerationAccess> xParentMeta(xChild->getParent(),
424 uno::UNO_QUERY);
425 if (xParentMeta.is())
426 MetadataToTreeNode(xParentMeta, rNode);
429 svx::sidebar::TreeNode aCurNode;
430 aCurNode.sNodeName = PropertyNametoRID(u"MetadataReference"_ustr);
431 aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
433 aCurNode.children.push_back(
434 SimplePropToTreeNode(u"xml:id"_ustr, uno::Any(xMeta->getMetadataReference().Second)));
436 // list associated (predicate, object) pairs of the actual subject
437 // under the tree node "Metadata Reference"
438 if (SwDocShell* pDocSh = static_cast<SwDocShell*>(SfxObjectShell::Current()))
440 rtl::Reference<SwXTextDocument> xDocumentMetadataAccess(pDocSh->GetBaseModel());
441 const uno::Reference<rdf::XRepository> xRepo = xDocumentMetadataAccess->getRDFRepository();
442 const css::uno::Reference<css::rdf::XResource> xSubject(rSource, uno::UNO_QUERY);
443 std::map<OUString, OUString> xStatements
444 = SwRDFHelper::getStatements(pDocSh->GetBaseModel(), xRepo->getGraphNames(), xSubject);
445 for (const auto& pair : xStatements)
446 aCurNode.children.push_back(SimplePropToTreeNode(pair.first, uno::Any(pair.second)));
449 rNode.children.push_back(aCurNode);
452 static svx::sidebar::TreeNode
453 PropertyToTreeNode(const css::beans::Property& rProperty,
454 const uno::Reference<beans::XPropertySet>& xPropertiesSet, const bool rIsGrey)
456 const OUString& rPropName = rProperty.Name;
457 svx::sidebar::TreeNode aCurNode;
458 const uno::Any aAny = xPropertiesSet->getPropertyValue(rPropName);
459 aCurNode.sNodeName = PropertyNametoRID(rPropName);
461 // These properties are handled separately as they are stored in STRUCT and not in single data members
462 if (rPropName == "CharTopBorder" || rPropName == "CharBottomBorder"
463 || rPropName == "CharLeftBorder" || rPropName == "CharRightBorder"
464 || rPropName == "TopBorder" || rPropName == "BottomBorder" || rPropName == "LeftBorder"
465 || rPropName == "RightBorder")
467 aCurNode = BorderToTreeNode(rPropName, aAny);
469 else if (rPropName == "CharLocale")
471 aCurNode = LocaleToTreeNode(rPropName, aAny);
473 else
474 aCurNode = SimplePropToTreeNode(rPropName, aAny);
476 if (rIsGrey)
478 aCurNode.isGrey = true;
479 for (svx::sidebar::TreeNode& rChildNode : aCurNode.children)
480 rChildNode.isGrey = true; // grey out all the children nodes
483 return aCurNode;
486 static void InsertValues(const css::uno::Reference<css::uno::XInterface>& rSource,
487 std::unordered_map<OUString, bool>& rIsDefined,
488 svx::sidebar::TreeNode& rNode, const bool isRoot,
489 const std::vector<OUString>& rHiddenProperty,
490 svx::sidebar::TreeNode& rFieldsNode)
492 uno::Reference<beans::XPropertySet> xPropertiesSet(rSource, uno::UNO_QUERY_THROW);
493 uno::Reference<beans::XPropertyState> xPropertiesState(rSource, uno::UNO_QUERY_THROW);
494 const uno::Sequence<beans::Property> aProperties
495 = xPropertiesSet->getPropertySetInfo()->getProperties();
497 for (const beans::Property& rProperty : aProperties)
499 const OUString& rPropName = rProperty.Name;
500 if (std::find(rHiddenProperty.begin(), rHiddenProperty.end(), rPropName)
501 != rHiddenProperty.end())
502 continue;
504 if (isRoot
505 || xPropertiesState->getPropertyState(rPropName) == beans::PropertyState_DIRECT_VALUE)
507 svx::sidebar::TreeNode aCurNode
508 = PropertyToTreeNode(rProperty, xPropertiesSet, rIsDefined[rPropName]);
509 rIsDefined[rPropName] = true;
511 // process NestedTextContent and show associated metadata
512 // under the tree node "Metadata Reference", if they exist
513 if (rPropName == "NestedTextContent")
515 uno::Reference<container::XEnumerationAccess> xMeta;
516 if (aCurNode.aValue >>= xMeta)
517 MetadataToTreeNode(xMeta, rFieldsNode);
518 aCurNode.aValue <<= NestedTextContentToText(aCurNode.aValue);
521 rNode.children.push_back(aCurNode);
525 const comphelper::string::NaturalStringSorter aSorter(
526 comphelper::getProcessComponentContext(),
527 Application::GetSettings().GetUILanguageTag().getLocale());
529 std::sort(
530 rNode.children.begin(), rNode.children.end(),
531 [&aSorter](svx::sidebar::TreeNode const& rEntry1, svx::sidebar::TreeNode const& rEntry2) {
532 return aSorter.compare(rEntry1.sNodeName, rEntry2.sNodeName) < 0;
536 static void UpdateTree(SwDocShell& rDocSh, SwEditShell& rEditSh,
537 std::vector<svx::sidebar::TreeNode>& aStore, sal_Int32& rParIdx)
539 SwDoc* pDoc = rDocSh.GetDoc();
540 SwPaM* pCursor = rEditSh.GetCursor();
541 svx::sidebar::TreeNode aCharDFNode;
542 svx::sidebar::TreeNode aCharNode;
543 svx::sidebar::TreeNode aParaNode;
544 svx::sidebar::TreeNode aParaDFNode;
545 svx::sidebar::TreeNode aBookmarksNode;
546 svx::sidebar::TreeNode aFieldsNode;
547 svx::sidebar::TreeNode aTextSectionsNode;
549 aCharNode.sNodeName = SwResId(STR_CHARACTERSTYLEFAMILY);
550 aParaNode.sNodeName = SwResId(STR_PARAGRAPHSTYLEFAMILY);
551 aCharDFNode.sNodeName = SwResId(RID_CHAR_DIRECTFORMAT);
552 aParaDFNode.sNodeName = SwResId(RID_PARA_DIRECTFORMAT);
553 aBookmarksNode.sNodeName = SwResId(STR_CONTENT_TYPE_BOOKMARK);
554 aFieldsNode.sNodeName = SwResId(STR_CONTENT_TYPE_TEXTFIELD);
555 aTextSectionsNode.sNodeName = SwResId(STR_CONTENT_TYPE_REGION);
556 aCharDFNode.NodeType = svx::sidebar::TreeNode::Category;
557 aCharNode.NodeType = svx::sidebar::TreeNode::Category;
558 aParaNode.NodeType = svx::sidebar::TreeNode::Category;
559 aParaDFNode.NodeType = svx::sidebar::TreeNode::Category;
560 aBookmarksNode.NodeType = svx::sidebar::TreeNode::Category;
561 aFieldsNode.NodeType = svx::sidebar::TreeNode::Category;
562 aTextSectionsNode.NodeType = svx::sidebar::TreeNode::Category;
564 rtl::Reference<SwXTextRange> xRange(
565 SwXTextRange::CreateXTextRange(*pDoc, *pCursor->GetPoint(), nullptr));
566 if (!xRange)
567 throw uno::RuntimeException();
568 std::unordered_map<OUString, bool> aIsDefined;
570 const std::vector<OUString> aHiddenProperties{ UNO_NAME_RSID,
571 UNO_NAME_PARA_IS_NUMBERING_RESTART,
572 UNO_NAME_PARA_STYLE_NAME,
573 UNO_NAME_PARA_CONDITIONAL_STYLE_NAME,
574 UNO_NAME_PAGE_STYLE_NAME,
575 UNO_NAME_NUMBERING_START_VALUE,
576 UNO_NAME_NUMBERING_IS_NUMBER,
577 UNO_NAME_PARA_CONTINUEING_PREVIOUS_SUB_TREE,
578 UNO_NAME_CHAR_STYLE_NAME,
579 UNO_NAME_NUMBERING_LEVEL,
580 UNO_NAME_SORTED_TEXT_ID,
581 UNO_NAME_PARRSID,
582 UNO_NAME_CHAR_COLOR_THEME,
583 UNO_NAME_CHAR_COLOR_TINT_OR_SHADE };
585 const std::vector<OUString> aHiddenCharacterProperties{ UNO_NAME_CHAR_COLOR_THEME,
586 UNO_NAME_CHAR_COLOR_TINT_OR_SHADE };
588 InsertValues(static_cast<cppu::OWeakObject*>(xRange.get()), aIsDefined, aCharDFNode, false,
589 aHiddenProperties, aFieldsNode);
591 rtl::Reference<SwXTextDocument> xStyleFamiliesSupplier(rDocSh.GetBaseModel());
592 uno::Reference<container::XNameAccess> xStyleFamilies
593 = xStyleFamiliesSupplier->getStyleFamilies();
594 OUString sCurrentCharStyle, sCurrentParaStyle, sDisplayName;
596 uno::Reference<container::XNameAccess> xStyleFamily(
597 xStyleFamilies->getByName(u"CharacterStyles"_ustr), uno::UNO_QUERY_THROW);
598 xRange->getPropertyValue(u"CharStyleName"_ustr) >>= sCurrentCharStyle;
599 xRange->getPropertyValue(u"ParaStyleName"_ustr) >>= sCurrentParaStyle;
601 if (!sCurrentCharStyle.isEmpty())
603 uno::Reference<beans::XPropertySet> xPropertiesSet(
604 xStyleFamily->getByName(sCurrentCharStyle), css::uno::UNO_QUERY_THROW);
605 xPropertiesSet->getPropertyValue(u"DisplayName"_ustr) >>= sDisplayName;
606 svx::sidebar::TreeNode aCurrentChild;
607 aCurrentChild.sNodeName = sDisplayName;
608 aCurrentChild.NodeType = svx::sidebar::TreeNode::ComplexProperty;
610 InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, false, aHiddenCharacterProperties,
611 aFieldsNode);
613 aCharNode.children.push_back(aCurrentChild);
616 // Collect paragraph direct formatting
617 uno::Reference<container::XEnumeration> xParaEnum = xRange->createEnumeration();
618 uno::Reference<text::XTextRange> xThisParagraphRange(xParaEnum->nextElement(), uno::UNO_QUERY);
619 if (xThisParagraphRange.is())
621 // Collect metadata of the current paragraph
622 MetadataToTreeNode(xThisParagraphRange, aParaDFNode);
623 InsertValues(xThisParagraphRange, aIsDefined, aParaDFNode, false, aHiddenProperties,
624 aFieldsNode);
627 xStyleFamily.set(xStyleFamilies->getByName(u"ParagraphStyles"_ustr), uno::UNO_QUERY_THROW);
629 while (!sCurrentParaStyle.isEmpty())
631 uno::Reference<style::XStyle> xPropertiesStyle(xStyleFamily->getByName(sCurrentParaStyle),
632 uno::UNO_QUERY_THROW);
633 uno::Reference<beans::XPropertySet> xPropertiesSet(xPropertiesStyle,
634 css::uno::UNO_QUERY_THROW);
635 xPropertiesSet->getPropertyValue(u"DisplayName"_ustr) >>= sDisplayName;
636 OUString aParentParaStyle = xPropertiesStyle->getParentStyle();
637 svx::sidebar::TreeNode aCurrentChild;
638 aCurrentChild.sNodeName = sDisplayName;
639 aCurrentChild.NodeType = svx::sidebar::TreeNode::ComplexProperty;
641 InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, aParentParaStyle.isEmpty(),
642 aHiddenCharacterProperties, aFieldsNode);
644 aParaNode.children.push_back(aCurrentChild);
645 sCurrentParaStyle = aParentParaStyle;
648 std::reverse(aParaNode.children.begin(),
649 aParaNode.children.end()); // Parent style should be first then children
651 // Collect bookmarks at character position
652 rtl::Reference<SwXTextDocument> xBookmarksSupplier(rDocSh.GetBaseModel());
654 uno::Reference<container::XIndexAccess> xBookmarks(xBookmarksSupplier->getBookmarks(),
655 uno::UNO_QUERY);
656 for (sal_Int32 i = 0; i < xBookmarks->getCount(); ++i)
658 svx::sidebar::TreeNode aCurNode;
659 uno::Reference<text::XTextContent> bookmark;
660 xBookmarks->getByIndex(i) >>= bookmark;
661 uno::Reference<container::XNamed> xBookmark(bookmark, uno::UNO_QUERY);
665 uno::Reference<text::XTextRange> bookmarkRange = bookmark->getAnchor();
666 uno::Reference<text::XTextRangeCompare> xTextRangeCompare(xRange->getText(),
667 uno::UNO_QUERY);
668 if (xTextRangeCompare.is()
669 && xTextRangeCompare->compareRegionStarts(bookmarkRange, xRange) != -1
670 && xTextRangeCompare->compareRegionEnds(xRange, bookmarkRange) != -1)
672 aCurNode.sNodeName = xBookmark->getName();
673 aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
675 MetadataToTreeNode(xBookmark, aCurNode);
676 // show bookmark only if it has RDF metadata
677 if (aCurNode.children.size() > 0)
678 aBookmarksNode.children.push_back(aCurNode);
681 catch (const lang::IllegalArgumentException&)
686 // Collect sections at character position
687 rtl::Reference<SwXTextDocument> xTextSectionsSupplier(rDocSh.GetBaseModel());
689 uno::Reference<container::XIndexAccess> xTextSections(xTextSectionsSupplier->getTextSections(),
690 uno::UNO_QUERY);
691 for (sal_Int32 i = 0; i < xTextSections->getCount(); ++i)
693 svx::sidebar::TreeNode aCurNode;
694 uno::Reference<text::XTextContent> section;
695 xTextSections->getByIndex(i) >>= section;
696 uno::Reference<container::XNamed> xTextSection(section, uno::UNO_QUERY);
700 uno::Reference<text::XTextRange> sectionRange = section->getAnchor();
701 uno::Reference<text::XTextRangeCompare> xTextRangeCompare(xRange->getText(),
702 uno::UNO_QUERY);
703 if (xTextRangeCompare.is()
704 && xTextRangeCompare->compareRegionStarts(sectionRange, xRange) != -1
705 && xTextRangeCompare->compareRegionEnds(xRange, sectionRange) != -1)
707 aCurNode.sNodeName = xTextSection->getName();
708 aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
710 MetadataToTreeNode(xTextSection, aCurNode);
711 // show section only if it has RDF metadata
712 if (aCurNode.children.size() > 0)
713 aTextSectionsNode.children.push_back(aCurNode);
716 catch (const lang::IllegalArgumentException&)
722 Display Order :-
723 SECTIONS with RDF metadata (optional)
724 BOOKMARKS with RDF metadata (optional)
725 FIELDS with RDF metadata (optional)
726 PARAGRAPH STYLE
727 PARAGRAPH DIRECT FORMATTING
728 CHARACTER STYLE
729 DIRECT FORMATTING
731 rParIdx = 0;
732 // show sections, bookmarks and fields only if they have RDF metadata
733 if (aTextSectionsNode.children.size() > 0)
735 aStore.push_back(aTextSectionsNode);
736 rParIdx++;
738 if (aBookmarksNode.children.size() > 0)
740 aStore.push_back(aBookmarksNode);
741 rParIdx++;
743 if (aFieldsNode.children.size() > 0)
745 aStore.push_back(aFieldsNode);
746 rParIdx++;
748 aStore.push_back(aParaNode);
749 aStore.push_back(aParaDFNode);
750 aStore.push_back(aCharNode);
751 aStore.push_back(aCharDFNode);
754 IMPL_LINK(WriterInspectorTextPanel, AttrChangedNotify, LinkParamNone*, pLink, void)
756 if (m_oldLink.IsSet())
757 m_oldLink.Call(pLink);
759 if (m_pShell->IsViewLocked())
761 return; // tdf#142806 avoid slowdown when storing files
764 SwDocShell* pDocSh = m_pShell->GetDoc()->GetDocShell();
765 if (!pDocSh)
766 return;
768 std::vector<svx::sidebar::TreeNode> aStore;
770 if (m_pShell->GetCursor()->GetPointNode().GetTextNode())
772 UpdateTree(*pDocSh, *m_pShell, aStore, m_nParIdx);
775 updateEntries(aStore, m_nParIdx);
778 } // end of namespace svx::sidebar
780 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */