1 /***************************************************************************
2 titledocument.h - description
5 copyright : (C) 2008 by Marco Gittler
6 email : g.marco@freenet.de
7 ***************************************************************************/
9 /***************************************************************************
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. *
16 ***************************************************************************/
18 #include "titledocument.h"
21 #include <KTemporaryFile>
22 #include <kio/netaccess.h>
23 #include <KApplication>
25 #include <KMessageBox>
27 #include <QGraphicsScene>
28 #include <QDomElement>
29 #include <QGraphicsItem>
30 #include <QGraphicsRectItem>
31 #include <QGraphicsTextItem>
32 #include <QGraphicsSvgItem>
35 #include <QTextCursor>
38 TitleDocument::TitleDocument()
43 void TitleDocument::setScene(QGraphicsScene* _scene)
48 QDomDocument TitleDocument::xml(QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv)
52 QDomElement main = doc.createElement("kdenlivetitle");
53 doc.appendChild(main);
55 foreach(QGraphicsItem* item, m_scene->items()) {
56 QDomElement e = doc.createElement("item");
57 QDomElement content = doc.createElement("content");
61 switch (item->type()) {
63 e.setAttribute("type", "QGraphicsPixmapItem");
64 content.setAttribute("url", item->data(Qt::UserRole).toString());
67 e.setAttribute("type", "QGraphicsSvgItem");
68 content.setAttribute("url", item->data(Qt::UserRole).toString());
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()));
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()));
85 content.setAttribute("font", font.family());
86 content.setAttribute("font-weight", font.weight());
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()));
92 // Only save when necessary.
93 if (t->data(OriginXLeft).toInt() == AxisInverted) {
94 content.setAttribute("kdenlive-axis-x-inverted", t->data(OriginXLeft).toInt());
96 if (t->data(OriginYTop).toInt() == AxisInverted) {
97 content.setAttribute("kdenlive-axis-y-inverted", t->data(OriginYTop).toInt());
99 if (t->textWidth() != -1) {
100 content.setAttribute("alignment", t->textCursor().blockFormat().alignment());
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())
116 e.setAttribute("z-index", item->zValue());
121 e.appendChild(content);
122 if (item->zValue() > -1100) main.appendChild(e);
124 if (startv && endv) {
125 QDomElement endp = doc.createElement("endviewport");
126 QDomElement startp = doc.createElement("startviewport");
127 endp.setAttribute("x", endv->data(0).toString());
128 endp.setAttribute("y", endv->data(1).toString());
129 endp.setAttribute("size", endv->data(2).toString());
130 endp.setAttribute("rect", rectFToString(endv->boundingRect()));
132 startp.setAttribute("x", startv->data(0).toString());
133 startp.setAttribute("y", startv->data(1).toString());
134 startp.setAttribute("size", startv->data(2).toString());
135 startp.setAttribute("rect", rectFToString(startv->boundingRect()));
137 startp.setAttribute("z-index", startv->zValue());
138 endp.setAttribute("z-index", endv->zValue());
139 main.appendChild(startp);
140 main.appendChild(endp);
142 QDomElement backgr = doc.createElement("background");
143 QColor color = getBackgroundColor();
144 backgr.setAttribute("color", colorToString(color));
145 main.appendChild(backgr);
150 /** \brief Get the background color (incl. alpha) from the document, if possibly
151 * \returns The background color of the document, inclusive alpha. If none found, returns (0,0,0,0) */
152 QColor TitleDocument::getBackgroundColor()
154 QColor color(0, 0, 0, 0);
156 QList<QGraphicsItem *> items = m_scene->items();
157 for (int i = 0; i < items.size(); i++) {
158 if (items.at(i)->zValue() == -1100) {
159 color = ((QGraphicsRectItem *)items.at(i))->brush().color();
168 bool TitleDocument::saveDocument(const KUrl& url, QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv, double out)
173 QDomDocument doc = xml(startv, endv);
174 doc.documentElement().setAttribute("out", out);
175 KTemporaryFile tmpfile;
176 if (!tmpfile.open()) {
177 kWarning() << "///// CANNOT CREATE TMP FILE in: " << tmpfile.fileName();
180 QFile xmlf(tmpfile.fileName());
181 xmlf.open(QIODevice::WriteOnly);
182 xmlf.write(doc.toString().toUtf8());
183 if (xmlf.error() != QFile::NoError) {
188 return KIO::NetAccess::upload(tmpfile.fileName(), url, 0);
191 int TitleDocument::loadDocument(const KUrl& url, QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv, double *out)
198 if (KIO::NetAccess::download(url, tmpfile, 0)) {
200 if (file.open(QIODevice::ReadOnly)) {
201 doc.setContent(&file, false);
205 KIO::NetAccess::removeTempFile(tmpfile);
206 return loadFromXml(doc, startv, endv, out);
211 int TitleDocument::loadFromXml(QDomDocument doc, QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv, double *out)
213 QDomNodeList titles = doc.elementsByTagName("kdenlivetitle");
215 //TODO: get default title duration instead of hardcoded one
216 if (doc.documentElement().hasAttribute("out"))
217 *out = doc.documentElement().attribute("out").toDouble();
224 QDomNodeList items = titles.item(0).childNodes();
225 for (int i = 0; i < items.count(); i++) {
226 QGraphicsItem *gitem = NULL;
227 kDebug() << items.item(i).attributes().namedItem("type").nodeValue();
228 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
229 if (zValue > -1000) {
230 if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsTextItem") {
231 QDomNamedNodeMap txtProperties = items.item(i).namedItem("content").attributes();
232 QFont font(txtProperties.namedItem("font").nodeValue());
234 QDomNode node = txtProperties.namedItem("font-bold");
235 if (!node.isNull()) {
236 // Old: Bold/Not bold.
237 font.setBold(node.nodeValue().toInt());
239 // New: Font weight (QFont::)
240 font.setWeight(txtProperties.namedItem("font-weight").nodeValue().toInt());
242 //font.setBold(txtProperties.namedItem("font-bold").nodeValue().toInt());
243 font.setItalic(txtProperties.namedItem("font-italic").nodeValue().toInt());
244 font.setUnderline(txtProperties.namedItem("font-underline").nodeValue().toInt());
245 // Older Kdenlive version did not store pixel size but point size
246 if (txtProperties.namedItem("font-pixel-size").isNull()) {
247 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"));
249 f2.setPointSize(txtProperties.namedItem("font-size").nodeValue().toInt());
250 font.setPixelSize(QFontInfo(f2).pixelSize());
252 font.setPixelSize(txtProperties.namedItem("font-pixel-size").nodeValue().toInt());
253 QColor col(stringToColor(txtProperties.namedItem("font-color").nodeValue()));
254 QGraphicsTextItem *txt = m_scene->addText(items.item(i).namedItem("content").firstChild().nodeValue(), font);
255 txt->setDefaultTextColor(col);
256 txt->setTextInteractionFlags(Qt::NoTextInteraction);
257 if (txtProperties.namedItem("alignment").isNull() == false) {
258 txt->setTextWidth(txt->boundingRect().width());
259 QTextCursor cur = txt->textCursor();
260 QTextBlockFormat format = cur.blockFormat();
261 format.setAlignment((Qt::Alignment) txtProperties.namedItem("alignment").nodeValue().toInt());
262 cur.select(QTextCursor::Document);
263 cur.setBlockFormat(format);
264 txt->setTextCursor(cur);
265 cur.clearSelection();
266 txt->setTextCursor(cur);
269 if (!txtProperties.namedItem("kdenlive-axis-x-inverted").isNull()) {
270 txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt());
272 if (!txtProperties.namedItem("kdenlive-axis-y-inverted").isNull()) {
273 txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt());
277 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsRectItem") {
278 QString rect = items.item(i).namedItem("content").attributes().namedItem("rect").nodeValue();
279 QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
280 QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
281 double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
282 QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
284 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
285 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
287 QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
288 rec->setData(Qt::UserRole, url);
290 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
291 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
292 QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
293 m_scene->addItem(rec);
294 rec->setData(Qt::UserRole, url);
300 QPointF p(items.item(i).namedItem("position").attributes().namedItem("x").nodeValue().toDouble(),
301 items.item(i).namedItem("position").attributes().namedItem("y").nodeValue().toDouble());
303 gitem->setTransform(stringToTransform(items.item(i).namedItem("position").firstChild().firstChild().nodeValue()));
304 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
305 if (zValue > maxZValue) maxZValue = zValue;
306 gitem->setZValue(zValue);
307 gitem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
309 if (items.item(i).nodeName() == "background") {
310 kDebug() << items.item(i).attributes().namedItem("color").nodeValue();
311 QColor color = QColor(stringToColor(items.item(i).attributes().namedItem("color").nodeValue()));
312 //color.setAlpha(items.item(i).attributes().namedItem("alpha").nodeValue().toInt());
313 QList<QGraphicsItem *> items = m_scene->items();
314 for (int i = 0; i < items.size(); i++) {
315 if (items.at(i)->zValue() == -1100) {
316 ((QGraphicsRectItem *)items.at(i))->setBrush(QBrush(color));
320 } else if (items.item(i).nodeName() == "startviewport" && startv) {
321 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
322 startv->setPolygon(stringToRect(rect));
323 int x = items.item(i).attributes().namedItem("x").nodeValue().toInt();
324 int y = items.item(i).attributes().namedItem("y").nodeValue().toInt();
325 int size = items.item(i).attributes().namedItem("size").nodeValue().toInt();
326 startv->setData(0, x);
327 startv->setData(1, y);
328 startv->setData(2, size);
330 } else if (items.item(i).nodeName() == "endviewport" && endv) {
331 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
332 endv->setPolygon(stringToRect(rect));
333 int x = items.item(i).attributes().namedItem("x").nodeValue().toInt();
334 int y = items.item(i).attributes().namedItem("y").nodeValue().toInt();
335 int size = items.item(i).attributes().namedItem("size").nodeValue().toInt();
338 endv->setData(2, size);
345 QString TitleDocument::colorToString(const QColor& c)
347 QString ret = "%1,%2,%3,%4";
348 ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
352 QString TitleDocument::rectFToString(const QRectF& c)
354 QString ret = "%1,%2,%3,%4";
355 ret = ret.arg(c.left()).arg(c.top()).arg(c.width()).arg(c.height());
359 QRectF TitleDocument::stringToRect(const QString & s)
362 QStringList l = s.split(',');
365 return QRectF(l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(), l.at(3).toDouble()).normalized();
368 QColor TitleDocument::stringToColor(const QString & s)
370 QStringList l = s.split(',');
373 return QColor(l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt(), l.at(3).toInt());;
375 QTransform TitleDocument::stringToTransform(const QString& s)
377 QStringList l = s.split(',');
381 l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(),
382 l.at(3).toDouble(), l.at(4).toDouble(), l.at(5).toDouble(),
383 l.at(6).toDouble(), l.at(7).toDouble(), l.at(8).toDouble()