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."), i18n("Title Profile"));
224 //TODO: convert using QTransform
226 m_height = doc_height;
229 //TODO: get default title duration instead of hardcoded one
230 if (doc.documentElement().hasAttribute("out"))
231 *out = doc.documentElement().attribute("out").toDouble();
238 QDomNodeList items = titles.item(0).childNodes();
239 for (int i = 0; i < items.count(); i++) {
240 QGraphicsItem *gitem = NULL;
241 kDebug() << items.item(i).attributes().namedItem("type").nodeValue();
242 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
243 if (zValue > -1000) {
244 if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsTextItem") {
245 QDomNamedNodeMap txtProperties = items.item(i).namedItem("content").attributes();
246 QFont font(txtProperties.namedItem("font").nodeValue());
248 QDomNode node = txtProperties.namedItem("font-bold");
249 if (!node.isNull()) {
250 // Old: Bold/Not bold.
251 font.setBold(node.nodeValue().toInt());
253 // New: Font weight (QFont::)
254 font.setWeight(txtProperties.namedItem("font-weight").nodeValue().toInt());
256 //font.setBold(txtProperties.namedItem("font-bold").nodeValue().toInt());
257 font.setItalic(txtProperties.namedItem("font-italic").nodeValue().toInt());
258 font.setUnderline(txtProperties.namedItem("font-underline").nodeValue().toInt());
259 // Older Kdenlive version did not store pixel size but point size
260 if (txtProperties.namedItem("font-pixel-size").isNull()) {
261 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"));
263 f2.setPointSize(txtProperties.namedItem("font-size").nodeValue().toInt());
264 font.setPixelSize(QFontInfo(f2).pixelSize());
266 font.setPixelSize(txtProperties.namedItem("font-pixel-size").nodeValue().toInt());
267 QColor col(stringToColor(txtProperties.namedItem("font-color").nodeValue()));
268 QGraphicsTextItem *txt = m_scene->addText(items.item(i).namedItem("content").firstChild().nodeValue(), font);
269 txt->setDefaultTextColor(col);
270 txt->setTextInteractionFlags(Qt::NoTextInteraction);
271 if (txtProperties.namedItem("alignment").isNull() == false) {
272 txt->setTextWidth(txt->boundingRect().width());
273 QTextCursor cur = txt->textCursor();
274 QTextBlockFormat format = cur.blockFormat();
275 format.setAlignment((Qt::Alignment) txtProperties.namedItem("alignment").nodeValue().toInt());
276 cur.select(QTextCursor::Document);
277 cur.setBlockFormat(format);
278 txt->setTextCursor(cur);
279 cur.clearSelection();
280 txt->setTextCursor(cur);
283 if (!txtProperties.namedItem("kdenlive-axis-x-inverted").isNull()) {
284 txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt());
286 if (!txtProperties.namedItem("kdenlive-axis-y-inverted").isNull()) {
287 txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt());
291 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsRectItem") {
292 QString rect = items.item(i).namedItem("content").attributes().namedItem("rect").nodeValue();
293 QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
294 QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
295 double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
296 QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
298 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
299 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
301 QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
302 rec->setData(Qt::UserRole, url);
304 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
305 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
306 QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
307 m_scene->addItem(rec);
308 rec->setData(Qt::UserRole, url);
314 QPointF p(items.item(i).namedItem("position").attributes().namedItem("x").nodeValue().toDouble(),
315 items.item(i).namedItem("position").attributes().namedItem("y").nodeValue().toDouble());
317 gitem->setTransform(stringToTransform(items.item(i).namedItem("position").firstChild().firstChild().nodeValue()));
318 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
319 if (zValue > maxZValue) maxZValue = zValue;
320 gitem->setZValue(zValue);
321 gitem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
323 if (items.item(i).nodeName() == "background") {
324 kDebug() << items.item(i).attributes().namedItem("color").nodeValue();
325 QColor color = QColor(stringToColor(items.item(i).attributes().namedItem("color").nodeValue()));
326 //color.setAlpha(items.item(i).attributes().namedItem("alpha").nodeValue().toInt());
327 QList<QGraphicsItem *> items = m_scene->items();
328 for (int i = 0; i < items.size(); i++) {
329 if (items.at(i)->zValue() == -1100) {
330 ((QGraphicsRectItem *)items.at(i))->setBrush(QBrush(color));
334 } else if (items.item(i).nodeName() == "startviewport" && startv) {
335 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
336 startv->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();
340 startv->setData(0, x);
341 startv->setData(1, y);
342 startv->setData(2, size);
344 } else if (items.item(i).nodeName() == "endviewport" && endv) {
345 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
346 endv->setPolygon(stringToRect(rect));
347 int x = items.item(i).attributes().namedItem("x").nodeValue().toInt();
348 int y = items.item(i).attributes().namedItem("y").nodeValue().toInt();
349 int size = items.item(i).attributes().namedItem("size").nodeValue().toInt();
352 endv->setData(2, size);
359 QString TitleDocument::colorToString(const QColor& c)
361 QString ret = "%1,%2,%3,%4";
362 ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
366 QString TitleDocument::rectFToString(const QRectF& c)
368 QString ret = "%1,%2,%3,%4";
369 ret = ret.arg(c.left()).arg(c.top()).arg(c.width()).arg(c.height());
373 QRectF TitleDocument::stringToRect(const QString & s)
376 QStringList l = s.split(',');
379 return QRectF(l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(), l.at(3).toDouble()).normalized();
382 QColor TitleDocument::stringToColor(const QString & s)
384 QStringList l = s.split(',');
387 return QColor(l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt(), l.at(3).toInt());;
389 QTransform TitleDocument::stringToTransform(const QString& s)
391 QStringList l = s.split(',');
395 l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(),
396 l.at(3).toDouble(), l.at(4).toDouble(), l.at(5).toDouble(),
397 l.at(6).toDouble(), l.at(7).toDouble(), l.at(8).toDouble()
401 int TitleDocument::frameWidth() const
406 int TitleDocument::frameHeight() const