Silence some unused parameter warnings
[kworship.git] / kworship / filters / zionworx / KwZionworxFilter.cpp
blobf3752fde81fbc02cda07656b2108339ddb214d14
1 /***************************************************************************
2 * This file is part of KWorship. *
3 * Copyright 2008 James Hogan <james@albanarts.com> *
4 * *
5 * KWorship is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation, either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * KWorship is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with KWorship. If not, write to the Free Software Foundation, *
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
20 /**
21 * @file KwZionworxFilter.cpp
22 * @brief Main Zionworx load and save filter.
23 * @author James Hogan <james@albanarts.com>
26 #include "KwZionworxFilter.h"
27 #include "KwPascalStream.h"
28 #include <KwDocument.h>
29 #include <KwArchive.h>
30 #include <KwPlaylistList.h>
31 #include <KwPlaylistText.h>
32 #include <KwPlaylistSong.h>
33 #include <KwSongdbSong.h>
34 #include <KwSongdbVersion.h>
35 #include <KwBiblePlaylistItem.h>
36 #include <KwPlaylistPresentation.h>
37 #include <KwCssStyleRule.h>
38 #include <KwDisplayStyles.h>
40 #include <VTable.h>
42 #include <KUrl>
43 #include <KMessageBox>
44 #include <KLocale>
45 #include <KSaveFile>
47 #include <QFile>
48 #include <QDomDocument>
49 #include <QDomElement>
50 #include <QPen>
52 #include <inttypes.h>
55 * Constructors + destructor
58 /// Primary constructor.
59 KwZionworxFilter::KwZionworxFilter()
60 : KwLoadSaveFilter()
62 m_importMimeTypes += "application/x-zionworx+xml";
63 m_exportMimeTypes += "application/x-zionworx+xml";
66 /// Destructor.
67 KwZionworxFilter::~KwZionworxFilter()
72 * Main interface
75 KwDocument* KwZionworxFilter::load(const KUrl& url, const QString& mimeType)
77 /// @todo Handle non-local files
78 if (!url.isLocalFile())
80 KMessageBox::error(0,
81 i18n("Non-local loads not yet supported"),
82 i18n("KWorship"));
83 return 0;
86 KwDocument* doc = 0;
88 if (mimeType == "application/x-zionworx+xml")
90 QFile file(url.toLocalFile());
91 if (file.open(QIODevice::ReadOnly))
93 QDomDocument domDoc;
94 if (domDoc.setContent(&file))
96 QDomElement root = domDoc.documentElement();
97 QDomElement versionEl = root.firstChildElement("ZionWorx");
98 if (root.tagName() != "Root" || versionEl.isNull())
100 KMessageBox::error(0,
101 i18n("Doesn't look like a ZionWorx playlist"),
102 i18n("KWorship"));
104 else
106 bool versionOk = false;
107 double version = versionEl.attribute("Version").toDouble(&versionOk);
108 if (!versionOk || version != 2.6)
110 KMessageBox::error(0,
111 i18n("Only version 2.6 is supported (version is %1)").arg(versionEl.attribute("Version", "unspecified")),
112 i18n("KWorship"));
114 else
116 doc = new KwDocument(this, mimeType, url);
117 KwPlaylistList* list = new KwPlaylistList();
118 doc->setPlaylist(list);
120 QDomNodeList playlistNodes = root.elementsByTagName("TPlayListNode");
121 for (int i = 0; i < playlistNodes.count(); ++i)
123 QDomElement playlistNode = playlistNodes.at(i).toElement();
124 QDomElement item = playlistNode.firstChildElement("PlayListItem");
125 if (!item.isNull())
127 KwPlaylistItem* newItem = 0;
128 QString biDiText = item.firstChildElement("BiDiMode").text();
129 bool rightToLeft = (biDiText == "bdRightToLeft");
130 QString itemType = item.firstChildElement("ItemType").text();
131 if (itemType == "siPowerPoint")
133 KwPlaylistPresentation* powerpoint = new KwPlaylistPresentation(QUrl(item.firstChildElement("FilenameRelative").text()));
134 powerpoint->setTitle(item.firstChildElement("Title").text());
135 newItem = powerpoint;
137 else if (itemType == "siSong")
139 QString title1 = item.firstChildElement("Title1").text();
140 QString title2 = item.firstChildElement("Title2").text();
141 QString writer = item.firstChildElement("Writer").text();
142 QString copyright = item.firstChildElement("Copyright").text();
143 QString lyricsStr = item.firstChildElement("Lyrics").text();
144 // Remove windows line endings and use newline to split
145 lyricsStr.replace("\r\n", "\n");
146 QStringList lyricsPlain = lyricsStr.split("\n\n");
148 /// @todo Find song in database if possible
149 KwSongdbSong* song = new KwSongdbSong();
150 song->setName(title1);
151 song->setAlternateName(title2);
152 KwSongdbVersion* version = new KwSongdbVersion(song);
153 version->setWriter(writer);
154 version->setCopyright(copyright);
155 version->setLyricsPlainVerses(lyricsPlain);
157 KwPlaylistSong* songItem = new KwPlaylistSong(version, true);
158 newItem = songItem;
160 else if (itemType == "siQuickNote")
162 QStringList quickNote = readStringList(item.firstChildElement("QuickNote"));
163 // Rejoin list and split on blank lines
164 /// @todo Handle more than 2 newlines without losing data
165 quickNote = quickNote.join("\n").split("\n\n");
166 KwPlaylistText* note = new KwPlaylistText(item.firstChildElement("Title").text(),
167 quickNote);
168 newItem = note;
170 else if (itemType == "siBible")
172 bool error = true;
173 QStringList verses = readStringList(item.firstChildElement("Verses"));
174 // Try and understand the passage referred to on the first line.
175 static QRegExp rePassage("^(.*)\\s+(\\d+)(:(\\d+)(-(\\d+))?)?\\s+\\(([^\\)]*)\\).*");
176 if (verses.size() >= 1 && rePassage.exactMatch(verses[0]))
178 error = false;
179 QString bookName = rePassage.cap(1);
180 QString moduleName = rePassage.cap(7);
181 /// @todo Try and get a more accurate set of book ids
182 int bookNum = 0;
183 int chapterNum = rePassage.cap(2).toInt();
184 bool validVerse;
185 int firstVerse = rePassage.cap(4).toInt(&validVerse);
186 if (!validVerse)
188 firstVerse = 1;
190 int nextVerse = firstVerse;
191 QStringList verseHeadings;
192 QStringList verseContents;
193 QStringList tempHeadings;
194 for (int i = 1; i < verses.size(); ++i)
196 const QString& verse = verses[i];
197 // See if it starts with a number, otherwise its a heading
198 static QRegExp reVerseLine("^(\\d+)\\.\\s*(\\S.*)$");
199 if (reVerseLine.exactMatch(verse))
201 int verseNum = reVerseLine.cap(1).toInt();
202 if (verseNum != nextVerse)
204 error = true;
206 nextVerse++;
208 if (!tempHeadings.isEmpty())
210 verseHeadings += QString("<h4>%1</h4>").arg(tempHeadings.join("<br />\n"));
212 else
214 verseHeadings += QString();
216 verseContents += reVerseLine.cap(2);
217 tempHeadings = QStringList();
219 else
221 tempHeadings += verse;
224 if (error)
226 KMessageBox::error(0,
227 i18n("Problems were encountered reading numbered verses in bible passage %1").arg(item.firstChildElement("Title").text()),
228 i18n("KWorship"));
230 else
232 KwBiblePlaylistItem* bible = new KwBiblePlaylistItem();
233 KwBiblePassage& passage = bible->passage();
234 passage.setSource(QString(), moduleName, rightToLeft);
235 passage.initBooks(bookNum,1);
236 passage.initBook(bookNum, bookName, chapterNum, 1);
237 passage.initChapter(bookNum, chapterNum, firstVerse, verseContents.size());
238 for (int i = 0; i < verseContents.size(); ++i)
240 passage.initVerse(bookNum, chapterNum, firstVerse+i, verseHeadings[i], verseContents[i]);
242 newItem = bible;
245 if (error)
247 KwPlaylistText* bible = new KwPlaylistText(item.firstChildElement("Title").text(),
248 verses);
249 newItem = bible;
253 if (0 != newItem)
255 QDomElement overlayStyleEl = playlistNode.firstChildElement("OverlayStyle");
256 if (!overlayStyleEl.isNull())
258 KwCssStyleSheet* styleRules = new KwCssStyleSheet;
259 KwCssStyleRule overlayStyle;
262 QDomElement fontEl = overlayStyleEl.firstChildElement("Font");
263 if (!fontEl.isNull())
265 QFont font;
266 QDomElement fontHeightEl = fontEl.firstChildElement("Height");
267 if (!fontHeightEl.isNull())
269 bool ok;
270 int height = fontHeightEl.text().toInt(&ok);
271 if (ok)
273 font.setPointSize(abs(height));
276 QDomElement fontNameEl = fontEl.firstChildElement("Name");
277 /// @todo Remember font name
278 /// @todo Use font names
279 QDomElement fontStyleEl = fontEl.firstChildElement("Style");
280 if (!fontStyleEl.isNull())
282 static QRegExp reFontStyleList("^\\s*\\[(.*)\\]\\s*$");
283 if (reFontStyleList.exactMatch(fontStyleEl.text()))
285 QStringList styles = reFontStyleList.cap(1).split(",");
286 foreach (QString style, styles)
288 style = style.trimmed();
289 if (style == "fsBold")
291 font.setWeight(QFont::Bold);
293 else if (style == "fsItalic")
295 font.setStyle(QFont::StyleItalic);
301 overlayStyle.setStyle<QFont>("text.character.font", font);
303 QDomElement fontColorEl = fontEl.firstChildElement("Color");
304 if (!fontColorEl.isNull())
306 bool ok;
307 QColor colour = readColour(fontColorEl, &ok);
308 if (ok)
310 overlayStyle.setStyle<QBrush>("text.character.brush", QBrush(colour));
314 QDomElement textStyleEl = overlayStyleEl.firstChildElement("TextStyle");
315 if (!textStyleEl.isNull())
317 QString style = textStyleEl.text();
318 if (style == "tsShadow")
320 overlayStyle.setStyle<bool>("text.character.shadow.enabled", true);
322 else if (style == "tsOutline")
324 overlayStyle.setStyle<bool>("text.character.outline.enabled", true);
327 QDomElement textAlignmentEl = overlayStyleEl.firstChildElement("TextAlignment");
329 // Shadow
330 QDomElement shadowWidthEl = overlayStyleEl.firstChildElement("ShadowWidth");
331 if (!shadowWidthEl.isNull())
333 bool ok;
334 int offset = shadowWidthEl.text().toInt(&ok);
335 if (ok)
337 overlayStyle.setStyle<int>("text.character.shadow.offset", offset);
340 QDomElement shadowColorEl = overlayStyleEl.firstChildElement("ShadowColor");
341 if (!shadowColorEl.isNull())
343 bool ok;
344 QColor colour = readColour(shadowColorEl, &ok);
345 if (ok)
347 overlayStyle.setStyle<QBrush>("text.character.shadow.brush", QBrush(colour));
351 // Outline
352 QDomElement outlineWidthEl = overlayStyleEl.firstChildElement("OutlineWidth");
353 int outlineWidth = 1;
354 if (!outlineWidthEl.isNull())
356 bool ok;
357 int width = outlineWidthEl.text().toInt(&ok);
358 if (ok)
360 outlineWidth = width;
363 QDomElement outlineColorEl = overlayStyleEl.firstChildElement("OutlineColor");
364 QColor outlineColour = Qt::black;
365 if (!outlineColorEl.isNull())
367 bool ok;
368 QColor colour = readColour(outlineColorEl, &ok);
369 if (ok)
371 outlineColour = colour;
374 overlayStyle.setStyle<QPen>("text.character.outline.pen", QPen(outlineColour, outlineWidth));
376 QDomElement fillColorEl = overlayStyleEl.firstChildElement("FillColor");
377 if (!fillColorEl.isNull())
379 bool ok;
380 QColor colour = readColour(fillColorEl, &ok);
381 if (ok)
383 overlayStyle.setStyle<QBrush>("background.brush", QBrush(colour));
386 QDomElement imageFilenameEl = overlayStyleEl.firstChildElement("ImageFilename");
387 //overlayStyle.setStyle<KwResourceLink>("background.image.src", KUrl("file:///home/james/media/images/projector/misc/bible.jpg"));
388 QDomElement imageAlignmentEl = overlayStyleEl.firstChildElement("ImageAlignment");
390 // Margins
391 QDomElement marginRightEl = overlayStyleEl.firstChildElement("MarginRight");
392 if (!marginRightEl.isNull())
394 bool ok;
395 float margin = marginRightEl.text().toFloat(&ok);
396 if (ok)
398 overlayStyle.setStyle<float>("text.layout.margins.right", margin);
401 QDomElement marginLeftEl = overlayStyleEl.firstChildElement("MarginLeft");
402 if (!marginLeftEl.isNull())
404 bool ok;
405 float margin = marginLeftEl.text().toFloat(&ok);
406 if (ok)
408 overlayStyle.setStyle<float>("text.layout.margins.left", margin);
411 QDomElement marginTopEl = overlayStyleEl.firstChildElement("MarginTop");
412 if (!marginTopEl.isNull())
414 bool ok;
415 float margin = marginTopEl.text().toFloat(&ok);
416 if (ok)
418 overlayStyle.setStyle<float>("text.layout.margins.top", margin);
421 QDomElement marginBottomEl = overlayStyleEl.firstChildElement("MarginBottom");
422 if (!marginBottomEl.isNull())
424 bool ok;
425 float margin = marginBottomEl.text().toFloat(&ok);
426 if (ok)
428 overlayStyle.setStyle<float>("text.layout.margins.bottom", margin);
432 styleRules->addRule(overlayStyle);
433 newItem->addStyleSheet(styleRules);
436 list->addItem(newItem);
438 else
440 KMessageBox::error(0,
441 i18n("Unrecognised item type \"%1\"").arg(itemType),
442 i18n("KWorship"));
447 doc->setModified(false);
451 else
453 KMessageBox::error(0,
454 i18n("Invalid XML"),
455 i18n("KWorship"));
459 else
461 Q_ASSERT(!"Unsupported mime type");
464 return doc;
467 /// Contains implementations of export functions.
468 class KwZionworxFilter::ExportToDom
470 public:
472 /// Write a colour to a string.
473 static QString writeColour(const QColor& colour, bool wierd)
475 /// @todo Use symbolic colours when possible
476 if (wierd)
478 return QString::number((int32_t)((colour.red() << 16) | (colour.green() << 8) | colour.blue() | 0xFF000000));
480 else
482 return QString::number((int32_t)(colour.red() | (colour.green() << 8) | (colour.blue() << 16)));
485 static QDomElement createPlaylistNode(QDomDocument& document, QDomElement& element)
487 QDomElement node = document.createElement("TPlayListNode");
488 element.appendChild(node);
489 return node;
491 static QDomElement createOverlayStyle(QDomDocument& document, QDomElement& element, const KwPlaylistItem* item)
493 QDomElement style = document.createElement("OverlayStyle");
495 style.appendChild(document.createTextNode("(TOverlayStyle)"));
497 QDomElement fontEl = document.createElement("Font");
499 fontEl.appendChild(document.createTextNode("(TFont)"));
501 QFont font = KwDisplayStyles::text::character::font(item);
502 QStringList textStyles;
503 if (font.italic())
505 textStyles += "fsItalic";
507 if (font.bold())
509 textStyles += "fsBold";
512 /// @todo find out what this element does, restore from saved
513 QDomElement charsetEl = document.createElement("Charset");
514 charsetEl.appendChild(document.createTextNode("ANSI_CHARSET"));
515 fontEl.appendChild(charsetEl);
517 QDomElement colorEl = document.createElement("Color");
518 colorEl.appendChild(document.createTextNode(writeColour(KwDisplayStyles::text::character::brush(item).color(), false)));
519 fontEl.appendChild(colorEl);
521 /// @todo Handle if font is specified in pixels
522 QDomElement heightEl = document.createElement("Height");
523 heightEl.appendChild(document.createTextNode(QString::number(-font.pointSize())));
524 fontEl.appendChild(heightEl);
526 /// @todo Get a sensible font name here
527 QDomElement nameEl = document.createElement("Name");
528 nameEl.appendChild(document.createTextNode("Tahoma"));
529 fontEl.appendChild(nameEl);
531 QDomElement StyleEl = document.createElement("Style");
532 StyleEl.appendChild(document.createTextNode(QString("[%1]").arg(textStyles.join(","))));
533 fontEl.appendChild(StyleEl);
535 style.appendChild(fontEl);
537 bool outline = KwDisplayStyles::text::character::outline::enabled(item);
538 bool shadow = KwDisplayStyles::text::character::shadow::enabled(item);
539 QDomElement textStyleEl = document.createElement("TextStyle");
540 textStyleEl.appendChild(document.createTextNode(outline ? "tsOutline" : shadow ? "tsShadow" : "tsPlain"));
541 style.appendChild(textStyleEl);
543 /// @todo Implement text alignment saving
544 QDomElement textAlignmentEl = document.createElement("TextAlignment");
545 textAlignmentEl.appendChild(document.createTextNode("taLeft"));
546 style.appendChild(textAlignmentEl);
548 QDomElement shadowWidthEl = document.createElement("ShadowWidth");
549 shadowWidthEl.appendChild(document.createTextNode(QString::number(KwDisplayStyles::text::character::shadow::offset(item))));
550 style.appendChild(shadowWidthEl);
552 QDomElement shadowColorEl = document.createElement("ShadowColor");
553 shadowColorEl.appendChild(document.createTextNode(writeColour(KwDisplayStyles::text::character::shadow::brush(item).color(), true)));
554 style.appendChild(shadowColorEl);
556 QDomElement outlineWidthEl = document.createElement("OutlineWidth");
557 outlineWidthEl.appendChild(document.createTextNode(QString::number(KwDisplayStyles::text::character::outline::pen(item).width())));
558 style.appendChild(outlineWidthEl);
560 QDomElement outlineColorEl = document.createElement("OutlineColor");
561 outlineColorEl.appendChild(document.createTextNode(writeColour(KwDisplayStyles::text::character::outline::pen(item).color(), true)));
562 style.appendChild(outlineColorEl);
564 QDomElement fillColorEl = document.createElement("FillColor");
565 fillColorEl.appendChild(document.createTextNode(writeColour(KwDisplayStyles::background::brush(item).color(), false)));
566 style.appendChild(fillColorEl);
568 /// @todo Implement image filename saving
569 if (0)
571 QDomElement imageFilenameEl = document.createElement("ImageFilename");
572 imageFilenameEl.appendChild(document.createTextNode(""));
573 style.appendChild(imageFilenameEl);
576 /// @todo Implement image alignment saving
577 QDomElement imageAlignmentEl = document.createElement("ImageAlignment");
578 imageAlignmentEl.appendChild(document.createTextNode("iaStretch"));
579 style.appendChild(imageAlignmentEl);
581 QDomElement marginRightEl = document.createElement("MarginRight");
582 marginRightEl.appendChild(document.createTextNode(QString::number(KwDisplayStyles::text::layout::margins::right(item))));
583 style.appendChild(marginRightEl);
585 QDomElement marginLeftEl = document.createElement("MarginLeft");
586 marginLeftEl.appendChild(document.createTextNode(QString::number(KwDisplayStyles::text::layout::margins::left(item))));
587 style.appendChild(marginLeftEl);
589 QDomElement marginTopEl = document.createElement("MarginTop");
590 marginTopEl.appendChild(document.createTextNode(QString::number(KwDisplayStyles::text::layout::margins::top(item))));
591 style.appendChild(marginTopEl);
593 QDomElement marginBottomEl = document.createElement("MarginBottom");
594 marginBottomEl.appendChild(document.createTextNode(QString::number(KwDisplayStyles::text::layout::margins::bottom(item))));
595 style.appendChild(marginBottomEl);
597 element.appendChild(style);
598 return style;
600 static QDomElement createPlaylistItem(QDomDocument& document, QDomElement& element,
601 const QString& type, const QString& title, bool rightToLeft)
603 QDomElement item = document.createElement("PlayListItem");
605 QDomElement typeEl = document.createElement("ItemType");
606 typeEl.appendChild(document.createTextNode(type));
607 item.appendChild(typeEl);
610 QDomElement titleEl = document.createElement("Title");
611 titleEl.appendChild(document.createTextNode(title));
612 item.appendChild(titleEl);
615 QDomElement biDiEl = document.createElement("BiDiMode");
616 biDiEl.appendChild(document.createTextNode(rightToLeft ? "bdRightToLeft" : "bdLeftToRight"));
617 item.appendChild(biDiEl);
619 element.appendChild(item);
620 return item;
622 static int list(const KwPlaylistList* self, QDomDocument& document, QDomElement& element)
624 for (int i = 0; i < self->getItemCount(); ++i)
626 call(self->getItem(i), document, element);
628 return 0;
630 static int song(const KwPlaylistSong* self, QDomDocument& document, QDomElement& element)
632 QDomElement node = createPlaylistNode(document, element);
633 QDomElement style = createOverlayStyle(document, node, self);
634 const KwSongdbVersion* version = self->getSongVersion();
635 const KwSongdbSong* song = version->song();
636 /// @todo Store and reload right to leftness of songs.
637 QDomElement item = createPlaylistItem(document, node,
638 "siSong", song->name(),
639 false);
641 QDomElement title1El = document.createElement("Title1");
642 if (!song->name().isEmpty())
644 title1El.appendChild(document.createTextNode(song->name()));
646 item.appendChild(title1El);
648 QDomElement title2El = document.createElement("Title2");
649 if (!song->alternateName().isEmpty())
651 title2El.appendChild(document.createTextNode(song->alternateName()));
653 item.appendChild(title2El);
655 QString lyrics = version->lyrics().plainVerses().join("\n\n");
656 QDomElement lyricsEl = document.createElement("Lyrics");
657 lyricsEl.appendChild(document.createTextNode(lyrics));
658 item.appendChild(lyricsEl);
660 QDomElement writerEl = document.createElement("Writer");
661 if (!version->writer().isEmpty())
663 writerEl.appendChild(document.createTextNode(version->writer()));
665 item.appendChild(writerEl);
667 QDomElement copyrightEl = document.createElement("Copyright");
668 if (!version->copyright().isEmpty())
670 copyrightEl.appendChild(document.createTextNode(version->copyright()));
672 item.appendChild(copyrightEl);
673 return 0;
675 static int note(const KwPlaylistText* self, QDomDocument& document, QDomElement& element)
677 QDomElement node = createPlaylistNode(document, element);
678 QDomElement style = createOverlayStyle(document, node, self);
679 /// @todo Get bi di from text item
680 QDomElement item = createPlaylistItem(document, node,
681 "siQuickNote", self->getLabel(),
682 false);
684 QDomElement quickNoteEl = document.createElement("QuickNote");
685 quickNoteEl.appendChild(document.createTextNode("(TTntStringList)"));
687 QDomElement definedPropsEl = document.createElement("DefinedProperties");
688 QByteArray propsData;
689 KwPascalStream data(&propsData, QIODevice::WriteOnly);
691 QStringList quickNote = self->blocks();
692 // resplit on newlines
693 quickNote = quickNote.join("\n\n").split('\n');
694 data.writeProperty("Strings", quickNote);
696 propsData = propsData.toBase64();
697 definedPropsEl.appendChild(document.createTextNode(propsData));
698 quickNoteEl.appendChild(definedPropsEl);
700 item.appendChild(quickNoteEl);
701 return 0;
703 static int bible(const KwBiblePlaylistItem* self, QDomDocument& document, QDomElement& element)
705 QDomElement node = createPlaylistNode(document, element);
706 QDomElement style = createOverlayStyle(document, node, self);
707 const KwBiblePassage& passage = self->passage();
708 QDomElement item = createPlaylistItem(document, node,
709 "siBible", passage.textualKey(),
710 passage.isRightToLeft());
712 QDomElement versesEl = document.createElement("Verses");
713 versesEl.appendChild(document.createTextNode("(TTntStringList)"));
715 QDomElement definedPropsEl = document.createElement("DefinedProperties");
716 QByteArray propsData;
717 KwPascalStream data(&propsData, QIODevice::WriteOnly);
719 QStringList verses;
720 verses << passage.textualKey();
721 for (int book = passage.firstBookNumber(); book <= passage.lastBookNumber(); ++book)
723 for (int chap = passage.firstChapterNumber(book); chap <= passage.lastChapterNumber(book); ++chap)
725 for (int verse = passage.firstVerseNumber(book, chap); verse <= passage.lastVerseNumber(book, chap); ++verse)
727 const QString& headings = passage.verseHeadings(book, chap, verse, true);
728 if (!headings.isEmpty())
730 verses += headings;
732 const QString& content = passage.verseContent(book, chap, verse, true);
733 if (!content.isEmpty())
735 verses += i18nc("Verse number, bible verse, for zionworx export", "%1. %2").arg(verse).arg(content);
740 data.writeProperty("Strings", verses);
742 propsData = propsData.toBase64();
743 definedPropsEl.appendChild(document.createTextNode(propsData));
744 versesEl.appendChild(definedPropsEl);
746 item.appendChild(versesEl);
747 return 0;
749 static int presentation(const KwPlaylistPresentation* self, QDomDocument& document, QDomElement& element)
751 QDomElement node = createPlaylistNode(document, element);
752 QDomElement item = createPlaylistItem(document, node,
753 "siPowerPoint", self->title(),
754 false);
756 return 0;
759 static void init()
761 static bool done = false;
762 if (!done)
764 call.addImplementation(&list);
765 call.addImplementation(&song);
766 call.addImplementation(&note);
767 call.addImplementation(&bible);
768 call.addImplementation(&presentation);
769 done = true;
773 typedef VTable<const KwPlaylistItem, int (*)(QDomDocument& document, QDomElement& element)> ExportVTable;
774 static ExportVTable call;
776 KwZionworxFilter::ExportToDom::ExportVTable KwZionworxFilter::ExportToDom::call;
778 bool KwZionworxFilter::save(KwDocument* doc, const KUrl& url, const QString& mimeType)
780 Q_UNUSED(mimeType);
781 /// @todo Handle non-local files
782 if (!url.isLocalFile())
784 KMessageBox::error(0,
785 i18n("Non-local loads not yet supported"),
786 i18n("KWorship"));
787 return false;
789 KSaveFile file;
790 file.setFileName(url.toLocalFile());
791 if (!file.open(QFile::WriteOnly))
793 KMessageBox::error(0,
794 i18n("Cannot write file %1:\n%2.")
795 .arg(file.fileName())
796 .arg(file.errorString()),
797 i18n("KWorship"));
798 return false;
801 // Create document
802 QDomDocument domDoc;
803 QDomElement root = domDoc.createElement("Root");
804 domDoc.appendChild(root);
806 // Version element
807 QDomElement version = domDoc.createElement("ZionWorx");
808 version.setAttribute("Version", 2.6);
809 version.setAttribute("FullFilename", url.toLocalFile());
810 root.appendChild(version);
812 // Playlist nodes element
813 QDomElement playlist = domDoc.createElement("PlayListNodes");
814 ExportToDom::init();
815 ExportToDom::call(doc->playlist(), domDoc, playlist);
816 root.appendChild(playlist);
818 // Write document to file
819 QByteArray xml = domDoc.toByteArray(2);
820 file.write(xml, xml.size());
822 if (!file.finalize())
824 KMessageBox::error(0,
825 i18n("Cannot finalize file %1:\n%2.")
826 .arg(file.fileName())
827 .arg(file.errorString()),
828 i18n("KWorship"));
829 return false;
832 doc->setModified(false);
834 return true;
838 * Virtual interface
841 void KwZionworxFilter::v_saveLimitations(KwDocument* doc, const QString& mimeType, Limitations* o_limitations)
843 /// @todo Implement KwZionworxFilter::v_saveLimitations
844 Q_ASSERT(false);
848 * Private functions
851 /// Read a TTntStringList from DOM.
852 QStringList KwZionworxFilter::readStringList(const QDomElement& el) const
854 // Go straight to the <DefinedProperties>
855 QDomElement definedProperties = el.firstChildElement("DefinedProperties");
856 if (!definedProperties.isNull())
858 const QByteArray buf = QByteArray::fromBase64(definedProperties.text().toAscii());
860 KwPascalStream stream(&buf);
861 QByteArray name;
862 QVariant value;
863 while (!stream.atEnd())
865 stream.readProperty(name, value);
866 if (name == "Strings")
868 // Turn into a QStringList
869 QStringList result;
870 foreach (QVariant item, value.toList())
872 result += item.toString();
874 return result;
878 return QStringList();
881 /// Read a colour from DOM.
882 QColor KwZionworxFilter::readColour(const QDomElement& el, bool* ok) const
884 bool isOk = false;
886 static QHash<QString, QColor> colours;
887 static bool inited = false;
888 if (!inited)
890 colours["clWhite"] = Qt::white;
891 colours["clBlack"] = Qt::black;
892 colours["clRed"] = Qt::red;
893 colours["clDarkRed"] = Qt::darkRed;
894 colours["clGreen"] = Qt::green;
895 colours["clDarkGreen"] = Qt::darkGreen;
896 colours["clBlue"] = Qt::blue;
897 colours["clDarkBlue"] = Qt::darkBlue;
898 colours["clCyan"] = Qt::cyan;
899 colours["clDarkCyan"] = Qt::darkCyan;
900 colours["clMagenta"] = Qt::magenta;
901 colours["clDarkMagenta"] = Qt::darkMagenta;
902 colours["clYellow"] = Qt::yellow;
903 colours["clDarkGray"] = Qt::darkYellow;
904 colours["clGray"] = Qt::gray;
905 colours["clDarkGray"] = Qt::darkGray;
906 colours["clLightGray"] = Qt::lightGray;
907 inited = true;
910 QString colourName = el.text();
911 QColor result;
912 uint32_t colourNum = colourName.toInt(&isOk);
913 if (isOk)
915 // 0xff in msb apparently changes byte order
916 if (((colourNum >> 24) & 0xFF) == 0xFF)
918 // least significant byte is blue, followed by green and red
919 result.setRgb((colourNum >> 16) & 0xFF,
920 (colourNum >> 8) & 0xFF,
921 colourNum & 0xFF);
923 else
925 // least significant byte is red, followed by green and blue
926 result.setRgb( colourNum & 0xFF,
927 (colourNum >> 8) & 0xFF,
928 (colourNum >> 16) & 0xFF);
931 else if (colours.contains(colourName))
933 result = colours[colourName];
934 isOk = true;
937 if (0 != ok)
939 *ok = isOk;
941 return result;