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 if (doc.documentElement().hasAttribute("width") && doc.documentElement().hasAttribute("height")) {
220 int doc_width = doc.documentElement().attribute("width").toInt();
221 int doc_height = doc.documentElement().attribute("height").toInt();
222 if (doc_width != m_width || doc_height != m_height) {
223 KMessageBox::information(kapp->activeWindow(), i18n("This title clip was created with a different frame size. It will now be converted to the current project's size."), i18n("Resizing Title Clip"));
224 //TODO: convert using QTransform
227 //TODO: get default title duration instead of hardcoded one
228 if (doc.documentElement().hasAttribute("out"))
229 *out = doc.documentElement().attribute("out").toDouble();
236 QDomNodeList items = titles.item(0).childNodes();
237 for (int i = 0; i < items.count(); i++) {
238 QGraphicsItem *gitem = NULL;
239 kDebug() << items.item(i).attributes().namedItem("type").nodeValue();
240 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
241 if (zValue > -1000) {
242 if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsTextItem") {
243 QDomNamedNodeMap txtProperties = items.item(i).namedItem("content").attributes();
244 QFont font(txtProperties.namedItem("font").nodeValue());
246 QDomNode node = txtProperties.namedItem("font-bold");
247 if (!node.isNull()) {
248 // Old: Bold/Not bold.
249 font.setBold(node.nodeValue().toInt());
251 // New: Font weight (QFont::)
252 font.setWeight(txtProperties.namedItem("font-weight").nodeValue().toInt());
254 //font.setBold(txtProperties.namedItem("font-bold").nodeValue().toInt());
255 font.setItalic(txtProperties.namedItem("font-italic").nodeValue().toInt());
256 font.setUnderline(txtProperties.namedItem("font-underline").nodeValue().toInt());
257 // Older Kdenlive version did not store pixel size but point size
258 if (txtProperties.namedItem("font-pixel-size").isNull()) {
259 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"));
261 f2.setPointSize(txtProperties.namedItem("font-size").nodeValue().toInt());
262 font.setPixelSize(QFontInfo(f2).pixelSize());
264 font.setPixelSize(txtProperties.namedItem("font-pixel-size").nodeValue().toInt());
265 QColor col(stringToColor(txtProperties.namedItem("font-color").nodeValue()));
266 QGraphicsTextItem *txt = m_scene->addText(items.item(i).namedItem("content").firstChild().nodeValue(), font);
267 txt->setDefaultTextColor(col);
268 txt->setTextInteractionFlags(Qt::NoTextInteraction);
269 if (txtProperties.namedItem("alignment").isNull() == false) {
270 txt->setTextWidth(txt->boundingRect().width());
271 QTextCursor cur = txt->textCursor();
272 QTextBlockFormat format = cur.blockFormat();
273 format.setAlignment((Qt::Alignment) txtProperties.namedItem("alignment").nodeValue().toInt());
274 cur.select(QTextCursor::Document);
275 cur.setBlockFormat(format);
276 txt->setTextCursor(cur);
277 cur.clearSelection();
278 txt->setTextCursor(cur);
281 if (!txtProperties.namedItem("kdenlive-axis-x-inverted").isNull()) {
282 txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt());
284 if (!txtProperties.namedItem("kdenlive-axis-y-inverted").isNull()) {
285 txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt());
289 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsRectItem") {
290 QString rect = items.item(i).namedItem("content").attributes().namedItem("rect").nodeValue();
291 QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
292 QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
293 double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
294 QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
296 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
297 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
299 QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
300 rec->setData(Qt::UserRole, url);
302 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
303 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
304 QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
305 m_scene->addItem(rec);
306 rec->setData(Qt::UserRole, url);
312 QPointF p(items.item(i).namedItem("position").attributes().namedItem("x").nodeValue().toDouble(),
313 items.item(i).namedItem("position").attributes().namedItem("y").nodeValue().toDouble());
315 gitem->setTransform(stringToTransform(items.item(i).namedItem("position").firstChild().firstChild().nodeValue()));
316 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
317 if (zValue > maxZValue) maxZValue = zValue;
318 gitem->setZValue(zValue);
319 gitem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
321 if (items.item(i).nodeName() == "background") {
322 kDebug() << items.item(i).attributes().namedItem("color").nodeValue();
323 QColor color = QColor(stringToColor(items.item(i).attributes().namedItem("color").nodeValue()));
324 //color.setAlpha(items.item(i).attributes().namedItem("alpha").nodeValue().toInt());
325 QList<QGraphicsItem *> items = m_scene->items();
326 for (int i = 0; i < items.size(); i++) {
327 if (items.at(i)->zValue() == -1100) {
328 ((QGraphicsRectItem *)items.at(i))->setBrush(QBrush(color));
332 } else if (items.item(i).nodeName() == "startviewport" && startv) {
333 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
334 startv->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();
338 startv->setData(0, x);
339 startv->setData(1, y);
340 startv->setData(2, size);
342 } else if (items.item(i).nodeName() == "endviewport" && endv) {
343 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
344 endv->setPolygon(stringToRect(rect));
345 int x = items.item(i).attributes().namedItem("x").nodeValue().toInt();
346 int y = items.item(i).attributes().namedItem("y").nodeValue().toInt();
347 int size = items.item(i).attributes().namedItem("size").nodeValue().toInt();
350 endv->setData(2, size);
357 QString TitleDocument::colorToString(const QColor& c)
359 QString ret = "%1,%2,%3,%4";
360 ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
364 QString TitleDocument::rectFToString(const QRectF& c)
366 QString ret = "%1,%2,%3,%4";
367 ret = ret.arg(c.left()).arg(c.top()).arg(c.width()).arg(c.height());
371 QRectF TitleDocument::stringToRect(const QString & s)
374 QStringList l = s.split(',');
377 return QRectF(l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(), l.at(3).toDouble()).normalized();
380 QColor TitleDocument::stringToColor(const QString & s)
382 QStringList l = s.split(',');
385 return QColor(l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt(), l.at(3).toInt());;
387 QTransform TitleDocument::stringToTransform(const QString& s)
389 QStringList l = s.split(',');
393 l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(),
394 l.at(3).toDouble(), l.at(4).toDouble(), l.at(5).toDouble(),
395 l.at(6).toDouble(), l.at(7).toDouble(), l.at(8).toDouble()