xref: /AOO41X/main/editeng/source/editeng/impedit4.cxx (revision 00a33fa1c448e04aab84f5e09d5590b377f85e52)
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_uInt16 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_uInt16 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_uInt16 nPara,sal_uInt16 nPos,SvxFontTable & rFontTable,SvxColorList & rColorList)298 sal_Bool ImpEditEngine::WriteItemListAsRTF( ItemList& rLst, SvStream& rOutput, sal_uInt16 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_uInt16 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_uInt16 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_uInt16 nPara,sal_uInt16 nPos,SvxFontTable & rFontTable,SvxColorList & rColorList)740 void ImpEditEngine::WriteItemAsRTF( const SfxPoolItem& rItem, SvStream& rOutput, sal_uInt16 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_uInt16 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_uInt16 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_uInt16 nContents = rTextObject.GetContents().Count();
1268     sal_uInt16 nPara = aEditDoc.GetPos( aPaM.GetNode() );
1269 
1270     for ( sal_uInt16 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_uInt16 nParas = pEditEngine->GetParagraphCount();
1539     for (sal_uInt16 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_uInt16 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( (sal_uInt16)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 preceeding 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_uInt16 nNodes = GetEditDoc().Count();
2366     sal_uInt16 nInvalids = 0;
2367     Sequence< PropertyValue > aEmptySeq;
2368     for ( sal_uInt16 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_uInt16 nStartNode = aEditDoc.GetPos( rStartPos.GetNode() );
2726     sal_uInt16 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_uInt16 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_uInt16 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
2844     const sal_uInt16 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_uInt16 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 loosing 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_uInt16 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 loosing 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