blob: 9ac59e19be2d9c604b82720af2db8cfc30902429 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#ifdef DBG_UTIL
/* -----------------08.01.99 14:55-------------------
* Und hier die Beschreibung:
*
* Durch die PROTOCOL-Makros wird es ermoeglicht, Ereignisse im Frame-Methoden zu protokollieren.
* In protokollwuerdigen Stellen in Frame-Methoden muss entweder ein PROTOCOL(...) oder bei Methoden,
* bei denen auch das Verlassen der Methode mitprotokolliert werden soll, ein PROTOCOL_ENTER(...)-Makro
* stehen.
* Die Parameter der PROTOCOL-Makros sind
* 1. Ein Pointer auf einen SwFrm, also meist "this" oder "rThis"
* 2. Die Funktionsgruppe z.B. PROT_MAKEALL, hierueber wird (inline) entschieden, ob dies
* zur Zeit protokolliert werden soll oder nicht.
* 3. Die Aktion, im Normalfall 0, aber z.B. ein ACT_START bewirkt eine Einrueckung in der
* Ausgabedatei, ein ACT_END nimmt dies wieder zurueck. Auf diese Art wird z.B. durch
* PROTOCOL_ENTER am Anfang einer Methode eingerueckt und beim Verlassen wieder zurueck.
* 4. Der vierte Parameter ist ein void-Pointer, damit man irgendetwas uebergeben kann,
* was in das Protokoll einfliessen kann, typesches Beispiel bei PROT_GROW muss man
* einen Pointer auf den Wert, um den gegrowt werden soll, uebergeben.
*
*
* Das Protokoll ist die Datei "dbg_lay.out" im aktuellen (BIN-)Verzeichnis.
* Es enthaelt Zeilen mit FrmId, Funktionsgruppe sowie weiteren Infos.
*
* Was genau protokolliert wird, kann auf folgende Arten eingestellt werden:
* 1. Die statische Variable SwProtokoll::nRecord enthaelt die Funktionsgruppen,
* die aufgezeichnet werden sollen.
* Ein Wert von z.B. PROT_GROW bewirkt, das Aufrufe von SwFrm::Grow dokumentiert werden,
* PROT_MAKEALL protokolliert Aufrufe von xxx::MakeAll.
* Die PROT_XY-Werte koennen oderiert werden.
* Default ist Null, es wird keine Methode aufgezeichnet.
* 2. In der SwImplProtocol-Klasse gibt es einen Filter fuer Frame-Typen,
* nur die Methodenaufrufe von Frame-Typen, die dort gesetzt sind, werden protokolliert.
* Der Member nTypes kann auf Werte wie FRM_PAGE, FRM_SECTION gesetzt und oderiert werden.
* Default ist 0xFFFF, d.h. alle Frame-Typen.
* 3. In der SwImplProtocol-Klasse gibt es einen ArrayPointer auf FrmIds, die zu ueberwachen sind.
* Ist der Pointer Null, so werden alle Frames protokolliert, ansonsten nur Frames,
* die in dem Array vermerkt sind.
*
* Eine Aufzeichnung in Gang zu setzen, erfordert entweder Codemanipulation, z.B. in
* SwProtocol::Init() einen anderen Default fuer nRecord setzen oder Debuggermanipulation.
* Im Debugger gibt verschiedene, sich anbietende Stellen:
* 1. In SwProtocol::Init() einen Breakpoint setzen und dort nRecord manipulieren, ggf.
* FrmIds eintragen, dann beginnt die Aufzeichnung bereits beim Programmstart.
* 2. Waehrend des Programmlaufs einen Breakpoint vor irgendein PROTOCOL oder PROTOCOL_ENTER-
* Makro setzen, dann am SwProtocol::nRecord das unterste Bit setzen (PROT_INIT). Dies
* bewirkt, dass die Funktionsgruppe des folgenden Makros aktiviert und in Zukunft
* protokolliert wird.
* 3. Spezialfall von 2.: Wenn man 2. in der Methode SwRootFrm::Paint(..) anwendet, werden
* die Aufzeichnungseinstellung aus der Datei "dbg_lay.ini" ausgelesen!
* In dieser INI-Datei kann es Kommentarzeilen geben, diese beginnen mit '#', dann
* sind die Sektionen "[frmid]", "[frmtype]" und "[record]" relevant.
* Nach [frmid] koennen die FrameIds der zu protokollierenden Frames folgen. Gibt es
* dort keine Eintraege, werden alle Frames aufgezeichnet.
* Nach [frmtype] koennen FrameTypen folgen, die aufgezeichnet werden sollen, da der
* Default hier allerdings USHRT_MAX ist, werden sowieso alle aufgezeichnet. Man kann
* allerdings auch Typen entfernen, in dem man ein '!' vor den Wert setzt, z.B.
* !0xC000 nimmt die SwCntntFrms aus der Aufzeichnung heraus.
* Nach [record] folgen die Funktionsgruppen, die aufgezeichnet werden sollen, Default
* ist hier 0, also keine. Auch hier kann man mit einem vorgestellten '!' Funktionen
* wieder entfernen.
* Hier mal ein Beispiel fuer eine INI-Datei:
* ------------------------------------------
* #Funktionen: Alle, ausser PRTAREA
* [record] 0xFFFFFFE !0x200
* [frmid]
* #folgende FrmIds:
* 1 2 12 13 14 15
* #keine Layoutframes ausser ColumnFrms
* [frmtype] !0x3FFF 0x4
* ------------------------------------------
*
* Wenn die Aufzeichnung erstmal laeuft, kann man in SwImplProtocol::_Record(...) mittels
* Debugger vielfaeltige Manipulationen vornehmen, z.B. bezueglich FrameTypen oder FrmIds.
*
* --------------------------------------------------*/
#ifndef DBG_UTIL
#error Wer fummelt denn an den makefiles rum?
#endif
#include "dbg_lay.hxx"
#include <tools/stream.hxx>
#ifndef _SVSTDARR_HXX
#define _SVSTDARR_USHORTS
#define _SVSTDARR_USHORTSSORT
#define _SVSTDARR_LONGS
#include <svl/svstdarr.hxx>
#endif
#include <stdio.h>
#include "frame.hxx"
#include "layfrm.hxx"
#include "flyfrm.hxx"
#include "txtfrm.hxx"
#include "ndtxt.hxx"
#include "dflyobj.hxx"
#include <fntcache.hxx>
// OD 2004-05-24 #i28701#
#include <sortedobjs.hxx>
sal_uLong SwProtocol::nRecord = 0;
SwImplProtocol* SwProtocol::pImpl = NULL;
sal_uLong lcl_GetFrameId( const SwFrm* pFrm )
{
#ifdef DBG_UTIL
static sal_Bool bFrameId = sal_False;
if( bFrameId )
return pFrm->GetFrmId();
#endif
if( pFrm && pFrm->IsTxtFrm() )
return ((SwTxtFrm*)pFrm)->GetTxtNode()->GetIndex();
return 0;
}
class SwImplProtocol
{
SvFileStream *pStream; // Ausgabestream
SvUShortsSort *pFrmIds; // welche FrmIds sollen aufgezeichnet werden ( NULL == alle )
SvLongs *pVar; // Variables
ByteString aLayer; // Einrueckung der Ausgabe (" " pro Start/End)
sal_uInt16 nTypes; // welche Typen sollen aufgezeichnet werden
sal_uInt16 nLineCount; // Ausgegebene Zeilen
sal_uInt16 nMaxLines; // Maximal auszugebende Zeilen
sal_uInt8 nInitFile; // Bereich (FrmId,FrmType,Record) beim Einlesen der INI-Datei
sal_uInt8 nTestMode; // Special fuer Testformatierung, es wird ggf. nur
// innerhalb einer Testformatierung aufgezeichnet.
void _Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam );
sal_Bool NewStream();
void CheckLine( ByteString& rLine );
void SectFunc( ByteString &rOut, const SwFrm* pFrm, sal_uLong nAct, void* pParam );
public:
SwImplProtocol();
~SwImplProtocol();
// Aufzeichnen
void Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam )
{ if( pStream ) _Record( pFrm, nFunction, nAct, pParam ); }
sal_Bool InsertFrm( sal_uInt16 nFrmId ); // FrmId aufnehmen zum Aufzeichnen
sal_Bool DeleteFrm( sal_uInt16 nFrmId ); // FrmId entfernen, diesen nicht mehr Aufzeichnen
void FileInit(); // Auslesen der INI-Datei
void ChkStream() { if( !pStream ) NewStream(); }
void SnapShot( const SwFrm* pFrm, sal_uLong nFlags );
void GetVar( const sal_uInt16 nNo, long& rVar )
{ if( pVar && nNo < pVar->Count() ) rVar = (*pVar)[ nNo ]; }
};
/* -----------------11.01.99 10:43-------------------
* Durch das PROTOCOL_ENTER-Makro wird ein SwEnterLeave-Objekt erzeugt,
* wenn die aktuelle Funktion aufgezeichnet werden soll, wird ein
* SwImplEnterLeave-Objekt angelegt. Der Witz dabei ist, das der Ctor
* des Impl-Objekt am Anfang der Funktion und automatisch der Dtor beim
* Verlassen der Funktion gerufen wird. In der Basis-Implementierung ruft
* der Ctor lediglich ein PROTOCOL(..) mit ACT_START und im Dtor ein
* PROTOCOL(..) mit ACT_END.
* Es lassen sich Ableitungen der Klasse bilden, um z.B. beim Verlassen
* einer Funktion Groessenaenderungen des Frames zu dokumentieren u.v.a.m.
* Dazu braucht dann nur noch in SwEnterLeave::Ctor(...) die gewuenschte
* SwImplEnterLeave-Klasse angelegt zu werden.
*
* --------------------------------------------------*/
class SwImplEnterLeave
{
protected:
const SwFrm* pFrm; // Der Frame,
sal_uLong nFunction, nAction; // die Funktion, ggf. die Aktion
void* pParam; // und weitere Parameter
public:
SwImplEnterLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar )
: pFrm( pF ), nFunction( nFunct ), nAction( nAct ), pParam( pPar ) {}
virtual void Enter(); // Ausgabe beim Eintritt
virtual void Leave(); // Ausgabe beim Verlassen
};
class SwSizeEnterLeave : public SwImplEnterLeave
{
long nFrmHeight;
public:
SwSizeEnterLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar )
: SwImplEnterLeave( pF, nFunct, nAct, pPar ), nFrmHeight( pF->Frm().Height() ) {}
virtual void Leave(); // Ausgabe der Groessenaenderung
};
class SwUpperEnterLeave : public SwImplEnterLeave
{
sal_uInt16 nFrmId;
public:
SwUpperEnterLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar )
: SwImplEnterLeave( pF, nFunct, nAct, pPar ), nFrmId( 0 ) {}
virtual void Enter(); // Ausgabe
virtual void Leave(); // Ausgabe der FrmId des Uppers
};
class SwFrmChangesLeave : public SwImplEnterLeave
{
SwRect aFrm;
public:
SwFrmChangesLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar )
: SwImplEnterLeave( pF, nFunct, nAct, pPar ), aFrm( pF->Frm() ) {}
virtual void Enter(); // keine Ausgabe
virtual void Leave(); // Ausgabe bei Aenderung der Frm-Area
};
void SwProtocol::Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam )
{
if( Start() )
{ // Hier landen wir, wenn im Debugger SwProtocol::nRecord mit PROT_INIT(0x1) oderiert wurde
sal_Bool bFinit = sal_False; // Dies bietet im Debugger die Moeglichkeit,
if( bFinit ) // die Aufzeichnung dieser Action zu beenden
{
nRecord &= ~nFunction; // Diese Funktion nicht mehr aufzeichnen
nRecord &= ~PROT_INIT; // PROT_INIT stets zuruecksetzen
return;
}
nRecord |= nFunction; // Aufzeichnung dieser Funktion freischalten
nRecord &= ~PROT_INIT; // PROT_INIT stets zuruecksetzen
if( pImpl )
pImpl->ChkStream();
}
if( !pImpl ) // Impl-Object anlegen, wenn noetig
pImpl = new SwImplProtocol();
pImpl->Record( pFrm, nFunction, nAct, pParam ); // ...und Aufzeichnen
}
// Die folgende Funktion wird beim Anziehen der Writer-DLL durch TxtInit(..) aufgerufen
// und ermoeglicht dem Debuggenden Funktionen und/oder FrmIds freizuschalten
void SwProtocol::Init()
{
nRecord = 0;
XubString aName( "dbg_lay.go", RTL_TEXTENCODING_MS_1252 );
SvFileStream aStream( aName, STREAM_READ );
if( aStream.IsOpen() )
{
pImpl = new SwImplProtocol();
pImpl->FileInit();
}
aStream.Close();
}
// Ende der Aufzeichnung
void SwProtocol::Stop()
{
if( pImpl )
{
delete pImpl;
pImpl = NULL;
if( pFntCache )
pFntCache->Flush();
}
nRecord = 0;
}
// Creates a more or less detailed snapshot of the layout structur
void SwProtocol::SnapShot( const SwFrm* pFrm, sal_uLong nFlags )
{
if( pImpl )
pImpl->SnapShot( pFrm, nFlags );
}
void SwProtocol::GetVar( const sal_uInt16 nNo, long& rVar )
{
if( pImpl )
pImpl->GetVar( nNo, rVar );
}
SwImplProtocol::SwImplProtocol()
: pStream( NULL ), pFrmIds( NULL ), pVar( NULL ), nTypes( 0xffff ),
nLineCount( 0 ), nMaxLines( USHRT_MAX ), nTestMode( 0 )
{
NewStream();
}
sal_Bool SwImplProtocol::NewStream()
{
XubString aName( "dbg_lay.out", RTL_TEXTENCODING_MS_1252 );
nLineCount = 0;
pStream = new SvFileStream( aName, STREAM_WRITE | STREAM_TRUNC );
if( pStream->GetError() )
{
delete pStream;
pStream = NULL;
}
return 0 != pStream;
}
SwImplProtocol::~SwImplProtocol()
{
if( pStream )
{
pStream->Close();
delete pStream;
}
delete pFrmIds;
delete pVar;
}
/* -----------------11.01.99 11:03-------------------
* SwImplProtocol::CheckLine analysiert eine Zeile der INI-Datei
* --------------------------------------------------*/
void SwImplProtocol::CheckLine( ByteString& rLine )
{
rLine = rLine.ToLowerAscii(); // Gross/Kleinschreibung ist einerlei
while( STRING_LEN > rLine.SearchAndReplace( '\t', ' ' ) )
; //nothing // Tabs werden durch Blanks ersetzt
if( '#' == rLine.GetChar(0) ) // Kommentarzeilen beginnen mit '#'
return;
if( '[' == rLine.GetChar(0) ) // Bereiche: FrmIds, Typen oder Funktionen
{
ByteString aTmp = rLine.GetToken( 0, ']' );
if( "[frmid" == aTmp ) // Bereich FrmIds
{
nInitFile = 1;
delete pFrmIds;
pFrmIds = NULL; // Default: Alle Frames aufzeichnen
}
else if( "[frmtype" == aTmp )// Bereich Typen
{
nInitFile = 2;
nTypes = USHRT_MAX; // Default: Alle FrmaeTypen aufzeichnen
}
else if( "[record" == aTmp )// Bereich Funktionen
{
nInitFile = 3;
SwProtocol::SetRecord( 0 );// Default: Keine Funktion wird aufgezeichnet
}
else if( "[test" == aTmp )// Bereich Funktionen
{
nInitFile = 4; // Default:
nTestMode = 0; // Ausserhalb der Testformatierung wird aufgezeichnet
}
else if( "[max" == aTmp )// maximale Zeilenzahl
{
nInitFile = 5; // Default:
nMaxLines = USHRT_MAX;
}
else if( "[var" == aTmp )// variables
{
nInitFile = 6;
if( !pVar )
pVar = new SvLongs( 5, 5 );
}
else
nInitFile = 0; // Nanu: Unbekannter Bereich?
rLine.Erase( 0, aTmp.Len() + 1 );
}
sal_uInt16 nToks = rLine.GetTokenCount( ' ' ); // Blanks (oder Tabs) sind die Trenner
for( sal_uInt16 i=0; i < nToks; ++i )
{
ByteString aTok = rLine.GetToken( i, ' ' );
sal_Bool bNo = sal_False;
if( '!' == aTok.GetChar(0) )
{
bNo = sal_True; // Diese(n) Funktion/Typ entfernen
aTok.Erase( 0, 1 );
}
if( aTok.Len() )
{
sal_uLong nVal;
sscanf( aTok.GetBuffer(), "%li", &nVal );
switch ( nInitFile )
{
case 1: InsertFrm( sal_uInt16( nVal ) ); // FrmId aufnehmen
break;
case 2: {
sal_uInt16 nNew = (sal_uInt16)nVal;
if( bNo )
nTypes &= ~nNew; // Typ entfernen
else
nTypes |= nNew; // Typ aufnehmen
}
break;
case 3: {
sal_uLong nOld = SwProtocol::Record();
if( bNo )
nOld &= ~nVal; // Funktion entfernen
else
nOld |= nVal; // Funktion aufnehmen
SwProtocol::SetRecord( nOld );
}
break;
case 4: {
sal_uInt8 nNew = (sal_uInt8)nVal;
if( bNo )
nTestMode &= ~nNew; // TestMode zuruecksetzen
else
nTestMode |= nNew; // TestMode setzen
}
break;
case 5: nMaxLines = (sal_uInt16)nVal;
break;
case 6: pVar->Insert( (long)nVal, pVar->Count() );
break;
}
}
}
}
/* -----------------11.01.99 11:17-------------------
* SwImplProtocol::FileInit() liest die Datei "dbg_lay.ini"
* im aktuellen Verzeichnis und wertet sie aus.
* --------------------------------------------------*/
void SwImplProtocol::FileInit()
{
XubString aName( "dbg_lay.ini", RTL_TEXTENCODING_MS_1252 );
SvFileStream aStream( aName, STREAM_READ );
if( aStream.IsOpen() )
{
ByteString aLine;
nInitFile = 0;
while( !aStream.IsEof() )
{
sal_Char c;
aStream >> c;
if( '\n' == c || '\r' == c ) // Zeilenende
{
aLine.EraseLeadingChars();
aLine.EraseTrailingChars();
if( aLine.Len() )
CheckLine( aLine ); // Zeile auswerten
aLine.Erase();
}
else
aLine += c;
}
if( aLine.Len() )
CheckLine( aLine ); // letzte Zeile auswerten
}
aStream.Close();
}
/* -----------------11.01.99 11:20-------------------
* lcl_Start sorgt fuer Einrueckung um zwei Blanks bei ACT_START
* und nimmt diese bei ACT_END wieder zurueck.
* --------------------------------------------------*/
void lcl_Start( ByteString& rOut, ByteString& rLay, sal_uLong nAction )
{
if( nAction == ACT_START )
{
rLay += " ";
rOut += " On";
}
else if( nAction == ACT_END )
{
if( rLay.Len() > 1 )
{
rLay.Erase( rLay.Len() - 2 );
rOut.Erase( 0, 2 );
}
rOut += " Off";
}
}
/* -----------------11.01.99 11:21-------------------
* lcl_Flags gibt das ValidSize-, ValidPos- und ValidPrtArea-Flag ("Sz","Ps","PA")
* des Frames aus, "+" fuer valid, "-" fuer invalid.
* --------------------------------------------------*/
void lcl_Flags( ByteString& rOut, const SwFrm* pFrm )
{
rOut += " Sz";
rOut += pFrm->GetValidSizeFlag() ? '+' : '-';
rOut += " Ps";
rOut += pFrm->GetValidPosFlag() ? '+' : '-';
rOut += " PA";
rOut += pFrm->GetValidPrtAreaFlag() ? '+' : '-';
}
/* -----------------11.01.99 11:23-------------------
* lcl_FrameType gibt den Typ des Frames in Klartext aus.
* --------------------------------------------------*/
void lcl_FrameType( ByteString& rOut, const SwFrm* pFrm )
{
if( pFrm->IsTxtFrm() )
rOut += "Txt ";
else if( pFrm->IsLayoutFrm() )
{
if( pFrm->IsPageFrm() )
rOut += "Page ";
else if( pFrm->IsColumnFrm() )
rOut += "Col ";
else if( pFrm->IsBodyFrm() )
{
if( pFrm->GetUpper() && pFrm->IsColBodyFrm() )
rOut += "(Col)";
rOut += "Body ";
}
else if( pFrm->IsRootFrm() )
rOut += "Root ";
else if( pFrm->IsCellFrm() )
rOut += "Cell ";
else if( pFrm->IsTabFrm() )
rOut += "Tab ";
else if( pFrm->IsRowFrm() )
rOut += "Row ";
else if( pFrm->IsSctFrm() )
rOut += "Sect ";
else if( pFrm->IsHeaderFrm() )
rOut += "Header ";
else if( pFrm->IsFooterFrm() )
rOut += "Footer ";
else if( pFrm->IsFtnFrm() )
rOut += "Ftn ";
else if( pFrm->IsFtnContFrm() )
rOut += "FtnCont ";
else if( pFrm->IsFlyFrm() )
rOut += "Fly ";
else
rOut += "Layout ";
}
else if( pFrm->IsNoTxtFrm() )
rOut += "NoTxt ";
else
rOut += "Not impl. ";
}
/* -----------------11.01.99 11:25-------------------
* SwImplProtocol::Record(..) wird nur gerufen, wenn das PROTOCOL-Makro
* feststellt, dass die Funktion aufgezeichnet werden soll ( SwProtocol::nRecord ).
* In dieser Methode werden noch die beiden weiteren Einschraenkungen ueberprueft,
* ob die FrmId und der FrameType zu den aufzuzeichnenden gehoeren.
* --------------------------------------------------*/
void SwImplProtocol::_Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam )
{
sal_uInt16 nSpecial = 0;
if( nSpecial ) // Debugger-Manipulationsmoeglichkeit
{
sal_uInt16 nId = sal_uInt16(lcl_GetFrameId( pFrm ));
switch ( nSpecial )
{
case 1: InsertFrm( nId ); break;
case 2: DeleteFrm( nId ); break;
case 3: delete pFrmIds; pFrmIds = NULL; break;
case 4: delete pStream; pStream = NULL; break;
}
return;
}
if( !pStream && !NewStream() )
return; // Immer noch kein Stream
if( pFrmIds && !pFrmIds->Seek_Entry( sal_uInt16(lcl_GetFrameId( pFrm )) ) )
return; // gehoert nicht zu den gewuenschten FrmIds
if( !(pFrm->GetType() & nTypes) )
return; // Der Typ ist unerwuenscht
if( 1 == nTestMode && nFunction != PROT_TESTFORMAT )
return; // Wir sollen nur innerhalb einer Testformatierung aufzeichnen
sal_Bool bTmp = sal_False;
ByteString aOut = aLayer;
aOut += ByteString::CreateFromInt64( lcl_GetFrameId( pFrm ) );
aOut += ' ';
lcl_FrameType( aOut, pFrm ); // dann den FrameType
switch ( nFunction ) // und die Funktion
{
case PROT_SNAPSHOT: lcl_Flags( aOut, pFrm );
break;
case PROT_MAKEALL: aOut += "MakeAll";
lcl_Start( aOut, aLayer, nAct );
if( nAct == ACT_START )
lcl_Flags( aOut, pFrm );
break;
case PROT_MOVE_FWD: bTmp = sal_True; // NoBreak
case PROT_MOVE_BWD: aOut += ( nFunction == bTmp ) ? "Fwd" : "Bwd";
lcl_Start( aOut, aLayer, nAct );
if( pParam )
{
aOut += ' ';
aOut += ByteString::CreateFromInt32( *((sal_uInt16*)pParam) );
}
break;
case PROT_GROW_TST: if( ACT_START != nAct )
return;
aOut += "TestGrow";
break;
case PROT_SHRINK_TST: if( ACT_START != nAct )
return;
aOut += "TestShrink";
break;
case PROT_ADJUSTN :
case PROT_SHRINK: bTmp = sal_True; // NoBreak
case PROT_GROW: aOut += !bTmp ? "Grow" :
( nFunction == PROT_SHRINK ? "Shrink" : "AdjustNgbhd" );
lcl_Start( aOut, aLayer, nAct );
if( pParam )
{
aOut += ' ';
aOut += ByteString::CreateFromInt64( *((long*)pParam) );
}
break;
case PROT_POS: break;
case PROT_PRTAREA: aOut += "PrtArea";
lcl_Start( aOut, aLayer, nAct );
break;
case PROT_SIZE: aOut += "Size";
lcl_Start( aOut, aLayer, nAct );
aOut += ' ';
aOut += ByteString::CreateFromInt64( pFrm->Frm().Height() );
break;
case PROT_LEAF: aOut += "Prev/NextLeaf";
lcl_Start( aOut, aLayer, nAct );
aOut += ' ';
if( pParam )
{
aOut += ' ';
aOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) );
}
break;
case PROT_FILE_INIT: FileInit();
aOut = "Initialize";
break;
case PROT_SECTION: SectFunc( aOut, pFrm, nAct, pParam );
break;
case PROT_CUT: bTmp = sal_True; // NoBreak
case PROT_PASTE: aOut += bTmp ? "Cut from " : "Paste to ";
aOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) );
break;
case PROT_TESTFORMAT: aOut += "Test";
lcl_Start( aOut, aLayer, nAct );
if( ACT_START == nAct )
nTestMode |= 2;
else
nTestMode &= ~2;
break;
case PROT_FRMCHANGES:
{
SwRect& rFrm = *((SwRect*)pParam);
if( pFrm->Frm().Pos() != rFrm.Pos() )
{
aOut += "PosChg: (";
aOut += ByteString::CreateFromInt64(rFrm.Left());
aOut += ", ";
aOut += ByteString::CreateFromInt64(rFrm.Top());
aOut += ") (";
aOut += ByteString::CreateFromInt64(pFrm->Frm().Left());
aOut += ", ";
aOut += ByteString::CreateFromInt64(pFrm->Frm().Top());
aOut += ") ";
}
if( pFrm->Frm().Height() != rFrm.Height() )
{
aOut += "Height: ";
aOut += ByteString::CreateFromInt64(rFrm.Height());
aOut += " -> ";
aOut += ByteString::CreateFromInt64(pFrm->Frm().Height());
aOut += " ";
}
if( pFrm->Frm().Width() != rFrm.Width() )
{
aOut += "Width: ";
aOut += ByteString::CreateFromInt64(rFrm.Width());
aOut += " -> ";
aOut += ByteString::CreateFromInt64(pFrm->Frm().Width());
aOut += " ";
}
break;
}
}
*pStream << aOut.GetBuffer() << endl; // Ausgabe
pStream->Flush(); // Gleich auf die Platte, damit man mitlesen kann
if( ++nLineCount >= nMaxLines ) // Maximale Ausgabe erreicht?
SwProtocol::SetRecord( 0 ); // => Ende der Aufzeichnung
}
/* -----------------13.01.99 11:39-------------------
* SwImplProtocol::SectFunc(...) wird von SwImplProtocol::_Record(..) gerufen,
* hier werden die Ausgaben rund um SectionFrms abgehandelt.
* --------------------------------------------------*/
void SwImplProtocol::SectFunc( ByteString &rOut, const SwFrm* , sal_uLong nAct, void* pParam )
{
sal_Bool bTmp = sal_False;
switch( nAct )
{
case ACT_MERGE: rOut += "Merge Section ";
rOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) );
break;
case ACT_CREATE_MASTER: bTmp = sal_True; // NoBreak
case ACT_CREATE_FOLLOW: rOut += "Create Section ";
rOut += bTmp ? "Master to " : "Follow from ";
rOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) );
break;
case ACT_DEL_MASTER: bTmp = sal_True; // NoBreak
case ACT_DEL_FOLLOW: rOut += "Delete Section ";
rOut += bTmp ? "Master to " : "Follow from ";
rOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) );
break;
}
}
/* -----------------11.01.99 11:31-------------------
* SwImplProtocol::InsertFrm(..) nimmt eine neue FrmId zum Aufzeichnen auf,
* wenn pFrmIds==NULL, werden alle aufgezeichnet, sobald durch InsertFrm(..)
* pFrmIds angelegt wird, werden nur noch die enthaltenen FrmIds aufgezeichnet.
* --------------------------------------------------*/
sal_Bool SwImplProtocol::InsertFrm( sal_uInt16 nId )
{
if( !pFrmIds )
pFrmIds = new SvUShortsSort(5,5);
if( pFrmIds->Seek_Entry( nId ) )
return sal_False;
pFrmIds->Insert( nId );
return sal_True;
}
/* -----------------11.01.99 11:52-------------------
* SwImplProtocol::DeleteFrm(..) entfernt eine FrmId aus dem pFrmIds-Array,
* so dass diese Frame nicht mehr aufgezeichnet wird.
* --------------------------------------------------*/
sal_Bool SwImplProtocol::DeleteFrm( sal_uInt16 nId )
{
sal_uInt16 nPos;
if( !pFrmIds || !pFrmIds->Seek_Entry( nId, &nPos ) )
return sal_False;
pFrmIds->Remove( nPos );
return sal_True;
}
/*-----------------20.9.2001 10:29------------------
* SwProtocol::SnapShot(..)
* creates a snapshot of the given frame and its content.
* --------------------------------------------------*/
void SwImplProtocol::SnapShot( const SwFrm* pFrm, sal_uLong nFlags )
{
while( pFrm )
{
_Record( pFrm, PROT_SNAPSHOT, 0, 0);
if( pFrm->GetDrawObjs() && nFlags & SNAP_FLYFRAMES )
{
aLayer += "[ ";
const SwSortedObjs &rObjs = *pFrm->GetDrawObjs();
for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
{
SwAnchoredObject* pObj = rObjs[i];
if ( pObj->ISA(SwFlyFrm) )
SnapShot( static_cast<SwFlyFrm*>(pObj), nFlags );
}
if( aLayer.Len() > 1 )
aLayer.Erase( aLayer.Len() - 2 );
}
if( pFrm->IsLayoutFrm() && nFlags & SNAP_LOWER &&
( !pFrm->IsTabFrm() || nFlags & SNAP_TABLECONT ) )
{
aLayer += " ";
SnapShot( ((SwLayoutFrm*)pFrm)->Lower(), nFlags );
if( aLayer.Len() > 1 )
aLayer.Erase( aLayer.Len() - 2 );
}
pFrm = pFrm->GetNext();
}
}
/* -----------------11.01.99 11:53-------------------
* SwEnterLeave::Ctor(..) wird vom eigentlichen (inline-)Kontruktor gerufen,
* wenn die Funktion aufgezeichnet werden soll.
* Die Aufgabe ist es abhaengig von der Funktion das richtige SwImplEnterLeave-Objekt
* zu erzeugen, alles weitere geschieht dann in dessen Ctor/Dtor.
* --------------------------------------------------*/
void SwEnterLeave::Ctor( const SwFrm* pFrm, sal_uLong nFunc, sal_uLong nAct, void* pPar )
{
switch( nFunc )
{
case PROT_ADJUSTN :
case PROT_GROW:
case PROT_SHRINK : pImpl = new SwSizeEnterLeave( pFrm, nFunc, nAct, pPar ); break;
case PROT_MOVE_FWD:
case PROT_MOVE_BWD : pImpl = new SwUpperEnterLeave( pFrm, nFunc, nAct, pPar ); break;
case PROT_FRMCHANGES : pImpl = new SwFrmChangesLeave( pFrm, nFunc, nAct, pPar ); break;
default: pImpl = new SwImplEnterLeave( pFrm, nFunc, nAct, pPar ); break;
}
pImpl->Enter();
}
/* -----------------11.01.99 11:56-------------------
* SwEnterLeave::Dtor() ruft lediglich den Destruktor des SwImplEnterLeave-Objekts,
* ist nur deshalb nicht inline, damit die SwImplEnterLeave-Definition nicht
* im dbg_lay.hxx zu stehen braucht.
* --------------------------------------------------*/
void SwEnterLeave::Dtor()
{
if( pImpl )
{
pImpl->Leave();
delete pImpl;
}
}
void SwImplEnterLeave::Enter()
{
SwProtocol::Record( pFrm, nFunction, ACT_START, pParam );
}
void SwImplEnterLeave::Leave()
{
SwProtocol::Record( pFrm, nFunction, ACT_END, pParam );
}
void SwSizeEnterLeave::Leave()
{
nFrmHeight = pFrm->Frm().Height() - nFrmHeight;
SwProtocol::Record( pFrm, nFunction, ACT_END, &nFrmHeight );
}
void SwUpperEnterLeave::Enter()
{
nFrmId = pFrm->GetUpper() ? sal_uInt16(lcl_GetFrameId( pFrm->GetUpper() )) : 0;
SwProtocol::Record( pFrm, nFunction, ACT_START, &nFrmId );
}
void SwUpperEnterLeave::Leave()
{
nFrmId = pFrm->GetUpper() ? sal_uInt16(lcl_GetFrameId( pFrm->GetUpper() )) : 0;
SwProtocol::Record( pFrm, nFunction, ACT_END, &nFrmId );
}
void SwFrmChangesLeave::Enter()
{
}
void SwFrmChangesLeave::Leave()
{
if( pFrm->Frm() != aFrm )
SwProtocol::Record( pFrm, PROT_FRMCHANGES, 0, &aFrm );
}
#endif // DBG_UTIL