LibreOffice Module sc (master)  1
worksheetbuffer.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <worksheetbuffer.hxx>
21 
22 #include <com/sun/star/container/XIndexAccess.hpp>
23 #include <com/sun/star/container/XNamed.hpp>
24 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
25 #include <osl/diagnose.h>
26 #include <rtl/ustrbuf.hxx>
30 #include <oox/token/namespaces.hxx>
31 #include <oox/token/tokens.hxx>
32 #include <document.hxx>
33 #include <documentimport.hxx>
34 #include <biffhelper.hxx>
35 #include <globstr.hrc>
36 #include <scresid.hxx>
37 
38 namespace oox::xls {
39 
40 using namespace ::com::sun::star::container;
41 using namespace ::com::sun::star::sheet;
42 using namespace ::com::sun::star::uno;
43 
45  mnSheetId( -1 ),
46  mnState( XML_visible )
47 {
48 }
49 
51  WorkbookHelper( rHelper )
52 {
53 }
54 
56 {
57  SheetInfoModel aModel;
58  aModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
59  aModel.maName = rAttribs.getXString( XML_name, OUString() );
60  aModel.mnSheetId = rAttribs.getInteger( XML_sheetId, -1 );
61  aModel.mnState = rAttribs.getToken( XML_state, XML_visible );
62  insertSheet( aModel );
63 }
64 
66 {
67  sal_Int32 nState;
68  SheetInfoModel aModel;
69  nState = rStrm.readInt32();
70  aModel.mnSheetId = rStrm.readInt32();
71  rStrm >> aModel.maRelId >> aModel.maName;
72  static const sal_Int32 spnStates[] = { XML_visible, XML_hidden, XML_veryHidden };
73  aModel.mnState = STATIC_ARRAY_SELECT( spnStates, nState, XML_visible );
74  insertSheet( aModel );
75 }
76 
77 sal_Int16 WorksheetBuffer::insertEmptySheet( const OUString& rPreferredName )
78 {
79  IndexNamePair aIndexName = createSheet( rPreferredName, SAL_MAX_INT32 );
80  ScDocument& rDoc = getScDocument();
81 
82  rDoc.SetVisible( aIndexName.first, false );
83  return aIndexName.first;
84 }
85 
87 {
88  return static_cast< sal_Int32 >( maSheetInfos.size() );
89 }
90 
92 {
93  const ScDocumentImport& rDoc = getDocImport();
94  return rDoc.getSheetCount();
95 }
96 
97 OUString WorksheetBuffer::getWorksheetRelId( sal_Int32 nWorksheet ) const
98 {
99  const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get();
100  return pSheetInfo ? pSheetInfo->maRelId : OUString();
101 }
102 
103 sal_Int16 WorksheetBuffer::getCalcSheetIndex( sal_Int32 nWorksheet ) const
104 {
105  const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get();
106  return pSheetInfo ? pSheetInfo->mnCalcSheet : -1;
107 }
108 
109 OUString WorksheetBuffer::getCalcSheetName( sal_Int32 nWorksheet ) const
110 {
111  const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get();
112  return pSheetInfo ? pSheetInfo->maCalcName : OUString();
113 }
114 
115 void WorksheetBuffer::convertSheetNameRef( OUString& sSheetNameRef ) const
116 {
117  if( !sSheetNameRef.startsWith("#") )
118  return;
119 
120  sal_Int32 nSepPos = sSheetNameRef.lastIndexOf( '!' );
121  if( nSepPos <= 0 )
122  return;
123 
124  // Do not attempt to blindly convert '#SheetName!A1' to
125  // '#SheetName.A1', it can be #SheetName!R1C1 as well. Hyperlink
126  // handler has to handle all, but prefer '#SheetName.A1' if
127  // possible.
128  if (nSepPos < sSheetNameRef.getLength() - 1)
129  {
130  ScRange aRange;
131  if ((aRange.ParseAny( sSheetNameRef.copy( nSepPos + 1 ), getScDocument(),
133  sSheetNameRef = sSheetNameRef.replaceAt( nSepPos, 1, OUString( '.' ) );
134  }
135  // #i66592# convert sheet names that have been renamed on import
136  OUString aSheetName = sSheetNameRef.copy( 1, nSepPos - 1 );
137  OUString aCalcName = getCalcSheetName( aSheetName );
138  if( !aCalcName.isEmpty() )
139  sSheetNameRef = sSheetNameRef.replaceAt( 1, nSepPos - 1, aCalcName );
140 }
141 
142 sal_Int16 WorksheetBuffer::getCalcSheetIndex( const OUString& rWorksheetName ) const
143 {
144  const SheetInfo* pSheetInfo = maSheetInfosByName.get( rWorksheetName ).get();
145  return pSheetInfo ? pSheetInfo->mnCalcSheet : -1;
146 }
147 
148 OUString WorksheetBuffer::getCalcSheetName( const OUString& rWorksheetName ) const
149 {
150  if( const SheetInfo* pSheetInfo = maSheetInfosByName.get( rWorksheetName ).get() )
151  {
152  bool bIsQuoted = pSheetInfo->maName != rWorksheetName;
153  return bIsQuoted ? pSheetInfo->maCalcQuotedName : pSheetInfo->maCalcName;
154  }
155  return OUString();
156 }
157 
158 // private --------------------------------------------------------------------
159 
160 namespace {
161 
162 OUString lclQuoteName( const OUString& rName )
163 {
164  OUStringBuffer aBuffer( rName );
165  // duplicate all quote characters
166  for( sal_Int32 nPos = aBuffer.getLength() - 1; nPos >= 0; --nPos )
167  if( aBuffer[nPos] == '\'' )
168  aBuffer.insert( nPos, '\'' );
169  // add outer quotes and return
170  return aBuffer.insert( 0, '\'' ).append( '\'' ).makeStringAndClear();
171 }
172 
173 } // namespace
174 
175 WorksheetBuffer::SheetInfo::SheetInfo( const SheetInfoModel& rModel, sal_Int16 nCalcSheet, const OUString& rCalcName ) :
176  SheetInfoModel( rModel ),
177  maCalcName( rCalcName ),
178  maCalcQuotedName( lclQuoteName( rCalcName ) ),
179  mnCalcSheet( nCalcSheet )
180 {
181 }
182 
183 WorksheetBuffer::IndexNamePair WorksheetBuffer::createSheet( const OUString& rPreferredName, sal_Int32 nSheetPos )
184 {
185  //FIXME: Rewrite this block using ScDocument[Import] instead of UNO
186  try
187  {
188  Reference< XSpreadsheets > xSheets( getDocument()->getSheets(), UNO_SET_THROW );
189  Reference< XIndexAccess > xSheetsIA( xSheets, UNO_QUERY_THROW );
190  sal_Int16 nCalcSheet = -1;
191  OUString aSheetName = rPreferredName.isEmpty() ? ScResId(STR_TABLE_DEF) : rPreferredName;
192  if( nSheetPos < xSheetsIA->getCount() )
193  {
194  nCalcSheet = static_cast< sal_Int16 >( nSheetPos );
195  // existing sheet - try to rename
196  Reference< XNamed > xSheetName( xSheetsIA->getByIndex( nSheetPos ), UNO_QUERY_THROW );
197  if( xSheetName->getName() != aSheetName )
198  {
199  aSheetName = ContainerHelper::getUnusedName( xSheets, aSheetName, ' ' );
200  xSheetName->setName( aSheetName );
201  }
202  }
203  else
204  {
205  nCalcSheet = static_cast< sal_Int16 >( xSheetsIA->getCount() );
206  // new sheet - insert with unused name
207  aSheetName = ContainerHelper::getUnusedName( xSheets, aSheetName, ' ' );
208  xSheets->insertNewByName( aSheetName, nCalcSheet );
209  }
210 
211  // return final sheet index if sheet exists
212  return IndexNamePair( nCalcSheet, aSheetName );
213  }
214  catch (const Exception&)
215  {
216  OSL_FAIL( "WorksheetBuffer::createSheet - cannot insert or rename worksheet" );
217  }
218  return IndexNamePair( -1, OUString() );
219 }
220 
222 {
223  sal_Int32 nWorksheet = static_cast< sal_Int32 >( maSheetInfos.size() );
224  IndexNamePair aIndexName = createSheet( rModel.maName, nWorksheet );
225  auto xSheetInfo = std::make_shared<SheetInfo>( rModel, aIndexName.first, aIndexName.second );
226  maSheetInfos.push_back( xSheetInfo );
227  maSheetInfosByName[ rModel.maName ] = xSheetInfo;
228  maSheetInfosByName[ lclQuoteName( rModel.maName ) ] = xSheetInfo;
229 }
230 
231 void WorksheetBuffer::finalizeImport( sal_Int16 nActiveSheet )
232 {
233  ScDocument& rDoc = getScDocument();
234 
235  for ( const auto& aSheetInfo: maSheetInfos )
236  {
237  // make sure at least 1 sheet (the active one) is visible
238  if ( aSheetInfo->mnCalcSheet == nActiveSheet)
239  rDoc.SetVisible( aSheetInfo->mnCalcSheet, true );
240  else
241  rDoc.SetVisible( aSheetInfo->mnCalcSheet, aSheetInfo->mnState == XML_visible );
242  }
243 }
244 
245 } // namespace oox::xls
246 
247 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SC_DLLPUBLIC ScRefFlags ParseAny(const OUString &, const ScDocument &, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1)
Definition: address.cxx:1766
Helper class to provide access to global workbook data.
sal_Int32 getAllSheetCount() const
Returns the number of all sheets, workbook + dummy ones (pivot table cache records ) ...
ScDocumentImport & getDocImport()
WorksheetBuffer(const WorkbookHelper &rHelper)
OptValue< OUString > getXString(sal_Int32 nAttrToken) const
OptValue< sal_Int32 > getInteger(sal_Int32 nAttrToken) const
RefVector< SheetInfo > maSheetInfos
OUString getCalcSheetName(sal_Int32 nWorksheet) const
Returns the finalized name of the specified worksheet.
SheetInfoModel()
Visibility state.
#define STATIC_ARRAY_SELECT(array, index, def)
OptValue< OUString > getString(sal_Int32 nAttrToken) const
Accessor class to ScDocument.
SC_DLLPUBLIC void SetVisible(SCTAB nTab, bool bVisible)
Definition: document.cxx:901
OUString getWorksheetRelId(sal_Int32 nWorksheet) const
Returns the OOXML relation identifier of the specified worksheet.
SheetInfo(const SheetInfoModel &rModel, sal_Int16 nCalcSheet, const OUString &rCalcName)
OUString maName
Relation identifier for the sheet substream.
void convertSheetNameRef(OUString &sSheetNameRef) const
Converts sSheetNameRef (e.g.
Contains data from the 'sheet' element describing a sheet in the workbook.
#define SAL_MAX_INT32
const css::uno::Reference< css::sheet::XSpreadsheetDocument > & getDocument() const
Returns a reference to the source/target spreadsheet document model.
SCTAB getSheetCount() const
sal_Int32 mnState
Sheet identifier.
void insertSheet(const SheetInfoModel &rModel)
Creates a new sheet in the Calc document and inserts the related SheetInfo.
OUString ScResId(const char *pId)
Definition: scdll.cxx:95
sal_Int32 getWorksheetCount() const
Returns the number of original sheets contained in the workbook.
RefMap< OUString, SheetInfo, IgnoreCaseCompare > maSheetInfosByName
sal_Int16 getCalcSheetIndex(sal_Int32 nWorksheet) const
Returns the Calc index of the specified worksheet.
static OUString getUnusedName(const css::uno::Reference< css::container::XNameAccess > &rxNameAccess, const OUString &rSuggestedName, sal_Unicode cSeparator)
std::unique_ptr< char[]> aBuffer
::std::pair< sal_Int16, OUString > IndexNamePair
void importSheet(const AttributeList &rAttribs)
Imports the attributes of a sheet element.
sal_Int32 mnSheetId
Original name of the sheet.
sal_Int16 insertEmptySheet(const OUString &rPreferredName)
Inserts a new empty sheet into the document.
void finalizeImport(sal_Int16 nActiveSheet)
IndexNamePair createSheet(const OUString &rPreferredName, sal_Int32 nSheetPos)
Creates a new sheet in the Calc document.
sal_Int32 nState
sal_uInt16 nPos
OptValue< sal_Int32 > getToken(sal_Int32 nAttrToken) const