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