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, int width, int height)
50 QDomDocument TitleDocument::xml(QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv)
54 QDomElement main = doc.createElement("kdenlivetitle");
55 main.setAttribute("width", m_width);
56 main.setAttribute("height", m_height);
57 doc.appendChild(main);
59 foreach(QGraphicsItem* item, m_scene->items()) {
60 QDomElement e = doc.createElement("item");
61 QDomElement content = doc.createElement("content");
65 switch (item->type()) {
67 e.setAttribute("type", "QGraphicsPixmapItem");
68 content.setAttribute("url", item->data(Qt::UserRole).toString());
71 e.setAttribute("type", "QGraphicsSvgItem");
72 content.setAttribute("url", item->data(Qt::UserRole).toString());
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()));
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()));
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()));
96 // Only save when necessary.
97 if (t->data(OriginXLeft).toInt() == AxisInverted) {
98 content.setAttribute("kdenlive-axis-x-inverted", t->data(OriginXLeft).toInt());
100 if (t->data(OriginYTop).toInt() == AxisInverted) {
101 content.setAttribute("kdenlive-axis-y-inverted", t->data(OriginYTop).toInt());
103 if (t->textWidth() != -1) {
104 content.setAttribute("alignment", t->textCursor().blockFormat().alignment());
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())
120 e.setAttribute("z-index", item->zValue());
125 e.appendChild(content);
126 if (item->zValue() > -1100) main.appendChild(e);
128 if (startv && endv) {
129 QDomElement endp = doc.createElement("endviewport");
130 QDomElement startp = doc.createElement("startviewport");
131 endp.setAttribute("x", endv->data(0).toString());
132 endp.setAttribute("y", endv->data(1).toString());
133 endp.setAttribute("size", endv->data(2).toString());
134 endp.setAttribute("rect", rectFToString(endv->boundingRect()));
136 startp.setAttribute("x", startv->data(0).toString());
137 startp.setAttribute("y", startv->data(1).toString());
138 startp.setAttribute("size", startv->data(2).toString());
139 startp.setAttribute("rect", rectFToString(startv->boundingRect()));
141 startp.setAttribute("z-index", startv->zValue());
142 endp.setAttribute("z-index", endv->zValue());
143 main.appendChild(startp);
144 main.appendChild(endp);
146 QDomElement backgr = doc.createElement("background");
147 QColor color = getBackgroundColor();
148 backgr.setAttribute("color", colorToString(color));
149 main.appendChild(backgr);
154 /** \brief Get the background color (incl. alpha) from the document, if possibly
155 * \returns The background color of the document, inclusive alpha. If none found, returns (0,0,0,0) */
156 QColor TitleDocument::getBackgroundColor()
158 QColor color(0, 0, 0, 0);
160 QList<QGraphicsItem *> items = m_scene->items();
161 for (int i = 0; i < items.size(); i++) {
162 if (items.at(i)->zValue() == -1100) {
163 color = ((QGraphicsRectItem *)items.at(i))->brush().color();
172 bool TitleDocument::saveDocument(const KUrl& url, QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv, double out)
177 QDomDocument doc = xml(startv, endv);
178 doc.documentElement().setAttribute("out", out);
179 KTemporaryFile tmpfile;
180 if (!tmpfile.open()) {
181 kWarning() << "///// CANNOT CREATE TMP FILE in: " << tmpfile.fileName();
184 QFile xmlf(tmpfile.fileName());
185 xmlf.open(QIODevice::WriteOnly);
186 xmlf.write(doc.toString().toUtf8());
187 if (xmlf.error() != QFile::NoError) {
192 return KIO::NetAccess::upload(tmpfile.fileName(), url, 0);
195 int TitleDocument::loadDocument(const KUrl& url, QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv, double *out)
202 if (KIO::NetAccess::download(url, tmpfile, 0)) {
204 if (file.open(QIODevice::ReadOnly)) {
205 doc.setContent(&file, false);
209 KIO::NetAccess::removeTempFile(tmpfile);
210 return loadFromXml(doc, startv, endv, out);
215 int TitleDocument::loadFromXml(QDomDocument doc, QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv, double *out)
217 QDomNodeList titles = doc.elementsByTagName("kdenlivetitle");
218 //TODO: Check if the opened title size is equal to project size, otherwise warn user and rescale
219 //TODO: get default title duration instead of hardcoded one
220 if (doc.documentElement().hasAttribute("out"))
221 *out = doc.documentElement().attribute("out").toDouble();
228 QDomNodeList items = titles.item(0).childNodes();
229 for (int i = 0; i < items.count(); i++) {
230 QGraphicsItem *gitem = NULL;
231 kDebug() << items.item(i).attributes().namedItem("type").nodeValue();
232 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
233 if (zValue > -1000) {
234 if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsTextItem") {
235 QDomNamedNodeMap txtProperties = items.item(i).namedItem("content").attributes();
236 QFont font(txtProperties.namedItem("font").nodeValue());
238 QDomNode node = txtProperties.namedItem("font-bold");
239 if (!node.isNull()) {
240 // Old: Bold/Not bold.
241 font.setBold(node.nodeValue().toInt());
243 // New: Font weight (QFont::)
244 font.setWeight(txtProperties.namedItem("font-weight").nodeValue().toInt());
246 //font.setBold(txtProperties.namedItem("font-bold").nodeValue().toInt());
247 font.setItalic(txtProperties.namedItem("font-italic").nodeValue().toInt());
248 font.setUnderline(txtProperties.namedItem("font-underline").nodeValue().toInt());
249 // Older Kdenlive version did not store pixel size but point size
250 if (txtProperties.namedItem("font-pixel-size").isNull()) {
251 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"));
253 f2.setPointSize(txtProperties.namedItem("font-size").nodeValue().toInt());
254 font.setPixelSize(QFontInfo(f2).pixelSize());
256 font.setPixelSize(txtProperties.namedItem("font-pixel-size").nodeValue().toInt());
257 QColor col(stringToColor(txtProperties.namedItem("font-color").nodeValue()));
258 QGraphicsTextItem *txt = m_scene->addText(items.item(i).namedItem("content").firstChild().nodeValue(), font);
259 txt->setDefaultTextColor(col);
260 txt->setTextInteractionFlags(Qt::NoTextInteraction);
261 if (txtProperties.namedItem("alignment").isNull() == false) {
262 txt->setTextWidth(txt->boundingRect().width());
263 QTextCursor cur = txt->textCursor();
264 QTextBlockFormat format = cur.blockFormat();
265 format.setAlignment((Qt::Alignment) txtProperties.namedItem("alignment").nodeValue().toInt());
266 cur.select(QTextCursor::Document);
267 cur.setBlockFormat(format);
268 txt->setTextCursor(cur);
269 cur.clearSelection();
270 txt->setTextCursor(cur);
273 if (!txtProperties.namedItem("kdenlive-axis-x-inverted").isNull()) {
274 txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt());
276 if (!txtProperties.namedItem("kdenlive-axis-y-inverted").isNull()) {
277 txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt());
281 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsRectItem") {
282 QString rect = items.item(i).namedItem("content").attributes().namedItem("rect").nodeValue();
283 QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
284 QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
285 double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
286 QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
288 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
289 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
291 QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
292 rec->setData(Qt::UserRole, url);
294 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
295 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
296 QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
297 m_scene->addItem(rec);
298 rec->setData(Qt::UserRole, url);
304 QPointF p(items.item(i).namedItem("position").attributes().namedItem("x").nodeValue().toDouble(),
305 items.item(i).namedItem("position").attributes().namedItem("y").nodeValue().toDouble());
307 gitem->setTransform(stringToTransform(items.item(i).namedItem("position").firstChild().firstChild().nodeValue()));
308 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
309 if (zValue > maxZValue) maxZValue = zValue;
310 gitem->setZValue(zValue);
311 gitem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
313 if (items.item(i).nodeName() == "background") {
314 kDebug() << items.item(i).attributes().namedItem("color").nodeValue();
315 QColor color = QColor(stringToColor(items.item(i).attributes().namedItem("color").nodeValue()));
316 //color.setAlpha(items.item(i).attributes().namedItem("alpha").nodeValue().toInt());
317 QList<QGraphicsItem *> items = m_scene->items();
318 for (int i = 0; i < items.size(); i++) {
319 if (items.at(i)->zValue() == -1100) {
320 ((QGraphicsRectItem *)items.at(i))->setBrush(QBrush(color));
324 } else if (items.item(i).nodeName() == "startviewport" && startv) {
325 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
326 startv->setPolygon(stringToRect(rect));
327 int x = items.item(i).attributes().namedItem("x").nodeValue().toInt();
328 int y = items.item(i).attributes().namedItem("y").nodeValue().toInt();
329 int size = items.item(i).attributes().namedItem("size").nodeValue().toInt();
330 startv->setData(0, x);
331 startv->setData(1, y);
332 startv->setData(2, size);
334 } else if (items.item(i).nodeName() == "endviewport" && endv) {
335 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
336 endv->setPolygon(stringToRect(rect));
337 int x = items.item(i).attributes().namedItem("x").nodeValue().toInt();
338 int y = items.item(i).attributes().namedItem("y").nodeValue().toInt();
339 int size = items.item(i).attributes().namedItem("size").nodeValue().toInt();
342 endv->setData(2, size);
349 QString TitleDocument::colorToString(const QColor& c)
351 QString ret = "%1,%2,%3,%4";
352 ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
356 QString TitleDocument::rectFToString(const QRectF& c)
358 QString ret = "%1,%2,%3,%4";
359 ret = ret.arg(c.left()).arg(c.top()).arg(c.width()).arg(c.height());
363 QRectF TitleDocument::stringToRect(const QString & s)
366 QStringList l = s.split(',');
369 return QRectF(l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(), l.at(3).toDouble()).normalized();
372 QColor TitleDocument::stringToColor(const QString & s)
374 QStringList l = s.split(',');
377 return QColor(l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt(), l.at(3).toInt());;
379 QTransform TitleDocument::stringToTransform(const QString& s)
381 QStringList l = s.split(',');
385 l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(),
386 l.at(3).toDouble(), l.at(4).toDouble(), l.at(5).toDouble(),
387 l.at(6).toDouble(), l.at(7).toDouble(), l.at(8).toDouble()