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(QGraphicsRectItem* startv, QGraphicsRectItem* 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() > -1000) main.appendChild(e);
128 if (startv && endv) {
129 QDomElement endp = doc.createElement("endviewport");
130 QDomElement startp = doc.createElement("startviewport");
131 QRectF r(endv->pos().x(), endv->pos().y(), endv->rect().width(), endv->rect().height());
132 endp.setAttribute("rect", rectFToString(r));
133 QRectF r2(startv->pos().x(), startv->pos().y(), startv->rect().width(), startv->rect().height());
134 startp.setAttribute("rect", rectFToString(r2));
136 main.appendChild(startp);
137 main.appendChild(endp);
139 QDomElement backgr = doc.createElement("background");
140 QColor color = getBackgroundColor();
141 backgr.setAttribute("color", colorToString(color));
142 main.appendChild(backgr);
147 /** \brief Get the background color (incl. alpha) from the document, if possibly
148 * \returns The background color of the document, inclusive alpha. If none found, returns (0,0,0,0) */
149 QColor TitleDocument::getBackgroundColor()
151 QColor color(0, 0, 0, 0);
153 QList<QGraphicsItem *> items = m_scene->items();
154 for (int i = 0; i < items.size(); i++) {
155 if (items.at(i)->zValue() == -1100) {
156 color = ((QGraphicsRectItem *)items.at(i))->brush().color();
165 bool TitleDocument::saveDocument(const KUrl& url, QGraphicsRectItem* startv, QGraphicsRectItem* endv, int out)
170 QDomDocument doc = xml(startv, endv);
171 doc.documentElement().setAttribute("out", out);
172 KTemporaryFile tmpfile;
173 if (!tmpfile.open()) {
174 kWarning() << "///// CANNOT CREATE TMP FILE in: " << tmpfile.fileName();
177 QFile xmlf(tmpfile.fileName());
178 xmlf.open(QIODevice::WriteOnly);
179 xmlf.write(doc.toString().toUtf8());
180 if (xmlf.error() != QFile::NoError) {
185 return KIO::NetAccess::upload(tmpfile.fileName(), url, 0);
188 int TitleDocument::loadFromXml(QDomDocument doc, QGraphicsRectItem* startv, QGraphicsRectItem* endv, int *out)
190 QDomNodeList titles = doc.elementsByTagName("kdenlivetitle");
191 //TODO: Check if the opened title size is equal to project size, otherwise warn user and rescale
192 if (doc.documentElement().hasAttribute("width") && doc.documentElement().hasAttribute("height")) {
193 int doc_width = doc.documentElement().attribute("width").toInt();
194 int doc_height = doc.documentElement().attribute("height").toInt();
195 if (doc_width != m_width || doc_height != m_height) {
196 KMessageBox::information(kapp->activeWindow(), i18n("This title clip was created with a different frame size."), i18n("Title Profile"));
197 //TODO: convert using QTransform
199 m_height = doc_height;
202 //TODO: get default title duration instead of hardcoded one
203 if (doc.documentElement().hasAttribute("out"))
204 *out = doc.documentElement().attribute("out").toInt();
211 QDomNodeList items = titles.item(0).childNodes();
212 for (int i = 0; i < items.count(); i++) {
213 QGraphicsItem *gitem = NULL;
214 kDebug() << items.item(i).attributes().namedItem("type").nodeValue();
215 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
216 if (zValue > -1000) {
217 if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsTextItem") {
218 QDomNamedNodeMap txtProperties = items.item(i).namedItem("content").attributes();
219 QFont font(txtProperties.namedItem("font").nodeValue());
221 QDomNode node = txtProperties.namedItem("font-bold");
222 if (!node.isNull()) {
223 // Old: Bold/Not bold.
224 font.setBold(node.nodeValue().toInt());
226 // New: Font weight (QFont::)
227 font.setWeight(txtProperties.namedItem("font-weight").nodeValue().toInt());
229 //font.setBold(txtProperties.namedItem("font-bold").nodeValue().toInt());
230 font.setItalic(txtProperties.namedItem("font-italic").nodeValue().toInt());
231 font.setUnderline(txtProperties.namedItem("font-underline").nodeValue().toInt());
232 // Older Kdenlive version did not store pixel size but point size
233 if (txtProperties.namedItem("font-pixel-size").isNull()) {
234 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"));
236 f2.setPointSize(txtProperties.namedItem("font-size").nodeValue().toInt());
237 font.setPixelSize(QFontInfo(f2).pixelSize());
239 font.setPixelSize(txtProperties.namedItem("font-pixel-size").nodeValue().toInt());
240 QColor col(stringToColor(txtProperties.namedItem("font-color").nodeValue()));
241 QGraphicsTextItem *txt = m_scene->addText(items.item(i).namedItem("content").firstChild().nodeValue(), font);
242 txt->setDefaultTextColor(col);
243 txt->setTextInteractionFlags(Qt::NoTextInteraction);
244 if (txtProperties.namedItem("alignment").isNull() == false) {
245 txt->setTextWidth(txt->boundingRect().width());
246 QTextCursor cur = txt->textCursor();
247 QTextBlockFormat format = cur.blockFormat();
248 format.setAlignment((Qt::Alignment) txtProperties.namedItem("alignment").nodeValue().toInt());
249 cur.select(QTextCursor::Document);
250 cur.setBlockFormat(format);
251 txt->setTextCursor(cur);
252 cur.clearSelection();
253 txt->setTextCursor(cur);
256 if (!txtProperties.namedItem("kdenlive-axis-x-inverted").isNull()) {
257 txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt());
259 if (!txtProperties.namedItem("kdenlive-axis-y-inverted").isNull()) {
260 txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt());
264 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsRectItem") {
265 QString rect = items.item(i).namedItem("content").attributes().namedItem("rect").nodeValue();
266 QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
267 QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
268 double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
269 QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
271 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
272 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
274 QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
275 rec->setData(Qt::UserRole, url);
277 } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
278 QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
279 QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
280 m_scene->addItem(rec);
281 rec->setData(Qt::UserRole, url);
287 QPointF p(items.item(i).namedItem("position").attributes().namedItem("x").nodeValue().toDouble(),
288 items.item(i).namedItem("position").attributes().namedItem("y").nodeValue().toDouble());
290 gitem->setTransform(stringToTransform(items.item(i).namedItem("position").firstChild().firstChild().nodeValue()));
291 int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
292 if (zValue > maxZValue) maxZValue = zValue;
293 gitem->setZValue(zValue);
294 gitem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
296 if (items.item(i).nodeName() == "background") {
297 kDebug() << items.item(i).attributes().namedItem("color").nodeValue();
298 QColor color = QColor(stringToColor(items.item(i).attributes().namedItem("color").nodeValue()));
299 //color.setAlpha(items.item(i).attributes().namedItem("alpha").nodeValue().toInt());
300 QList<QGraphicsItem *> items = m_scene->items();
301 for (int i = 0; i < items.size(); i++) {
302 if (items.at(i)->zValue() == -1100) {
303 ((QGraphicsRectItem *)items.at(i))->setBrush(QBrush(color));
307 } else if (items.item(i).nodeName() == "startviewport" && startv) {
308 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
309 QRectF r = stringToRect(rect);
310 startv->setRect(0, 0, r.width(), r.height());
311 startv->setPos(r.topLeft());
312 } else if (items.item(i).nodeName() == "endviewport" && endv) {
313 QString rect = items.item(i).attributes().namedItem("rect").nodeValue();
314 QRectF r = stringToRect(rect);
315 endv->setRect(0, 0, r.width(), r.height());
316 endv->setPos(r.topLeft());
323 QString TitleDocument::colorToString(const QColor& c)
325 QString ret = "%1,%2,%3,%4";
326 ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
330 QString TitleDocument::rectFToString(const QRectF& c)
332 QString ret = "%1,%2,%3,%4";
333 ret = ret.arg(c.left()).arg(c.top()).arg(c.width()).arg(c.height());
337 QRectF TitleDocument::stringToRect(const QString & s)
340 QStringList l = s.split(',');
343 return QRectF(l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(), l.at(3).toDouble()).normalized();
346 QColor TitleDocument::stringToColor(const QString & s)
348 QStringList l = s.split(',');
351 return QColor(l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt(), l.at(3).toInt());;
353 QTransform TitleDocument::stringToTransform(const QString& s)
355 QStringList l = s.split(',');
359 l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(),
360 l.at(3).toDouble(), l.at(4).toDouble(), l.at(5).toDouble(),
361 l.at(6).toDouble(), l.at(7).toDouble(), l.at(8).toDouble()
365 int TitleDocument::frameWidth() const
370 int TitleDocument::frameHeight() const