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