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_sw.hxx"
26
27
28 #define _SVSTDARR_LONGS
29 #define _SVSTDARR_USHORTS
30
31 #include <ctype.h>
32 #include <hintids.hxx>
33
34 #include <svl/svstdarr.hxx>
35
36 #include <unotools/charclass.hxx>
37
38 #include <vcl/msgbox.hxx>
39
40 #include <editeng/boxitem.hxx>
41 #include <editeng/lrspitem.hxx>
42 #include <editeng/brkitem.hxx>
43 #include <editeng/adjitem.hxx>
44 #include <editeng/tstpitem.hxx>
45 #include <editeng/fontitem.hxx>
46 #include <editeng/langitem.hxx>
47 #include <editeng/cscoitem.hxx>
48 #include <editeng/unolingu.hxx>
49 #include <editeng/acorrcfg.hxx>
50
51 #include <swwait.hxx>
52 #include <fmtpdsc.hxx>
53 #include <fmtanchr.hxx>
54 #include <doc.hxx>
55 #include <IDocumentUndoRedo.hxx>
56 #include <docary.hxx>
57 #include <editsh.hxx>
58 #include <index.hxx>
59 #include <pam.hxx>
60 #include <edimp.hxx>
61 #include <fesh.hxx>
62 #include <swundo.hxx> // fuer die UndoIds
63 #include <poolfmt.hxx>
64 #include <ndtxt.hxx>
65 #include <txtfrm.hxx>
66 #include <frminf.hxx>
67 #include <pagedesc.hxx>
68 #include <paratr.hxx>
69 #include <swtable.hxx>
70 #include <acorrect.hxx>
71 #include <shellres.hxx>
72 #include <section.hxx>
73 #include <frmatr.hxx>
74 #include <charatr.hxx>
75 #include <mdiexp.hxx>
76 #include <statstr.hrc>
77 #include <comcore.hrc>
78 #include <numrule.hxx>
79
80 using namespace ::com::sun::star;
81
82 //-------------------------------------------------------------------
83
84 //JP 16.12.99: definition:
85 // from pos cPosEnDash to cPosEmDash all chars changed to endashes,
86 // from pos cPosEmDash to cPosEnd all chars changed to emdashes
87 // all other chars are changed to the user configuration
88
89 const sal_Unicode pBulletChar[6] = { '+', '*', '-', 0x2013, 0x2014, 0 };
90 const int cnPosEnDash = 2, cnPosEmDash = 4, cnPosEnd = 5;
91
92 const sal_Unicode cStarSymbolEnDash = 0x2013;
93 const sal_Unicode cStarSymbolEmDash = 0x2014;
94
95
96 SvxSwAutoFmtFlags* SwEditShell::pAutoFmtFlags = 0;
97
98 // Anzahl von Num-/Bullet-Absatzvorlagen. MAXLEVEL wird demnaechst auf
99 // x erhoeht, die Anzahl Vorlagen aber nicht (Ueberbleibsel aus <= 4.0)
100 const sal_uInt16 cnNumBullColls = 4;
101
102 class SwAutoFormat
103 {
104 SvxSwAutoFmtFlags aFlags;
105 SwPaM aDelPam; // ein Pam der benutzt werden kann
106 SwNodeIndex aNdIdx; // der Index auf den akt. TextNode
107 SwNodeIndex aEndNdIdx; // Index auf das Ende vom Bereich
108
109 SwEditShell* pEditShell;
110 SwDoc* pDoc;
111 SwTxtNode* pAktTxtNd; // der akt. TextNode
112 SwTxtFrm* pAktTxtFrm; // Frame vom akt. TextNode
113 CharClass* pCharClass; // Character classification
114 sal_uLong nEndNdIdx; // fuer die Prozent-Anzeige
115 LanguageType eCharClassLang;
116
117 sal_uInt16 nLastHeadLvl, nLastCalcHeadLvl;
118 sal_uInt16 nLastEnumLvl, nLastCalcEnumLvl;
119 sal_uInt16 nRedlAutoFmtSeqId;
120
121 enum
122 {
123 NONE = 0,
124 DELIM = 1,
125 DIGIT = 2,
126 CHG = 4,
127 LOWER_ALPHA = 8,
128 UPPER_ALPHA = 16,
129 LOWER_ROMAN = 32,
130 UPPER_ROMAN = 64,
131 NO_DELIM = (DIGIT|LOWER_ALPHA|UPPER_ALPHA|LOWER_ROMAN|UPPER_ROMAN)
132 };
133
134 enum Format_Status
135 {
136 READ_NEXT_PARA,
137 TST_EMPTY_LINE,
138 TST_ALPHA_LINE,
139 GET_ALL_INFO,
140 IS_ONE_LINE,
141 TST_ENUMERIC,
142 TST_IDENT,
143 TST_NEG_IDENT,
144 TST_TXT_BODY,
145 HAS_FMTCOLL,
146 IS_ENDE
147 } eStat;
148
149 sal_Bool bEnde : 1;
150 sal_Bool bEmptyLine : 1;
151 sal_Bool bMoreLines : 1;
152
153 static sal_Bool m_bAskForCancelUndoWhileBufferOverflow;
154 static short m_nActionWhileAutoformatUndoBufferOverflow;
155
156
157 // ------------- private methods -----------------------------
158 void _GetCharClass( LanguageType eLang );
GetCharClass(LanguageType eLang) const159 CharClass& GetCharClass( LanguageType eLang ) const
160 {
161 if( !pCharClass || eLang != eCharClassLang )
162 {
163 SwAutoFormat* pThis = (SwAutoFormat*)this;
164 pThis->_GetCharClass( eLang );
165 }
166 return *pCharClass;
167 }
168
169
IsSpace(const sal_Unicode c) const170 sal_Bool IsSpace( const sal_Unicode c ) const
171 { return (' ' == c || '\t' == c || 0x0a == c|| 0x3000 == c /* Jap. space */) ? sal_True : sal_False; }
172
173 void SetColl( sal_uInt16 nId, sal_Bool bHdLineOrText = sal_False );
174 String GoNextPara();
175 sal_Bool HasObjects( const SwNode& rNd );
176
177 // TxtNode Methoden
178 const SwTxtNode* GetNextNode() const;
IsEmptyLine(const SwTxtNode & rNd) const179 sal_Bool IsEmptyLine( const SwTxtNode& rNd ) const
180 { return 0 == rNd.GetTxt().Len() ||
181 rNd.GetTxt().Len() == GetLeadingBlanks( rNd.GetTxt() ); }
182
183 sal_Bool IsOneLine( const SwTxtNode& ) const;
184 sal_Bool IsFastFullLine( const SwTxtNode& ) const;
185 sal_Bool IsNoAlphaLine( const SwTxtNode&) const;
186 sal_Bool IsEnumericChar( const SwTxtNode&) const;
187 sal_Bool IsBlanksInString( const SwTxtNode&) const;
188 sal_uInt16 CalcLevel( const SwTxtNode&, sal_uInt16 *pDigitLvl = 0 ) const;
189 xub_StrLen GetBigIndent( xub_StrLen& rAktSpacePos ) const;
190
191 String& DelLeadingBlanks( String& rStr ) const;
192 String& DelTrailingBlanks( String& rStr ) const;
193 xub_StrLen GetLeadingBlanks( const String& rStr ) const;
194 xub_StrLen GetTrailingBlanks( const String& rStr ) const;
195
196 sal_Bool IsFirstCharCapital( const SwTxtNode& rNd ) const;
197 sal_uInt16 GetDigitLevel( const SwTxtNode& rTxtNd, xub_StrLen& rPos,
198 String* pPreFix = 0, String* pPostFix = 0,
199 String* pNumTypes = 0 ) const;
200 // hole den FORMATIERTEN TextFrame
201 SwTxtFrm* GetFrm( const SwTxtNode& rTxtNd ) const;
202
203 void BuildIndent();
204 void BuildText();
205 void BuildTextIndent();
206 void BuildEnum( sal_uInt16 nLvl, sal_uInt16 nDigitLevel );
207 void BuildNegIndent( SwTwips nSpaces );
208 void BuildHeadLine( sal_uInt16 nLvl );
209
210 sal_Bool HasSelBlanks( SwPaM& rPam ) const;
211 sal_Bool HasBreakAttr( const SwTxtNode& ) const;
212 void DeleteSel( SwPaM& rPam );
213 sal_Bool DeleteAktNxtPara( const String& rNxtPara );
214 // loesche im Node Anfang oder/und Ende
215 void DeleteAktPara( sal_Bool bStart = sal_True, sal_Bool nEnd = sal_True );
216 void DelEmptyLine( sal_Bool bTstNextPara = sal_True );
217 // loesche bei mehrzeiligen Absaetzen die "linken" und/oder
218 // "rechten" Raender
219 void DelMoreLinesBlanks( sal_Bool bWithLineBreaks = sal_False );
220 // loesche den vorherigen Absatz
221 void DelPrevPara();
222 // dann lasse doch mal das AutoCorrect auf den akt. TextNode los
223 void AutoCorrect( xub_StrLen nSttPos = 0 );
224
CanJoin(const SwTxtNode * pTxtNd) const225 sal_Bool CanJoin( const SwTxtNode* pTxtNd ) const
226 {
227 return !bEnde && pTxtNd &&
228 !IsEmptyLine( *pTxtNd ) &&
229 !IsNoAlphaLine( *pTxtNd) &&
230 !IsEnumericChar( *pTxtNd ) &&
231 ((STRING_MAXLEN - 50 - pTxtNd->GetTxt().Len()) >
232 pAktTxtNd->GetTxt().Len()) &&
233 !HasBreakAttr( *pTxtNd );
234 }
235
236 // ist ein Punkt am Ende ??
237 sal_Bool IsSentenceAtEnd( const SwTxtNode& rTxtNd ) const;
238
239 sal_Bool DoUnderline();
240 sal_Bool DoTable();
241
242 void _SetRedlineTxt( sal_uInt16 nId );
SetRedlineTxt(sal_uInt16 nId)243 sal_Bool SetRedlineTxt( sal_uInt16 nId )
244 { if( aFlags.bWithRedlining ) _SetRedlineTxt( nId ); return sal_True; }
ClearRedlineTxt()245 sal_Bool ClearRedlineTxt()
246 { if( aFlags.bWithRedlining ) pDoc->SetAutoFmtRedlineComment(0); return sal_True; }
247
248 public:
249 SwAutoFormat( SwEditShell* pEdShell, SvxSwAutoFmtFlags& rFlags,
250 SwNodeIndex* pSttNd = 0, SwNodeIndex* pEndNd = 0 );
~SwAutoFormat()251 ~SwAutoFormat() {
252 delete pCharClass;
253 }
254 };
255
256 sal_Bool SwAutoFormat::m_bAskForCancelUndoWhileBufferOverflow = sal_True;
257 short SwAutoFormat::m_nActionWhileAutoformatUndoBufferOverflow = RET_YES;
258
StrChr(const sal_Unicode * pSrc,sal_Unicode c)259 const sal_Unicode* StrChr( const sal_Unicode* pSrc, sal_Unicode c )
260 {
261 while( *pSrc && *pSrc != c )
262 ++pSrc;
263 return *pSrc ? pSrc : 0;
264 }
265
GetFrm(const SwTxtNode & rTxtNd) const266 SwTxtFrm* SwAutoFormat::GetFrm( const SwTxtNode& rTxtNd ) const
267 {
268 // besorge mal den Frame
269 const SwCntntFrm *pFrm = rTxtNd.getLayoutFrm( pEditShell->GetLayout() );
270 ASSERT( pFrm, "zum Autoformat muss das Layout vorhanden sein" );
271 if( aFlags.bAFmtByInput && !pFrm->IsValid() )
272 {
273 SwRect aTmpFrm( pFrm->Frm() );
274 SwRect aTmpPrt( pFrm->Prt() );
275 pFrm->Calc();
276 if( pFrm->Frm() != aTmpFrm || pFrm->Prt() != aTmpPrt ||
277 ( pFrm->IsTxtFrm() && !((SwTxtFrm*)pFrm)->Paint().IsEmpty() ) )
278 pFrm->SetCompletePaint();
279 }
280 return ((SwTxtFrm*)pFrm)->GetFormatted();
281 }
282
_GetCharClass(LanguageType eLang)283 void SwAutoFormat::_GetCharClass( LanguageType eLang )
284 {
285 delete pCharClass;
286 pCharClass = new CharClass( SvxCreateLocale( eLang ));
287 eCharClassLang = eLang;
288 }
289
_SetRedlineTxt(sal_uInt16 nActionId)290 void SwAutoFormat::_SetRedlineTxt( sal_uInt16 nActionId )
291 {
292 String sTxt;
293 sal_uInt16 nSeqNo = 0;
294 if( STR_AUTOFMTREDL_END > nActionId )
295 {
296 sTxt = *ViewShell::GetShellRes()->GetAutoFmtNameLst()[ nActionId ];
297 switch( nActionId )
298 {
299 case STR_AUTOFMTREDL_SET_NUMBULET:
300 case STR_AUTOFMTREDL_DEL_MORELINES:
301
302 // AutoCorrect-Actions
303 case STR_AUTOFMTREDL_USE_REPLACE:
304 case STR_AUTOFMTREDL_CPTL_STT_WORD:
305 case STR_AUTOFMTREDL_CPTL_STT_SENT:
306 case STR_AUTOFMTREDL_TYPO:
307 case STR_AUTOFMTREDL_UNDER:
308 case STR_AUTOFMTREDL_BOLD:
309 case STR_AUTOFMTREDL_FRACTION:
310 case STR_AUTOFMTREDL_DASH:
311 case STR_AUTOFMTREDL_ORDINAL:
312 case STR_AUTOFMTREDL_NON_BREAK_SPACE:
313 nSeqNo = ++nRedlAutoFmtSeqId;
314 break;
315 }
316 }
317 #if OSL_DEBUG_LEVEL > 1
318 else
319 sTxt = String::CreateFromAscii(
320 RTL_CONSTASCII_STRINGPARAM( "Action-Text fehlt" ));
321 #endif
322
323 pDoc->SetAutoFmtRedlineComment( &sTxt, nSeqNo );
324 }
325
GoNextPara()326 String SwAutoFormat::GoNextPara()
327 {
328 SwNode* pNewNd = 0;
329 do {
330 //has to be checed twice before and after incrementation
331 if( aNdIdx.GetIndex() >= aEndNdIdx.GetIndex() )
332 {
333 bEnde = sal_True;
334 return aEmptyStr;
335 }
336
337 aNdIdx++;
338 if( aNdIdx.GetIndex() >= aEndNdIdx.GetIndex() )
339 {
340 bEnde = sal_True;
341 return aEmptyStr;
342 }
343 else
344 pNewNd = &aNdIdx.GetNode();
345
346 // kein TextNode ->
347 // TableNode : Tabelle ueberspringen
348 // NoTxtNode : Nodes ueberspringen
349 // EndNode : Ende erreicht, beenden
350 if( pNewNd->IsEndNode() )
351 {
352 bEnde = sal_True;
353 return aEmptyStr;
354 }
355 else if( pNewNd->IsTableNode() )
356 aNdIdx = *pNewNd->EndOfSectionNode();
357 else if( pNewNd->IsSectionNode() )
358 {
359 const SwSection& rSect = pNewNd->GetSectionNode()->GetSection();
360 if( rSect.IsHiddenFlag() || rSect.IsProtectFlag() )
361 aNdIdx = *pNewNd->EndOfSectionNode();
362 }
363 } while( !pNewNd->IsTxtNode() );
364
365 if( !aFlags.bAFmtByInput )
366 ::SetProgressState( aNdIdx.GetIndex() + nEndNdIdx - aEndNdIdx.GetIndex(),
367 pDoc->GetDocShell() );
368
369 pAktTxtNd = (SwTxtNode*)pNewNd;
370 pAktTxtFrm = GetFrm( *pAktTxtNd );
371 return pAktTxtNd->GetTxt();
372 }
373
HasObjects(const SwNode & rNd)374 sal_Bool SwAutoFormat::HasObjects( const SwNode& rNd )
375 {
376 // haengt irgend etwas absatzgebundenes am Absatz?
377 // z.B. Rahmen, DrawObjecte, ..
378 sal_Bool bRet = sal_False;
379 const SwSpzFrmFmts& rFmts = *pDoc->GetSpzFrmFmts();
380 for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
381 {
382 const SwFmtAnchor& rAnchor = rFmts[ n ]->GetAnchor();
383 if ((FLY_AT_PAGE != rAnchor.GetAnchorId()) &&
384 rAnchor.GetCntntAnchor() &&
385 &rAnchor.GetCntntAnchor()->nNode.GetNode() == &rNd )
386 {
387 bRet = sal_True;
388 break;
389 }
390 }
391 return bRet;
392 }
393
GetNextNode() const394 const SwTxtNode* SwAutoFormat::GetNextNode() const
395 {
396 if( aNdIdx.GetIndex()+1 >= aEndNdIdx.GetIndex() )
397 return 0;
398 return pDoc->GetNodes()[ aNdIdx.GetIndex() + 1 ]->GetTxtNode();
399 }
400
401
IsOneLine(const SwTxtNode & rNd) const402 sal_Bool SwAutoFormat::IsOneLine( const SwTxtNode& rNd ) const
403 {
404 SwTxtFrmInfo aFInfo( GetFrm( rNd ) );
405 return aFInfo.IsOneLine();
406 }
407
408
IsFastFullLine(const SwTxtNode & rNd) const409 sal_Bool SwAutoFormat::IsFastFullLine( const SwTxtNode& rNd ) const
410 {
411 sal_Bool bRet = aFlags.bRightMargin;
412 if( bRet )
413 {
414 SwTxtFrmInfo aFInfo( GetFrm( rNd ) );
415 bRet = aFInfo.IsFilled( aFlags.nRightMargin );
416 }
417 return bRet;
418 }
419
420
IsEnumericChar(const SwTxtNode & rNd) const421 sal_Bool SwAutoFormat::IsEnumericChar( const SwTxtNode& rNd ) const
422 {
423 const String& rTxt = rNd.GetTxt();
424 String sTmp( rTxt );
425 xub_StrLen nBlnks = GetLeadingBlanks( sTmp );
426 xub_StrLen nLen = rTxt.Len() - nBlnks;
427 if( !nLen )
428 return sal_False;
429
430 // -, +, * getrennt durch Blank ??
431 if( 2 < nLen && IsSpace( rTxt.GetChar( nBlnks + 1 ) ) )
432 {
433 if( StrChr( pBulletChar, rTxt.GetChar( nBlnks ) ) )
434 return sal_True;
435 // sollte an der Position ein Symbolfont existieren ?
436 SwTxtFrmInfo aFInfo( GetFrm( rNd ) );
437 if( aFInfo.IsBullet( nBlnks ))
438 return sal_True;
439 }
440
441 // 1.) / 1. / 1.1.1 / (1). / (1) / ....
442 return USHRT_MAX != GetDigitLevel( rNd, nBlnks );
443 }
444
445
IsBlanksInString(const SwTxtNode & rNd) const446 sal_Bool SwAutoFormat::IsBlanksInString( const SwTxtNode& rNd ) const
447 {
448 // suche im String mehr als 5 Blanks/Tabs
449 String sTmp( rNd.GetTxt() );
450 DelTrailingBlanks( DelLeadingBlanks( sTmp ));
451 const sal_Unicode* pTmp = sTmp.GetBuffer();
452 while( *pTmp )
453 {
454 if( IsSpace( *pTmp ) )
455 {
456 if( IsSpace( *++pTmp )) // 2 Space nach einander
457 {
458 const sal_Unicode* pStt = pTmp;
459 while( *pTmp && IsSpace( *++pTmp ))
460 ;
461 if( 5 <= pTmp - pStt )
462 return sal_True;
463 }
464 else
465 ++pTmp;
466 }
467 else
468 ++pTmp;
469 }
470 return sal_False;
471 }
472
473
CalcLevel(const SwTxtNode & rNd,sal_uInt16 * pDigitLvl) const474 sal_uInt16 SwAutoFormat::CalcLevel( const SwTxtNode& rNd, sal_uInt16 *pDigitLvl ) const
475 {
476 sal_uInt16 nLvl = 0, nBlnk = 0;
477 const String& rTxt = rNd.GetTxt();
478 if( pDigitLvl )
479 *pDigitLvl = USHRT_MAX;
480
481 if( RES_POOLCOLL_TEXT_MOVE == rNd.GetTxtColl()->GetPoolFmtId() )
482 {
483 if( aFlags.bAFmtByInput )
484 {
485 nLvl = rNd.GetAutoFmtLvl();
486 ((SwTxtNode&)rNd).SetAutoFmtLvl( 0 );
487 if( nLvl )
488 return nLvl;
489 }
490 ++nLvl;
491 }
492
493
494 for( xub_StrLen n = 0, nEnd = rTxt.Len(); n < nEnd; ++n )
495 {
496 switch( rTxt.GetChar( n ) )
497 {
498 case ' ': if( 3 == ++nBlnk )
499 ++nLvl, nBlnk = 0;
500 break;
501 case '\t': ++nLvl, nBlnk = 0;
502 break;
503 default:
504 if( pDigitLvl )
505 // Teste auf 1.) / 1. / 1.1.1 / (1). / (1) / ....
506 *pDigitLvl = GetDigitLevel( rNd, n );
507 return nLvl;
508 }
509 }
510 return nLvl;
511 }
512
513
514
GetBigIndent(xub_StrLen & rAktSpacePos) const515 xub_StrLen SwAutoFormat::GetBigIndent( xub_StrLen& rAktSpacePos ) const
516 {
517 SwTxtFrmInfo aFInfo( GetFrm( *pAktTxtNd ) );
518 const SwTxtFrm* pNxtFrm = 0;
519
520 if( !bMoreLines )
521 {
522 const SwTxtNode* pNxtNd = GetNextNode();
523 if( !CanJoin( pNxtNd ) || !IsOneLine( *pNxtNd ) )
524 return 0;
525
526 pNxtFrm = GetFrm( *pNxtNd );
527 }
528
529 return aFInfo.GetBigIndent( rAktSpacePos, pNxtFrm );
530 }
531
532
IsNoAlphaLine(const SwTxtNode & rNd) const533 sal_Bool SwAutoFormat::IsNoAlphaLine( const SwTxtNode& rNd ) const
534 {
535 const String& rStr = rNd.GetTxt();
536 if( !rStr.Len() )
537 return sal_False;
538 // oder besser: ueber die Anzahl von Alpha/Num- und !AN-Zeichen
539 // bestimmen.
540 xub_StrLen nANChar = 0, nBlnk = 0;
541
542 CharClass& rCC = GetCharClass( rNd.GetSwAttrSet().GetLanguage().GetLanguage() );
543 for( xub_StrLen n = 0, nEnd = rStr.Len(); n < nEnd; ++n )
544 if( IsSpace( rStr.GetChar( n ) ) )
545 ++nBlnk;
546 else if( rCC.isLetterNumeric( rStr, n ))
547 ++nANChar;
548
549 // sind zu 75% keine Alpha-Nummerische-Zeichen, dann sal_True
550 sal_uLong nLen = rStr.Len() - nBlnk;
551 nLen = ( nLen * 3 ) / 4; // long overflow, if the strlen > sal_uInt16
552 return xub_StrLen(nLen) < (rStr.Len() - nANChar - nBlnk);
553 }
554
555
556
DoUnderline()557 sal_Bool SwAutoFormat::DoUnderline()
558 {
559 if( !aFlags.bSetBorder )
560 return sal_False;
561
562 const sal_Unicode* pStr = pAktTxtNd->GetTxt().GetBuffer();
563 int eState = 0;
564 xub_StrLen nCnt = 0;
565 while( *pStr )
566 {
567 //JP 29.03.96: Spaces unterbrechen die Umrandung!
568 // if( !IsSpace( *pStr ) )
569 {
570 int eTmp = 0;
571 switch( *pStr )
572 {
573 case '-': eTmp = 1; break;
574 case '_': eTmp = 2; break;
575 case '=': eTmp = 3; break;
576 case '*': eTmp = 4; break;
577 case '~': eTmp = 5; break;
578 case '#': eTmp = 6; break;
579 default:
580 return sal_False;
581 }
582 if( 0 == eState )
583 eState = eTmp;
584 else if( eState != eTmp )
585 return sal_False;
586 ++nCnt;
587 }
588 ++pStr;
589 }
590
591 if( 2 < nCnt )
592 {
593 // dann unterstreiche mal den vorherigen Absatz, wenn es diesen gibt!
594 DelEmptyLine( sal_False );
595 aDelPam.SetMark();
596 aDelPam.GetMark()->nContent = 0;
597 //JP 19.03.96: kein Underline sondern eine Umrandung setzen!
598 // pDoc->Insert( aDelPam, SvxUnderlineItem( eState ) );
599
600 SvxBorderLine aLine;
601 switch( eState )
602 {
603 case 1: // einfach, 0,05 pt
604 aLine.SetOutWidth( DEF_LINE_WIDTH_0 );
605 break;
606 case 2: // einfach, 1,0 pt
607 aLine.SetOutWidth( DEF_LINE_WIDTH_1 );
608 break;
609 case 3: // doppelt, 1,1 pt
610 aLine.SetOutWidth( DEF_DOUBLE_LINE0_OUT );
611 aLine.SetInWidth( DEF_DOUBLE_LINE0_IN );
612 aLine.SetDistance( DEF_DOUBLE_LINE0_DIST );
613 break;
614 case 4: // doppelt, 4,5 pt
615 aLine.SetOutWidth( DEF_DOUBLE_LINE4_OUT );
616 aLine.SetInWidth( DEF_DOUBLE_LINE4_IN );
617 aLine.SetDistance( DEF_DOUBLE_LINE4_DIST );
618 break;
619 case 5: // doppelt, 6,0 pt
620 aLine.SetOutWidth( DEF_DOUBLE_LINE5_OUT );
621 aLine.SetInWidth( DEF_DOUBLE_LINE5_IN );
622 aLine.SetDistance( DEF_DOUBLE_LINE5_DIST );
623 break;
624 case 6: // doppelt, 9,0 pt
625 aLine.SetOutWidth( DEF_DOUBLE_LINE6_OUT );
626 aLine.SetInWidth( DEF_DOUBLE_LINE6_IN );
627 aLine.SetDistance( DEF_DOUBLE_LINE6_DIST );
628 break;
629 }
630 SfxItemSet aSet(pDoc->GetAttrPool(),
631 RES_PARATR_CONNECT_BORDER, RES_PARATR_CONNECT_BORDER,
632 RES_BOX, RES_BOX,
633 0);
634 aSet.Put( SwParaConnectBorderItem( sal_False ) );
635 SvxBoxItem aBox( RES_BOX );
636 aBox.SetLine( &aLine, BOX_LINE_BOTTOM );
637 aBox.SetDistance( 42 ); // ~0,75 mm
638 aSet.Put(aBox);
639 pDoc->InsertItemSet( aDelPam, aSet, 0 );
640
641 aDelPam.DeleteMark();
642 }
643 return 2 < nCnt;
644 }
645
646
DoTable()647 sal_Bool SwAutoFormat::DoTable()
648 {
649 if( !aFlags.bCreateTable || !aFlags.bAFmtByInput ||
650 pAktTxtNd->FindTableNode() )
651 return sal_False;
652
653 const String& rTmp = pAktTxtNd->GetTxt();
654 xub_StrLen nSttPlus = GetLeadingBlanks( rTmp );
655 xub_StrLen nEndPlus = GetTrailingBlanks( rTmp );
656 sal_Unicode cChar;
657
658 if( 2 > nEndPlus - nSttPlus ||
659 ( '+' != ( cChar = rTmp.GetChar( nSttPlus )) && '|' != cChar ) ||
660 ( '+' != ( cChar = rTmp.GetChar( nEndPlus - 1)) && '|' != cChar ))
661 return sal_False;
662
663 SwTxtFrmInfo aInfo( pAktTxtFrm );
664
665 xub_StrLen n = nSttPlus;
666 const sal_Unicode* pStr = rTmp.GetBuffer() + n;
667 SvUShorts aPosArr( 5, 5 );
668
669 while( *pStr )
670 {
671 switch( *pStr )
672 {
673 case '-':
674 case '_':
675 case '=':
676 case ' ':
677 case '\t':
678 break;
679
680 case '+':
681 case '|':
682 aPosArr.Insert( static_cast<sal_uInt16>(aInfo.GetCharPos(n)), aPosArr.Count() );
683 break;
684
685 default:
686 return sal_False;
687 }
688 if( ++n == nEndPlus )
689 break;
690
691 ++pStr;
692 }
693
694 if( 1 < aPosArr.Count() )
695 {
696 // Ausrichtung vom Textnode besorgen:
697 sal_uInt16 nColCnt = aPosArr.Count() - 1;
698 SwTwips nSttPos = aPosArr[ 0 ];
699 sal_Int16 eHori;
700 switch( pAktTxtNd->GetSwAttrSet().GetAdjust().GetAdjust() )
701 {
702 case SVX_ADJUST_CENTER: eHori = text::HoriOrientation::CENTER; break;
703 case SVX_ADJUST_RIGHT: eHori = text::HoriOrientation::RIGHT; break;
704
705 default:
706 if( nSttPos )
707 {
708 eHori = text::HoriOrientation::NONE;
709 // dann muss als letztes noch die akt. FrameBreite
710 // ins Array
711 aPosArr.Insert( static_cast<sal_uInt16>(pAktTxtFrm->Frm().Width()), aPosArr.Count() );
712 }
713 else
714 eHori = text::HoriOrientation::LEFT;
715 break;
716 }
717
718 // dann erzeuge eine Tabelle, die den Zeichen entspricht
719 DelEmptyLine();
720 SwNodeIndex aIdx( aDelPam.GetPoint()->nNode );
721 aDelPam.Move( fnMoveForward );
722 pDoc->InsertTable( SwInsertTableOptions( tabopts::ALL_TBL_INS_ATTR , 1 ),
723 *aDelPam.GetPoint(), 1, nColCnt, eHori,
724 0, &aPosArr );
725 aDelPam.GetPoint()->nNode = aIdx;
726 }
727 return 1 < aPosArr.Count();
728 }
729
730
DelLeadingBlanks(String & rStr) const731 String& SwAutoFormat::DelLeadingBlanks( String& rStr ) const
732 {
733 xub_StrLen nL;
734 xub_StrLen n;
735
736 for( nL = rStr.Len(), n = 0; n < nL && IsSpace( rStr.GetChar(n) ); ++n )
737 ;
738 if( n ) // keine Spaces
739 rStr.Erase( 0, n );
740 return rStr;
741 }
742
743
DelTrailingBlanks(String & rStr) const744 String& SwAutoFormat::DelTrailingBlanks( String& rStr ) const
745 {
746 xub_StrLen nL = rStr.Len(), n = nL;
747 if( !nL )
748 return rStr;
749
750 while( --n && IsSpace( rStr.GetChar( n ) ) )
751 ;
752 if( n+1 != nL ) // keine Spaces
753 rStr.Erase( n+1 );
754 return rStr;
755 }
756
757
GetLeadingBlanks(const String & rStr) const758 xub_StrLen SwAutoFormat::GetLeadingBlanks( const String& rStr ) const
759 {
760 xub_StrLen nL;
761 xub_StrLen n;
762
763 for( nL = rStr.Len(), n = 0; n < nL && IsSpace( rStr.GetChar( n ) ); ++n )
764 ;
765 return n;
766 }
767
768
GetTrailingBlanks(const String & rStr) const769 xub_StrLen SwAutoFormat::GetTrailingBlanks( const String& rStr ) const
770 {
771 xub_StrLen nL = rStr.Len(), n = nL;
772 if( !nL )
773 return 0;
774
775 while( --n && IsSpace( rStr.GetChar( n ) ) )
776 ;
777 return ++n;
778 }
779
780
IsFirstCharCapital(const SwTxtNode & rNd) const781 sal_Bool SwAutoFormat::IsFirstCharCapital( const SwTxtNode& rNd ) const
782 {
783 const String& rTxt = rNd.GetTxt();
784 for( xub_StrLen n = 0, nEnd = rTxt.Len(); n < nEnd; ++n )
785 if( !IsSpace( rTxt.GetChar( n ) ) )
786 {
787 CharClass& rCC = GetCharClass( rNd.GetSwAttrSet().
788 GetLanguage().GetLanguage() );
789 sal_Int32 nCharType = rCC.getCharacterType( rTxt, n );
790 return CharClass::isLetterType( nCharType ) &&
791 0 != ( i18n::KCharacterType::UPPER &
792 nCharType );
793 }
794 return sal_False;
795 }
796
797
GetDigitLevel(const SwTxtNode & rNd,xub_StrLen & rPos,String * pPreFix,String * pPostFix,String * pNumTypes) const798 sal_uInt16 SwAutoFormat::GetDigitLevel( const SwTxtNode& rNd, xub_StrLen& rPos,
799 String* pPreFix, String* pPostFix, String* pNumTypes ) const
800 {
801 // Teste auf 1.) / 1. / 1.1.1 / (1). / (1) / ....
802 const String& rTxt = rNd.GetTxt();
803 xub_StrLen nPos = rPos;
804 int eScan = NONE;
805
806 sal_uInt16 nStart = 0;
807 sal_uInt8 nDigitLvl = 0, nDigitCnt = 0;
808 //count number of parenthesis to assure a sensible order is found
809 sal_uInt16 nOpeningParentheses = 0;
810 sal_uInt16 nClosingParentheses = 0;
811
812 CharClass& rCC = GetCharClass( rNd.GetSwAttrSet().GetLanguage().GetLanguage() );
813
814 while( nPos < rTxt.Len() && nDigitLvl < MAXLEVEL - 1)
815 {
816 const sal_Unicode cCurrentChar = rTxt.GetChar( nPos );
817 if( ('0' <= cCurrentChar && '9' >= cCurrentChar) ||
818 (0xff10 <= cCurrentChar && 0xff19 >= cCurrentChar) )
819 {
820 if( eScan & DELIM )
821 {
822 if( eScan & CHG ) // nicht wenns mit einer Zahl beginnt
823 {
824 ++nDigitLvl;
825 if( pPostFix )
826 *pPostFix += (sal_Unicode)1;
827 }
828
829 if( pNumTypes )
830 *pNumTypes += (sal_Unicode)('0' + SVX_NUM_ARABIC);
831
832 eScan = eScan | CHG;
833 }
834 else if( pNumTypes && !(eScan & DIGIT) )
835 *pNumTypes += (sal_Unicode)('0' + SVX_NUM_ARABIC);
836
837 eScan &= ~DELIM; // Delim raus
838 if( 0 != (eScan & ~CHG) && DIGIT != (eScan & ~CHG))
839 return USHRT_MAX;
840
841 eScan |= DIGIT; // Digit rein
842 if( 3 == ++nDigitCnt ) // mehr als 2 Nummern sind kein Enum mehr
843 return USHRT_MAX;
844
845 nStart *= 10;
846 nStart += cCurrentChar <= '9' ? cCurrentChar - '0' : cCurrentChar - 0xff10;
847 }
848 else if( rCC.isAlpha( rTxt, nPos ) )
849 {
850 sal_Bool bIsUpper =
851 0 != ( i18n::KCharacterType::UPPER &
852 rCC.getCharacterType( rTxt, nPos ));
853 sal_Unicode cLow = rCC.toLower( rTxt, nPos, 1 ).GetChar(0), cNumTyp;
854 int eTmpScan;
855
856 // roemische Zeichen sind "mdclxvi". Da man aber eher mal eine
857 // Numerierung mit c oder d anfangen will, werden diese erstmal
858 // zu chars und spaeter ggfs. zu romischen Zeichen!
859 // if( strchr( "mdclxvi", cLow ))
860 #ifdef WITH_ALPHANUM_AS_NUMFMT
861 //detection of 'c' and 'd' a ROMAN numbering should not be done here
862 if( 256 > cLow &&( (eScan & (LOWER_ROMAN|UPPER_ROMAN))
863 ? strchr( "mdclxvi", cLow )
864 : strchr( "mlxvi", cLow ) ))
865 #else
866 if( 256 > cLow && ( strchr( "mdclxvi", cLow ) ))
867 #endif
868 {
869 if( bIsUpper )
870 cNumTyp = '0' + SVX_NUM_ROMAN_UPPER, eTmpScan = UPPER_ROMAN;
871 else
872 cNumTyp = '0' + SVX_NUM_ROMAN_LOWER, eTmpScan = LOWER_ROMAN;
873 }
874 else if( bIsUpper )
875 cNumTyp = '0' + SVX_NUM_CHARS_UPPER_LETTER, eTmpScan = UPPER_ALPHA;
876 else
877 cNumTyp = '0' + SVX_NUM_CHARS_LOWER_LETTER, eTmpScan = LOWER_ALPHA;
878
879
880 //ggfs. auf roemische Zeichen umschalten (nur bei c/d!)?
881 if( 1 == nDigitCnt && ( eScan & (UPPER_ALPHA|LOWER_ALPHA) ) &&
882 ( 3 == nStart || 4 == nStart) && 256 > cLow &&
883 strchr( "mdclxvi", cLow ) &&
884 (( eScan & UPPER_ALPHA ) ? (eTmpScan & (UPPER_ALPHA|UPPER_ROMAN))
885 : (eTmpScan & (LOWER_ALPHA|LOWER_ROMAN))) )
886 {
887 sal_Unicode c = '0';
888 nStart = 3 == nStart ? 100 : 500;
889 if( UPPER_ALPHA == eTmpScan )
890 eTmpScan = UPPER_ROMAN, c += SVX_NUM_ROMAN_UPPER;
891 else
892 eTmpScan = LOWER_ROMAN, c += SVX_NUM_ROMAN_LOWER;
893
894 ( eScan &= ~(UPPER_ALPHA|LOWER_ALPHA)) |= eTmpScan;
895 if( pNumTypes )
896 pNumTypes->SetChar( pNumTypes->Len() - 1, c );
897 }
898
899 if( eScan & DELIM )
900 {
901 if( eScan & CHG ) // nicht wenns mit einer Zahl beginnt
902 {
903 ++nDigitLvl;
904 if( pPostFix )
905 *pPostFix += (sal_Unicode)1;
906 }
907
908 if( pNumTypes )
909 *pNumTypes += cNumTyp;
910 eScan = eScan | CHG;
911 }
912 else if( pNumTypes && !(eScan & eTmpScan) )
913 *pNumTypes += cNumTyp;
914
915 eScan &= ~DELIM; // Delim raus
916
917 // falls ein andere Type gesetzt ist, brechen wir ab
918 if( 0 != ( eScan & ~CHG ) && eTmpScan != ( eScan & ~CHG ))
919 return USHRT_MAX;
920
921 if( eTmpScan & (UPPER_ALPHA | LOWER_ALPHA) )
922 {
923 // Buchstaben nur zulassen, wenn sie einmalig vorkommen
924 return USHRT_MAX;
925 }
926 else
927 {
928 // roemische Zahlen: checke ob das gueltige Zeichen sind
929 sal_uInt16 nVal;
930 sal_Bool bError = sal_False;
931 switch( cLow )
932 {
933 case 'm': nVal = 1000; goto CHECK_ROMAN_1;
934 case 'd': nVal = 500; goto CHECK_ROMAN_5;
935 case 'c': nVal = 100; goto CHECK_ROMAN_1;
936 case 'l': nVal = 50; goto CHECK_ROMAN_5;
937 case 'x': nVal = 10; goto CHECK_ROMAN_1;
938 case 'v': nVal = 5; goto CHECK_ROMAN_5;
939
940 CHECK_ROMAN_1:
941 {
942 int nMod5 = nStart % (nVal * 5);
943 int nLast = nStart % nVal;
944 int n10 = nVal / 10;
945
946 if( nMod5 == ((3 * nVal) + n10 ) ||
947 nMod5 == ((4 * nVal) + n10 ) ||
948 nLast == n10 )
949 nStart = static_cast<sal_uInt16>(nStart + (n10 * 8));
950 else if( nMod5 == 0 ||
951 nMod5 == (1 * nVal) ||
952 nMod5 == (2 * nVal) )
953 nStart = nStart + nVal;
954 else
955 bError = sal_True;
956 }
957 break;
958
959 CHECK_ROMAN_5:
960 {
961 if( ( nStart / nVal ) & 1 )
962 bError = sal_True;
963 else
964 {
965 int nMod = nStart % nVal;
966 int n10 = nVal / 5;
967 if( n10 == nMod )
968 nStart = static_cast<sal_uInt16>(nStart + (3 * n10));
969 else if( 0 == nMod )
970 nStart = nStart + nVal;
971 else
972 bError = sal_True;
973 }
974 }
975 break;
976
977 case 'i':
978 if( nStart % 5 >= 3 )
979 bError = sal_True;
980 else
981 nStart += 1;
982 break;
983
984 default:
985 bError = sal_True;
986 }
987
988 if( bError )
989 return USHRT_MAX;
990 }
991 eScan |= eTmpScan; // Digit rein
992 ++nDigitCnt;
993 }
994 else if( (256 > cCurrentChar &&
995 strchr( ".)(", cCurrentChar )) ||
996 0x3002 == cCurrentChar /* Chinese trad. dot */||
997 0xff0e == cCurrentChar /* Japanese dot */||
998 0xFF08 == cCurrentChar /* opening bracket Chin./Jap.*/||
999 0xFF09 == cCurrentChar )/* closing bracket Chin./Jap. */
1000 {
1001 if(cCurrentChar == '(' || cCurrentChar == 0xFF09)
1002 nOpeningParentheses++;
1003 else if(cCurrentChar == ')'|| cCurrentChar == 0xFF08)
1004 nClosingParentheses++;
1005 // nur wenn noch keine Zahlen gelesen wurden!
1006 if( pPreFix && !( eScan & ( NO_DELIM | CHG )) )
1007 *pPreFix += rTxt.GetChar( nPos );
1008 else if( pPostFix )
1009 *pPostFix += rTxt.GetChar( nPos );
1010
1011 if( NO_DELIM & eScan )
1012 {
1013 eScan |= CHG;
1014 if( pPreFix )
1015 (*pPreFix += (sal_Unicode)1)
1016 += String::CreateFromInt32( nStart );
1017 }
1018 eScan &= ~NO_DELIM; // Delim raus
1019 eScan |= DELIM; // Digit rein
1020 nDigitCnt = 0;
1021 nStart = 0;
1022 }
1023 else
1024 break;
1025 ++nPos;
1026 }
1027 if( !( CHG & eScan ) || rPos == nPos ||
1028 nPos == rTxt.Len() || !IsSpace( rTxt.GetChar( nPos ) ) ||
1029 (nOpeningParentheses > nClosingParentheses))
1030 return USHRT_MAX;
1031
1032 if( (NO_DELIM & eScan) && pPreFix ) // den letzen nicht vergessen
1033 (*pPreFix += (sal_Unicode)1) += String::CreateFromInt32( nStart );
1034
1035 rPos = nPos;
1036 return nDigitLvl; // 0 .. 9 (MAXLEVEL - 1)
1037 }
1038
1039
SetColl(sal_uInt16 nId,sal_Bool bHdLineOrText)1040 void SwAutoFormat::SetColl( sal_uInt16 nId, sal_Bool bHdLineOrText )
1041 {
1042 aDelPam.DeleteMark();
1043 aDelPam.GetPoint()->nNode = aNdIdx;
1044 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1045
1046 // behalte harte Tabs, Ausrichtung, Sprache, Silbentrennung,
1047 // DropCaps und fast alle Frame-Attribute
1048 SfxItemSet aSet( pDoc->GetAttrPool(),
1049 RES_PARATR_ADJUST, RES_PARATR_ADJUST,
1050 RES_PARATR_TABSTOP, RES_PARATR_DROP,
1051 RES_CHRATR_LANGUAGE, RES_CHRATR_LANGUAGE,
1052 RES_BACKGROUND, RES_SHADOW,
1053 0 );
1054
1055 if( pAktTxtNd->HasSwAttrSet() )
1056 {
1057 aSet.Put( *pAktTxtNd->GetpSwAttrSet() );
1058 // einige Sonderbedingungen:
1059 // HeaderLine/Textkoerper: nur zentriert oder rechts mitnehmem
1060 // sonst nur den Blocksatz
1061 SvxAdjustItem* pAdj;
1062 if( SFX_ITEM_SET == aSet.GetItemState( RES_PARATR_ADJUST,
1063 sal_False, (const SfxPoolItem**)&pAdj ))
1064 {
1065 SvxAdjust eAdj = pAdj->GetAdjust();
1066 if( bHdLineOrText ? (SVX_ADJUST_RIGHT != eAdj &&
1067 SVX_ADJUST_CENTER != eAdj)
1068 : SVX_ADJUST_BLOCK != eAdj )
1069 aSet.ClearItem( RES_PARATR_ADJUST );
1070 }
1071 }
1072
1073 pDoc->SetTxtFmtCollByAutoFmt( *aDelPam.GetPoint(), nId, &aSet );
1074 }
1075
1076
HasSelBlanks(SwPaM & rPam) const1077 sal_Bool SwAutoFormat::HasSelBlanks( SwPaM& rPam ) const
1078 {
1079 // noch ein Blank am Anfang oder Ende ?
1080 // nicht loeschen, wird wieder eingefuegt.
1081 SwPosition * pPos = rPam.End();
1082 xub_StrLen nBlnkPos = pPos->nContent.GetIndex();
1083 SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode();
1084 if( nBlnkPos && nBlnkPos-- < pTxtNd->GetTxt().Len() &&
1085 ( ' ' == pTxtNd->GetTxt().GetChar( nBlnkPos ) ))
1086 // JP 23.08.95: keine Tabs stehen lassen, diese in Blanks wandeln
1087 // ( ' ' == ( cCh = pTxtNd->GetTxt()[ nBlnkPos ] ) || '\t' == cCh ))
1088 pPos->nContent--;
1089 else
1090 {
1091 pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint();
1092 nBlnkPos = pPos->nContent.GetIndex();
1093 pTxtNd = pPos->nNode.GetNode().GetTxtNode();
1094 if( nBlnkPos < pTxtNd->GetTxt().Len() &&
1095 ( ' ' == pTxtNd->GetTxt().GetChar( nBlnkPos )))
1096 // JP 23.08.95: keine Tabs stehen lassen, diese in Blanks wandeln
1097 // ( ' ' == ( cCh = pTxtNd->GetTxt()[ nBlnkPos ] ) || '\t' == cCh ))
1098 pPos->nContent++;
1099 else
1100 return sal_False;
1101 }
1102 return sal_True;
1103 }
1104
1105
HasBreakAttr(const SwTxtNode & rTxtNd) const1106 sal_Bool SwAutoFormat::HasBreakAttr( const SwTxtNode& rTxtNd ) const
1107 {
1108 const SfxItemSet* pSet = rTxtNd.GetpSwAttrSet();
1109 if( !pSet )
1110 return sal_False;
1111
1112 const SfxPoolItem* pItem;
1113 if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem )
1114 && SVX_BREAK_NONE != ((SvxFmtBreakItem*)pItem)->GetBreak() )
1115 return sal_True;
1116
1117 if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC, sal_False, &pItem )
1118 && ((SwFmtPageDesc*)pItem)->GetPageDesc()
1119 && nsUseOnPage::PD_NONE != ((SwFmtPageDesc*)pItem)->GetPageDesc()->GetUseOn() )
1120 return sal_True;
1121 return sal_False;
1122 }
1123
1124
1125 // ist ein Punkt am Ende ??
IsSentenceAtEnd(const SwTxtNode & rTxtNd) const1126 sal_Bool SwAutoFormat::IsSentenceAtEnd( const SwTxtNode& rTxtNd ) const
1127 {
1128 const String& rStr = rTxtNd.GetTxt();
1129 xub_StrLen n = rStr.Len();
1130 if( !n )
1131 return sal_True;
1132
1133 while( --n && IsSpace( rStr.GetChar( n ) ) )
1134 ;
1135 return '.' == rStr.GetChar( n );
1136 }
1137
1138
1139 // loesche im Node Anfang oder/und Ende
DeleteAktPara(sal_Bool bStart,sal_Bool bEnd)1140 void SwAutoFormat::DeleteAktPara( sal_Bool bStart, sal_Bool bEnd )
1141 {
1142 if( aFlags.bAFmtByInput
1143 ? aFlags.bAFmtByInpDelSpacesAtSttEnd
1144 : aFlags.bAFmtDelSpacesAtSttEnd )
1145 {
1146 // Loesche Blanks am Ende vom akt. und am Anfang vom naechsten
1147 aDelPam.DeleteMark();
1148 aDelPam.GetPoint()->nNode = aNdIdx;
1149 xub_StrLen nPos;
1150 if( bStart && 0 != ( nPos = GetLeadingBlanks( pAktTxtNd->GetTxt() )))
1151 {
1152 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1153 aDelPam.SetMark();
1154 aDelPam.GetPoint()->nContent = nPos;
1155 DeleteSel( aDelPam );
1156 aDelPam.DeleteMark();
1157 }
1158 if( bEnd && pAktTxtNd->GetTxt().Len() !=
1159 ( nPos = GetTrailingBlanks( pAktTxtNd->GetTxt() )) )
1160 {
1161 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, pAktTxtNd->GetTxt().Len() );
1162 aDelPam.SetMark();
1163 aDelPam.GetPoint()->nContent = nPos;
1164 DeleteSel( aDelPam );
1165 aDelPam.DeleteMark();
1166 }
1167 }
1168 }
1169
DeleteSel(SwPaM & rDelPam)1170 void SwAutoFormat::DeleteSel( SwPaM& rDelPam )
1171 {
1172 if( aFlags.bWithRedlining )
1173 {
1174 // damit der DelPam auch verschoben wird, in den Shell-Cursr-Ring
1175 // mit aufnehmen !!
1176 SwPaM* pShCrsr = pEditShell->_GetCrsr();
1177 SwPaM aTmp( *pAktTxtNd, 0, pShCrsr );
1178
1179 Ring *pPrev = rDelPam.GetPrev();
1180 rDelPam.MoveRingTo( pShCrsr );
1181
1182 pEditShell->DeleteSel( rDelPam );
1183
1184 // und den Pam wieder herausnehmen:
1185 Ring *p, *pNext = (Ring*)&rDelPam;
1186 do {
1187 p = pNext;
1188 pNext = p->GetNext();
1189 p->MoveTo( &rDelPam );
1190 } while( p != pPrev );
1191
1192 aNdIdx = aTmp.GetPoint()->nNode;
1193 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
1194 }
1195 else
1196 pEditShell->DeleteSel( rDelPam );
1197 }
1198
DeleteAktNxtPara(const String & rNxtPara)1199 sal_Bool SwAutoFormat::DeleteAktNxtPara( const String& rNxtPara )
1200 {
1201 // Loesche Blanks am Ende vom akt. und am Anfang vom naechsten
1202 aDelPam.DeleteMark();
1203 aDelPam.GetPoint()->nNode = aNdIdx;
1204 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd,
1205 GetTrailingBlanks( pAktTxtNd->GetTxt() ) );
1206 aDelPam.SetMark();
1207
1208 aDelPam.GetPoint()->nNode++;
1209 SwTxtNode* pTNd = aDelPam.GetNode()->GetTxtNode();
1210 if( !pTNd )
1211 {
1212 // dann nur bis zum Ende von Absatz loeschen
1213 aDelPam.GetPoint()->nNode--;
1214 aDelPam.GetPoint()->nContent = pAktTxtNd->GetTxt().Len();
1215 }
1216 else
1217 aDelPam.GetPoint()->nContent.Assign( pTNd,
1218 GetLeadingBlanks( rNxtPara ));
1219
1220 // noch ein Blank am Anfang oder Ende ?
1221 // nicht loeschen, wird wieder eingefuegt.
1222 sal_Bool bHasBlnks = HasSelBlanks( aDelPam );
1223
1224 if( *aDelPam.GetPoint() != *aDelPam.GetMark() )
1225 DeleteSel( aDelPam );
1226 aDelPam.DeleteMark();
1227
1228 return !bHasBlnks;
1229 }
1230
1231
DelEmptyLine(sal_Bool bTstNextPara)1232 void SwAutoFormat::DelEmptyLine( sal_Bool bTstNextPara )
1233 {
1234 SetRedlineTxt( STR_AUTOFMTREDL_DEL_EMPTY_PARA );
1235 // Loesche Blanks den leeren Absatz
1236 aDelPam.DeleteMark();
1237 aDelPam.GetPoint()->nNode = aNdIdx;
1238 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, pAktTxtNd->GetTxt().Len() );
1239 aDelPam.SetMark();
1240
1241 aDelPam.GetMark()->nNode--;
1242 SwTxtNode* pTNd = aDelPam.GetNode( sal_False )->GetTxtNode();
1243 if( pTNd )
1244 // erstmal den vorherigen Textnode benutzen.
1245 aDelPam.GetMark()->nContent.Assign( pTNd, pTNd->GetTxt().Len() );
1246 else if( bTstNextPara )
1247 {
1248 // dann versuche den naechsten (am Anfang vom Dok, Tabellen-Zellen,
1249 // Rahmen, ...
1250 aDelPam.GetMark()->nNode += 2;
1251 pTNd = aDelPam.GetNode( sal_False )->GetTxtNode();
1252 if( pTNd )
1253 {
1254 aDelPam.GetMark()->nContent.Assign( pTNd, 0 );
1255 aDelPam.GetPoint()->nContent = 0;
1256 }
1257 }
1258 else
1259 {
1260 aDelPam.GetMark()->nNode = aNdIdx;
1261 aDelPam.GetMark()->nContent = 0;
1262 pTNd = pAktTxtNd;
1263 }
1264 if( pTNd )
1265 DeleteSel( aDelPam );
1266
1267 aDelPam.DeleteMark();
1268 ClearRedlineTxt();
1269 }
1270
1271
DelMoreLinesBlanks(sal_Bool bWithLineBreaks)1272 void SwAutoFormat::DelMoreLinesBlanks( sal_Bool bWithLineBreaks )
1273 {
1274 if( aFlags.bAFmtByInput
1275 ? aFlags.bAFmtByInpDelSpacesBetweenLines
1276 : aFlags.bAFmtDelSpacesBetweenLines )
1277 {
1278 // loesche alle "Blanks" Links und Rechts vom Einzug
1279 aDelPam.DeleteMark();
1280 aDelPam.GetPoint()->nNode = aNdIdx;
1281 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1282
1283 SwTxtFrmInfo aFInfo( pAktTxtFrm );
1284 aFInfo.GetSpaces( aDelPam, !aFlags.bAFmtByInput || bWithLineBreaks );
1285
1286 SwPaM* pNxt;
1287 do {
1288 pNxt = (SwPaM*)aDelPam.GetNext();
1289 if( pNxt->HasMark() && *pNxt->GetPoint() != *pNxt->GetMark() )
1290 {
1291 sal_Bool bHasBlnks = HasSelBlanks( *pNxt );
1292 DeleteSel( *pNxt );
1293 if( !bHasBlnks )
1294 {
1295 pDoc->InsertString( *pNxt, sal_Unicode(' ') );
1296 }
1297 }
1298
1299 if( pNxt == &aDelPam )
1300 break;
1301 delete pNxt;
1302 } while( sal_True );
1303
1304 aDelPam.DeleteMark();
1305 }
1306 }
1307
1308
1309 // loesche den vorherigen Absatz
DelPrevPara()1310 void SwAutoFormat::DelPrevPara()
1311 {
1312 aDelPam.DeleteMark();
1313 aDelPam.GetPoint()->nNode = aNdIdx;
1314 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1315 aDelPam.SetMark();
1316
1317 aDelPam.GetPoint()->nNode--;
1318 SwTxtNode* pTNd = aDelPam.GetNode()->GetTxtNode();
1319 if( pTNd )
1320 {
1321 // erstmal den vorherigen Textnode benutzen.
1322 aDelPam.GetPoint()->nContent.Assign( pTNd, pTNd->GetTxt().Len() );
1323 DeleteSel( aDelPam );
1324 }
1325 aDelPam.DeleteMark();
1326 }
1327
1328
BuildIndent()1329 void SwAutoFormat::BuildIndent()
1330 {
1331 SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_INDENT );
1332
1333 // lese alle nachfolgenden Absaetze die zu diesem Einzug gehoeren
1334 sal_Bool bBreak = sal_True;
1335 if( bMoreLines )
1336 DelMoreLinesBlanks( sal_True );
1337 else
1338 bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1339 IsBlanksInString( *pAktTxtNd ) ||
1340 IsSentenceAtEnd( *pAktTxtNd );
1341 SetColl( RES_POOLCOLL_TEXT_IDENT );
1342 if( !bBreak )
1343 {
1344 SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1345 const SwTxtNode* pNxtNd = GetNextNode();
1346 if( pNxtNd && !bEnde )
1347 {
1348 do {
1349 bBreak = !IsFastFullLine( *pNxtNd ) ||
1350 IsBlanksInString( *pNxtNd ) ||
1351 IsSentenceAtEnd( *pNxtNd );
1352 if( DeleteAktNxtPara( pNxtNd->GetTxt() ))
1353 {
1354 pDoc->InsertString( aDelPam, sal_Unicode(' ') );
1355 }
1356 if( bBreak )
1357 break;
1358 pNxtNd = GetNextNode();
1359 } while( CanJoin( pNxtNd ) &&
1360 !CalcLevel( *pNxtNd ) );
1361 }
1362 }
1363 DeleteAktPara( sal_True, sal_True );
1364 AutoCorrect();
1365 }
1366
1367
BuildTextIndent()1368 void SwAutoFormat::BuildTextIndent()
1369 {
1370 SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_TEXT_INDENT);
1371 // lese alle nachfolgenden Absaetze die zu diesem Einzug gehoeren
1372 sal_Bool bBreak = sal_True;
1373 if( bMoreLines )
1374 DelMoreLinesBlanks( sal_True );
1375 else
1376 bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1377 IsBlanksInString( *pAktTxtNd ) ||
1378 IsSentenceAtEnd( *pAktTxtNd );
1379
1380 if( aFlags.bAFmtByInput )
1381 pAktTxtNd->SetAutoFmtLvl( (sal_uInt8)CalcLevel( *pAktTxtNd ) );
1382
1383 SetColl( RES_POOLCOLL_TEXT_MOVE );
1384 if( !bBreak )
1385 {
1386 SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1387 const SwTxtNode* pNxtNd = GetNextNode();
1388 while( CanJoin( pNxtNd ) &&
1389 CalcLevel( *pNxtNd ) )
1390 {
1391 bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) ||
1392 IsSentenceAtEnd( *pNxtNd );
1393 if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
1394 {
1395 pDoc->InsertString( aDelPam, sal_Unicode(' ') );
1396 }
1397 if( bBreak )
1398 break;
1399 pNxtNd = GetNextNode();
1400 }
1401 }
1402 DeleteAktPara( sal_True, sal_True );
1403 AutoCorrect();
1404 }
1405
1406
BuildText()1407 void SwAutoFormat::BuildText()
1408 {
1409 SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_TEXT );
1410 // lese alle nachfolgenden Absaetze die zu diesem Text
1411 // ohne Einzug gehoeren
1412 sal_Bool bBreak = sal_True;
1413 if( bMoreLines )
1414 DelMoreLinesBlanks();
1415 else
1416 bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1417 IsBlanksInString( *pAktTxtNd ) ||
1418 IsSentenceAtEnd( *pAktTxtNd );
1419 SetColl( RES_POOLCOLL_TEXT, sal_True );
1420 if( !bBreak )
1421 {
1422 SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1423 const SwTxtNode* pNxtNd = GetNextNode();
1424 while( CanJoin( pNxtNd ) &&
1425 !CalcLevel( *pNxtNd ) )
1426 {
1427 bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) ||
1428 IsSentenceAtEnd( *pNxtNd );
1429 if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
1430 {
1431 pDoc->InsertString( aDelPam, sal_Unicode(' ') );
1432 }
1433 if( bBreak )
1434 break;
1435 const SwTxtNode* pCurrNode = pNxtNd;
1436 pNxtNd = GetNextNode();
1437 if(!pNxtNd || pCurrNode == pNxtNd)
1438 break;
1439 }
1440 }
1441 DeleteAktPara( sal_True, sal_True );
1442 AutoCorrect();
1443 }
1444
1445
BuildEnum(sal_uInt16 nLvl,sal_uInt16 nDigitLevel)1446 void SwAutoFormat::BuildEnum( sal_uInt16 nLvl, sal_uInt16 nDigitLevel )
1447 {
1448 SetRedlineTxt( STR_AUTOFMTREDL_SET_NUMBULET );
1449
1450 sal_Bool bBreak = sal_True;
1451
1452 // als erstes den akt. Einzug bestimmen und die Framebreite bestimmen
1453 SwTwips nFrmWidth = pAktTxtFrm->Prt().Width();;
1454 SwTwips nLeftTxtPos;
1455 {
1456 const sal_Unicode* pTxt = pAktTxtNd->GetTxt().GetBuffer(), *pSav = pTxt;
1457 while( IsSpace( *pTxt ) )
1458 ++pTxt;
1459
1460 SwTxtFrmInfo aInfo( pAktTxtFrm );
1461 nLeftTxtPos = aInfo.GetCharPos( static_cast<xub_StrLen>(pTxt - pSav) );
1462 nLeftTxtPos -= pAktTxtNd->GetSwAttrSet().GetLRSpace().GetLeft();
1463 }
1464
1465 if( bMoreLines )
1466 DelMoreLinesBlanks();
1467 else
1468 bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1469 IsBlanksInString( *pAktTxtNd ) ||
1470 IsSentenceAtEnd( *pAktTxtNd );
1471 sal_Bool bRTL = pEditShell->IsInRightToLeftText();
1472 // SetColl( RES_POOLCOLL_NUM_LEVEL1 + ( nLvl * 4 ) );
1473 DeleteAktPara( sal_True, sal_True );
1474
1475 sal_Bool bChgBullet = sal_False, bChgEnum = sal_False;
1476 xub_StrLen nAutoCorrPos = 0;
1477
1478 // falls die Numerierung gesetzt werden, die akt. besorgen
1479 // --> OD 2008-02-11 #newlistlevelattrs#
1480 SwNumRule aRule( pDoc->GetUniqueNumRuleName(),
1481 // --> OD 2008-06-06 #i89178#
1482 numfunc::GetDefaultPositionAndSpaceMode() );
1483 // <--
1484 // <--
1485 const SwNumRule* pCur = 0;
1486 if( aFlags.bSetNumRule && 0 != (pCur = pAktTxtNd->GetNumRule()) )
1487 aRule = *pCur;
1488
1489 // ersetze das Bullet-Zeichen mit dem definiertem
1490 const String& rStr = pAktTxtNd->GetTxt();
1491 xub_StrLen nTxtStt = 0, nOrigTxtStt = 0;
1492 const sal_Unicode* pFndBulletChr;
1493 // if( aFlags.bAFmtByInput ? aFlags.bSetNumRule : aFlags.bChgEnumNum &&
1494 if( aFlags.bChgEnumNum &&
1495 2 < rStr.Len() &&
1496 0 != ( pFndBulletChr = StrChr( pBulletChar, rStr.GetChar( nTxtStt ) ))
1497 && IsSpace( rStr.GetChar( nTxtStt + 1 ) ) )
1498 {
1499 if( aFlags.bAFmtByInput )
1500 {
1501 if( aFlags.bSetNumRule )
1502 {
1503 SwCharFmt* pCFmt = pDoc->GetCharFmtFromPool(
1504 RES_POOLCHR_BUL_LEVEL );
1505 bChgBullet = sal_True;
1506 // wurde das Format schon mal angepasst?
1507 if( !aRule.GetNumFmt( nLvl ) )
1508 {
1509 int nBulletPos = pFndBulletChr - pBulletChar;
1510 sal_Unicode cBullChar;
1511 const Font* pBullFnt( 0 );
1512 if( nBulletPos < cnPosEnDash )
1513 {
1514 cBullChar = aFlags.cBullet;
1515 pBullFnt = &aFlags.aBulletFont;
1516 }
1517 else
1518 {
1519 cBullChar = nBulletPos < cnPosEmDash
1520 ? cStarSymbolEnDash
1521 : cStarSymbolEmDash;
1522 // --> OD 2008-06-03 #i63395#
1523 // Only apply user defined default bullet font
1524 if ( numfunc::IsDefBulletFontUserDefined() )
1525 {
1526 pBullFnt = &numfunc::GetDefBulletFont();
1527 }
1528 // <--
1529 }
1530
1531 sal_uInt16 nAbsPos = lBullIndent;
1532 sal_uInt16 nSpaceSteps = nLvl
1533 ? sal_uInt16(nLeftTxtPos / nLvl)
1534 : lBullIndent;
1535 for( sal_uInt8 n = 0; n < MAXLEVEL; ++n, nAbsPos = nAbsPos + nSpaceSteps )
1536 {
1537 SwNumFmt aFmt( aRule.Get( n ) );
1538 aFmt.SetBulletFont( pBullFnt );
1539 aFmt.SetBulletChar( cBullChar );
1540 aFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
1541 // #i93908# clear suffix for bullet lists
1542 aFmt.SetPrefix(::rtl::OUString());
1543 aFmt.SetSuffix(::rtl::OUString());
1544 aFmt.SetFirstLineOffset( lBullFirstLineOffset );
1545 aFmt.SetAbsLSpace( nAbsPos );
1546 if( !aFmt.GetCharFmt() )
1547 aFmt.SetCharFmt( pCFmt );
1548 if( bRTL )
1549 aFmt.SetNumAdjust( SVX_ADJUST_RIGHT );
1550
1551 aRule.Set( n, aFmt );
1552
1553 if( n == nLvl &&
1554 nFrmWidth < ( nSpaceSteps * MAXLEVEL ) )
1555 nSpaceSteps = static_cast<sal_uInt16>(( nFrmWidth - nLeftTxtPos ) /
1556 ( MAXLEVEL - nLvl ));
1557 }
1558 }
1559 }
1560 }
1561 else
1562 {
1563 bChgBullet = sal_True;
1564 SetColl( static_cast<sal_uInt16>(RES_POOLCOLL_BUL_LEVEL1 + ( Min( nLvl, cnNumBullColls ) * 4 )) );
1565 }
1566 }
1567 else
1568 {
1569 // dann ist das eine Nummerierung
1570
1571 //JP 21.11.97: Der NumLevel wird entweder der DigitLevel oder
1572 // wenn der nicht vorhanden oder 0 ist, durch den
1573 // (Einrueckungs-)Level.
1574
1575 String aPostFix, aPreFix, aNumTypes;
1576 if( USHRT_MAX != ( nDigitLevel = GetDigitLevel( *pAktTxtNd, nTxtStt,
1577 &aPreFix, &aPostFix, &aNumTypes )) )
1578 {
1579 bChgEnum = sal_True;
1580
1581 // Ebene 0 und Einrueckung dann wird die Ebene durch den linken
1582 // Einzug und der default NumEinrueckung bestimmt.
1583 if( !nDigitLevel && nLeftTxtPos )
1584 nLvl = Min( sal_uInt16( nLeftTxtPos / lNumIndent ),
1585 sal_uInt16( MAXLEVEL - 1 ) );
1586 else
1587 nLvl = nDigitLevel;
1588 }
1589
1590 if( bChgEnum && aFlags.bSetNumRule )
1591 {
1592 if( !pCur ) // NumRule anpassen, wenn sie neu ist
1593 {
1594 SwCharFmt* pCFmt = pDoc->GetCharFmtFromPool(
1595 RES_POOLCHR_NUM_LEVEL );
1596 if( !nDigitLevel )
1597 {
1598 SwNumFmt aFmt( aRule.Get( nLvl ) );
1599 aFmt.SetStart( static_cast<sal_uInt16>(aPreFix.GetToken( 1,
1600 (sal_Unicode)1 ).ToInt32()));
1601 aFmt.SetPrefix( aPreFix.GetToken( 0, (sal_Unicode)1 ));
1602 aFmt.SetSuffix( aPostFix.GetToken( 0, (sal_Unicode)1 ));
1603 aFmt.SetIncludeUpperLevels( 0 );
1604
1605 if( !aFmt.GetCharFmt() )
1606 aFmt.SetCharFmt( pCFmt );
1607
1608 if( aNumTypes.Len() )
1609 aFmt.SetNumberingType(aNumTypes.GetChar( 0 ) - '0');
1610
1611 if( bRTL )
1612 aFmt.SetNumAdjust( SVX_ADJUST_RIGHT );
1613 aRule.Set( nLvl, aFmt );
1614 }
1615 else
1616 {
1617 sal_uInt16 nSpaceSteps = nLvl ? sal_uInt16(nLeftTxtPos / nLvl) : 0;
1618 sal_uInt8 n;
1619 for( n = 0; n <= nLvl; ++n )
1620 {
1621 SwNumFmt aFmt( aRule.Get( n ) );
1622
1623 aFmt.SetStart( static_cast<sal_uInt16>(aPreFix.GetToken( n+1,
1624 (sal_Unicode)1 ).ToInt32() ));
1625 if( !n )
1626 aFmt.SetPrefix( aPreFix.GetToken( n, (sal_Unicode)1 ));
1627 aFmt.SetSuffix( aPostFix.GetToken( n, (sal_Unicode)1 ));
1628 aFmt.SetIncludeUpperLevels( MAXLEVEL );
1629 if( n < aNumTypes.Len() )
1630 aFmt.SetNumberingType((aNumTypes.GetChar( n ) - '0'));
1631
1632 aFmt.SetAbsLSpace( sal_uInt16( nSpaceSteps * n )
1633 + lNumIndent );
1634
1635 if( !aFmt.GetCharFmt() )
1636 aFmt.SetCharFmt( pCFmt );
1637 if( bRTL )
1638 aFmt.SetNumAdjust( SVX_ADJUST_RIGHT );
1639
1640 aRule.Set( n, aFmt );
1641 }
1642
1643 // passt alles vollstaendig in den Frame?
1644 sal_Bool bDefStep = nFrmWidth < (nSpaceSteps * MAXLEVEL);
1645 for( ; n < MAXLEVEL; ++n )
1646 {
1647 SwNumFmt aFmt( aRule.Get( n ) );
1648 aFmt.SetIncludeUpperLevels( MAXLEVEL );
1649 if( bDefStep )
1650 aFmt.SetAbsLSpace( sal_uInt16( (nLeftTxtPos +
1651 SwNumRule::GetNumIndent(static_cast<sal_uInt8>(n-nLvl)))));
1652 else
1653 aFmt.SetAbsLSpace( sal_uInt16( nSpaceSteps * n )
1654 + lNumIndent );
1655 aRule.Set( n, aFmt );
1656 }
1657 }
1658 }
1659 }
1660 else if( !aFlags.bAFmtByInput )
1661 SetColl( static_cast<sal_uInt16>(RES_POOLCOLL_NUM_LEVEL1 + ( Min( nLvl, cnNumBullColls ) * 4 ) ));
1662 else
1663 bChgEnum = sal_False;
1664 }
1665
1666 if( bChgEnum || bChgBullet )
1667 {
1668 aDelPam.DeleteMark();
1669 aDelPam.GetPoint()->nNode = aNdIdx;
1670
1671 if( aFlags.bSetNumRule )
1672 {
1673 if( aFlags.bAFmtByInput )
1674 {
1675 aDelPam.SetMark();
1676 aDelPam.GetMark()->nNode++;
1677 aDelPam.GetNode(sal_False)->GetTxtNode()->SetAttrListLevel( nLvl );
1678 }
1679
1680 pAktTxtNd->SetAttrListLevel(nLvl);
1681 pAktTxtNd->SetNumLSpace( sal_True );
1682
1683 // --> OD 2008-03-17 #refactorlists#
1684 // start new list
1685 pDoc->SetNumRule( aDelPam, aRule, true );
1686 // <--
1687 aDelPam.DeleteMark();
1688
1689 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1690 }
1691 else
1692 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd,
1693 bChgEnum ? (nTxtStt - nOrigTxtStt) : 0 );
1694 aDelPam.SetMark();
1695
1696 if( bChgBullet )
1697 nTxtStt += 2;
1698
1699 while( nTxtStt < rStr.Len() && IsSpace( rStr.GetChar( nTxtStt ) ))
1700 nTxtStt++;
1701
1702 aDelPam.GetPoint()->nContent = nTxtStt - nOrigTxtStt;
1703 DeleteSel( aDelPam );
1704
1705 if( !aFlags.bSetNumRule )
1706 {
1707 String sChgStr( '\t' );
1708 if( bChgBullet )
1709 sChgStr.Insert( aFlags.cBullet, 0 );
1710 pDoc->InsertString( aDelPam, sChgStr );
1711
1712 SfxItemSet aSet( pDoc->GetAttrPool(), aTxtNodeSetRange );
1713 if( bChgBullet )
1714 {
1715 aDelPam.GetPoint()->nContent = 0;
1716 aDelPam.SetMark();
1717 aDelPam.GetMark()->nContent = 1;
1718 SetAllScriptItem( aSet,
1719 SvxFontItem( aFlags.aBulletFont.GetFamily(),
1720 aFlags.aBulletFont.GetName(),
1721 aFlags.aBulletFont.GetStyleName(),
1722 aFlags.aBulletFont.GetPitch(),
1723 aFlags.aBulletFont.GetCharSet(),
1724 RES_CHRATR_FONT ) );
1725 pDoc->SetFmtItemByAutoFmt( aDelPam, aSet );
1726 aDelPam.DeleteMark();
1727 nAutoCorrPos = 2;
1728 aSet.ClearItem();
1729 }
1730 SvxTabStopItem aTStops( RES_PARATR_TABSTOP ); aTStops.Insert( SvxTabStop( 0 ));
1731 aSet.Put( aTStops );
1732 pDoc->SetFmtItemByAutoFmt( aDelPam, aSet );
1733 }
1734 }
1735
1736 if( bBreak )
1737 {
1738 AutoCorrect( nAutoCorrPos ); /* Offset wegen Bullet + Tab */
1739 return;
1740 }
1741
1742 const SwTxtNode* pNxtNd = GetNextNode();
1743 while( CanJoin( pNxtNd ) &&
1744 nLvl == CalcLevel( *pNxtNd ) )
1745 {
1746 SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1747 bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) ||
1748 IsSentenceAtEnd( *pNxtNd );
1749 if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
1750 {
1751 pDoc->InsertString( aDelPam, sal_Unicode(' ') );
1752 }
1753 if( bBreak )
1754 break;
1755 const SwTxtNode* pCurrNode = pNxtNd;
1756 pNxtNd = GetNextNode();
1757 if(!pNxtNd || pCurrNode == pNxtNd)
1758 break;
1759 }
1760 DeleteAktPara( sal_False, sal_True );
1761 AutoCorrect( nAutoCorrPos );
1762 }
1763
1764
BuildNegIndent(SwTwips nSpaces)1765 void SwAutoFormat::BuildNegIndent( SwTwips nSpaces )
1766 {
1767 SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_NEG_INDENT );
1768 // Test auf Gegenueberstellung:
1769 // (n Worte, durch Space/Tabs getrennt, mit gleicher
1770 // Einrueckung in der 2.Zeile)
1771
1772 // lese alle nachfolgenden Absaetze die zu dieser Aufzaehlung gehoeren
1773 sal_Bool bBreak = sal_True;
1774 xub_StrLen nSpacePos, nTxtPos = GetBigIndent( nSpacePos );
1775 if( bMoreLines )
1776 DelMoreLinesBlanks( sal_True );
1777 else
1778 bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1779 ( !nTxtPos && IsBlanksInString( *pAktTxtNd )) ||
1780 IsSentenceAtEnd( *pAktTxtNd );
1781
1782 SetColl( static_cast<sal_uInt16>( nTxtPos
1783 ? RES_POOLCOLL_CONFRONTATION
1784 : RES_POOLCOLL_TEXT_NEGIDENT ) );
1785
1786 if( nTxtPos )
1787 {
1788 const String& rStr = pAktTxtNd->GetTxt();
1789 sal_Bool bInsTab = sal_True;
1790
1791 if( '\t' == rStr.GetChar( nSpacePos+1 )) // ein Tab, das belassen wir
1792 {
1793 --nSpacePos;
1794 bInsTab = sal_False;
1795 }
1796
1797 xub_StrLen nSpaceStt = nSpacePos;
1798 while( nSpaceStt && IsSpace( rStr.GetChar( --nSpaceStt ) ) )
1799 ;
1800 ++nSpaceStt;
1801
1802 if( bInsTab && '\t' == rStr.GetChar( nSpaceStt ) ) // ein Tab, das belassen wir
1803 {
1804 ++nSpaceStt;
1805 bInsTab = sal_False;
1806 }
1807
1808
1809 aDelPam.DeleteMark();
1810 aDelPam.GetPoint()->nNode = aNdIdx;
1811 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, nSpacePos );
1812
1813 // alten Spaces, usw. loeschen
1814 if( nSpaceStt < nSpacePos )
1815 {
1816 aDelPam.SetMark();
1817 aDelPam.GetMark()->nContent = nSpaceStt;
1818 DeleteSel( aDelPam );
1819 if( bInsTab )
1820 {
1821 pDoc->InsertString( aDelPam, sal_Unicode('\t') );
1822 }
1823 }
1824 }
1825
1826 if( !bBreak )
1827 {
1828 SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1829 SwTxtFrmInfo aFInfo( pAktTxtFrm );
1830 const SwTxtNode* pNxtNd = GetNextNode();
1831 while( CanJoin( pNxtNd ) &&
1832 20 < Abs( (long)(nSpaces - aFInfo.SetFrm(
1833 GetFrm( *pNxtNd ) ).GetLineStart() ))
1834 )
1835 {
1836 bBreak = !IsFastFullLine( *pNxtNd ) ||
1837 IsBlanksInString( *pNxtNd ) ||
1838 IsSentenceAtEnd( *pNxtNd );
1839 if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
1840 {
1841 pDoc->InsertString( aDelPam, sal_Unicode(' ') );
1842 }
1843 if( bBreak )
1844 break;
1845 pNxtNd = GetNextNode();
1846 }
1847 }
1848 DeleteAktPara( sal_True, sal_True );
1849 AutoCorrect();
1850 }
1851
1852
BuildHeadLine(sal_uInt16 nLvl)1853 void SwAutoFormat::BuildHeadLine( sal_uInt16 nLvl )
1854 {
1855 if( aFlags.bWithRedlining )
1856 {
1857 String sTxt( *ViewShell::GetShellRes()->GetAutoFmtNameLst()[
1858 STR_AUTOFMTREDL_SET_TMPL_HEADLINE ] );
1859 sTxt.SearchAndReplace( String::CreateFromAscii(
1860 RTL_CONSTASCII_STRINGPARAM( "$(ARG1)" )),
1861 String::CreateFromInt32( nLvl + 1 ) );
1862 pDoc->SetAutoFmtRedlineComment( &sTxt );
1863 }
1864
1865 SetColl( static_cast<sal_uInt16>(RES_POOLCOLL_HEADLINE1 + nLvl ), sal_True );
1866 if( aFlags.bAFmtByInput )
1867 {
1868 SwTxtFmtColl& rNxtColl = pAktTxtNd->GetTxtColl()->GetNextTxtFmtColl();
1869
1870 DelPrevPara();
1871
1872 DeleteAktPara( sal_True, sal_False );
1873 DeleteAktNxtPara( aEmptyStr );
1874
1875 aDelPam.DeleteMark();
1876 aDelPam.GetPoint()->nNode = aNdIdx.GetIndex() + 1;
1877 aDelPam.GetPoint()->nContent.Assign( aDelPam.GetCntntNode(), 0 );
1878 pDoc->SetTxtFmtColl( aDelPam, &rNxtColl );
1879 }
1880 else
1881 {
1882 DeleteAktPara( sal_True, sal_True );
1883 AutoCorrect();
1884 }
1885 }
1886
1887
1888 // dann lasse doch mal das AutoCorrect auf den akt. TextNode los
AutoCorrect(xub_StrLen nPos)1889 void SwAutoFormat::AutoCorrect( xub_StrLen nPos )
1890 {
1891 SvxAutoCorrect* pATst = SvxAutoCorrCfg::Get()->GetAutoCorrect();
1892 long aSvxFlags = pATst->GetFlags( );
1893 bool bReplaceQuote = ( aSvxFlags & ChgQuotes ) > 0;
1894 bool bReplaceSglQuote = ( aSvxFlags & ChgSglQuotes ) > 0;
1895
1896 if( aFlags.bAFmtByInput ||
1897 (!aFlags.bAutoCorrect && !bReplaceQuote && !bReplaceSglQuote &&
1898 !aFlags.bCptlSttSntnc && !aFlags.bCptlSttWrd &&
1899 !aFlags.bChgOrdinalNumber &&
1900 !aFlags.bChgToEnEmDash && !aFlags.bSetINetAttr &&
1901 !aFlags.bChgWeightUnderl && !aFlags.bAddNonBrkSpace) )
1902 return;
1903
1904 const String* pTxt = &pAktTxtNd->GetTxt();
1905 if( nPos >= pTxt->Len() )
1906 return;
1907
1908 sal_Bool bGetLanguage = aFlags.bChgOrdinalNumber ||
1909 aFlags.bChgToEnEmDash || aFlags.bSetINetAttr ||
1910 aFlags.bCptlSttWrd || aFlags.bCptlSttSntnc ||
1911 aFlags.bAddNonBrkSpace;
1912
1913
1914 aDelPam.DeleteMark();
1915 aDelPam.GetPoint()->nNode = aNdIdx;
1916 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1917
1918 SwAutoCorrDoc aACorrDoc( *pEditShell, aDelPam );
1919
1920 SwTxtFrmInfo aFInfo( 0 );
1921
1922 xub_StrLen nSttPos, nLastBlank = nPos;
1923 sal_Bool bFirst = aFlags.bCptlSttSntnc, bFirstSent = bFirst;
1924 sal_Unicode cChar = 0;
1925
1926 CharClass& rAppCC = GetAppCharClass();
1927
1928 do {
1929 while( nPos < pTxt->Len() && IsSpace( cChar = pTxt->GetChar( nPos ) ))
1930 ++nPos;
1931 if( nPos == pTxt->Len() )
1932 break; // das wars
1933
1934 if( ( ( bReplaceQuote && '\"' == cChar ) ||
1935 ( bReplaceSglQuote && '\'' == cChar ) ) &&
1936 ( !nPos || ' ' == pTxt->GetChar( nPos-1 ) ) )
1937 {
1938 // --------------------------------------
1939 // beachte: Sonderfall Symbolfonts !!!
1940 if( !aFInfo.GetFrm() )
1941 aFInfo.SetFrm( GetFrm( *pAktTxtNd ) );
1942 if( !aFInfo.IsBullet( nPos ))
1943 {
1944 SetRedlineTxt( STR_AUTOFMTREDL_TYPO );
1945 aDelPam.GetPoint()->nContent = nPos;
1946 sal_Bool bSetHardBlank = sal_False;
1947
1948 String sReplace( pATst->GetQuote( aACorrDoc,
1949 nPos, cChar, sal_True ));
1950
1951 aDelPam.SetMark();
1952 aDelPam.GetPoint()->nContent = nPos+1;
1953 if( 2 == sReplace.Len() && ' ' == sReplace.GetChar( 1 ))
1954 {
1955 sReplace.Erase( 1 );
1956 bSetHardBlank = sal_True;
1957 }
1958 pDoc->ReplaceRange( aDelPam, sReplace, false );
1959
1960 if( aFlags.bWithRedlining )
1961 {
1962 aNdIdx = aDelPam.GetPoint()->nNode;
1963 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
1964 pTxt = &pAktTxtNd->GetTxt();
1965 aDelPam.SetMark();
1966 aFInfo.SetFrm( 0 );
1967 }
1968
1969 nPos += sReplace.Len() - 1;
1970 aDelPam.DeleteMark();
1971 if( bSetHardBlank )
1972 {
1973 pDoc->InsertString( aDelPam, CHAR_HARDBLANK );
1974 ++nPos;
1975 }
1976 }
1977 }
1978
1979 int bCallACorr = sal_False;
1980 int bBreak = 0;
1981 if( nPos && IsSpace( pTxt->GetChar( nPos-1 )))
1982 nLastBlank = nPos;
1983 for( nSttPos = nPos; !bBreak && nPos < pTxt->Len(); ++nPos )
1984 switch( cChar = pTxt->GetChar( nPos ) )
1985 {
1986 case '\"':
1987 case '\'':
1988 if( ( cChar == '\"' && bReplaceQuote ) || ( cChar == '\'' && bReplaceSglQuote ) )
1989 {
1990 // --------------------------------------
1991 // beachte: Sonderfall Symbolfonts !!!
1992 if( !aFInfo.GetFrm() )
1993 aFInfo.SetFrm( GetFrm( *pAktTxtNd ) );
1994 if( !aFInfo.IsBullet( nPos ))
1995 {
1996 SetRedlineTxt( STR_AUTOFMTREDL_TYPO );
1997 sal_Bool bSetHardBlank = sal_False;
1998 aDelPam.GetPoint()->nContent = nPos;
1999 String sReplace( pATst->GetQuote( aACorrDoc,
2000 nPos, cChar, sal_False ));
2001
2002 if( 2 == sReplace.Len() && ' ' == sReplace.GetChar( 0 ))
2003 {
2004 sReplace.Erase( 0, 1 );
2005 bSetHardBlank = sal_True;
2006 }
2007
2008 aDelPam.SetMark();
2009 aDelPam.GetPoint()->nContent = nPos+1;
2010 pDoc->ReplaceRange( aDelPam, sReplace, false );
2011
2012 if( aFlags.bWithRedlining )
2013 {
2014 aNdIdx = aDelPam.GetPoint()->nNode;
2015 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
2016 pTxt = &pAktTxtNd->GetTxt();
2017 aDelPam.SetMark();
2018 aDelPam.DeleteMark();
2019 aFInfo.SetFrm( 0 );
2020 }
2021
2022 nPos += sReplace.Len() - 1;
2023 aDelPam.DeleteMark();
2024
2025 if( bSetHardBlank )
2026 {
2027 aDelPam.GetPoint()->nContent = nPos;
2028 pDoc->InsertString( aDelPam, CHAR_HARDBLANK );
2029 aDelPam.GetPoint()->nContent = ++nPos;
2030 }
2031 }
2032 }
2033 break;
2034 case '*':
2035 case '_':
2036 if( aFlags.bChgWeightUnderl )
2037 {
2038 // --------------------------------------
2039 // beachte: Sonderfall Symbolfonts !!!
2040 if( !aFInfo.GetFrm() )
2041 aFInfo.SetFrm( GetFrm( *pAktTxtNd ) );
2042 if( !aFInfo.IsBullet( nPos ))
2043 {
2044 SetRedlineTxt( '*' == cChar
2045 ? STR_AUTOFMTREDL_BOLD
2046 : STR_AUTOFMTREDL_UNDER );
2047
2048 sal_Unicode cBlank = nSttPos ? pTxt->GetChar(nSttPos - 1) : 0;
2049 aDelPam.GetPoint()->nContent = nPos;
2050
2051 if( pATst->FnChgWeightUnderl( aACorrDoc, *pTxt,
2052 nSttPos, nPos ))
2053 {
2054 if( aFlags.bWithRedlining )
2055 {
2056 aNdIdx = aDelPam.GetPoint()->nNode;
2057 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
2058 pTxt = &pAktTxtNd->GetTxt();
2059 aDelPam.SetMark();
2060 aDelPam.DeleteMark();
2061 aFInfo.SetFrm( 0 );
2062 }
2063 //#125102# in case of the mode REDLINE_SHOW_DELETE the ** are still contained in pTxt
2064 if(0 == (pDoc->GetRedlineMode() & nsRedlineMode_t::REDLINE_SHOW_DELETE))
2065 nPos = aDelPam.GetPoint()->nContent.GetIndex() - 1;
2066 // wurde vorm Start ein Zeichen entfernt?
2067 if( cBlank && cBlank != pTxt->GetChar(nSttPos - 1) )
2068 --nSttPos;
2069 }
2070 }
2071 }
2072 break;
2073 case '/':
2074 if ( aFlags.bAddNonBrkSpace )
2075 {
2076 LanguageType eLang = (bGetLanguage && pAktTxtNd)
2077 ? pAktTxtNd->GetLang( nSttPos )
2078 : LANGUAGE_SYSTEM;
2079
2080 SetRedlineTxt( STR_AUTOFMTREDL_NON_BREAK_SPACE );
2081 if ( pATst->FnAddNonBrkSpace( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) )
2082 --nPos;
2083 }
2084 break;
2085
2086 case '.':
2087 case '!':
2088 case '?':
2089 if( aFlags.bCptlSttSntnc )
2090 bFirstSent = sal_True;
2091 //alle Wortrenner loesen die Autokorrektur aus!
2092 // break;
2093 default:
2094 //alle Wortrenner loesen die Autokorrektur aus!
2095 // case ' ':
2096 // case '\t':
2097 if( !( rAppCC.isLetterNumeric( *pTxt, nPos )
2098 || '/' == cChar )) // '/' should not be a word seperator (e.g. '1/2' needs to be handled as one word for replacement)
2099 {
2100 --nPos; // ++nPos von dem for ungueltig machen !
2101 ++bBreak;
2102 }
2103 break;
2104 }
2105
2106 if( nPos == nSttPos )
2107 {
2108 if( ++nPos == pTxt->Len() )
2109 bCallACorr = sal_True;
2110 }
2111 else
2112 bCallACorr = sal_True;
2113
2114
2115 if( bCallACorr )
2116 {
2117 bCallACorr = sal_False;
2118 aDelPam.GetPoint()->nContent = nPos;
2119 SetRedlineTxt( STR_AUTOFMTREDL_USE_REPLACE );
2120 if( aFlags.bAutoCorrect &&
2121 aACorrDoc.ChgAutoCorrWord( nSttPos, nPos, *pATst, 0 ) )
2122 {
2123 nPos = aDelPam.GetPoint()->nContent.GetIndex();
2124
2125 if( aFlags.bWithRedlining )
2126 {
2127 aNdIdx = aDelPam.GetPoint()->nNode;
2128 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
2129 pTxt = &pAktTxtNd->GetTxt();
2130 aDelPam.SetMark();
2131 aDelPam.DeleteMark();
2132 }
2133
2134 continue; // nichts weiter mehr abpruefen
2135 }
2136
2137 LanguageType eLang = (bGetLanguage && pAktTxtNd)
2138 ? pAktTxtNd->GetLang( nSttPos )
2139 : LANGUAGE_SYSTEM;
2140
2141 if ( aFlags.bAddNonBrkSpace )
2142 {
2143 SetRedlineTxt( STR_AUTOFMTREDL_NON_BREAK_SPACE );
2144 pATst->FnAddNonBrkSpace( aACorrDoc, *pTxt, nSttPos, nPos, eLang );
2145 }
2146
2147 if( ( aFlags.bChgOrdinalNumber &&
2148 SetRedlineTxt( STR_AUTOFMTREDL_ORDINAL ) &&
2149 pATst->FnChgOrdinalNumber( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) ) ||
2150 ( aFlags.bChgToEnEmDash &&
2151 SetRedlineTxt( STR_AUTOFMTREDL_DASH ) &&
2152 pATst->FnChgToEnEmDash( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) ) ||
2153 ( aFlags.bSetINetAttr &&
2154 ( nPos == pTxt->Len() || IsSpace( pTxt->GetChar( nPos )) ) &&
2155 SetRedlineTxt( STR_AUTOFMTREDL_DETECT_URL ) &&
2156 pATst->FnSetINetAttr( aACorrDoc, *pTxt, nLastBlank, nPos, eLang ) ) )
2157 nPos = aDelPam.GetPoint()->nContent.GetIndex();
2158 else
2159 {
2160 // Zwei Grossbuchstaben am Wort-Anfang ??
2161 if( aFlags.bCptlSttWrd )
2162 {
2163 SetRedlineTxt( STR_AUTOFMTREDL_CPTL_STT_WORD );
2164 pATst->FnCptlSttWrd( aACorrDoc, *pTxt, nSttPos, nPos, eLang );
2165 }
2166 // Grossbuchstabe am Satz-Anfang ??
2167 if( aFlags.bCptlSttSntnc && bFirst )
2168 {
2169 SetRedlineTxt( STR_AUTOFMTREDL_CPTL_STT_SENT );
2170 pATst->FnCptlSttSntnc( aACorrDoc, *pTxt, sal_True, nSttPos, nPos, eLang);
2171 bFirst = sal_False;
2172 }
2173
2174 bFirst = bFirstSent;
2175 bFirstSent = sal_False;
2176
2177 if( aFlags.bWithRedlining )
2178 {
2179 aNdIdx = aDelPam.GetPoint()->nNode;
2180 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
2181 pTxt = &pAktTxtNd->GetTxt();
2182 aDelPam.SetMark();
2183 aDelPam.DeleteMark();
2184 }
2185 }
2186 }
2187 } while( nPos < pTxt->Len() );
2188 ClearRedlineTxt();
2189 }
2190
2191
SwAutoFormat(SwEditShell * pEdShell,SvxSwAutoFmtFlags & rFlags,SwNodeIndex * pSttNd,SwNodeIndex * pEndNd)2192 SwAutoFormat::SwAutoFormat( SwEditShell* pEdShell, SvxSwAutoFmtFlags& rFlags,
2193 SwNodeIndex* pSttNd, SwNodeIndex* pEndNd )
2194 : aFlags( rFlags ),
2195 aDelPam( pEdShell->GetDoc()->GetNodes().GetEndOfExtras() ),
2196 aNdIdx( pEdShell->GetDoc()->GetNodes().GetEndOfExtras(), +1 ),
2197 aEndNdIdx( pEdShell->GetDoc()->GetNodes().GetEndOfContent() ),
2198 pEditShell( pEdShell ),
2199 pDoc( pEdShell->GetDoc() ),
2200 pAktTxtNd( 0 ), pAktTxtFrm( 0 ),
2201 pCharClass( 0 ),
2202 nRedlAutoFmtSeqId( 0 )
2203 {
2204 ASSERT( (pSttNd && pEndNd) || (!pSttNd && !pEndNd),
2205 "Kein Bereich angegeben" );
2206
2207 if( aFlags.bSetNumRule && !aFlags.bAFmtByInput )
2208 aFlags.bSetNumRule = sal_False;
2209
2210 sal_Bool bReplaceStyles = !aFlags.bAFmtByInput || aFlags.bReplaceStyles;
2211
2212 const SwTxtNode* pNxtNd = 0;
2213 sal_Bool bNxtEmpty = sal_False;
2214 sal_Bool bNxtAlpha = sal_False;
2215 sal_uInt16 nNxtLevel = 0;
2216
2217 // setze den Bereich zum Autoformatieren
2218 if( pSttNd )
2219 {
2220 aNdIdx = *pSttNd;
2221 aNdIdx--; // fuer GoNextPara, ein Absatz davor
2222 aEndNdIdx = *pEndNd;
2223 aEndNdIdx++;
2224
2225 // teste den vorhergehenden TextNode
2226 pNxtNd = aNdIdx.GetNode().GetTxtNode();
2227 bEmptyLine = !pNxtNd ||
2228 IsEmptyLine( *pNxtNd ) ||
2229 IsNoAlphaLine( *pNxtNd );
2230 }
2231 else
2232 bEmptyLine = sal_True; // am Dokument Anfang
2233
2234 bEnde = sal_False;
2235
2236 // setze die Werte fuer die Prozent-Anzeige
2237 nEndNdIdx = aEndNdIdx.GetIndex();
2238
2239 if( !aFlags.bAFmtByInput )
2240 ::StartProgress( STR_STATSTR_AUTOFORMAT, aNdIdx.GetIndex(),
2241 nEndNdIdx = aEndNdIdx.GetIndex(),
2242 pDoc->GetDocShell() );
2243
2244 RedlineMode_t eRedlMode = pDoc->GetRedlineMode(), eOldMode = eRedlMode;
2245 if( aFlags.bWithRedlining )
2246 {
2247 pDoc->SetAutoFmtRedline( sal_True );
2248 eRedlMode = (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT);
2249 }
2250 else
2251 eRedlMode = (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_IGNORE);
2252 pDoc->SetRedlineMode( eRedlMode );
2253
2254 // save undo state (might be turned off)
2255 bool const bUndoState = pDoc->GetIDocumentUndoRedo().DoesUndo();
2256
2257 // wenn mehrere Zeilen, dann erstmal nicht mit
2258 // dem nachfolgenden Absatz zusammenfassen.
2259 bMoreLines = sal_False;
2260
2261 nLastCalcHeadLvl = nLastCalcEnumLvl = 0;
2262 nLastHeadLvl = nLastEnumLvl = USHRT_MAX;
2263 sal_uInt16 nLevel = 0;
2264 sal_uInt16 nDigitLvl = 0;
2265
2266 // defaulten
2267 SwTxtFrmInfo aFInfo( 0 );
2268
2269 // das ist unser Automat fuer die Auto-Formatierung
2270 eStat = READ_NEXT_PARA;
2271 while( !bEnde )
2272 {
2273 switch( eStat )
2274 {
2275 case READ_NEXT_PARA:
2276 {
2277 GoNextPara();
2278 eStat = bEnde ? IS_ENDE : TST_EMPTY_LINE;
2279 }
2280 break;
2281
2282 case TST_EMPTY_LINE:
2283 if( IsEmptyLine( *pAktTxtNd ) )
2284 {
2285 if( aFlags.bDelEmptyNode && !HasObjects( *pAktTxtNd ) )
2286 {
2287 bEmptyLine = sal_True;
2288 sal_uLong nOldCnt = pDoc->GetNodes().Count();
2289 DelEmptyLine();
2290 // wurde wiklich ein Node geloescht ?
2291 if( nOldCnt != pDoc->GetNodes().Count() )
2292 aNdIdx--; // nicht den naechsten Absatz ueberspringen
2293 }
2294 eStat = READ_NEXT_PARA;
2295 }
2296 else
2297 eStat = TST_ALPHA_LINE;
2298 break;
2299
2300 case TST_ALPHA_LINE:
2301 if( IsNoAlphaLine( *pAktTxtNd ))
2302 {
2303 // erkenne eine Tabellendefinition +---+---+
2304 if( aFlags.bAFmtByInput && aFlags.bCreateTable && DoTable() )
2305 {
2306 //JP 30.09.96: das DoTable() verlaesst sich auf das
2307 // Pop und Move - Crsr nach dem AutoFormat!
2308 pEdShell->Pop( sal_False );
2309 *pEdShell->GetCrsr() = aDelPam;
2310 pEdShell->Push();
2311
2312 eStat = IS_ENDE;
2313 break;
2314 }
2315
2316 // dann teste mal auf 3 "---" oder "===". In dem Fall
2317 // soll der vorherige Absatz unterstrichen und dieser
2318 // geloescht werden!
2319 if( !DoUnderline() && bReplaceStyles )
2320 {
2321 SetColl( RES_POOLCOLL_STANDARD, sal_True );
2322 bEmptyLine = sal_True;
2323 }
2324 eStat = READ_NEXT_PARA;
2325 }
2326 else
2327 eStat = GET_ALL_INFO;
2328 break;
2329
2330 case GET_ALL_INFO:
2331 {
2332 if( pAktTxtNd->GetNumRule() )
2333 {
2334 // in Numerierung nichts machen, zum naechsten
2335 bEmptyLine = sal_False;
2336 eStat = READ_NEXT_PARA;
2337 // loesche alle Blanks am Anfang/Ende
2338 // und alle mitten drin
2339 //JP 29.04.98: erstmal nur alle "mitten drin".
2340 DelMoreLinesBlanks( sal_False );
2341 break;
2342 }
2343
2344 aFInfo.SetFrm( pAktTxtFrm );
2345
2346 // erstmal: wurden schon mal entsprechende Vorlagen
2347 // vergeben, so behalte die bei, gehe zum
2348 // naechsten Node.
2349 sal_uInt16 nPoolId = pAktTxtNd->GetTxtColl()->GetPoolFmtId();
2350 if( IsPoolUserFmt( nPoolId )
2351 ? !aFlags.bChgUserColl
2352 : ( RES_POOLCOLL_STANDARD != nPoolId &&
2353 ( !aFlags.bAFmtByInput ||
2354 (RES_POOLCOLL_TEXT_MOVE != nPoolId &&
2355 RES_POOLCOLL_TEXT != nPoolId )) ))
2356 {
2357 eStat = HAS_FMTCOLL;
2358 break;
2359 }
2360
2361 // teste auf Harte oder aus Vorlagen gesetzte LRSpaces
2362 if( IsPoolUserFmt( nPoolId ) ||
2363 RES_POOLCOLL_STANDARD == nPoolId )
2364 {
2365 short nSz;
2366 SvxLRSpaceItem* pLRSpace;
2367 if( SFX_ITEM_SET == pAktTxtNd->GetSwAttrSet().
2368 GetItemState( RES_LR_SPACE, sal_True,
2369 (const SfxPoolItem**)&pLRSpace ) &&
2370 ( 0 != (nSz = pLRSpace->GetTxtFirstLineOfst()) ||
2371 0 != pLRSpace->GetTxtLeft() ) )
2372 {
2373 // Ausnahme: Numerierun/Aufzaehlung kann mit Einzug
2374 // existieren!!
2375 if( IsEnumericChar( *pAktTxtNd ))
2376 {
2377 nLevel = CalcLevel( *pAktTxtNd, &nDigitLvl );
2378 if( nLevel >= MAXLEVEL )
2379 nLevel = MAXLEVEL-1;
2380 BuildEnum( nLevel, nDigitLvl );
2381 eStat = READ_NEXT_PARA;
2382 break;
2383 }
2384
2385
2386 // nie zusammenfassen, so belassen
2387 // (Opt. vielleicht als Ausnahmen nur Einzug)
2388 bMoreLines = sal_True;
2389
2390 if( bReplaceStyles )
2391 {
2392 // dann setze doch eine unserer Vorlagen
2393 if( 0 < nSz ) // positiver 1. Zeileneinzug
2394 BuildIndent();
2395 else if( 0 > nSz ) // negativer 1. Zeileneinzug
2396 BuildNegIndent( aFInfo.GetLineStart() );
2397 else if( pLRSpace->GetTxtLeft() ) // ist ein Einzug
2398 BuildTextIndent();
2399 }
2400 eStat = READ_NEXT_PARA;
2401 break;
2402 }
2403 }
2404
2405 nLevel = CalcLevel( *pAktTxtNd, &nDigitLvl );
2406 bMoreLines = !IsOneLine( *pAktTxtNd );
2407 pNxtNd = GetNextNode();
2408 if( pNxtNd )
2409 {
2410 bNxtEmpty = IsEmptyLine( *pNxtNd );
2411 bNxtAlpha = IsNoAlphaLine( *pNxtNd );
2412 nNxtLevel = CalcLevel( *pNxtNd );
2413
2414 if( !bEmptyLine && HasBreakAttr( *pAktTxtNd ) )
2415 bEmptyLine = sal_True;
2416 if( !bNxtEmpty && HasBreakAttr( *pNxtNd ) )
2417 bNxtEmpty = sal_True;
2418
2419 // fuer z.B. selbst definierte Einzuege oder
2420 // rechts/zentierte Ausrichtung
2421 // if( !nLevel && 0 != aFInfo.GetLineStart() )
2422 // nLevel = 1;
2423 }
2424 else
2425 {
2426 bNxtEmpty = sal_False; // sal_True;
2427 bNxtAlpha = sal_False;
2428 nNxtLevel = 0;
2429 }
2430 eStat = !bMoreLines ? IS_ONE_LINE : TST_ENUMERIC;
2431 }
2432 break;
2433
2434 case IS_ONE_LINE:
2435 {
2436 eStat = TST_ENUMERIC;
2437 if( !bReplaceStyles )
2438 break;
2439
2440 String sClrStr( pAktTxtNd->GetTxt() );
2441
2442 if( !DelLeadingBlanks( sClrStr ).Len() )
2443 {
2444 bEmptyLine = sal_True;
2445 eStat = READ_NEXT_PARA;
2446 break; // naechsten Absatz lesen
2447 }
2448
2449 // Teste auf Ueberschrift
2450 if( !bEmptyLine || !IsFirstCharCapital( *pAktTxtNd ) ||
2451 IsBlanksInString( *pAktTxtNd ) )
2452 break;
2453
2454 bEmptyLine = sal_False;
2455 String sEndClrStr( sClrStr );
2456 xub_StrLen nLen = DelTrailingBlanks( sEndClrStr ).Len();
2457
2458 // nicht, dann teste auf Ueberschrift
2459 if( ':' == sEndClrStr.GetChar( nLen - 1 ) )
2460 {
2461 //---------------------------------------------------------------------------
2462 // Wie ist denn nun die Bedingung fuer die Ueberschrift auf Ebene 3 ??
2463 // Zur Zeit: generell wenn am Ende ein ':' ist.
2464 //
2465 // if( bNxtEmpty || bNxtAlpha )
2466 // !IsEnumericChar( *pNxtNd ) )
2467 //---------------------------------------------------------------------------
2468 {
2469 BuildHeadLine( 2 );
2470 eStat = READ_NEXT_PARA;
2471 break;
2472 }
2473 }
2474 else if( 256 <= sEndClrStr.GetChar( nLen-1 ) ||
2475 !strchr( ",.;", sEndClrStr.GetChar( nLen-1 )) )
2476 {
2477 if( bNxtEmpty || bNxtAlpha
2478 || ( pNxtNd && IsEnumericChar( *pNxtNd ))
2479
2480 //---------------------------------------------------------------------------
2481 // ist zum Verwechseln mit neg. Einzug !!
2482 /*|| nLevel < nNxtLevel*/
2483 //---------------------------------------------------------------------------
2484
2485 )
2486 {
2487 // wurde Level vom Text vorgegeben ?
2488 // if( USHRT_MAX != nDigitLvl )
2489 // nLevel = nDigitLvl;
2490
2491 // eine Ebene runter ?
2492 if( nLevel >= MAXLEVEL )
2493 nLevel = MAXLEVEL-1;
2494
2495 if( USHRT_MAX == nLastHeadLvl )
2496 nLastHeadLvl = 0;
2497 else if( nLastCalcHeadLvl < nLevel )
2498 {
2499 if( nLastHeadLvl+1 < MAXLEVEL )
2500 ++nLastHeadLvl;
2501 }
2502 // eine Ebene hoch ?
2503 else if( nLastCalcHeadLvl > nLevel )
2504 {
2505 if( nLastHeadLvl )
2506 --nLastHeadLvl;
2507 }
2508 nLastCalcHeadLvl = nLevel;
2509
2510 if( aFlags.bAFmtByInput )
2511 BuildHeadLine( nLevel );
2512 else
2513 BuildHeadLine( nLastHeadLvl );
2514 eStat = READ_NEXT_PARA;
2515 break;
2516 }
2517 }
2518 }
2519 break;
2520
2521 case TST_ENUMERIC:
2522 {
2523 bEmptyLine = sal_False;
2524 if( IsEnumericChar( *pAktTxtNd ))
2525 {
2526 if( nLevel >= MAXLEVEL )
2527 nLevel = MAXLEVEL-1;
2528 BuildEnum( nLevel, nDigitLvl );
2529 eStat = READ_NEXT_PARA;
2530 }
2531 //JP 25.03.96: Vorlagen fuer Einzug zulassen
2532 // else if( aFlags.bAFmtByInput )
2533 // eStat = READ_NEXT_PARA;
2534 else if( bReplaceStyles )
2535 eStat = nLevel ? TST_IDENT : TST_NEG_IDENT;
2536 else
2537 eStat = READ_NEXT_PARA;
2538 }
2539 break;
2540
2541 case TST_IDENT:
2542 // Spaces am Anfang, dann teste doch mal auf Einzuege
2543 if( bMoreLines && nLevel )
2544 {
2545 SwTwips nSz = aFInfo.GetFirstIndent();
2546 if( 0 < nSz ) // positiver 1. Zeileneinzug
2547 BuildIndent();
2548 else if( 0 > nSz ) // negativer 1. Zeileneinzug
2549 BuildNegIndent( aFInfo.GetLineStart() );
2550 else // ist ein Einzug
2551 BuildTextIndent();
2552 eStat = READ_NEXT_PARA;
2553 }
2554 else if( nLevel && pNxtNd && !bEnde &&
2555 !bNxtEmpty && !bNxtAlpha && !nNxtLevel &&
2556 !IsEnumericChar( *pNxtNd ) )
2557 {
2558 // ist ein Einzug
2559 BuildIndent();
2560 eStat = READ_NEXT_PARA;
2561 }
2562 else
2563 eStat = TST_TXT_BODY;
2564 break;
2565
2566 case TST_NEG_IDENT:
2567 // keine Spaces am Anfang, dann teste doch mal auf neg. Einzuege
2568 {
2569 if( bMoreLines && !nLevel )
2570 {
2571 SwTwips nSz = aFInfo.GetFirstIndent();
2572 if( 0 < nSz ) // positiver 1. Zeileneinzug
2573 BuildIndent();
2574 else if( 0 > nSz ) // negativer 1. Zeileneinzug
2575 BuildNegIndent( aFInfo.GetLineStart() );
2576 else // ist ein kein Einzug
2577 BuildText();
2578 eStat = READ_NEXT_PARA;
2579 }
2580 else if( !nLevel && pNxtNd && !bEnde &&
2581 !bNxtEmpty && !bNxtAlpha && nNxtLevel &&
2582 !IsEnumericChar( *pNxtNd ) )
2583 {
2584 // ist ein neg. Einzug
2585 BuildNegIndent( aFInfo.GetLineStart() );
2586 eStat = READ_NEXT_PARA;
2587 }
2588 else
2589 eStat = TST_TXT_BODY;
2590 }
2591 break;
2592
2593 case TST_TXT_BODY:
2594 {
2595 if( bMoreLines )
2596 {
2597 SwTwips nSz = aFInfo.GetFirstIndent();
2598 if( 0 < nSz ) // positiver 1. Zeileneinzug
2599 BuildIndent();
2600 else if( 0 > nSz ) // negativer 1. Zeileneinzug
2601 BuildNegIndent( aFInfo.GetLineStart() );
2602 else if( nLevel ) // ist ein Einzug
2603 BuildTextIndent();
2604 else
2605 BuildText();
2606 }
2607 else if( nLevel )
2608 BuildTextIndent();
2609 else
2610 BuildText();
2611 eStat = READ_NEXT_PARA;
2612 }
2613 break;
2614
2615 case HAS_FMTCOLL:
2616 {
2617 // erstmal: wurden schon mal entsprechende Vorlagen
2618 // vergeben, so behalte die bei, gehe zum
2619 // naechsten Node.
2620 bEmptyLine = sal_False;
2621 eStat = READ_NEXT_PARA;
2622 // loesche alle Blanks am Anfang/Ende
2623 // und alle mitten drin
2624 //JP 29.04.98: erstmal nur alle "mitten drin".
2625 DelMoreLinesBlanks( sal_False );
2626
2627 // behandel die harte Attributierung
2628 if( pAktTxtNd->HasSwAttrSet() )
2629 {
2630 short nSz;
2631 SvxLRSpaceItem* pLRSpace;
2632 if( bReplaceStyles &&
2633 SFX_ITEM_SET == pAktTxtNd->GetSwAttrSet().
2634 GetItemState( RES_LR_SPACE, sal_False,
2635 (const SfxPoolItem**)&pLRSpace ) &&
2636 ( 0 != (nSz = pLRSpace->GetTxtFirstLineOfst()) ||
2637 0 != pLRSpace->GetTxtLeft() ) )
2638 {
2639 // dann setze doch eine unserer Vorlagen
2640 if( 0 < nSz ) // positiver 1. Zeileneinzug
2641 BuildIndent();
2642 else if( 0 > nSz ) // negativer 1. Zeileneinzug
2643 {
2644 BuildNegIndent( aFInfo.GetLineStart() );
2645 }
2646 else if( pLRSpace->GetTxtLeft() ) // ist ein Einzug
2647 BuildTextIndent();
2648 else
2649 BuildText();
2650 }
2651 }
2652 }
2653 break;
2654
2655 case IS_ENDE:
2656 bEnde = sal_True;
2657 break;
2658 }
2659 }
2660
2661 if( aFlags.bWithRedlining )
2662 pDoc->SetAutoFmtRedline( sal_False );
2663 pDoc->SetRedlineMode( eOldMode );
2664
2665 // restore undo (in case it has been changed)
2666 pDoc->GetIDocumentUndoRedo().DoUndo(bUndoState);
2667
2668 // Prozent-Anzeige wieder abschalten
2669 if( !aFlags.bAFmtByInput )
2670 ::EndProgress( pDoc->GetDocShell() );
2671 }
2672
AutoFormat(const SvxSwAutoFmtFlags * pAFlags)2673 void SwEditShell::AutoFormat( const SvxSwAutoFmtFlags* pAFlags )
2674 {
2675 SwWait* pWait = 0;
2676
2677 SET_CURR_SHELL( this );
2678 StartAllAction();
2679 StartUndo( UNDO_AUTOFORMAT );
2680
2681 SvxSwAutoFmtFlags aAFFlags; // erst mal default - Werte
2682 if( pAFlags ) // oder doch angegeben ??
2683 {
2684 aAFFlags = *pAFlags;
2685 if( !aAFFlags.bAFmtByInput )
2686 pWait = new SwWait( *GetDoc()->GetDocShell(), true );
2687 }
2688
2689 SwPaM* pCrsr = GetCrsr();
2690 // es gibt mehr als einen oder ist eine Selektion offen
2691 if( pCrsr->GetNext() != pCrsr || pCrsr->HasMark() )
2692 {
2693 FOREACHPAM_START(this)
2694 if( PCURCRSR->HasMark() )
2695 {
2696 SwAutoFormat aFmt( this, aAFFlags, &PCURCRSR->Start()->nNode,
2697 &PCURCRSR->End()->nNode );
2698 }
2699 FOREACHPAM_END()
2700 }
2701 else
2702 {
2703 SwAutoFormat aFmt( this, aAFFlags );
2704 }
2705
2706 EndUndo( UNDO_AUTOFORMAT );
2707 EndAllAction();
2708
2709 delete pWait;
2710 }
2711
2712
AutoFmtBySplitNode()2713 void SwEditShell::AutoFmtBySplitNode()
2714 {
2715 SET_CURR_SHELL( this );
2716 SwPaM* pCrsr = GetCrsr();
2717 if( pCrsr->GetNext() == pCrsr && pCrsr->Move( fnMoveBackward, fnGoNode ) )
2718 {
2719 StartAllAction();
2720 StartUndo( UNDO_AUTOFORMAT );
2721
2722 sal_Bool bRange = sal_False;
2723 pCrsr->SetMark();
2724 SwIndex* pCntnt = &pCrsr->GetMark()->nContent;
2725 if( pCntnt->GetIndex() )
2726 {
2727 *pCntnt = 0;
2728 bRange = sal_True;
2729 }
2730 else
2731 {
2732 // dann einen Node zurueckspringen
2733 SwNodeIndex aNdIdx( pCrsr->GetMark()->nNode, -1 );
2734 SwTxtNode* pTxtNd = aNdIdx.GetNode().GetTxtNode();
2735 if( pTxtNd && pTxtNd->GetTxt().Len() )
2736 {
2737 pCntnt->Assign( pTxtNd, 0 );
2738 pCrsr->GetMark()->nNode = aNdIdx;
2739 bRange = sal_True;
2740 }
2741 }
2742
2743 if( bRange )
2744 {
2745 Push(); // Cursor sichern
2746
2747 SvxSwAutoFmtFlags aAFFlags = *GetAutoFmtFlags(); // erst mal default - Werte
2748
2749 SwAutoFormat aFmt( this, aAFFlags, &pCrsr->GetMark()->nNode,
2750 &pCrsr->GetPoint()->nNode );
2751
2752 //JP 30.09.96: das DoTable() verlaesst sich auf das PopCrsr
2753 // und MoveCrsr!
2754 Pop( sal_False );
2755 pCrsr = GetCrsr();
2756 }
2757 pCrsr->DeleteMark();
2758 pCrsr->Move( fnMoveForward, fnGoNode );
2759
2760 EndUndo( UNDO_AUTOFORMAT );
2761 EndAllAction();
2762 }
2763 }
2764
GetAutoFmtFlags()2765 SvxSwAutoFmtFlags* SwEditShell::GetAutoFmtFlags()
2766 {
2767 if (!pAutoFmtFlags)
2768 pAutoFmtFlags = new SvxSwAutoFmtFlags;
2769
2770 return pAutoFmtFlags;
2771 }
2772
SetAutoFmtFlags(SvxSwAutoFmtFlags * pFlags)2773 void SwEditShell::SetAutoFmtFlags(SvxSwAutoFmtFlags * pFlags)
2774 {
2775 SvxSwAutoFmtFlags* pEditFlags = GetAutoFmtFlags();
2776
2777 pEditFlags->bSetNumRule = pFlags->bSetNumRule;
2778 pEditFlags->bChgEnumNum = pFlags->bChgEnumNum;
2779 pEditFlags->bSetBorder = pFlags->bSetBorder;
2780 pEditFlags->bCreateTable = pFlags->bCreateTable;
2781 pEditFlags->bReplaceStyles = pFlags->bReplaceStyles;
2782 pEditFlags->bAFmtByInpDelSpacesAtSttEnd =
2783 pFlags->bAFmtByInpDelSpacesAtSttEnd;
2784 pEditFlags->bAFmtByInpDelSpacesBetweenLines =
2785 pFlags->bAFmtByInpDelSpacesBetweenLines;
2786
2787 //JP 15.12.98: BulletZeichen und Font in die "normalen" kopieren,
2788 // weil beim Autoformat nur mit diesen gearbeitet wird!
2789 pEditFlags->cBullet = pFlags->cByInputBullet;
2790 pEditFlags->aBulletFont = pFlags->aByInputBulletFont;
2791 pEditFlags->cByInputBullet = pFlags->cByInputBullet;
2792 pEditFlags->aByInputBulletFont = pFlags->aByInputBulletFont;
2793 }
2794
2795