xref: /AOO41X/main/oox/source/xls/commentsbuffer.cxx (revision 0dac23a028e94a6fba9a1aae98418dd869e3a496)
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