Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name impedit4.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D EDITENG_DLLIMPLEMENTATION -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/editeng/inc -I /home/maarten/src/libreoffice/core/editeng/source/editeng -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/editeng/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx

/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx

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
21#include <vcl/svapp.hxx>
22
23#include <svl/srchitem.hxx>
24#include <editeng/lspcitem.hxx>
25#include <editeng/adjustitem.hxx>
26#include <editeng/tstpitem.hxx>
27
28#include "eertfpar.hxx"
29#include <editeng/editeng.hxx>
30#include "impedit.hxx"
31#include <editeng/editview.hxx>
32#include "eehtml.hxx"
33#include "editobj2.hxx"
34#include <i18nlangtag/lang.h>
35#include <sal/log.hxx>
36#include <o3tl/safeint.hxx>
37#include <osl/diagnose.h>
38
39#include <editxml.hxx>
40
41#include <editeng/autokernitem.hxx>
42#include <editeng/contouritem.hxx>
43#include <editeng/colritem.hxx>
44#include <editeng/crossedoutitem.hxx>
45#include <editeng/escapementitem.hxx>
46#include <editeng/fhgtitem.hxx>
47#include <editeng/fontitem.hxx>
48#include <editeng/kernitem.hxx>
49#include <editeng/lrspitem.hxx>
50#include <editeng/postitem.hxx>
51#include <editeng/shdditem.hxx>
52#include <editeng/udlnitem.hxx>
53#include <editeng/ulspitem.hxx>
54#include <editeng/wghtitem.hxx>
55#include <editeng/langitem.hxx>
56#include <editeng/charreliefitem.hxx>
57#include <editeng/frmdiritem.hxx>
58#include <editeng/emphasismarkitem.hxx>
59#include "textconv.hxx"
60#include <rtl/tencinfo.h>
61#include <svtools/rtfout.hxx>
62#include <tools/stream.hxx>
63#include <edtspell.hxx>
64#include <editeng/unolingu.hxx>
65#include <com/sun/star/linguistic2/XThesaurus.hpp>
66#include <com/sun/star/i18n/ScriptType.hpp>
67#include <com/sun/star/i18n/WordType.hpp>
68#include <unotools/transliterationwrapper.hxx>
69#include <unotools/textsearch.hxx>
70#include <comphelper/processfactory.hxx>
71#include <vcl/help.hxx>
72#include <vcl/metric.hxx>
73#include <svtools/rtfkeywd.hxx>
74#include <editeng/edtdlg.hxx>
75
76#include <memory>
77#include <unordered_map>
78#include <vector>
79
80using namespace ::com::sun::star;
81using namespace ::com::sun::star::uno;
82using namespace ::com::sun::star::beans;
83using namespace ::com::sun::star::linguistic2;
84
85
86EditPaM ImpEditEngine::Read(SvStream& rInput, const OUString& rBaseURL, EETextFormat eFormat, const EditSelection& rSel, SvKeyValueIterator* pHTTPHeaderAttrs)
87{
88 bool _bUpdate = GetUpdateMode();
89 SetUpdateMode( false );
90 EditPaM aPaM;
91 if ( eFormat == EETextFormat::Text )
92 aPaM = ReadText( rInput, rSel );
93 else if ( eFormat == EETextFormat::Rtf )
94 aPaM = ReadRTF( rInput, rSel );
95 else if ( eFormat == EETextFormat::Xml )
96 aPaM = ReadXML( rInput, rSel );
97 else if ( eFormat == EETextFormat::Html )
98 aPaM = ReadHTML( rInput, rBaseURL, rSel, pHTTPHeaderAttrs );
99 else
100 {
101 OSL_FAIL( "Read: Unknown Format" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "101" ": "), "%s", "Read: Unknown Format"); } } while (false
)
;
102 }
103
104 FormatFullDoc(); // perhaps a simple format is enough?
105 SetUpdateMode( _bUpdate );
106
107 return aPaM;
108}
109
110EditPaM ImpEditEngine::ReadText( SvStream& rInput, EditSelection aSel )
111{
112 if ( aSel.HasRange() )
113 aSel = ImpDeleteSelection( aSel );
114 EditPaM aPaM = aSel.Max();
115
116 OUString aTmpStr;
117 bool bDone = rInput.ReadByteStringLine( aTmpStr, rInput.GetStreamCharSet() );
118 while ( bDone )
119 {
120 if (aTmpStr.getLength() > MAXCHARSINPARA0x3FFF-16)
121 {
122 aTmpStr = aTmpStr.copy(0, MAXCHARSINPARA0x3FFF-16);
123 }
124 aPaM = ImpInsertText( EditSelection( aPaM, aPaM ), aTmpStr );
125 aPaM = ImpInsertParaBreak( aPaM );
126 bDone = rInput.ReadByteStringLine( aTmpStr, rInput.GetStreamCharSet() );
127 }
128 return aPaM;
129}
130
131EditPaM ImpEditEngine::ReadXML( SvStream& rInput, EditSelection aSel )
132{
133 if ( aSel.HasRange() )
134 aSel = ImpDeleteSelection( aSel );
135
136 ESelection aESel = CreateESel( aSel );
137
138 return ::SvxReadXML( *GetEditEnginePtr(), rInput, aESel );
139}
140
141EditPaM ImpEditEngine::ReadRTF( SvStream& rInput, EditSelection aSel )
142{
143 if ( aSel.HasRange() )
144 aSel = ImpDeleteSelection( aSel );
145
146 // The SvRTF parser expects the Which-mapping passed on in the pool, not
147 // dependent on a secondary.
148 SfxItemPool* pPool = &aEditDoc.GetItemPool();
149 while (pPool->GetSecondaryPool() && pPool->GetName() != "EditEngineItemPool")
150 {
151 pPool = pPool->GetSecondaryPool();
152
153 }
154
155 DBG_ASSERT(pPool && pPool->GetName() == "EditEngineItemPool",do { if (true && (!(pPool && pPool->GetName
() == "EditEngineItemPool"))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "156" ": "), "%s", "ReadRTF: no EditEnginePool!"); } } while
(false)
156 "ReadRTF: no EditEnginePool!")do { if (true && (!(pPool && pPool->GetName
() == "EditEngineItemPool"))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "156" ": "), "%s", "ReadRTF: no EditEnginePool!"); } } while
(false)
;
157
158 EditRTFParserRef xPrsr = new EditRTFParser(rInput, aSel, *pPool, pEditEngine);
159 SvParserState eState = xPrsr->CallParser();
160 if ( ( eState != SvParserState::Accepted ) && ( !rInput.GetError() ) )
161 {
162 rInput.SetError( EE_READWRITE_WRONGFORMATErrCode(ErrCodeArea::Svx, 1) );
163 return aSel.Min();
164 }
165 return xPrsr->GetCurPaM();
166}
167
168EditPaM ImpEditEngine::ReadHTML( SvStream& rInput, const OUString& rBaseURL, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs )
169{
170 if ( aSel.HasRange() )
171 aSel = ImpDeleteSelection( aSel );
172
173 EditHTMLParserRef xPrsr = new EditHTMLParser( rInput, rBaseURL, pHTTPHeaderAttrs );
174 SvParserState eState = xPrsr->CallParser(pEditEngine, aSel.Max());
175 if ( ( eState != SvParserState::Accepted ) && ( !rInput.GetError() ) )
176 {
177 rInput.SetError( EE_READWRITE_WRONGFORMATErrCode(ErrCodeArea::Svx, 1) );
178 return aSel.Min();
179 }
180 return xPrsr->GetCurSelection().Max();
181}
182
183void ImpEditEngine::Write(SvStream& rOutput, EETextFormat eFormat, const EditSelection& rSel)
184{
185 if ( !rOutput.IsWritable() )
186 rOutput.SetError( SVSTREAM_WRITE_ERRORErrCode( ErrCodeArea::Io, ErrCodeClass::Write, 16 ) );
187
188 if ( rOutput.GetError() )
189 return;
190
191 if ( eFormat == EETextFormat::Text )
192 WriteText( rOutput, rSel );
193 else if ( eFormat == EETextFormat::Rtf )
194 WriteRTF( rOutput, rSel );
195 else if ( eFormat == EETextFormat::Xml )
196 WriteXML( rOutput, rSel );
197 else if ( eFormat == EETextFormat::Html )
198 ;
199 else
200 {
201 OSL_FAIL( "Write: Unknown Format" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "201" ": "), "%s", "Write: Unknown Format"); } } while (
false)
;
202 }
203}
204
205ErrCode ImpEditEngine::WriteText( SvStream& rOutput, EditSelection aSel )
206{
207 sal_Int32 nStartNode, nEndNode;
208 bool bRange = aSel.HasRange();
209 if ( bRange )
210 {
211 aSel.Adjust( aEditDoc );
212 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
213 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
214 }
215 else
216 {
217 nStartNode = 0;
218 nEndNode = aEditDoc.Count()-1;
219 }
220
221 // iterate over the paragraphs ...
222 for ( sal_Int32 nNode = nStartNode; nNode <= nEndNode; nNode++ )
223 {
224 ContentNode* pNode = aEditDoc.GetObject( nNode );
225 DBG_ASSERT( pNode, "Node not found: Search&Replace" )do { if (true && (!(pNode))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "225" ": "), "%s", "Node not found: Search&Replace")
; } } while (false)
;
226
227 sal_Int32 nStartPos = 0;
228 sal_Int32 nEndPos = pNode->Len();
229 if ( bRange )
230 {
231 if ( nNode == nStartNode )
232 nStartPos = aSel.Min().GetIndex();
233 if ( nNode == nEndNode ) // can also be == nStart!
234 nEndPos = aSel.Max().GetIndex();
235 }
236 OUString aTmpStr = EditDoc::GetParaAsString( pNode, nStartPos, nEndPos );
237 rOutput.WriteByteStringLine( aTmpStr, rOutput.GetStreamCharSet() );
238 }
239
240 return rOutput.GetError();
241}
242
243bool ImpEditEngine::WriteItemListAsRTF( ItemList& rLst, SvStream& rOutput, sal_Int32 nPara, sal_Int32 nPos,
244 std::vector<std::unique_ptr<SvxFontItem>>& rFontTable, SvxColorList& rColorList )
245{
246 const SfxPoolItem* pAttrItem = rLst.First();
247 while ( pAttrItem )
248 {
249 WriteItemAsRTF( *pAttrItem, rOutput, nPara, nPos,rFontTable, rColorList );
250 pAttrItem = rLst.Next();
251 }
252 return rLst.Count() != 0;
253}
254
255static void lcl_FindValidAttribs( ItemList& rLst, ContentNode* pNode, sal_Int32 nIndex, sal_uInt16 nScriptType )
256{
257 sal_uInt16 nAttr = 0;
258 EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
259 while ( pAttr && ( pAttr->GetStart() <= nIndex ) )
260 {
261 // Start is checked in while ...
262 if ( pAttr->GetEnd() > nIndex )
263 {
264 if ( IsScriptItemValid( pAttr->GetItem()->Which(), nScriptType ) )
265 rLst.Insert( pAttr->GetItem() );
266 }
267 nAttr++;
268 pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
269 }
270}
271
272void ImpEditEngine::WriteXML(SvStream& rOutput, const EditSelection& rSel)
273{
274 ESelection aESel = CreateESel(rSel);
275
276 SvxWriteXML( *GetEditEnginePtr(), rOutput, aESel );
277}
278
279ErrCode ImpEditEngine::WriteRTF( SvStream& rOutput, EditSelection aSel )
280{
281 DBG_ASSERT( GetUpdateMode(), "WriteRTF for UpdateMode = sal_False!" )do { if (true && (!(GetUpdateMode()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "281" ": "), "%s", "WriteRTF for UpdateMode = sal_False!"
); } } while (false)
;
282 CheckIdleFormatter();
283 if ( !IsFormatted() )
284 FormatDoc();
285
286 sal_Int32 nStartNode, nEndNode;
287 aSel.Adjust( aEditDoc );
288
289 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
290 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
291
292 // RTF header ...
293 rOutput.WriteChar( '{' ) ;
294
295 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RTF"\\rtf" );
296
297 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ANSI"\\ansi" );
298 rtl_TextEncoding eDestEnc = RTL_TEXTENCODING_MS_1252(((rtl_TextEncoding) 1));
299
300 // Generate and write out Font table ...
301 std::vector<std::unique_ptr<SvxFontItem>> aFontTable;
302 // default font must be up front, so DEF font in RTF
303 aFontTable.emplace_back( new SvxFontItem( aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO ) ) );
304 aFontTable.emplace_back( new SvxFontItem( aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO_CJK ) ) );
305 aFontTable.emplace_back( new SvxFontItem( aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO_CTL ) ) );
306 for ( sal_uInt16 nScriptType = 0; nScriptType < 3; nScriptType++ )
307 {
308 sal_uInt16 nWhich = EE_CHAR_FONTINFO;
309 if ( nScriptType == 1 )
310 nWhich = EE_CHAR_FONTINFO_CJK;
311 else if ( nScriptType == 2 )
312 nWhich = EE_CHAR_FONTINFO_CTL;
313
314 for (const SfxPoolItem* pItem : aEditDoc.GetItemPool().GetItemSurrogates(nWhich))
315 {
316 SvxFontItem const*const pFontItem = static_cast<const SvxFontItem*>(pItem);
317 bool bAlreadyExist = false;
318 sal_uLong nTestMax = nScriptType ? aFontTable.size() : 1;
319 for ( sal_uLong nTest = 0; !bAlreadyExist && ( nTest < nTestMax ); nTest++ )
320 {
321 bAlreadyExist = *aFontTable[ nTest ] == *pFontItem;
322 }
323
324 if ( !bAlreadyExist )
325 aFontTable.emplace_back( new SvxFontItem( *pFontItem ) );
326 }
327 }
328
329 rOutput << endl;
330 rOutput.WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_FONTTBL"\\fonttbl" );
331 for ( std::vector<SvxFontItem*>::size_type j = 0; j < aFontTable.size(); j++ )
332 {
333 SvxFontItem* pFontItem = aFontTable[ j ].get();
334 rOutput.WriteChar( '{' );
335 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_F"\\f" );
336 rOutput.WriteUInt32AsString( j );
337 switch ( pFontItem->GetFamily() )
338 {
339 case FAMILY_DONTKNOW: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_FNIL"\\fnil" );
340 break;
341 case FAMILY_DECORATIVE: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_FDECOR"\\fdecor" );
342 break;
343 case FAMILY_MODERN: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_FMODERN"\\fmodern" );
344 break;
345 case FAMILY_ROMAN: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_FROMAN"\\froman" );
346 break;
347 case FAMILY_SCRIPT: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_FSCRIPT"\\fscript" );
348 break;
349 case FAMILY_SWISS: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_FSWISS"\\fswiss" );
350 break;
351 default:
352 break;
353 }
354 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_FPRQ"\\fprq" );
355 sal_uInt16 nVal = 0;
356 switch( pFontItem->GetPitch() )
357 {
358 case PITCH_FIXED: nVal = 1; break;
359 case PITCH_VARIABLE: nVal = 2; break;
360 default:
361 break;
362 }
363 rOutput.WriteUInt32AsString( nVal );
364
365 rtl_TextEncoding eChrSet = pFontItem->GetCharSet();
366 DBG_ASSERT( eChrSet != 9, "SystemCharSet?!" )do { if (true && (!(eChrSet != 9))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "366" ": "), "%s", "SystemCharSet?!"); } } while (false)
;
367 if( RTL_TEXTENCODING_DONTKNOW(((rtl_TextEncoding) 0)) == eChrSet )
368 eChrSet = osl_getThreadTextEncoding();
369 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_FCHARSET"\\fcharset" );
370 rOutput.WriteUInt32AsString( rtl_getBestWindowsCharsetFromTextEncoding( eChrSet ) );
371
372 rOutput.WriteChar( ' ' );
373 RTFOutFuncs::Out_String( rOutput, pFontItem->GetFamilyName(), eDestEnc );
374 rOutput.WriteCharPtr( ";}" );
375 }
376 rOutput.WriteChar( '}' );
377 rOutput << endl;
378
379 // Write out ColorList ...
380 SvxColorList aColorList;
381 // COL_AUTO should be the default color, always put it first
382 aColorList.emplace_back(COL_AUTO);
383 SvxColorItem const& rDefault(aEditDoc.GetItemPool().GetDefaultItem(EE_CHAR_COLOR));
384 if (rDefault.GetValue() != COL_AUTO) // is the default always AUTO?
385 {
386 aColorList.push_back(rDefault.GetValue());
387 }
388 for (const SfxPoolItem* pItem : aEditDoc.GetItemPool().GetItemSurrogates(EE_CHAR_COLOR))
389 {
390 auto pColorItem(dynamic_cast<SvxColorItem const*>(pItem));
391 if (pColorItem && pColorItem->GetValue() != COL_AUTO) // may be null!
392 {
393 aColorList.push_back(pColorItem->GetValue());
394 }
395 }
396
397 rOutput.WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_COLORTBL"\\colortbl" );
398 for ( SvxColorList::size_type j = 0; j < aColorList.size(); j++ )
399 {
400 Color const color = aColorList[j];
401 if (color != COL_AUTO) // auto is represented by "empty" element
402 {
403 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RED"\\red" );
404 rOutput.WriteUInt32AsString( color.GetRed() );
405 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_GREEN"\\green" );
406 rOutput.WriteUInt32AsString( color.GetGreen() );
407 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_BLUE"\\blue" );
408 rOutput.WriteUInt32AsString( color.GetBlue() );
409 }
410 rOutput.WriteChar( ';' );
411 }
412 rOutput.WriteChar( '}' );
413 rOutput << endl;
414
415 std::unordered_map<SfxStyleSheetBase*, sal_uInt32> aStyleSheetToIdMap;
416 // StyleSheets...
417 if ( GetStyleSheetPool() )
418 {
419 std::shared_ptr<SfxStyleSheetIterator> aSSSIterator = std::make_shared<SfxStyleSheetIterator>(GetStyleSheetPool(),
420 SfxStyleFamily::All);
421 // fill aStyleSheetToIdMap
422 sal_uInt32 nId = 1;
423 for ( SfxStyleSheetBase* pStyle = aSSSIterator->First(); pStyle;
424 pStyle = aSSSIterator->Next() )
425 {
426 aStyleSheetToIdMap[pStyle] = nId;
427 nId++;
428 }
429
430 if ( aSSSIterator->Count() )
431 {
432
433 sal_uInt32 nStyle = 0;
434 rOutput.WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STYLESHEET"\\stylesheet" );
435
436 for ( SfxStyleSheetBase* pStyle = aSSSIterator->First(); pStyle;
437 pStyle = aSSSIterator->Next() )
438 {
439
440 rOutput << endl;
441 rOutput.WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_S"\\s" );
442 sal_uInt32 nNumber = nStyle + 1;
443 rOutput.WriteUInt32AsString( nNumber );
444
445 // Attribute, also from Parent!
446 for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ )
447 {
448 if ( pStyle->GetItemSet().GetItemState( nParAttr ) == SfxItemState::SET )
449 {
450 const SfxPoolItem& rItem = pStyle->GetItemSet().Get( nParAttr );
451 WriteItemAsRTF( rItem, rOutput, 0, 0, aFontTable, aColorList );
452 }
453 }
454
455 // Parent ... (only if necessary)
456 if ( !pStyle->GetParent().isEmpty() && ( pStyle->GetParent() != pStyle->GetName() ) )
457 {
458 SfxStyleSheet* pParent = static_cast<SfxStyleSheet*>(GetStyleSheetPool()->Find( pStyle->GetParent(), pStyle->GetFamily() ));
459 DBG_ASSERT( pParent, "Parent not found!" )do { if (true && (!(pParent))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "459" ": "), "%s", "Parent not found!"); } } while (false
)
;
460 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_SBASEDON"\\sbasedon" );
461 nNumber = aStyleSheetToIdMap.find(pParent)->second;
462 rOutput.WriteUInt32AsString( nNumber );
463 }
464
465 // Next Style... (more)
466 // we assume that we have only SfxStyleSheet in the pool
467 SfxStyleSheet* pNext = static_cast<SfxStyleSheet*>(pStyle);
468 if ( !pStyle->GetFollow().isEmpty() && ( pStyle->GetFollow() != pStyle->GetName() ) )
469 pNext = static_cast<SfxStyleSheet*>(GetStyleSheetPool()->Find( pStyle->GetFollow(), pStyle->GetFamily() ));
470
471 DBG_ASSERT( pNext, "Next not found!" )do { if (true && (!(pNext))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "471" ": "), "%s", "Next not found!"); } } while (false)
;
472 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_SNEXT"\\snext" );
473 nNumber = aStyleSheetToIdMap.find(pNext)->second;
474 rOutput.WriteUInt32AsString( nNumber );
475
476 // Name of the template...
477 rOutput.WriteCharPtr( " " );
478 RTFOutFuncs::Out_String( rOutput, pStyle->GetName(), eDestEnc );
479 rOutput.WriteCharPtr( ";}" );
480 nStyle++;
481 }
482 rOutput.WriteChar( '}' );
483 rOutput << endl;
484 }
485 }
486
487 // Write the pool defaults in advance ...
488 rOutput.WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_IGNORE"\\*" ).WriteCharPtr( "\\EditEnginePoolDefaults" );
489 for ( sal_uInt16 nPoolDefItem = EE_PARA_START; nPoolDefItem <= EE_CHAR_END; nPoolDefItem++)
490 {
491 const SfxPoolItem& rItem = aEditDoc.GetItemPool().GetDefaultItem( nPoolDefItem );
492 WriteItemAsRTF( rItem, rOutput, 0, 0, aFontTable, aColorList );
493 }
494 rOutput.WriteChar( '}' ) << endl;
495
496 // DefTab:
497 MapMode aTwpMode( MapUnit::MapTwip );
498 sal_uInt16 nDefTabTwps = static_cast<sal_uInt16>(GetRefDevice()->LogicToLogic(
499 Point( aEditDoc.GetDefTab(), 0 ),
500 &GetRefMapMode(), &aTwpMode ).X());
501 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_DEFTAB"\\deftab" );
502 rOutput.WriteUInt32AsString( nDefTabTwps );
503 rOutput << endl;
504
505 // iterate over the paragraphs ...
506 rOutput.WriteChar( '{' ) << endl;
507 for ( sal_Int32 nNode = nStartNode; nNode <= nEndNode; nNode++ )
508 {
509 ContentNode* pNode = aEditDoc.GetObject( nNode );
510 DBG_ASSERT( pNode, "Node not found: Search&Replace" )do { if (true && (!(pNode))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "510" ": "), "%s", "Node not found: Search&Replace")
; } } while (false)
;
511
512 // The paragraph attributes in advance ...
513 bool bAttr = false;
514
515 // Template?
516 if ( pNode->GetStyleSheet() )
517 {
518 // Number of template
519 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_S"\\s" );
520 sal_uInt32 nNumber = aStyleSheetToIdMap.find(pNode->GetStyleSheet())->second;
521 rOutput.WriteUInt32AsString( nNumber );
522
523 // All Attribute
524 // Attribute, also from Parent!
525 for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ )
526 {
527 if ( pNode->GetStyleSheet()->GetItemSet().GetItemState( nParAttr ) == SfxItemState::SET )
528 {
529 const SfxPoolItem& rItem = pNode->GetStyleSheet()->GetItemSet().Get( nParAttr );
530 WriteItemAsRTF( rItem, rOutput, nNode, 0, aFontTable, aColorList );
531 bAttr = true;
532 }
533 }
534 }
535
536 for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ )
537 {
538 // Now where stylesheet processing, only hard paragraph attributes!
539 if ( pNode->GetContentAttribs().GetItems().GetItemState( nParAttr ) == SfxItemState::SET )
540 {
541 const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItems().Get( nParAttr );
542 WriteItemAsRTF( rItem, rOutput, nNode, 0, aFontTable, aColorList );
543 bAttr = true;
544 }
545 }
546 if ( bAttr )
547 rOutput.WriteChar( ' ' ); // Separator
548
549 ItemList aAttribItems;
550 ParaPortion* pParaPortion = FindParaPortion( pNode );
551 DBG_ASSERT( pParaPortion, "Portion not found: WriteRTF" )do { if (true && (!(pParaPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "551" ": "), "%s", "Portion not found: WriteRTF"); } } while
(false)
;
552
553 sal_Int32 nIndex = 0;
554 sal_Int32 nStartPos = 0;
555 sal_Int32 nEndPos = pNode->Len();
556 sal_Int32 nStartPortion = 0;
557 sal_Int32 nEndPortion = pParaPortion->GetTextPortions().Count() - 1;
558 bool bFinishPortion = false;
559 sal_Int32 nPortionStart;
560
561 if ( nNode == nStartNode )
562 {
563 nStartPos = aSel.Min().GetIndex();
564 nStartPortion = pParaPortion->GetTextPortions().FindPortion( nStartPos, nPortionStart );
565 if ( nStartPos != 0 )
566 {
567 aAttribItems.Clear();
568 lcl_FindValidAttribs( aAttribItems, pNode, nStartPos, GetI18NScriptType( EditPaM( pNode, 0 ) ) );
569 if ( aAttribItems.Count() )
570 {
571 // These attributes may not apply to the entire paragraph:
572 rOutput.WriteChar( '{' );
573 WriteItemListAsRTF( aAttribItems, rOutput, nNode, nStartPos, aFontTable, aColorList );
574 bFinishPortion = true;
575 }
576 aAttribItems.Clear();
577 }
578 }
579 if ( nNode == nEndNode ) // can also be == nStart!
580 {
581 nEndPos = aSel.Max().GetIndex();
582 nEndPortion = pParaPortion->GetTextPortions().FindPortion( nEndPos, nPortionStart );
583 }
584
585 const EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature(nIndex);
586 // start at 0, so the index is right ...
587 for ( sal_Int32 n = 0; n <= nEndPortion; n++ )
588 {
589 const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[n];
590 if ( n < nStartPortion )
591 {
592 nIndex = nIndex + rTextPortion.GetLen();
593 continue;
594 }
595
596 if ( pNextFeature && ( pNextFeature->GetStart() == nIndex ) && ( pNextFeature->GetItem()->Which() != EE_FEATURE_FIELD ) )
597 {
598 WriteItemAsRTF( *pNextFeature->GetItem(), rOutput, nNode, nIndex, aFontTable, aColorList );
599 pNextFeature = pNode->GetCharAttribs().FindFeature( pNextFeature->GetStart() + 1 );
600 }
601 else
602 {
603 aAttribItems.Clear();
604 sal_uInt16 nScriptTypeI18N = GetI18NScriptType( EditPaM( pNode, nIndex+1 ) );
605 SvtScriptType nScriptType = SvtLanguageOptions::FromI18NToSvtScriptType(nScriptTypeI18N);
606 if ( !n || IsScriptChange( EditPaM( pNode, nIndex ) ) )
607 {
608 SfxItemSet aAttribs = GetAttribs( nNode, nIndex+1, nIndex+1 );
609 aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ) ) );
610 aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ) ) );
611 aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ) ) );
612 aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_ITALIC, nScriptType ) ) );
613 aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ) ) );
614 }
615 // Insert hard attribs AFTER CJK attribs...
616 lcl_FindValidAttribs( aAttribItems, pNode, nIndex, nScriptTypeI18N );
617
618 rOutput.WriteChar( '{' );
619 if ( WriteItemListAsRTF( aAttribItems, rOutput, nNode, nIndex, aFontTable, aColorList ) )
620 rOutput.WriteChar( ' ' );
621
622 sal_Int32 nS = nIndex;
623 sal_Int32 nE = nIndex + rTextPortion.GetLen();
624 if ( n == nStartPortion )
625 nS = nStartPos;
626 if ( n == nEndPortion )
627 nE = nEndPos;
628
629 OUString aRTFStr = EditDoc::GetParaAsString( pNode, nS, nE);
630 RTFOutFuncs::Out_String( rOutput, aRTFStr, eDestEnc );
631 rOutput.WriteChar( '}' );
632 }
633 if ( bFinishPortion )
634 {
635 rOutput.WriteChar( '}' );
636 bFinishPortion = false;
637 }
638
639 nIndex = nIndex + rTextPortion.GetLen();
640 }
641
642 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PAR"\\par" ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PARD"\\pard" ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PLAIN"\\plain" );
643 rOutput << endl;
644 }
645 // RTF-trailer ...
646 rOutput.WriteCharPtr( "}}" ); // 1xparentheses paragraphs, 1xparentheses RTF document
647 rOutput.Flush();
648
649 aFontTable.clear();
650
651 return rOutput.GetError();
652}
653
654
655void ImpEditEngine::WriteItemAsRTF( const SfxPoolItem& rItem, SvStream& rOutput, sal_Int32 nPara, sal_Int32 nPos,
656 std::vector<std::unique_ptr<SvxFontItem>>& rFontTable, SvxColorList& rColorList )
657{
658 sal_uInt16 nWhich = rItem.Which();
659 switch ( nWhich )
660 {
661 case EE_PARA_WRITINGDIR:
662 {
663 const SvxFrameDirectionItem& rWritingMode = static_cast<const SvxFrameDirectionItem&>(rItem);
664 if ( rWritingMode.GetValue() == SvxFrameDirection::Horizontal_RL_TB )
665 rOutput.WriteCharPtr( "\\rtlpar" );
666 else
667 rOutput.WriteCharPtr( "\\ltrpar" );
668 }
669 break;
670 case EE_PARA_OUTLLEVEL:
671 {
672 sal_Int32 nLevel = static_cast<const SfxInt16Item&>(rItem).GetValue();
673 if( nLevel >= 0 )
674 {
675 rOutput.WriteCharPtr( "\\level" );
676 rOutput.WriteInt32AsString( nLevel );
677 }
678 }
679 break;
680 case EE_PARA_OUTLLRSPACE:
681 case EE_PARA_LRSPACE:
682 {
683 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_FI"\\fi" );
684 sal_Int32 nTxtFirst = static_cast<const SvxLRSpaceItem&>(rItem).GetTextFirstLineOffset();
685 nTxtFirst = LogicToTwips( nTxtFirst );
686 rOutput.WriteInt32AsString( nTxtFirst );
687 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_LI"\\li" );
688 sal_uInt32 nTxtLeft = static_cast< sal_uInt32 >(static_cast<const SvxLRSpaceItem&>(rItem).GetTextLeft());
689 nTxtLeft = static_cast<sal_uInt32>(LogicToTwips( nTxtLeft ));
690 rOutput.WriteInt32AsString( nTxtLeft );
691 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RI"\\ri" );
692 sal_uInt32 nTxtRight = static_cast<const SvxLRSpaceItem&>(rItem).GetRight();
693 nTxtRight = LogicToTwips( nTxtRight);
694 rOutput.WriteUInt32AsString( nTxtRight );
695 }
696 break;
697 case EE_PARA_ULSPACE:
698 {
699 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_SB"\\sb" );
700 sal_uInt32 nUpper = static_cast<const SvxULSpaceItem&>(rItem).GetUpper();
701 nUpper = static_cast<sal_uInt32>(LogicToTwips( nUpper ));
702 rOutput.WriteUInt32AsString( nUpper );
703 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_SA"\\sa" );
704 sal_uInt32 nLower = static_cast<const SvxULSpaceItem&>(rItem).GetLower();
705 nLower = LogicToTwips( nLower );
706 rOutput.WriteUInt32AsString( nLower );
707 }
708 break;
709 case EE_PARA_SBL:
710 {
711 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_SL"\\sl" );
712 sal_Int32 nVal = static_cast<const SvxLineSpacingItem&>(rItem).GetLineHeight();
713 char cMult = '0';
714 if ( static_cast<const SvxLineSpacingItem&>(rItem).GetInterLineSpaceRule() == SvxInterLineSpaceRule::Prop )
715 {
716 // From where do I get the value now?
717 // The SwRTF parser is based on a 240 Font!
718 nVal = static_cast<const SvxLineSpacingItem&>(rItem).GetPropLineSpace();
719 nVal *= 240;
720 nVal /= 100;
721 cMult = '1';
722 }
723 rOutput.WriteInt32AsString( nVal );
724 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_SLMULT"\\slmult" ).WriteChar( cMult );
725 }
726 break;
727 case EE_PARA_JUST:
728 {
729 SvxAdjust eJustification = static_cast<const SvxAdjustItem&>(rItem).GetAdjust();
730 switch ( eJustification )
731 {
732 case SvxAdjust::Center: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_QC"\\qc" );
733 break;
734 case SvxAdjust::Right: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_QR"\\qr" );
735 break;
736 default: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_QL"\\ql" );
737 break;
738 }
739 }
740 break;
741 case EE_PARA_TABS:
742 {
743 const SvxTabStopItem& rTabs = static_cast<const SvxTabStopItem&>(rItem);
744 for ( sal_uInt16 i = 0; i < rTabs.Count(); i++ )
745 {
746 const SvxTabStop& rTab = rTabs[i];
747 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TX"\\tx" );
748 rOutput.WriteInt32AsString( LogicToTwips( rTab.GetTabPos() ) );
749 }
750 }
751 break;
752 case EE_CHAR_COLOR:
753 {
754 SvxColorList::const_iterator const iter = std::find(
755 rColorList.begin(), rColorList.end(),
756 static_cast<SvxColorItem const&>(rItem).GetValue());
757 assert(iter != rColorList.end())(static_cast <bool> (iter != rColorList.end()) ? void (
0) : __assert_fail ("iter != rColorList.end()", "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
, 757, __extension__ __PRETTY_FUNCTION__))
;
758 sal_uInt32 const n = iter - rColorList.begin();
759 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CF"\\cf" );
760 rOutput.WriteUInt32AsString( n );
761 }
762 break;
763 case EE_CHAR_FONTINFO:
764 case EE_CHAR_FONTINFO_CJK:
765 case EE_CHAR_FONTINFO_CTL:
766 {
767 sal_uInt32 n = 0;
768 for (size_t i = 0; i < rFontTable.size(); ++i)
769 {
770 if (*rFontTable[i] == rItem)
771 {
772 n = i;
773 break;
774 }
775 }
776
777 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_F"\\f" );
778 rOutput.WriteUInt32AsString( n );
779 }
780 break;
781 case EE_CHAR_FONTHEIGHT:
782 case EE_CHAR_FONTHEIGHT_CJK:
783 case EE_CHAR_FONTHEIGHT_CTL:
784 {
785 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_FS"\\fs" );
786 sal_Int32 nHeight = static_cast<const SvxFontHeightItem&>(rItem).GetHeight();
787 nHeight = LogicToTwips( nHeight );
788 // Twips => HalfPoints
789 nHeight /= 10;
790 rOutput.WriteInt32AsString( nHeight );
791 }
792 break;
793 case EE_CHAR_WEIGHT:
794 case EE_CHAR_WEIGHT_CJK:
795 case EE_CHAR_WEIGHT_CTL:
796 {
797 FontWeight e = static_cast<const SvxWeightItem&>(rItem).GetWeight();
798 switch ( e )
799 {
800 case WEIGHT_BOLD: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B"\\b" ); break;
801 default: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B"\\b" ).WriteChar( '0' ); break;
802 }
803 }
804 break;
805 case EE_CHAR_UNDERLINE:
806 {
807 // Must underlined if in WordLineMode, but the information is
808 // missing here
809 FontLineStyle e = static_cast<const SvxUnderlineItem&>(rItem).GetLineStyle();
810 switch ( e )
811 {
812 case LINESTYLE_NONE: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ULNONE"\\ulnone" ); break;
813 case LINESTYLE_SINGLE: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UL"\\ul" ); break;
814 case LINESTYLE_DOUBLE: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ULDB"\\uldb" ); break;
815 case LINESTYLE_DOTTED: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ULD"\\uld" ); break;
816 default:
817 break;
818 }
819 }
820 break;
821 case EE_CHAR_OVERLINE:
822 {
823 FontLineStyle e = static_cast<const SvxOverlineItem&>(rItem).GetLineStyle();
824 switch ( e )
825 {
826 case LINESTYLE_NONE: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_OLNONE"\\olnone" ); break;
827 case LINESTYLE_SINGLE: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_OL"\\ol" ); break;
828 case LINESTYLE_DOUBLE: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_OLDB"\\oldb" ); break;
829 case LINESTYLE_DOTTED: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_OLD"\\old" ); break;
830 default:
831 break;
832 }
833 }
834 break;
835 case EE_CHAR_STRIKEOUT:
836 {
837 FontStrikeout e = static_cast<const SvxCrossedOutItem&>(rItem).GetStrikeout();
838 switch ( e )
839 {
840 case STRIKEOUT_SINGLE:
841 case STRIKEOUT_DOUBLE: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STRIKE"\\strike" ); break;
842 case STRIKEOUT_NONE: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STRIKE"\\strike" ).WriteChar( '0' ); break;
843 default:
844 break;
845 }
846 }
847 break;
848 case EE_CHAR_ITALIC:
849 case EE_CHAR_ITALIC_CJK:
850 case EE_CHAR_ITALIC_CTL:
851 {
852 FontItalic e = static_cast<const SvxPostureItem&>(rItem).GetPosture();
853 switch ( e )
854 {
855 case ITALIC_OBLIQUE:
856 case ITALIC_NORMAL: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I"\\i" ); break;
857 case ITALIC_NONE: rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I"\\i" ).WriteChar( '0' ); break;
858 default:
859 break;
860 }
861 }
862 break;
863 case EE_CHAR_OUTLINE:
864 {
865 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_OUTL"\\outl" );
866 if ( !static_cast<const SvxContourItem&>(rItem).GetValue() )
867 rOutput.WriteChar( '0' );
868 }
869 break;
870 case EE_CHAR_RELIEF:
871 {
872 FontRelief nRelief = static_cast<const SvxCharReliefItem&>(rItem).GetValue();
873 if ( nRelief == FontRelief::Embossed )
874 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_EMBO"\\embo" );
875 if ( nRelief == FontRelief::Engraved )
876 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_IMPR"\\impr" );
877 }
878 break;
879 case EE_CHAR_EMPHASISMARK:
880 {
881 FontEmphasisMark nMark = static_cast<const SvxEmphasisMarkItem&>(rItem).GetEmphasisMark();
882 if ( nMark == FontEmphasisMark::NONE )
883 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ACCNONE"\\accnone" );
884 else if ( nMark == (FontEmphasisMark::Accent | FontEmphasisMark::PosAbove) )
885 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ACCCOMMA"\\acccomma" );
886 else
887 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ACCDOT"\\accdot" );
888 }
889 break;
890 case EE_CHAR_SHADOW:
891 {
892 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_SHAD"\\shad" );
893 if ( !static_cast<const SvxShadowedItem&>(rItem).GetValue() )
894 rOutput.WriteChar( '0' );
895 }
896 break;
897 case EE_FEATURE_TAB:
898 {
899 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TAB"\\tab" );
900 }
901 break;
902 case EE_FEATURE_LINEBR:
903 {
904 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_SL"\\sl" );
905 }
906 break;
907 case EE_CHAR_KERNING:
908 {
909 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_EXPNDTW"\\expndtw" );
910 rOutput.WriteInt32AsString( LogicToTwips(
911 static_cast<const SvxKerningItem&>(rItem).GetValue() ) );
912 }
913 break;
914 case EE_CHAR_PAIRKERNING:
915 {
916 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_KERNING"\\kerning" );
917 rOutput.WriteUInt32AsString( static_cast<const SvxAutoKernItem&>(rItem).GetValue() ? 1 : 0 );
918 }
919 break;
920 case EE_CHAR_ESCAPEMENT:
921 {
922 SvxFont aFont;
923 ContentNode* pNode = aEditDoc.GetObject( nPara );
924 SeekCursor( pNode, nPos, aFont );
925 MapMode aPntMode( MapUnit::MapPoint );
926 long nFontHeight = GetRefDevice()->LogicToLogic(
927 aFont.GetFontSize(), &GetRefMapMode(), &aPntMode ).Height();
928 nFontHeight *=2; // Half Points
929 sal_uInt16 const nProp = static_cast<const SvxEscapementItem&>(rItem).GetProportionalHeight();
930 sal_uInt16 nProp100 = nProp*100; // For SWG-Token Prop in 100th percent.
931 short nEsc = static_cast<const SvxEscapementItem&>(rItem).GetEsc();
932 const FontMetric& rFontMetric = GetRefDevice()->GetFontMetric();
933 double fFontHeight = rFontMetric.GetAscent() + rFontMetric.GetDescent();
934 double fAutoAscent = .8;
935 double fAutoDescent = .2;
936 if ( fFontHeight )
937 {
938 fAutoAscent = rFontMetric.GetAscent() / fFontHeight;
939 fAutoDescent = rFontMetric.GetDescent() / fFontHeight;
940 }
941 if ( nEsc == DFLT_ESC_AUTO_SUPER(13999 +1) )
942 {
943 nEsc = fAutoAscent * (100 - nProp);
944 nProp100++; // A 1 afterwards means 'automatic'.
945 }
946 else if ( nEsc == DFLT_ESC_AUTO_SUB-(13999 +1) )
947 {
948 nEsc = fAutoDescent * -(100 - nProp);
949 nProp100++;
950 }
951 // SWG:
952 if ( nEsc )
953 {
954 rOutput.WriteCharPtr( "{\\*\\updnprop" ).WriteCharPtr( OString::number(
955 nProp100).getStr() ).WriteChar( '}' );
956 }
957 long nUpDown = nFontHeight * std::abs( nEsc ) / 100;
958 if ( nEsc < 0 )
959 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_DN"\\dn" );
960 else if ( nEsc > 0 )
961 rOutput.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UP"\\up" );
962 rOutput.WriteOString( OString::number(nUpDown) );
963 }
964 break;
965 }
966}
967
968std::unique_ptr<EditTextObject> ImpEditEngine::GetEmptyTextObject()
969{
970 EditSelection aEmptySel;
971 aEmptySel.Min() = aEditDoc.GetStartPaM();
972 aEmptySel.Max() = aEditDoc.GetStartPaM();
973
974 return CreateTextObject( aEmptySel );
975}
976
977std::unique_ptr<EditTextObject> ImpEditEngine::CreateTextObject()
978{
979 EditSelection aCompleteSelection;
980 aCompleteSelection.Min() = aEditDoc.GetStartPaM();
981 aCompleteSelection.Max() = aEditDoc.GetEndPaM();
982
983 return CreateTextObject( aCompleteSelection );
984}
985
986std::unique_ptr<EditTextObject> ImpEditEngine::CreateTextObject(const EditSelection& rSel)
987{
988 return CreateTextObject(rSel, GetEditTextObjectPool(), aStatus.AllowBigObjects(), nBigTextObjectStart);
989}
990
991std::unique_ptr<EditTextObject> ImpEditEngine::CreateTextObject( EditSelection aSel, SfxItemPool* pPool, bool bAllowBigObjects, sal_Int32 nBigObjectStart )
992{
993 std::unique_ptr<EditTextObject> pTxtObj(new EditTextObject(pPool));
994 pTxtObj->SetVertical( GetDirectVertical() );
995 pTxtObj->SetRotation( GetRotation() );
996 MapUnit eMapUnit = aEditDoc.GetItemPool().GetMetric( DEF_METRIC0 );
997 pTxtObj->mpImpl->SetMetric( static_cast<sal_uInt16>(eMapUnit) );
998 if ( pTxtObj->mpImpl->IsOwnerOfPool() )
999 pTxtObj->mpImpl->GetPool()->SetDefaultMetric( eMapUnit );
1000
1001 sal_Int32 nStartNode, nEndNode;
1002 sal_Int32 nTextPortions = 0;
1003
1004 aSel.Adjust( aEditDoc );
1005 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
1006 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
1007
1008 bool bOnlyFullParagraphs = !( aSel.Min().GetIndex() ||
1009 ( aSel.Max().GetIndex() < aSel.Max().GetNode()->Len() ) );
1010
1011 // Templates are not saved!
1012 // (Only the name and family, template itself must be in App!)
1013 pTxtObj->mpImpl->SetScriptType(GetItemScriptType(aSel));
1014
1015 // iterate over the paragraphs ...
1016 sal_Int32 nNode;
1017 for ( nNode = nStartNode; nNode <= nEndNode; nNode++ )
1018 {
1019 ContentNode* pNode = aEditDoc.GetObject( nNode );
1020 DBG_ASSERT( pNode, "Node not found: Search&Replace" )do { if (true && (!(pNode))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1020" ": "), "%s", "Node not found: Search&Replace"
); } } while (false)
;
1021
1022 if ( bOnlyFullParagraphs )
1023 {
1024 const ParaPortion* pParaPortion = GetParaPortions()[nNode];
1025 nTextPortions += pParaPortion->GetTextPortions().Count();
1026 }
1027
1028 sal_Int32 nStartPos = 0;
1029 sal_Int32 nEndPos = pNode->Len();
1030
1031 bool bEmptyPara = nEndPos == 0;
1032
1033 if ( ( nNode == nStartNode ) && !bOnlyFullParagraphs )
1034 nStartPos = aSel.Min().GetIndex();
1035 if ( ( nNode == nEndNode ) && !bOnlyFullParagraphs )
1036 nEndPos = aSel.Max().GetIndex();
1037
1038
1039 ContentInfo *pC = pTxtObj->mpImpl->CreateAndInsertContent();
1040
1041 // The paragraph attributes ...
1042 pC->GetParaAttribs().Set( pNode->GetContentAttribs().GetItems() );
1043
1044 // The StyleSheet...
1045 if ( pNode->GetStyleSheet() )
1046 {
1047 pC->SetStyle(pNode->GetStyleSheet()->GetName());
1048 pC->SetFamily(pNode->GetStyleSheet()->GetFamily());
1049 }
1050
1051 // The Text...
1052 pC->SetText(pNode->Copy(nStartPos, nEndPos-nStartPos));
1053 auto& rCAttriblist = pC->GetCharAttribs();
1054
1055 // and the Attribute...
1056 sal_uInt16 nAttr = 0;
1057 EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
1058 while ( pAttr )
1059 {
1060 // In a blank paragraph keep the attributes!
1061 if ( bEmptyPara ||
1062 ( ( pAttr->GetEnd() > nStartPos ) && ( pAttr->GetStart() < nEndPos ) ) )
1063 {
1064 std::unique_ptr<XEditAttribute> pX = pTxtObj->mpImpl->CreateAttrib(*pAttr->GetItem(), pAttr->GetStart(), pAttr->GetEnd());
1065 // Possibly Correct ...
1066 if ( ( nNode == nStartNode ) && ( nStartPos != 0 ) )
1067 {
1068 pX->GetStart() = ( pX->GetStart() > nStartPos ) ? pX->GetStart()-nStartPos : 0;
1069 pX->GetEnd() = pX->GetEnd() - nStartPos;
1070
1071 }
1072 if ( nNode == nEndNode )
1073 {
1074 if ( pX->GetEnd() > (nEndPos-nStartPos) )
1075 pX->GetEnd() = nEndPos-nStartPos;
1076 }
1077 DBG_ASSERT( pX->GetEnd() <= (nEndPos-nStartPos), "CreateBinTextObject: Attribute too long!" )do { if (true && (!(pX->GetEnd() <= (nEndPos-nStartPos
)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1077" ": "), "%s", "CreateBinTextObject: Attribute too long!"
); } } while (false)
;
1078 if ( !pX->GetLen() && !bEmptyPara )
1079 pTxtObj->mpImpl->DestroyAttrib(std::move(pX));
1080 else
1081 rCAttriblist.push_back(std::move(pX));
1082 }
1083 nAttr++;
1084 pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
1085 }
1086
1087 // If possible online spelling
1088 if ( bAllowBigObjects && bOnlyFullParagraphs && pNode->GetWrongList() )
1089 pC->SetWrongList( pNode->GetWrongList()->Clone() );
1090
1091 }
1092
1093 // Remember the portions info in case of large text objects:
1094 // sleeper set up when Olli paragraphs not hacked!
1095 if ( bAllowBigObjects && bOnlyFullParagraphs && IsFormatted() && GetUpdateMode() && ( nTextPortions >= nBigObjectStart ) )
1096 {
1097 XParaPortionList* pXList = new XParaPortionList( GetRefDevice(), aPaperSize.Width(), nStretchX, nStretchY );
1098 pTxtObj->mpImpl->SetPortionInfo(std::unique_ptr<XParaPortionList>(pXList));
1099 for ( nNode = nStartNode; nNode <= nEndNode; nNode++ )
1100 {
1101 const ParaPortion* pParaPortion = GetParaPortions()[nNode];
1102 XParaPortion* pX = new XParaPortion;
1103 pXList->push_back(pX);
1104
1105 pX->nHeight = pParaPortion->GetHeight();
1106 pX->nFirstLineOffset = pParaPortion->GetFirstLineOffset();
1107
1108 // The TextPortions
1109 sal_uInt16 nCount = pParaPortion->GetTextPortions().Count();
1110 sal_uInt16 n;
1111 for ( n = 0; n < nCount; n++ )
1112 {
1113 const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[n];
1114 TextPortion* pNew = new TextPortion( rTextPortion );
1115 pX->aTextPortions.Append(pNew);
1116 }
1117
1118 // The lines
1119 nCount = pParaPortion->GetLines().Count();
1120 for ( n = 0; n < nCount; n++ )
1121 {
1122 const EditLine& rLine = pParaPortion->GetLines()[n];
1123 EditLine* pNew = rLine.Clone();
1124 pX->aLines.Append(pNew);
1125 }
1126#ifdef DBG_UTIL
1127 sal_uInt16 nTest;
1128 int nTPLen = 0, nTxtLen = 0;
1129 for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; )
1130 nTPLen += pParaPortion->GetTextPortions()[--nTest].GetLen();
1131 for ( nTest = pParaPortion->GetLines().Count(); nTest; )
1132 nTxtLen += pParaPortion->GetLines()[--nTest].GetLen();
1133 DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "CreateBinTextObject: ParaPortion not completely formatted!" )do { if (true && (!(( nTPLen == pParaPortion->GetNode
()->Len() ) && ( nTxtLen == pParaPortion->GetNode
()->Len() )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1133" ": "), "%s", "CreateBinTextObject: ParaPortion not completely formatted!"
); } } while (false)
;
1134#endif
1135 }
1136 }
1137 return pTxtObj;
1138}
1139
1140void ImpEditEngine::SetText( const EditTextObject& rTextObject )
1141{
1142 // Since setting a text object is not undo-able!
1143 ResetUndoManager();
1144 bool _bUpdate = GetUpdateMode();
1145 bool _bUndo = IsUndoEnabled();
1146
1147 SetText( OUString() );
1148 EditPaM aPaM = aEditDoc.GetStartPaM();
1149
1150 SetUpdateMode( false );
1151 EnableUndo( false );
1152
1153 InsertText( rTextObject, EditSelection( aPaM, aPaM ) );
1154 SetVertical(rTextObject.GetDirectVertical());
1155 SetRotation(rTextObject.GetRotation());
1156
1157 DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "From where comes the Undo in SetText ?!" )do { if (true && (!(!HasUndoManager() || !GetUndoManager
().GetUndoActionCount()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1157" ": "), "%s", "From where comes the Undo in SetText ?!"
); } } while (false)
;
1158 SetUpdateMode( _bUpdate );
1159 EnableUndo( _bUndo );
1160}
1161
1162EditSelection ImpEditEngine::InsertText( const EditTextObject& rTextObject, EditSelection aSel )
1163{
1164 aSel.Adjust( aEditDoc );
1165 if ( aSel.HasRange() )
1166 aSel = ImpDeleteSelection( aSel );
1167 EditSelection aNewSel = InsertTextObject( rTextObject, aSel.Max() );
1168 return aNewSel;
1169}
1170
1171EditSelection ImpEditEngine::InsertTextObject( const EditTextObject& rTextObject, EditPaM aPaM )
1172{
1173 // Optimize: No getPos undFindParaportion, instead calculate index!
1174 EditSelection aSel( aPaM, aPaM );
1175 DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "InsertBibTextObject: Selection broken!(1)" )do { if (true && (!(!aSel.DbgIsBuggy( aEditDoc )))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1175" ": "), "%s", "InsertBibTextObject: Selection broken!(1)"
); } } while (false)
;
1176
1177 bool bUsePortionInfo = false;
1178 XParaPortionList* pPortionInfo = rTextObject.mpImpl->GetPortionInfo();
1179
1180 if ( pPortionInfo && ( static_cast<long>(pPortionInfo->GetPaperWidth()) == aPaperSize.Width() )
1181 && ( pPortionInfo->GetRefMapMode() == GetRefDevice()->GetMapMode() )
1182 && ( pPortionInfo->GetStretchX() == nStretchX )
1183 && ( pPortionInfo->GetStretchY() == nStretchY ) )
1184 {
1185 if ( (pPortionInfo->GetRefDevPtr() == GetRefDevice()) ||
1186 (pPortionInfo->RefDevIsVirtual() && GetRefDevice()->IsVirtual()) )
1187 bUsePortionInfo = true;
1188 }
1189
1190 bool bConvertMetricOfItems = false;
1191 MapUnit eSourceUnit = MapUnit(), eDestUnit = MapUnit();
1192 if (rTextObject.mpImpl->HasMetric())
1193 {
1194 eSourceUnit = static_cast<MapUnit>(rTextObject.mpImpl->GetMetric());
1195 eDestUnit = aEditDoc.GetItemPool().GetMetric( DEF_METRIC0 );
1196 if ( eSourceUnit != eDestUnit )
1197 bConvertMetricOfItems = true;
1198 }
1199
1200 // Before, paragraph count was of type sal_uInt16 so if nContents exceeded
1201 // 0xFFFF this wouldn't have worked anyway, given that nPara is used to
1202 // number paragraphs and is fearlessly incremented.
1203 sal_Int32 nContents = static_cast<sal_Int32>(rTextObject.mpImpl->GetContents().size());
1204 SAL_WARN_IF( nContents < 0, "editeng", "ImpEditEngine::InsertTextObject - contents overflow " << nContents)do { if (true && (nContents < 0)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "editeng")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "ImpEditEngine::InsertTextObject - contents overflow "
<< nContents) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1204" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImpEditEngine::InsertTextObject - contents overflow "
<< nContents), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "ImpEditEngine::InsertTextObject - contents overflow "
<< nContents; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1204" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpEditEngine::InsertTextObject - contents overflow "
<< nContents) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1204" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImpEditEngine::InsertTextObject - contents overflow "
<< nContents), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "ImpEditEngine::InsertTextObject - contents overflow "
<< nContents; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1204" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1205 sal_Int32 nPara = aEditDoc.GetPos( aPaM.GetNode() );
1206
1207 for (sal_Int32 n = 0; n < nContents; ++n, ++nPara)
1208 {
1209 const ContentInfo* pC = rTextObject.mpImpl->GetContents()[n].get();
1210 bool bNewContent = aPaM.GetNode()->Len() == 0;
1211 const sal_Int32 nStartPos = aPaM.GetIndex();
1212
1213 aPaM = ImpFastInsertText( aPaM, pC->GetText() );
1214
1215 ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() );
1216 DBG_ASSERT( pPortion, "Blind Portion in FastInsertText" )do { if (true && (!(pPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1216" ": "), "%s", "Blind Portion in FastInsertText"); }
} while (false)
;
1217 pPortion->MarkInvalid( nStartPos, pC->GetText().getLength() );
1218
1219 // Character attributes ...
1220 bool bAllreadyHasAttribs = aPaM.GetNode()->GetCharAttribs().Count() != 0;
1221 size_t nNewAttribs = pC->GetCharAttribs().size();
1222 if ( nNewAttribs )
1223 {
1224 bool bUpdateFields = false;
1225 for (size_t nAttr = 0; nAttr < nNewAttribs; ++nAttr)
1226 {
1227 const XEditAttribute& rX = *pC->GetCharAttribs()[nAttr];
1228 // Can happen when paragraphs > 16K, it is simply wrapped.
1229 //TODO! Still true, still needed?
1230 if ( rX.GetEnd() <= aPaM.GetNode()->Len() )
1231 {
1232 if ( !bAllreadyHasAttribs || rX.IsFeature() )
1233 {
1234 // Normal attributes then go faster ...
1235 // Features shall not be inserted through
1236 // EditDoc:: InsertAttrib, using FastInsertText they are
1237 // already in the flow
1238 DBG_ASSERT( rX.GetEnd() <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribute too large!" )do { if (true && (!(rX.GetEnd() <= aPaM.GetNode()->
Len()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), (
"legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1238" ": "), "%s", "InsertBinTextObject: Attribute too large!"
); } } while (false)
;
1239 EditCharAttrib* pAttr;
1240 if ( !bConvertMetricOfItems )
1241 pAttr = MakeCharAttrib( aEditDoc.GetItemPool(), *(rX.GetItem()), rX.GetStart()+nStartPos, rX.GetEnd()+nStartPos );
1242 else
1243 {
1244 std::unique_ptr<SfxPoolItem> pNew(rX.GetItem()->Clone());
1245 ConvertItem( pNew, eSourceUnit, eDestUnit );
1246 pAttr = MakeCharAttrib( aEditDoc.GetItemPool(), *pNew, rX.GetStart()+nStartPos, rX.GetEnd()+nStartPos );
1247 }
1248 DBG_ASSERT( pAttr->GetEnd() <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribute does not fit! (1)" )do { if (true && (!(pAttr->GetEnd() <= aPaM.GetNode
()->Len()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1248" ": "), "%s", "InsertBinTextObject: Attribute does not fit! (1)"
); } } while (false)
;
1249 aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttr );
1250 if ( pAttr->Which() == EE_FEATURE_FIELD )
1251 bUpdateFields = true;
1252 }
1253 else
1254 {
1255 DBG_ASSERT( rX.GetEnd()+nStartPos <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribute does not fit! (2)" )do { if (true && (!(rX.GetEnd()+nStartPos <= aPaM.
GetNode()->Len()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1255" ": "), "%s", "InsertBinTextObject: Attribute does not fit! (2)"
); } } while (false)
;
1256 // Tabs and other Features can not be inserted through InsertAttrib:
1257 aEditDoc.InsertAttrib( aPaM.GetNode(), rX.GetStart()+nStartPos, rX.GetEnd()+nStartPos, *rX.GetItem() );
1258 }
1259 }
1260 }
1261 if ( bUpdateFields )
1262 UpdateFields();
1263
1264 // Otherwise, quick format => no attributes!
1265 pPortion->MarkSelectionInvalid( nStartPos );
1266 }
1267
1268#if OSL_DEBUG_LEVEL1 > 0 && !defined NDEBUG
1269 CharAttribList::DbgCheckAttribs(aPaM.GetNode()->GetCharAttribs());
1270#endif
1271
1272 bool bParaAttribs = false;
1273 if ( bNewContent || ( ( n > 0 ) && ( n < (nContents-1) ) ) )
1274 {
1275 // only style and ParaAttribs when new paragraph, or
1276 // completely internal ...
1277 bParaAttribs = pC->GetParaAttribs().Count() != 0;
1278 if ( GetStyleSheetPool() && pC->GetStyle().getLength() )
1279 {
1280 SfxStyleSheet* pStyle = static_cast<SfxStyleSheet*>(GetStyleSheetPool()->Find( pC->GetStyle(), pC->GetFamily() ));
1281 DBG_ASSERT( pStyle, "InsertBinTextObject - Style not found!" )do { if (true && (!(pStyle))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1281" ": "), "%s", "InsertBinTextObject - Style not found!"
); } } while (false)
;
1282 SetStyleSheet( nPara, pStyle );
1283 }
1284 if ( !bConvertMetricOfItems )
1285 SetParaAttribs( aEditDoc.GetPos( aPaM.GetNode() ), pC->GetParaAttribs() );
1286 else
1287 {
1288 SfxItemSet aAttribs( GetEmptyItemSet() );
1289 ConvertAndPutItems( aAttribs, pC->GetParaAttribs(), &eSourceUnit, &eDestUnit );
1290 SetParaAttribs( aEditDoc.GetPos( aPaM.GetNode() ), aAttribs );
1291 }
1292 if ( bNewContent && bUsePortionInfo )
1293 {
1294 const XParaPortion& rXP = (*pPortionInfo)[n];
1295 ParaPortion* pParaPortion = GetParaPortions()[ nPara ];
1296 DBG_ASSERT( pParaPortion, "InsertBinTextObject: ParaPortion?" )do { if (true && (!(pParaPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1296" ": "), "%s", "InsertBinTextObject: ParaPortion?")
; } } while (false)
;
1297 pParaPortion->nHeight = rXP.nHeight;
1298 pParaPortion->nFirstLineOffset = rXP.nFirstLineOffset;
1299 pParaPortion->bForceRepaint = true;
1300 pParaPortion->SetValid(); // Do not format
1301
1302 // The Text Portions
1303 pParaPortion->GetTextPortions().Reset();
1304 sal_uInt16 nCount = rXP.aTextPortions.Count();
1305 for ( sal_uInt16 _n = 0; _n < nCount; _n++ )
1306 {
1307 const TextPortion& rTextPortion = rXP.aTextPortions[_n];
1308 TextPortion* pNew = new TextPortion( rTextPortion );
1309 pParaPortion->GetTextPortions().Insert(_n, pNew);
1310 }
1311
1312 // The lines
1313 pParaPortion->GetLines().Reset();
1314 nCount = rXP.aLines.Count();
1315 for ( sal_uInt16 m = 0; m < nCount; m++ )
1316 {
1317 const EditLine& rLine = rXP.aLines[m];
1318 EditLine* pNew = rLine.Clone();
1319 pNew->SetInvalid(); // Paint again!
1320 pParaPortion->GetLines().Insert(m, pNew);
1321 }
1322#ifdef DBG_UTIL
1323 sal_uInt16 nTest;
1324 int nTPLen = 0, nTxtLen = 0;
1325 for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; )
1326 nTPLen += pParaPortion->GetTextPortions()[--nTest].GetLen();
1327 for ( nTest = pParaPortion->GetLines().Count(); nTest; )
1328 nTxtLen += pParaPortion->GetLines()[--nTest].GetLen();
1329 DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "InsertBinTextObject: ParaPortion not completely formatted!" )do { if (true && (!(( nTPLen == pParaPortion->GetNode
()->Len() ) && ( nTxtLen == pParaPortion->GetNode
()->Len() )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1329" ": "), "%s", "InsertBinTextObject: ParaPortion not completely formatted!"
); } } while (false)
;
1330#endif
1331 }
1332 }
1333 if ( !bParaAttribs ) // DefFont is not calculated for FastInsertParagraph
1334 {
1335 aPaM.GetNode()->GetCharAttribs().GetDefFont() = aEditDoc.GetDefFont();
1336 if ( aStatus.UseCharAttribs() )
1337 aPaM.GetNode()->CreateDefFont();
1338 }
1339
1340 if ( bNewContent && GetStatus().DoOnlineSpelling() && pC->GetWrongList() )
1341 {
1342 aPaM.GetNode()->SetWrongList( pC->GetWrongList()->Clone() );
1343 }
1344
1345 // Wrap when followed by other ...
1346 if ( n < ( nContents-1) )
1347 {
1348 if ( bNewContent )
1349 aPaM = ImpFastInsertParagraph( nPara+1 );
1350 else
1351 aPaM = ImpInsertParaBreak( aPaM, false );
1352 }
1353 }
1354
1355 aSel.Max() = aPaM;
1356 DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "InsertBibTextObject: Selection broken!(1)" )do { if (true && (!(!aSel.DbgIsBuggy( aEditDoc )))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1356" ": "), "%s", "InsertBibTextObject: Selection broken!(1)"
); } } while (false)
;
1357 return aSel;
1358}
1359
1360void ImpEditEngine::GetAllMisspellRanges( std::vector<editeng::MisspellRanges>& rRanges ) const
1361{
1362 std::vector<editeng::MisspellRanges> aRanges;
1363 const EditDoc& rDoc = GetEditDoc();
1364 for (sal_Int32 i = 0, n = rDoc.Count(); i < n; ++i)
1365 {
1366 const ContentNode* pNode = rDoc.GetObject(i);
1367 const WrongList* pWrongList = pNode->GetWrongList();
1368 if (!pWrongList)
1369 continue;
1370
1371 aRanges.emplace_back(i, pWrongList->GetRanges());
1372 }
1373
1374 aRanges.swap(rRanges);
1375}
1376
1377void ImpEditEngine::SetAllMisspellRanges( const std::vector<editeng::MisspellRanges>& rRanges )
1378{
1379 EditDoc& rDoc = GetEditDoc();
1380 for (auto const& rParaRanges : rRanges)
1381 {
1382 ContentNode* pNode = rDoc.GetObject(rParaRanges.mnParagraph);
1383 if (!pNode)
1384 continue;
1385
1386 pNode->CreateWrongList();
1387 WrongList* pWrongList = pNode->GetWrongList();
1388 pWrongList->SetRanges(rParaRanges.maRanges);
1389 }
1390}
1391
1392LanguageType ImpEditEngine::GetLanguage( const EditPaM& rPaM, sal_Int32* pEndPos ) const
1393{
1394 short nScriptTypeI18N = GetI18NScriptType( rPaM, pEndPos ); // pEndPos will be valid now, pointing to ScriptChange or NodeLen
1395 SvtScriptType nScriptType = SvtLanguageOptions::FromI18NToSvtScriptType(nScriptTypeI18N);
1396 sal_uInt16 nLangId = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType );
1397 const SvxLanguageItem* pLangItem = &static_cast<const SvxLanguageItem&>(rPaM.GetNode()->GetContentAttribs().GetItem( nLangId ));
1398 const EditCharAttrib* pAttr = rPaM.GetNode()->GetCharAttribs().FindAttrib( nLangId, rPaM.GetIndex() );
1399 if ( pAttr )
1400 pLangItem = static_cast<const SvxLanguageItem*>(pAttr->GetItem());
1401
1402 if ( pEndPos && pAttr && ( pAttr->GetEnd() < *pEndPos ) )
1403 *pEndPos = pAttr->GetEnd();
1404
1405 return pLangItem->GetLanguage();
1406}
1407
1408css::lang::Locale ImpEditEngine::GetLocale( const EditPaM& rPaM ) const
1409{
1410 return LanguageTag( GetLanguage( rPaM ) ).getLocale();
1411}
1412
1413Reference< XSpellChecker1 > const & ImpEditEngine::GetSpeller()
1414{
1415 if ( !xSpeller.is() )
1416 xSpeller = LinguMgr::GetSpellChecker();
1417 return xSpeller;
1418}
1419
1420
1421void ImpEditEngine::CreateSpellInfo( bool bMultipleDocs )
1422{
1423 if (!pSpellInfo)
1424 pSpellInfo.reset( new SpellInfo );
1425 else
1426 *pSpellInfo = SpellInfo(); // reset to default values
1427
1428 pSpellInfo->bMultipleDoc = bMultipleDocs;
1429 // always spell draw objects completely, starting at the top.
1430 // (spelling in only a selection or not starting with the top requires
1431 // further changes elsewhere to work properly)
1432 pSpellInfo->aSpellStart = EPaM();
1433 pSpellInfo->aSpellTo = EPaM( EE_PARA_NOT_FOUND((sal_Int32) 0x7FFFFFFF), EE_INDEX_NOT_FOUND((sal_Int32) 0x7FFFFFFF) );
1434}
1435
1436
1437EESpellState ImpEditEngine::Spell( EditView* pEditView, bool bMultipleDoc )
1438{
1439 SAL_WARN_IF( !xSpeller.is(), "editeng", "No Spell checker set!" )do { if (true && (!xSpeller.is())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "editeng")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "No Spell checker set!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1439" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "No Spell checker set!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"No Spell checker set!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1439" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "No Spell checker set!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1439" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "No Spell checker set!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"No Spell checker set!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1439" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1440
1441 if ( !xSpeller.is() )
1442 return EESpellState::NoSpeller;
1443
1444 aOnlineSpellTimer.Stop();
1445
1446 // In MultipleDoc always from the front / rear ...
1447 if ( bMultipleDoc )
1448 {
1449 pEditView->pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() );
1450 }
1451
1452 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() );
1453 CreateSpellInfo( bMultipleDoc );
1454
1455 bool bIsStart = false;
1456 if ( bMultipleDoc )
1457 bIsStart = true; // Accessible from the front or from behind ...
1458 else if ( CreateEPaM( aEditDoc.GetStartPaM() ) == pSpellInfo->aSpellStart )
1459 bIsStart = true;
1460
1461 vcl::Window* pParent = Application::GetDefDialogParent();
1462 std::unique_ptr<EditSpellWrapper> pWrp(new EditSpellWrapper(pParent ? pParent->GetFrameWeld() : nullptr,
1463 bIsStart, pEditView ));
1464 pWrp->SpellDocument();
1465 pWrp.reset();
1466
1467 if ( !bMultipleDoc )
1468 {
1469 pEditView->pImpEditView->DrawSelectionXOR();
1470 if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() )
1471 aCurSel.Max().SetIndex( aCurSel.Max().GetNode()->Len() );
1472 aCurSel.Min() = aCurSel.Max();
1473 pEditView->pImpEditView->SetEditSelection( aCurSel );
1474 pEditView->pImpEditView->DrawSelectionXOR();
1475 pEditView->ShowCursor( true, false );
1476 }
1477 EESpellState eState = pSpellInfo->eState;
1478 pSpellInfo.reset();
1479 return eState;
1480}
1481
1482
1483bool ImpEditEngine::HasConvertibleTextPortion( LanguageType nSrcLang )
1484{
1485 bool bHasConvTxt = false;
1486
1487 sal_Int32 nParas = pEditEngine->GetParagraphCount();
1488 for (sal_Int32 k = 0; k < nParas; ++k)
1489 {
1490 std::vector<sal_Int32> aPortions;
1491 pEditEngine->GetPortions( k, aPortions );
1492 for ( size_t nPos = 0; nPos < aPortions.size(); ++nPos )
1493 {
1494 sal_Int32 nEnd = aPortions[ nPos ];
1495 sal_Int32 nStart = nPos > 0 ? aPortions[ nPos - 1 ] : 0;
1496
1497 // if the paragraph is not empty we need to increase the index
1498 // by one since the attribute of the character left to the
1499 // specified position is evaluated.
1500 if (nEnd > nStart) // empty para?
1501 ++nStart;
1502 LanguageType nLangFound = pEditEngine->GetLanguage( k, nStart );
1503#ifdef DEBUG
1504 lang::Locale aLocale( LanguageTag::convertToLocale( nLangFound ) );
1505#endif
1506 bHasConvTxt = (nSrcLang == nLangFound) ||
1507 (editeng::HangulHanjaConversion::IsChinese( nLangFound ) &&
1508 editeng::HangulHanjaConversion::IsChinese( nSrcLang ));
1509 if (bHasConvTxt)
1510 return bHasConvTxt;
1511 }
1512 }
1513
1514 return bHasConvTxt;
1515}
1516
1517
1518void ImpEditEngine::Convert( EditView* pEditView,
1519 LanguageType nSrcLang, LanguageType nDestLang, const vcl::Font *pDestFont,
1520 sal_Int32 nOptions, bool bIsInteractive, bool bMultipleDoc )
1521{
1522 // modified version of ImpEditEngine::Spell
1523
1524 // In MultipleDoc always from the front / rear ...
1525 if ( bMultipleDoc )
1526 pEditView->pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() );
1527
1528
1529 // initialize pConvInfo
1530 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() );
1531 aCurSel.Adjust( aEditDoc );
1532 pConvInfo.reset(new ConvInfo);
1533 pConvInfo->bMultipleDoc = bMultipleDoc;
1534 pConvInfo->aConvStart = CreateEPaM( aCurSel.Min() );
1535
1536 // if it is not just a selection and we are about to begin
1537 // with the current conversion for the very first time
1538 // we need to find the start of the current (initial)
1539 // convertible unit in order for the text conversion to give
1540 // the correct result for that. Since it is easier to obtain
1541 // the start of the word we use that though.
1542 if (!aCurSel.HasRange() && ImplGetBreakIterator().is())
1543 {
1544 EditPaM aWordStartPaM( SelectWord( aCurSel, i18n::WordType::DICTIONARY_WORD ).Min() );
1545
1546 // since #118246 / #117803 still occurs if the cursor is placed
1547 // between the two chinese characters to be converted (because both
1548 // of them are words on their own!) using the word boundary here does
1549 // not work. Thus since chinese conversion is not interactive we start
1550 // at the begin of the paragraph to solve the problem, i.e. have the
1551 // TextConversion service get those characters together in the same call.
1552 pConvInfo->aConvStart.nIndex = editeng::HangulHanjaConversion::IsChinese( nSrcLang )
1553 ? 0 : aWordStartPaM.GetIndex();
1554 }
1555
1556 pConvInfo->aConvContinue = pConvInfo->aConvStart;
1557
1558 bool bIsStart = false;
1559 if ( bMultipleDoc )
1560 bIsStart = true; // Accessible from the front or from behind ...
1561 else if ( CreateEPaM( aEditDoc.GetStartPaM() ) == pConvInfo->aConvStart )
1562 bIsStart = true;
1563
1564 TextConvWrapper aWrp( pEditView->GetWindow()->GetFrameWeld(),
1565 ::comphelper::getProcessComponentContext(),
1566 LanguageTag::convertToLocale( nSrcLang ),
1567 LanguageTag::convertToLocale( nDestLang ),
1568 pDestFont,
1569 nOptions, bIsInteractive,
1570 bIsStart, pEditView );
1571
1572
1573 //!! optimization does not work since when update mode is false
1574 //!! the object is 'lying' about it portions, paragraphs,
1575 //!! EndPaM... later on.
1576 //!! Should not be a great problem since text boxes or cells in
1577 //!! Calc usually have only a rather short text.
1578 //
1579 // disallow formatting, updating the view, ... while
1580 // non-interactively converting the document. (saves time)
1581 //if (!bIsInteractive)
1582 // SetUpdateMode( sal_False );
1583
1584 aWrp.Convert();
1585
1586 //if (!bIsInteractive)
1587 //SetUpdateMode( sal_True, 0, sal_True );
1588
1589 if ( !bMultipleDoc )
1590 {
1591 pEditView->pImpEditView->DrawSelectionXOR();
1592 if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() )
1593 aCurSel.Max().SetIndex( aCurSel.Max().GetNode()->Len() );
1594 aCurSel.Min() = aCurSel.Max();
1595 pEditView->pImpEditView->SetEditSelection( aCurSel );
1596 pEditView->pImpEditView->DrawSelectionXOR();
1597 pEditView->ShowCursor( true, false );
1598 }
1599 pConvInfo.reset();
1600}
1601
1602
1603void ImpEditEngine::SetLanguageAndFont(
1604 const ESelection &rESel,
1605 LanguageType nLang, sal_uInt16 nLangWhichId,
1606 const vcl::Font *pFont, sal_uInt16 nFontWhichId )
1607{
1608 ESelection aOldSel = pActiveView->GetSelection();
1609 pActiveView->SetSelection( rESel );
1610
1611 // set new language attribute
1612 SfxItemSet aNewSet( pActiveView->GetEmptyItemSet() );
1613 aNewSet.Put( SvxLanguageItem( nLang, nLangWhichId ) );
1614
1615 // new font to be set?
1616 DBG_ASSERT( pFont, "target font missing?" )do { if (true && (!(pFont))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1616" ": "), "%s", "target font missing?"); } } while (
false)
;
1617 if (pFont)
1618 {
1619 // set new font attribute
1620 SvxFontItem aFontItem = static_cast<const SvxFontItem&>( aNewSet.Get( nFontWhichId ) );
1621 aFontItem.SetFamilyName( pFont->GetFamilyName());
1622 aFontItem.SetFamily( pFont->GetFamilyType());
1623 aFontItem.SetStyleName( pFont->GetStyleName());
1624 aFontItem.SetPitch( pFont->GetPitch());
1625 aFontItem.SetCharSet( pFont->GetCharSet() );
1626 aNewSet.Put( aFontItem );
1627 }
1628
1629 // apply new attributes
1630 pActiveView->SetAttribs( aNewSet );
1631
1632 pActiveView->SetSelection( aOldSel );
1633}
1634
1635
1636void ImpEditEngine::ImpConvert( OUString &rConvTxt, LanguageType &rConvTxtLang,
1637 EditView* pEditView, LanguageType nSrcLang, const ESelection &rConvRange,
1638 bool bAllowImplicitChangesForNotConvertibleText,
1639 LanguageType nTargetLang, const vcl::Font *pTargetFont )
1640{
1641 // modified version of ImpEditEngine::ImpSpell
1642
1643 // looks for next convertible text portion to be passed on to the wrapper
1644
1645 OUString aRes;
1646 LanguageType nResLang = LANGUAGE_NONELanguageType(0x00FF);
1647
1648 EditPaM aPos( CreateEditPaM( pConvInfo->aConvContinue ) );
1649 EditSelection aCurSel( aPos, aPos );
1650
1651 OUString aWord;
1652
1653 while (aRes.isEmpty())
1654 {
1655 // empty paragraph found that needs to have language and font set?
1656 if (bAllowImplicitChangesForNotConvertibleText &&
1657 pEditEngine->GetText( pConvInfo->aConvContinue.nPara ).isEmpty())
1658 {
1659 sal_Int32 nPara = pConvInfo->aConvContinue.nPara;
1660 ESelection aESel( nPara, 0, nPara, 0 );
1661 // see comment for below same function call
1662 SetLanguageAndFont( aESel,
1663 nTargetLang, EE_CHAR_LANGUAGE_CJK,
1664 pTargetFont, EE_CHAR_FONTINFO_CJK );
1665 }
1666
1667
1668 if (pConvInfo->aConvContinue.nPara == pConvInfo->aConvTo.nPara &&
1669 pConvInfo->aConvContinue.nIndex >= pConvInfo->aConvTo.nIndex)
1670 break;
1671
1672 sal_Int32 nAttribStart = -1;
1673 sal_Int32 nAttribEnd = -1;
1674 sal_Int32 nCurPos = -1;
1675 EPaM aCurStart = CreateEPaM( aCurSel.Min() );
1676 std::vector<sal_Int32> aPortions;
1677 pEditEngine->GetPortions( aCurStart.nPara, aPortions );
1678 for ( size_t nPos = 0; nPos < aPortions.size(); ++nPos )
1679 {
1680 const sal_Int32 nEnd = aPortions[ nPos ];
1681 const sal_Int32 nStart = nPos > 0 ? aPortions[ nPos - 1 ] : 0;
1682
1683 // the language attribute is obtained from the left character
1684 // (like usually all other attributes)
1685 // thus we usually have to add 1 in order to get the language
1686 // of the text right to the cursor position
1687 const sal_Int32 nLangIdx = nEnd > nStart ? nStart + 1 : nStart;
1688 LanguageType nLangFound = pEditEngine->GetLanguage( aCurStart.nPara, nLangIdx );
1689#ifdef DEBUG
1690 lang::Locale aLocale( LanguageTag::convertToLocale( nLangFound ) );
1691#endif
1692 bool bLangOk = (nLangFound == nSrcLang) ||
1693 (editeng::HangulHanjaConversion::IsChinese( nLangFound ) &&
1694 editeng::HangulHanjaConversion::IsChinese( nSrcLang ));
1695
1696 if (nAttribEnd>=0) // start already found?
1697 {
1698 DBG_ASSERT(nEnd >= aCurStart.nIndex, "error while scanning attributes (a)" )do { if (true && (!(nEnd >= aCurStart.nIndex))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1698" ": "), "%s", "error while scanning attributes (a)"
); } } while (false)
;
1699 DBG_ASSERT(nEnd >= nAttribEnd, "error while scanning attributes (b)" )do { if (true && (!(nEnd >= nAttribEnd))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1699" ": "), "%s", "error while scanning attributes (b)"
); } } while (false)
;
1700 if (/*nEnd >= aCurStart.nIndex &&*/ nLangFound == nResLang)
1701 nAttribEnd = nEnd;
1702 else // language attrib has changed
1703 break;
1704 }
1705 if (nAttribStart<0 && // start not yet found?
1706 nEnd > aCurStart.nIndex && bLangOk)
1707 {
1708 nAttribStart = nStart;
1709 nAttribEnd = nEnd;
1710 nResLang = nLangFound;
1711 }
1712 //! the list of portions may have changed compared to the previous
1713 //! call to this function (because of possibly changed language
1714 //! attribute!)
1715 //! But since we don't want to start in the already processed part
1716 //! we clip the start accordingly.
1717 if (nAttribStart >= 0 && nAttribStart < aCurStart.nIndex)
1718 {
1719 nAttribStart = aCurStart.nIndex;
1720 }
1721
1722 // check script type to the right of the start of the current portion
1723 EditPaM aPaM( CreateEditPaM( EPaM(aCurStart.nPara, nLangIdx) ) );
1724 bool bIsAsianScript = (i18n::ScriptType::ASIAN == GetI18NScriptType( aPaM ));
1725 // not yet processed text part with for conversion
1726 // not suitable language found that needs to be changed?
1727 if (bAllowImplicitChangesForNotConvertibleText &&
1728 !bLangOk && !bIsAsianScript && nEnd > aCurStart.nIndex)
1729 {
1730 ESelection aESel( aCurStart.nPara, nStart, aCurStart.nPara, nEnd );
1731 // set language and font to target language and font of conversion
1732 //! Now this especially includes all non convertible text e.g.
1733 //! spaces, empty paragraphs and western text.
1734 // This is in order for every *new* text entered at *any* position to
1735 // have the correct language and font attributes set.
1736 SetLanguageAndFont( aESel,
1737 nTargetLang, EE_CHAR_LANGUAGE_CJK,
1738 pTargetFont, EE_CHAR_FONTINFO_CJK );
1739 }
1740
1741 nCurPos = nEnd;
1742 }
1743
1744 if (nAttribStart>=0 && nAttribEnd>=0)
1745 {
1746 aCurSel.Min().SetIndex( nAttribStart );
1747 aCurSel.Max().SetIndex( nAttribEnd );
1748 }
1749 else if (nCurPos>=0)
1750 {
1751 // set selection to end of scanned text
1752 // (used to set the position where to continue from later on)
1753 aCurSel.Min().SetIndex( nCurPos );
1754 aCurSel.Max().SetIndex( nCurPos );
1755 }
1756
1757 if ( !pConvInfo->bConvToEnd )
1758 {
1759 EPaM aEPaM( CreateEPaM( aCurSel.Min() ) );
1760 if ( !( aEPaM < pConvInfo->aConvTo ) )
1761 break;
1762 }
1763
1764 // clip selected word to the converted area
1765 // (main use when conversion starts/ends **within** a word)
1766 EditPaM aPaM( CreateEditPaM( pConvInfo->aConvStart ) );
1767 if (pConvInfo->bConvToEnd &&
1768 aCurSel.Min().GetNode() == aPaM.GetNode() &&
1769 aCurSel.Min().GetIndex() < aPaM.GetIndex())
1770 aCurSel.Min().SetIndex( aPaM.GetIndex() );
1771 aPaM = CreateEditPaM( pConvInfo->aConvContinue );
1772 if (aCurSel.Min().GetNode() == aPaM.GetNode() &&
1773 aCurSel.Min().GetIndex() < aPaM.GetIndex())
1774 aCurSel.Min().SetIndex( aPaM.GetIndex() );
1775 aPaM = CreateEditPaM( pConvInfo->aConvTo );
1776 if ((!pConvInfo->bConvToEnd || rConvRange.HasRange())&&
1777 aCurSel.Max().GetNode() == aPaM.GetNode() &&
1778 aCurSel.Max().GetIndex() > aPaM.GetIndex())
1779 aCurSel.Max().SetIndex( aPaM.GetIndex() );
1780
1781 aWord = GetSelected( aCurSel );
1782
1783 if ( !aWord.isEmpty() /* && bLangOk */)
1784 aRes = aWord;
1785
1786 // move to next word/paragraph if necessary
1787 if ( aRes.isEmpty() )
1788 aCurSel = WordRight( aCurSel.Min(), css::i18n::WordType::DICTIONARY_WORD );
1789
1790 pConvInfo->aConvContinue = CreateEPaM( aCurSel.Max() );
1791 }
1792
1793 pEditView->pImpEditView->DrawSelectionXOR();
1794 pEditView->pImpEditView->SetEditSelection( aCurSel );
1795 pEditView->pImpEditView->DrawSelectionXOR();
1796 pEditView->ShowCursor( true, false );
1797
1798 rConvTxt = aRes;
1799 if ( !rConvTxt.isEmpty() )
1800 rConvTxtLang = nResLang;
1801}
1802
1803
1804Reference< XSpellAlternatives > ImpEditEngine::ImpSpell( EditView* pEditView )
1805{
1806 DBG_ASSERT( xSpeller.is(), "No spell checker set!" )do { if (true && (!(xSpeller.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1806" ": "), "%s", "No spell checker set!"); } } while (
false)
;
1807
1808 ContentNode* pLastNode = aEditDoc.GetObject( aEditDoc.Count()-1 );
1809 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() );
1810 aCurSel.Min() = aCurSel.Max();
1811
1812 Reference< XSpellAlternatives > xSpellAlt;
1813 Sequence< PropertyValue > aEmptySeq;
1814 while (!xSpellAlt.is())
1815 {
1816 // Known (most likely) bug: If SpellToCurrent, the current has to be
1817 // corrected at each replacement, otherwise it may not fit exactly in
1818 // the end ...
1819 if ( pSpellInfo->bSpellToEnd || pSpellInfo->bMultipleDoc )
1820 {
1821 if ( aCurSel.Max().GetNode() == pLastNode )
1822 {
1823 if ( aCurSel.Max().GetIndex() >= pLastNode->Len() )
1824 break;
1825 }
1826 }
1827 else if ( !pSpellInfo->bSpellToEnd )
1828 {
1829 EPaM aEPaM( CreateEPaM( aCurSel.Max() ) );
1830 if ( !( aEPaM < pSpellInfo->aSpellTo ) )
1831 break;
1832 }
1833
1834 aCurSel = SelectWord( aCurSel, css::i18n::WordType::DICTIONARY_WORD );
1835 OUString aWord = GetSelected( aCurSel );
1836
1837 // If afterwards a dot, this must be handed over!
1838 // If an abbreviation ...
1839 if ( !aWord.isEmpty() && ( aCurSel.Max().GetIndex() < aCurSel.Max().GetNode()->Len() ) )
1840 {
1841 sal_Unicode cNext = aCurSel.Max().GetNode()->GetChar( aCurSel.Max().GetIndex() );
1842 if ( cNext == '.' )
1843 {
1844 aCurSel.Max().SetIndex( aCurSel.Max().GetIndex()+1 );
1845 aWord += OUStringChar(cNext);
1846 }
1847 }
1848
1849 if ( !aWord.isEmpty() )
1850 {
1851 LanguageType eLang = GetLanguage( aCurSel.Max() );
1852 SvxSpellWrapper::CheckSpellLang( xSpeller, eLang );
1853 xSpellAlt = xSpeller->spell( aWord, static_cast<sal_uInt16>(eLang), aEmptySeq );
1854 }
1855
1856 if ( !xSpellAlt.is() )
1857 aCurSel = WordRight( aCurSel.Min(), css::i18n::WordType::DICTIONARY_WORD );
1858 else
1859 pSpellInfo->eState = EESpellState::ErrorFound;
1860 }
1861
1862 pEditView->pImpEditView->DrawSelectionXOR();
1863 pEditView->pImpEditView->SetEditSelection( aCurSel );
1864 pEditView->pImpEditView->DrawSelectionXOR();
1865 pEditView->ShowCursor( true, false );
1866 return xSpellAlt;
1867}
1868
1869Reference< XSpellAlternatives > ImpEditEngine::ImpFindNextError(EditSelection& rSelection)
1870{
1871 EditSelection aCurSel( rSelection.Min() );
1872
1873 Reference< XSpellAlternatives > xSpellAlt;
1874 Sequence< PropertyValue > aEmptySeq;
1875 while (!xSpellAlt.is())
1876 {
1877 //check if the end of the selection has been reached
1878 {
1879 EPaM aEPaM( CreateEPaM( aCurSel.Max() ) );
1880 if ( !( aEPaM < CreateEPaM( rSelection.Max()) ) )
1881 break;
1882 }
1883
1884 aCurSel = SelectWord( aCurSel, css::i18n::WordType::DICTIONARY_WORD );
1885 OUString aWord = GetSelected( aCurSel );
1886
1887 // If afterwards a dot, this must be handed over!
1888 // If an abbreviation ...
1889 if ( !aWord.isEmpty() && ( aCurSel.Max().GetIndex() < aCurSel.Max().GetNode()->Len() ) )
1890 {
1891 sal_Unicode cNext = aCurSel.Max().GetNode()->GetChar( aCurSel.Max().GetIndex() );
1892 if ( cNext == '.' )
1893 {
1894 aCurSel.Max().SetIndex( aCurSel.Max().GetIndex()+1 );
1895 aWord += OUStringChar(cNext);
1896 }
1897 }
1898
1899 if ( !aWord.isEmpty() )
1900 xSpellAlt = xSpeller->spell( aWord, static_cast<sal_uInt16>(GetLanguage( aCurSel.Max() )), aEmptySeq );
1901
1902 if ( !xSpellAlt.is() )
1903 aCurSel = WordRight( aCurSel.Min(), css::i18n::WordType::DICTIONARY_WORD );
1904 else
1905 {
1906 pSpellInfo->eState = EESpellState::ErrorFound;
1907 rSelection = aCurSel;
1908 }
1909 }
1910 return xSpellAlt;
1911}
1912
1913bool ImpEditEngine::SpellSentence(EditView const & rEditView,
1914 svx::SpellPortions& rToFill )
1915{
1916 bool bRet = false;
1917 EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() );
1918 if(!pSpellInfo)
1919 CreateSpellInfo( true );
1920 pSpellInfo->aCurSentenceStart = aCurSel.Min();
1921 DBG_ASSERT( xSpeller.is(), "No spell checker set!" )do { if (true && (!(xSpeller.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "1921" ": "), "%s", "No spell checker set!"); } } while (
false)
;
1922 pSpellInfo->aLastSpellPortions.clear();
1923 pSpellInfo->aLastSpellContentSelections.clear();
1924 rToFill.clear();
1925 //if no selection previously exists the range is extended to the end of the object
1926 if (!aCurSel.HasRange())
1927 {
1928 ContentNode* pLastNode = aEditDoc.GetObject( aEditDoc.Count()-1);
1929 aCurSel.Max() = EditPaM(pLastNode, pLastNode->Len());
1930 }
1931 // check for next error in aCurSel and set aCurSel to that one if any was found
1932 Reference< XSpellAlternatives > xAlt = ImpFindNextError(aCurSel);
1933 if (xAlt.is())
1934 {
1935 bRet = true;
1936 //find the sentence boundaries
1937 EditSelection aSentencePaM = SelectSentence(aCurSel);
1938 //make sure that the sentence is never smaller than the error range!
1939 if(aSentencePaM.Max().GetIndex() < aCurSel.Max().GetIndex())
1940 aSentencePaM.Max() = aCurSel.Max();
1941 //add the portion preceding the error
1942 EditSelection aStartSelection(aSentencePaM.Min(), aCurSel.Min());
1943 if(aStartSelection.HasRange())
1944 AddPortionIterated(rEditView, aStartSelection, nullptr, rToFill);
1945 //add the error portion
1946 AddPortionIterated(rEditView, aCurSel, xAlt, rToFill);
1947 //find the end of the sentence
1948 //search for all errors in the rest of the sentence and add all the portions
1949 do
1950 {
1951 EditSelection aNextSel(aCurSel.Max(), aSentencePaM.Max());
1952 xAlt = ImpFindNextError(aNextSel);
1953 if(xAlt.is())
1954 {
1955 //add the part between the previous and the current error
1956 AddPortionIterated(rEditView, EditSelection(aCurSel.Max(), aNextSel.Min()), nullptr, rToFill);
1957 //add the current error
1958 AddPortionIterated(rEditView, aNextSel, xAlt, rToFill);
1959 }
1960 else
1961 AddPortionIterated(rEditView, EditSelection(aCurSel.Max(), aSentencePaM.Max()), xAlt, rToFill);
1962 aCurSel = aNextSel;
1963 }
1964 while( xAlt.is() );
1965
1966 //set the selection to the end of the current sentence
1967 rEditView.pImpEditView->SetEditSelection(aSentencePaM.Max());
1968 }
1969 return bRet;
1970}
1971
1972// Adds one portion to the SpellPortions
1973void ImpEditEngine::AddPortion(
1974 const EditSelection& rSel,
1975 const uno::Reference< XSpellAlternatives >& xAlt,
1976 svx::SpellPortions& rToFill,
1977 bool bIsField)
1978{
1979 if(!rSel.HasRange())
1980 return;
1981
1982 svx::SpellPortion aPortion;
1983 aPortion.sText = GetSelected( rSel );
1984 aPortion.eLanguage = GetLanguage( rSel.Min() );
1985 aPortion.xAlternatives = xAlt;
1986 aPortion.bIsField = bIsField;
1987 rToFill.push_back(aPortion);
1988
1989 //save the spelled portions for later use
1990 pSpellInfo->aLastSpellPortions.push_back(aPortion);
1991 pSpellInfo->aLastSpellContentSelections.push_back(rSel);
1992}
1993
1994// Adds one or more portions of text to the SpellPortions depending on language changes
1995void ImpEditEngine::AddPortionIterated(
1996 EditView const & rEditView,
1997 const EditSelection& rSel,
1998 const Reference< XSpellAlternatives >& xAlt,
1999 svx::SpellPortions& rToFill)
2000{
2001 if (!rSel.HasRange())
2002 return;
2003
2004 if(xAlt.is())
2005 {
2006 AddPortion(rSel, xAlt, rToFill, false);
2007 }
2008 else
2009 {
2010 //iterate and search for language attribute changes
2011 //save the start and end positions
2012 bool bTest = rSel.Min().GetIndex() <= rSel.Max().GetIndex();
2013 EditPaM aStart(bTest ? rSel.Min() : rSel.Max());
2014 EditPaM aEnd(bTest ? rSel.Max() : rSel.Min());
2015 //iterate over the text to find changes in language
2016 //set the mark equal to the point
2017 EditPaM aCursor(aStart);
2018 rEditView.pImpEditView->SetEditSelection( aCursor );
2019 LanguageType eStartLanguage = GetLanguage( aCursor );
2020 //search for a field attribute at the beginning - only the end position
2021 //of this field is kept to end a portion at that position
2022 const EditCharAttrib* pFieldAttr = aCursor.GetNode()->GetCharAttribs().
2023 FindFeature( aCursor.GetIndex() );
2024 bool bIsField = pFieldAttr &&
2025 pFieldAttr->GetStart() == aCursor.GetIndex() &&
2026 pFieldAttr->GetStart() != pFieldAttr->GetEnd() &&
2027 pFieldAttr->Which() == EE_FEATURE_FIELD;
2028 sal_Int32 nEndField = bIsField ? pFieldAttr->GetEnd() : -1;
2029 do
2030 {
2031 aCursor = CursorRight( aCursor);
2032 //determine whether a field and has been reached
2033 bool bIsEndField = nEndField == aCursor.GetIndex();
2034 //search for a new field attribute
2035 const EditCharAttrib* _pFieldAttr = aCursor.GetNode()->GetCharAttribs().
2036 FindFeature( aCursor.GetIndex() );
2037 bIsField = _pFieldAttr &&
2038 _pFieldAttr->GetStart() == aCursor.GetIndex() &&
2039 _pFieldAttr->GetStart() != _pFieldAttr->GetEnd() &&
2040 _pFieldAttr->Which() == EE_FEATURE_FIELD;
2041 //on every new field move the end position
2042 if (bIsField)
2043 nEndField = _pFieldAttr->GetEnd();
2044
2045 LanguageType eCurLanguage = GetLanguage( aCursor );
2046 if(eCurLanguage != eStartLanguage || bIsField || bIsEndField)
2047 {
2048 eStartLanguage = eCurLanguage;
2049 //go one step back - the cursor currently selects the first character
2050 //with a different language
2051 //create a selection from start to the current Cursor
2052 EditSelection aSelection(aStart, aCursor);
2053 AddPortion(aSelection, xAlt, rToFill, bIsEndField);
2054 aStart = aCursor;
2055 }
2056 }
2057 while(aCursor.GetIndex() < aEnd.GetIndex());
2058 EditSelection aSelection(aStart, aCursor);
2059 AddPortion(aSelection, xAlt, rToFill, bIsField);
2060 }
2061}
2062
2063void ImpEditEngine::ApplyChangedSentence(EditView const & rEditView,
2064 const svx::SpellPortions& rNewPortions,
2065 bool bRecheck )
2066{
2067 // Note: rNewPortions.size() == 0 is valid and happens when the whole
2068 // sentence got removed in the dialog
2069
2070 DBG_ASSERT(pSpellInfo, "pSpellInfo not initialized")do { if (true && (!(pSpellInfo))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2070" ": "), "%s", "pSpellInfo not initialized"); } } while
(false)
;
2071 if (!pSpellInfo || pSpellInfo->aLastSpellPortions.empty()) // no portions -> no text to be changed
2072 return;
2073
2074 // get current paragraph length to calculate later on how the sentence length changed,
2075 // in order to place the cursor at the end of the sentence again
2076 EditSelection aOldSel( rEditView.pImpEditView->GetEditSelection() );
2077 sal_Int32 nOldLen = aOldSel.Max().GetNode()->Len();
2078
2079 UndoActionStart( EDITUNDO_INSERT111 );
2080 if(pSpellInfo->aLastSpellPortions.size() == rNewPortions.size())
2081 {
2082 DBG_ASSERT( !rNewPortions.empty(), "rNewPortions should not be empty here" )do { if (true && (!(!rNewPortions.empty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2082" ": "), "%s", "rNewPortions should not be empty here"
); } } while (false)
;
2083 DBG_ASSERT( pSpellInfo->aLastSpellPortions.size() == pSpellInfo->aLastSpellContentSelections.size(),do { if (true && (!(pSpellInfo->aLastSpellPortions
.size() == pSpellInfo->aLastSpellContentSelections.size())
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2084" ": "), "%s", "aLastSpellPortions and aLastSpellContentSelections size mismatch"
); } } while (false)
2084 "aLastSpellPortions and aLastSpellContentSelections size mismatch" )do { if (true && (!(pSpellInfo->aLastSpellPortions
.size() == pSpellInfo->aLastSpellContentSelections.size())
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2084" ": "), "%s", "aLastSpellPortions and aLastSpellContentSelections size mismatch"
); } } while (false)
;
2085
2086 //the simple case: the same number of elements on both sides
2087 //each changed element has to be applied to the corresponding source element
2088 svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.end();
2089 svx::SpellPortions::const_iterator aCurrentOldPortion = pSpellInfo->aLastSpellPortions.end();
2090 SpellContentSelections::const_iterator aCurrentOldPosition = pSpellInfo->aLastSpellContentSelections.end();
2091 bool bSetToEnd = false;
2092 do
2093 {
2094 --aCurrentNewPortion;
2095 --aCurrentOldPortion;
2096 --aCurrentOldPosition;
2097 //set the cursor to the end of the sentence - necessary to
2098 //resume there at the next step
2099 if(!bSetToEnd)
2100 {
2101 bSetToEnd = true;
2102 rEditView.pImpEditView->SetEditSelection( aCurrentOldPosition->Max() );
2103 }
2104
2105 SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( aCurrentNewPortion->eLanguage );
2106 sal_uInt16 nLangWhichId = EE_CHAR_LANGUAGE;
2107 switch(nScriptType)
2108 {
2109 case SvtScriptType::ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break;
2110 case SvtScriptType::COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break;
2111 default: break;
2112 }
2113 if(aCurrentNewPortion->sText != aCurrentOldPortion->sText)
2114 {
2115 //change text and apply language
2116 SfxItemSet aSet( aEditDoc.GetItemPool(), {{nLangWhichId, nLangWhichId}});
2117 aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId));
2118 SetAttribs( *aCurrentOldPosition, aSet );
2119 ImpInsertText( *aCurrentOldPosition, aCurrentNewPortion->sText );
2120 }
2121 else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
2122 {
2123 //apply language
2124 SfxItemSet aSet( aEditDoc.GetItemPool(), {{nLangWhichId, nLangWhichId}});
2125 aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId));
2126 SetAttribs( *aCurrentOldPosition, aSet );
2127 }
2128 }
2129 while(aCurrentNewPortion != rNewPortions.begin());
2130 }
2131 else
2132 {
2133 DBG_ASSERT( !pSpellInfo->aLastSpellContentSelections.empty(), "aLastSpellContentSelections should not be empty here" )do { if (true && (!(!pSpellInfo->aLastSpellContentSelections
.empty()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2133" ": "), "%s", "aLastSpellContentSelections should not be empty here"
); } } while (false)
;
2134
2135 //select the complete sentence
2136 SpellContentSelections::const_iterator aCurrentEndPosition = pSpellInfo->aLastSpellContentSelections.end();
2137 --aCurrentEndPosition;
2138 SpellContentSelections::const_iterator aCurrentStartPosition = pSpellInfo->aLastSpellContentSelections.begin();
2139 EditSelection aAllSentence(aCurrentStartPosition->Min(), aCurrentEndPosition->Max());
2140
2141 //delete the sentence completely
2142 ImpDeleteSelection( aAllSentence );
2143 EditPaM aCurrentPaM = aAllSentence.Min();
2144 for(const auto& rCurrentNewPortion : rNewPortions)
2145 {
2146 //set the language attribute
2147 LanguageType eCurLanguage = GetLanguage( aCurrentPaM );
2148 if(eCurLanguage != rCurrentNewPortion.eLanguage)
2149 {
2150 SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( rCurrentNewPortion.eLanguage );
2151 sal_uInt16 nLangWhichId = EE_CHAR_LANGUAGE;
2152 switch(nScriptType)
2153 {
2154 case SvtScriptType::ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break;
2155 case SvtScriptType::COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break;
2156 default: break;
2157 }
2158 SfxItemSet aSet( aEditDoc.GetItemPool(), {{nLangWhichId, nLangWhichId}});
2159 aSet.Put(SvxLanguageItem(rCurrentNewPortion.eLanguage, nLangWhichId));
2160 SetAttribs( aCurrentPaM, aSet );
2161 }
2162 //insert the new string and set the cursor to the end of the inserted string
2163 aCurrentPaM = ImpInsertText( aCurrentPaM , rCurrentNewPortion.sText );
2164 }
2165 }
2166 UndoActionEnd();
2167
2168 EditPaM aNext;
2169 if (bRecheck)
2170 aNext = pSpellInfo->aCurSentenceStart;
2171 else
2172 {
2173 // restore cursor position to the end of the modified sentence.
2174 // (This will define the continuation position for spell/grammar checking)
2175 // First: check if the sentence/para length changed
2176 const sal_Int32 nDelta = rEditView.pImpEditView->GetEditSelection().Max().GetNode()->Len() - nOldLen;
2177 const sal_Int32 nEndOfSentence = aOldSel.Max().GetIndex() + nDelta;
2178 aNext = EditPaM( aOldSel.Max().GetNode(), nEndOfSentence );
2179 }
2180 rEditView.pImpEditView->SetEditSelection( aNext );
2181
2182 FormatAndUpdate();
2183 aEditDoc.SetModified(true);
2184}
2185
2186void ImpEditEngine::PutSpellingToSentenceStart( EditView const & rEditView )
2187{
2188 if( pSpellInfo && !pSpellInfo->aLastSpellContentSelections.empty() )
2189 {
2190 rEditView.pImpEditView->SetEditSelection( pSpellInfo->aLastSpellContentSelections.begin()->Min() );
2191 }
2192}
2193
2194
2195void ImpEditEngine::DoOnlineSpelling( ContentNode* pThisNodeOnly, bool bSpellAtCursorPos, bool bInterruptible )
2196{
2197 /*
2198 It will iterate over all the paragraphs, paragraphs with only
2199 invalidated wrong list will be checked ...
2200
2201 All the words are checked in the invalidated region. Is a word wrong,
2202 but not in the wrong list, or vice versa, the range of the word will be
2203 invalidated
2204 (no Invalidate, but if only transitions wrong from right =>, simple Paint,
2205 even out properly with VDev on transitions from wrong => right)
2206 */
2207
2208 if ( !xSpeller.is() )
2209 return;
2210
2211 EditPaM aCursorPos;
2212 if( pActiveView && !bSpellAtCursorPos )
2213 {
2214 aCursorPos = pActiveView->pImpEditView->GetEditSelection().Max();
2215 }
2216
2217 bool bRestartTimer = false;
2218
2219 ContentNode* pLastNode = aEditDoc.GetObject( aEditDoc.Count() - 1 );
2220 sal_Int32 nNodes = GetEditDoc().Count();
2221 sal_Int32 nInvalids = 0;
2222 Sequence< PropertyValue > aEmptySeq;
2223 for ( sal_Int32 n = 0; n < nNodes; n++ )
2224 {
2225 ContentNode* pNode = GetEditDoc().GetObject( n );
2226 if ( pThisNodeOnly )
2227 pNode = pThisNodeOnly;
2228
2229 pNode->EnsureWrongList();
2230 if (!pNode->GetWrongList()->IsValid())
2231 {
2232 WrongList* pWrongList = pNode->GetWrongList();
2233 const size_t nInvStart = pWrongList->GetInvalidStart();
2234 const size_t nInvEnd = pWrongList->GetInvalidEnd();
2235
2236 sal_Int32 nPaintFrom = -1;
2237 sal_Int32 nPaintTo = 0;
2238 bool bSimpleRepaint = true;
2239
2240 pWrongList->SetValid();
2241
2242 EditPaM aPaM( pNode, nInvStart );
2243 EditSelection aSel( aPaM, aPaM );
2244 while ( aSel.Max().GetNode() == pNode )
2245 {
2246 if ( ( o3tl::make_unsigned(aSel.Min().GetIndex()) > nInvEnd )
2247 || ( ( aSel.Max().GetNode() == pLastNode ) && ( aSel.Max().GetIndex() >= pLastNode->Len() ) ) )
2248 break; // Document end or end of invalid region
2249
2250 aSel = SelectWord( aSel, i18n::WordType::DICTIONARY_WORD );
2251 // If afterwards a dot, this must be handed over!
2252 // If an abbreviation ...
2253 bool bDottAdded = false;
2254 if ( aSel.Max().GetIndex() < aSel.Max().GetNode()->Len() )
2255 {
2256 sal_Unicode cNext = aSel.Max().GetNode()->GetChar( aSel.Max().GetIndex() );
2257 if ( cNext == '.' )
2258 {
2259 aSel.Max().SetIndex( aSel.Max().GetIndex()+1 );
2260 bDottAdded = true;
2261 }
2262 }
2263 OUString aWord = GetSelected(aSel);
2264
2265 bool bChanged = false;
2266 if (!aWord.isEmpty())
2267 {
2268 const sal_Int32 nWStart = aSel.Min().GetIndex();
2269 const sal_Int32 nWEnd = aSel.Max().GetIndex();
2270 if ( !xSpeller->isValid( aWord, static_cast<sal_uInt16>(GetLanguage( EditPaM( aSel.Min().GetNode(), nWStart+1 ) )), aEmptySeq ) )
2271 {
2272 // Check if already marked correctly...
2273 const sal_Int32 nXEnd = bDottAdded ? nWEnd -1 : nWEnd;
2274 if ( !pWrongList->HasWrong( nWStart, nXEnd ) )
2275 {
2276 // Mark Word as wrong...
2277 // But only when not at Cursor-Position...
2278 bool bCursorPos = false;
2279 if ( aCursorPos.GetNode() == pNode )
2280 {
2281 if ( ( nWStart <= aCursorPos.GetIndex() ) && nWEnd >= aCursorPos.GetIndex() )
2282 bCursorPos = true;
2283 }
2284 if ( bCursorPos )
2285 {
2286 // Then continue to mark as invalid ...
2287 pWrongList->ResetInvalidRange(nWStart, nWEnd);
2288 bRestartTimer = true;
2289 }
2290 else
2291 {
2292 // It may be that the Wrongs in the list are not
2293 // spanning exactly over words because the
2294 // WordDelimiters during expansion are not
2295 // evaluated.
2296 pWrongList->InsertWrong(nWStart, nXEnd);
2297 bChanged = true;
2298 }
2299 }
2300 }
2301 else
2302 {
2303 // Check if not marked as wrong
2304 if ( pWrongList->HasAnyWrong( nWStart, nWEnd ) )
2305 {
2306 pWrongList->ClearWrongs( nWStart, nWEnd, pNode );
2307 bSimpleRepaint = false;
2308 bChanged = true;
2309 }
2310 }
2311 if ( bChanged )
2312 {
2313 if ( nPaintFrom<0 )
2314 nPaintFrom = nWStart;
2315 nPaintTo = nWEnd;
2316 }
2317 }
2318
2319 EditPaM aLastEnd( aSel.Max() );
2320 aSel = WordRight( aSel.Max(), i18n::WordType::DICTIONARY_WORD );
2321 if ( bChanged && ( aSel.Min().GetNode() == pNode ) &&
2322 ( aSel.Min().GetIndex()-aLastEnd.GetIndex() > 1 ) )
2323 {
2324 // If two words are separated by more than one blank, it
2325 // can happen that when splitting a Wrongs the start of
2326 // the second word is before the actually word
2327 pWrongList->ClearWrongs( aLastEnd.GetIndex(), aSel.Min().GetIndex(), pNode );
2328 }
2329 }
2330
2331 // Invalidate?
2332 if ( nPaintFrom>=0 )
2333 {
2334 aStatus.GetStatusWord() |= EditStatusFlags::WRONGWORDCHANGED;
2335 CallStatusHdl();
2336
2337 if (!aEditViews.empty())
2338 {
2339 // For SimpleRepaint one was painted over a range without
2340 // reaching VDEV, but then one would have to intersect, c
2341 // clipping, ... over all views. Probably not worthwhile.
2342 EditPaM aStartPaM( pNode, nPaintFrom );
2343 EditPaM aEndPaM( pNode, nPaintTo );
2344 tools::Rectangle aStartCursor( PaMtoEditCursor( aStartPaM ) );
2345 tools::Rectangle aEndCursor( PaMtoEditCursor( aEndPaM ) );
2346 DBG_ASSERT( aInvalidRect.IsEmpty(), "InvalidRect set!" )do { if (true && (!(aInvalidRect.IsEmpty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2346" ": "), "%s", "InvalidRect set!"); } } while (false
)
;
2347 aInvalidRect.SetLeft( 0 );
2348 aInvalidRect.SetRight( GetPaperSize().Width() );
2349 aInvalidRect.SetTop( aStartCursor.Top() );
2350 aInvalidRect.SetBottom( aEndCursor.Bottom() );
2351 if ( pActiveView && pActiveView->HasSelection() )
2352 {
2353 // Then no output through VDev.
2354 UpdateViews();
2355 }
2356 else if ( bSimpleRepaint )
2357 {
2358 for (EditView* pView : aEditViews)
2359 {
2360 tools::Rectangle aClipRect( aInvalidRect );
2361 aClipRect.Intersection( pView->GetVisArea() );
2362 if ( !aClipRect.IsEmpty() )
2363 {
2364 // convert to window coordinates...
2365 aClipRect.SetPos( pView->pImpEditView->GetWindowPos( aClipRect.TopLeft() ) );
2366 pView->pImpEditView->InvalidateAtWindow(aClipRect);
2367 }
2368 }
2369 }
2370 else
2371 {
2372 UpdateViews( pActiveView );
2373 }
2374 aInvalidRect = tools::Rectangle();
2375 }
2376 }
2377 // After two corrected nodes give up the control...
2378 nInvalids++;
2379 if ( bInterruptible && ( nInvalids >= 2 ) )
2380 {
2381 bRestartTimer = true;
2382 break;
2383 }
2384 }
2385
2386 if ( pThisNodeOnly )
2387 break;
2388 }
2389 if ( bRestartTimer )
2390 aOnlineSpellTimer.Start();
2391}
2392
2393
2394EESpellState ImpEditEngine::HasSpellErrors()
2395{
2396 DBG_ASSERT( xSpeller.is(), "No spell checker set!" )do { if (true && (!(xSpeller.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2396" ": "), "%s", "No spell checker set!"); } } while (
false)
;
2397
2398 ContentNode* pLastNode = aEditDoc.GetObject( aEditDoc.Count() - 1 );
2399 EditSelection aCurSel( aEditDoc.GetStartPaM() );
2400
2401 OUString aWord;
2402 Reference< XSpellAlternatives > xSpellAlt;
2403 Sequence< PropertyValue > aEmptySeq;
2404 while ( !xSpellAlt.is() )
2405 {
2406 if ( ( aCurSel.Max().GetNode() == pLastNode ) &&
2407 ( aCurSel.Max().GetIndex() >= pLastNode->Len() ) )
2408 {
2409 return EESpellState::Ok;
2410 }
2411
2412 aCurSel = SelectWord( aCurSel, css::i18n::WordType::DICTIONARY_WORD );
2413 aWord = GetSelected( aCurSel );
2414 if ( !aWord.isEmpty() )
2415 {
2416 LanguageType eLang = GetLanguage( aCurSel.Max() );
2417 SvxSpellWrapper::CheckSpellLang( xSpeller, eLang );
2418 xSpellAlt = xSpeller->spell( aWord, static_cast<sal_uInt16>(eLang), aEmptySeq );
2419 }
2420 aCurSel = WordRight( aCurSel.Max(), css::i18n::WordType::DICTIONARY_WORD );
2421 }
2422
2423 return EESpellState::ErrorFound;
2424}
2425
2426void ImpEditEngine::ClearSpellErrors()
2427{
2428 aEditDoc.ClearSpellErrors();
2429}
2430
2431EESpellState ImpEditEngine::StartThesaurus( EditView* pEditView )
2432{
2433 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() );
2434 if ( !aCurSel.HasRange() )
1
Assuming the condition is false
2
Taking false branch
2435 aCurSel = SelectWord( aCurSel, css::i18n::WordType::DICTIONARY_WORD );
2436 OUString aWord( GetSelected( aCurSel ) );
2437
2438 Reference< XThesaurus > xThes( LinguMgr::GetThesaurus() );
2439 if (!xThes.is())
3
Taking false branch
2440 return EESpellState::ErrorFound;
2441
2442 EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
2443 ScopedVclPtr<AbstractThesaurusDialog> xDlg(pFact->CreateThesaurusDialog(pEditView->GetWindow()->GetFrameWeld(), xThes,
4
Calling constructor for 'ScopedVclPtr<AbstractThesaurusDialog>'
11
Returning from constructor for 'ScopedVclPtr<AbstractThesaurusDialog>'
2444 aWord, GetLanguage( aCurSel.Max() ) ));
12
Calling implicit destructor for 'VclPtr<AbstractThesaurusDialog>'
13
Calling '~Reference'
20
Returning from '~Reference'
21
Returning from destructor for 'VclPtr<AbstractThesaurusDialog>'
2445 if (xDlg->Execute() == RET_OK)
22
Calling 'VclPtr::operator->'
2446 {
2447 // Replace Word...
2448 pEditView->pImpEditView->DrawSelectionXOR();
2449 pEditView->pImpEditView->SetEditSelection( aCurSel );
2450 pEditView->pImpEditView->DrawSelectionXOR();
2451 pEditView->InsertText(xDlg->GetWord());
2452 pEditView->ShowCursor(true, false);
2453 }
2454
2455 return EESpellState::Ok;
2456}
2457
2458sal_Int32 ImpEditEngine::StartSearchAndReplace( EditView* pEditView, const SvxSearchItem& rSearchItem )
2459{
2460 sal_Int32 nFound = 0;
2461
2462 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() );
2463
2464 // FIND_ALL is not possible without multiple selection.
2465 if ( ( rSearchItem.GetCommand() == SvxSearchCmd::FIND ) ||
2466 ( rSearchItem.GetCommand() == SvxSearchCmd::FIND_ALL ) )
2467 {
2468 if ( Search( rSearchItem, pEditView ) )
2469 nFound++;
2470 }
2471 else if ( rSearchItem.GetCommand() == SvxSearchCmd::REPLACE )
2472 {
2473 // The word is selected if the user not altered the selection
2474 // in between:
2475 if ( aCurSel.HasRange() )
2476 {
2477 pEditView->InsertText( rSearchItem.GetReplaceString() );
2478 nFound = 1;
2479 }
2480 else
2481 if( Search( rSearchItem, pEditView ) )
2482 nFound = 1;
2483 }
2484 else if ( rSearchItem.GetCommand() == SvxSearchCmd::REPLACE_ALL )
2485 {
2486 // The Writer replaces all front beginning to end ...
2487 SvxSearchItem aTmpItem( rSearchItem );
2488 aTmpItem.SetBackward( false );
2489
2490 pEditView->pImpEditView->DrawSelectionXOR();
2491
2492 aCurSel.Adjust( aEditDoc );
2493 EditPaM aStartPaM = aTmpItem.GetSelection() ? aCurSel.Min() : aEditDoc.GetStartPaM();
2494 EditSelection aFoundSel( aCurSel.Max() );
2495 bool bFound = ImpSearch( aTmpItem, aCurSel, aStartPaM, aFoundSel );
2496 if ( bFound )
2497 UndoActionStart( EDITUNDO_REPLACEALL119 );
2498 while ( bFound )
2499 {
2500 nFound++;
2501 aStartPaM = ImpInsertText( aFoundSel, rSearchItem.GetReplaceString() );
2502 bFound = ImpSearch( aTmpItem, aCurSel, aStartPaM, aFoundSel );
2503 }
2504 if ( nFound )
2505 {
2506 EditPaM aNewPaM( aFoundSel.Max() );
2507 if ( aNewPaM.GetIndex() > aNewPaM.GetNode()->Len() )
2508 aNewPaM.SetIndex( aNewPaM.GetNode()->Len() );
2509 pEditView->pImpEditView->SetEditSelection( aNewPaM );
2510 FormatAndUpdate( pEditView );
2511 UndoActionEnd();
2512 }
2513 else
2514 {
2515 pEditView->pImpEditView->DrawSelectionXOR();
2516 pEditView->ShowCursor( true, false );
2517 }
2518 }
2519 return nFound;
2520}
2521
2522bool ImpEditEngine::Search( const SvxSearchItem& rSearchItem, EditView* pEditView )
2523{
2524 EditSelection aSel( pEditView->pImpEditView->GetEditSelection() );
2525 aSel.Adjust( aEditDoc );
2526 EditPaM aStartPaM( aSel.Max() );
2527 if ( rSearchItem.GetSelection() && !rSearchItem.GetBackward() )
2528 aStartPaM = aSel.Min();
2529
2530 EditSelection aFoundSel;
2531 bool bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel );
2532 if ( bFound && ( aFoundSel == aSel ) ) // For backwards-search
2533 {
2534 aStartPaM = aSel.Min();
2535 bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel );
2536 }
2537
2538 pEditView->pImpEditView->DrawSelectionXOR();
2539 if ( bFound )
2540 {
2541 // First, set the minimum, so the whole word is in the visible range.
2542 pEditView->pImpEditView->SetEditSelection( aFoundSel.Min() );
2543 pEditView->ShowCursor( true, false );
2544 pEditView->pImpEditView->SetEditSelection( aFoundSel );
2545 }
2546 else
2547 pEditView->pImpEditView->SetEditSelection( aSel.Max() );
2548
2549 pEditView->pImpEditView->DrawSelectionXOR();
2550 pEditView->ShowCursor( true, false );
2551 return bFound;
2552}
2553
2554bool ImpEditEngine::ImpSearch( const SvxSearchItem& rSearchItem,
2555 const EditSelection& rSearchSelection, const EditPaM& rStartPos, EditSelection& rFoundSel )
2556{
2557 i18nutil::SearchOptions2 aSearchOptions( rSearchItem.GetSearchOptions() );
2558 aSearchOptions.Locale = GetLocale( rStartPos );
2559
2560 bool bBack = rSearchItem.GetBackward();
2561 bool bSearchInSelection = rSearchItem.GetSelection();
2562 sal_Int32 nStartNode = aEditDoc.GetPos( rStartPos.GetNode() );
2563 sal_Int32 nEndNode;
2564 if ( bSearchInSelection )
2565 {
2566 nEndNode = aEditDoc.GetPos( bBack ? rSearchSelection.Min().GetNode() : rSearchSelection.Max().GetNode() );
2567 }
2568 else
2569 {
2570 nEndNode = bBack ? 0 : aEditDoc.Count()-1;
2571 }
2572
2573 utl::TextSearch aSearcher( aSearchOptions );
2574
2575 // iterate over the paragraphs ...
2576 for ( sal_Int32 nNode = nStartNode;
2577 bBack ? ( nNode >= nEndNode ) : ( nNode <= nEndNode) ;
2578 bBack ? nNode-- : nNode++ )
2579 {
2580 // For backwards-search if nEndNode = 0:
2581 if ( nNode < 0 )
2582 return false;
2583
2584 ContentNode* pNode = aEditDoc.GetObject( nNode );
2585
2586 sal_Int32 nStartPos = 0;
2587 sal_Int32 nEndPos = pNode->GetExpandedLen();
2588 if ( nNode == nStartNode )
2589 {
2590 if ( bBack )
2591 nEndPos = rStartPos.GetIndex();
2592 else
2593 nStartPos = rStartPos.GetIndex();
2594 }
2595 if ( ( nNode == nEndNode ) && bSearchInSelection )
2596 {
2597 if ( bBack )
2598 nStartPos = rSearchSelection.Min().GetIndex();
2599 else
2600 nEndPos = rSearchSelection.Max().GetIndex();
2601 }
2602
2603 // Searching ...
2604 OUString aParaStr( pNode->GetExpandedText() );
2605 bool bFound = false;
2606 if ( bBack )
2607 {
2608 sal_Int32 nTemp;
2609 nTemp = nStartPos;
2610 nStartPos = nEndPos;
2611 nEndPos = nTemp;
2612
2613 bFound = aSearcher.SearchBackward( aParaStr, &nStartPos, &nEndPos);
2614 }
2615 else
2616 {
2617 bFound = aSearcher.SearchForward( aParaStr, &nStartPos, &nEndPos);
2618 }
2619 if ( bFound )
2620 {
2621 pNode->UnExpandPositions( nStartPos, nEndPos );
2622
2623 rFoundSel.Min().SetNode( pNode );
2624 rFoundSel.Min().SetIndex( nStartPos );
2625 rFoundSel.Max().SetNode( pNode );
2626 rFoundSel.Max().SetIndex( nEndPos );
2627 return true;
2628 }
2629 }
2630 return false;
2631}
2632
2633bool ImpEditEngine::HasText( const SvxSearchItem& rSearchItem )
2634{
2635 SvxSearchItem aTmpItem( rSearchItem );
2636 aTmpItem.SetBackward( false );
2637 aTmpItem.SetSelection( false );
2638
2639 EditPaM aStartPaM( aEditDoc.GetStartPaM() );
2640 EditSelection aDummySel( aStartPaM );
2641 EditSelection aFoundSel;
2642 return ImpSearch( aTmpItem, aDummySel, aStartPaM, aFoundSel );
2643}
2644
2645void ImpEditEngine::SetAutoCompleteText(const OUString& rStr, bool bClearTipWindow)
2646{
2647 aAutoCompleteText = rStr;
2648 if ( bClearTipWindow && pActiveView )
2649 Help::ShowQuickHelp( pActiveView->GetWindow(), tools::Rectangle(), OUString() );
2650}
2651
2652namespace
2653{
2654 struct eeTransliterationChgData
2655 {
2656 sal_Int32 nStart;
2657 sal_Int32 nLen;
2658 EditSelection aSelection;
2659 OUString aNewText;
2660 uno::Sequence< sal_Int32 > aOffsets;
2661 };
2662}
2663
2664EditSelection ImpEditEngine::TransliterateText( const EditSelection& rSelection, TransliterationFlags nTransliterationMode )
2665{
2666 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
2667 if (!_xBI.is())
2668 return rSelection;
2669
2670 EditSelection aSel( rSelection );
2671 aSel.Adjust( aEditDoc );
2672
2673 if ( !aSel.HasRange() )
2674 aSel = SelectWord( aSel );
2675
2676 // tdf#107176: if there's still no range, just return aSel
2677 if ( !aSel.HasRange() )
2678 return aSel;
2679
2680 EditSelection aNewSel( aSel );
2681
2682 const sal_Int32 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
2683 const sal_Int32 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
2684
2685 bool bChanges = false;
2686 bool bLenChanged = false;
2687 std::unique_ptr<EditUndoTransliteration> pUndo;
2688
2689 utl::TransliterationWrapper aTransliterationWrapper( ::comphelper::getProcessComponentContext(), nTransliterationMode );
2690 bool bConsiderLanguage = aTransliterationWrapper.needLanguageForTheMode();
2691
2692 for ( sal_Int32 nNode = nStartNode; nNode <= nEndNode; nNode++ )
2693 {
2694 ContentNode* pNode = aEditDoc.GetObject( nNode );
2695 const OUString& aNodeStr = pNode->GetString();
2696 const sal_Int32 nStartPos = nNode==nStartNode ? aSel.Min().GetIndex() : 0;
2697 const sal_Int32 nEndPos = nNode==nEndNode ? aSel.Max().GetIndex() : aNodeStr.getLength(); // can also be == nStart!
2698
2699 sal_Int32 nCurrentStart = nStartPos;
2700 sal_Int32 nCurrentEnd = nEndPos;
2701 LanguageType nLanguage = LANGUAGE_SYSTEMLanguageType(0x0000);
2702
2703 // since we don't use Hiragana/Katakana or half-width/full-width transliterations here
2704 // it is fine to use ANYWORD_IGNOREWHITESPACES. (ANY_WORD btw is broken and will
2705 // occasionally miss words in consecutive sentences). Also with ANYWORD_IGNOREWHITESPACES
2706 // text like 'just-in-time' will be converted to 'Just-In-Time' which seems to be the
2707 // proper thing to do.
2708 const sal_Int16 nWordType = i18n::WordType::ANYWORD_IGNOREWHITESPACES;
2709
2710 //! In order to have less trouble with changing text size, e.g. because
2711 //! of ligatures or German small sz being resolved, we need to process
2712 //! the text replacements from end to start.
2713 //! This way the offsets for the yet to be changed words will be
2714 //! left unchanged by the already replaced text.
2715 //! For this we temporarily save the changes to be done in this vector
2716 std::vector< eeTransliterationChgData > aChanges;
2717 eeTransliterationChgData aChgData;
2718
2719 if (nTransliterationMode == TransliterationFlags::TITLE_CASE)
2720 {
2721 // for 'capitalize every word' we need to iterate over each word
2722
2723 i18n::Boundary aSttBndry;
2724 i18n::Boundary aEndBndry;
2725 aSttBndry = _xBI->getWordBoundary(
2726 aNodeStr, nStartPos,
2727 GetLocale( EditPaM( pNode, nStartPos + 1 ) ),
2728 nWordType, true /*prefer forward direction*/);
2729 aEndBndry = _xBI->getWordBoundary(
2730 aNodeStr, nEndPos,
2731 GetLocale( EditPaM( pNode, nEndPos + 1 ) ),
2732 nWordType, false /*prefer backward direction*/);
2733
2734 // prevent backtracking to the previous word if selection is at word boundary
2735 if (aSttBndry.endPos <= nStartPos)
2736 {
2737 aSttBndry = _xBI->nextWord(
2738 aNodeStr, aSttBndry.endPos,
2739 GetLocale( EditPaM( pNode, aSttBndry.endPos + 1 ) ),
2740 nWordType);
2741 }
2742 // prevent advancing to the next word if selection is at word boundary
2743 if (aEndBndry.startPos >= nEndPos)
2744 {
2745 aEndBndry = _xBI->previousWord(
2746 aNodeStr, aEndBndry.startPos,
2747 GetLocale( EditPaM( pNode, aEndBndry.startPos + 1 ) ),
2748 nWordType);
2749 }
2750
2751 i18n::Boundary aCurWordBndry( aSttBndry );
2752 while (aCurWordBndry.endPos && aCurWordBndry.startPos <= aEndBndry.startPos)
2753 {
2754 nCurrentStart = aCurWordBndry.startPos;
2755 nCurrentEnd = aCurWordBndry.endPos;
2756 sal_Int32 nLen = nCurrentEnd - nCurrentStart;
2757 DBG_ASSERT( nLen > 0, "invalid word length of 0" )do { if (true && (!(nLen > 0))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2757" ": "), "%s", "invalid word length of 0"); } } while
(false)
;
2758
2759 Sequence< sal_Int32 > aOffsets;
2760 OUString aNewText( aTransliterationWrapper.transliterate(aNodeStr,
2761 GetLanguage( EditPaM( pNode, nCurrentStart + 1 ) ),
2762 nCurrentStart, nLen, &aOffsets ));
2763
2764 if (aNodeStr != aNewText)
2765 {
2766 aChgData.nStart = nCurrentStart;
2767 aChgData.nLen = nLen;
2768 aChgData.aSelection = EditSelection( EditPaM( pNode, nCurrentStart ), EditPaM( pNode, nCurrentEnd ) );
2769 aChgData.aNewText = aNewText;
2770 aChgData.aOffsets = aOffsets;
2771 aChanges.push_back( aChgData );
2772 }
2773#if OSL_DEBUG_LEVEL1 > 1
2774 OUString aSelTxt ( GetSelected( aChgData.aSelection ) );
2775 (void) aSelTxt;
2776#endif
2777
2778 aCurWordBndry = _xBI->nextWord(aNodeStr, nCurrentStart,
2779 GetLocale( EditPaM( pNode, nCurrentStart + 1 ) ),
2780 nWordType);
2781 }
2782 DBG_ASSERT( nCurrentEnd >= aEndBndry.endPos, "failed to reach end of transliteration" )do { if (true && (!(nCurrentEnd >= aEndBndry.endPos
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2782" ": "), "%s", "failed to reach end of transliteration"
); } } while (false)
;
2783 }
2784 else if (nTransliterationMode == TransliterationFlags::SENTENCE_CASE)
2785 {
2786 // for 'sentence case' we need to iterate sentence by sentence
2787
2788 sal_Int32 nLastStart = _xBI->beginOfSentence(
2789 aNodeStr, nEndPos,
2790 GetLocale( EditPaM( pNode, nEndPos + 1 ) ) );
2791 sal_Int32 nLastEnd = _xBI->endOfSentence(
2792 aNodeStr, nLastStart,
2793 GetLocale( EditPaM( pNode, nLastStart + 1 ) ) );
2794
2795 // extend nCurrentStart, nCurrentEnd to the current sentence boundaries
2796 nCurrentStart = _xBI->beginOfSentence(
2797 aNodeStr, nStartPos,
2798 GetLocale( EditPaM( pNode, nStartPos + 1 ) ) );
2799 nCurrentEnd = _xBI->endOfSentence(
2800 aNodeStr, nCurrentStart,
2801 GetLocale( EditPaM( pNode, nCurrentStart + 1 ) ) );
2802
2803 // prevent backtracking to the previous sentence if selection starts at end of a sentence
2804 if (nCurrentEnd <= nStartPos)
2805 {
2806 // now nCurrentStart is probably located on a non-letter word. (unless we
2807 // are in Asian text with no spaces...)
2808 // Thus to get the real sentence start we should locate the next real word,
2809 // that is one found by DICTIONARY_WORD
2810 i18n::Boundary aBndry = _xBI->nextWord( aNodeStr, nCurrentEnd,
2811 GetLocale( EditPaM( pNode, nCurrentEnd + 1 ) ),
2812 i18n::WordType::DICTIONARY_WORD);
2813
2814 // now get new current sentence boundaries
2815 nCurrentStart = _xBI->beginOfSentence(
2816 aNodeStr, aBndry.startPos,
2817 GetLocale( EditPaM( pNode, aBndry.startPos + 1 ) ) );
2818 nCurrentEnd = _xBI->endOfSentence(
2819 aNodeStr, nCurrentStart,
2820 GetLocale( EditPaM( pNode, nCurrentStart + 1 ) ) );
2821 }
2822 // prevent advancing to the next sentence if selection ends at start of a sentence
2823 if (nLastStart >= nEndPos)
2824 {
2825 // now nCurrentStart is probably located on a non-letter word. (unless we
2826 // are in Asian text with no spaces...)
2827 // Thus to get the real sentence start we should locate the previous real word,
2828 // that is one found by DICTIONARY_WORD
2829 i18n::Boundary aBndry = _xBI->previousWord( aNodeStr, nLastStart,
2830 GetLocale( EditPaM( pNode, nLastStart + 1 ) ),
2831 i18n::WordType::DICTIONARY_WORD);
2832 nLastEnd = _xBI->endOfSentence(
2833 aNodeStr, aBndry.startPos,
2834 GetLocale( EditPaM( pNode, aBndry.startPos + 1 ) ) );
2835 if (nCurrentEnd > nLastEnd)
2836 nCurrentEnd = nLastEnd;
2837 }
2838
2839 while (nCurrentStart < nLastEnd)
2840 {
2841 const sal_Int32 nLen = nCurrentEnd - nCurrentStart;
2842 DBG_ASSERT( nLen > 0, "invalid word length of 0" )do { if (true && (!(nLen > 0))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2842" ": "), "%s", "invalid word length of 0"); } } while
(false)
;
2843
2844 Sequence< sal_Int32 > aOffsets;
2845 OUString aNewText( aTransliterationWrapper.transliterate( aNodeStr,
2846 GetLanguage( EditPaM( pNode, nCurrentStart + 1 ) ),
2847 nCurrentStart, nLen, &aOffsets ));
2848
2849 if (aNodeStr != aNewText)
2850 {
2851 aChgData.nStart = nCurrentStart;
2852 aChgData.nLen = nLen;
2853 aChgData.aSelection = EditSelection( EditPaM( pNode, nCurrentStart ), EditPaM( pNode, nCurrentEnd ) );
2854 aChgData.aNewText = aNewText;
2855 aChgData.aOffsets = aOffsets;
2856 aChanges.push_back( aChgData );
2857 }
2858
2859 i18n::Boundary aFirstWordBndry = _xBI->nextWord(
2860 aNodeStr, nCurrentEnd,
2861 GetLocale( EditPaM( pNode, nCurrentEnd + 1 ) ),
2862 nWordType);
2863 nCurrentStart = aFirstWordBndry.startPos;
2864 nCurrentEnd = _xBI->endOfSentence(
2865 aNodeStr, nCurrentStart,
2866 GetLocale( EditPaM( pNode, nCurrentStart + 1 ) ) );
2867 }
2868 DBG_ASSERT( nCurrentEnd >= nLastEnd, "failed to reach end of transliteration" )do { if (true && (!(nCurrentEnd >= nLastEnd))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2868" ": "), "%s", "failed to reach end of transliteration"
); } } while (false)
;
2869 }
2870 else
2871 {
2872 do
2873 {
2874 if ( bConsiderLanguage )
2875 {
2876 nLanguage = GetLanguage( EditPaM( pNode, nCurrentStart+1 ), &nCurrentEnd );
2877 if ( nCurrentEnd > nEndPos )
2878 nCurrentEnd = nEndPos;
2879 }
2880
2881 const sal_Int32 nLen = nCurrentEnd - nCurrentStart;
2882
2883 Sequence< sal_Int32 > aOffsets;
2884 OUString aNewText( aTransliterationWrapper.transliterate( aNodeStr, nLanguage, nCurrentStart, nLen, &aOffsets ) );
2885
2886 if (aNodeStr != aNewText)
2887 {
2888 aChgData.nStart = nCurrentStart;
2889 aChgData.nLen = nLen;
2890 aChgData.aSelection = EditSelection( EditPaM( pNode, nCurrentStart ), EditPaM( pNode, nCurrentEnd ) );
2891 aChgData.aNewText = aNewText;
2892 aChgData.aOffsets = aOffsets;
2893 aChanges.push_back( aChgData );
2894 }
2895
2896 nCurrentStart = nCurrentEnd;
2897 } while( nCurrentEnd < nEndPos );
2898 }
2899
2900 if (!aChanges.empty())
2901 {
2902 // Create a single UndoAction on Demand for all the changes ...
2903 if ( !pUndo && IsUndoEnabled() && !IsInUndo() )
2904 {
2905 // adjust selection to include all changes
2906 for (const eeTransliterationChgData & aChange : aChanges)
2907 {
2908 const EditSelection &rSel = aChange.aSelection;
2909 if (aSel.Min().GetNode() == rSel.Min().GetNode() &&
2910 aSel.Min().GetIndex() > rSel.Min().GetIndex())
2911 aSel.Min().SetIndex( rSel.Min().GetIndex() );
2912 if (aSel.Max().GetNode() == rSel.Max().GetNode() &&
2913 aSel.Max().GetIndex() < rSel.Max().GetIndex())
2914 aSel.Max().SetIndex( rSel.Max().GetIndex() );
2915 }
2916 aNewSel = aSel;
2917
2918 ESelection aESel( CreateESel( aSel ) );
2919 pUndo.reset(new EditUndoTransliteration(pEditEngine, aESel, nTransliterationMode));
2920
2921 const bool bSingleNode = aSel.Min().GetNode()== aSel.Max().GetNode();
2922 const bool bHasAttribs = aSel.Min().GetNode()->GetCharAttribs().HasAttrib( aSel.Min().GetIndex(), aSel.Max().GetIndex() );
2923 if (bSingleNode && !bHasAttribs)
2924 pUndo->SetText( aSel.Min().GetNode()->Copy( aSel.Min().GetIndex(), aSel.Max().GetIndex()-aSel.Min().GetIndex() ) );
2925 else
2926 pUndo->SetText( CreateTextObject( aSel, nullptr ) );
2927 }
2928
2929 // now apply the changes from end to start to leave the offsets of the
2930 // yet unchanged text parts remain the same.
2931 for (size_t i = 0; i < aChanges.size(); ++i)
2932 {
2933 eeTransliterationChgData& rData = aChanges[ aChanges.size() - 1 - i ];
2934
2935 bChanges = true;
2936 if (rData.nLen != rData.aNewText.getLength())
2937 bLenChanged = true;
2938
2939 // Change text without losing the attributes
2940 const sal_Int32 nDiffs =
2941 ReplaceTextOnly( rData.aSelection.Min().GetNode(),
2942 rData.nStart, rData.aNewText, rData.aOffsets );
2943
2944 // adjust selection in end node to possibly changed size
2945 if (aSel.Max().GetNode() == rData.aSelection.Max().GetNode())
2946 aNewSel.Max().SetIndex( aNewSel.Max().GetIndex() + nDiffs );
2947
2948 sal_Int32 nSelNode = aEditDoc.GetPos( rData.aSelection.Min().GetNode() );
2949 ParaPortion* pParaPortion = GetParaPortions()[nSelNode];
2950 pParaPortion->MarkSelectionInvalid( rData.nStart );
2951 }
2952 }
2953 }
2954
2955 if ( pUndo )
2956 {
2957 ESelection aESel( CreateESel( aNewSel ) );
2958 pUndo->SetNewSelection( aESel );
2959 InsertUndo( std::move(pUndo) );
2960 }
2961
2962 if ( bChanges )
2963 {
2964 TextModified();
2965 SetModifyFlag( true );
2966 if ( bLenChanged )
2967 UpdateSelections();
2968 FormatAndUpdate();
2969 }
2970
2971 return aNewSel;
2972}
2973
2974
2975short ImpEditEngine::ReplaceTextOnly(
2976 ContentNode* pNode,
2977 sal_Int32 nCurrentStart,
2978 const OUString& rNewText,
2979 const uno::Sequence< sal_Int32 >& rOffsets )
2980{
2981 // Change text without losing the attributes
2982 sal_Int32 nCharsAfterTransliteration = rOffsets.getLength();
2983 const sal_Int32* pOffsets = rOffsets.getConstArray();
2984 short nDiffs = 0;
2985 for ( sal_Int32 n = 0; n < nCharsAfterTransliteration; n++ )
2986 {
2987 sal_Int32 nCurrentPos = nCurrentStart+n;
2988 sal_Int32 nDiff = (nCurrentPos-nDiffs) - pOffsets[n];
2989
2990 if ( !nDiff )
2991 {
2992 DBG_ASSERT( nCurrentPos < pNode->Len(), "TransliterateText - String smaller than expected!" )do { if (true && (!(nCurrentPos < pNode->Len())
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2992" ": "), "%s", "TransliterateText - String smaller than expected!"
); } } while (false)
;
2993 pNode->SetChar( nCurrentPos, rNewText[n] );
2994 }
2995 else if ( nDiff < 0 )
2996 {
2997 // Replace first char, delete the rest...
2998 DBG_ASSERT( nCurrentPos < pNode->Len(), "TransliterateText - String smaller than expected!" )do { if (true && (!(nCurrentPos < pNode->Len())
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "2998" ": "), "%s", "TransliterateText - String smaller than expected!"
); } } while (false)
;
2999 pNode->SetChar( nCurrentPos, rNewText[n] );
3000
3001 DBG_ASSERT( (nCurrentPos+1) < pNode->Len(), "TransliterateText - String smaller than expected!" )do { if (true && (!((nCurrentPos+1) < pNode->Len
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "3001" ": "), "%s", "TransliterateText - String smaller than expected!"
); } } while (false)
;
3002 GetEditDoc().RemoveChars( EditPaM( pNode, nCurrentPos+1 ), -nDiff);
3003 }
3004 else
3005 {
3006 DBG_ASSERT( nDiff == 1, "TransliterateText - Diff other than expected! But should work..." )do { if (true && (!(nDiff == 1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit4.cxx"
":" "3006" ": "), "%s", "TransliterateText - Diff other than expected! But should work..."
); } } while (false)
;
3007 GetEditDoc().InsertText( EditPaM( pNode, nCurrentPos ), OUString(rNewText[n]) );
3008
3009 }
3010 nDiffs = sal::static_int_cast< short >(nDiffs + nDiff);
3011 }
3012
3013 return nDiffs;
3014}
3015
3016
3017void ImpEditEngine::SetAsianCompressionMode( CharCompressType n )
3018{
3019 if ( n != nAsianCompressionMode )
3020 {
3021 nAsianCompressionMode = n;
3022 if ( ImplHasText() )
3023 {
3024 FormatFullDoc();
3025 UpdateViews();
3026 }
3027 }
3028}
3029
3030void ImpEditEngine::SetKernAsianPunctuation( bool b )
3031{
3032 if ( b != bKernAsianPunctuation )
3033 {
3034 bKernAsianPunctuation = b;
3035 if ( ImplHasText() )
3036 {
3037 FormatFullDoc();
3038 UpdateViews();
3039 }
3040 }
3041}
3042
3043void ImpEditEngine::SetAddExtLeading( bool bExtLeading )
3044{
3045 if ( IsAddExtLeading() != bExtLeading )
3046 {
3047 bAddExtLeading = bExtLeading;
3048 if ( ImplHasText() )
3049 {
3050 FormatFullDoc();
3051 UpdateViews();
3052 }
3053 }
3054};
3055
3056
3057bool ImpEditEngine::ImplHasText() const
3058{
3059 return ( ( GetEditDoc().Count() > 1 ) || GetEditDoc().GetObject(0)->Len() );
3060}
3061
3062sal_Int32 ImpEditEngine::LogicToTwips(sal_Int32 n)
3063{
3064 Size aSz(n, 0);
3065 MapMode aTwipsMode( MapUnit::MapTwip );
3066 aSz = pRefDev->LogicToLogic( aSz, nullptr, &aTwipsMode );
3067 return aSz.Width();
3068}
3069
3070/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

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_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
23
Calling 'Reference::get'
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
205 if (aTmp.get()) {
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
5
Calling implicit copy constructor for 'VclPtr<AbstractThesaurusDialog>'
6
Calling copy constructor for 'Reference<AbstractThesaurusDialog>'
9
Returning from copy constructor for 'Reference<AbstractThesaurusDialog>'
10
Returning from copy constructor for 'VclPtr<AbstractThesaurusDialog>'
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

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_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
7
Assuming field 'm_pBody' is non-null
8
Taking true branch
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody
13.1
Field 'm_pBody' is non-null
13.1
Field 'm_pBody' is non-null
13.1
Field 'm_pBody' is non-null
13.1
Field 'm_pBody' is non-null
)
14
Taking true branch
113 m_pBody->release();
15
Calling 'VclReferenceBase::release'
19
Returning; memory was released
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody)
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
24
Use of memory after it is freed
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

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#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
16
Assuming the condition is true
17
Taking true branch
40 delete this;
18
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif