1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 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/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 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 . 18 */ 19 20 #include "WriterInspectorTextPanel.hxx" 21 #include <svx/svxids.hrc> 22 #include <doc.hxx> 23 #include <docsh.hxx> 24 #include <wrtsh.hxx> 25 #include <com/sun/star/text/XTextRange.hpp> 26 #include <com/sun/star/text/XTextCursor.hpp> 27 #include <com/sun/star/awt/FontSlant.hpp> 28 #include <com/sun/star/beans/XPropertySet.hpp> 29 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> 30 #include <com/sun/star/lang/IllegalArgumentException.hpp> 31 32 #include <unotextrange.hxx> 33 34 namespace sw::sidebar 35 { 36 VclPtr<vcl::Window> WriterInspectorTextPanel::Create(vcl::Window* pParent, 37 const uno::Reference<frame::XFrame>& rxFrame, 38 SfxBindings* pBindings) 39 { 40 if (pParent == nullptr) 41 throw lang::IllegalArgumentException( 42 "no parent Window given to WriterInspectorTextPanel::Create", nullptr, 0); 43 if (!rxFrame.is()) 44 throw lang::IllegalArgumentException("no XFrame given to WriterInspectorTextPanel::Create", 45 nullptr, 1); 46 if (pBindings == nullptr) 47 throw lang::IllegalArgumentException( 48 "no SfxBindings given to WriterInspectorTextPanel::Create", nullptr, 2); 49 50 return VclPtr<WriterInspectorTextPanel>::Create(pParent, rxFrame, pBindings); 51 } 52 53 WriterInspectorTextPanel::WriterInspectorTextPanel(vcl::Window* pParent, 54 const uno::Reference<frame::XFrame>& rxFrame, 55 SfxBindings* pBindings) 56 : InspectorTextPanel(pParent, rxFrame) 57 , maCharStyle(SID_STYLE_FAMILY1, *pBindings, *this) 58 , maParaStyle(SID_STYLE_FAMILY2, *pBindings, *this) 59 { 60 } 61 62 static bool GetPropertyValues(const beans::Property rProperty, const uno::Any& rAny, 63 OUString& rString) 64 { 65 // Hide Asian and Complex properties 66 if (rProperty.Name.indexOf("Asian") != -1 || rProperty.Name.indexOf("Complex") != -1) 67 return false; 68 69 OUString aValue; 70 double fValue; 71 bool bValue; 72 short sValue; 73 long lValue; 74 awt::FontSlant iValue; 75 76 rString = rProperty.Name + " "; 77 78 if (rAny >>= bValue) 79 { 80 rString += OUString::boolean(bValue); 81 } 82 else if ((rAny >>= aValue) && !(aValue.isEmpty())) 83 { 84 rString += aValue; 85 } 86 else if (rAny >>= iValue) 87 { 88 rString += (iValue == awt::FontSlant_ITALIC) ? OUStringLiteral("italic") 89 : OUStringLiteral("normal"); 90 } 91 else if ((rAny >>= lValue) && lValue) 92 { 93 if (rString.indexOf("Color") != -1) 94 rString += "0x" + OUString::number(lValue, 16); 95 else 96 rString += OUString::number(lValue); 97 } 98 else if ((rAny >>= fValue) && fValue) 99 { 100 if (rString.indexOf("Weight") != -1) 101 rString += (fValue > 100) ? OUStringLiteral("bold") : OUStringLiteral("normal"); 102 else 103 rString += OUString::number((round(fValue * 100)) / 100.00); 104 } 105 else if ((rAny >>= sValue) && sValue) 106 { 107 rString += OUString::number(sValue); 108 } 109 else 110 return false; 111 return true; 112 } 113 114 static void UpdateTree(SwDocShell* pDocSh, svx::sidebar::TreeNode& pParentNode, 115 std::unordered_map<OUString, bool>& maIsDefined, StyleType sType) 116 { 117 SwDoc* pDoc = pDocSh->GetDoc(); 118 SwPaM* pCursor = pDoc->GetEditShell()->GetCursor(); 119 120 uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(pDocSh->GetBaseModel(), 121 uno::UNO_QUERY); 122 uno::Reference<container::XNameAccess> xStyleFamilies 123 = xStyleFamiliesSupplier->getStyleFamilies(); 124 uno::Reference<container::XNameAccess> xStyleFamily; 125 126 if (sType == CHARACTERSTYLES) 127 xStyleFamilies->getByName("CharacterStyles") >>= xStyleFamily; 128 else 129 xStyleFamilies->getByName("ParagraphStyles") >>= xStyleFamily; 130 131 uno::Reference<text::XTextCursor> xCursor = dynamic_cast<text::XTextCursor*>(pCursor); 132 uno::Reference<text::XTextRange> xRange( 133 SwXTextRange::CreateXTextRange(*pDoc, *pCursor->GetPoint(), nullptr)); 134 uno::Reference<beans::XPropertySet> properties(xRange, uno::UNO_QUERY_THROW); 135 136 OUString sCurrentStyleName, sDisplayName; 137 if (sType == CHARACTERSTYLES) 138 properties->getPropertyValue("CharStyleName") >>= sCurrentStyleName; 139 else 140 properties->getPropertyValue("ParaStyleName") >>= sCurrentStyleName; 141 142 if (sCurrentStyleName.isEmpty()) 143 sCurrentStyleName = "Standard"; 144 145 while (true) 146 { 147 uno::Reference<style::XStyle> xProp1; 148 uno::Reference<beans::XPropertySet> xProp1Set; 149 uno::Reference<beans::XPropertyState> xProp1State; 150 xStyleFamily->getByName(sCurrentStyleName) >>= xProp1; 151 xStyleFamily->getByName(sCurrentStyleName) >>= xProp1Set; 152 xStyleFamily->getByName(sCurrentStyleName) >>= xProp1State; 153 OUString aParentCharStyle = xProp1->getParentStyle(); 154 xProp1Set->getPropertyValue("DisplayName") >>= sDisplayName; 155 svx::sidebar::TreeNode pCurrentChild; 156 pCurrentChild.sNodeName = sDisplayName; 157 158 if (aParentCharStyle.isEmpty()) 159 { 160 break; // when current style is "Standard" there is no parent 161 } 162 163 const uno::Sequence<beans::Property> aProperties 164 = xProp1Set->getPropertySetInfo()->getProperties(); 165 const uno::Reference<beans::XPropertySet> xProp2Set( 166 xStyleFamily->getByName(aParentCharStyle), uno::UNO_QUERY); 167 168 try 169 { 170 for (const beans::Property& rProperty : aProperties) 171 { 172 OUString sPropName = rProperty.Name; 173 // If property's current value equals default value 174 if (xProp1Set->getPropertyValue(sPropName) 175 == xProp1State->getPropertyDefault(sPropName)) 176 continue; 177 178 if (maIsDefined[sPropName]) 179 continue; 180 181 if (xProp1Set->getPropertyValue(sPropName) 182 != xProp2Set->getPropertyValue(sPropName)) 183 { 184 maIsDefined[sPropName] = true; 185 OUString aPropertyValuePair; 186 const uno::Any aAny = xProp1Set->getPropertyValue(sPropName); 187 GetPropertyValues(rProperty, aAny, aPropertyValuePair); 188 if (!aPropertyValuePair.isEmpty()) 189 { 190 svx::sidebar::TreeNode pTemp; 191 pTemp.sNodeName = aPropertyValuePair; 192 pCurrentChild.children.push_back(pTemp); 193 } 194 } 195 } 196 } 197 catch (const uno::Exception&) 198 { 199 //do nothing 200 } 201 202 pParentNode.children.emplace_back(pCurrentChild); 203 sCurrentStyleName = aParentCharStyle; 204 } 205 206 uno::Reference<beans::XPropertySet> aProp1Set; 207 uno::Reference<beans::XPropertyState> aProp1State; 208 xStyleFamily->getByName(sCurrentStyleName) >>= aProp1Set; 209 xStyleFamily->getByName(sCurrentStyleName) >>= aProp1State; 210 211 const uno::Sequence<beans::Property> aProperties 212 = aProp1Set->getPropertySetInfo()->getProperties(); 213 svx::sidebar::TreeNode pCurrentChild; 214 pCurrentChild.sNodeName = sDisplayName; 215 216 for (const beans::Property& rProperty : aProperties) 217 { 218 OUString aPropertyValuePair, sPropName = rProperty.Name; 219 if (aProp1Set->getPropertyValue(sPropName) == aProp1State->getPropertyDefault(sPropName)) 220 continue; 221 if (maIsDefined[sPropName]) 222 continue; 223 maIsDefined[sPropName] = true; 224 225 const uno::Any aAny = aProp1Set->getPropertyValue(sPropName); 226 if (GetPropertyValues(rProperty, aAny, aPropertyValuePair)) 227 { 228 if (!aPropertyValuePair.isEmpty()) 229 { 230 svx::sidebar::TreeNode pTemp; 231 pTemp.sNodeName = aPropertyValuePair; 232 pCurrentChild.children.push_back(pTemp); 233 } 234 } 235 } 236 237 pParentNode.children.emplace_back(pCurrentChild); 238 std::reverse(pParentNode.children.begin(), pParentNode.children.end()); 239 } 240 241 void WriterInspectorTextPanel::NotifyItemUpdate(const sal_uInt16 nSId, 242 const SfxItemState /*eState*/, 243 const SfxPoolItem* /*pState*/) 244 { 245 SwDocShell* pDocSh = static_cast<SwDocShell*>(SfxObjectShell::Current()); 246 std::vector<svx::sidebar::TreeNode> aStore; 247 std::unordered_map<OUString, bool> maIsDefined; 248 249 switch (nSId) 250 { 251 case SID_STYLE_FAMILY1: 252 case SID_STYLE_FAMILY2: 253 { 254 if (pDocSh) 255 { 256 /* 257 First check in the property set of Character Styles 258 (as CS has higher priority over PS), then look into 259 property set of Paragraph Styles; 260 */ 261 svx::sidebar::TreeNode pTempChar; 262 pTempChar.sNodeName = "CHARACTER STYLES"; 263 UpdateTree(pDocSh, pTempChar, maIsDefined, CHARACTERSTYLES); 264 svx::sidebar::TreeNode pTempPara; 265 pTempPara.sNodeName = "PARAGRAPH STYLES"; 266 UpdateTree(pDocSh, pTempPara, maIsDefined, PARAGRAPHSTYLES); 267 268 /* 269 Order:- 270 PARAGRAPH STYLES 271 CHARACTER STYLES 272 DEFAULT FORMATTING 273 */ 274 aStore.push_back(pTempPara); 275 aStore.push_back(pTempChar); 276 } 277 } 278 break; 279 } 280 281 updateEntries(aStore); 282 } 283 284 } // end of namespace svx::sidebar 285 286 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 287
