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