1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: XclImpChangeTrack.cxx,v $
10 * $Revision: 1.34.48.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 #include "XclImpChangeTrack.hxx"
35 #include <tools/debug.hxx>
36 #include <sot/storage.hxx>
37 #include <svtools/zforlist.hxx>
38 #include "chgviset.hxx"
40 #include "chgtrack.hxx"
41 #include "xihelper.hxx"
43 #include "externalrefmgr.hxx"
45 //___________________________________________________________________
46 // class XclImpChangeTrack
48 XclImpChangeTrack::XclImpChangeTrack( const XclImpRoot
& rRoot
, const XclImpStream
& rBookStrm
) :
55 bGlobExit( sal_False
),
58 // Verify that the User Names stream exists before going any further. Excel adds both
59 // "Revision Log" and "User Names" streams when Change Tracking is active but the Revision log
60 // remains if Change Tracking is turned off.
61 SotStorageStreamRef xUserStrm
= OpenStream( EXC_STREAM_USERNAMES
);
65 xInStrm
= OpenStream( EXC_STREAM_REVLOG
);
68 xInStrm
->Seek( STREAM_SEEK_TO_END
);
69 ULONG nStreamLen
= xInStrm
->Tell();
70 if( (xInStrm
->GetErrorCode() == ERRCODE_NONE
) && (nStreamLen
!= STREAM_SEEK_TO_END
) )
72 xInStrm
->Seek( STREAM_SEEK_TO_BEGIN
);
73 pStrm
= new XclImpStream( *xInStrm
, GetRoot() );
74 pStrm
->CopyDecrypterFrom( rBookStrm
);
75 pChangeTrack
= new ScChangeTrack( GetDocPtr() );
77 sOldUsername
= pChangeTrack
->GetUser();
78 pChangeTrack
->SetUseFixDateTime( TRUE
);
85 XclImpChangeTrack::~XclImpChangeTrack()
91 void XclImpChangeTrack::DoAcceptRejectAction( ScChangeAction
* pAction
)
93 if( !pAction
) return;
94 switch( aRecHeader
.nAccept
)
97 pChangeTrack
->Accept( pAction
);
104 void XclImpChangeTrack::DoAcceptRejectAction( sal_uInt32 nFirst
, sal_uInt32 nLast
)
106 for( sal_uInt32 nIndex
= nFirst
; nIndex
<= nLast
; nIndex
++ )
107 DoAcceptRejectAction( pChangeTrack
->GetAction( nIndex
) );
110 void XclImpChangeTrack::DoInsertRange( const ScRange
& rRange
)
112 sal_uInt32 nFirst
= pChangeTrack
->GetActionMax() + 1;
113 pChangeTrack
->AppendInsert( rRange
);
114 sal_uInt32 nLast
= pChangeTrack
->GetActionMax();
115 DoAcceptRejectAction( nFirst
, nLast
);
118 void XclImpChangeTrack::DoDeleteRange( const ScRange
& rRange
)
121 pChangeTrack
->AppendDeleteRange( rRange
, NULL
, nFirst
, nLast
);
122 DoAcceptRejectAction( nFirst
, nLast
);
125 SCTAB
XclImpChangeTrack::ReadTabNum()
127 return static_cast<SCTAB
>(GetTabInfo().GetCurrentIndex(
128 pStrm
->ReaduInt16(), nTabIdCount
));
131 void XclImpChangeTrack::ReadDateTime( DateTime
& rDateTime
)
134 sal_uInt8 nMonth
, nDay
, nHour
, nMin
, nSec
;
136 *pStrm
>> nYear
>> nMonth
>> nDay
>> nHour
>> nMin
>> nSec
;
138 rDateTime
.SetYear( nYear
);
139 rDateTime
.SetMonth( nMonth
);
140 rDateTime
.SetDay( nDay
);
141 rDateTime
.SetHour( nHour
);
142 rDateTime
.SetMin( nMin
);
143 rDateTime
.SetSec( nSec
);
144 rDateTime
.Set100Sec( 0 );
147 sal_Bool
XclImpChangeTrack::CheckRecord( sal_uInt16 nOpCode
)
149 if( (nOpCode
!= EXC_CHTR_OP_UNKNOWN
) && (aRecHeader
.nOpCode
!= nOpCode
) )
151 DBG_ERROR( "XclImpChangeTrack::CheckRecord - unknown action" );
154 return aRecHeader
.nIndex
!= 0;
157 sal_Bool
XclImpChangeTrack::Read3DTabRefInfo( SCTAB
& rFirstTab
, SCTAB
& rLastTab
, ExcelToSc8::ExternalTabInfo
& rExtInfo
)
159 if( LookAtuInt8() == 0x01 )
161 rExtInfo
.mbExternal
= false;
162 // internal ref - read tab num and return sc tab num (position in TABID list)
164 rFirstTab
= static_cast< SCTAB
>( GetTabInfo().GetCurrentIndex( pStrm
->ReaduInt16(), nTabIdCount
) );
165 sal_uInt8 nFillByte
= pStrm
->ReaduInt8();
166 rLastTab
= (nFillByte
== 0x00) ?
167 static_cast< SCTAB
>( GetTabInfo().GetCurrentIndex( pStrm
->ReaduInt16(), nTabIdCount
) ) : rFirstTab
;
171 // external ref - read doc and tab name and find sc tab num
173 String
aEncUrl( pStrm
->ReadUniString() );
176 XclImpUrlHelper::DecodeUrl( aUrl
, bSelf
, GetRoot(), aEncUrl
);
178 // - sheet name, always separated from URL
179 String
aTabName( pStrm
->ReadUniString() );
182 rExtInfo
.mbExternal
= true;
183 ScExternalRefManager
* pRefMgr
= GetDoc().GetExternalRefManager();
184 pRefMgr
->convertToAbsName(aUrl
);
185 rExtInfo
.mnFileId
= pRefMgr
->getExternalFileId(aUrl
);
186 rExtInfo
.maTabName
= aTabName
;
187 rFirstTab
= rLastTab
= 0;
192 void XclImpChangeTrack::ReadFormula( ScTokenArray
*& rpTokenArray
, const ScAddress
& rPosition
)
197 // create a memory stream and copy the formula to be able to read simultaneously
198 // the formula and the additional 3D tab ref data following the formula
199 // here we have to simulate an Excel record to be able to use an XclImpStream...
200 // 2do: remove the stream member from formula converter and add it as a parameter
201 // to the Convert() routine (to prevent the construction/destruction of the
202 // converter in each formula)
203 SvMemoryStream aMemStrm
;
204 aMemStrm
<< (sal_uInt16
) 0x0001 << nFmlSize
;
205 pStrm
->CopyToStream( aMemStrm
, nFmlSize
);
206 XclImpStream
aFmlaStrm( aMemStrm
, GetRoot() );
207 aFmlaStrm
.StartNextRecord();
208 XclImpChTrFmlConverter
aFmlConv( GetRoot(), *this );
210 // read the formula, 3D tab refs from extended data
211 const ScTokenArray
* pArray
= NULL
;
212 aFmlConv
.Reset( rPosition
);
213 ExcelConverterBase::ConvertParam aParam
;
214 aParam
.mbAllowArrays
= false;
215 BOOL bOK
= (aFmlConv
.Convert( pArray
, aFmlaStrm
, nFmlSize
, aParam
, FT_CellFormula
) == ConvOK
); // JEG : Check This
216 rpTokenArray
= (bOK
&& pArray
) ? new ScTokenArray( *pArray
) : NULL
;
220 void XclImpChangeTrack::ReadCell(
224 const ScAddress
& rPosition
)
228 switch( nFlags
& EXC_CHTR_TYPE_MASK
)
230 case EXC_CHTR_TYPE_EMPTY
:
232 case EXC_CHTR_TYPE_RK
:
234 double fValue
= ReadRK();
235 if( pStrm
->IsValid() )
236 rpCell
= new ScValueCell( fValue
);
239 case EXC_CHTR_TYPE_DOUBLE
:
243 if( pStrm
->IsValid() )
244 rpCell
= new ScValueCell( fValue
);
247 case EXC_CHTR_TYPE_STRING
:
249 String
sString( pStrm
->ReadUniString() );
250 if( pStrm
->IsValid() )
251 rpCell
= new ScStringCell( sString
);
254 case EXC_CHTR_TYPE_BOOL
:
256 double fValue
= (double) ReadBool();
257 if( pStrm
->IsValid() )
259 rpCell
= new ScValueCell( fValue
);
260 rFormat
= GetFormatter().GetStandardFormat( NUMBERFORMAT_LOGICAL
, ScGlobal::eLnge
);
264 case EXC_CHTR_TYPE_FORMULA
:
266 ScTokenArray
* pTokenArray
= NULL
;
267 ReadFormula( pTokenArray
, rPosition
);
268 if( pStrm
->IsValid() && pTokenArray
)
269 rpCell
= new ScFormulaCell( GetDocPtr(), rPosition
, pTokenArray
);
273 DBG_ERROR( "XclImpChangeTrack::ReadCell - unknown data type" );
277 void XclImpChangeTrack::ReadChTrInsert()
279 *pStrm
>> aRecHeader
;
280 if( CheckRecord( EXC_CHTR_OP_UNKNOWN
) )
282 if( (aRecHeader
.nOpCode
!= EXC_CHTR_OP_INSROW
) &&
283 (aRecHeader
.nOpCode
!= EXC_CHTR_OP_INSCOL
) &&
284 (aRecHeader
.nOpCode
!= EXC_CHTR_OP_DELROW
) &&
285 (aRecHeader
.nOpCode
!= EXC_CHTR_OP_DELCOL
) )
287 DBG_ERROR( "XclImpChangeTrack::ReadChTrInsert - unknown action" );
292 aRange
.aStart
.SetTab( ReadTabNum() );
293 aRange
.aEnd
.SetTab( aRange
.aStart
.Tab() );
295 Read2DRange( aRange
);
297 if( aRecHeader
.nOpCode
& EXC_CHTR_OP_COLFLAG
)
298 aRange
.aEnd
.SetRow( MAXROW
);
300 aRange
.aEnd
.SetCol( MAXCOL
);
302 BOOL bValid
= pStrm
->IsValid();
303 if( FoundNestedMode() )
308 if( aRecHeader
.nOpCode
& EXC_CHTR_OP_DELFLAG
)
309 DoDeleteRange( aRange
);
311 DoInsertRange( aRange
);
316 void XclImpChangeTrack::ReadChTrInfo()
318 pStrm
->DisableDecryption();
320 String
sUsername( pStrm
->ReadUniString() );
321 if( !pStrm
->IsValid() ) return;
323 if( sUsername
.Len() )
324 pChangeTrack
->SetUser( sUsername
);
326 if( !pStrm
->IsValid() ) return;
329 ReadDateTime( aDateTime
);
330 if( pStrm
->IsValid() )
331 pChangeTrack
->SetFixDateTimeLocal( aDateTime
);
334 void XclImpChangeTrack::ReadChTrCellContent()
336 *pStrm
>> aRecHeader
;
337 if( CheckRecord( EXC_CHTR_OP_CELL
) )
340 SCTAB nTab
= ReadTabNum();
341 aPosition
.SetTab( nTab
);
342 sal_uInt16 nValueType
;
343 *pStrm
>> nValueType
;
344 sal_uInt16 nOldValueType
= (nValueType
>> 3) & EXC_CHTR_TYPE_MASK
;
345 sal_uInt16 nNewValueType
= nValueType
& EXC_CHTR_TYPE_MASK
;
347 Read2DAddress( aPosition
);
350 DBG_ASSERT( (nOldSize
== 0) == (nOldValueType
== EXC_CHTR_TYPE_EMPTY
),
351 "XclImpChangeTrack::ReadChTrCellContent - old value mismatch" );
353 switch( nValueType
& EXC_CHTR_TYPE_FORMATMASK
)
356 case 0x1100: pStrm
->Ignore( 16 ); break;
357 case 0x1300: pStrm
->Ignore( 8 ); break;
358 default: DBG_ERROR( "XclImpChangeTrack::ReadChTrCellContent - unknown format info" );
361 ScBaseCell
* pOldCell
;
362 ScBaseCell
* pNewCell
;
363 sal_uInt32 nOldFormat
;
364 sal_uInt32 nNewFormat
;
365 ReadCell( pOldCell
, nOldFormat
, nOldValueType
, aPosition
);
366 ReadCell( pNewCell
, nNewFormat
, nNewValueType
, aPosition
);
367 if( !pStrm
->IsValid() || (pStrm
->GetRecLeft() > 0) )
369 DBG_ERROR( "XclImpChangeTrack::ReadChTrCellContent - bytes left, action ignored" );
377 ScChangeActionContent
* pNewAction
=
378 pChangeTrack
->AppendContentOnTheFly( aPosition
, pOldCell
, pNewCell
, nOldFormat
, nNewFormat
);
379 DoAcceptRejectAction( pNewAction
);
384 void XclImpChangeTrack::ReadChTrTabId()
386 if( nTabIdCount
== 0 ) // read only 1st time, otherwise calculated by <ReadChTrInsertTab()>
387 nTabIdCount
= static_cast< sal_uInt16
>( pStrm
->GetRecLeft() >> 1 );
390 void XclImpChangeTrack::ReadChTrMoveRange()
392 *pStrm
>> aRecHeader
;
393 if( CheckRecord( EXC_CHTR_OP_MOVE
) )
395 ScRange aSourceRange
;
397 aDestRange
.aStart
.SetTab( ReadTabNum() );
398 aDestRange
.aEnd
.SetTab( aDestRange
.aStart
.Tab() );
399 Read2DRange( aSourceRange
);
400 Read2DRange( aDestRange
);
401 aSourceRange
.aStart
.SetTab( ReadTabNum() );
402 aSourceRange
.aEnd
.SetTab( aSourceRange
.aStart
.Tab() );
404 BOOL bValid
= pStrm
->IsValid();
405 if( FoundNestedMode() )
410 pChangeTrack
->AppendMove( aSourceRange
, aDestRange
, NULL
);
411 DoAcceptRejectAction( pChangeTrack
->GetLast() );
416 void XclImpChangeTrack::ReadChTrInsertTab()
418 *pStrm
>> aRecHeader
;
419 if( CheckRecord( EXC_CHTR_OP_INSTAB
) )
421 SCTAB nTab
= ReadTabNum();
422 if( pStrm
->IsValid() )
425 DoInsertRange( ScRange( 0, 0, nTab
, MAXCOL
, MAXROW
, nTab
) );
430 void XclImpChangeTrack::InitNestedMode()
432 DBG_ASSERT( eNestedMode
== nmBase
, "XclImpChangeTrack::InitNestedMode - unexpected nested mode" );
433 if( eNestedMode
== nmBase
)
434 eNestedMode
= nmFound
;
437 void XclImpChangeTrack::ReadNestedRecords()
439 DBG_ASSERT( eNestedMode
== nmFound
, "XclImpChangeTrack::StartNestedMode - missing nested mode" );
440 if( eNestedMode
== nmFound
)
442 eNestedMode
= nmNested
;
447 sal_Bool
XclImpChangeTrack::EndNestedMode()
449 DBG_ASSERT( eNestedMode
!= nmBase
, "XclImpChangeTrack::EndNestedMode - missing nested mode" );
450 sal_Bool bReturn
= (eNestedMode
== nmNested
);
451 eNestedMode
= nmBase
;
455 void XclImpChangeTrack::ReadRecords()
457 sal_Bool bExitLoop
= sal_False
;
459 while( !bExitLoop
&& !bGlobExit
&& pStrm
->StartNextRecord() )
461 switch( pStrm
->GetRecId() )
463 case 0x000A: bGlobExit
= sal_True
; break;
464 case 0x0137: ReadChTrInsert(); break;
465 case 0x0138: ReadChTrInfo(); break;
466 case 0x013B: ReadChTrCellContent(); break;
467 case 0x013D: ReadChTrTabId(); break;
468 case 0x0140: ReadChTrMoveRange(); break;
469 case 0x014D: ReadChTrInsertTab(); break;
471 case 0x0150: InitNestedMode(); break;
473 case 0x0151: bExitLoop
= EndNestedMode(); break;
478 void XclImpChangeTrack::Apply()
482 pChangeTrack
->SetUser( sOldUsername
);
483 pChangeTrack
->SetUseFixDateTime( FALSE
);
485 GetDoc().SetChangeTrack( pChangeTrack
);
488 ScChangeViewSettings aSettings
;
489 aSettings
.SetShowChanges( TRUE
);
490 GetDoc().SetChangeViewSettings( aSettings
);
494 //___________________________________________________________________
495 // class XclImpChTrFmlConverter
497 XclImpChTrFmlConverter::~XclImpChTrFmlConverter()
501 // virtual, called from ExcToSc8::Convert()
502 bool XclImpChTrFmlConverter::Read3DTabReference( UINT16
/*nIxti*/, SCTAB
& rFirstTab
, SCTAB
& rLastTab
,
503 ExternalTabInfo
& rExtInfo
)
505 return rChangeTrack
.Read3DTabRefInfo( rFirstTab
, rLastTab
, rExtInfo
);