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