]> git.sesse.net Git - kdenlive/blob - src/titledocument.cpp
Update title widget ui
[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
38 TitleDocument::TitleDocument()
39 {
40     m_scene = NULL;
41 }
42
43 void TitleDocument::setScene(QGraphicsScene* _scene, int width, int height)
44 {
45     m_scene = _scene;
46     m_width = width;
47     m_height = height;
48 }
49
50 QDomDocument TitleDocument::xml(QGraphicsRectItem* startv, QGraphicsRectItem* endv)
51 {
52     QDomDocument doc;
53
54     QDomElement main = doc.createElement("kdenlivetitle");
55     main.setAttribute("width", m_width);
56     main.setAttribute("height", m_height);
57     doc.appendChild(main);
58
59     foreach(QGraphicsItem* item, m_scene->items()) {
60         QDomElement e = doc.createElement("item");
61         QDomElement content = doc.createElement("content");
62         QFont font;
63         QGraphicsTextItem *t;
64
65         switch (item->type()) {
66         case 7:
67             e.setAttribute("type", "QGraphicsPixmapItem");
68             content.setAttribute("url", item->data(Qt::UserRole).toString());
69             break;
70         case 13:
71             e.setAttribute("type", "QGraphicsSvgItem");
72             content.setAttribute("url", item->data(Qt::UserRole).toString());
73             break;
74         case 3:
75             e.setAttribute("type", "QGraphicsRectItem");
76             content.setAttribute("rect", rectFToString(((QGraphicsRectItem*)item)->rect().normalized()));
77             content.setAttribute("pencolor", colorToString(((QGraphicsRectItem*)item)->pen().color()));
78             content.setAttribute("penwidth", ((QGraphicsRectItem*)item)->pen().width());
79             content.setAttribute("brushcolor", colorToString(((QGraphicsRectItem*)item)->brush().color()));
80             break;
81         case 8:
82             e.setAttribute("type", "QGraphicsTextItem");
83             t = static_cast<QGraphicsTextItem *>(item);
84             // Don't save empty text nodes
85             if (t->toPlainText().simplified().isEmpty()) continue;
86             //content.appendChild(doc.createTextNode(((QGraphicsTextItem*)item)->toHtml()));
87             content.appendChild(doc.createTextNode(t->toPlainText()));
88             font = t->font();
89             content.setAttribute("font", font.family());
90             content.setAttribute("font-weight", font.weight());
91             content.setAttribute("font-pixel-size", font.pixelSize());
92             content.setAttribute("font-italic", font.italic());
93             content.setAttribute("font-underline", font.underline());
94             content.setAttribute("font-color", colorToString(t->defaultTextColor()));
95
96             // Only save when necessary.
97             if (t->data(OriginXLeft).toInt() == AxisInverted) {
98                 content.setAttribute("kdenlive-axis-x-inverted", t->data(OriginXLeft).toInt());
99             }
100             if (t->data(OriginYTop).toInt() == AxisInverted) {
101                 content.setAttribute("kdenlive-axis-y-inverted", t->data(OriginYTop).toInt());
102             }
103             if (t->textWidth() != -1) {
104                 content.setAttribute("alignment", t->textCursor().blockFormat().alignment());
105             }
106             break;
107         default:
108             continue;
109         }
110         QDomElement pos = doc.createElement("position");
111         pos.setAttribute("x", item->pos().x());
112         pos.setAttribute("y", item->pos().y());
113         QTransform transform = item->transform();
114         QDomElement tr = doc.createElement("transform");
115         tr.appendChild(doc.createTextNode(
116                            QString("%1,%2,%3,%4,%5,%6,%7,%8,%9").arg(
117                                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())
118                        )
119                       );
120         e.setAttribute("z-index", item->zValue());
121         pos.appendChild(tr);
122
123
124         e.appendChild(pos);
125         e.appendChild(content);
126         if (item->zValue() > -1000) main.appendChild(e);
127     }
128     if (startv && endv) {
129         QDomElement endp = doc.createElement("endviewport");
130         QDomElement startp = doc.createElement("startviewport");
131         QRectF r(endv->pos().x(), endv->pos().y(), endv->rect().width(), endv->rect().height());
132         endp.setAttribute("rect", rectFToString(r));
133         QRectF r2(startv->pos().x(), startv->pos().y(), startv->rect().width(), startv->rect().height());
134         startp.setAttribute("rect", rectFToString(r2));
135
136         main.appendChild(startp);
137         main.appendChild(endp);
138     }
139     QDomElement backgr = doc.createElement("background");
140     QColor color = getBackgroundColor();
141     backgr.setAttribute("color", colorToString(color));
142     main.appendChild(backgr);
143
144     return doc;
145 }
146
147 /** \brief Get the background color (incl. alpha) from the document, if possibly
148   * \returns The background color of the document, inclusive alpha. If none found, returns (0,0,0,0) */
149 QColor TitleDocument::getBackgroundColor()
150 {
151     QColor color(0, 0, 0, 0);
152     if (m_scene) {
153         QList<QGraphicsItem *> items = m_scene->items();
154         for (int i = 0; i < items.size(); i++) {
155             if (items.at(i)->zValue() == -1100) {
156                 color = ((QGraphicsRectItem *)items.at(i))->brush().color();
157                 return color;
158             }
159         }
160     }
161     return color;
162 }
163
164
165 bool TitleDocument::saveDocument(const KUrl& url, QGraphicsRectItem* startv, QGraphicsRectItem* endv, int out)
166 {
167     if (!m_scene)
168         return false;
169
170     QDomDocument doc = xml(startv, endv);
171     doc.documentElement().setAttribute("out", out);
172     KTemporaryFile tmpfile;
173     if (!tmpfile.open()) {
174         kWarning() << "/////  CANNOT CREATE TMP FILE in: " << tmpfile.fileName();
175         return false;
176     }
177     QFile xmlf(tmpfile.fileName());
178     xmlf.open(QIODevice::WriteOnly);
179     xmlf.write(doc.toString().toUtf8());
180     if (xmlf.error() != QFile::NoError) {
181         xmlf.close();
182         return false;
183     }
184     xmlf.close();
185     return KIO::NetAccess::upload(tmpfile.fileName(), url, 0);
186 }
187
188 int TitleDocument::loadFromXml(QDomDocument doc, QGraphicsRectItem* startv, QGraphicsRectItem* endv, int *out)
189 {
190     QDomNodeList titles = doc.elementsByTagName("kdenlivetitle");
191     //TODO: Check if the opened title size is equal to project size, otherwise warn user and rescale
192     if (doc.documentElement().hasAttribute("width") && doc.documentElement().hasAttribute("height")) {
193         int doc_width = doc.documentElement().attribute("width").toInt();
194         int doc_height = doc.documentElement().attribute("height").toInt();
195         if (doc_width != m_width || doc_height != m_height) {
196             KMessageBox::information(kapp->activeWindow(), i18n("This title clip was created with a different frame size."), i18n("Title Profile"));
197             //TODO: convert using QTransform
198             m_width = doc_width;
199             m_height = doc_height;
200         }
201     }
202     //TODO: get default title duration instead of hardcoded one
203     if (doc.documentElement().hasAttribute("out"))
204         *out = doc.documentElement().attribute("out").toInt();
205     else
206         *out = 125;
207
208     int maxZValue = 0;
209     if (titles.size()) {
210
211         QDomNodeList items = titles.item(0).childNodes();
212         for (int i = 0; i < items.count(); i++) {
213             QGraphicsItem *gitem = NULL;
214             kDebug() << items.item(i).attributes().namedItem("type").nodeValue();
215             int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
216             if (zValue > -1000) {
217                 if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsTextItem") {
218                     QDomNamedNodeMap txtProperties = items.item(i).namedItem("content").attributes();
219                     QFont font(txtProperties.namedItem("font").nodeValue());
220
221                     QDomNode node = txtProperties.namedItem("font-bold");
222                     if (!node.isNull()) {
223                         // Old: Bold/Not bold.
224                         font.setBold(node.nodeValue().toInt());
225                     } else {
226                         // New: Font weight (QFont::)
227                         font.setWeight(txtProperties.namedItem("font-weight").nodeValue().toInt());
228                     }
229                     //font.setBold(txtProperties.namedItem("font-bold").nodeValue().toInt());
230                     font.setItalic(txtProperties.namedItem("font-italic").nodeValue().toInt());
231                     font.setUnderline(txtProperties.namedItem("font-underline").nodeValue().toInt());
232                     // Older Kdenlive version did not store pixel size but point size
233                     if (txtProperties.namedItem("font-pixel-size").isNull()) {
234                         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"));
235                         QFont f2;
236                         f2.setPointSize(txtProperties.namedItem("font-size").nodeValue().toInt());
237                         font.setPixelSize(QFontInfo(f2).pixelSize());
238                     } else
239                         font.setPixelSize(txtProperties.namedItem("font-pixel-size").nodeValue().toInt());
240                     QColor col(stringToColor(txtProperties.namedItem("font-color").nodeValue()));
241                     QGraphicsTextItem *txt = m_scene->addText(items.item(i).namedItem("content").firstChild().nodeValue(), font);
242                     txt->setDefaultTextColor(col);
243                     txt->setTextInteractionFlags(Qt::NoTextInteraction);
244                     if (txtProperties.namedItem("alignment").isNull() == false) {
245                         txt->setTextWidth(txt->boundingRect().width());
246                         QTextCursor cur = txt->textCursor();
247                         QTextBlockFormat format = cur.blockFormat();
248                         format.setAlignment((Qt::Alignment) txtProperties.namedItem("alignment").nodeValue().toInt());
249                         cur.select(QTextCursor::Document);
250                         cur.setBlockFormat(format);
251                         txt->setTextCursor(cur);
252                         cur.clearSelection();
253                         txt->setTextCursor(cur);
254                     }
255
256                     if (!txtProperties.namedItem("kdenlive-axis-x-inverted").isNull()) {
257                         txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt());
258                     }
259                     if (!txtProperties.namedItem("kdenlive-axis-y-inverted").isNull()) {
260                         txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt());
261                     }
262
263                     gitem = txt;
264                 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsRectItem") {
265                     QString rect = items.item(i).namedItem("content").attributes().namedItem("rect").nodeValue();
266                     QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
267                     QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
268                     double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
269                     QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
270                     gitem = rec;
271                 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
272                     QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
273                     QPixmap pix(url);
274                     QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
275                     rec->setData(Qt::UserRole, url);
276                     gitem = rec;
277                 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
278                     QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
279                     QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
280                     m_scene->addItem(rec);
281                     rec->setData(Qt::UserRole, url);
282                     gitem = rec;
283                 }
284             }
285             //pos and transform
286             if (gitem) {
287                 QPointF p(items.item(i).namedItem("position").attributes().namedItem("x").nodeValue().toDouble(),
288                           items.item(i).namedItem("position").attributes().namedItem("y").nodeValue().toDouble());
289                 gitem->setPos(p);
290                 gitem->setTransform(stringToTransform(items.item(i).namedItem("position").firstChild().firstChild().nodeValue()));
291                 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
292                 if (zValue > maxZValue) maxZValue = zValue;
293                 gitem->setZValue(zValue);
294                 gitem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
295             }
296             if (items.item(i).nodeName() == "background") {
297                 kDebug() << items.item(i).attributes().namedItem("color").nodeValue();
298                 QColor color = QColor(stringToColor(items.item(i).attributes().namedItem("color").nodeValue()));
299                 //color.setAlpha(items.item(i).attributes().namedItem("alpha").nodeValue().toInt());
300                 QList<QGraphicsItem *> items = m_scene->items();
301                 for (int i = 0; i < items.size(); i++) {
302                     if (items.at(i)->zValue() == -1100) {
303                         ((QGraphicsRectItem *)items.at(i))->setBrush(QBrush(color));
304                         break;
305                     }
306                 }
307             } else if (items.item(i).nodeName() == "startviewport" && startv) {
308                 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
309                 QRectF r = stringToRect(rect);
310                 startv->setRect(0, 0, r.width(), r.height());
311                 startv->setPos(r.topLeft());
312             } else if (items.item(i).nodeName() == "endviewport" && endv) {
313                 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
314                 QRectF r = stringToRect(rect);
315                 endv->setRect(0, 0, r.width(), r.height());
316                 endv->setPos(r.topLeft());
317             }
318         }
319     }
320     return maxZValue;
321 }
322
323 QString TitleDocument::colorToString(const QColor& c)
324 {
325     QString ret = "%1,%2,%3,%4";
326     ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
327     return ret;
328 }
329
330 QString TitleDocument::rectFToString(const QRectF& c)
331 {
332     QString ret = "%1,%2,%3,%4";
333     ret = ret.arg(c.left()).arg(c.top()).arg(c.width()).arg(c.height());
334     return ret;
335 }
336
337 QRectF TitleDocument::stringToRect(const QString & s)
338 {
339
340     QStringList l = s.split(',');
341     if (l.size() < 4)
342         return QRectF();
343     return QRectF(l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(), l.at(3).toDouble()).normalized();
344 }
345
346 QColor TitleDocument::stringToColor(const QString & s)
347 {
348     QStringList l = s.split(',');
349     if (l.size() < 4)
350         return QColor();
351     return QColor(l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt(), l.at(3).toInt());;
352 }
353 QTransform TitleDocument::stringToTransform(const QString& s)
354 {
355     QStringList l = s.split(',');
356     if (l.size() < 9)
357         return QTransform();
358     return QTransform(
359                l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(),
360                l.at(3).toDouble(), l.at(4).toDouble(), l.at(5).toDouble(),
361                l.at(6).toDouble(), l.at(7).toDouble(), l.at(8).toDouble()
362            );
363 }
364
365 int TitleDocument::frameWidth() const
366 {
367     return m_width;
368 }
369
370 int TitleDocument::frameHeight() const
371 {
372     return m_height;
373 }
374
375