1
/* This file is part of the KDE project
2
Copyright (C) 2010 KO GmbH <jos.van.den.oever@kogmbh.com>
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License as published by the Free Software Foundation; either
7
version 2 of the License, or (at your option) any later version.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to
16
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
* Boston, MA 02110-1301, USA.
20
#include "ODrawToOdf.h"
21
#include "drawstyle.h"
22
#include <KoXmlWriter.h>
23
#include <QtCore/QtDebug>
24
#include <QtGui/QColor>
29
* Return the bounding rectangle for this object.
32
ODrawToOdf::getRect(const OfficeArtFSPGR &r)
34
return QRect(r.xLeft, r.yTop, r.xRight - r.xLeft, r.yBottom - r.yTop);
37
void ODrawToOdf::processDrawing(const OfficeArtSpgrContainerFileBlock& of,
40
if (of.anon.is<OfficeArtSpgrContainer>()) {
41
processGroup(*of.anon.get<OfficeArtSpgrContainer>(), out);
42
} else { // OfficeArtSpContainer
43
processDrawingObject(*of.anon.get<OfficeArtSpContainer>(), out);
46
void ODrawToOdf::processGroup(const MSO::OfficeArtSpgrContainer& o, Writer& out)
48
if (o.rgfb.size() < 2) return;
49
out.xml.startElement("draw:g");
50
/* if the first OfficeArtSpContainer has a clientAnchor,
51
a new coordinate system is introduced.
53
const OfficeArtSpContainer* first
54
= o.rgfb[0].anon.get<OfficeArtSpContainer>();
56
if (first && first->shapeGroup && first->clientAnchor) {
57
oldCoords = client->getRect(*first->clientAnchor);
59
if (oldCoords.isValid()) {
60
QRect newCoords = getRect(*first->shapeGroup);
61
Writer transformedOut = out.transform(oldCoords, newCoords);
62
for (int i = 1; i < o.rgfb.size(); ++i) {
63
processDrawing(o.rgfb[i], transformedOut);
66
for (int i = 1; i < o.rgfb.size(); ++i) {
67
processDrawing(o.rgfb[i], out);
70
out.xml.endElement(); // draw:g
72
void ODrawToOdf::addGraphicStyleToDrawElement(Writer& out,
73
const OfficeArtSpContainer& o)
76
const OfficeArtDggContainer* drawingGroup = 0;
78
style = client->createGraphicStyle(o.clientTextbox.data(),
79
o.clientData.data(), out);
80
drawingGroup = client->getOfficeArtDggContainer();
82
if (!drawingGroup) return;
84
const DrawStyle ds(*drawingGroup, &o);
85
defineGraphicProperties(style, ds);
87
client->addTextStyles(o.clientTextbox.data(),
88
o.clientData.data(), out, style);
93
const char* dashses[11] = {
94
"", "Dash_20_2", "Dash_20_3", "Dash_20_2", "Dash_20_2", "Dash_20_2",
95
"Dash_20_4", "Dash_20_6", "Dash_20_5", "Dash_20_7", "Dash_20_8"
97
const char* arrowHeads[6] = {
98
"", "msArrowEnd_20_5", "msArrowStealthEnd_20_5", "msArrowDiamondEnd_20_5",
99
"msArrowOvalEnd_20_5", "msArrowOpenEnd_20_5"
101
QString format(double v) {
102
static const QString f("%1");
103
static const QString e("");
104
static const QRegExp r("\\.?0+$");
105
return f.arg(v, 0, 'f').replace(r, e);
107
QString pt(double v) {
108
static const QString pt("pt");
109
return format(v) + pt;
111
QString percent(double v) {
112
return format(v) + '%';
115
void ODrawToOdf::defineGraphicProperties(KoGenStyle& style, const DrawStyle& ds,
116
const QString& listStyle)
118
const KoGenStyle::PropertyType gt = KoGenStyle::GraphicType;
119
// dr3d:ambient-color
121
// dr3d:backface-culling
125
// dr3d:diffuse-color
126
// dr3d:edge-rounding
127
// dr3d:edge-rounding-mode
128
// dr3d:emissive-color
130
// dr3d:horizontal-segments
131
// dr3d:lighting-mode
132
// dr3d:normals-direction
136
// dr3d:specular-color
137
// dr3d:texture-filter
138
// dr3d:texture-generation-mode-x
139
// dr3d:texture-generation-mode-y
142
// dr3d:vertical-segments
143
// draw:auto-grow-height
144
// draw:auto-grow-width
146
// draw:caption-angle
147
// draw:caption-angle-type
148
// draw:caption-escape
149
// draw:caption-escape-direction
150
// draw:caption-fit-line-length
152
// draw:caption-line-length
154
// draw:color-inversion
157
// draw:decimal-places
159
// draw:end-line-spacing-horizontal
160
// draw:end-line-spacing-vertical
161
// draw:fill ("bitmap", "gradient", "hatch", "none" or "solid")
162
qint32 fillType = ds.fillType();
164
style.addProperty("draw:fill", getFillType(fillType), gt);
166
style.addProperty("draw:fill", "none", gt);
169
// only set the color if the fill type is 'solid' because OOo ignores
170
// fill='none' if the color is set
171
if (fillType == 0 && client) {
172
style.addProperty("draw:fill-color",
173
client->toQColor(ds.fillColor()).name(), gt);
175
// draw:fill-gradient-name
176
// draw:fill-hatch-name
177
// draw:fill-hatch-solid
178
// draw:fill-image-height
179
// draw:fill-image-name
180
quint32 fillBlip = ds.fillBlip();
181
QString fillImagePath;
183
fillImagePath = client->getPicturePath(fillBlip);
185
if (!fillImagePath.isEmpty()) {
186
style.addProperty("draw:fill-image-name",
187
"fillImage" + QString::number(fillBlip), gt);
189
// draw:fill-image-ref-point
190
// draw:fill-image-ref-point-x
191
// draw:fill-image-ref-point-y
192
// draw:fill-image-width
193
// draw:fit-to-contour
195
// draw:frame-display-border
196
// draw:frame-display-scrollbar
197
// draw:frame-margin-horizontal
198
// draw:frame-margin-vertical
200
// draw:gradient-step-count
202
// draw:guide-distance
203
// draw:guide-overhang
204
// draw:image-opacity
205
// draw:line-distance
208
quint32 lineEndArrowhead = ds.lineEndArrowhead();
209
if (lineEndArrowhead > 0 && lineEndArrowhead < 6) {
210
style.addProperty("draw:marker-end", arrowHeads[lineEndArrowhead], gt);
212
// draw:marker-end-center
213
// draw:marker-end-width
214
qreal lineWidthPt = ds.lineWidth() / 12700.;
215
style.addProperty("draw:marker-end-width",
216
pt(lineWidthPt*4*(1+ds.lineEndArrowWidth())), gt);
218
quint32 lineStartArrowhead = ds.lineStartArrowhead();
219
if (lineStartArrowhead > 0 && lineStartArrowhead < 6) {
220
style.addProperty("draw:marker-start", arrowHeads[lineStartArrowhead],
223
// draw:marker-start-center
224
// draw:marker-start-width
225
style.addProperty("draw:marker-start-width",
226
pt(lineWidthPt*4*(1+ds.lineStartArrowWidth())), gt);
227
// draw:measure-align
228
// draw:measure-vertical-align
229
// draw:ole-draw-aspect
235
// draw:secondary-fill-color
238
// draw:shadow-offset-x
239
style.addProperty("draw:shadow-offset-x", pt(ds.shadowOffsetX()/12700.),gt);
240
// draw:shadow-offset-y
241
style.addProperty("draw:shadow-offset-y", pt(ds.shadowOffsetY()/12700.),gt);
242
// draw:shadow-opacity
243
float shadowOpacity = toQReal(ds.shadowOpacity());
244
style.addProperty("draw:shadow-opacity", percent(100*shadowOpacity), gt);
247
// draw:start-line-spacing-horizontal
248
// draw:start-line-spacing-vertical
249
// draw:stroke ('dash', 'none' or 'solid')
250
quint32 lineDashing = ds.lineDashing();
251
// OOo interprets solid line with with 0 as hairline, so if
252
// width == 0, stroke *must* be none to avoid OOo from
254
if (lineWidthPt == 0) {
255
style.addProperty("draw:stroke", "none", gt);
256
} else if (ds.fLine() || ds.fNoLineDrawDash()) {
257
if (lineDashing > 0 && lineDashing < 11) {
258
style.addProperty("draw:stroke", "dash", gt);
260
style.addProperty("draw:stroke", "solid", gt);
263
style.addProperty("draw:stroke", "none", gt);
265
// draw:stroke-dash from 2.3.8.17 lineDashing
266
if (lineDashing > 0 && lineDashing < 11) {
267
style.addProperty("draw:stroke-dash", dashses[lineDashing], gt);
269
// draw:stroke-dash-names
270
// draw:stroke-linejoin
272
// draw:textarea-horizontal-align
273
// draw:textarea-vertical-align
274
// draw:tile-repeat-offset
276
// draw:visible-area-height
277
// draw:visible-area-left
278
// draw:visible-area-top
279
// draw:visible-area-width
280
// draw:wrap-influence-on-position
281
// fo:background-color
303
// style:border-line-width
304
// style:border-line-width-bottom
305
// style:border-line-width-left
306
// style:border-line-width-right
307
// style:border-line-width-top
309
// style:flow-with-text
310
// style:horizontal-pos
311
// style:horizontal-rel
313
// style:number-wrapped-paragraphs
314
// style:overflow-behavior
315
// style:print-content
322
// style:vertical-pos
323
// style:vertical-rel
325
// style:wrap-contour
326
// style:wrap-contour-mode
327
// style:wrap-dynamic-treshold
330
// svg:stroke-color from 2.3.8.1 lineColor
332
style.addProperty("svg:stroke-color",
333
client->toQColor(ds.lineColor()).name(), gt);
335
// svg:stroke-opacity from 2.3.8.2 lineOpacity
336
style.addProperty("svg:stroke-opacity",
337
percent(100.0 * ds.lineOpacity() / 0x10000), gt);
338
// svg:stroke-width from 2.3.8.14 lineWidth
339
style.addProperty("svg:stroke-width", pt(lineWidthPt), gt);
343
// text:anchor-page-number
346
// text:animation-delay
347
// text:animation-direction
348
// text:animation-repeat
349
// text:animation-start-inside
350
// text:animation-steps
351
// text:animation-stop-inside
353
/* associate with a text:list-style element */
354
if (!listStyle.isNull()) {
355
style.addAttribute("style:list-style-name", listStyle);
358
const char* getFillType(quint32 fillType)
361
case 2: // msofillTexture
362
case 3: // msofillPicture
364
case 4: // msofillShade
365
case 5: // msofillShadeCenter
366
case 6: // msofillShadeShape
367
case 7: // msofillShadeScale
368
case 8: // msofillShadeTitle
370
case 1: // msofillPattern
372
case 9: // msofillBackground
374
case 0: // msofillSolid