dr78: #i96587# oox - import BIFF8 cell notes

This commit is contained in:
Daniel Rentz [dr] 2011-01-06 13:56:27 +01:00
parent 1ed3654a1c
commit b03baea914
8 changed files with 135 additions and 39 deletions

View file

@ -425,6 +425,7 @@ const sal_uInt16 BIFF_ID_MTHREADSETTINGS = 0x089A;
const sal_uInt16 BIFF_ID_MULTBLANK = 0x00BE;
const sal_uInt16 BIFF_ID_MULTRK = 0x00BD;
const sal_uInt16 BIFF_ID_NOTE = 0x001C;
const sal_uInt16 BIFF_ID_NOTESOUND = 0x0096;
const sal_uInt16 BIFF2_ID_NUMBER = 0x0003;
const sal_uInt16 BIFF3_ID_NUMBER = 0x0203;
const sal_uInt16 BIFF_ID_OBJ = 0x005D;

View file

@ -40,8 +40,11 @@ struct CommentModel
{
::com::sun::star::table::CellRangeAddress
maRange; /// Position of the comment in the worksheet.
RichStringRef mxText; /// Formatted text of the comment.
sal_Int32 mnAuthorId; /// Identifier of the comment's author.
RichStringRef mxText; /// Formatted text of the comment (not used in BIFF8).
::rtl::OUString maAuthor; /// Comment author (BIFF8 only).
sal_Int32 mnAuthorId; /// Identifier of the comment's author (OOXML and BIFF12 only).
sal_uInt16 mnObjId; /// Drawing object identifier (BIFF8 only).
bool mbVisible; /// True = comment is always shown (BIFF2-BIFF8 only).
explicit CommentModel();
};
@ -66,6 +69,14 @@ public:
/** Finalizes the formatted string of the comment. */
void finalizeImport();
private:
/** Reads a BIFF2-BIFF5 NOTE record. */
void importNoteBiff2( BiffInputStream& rStrm );
/** Reads a BIFF8 NOTE record. */
void importNoteBiff8( BiffInputStream& rStrm );
/** Reads a NOTESOUND record. */
void importNoteSound( BiffInputStream& rStrm );
private:
CommentModel maModel;
};

View file

@ -39,6 +39,10 @@ namespace com { namespace sun { namespace star {
namespace oox {
namespace xls {
// ============================================================================
const sal_uInt16 BIFF_OBJ_INVALID_ID = 0;
// ============================================================================
// Model structures for BIFF OBJ record data
// ============================================================================

View file

@ -2520,6 +2520,8 @@ void WorkbookStreamObject::implDumpRecordBody()
{
dumpHex< sal_uInt16 >( "flags", "NOTE-FLAGS" );
dumpDec< sal_uInt16 >( "obj-id" );
dumpUniString( "author" );
dumpUnused( 1 );
}
else
{
@ -2529,6 +2531,21 @@ void WorkbookStreamObject::implDumpRecordBody()
}
break;
case BIFF_ID_NOTESOUND:
dumpHex< sal_uInt32 >( "identifier" );
dumpDec< sal_uInt32 >( "total-data-size" );
dumpDec< sal_uInt32 >( "wave-data-size" );
if( dumpDec< sal_uInt32 >( "fmt-size" ) >= 16 )
{
dumpDec< sal_uInt16 >( "format", "NOTESOUND-FORMAT" );
dumpDec< sal_uInt16 >( "channels" );
dumpDec< sal_uInt32 >( "sampling-rate" );
dumpDec< sal_uInt32 >( "data-rate" );
dumpDec< sal_uInt16 >( "data-block-size" );
dumpDec< sal_uInt16 >( "bits-per-sample" );
}
break;
case BIFF2_ID_NUMBER:
case BIFF3_ID_NUMBER:
dumpCellHeader( nRecId == BIFF2_ID_NUMBER );

View file

@ -324,7 +324,7 @@ multilist=RECORD-NAMES-BIFF4
exclude=0x0206,0x0209,0x001E,0x0243
0x0085=SHEET
0x0088=,,,,,,SHEETSOFFSET,SHEETHEADER
0x0090=,,,,,SOUND,SYNC
0x0090=,,,,,,NOTESOUND,SYNC
0x0098=LPR,STANDARDWIDTH,FNGROUPNAME,,FNGROUPCOUNT,,,
0x00A0=SCL,PAGESETUP,FNPROTO,PROJEXTSHEET,,,,
0x00A8=DRAGDROP,COORDLIST,,GCW,,,,
@ -1441,6 +1441,18 @@ shortlist=IMGDATA-ENV,1,windows,apple
flagslist=NOTE-FLAGS-BIFF8
0x0002=visible
0x0080=row-hidden
0x0100=col-hidden
end
# NOTESOUND ------------------------------------------------------------------
constlist=NOTESOUND-FORMAT
1=pcm
3=ieee-float
6=a-law
7=mu-law
0xFFFE=extensible
end
# OBJ ------------------------------------------------------------------------

View file

@ -36,6 +36,7 @@
#include "oox/xls/addressconverter.hxx"
#include "oox/xls/biffinputstream.hxx"
#include "oox/xls/drawingfragment.hxx"
#include "oox/xls/drawingmanager.hxx"
using ::rtl::OUString;
using ::com::sun::star::uno::Reference;
@ -56,8 +57,18 @@ namespace xls {
// ============================================================================
namespace {
const sal_uInt16 BIFF_NOTE_VISIBLE = 0x0002;
} // namespace
// ============================================================================
CommentModel::CommentModel() :
mnAuthorId( -1 )
mnAuthorId( -1 ),
mnObjId( BIFF_OBJ_INVALID_ID ),
mbVisible( false )
{
}
@ -86,33 +97,29 @@ void Comment::importComment( RecordInputStream& rStrm )
void Comment::importNote( BiffInputStream& rStrm )
{
BinAddress aBinAddr;
sal_uInt16 nTotalLen;
rStrm >> aBinAddr >> nTotalLen;
rStrm >> aBinAddr;
// cell range will be checked while inserting the comment into the document
getAddressConverter().convertToCellRangeUnchecked( maModel.maRange, BinRange( aBinAddr ), getSheetIndex() );
RichStringRef xNoteText = createText();
sal_uInt16 nPartLen = ::std::min( nTotalLen, static_cast< sal_uInt16 >( rStrm.getRemaining() ) );
xNoteText->importCharArray( rStrm, nPartLen, getTextEncoding() );
nTotalLen = nTotalLen - nPartLen; // operator-=() gives compiler warning
while( (nTotalLen > 0) && (rStrm.getNextRecId() == BIFF_ID_NOTE) && rStrm.startNextRecord() )
// remaining record data is BIFF dependent
switch( getBiff() )
{
rStrm >> aBinAddr >> nPartLen;
OSL_ENSURE( aBinAddr.mnRow == 0xFFFF, "Comment::importNote - missing continuation NOTE record" );
if( aBinAddr.mnRow == 0xFFFF )
{
OSL_ENSURE( nPartLen <= nTotalLen, "Comment::importNote - string too long" );
// call to RichString::importCharArray() appends new text portion
xNoteText->importCharArray( rStrm, nPartLen, getTextEncoding() );
nTotalLen = nTotalLen - ::std::min( nTotalLen, nPartLen );
}
else
{
// seems to be a new note, rewind record, so worksheet fragment loop will find it
rStrm.rewindRecord();
nTotalLen = 0;
}
case BIFF2:
case BIFF3:
importNoteBiff2( rStrm );
break;
case BIFF4:
case BIFF5:
importNoteBiff2( rStrm );
// in BIFF4 and BIFF5, comments can have an associated sound
if( (rStrm.getNextRecId() == BIFF_ID_NOTESOUND) && rStrm.startNextRecord() )
importNoteSound( rStrm );
break;
case BIFF8:
importNoteBiff8( rStrm );
break;
case BIFF_UNKNOWN:
break;
}
}
@ -135,12 +142,15 @@ void Comment::finalizeImport()
Reference< XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), UNO_SET_THROW );
// non-empty string required by note implementation (real text will be added below)
xAnnos->insertNew( aNotePos, OUString( sal_Unicode( ' ' ) ) );
// receive craeted note from cell (insertNew does not return the note)
// receive created note from cell (insertNew does not return the note)
Reference< XSheetAnnotationAnchor > xAnnoAnchor( getCell( aNotePos ), UNO_QUERY_THROW );
Reference< XSheetAnnotation > xAnno( xAnnoAnchor->getAnnotation(), UNO_SET_THROW );
Reference< XSheetAnnotationShapeSupplier > xAnnoShapeSupp( xAnno, UNO_QUERY_THROW );
Reference< XShape > xAnnoShape( xAnnoShapeSupp->getAnnotationShape(), UNO_SET_THROW );
// convert shape formatting
// convert shape formatting and visibility
sal_Bool bVisible = sal_True;
switch( getFilterType() )
{
case FILTER_OOX:
@ -150,17 +160,17 @@ void Comment::finalizeImport()
pNoteShape->convertFormatting( xAnnoShape );
// visibility
const ::oox::vml::ShapeModel::ShapeClientDataPtr& rxClientData = pNoteShape->getShapeModel().mxClientData;
bool bVisible = rxClientData.get() && rxClientData->mbVisible;
xAnno->setIsVisible( bVisible );
bVisible = rxClientData.get() && rxClientData->mbVisible;
}
break;
case FILTER_BIFF:
// notes are always hidden and unformatted in BIFF3-BIFF5
xAnno->setIsVisible( sal_False );
bVisible = maModel.mbVisible;
break;
case FILTER_UNKNOWN:
break;
}
xAnno->setIsVisible( bVisible );
// insert text and convert text formatting
maModel.mxText->finalizeImport();
Reference< XText > xAnnoText( xAnnoShape, UNO_QUERY_THROW );
@ -171,6 +181,52 @@ void Comment::finalizeImport()
}
}
// private --------------------------------------------------------------------
void Comment::importNoteBiff2( BiffInputStream& rStrm )
{
sal_uInt16 nTotalLen;
rStrm >> nTotalLen;
sal_uInt16 nPartLen = ::std::min( nTotalLen, static_cast< sal_uInt16 >( rStrm.getRemaining() ) );
RichStringRef xNoteText = createText();
xNoteText->importCharArray( rStrm, nPartLen, getTextEncoding() );
nTotalLen = nTotalLen - nPartLen; // operator-=() gives compiler warning
while( (nTotalLen > 0) && (rStrm.getNextRecId() == BIFF_ID_NOTE) && rStrm.startNextRecord() )
{
sal_uInt16 nMarker;
rStrm >> nMarker;
rStrm.skip( 2 );
rStrm >> nPartLen;
OSL_ENSURE( nMarker == 0xFFFF, "Comment::importNoteBiff2 - missing continuation NOTE record" );
if( nMarker == 0xFFFF )
{
OSL_ENSURE( nPartLen <= nTotalLen, "Comment::importNoteBiff2 - string too long" );
// call to RichString::importCharArray() appends new text portion
xNoteText->importCharArray( rStrm, nPartLen, getTextEncoding() );
nTotalLen = nTotalLen - ::std::min( nTotalLen, nPartLen );
}
else
{
// seems to be a new note, rewind record, so worksheet fragment loop will find it
rStrm.rewindRecord();
nTotalLen = 0;
}
}
}
void Comment::importNoteBiff8( BiffInputStream& rStrm )
{
sal_uInt16 nFlags;
rStrm >> nFlags >> maModel.mnObjId;
maModel.maAuthor = rStrm.readUniString();
maModel.mbVisible = getFlag( nFlags, BIFF_NOTE_VISIBLE );
}
void Comment::importNoteSound( BiffInputStream& /*rStrm*/ )
{
}
// ============================================================================
CommentsBuffer::CommentsBuffer( const WorksheetHelper& rHelper ) :

View file

@ -51,8 +51,6 @@ namespace {
// OBJ record -----------------------------------------------------------------
const sal_uInt16 BIFF_OBJ_INVALID_ID = 0;
const sal_uInt16 BIFF_OBJTYPE_GROUP = 0;
const sal_uInt16 BIFF_OBJTYPE_LINE = 1;
const sal_uInt16 BIFF_OBJTYPE_RECTANGLE = 2;

View file

@ -804,6 +804,7 @@ bool BiffWorksheetFragment::importFragment()
case BIFF_ID_HORPAGEBREAKS: importPageBreaks( true ); break;
case BIFF_ID_ITERATION: rWorkbookSett.importIteration( mrStrm ); break;
case BIFF_ID_LEFTMARGIN: rPageSett.importLeftMargin( mrStrm ); break;
case BIFF_ID_NOTE: importNote(); break;
case BIFF_ID_PANE: rSheetViewSett.importPane( mrStrm ); break;
case BIFF_ID_PASSWORD: rWorksheetSett.importPassword( mrStrm ); break;
case BIFF_ID_PRINTGRIDLINES: rPageSett.importPrintGridLines( mrStrm ); break;
@ -823,7 +824,6 @@ bool BiffWorksheetFragment::importFragment()
case BIFF_ID_COLUMNDEFAULT: importColumnDefault(); break;
case BIFF_ID_COLWIDTH: importColWidth(); break;
case BIFF2_ID_DEFROWHEIGHT: importDefRowHeight(); break;
case BIFF_ID_NOTE: importNote(); break;
case BIFF2_ID_WINDOW2: rSheetViewSett.importWindow2( mrStrm ); break;
}
break;
@ -834,7 +834,6 @@ bool BiffWorksheetFragment::importFragment()
case BIFF_ID_DEFCOLWIDTH: importDefColWidth(); break;
case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight(); break;
case BIFF_ID_HCENTER: rPageSett.importHorCenter( mrStrm ); break;
case BIFF_ID_NOTE: importNote(); break;
case BIFF_ID_OBJ: rDrawing.importObj( mrStrm ); break;
case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( mrStrm ); break;
case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( mrStrm ); break;
@ -851,7 +850,6 @@ bool BiffWorksheetFragment::importFragment()
case BIFF_ID_COLINFO: importColInfo(); break;
case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight(); break;
case BIFF_ID_HCENTER: rPageSett.importHorCenter( mrStrm ); break;
case BIFF_ID_NOTE: importNote(); break;
case BIFF_ID_OBJ: rDrawing.importObj( mrStrm ); break;
case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( mrStrm ); break;
case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( mrStrm ); break;
@ -870,7 +868,6 @@ bool BiffWorksheetFragment::importFragment()
case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight(); break;
case BIFF_ID_HCENTER: rPageSett.importHorCenter( mrStrm ); break;
case BIFF_ID_MERGEDCELLS: importMergedCells(); break; // #i62300# also in BIFF5
case BIFF_ID_NOTE: importNote(); break;
case BIFF_ID_OBJ: rDrawing.importObj( mrStrm ); break;
case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( mrStrm ); break;
case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( mrStrm ); break;