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 
10 #include <xedbdata.hxx>
11 #include <excrecds.hxx>
12 #include <dbdata.hxx>
13 #include <document.hxx>
14 #include <oox/export/utils.hxx>
15 #include <oox/token/namespaces.hxx>
16 
17 using namespace oox;
18 
19 namespace {
20 
21 /** (So far) dummy implementation of table export for BIFF5/BIFF7. */
22 class XclExpTablesImpl5 : public XclExpTables
23 {
24 public:
25     explicit            XclExpTablesImpl5( const XclExpRoot& rRoot );
26 
27     virtual void        Save( XclExpStream& rStrm ) override;
28     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
29 };
30 
31 /** Implementation of table export for OOXML, so far dummy for BIFF8. */
32 class XclExpTablesImpl8 : public XclExpTables
33 {
34 public:
35     explicit            XclExpTablesImpl8( const XclExpRoot& rRoot );
36 
37     virtual void        Save( XclExpStream& rStrm ) override;
38     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
39 };
40 
41 }
42 
XclExpTablesImpl5(const XclExpRoot & rRoot)43 XclExpTablesImpl5::XclExpTablesImpl5( const XclExpRoot& rRoot ) :
44     XclExpTables( rRoot )
45 {
46 }
47 
Save(XclExpStream &)48 void XclExpTablesImpl5::Save( XclExpStream& /*rStrm*/ )
49 {
50     // not implemented
51 }
52 
SaveXml(XclExpXmlStream &)53 void XclExpTablesImpl5::SaveXml( XclExpXmlStream& /*rStrm*/ )
54 {
55     // not applicable
56 }
57 
58 
XclExpTablesImpl8(const XclExpRoot & rRoot)59 XclExpTablesImpl8::XclExpTablesImpl8( const XclExpRoot& rRoot ) :
60     XclExpTables( rRoot )
61 {
62 }
63 
Save(XclExpStream &)64 void XclExpTablesImpl8::Save( XclExpStream& /*rStrm*/ )
65 {
66     // not implemented
67 }
68 
SaveXml(XclExpXmlStream & rStrm)69 void XclExpTablesImpl8::SaveXml( XclExpXmlStream& rStrm )
70 {
71 
72     sax_fastparser::FSHelperPtr& pWorksheetStrm = rStrm.GetCurrentStream();
73     pWorksheetStrm->startElement(XML_tableParts);
74     for (auto const& it : maTables)
75     {
76         OUString aRelId;
77         sax_fastparser::FSHelperPtr pTableStrm = rStrm.CreateOutputStream(
78                 XclXmlUtils::GetStreamName("xl/tables/", "table", it.mnTableId),
79                 XclXmlUtils::GetStreamName("../tables/", "table", it.mnTableId),
80                 pWorksheetStrm->getOutputStream(),
81                 CREATE_XL_CONTENT_TYPE("table"),
82                 CREATE_OFFICEDOC_RELATION_TYPE("table"),
83                 &aRelId);
84 
85         pWorksheetStrm->singleElement(XML_tablePart, FSNS(XML_r, XML_id), aRelId.toUtf8());
86 
87         rStrm.PushStream( pTableStrm);
88         SaveTableXml( rStrm, it);
89         rStrm.PopStream();
90     }
91     pWorksheetStrm->endElement( XML_tableParts);
92 }
93 
94 
XclExpTablesManager(const XclExpRoot & rRoot)95 XclExpTablesManager::XclExpTablesManager( const XclExpRoot& rRoot ) :
96     XclExpRoot( rRoot )
97 {
98 }
99 
~XclExpTablesManager()100 XclExpTablesManager::~XclExpTablesManager()
101 {
102 }
103 
Initialize()104 void XclExpTablesManager::Initialize()
105 {
106     // All non-const to be able to call RefreshTableColumnNames().
107     ScDocument& rDoc = GetDoc();
108     ScDBCollection* pDBColl = rDoc.GetDBCollection();
109     if (!pDBColl)
110         return;
111 
112     ScDBCollection::NamedDBs& rDBs = pDBColl->getNamedDBs();
113     if (rDBs.empty())
114         return;
115 
116     sal_Int32 nTableId = 0;
117     for (const auto& rxDB : rDBs)
118     {
119         ScDBData* pDBData = rxDB.get();
120         pDBData->RefreshTableColumnNames( &rDoc);   // currently not in sync, so refresh
121         ScRange aRange( ScAddress::UNINITIALIZED);
122         pDBData->GetArea( aRange);
123         SCTAB nTab = aRange.aStart.Tab();
124         TablesMapType::iterator it = maTablesMap.find( nTab);
125         if (it == maTablesMap.end())
126         {
127             rtl::Reference< XclExpTables > pNew;
128             switch( GetBiff() )
129             {
130                 case EXC_BIFF5:
131                     pNew = new XclExpTablesImpl5( GetRoot());
132                     break;
133                 case EXC_BIFF8:
134                     pNew = new XclExpTablesImpl8( GetRoot());
135                     break;
136                 default:
137                     assert(!"Unknown BIFF type!");
138                     continue;   // for
139             }
140             ::std::pair< TablesMapType::iterator, bool > ins( maTablesMap.insert( ::std::make_pair( nTab, pNew)));
141             if (!ins.second)
142             {
143                 assert(!"XclExpTablesManager::Initialize - XclExpTables insert failed");
144                 continue;   // for
145             }
146             it = ins.first;
147         }
148         it->second->AppendTable( pDBData, ++nTableId);
149     }
150 }
151 
GetTablesBySheet(SCTAB nTab)152 rtl::Reference< XclExpTables > XclExpTablesManager::GetTablesBySheet( SCTAB nTab )
153 {
154     TablesMapType::iterator it = maTablesMap.find(nTab);
155     return it == maTablesMap.end() ? nullptr : it->second;
156 }
157 
Entry(const ScDBData * pData,sal_Int32 nTableId)158 XclExpTables::Entry::Entry( const ScDBData* pData, sal_Int32 nTableId ) :
159     mpData(pData), mnTableId(nTableId)
160 {
161 }
162 
XclExpTables(const XclExpRoot & rRoot)163 XclExpTables::XclExpTables( const XclExpRoot& rRoot ) :
164     XclExpRoot(rRoot)
165 {
166 }
167 
~XclExpTables()168 XclExpTables::~XclExpTables()
169 {
170 }
171 
AppendTable(const ScDBData * pData,sal_Int32 nTableId)172 void XclExpTables::AppendTable( const ScDBData* pData, sal_Int32 nTableId )
173 {
174     maTables.emplace_back( pData, nTableId);
175 }
176 
SaveTableXml(XclExpXmlStream & rStrm,const Entry & rEntry)177 void XclExpTables::SaveTableXml( XclExpXmlStream& rStrm, const Entry& rEntry )
178 {
179     const ScDBData& rData = *rEntry.mpData;
180     ScRange aRange( ScAddress::UNINITIALIZED);
181     rData.GetArea( aRange);
182     sax_fastparser::FSHelperPtr& pTableStrm = rStrm.GetCurrentStream();
183     pTableStrm->startElement( XML_table,
184         XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)).toUtf8(),
185         XML_id, OString::number( rEntry.mnTableId),
186         XML_name, rData.GetName().toUtf8(),
187         XML_displayName, rData.GetName().toUtf8(),
188         XML_ref, XclXmlUtils::ToOString(rStrm.GetRoot().GetDoc(), aRange),
189         XML_headerRowCount, ToPsz10(rData.HasHeader()),
190         XML_totalsRowCount, ToPsz10(rData.HasTotals()),
191         XML_totalsRowShown, ToPsz10(rData.HasTotals())  // we don't support that but if there are totals they are shown
192         // OOXTODO: XML_comment, ...,
193         // OOXTODO: XML_connectionId, ...,
194         // OOXTODO: XML_dataCellStyle, ...,
195         // OOXTODO: XML_dataDxfId, ...,
196         // OOXTODO: XML_headerRowBorderDxfId, ...,
197         // OOXTODO: XML_headerRowCellStyle, ...,
198         // OOXTODO: XML_headerRowDxfId, ...,
199         // OOXTODO: XML_insertRow, ...,
200         // OOXTODO: XML_insertRowShift, ...,
201         // OOXTODO: XML_published, ...,
202         // OOXTODO: XML_tableBorderDxfId, ...,
203         // OOXTODO: XML_tableType, ...,
204         // OOXTODO: XML_totalsRowBorderDxfId, ...,
205         // OOXTODO: XML_totalsRowCellStyle, ...,
206         // OOXTODO: XML_totalsRowDxfId, ...
207     );
208 
209     if (rData.HasAutoFilter())
210     {
211         /* TODO: does this need to exclude totals row? */
212 
213         /* TODO: in OOXML  12.3.21 Table Definition Part  has information
214          * that an applied autoFilter has child elements
215          * <af:filterColumn><af:filters><af:filter>.
216          * When not applied but buttons hidden, Excel writes, for example,
217          * <filterColumn colId="0" hiddenButton="1"/> */
218 
219         ExcAutoFilterRecs aAutoFilter( rStrm.GetRoot(), aRange.aStart.Tab(), &rData);
220         aAutoFilter.SaveXml( rStrm);
221     }
222 
223     const std::vector< OUString >& rColNames = rData.GetTableColumnNames();
224     if (!rColNames.empty())
225     {
226         pTableStrm->startElement(XML_tableColumns,
227                 XML_count, OString::number(aRange.aEnd.Col() - aRange.aStart.Col() + 1));
228 
229         for (size_t i=0, n=rColNames.size(); i < n; ++i)
230         {
231             // OOXTODO: write <calculatedColumnFormula> once we support it, in
232             // which case we'd need start/endElement XML_tableColumn for such
233             // column.
234 
235             // OOXTODO: write <totalsRowFormula> once we support it.
236 
237             pTableStrm->singleElement( XML_tableColumn,
238                     XML_id, OString::number(i+1),
239                     XML_name, rColNames[i].toUtf8()
240                     // OOXTODO: XML_dataCellStyle, ...,
241                     // OOXTODO: XML_dataDxfId, ...,
242                     // OOXTODO: XML_headerRowCellStyle, ...,
243                     // OOXTODO: XML_headerRowDxfId, ...,
244                     // OOXTODO: XML_queryTableFieldId, ...,
245                     // OOXTODO: XML_totalsRowCellStyle, ...,
246                     // OOXTODO: XML_totalsRowDxfId, ...,
247                     // OOXTODO: XML_totalsRowFunction, ...,
248                     // OOXTODO: XML_totalsRowLabel, ...,
249                     // OOXTODO: XML_uniqueName, ...
250             );
251         }
252 
253         pTableStrm->endElement( XML_tableColumns);
254     }
255 
256     // OOXTODO: write <tableStyleInfo> once we have table styles.
257 
258     pTableStrm->endElement( XML_table);
259 }
260 
261 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
262