xref: /trunk/main/sw/source/core/layout/dbg_lay.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #ifdef DBG_UTIL
32 
33 /* -----------------08.01.99 14:55-------------------
34  * Und hier die Beschreibung:
35  *
36  * Durch die PROTOCOL-Makros wird es ermoeglicht, Ereignisse im Frame-Methoden zu protokollieren.
37  * In protokollwuerdigen Stellen in Frame-Methoden muss entweder ein PROTOCOL(...) oder bei Methoden,
38  * bei denen auch das Verlassen der Methode mitprotokolliert werden soll, ein PROTOCOL_ENTER(...)-Makro
39  * stehen.
40  * Die Parameter der PROTOCOL-Makros sind
41  * 1.   Ein Pointer auf einen SwFrm, also meist "this" oder "rThis"
42  * 2.   Die Funktionsgruppe z.B. PROT_MAKEALL, hierueber wird (inline) entschieden, ob dies
43  *      zur Zeit protokolliert werden soll oder nicht.
44  * 3.   Die Aktion, im Normalfall 0, aber z.B. ein ACT_START bewirkt eine Einrueckung in der
45  *      Ausgabedatei, ein ACT_END nimmt dies wieder zurueck. Auf diese Art wird z.B. durch
46  *      PROTOCOL_ENTER am Anfang einer Methode eingerueckt und beim Verlassen wieder zurueck.
47  * 4.   Der vierte Parameter ist ein void-Pointer, damit man irgendetwas uebergeben kann,
48  *      was in das Protokoll einfliessen kann, typesches Beispiel bei PROT_GROW muss man
49  *      einen Pointer auf den Wert, um den gegrowt werden soll, uebergeben.
50  *
51  *
52  * Das Protokoll ist die Datei "dbg_lay.out" im aktuellen (BIN-)Verzeichnis.
53  * Es enthaelt Zeilen mit FrmId, Funktionsgruppe sowie weiteren Infos.
54  *
55  * Was genau protokolliert wird, kann auf folgende Arten eingestellt werden:
56  * 1.   Die statische Variable SwProtokoll::nRecord enthaelt die Funktionsgruppen,
57  *      die aufgezeichnet werden sollen.
58  *      Ein Wert von z.B. PROT_GROW bewirkt, das Aufrufe von SwFrm::Grow dokumentiert werden,
59  *      PROT_MAKEALL protokolliert Aufrufe von xxx::MakeAll.
60  *      Die PROT_XY-Werte koennen oderiert werden.
61  *      Default ist Null, es wird keine Methode aufgezeichnet.
62  * 2.   In der SwImplProtocol-Klasse gibt es einen Filter fuer Frame-Typen,
63  *      nur die Methodenaufrufe von Frame-Typen, die dort gesetzt sind, werden protokolliert.
64  *      Der Member nTypes kann auf Werte wie FRM_PAGE, FRM_SECTION gesetzt und oderiert werden.
65  *      Default ist 0xFFFF, d.h. alle Frame-Typen.
66  * 3.   In der SwImplProtocol-Klasse gibt es einen ArrayPointer auf FrmIds, die zu ueberwachen sind.
67  *      Ist der Pointer Null, so werden alle Frames protokolliert, ansonsten nur Frames,
68  *      die in dem Array vermerkt sind.
69  *
70  * Eine Aufzeichnung in Gang zu setzen, erfordert entweder Codemanipulation, z.B. in
71  * SwProtocol::Init() einen anderen Default fuer nRecord setzen oder Debuggermanipulation.
72  * Im Debugger gibt verschiedene, sich anbietende Stellen:
73  * 1.   In SwProtocol::Init() einen Breakpoint setzen und dort nRecord manipulieren, ggf.
74  *      FrmIds eintragen, dann beginnt die Aufzeichnung bereits beim Programmstart.
75  * 2.   Waehrend des Programmlaufs einen Breakpoint vor irgendein PROTOCOL oder PROTOCOL_ENTER-
76  *      Makro setzen, dann am SwProtocol::nRecord das unterste Bit setzen (PROT_INIT). Dies
77  *      bewirkt, dass die Funktionsgruppe des folgenden Makros aktiviert und in Zukunft
78  *      protokolliert wird.
79  * 3.   Spezialfall von 2.: Wenn man 2. in der Methode SwRootFrm::Paint(..) anwendet, werden
80  *      die Aufzeichnungseinstellung aus der Datei "dbg_lay.ini" ausgelesen!
81  *      In dieser INI-Datei kann es Kommentarzeilen geben, diese beginnen mit '#', dann
82  *      sind die Sektionen "[frmid]", "[frmtype]" und "[record]" relevant.
83  *      Nach [frmid] koennen die FrameIds der zu protokollierenden Frames folgen. Gibt es
84  *      dort keine Eintraege, werden alle Frames aufgezeichnet.
85  *      Nach [frmtype] koennen FrameTypen folgen, die aufgezeichnet werden sollen, da der
86  *      Default hier allerdings USHRT_MAX ist, werden sowieso alle aufgezeichnet. Man kann
87  *      allerdings auch Typen entfernen, in dem man ein '!' vor den Wert setzt, z.B.
88  *      !0xC000 nimmt die SwCntntFrms aus der Aufzeichnung heraus.
89  *      Nach [record] folgen die Funktionsgruppen, die aufgezeichnet werden sollen, Default
90  *      ist hier 0, also keine. Auch hier kann man mit einem vorgestellten '!' Funktionen
91  *      wieder entfernen.
92  *      Hier mal ein Beispiel fuer eine INI-Datei:
93  *      ------------------------------------------
94  *          #Funktionen: Alle, ausser PRTAREA
95  *          [record] 0xFFFFFFE !0x200
96  *          [frmid]
97  *          #folgende FrmIds:
98  *          1 2 12 13 14 15
99  *          #keine Layoutframes ausser ColumnFrms
100  *          [frmtype] !0x3FFF 0x4
101  *      ------------------------------------------
102  *
103  * Wenn die Aufzeichnung erstmal laeuft, kann man in SwImplProtocol::_Record(...) mittels
104  * Debugger vielfaeltige Manipulationen vornehmen, z.B. bezueglich FrameTypen oder FrmIds.
105  *
106  * --------------------------------------------------*/
107 
108 #ifndef DBG_UTIL
109 #error Wer fummelt denn an den makefiles rum?
110 #endif
111 
112 
113 
114 #include "dbg_lay.hxx"
115 #include <tools/stream.hxx>
116 
117 #ifndef _SVSTDARR_HXX
118 #define _SVSTDARR_USHORTS
119 #define _SVSTDARR_USHORTSSORT
120 #define _SVSTDARR_LONGS
121 #include <svl/svstdarr.hxx>
122 #endif
123 
124 #include <stdio.h>
125 
126 #include "frame.hxx"
127 #include "layfrm.hxx"
128 #include "flyfrm.hxx"
129 #include "txtfrm.hxx"
130 #include "ndtxt.hxx"
131 #include "dflyobj.hxx"
132 #include <fntcache.hxx>
133 // OD 2004-05-24 #i28701#
134 #include <sortedobjs.hxx>
135 
136 sal_uLong SwProtocol::nRecord = 0;
137 SwImplProtocol* SwProtocol::pImpl = NULL;
138 
139 sal_uLong lcl_GetFrameId( const SwFrm* pFrm )
140 {
141 #ifdef DBG_UTIL
142     static sal_Bool bFrameId = sal_False;
143     if( bFrameId )
144         return pFrm->GetFrmId();
145 #endif
146     if( pFrm && pFrm->IsTxtFrm() )
147         return ((SwTxtFrm*)pFrm)->GetTxtNode()->GetIndex();
148     return 0;
149 }
150 
151 class SwImplProtocol
152 {
153     SvFileStream *pStream;      // Ausgabestream
154     SvUShortsSort *pFrmIds;     // welche FrmIds sollen aufgezeichnet werden ( NULL == alle )
155     SvLongs *pVar;              // Variables
156     ByteString aLayer;          // Einrueckung der Ausgabe ("  " pro Start/End)
157     sal_uInt16 nTypes;              // welche Typen sollen aufgezeichnet werden
158     sal_uInt16 nLineCount;          // Ausgegebene Zeilen
159     sal_uInt16 nMaxLines;           // Maximal auszugebende Zeilen
160     sal_uInt8 nInitFile;                // Bereich (FrmId,FrmType,Record) beim Einlesen der INI-Datei
161     sal_uInt8 nTestMode;                // Special fuer Testformatierung, es wird ggf. nur
162                                 // innerhalb einer Testformatierung aufgezeichnet.
163     void _Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam );
164     sal_Bool NewStream();
165     void CheckLine( ByteString& rLine );
166     void SectFunc( ByteString &rOut, const SwFrm* pFrm, sal_uLong nAct, void* pParam );
167 public:
168     SwImplProtocol();
169     ~SwImplProtocol();
170     // Aufzeichnen
171     void Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam )
172         { if( pStream ) _Record( pFrm, nFunction, nAct, pParam ); }
173     sal_Bool InsertFrm( sal_uInt16 nFrmId );    // FrmId aufnehmen zum Aufzeichnen
174     sal_Bool DeleteFrm( sal_uInt16 nFrmId );    // FrmId entfernen, diesen nicht mehr Aufzeichnen
175     void FileInit();                    // Auslesen der INI-Datei
176     void ChkStream() { if( !pStream ) NewStream(); }
177     void SnapShot( const SwFrm* pFrm, sal_uLong nFlags );
178     void GetVar( const sal_uInt16 nNo, long& rVar )
179         { if( pVar && nNo < pVar->Count() ) rVar = (*pVar)[ nNo ]; }
180 };
181 
182 /* -----------------11.01.99 10:43-------------------
183  * Durch das PROTOCOL_ENTER-Makro wird ein SwEnterLeave-Objekt erzeugt,
184  * wenn die aktuelle Funktion aufgezeichnet werden soll, wird ein
185  * SwImplEnterLeave-Objekt angelegt. Der Witz dabei ist, das der Ctor
186  * des Impl-Objekt am Anfang der Funktion und automatisch der Dtor beim
187  * Verlassen der Funktion gerufen wird. In der Basis-Implementierung ruft
188  * der Ctor lediglich ein PROTOCOL(..) mit ACT_START und im Dtor ein
189  * PROTOCOL(..) mit ACT_END.
190  * Es lassen sich Ableitungen der Klasse bilden, um z.B. beim Verlassen
191  * einer Funktion Groessenaenderungen des Frames zu dokumentieren u.v.a.m.
192  * Dazu braucht dann nur noch in SwEnterLeave::Ctor(...) die gewuenschte
193  * SwImplEnterLeave-Klasse angelegt zu werden.
194  *
195  * --------------------------------------------------*/
196 
197 class SwImplEnterLeave
198 {
199 protected:
200     const SwFrm* pFrm;              // Der Frame,
201     sal_uLong nFunction, nAction;       // die Funktion, ggf. die Aktion
202     void* pParam;                   // und weitere Parameter
203 public:
204     SwImplEnterLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar )
205         : pFrm( pF ), nFunction( nFunct ), nAction( nAct ), pParam( pPar ) {}
206     virtual void Enter();           // Ausgabe beim Eintritt
207     virtual void Leave();           // Ausgabe beim Verlassen
208 };
209 
210 class SwSizeEnterLeave : public SwImplEnterLeave
211 {
212     long nFrmHeight;
213 public:
214     SwSizeEnterLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar )
215         : SwImplEnterLeave( pF, nFunct, nAct, pPar ), nFrmHeight( pF->Frm().Height() ) {}
216     virtual void Leave();           // Ausgabe der Groessenaenderung
217 };
218 
219 class SwUpperEnterLeave : public SwImplEnterLeave
220 {
221     sal_uInt16 nFrmId;
222 public:
223     SwUpperEnterLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar )
224         : SwImplEnterLeave( pF, nFunct, nAct, pPar ), nFrmId( 0 ) {}
225     virtual void Enter();           // Ausgabe
226     virtual void Leave();           // Ausgabe der FrmId des Uppers
227 };
228 
229 class SwFrmChangesLeave : public SwImplEnterLeave
230 {
231     SwRect aFrm;
232 public:
233     SwFrmChangesLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar )
234         : SwImplEnterLeave( pF, nFunct, nAct, pPar ), aFrm( pF->Frm() ) {}
235     virtual void Enter();           // keine Ausgabe
236     virtual void Leave();           // Ausgabe bei Aenderung der Frm-Area
237 };
238 
239 void SwProtocol::Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam )
240 {
241     if( Start() )
242     {   // Hier landen wir, wenn im Debugger SwProtocol::nRecord mit PROT_INIT(0x1) oderiert wurde
243         sal_Bool bFinit = sal_False; // Dies bietet im Debugger die Moeglichkeit,
244         if( bFinit )         // die Aufzeichnung dieser Action zu beenden
245         {
246             nRecord &= ~nFunction;  // Diese Funktion nicht mehr aufzeichnen
247             nRecord &= ~PROT_INIT;  // PROT_INIT stets zuruecksetzen
248             return;
249         }
250         nRecord |= nFunction;       // Aufzeichnung dieser Funktion freischalten
251         nRecord &= ~PROT_INIT;      // PROT_INIT stets zuruecksetzen
252         if( pImpl )
253             pImpl->ChkStream();
254     }
255     if( !pImpl )                        // Impl-Object anlegen, wenn noetig
256         pImpl = new SwImplProtocol();
257     pImpl->Record( pFrm, nFunction, nAct, pParam ); // ...und Aufzeichnen
258 }
259 
260 // Die folgende Funktion wird beim Anziehen der Writer-DLL durch TxtInit(..) aufgerufen
261 // und ermoeglicht dem Debuggenden Funktionen und/oder FrmIds freizuschalten
262 
263 void SwProtocol::Init()
264 {
265     nRecord = 0;
266     XubString aName( "dbg_lay.go", RTL_TEXTENCODING_MS_1252 );
267     SvFileStream aStream( aName, STREAM_READ );
268     if( aStream.IsOpen() )
269     {
270         pImpl = new SwImplProtocol();
271         pImpl->FileInit();
272     }
273     aStream.Close();
274 }
275 
276 // Ende der Aufzeichnung
277 
278 void SwProtocol::Stop()
279 {
280      if( pImpl )
281      {
282         delete pImpl;
283         pImpl = NULL;
284         if( pFntCache )
285             pFntCache->Flush();
286      }
287      nRecord = 0;
288 }
289 
290 // Creates a more or less detailed snapshot of the layout structur
291 
292 void SwProtocol::SnapShot( const SwFrm* pFrm, sal_uLong nFlags )
293 {
294     if( pImpl )
295         pImpl->SnapShot( pFrm, nFlags );
296 }
297 
298 void SwProtocol::GetVar( const sal_uInt16 nNo, long& rVar )
299 {
300     if( pImpl )
301         pImpl->GetVar( nNo, rVar );
302 }
303 
304 SwImplProtocol::SwImplProtocol()
305     : pStream( NULL ), pFrmIds( NULL ), pVar( NULL ), nTypes( 0xffff ),
306       nLineCount( 0 ), nMaxLines( USHRT_MAX ), nTestMode( 0 )
307 {
308     NewStream();
309 }
310 
311 sal_Bool SwImplProtocol::NewStream()
312 {
313     XubString aName( "dbg_lay.out", RTL_TEXTENCODING_MS_1252 );
314     nLineCount = 0;
315     pStream = new SvFileStream( aName, STREAM_WRITE | STREAM_TRUNC );
316     if( pStream->GetError() )
317     {
318         delete pStream;
319         pStream = NULL;
320     }
321     return 0 != pStream;
322 }
323 
324 SwImplProtocol::~SwImplProtocol()
325 {
326     if( pStream )
327     {
328         pStream->Close();
329         delete pStream;
330     }
331     delete pFrmIds;
332     delete pVar;
333 }
334 
335 /* -----------------11.01.99 11:03-------------------
336  * SwImplProtocol::CheckLine analysiert eine Zeile der INI-Datei
337  * --------------------------------------------------*/
338 
339 void SwImplProtocol::CheckLine( ByteString& rLine )
340 {
341     rLine = rLine.ToLowerAscii(); // Gross/Kleinschreibung ist einerlei
342     while( STRING_LEN > rLine.SearchAndReplace( '\t', ' ' ) )
343         ; //nothing                 // Tabs werden durch Blanks ersetzt
344     if( '#' == rLine.GetChar(0) )   // Kommentarzeilen beginnen mit '#'
345         return;
346     if( '[' == rLine.GetChar(0) )   // Bereiche: FrmIds, Typen oder Funktionen
347     {
348         ByteString aTmp = rLine.GetToken( 0, ']' );
349         if( "[frmid" == aTmp )      // Bereich FrmIds
350         {
351             nInitFile = 1;
352             delete pFrmIds;
353             pFrmIds = NULL;         // Default: Alle Frames aufzeichnen
354         }
355         else if( "[frmtype" == aTmp )// Bereich Typen
356         {
357             nInitFile = 2;
358             nTypes = USHRT_MAX;     // Default: Alle FrmaeTypen aufzeichnen
359         }
360         else if( "[record" == aTmp )// Bereich Funktionen
361         {
362             nInitFile = 3;
363             SwProtocol::SetRecord( 0 );// Default: Keine Funktion wird aufgezeichnet
364         }
365         else if( "[test" == aTmp )// Bereich Funktionen
366         {
367             nInitFile = 4; // Default:
368             nTestMode = 0; // Ausserhalb der Testformatierung wird aufgezeichnet
369         }
370         else if( "[max" == aTmp )// maximale Zeilenzahl
371         {
372             nInitFile = 5; // Default:
373             nMaxLines = USHRT_MAX;
374         }
375         else if( "[var" == aTmp )// variables
376         {
377             nInitFile = 6;
378             if( !pVar )
379                 pVar = new SvLongs( 5, 5 );
380         }
381         else
382             nInitFile = 0;          // Nanu: Unbekannter Bereich?
383         rLine.Erase( 0, aTmp.Len() + 1 );
384     }
385     sal_uInt16 nToks = rLine.GetTokenCount( ' ' );  // Blanks (oder Tabs) sind die Trenner
386     for( sal_uInt16 i=0; i < nToks; ++i )
387     {
388         ByteString aTok = rLine.GetToken( i, ' ' );
389         sal_Bool bNo = sal_False;
390         if( '!' == aTok.GetChar(0) )
391         {
392             bNo = sal_True;                 // Diese(n) Funktion/Typ entfernen
393             aTok.Erase( 0, 1 );
394         }
395         if( aTok.Len() )
396         {
397             sal_uLong nVal;
398             sscanf( aTok.GetBuffer(), "%li", &nVal );
399             switch ( nInitFile )
400             {
401                 case 1: InsertFrm( sal_uInt16( nVal ) );    // FrmId aufnehmen
402                         break;
403                 case 2: {
404                             sal_uInt16 nNew = (sal_uInt16)nVal;
405                             if( bNo )
406                                 nTypes &= ~nNew;    // Typ entfernen
407                             else
408                                 nTypes |= nNew;     // Typ aufnehmen
409                         }
410                         break;
411                 case 3: {
412                             sal_uLong nOld = SwProtocol::Record();
413                             if( bNo )
414                                 nOld &= ~nVal;      // Funktion entfernen
415                             else
416                                 nOld |= nVal;       // Funktion aufnehmen
417                             SwProtocol::SetRecord( nOld );
418                         }
419                         break;
420                 case 4: {
421                             sal_uInt8 nNew = (sal_uInt8)nVal;
422                             if( bNo )
423                                 nTestMode &= ~nNew; // TestMode zuruecksetzen
424                             else
425                                 nTestMode |= nNew;      // TestMode setzen
426                         }
427                         break;
428                 case 5: nMaxLines = (sal_uInt16)nVal;
429                         break;
430                 case 6: pVar->Insert( (long)nVal, pVar->Count() );
431                         break;
432             }
433         }
434     }
435 }
436 
437 /* -----------------11.01.99 11:17-------------------
438  * SwImplProtocol::FileInit() liest die Datei "dbg_lay.ini"
439  * im aktuellen Verzeichnis und wertet sie aus.
440  * --------------------------------------------------*/
441 void SwImplProtocol::FileInit()
442 {
443     XubString aName( "dbg_lay.ini", RTL_TEXTENCODING_MS_1252 );
444     SvFileStream aStream( aName, STREAM_READ );
445     if( aStream.IsOpen() )
446     {
447         ByteString aLine;
448         nInitFile = 0;
449         while( !aStream.IsEof() )
450         {
451             sal_Char c;
452             aStream >> c;
453             if( '\n' == c || '\r' == c )    // Zeilenende
454             {
455                 aLine.EraseLeadingChars();
456                 aLine.EraseTrailingChars();
457                 if( aLine.Len() )
458                     CheckLine( aLine );     // Zeile auswerten
459                 aLine.Erase();
460             }
461             else
462                 aLine += c;
463         }
464         if( aLine.Len() )
465             CheckLine( aLine );     // letzte Zeile auswerten
466     }
467     aStream.Close();
468 }
469 
470 /* -----------------11.01.99 11:20-------------------
471  * lcl_Start sorgt fuer Einrueckung um zwei Blanks bei ACT_START
472  * und nimmt diese bei ACT_END wieder zurueck.
473  * --------------------------------------------------*/
474 void lcl_Start( ByteString& rOut, ByteString& rLay, sal_uLong nAction )
475 {
476     if( nAction == ACT_START )
477     {
478         rLay += "  ";
479         rOut += " On";
480     }
481     else if( nAction == ACT_END )
482     {
483         if( rLay.Len() > 1 )
484         {
485             rLay.Erase( rLay.Len() - 2 );
486             rOut.Erase( 0, 2 );
487         }
488         rOut += " Off";
489     }
490 }
491 
492 /* -----------------11.01.99 11:21-------------------
493  * lcl_Flags gibt das ValidSize-, ValidPos- und ValidPrtArea-Flag ("Sz","Ps","PA")
494  * des Frames aus, "+" fuer valid, "-" fuer invalid.
495  * --------------------------------------------------*/
496 
497 void lcl_Flags( ByteString& rOut, const SwFrm* pFrm )
498 {
499     rOut += " Sz";
500     rOut += pFrm->GetValidSizeFlag() ? '+' : '-';
501     rOut += " Ps";
502     rOut += pFrm->GetValidPosFlag() ? '+' : '-';
503     rOut += " PA";
504     rOut += pFrm->GetValidPrtAreaFlag() ? '+' : '-';
505 }
506 
507 /* -----------------11.01.99 11:23-------------------
508  * lcl_FrameType gibt den Typ des Frames in Klartext aus.
509  * --------------------------------------------------*/
510 
511 void lcl_FrameType( ByteString& rOut, const SwFrm* pFrm )
512 {
513     if( pFrm->IsTxtFrm() )
514         rOut += "Txt ";
515     else if( pFrm->IsLayoutFrm() )
516     {
517         if( pFrm->IsPageFrm() )
518             rOut += "Page ";
519         else if( pFrm->IsColumnFrm() )
520             rOut += "Col ";
521         else if( pFrm->IsBodyFrm() )
522         {
523             if( pFrm->GetUpper() && pFrm->IsColBodyFrm() )
524                 rOut += "(Col)";
525             rOut += "Body ";
526         }
527         else if( pFrm->IsRootFrm() )
528             rOut += "Root ";
529         else if( pFrm->IsCellFrm() )
530             rOut += "Cell ";
531         else if( pFrm->IsTabFrm() )
532             rOut += "Tab ";
533         else if( pFrm->IsRowFrm() )
534             rOut += "Row ";
535         else if( pFrm->IsSctFrm() )
536             rOut += "Sect ";
537         else if( pFrm->IsHeaderFrm() )
538             rOut += "Header ";
539         else if( pFrm->IsFooterFrm() )
540             rOut += "Footer ";
541         else if( pFrm->IsFtnFrm() )
542             rOut += "Ftn ";
543         else if( pFrm->IsFtnContFrm() )
544             rOut += "FtnCont ";
545         else if( pFrm->IsFlyFrm() )
546             rOut += "Fly ";
547         else
548             rOut += "Layout ";
549     }
550     else if( pFrm->IsNoTxtFrm() )
551         rOut += "NoTxt ";
552     else
553         rOut += "Not impl. ";
554 }
555 
556 /* -----------------11.01.99 11:25-------------------
557  * SwImplProtocol::Record(..) wird nur gerufen, wenn das PROTOCOL-Makro
558  * feststellt, dass die Funktion aufgezeichnet werden soll ( SwProtocol::nRecord ).
559  * In dieser Methode werden noch die beiden weiteren Einschraenkungen ueberprueft,
560  * ob die FrmId und der FrameType zu den aufzuzeichnenden gehoeren.
561  * --------------------------------------------------*/
562 
563 void SwImplProtocol::_Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam )
564 {
565     sal_uInt16 nSpecial = 0;
566     if( nSpecial )  // Debugger-Manipulationsmoeglichkeit
567     {
568         sal_uInt16 nId = sal_uInt16(lcl_GetFrameId( pFrm ));
569         switch ( nSpecial )
570         {
571             case 1: InsertFrm( nId ); break;
572             case 2: DeleteFrm( nId ); break;
573             case 3: delete pFrmIds; pFrmIds = NULL; break;
574             case 4: delete pStream; pStream = NULL; break;
575         }
576         return;
577     }
578     if( !pStream && !NewStream() )
579         return; // Immer noch kein Stream
580 
581     if( pFrmIds && !pFrmIds->Seek_Entry( sal_uInt16(lcl_GetFrameId( pFrm )) ) )
582         return; // gehoert nicht zu den gewuenschten FrmIds
583 
584     if( !(pFrm->GetType() & nTypes) )
585         return; // Der Typ ist unerwuenscht
586 
587     if( 1 == nTestMode && nFunction != PROT_TESTFORMAT )
588         return; // Wir sollen nur innerhalb einer Testformatierung aufzeichnen
589     sal_Bool bTmp = sal_False;
590     ByteString aOut = aLayer;
591     aOut += ByteString::CreateFromInt64( lcl_GetFrameId( pFrm ) );
592     aOut += ' ';
593     lcl_FrameType( aOut, pFrm );    // dann den FrameType
594     switch ( nFunction )            // und die Funktion
595     {
596         case PROT_SNAPSHOT: lcl_Flags( aOut, pFrm );
597                             break;
598         case PROT_MAKEALL:  aOut += "MakeAll";
599                             lcl_Start( aOut, aLayer, nAct );
600                             if( nAct == ACT_START )
601                                 lcl_Flags( aOut, pFrm );
602                             break;
603         case PROT_MOVE_FWD: bTmp = sal_True; // NoBreak
604         case PROT_MOVE_BWD: aOut += ( nFunction == bTmp ) ? "Fwd" : "Bwd";
605                             lcl_Start( aOut, aLayer, nAct );
606                             if( pParam )
607                             {
608                                 aOut += ' ';
609                                 aOut += ByteString::CreateFromInt32( *((sal_uInt16*)pParam) );
610                             }
611                             break;
612         case PROT_GROW_TST: if( ACT_START != nAct )
613                                 return;
614                             aOut += "TestGrow";
615                             break;
616         case PROT_SHRINK_TST: if( ACT_START != nAct )
617                                 return;
618                             aOut += "TestShrink";
619                             break;
620         case PROT_ADJUSTN :
621         case PROT_SHRINK:   bTmp = sal_True; // NoBreak
622         case PROT_GROW:     aOut += !bTmp ? "Grow" :
623                                     ( nFunction == PROT_SHRINK ? "Shrink" : "AdjustNgbhd" );
624                             lcl_Start( aOut, aLayer, nAct );
625                             if( pParam )
626                             {
627                                 aOut += ' ';
628                                 aOut += ByteString::CreateFromInt64( *((long*)pParam) );
629                             }
630                             break;
631         case PROT_POS:      break;
632         case PROT_PRTAREA:  aOut += "PrtArea";
633                             lcl_Start( aOut, aLayer, nAct );
634                             break;
635         case PROT_SIZE:     aOut += "Size";
636                             lcl_Start( aOut, aLayer, nAct );
637                             aOut += ' ';
638                             aOut += ByteString::CreateFromInt64( pFrm->Frm().Height() );
639                             break;
640         case PROT_LEAF:     aOut += "Prev/NextLeaf";
641                             lcl_Start( aOut, aLayer, nAct );
642                             aOut += ' ';
643                             if( pParam )
644                             {
645                                 aOut += ' ';
646                                 aOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) );
647                             }
648                             break;
649         case PROT_FILE_INIT: FileInit();
650                              aOut = "Initialize";
651                             break;
652         case PROT_SECTION:  SectFunc( aOut, pFrm, nAct, pParam );
653                             break;
654         case PROT_CUT:      bTmp = sal_True; // NoBreak
655         case PROT_PASTE:    aOut += bTmp ? "Cut from " : "Paste to ";
656                             aOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) );
657                             break;
658         case PROT_TESTFORMAT: aOut += "Test";
659                             lcl_Start( aOut, aLayer, nAct );
660                             if( ACT_START == nAct )
661                                 nTestMode |= 2;
662                             else
663                                 nTestMode &= ~2;
664                             break;
665         case PROT_FRMCHANGES:
666                             {
667                                 SwRect& rFrm = *((SwRect*)pParam);
668                                 if( pFrm->Frm().Pos() != rFrm.Pos() )
669                                 {
670                                     aOut += "PosChg: (";
671                                     aOut += ByteString::CreateFromInt64(rFrm.Left());
672                                     aOut += ", ";
673                                     aOut += ByteString::CreateFromInt64(rFrm.Top());
674                                     aOut += ") (";
675                                     aOut += ByteString::CreateFromInt64(pFrm->Frm().Left());
676                                     aOut += ", ";
677                                     aOut += ByteString::CreateFromInt64(pFrm->Frm().Top());
678                                     aOut += ") ";
679                                 }
680                                 if( pFrm->Frm().Height() != rFrm.Height() )
681                                 {
682                                     aOut += "Height: ";
683                                     aOut += ByteString::CreateFromInt64(rFrm.Height());
684                                     aOut += " -> ";
685                                     aOut += ByteString::CreateFromInt64(pFrm->Frm().Height());
686                                     aOut += " ";
687                                 }
688                                 if( pFrm->Frm().Width() != rFrm.Width() )
689                                 {
690                                     aOut += "Width: ";
691                                     aOut += ByteString::CreateFromInt64(rFrm.Width());
692                                     aOut += " -> ";
693                                     aOut += ByteString::CreateFromInt64(pFrm->Frm().Width());
694                                     aOut += " ";
695                                 }
696                                 break;
697                             }
698     }
699     *pStream << aOut.GetBuffer() << endl;   // Ausgabe
700     pStream->Flush();   // Gleich auf die Platte, damit man mitlesen kann
701     if( ++nLineCount >= nMaxLines )     // Maximale Ausgabe erreicht?
702         SwProtocol::SetRecord( 0 );        // => Ende der Aufzeichnung
703 }
704 
705 /* -----------------13.01.99 11:39-------------------
706  * SwImplProtocol::SectFunc(...) wird von SwImplProtocol::_Record(..) gerufen,
707  * hier werden die Ausgaben rund um SectionFrms abgehandelt.
708  * --------------------------------------------------*/
709 
710 void SwImplProtocol::SectFunc( ByteString &rOut, const SwFrm* , sal_uLong nAct, void* pParam )
711 {
712     sal_Bool bTmp = sal_False;
713     switch( nAct )
714     {
715         case ACT_MERGE:         rOut += "Merge Section ";
716                                 rOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) );
717                                 break;
718         case ACT_CREATE_MASTER: bTmp = sal_True; // NoBreak
719         case ACT_CREATE_FOLLOW: rOut += "Create Section ";
720                                 rOut += bTmp ? "Master to " : "Follow from ";
721                                 rOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) );
722                                 break;
723         case ACT_DEL_MASTER:    bTmp = sal_True; // NoBreak
724         case ACT_DEL_FOLLOW:    rOut += "Delete Section ";
725                                 rOut += bTmp ? "Master to " : "Follow from ";
726                                 rOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) );
727                                 break;
728     }
729 }
730 
731 /* -----------------11.01.99 11:31-------------------
732  * SwImplProtocol::InsertFrm(..) nimmt eine neue FrmId zum Aufzeichnen auf,
733  * wenn pFrmIds==NULL, werden alle aufgezeichnet, sobald durch InsertFrm(..)
734  * pFrmIds angelegt wird, werden nur noch die enthaltenen FrmIds aufgezeichnet.
735  * --------------------------------------------------*/
736 
737 sal_Bool SwImplProtocol::InsertFrm( sal_uInt16 nId )
738 {
739     if( !pFrmIds )
740         pFrmIds = new SvUShortsSort(5,5);
741     if( pFrmIds->Seek_Entry( nId ) )
742         return sal_False;
743     pFrmIds->Insert( nId );
744     return sal_True;
745 }
746 
747 /* -----------------11.01.99 11:52-------------------
748  * SwImplProtocol::DeleteFrm(..) entfernt eine FrmId aus dem pFrmIds-Array,
749  * so dass diese Frame nicht mehr aufgezeichnet wird.
750  * --------------------------------------------------*/
751 sal_Bool SwImplProtocol::DeleteFrm( sal_uInt16 nId )
752 {
753     sal_uInt16 nPos;
754     if( !pFrmIds || !pFrmIds->Seek_Entry( nId, &nPos ) )
755         return sal_False;
756     pFrmIds->Remove( nPos );
757     return sal_True;
758 }
759 
760 /*-----------------20.9.2001 10:29------------------
761  * SwProtocol::SnapShot(..)
762  * creates a snapshot of the given frame and its content.
763  * --------------------------------------------------*/
764 void SwImplProtocol::SnapShot( const SwFrm* pFrm, sal_uLong nFlags )
765 {
766     while( pFrm )
767     {
768         _Record( pFrm, PROT_SNAPSHOT, 0, 0);
769         if( pFrm->GetDrawObjs() && nFlags & SNAP_FLYFRAMES )
770         {
771             aLayer += "[ ";
772             const SwSortedObjs &rObjs = *pFrm->GetDrawObjs();
773             for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
774             {
775                 SwAnchoredObject* pObj = rObjs[i];
776                 if ( pObj->ISA(SwFlyFrm) )
777                     SnapShot( static_cast<SwFlyFrm*>(pObj), nFlags );
778             }
779             if( aLayer.Len() > 1 )
780                 aLayer.Erase( aLayer.Len() - 2 );
781         }
782         if( pFrm->IsLayoutFrm() && nFlags & SNAP_LOWER &&
783             ( !pFrm->IsTabFrm() || nFlags & SNAP_TABLECONT ) )
784         {
785             aLayer += "  ";
786             SnapShot( ((SwLayoutFrm*)pFrm)->Lower(), nFlags );
787             if( aLayer.Len() > 1 )
788                 aLayer.Erase( aLayer.Len() - 2 );
789         }
790         pFrm = pFrm->GetNext();
791     }
792 }
793 
794 /* -----------------11.01.99 11:53-------------------
795  * SwEnterLeave::Ctor(..) wird vom eigentlichen (inline-)Kontruktor gerufen,
796  * wenn die Funktion aufgezeichnet werden soll.
797  * Die Aufgabe ist es abhaengig von der Funktion das richtige SwImplEnterLeave-Objekt
798  * zu erzeugen, alles weitere geschieht dann in dessen Ctor/Dtor.
799  * --------------------------------------------------*/
800 void SwEnterLeave::Ctor( const SwFrm* pFrm, sal_uLong nFunc, sal_uLong nAct, void* pPar )
801 {
802     switch( nFunc )
803     {
804         case PROT_ADJUSTN :
805         case PROT_GROW:
806         case PROT_SHRINK : pImpl = new SwSizeEnterLeave( pFrm, nFunc, nAct, pPar ); break;
807         case PROT_MOVE_FWD:
808         case PROT_MOVE_BWD : pImpl = new SwUpperEnterLeave( pFrm, nFunc, nAct, pPar ); break;
809         case PROT_FRMCHANGES : pImpl = new SwFrmChangesLeave( pFrm, nFunc, nAct, pPar ); break;
810         default: pImpl = new SwImplEnterLeave( pFrm, nFunc, nAct, pPar ); break;
811     }
812     pImpl->Enter();
813 }
814 
815 /* -----------------11.01.99 11:56-------------------
816  * SwEnterLeave::Dtor() ruft lediglich den Destruktor des SwImplEnterLeave-Objekts,
817  * ist nur deshalb nicht inline, damit die SwImplEnterLeave-Definition nicht
818  * im dbg_lay.hxx zu stehen braucht.
819  * --------------------------------------------------*/
820 
821 void SwEnterLeave::Dtor()
822 {
823     if( pImpl )
824     {
825         pImpl->Leave();
826         delete pImpl;
827     }
828 }
829 
830 void SwImplEnterLeave::Enter()
831 {
832     SwProtocol::Record( pFrm, nFunction, ACT_START, pParam );
833 }
834 
835 void SwImplEnterLeave::Leave()
836 {
837     SwProtocol::Record( pFrm, nFunction, ACT_END, pParam );
838 }
839 
840 void SwSizeEnterLeave::Leave()
841 {
842     nFrmHeight = pFrm->Frm().Height() - nFrmHeight;
843     SwProtocol::Record( pFrm, nFunction, ACT_END, &nFrmHeight );
844 }
845 
846 void SwUpperEnterLeave::Enter()
847 {
848     nFrmId = pFrm->GetUpper() ? sal_uInt16(lcl_GetFrameId( pFrm->GetUpper() )) : 0;
849     SwProtocol::Record( pFrm, nFunction, ACT_START, &nFrmId );
850 }
851 
852 void SwUpperEnterLeave::Leave()
853 {
854     nFrmId = pFrm->GetUpper() ? sal_uInt16(lcl_GetFrameId( pFrm->GetUpper() )) : 0;
855     SwProtocol::Record( pFrm, nFunction, ACT_END, &nFrmId );
856 }
857 
858 void SwFrmChangesLeave::Enter()
859 {
860 }
861 
862 void SwFrmChangesLeave::Leave()
863 {
864     if( pFrm->Frm() != aFrm )
865         SwProtocol::Record( pFrm, PROT_FRMCHANGES, 0, &aFrm );
866 }
867 
868 #endif // DBG_UTIL
869 
870