]> git.sesse.net Git - kdenlive/blob - src/titledocument.cpp
Fix compile
[kdenlive] / src / titledocument.cpp
1 /***************************************************************************
2                           titledocument.h  -  description
3                              -------------------
4     begin                : Feb 28 2008
5     copyright            : (C) 2008 by Marco Gittler
6     email                : g.marco@freenet.de
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17
18 #include "titledocument.h"
19
20 #include <KDebug>
21 #include <KTemporaryFile>
22 #include <kio/netaccess.h>
23 #include <KApplication>
24 #include <KLocale>
25 #include <KMessageBox>
26
27 #include <QGraphicsScene>
28 #include <QDomElement>
29 #include <QGraphicsItem>
30 #include <QGraphicsRectItem>
31 #include <QGraphicsTextItem>
32 #include <QGraphicsSvgItem>
33 #include <QFontInfo>
34 #include <QFile>
35 #include <QTextCursor>
36
37 #if QT_VERSION >= 0x040600
38 #include <QGraphicsEffect>
39 #include <QGraphicsBlurEffect>
40 #include <QGraphicsDropShadowEffect>
41 #endif
42
43 TitleDocument::TitleDocument()
44 {
45     m_scene = NULL;
46 }
47
48 void TitleDocument::setScene(QGraphicsScene* _scene, int width, int height)
49 {
50     m_scene = _scene;
51     m_width = width;
52     m_height = height;
53 }
54
55 QDomDocument TitleDocument::xml(QGraphicsRectItem* startv, QGraphicsRectItem* endv)
56 {
57     QDomDocument doc;
58
59     QDomElement main = doc.createElement("kdenlivetitle");
60     main.setAttribute("width", m_width);
61     main.setAttribute("height", m_height);
62     doc.appendChild(main);
63
64     foreach(QGraphicsItem* item, m_scene->items()) {
65         QDomElement e = doc.createElement("item");
66         QDomElement content = doc.createElement("content");
67         QFont font;
68         QGraphicsTextItem *t;
69
70         switch (item->type()) {
71         case 7:
72             e.setAttribute("type", "QGraphicsPixmapItem");
73             content.setAttribute("url", item->data(Qt::UserRole).toString());
74             break;
75         case 13:
76             e.setAttribute("type", "QGraphicsSvgItem");
77             content.setAttribute("url", item->data(Qt::UserRole).toString());
78             break;
79         case 3:
80             e.setAttribute("type", "QGraphicsRectItem");
81             content.setAttribute("rect", rectFToString(((QGraphicsRectItem*)item)->rect().normalized()));
82             content.setAttribute("pencolor", colorToString(((QGraphicsRectItem*)item)->pen().color()));
83             content.setAttribute("penwidth", ((QGraphicsRectItem*)item)->pen().width());
84             content.setAttribute("brushcolor", colorToString(((QGraphicsRectItem*)item)->brush().color()));
85             break;
86         case 8:
87             e.setAttribute("type", "QGraphicsTextItem");
88             t = static_cast<QGraphicsTextItem *>(item);
89             // Don't save empty text nodes
90             if (t->toPlainText().simplified().isEmpty()) continue;
91             //content.appendChild(doc.createTextNode(((QGraphicsTextItem*)item)->toHtml()));
92             content.appendChild(doc.createTextNode(t->toPlainText()));
93             font = t->font();
94             content.setAttribute("font", font.family());
95             content.setAttribute("font-weight", font.weight());
96             content.setAttribute("font-pixel-size", font.pixelSize());
97             content.setAttribute("font-italic", font.italic());
98             content.setAttribute("font-underline", font.underline());
99             content.setAttribute("font-color", colorToString(t->defaultTextColor()));
100
101             // Only save when necessary.
102             if (t->data(OriginXLeft).toInt() == AxisInverted) {
103                 content.setAttribute("kdenlive-axis-x-inverted", t->data(OriginXLeft).toInt());
104             }
105             if (t->data(OriginYTop).toInt() == AxisInverted) {
106                 content.setAttribute("kdenlive-axis-y-inverted", t->data(OriginYTop).toInt());
107             }
108             if (t->textWidth() != -1) {
109                 content.setAttribute("alignment", t->textCursor().blockFormat().alignment());
110             }
111             break;
112         default:
113             continue;
114         }
115
116         // position
117         QDomElement pos = doc.createElement("position");
118         pos.setAttribute("x", item->pos().x());
119         pos.setAttribute("y", item->pos().y());
120         QTransform transform = item->transform();
121         QDomElement tr = doc.createElement("transform");
122         tr.appendChild(doc.createTextNode(
123                            QString("%1,%2,%3,%4,%5,%6,%7,%8,%9").arg(
124                                transform.m11()).arg(transform.m12()).arg(transform.m13()).arg(transform.m21()).arg(transform.m22()).arg(transform.m23()).arg(transform.m31()).arg(transform.m32()).arg(transform.m33())
125                        )
126                       );
127         e.setAttribute("z-index", item->zValue());
128         pos.appendChild(tr);
129
130 #if QT_VERSION >= 0x040600
131         // effects
132         QGraphicsEffect *eff = item->graphicsEffect();
133         if (eff) {
134             QGraphicsBlurEffect *blur = static_cast <QGraphicsBlurEffect *>(eff);
135             QDomElement effect = doc.createElement("effect");
136             if (blur) {
137                 effect.setAttribute("type", "blur");
138                 effect.setAttribute("blurradius", blur->blurRadius());
139             } else {
140                 QGraphicsDropShadowEffect *shadow = static_cast <QGraphicsDropShadowEffect *>(eff);
141                 if (shadow) {
142                     effect.setAttribute("type", "shadow");
143                     effect.setAttribute("blurradius", shadow->blurRadius());
144                     effect.setAttribute("xoffset", shadow->xOffset());
145                     effect.setAttribute("yoffset", shadow->yOffset());
146                 }
147             }
148             e.appendChild(effect);
149         }
150 #endif
151
152         e.appendChild(pos);
153         e.appendChild(content);
154         if (item->zValue() > -1000) main.appendChild(e);
155     }
156     if (startv && endv) {
157         QDomElement endp = doc.createElement("endviewport");
158         QDomElement startp = doc.createElement("startviewport");
159         QRectF r(endv->pos().x(), endv->pos().y(), endv->rect().width(), endv->rect().height());
160         endp.setAttribute("rect", rectFToString(r));
161         QRectF r2(startv->pos().x(), startv->pos().y(), startv->rect().width(), startv->rect().height());
162         startp.setAttribute("rect", rectFToString(r2));
163
164         main.appendChild(startp);
165         main.appendChild(endp);
166     }
167     QDomElement backgr = doc.createElement("background");
168     QColor color = getBackgroundColor();
169     backgr.setAttribute("color", colorToString(color));
170     main.appendChild(backgr);
171
172     return doc;
173 }
174
175 /** \brief Get the background color (incl. alpha) from the document, if possibly
176   * \returns The background color of the document, inclusive alpha. If none found, returns (0,0,0,0) */
177 QColor TitleDocument::getBackgroundColor()
178 {
179     QColor color(0, 0, 0, 0);
180     if (m_scene) {
181         QList<QGraphicsItem *> items = m_scene->items();
182         for (int i = 0; i < items.size(); i++) {
183             if (items.at(i)->zValue() == -1100) {
184                 color = ((QGraphicsRectItem *)items.at(i))->brush().color();
185                 return color;
186             }
187         }
188     }
189     return color;
190 }
191
192
193 bool TitleDocument::saveDocument(const KUrl& url, QGraphicsRectItem* startv, QGraphicsRectItem* endv, int out)
194 {
195     if (!m_scene)
196         return false;
197
198     QDomDocument doc = xml(startv, endv);
199     doc.documentElement().setAttribute("out", out);
200     KTemporaryFile tmpfile;
201     if (!tmpfile.open()) {
202         kWarning() << "/////  CANNOT CREATE TMP FILE in: " << tmpfile.fileName();
203         return false;
204     }
205     QFile xmlf(tmpfile.fileName());
206     xmlf.open(QIODevice::WriteOnly);
207     xmlf.write(doc.toString().toUtf8());
208     if (xmlf.error() != QFile::NoError) {
209         xmlf.close();
210         return false;
211     }
212     xmlf.close();
213     return KIO::NetAccess::upload(tmpfile.fileName(), url, 0);
214 }
215
216 int TitleDocument::loadFromXml(QDomDocument doc, QGraphicsRectItem* startv, QGraphicsRectItem* endv, int *out)
217 {
218     QDomNodeList titles = doc.elementsByTagName("kdenlivetitle");
219     //TODO: Check if the opened title size is equal to project size, otherwise warn user and rescale
220     if (doc.documentElement().hasAttribute("width") && doc.documentElement().hasAttribute("height")) {
221         int doc_width = doc.documentElement().attribute("width").toInt();
222         int doc_height = doc.documentElement().attribute("height").toInt();
223         if (doc_width != m_width || doc_height != m_height) {
224             KMessageBox::information(kapp->activeWindow(), i18n("This title clip was created with a different frame size."), i18n("Title Profile"));
225             //TODO: convert using QTransform
226             m_width = doc_width;
227             m_height = doc_height;
228         }
229     }
230     //TODO: get default title duration instead of hardcoded one
231     if (doc.documentElement().hasAttribute("out"))
232         *out = doc.documentElement().attribute("out").toInt();
233     else
234         *out = 125;
235
236     int maxZValue = 0;
237     if (titles.size()) {
238
239         QDomNodeList items = titles.item(0).childNodes();
240         for (int i = 0; i < items.count(); i++) {
241             QGraphicsItem *gitem = NULL;
242             kDebug() << items.item(i).attributes().namedItem("type").nodeValue();
243             int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
244             if (zValue > -1000) {
245                 if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsTextItem") {
246                     QDomNamedNodeMap txtProperties = items.item(i).namedItem("content").attributes();
247                     QFont font(txtProperties.namedItem("font").nodeValue());
248
249                     QDomNode node = txtProperties.namedItem("font-bold");
250                     if (!node.isNull()) {
251                         // Old: Bold/Not bold.
252                         font.setBold(node.nodeValue().toInt());
253                     } else {
254                         // New: Font weight (QFont::)
255                         font.setWeight(txtProperties.namedItem("font-weight").nodeValue().toInt());
256                     }
257                     //font.setBold(txtProperties.namedItem("font-bold").nodeValue().toInt());
258                     font.setItalic(txtProperties.namedItem("font-italic").nodeValue().toInt());
259                     font.setUnderline(txtProperties.namedItem("font-underline").nodeValue().toInt());
260                     // Older Kdenlive version did not store pixel size but point size
261                     if (txtProperties.namedItem("font-pixel-size").isNull()) {
262                         KMessageBox::information(kapp->activeWindow(), i18n("Some of your text clips were saved with size in points, which means different sizes on different displays. They will be converted to pixel size, making them portable, but you could have to adjust their size."), i18n("Text Clips Updated"));
263                         QFont f2;
264                         f2.setPointSize(txtProperties.namedItem("font-size").nodeValue().toInt());
265                         font.setPixelSize(QFontInfo(f2).pixelSize());
266                     } else
267                         font.setPixelSize(txtProperties.namedItem("font-pixel-size").nodeValue().toInt());
268                     QColor col(stringToColor(txtProperties.namedItem("font-color").nodeValue()));
269                     QGraphicsTextItem *txt = m_scene->addText(items.item(i).namedItem("content").firstChild().nodeValue(), font);
270                     txt->setDefaultTextColor(col);
271                     txt->setTextInteractionFlags(Qt::NoTextInteraction);
272                     if (txtProperties.namedItem("alignment").isNull() == false) {
273                         txt->setTextWidth(txt->boundingRect().width());
274                         QTextCursor cur = txt->textCursor();
275                         QTextBlockFormat format = cur.blockFormat();
276                         format.setAlignment((Qt::Alignment) txtProperties.namedItem("alignment").nodeValue().toInt());
277                         cur.select(QTextCursor::Document);
278                         cur.setBlockFormat(format);
279                         txt->setTextCursor(cur);
280                         cur.clearSelection();
281                         txt->setTextCursor(cur);
282                     }
283
284                     if (!txtProperties.namedItem("kdenlive-axis-x-inverted").isNull()) {
285                         txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt());
286                     }
287                     if (!txtProperties.namedItem("kdenlive-axis-y-inverted").isNull()) {
288                         txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt());
289                     }
290
291                     gitem = txt;
292                 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsRectItem") {
293                     QString rect = items.item(i).namedItem("content").attributes().namedItem("rect").nodeValue();
294                     QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
295                     QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
296                     double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
297                     QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
298                     gitem = rec;
299                 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
300                     QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
301                     QPixmap pix(url);
302                     QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
303                     rec->setData(Qt::UserRole, url);
304                     gitem = rec;
305                 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
306                     QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
307                     QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
308                     m_scene->addItem(rec);
309                     rec->setData(Qt::UserRole, url);
310                     gitem = rec;
311                 }
312             }
313             //pos and transform
314             if (gitem) {
315                 QPointF p(items.item(i).namedItem("position").attributes().namedItem("x").nodeValue().toDouble(),
316                           items.item(i).namedItem("position").attributes().namedItem("y").nodeValue().toDouble());
317                 gitem->setPos(p);
318                 gitem->setTransform(stringToTransform(items.item(i).namedItem("position").firstChild().firstChild().nodeValue()));
319                 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
320                 if (zValue > maxZValue) maxZValue = zValue;
321                 gitem->setZValue(zValue);
322                 gitem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
323
324 #if QT_VERSION >= 0x040600
325                 // effects
326                 QDomNode eff = items.item(i).namedItem("effect");
327                 if (!eff.isNull()) {
328                     QDomElement e = eff.toElement();
329                     if (e.attribute("type") == "blur") {
330                         QGraphicsBlurEffect *blur = new QGraphicsBlurEffect();
331                         blur->setBlurRadius(e.attribute("blurradius").toInt());
332                         gitem->setGraphicsEffect(blur);
333                     } else if (e.attribute("type") == "shadow") {
334                         QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect();
335                         shadow->setBlurRadius(e.attribute("blurradius").toInt());
336                         shadow->setOffset(e.attribute("xoffset").toInt(), e.attribute("yoffset").toInt());
337                         gitem->setGraphicsEffect(shadow);
338                     }
339                 }
340 #endif
341             }
342
343             if (items.item(i).nodeName() == "background") {
344                 kDebug() << items.item(i).attributes().namedItem("color").nodeValue();
345                 QColor color = QColor(stringToColor(items.item(i).attributes().namedItem("color").nodeValue()));
346                 //color.setAlpha(items.item(i).attributes().namedItem("alpha").nodeValue().toInt());
347                 QList<QGraphicsItem *> items = m_scene->items();
348                 for (int i = 0; i < items.size(); i++) {
349                     if (items.at(i)->zValue() == -1100) {
350                         ((QGraphicsRectItem *)items.at(i))->setBrush(QBrush(color));
351                         break;
352                     }
353                 }
354             } else if (items.item(i).nodeName() == "startviewport" && startv) {
355                 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
356                 QRectF r = stringToRect(rect);
357                 startv->setRect(0, 0, r.width(), r.height());
358                 startv->setPos(r.topLeft());
359             } else if (items.item(i).nodeName() == "endviewport" && endv) {
360                 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
361                 QRectF r = stringToRect(rect);
362                 endv->setRect(0, 0, r.width(), r.height());
363                 endv->setPos(r.topLeft());
364             }
365         }
366     }
367     return maxZValue;
368 }
369
370 QString TitleDocument::colorToString(const QColor& c)
371 {
372     QString ret = "%1,%2,%3,%4";
373     ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
374     return ret;
375 }
376
377 QString TitleDocument::rectFToString(const QRectF& c)
378 {
379     QString ret = "%1,%2,%3,%4";
380     ret = ret.arg(c.left()).arg(c.top()).arg(c.width()).arg(c.height());
381     return ret;
382 }
383
384 QRectF TitleDocument::stringToRect(const QString & s)
385 {
386
387     QStringList l = s.split(',');
388     if (l.size() < 4)
389         return QRectF();
390     return QRectF(l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(), l.at(3).toDouble()).normalized();
391 }
392
393 QColor TitleDocument::stringToColor(const QString & s)
394 {
395     QStringList l = s.split(',');
396     if (l.size() < 4)
397         return QColor();
398     return QColor(l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt(), l.at(3).toInt());;
399 }
400 QTransform TitleDocument::stringToTransform(const QString& s)
401 {
402     QStringList l = s.split(',');
403     if (l.size() < 9)
404         return QTransform();
405     return QTransform(
406                l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(),
407                l.at(3).toDouble(), l.at(4).toDouble(), l.at(5).toDouble(),
408                l.at(6).toDouble(), l.at(7).toDouble(), l.at(8).toDouble()
409            );
410 }
411
412 int TitleDocument::frameWidth() const
413 {
414     return m_width;
415 }
416
417 int TitleDocument::frameHeight() const
418 {
419     return m_height;
420 }
421
422