2
* This file is part of Office 2007 Filters for KOffice
4
* Copyright (C) 2010 Sebastian Sauer <sebsauer@kdab.com>
5
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
7
* Contact: Suresh Chande suresh.chande@nokia.com
9
* This library is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU Lesser General Public License
11
* version 2.1 as published by the Free Software Foundation.
13
* This library is distributed in the hope that it will be useful, but
14
* WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25
#include "XlsxXmlChartReader.h"
26
#include "XlsxXmlDrawingReader.h"
27
#include "XlsxXmlWorksheetReader.h"
28
#include "XlsxImport.h"
31
#include "ChartExport.h"
33
#define MSOOXML_CURRENT_NS "c"
34
#define MSOOXML_CURRENT_CLASS XlsxXmlChartReader
35
#define BIND_READ_CLASS MSOOXML_CURRENT_CLASS
37
#include <MsooXmlReader_p.h>
38
#include <MsooXmlUtils.h>
40
#include <QFontMetricsF>
42
// calculates the column width in pixels
43
int columnWidth(unsigned long col, unsigned long dx = 0, qreal defaultColumnWidth = 8.43) {
44
QFont font("Arial", 10);
45
QFontMetricsF fm(font);
46
const qreal characterWidth = fm.width("h");
47
defaultColumnWidth *= characterWidth;
48
return (defaultColumnWidth * col) + (dx / 1024.0 * defaultColumnWidth);
51
// calculates the row height in pixels
52
int rowHeight(unsigned long row, unsigned long dy = 0, qreal defaultRowHeight = 12.75)
54
return defaultRowHeight * row + dy;
57
// Returns A for 1, B for 2, C for 3, etc.
58
QString columnName(uint column)
63
for (unsigned limit = 26; column >= limit + offset; limit *= 26, digits++)
65
for (unsigned col = column - offset; digits; --digits, col /= 26)
66
s.prepend(QChar('A' + (col % 26)));
70
XlsxXmlChartReaderContext::XlsxXmlChartReaderContext(XlsxXmlDrawingReaderContext* _drawingReaderContext)
71
: MSOOXML::MsooXmlReaderContext()
72
, drawingReaderContext(_drawingReaderContext)
78
XlsxXmlChartReaderContext::~XlsxXmlChartReaderContext()
83
XlsxXmlChartReader::XlsxXmlChartReader(KoOdfWriters *writers)
84
: MSOOXML::MsooXmlCommonReader(writers)
90
XlsxXmlChartReader::~XlsxXmlChartReader()
94
KoFilter::ConversionStatus XlsxXmlChartReader::read(MSOOXML::MsooXmlReaderContext* context)
96
m_context = dynamic_cast<XlsxXmlChartReaderContext*>(context);
98
Q_ASSERT(m_context->drawingReaderContext);
99
Q_ASSERT(m_context->drawingReaderContext->worksheetReaderContext);
102
if (!isStartDocument()) {
103
return KoFilter::WrongFormat;
107
if (!expectEl("c:chartSpace")) {
108
return KoFilter::WrongFormat;
111
delete m_context->m_chart;
112
m_context->m_chart = new Charting::Chart;
114
delete m_context->m_chartExport;
115
m_context->m_chartExport = new ChartExport(m_context->m_chart);
118
QXmlStreamReader::TokenType tokenType = readNext();
119
if(tokenType == QXmlStreamReader::Invalid || tokenType == QXmlStreamReader::EndDocument) break;
120
if (isStartElement()) {
121
TRY_READ_IF(plotArea)
122
ELSE_TRY_READ_IF(legend)
126
// static is fine here cause we only need to take care that that number is unique in the
127
// exported ODS file and do not take if the number is continuous or whatever.
128
static int chartNumber = 0;
130
m_context->m_chartExport->m_href = QString("Chart%1").arg(++chartNumber);
131
QMap<XlsxXmlDrawingReaderContext::AnchorType, XlsxXmlDrawingReaderContext::Position> positions = m_context->drawingReaderContext->m_positions;
132
const QString sheetName = m_context->drawingReaderContext->worksheetReaderContext->worksheetName;
133
if(! sheetName.isEmpty()) {
134
m_context->m_chartExport->m_endCellAddress += sheetName + '.';
137
if(positions.contains(XlsxXmlDrawingReaderContext::FromAnchor)) {
138
XlsxXmlDrawingReaderContext::Position f = positions[XlsxXmlDrawingReaderContext::FromAnchor];
139
m_context->m_chartExport->m_endCellAddress += columnName(f.m_col) + QString::number(f.m_row);
140
m_context->m_chartExport->m_x = columnWidth(f.m_col-1, 0 /*f.m_colOff*/);
141
m_context->m_chartExport->m_y = rowHeight(f.m_row-1, 0 /*f.m_rowOff*/);
142
if(positions.contains(XlsxXmlDrawingReaderContext::ToAnchor)) {
143
XlsxXmlDrawingReaderContext::Position t = positions[XlsxXmlDrawingReaderContext::ToAnchor];
144
m_context->m_chartExport->m_width = columnWidth( t.m_col - f.m_col - 1, 0 /*t.m_colOff*/);
145
m_context->m_chartExport->m_height = rowHeight( t.m_row - f.m_row - 1, 0 /*t.m_rowOff*/);
150
if (!m_context->m_chart->m_cellRangeAddress.isNull() ) {
151
m_context->m_chartExport->m_cellRangeAddress.clear();
152
if (!sheetName.isEmpty()) m_context->m_chartExport->m_cellRangeAddress += sheetName + '.';
153
m_context->m_chartExport->m_cellRangeAddress += columnName(m_context->m_chart->m_cellRangeAddress.left()) + QString::number(m_context->m_chart->m_cellRangeAddress.top()) + ":" +
154
columnName(m_context->m_chart->m_cellRangeAddress.right()) + QString::number(m_context->m_chart->m_cellRangeAddress.bottom());
157
m_context->m_chartExport->m_notifyOnUpdateOfRanges = m_currentSeries->m_valuesCellRangeAddress; //m_cellRangeAddress
159
// the index will by written by the XlsxXmlWorksheetReader
160
//m_context->m_chartExport->saveIndex(body);
162
// write the embedded object file
163
KoStore* storeout = m_context->drawingReaderContext->worksheetReaderContext->import->outputStore();
164
m_context->m_chartExport->saveContent(storeout, manifest);
171
#define CURRENT_EL plotArea
172
KoFilter::ConversionStatus XlsxXmlChartReader::read_plotArea()
177
if (isStartElement()) {
179
ELSE_TRY_READ_IF(pieChart)
180
ELSE_TRY_READ_IF(firstSliceAng)
182
BREAK_IF_END_OF(CURRENT_EL);
188
#define CURRENT_EL ser
189
KoFilter::ConversionStatus XlsxXmlChartReader::read_ser()
193
m_currentSeries = new Charting::Series;
194
m_context->m_chart->m_series << m_currentSeries;
195
//m_currentSeries->m_dataTypeX = record->dataTypeX();
196
//m_currentSeries->m_countXValues = record->countXValues();
197
//m_currentSeries->m_countYValues = record->countYValues();
198
//m_currentSeries->m_countBubbleSizeValues = record->countBubbleSizeValues();
202
if (isStartElement()) {
204
//ELSE_TRY_READ_IF(idx)
205
//ELSE_TRY_READ_IF(order)
207
BREAK_IF_END_OF(CURRENT_EL);
214
#define CURRENT_EL val
215
KoFilter::ConversionStatus XlsxXmlChartReader::read_val()
220
if (isStartElement()) {
221
TRY_READ_IF(numCache)
222
if (qualifiedName() == QLatin1String(QUALIFIED_NAME(f))) {
223
m_currentSeries->m_valuesCellRangeAddress = readElementText();
226
BREAK_IF_END_OF(CURRENT_EL);
232
#define CURRENT_EL numCache
233
KoFilter::ConversionStatus XlsxXmlChartReader::read_numCache()
238
if (isStartElement()) {
239
if (qualifiedName() == QLatin1String(QUALIFIED_NAME(ptCount))) {
240
const QXmlStreamAttributes attrs(attributes());
241
TRY_READ_ATTR_WITHOUT_NS(val)
242
m_currentSeries->m_countYValues = val.toInt();
244
//else if (qualifiedName() == QLatin1String(QUALIFIED_NAME(pt)))
245
//else if (qualifiedName() == QLatin1String(QUALIFIED_NAME(formatCode)))
247
BREAK_IF_END_OF(CURRENT_EL);
253
#define CURRENT_EL legend
254
KoFilter::ConversionStatus XlsxXmlChartReader::read_legend()
261
#define CURRENT_EL pieChart
262
KoFilter::ConversionStatus XlsxXmlChartReader::read_pieChart()
264
if(!m_context->m_chart->m_impl) {
265
m_context->m_chart->m_impl = new Charting::PieImpl();
270
KoFilter::ConversionStatus XlsxXmlChartReader::read_firstSliceAng()
272
if(Charting::PieImpl* pie = dynamic_cast<Charting::PieImpl*>(m_context->m_chart->m_impl)) {
273
const QXmlStreamAttributes attrs(attributes());
275
pie->m_anStart = val.toInt(); // default value is zero