1 /***************************************************************************
2 * This file is part of KWorship. *
3 * Copyright 2008 James Hogan <james@albanarts.com> *
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. *
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. *
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 ***************************************************************************/
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>
43 #include <KMessageBox>
48 #include <QDomDocument>
49 #include <QDomElement>
55 * Constructors + destructor
58 /// Primary constructor.
59 KwZionworxFilter::KwZionworxFilter()
62 m_importMimeTypes
+= "application/x-zionworx+xml";
63 m_exportMimeTypes
+= "application/x-zionworx+xml";
67 KwZionworxFilter::~KwZionworxFilter()
75 KwDocument
* KwZionworxFilter::load(const KUrl
& url
, const QString
& mimeType
)
77 /// @todo Handle non-local files
78 if (!url
.isLocalFile())
81 i18n("Non-local loads not yet supported"),
88 if (mimeType
== "application/x-zionworx+xml")
90 QFile
file(url
.toLocalFile());
91 if (file
.open(QIODevice::ReadOnly
))
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"),
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")),
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");
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);
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(),
170 else if (itemType
== "siBible")
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]))
179 QString bookName
= rePassage
.cap(1);
180 QString moduleName
= rePassage
.cap(7);
181 /// @todo Try and get a more accurate set of book ids
183 int chapterNum
= rePassage
.cap(2).toInt();
185 int firstVerse
= rePassage
.cap(4).toInt(&validVerse
);
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
)
208 if (!tempHeadings
.isEmpty())
210 verseHeadings
+= QString("<h4>%1</h4>").arg(tempHeadings
.join("<br />\n"));
214 verseHeadings
+= QString();
216 verseContents
+= reVerseLine
.cap(2);
217 tempHeadings
= QStringList();
221 tempHeadings
+= verse
;
226 KMessageBox::error(0,
227 i18n("Problems were encountered reading numbered verses in bible passage %1").arg(item
.firstChildElement("Title").text()),
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
]);
247 KwPlaylistText
* bible
= new KwPlaylistText(item
.firstChildElement("Title").text(),
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())
266 QDomElement fontHeightEl
= fontEl
.firstChildElement("Height");
267 if (!fontHeightEl
.isNull())
270 int height
= fontHeightEl
.text().toInt(&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())
307 QColor colour
= readColour(fontColorEl
, &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");
330 QDomElement shadowWidthEl
= overlayStyleEl
.firstChildElement("ShadowWidth");
331 if (!shadowWidthEl
.isNull())
334 int offset
= shadowWidthEl
.text().toInt(&ok
);
337 overlayStyle
.setStyle
<int>("text.character.shadow.offset", offset
);
340 QDomElement shadowColorEl
= overlayStyleEl
.firstChildElement("ShadowColor");
341 if (!shadowColorEl
.isNull())
344 QColor colour
= readColour(shadowColorEl
, &ok
);
347 overlayStyle
.setStyle
<QBrush
>("text.character.shadow.brush", QBrush(colour
));
352 QDomElement outlineWidthEl
= overlayStyleEl
.firstChildElement("OutlineWidth");
353 int outlineWidth
= 1;
354 if (!outlineWidthEl
.isNull())
357 int width
= outlineWidthEl
.text().toInt(&ok
);
360 outlineWidth
= width
;
363 QDomElement outlineColorEl
= overlayStyleEl
.firstChildElement("OutlineColor");
364 QColor outlineColour
= Qt::black
;
365 if (!outlineColorEl
.isNull())
368 QColor colour
= readColour(outlineColorEl
, &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())
380 QColor colour
= readColour(fillColorEl
, &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");
391 QDomElement marginRightEl
= overlayStyleEl
.firstChildElement("MarginRight");
392 if (!marginRightEl
.isNull())
395 float margin
= marginRightEl
.text().toFloat(&ok
);
398 overlayStyle
.setStyle
<float>("text.layout.margins.right", margin
);
401 QDomElement marginLeftEl
= overlayStyleEl
.firstChildElement("MarginLeft");
402 if (!marginLeftEl
.isNull())
405 float margin
= marginLeftEl
.text().toFloat(&ok
);
408 overlayStyle
.setStyle
<float>("text.layout.margins.left", margin
);
411 QDomElement marginTopEl
= overlayStyleEl
.firstChildElement("MarginTop");
412 if (!marginTopEl
.isNull())
415 float margin
= marginTopEl
.text().toFloat(&ok
);
418 overlayStyle
.setStyle
<float>("text.layout.margins.top", margin
);
421 QDomElement marginBottomEl
= overlayStyleEl
.firstChildElement("MarginBottom");
422 if (!marginBottomEl
.isNull())
425 float margin
= marginBottomEl
.text().toFloat(&ok
);
428 overlayStyle
.setStyle
<float>("text.layout.margins.bottom", margin
);
432 styleRules
->addRule(overlayStyle
);
433 newItem
->addStyleSheet(styleRules
);
436 list
->addItem(newItem
);
440 KMessageBox::error(0,
441 i18n("Unrecognised item type \"%1\"").arg(itemType
),
447 doc
->setModified(false);
453 KMessageBox::error(0,
461 Q_ASSERT(!"Unsupported mime type");
467 /// Contains implementations of export functions.
468 class KwZionworxFilter::ExportToDom
472 /// Write a colour to a string.
473 static QString
writeColour(const QColor
& colour
, bool wierd
)
475 /// @todo Use symbolic colours when possible
478 return QString::number((int32_t)((colour
.red() << 16) | (colour
.green() << 8) | colour
.blue() | 0xFF000000));
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
);
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
;
505 textStyles
+= "fsItalic";
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
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
);
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
);
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
);
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(),
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
);
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(),
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
);
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
);
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())
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
);
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(),
761 static bool done
= false;
764 call
.addImplementation(&list
);
765 call
.addImplementation(&song
);
766 call
.addImplementation(¬e
);
767 call
.addImplementation(&bible
);
768 call
.addImplementation(&presentation
);
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
)
781 /// @todo Handle non-local files
782 if (!url
.isLocalFile())
784 KMessageBox::error(0,
785 i18n("Non-local loads not yet supported"),
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()),
803 QDomElement root
= domDoc
.createElement("Root");
804 domDoc
.appendChild(root
);
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");
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()),
832 doc
->setModified(false);
841 void KwZionworxFilter::v_saveLimitations(KwDocument
* doc
, const QString
& mimeType
, Limitations
* o_limitations
)
843 /// @todo Implement KwZionworxFilter::v_saveLimitations
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
);
863 while (!stream
.atEnd())
865 stream
.readProperty(name
, value
);
866 if (name
== "Strings")
868 // Turn into a QStringList
870 foreach (QVariant item
, value
.toList())
872 result
+= item
.toString();
878 return QStringList();
881 /// Read a colour from DOM.
882 QColor
KwZionworxFilter::readColour(const QDomElement
& el
, bool* ok
) const
886 static QHash
<QString
, QColor
> colours
;
887 static bool inited
= false;
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
;
910 QString colourName
= el
.text();
912 uint32_t colourNum
= colourName
.toInt(&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,
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
];