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