Add import/export of Streams XML files - these contians just streams, without categories. The intention is to be able to import these into MPDroid.

This commit is contained in:
craig.p.drummond
2013-06-07 19:21:59 +00:00
parent 9125bc5d5a
commit 6ee798eed5
5 changed files with 71 additions and 35 deletions

View File

@@ -51,6 +51,9 @@
33. Automatic accelator assignment for Qt builds.
34. Add cmake check to see if TagLib has id3version in MPEG save.
35. RTL fixes.
36. Add import/export of Streams XML files - these contians just streams,
without categories. The intention is to be able to import these into
MPDroid.
1.0.3
-----

View File

@@ -390,29 +390,32 @@ bool StreamsModel::load(QIODevice *dev, bool isInternal)
{
QXmlStreamReader doc(dev);
bool haveInserted=false;
int level=0;
CategoryItem *cat=0;
QString unknown=i18n("Unknown");
QString import=i18n("Import");
while (!doc.atEnd()) {
doc.readNext();
if (doc.isStartElement()) {
++level;
if (2==level && QLatin1String("category")==doc.name()) {
if (QLatin1String("category")==doc.name()) {
QString catName=doc.attributes().value("name").toString();
QString catIcon=doc.attributes().value("icon").toString();
cat=getCategory(catName, true, !isInternal);
if (cat && cat->icon.isEmpty() && !catIcon.isEmpty()) {
cat->icon=catIcon;
}
} else if (cat && 3==level && QLatin1String("stream")==doc.name()) {
} else if (QLatin1String("stream")==doc.name()) {
QString name=doc.attributes().value("name").toString();
QString icon=doc.attributes().value("icon").toString();
QString genre=doc.attributes().value("genre").toString();
QString origName=name;
QUrl url=QUrl(doc.attributes().value("url").toString());
if (!cat) {
cat=getCategory(isInternal ? unknown : import, true, !isInternal);
}
if (!name.isEmpty() && url.isValid() && (isInternal || !entryExists(cat, QString(), url))) {
int i=1;
for (; i<100 && entryExists(cat, name); ++i) {
@@ -436,8 +439,7 @@ bool StreamsModel::load(QIODevice *dev, bool isInternal)
}
}
} else if (doc.isEndElement()) {
--level;
if (2==level && QLatin1String("category")==doc.name()) {
if (QLatin1String("category")==doc.name()) {
cat=0;
}
}
@@ -454,41 +456,49 @@ bool StreamsModel::load(QIODevice *dev, bool isInternal)
return haveInserted;
}
bool StreamsModel::save(const QString &filename, const QSet<StreamsModel::Item *> &selection)
bool StreamsModel::save(const QString &filename, const QSet<StreamsModel::Item *> &selection, bool streamsOnly)
{
QFile file(filename);
QtIOCompressor compressor(&file);
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
if (!compressor.open(QIODevice::WriteOnly)) {
return false;
}
QXmlStreamWriter doc(&compressor);
if (streamsOnly) {
return file.open(QIODevice::WriteOnly) && save(&file, selection, streamsOnly, true);
} else {
QtIOCompressor compressor(&file);
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
return compressor.open(QIODevice::WriteOnly) && save(&compressor, selection, streamsOnly, filename!=getInternalFile(false));
}
}
bool StreamsModel::save(QIODevice *dev, const QSet<StreamsModel::Item *> &selection, bool streamsOnly, bool format)
{
QXmlStreamWriter doc(dev);
doc.writeStartDocument();
doc.writeStartElement("streams");
doc.writeAttribute("version", "1.0");
if (filename==getInternalFile(false)) {
doc.setAutoFormatting(false);
} else {
if (format) {
doc.setAutoFormatting(true);
doc.setAutoFormattingIndent(1);
} else {
doc.setAutoFormatting(false);
}
QString unknown=i18n("Unknown");
foreach (CategoryItem *c, items) {
if (selection.isEmpty() || selection.contains(c)) {
doc.writeStartElement("category");
doc.writeAttribute("name", c->name);
if (!c->icon.isEmpty()) {
doc.writeAttribute("icon", c->icon);
if (!streamsOnly) {
doc.writeStartElement("category");
doc.writeAttribute("name", c->name);
if (!c->icon.isEmpty()) {
doc.writeAttribute("icon", c->icon);
}
}
foreach (StreamItem *s, c->streams) {
if (selection.isEmpty() || selection.contains(s)) {
doc.writeStartElement("stream");
doc.writeAttribute("name", s->name);
doc.writeAttribute("url", s->url.toString());
if (!s->icon.isEmpty()) {
if (!streamsOnly && !s->icon.isEmpty()) {
doc.writeAttribute("icon", s->icon);
}
QSet<QString> genres=s->genres;
@@ -499,7 +509,9 @@ bool StreamsModel::save(const QString &filename, const QSet<StreamsModel::Item *
doc.writeEndElement();
}
}
doc.writeEndElement();
if (!streamsOnly) {
doc.writeEndElement();
}
}
}
doc.writeEndElement();

View File

@@ -92,7 +92,7 @@ public:
QVariant data(const QModelIndex &, int) const;
void reload();
void save(bool force=false);
bool save(const QString &filename, const QSet<StreamsModel::Item *> &selection=QSet<StreamsModel::Item *>());
bool save(const QString &filename, const QSet<StreamsModel::Item *> &selection=QSet<StreamsModel::Item *>(), bool streamsOnly=false);
bool import(const QString &filename) { return load(filename, false); }
bool add(const QString &cat, const QString &name, const QString &genre, const QString &icon, const QString &url);
void add(const QString &cat, const QString &icon, const QList<StreamsModel::StreamItem *> &streams);
@@ -128,6 +128,7 @@ private Q_SLOTS:
void downloadFinished();
private:
bool save(QIODevice *dev, const QSet<StreamsModel::Item *> &selection, bool streamsOnly, bool format);
void clearCategories();
bool load(const QString &filename, bool isInternal);
bool load(QIODevice *dev, bool isInternal);

View File

@@ -47,6 +47,7 @@
#include <QFileInfo>
static const char * constUrlProperty("url");
static const char * constStreamsOnly("streamsOnly");
StreamsPage::StreamsPage(QWidget *p)
: QWidget(p)
@@ -60,7 +61,7 @@ StreamsPage::StreamsPage(QWidget *p)
editAction = ActionCollection::get()->createAction("editstream", i18n("Edit"), Icons::editIcon);
QMenu *importMenu=new QMenu(this);
importFileAction=importMenu->addAction("From Cantata File");
QAction *importFileAction=importMenu->addAction("From File");
QList<WebStream *> webStreams=WebStream::getAll();
QAction *radioAction=0;
QMenu *radioMenu=0;
@@ -95,6 +96,14 @@ StreamsPage::StreamsPage(QWidget *p)
}
importAction->setMenu(importMenu);
QMenu *exportMenu=new QMenu(this);
QAction *exportCantataFileAction=exportMenu->addAction("Streams And Categories");
exportCantataFileAction->setProperty(constStreamsOnly, false);
QAction *exportStreamsFileAction=exportMenu->addAction("Streams Only");
exportStreamsFileAction->setProperty(constStreamsOnly, true);
exportAction->setMenu(exportMenu);
replacePlayQueue->setDefaultAction(StdActions::self()->replacePlayQueueAction);
// connect(view, SIGNAL(itemsSelected(bool)), addToPlaylist, SLOT(setEnabled(bool)));
connect(view, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(itemDoubleClicked(const QModelIndex &)));
@@ -103,7 +112,8 @@ StreamsPage::StreamsPage(QWidget *p)
connect(addAction, SIGNAL(triggered(bool)), this, SLOT(add()));
connect(editAction, SIGNAL(triggered(bool)), this, SLOT(edit()));
connect(importFileAction, SIGNAL(triggered(bool)), this, SLOT(importXml()));
connect(exportAction, SIGNAL(triggered(bool)), this, SLOT(exportXml()));
connect(exportCantataFileAction, SIGNAL(triggered(bool)), this, SLOT(exportXml()));
connect(exportStreamsFileAction, SIGNAL(triggered(bool)), this, SLOT(exportXml()));
connect(genreCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(searchItems()));
connect(StreamsModel::self(), SIGNAL(updateGenres(const QSet<QString> &)), genreCombo, SLOT(update(const QSet<QString> &)));
connect(StreamsModel::self(), SIGNAL(error(const QString &)), this, SIGNAL(error(const QString &)));
@@ -255,9 +265,10 @@ void StreamsPage::importXml()
return;
}
#ifdef ENABLE_KDE_SUPPORT
QString fileName=KFileDialog::getOpenFileName(KUrl(), i18n("*.cantata|Cantata Streams"), this, i18n("Import Streams"));
QString fileName=KFileDialog::getOpenFileName(KUrl(), i18n("*.cantata|Cantata Streams\n*.xml|XML Streams"), this, i18n("Import Streams"));
#else
QString fileName=QFileDialog::getOpenFileName(this, i18n("Import Streams"), QDir::homePath(), i18n("Cantata Streams (*.cantata)"));
QString fileName=QFileDialog::getOpenFileName(this, i18n("Import Streams"), QDir::homePath(),
i18n("Cantata Streams (*.cantata)\nXML Streams (*.xml)"));
#endif
if (fileName.isEmpty()) {
@@ -271,6 +282,8 @@ void StreamsPage::importXml()
void StreamsPage::exportXml()
{
QAction *act=qobject_cast<QAction *>(sender());
bool streamsOnly=act && act->property(constStreamsOnly).toBool();
QModelIndexList selected=view->selectedIndexes();
QSet<StreamsModel::Item *> items;
QSet<StreamsModel::Item *> categories;
@@ -290,22 +303,30 @@ void StreamsPage::exportXml()
}
}
QString name;
QLatin1String ext(streamsOnly ? ".xml" : ".cantata");
QString name=1==categories.count()
? static_cast<StreamsModel::StreamItem *>(*(categories.begin()))->name+ext
: QLatin1String("Cantata")+ext;
if (1==categories.count()) {
name=static_cast<StreamsModel::StreamItem *>(*(categories.begin()))->name+QLatin1String(".cantata");
}
#ifdef ENABLE_KDE_SUPPORT
QString fileName=KFileDialog::getSaveFileName(name, i18n("*.cantata|Cantata Streams"), this, i18n("Export Streams"));
QString fileName=streamsOnly
? KFileDialog::getSaveFileName(name, i18n("*.xml|XML Streams"), this, i18n("Export Streams"))
: KFileDialog::getSaveFileName(name, i18n("*.cantata|Cantata Streams"), this, i18n("Streams And Categories"));
#else
QString fileName=QFileDialog::getSaveFileName(this, i18n("Export Streams"), name, i18n("Cantata Streams (*.cantata)"));
QString fileName=streamsOnly
? QFileDialog::getSaveFileName(this, i18n("Export Streams"), name, i18n("XML Streams (*.xml)"))
: QFileDialog::getSaveFileName(this, i18n("Streams And Categories"), name, i18n("Cantata Streams (*.cantata)"));
#endif
if (fileName.isEmpty()) {
return;
}
if (!StreamsModel::self()->save(fileName, categories+items)) {
if (!fileName.endsWith(ext)) {
fileName+=ext;
}
if (!StreamsModel::self()->save(fileName, categories+items, streamsOnly)) {
MessageBox::error(this, i18n("Failed to create <b>%1</b>!").arg(fileName));
}
}

View File

@@ -83,7 +83,6 @@ private:
Action *exportAction;
Action *addAction;
Action *editAction;
QAction *importFileAction;
QAction *importIceCastAction;
QAction *importSomaFmCastAction;
StreamsProxyModel proxy;