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