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