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