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, int 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::loadFromXml(QDomDocument doc, QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv, int *out)
197 QDomNodeList titles = doc.elementsByTagName("kdenlivetitle");
198 //TODO: Check if the opened title size is equal to project size, otherwise warn user and rescale
199 if (doc.documentElement().hasAttribute("width") && doc.documentElement().hasAttribute("height")) {
200 int doc_width = doc.documentElement().attribute("width").toInt();
201 int doc_height = doc.documentElement().attribute("height").toInt();
202 if (doc_width != m_width || doc_height != m_height) {
203 KMessageBox::information(kapp->activeWindow(), i18n("This title clip was created with a different frame size."), i18n("Title Profile"));
204 //TODO: convert using QTransform
206 m_height = doc_height;
209 //TODO: get default title duration instead of hardcoded one
210 if (doc.documentElement().hasAttribute("out"))
211 *out = doc.documentElement().attribute("out").toInt();
218 QDomNodeList items = titles.item(0).childNodes();
219 for (int i = 0; i < items.count(); i++) {
220 QGraphicsItem *gitem = NULL;
221 kDebug() << items.item(i).attributes().namedItem("type").nodeValue();
222 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
223 if (zValue > -1000) {
224 if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsTextItem") {
225 QDomNamedNodeMap txtProperties = items.item(i).namedItem("content").attributes();
226 QFont font(txtProperties.namedItem("font").nodeValue());
228 QDomNode node = txtProperties.namedItem("font-bold");
229 if (!node.isNull()) {
230 // Old: Bold/Not bold.
231 font.setBold(node.nodeValue().toInt());
233 // New: Font weight (QFont::)
234 font.setWeight(txtProperties.namedItem("font-weight").nodeValue().toInt());
236 //font.setBold(txtProperties.namedItem("font-bold").nodeValue().toInt());
237 font.setItalic(txtProperties.namedItem("font-italic").nodeValue().toInt());
238 font.setUnderline(txtProperties.namedItem("font-underline").nodeValue().toInt());
239 // Older Kdenlive version did not store pixel size but point size
240 if (txtProperties.namedItem("font-pixel-size").isNull()) {
241 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"));
243 f2.setPointSize(txtProperties.namedItem("font-size").nodeValue().toInt());
244 font.setPixelSize(QFontInfo(f2).pixelSize());
246 font.setPixelSize(txtProperties.namedItem("font-pixel-size").nodeValue().toInt());
247 QColor col(stringToColor(txtProperties.namedItem("font-color").nodeValue()));
248 QGraphicsTextItem *txt = m_scene->addText(items.item(i).namedItem("content").firstChild().nodeValue(), font);
249 txt->setDefaultTextColor(col);
250 txt->setTextInteractionFlags(Qt::NoTextInteraction);
251 if (txtProperties.namedItem("alignment").isNull() == false) {
252 txt->setTextWidth(txt->boundingRect().width());
253 QTextCursor cur = txt->textCursor();
254 QTextBlockFormat format = cur.blockFormat();
255 format.setAlignment((Qt::Alignment) txtProperties.namedItem("alignment").nodeValue().toInt());
256 cur.select(QTextCursor::Document);
257 cur.setBlockFormat(format);
258 txt->setTextCursor(cur);
259 cur.clearSelection();
260 txt->setTextCursor(cur);
263 if (!txtProperties.namedItem("kdenlive-axis-x-inverted").isNull()) {
264 txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt());
266 if (!txtProperties.namedItem("kdenlive-axis-y-inverted").isNull()) {
267 txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt());
271 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsRectItem") {
272 QString rect = items.item(i).namedItem("content").attributes().namedItem("rect").nodeValue();
273 QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
274 QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
275 double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
276 QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
278 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
279 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
281 QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
282 rec->setData(Qt::UserRole, url);
284 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
285 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
286 QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
287 m_scene->addItem(rec);
288 rec->setData(Qt::UserRole, url);
294 QPointF p(items.item(i).namedItem("position").attributes().namedItem("x").nodeValue().toDouble(),
295 items.item(i).namedItem("position").attributes().namedItem("y").nodeValue().toDouble());
297 gitem->setTransform(stringToTransform(items.item(i).namedItem("position").firstChild().firstChild().nodeValue()));
298 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
299 if (zValue > maxZValue) maxZValue = zValue;
300 gitem->setZValue(zValue);
301 gitem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
303 if (items.item(i).nodeName() == "background") {
304 kDebug() << items.item(i).attributes().namedItem("color").nodeValue();
305 QColor color = QColor(stringToColor(items.item(i).attributes().namedItem("color").nodeValue()));
306 //color.setAlpha(items.item(i).attributes().namedItem("alpha").nodeValue().toInt());
307 QList<QGraphicsItem *> items = m_scene->items();
308 for (int i = 0; i < items.size(); i++) {
309 if (items.at(i)->zValue() == -1100) {
310 ((QGraphicsRectItem *)items.at(i))->setBrush(QBrush(color));
314 } else if (items.item(i).nodeName() == "startviewport" && startv) {
315 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
316 startv->setPolygon(stringToRect(rect));
317 int x = items.item(i).attributes().namedItem("x").nodeValue().toInt();
318 int y = items.item(i).attributes().namedItem("y").nodeValue().toInt();
319 int size = items.item(i).attributes().namedItem("size").nodeValue().toInt();
320 startv->setData(0, x);
321 startv->setData(1, y);
322 startv->setData(2, size);
324 } else if (items.item(i).nodeName() == "endviewport" && endv) {
325 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
326 endv->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();
332 endv->setData(2, size);
339 QString TitleDocument::colorToString(const QColor& c)
341 QString ret = "%1,%2,%3,%4";
342 ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
346 QString TitleDocument::rectFToString(const QRectF& c)
348 QString ret = "%1,%2,%3,%4";
349 ret = ret.arg(c.left()).arg(c.top()).arg(c.width()).arg(c.height());
353 QRectF TitleDocument::stringToRect(const QString & s)
356 QStringList l = s.split(',');
359 return QRectF(l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(), l.at(3).toDouble()).normalized();
362 QColor TitleDocument::stringToColor(const QString & s)
364 QStringList l = s.split(',');
367 return QColor(l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt(), l.at(3).toInt());;
369 QTransform TitleDocument::stringToTransform(const QString& s)
371 QStringList l = s.split(',');
375 l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(),
376 l.at(3).toDouble(), l.at(4).toDouble(), l.at(5).toDouble(),
377 l.at(6).toDouble(), l.at(7).toDouble(), l.at(8).toDouble()
381 int TitleDocument::frameWidth() const
386 int TitleDocument::frameHeight() const