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