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