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