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