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>
37 #if QT_VERSION >= 0x040600
38 #include <QGraphicsEffect>
39 #include <QGraphicsBlurEffect>
40 #include <QGraphicsDropShadowEffect>
43 TitleDocument::TitleDocument()
48 void TitleDocument::setScene(QGraphicsScene* _scene, int width, int height)
55 QDomDocument TitleDocument::xml(QGraphicsRectItem* startv, QGraphicsRectItem* endv)
59 QDomElement main = doc.createElement("kdenlivetitle");
60 main.setAttribute("width", m_width);
61 main.setAttribute("height", m_height);
62 doc.appendChild(main);
64 foreach(QGraphicsItem* item, m_scene->items()) {
65 QDomElement e = doc.createElement("item");
66 QDomElement content = doc.createElement("content");
70 switch (item->type()) {
72 e.setAttribute("type", "QGraphicsPixmapItem");
73 content.setAttribute("url", item->data(Qt::UserRole).toString());
76 e.setAttribute("type", "QGraphicsSvgItem");
77 content.setAttribute("url", item->data(Qt::UserRole).toString());
80 e.setAttribute("type", "QGraphicsRectItem");
81 content.setAttribute("rect", rectFToString(((QGraphicsRectItem*)item)->rect().normalized()));
82 content.setAttribute("pencolor", colorToString(((QGraphicsRectItem*)item)->pen().color()));
83 content.setAttribute("penwidth", ((QGraphicsRectItem*)item)->pen().width());
84 content.setAttribute("brushcolor", colorToString(((QGraphicsRectItem*)item)->brush().color()));
87 e.setAttribute("type", "QGraphicsTextItem");
88 t = static_cast<QGraphicsTextItem *>(item);
89 // Don't save empty text nodes
90 if (t->toPlainText().simplified().isEmpty()) continue;
91 //content.appendChild(doc.createTextNode(((QGraphicsTextItem*)item)->toHtml()));
92 content.appendChild(doc.createTextNode(t->toPlainText()));
94 content.setAttribute("font", font.family());
95 content.setAttribute("font-weight", font.weight());
96 content.setAttribute("font-pixel-size", font.pixelSize());
97 content.setAttribute("font-italic", font.italic());
98 content.setAttribute("font-underline", font.underline());
99 content.setAttribute("font-color", colorToString(t->defaultTextColor()));
101 // Only save when necessary.
102 if (t->data(OriginXLeft).toInt() == AxisInverted) {
103 content.setAttribute("kdenlive-axis-x-inverted", t->data(OriginXLeft).toInt());
105 if (t->data(OriginYTop).toInt() == AxisInverted) {
106 content.setAttribute("kdenlive-axis-y-inverted", t->data(OriginYTop).toInt());
108 if (t->textWidth() != -1) {
109 content.setAttribute("alignment", t->textCursor().blockFormat().alignment());
117 QDomElement pos = doc.createElement("position");
118 pos.setAttribute("x", item->pos().x());
119 pos.setAttribute("y", item->pos().y());
120 QTransform transform = item->transform();
121 QDomElement tr = doc.createElement("transform");
122 tr.appendChild(doc.createTextNode(
123 QString("%1,%2,%3,%4,%5,%6,%7,%8,%9").arg(
124 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())
127 e.setAttribute("z-index", item->zValue());
130 #if QT_VERSION >= 0x040600
132 QGraphicsEffect *eff = item->graphicsEffect();
134 QGraphicsBlurEffect *blur = static_cast <QGraphicsBlurEffect *>(eff);
135 QDomElement effect = doc.createElement("effect");
137 effect.setAttribute("type", "blur");
138 effect.setAttribute("blurradius", blur->blurRadius());
140 QGraphicsDropShadowEffect *shadow = static_cast <QGraphicsDropShadowEffect *>(eff);
142 effect.setAttribute("type", "shadow");
143 effect.setAttribute("blurradius", shadow->blurRadius());
144 effect.setAttribute("xoffset", shadow->xOffset());
145 effect.setAttribute("yoffset", shadow->yOffset());
148 e.appendChild(effect);
153 e.appendChild(content);
154 if (item->zValue() > -1000) main.appendChild(e);
156 if (startv && endv) {
157 QDomElement endp = doc.createElement("endviewport");
158 QDomElement startp = doc.createElement("startviewport");
159 QRectF r(endv->pos().x(), endv->pos().y(), endv->rect().width(), endv->rect().height());
160 endp.setAttribute("rect", rectFToString(r));
161 QRectF r2(startv->pos().x(), startv->pos().y(), startv->rect().width(), startv->rect().height());
162 startp.setAttribute("rect", rectFToString(r2));
164 main.appendChild(startp);
165 main.appendChild(endp);
167 QDomElement backgr = doc.createElement("background");
168 QColor color = getBackgroundColor();
169 backgr.setAttribute("color", colorToString(color));
170 main.appendChild(backgr);
175 /** \brief Get the background color (incl. alpha) from the document, if possibly
176 * \returns The background color of the document, inclusive alpha. If none found, returns (0,0,0,0) */
177 QColor TitleDocument::getBackgroundColor()
179 QColor color(0, 0, 0, 0);
181 QList<QGraphicsItem *> items = m_scene->items();
182 for (int i = 0; i < items.size(); i++) {
183 if (items.at(i)->zValue() == -1100) {
184 color = ((QGraphicsRectItem *)items.at(i))->brush().color();
193 bool TitleDocument::saveDocument(const KUrl& url, QGraphicsRectItem* startv, QGraphicsRectItem* endv, int out)
198 QDomDocument doc = xml(startv, endv);
199 doc.documentElement().setAttribute("out", out);
200 KTemporaryFile tmpfile;
201 if (!tmpfile.open()) {
202 kWarning() << "///// CANNOT CREATE TMP FILE in: " << tmpfile.fileName();
205 QFile xmlf(tmpfile.fileName());
206 xmlf.open(QIODevice::WriteOnly);
207 xmlf.write(doc.toString().toUtf8());
208 if (xmlf.error() != QFile::NoError) {
213 return KIO::NetAccess::upload(tmpfile.fileName(), url, 0);
216 int TitleDocument::loadFromXml(QDomDocument doc, QGraphicsRectItem* startv, QGraphicsRectItem* endv, int *out)
218 QDomNodeList titles = doc.elementsByTagName("kdenlivetitle");
219 //TODO: Check if the opened title size is equal to project size, otherwise warn user and rescale
220 if (doc.documentElement().hasAttribute("width") && doc.documentElement().hasAttribute("height")) {
221 int doc_width = doc.documentElement().attribute("width").toInt();
222 int doc_height = doc.documentElement().attribute("height").toInt();
223 if (doc_width != m_width || doc_height != m_height) {
224 KMessageBox::information(kapp->activeWindow(), i18n("This title clip was created with a different frame size."), i18n("Title Profile"));
225 //TODO: convert using QTransform
227 m_height = doc_height;
230 //TODO: get default title duration instead of hardcoded one
231 if (doc.documentElement().hasAttribute("out"))
232 *out = doc.documentElement().attribute("out").toInt();
239 QDomNodeList items = titles.item(0).childNodes();
240 for (int i = 0; i < items.count(); i++) {
241 QGraphicsItem *gitem = NULL;
242 kDebug() << items.item(i).attributes().namedItem("type").nodeValue();
243 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
244 if (zValue > -1000) {
245 if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsTextItem") {
246 QDomNamedNodeMap txtProperties = items.item(i).namedItem("content").attributes();
247 QFont font(txtProperties.namedItem("font").nodeValue());
249 QDomNode node = txtProperties.namedItem("font-bold");
250 if (!node.isNull()) {
251 // Old: Bold/Not bold.
252 font.setBold(node.nodeValue().toInt());
254 // New: Font weight (QFont::)
255 font.setWeight(txtProperties.namedItem("font-weight").nodeValue().toInt());
257 //font.setBold(txtProperties.namedItem("font-bold").nodeValue().toInt());
258 font.setItalic(txtProperties.namedItem("font-italic").nodeValue().toInt());
259 font.setUnderline(txtProperties.namedItem("font-underline").nodeValue().toInt());
260 // Older Kdenlive version did not store pixel size but point size
261 if (txtProperties.namedItem("font-pixel-size").isNull()) {
262 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"));
264 f2.setPointSize(txtProperties.namedItem("font-size").nodeValue().toInt());
265 font.setPixelSize(QFontInfo(f2).pixelSize());
267 font.setPixelSize(txtProperties.namedItem("font-pixel-size").nodeValue().toInt());
268 QColor col(stringToColor(txtProperties.namedItem("font-color").nodeValue()));
269 QGraphicsTextItem *txt = m_scene->addText(items.item(i).namedItem("content").firstChild().nodeValue(), font);
270 txt->setDefaultTextColor(col);
271 txt->setTextInteractionFlags(Qt::NoTextInteraction);
272 if (txtProperties.namedItem("alignment").isNull() == false) {
273 txt->setTextWidth(txt->boundingRect().width());
274 QTextCursor cur = txt->textCursor();
275 QTextBlockFormat format = cur.blockFormat();
276 format.setAlignment((Qt::Alignment) txtProperties.namedItem("alignment").nodeValue().toInt());
277 cur.select(QTextCursor::Document);
278 cur.setBlockFormat(format);
279 txt->setTextCursor(cur);
280 cur.clearSelection();
281 txt->setTextCursor(cur);
284 if (!txtProperties.namedItem("kdenlive-axis-x-inverted").isNull()) {
285 txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt());
287 if (!txtProperties.namedItem("kdenlive-axis-y-inverted").isNull()) {
288 txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt());
292 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsRectItem") {
293 QString rect = items.item(i).namedItem("content").attributes().namedItem("rect").nodeValue();
294 QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
295 QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
296 double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
297 QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
299 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
300 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
302 QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
303 rec->setData(Qt::UserRole, url);
305 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
306 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
307 QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
308 m_scene->addItem(rec);
309 rec->setData(Qt::UserRole, url);
315 QPointF p(items.item(i).namedItem("position").attributes().namedItem("x").nodeValue().toDouble(),
316 items.item(i).namedItem("position").attributes().namedItem("y").nodeValue().toDouble());
318 gitem->setTransform(stringToTransform(items.item(i).namedItem("position").firstChild().firstChild().nodeValue()));
319 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
320 if (zValue > maxZValue) maxZValue = zValue;
321 gitem->setZValue(zValue);
322 gitem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
324 #if QT_VERSION >= 0x040600
326 QDomNode eff = items.item(i).namedItem("effect");
328 QDomElement e = eff.toElement();
329 if (e.attribute("type") == "blur") {
330 QGraphicsBlurEffect *blur = new QGraphicsBlurEffect();
331 blur->setBlurRadius(e.attribute("blurradius").toInt());
332 gitem->setGraphicsEffect(blur);
333 } else if (e.attribute("type") == "shadow") {
334 QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect();
335 shadow->setBlurRadius(e.attribute("blurradius").toInt());
336 shadow->setOffset(e.attribute("xoffset").toInt(), e.attribute("yoffset").toInt());
337 gitem->setGraphicsEffect(shadow);
343 if (items.item(i).nodeName() == "background") {
344 kDebug() << items.item(i).attributes().namedItem("color").nodeValue();
345 QColor color = QColor(stringToColor(items.item(i).attributes().namedItem("color").nodeValue()));
346 //color.setAlpha(items.item(i).attributes().namedItem("alpha").nodeValue().toInt());
347 QList<QGraphicsItem *> items = m_scene->items();
348 for (int i = 0; i < items.size(); i++) {
349 if (items.at(i)->zValue() == -1100) {
350 ((QGraphicsRectItem *)items.at(i))->setBrush(QBrush(color));
354 } else if (items.item(i).nodeName() == "startviewport" && startv) {
355 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
356 QRectF r = stringToRect(rect);
357 startv->setRect(0, 0, r.width(), r.height());
358 startv->setPos(r.topLeft());
359 } else if (items.item(i).nodeName() == "endviewport" && endv) {
360 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
361 QRectF r = stringToRect(rect);
362 endv->setRect(0, 0, r.width(), r.height());
363 endv->setPos(r.topLeft());
370 QString TitleDocument::colorToString(const QColor& c)
372 QString ret = "%1,%2,%3,%4";
373 ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
377 QString TitleDocument::rectFToString(const QRectF& c)
379 QString ret = "%1,%2,%3,%4";
380 ret = ret.arg(c.left()).arg(c.top()).arg(c.width()).arg(c.height());
384 QRectF TitleDocument::stringToRect(const QString & s)
387 QStringList l = s.split(',');
390 return QRectF(l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(), l.at(3).toDouble()).normalized();
393 QColor TitleDocument::stringToColor(const QString & s)
395 QStringList l = s.split(',');
398 return QColor(l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt(), l.at(3).toInt());;
400 QTransform TitleDocument::stringToTransform(const QString& s)
402 QStringList l = s.split(',');
406 l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(),
407 l.at(3).toDouble(), l.at(4).toDouble(), l.at(5).toDouble(),
408 l.at(6).toDouble(), l.at(7).toDouble(), l.at(8).toDouble()
412 int TitleDocument::frameWidth() const
417 int TitleDocument::frameHeight() const