xref: /aoo41x/main/oox/source/xls/commentsbuffer.cxx (revision ca5ec200)
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
10*ca5ec200SAndrew Rist  *
11*ca5ec200SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*ca5ec200SAndrew Rist  *
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.
19*ca5ec200SAndrew Rist  *
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 
CommentModel()60cdf0e10cSrcweir CommentModel::CommentModel() :
61cdf0e10cSrcweir     mnAuthorId( -1 ),
62cdf0e10cSrcweir     mnObjId( BIFF_OBJ_INVALID_ID ),
63cdf0e10cSrcweir     mbVisible( false )
64cdf0e10cSrcweir {
65cdf0e10cSrcweir }
66cdf0e10cSrcweir 
67cdf0e10cSrcweir // ----------------------------------------------------------------------------
68cdf0e10cSrcweir 
Comment(const WorksheetHelper & rHelper)69cdf0e10cSrcweir Comment::Comment( const WorksheetHelper& rHelper ) :
70cdf0e10cSrcweir     WorksheetHelper( rHelper )
71cdf0e10cSrcweir {
72cdf0e10cSrcweir }
73cdf0e10cSrcweir 
importComment(const AttributeList & rAttribs)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 
importComment(SequenceInputStream & rStrm)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 
importNote(BiffInputStream & rStrm)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 
createText()118cdf0e10cSrcweir RichStringRef Comment::createText()
119cdf0e10cSrcweir {
120cdf0e10cSrcweir     maModel.mxText.reset( new RichString( *this ) );
121cdf0e10cSrcweir     return maModel.mxText;
122cdf0e10cSrcweir }
123cdf0e10cSrcweir 
finalizeImport()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 
importNoteBiff2(BiffInputStream & rStrm)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 
importNoteBiff8(BiffInputStream & rStrm)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 
importNoteSound(BiffInputStream &)218cdf0e10cSrcweir void Comment::importNoteSound( BiffInputStream& /*rStrm*/ )
219cdf0e10cSrcweir {
220cdf0e10cSrcweir }
221cdf0e10cSrcweir 
222cdf0e10cSrcweir // ============================================================================
223cdf0e10cSrcweir 
CommentsBuffer(const WorksheetHelper & rHelper)224cdf0e10cSrcweir CommentsBuffer::CommentsBuffer( const WorksheetHelper& rHelper ) :
225cdf0e10cSrcweir     WorksheetHelper( rHelper )
226cdf0e10cSrcweir {
227cdf0e10cSrcweir }
228cdf0e10cSrcweir 
appendAuthor(const OUString & rAuthor)229cdf0e10cSrcweir void CommentsBuffer::appendAuthor( const OUString& rAuthor )
230cdf0e10cSrcweir {
231cdf0e10cSrcweir     maAuthors.push_back( rAuthor );
232cdf0e10cSrcweir }
233cdf0e10cSrcweir 
createComment()234cdf0e10cSrcweir CommentRef CommentsBuffer::createComment()
235cdf0e10cSrcweir {
236cdf0e10cSrcweir     CommentRef xComment( new Comment( *this ) );
237cdf0e10cSrcweir     maComments.push_back( xComment );
238cdf0e10cSrcweir     return xComment;
239cdf0e10cSrcweir }
240cdf0e10cSrcweir 
finalizeImport()241cdf0e10cSrcweir void CommentsBuffer::finalizeImport()
242cdf0e10cSrcweir {
243cdf0e10cSrcweir     maComments.forEachMem( &Comment::finalizeImport );
244cdf0e10cSrcweir }
245cdf0e10cSrcweir 
246cdf0e10cSrcweir // ============================================================================
247cdf0e10cSrcweir 
248cdf0e10cSrcweir } // namespace xls
249cdf0e10cSrcweir } // namespace oox
250