xref: /AOO41X/main/sw/source/core/layout/dbg_lay.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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