1 /* This file is part of the KDE project
2 Copyright (C) 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org>
3
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.
8
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.
13
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.
18 */
19 #include "ODrawClient.h"
20
21 #include <QDebug>
22 #include <QColor>
23 #include <KoGenStyles.h>
24 #include <KoXmlWriter.h>
25 #include <KoEmbeddedDocumentSaver.h>
26 #include <KoShapeSavingContext.h>
27 #include <KoTextWriter.h>
28 #include <KoStyleManager.h>
29 #include <KoTextDocument.h>
30
31 #include "sheet.h"
32 #include "workbook.h"
33
34 #ifndef __GNUC__
35 #define __PRETTY_FUNCTION__ __FUNCTION__
36 #endif /* __PRETTY_FUNCTION__ only exists in gnu c++ */
37
ODrawClient(Swinder::Sheet * sheet)38 ODrawClient::ODrawClient(Swinder::Sheet* sheet)
39 : m_sheet(sheet), m_zIndex(0), m_styleManager(0)
40 {
41 }
42
offset(unsigned long dimension,unsigned long offset,qreal factor)43 static qreal offset( unsigned long dimension, unsigned long offset, qreal factor ) {
44 return (float)dimension * (float)offset / factor;
45 }
46
columnWidth(Swinder::Sheet * sheet,unsigned long col)47 static qreal columnWidth(Swinder::Sheet* sheet, unsigned long col) {
48 if( sheet->column(col, false) )
49 return sheet->column(col)->width();
50
51 return sheet->defaultColWidth();
52 }
53
rowHeight(Swinder::Sheet * sheet,unsigned long row)54 static qreal rowHeight(Swinder::Sheet* sheet, unsigned long row) {
55 if( sheet->row(row, false) )
56 return sheet->row(row)->height();
57
58 return sheet->defaultRowHeight();
59 }
60
getRect(const MSO::OfficeArtClientAnchor & clientAnchor)61 QRectF ODrawClient::getRect(const MSO::OfficeArtClientAnchor& clientAnchor)
62 {
63 const MSO::XlsOfficeArtClientAnchor* anchor = clientAnchor.anon.get<MSO::XlsOfficeArtClientAnchor>();
64 if (anchor) {
65 QRectF r;
66 qreal colWidth = columnWidth(m_sheet, anchor->colL);
67 r.setLeft(offset(colWidth, anchor->dxL, 1024));
68 if (anchor->colR == anchor->colL) {
69 r.setRight(offset(colWidth, anchor->dxR, 1024));
70 } else {
71 qreal width = colWidth - r.left();
72 for (int col = anchor->colL + 1; col < anchor->colR; ++col) {
73 width += columnWidth(m_sheet, col);
74 }
75 width += offset(columnWidth(m_sheet, anchor->colR), anchor->dxR, 1024);
76 r.setWidth(width);
77 }
78 qreal rowHgt = rowHeight(m_sheet, anchor->rwT);
79 r.setTop(offset(rowHgt, anchor->dyT, 256));
80 if (anchor->rwT == anchor->rwB) {
81 r.setBottom(offset(rowHgt, anchor->dyB, 256));
82 } else {
83 qreal height = rowHgt - r.top();
84 for (int row = anchor->rwT + 1; row < anchor->rwB; ++row) {
85 height += rowHeight(m_sheet, row);
86 }
87 height += offset(rowHeight(m_sheet, anchor->rwB), anchor->dyB, 256);
88 r.setHeight(height);
89 }
90 return r;
91 } else {
92 qDebug() << "Invalid client anchor!";
93 }
94 return QRectF();
95 }
96
getReserveRect(void)97 QRectF ODrawClient::getReserveRect(void)
98 {
99 //NOTE: No XLS test files at the moment.
100 return QRectF();
101 }
102
getGlobalRect(const MSO::OfficeArtClientAnchor & clientAnchor)103 QRectF ODrawClient::getGlobalRect(const MSO::OfficeArtClientAnchor &clientAnchor)
104 {
105 const MSO::XlsOfficeArtClientAnchor* anchor = clientAnchor.anon.get<MSO::XlsOfficeArtClientAnchor>();
106 if (!anchor) return QRectF();
107 QRectF r = getRect(clientAnchor);
108 qreal x = 0, y = 0;
109 for (int row = 0; row < anchor->rwT; row++) {
110 y += rowHeight(m_sheet, row);
111 }
112 for (int col = 0; col < anchor->colL; col++) {
113 x += columnWidth(m_sheet, col);
114 }
115 return r.adjusted(x, y, x, y);
116 }
117
118
getPicturePath(const quint32 pib)119 QString ODrawClient::getPicturePath(const quint32 pib)
120 {
121 quint32 offset = 0;
122 if (!m_sheet->workbook()->officeArtDggContainer()) {
123 return QString();
124 }
125
126 QByteArray rgbUid = getRgbUid(*m_sheet->workbook()->officeArtDggContainer(), pib, offset);
127
128 QString fileName;
129 if (rgbUid.isEmpty()) {
130 qDebug() << "Object in blipStore with pib: " << pib << "was not found.";
131 }else {
132 fileName = m_sheet->workbook()->pictureName(rgbUid);
133 }
134
135 if (!fileName.isEmpty()){
136 return "Pictures/" + fileName;
137 }
138 return QString();
139 }
140
processRectangleAsTextBox(const MSO::OfficeArtClientData & cd)141 bool ODrawClient::processRectangleAsTextBox(const MSO::OfficeArtClientData& cd)
142 {
143 Q_UNUSED(cd);
144 return false;
145 }
146
onlyClientData(const MSO::OfficeArtClientData & o)147 bool ODrawClient::onlyClientData(const MSO::OfficeArtClientData &o)
148 {
149 Q_UNUSED(o);
150 qDebug() << "NOT YET IMPLEMENTED" << __PRETTY_FUNCTION__;
151 return !m_shapeText.text().isEmpty();
152 }
153
processClientData(const MSO::OfficeArtClientTextBox * ct,const MSO::OfficeArtClientData & o,Writer & out)154 void ODrawClient::processClientData(const MSO::OfficeArtClientTextBox *ct,
155 const MSO::OfficeArtClientData &o, Writer &out)
156 {
157 Q_UNUSED(ct);
158 Q_UNUSED(o);
159 if (m_shapeText.richText()) { // rich-text
160 KoTextDocument doc(m_shapeText.richText());
161 Q_ASSERT(!doc.styleManager());
162 Q_ASSERT(m_styleManager);
163 doc.setStyleManager(m_styleManager);
164
165 KoEmbeddedDocumentSaver embeddedSaver;
166 KoShapeSavingContext context(out.xml, out.styles, embeddedSaver);
167 KoTextWriter textWriter(context);
168 textWriter.write(m_shapeText.richText(), 0);
169
170 doc.setStyleManager(0);
171 } else { // plain-text
172 QStringList lines = m_shapeText.text().split(QRegExp("[\n\r]"));
173 foreach (const QString& line, lines) {
174 out.xml.startElement("text:p", false);
175 int pos = 0;
176 while (pos < line.length()) {
177 int idx = line.indexOf(QRegExp("[^ ]"), pos);
178 if (idx == -1) idx = line.length();
179 int cnt = idx - pos;
180 if (cnt > 1) {
181 out.xml.startElement("text:s");
182 out.xml.addAttribute("text:c", cnt);
183 out.xml.endElement();
184 pos += cnt; cnt = 0;
185 }
186 int endPos = qMax(line.length()-1, line.indexOf(' ', pos+cnt));
187 out.xml.addTextNode(line.mid(pos, endPos - pos + 1));
188 pos = endPos + 1;
189 }
190 out.xml.endElement();
191 }
192 }
193 }
194
processClientTextBox(const MSO::OfficeArtClientTextBox & ct,const MSO::OfficeArtClientData * cd,Writer & out)195 void ODrawClient::processClientTextBox(const MSO::OfficeArtClientTextBox &ct,
196 const MSO::OfficeArtClientData *cd, Writer &out)
197 {
198 Q_UNUSED(ct);
199 Q_UNUSED(cd);
200 Q_UNUSED(out);
201 qDebug() << "NOT YET IMPLEMENTED" << __PRETTY_FUNCTION__;
202 }
203
createGraphicStyle(const MSO::OfficeArtClientTextBox * ct,const MSO::OfficeArtClientData * cd,const DrawStyle & ds,Writer & out)204 KoGenStyle ODrawClient::createGraphicStyle(const MSO::OfficeArtClientTextBox *ct,
205 const MSO::OfficeArtClientData *cd,
206 const DrawStyle& ds,
207 Writer &out)
208 {
209 Q_UNUSED(ct);
210 Q_UNUSED(cd);
211 Q_UNUSED(ds);
212 KoGenStyle style = KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic");
213 if (!m_shapeText.text().isEmpty()) {
214 switch (m_shapeText.hAlign()) {
215 case Swinder::TxORecord::Left:
216 style.addProperty("draw:textarea-horizontal-align", "left");
217 break;
218 case Swinder::TxORecord::Centered:
219 style.addProperty("draw:textarea-horizontal-align", "center");
220 break;
221 case Swinder::TxORecord::Right:
222 style.addProperty("draw:textarea-horizontal-align", "right");
223 break;
224 case Swinder::TxORecord::Justified: // FIXME: Not supported
225 case Swinder::TxORecord::Distributed: // FIXME: Not supported
226 default:
227 ;
228 }
229 switch (m_shapeText.vAlign()) {
230 case Swinder::TxORecord::Top:
231 style.addProperty("draw:textarea-vertical-align", "top");
232 break;
233 case Swinder::TxORecord::VCentered:
234 style.addProperty("draw:textarea-vertical-align", "middle");
235 break;
236 case Swinder::TxORecord::Bottom:
237 style.addProperty("draw:textarea-vertical-align", "bottom");
238 break;
239 case Swinder::TxORecord::VJustified: // FIXME: Not supported
240 case Swinder::TxORecord::VDistributed: // FIXME: Not supported
241 default:
242 ;
243 }
244 }
245 //draw:textarea-horizontal-align="justify" draw:textarea-vertical-align="top"
246 style.setAutoStyleInStylesDotXml(out.stylesxml);
247 return style;
248 }
249
addTextStyles(const MSO::OfficeArtClientTextBox * clientTextbox,const MSO::OfficeArtClientData * clientData,KoGenStyle & style,Writer & out)250 void ODrawClient::addTextStyles(const MSO::OfficeArtClientTextBox *clientTextbox,
251 const MSO::OfficeArtClientData *clientData,
252 KoGenStyle &style, Writer &out)
253 {
254 Q_UNUSED(clientTextbox);
255 Q_UNUSED(clientData);
256 const QString styleName = out.styles.insert(style);
257 out.xml.addAttribute("draw:style-name", styleName);
258
259 setZIndexAttribute(out);
260 }
261
toQColor(const MSO::OfficeArtCOLORREF & c)262 QColor ODrawClient::toQColor(const MSO::OfficeArtCOLORREF &c)
263 {
264 if (c.fSchemeIndex) {
265 return m_sheet->workbook()->color(c.red);
266 }
267 return QColor(c.red, c.green, c.blue);
268 }
269
formatPos(qreal v)270 QString ODrawClient::formatPos(qreal v)
271 {
272 return QString::number(v, 'f', 11) + "pt";
273 }
274
getOfficeArtDggContainer()275 const MSO::OfficeArtDggContainer* ODrawClient::getOfficeArtDggContainer()
276 {
277 return m_sheet->workbook()->officeArtDggContainer();
278 }
279
getMasterShapeContainer(quint32 spid)280 const MSO::OfficeArtSpContainer* ODrawClient::getMasterShapeContainer(quint32 spid)
281 {
282 Q_UNUSED(spid);
283 //TODO: locate the OfficeArtSpContainer with shapeProp/spid == spid
284 MSO::OfficeArtSpContainer* sp = nullptr;
285 return sp;
286 }
287
setShapeText(const Swinder::TxORecord & text)288 void ODrawClient::setShapeText(const Swinder::TxORecord &text)
289 {
290 m_shapeText = text;
291 }
292
setZIndexAttribute(Writer & out)293 void ODrawClient::setZIndexAttribute(Writer& out)
294 {
295 out.xml.addAttribute("draw:z-index", m_zIndex);
296 m_zIndex++;
297 }
298
setStyleManager(KoStyleManager * styleManager)299 void ODrawClient::setStyleManager(KoStyleManager* styleManager)
300 {
301 m_styleManager = styleManager;
302 }
303
styleManager() const304 KoStyleManager* ODrawClient::styleManager() const
305 {
306 return m_styleManager;
307 }
308