comparison src/xlsx/xlsxdrawinganchor.cpp @ 1:93d3106bb9a4

Add qt xlsx library
author Andre Heinecke <andre.heinecke@intevation.de>
date Tue, 22 Mar 2016 10:38:08 +0100
parents
children
comparison
equal deleted inserted replaced
0:49cd5cc0b072 1:93d3106bb9a4
1 /****************************************************************************
2 ** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
3 ** All right reserved.
4 **
5 ** Permission is hereby granted, free of charge, to any person obtaining
6 ** a copy of this software and associated documentation files (the
7 ** "Software"), to deal in the Software without restriction, including
8 ** without limitation the rights to use, copy, modify, merge, publish,
9 ** distribute, sublicense, and/or sell copies of the Software, and to
10 ** permit persons to whom the Software is furnished to do so, subject to
11 ** the following conditions:
12 **
13 ** The above copyright notice and this permission notice shall be
14 ** included in all copies or substantial portions of the Software.
15 **
16 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 **
24 ****************************************************************************/
25
26 #include "xlsxdrawinganchor_p.h"
27 #include "xlsxdrawing_p.h"
28 #include "xlsxmediafile_p.h"
29 #include "xlsxchart.h"
30 #include "xlsxworkbook.h"
31 #include "xlsxutility_p.h"
32
33 #include <QXmlStreamReader>
34 #include <QXmlStreamWriter>
35 #include <QBuffer>
36 #include <QDir>
37
38 namespace QXlsx {
39
40 /*
41 The vertices that define the position of a graphical object
42 within the worksheet in pixels.
43
44 +------------+------------+
45 | A | B |
46 +-----+------------+------------+
47 | |(x1,y1) | |
48 | 1 |(A1)._______|______ |
49 | | | | |
50 | | | | |
51 +-----+----| OBJECT |-----+
52 | | | | |
53 | 2 | |______________. |
54 | | | (B2)|
55 | | | (x2,y2)|
56 +---- +------------+------------+
57
58 Example of an object that covers some of the area from cell A1 to B2.
59
60 Based on the width and height of the object we need to calculate 8 vars:
61
62 col_start, row_start, col_end, row_end, x1, y1, x2, y2.
63
64 We also calculate the absolute x and y position of the top left vertex of
65 the object. This is required for images.
66
67 The width and height of the cells that the object occupies can be
68 variable and have to be taken into account.
69 */
70
71 //anchor
72
73 DrawingAnchor::DrawingAnchor(Drawing *drawing, ObjectType objectType)
74 :m_drawing(drawing), m_objectType(objectType)
75 {
76 m_drawing->anchors.append(this);
77 m_id = m_drawing->anchors.size();//must be unique in one drawing{x}.xml file.
78 }
79
80 DrawingAnchor::~DrawingAnchor()
81 {
82
83 }
84
85 void DrawingAnchor::setObjectPicture(const QImage &img)
86 {
87 QByteArray ba;
88 QBuffer buffer(&ba);
89 buffer.open(QIODevice::WriteOnly);
90 img.save(&buffer, "PNG");
91
92 m_pictureFile = QSharedPointer<MediaFile>(new MediaFile(ba, QStringLiteral("png"), QStringLiteral("image/png")));
93 m_drawing->workbook->addMediaFile(m_pictureFile);
94
95 m_objectType = Picture;
96 }
97
98 void DrawingAnchor::setObjectGraphicFrame(QSharedPointer<Chart> chart)
99 {
100 m_chartFile = chart;
101 m_drawing->workbook->addChartFile(chart);
102
103 m_objectType = GraphicFrame;
104 }
105
106 QPoint DrawingAnchor::loadXmlPos(QXmlStreamReader &reader)
107 {
108 Q_ASSERT(reader.name() == QLatin1String("pos"));
109
110 QPoint pos;
111 QXmlStreamAttributes attrs = reader.attributes();
112 pos.setX(attrs.value(QLatin1String("x")).toString().toInt());
113 pos.setY(attrs.value(QLatin1String("y")).toString().toInt());
114 return pos;
115 }
116
117 QSize DrawingAnchor::loadXmlExt(QXmlStreamReader &reader)
118 {
119 Q_ASSERT(reader.name() == QLatin1String("ext"));
120
121 QSize size;
122 QXmlStreamAttributes attrs = reader.attributes();
123 size.setWidth(attrs.value(QLatin1String("cx")).toString().toInt());
124 size.setHeight(attrs.value(QLatin1String("cy")).toString().toInt());
125 return size;
126 }
127
128 XlsxMarker DrawingAnchor::loadXmlMarker(QXmlStreamReader &reader, const QString &node)
129 {
130 Q_ASSERT(reader.name() == node);
131
132 int col = 0;
133 int colOffset = 0;
134 int row = 0;
135 int rowOffset = 0;
136 while (!reader.atEnd()) {
137 reader.readNextStartElement();
138 if (reader.tokenType() == QXmlStreamReader::StartElement) {
139 if (reader.name() == QLatin1String("col")) {
140 col = reader.readElementText().toInt();
141 } else if (reader.name() == QLatin1String("colOff")) {
142 colOffset = reader.readElementText().toInt();
143 } else if (reader.name() == QLatin1String("row")) {
144 row = reader.readElementText().toInt();
145 } else if (reader.name() == QLatin1String("rowOff")) {
146 rowOffset = reader.readElementText().toInt();
147 }
148 } else if (reader.tokenType() == QXmlStreamReader::EndElement
149 && reader.name() == node) {
150 break;
151 }
152 }
153
154 return XlsxMarker(row, col, rowOffset, colOffset);
155 }
156
157 void DrawingAnchor::loadXmlObject(QXmlStreamReader &reader)
158 {
159 if (reader.name() == QLatin1String("sp")) {
160 //Shape
161 m_objectType = Shape;
162 loadXmlObjectShape(reader);
163 } else if (reader.name() == QLatin1String("grpSp")) {
164 //Group Shape
165 m_objectType = GroupShape;
166 loadXmlObjectGroupShape(reader);
167 } else if (reader.name() == QLatin1String("graphicFrame")) {
168 //Graphic Frame
169 m_objectType = GraphicFrame;
170 loadXmlObjectGraphicFrame(reader);
171 } else if (reader.name() == QLatin1String("cxnSp")) {
172 //Connection Shape
173 m_objectType = ConnectionShape;
174 loadXmlObjectConnectionShape(reader);
175 } else if (reader.name() == QLatin1String("pic")) {
176 //Picture
177 m_objectType = Picture;
178 loadXmlObjectPicture(reader);
179 }
180 }
181
182 void DrawingAnchor::loadXmlObjectConnectionShape(QXmlStreamReader &reader)
183 {
184 Q_UNUSED(reader)
185 }
186
187 void DrawingAnchor::loadXmlObjectGraphicFrame(QXmlStreamReader &reader)
188 {
189 Q_ASSERT(reader.name() == QLatin1String("graphicFrame"));
190
191 while (!reader.atEnd()) {
192 reader.readNextStartElement();
193 if (reader.tokenType() == QXmlStreamReader::StartElement) {
194 if (reader.name() == QLatin1String("chart")) {
195 QString rId = reader.attributes().value(QLatin1String("r:id")).toString();
196 QString name = m_drawing->relationships()->getRelationshipById(rId).target;
197 QString path = QDir::cleanPath(splitPath(m_drawing->filePath())[0] + QLatin1String("/") + name);
198
199 bool exist = false;
200 QList<QSharedPointer<Chart> > cfs = m_drawing->workbook->chartFiles();
201 for (int i=0; i<cfs.size(); ++i) {
202 if (cfs[i]->filePath() == path) {
203 //already exist
204 exist = true;
205 m_chartFile = cfs[i];
206 }
207 }
208 if (!exist) {
209 m_chartFile = QSharedPointer<Chart> (new Chart(m_drawing->sheet, Chart::F_LoadFromExists));
210 m_chartFile->setFilePath(path);
211 m_drawing->workbook->addChartFile(m_chartFile);
212 }
213 }
214 } else if (reader.tokenType() == QXmlStreamReader::EndElement
215 && reader.name() == QLatin1String("graphicFrame")) {
216 break;
217 }
218 }
219
220 return;
221 }
222
223 void DrawingAnchor::loadXmlObjectGroupShape(QXmlStreamReader &reader)
224 {
225 Q_UNUSED(reader)
226 }
227
228 void DrawingAnchor::loadXmlObjectPicture(QXmlStreamReader &reader)
229 {
230 Q_ASSERT(reader.name() == QLatin1String("pic"));
231
232 while (!reader.atEnd()) {
233 reader.readNextStartElement();
234 if (reader.tokenType() == QXmlStreamReader::StartElement) {
235 if (reader.name() == QLatin1String("blip")) {
236 QString rId = reader.attributes().value(QLatin1String("r:embed")).toString();
237 QString name = m_drawing->relationships()->getRelationshipById(rId).target;
238 QString path = QDir::cleanPath(splitPath(m_drawing->filePath())[0] + QLatin1String("/") + name);
239
240 bool exist = false;
241 QList<QSharedPointer<MediaFile> > mfs = m_drawing->workbook->mediaFiles();
242 for (int i=0; i<mfs.size(); ++i) {
243 if (mfs[i]->fileName() == path) {
244 //already exist
245 exist = true;
246 m_pictureFile = mfs[i];
247 }
248 }
249 if (!exist) {
250 m_pictureFile = QSharedPointer<MediaFile> (new MediaFile(path));
251 m_drawing->workbook->addMediaFile(m_pictureFile, true);
252 }
253 }
254 } else if (reader.tokenType() == QXmlStreamReader::EndElement
255 && reader.name() == QLatin1String("pic")) {
256 break;
257 }
258 }
259
260 return;
261 }
262
263 void DrawingAnchor::loadXmlObjectShape(QXmlStreamReader &reader)
264 {
265 Q_UNUSED(reader)
266 }
267
268 void DrawingAnchor::saveXmlPos(QXmlStreamWriter &writer, const QPoint &pos) const
269 {
270 writer.writeEmptyElement(QStringLiteral("xdr:pos"));
271 writer.writeAttribute(QStringLiteral("x"), QString::number(pos.x()));
272 writer.writeAttribute(QStringLiteral("y"), QString::number(pos.y()));
273 }
274
275 void DrawingAnchor::saveXmlExt(QXmlStreamWriter &writer, const QSize &ext) const
276 {
277 writer.writeStartElement(QStringLiteral("xdr:ext"));
278 writer.writeAttribute(QStringLiteral("cx"), QString::number(ext.width()));
279 writer.writeAttribute(QStringLiteral("cy"), QString::number(ext.height()));
280 writer.writeEndElement(); //xdr:ext
281 }
282
283 void DrawingAnchor::saveXmlMarker(QXmlStreamWriter &writer, const XlsxMarker &marker, const QString &node) const
284 {
285 writer.writeStartElement(node); //xdr:from or xdr:to
286 writer.writeTextElement(QStringLiteral("xdr:col"), QString::number(marker.col()));
287 writer.writeTextElement(QStringLiteral("xdr:colOff"), QString::number(marker.colOff()));
288 writer.writeTextElement(QStringLiteral("xdr:row"), QString::number(marker.row()));
289 writer.writeTextElement(QStringLiteral("xdr:rowOff"), QString::number(marker.rowOff()));
290 writer.writeEndElement();
291 }
292
293 void DrawingAnchor::saveXmlObject(QXmlStreamWriter &writer) const
294 {
295 if (m_objectType == Picture)
296 saveXmlObjectPicture(writer);
297 else if (m_objectType == ConnectionShape)
298 saveXmlObjectConnectionShape(writer);
299 else if (m_objectType == GraphicFrame)
300 saveXmlObjectGraphicFrame(writer);
301 else if (m_objectType == GroupShape)
302 saveXmlObjectGroupShape(writer);
303 else if (m_objectType == Shape)
304 saveXmlObjectShape(writer);
305 }
306
307 void DrawingAnchor::saveXmlObjectConnectionShape(QXmlStreamWriter &writer) const
308 {
309 Q_UNUSED(writer)
310 }
311
312 void DrawingAnchor::saveXmlObjectGraphicFrame(QXmlStreamWriter &writer) const
313 {
314 writer.writeStartElement(QStringLiteral("xdr:graphicFrame"));
315 writer.writeAttribute(QStringLiteral("macro"), QString());
316
317 writer.writeStartElement(QStringLiteral("xdr:nvGraphicFramePr"));
318 writer.writeEmptyElement(QStringLiteral("xdr:cNvPr"));
319 writer.writeAttribute(QStringLiteral("id"), QString::number(m_id));
320 writer.writeAttribute(QStringLiteral("name"),QStringLiteral("Chart %1").arg(m_id));
321 writer.writeEmptyElement(QStringLiteral("xdr:cNvGraphicFramePr"));
322 writer.writeEndElement();//xdr:nvGraphicFramePr
323
324 writer.writeStartElement(QStringLiteral("xdr:xfrm"));
325 writer.writeEndElement(); //xdr:xfrm
326
327 writer.writeStartElement(QStringLiteral("a:graphic"));
328 writer.writeStartElement(QStringLiteral("a:graphicData"));
329 writer.writeAttribute(QStringLiteral("uri"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart"));
330
331 int idx = m_drawing->workbook->chartFiles().indexOf(m_chartFile);
332 m_drawing->relationships()->addDocumentRelationship(QStringLiteral("/chart"), QStringLiteral("../charts/chart%1.xml").arg(idx+1));
333
334 writer.writeEmptyElement(QStringLiteral("c:chart"));
335 writer.writeAttribute(QStringLiteral("xmlns:c"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart"));
336 writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
337 writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(m_drawing->relationships()->count()));
338
339 writer.writeEndElement(); //a:graphicData
340 writer.writeEndElement(); //a:graphic
341 writer.writeEndElement(); //xdr:graphicFrame
342 }
343
344 void DrawingAnchor::saveXmlObjectGroupShape(QXmlStreamWriter &writer) const
345 {
346 Q_UNUSED(writer)
347 }
348
349 void DrawingAnchor::saveXmlObjectPicture(QXmlStreamWriter &writer) const
350 {
351 Q_ASSERT(m_objectType == Picture && !m_pictureFile.isNull());
352
353 writer.writeStartElement(QStringLiteral("xdr:pic"));
354
355 writer.writeStartElement(QStringLiteral("xdr:nvPicPr"));
356 writer.writeEmptyElement(QStringLiteral("xdr:cNvPr"));
357 writer.writeAttribute(QStringLiteral("id"), QString::number(m_id));
358 writer.writeAttribute(QStringLiteral("name"), QStringLiteral("Picture %1").arg(m_id));
359
360 writer.writeStartElement(QStringLiteral("xdr:cNvPicPr"));
361 writer.writeEmptyElement(QStringLiteral("a:picLocks"));
362 writer.writeAttribute(QStringLiteral("noChangeAspect"), QStringLiteral("1"));
363 writer.writeEndElement(); //xdr:cNvPicPr
364
365 writer.writeEndElement(); //xdr:nvPicPr
366
367 m_drawing->relationships()->addDocumentRelationship(QStringLiteral("/image"), QStringLiteral("../media/image%1.%2")
368 .arg(m_pictureFile->index()+1)
369 .arg(m_pictureFile->suffix()));
370
371 writer.writeStartElement(QStringLiteral("xdr:blipFill"));
372 writer.writeEmptyElement(QStringLiteral("a:blip"));
373 writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
374 writer.writeAttribute(QStringLiteral("r:embed"), QStringLiteral("rId%1").arg(m_drawing->relationships()->count()));
375 writer.writeStartElement(QStringLiteral("a:stretch"));
376 writer.writeEmptyElement(QStringLiteral("a:fillRect"));
377 writer.writeEndElement(); //a:stretch
378 writer.writeEndElement();//xdr:blipFill
379
380 writer.writeStartElement(QStringLiteral("xdr:spPr"));
381
382 writer.writeStartElement(QStringLiteral("a:prstGeom"));
383 writer.writeAttribute(QStringLiteral("prst"), QStringLiteral("rect"));
384 writer.writeEmptyElement(QStringLiteral("a:avLst"));
385 writer.writeEndElement(); //a:prstGeom
386
387 writer.writeEndElement(); //xdr:spPr
388
389 writer.writeEndElement(); //xdr:pic
390 }
391
392 void DrawingAnchor::saveXmlObjectShape(QXmlStreamWriter &writer) const
393 {
394 Q_UNUSED(writer)
395 }
396
397 //absolute anchor
398
399 DrawingAbsoluteAnchor::DrawingAbsoluteAnchor(Drawing *drawing, ObjectType objectType)
400 :DrawingAnchor(drawing, objectType)
401 {
402
403 }
404
405 bool DrawingAbsoluteAnchor::loadFromXml(QXmlStreamReader &reader)
406 {
407 Q_ASSERT(reader.name() == QLatin1String("absoluteAnchor"));
408
409 while (!reader.atEnd()) {
410 reader.readNextStartElement();
411 if (reader.tokenType() == QXmlStreamReader::StartElement) {
412 if (reader.name() == QLatin1String("pos")) {
413 pos = loadXmlPos(reader);
414 } else if (reader.name() == QLatin1String("ext")) {
415 ext = loadXmlExt(reader);
416 } else {
417 loadXmlObject(reader);
418 }
419 } else if (reader.tokenType() == QXmlStreamReader::EndElement
420 && reader.name() == QLatin1String("absoluteAnchor")) {
421 break;
422 }
423 }
424 return true;
425 }
426
427 void DrawingAbsoluteAnchor::saveToXml(QXmlStreamWriter &writer) const
428 {
429 writer.writeStartElement(QStringLiteral("xdr:absoluteAnchor"));
430 saveXmlPos(writer, pos);
431 saveXmlExt(writer, ext);
432
433 saveXmlObject(writer);
434
435 writer.writeEmptyElement(QStringLiteral("xdr:clientData"));
436 writer.writeEndElement(); //xdr:absoluteAnchor
437 }
438
439 //one cell anchor
440
441 DrawingOneCellAnchor::DrawingOneCellAnchor(Drawing *drawing, ObjectType objectType)
442 :DrawingAnchor(drawing, objectType)
443 {
444
445 }
446
447 bool DrawingOneCellAnchor::loadFromXml(QXmlStreamReader &reader)
448 {
449 Q_ASSERT(reader.name() == QLatin1String("oneCellAnchor"));
450 while (!reader.atEnd()) {
451 reader.readNextStartElement();
452 if (reader.tokenType() == QXmlStreamReader::StartElement) {
453 if (reader.name() == QLatin1String("from")) {
454 from = loadXmlMarker(reader, QLatin1String("from"));
455 } else if (reader.name() == QLatin1String("ext")) {
456 ext = loadXmlExt(reader);
457 } else {
458 loadXmlObject(reader);
459 }
460 } else if (reader.tokenType() == QXmlStreamReader::EndElement
461 && reader.name() == QLatin1String("oneCellAnchor")) {
462 break;
463 }
464 }
465 return true;
466 }
467
468 void DrawingOneCellAnchor::saveToXml(QXmlStreamWriter &writer) const
469 {
470 writer.writeStartElement(QStringLiteral("xdr:oneCellAnchor"));
471
472 saveXmlMarker(writer, from, QStringLiteral("xdr:from"));
473 saveXmlExt(writer, ext);
474
475 saveXmlObject(writer);
476
477 writer.writeEmptyElement(QStringLiteral("xdr:clientData"));
478 writer.writeEndElement(); //xdr:oneCellAnchor
479 }
480
481 /*
482 Two cell anchor
483
484 This class specifies a two cell anchor placeholder for a group
485 , a shape, or a drawing element. It moves with
486 cells and its extents are in EMU units.
487 */
488 DrawingTwoCellAnchor::DrawingTwoCellAnchor(Drawing *drawing, ObjectType objectType)
489 :DrawingAnchor(drawing, objectType)
490 {
491
492 }
493
494 bool DrawingTwoCellAnchor::loadFromXml(QXmlStreamReader &reader)
495 {
496 Q_ASSERT(reader.name() == QLatin1String("twoCellAnchor"));
497 while (!reader.atEnd()) {
498 reader.readNextStartElement();
499 if (reader.tokenType() == QXmlStreamReader::StartElement) {
500 if (reader.name() == QLatin1String("from")) {
501 from = loadXmlMarker(reader, QLatin1String("from"));
502 } else if (reader.name() == QLatin1String("to")) {
503 to = loadXmlMarker(reader, QLatin1String("to"));
504 } else {
505 loadXmlObject(reader);
506 }
507 } else if (reader.tokenType() == QXmlStreamReader::EndElement
508 && reader.name() == QLatin1String("twoCellAnchor")) {
509 break;
510 }
511 }
512 return true;
513 }
514
515 void DrawingTwoCellAnchor::saveToXml(QXmlStreamWriter &writer) const
516 {
517 writer.writeStartElement(QStringLiteral("xdr:twoCellAnchor"));
518 writer.writeAttribute(QStringLiteral("editAs"), QStringLiteral("oneCell"));
519
520 saveXmlMarker(writer, from, QStringLiteral("xdr:from"));
521 saveXmlMarker(writer, to, QStringLiteral("xdr:to"));
522
523 saveXmlObject(writer);
524
525 writer.writeEmptyElement(QStringLiteral("xdr:clientData"));
526 writer.writeEndElement(); //xdr:twoCellAnchor
527 }
528
529 } // namespace QXlsx
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)