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 #ifndef INCLUDED_SW_SOURCE_CORE_INC_WRONG_HXX 21 #define INCLUDED_SW_SOURCE_CORE_INC_WRONG_HXX 22 23 #include <com/sun/star/container/NoSuchElementException.hpp> 24 #include <com/sun/star/container/XStringKeyMap.hpp> 25 26 #include <com/sun/star/util/Color.hpp> 27 #include <com/sun/star/awt/FontUnderline.hpp> 28 #include <com/sun/star/uno/Any.hxx> 29 30 #include <vector> 31 #include <memory> 32 #include <optional> 33 34 #include <tools/color.hxx> 35 #include <swtypes.hxx> 36 #include <viewopt.hxx> 37 #include "TextFrameIndex.hxx" 38 39 #if defined _MSC_VER 40 // For MSVC (without /vmg) SwTextNode must consistently be defined for 41 // WrongListIterator::m_pGetWrongList of pointer-to-SwTextNode-member type to consistently have the 42 // same size in all translation units that include this file: 43 #include <ndtxt.hxx> 44 #endif 45 46 class SwWrongList; 47 48 enum WrongAreaLineType 49 { 50 WRONGAREA_NONE, 51 WRONGAREA_WAVE, 52 WRONGAREA_BOLDWAVE, 53 WRONGAREA_BOLD, 54 WRONGAREA_DASHED 55 }; 56 57 enum WrongListType 58 { 59 WRONGLIST_SPELL, 60 WRONGLIST_GRAMMAR, 61 WRONGLIST_SMARTTAG, 62 WRONGLIST_CHANGETRACKING 63 }; 64 65 // ST2 66 class SwWrongArea 67 { 68 public: 69 OUString maType; 70 css::uno::Reference< css::container::XStringKeyMap > mxPropertyBag; 71 sal_Int32 mnPos; 72 sal_Int32 mnLen; 73 SwWrongList* mpSubList; 74 75 Color mColor; 76 WrongAreaLineType mLineType; 77 78 SwWrongArea( const OUString& rType, 79 WrongListType listType, 80 css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag, 81 sal_Int32 nPos, 82 sal_Int32 nLen); 83 84 SwWrongArea( const OUString& rType, 85 css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag, 86 sal_Int32 nPos, 87 sal_Int32 nLen, 88 SwWrongList* pSubList); 89 private: 90 getGrammarColor(css::uno::Reference<css::container::XStringKeyMap> const & xPropertyBag)91 static Color getGrammarColor ( css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag) 92 { 93 try 94 { 95 if (xPropertyBag.is()) 96 { 97 css::uno::Any aLineColor = xPropertyBag->getValue("LineColor"); 98 ::Color lineColor; 99 100 if (aLineColor >>= lineColor) 101 { 102 return lineColor; 103 } 104 } 105 } 106 catch(const css::container::NoSuchElementException&) 107 { 108 } 109 catch(const css::uno::RuntimeException&) 110 { 111 } 112 113 return COL_LIGHTBLUE; 114 } 115 getGrammarLineType(css::uno::Reference<css::container::XStringKeyMap> const & xPropertyBag)116 static WrongAreaLineType getGrammarLineType( css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag ) 117 { 118 try 119 { 120 if (xPropertyBag.is()) 121 { 122 css::uno::Any aLineType = xPropertyBag->getValue("LineType"); 123 ::sal_Int16 lineType = 0; 124 125 if (!(aLineType >>= lineType)) 126 { 127 return WRONGAREA_WAVE; 128 } 129 if (css::awt::FontUnderline::BOLDWAVE == lineType) 130 { 131 return WRONGAREA_BOLDWAVE; 132 } 133 if (css::awt::FontUnderline::BOLD == lineType) 134 { 135 return WRONGAREA_BOLD; 136 } 137 if (css::awt::FontUnderline::DASH == lineType) 138 { 139 return WRONGAREA_DASHED; 140 } 141 if (css::awt::FontUnderline::SMALLWAVE == lineType) 142 { 143 return WRONGAREA_WAVE; //Code draws wave height based on space that fits. 144 } 145 } 146 } 147 catch(const css::container::NoSuchElementException&) 148 { 149 } 150 catch(const css::uno::RuntimeException&) 151 { 152 } 153 154 return WRONGAREA_WAVE; 155 } 156 getSmartColor(css::uno::Reference<css::container::XStringKeyMap> const & xPropertyBag)157 static Color getSmartColor ( css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag) 158 { 159 try 160 { 161 if (xPropertyBag.is()) 162 { 163 css::uno::Any aLineColor = xPropertyBag->getValue("LineColor"); 164 ::Color lineColor; 165 166 if (aLineColor >>= lineColor) 167 { 168 return lineColor; 169 } 170 } 171 } 172 catch(const css::container::NoSuchElementException&) 173 { 174 } 175 catch(const css::uno::RuntimeException&) 176 { 177 } 178 179 return SwViewOption::GetSmarttagColor( ); 180 } 181 getSmartLineType(css::uno::Reference<css::container::XStringKeyMap> const & xPropertyBag)182 static WrongAreaLineType getSmartLineType( css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag ) 183 { 184 try 185 { 186 if (xPropertyBag.is()) 187 { 188 css::uno::Any aLineType = xPropertyBag->getValue("LineType"); 189 ::sal_Int16 lineType = 0; 190 191 if (!(aLineType >>= lineType)) 192 { 193 return WRONGAREA_DASHED; 194 } 195 if (css::awt::FontUnderline::WAVE == lineType) 196 { 197 return WRONGAREA_WAVE; 198 } 199 if (css::awt::FontUnderline::BOLDWAVE == lineType) 200 { 201 return WRONGAREA_BOLDWAVE; 202 } 203 if (css::awt::FontUnderline::BOLD == lineType) 204 { 205 return WRONGAREA_BOLD; 206 } 207 if (css::awt::FontUnderline::SMALLWAVE == lineType) 208 { 209 return WRONGAREA_WAVE; //Code draws wave height based on space that fits. 210 } 211 } 212 } 213 catch(const css::container::NoSuchElementException&) 214 { 215 } 216 catch(const css::uno::RuntimeException&) 217 { 218 } 219 220 return WRONGAREA_DASHED; 221 } 222 getWrongAreaColor(WrongListType listType,css::uno::Reference<css::container::XStringKeyMap> const & xPropertyBag)223 static Color getWrongAreaColor(WrongListType listType, 224 css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag ) 225 { 226 if (WRONGLIST_SPELL == listType) 227 { 228 return SwViewOption::GetSpellColor(); 229 } 230 else if (WRONGLIST_GRAMMAR == listType) 231 { 232 return getGrammarColor(xPropertyBag); 233 } 234 else if (WRONGLIST_SMARTTAG == listType) 235 { 236 return getSmartColor(xPropertyBag); 237 } 238 239 return SwViewOption::GetSpellColor(); 240 } 241 getWrongAreaLineType(WrongListType listType,css::uno::Reference<css::container::XStringKeyMap> const & xPropertyBag)242 static WrongAreaLineType getWrongAreaLineType(WrongListType listType, 243 css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag ) 244 { 245 if (WRONGLIST_SPELL == listType) 246 { 247 return WRONGAREA_WAVE; 248 } 249 else if (WRONGLIST_GRAMMAR == listType) 250 { 251 return getGrammarLineType(xPropertyBag); 252 } 253 else if (WRONGLIST_SMARTTAG == listType) 254 { 255 return getSmartLineType(xPropertyBag); 256 } 257 258 return WRONGAREA_WAVE; 259 } 260 261 }; 262 263 class SwWrongList 264 { 265 std::vector<SwWrongArea> maList; 266 WrongListType meType; 267 268 sal_Int32 mnBeginInvalid; // Start of the invalid range 269 sal_Int32 mnEndInvalid; // End of the invalid range 270 ShiftLeft(sal_Int32 & rPos,sal_Int32 nStart,sal_Int32 nEnd)271 static void ShiftLeft( sal_Int32 &rPos, sal_Int32 nStart, sal_Int32 nEnd ) 272 { if( rPos > nStart ) rPos = rPos > nEnd ? rPos - nEnd + nStart : nStart; } 273 void Invalidate_( sal_Int32 nBegin, sal_Int32 nEnd ); 274 275 void Insert(sal_uInt16 nWhere, std::vector<SwWrongArea>::iterator startPos, std::vector<SwWrongArea>::iterator const & endPos); 276 void Remove( sal_uInt16 nIdx, sal_uInt16 nLen ); 277 278 SwWrongList& operator= (const SwWrongList &) = delete; 279 SwWrongList( const SwWrongList& rCpy ) = delete; 280 281 public: 282 SwWrongList( WrongListType eType ); 283 284 virtual ~SwWrongList(); 285 virtual SwWrongList* Clone(); 286 virtual void CopyFrom( const SwWrongList& rCopy ); 287 GetWrongListType() const288 WrongListType GetWrongListType() const { return meType; } GetBeginInv() const289 sal_Int32 GetBeginInv() const { return mnBeginInvalid; } GetEndInv() const290 sal_Int32 GetEndInv() const { return mnEndInvalid; } 291 void SetInvalid( sal_Int32 nBegin, sal_Int32 nEnd ); Validate()292 void Validate(){ mnBeginInvalid = mnEndInvalid = COMPLETE_STRING; } 293 void Invalidate( sal_Int32 nBegin, sal_Int32 nEnd ); 294 bool InvalidateWrong(); 295 enum class FreshState { FRESH, CURSOR, NOTHING }; 296 FreshState Fresh( sal_Int32 &rStart, sal_Int32 &rEnd, sal_Int32 nPos, 297 sal_Int32 nLen, sal_uInt16 nIndex, sal_Int32 nCursorPos ); 298 sal_uInt16 GetWrongPos( sal_Int32 nValue ) const; 299 300 bool Check( sal_Int32 &rChk, sal_Int32 &rLn ) const; 301 bool InWrongWord( sal_Int32 &rChk, sal_Int32 &rLn ) const; 302 sal_Int32 NextWrong( sal_Int32 nChk ) const; 303 304 void Move( sal_Int32 nPos, sal_Int32 nDiff ); 305 void ClearList(); 306 307 // Divide the list into two part, the wrong words until nSplitPos will be 308 // removed and transferred to a new SwWrongList. 309 std::unique_ptr<SwWrongList> SplitList( sal_Int32 nSplitPos ); 310 // Join the next SwWrongList, nInsertPos is my own text length, where 311 // the other wrong list has to be inserted. 312 void JoinList( SwWrongList* pNext, sal_Int32 nInsertPos ); 313 Len(sal_uInt16 nIdx) const314 sal_Int32 Len( sal_uInt16 nIdx ) const 315 { 316 return nIdx < maList.size() ? maList[nIdx].mnLen : 0; 317 } 318 Pos(sal_uInt16 nIdx) const319 sal_Int32 Pos( sal_uInt16 nIdx ) const 320 { 321 return nIdx < maList.size() ? maList[nIdx].mnPos : 0; 322 } 323 Count() const324 sal_uInt16 Count() const { return o3tl::narrowing<sal_uInt16>(maList.size()); } 325 Insert(const OUString & rType,css::uno::Reference<css::container::XStringKeyMap> const & xPropertyBag,sal_Int32 nNewPos,sal_Int32 nNewLen,sal_uInt16 nWhere)326 void Insert( const OUString& rType, 327 css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag, 328 sal_Int32 nNewPos, sal_Int32 nNewLen, sal_uInt16 nWhere ) 329 { 330 std::vector<SwWrongArea>::iterator i = maList.begin(); 331 if ( nWhere >= maList.size() ) 332 i = maList.end(); // robust 333 else 334 i += nWhere; 335 336 maList.insert(i, SwWrongArea( rType, meType, xPropertyBag, nNewPos, nNewLen) ); 337 } 338 339 void Insert( const OUString& rType, 340 css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag, 341 sal_Int32 nNewPos, sal_Int32 nNewLen ); 342 SubList(sal_uInt16 nIdx) const343 SwWrongList* SubList( sal_uInt16 nIdx ) const 344 { 345 return nIdx < maList.size() ? maList[nIdx].mpSubList : nullptr; 346 } 347 348 void InsertSubList( sal_Int32 nNewPos, sal_Int32 nNewLen, sal_uInt16 nWhere, SwWrongList* pSubList ); 349 GetElement(sal_uInt16 nIdx) const350 const SwWrongArea* GetElement( sal_uInt16 nIdx ) const 351 { 352 return nIdx < maList.size() ? &maList[nIdx] : nullptr; 353 } 354 void RemoveEntry( sal_Int32 nBegin, sal_Int32 nEnd ); 355 bool LookForEntry( sal_Int32 nBegin, sal_Int32 nEnd ); 356 }; 357 358 class SwTextNode; 359 class SwTextFrame; 360 361 namespace sw { 362 363 struct MergedPara; 364 365 class WrongListIteratorBase 366 { 367 protected: 368 SwWrongList const* (SwTextNode::*const m_pGetWrongList)() const; 369 sw::MergedPara const*const m_pMergedPara; 370 size_t m_CurrentExtent; 371 TextFrameIndex m_CurrentIndex; 372 SwWrongList const*const m_pWrongList; 373 374 public: 375 /// for the text frame 376 WrongListIteratorBase(SwTextFrame const& rFrame, 377 SwWrongList const* (SwTextNode::*pGetWrongList)() const); 378 /// for SwTextSlot 379 WrongListIteratorBase(SwWrongList const& rWrongList); 380 }; 381 382 class WrongListIterator 383 : public WrongListIteratorBase 384 { 385 public: 386 /// for the text frame 387 WrongListIterator(SwTextFrame const& rFrame, 388 SwWrongList const* (SwTextNode::*pGetWrongList)() const); 389 /// for SwTextSlot 390 WrongListIterator(SwWrongList const& rWrongList); 391 392 bool Check(TextFrameIndex &rStart, TextFrameIndex &rLen); 393 const SwWrongArea* GetWrongElement(TextFrameIndex nStart); 394 LooksUseful()395 bool LooksUseful() { return m_pMergedPara || m_pWrongList; } 396 }; 397 398 class WrongListIteratorCounter 399 : public WrongListIteratorBase 400 { 401 public: 402 WrongListIteratorCounter(SwTextFrame const& rFrame, 403 SwWrongList const* (SwTextNode::*pGetWrongList)() const); 404 WrongListIteratorCounter(SwWrongList const& rWrongList); 405 406 sal_uInt16 GetElementCount(); 407 std::optional<std::pair<TextFrameIndex, TextFrameIndex>> GetElementAt(sal_uInt16 nIndex); 408 }; 409 410 } // namespace sw 411 412 #endif 413 414 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 415