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 <sal/config.h>
21 
22 #include <string_view>
23 
24 #include <worksheetbuffer.hxx>
25 
26 #include <com/sun/star/container/XIndexAccess.hpp>
27 #include <com/sun/star/container/XNamed.hpp>
28 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
29 #include <osl/diagnose.h>
30 #include <rtl/ustrbuf.hxx>
34 #include <oox/token/namespaces.hxx>
35 #include <oox/token/tokens.hxx>
36 #include <document.hxx>
37 #include <documentimport.hxx>
38 #include <biffhelper.hxx>
39 #include <globstr.hrc>
40 #include <scresid.hxx>
41 
42 namespace oox::xls {
43 
44 using namespace ::com::sun::star::container;
45 using namespace ::com::sun::star::sheet;
46 using namespace ::com::sun::star::uno;
47 
49  mnSheetId( -1 ),
50  mnState( XML_visible )
51 {
52 }
53 
55  WorkbookHelper( rHelper )
56 {
57 }
58 
60 {
61  SheetInfoModel aModel;
62  aModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
63  aModel.maName = rAttribs.getXString( XML_name, OUString() );
64  aModel.mnSheetId = rAttribs.getInteger( XML_sheetId, -1 );
65  aModel.mnState = rAttribs.getToken( XML_state, XML_visible );
66  insertSheet( aModel );
67 }
68 
70 {
71  sal_Int32 nState;
72  SheetInfoModel aModel;
73  nState = rStrm.readInt32();
74  aModel.mnSheetId = rStrm.readInt32();
75  rStrm >> aModel.maRelId >> aModel.maName;
76  static const sal_Int32 spnStates[] = { XML_visible, XML_hidden, XML_veryHidden };
77  aModel.mnState = STATIC_ARRAY_SELECT( spnStates, nState, XML_visible );
78  insertSheet( aModel );
79 }
80 
81 sal_Int16 WorksheetBuffer::insertEmptySheet( const OUString& rPreferredName )
82 {
83  IndexNamePair aIndexName = createSheet( rPreferredName, SAL_MAX_INT32 );
84  ScDocument& rDoc = getScDocument();
85 
86  rDoc.SetVisible( aIndexName.first, false );
87  return aIndexName.first;
88 }
89 
91 {
92  return static_cast< sal_Int32 >( maSheetInfos.size() );
93 }
94 
96 {
97  const ScDocumentImport& rDoc = getDocImport();
98  return rDoc.getSheetCount();
99 }
100 
101 OUString WorksheetBuffer::getWorksheetRelId( sal_Int32 nWorksheet ) const
102 {
103  const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get();
104  return pSheetInfo ? pSheetInfo->maRelId : OUString();
105 }
106 
107 sal_Int16 WorksheetBuffer::getCalcSheetIndex( sal_Int32 nWorksheet ) const
108 {
109  const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get();
110  return pSheetInfo ? pSheetInfo->mnCalcSheet : -1;
111 }
112 
113 OUString WorksheetBuffer::getCalcSheetName( sal_Int32 nWorksheet ) const
114 {
115  const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get();
116  return pSheetInfo ? pSheetInfo->maCalcName : OUString();
117 }
118 
119 void WorksheetBuffer::convertSheetNameRef( OUString& sSheetNameRef ) const
120 {
121  if( !sSheetNameRef.startsWith("#") )
122  return;
123 
124  sal_Int32 nSepPos = sSheetNameRef.lastIndexOf( '!' );
125  if( nSepPos <= 0 )
126  return;
127 
128  // Do not attempt to blindly convert '#SheetName!A1' to
129  // '#SheetName.A1', it can be #SheetName!R1C1 as well. Hyperlink
130  // handler has to handle all, but prefer '#SheetName.A1' if
131  // possible.
132  if (nSepPos < sSheetNameRef.getLength() - 1)
133  {
134  ScRange aRange;
135  if ((aRange.ParseAny( sSheetNameRef.copy( nSepPos + 1 ), getScDocument(),
137  sSheetNameRef = sSheetNameRef.replaceAt( nSepPos, 1, rtl::OUStringChar( '.' ) );
138  }
139  // #i66592# convert sheet names that have been renamed on import
140  OUString aSheetName = sSheetNameRef.copy( 1, nSepPos - 1 );
141  OUString aCalcName = getCalcSheetName( aSheetName );
142  if( !aCalcName.isEmpty() )
143  sSheetNameRef = sSheetNameRef.replaceAt( 1, nSepPos - 1, aCalcName );
144 }
145 
146 sal_Int16 WorksheetBuffer::getCalcSheetIndex( const OUString& rWorksheetName ) const
147 {
148  const SheetInfo* pSheetInfo = maSheetInfosByName.get( rWorksheetName ).get();
149  return pSheetInfo ? pSheetInfo->mnCalcSheet : -1;
150 }
151 
152 OUString WorksheetBuffer::getCalcSheetName( const OUString& rWorksheetName ) const
153 {
154  if( const SheetInfo* pSheetInfo = maSheetInfosByName.get( rWorksheetName ).get() )
155  {
156  bool bIsQuoted = pSheetInfo->maName != rWorksheetName;
157  return bIsQuoted ? pSheetInfo->maCalcQuotedName : pSheetInfo->maCalcName;
158  }
159  return OUString();
160 }
161 
162 // private --------------------------------------------------------------------
163 
164 namespace {
165 
166 OUString lclQuoteName( std::u16string_view rName )
167 {
168  OUStringBuffer aBuffer( rName );
169  // duplicate all quote characters
170  for( sal_Int32 nPos = aBuffer.getLength() - 1; nPos >= 0; --nPos )
171  if( aBuffer[nPos] == '\'' )
172  aBuffer.insert( nPos, '\'' );
173  // add outer quotes and return
174  return aBuffer.insert( 0, '\'' ).append( '\'' ).makeStringAndClear();
175 }
176 
177 } // namespace
178 
179 WorksheetBuffer::SheetInfo::SheetInfo( const SheetInfoModel& rModel, sal_Int16 nCalcSheet, const OUString& rCalcName ) :
180  SheetInfoModel( rModel ),
181  maCalcName( rCalcName ),
182  maCalcQuotedName( lclQuoteName( rCalcName ) ),
183  mnCalcSheet( nCalcSheet )
184 {
185 }
186 
187 WorksheetBuffer::IndexNamePair WorksheetBuffer::createSheet( const OUString& rPreferredName, sal_Int32 nSheetPos )
188 {
189  //FIXME: Rewrite this block using ScDocument[Import] instead of UNO
190  try
191  {
192  Reference< XSpreadsheets > xSheets( getDocument()->getSheets(), UNO_SET_THROW );
193  Reference< XIndexAccess > xSheetsIA( xSheets, UNO_QUERY_THROW );
194  sal_Int16 nCalcSheet = -1;
195  OUString aSheetName = rPreferredName.isEmpty() ? ScResId(STR_TABLE_DEF) : rPreferredName;
196  if( nSheetPos < xSheetsIA->getCount() )
197  {
198  nCalcSheet = static_cast< sal_Int16 >( nSheetPos );
199  // existing sheet - try to rename
200  Reference< XNamed > xSheetName( xSheetsIA->getByIndex( nSheetPos ), UNO_QUERY_THROW );
201  if( xSheetName->getName() != aSheetName )
202  {
203  aSheetName = ContainerHelper::getUnusedName( xSheets, aSheetName, ' ' );
204  xSheetName->setName( aSheetName );
205  }
206  }
207  else
208  {
209  nCalcSheet = static_cast< sal_Int16 >( xSheetsIA->getCount() );
210  // new sheet - insert with unused name
211  aSheetName = ContainerHelper::getUnusedName( xSheets, aSheetName, ' ' );
212  xSheets->insertNewByName( aSheetName, nCalcSheet );
213  }
214 
215  // return final sheet index if sheet exists
216  return IndexNamePair( nCalcSheet, aSheetName );
217  }
218  catch (const Exception&)
219  {
220  OSL_FAIL( "WorksheetBuffer::createSheet - cannot insert or rename worksheet" );
221  }
222  return IndexNamePair( -1, OUString() );
223 }
224 
226 {
227  sal_Int32 nWorksheet = static_cast< sal_Int32 >( maSheetInfos.size() );
228  IndexNamePair aIndexName = createSheet( rModel.maName, nWorksheet );
229  auto xSheetInfo = std::make_shared<SheetInfo>( rModel, aIndexName.first, aIndexName.second );
230  maSheetInfos.push_back( xSheetInfo );
231  maSheetInfosByName[ rModel.maName ] = xSheetInfo;
232  maSheetInfosByName[ lclQuoteName( rModel.maName ) ] = xSheetInfo;
233 }
234 
235 void WorksheetBuffer::finalizeImport( sal_Int16 nActiveSheet )
236 {
237  ScDocument& rDoc = getScDocument();
238 
239  for ( const auto& aSheetInfo: maSheetInfos )
240  {
241  // make sure at least 1 sheet (the active one) is visible
242  if ( aSheetInfo->mnCalcSheet == nActiveSheet)
243  rDoc.SetVisible( aSheetInfo->mnCalcSheet, true );
244  else
245  rDoc.SetVisible( aSheetInfo->mnCalcSheet, aSheetInfo->mnState == XML_visible );
246  }
247 }
248 
249 } // namespace oox::xls
250 
251 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScRefFlags ParseAny(const OUString &, const ScDocument &, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1)
Definition: address.cxx:1733
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)
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
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:904
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.
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