Related: tdf#149408 inspector crash with a writer OLE inside calc
[LibreOffice.git] / sw / source / uibase / sidebar / WriterInspectorTextPanel.cxx
blob09c773a1d28ab9fd5168d57e94337adcc6964240
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/frame/XFrame.hpp>
35 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
36 #include <com/sun/star/table/BorderLine2.hpp>
37 #include <com/sun/star/lang/IllegalArgumentException.hpp>
38 #include <com/sun/star/rdf/XMetadatable.hpp>
39 #include <com/sun/star/rdf/XDocumentMetadataAccess.hpp>
40 #include <com/sun/star/container/XChild.hpp>
42 #include <unotextrange.hxx>
43 #include <comphelper/string.hxx>
44 #include <comphelper/processfactory.hxx>
45 #include <i18nlangtag/languagetag.hxx>
46 #include <vcl/settings.hxx>
47 #include <inspectorproperties.hrc>
48 #include <strings.hrc>
49 #include <rdfhelper.hxx>
51 namespace sw::sidebar
53 static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>& aStore,
54 sal_Int32& rParIdx);
56 std::unique_ptr<PanelLayout> WriterInspectorTextPanel::Create(weld::Widget* pParent)
58 if (pParent == nullptr)
59 throw lang::IllegalArgumentException(
60 "no parent Window given to WriterInspectorTextPanel::Create", 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));
76 // Update panel on start
77 std::vector<svx::sidebar::TreeNode> aStore;
78 if (pDocSh && pDocSh->GetDoc()->GetEditShell()->GetCursor()->GetNode().GetTextNode())
79 UpdateTree(pDocSh, aStore, m_nParIdx);
80 updateEntries(aStore, m_nParIdx);
83 WriterInspectorTextPanel::~WriterInspectorTextPanel()
85 if (m_pShell)
86 m_pShell->SetChgLnk(m_oldLink);
89 static OUString PropertyNametoRID(const OUString& rName)
91 static const std::map<OUString, TranslateId> aNameToRID = {
92 { "BorderDistance", RID_BORDER_DISTANCE },
93 { "BottomBorder", RID_BOTTOM_BORDER },
94 { "BottomBorderDistance", RID_BOTTOM_BORDER_DISTANCE },
95 { "BreakType", RID_BREAK_TYPE },
96 { "Category", RID_CATEGORY },
97 { "Cell", RID_CELL },
98 { "CharAutoEscapement", RID_CHAR_AUTO_ESCAPEMENT },
99 { "CharAutoKerning", RID_CHAR_AUTO_KERNING },
100 { "CharAutoStyleName", RID_CHAR_AUTO_STYLE_NAME },
101 { "CharBackColor", RID_CHAR_BACK_COLOR },
102 { "CharBackTransparent", RID_CHAR_BACK_TRANSPARENT },
103 { "CharBorderDistance", RID_CHAR_BORDER_DISTANCE },
104 { "CharBottomBorder", RID_CHAR_BOTTOM_BORDER },
105 { "CharBottomBorderDistance", RID_CHAR_BOTTOM_BORDER_DISTANCE },
106 { "CharCaseMap", RID_CHAR_CASE_MAP },
107 { "CharColor", RID_CHAR_COLOR },
108 { "CharCombineIsOn", RID_CHAR_COMBINE_IS_ON },
109 { "CharCombinePrefix", RID_CHAR_COMBINE_PREFIX },
110 { "CharCombineSuffix", RID_CHAR_COMBINE_SUFFIX },
111 { "CharContoured", RID_CHAR_CONTOURED },
112 { "CharCrossedOut", RID_CHAR_CROSSED_OUT },
113 { "CharDiffHeight", RID_CHAR_DIFF_HEIGHT },
114 { "CharDiffHeightAsian", RID_CHAR_DIFF_HEIGHT_ASIAN },
115 { "CharDiffHeightComplex", RID_CHAR_DIFF_HEIGHT_COMPLEX },
116 { "CharEmphasis", RID_CHAR_EMPHASIS },
117 { "CharEscapement", RID_CHAR_ESCAPEMENT },
118 { "CharEscapementHeight", RID_CHAR_ESCAPEMENT_HEIGHT },
119 { "CharFlash", RID_CHAR_FLASH },
120 { "CharFontCharSet", RID_CHAR_FONT_CHAR_SET },
121 { "CharFontCharSetAsian", RID_CHAR_FONT_CHAR_SET_ASIAN },
122 { "CharFontCharSetComplex", RID_CHAR_FONT_CHAR_SET_COMPLEX },
123 { "CharFontFamily", RID_CHAR_FONT_FAMILY },
124 { "CharFontFamilyAsian", RID_CHAR_FONT_FAMILY_ASIAN },
125 { "CharFontFamilyComplex", RID_CHAR_FONT_FAMILY_COMPLEX },
126 { "CharFontName", RID_CHAR_FONT_NAME },
127 { "CharFontNameAsian", RID_CHAR_FONT_NAME_ASIAN },
128 { "CharFontNameComplex", RID_CHAR_FONT_NAME_COMPLEX },
129 { "CharFontPitch", RID_CHAR_FONT_PITCH },
130 { "CharFontPitchAsian", RID_CHAR_FONT_PITCH_ASIAN },
131 { "CharFontPitchComplex", RID_CHAR_FONT_PITCH_COMPLEX },
132 { "CharFontStyleName", RID_CHAR_FONT_STYLE_NAME },
133 { "CharFontStyleNameAsian", RID_CHAR_FONT_STYLE_NAME_ASIAN },
134 { "CharFontStyleNameComplex", RID_CHAR_FONT_STYLE_NAME_COMPLEX },
135 { "CharHeight", RID_CHAR_HEIGHT },
136 { "CharHeightAsian", RID_CHAR_HEIGHT_ASIAN },
137 { "CharHeightComplex", RID_CHAR_HEIGHT_COMPLEX },
138 { "CharHidden", RID_CHAR_HIDDEN },
139 { "CharHighlight", RID_CHAR_HIGHLIGHT },
140 { "CharInteropGrabBag", RID_CHAR_INTEROP_GRAB_BAG },
141 { "CharKerning", RID_CHAR_KERNING },
142 { "CharLeftBorder", RID_CHAR_LEFT_BORDER },
143 { "CharLeftBorderDistance", RID_CHAR_LEFT_BORDER_DISTANCE },
144 { "CharLocale", RID_CHAR_LOCALE },
145 { "CharLocaleAsian", RID_CHAR_LOCALE_ASIAN },
146 { "CharLocaleComplex", RID_CHAR_LOCALE_COMPLEX },
147 { "CharNoHyphenation", RID_CHAR_NO_HYPHENATION },
148 { "CharOverline", RID_CHAR_OVERLINE },
149 { "CharOverlineColor", RID_CHAR_OVERLINE_COLOR },
150 { "CharOverlineHasColor", RID_CHAR_OVERLINE_HAS_COLOR },
151 { "CharPosture", RID_CHAR_POSTURE },
152 { "CharPostureAsian", RID_CHAR_POSTURE_ASIAN },
153 { "CharPostureComplex", RID_CHAR_POSTURE_COMPLEX },
154 { "CharPropHeight", RID_CHAR_PROP_HEIGHT },
155 { "CharPropHeightAsian", RID_CHAR_PROP_HEIGHT_ASIAN },
156 { "CharPropHeightComplex", RID_CHAR_PROP_HEIGHT_COMPLEX },
157 { "CharRelief", RID_CHAR_RELIEF },
158 { "CharRightBorder", RID_CHAR_RIGHT_BORDER },
159 { "CharRightBorderDistance", RID_CHAR_RIGHT_BORDER_DISTANCE },
160 { "CharRotation", RID_CHAR_ROTATION },
161 { "CharRotationIsFitToLine", RID_CHAR_ROTATION_IS_FIT_TO_LINE },
162 { "CharScaleWidth", RID_CHAR_SCALE_WIDTH },
163 { "CharShadingValue", RID_CHAR_SHADING_VALUE },
164 { "CharShadowFormat", RID_CHAR_SHADOW_FORMAT },
165 { "CharShadowed", RID_CHAR_SHADOWED },
166 { "CharStrikeout", RID_CHAR_STRIKEOUT },
167 { "CharStyleName", RID_CHAR_STYLE_NAME },
168 { "CharStyleNames", RID_CHAR_STYLE_NAMES },
169 { "CharTopBorder", RID_CHAR_TOP_BORDER },
170 { "CharTopBorderDistance", RID_CHAR_TOP_BORDER_DISTANCE },
171 { "CharTransparence", RID_CHAR_TRANSPARENCE },
172 { "CharUnderline", RID_CHAR_UNDERLINE },
173 { "CharUnderlineColor", RID_CHAR_UNDERLINE_COLOR },
174 { "CharUnderlineHasColor", RID_CHAR_UNDERLINE_HAS_COLOR },
175 { "CharWeight", RID_CHAR_WEIGHT },
176 { "CharWeightAsian", RID_CHAR_WEIGHT_ASIAN },
177 { "CharWeightComplex", RID_CHAR_WEIGHT_COMPLEX },
178 { "CharWordMode", RID_CHAR_WORD_MODE },
179 { "ContinueingPreviousSubTree", RID_CONTINUING_PREVIOUS_SUB_TREE },
180 { "DisplayName", RID_DISPLAY_NAME },
181 { "DocumentIndex", RID_DOCUMENT_INDEX },
182 { "DocumentIndexMark", RID_DOCUMENT_INDEX_MARK },
183 { "DropCapCharStyleName", RID_DROP_CAP_CHAR_STYLE_NAME },
184 { "DropCapFormat", RID_DROP_CAP_FORMAT },
185 { "DropCapWholeWord", RID_DROP_CAP_WHOLE_WORD },
186 { "Endnote", RID_ENDNOTE },
187 { "FillBackground", RID_FILL_BACKGROUND },
188 { "FillBitmap", RID_FILL_BITMAP },
189 { "FillBitmapLogicalSize", RID_FILL_BITMAP_LOGICAL_SIZE },
190 { "FillBitmapMode", RID_FILL_BITMAP_MODE },
191 { "FillBitmapName", RID_FILL_BITMAP_NAME },
192 { "FillBitmapOffsetX", RID_FILL_BITMAP_OFFSET_X },
193 { "FillBitmapOffsetY", RID_FILL_BITMAP_OFFSET_Y },
194 { "FillBitmapPositionOffsetX", RID_FILL_BITMAP_POSITION_OFFSET_X },
195 { "FillBitmapPositionOffsetY", RID_FILL_BITMAP_POSITION_OFFSET_Y },
196 { "FillBitmapRectanglePoint", RID_FILL_BITMAP_RECTANGLE_POINT },
197 { "FillBitmapSizeX", RID_FILL_BITMAP_SIZE_X },
198 { "FillBitmapSizeY", RID_FILL_BITMAP_SIZE_Y },
199 { "FillBitmapStretch", RID_FILL_BITMAP_STRETCH },
200 { "FillBitmapTile", RID_FILL_BITMAP_TILE },
201 { "FillBitmapURL", RID_FILL_BITMAP_URL },
202 { "FillColor", RID_FILL_COLOR },
203 { "FillColor2", RID_FILL_COLOR2 },
204 { "FillGradient", RID_FILL_GRADIENT },
205 { "FillGradientName", RID_FILL_GRADIENT_NAME },
206 { "FillGradientStepCount", RID_FILL_GRADIENT_STEP_COUNT },
207 { "FillHatch", RID_FILL_HATCH },
208 { "FillHatchName", RID_FILL_HATCH_NAME },
209 { "FillStyle", RID_FILL_STYLE },
210 { "FillTransparence", RID_FILL_TRANSPARENCE },
211 { "FillTransparenceGradient", RID_FILL_TRANSPARENCE_GRADIENT },
212 { "FillTransparenceGradientName", RID_FILL_TRANSPARENCE_GRADIENT_NAME },
213 { "FollowStyle", RID_FOLLOW_STYLE },
214 { "Footnote", RID_FOOTNOTE },
215 { "Hidden", RID_HIDDEN },
216 { "HyperLinkEvents", RID_HYPERLINK_EVENTS },
217 { "HyperLinkName", RID_HYPERLINK_NAME },
218 { "HyperLinkTarget", RID_HYPERLINK_TARGET },
219 { "HyperLinkURL", RID_HYPERLINK_URL },
220 { "IsAutoUpdate", RID_IS_AUTO_UPDATE },
221 { "IsPhysical", RID_IS_PHYSICAL },
222 { "LeftBorder", RID_LEFT_BORDER },
223 { "LeftBorderDistance", RID_LEFT_BORDER_DISTANCE },
224 { "ListAutoFormat", RID_LIST_AUTO_FORMAT },
225 { "ListId", RID_LIST_ID },
226 { "ListLabelString", RID_LIST_LABEL_STRING },
227 { "MetadataReference", RID_METADATA_REFERENCE },
228 { "NestedTextContent", RID_NESTED_TEXT_CONTENT },
229 { "NumberingIsNumber", RID_NUMBERING_IS_NUMBER },
230 { "NumberingLevel", RID_NUMBERING_LEVEL },
231 { "NumberingRules", RID_NUMBERING_RULES },
232 { "NumberingStartValue", RID_NUMBERING_START_VALUE },
233 { "NumberingStyleName", RID_NUMBERING_STYLE_NAME },
234 { "OutlineContentVisible", RID_OUTLINE_CONTENT_VISIBLE },
235 { "OutlineLevel", RID_OUTLINE_LEVEL },
236 { "PageDescName", RID_PAGE_DESC_NAME },
237 { "PageNumberOffset", RID_PAGE_NUMBER_OFFSET },
238 { "PageStyleName", RID_PAGE_STYLE_NAME },
239 { "ParRsid", RID_PAR_RSID },
240 { "ParaAdjust", RID_PARA_ADJUST },
241 { "ParaAutoStyleName", RID_PARA_AUTO_STYLE_NAME },
242 { "ParaBackColor", RID_PARA_BACK_COLOR },
243 { "ParaBackGraphic", RID_PARA_BACK_GRAPHIC },
244 { "ParaBackGraphicFilter", RID_PARA_BACK_GRAPHIC_FILTER },
245 { "ParaBackGraphicLocation", RID_PARA_BACK_GRAPHIC_LOCATION },
246 { "ParaBackGraphicURL", RID_PARA_BACK_GRAPHIC_URL },
247 { "ParaBackTransparent", RID_PARA_BACK_TRANSPARENT },
248 { "ParaBottomMargin", RID_PARA_BOTTOM_MARGIN },
249 { "ParaBottomMarginRelative", RID_PARA_BOTTOM_MARGIN_RELATIVE },
250 { "ParaChapterNumberingLevel", RID_PARA_CHAPTER_NUMBERING_LEVEL },
251 { "ParaConditionalStyleName", RID_PARA_CONDITIONAL_STYLE_NAME },
252 { "ParaContextMargin", RID_PARA_CONTEXT_MARGIN },
253 { "ParaExpandSingleWord", RID_PARA_EXPAND_SINGLE_WORD },
254 { "ParaFirstLineIndent", RID_PARA_FIRST_LINE_INDENT },
255 { "ParaFirstLineIndentRelative", RID_PARA_FIRST_LINE_INDENT_RELATIVE },
256 { "ParaHyphenationMaxHyphens", RID_PARA_HYPHENATION_MAX_HYPHENS },
257 { "ParaHyphenationMaxLeadingChars", RID_PARA_HYPHENATION_MAX_LEADING_CHARS },
258 { "ParaHyphenationMaxTrailingChars", RID_PARA_HYPHENATION_MAX_TRAILING_CHARS },
259 { "ParaHyphenationNoCaps", RID_PARA_HYPHENATION_NO_CAPS },
260 { "ParaInteropGrabBag", RID_PARA_INTEROP_GRAB_BAG },
261 { "ParaIsAutoFirstLineIndent", RID_PARA_IS_AUTO_FIRST_LINE_INDENT },
262 { "ParaIsCharacterDistance", RID_PARA_IS_CHARACTER_DISTANCE },
263 { "ParaIsConnectBorder", RID_PARA_IS_CONNECT_BORDER },
264 { "ParaIsForbiddenRules", RID_PARA_IS_FORBIDDEN_RULES },
265 { "ParaIsHangingPunctuation", RID_PARA_IS_HANGING_PUNCTUATION },
266 { "ParaIsHyphenation", RID_PARA_IS_HYPHENATION },
267 { "ParaIsNumberingRestart", RID_PARA_IS_NUMBERING_RESTART },
268 { "ParaKeepTogether", RID_PARA_KEEP_TOGETHER },
269 { "ParaLastLineAdjust", RID_PARA_LAST_LINE_ADJUST },
270 { "ParaLeftMargin", RID_PARA_LEFT_MARGIN },
271 { "ParaLeftMarginRelative", RID_PARA_LEFT_MARGIN_RELATIVE },
272 { "ParaLineNumberCount", RID_PARA_LINE_NUMBER_COUNT },
273 { "ParaLineNumberStartValue", RID_PARA_LINE_NUMBER_START_VALUE },
274 { "ParaLineSpacing", RID_PARA_LINE_SPACING },
275 { "ParaOrphans", RID_PARA_ORPHANS },
276 { "ParaRegisterModeActive", RID_PARA_REGISTER_MODE_ACTIVE },
277 { "ParaRightMargin", RID_PARA_RIGHT_MARGIN },
278 { "ParaRightMarginRelative", RID_PARA_RIGHT_MARGIN_RELATIVE },
279 { "ParaShadowFormat", RID_PARA_SHADOW_FORMAT },
280 { "ParaSplit", RID_PARA_SPLIT },
281 { "ParaStyleName", RID_PARA_STYLE_NAME },
282 { "ParaTabStops", RID_PARA_TAB_STOPS },
283 { "ParaTopMargin", RID_PARA_TOP_MARGIN },
284 { "ParaTopMarginRelative", RID_PARA_TOP_MARGIN_RELATIVE },
285 { "ParaUserDefinedAttributes", RID_PARA_USER_DEFINED_ATTRIBUTES },
286 { "ParaVertAlignment", RID_PARA_VERT_ALIGNMENT },
287 { "ParaWidows", RID_PARA_WIDOWS },
288 { "ReferenceMark", RID_REFERENCE_MARK },
289 { "RightBorder", RID_RIGHT_BORDER },
290 { "RightBorderDistance", RID_RIGHT_BORDER_DISTANCE },
291 { "Rsid", RID_RSID },
292 { "RubyAdjust", RID_RUBY_ADJUST },
293 { "RubyCharStyleName", RID_RUBY_CHAR_STYLE_NAME },
294 { "RubyIsAbove", RID_RUBY_IS_ABOVE },
295 { "RubyPosition", RID_RUBY_POSITION },
296 { "RubyText", RID_RUBY_TEXT },
297 { "SnapToGrid", RID_SNAP_TO_GRID },
298 { "StyleInteropGrabBag", RID_STYLE_INTEROP_GRAB_BAG },
299 { "TextField", RID_TEXT_FIELD },
300 { "TextFrame", RID_TEXT_FRAME },
301 { "TextParagraph", RID_TEXT_PARAGRAPH },
302 { "TextSection", RID_TEXT_SECTION },
303 { "TextTable", RID_TEXT_TABLE },
304 { "TextUserDefinedAttributes", RID_TEXT_USER_DEFINED_ATTRIBUTES },
305 { "TopBorder", RID_TOP_BORDER },
306 { "TopBorderDistance", RID_TOP_BORDER_DISTANCE },
307 { "UnvisitedCharStyleName", RID_UNVISITED_CHAR_STYLE_NAME },
308 { "VisitedCharStyleName", RID_VISITED_CHAR_STYLE_NAME },
309 { "WritingMode", RID_WRITING_MODE },
310 { "BorderColor", RID_BORDER_COLOR },
311 { "BorderInnerLineWidth", RID_BORDER_INNER_LINE_WIDTH },
312 { "BorderLineDistance", RID_BORDER_LINE_DISTANCE },
313 { "BorderLineStyle", RID_BORDER_LINE_STYLE },
314 { "BorderLineWidth", RID_BORDER_LINE_WIDTH },
315 { "BorderOuterLineWidth", RID_BORDER_OUTER_LINE_WIDTH },
318 auto itr = aNameToRID.find(rName);
319 if (itr != aNameToRID.end())
320 return SwResId(itr->second);
321 return rName;
324 static svx::sidebar::TreeNode SimplePropToTreeNode(const OUString& rName, const css::uno::Any& rVal)
326 svx::sidebar::TreeNode aCurNode;
327 aCurNode.sNodeName = PropertyNametoRID(rName);
328 aCurNode.aValue = rVal;
330 return aCurNode;
333 static svx::sidebar::TreeNode BorderToTreeNode(const OUString& rName, const css::uno::Any& rVal)
335 table::BorderLine2 aBorder;
336 rVal >>= aBorder;
337 svx::sidebar::TreeNode aCurNode;
338 aCurNode.sNodeName = PropertyNametoRID(rName);
339 aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
341 aCurNode.children.push_back(SimplePropToTreeNode("BorderColor", css::uno::Any(aBorder.Color)));
342 aCurNode.children.push_back(
343 SimplePropToTreeNode("BorderLineWidth", css::uno::Any(aBorder.LineWidth)));
344 aCurNode.children.push_back(
345 SimplePropToTreeNode("BorderLineStyle", css::uno::Any(aBorder.LineStyle)));
346 aCurNode.children.push_back(
347 SimplePropToTreeNode("BorderLineDistance", css::uno::Any(aBorder.LineDistance)));
348 aCurNode.children.push_back(
349 SimplePropToTreeNode("BorderInnerLineWidth", css::uno::Any(aBorder.InnerLineWidth)));
350 aCurNode.children.push_back(
351 SimplePropToTreeNode("BorderOuterLineWidth", css::uno::Any(aBorder.OuterLineWidth)));
353 return aCurNode;
356 static svx::sidebar::TreeNode LocaleToTreeNode(const OUString& rName, const css::uno::Any& rVal)
358 svx::sidebar::TreeNode aCurNode;
359 aCurNode.sNodeName = PropertyNametoRID(rName);
360 lang::Locale aLocale;
361 rVal >>= aLocale;
362 OUString aLocaleText(aLocale.Language + "-" + aLocale.Country);
363 if (!aLocale.Variant.isEmpty())
364 aLocaleText += " (" + aLocale.Variant + ")";
365 aCurNode.aValue <<= aLocaleText;
367 return aCurNode;
370 // Collect text of the current level of the annotated text
371 // ranges (InContentMetadata) and metadata fields (MetadataField)
372 static OUString NestedTextContentToText(const css::uno::Any& rVal)
374 uno::Reference<container::XEnumerationAccess> xMeta;
375 if (rVal >>= xMeta)
377 uno::Reference<container::XEnumeration> xMetaPortions = xMeta->createEnumeration();
379 OUStringBuffer aBuf;
380 while (xMetaPortions->hasMoreElements())
382 uno::Reference<css::text::XTextRange> xRng(xMetaPortions->nextElement(),
383 uno::UNO_QUERY);
384 aBuf.append(xRng->getString());
386 return aBuf.makeStringAndClear();
389 return OUString();
392 // List metadata associated to the paragraph or character range
393 static void MetadataToTreeNode(const css::uno::Reference<css::uno::XInterface>& rSource,
394 svx::sidebar::TreeNode& rNode)
396 uno::Reference<rdf::XMetadatable> xMeta(rSource, uno::UNO_QUERY_THROW);
397 // don't add tree node "Metadata Reference", if there is no xml:id
398 if (!xMeta.is() || xMeta->getMetadataReference().Second.isEmpty())
399 return;
401 // add metadata of parents for nested annotated text ranges
402 uno::Reference<container::XChild> xChild(rSource, uno::UNO_QUERY);
403 if (xChild.is())
405 uno::Reference<container::XEnumerationAccess> xParentMeta(xChild->getParent(),
406 uno::UNO_QUERY);
407 if (xParentMeta.is())
408 MetadataToTreeNode(xParentMeta, rNode);
411 svx::sidebar::TreeNode aCurNode;
412 aCurNode.sNodeName = PropertyNametoRID("MetadataReference");
413 aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
415 aCurNode.children.push_back(
416 SimplePropToTreeNode("xml:id", uno::makeAny(xMeta->getMetadataReference().Second)));
418 // list associated (predicate, object) pairs of the actual subject
419 // under the tree node "Metadata Reference"
420 SwDocShell* pDocSh = static_cast<SwDocShell*>(SfxObjectShell::Current());
421 uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(pDocSh->GetBaseModel(),
422 uno::UNO_QUERY);
423 const uno::Reference<rdf::XRepository>& xRepo = xDocumentMetadataAccess->getRDFRepository();
424 const css::uno::Reference<css::rdf::XResource> xSubject(rSource, uno::UNO_QUERY);
425 std::map<OUString, OUString> xStatements
426 = SwRDFHelper::getStatements(pDocSh->GetBaseModel(), xRepo->getGraphNames(), xSubject);
427 for (const auto& pair : xStatements)
428 aCurNode.children.push_back(SimplePropToTreeNode(pair.first, uno::makeAny(pair.second)));
430 rNode.children.push_back(aCurNode);
433 static svx::sidebar::TreeNode
434 PropertyToTreeNode(const css::beans::Property& rProperty,
435 const uno::Reference<beans::XPropertySet>& xPropertiesSet, const bool rIsGrey)
437 const OUString& rPropName = rProperty.Name;
438 svx::sidebar::TreeNode aCurNode;
439 const uno::Any aAny = xPropertiesSet->getPropertyValue(rPropName);
440 aCurNode.sNodeName = PropertyNametoRID(rPropName);
442 // These properties are handled separately as they are stored in STRUCT and not in single data members
443 if (rPropName == "CharTopBorder" || rPropName == "CharBottomBorder"
444 || rPropName == "CharLeftBorder" || rPropName == "CharRightBorder"
445 || rPropName == "TopBorder" || rPropName == "BottomBorder" || rPropName == "LeftBorder"
446 || rPropName == "RightBorder")
448 aCurNode = BorderToTreeNode(rPropName, aAny);
450 else if (rPropName == "CharLocale")
452 aCurNode = LocaleToTreeNode(rPropName, aAny);
454 else
455 aCurNode = SimplePropToTreeNode(rPropName, aAny);
457 if (rIsGrey)
459 aCurNode.isGrey = true;
460 for (svx::sidebar::TreeNode& rChildNode : aCurNode.children)
461 rChildNode.isGrey = true; // grey out all the children nodes
464 return aCurNode;
467 static void InsertValues(const css::uno::Reference<css::uno::XInterface>& rSource,
468 std::unordered_map<OUString, bool>& rIsDefined,
469 svx::sidebar::TreeNode& rNode, const bool isRoot,
470 const std::vector<OUString>& rHiddenProperty,
471 svx::sidebar::TreeNode& rFieldsNode)
473 uno::Reference<beans::XPropertySet> xPropertiesSet(rSource, uno::UNO_QUERY_THROW);
474 uno::Reference<beans::XPropertyState> xPropertiesState(rSource, uno::UNO_QUERY_THROW);
475 const uno::Sequence<beans::Property> aProperties
476 = xPropertiesSet->getPropertySetInfo()->getProperties();
478 for (const beans::Property& rProperty : aProperties)
480 const OUString& rPropName = rProperty.Name;
481 if (std::find(rHiddenProperty.begin(), rHiddenProperty.end(), rPropName)
482 != rHiddenProperty.end())
483 continue;
485 if (isRoot
486 || xPropertiesState->getPropertyState(rPropName) == beans::PropertyState_DIRECT_VALUE)
488 svx::sidebar::TreeNode aCurNode
489 = PropertyToTreeNode(rProperty, xPropertiesSet, rIsDefined[rPropName]);
490 rIsDefined[rPropName] = true;
492 // process NestedTextContent and show associated metadata
493 // under the tree node "Metadata Reference", if they exist
494 if (rPropName == "NestedTextContent")
496 uno::Reference<container::XEnumerationAccess> xMeta;
497 if (aCurNode.aValue >>= xMeta)
498 MetadataToTreeNode(xMeta, rFieldsNode);
499 aCurNode.aValue <<= NestedTextContentToText(aCurNode.aValue);
502 rNode.children.push_back(aCurNode);
506 const comphelper::string::NaturalStringSorter aSorter(
507 comphelper::getProcessComponentContext(),
508 Application::GetSettings().GetUILanguageTag().getLocale());
510 std::sort(
511 rNode.children.begin(), rNode.children.end(),
512 [&aSorter](svx::sidebar::TreeNode const& rEntry1, svx::sidebar::TreeNode const& rEntry2) {
513 return aSorter.compare(rEntry1.sNodeName, rEntry2.sNodeName) < 0;
517 static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>& aStore,
518 sal_Int32& rParIdx)
520 SwDoc* pDoc = pDocSh->GetDoc();
521 SwPaM* pCursor = pDoc->GetEditShell()->GetCursor();
522 svx::sidebar::TreeNode aCharDFNode;
523 svx::sidebar::TreeNode aCharNode;
524 svx::sidebar::TreeNode aParaNode;
525 svx::sidebar::TreeNode aParaDFNode;
526 svx::sidebar::TreeNode aBookmarksNode;
527 svx::sidebar::TreeNode aFieldsNode;
528 svx::sidebar::TreeNode aTextSectionsNode;
530 aCharNode.sNodeName = SwResId(STR_CHARACTERSTYLEFAMILY);
531 aParaNode.sNodeName = SwResId(STR_PARAGRAPHSTYLEFAMILY);
532 aCharDFNode.sNodeName = SwResId(RID_CHAR_DIRECTFORMAT);
533 aParaDFNode.sNodeName = SwResId(RID_PARA_DIRECTFORMAT);
534 aBookmarksNode.sNodeName = SwResId(STR_CONTENT_TYPE_BOOKMARK);
535 aFieldsNode.sNodeName = SwResId(STR_CONTENT_TYPE_TEXTFIELD);
536 aTextSectionsNode.sNodeName = SwResId(STR_CONTENT_TYPE_REGION);
537 aCharDFNode.NodeType = svx::sidebar::TreeNode::Category;
538 aCharNode.NodeType = svx::sidebar::TreeNode::Category;
539 aParaNode.NodeType = svx::sidebar::TreeNode::Category;
540 aParaDFNode.NodeType = svx::sidebar::TreeNode::Category;
541 aBookmarksNode.NodeType = svx::sidebar::TreeNode::Category;
542 aFieldsNode.NodeType = svx::sidebar::TreeNode::Category;
543 aTextSectionsNode.NodeType = svx::sidebar::TreeNode::Category;
545 uno::Reference<text::XTextRange> xRange(
546 SwXTextRange::CreateXTextRange(*pDoc, *pCursor->GetPoint(), nullptr));
547 uno::Reference<beans::XPropertySet> xPropertiesSet(xRange, uno::UNO_QUERY_THROW);
548 std::unordered_map<OUString, bool> aIsDefined;
550 const std::vector<OUString> aHiddenProperties{ UNO_NAME_RSID,
551 UNO_NAME_PARA_IS_NUMBERING_RESTART,
552 UNO_NAME_PARA_STYLE_NAME,
553 UNO_NAME_PARA_CONDITIONAL_STYLE_NAME,
554 UNO_NAME_PAGE_STYLE_NAME,
555 UNO_NAME_NUMBERING_START_VALUE,
556 UNO_NAME_NUMBERING_IS_NUMBER,
557 UNO_NAME_PARA_CONTINUEING_PREVIOUS_SUB_TREE,
558 UNO_NAME_CHAR_STYLE_NAME,
559 UNO_NAME_NUMBERING_LEVEL,
560 UNO_NAME_PARRSID };
562 InsertValues(xRange, aIsDefined, aCharDFNode, false, aHiddenProperties, aFieldsNode);
564 uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(pDocSh->GetBaseModel(),
565 uno::UNO_QUERY);
566 uno::Reference<container::XNameAccess> xStyleFamilies
567 = xStyleFamiliesSupplier->getStyleFamilies();
568 OUString sCurrentCharStyle, sCurrentParaStyle, sDisplayName;
570 uno::Reference<container::XNameAccess> xStyleFamily(
571 xStyleFamilies->getByName("CharacterStyles"), uno::UNO_QUERY_THROW);
572 xPropertiesSet->getPropertyValue("CharStyleName") >>= sCurrentCharStyle;
573 xPropertiesSet->getPropertyValue("ParaStyleName") >>= sCurrentParaStyle;
575 if (!sCurrentCharStyle.isEmpty())
577 xPropertiesSet.set(xStyleFamily->getByName(sCurrentCharStyle), css::uno::UNO_QUERY_THROW);
578 xPropertiesSet->getPropertyValue("DisplayName") >>= sDisplayName;
579 svx::sidebar::TreeNode aCurrentChild;
580 aCurrentChild.sNodeName = sDisplayName;
581 aCurrentChild.NodeType = svx::sidebar::TreeNode::ComplexProperty;
583 InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, false, {}, aFieldsNode);
585 aCharNode.children.push_back(aCurrentChild);
588 // Collect paragraph direct formatting
589 uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xRange, uno::UNO_QUERY_THROW);
590 uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
591 uno::Reference<text::XTextRange> xThisParagraphRange(xParaEnum->nextElement(), uno::UNO_QUERY);
592 if (xThisParagraphRange.is())
594 // Collect metadata of the current paragraph
595 MetadataToTreeNode(xThisParagraphRange, aParaDFNode);
596 InsertValues(xThisParagraphRange, aIsDefined, aParaDFNode, false, aHiddenProperties,
597 aFieldsNode);
600 xStyleFamily.set(xStyleFamilies->getByName("ParagraphStyles"), uno::UNO_QUERY_THROW);
602 while (!sCurrentParaStyle.isEmpty())
604 uno::Reference<style::XStyle> xPropertiesStyle(xStyleFamily->getByName(sCurrentParaStyle),
605 uno::UNO_QUERY_THROW);
606 xPropertiesSet.set(xPropertiesStyle, css::uno::UNO_QUERY_THROW);
607 xPropertiesSet->getPropertyValue("DisplayName") >>= sDisplayName;
608 OUString aParentParaStyle = xPropertiesStyle->getParentStyle();
609 svx::sidebar::TreeNode aCurrentChild;
610 aCurrentChild.sNodeName = sDisplayName;
611 aCurrentChild.NodeType = svx::sidebar::TreeNode::ComplexProperty;
613 InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, aParentParaStyle.isEmpty(), {},
614 aFieldsNode);
616 aParaNode.children.push_back(aCurrentChild);
617 sCurrentParaStyle = aParentParaStyle;
620 std::reverse(aParaNode.children.begin(),
621 aParaNode.children.end()); // Parent style should be first then children
623 // Collect bookmarks at character position
624 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(pDocSh->GetBaseModel(),
625 uno::UNO_QUERY);
627 uno::Reference<container::XIndexAccess> xBookmarks(xBookmarksSupplier->getBookmarks(),
628 uno::UNO_QUERY);
629 for (sal_Int32 i = 0; i < xBookmarks->getCount(); ++i)
631 svx::sidebar::TreeNode aCurNode;
632 uno::Reference<text::XTextContent> bookmark;
633 xBookmarks->getByIndex(i) >>= bookmark;
634 uno::Reference<container::XNamed> xBookmark(bookmark, uno::UNO_QUERY);
638 uno::Reference<text::XTextRange> bookmarkRange = bookmark->getAnchor();
639 uno::Reference<text::XTextRangeCompare> xTextRangeCompare(xRange->getText(),
640 uno::UNO_QUERY);
641 if (xTextRangeCompare.is()
642 && xTextRangeCompare->compareRegionStarts(bookmarkRange, xRange) != -1
643 && xTextRangeCompare->compareRegionEnds(xRange, bookmarkRange) != -1)
645 aCurNode.sNodeName = xBookmark->getName();
646 aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
648 MetadataToTreeNode(xBookmark, aCurNode);
649 // show bookmark only if it has RDF metadata
650 if (aCurNode.children.size() > 0)
651 aBookmarksNode.children.push_back(aCurNode);
654 catch (const lang::IllegalArgumentException&)
659 // Collect sections at character position
660 uno::Reference<text::XTextSectionsSupplier> xTextSectionsSupplier(pDocSh->GetBaseModel(),
661 uno::UNO_QUERY);
663 uno::Reference<container::XIndexAccess> xTextSections(xTextSectionsSupplier->getTextSections(),
664 uno::UNO_QUERY);
665 for (sal_Int32 i = 0; i < xTextSections->getCount(); ++i)
667 svx::sidebar::TreeNode aCurNode;
668 uno::Reference<text::XTextContent> section;
669 xTextSections->getByIndex(i) >>= section;
670 uno::Reference<container::XNamed> xTextSection(section, uno::UNO_QUERY);
674 uno::Reference<text::XTextRange> sectionRange = section->getAnchor();
675 uno::Reference<text::XTextRangeCompare> xTextRangeCompare(xRange->getText(),
676 uno::UNO_QUERY);
677 if (xTextRangeCompare.is()
678 && xTextRangeCompare->compareRegionStarts(sectionRange, xRange) != -1
679 && xTextRangeCompare->compareRegionEnds(xRange, sectionRange) != -1)
681 aCurNode.sNodeName = xTextSection->getName();
682 aCurNode.NodeType = svx::sidebar::TreeNode::ComplexProperty;
684 MetadataToTreeNode(xTextSection, aCurNode);
685 // show section only if it has RDF metadata
686 if (aCurNode.children.size() > 0)
687 aTextSectionsNode.children.push_back(aCurNode);
690 catch (const lang::IllegalArgumentException&)
696 Display Order :-
697 SECTIONS with RDF metadata (optional)
698 BOOKMARKS with RDF metadata (optional)
699 FIELDS with RDF metadata (optional)
700 PARAGRAPH STYLE
701 PARAGRAPH DIRECT FORMATTING
702 CHARACTER STYLE
703 DIRECT FORMATTING
705 rParIdx = 0;
706 // show sections, bookmarks and fields only if they have RDF metadata
707 if (aTextSectionsNode.children.size() > 0)
709 aStore.push_back(aTextSectionsNode);
710 rParIdx++;
712 if (aBookmarksNode.children.size() > 0)
714 aStore.push_back(aBookmarksNode);
715 rParIdx++;
717 if (aFieldsNode.children.size() > 0)
719 aStore.push_back(aFieldsNode);
720 rParIdx++;
722 aStore.push_back(aParaNode);
723 aStore.push_back(aParaDFNode);
724 aStore.push_back(aCharNode);
725 aStore.push_back(aCharDFNode);
728 IMPL_LINK(WriterInspectorTextPanel, AttrChangedNotify, LinkParamNone*, pLink, void)
730 if (m_oldLink.IsSet())
731 m_oldLink.Call(pLink);
733 SwDocShell* pDocSh = m_pShell->GetDoc()->GetDocShell();
734 std::vector<svx::sidebar::TreeNode> aStore;
736 if (pDocSh && pDocSh->GetDoc()->GetEditShell()->GetCursor()->GetNode().GetTextNode())
737 UpdateTree(pDocSh, aStore, m_nParIdx);
739 updateEntries(aStore, m_nParIdx);
742 } // end of namespace svx::sidebar
744 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */