merged tag ooo/OOO330_m14
[LibreOffice.git] / sc / source / filter / xcl97 / XclImpChangeTrack.cxx
blob96a301e1bef545b22a5764f545c8ac6550377e05
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
31 #include "XclImpChangeTrack.hxx"
32 #include <tools/debug.hxx>
33 #include <sot/storage.hxx>
34 #include <svl/zforlist.hxx>
35 #include "chgviset.hxx"
36 #include "cell.hxx"
37 #include "chgtrack.hxx"
38 #include "xihelper.hxx"
39 #include "xilink.hxx"
40 #include "externalrefmgr.hxx"
42 //___________________________________________________________________
43 // class XclImpChangeTrack
45 XclImpChangeTrack::XclImpChangeTrack( const XclImpRoot& rRoot, const XclImpStream& rBookStrm ) :
46 XclImpRoot( rRoot ),
47 aRecHeader(),
48 sOldUsername(),
49 pChangeTrack( NULL ),
50 pStrm( NULL ),
51 nTabIdCount( 0 ),
52 bGlobExit( sal_False ),
53 eNestedMode( nmBase )
55 // Verify that the User Names stream exists before going any further. Excel adds both
56 // "Revision Log" and "User Names" streams when Change Tracking is active but the Revision log
57 // remains if Change Tracking is turned off.
58 SotStorageStreamRef xUserStrm = OpenStream( EXC_STREAM_USERNAMES );
59 if( !xUserStrm.Is() )
60 return;
62 xInStrm = OpenStream( EXC_STREAM_REVLOG );
63 if( xInStrm.Is() )
65 xInStrm->Seek( STREAM_SEEK_TO_END );
66 ULONG nStreamLen = xInStrm->Tell();
67 if( (xInStrm->GetErrorCode() == ERRCODE_NONE) && (nStreamLen != STREAM_SEEK_TO_END) )
69 xInStrm->Seek( STREAM_SEEK_TO_BEGIN );
70 pStrm = new XclImpStream( *xInStrm, GetRoot() );
71 pStrm->CopyDecrypterFrom( rBookStrm );
72 pChangeTrack = new ScChangeTrack( GetDocPtr() );
74 sOldUsername = pChangeTrack->GetUser();
75 pChangeTrack->SetUseFixDateTime( TRUE );
77 ReadRecords();
82 XclImpChangeTrack::~XclImpChangeTrack()
84 delete pChangeTrack;
85 delete pStrm;
88 void XclImpChangeTrack::DoAcceptRejectAction( ScChangeAction* pAction )
90 if( !pAction ) return;
91 switch( aRecHeader.nAccept )
93 case EXC_CHTR_ACCEPT:
94 pChangeTrack->Accept( pAction );
95 break;
96 case EXC_CHTR_REJECT:
97 break;
101 void XclImpChangeTrack::DoAcceptRejectAction( sal_uInt32 nFirst, sal_uInt32 nLast )
103 for( sal_uInt32 nIndex = nFirst; nIndex <= nLast; nIndex++ )
104 DoAcceptRejectAction( pChangeTrack->GetAction( nIndex ) );
107 void XclImpChangeTrack::DoInsertRange( const ScRange& rRange )
109 sal_uInt32 nFirst = pChangeTrack->GetActionMax() + 1;
110 pChangeTrack->AppendInsert( rRange );
111 sal_uInt32 nLast = pChangeTrack->GetActionMax();
112 DoAcceptRejectAction( nFirst, nLast );
115 void XclImpChangeTrack::DoDeleteRange( const ScRange& rRange )
117 ULONG nFirst, nLast;
118 pChangeTrack->AppendDeleteRange( rRange, NULL, nFirst, nLast );
119 DoAcceptRejectAction( nFirst, nLast );
122 SCTAB XclImpChangeTrack::ReadTabNum()
124 return static_cast<SCTAB>(GetTabInfo().GetCurrentIndex(
125 pStrm->ReaduInt16(), nTabIdCount ));
128 void XclImpChangeTrack::ReadDateTime( DateTime& rDateTime )
130 sal_uInt16 nYear;
131 sal_uInt8 nMonth, nDay, nHour, nMin, nSec;
133 *pStrm >> nYear >> nMonth >> nDay >> nHour >> nMin >> nSec;
135 rDateTime.SetYear( nYear );
136 rDateTime.SetMonth( nMonth );
137 rDateTime.SetDay( nDay );
138 rDateTime.SetHour( nHour );
139 rDateTime.SetMin( nMin );
140 rDateTime.SetSec( nSec );
141 rDateTime.Set100Sec( 0 );
144 sal_Bool XclImpChangeTrack::CheckRecord( sal_uInt16 nOpCode )
146 if( (nOpCode != EXC_CHTR_OP_UNKNOWN) && (aRecHeader.nOpCode != nOpCode) )
148 DBG_ERROR( "XclImpChangeTrack::CheckRecord - unknown action" );
149 return sal_False;
151 return aRecHeader.nIndex != 0;
154 sal_Bool XclImpChangeTrack::Read3DTabRefInfo( SCTAB& rFirstTab, SCTAB& rLastTab, ExcelToSc8::ExternalTabInfo& rExtInfo )
156 if( LookAtuInt8() == 0x01 )
158 rExtInfo.mbExternal = false;
159 // internal ref - read tab num and return sc tab num (position in TABID list)
160 pStrm->Ignore( 3 );
161 rFirstTab = static_cast< SCTAB >( GetTabInfo().GetCurrentIndex( pStrm->ReaduInt16(), nTabIdCount ) );
162 sal_uInt8 nFillByte = pStrm->ReaduInt8();
163 rLastTab = (nFillByte == 0x00) ?
164 static_cast< SCTAB >( GetTabInfo().GetCurrentIndex( pStrm->ReaduInt16(), nTabIdCount ) ) : rFirstTab;
166 else
168 // external ref - read doc and tab name and find sc tab num
169 // - URL
170 String aEncUrl( pStrm->ReadUniString() );
171 String aUrl;
172 bool bSelf;
173 XclImpUrlHelper::DecodeUrl( aUrl, bSelf, GetRoot(), aEncUrl );
174 pStrm->Ignore( 1 );
175 // - sheet name, always separated from URL
176 String aTabName( pStrm->ReadUniString() );
177 pStrm->Ignore( 1 );
179 rExtInfo.mbExternal = true;
180 ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
181 pRefMgr->convertToAbsName(aUrl);
182 rExtInfo.mnFileId = pRefMgr->getExternalFileId(aUrl);
183 rExtInfo.maTabName = aTabName;
184 rFirstTab = rLastTab = 0;
186 return sal_True;
189 void XclImpChangeTrack::ReadFormula( ScTokenArray*& rpTokenArray, const ScAddress& rPosition )
191 sal_uInt16 nFmlSize;
192 *pStrm >> nFmlSize;
194 // create a memory stream and copy the formula to be able to read simultaneously
195 // the formula and the additional 3D tab ref data following the formula
196 // here we have to simulate an Excel record to be able to use an XclImpStream...
197 // 2do: remove the stream member from formula converter and add it as a parameter
198 // to the Convert() routine (to prevent the construction/destruction of the
199 // converter in each formula)
200 SvMemoryStream aMemStrm;
201 aMemStrm << (sal_uInt16) 0x0001 << nFmlSize;
202 pStrm->CopyToStream( aMemStrm, nFmlSize );
203 XclImpStream aFmlaStrm( aMemStrm, GetRoot() );
204 aFmlaStrm.StartNextRecord();
205 XclImpChTrFmlConverter aFmlConv( GetRoot(), *this );
207 // read the formula, 3D tab refs from extended data
208 const ScTokenArray* pArray = NULL;
209 aFmlConv.Reset( rPosition );
210 BOOL bOK = (aFmlConv.Convert( pArray, aFmlaStrm, nFmlSize, false, FT_CellFormula) == ConvOK); // JEG : Check This
211 rpTokenArray = (bOK && pArray) ? new ScTokenArray( *pArray ) : NULL;
212 pStrm->Ignore( 1 );
215 void XclImpChangeTrack::ReadCell(
216 ScBaseCell*& rpCell,
217 sal_uInt32& rFormat,
218 sal_uInt16 nFlags,
219 const ScAddress& rPosition )
221 rpCell = NULL;
222 rFormat = 0;
223 switch( nFlags & EXC_CHTR_TYPE_MASK )
225 case EXC_CHTR_TYPE_EMPTY:
226 break;
227 case EXC_CHTR_TYPE_RK:
229 double fValue = ReadRK();
230 if( pStrm->IsValid() )
231 rpCell = new ScValueCell( fValue );
233 break;
234 case EXC_CHTR_TYPE_DOUBLE:
236 double fValue;
237 *pStrm >> fValue;
238 if( pStrm->IsValid() )
239 rpCell = new ScValueCell( fValue );
241 break;
242 case EXC_CHTR_TYPE_STRING:
244 String sString( pStrm->ReadUniString() );
245 if( pStrm->IsValid() )
246 rpCell = new ScStringCell( sString );
248 break;
249 case EXC_CHTR_TYPE_BOOL:
251 double fValue = (double) ReadBool();
252 if( pStrm->IsValid() )
254 rpCell = new ScValueCell( fValue );
255 rFormat = GetFormatter().GetStandardFormat( NUMBERFORMAT_LOGICAL, ScGlobal::eLnge );
258 break;
259 case EXC_CHTR_TYPE_FORMULA:
261 ScTokenArray* pTokenArray = NULL;
262 ReadFormula( pTokenArray, rPosition );
263 if( pStrm->IsValid() && pTokenArray )
264 rpCell = new ScFormulaCell( GetDocPtr(), rPosition, pTokenArray );
266 break;
267 default:
268 DBG_ERROR( "XclImpChangeTrack::ReadCell - unknown data type" );
272 void XclImpChangeTrack::ReadChTrInsert()
274 *pStrm >> aRecHeader;
275 if( CheckRecord( EXC_CHTR_OP_UNKNOWN ) )
277 if( (aRecHeader.nOpCode != EXC_CHTR_OP_INSROW) &&
278 (aRecHeader.nOpCode != EXC_CHTR_OP_INSCOL) &&
279 (aRecHeader.nOpCode != EXC_CHTR_OP_DELROW) &&
280 (aRecHeader.nOpCode != EXC_CHTR_OP_DELCOL) )
282 DBG_ERROR( "XclImpChangeTrack::ReadChTrInsert - unknown action" );
283 return;
286 ScRange aRange;
287 aRange.aStart.SetTab( ReadTabNum() );
288 aRange.aEnd.SetTab( aRange.aStart.Tab() );
289 pStrm->Ignore( 2 );
290 Read2DRange( aRange );
292 if( aRecHeader.nOpCode & EXC_CHTR_OP_COLFLAG )
293 aRange.aEnd.SetRow( MAXROW );
294 else
295 aRange.aEnd.SetCol( MAXCOL );
297 BOOL bValid = pStrm->IsValid();
298 if( FoundNestedMode() )
299 ReadNestedRecords();
301 if( bValid )
303 if( aRecHeader.nOpCode & EXC_CHTR_OP_DELFLAG )
304 DoDeleteRange( aRange );
305 else
306 DoInsertRange( aRange );
311 void XclImpChangeTrack::ReadChTrInfo()
313 pStrm->DisableDecryption();
314 pStrm->Ignore( 32 );
315 String sUsername( pStrm->ReadUniString() );
316 if( !pStrm->IsValid() ) return;
318 if( sUsername.Len() )
319 pChangeTrack->SetUser( sUsername );
320 pStrm->Seek( 148 );
321 if( !pStrm->IsValid() ) return;
323 DateTime aDateTime;
324 ReadDateTime( aDateTime );
325 if( pStrm->IsValid() )
326 pChangeTrack->SetFixDateTimeLocal( aDateTime );
329 void XclImpChangeTrack::ReadChTrCellContent()
331 *pStrm >> aRecHeader;
332 if( CheckRecord( EXC_CHTR_OP_CELL ) )
334 ScAddress aPosition;
335 SCTAB nTab = ReadTabNum();
336 aPosition.SetTab( nTab );
337 sal_uInt16 nValueType;
338 *pStrm >> nValueType;
339 sal_uInt16 nOldValueType = (nValueType >> 3) & EXC_CHTR_TYPE_MASK;
340 sal_uInt16 nNewValueType = nValueType & EXC_CHTR_TYPE_MASK;
341 pStrm->Ignore( 2 );
342 Read2DAddress( aPosition );
343 sal_uInt16 nOldSize;
344 *pStrm >> nOldSize;
345 DBG_ASSERT( (nOldSize == 0) == (nOldValueType == EXC_CHTR_TYPE_EMPTY),
346 "XclImpChangeTrack::ReadChTrCellContent - old value mismatch" );
347 pStrm->Ignore( 4 );
348 switch( nValueType & EXC_CHTR_TYPE_FORMATMASK )
350 case 0x0000: break;
351 case 0x1100: pStrm->Ignore( 16 ); break;
352 case 0x1300: pStrm->Ignore( 8 ); break;
353 default: DBG_ERROR( "XclImpChangeTrack::ReadChTrCellContent - unknown format info" );
356 ScBaseCell* pOldCell;
357 ScBaseCell* pNewCell;
358 sal_uInt32 nOldFormat;
359 sal_uInt32 nNewFormat;
360 ReadCell( pOldCell, nOldFormat, nOldValueType, aPosition );
361 ReadCell( pNewCell, nNewFormat, nNewValueType, aPosition );
362 if( !pStrm->IsValid() || (pStrm->GetRecLeft() > 0) )
364 DBG_ERROR( "XclImpChangeTrack::ReadChTrCellContent - bytes left, action ignored" );
365 if( pOldCell )
366 pOldCell->Delete();
367 if( pNewCell )
368 pNewCell->Delete();
370 else
372 ScChangeActionContent* pNewAction =
373 pChangeTrack->AppendContentOnTheFly( aPosition, pOldCell, pNewCell, nOldFormat, nNewFormat );
374 DoAcceptRejectAction( pNewAction );
379 void XclImpChangeTrack::ReadChTrTabId()
381 if( nTabIdCount == 0 ) // read only 1st time, otherwise calculated by <ReadChTrInsertTab()>
382 nTabIdCount = static_cast< sal_uInt16 >( pStrm->GetRecLeft() >> 1 );
385 void XclImpChangeTrack::ReadChTrMoveRange()
387 *pStrm >> aRecHeader;
388 if( CheckRecord( EXC_CHTR_OP_MOVE ) )
390 ScRange aSourceRange;
391 ScRange aDestRange;
392 aDestRange.aStart.SetTab( ReadTabNum() );
393 aDestRange.aEnd.SetTab( aDestRange.aStart.Tab() );
394 Read2DRange( aSourceRange );
395 Read2DRange( aDestRange );
396 aSourceRange.aStart.SetTab( ReadTabNum() );
397 aSourceRange.aEnd.SetTab( aSourceRange.aStart.Tab() );
399 BOOL bValid = pStrm->IsValid();
400 if( FoundNestedMode() )
401 ReadNestedRecords();
403 if( bValid )
405 pChangeTrack->AppendMove( aSourceRange, aDestRange, NULL );
406 DoAcceptRejectAction( pChangeTrack->GetLast() );
411 void XclImpChangeTrack::ReadChTrInsertTab()
413 *pStrm >> aRecHeader;
414 if( CheckRecord( EXC_CHTR_OP_INSTAB ) )
416 SCTAB nTab = ReadTabNum();
417 if( pStrm->IsValid() )
419 nTabIdCount++;
420 DoInsertRange( ScRange( 0, 0, nTab, MAXCOL, MAXROW, nTab ) );
425 void XclImpChangeTrack::InitNestedMode()
427 DBG_ASSERT( eNestedMode == nmBase, "XclImpChangeTrack::InitNestedMode - unexpected nested mode" );
428 if( eNestedMode == nmBase )
429 eNestedMode = nmFound;
432 void XclImpChangeTrack::ReadNestedRecords()
434 DBG_ASSERT( eNestedMode == nmFound, "XclImpChangeTrack::StartNestedMode - missing nested mode" );
435 if( eNestedMode == nmFound )
437 eNestedMode = nmNested;
438 ReadRecords();
442 sal_Bool XclImpChangeTrack::EndNestedMode()
444 DBG_ASSERT( eNestedMode != nmBase, "XclImpChangeTrack::EndNestedMode - missing nested mode" );
445 sal_Bool bReturn = (eNestedMode == nmNested);
446 eNestedMode = nmBase;
447 return bReturn;
450 void XclImpChangeTrack::ReadRecords()
452 sal_Bool bExitLoop = sal_False;
454 while( !bExitLoop && !bGlobExit && pStrm->StartNextRecord() )
456 switch( pStrm->GetRecId() )
458 case 0x000A: bGlobExit = sal_True; break;
459 case 0x0137: ReadChTrInsert(); break;
460 case 0x0138: ReadChTrInfo(); break;
461 case 0x013B: ReadChTrCellContent(); break;
462 case 0x013D: ReadChTrTabId(); break;
463 case 0x0140: ReadChTrMoveRange(); break;
464 case 0x014D: ReadChTrInsertTab(); break;
465 case 0x014E:
466 case 0x0150: InitNestedMode(); break;
467 case 0x014F:
468 case 0x0151: bExitLoop = EndNestedMode(); break;
473 void XclImpChangeTrack::Apply()
475 if( pChangeTrack )
477 pChangeTrack->SetUser( sOldUsername );
478 pChangeTrack->SetUseFixDateTime( FALSE );
480 GetDoc().SetChangeTrack( pChangeTrack );
481 pChangeTrack = NULL;
483 ScChangeViewSettings aSettings;
484 aSettings.SetShowChanges( TRUE );
485 GetDoc().SetChangeViewSettings( aSettings );
489 //___________________________________________________________________
490 // class XclImpChTrFmlConverter
492 XclImpChTrFmlConverter::~XclImpChTrFmlConverter()
496 // virtual, called from ExcToSc8::Convert()
497 bool XclImpChTrFmlConverter::Read3DTabReference( UINT16 /*nIxti*/, SCTAB& rFirstTab, SCTAB& rLastTab,
498 ExternalTabInfo& rExtInfo )
500 return rChangeTrack.Read3DTabRefInfo( rFirstTab, rLastTab, rExtInfo );