1cdf0e10cSrcweir /************************************************************************* 2cdf0e10cSrcweir * 3cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4cdf0e10cSrcweir * 5cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6cdf0e10cSrcweir * 7cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8cdf0e10cSrcweir * 9cdf0e10cSrcweir * This file is part of OpenOffice.org. 10cdf0e10cSrcweir * 11cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14cdf0e10cSrcweir * 15cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20cdf0e10cSrcweir * 21cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25cdf0e10cSrcweir * 26cdf0e10cSrcweir ************************************************************************/ 27cdf0e10cSrcweir 28cdf0e10cSrcweir #include "oox/xls/commentsbuffer.hxx" 29cdf0e10cSrcweir 30cdf0e10cSrcweir #include <com/sun/star/sheet/XSheetAnnotationAnchor.hpp> 31cdf0e10cSrcweir #include <com/sun/star/sheet/XSheetAnnotationShapeSupplier.hpp> 32cdf0e10cSrcweir #include <com/sun/star/sheet/XSheetAnnotations.hpp> 33cdf0e10cSrcweir #include <com/sun/star/sheet/XSheetAnnotationsSupplier.hpp> 34cdf0e10cSrcweir #include "oox/helper/attributelist.hxx" 35cdf0e10cSrcweir #include "oox/vml/vmlshape.hxx" 36cdf0e10cSrcweir #include "oox/xls/addressconverter.hxx" 37cdf0e10cSrcweir #include "oox/xls/biffinputstream.hxx" 38cdf0e10cSrcweir #include "oox/xls/drawingfragment.hxx" 39cdf0e10cSrcweir #include "oox/xls/drawingmanager.hxx" 40cdf0e10cSrcweir 41cdf0e10cSrcweir namespace oox { 42cdf0e10cSrcweir namespace xls { 43cdf0e10cSrcweir 44cdf0e10cSrcweir // ============================================================================ 45cdf0e10cSrcweir 46cdf0e10cSrcweir using namespace ::com::sun::star::drawing; 47cdf0e10cSrcweir using namespace ::com::sun::star::sheet; 48cdf0e10cSrcweir using namespace ::com::sun::star::table; 49cdf0e10cSrcweir using namespace ::com::sun::star::text; 50cdf0e10cSrcweir using namespace ::com::sun::star::uno; 51cdf0e10cSrcweir 52cdf0e10cSrcweir using ::rtl::OUString; 53cdf0e10cSrcweir 54cdf0e10cSrcweir // ============================================================================ 55cdf0e10cSrcweir 56cdf0e10cSrcweir namespace { 57cdf0e10cSrcweir 58cdf0e10cSrcweir const sal_uInt16 BIFF_NOTE_VISIBLE = 0x0002; 59cdf0e10cSrcweir 60cdf0e10cSrcweir } // namespace 61cdf0e10cSrcweir 62cdf0e10cSrcweir // ============================================================================ 63cdf0e10cSrcweir 64cdf0e10cSrcweir CommentModel::CommentModel() : 65cdf0e10cSrcweir mnAuthorId( -1 ), 66cdf0e10cSrcweir mnObjId( BIFF_OBJ_INVALID_ID ), 67cdf0e10cSrcweir mbVisible( false ) 68cdf0e10cSrcweir { 69cdf0e10cSrcweir } 70cdf0e10cSrcweir 71cdf0e10cSrcweir // ---------------------------------------------------------------------------- 72cdf0e10cSrcweir 73cdf0e10cSrcweir Comment::Comment( const WorksheetHelper& rHelper ) : 74cdf0e10cSrcweir WorksheetHelper( rHelper ) 75cdf0e10cSrcweir { 76cdf0e10cSrcweir } 77cdf0e10cSrcweir 78cdf0e10cSrcweir void Comment::importComment( const AttributeList& rAttribs ) 79cdf0e10cSrcweir { 80cdf0e10cSrcweir maModel.mnAuthorId = rAttribs.getInteger( XML_authorId, -1 ); 81cdf0e10cSrcweir // cell range will be checked while inserting the comment into the document 82cdf0e10cSrcweir getAddressConverter().convertToCellRangeUnchecked( maModel.maRange, rAttribs.getString( XML_ref, OUString() ), getSheetIndex() ); 83cdf0e10cSrcweir } 84cdf0e10cSrcweir 85cdf0e10cSrcweir void Comment::importComment( SequenceInputStream& rStrm ) 86cdf0e10cSrcweir { 87cdf0e10cSrcweir BinRange aBinRange; 88cdf0e10cSrcweir rStrm >> maModel.mnAuthorId >> aBinRange; 89cdf0e10cSrcweir // cell range will be checked while inserting the comment into the document 90cdf0e10cSrcweir getAddressConverter().convertToCellRangeUnchecked( maModel.maRange, aBinRange, getSheetIndex() ); 91cdf0e10cSrcweir } 92cdf0e10cSrcweir 93cdf0e10cSrcweir void Comment::importNote( BiffInputStream& rStrm ) 94cdf0e10cSrcweir { 95cdf0e10cSrcweir BinAddress aBinAddr; 96cdf0e10cSrcweir rStrm >> aBinAddr; 97cdf0e10cSrcweir // cell range will be checked while inserting the comment into the document 98cdf0e10cSrcweir getAddressConverter().convertToCellRangeUnchecked( maModel.maRange, BinRange( aBinAddr ), getSheetIndex() ); 99cdf0e10cSrcweir 100cdf0e10cSrcweir // remaining record data is BIFF dependent 101cdf0e10cSrcweir switch( getBiff() ) 102cdf0e10cSrcweir { 103cdf0e10cSrcweir case BIFF2: 104cdf0e10cSrcweir case BIFF3: 105cdf0e10cSrcweir importNoteBiff2( rStrm ); 106cdf0e10cSrcweir break; 107cdf0e10cSrcweir case BIFF4: 108cdf0e10cSrcweir case BIFF5: 109cdf0e10cSrcweir importNoteBiff2( rStrm ); 110cdf0e10cSrcweir // in BIFF4 and BIFF5, comments can have an associated sound 111cdf0e10cSrcweir if( (rStrm.getNextRecId() == BIFF_ID_NOTESOUND) && rStrm.startNextRecord() ) 112cdf0e10cSrcweir importNoteSound( rStrm ); 113cdf0e10cSrcweir break; 114cdf0e10cSrcweir case BIFF8: 115cdf0e10cSrcweir importNoteBiff8( rStrm ); 116cdf0e10cSrcweir break; 117cdf0e10cSrcweir case BIFF_UNKNOWN: 118cdf0e10cSrcweir break; 119cdf0e10cSrcweir } 120cdf0e10cSrcweir } 121cdf0e10cSrcweir 122cdf0e10cSrcweir RichStringRef Comment::createText() 123cdf0e10cSrcweir { 124cdf0e10cSrcweir maModel.mxText.reset( new RichString( *this ) ); 125cdf0e10cSrcweir return maModel.mxText; 126cdf0e10cSrcweir } 127cdf0e10cSrcweir 128cdf0e10cSrcweir void Comment::finalizeImport() 129cdf0e10cSrcweir { 130cdf0e10cSrcweir // BIFF12 stores cell range instead of cell address, use first cell of this range 131cdf0e10cSrcweir OSL_ENSURE( (maModel.maRange.StartColumn == maModel.maRange.EndColumn) && 132cdf0e10cSrcweir (maModel.maRange.StartRow == maModel.maRange.EndRow), 133cdf0e10cSrcweir "Comment::finalizeImport - comment anchor should be a single cell" ); 134cdf0e10cSrcweir CellAddress aNotePos( maModel.maRange.Sheet, maModel.maRange.StartColumn, maModel.maRange.StartRow ); 135cdf0e10cSrcweir if( getAddressConverter().checkCellAddress( aNotePos, true ) && maModel.mxText.get() ) try 136cdf0e10cSrcweir { 137cdf0e10cSrcweir Reference< XSheetAnnotationsSupplier > xAnnosSupp( getSheet(), UNO_QUERY_THROW ); 138cdf0e10cSrcweir Reference< XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), UNO_SET_THROW ); 139cdf0e10cSrcweir // non-empty string required by note implementation (real text will be added below) 140cdf0e10cSrcweir xAnnos->insertNew( aNotePos, OUString( sal_Unicode( ' ' ) ) ); 141cdf0e10cSrcweir 142cdf0e10cSrcweir // receive created note from cell (insertNew does not return the note) 143cdf0e10cSrcweir Reference< XSheetAnnotationAnchor > xAnnoAnchor( getCell( aNotePos ), UNO_QUERY_THROW ); 144cdf0e10cSrcweir Reference< XSheetAnnotation > xAnno( xAnnoAnchor->getAnnotation(), UNO_SET_THROW ); 145cdf0e10cSrcweir Reference< XSheetAnnotationShapeSupplier > xAnnoShapeSupp( xAnno, UNO_QUERY_THROW ); 146cdf0e10cSrcweir Reference< XShape > xAnnoShape( xAnnoShapeSupp->getAnnotationShape(), UNO_SET_THROW ); 147cdf0e10cSrcweir 148cdf0e10cSrcweir // convert shape formatting and visibility 149cdf0e10cSrcweir sal_Bool bVisible = sal_True; 150cdf0e10cSrcweir switch( getFilterType() ) 151cdf0e10cSrcweir { 152cdf0e10cSrcweir case FILTER_OOXML: 153cdf0e10cSrcweir if( const ::oox::vml::ShapeBase* pNoteShape = getVmlDrawing().getNoteShape( aNotePos ) ) 154cdf0e10cSrcweir { 155cdf0e10cSrcweir // position and formatting 156cdf0e10cSrcweir pNoteShape->convertFormatting( xAnnoShape ); 157cdf0e10cSrcweir // visibility 158cdf0e10cSrcweir const ::oox::vml::ClientData* pClientData = pNoteShape->getClientData(); 159cdf0e10cSrcweir bVisible = pClientData && pClientData->mbVisible; 160cdf0e10cSrcweir } 161cdf0e10cSrcweir break; 162cdf0e10cSrcweir case FILTER_BIFF: 163cdf0e10cSrcweir bVisible = maModel.mbVisible; 164cdf0e10cSrcweir break; 165cdf0e10cSrcweir case FILTER_UNKNOWN: 166cdf0e10cSrcweir break; 167cdf0e10cSrcweir } 168cdf0e10cSrcweir xAnno->setIsVisible( bVisible ); 169cdf0e10cSrcweir 170cdf0e10cSrcweir // insert text and convert text formatting 171cdf0e10cSrcweir maModel.mxText->finalizeImport(); 172cdf0e10cSrcweir Reference< XText > xAnnoText( xAnnoShape, UNO_QUERY_THROW ); 173*0dac23a0SMichael Stahl maModel.mxText->convert( xAnnoText, true ); 174cdf0e10cSrcweir } 175cdf0e10cSrcweir catch( Exception& ) 176cdf0e10cSrcweir { 177cdf0e10cSrcweir } 178cdf0e10cSrcweir } 179cdf0e10cSrcweir 180cdf0e10cSrcweir // private -------------------------------------------------------------------- 181cdf0e10cSrcweir 182cdf0e10cSrcweir void Comment::importNoteBiff2( BiffInputStream& rStrm ) 183cdf0e10cSrcweir { 184cdf0e10cSrcweir sal_uInt16 nTotalLen; 185cdf0e10cSrcweir rStrm >> nTotalLen; 186cdf0e10cSrcweir sal_uInt16 nPartLen = ::std::min( nTotalLen, static_cast< sal_uInt16 >( rStrm.getRemaining() ) ); 187cdf0e10cSrcweir RichStringRef xNoteText = createText(); 188cdf0e10cSrcweir xNoteText->importCharArray( rStrm, nPartLen, getTextEncoding() ); 189cdf0e10cSrcweir 190cdf0e10cSrcweir nTotalLen = nTotalLen - nPartLen; // operator-=() gives compiler warning 191cdf0e10cSrcweir while( (nTotalLen > 0) && (rStrm.getNextRecId() == BIFF_ID_NOTE) && rStrm.startNextRecord() ) 192cdf0e10cSrcweir { 193cdf0e10cSrcweir sal_uInt16 nMarker; 194cdf0e10cSrcweir rStrm >> nMarker; 195cdf0e10cSrcweir rStrm.skip( 2 ); 196cdf0e10cSrcweir rStrm >> nPartLen; 197cdf0e10cSrcweir OSL_ENSURE( nMarker == 0xFFFF, "Comment::importNoteBiff2 - missing continuation NOTE record" ); 198cdf0e10cSrcweir if( nMarker == 0xFFFF ) 199cdf0e10cSrcweir { 200cdf0e10cSrcweir OSL_ENSURE( nPartLen <= nTotalLen, "Comment::importNoteBiff2 - string too long" ); 201cdf0e10cSrcweir // call to RichString::importCharArray() appends new text portion 202cdf0e10cSrcweir xNoteText->importCharArray( rStrm, nPartLen, getTextEncoding() ); 203cdf0e10cSrcweir nTotalLen = nTotalLen - ::std::min( nTotalLen, nPartLen ); 204cdf0e10cSrcweir } 205cdf0e10cSrcweir else 206cdf0e10cSrcweir { 207cdf0e10cSrcweir // seems to be a new note, rewind record, so worksheet fragment loop will find it 208cdf0e10cSrcweir rStrm.rewindRecord(); 209cdf0e10cSrcweir nTotalLen = 0; 210cdf0e10cSrcweir } 211cdf0e10cSrcweir } 212cdf0e10cSrcweir } 213cdf0e10cSrcweir 214cdf0e10cSrcweir void Comment::importNoteBiff8( BiffInputStream& rStrm ) 215cdf0e10cSrcweir { 216cdf0e10cSrcweir sal_uInt16 nFlags; 217cdf0e10cSrcweir rStrm >> nFlags >> maModel.mnObjId; 218cdf0e10cSrcweir maModel.maAuthor = rStrm.readUniString(); 219cdf0e10cSrcweir maModel.mbVisible = getFlag( nFlags, BIFF_NOTE_VISIBLE ); 220cdf0e10cSrcweir } 221cdf0e10cSrcweir 222cdf0e10cSrcweir void Comment::importNoteSound( BiffInputStream& /*rStrm*/ ) 223cdf0e10cSrcweir { 224cdf0e10cSrcweir } 225cdf0e10cSrcweir 226cdf0e10cSrcweir // ============================================================================ 227cdf0e10cSrcweir 228cdf0e10cSrcweir CommentsBuffer::CommentsBuffer( const WorksheetHelper& rHelper ) : 229cdf0e10cSrcweir WorksheetHelper( rHelper ) 230cdf0e10cSrcweir { 231cdf0e10cSrcweir } 232cdf0e10cSrcweir 233cdf0e10cSrcweir void CommentsBuffer::appendAuthor( const OUString& rAuthor ) 234cdf0e10cSrcweir { 235cdf0e10cSrcweir maAuthors.push_back( rAuthor ); 236cdf0e10cSrcweir } 237cdf0e10cSrcweir 238cdf0e10cSrcweir CommentRef CommentsBuffer::createComment() 239cdf0e10cSrcweir { 240cdf0e10cSrcweir CommentRef xComment( new Comment( *this ) ); 241cdf0e10cSrcweir maComments.push_back( xComment ); 242cdf0e10cSrcweir return xComment; 243cdf0e10cSrcweir } 244cdf0e10cSrcweir 245cdf0e10cSrcweir void CommentsBuffer::finalizeImport() 246cdf0e10cSrcweir { 247cdf0e10cSrcweir maComments.forEachMem( &Comment::finalizeImport ); 248cdf0e10cSrcweir } 249cdf0e10cSrcweir 250cdf0e10cSrcweir // ============================================================================ 251cdf0e10cSrcweir 252cdf0e10cSrcweir } // namespace xls 253cdf0e10cSrcweir } // namespace oox 254