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