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 doc.documentElement().setAttribute("width", m_scene->width());
176 doc.documentElement().setAttribute("height", m_scene->height());
177 KTemporaryFile tmpfile;
178 if (!tmpfile.open()) {
179 kWarning() << "///// CANNOT CREATE TMP FILE in: " << tmpfile.fileName();
182 QFile xmlf(tmpfile.fileName());
183 xmlf.open(QIODevice::WriteOnly);
184 xmlf.write(doc.toString().toUtf8());
185 if (xmlf.error() != QFile::NoError) {
190 return KIO::NetAccess::upload(tmpfile.fileName(), url, 0);
193 int TitleDocument::loadDocument(const KUrl& url, QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv, double *out)
200 if (KIO::NetAccess::download(url, tmpfile, 0)) {
202 if (file.open(QIODevice::ReadOnly)) {
203 doc.setContent(&file, false);
207 KIO::NetAccess::removeTempFile(tmpfile);
208 return loadFromXml(doc, startv, endv, out);
213 int TitleDocument::loadFromXml(QDomDocument doc, QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv, double *out)
215 QDomNodeList titles = doc.elementsByTagName("kdenlivetitle");
216 //TODO: Check if the opened title size is equal to project size, otherwise warn user and rescale
217 //TODO: get default title duration instead of hardcoded one
218 if (doc.documentElement().hasAttribute("out"))
219 *out = doc.documentElement().attribute("out").toDouble();
226 QDomNodeList items = titles.item(0).childNodes();
227 for (int i = 0; i < items.count(); i++) {
228 QGraphicsItem *gitem = NULL;
229 kDebug() << items.item(i).attributes().namedItem("type").nodeValue();
230 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
231 if (zValue > -1000) {
232 if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsTextItem") {
233 QDomNamedNodeMap txtProperties = items.item(i).namedItem("content").attributes();
234 QFont font(txtProperties.namedItem("font").nodeValue());
236 QDomNode node = txtProperties.namedItem("font-bold");
237 if (!node.isNull()) {
238 // Old: Bold/Not bold.
239 font.setBold(node.nodeValue().toInt());
241 // New: Font weight (QFont::)
242 font.setWeight(txtProperties.namedItem("font-weight").nodeValue().toInt());
244 //font.setBold(txtProperties.namedItem("font-bold").nodeValue().toInt());
245 font.setItalic(txtProperties.namedItem("font-italic").nodeValue().toInt());
246 font.setUnderline(txtProperties.namedItem("font-underline").nodeValue().toInt());
247 // Older Kdenlive version did not store pixel size but point size
248 if (txtProperties.namedItem("font-pixel-size").isNull()) {
249 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"));
251 f2.setPointSize(txtProperties.namedItem("font-size").nodeValue().toInt());
252 font.setPixelSize(QFontInfo(f2).pixelSize());
254 font.setPixelSize(txtProperties.namedItem("font-pixel-size").nodeValue().toInt());
255 QColor col(stringToColor(txtProperties.namedItem("font-color").nodeValue()));
256 QGraphicsTextItem *txt = m_scene->addText(items.item(i).namedItem("content").firstChild().nodeValue(), font);
257 txt->setDefaultTextColor(col);
258 txt->setTextInteractionFlags(Qt::NoTextInteraction);
259 if (txtProperties.namedItem("alignment").isNull() == false) {
260 txt->setTextWidth(txt->boundingRect().width());
261 QTextCursor cur = txt->textCursor();
262 QTextBlockFormat format = cur.blockFormat();
263 format.setAlignment((Qt::Alignment) txtProperties.namedItem("alignment").nodeValue().toInt());
264 cur.select(QTextCursor::Document);
265 cur.setBlockFormat(format);
266 txt->setTextCursor(cur);
267 cur.clearSelection();
268 txt->setTextCursor(cur);
271 if (!txtProperties.namedItem("kdenlive-axis-x-inverted").isNull()) {
272 txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt());
274 if (!txtProperties.namedItem("kdenlive-axis-y-inverted").isNull()) {
275 txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt());
279 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsRectItem") {
280 QString rect = items.item(i).namedItem("content").attributes().namedItem("rect").nodeValue();
281 QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
282 QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
283 double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
284 QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
286 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
287 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
289 QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
290 rec->setData(Qt::UserRole, url);
292 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
293 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
294 QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
295 m_scene->addItem(rec);
296 rec->setData(Qt::UserRole, url);
302 QPointF p(items.item(i).namedItem("position").attributes().namedItem("x").nodeValue().toDouble(),
303 items.item(i).namedItem("position").attributes().namedItem("y").nodeValue().toDouble());
305 gitem->setTransform(stringToTransform(items.item(i).namedItem("position").firstChild().firstChild().nodeValue()));
306 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
307 if (zValue > maxZValue) maxZValue = zValue;
308 gitem->setZValue(zValue);
309 gitem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
311 if (items.item(i).nodeName() == "background") {
312 kDebug() << items.item(i).attributes().namedItem("color").nodeValue();
313 QColor color = QColor(stringToColor(items.item(i).attributes().namedItem("color").nodeValue()));
314 //color.setAlpha(items.item(i).attributes().namedItem("alpha").nodeValue().toInt());
315 QList<QGraphicsItem *> items = m_scene->items();
316 for (int i = 0; i < items.size(); i++) {
317 if (items.at(i)->zValue() == -1100) {
318 ((QGraphicsRectItem *)items.at(i))->setBrush(QBrush(color));
322 } else if (items.item(i).nodeName() == "startviewport" && startv) {
323 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
324 startv->setPolygon(stringToRect(rect));
325 int x = items.item(i).attributes().namedItem("x").nodeValue().toInt();
326 int y = items.item(i).attributes().namedItem("y").nodeValue().toInt();
327 int size = items.item(i).attributes().namedItem("size").nodeValue().toInt();
328 startv->setData(0, x);
329 startv->setData(1, y);
330 startv->setData(2, size);
332 } else if (items.item(i).nodeName() == "endviewport" && endv) {
333 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
334 endv->setPolygon(stringToRect(rect));
335 int x = items.item(i).attributes().namedItem("x").nodeValue().toInt();
336 int y = items.item(i).attributes().namedItem("y").nodeValue().toInt();
337 int size = items.item(i).attributes().namedItem("size").nodeValue().toInt();
340 endv->setData(2, size);
347 QString TitleDocument::colorToString(const QColor& c)
349 QString ret = "%1,%2,%3,%4";
350 ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
354 QString TitleDocument::rectFToString(const QRectF& c)
356 QString ret = "%1,%2,%3,%4";
357 ret = ret.arg(c.left()).arg(c.top()).arg(c.width()).arg(c.height());
361 QRectF TitleDocument::stringToRect(const QString & s)
364 QStringList l = s.split(',');
367 return QRectF(l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(), l.at(3).toDouble()).normalized();
370 QColor TitleDocument::stringToColor(const QString & s)
372 QStringList l = s.split(',');
375 return QColor(l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt(), l.at(3).toInt());;
377 QTransform TitleDocument::stringToTransform(const QString& s)
379 QStringList l = s.split(',');
383 l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(),
384 l.at(3).toDouble(), l.at(4).toDouble(), l.at(5).toDouble(),
385 l.at(6).toDouble(), l.at(7).toDouble(), l.at(8).toDouble()