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