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:
@@ -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
|
||||
-----
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,6 @@ private:
|
||||
Action *exportAction;
|
||||
Action *addAction;
|
||||
Action *editAction;
|
||||
QAction *importFileAction;
|
||||
QAction *importIceCastAction;
|
||||
QAction *importSomaFmCastAction;
|
||||
StreamsProxyModel proxy;
|
||||
|
||||
Reference in New Issue
Block a user