Simplify streams page
@@ -92,7 +92,7 @@ set(CANTATA_SRCS gui/application.cpp gui/main.cpp gui/initialsettingswizard.cpp
|
||||
gui/settings.cpp gui/covers.cpp gui/filesettings.cpp gui/interfacesettings.cpp gui/playbacksettings.cpp
|
||||
gui/serversettings.cpp gui/librarypage.cpp gui/albumspage.cpp gui/folderpage.cpp gui/playlistspage.cpp gui/trayitem.cpp
|
||||
gui/cachesettings.cpp gui/coverdialog.cpp gui/stdactions.cpp
|
||||
streams/streamspage.cpp streams/streamdialog.cpp streams/streamcategorydialog.cpp streams/streamfetcher.cpp streams/webstreams.cpp
|
||||
streams/streamspage.cpp streams/streamdialog.cpp streams/streamfetcher.cpp
|
||||
models/musiclibraryitemroot.cpp models/musiclibraryitemartist.cpp models/musiclibraryitemalbum.cpp models/musiclibrarymodel.cpp
|
||||
models/musiclibraryproxymodel.cpp models/playlistsmodel.cpp models/playlistsproxymodel.cpp models/playqueuemodel.cpp
|
||||
models/playqueueproxymodel.cpp models/dirviewmodel.cpp models/dirviewproxymodel.cpp models/dirviewitem.cpp models/dirviewitemdir.cpp
|
||||
@@ -114,7 +114,7 @@ set(CANTATA_MOC_HDRS
|
||||
gui/initialsettingswizard.h gui/mainwindow.h gui/settings.h gui/covers.h gui/folderpage.h gui/librarypage.h gui/albumspage.h
|
||||
gui/playlistspage.h gui/playbacksettings.h gui/serversettings.h gui/preferencesdialog.h gui/filesettings.h
|
||||
gui/interfacesettings.h gui/cachesettings.h gui/trayitem.h gui/coverdialog.h
|
||||
streams/streamspage.h streams/streamdialog.h streams/streamcategorydialog.h streams/streamfetcher.h streams/webstreams.h
|
||||
streams/streamspage.h streams/streamdialog.h streams/streamfetcher.h
|
||||
models/musiclibrarymodel.h models/musiclibraryproxymodel.h models/playlistsmodel.h models/playlistsproxymodel.h models/playqueuemodel.h
|
||||
models/playqueueproxymodel.h models/dirviewmodel.h models/dirviewproxymodel.h models/albumsmodel.h models/streamsmodel.h
|
||||
models/actionmodel.h
|
||||
@@ -402,8 +402,7 @@ endif (MSVC)
|
||||
|
||||
add_subdirectory(po)
|
||||
add_subdirectory(support)
|
||||
add_subdirectory(streams/icons)
|
||||
|
||||
|
||||
if (ENABLE_KDE_SUPPORT)
|
||||
include_directories(${KDE4_INCLUDES})
|
||||
add_definitions(${KDE4_DEFINITIONS})
|
||||
|
||||
64
ChangeLog
@@ -51,56 +51,54 @@
|
||||
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.
|
||||
37. For Qt4 linux builds, use system QJson if found.
|
||||
38. Remove amazon cover fetching - required API key that Cantata never really
|
||||
36. For Qt4 linux builds, use system QJson if found.
|
||||
37. Remove amazon cover fetching - required API key that Cantata never really
|
||||
had.
|
||||
39. Add debug logging. Please see README for details.
|
||||
40. Enable MPD HTTP stream playback using QtMultiMedia for Qt5 builds. Thanks
|
||||
38. Add debug logging. Please see README for details.
|
||||
39. Enable MPD HTTP stream playback using QtMultiMedia for Qt5 builds. Thanks
|
||||
to Marcel Bosling for the patch. Disabled by default, to enable pass
|
||||
-DENABLE_HTTP_STREAM_PLAYBACK=ON to cmake.
|
||||
41. Fix Qt5 segfault on exit, due to static QIcons being destructed.
|
||||
42. Work-around Qt5 bug where toolbuttons (usually with menus) stay in the
|
||||
40. Fix Qt5 segfault on exit, due to static QIcons being destructed.
|
||||
41. Work-around Qt5 bug where toolbuttons (usually with menus) stay in the
|
||||
raised state.
|
||||
43. Add port number to library cache filename, to cater for scenarios where
|
||||
42. Add port number to library cache filename, to cater for scenarios where
|
||||
there is more than 1 server on the same host.
|
||||
44. Fix retrieval of covers in albums view for multiple-artist albums when
|
||||
43. Fix retrieval of covers in albums view for multiple-artist albums when
|
||||
these are configured to be grouped under "Various Artists"
|
||||
45. Refresh albums view when multiple-artist grouping is changed.
|
||||
46. Add context menu to replygain and file organizer dialogs to remove items
|
||||
44. Refresh albums view when multiple-artist grouping is changed.
|
||||
45. Add context menu to replygain and file organizer dialogs to remove items
|
||||
from list.
|
||||
47. Also use discogs for artist images in cover dialog.
|
||||
48. Fix invalid covers showing for online services.
|
||||
49. For Qt builds, if shortcut is set to default then remove entry from config
|
||||
46. Also use discogs for artist images in cover dialog.
|
||||
47. Fix invalid covers showing for online services.
|
||||
48. For Qt builds, if shortcut is set to default then remove entry from config
|
||||
file.
|
||||
50. Don't show page shortcuts in tooltips, as tooltip is not updated when
|
||||
49. Don't show page shortcuts in tooltips, as tooltip is not updated when
|
||||
shortcut is changed.
|
||||
51. Check that perl is installed before attempting to start cantata-dynamic in
|
||||
50. Check that perl is installed before attempting to start cantata-dynamic in
|
||||
local mode.
|
||||
52. If cantata-dynamic is started in server mode, then have it create any
|
||||
51. If cantata-dynamic is started in server mode, then have it create any
|
||||
missing folders.
|
||||
53. Simpler proxy settings.
|
||||
54. Delay loading of local devices at atart-up, so that we have time to add
|
||||
52. Simpler proxy settings.
|
||||
53. Delay loading of local devices at atart-up, so that we have time to add
|
||||
device to view before try to expand it.
|
||||
55. If cantata-dynamic is started in server mode, then communicate status via
|
||||
54. If cantata-dynamic is started in server mode, then communicate status via
|
||||
UDP multicast messages.
|
||||
56. If using server mode cantata-dynamic and this is not started, then show an
|
||||
55. If using server mode cantata-dynamic and this is not started, then show an
|
||||
error message in dynamic page.
|
||||
57. Fix keyboard shortcuts of tab pages.
|
||||
58. Add support for a simple profile where MPD is started by cantata, and
|
||||
56. Fix keyboard shortcuts of tab pages.
|
||||
57. Add support for a simple profile where MPD is started by cantata, and
|
||||
the only settings are the music folder and cover names.
|
||||
59. Combine Output and Playback config pages.
|
||||
60. Remove proxy config from settings, and always use system proxy.
|
||||
58. Combine Output and Playback config pages.
|
||||
59. Remove proxy config from settings, and always use system proxy.
|
||||
To re-enable proxy settings pass -DENABLE_PROXY_CONFIG=ON to cmake.
|
||||
61. Add option to draw curent album cover as backdrop to play queue.
|
||||
62. Add 'Copy Songs To Device' action to playlists page.
|
||||
63. Copy Qt5 Linux system proxy code for Qt4 builds.
|
||||
64. Embed pre-rendered PNG versions of cantata icon, to help with Qt5 builds
|
||||
60. Add option to draw curent album cover as backdrop to play queue.
|
||||
61. Add 'Copy Songs To Device' action to playlists page.
|
||||
62. Copy Qt5 Linux system proxy code for Qt4 builds.
|
||||
63. Embed pre-rendered PNG versions of cantata icon, to help with Qt5 builds
|
||||
on systems that do not have the Qt SVG icon engine installed.
|
||||
65. Add support for importing Digitally Imported, Jazz Radio, and Sky.fm
|
||||
streams. Only free, ad supported, streams at the moment.
|
||||
64. Simplify streams page. Remove user-categories, instead have a set of
|
||||
predefined top-level items; Favourites (user streams), TuneIn, IceCast,
|
||||
SomaFM, Digitially Imported, Jazz Radio, and Sky.fm.
|
||||
|
||||
1.0.3
|
||||
-----
|
||||
|
||||
10
cantata.qrc
@@ -1,7 +1,6 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file alias="lyrics.xml">context/ultimate_providers.xml</file>
|
||||
<file alias="streams.xml">streams/providers.xml</file>
|
||||
<file alias="weblinks.xml">context/weblinks.xml</file>
|
||||
<file alias="repeat16.png">icons/view-media-repeat16.png</file>
|
||||
<file alias="repeat22.png">icons/view-media-repeat22.png</file>
|
||||
@@ -11,7 +10,6 @@
|
||||
<file alias="shuffle22.png">icons/view-media-shuffle22.png</file>
|
||||
<file alias="shuffle32.png">icons/view-media-shuffle32.png</file>
|
||||
<file alias="shuffle48.png">icons/view-media-shuffle48.png</file>
|
||||
|
||||
<file alias="sidebar-albums-dark">icons/sidebar-albums-dark.svg</file>
|
||||
<file alias="sidebar-artists-dark">icons/sidebar-artists-dark.svg</file>
|
||||
<file alias="sidebar-devices-dark">icons/sidebar-devices-dark.svg</file>
|
||||
@@ -32,5 +30,13 @@
|
||||
<file alias="sidebar-playlists-light">icons/sidebar-playlists-light.svg</file>
|
||||
<file alias="sidebar-playqueue-light">icons/sidebar-playqueue-light.svg</file>
|
||||
<file alias="sidebar-streams-light">icons/sidebar-streams-light.svg</file>
|
||||
<file alias="streams-icecast">icons/streams-icecast.svg</file>
|
||||
<file alias="streams-shoutcast">icons/streams-shoutcast.png</file>
|
||||
<file alias="streams-favourites">icons/streams-favourites.svg</file>
|
||||
<file alias="streams-tunein">icons/streams-tunein.png</file>
|
||||
<file alias="streams-digitallyimported">icons/streams-digitallyimported.png</file>
|
||||
<file alias="streams-somafm">icons/streams-somafm.png</file>
|
||||
<file alias="streams-skyfm">icons/streams-skyfm.png</file>
|
||||
<file alias="streams-jazzradio">icons/streams-jazzradio.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Save list of streams in music folder:</string>
|
||||
<string>Save list of favourite streams in music folder:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>storeStreamsInMpdDir</cstring>
|
||||
|
||||
@@ -744,7 +744,7 @@
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="storeStreamsInMpdDirLabel">
|
||||
<property name="text">
|
||||
<string>Save list of streams in music folder:</string>
|
||||
<string>Save list of favourite streams in music folder:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>storeStreamsInMpdDir</cstring>
|
||||
|
||||
@@ -2192,25 +2192,13 @@ void MainWindow::addToExistingStoredPlaylist(const QString &name, bool pq)
|
||||
|
||||
void MainWindow::addStreamToPlayQueue()
|
||||
{
|
||||
// Need to load streams, if not already loaded - so that we can get list of categories/genres...
|
||||
if (!(loaded&TAB_STREAMS)) {
|
||||
loaded|=TAB_STREAMS;
|
||||
streamsPage->refresh();
|
||||
}
|
||||
|
||||
StreamDialog dlg(streamsPage->getCategories(), streamsPage->getGenres(), this, true);
|
||||
StreamDialog dlg(this, true);
|
||||
|
||||
if (QDialog::Accepted==dlg.exec()) {
|
||||
QString url=dlg.url();
|
||||
|
||||
if (dlg.save()) {
|
||||
QString name=dlg.name();
|
||||
QString cat=dlg.category();
|
||||
QString existing=StreamsModel::self()->name(cat, url);
|
||||
|
||||
if (existing.isEmpty()) {
|
||||
StreamsModel::self()->add(cat, name, dlg.genre(), dlg.icon(), url);
|
||||
}
|
||||
StreamsModel::self()->addToFavourites(url, dlg.name());
|
||||
}
|
||||
playQueueModel.addItems(QStringList() << StreamsModel::modifyUrl(url), false, 0);
|
||||
}
|
||||
|
||||
BIN
icons/streams-digitallyimported.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
BIN
icons/streams-jazzradio.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
icons/streams-shoutcast.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
icons/streams-skyfm.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
icons/streams-somafm.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
icons/streams-tunein.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
@@ -20,133 +20,123 @@
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef STREAMSMODEL_H
|
||||
#define STREAMSMODEL_H
|
||||
|
||||
#include <QList>
|
||||
#include <QUrl>
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
#include <QMap>
|
||||
#include <QStringList>
|
||||
#include "actionmodel.h"
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QIcon>
|
||||
|
||||
class QTimer;
|
||||
class QIODevice;
|
||||
class QNetworkReply;
|
||||
class QXmlStreamReader;
|
||||
class QIODevice;
|
||||
class QTimer;
|
||||
|
||||
class StreamsModel : public ActionModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static const QString constPrefix;
|
||||
static QString modifyUrl(const QString &u, bool addPrefix=true, const QString &name=QString());
|
||||
static QString dir();
|
||||
static const QLatin1String constGenreSeparator;
|
||||
|
||||
static QSet<QString> genreSet(const QString &str) { return str.split(constGenreSeparator, QString::SkipEmptyParts).toSet(); }
|
||||
|
||||
struct CategoryItem;
|
||||
struct Item
|
||||
{
|
||||
Item(const QString &n, const QString &i) : name(n), icon(i) { name.replace("#", ""); }
|
||||
virtual bool isCategory() = 0;
|
||||
Item(const QString &u, const QString &n=QString(), CategoryItem *p=0) : url(u), name(n), parent(p) { }
|
||||
virtual ~Item() { }
|
||||
QString url;
|
||||
QString name;
|
||||
QString icon;
|
||||
};
|
||||
|
||||
struct CategoryItem;
|
||||
struct StreamItem : public Item
|
||||
{
|
||||
StreamItem(const QString &n, const QString &g, const QString &i, const QUrl &u, CategoryItem *p=0) : Item(n, i), genres(genreSet(g)), url(u), parent(p) { }
|
||||
StreamItem(const QString &n, const QSet<QString> &g, const QString &i, const QUrl &u, CategoryItem *p=0) : Item(n, i), genres(g), url(u), parent(p) { }
|
||||
bool isCategory() { return false; }
|
||||
QString genreString() const { return QStringList(genres.toList()).join(constGenreSeparator); }
|
||||
QSet<QString> genres;
|
||||
QUrl url;
|
||||
CategoryItem *parent;
|
||||
virtual bool isCategory() const { return false; }
|
||||
};
|
||||
|
||||
|
||||
struct CategoryItem : public Item
|
||||
{
|
||||
CategoryItem(const QString &n, const QString &i=QString()) : Item(n, i) { }
|
||||
virtual ~CategoryItem() { clearStreams(); }
|
||||
bool isCategory() { return true; }
|
||||
void clearStreams();
|
||||
QHash<QString, StreamItem *> itemMap;
|
||||
QList<StreamItem *> streams;
|
||||
QSet<QString> genres;
|
||||
enum State
|
||||
{
|
||||
Initial,
|
||||
Fetching,
|
||||
Fetched
|
||||
};
|
||||
|
||||
CategoryItem(const QString &u, const QString &n=QString(), CategoryItem *p=0, const QIcon &i=QIcon())
|
||||
: Item(u, n, p), state(Initial), isFavourites(false), icon(i) { }
|
||||
virtual ~CategoryItem() { qDeleteAll(children); }
|
||||
virtual bool isCategory() const { return true; }
|
||||
State state;
|
||||
bool isFavourites;
|
||||
QList<Item *> children;
|
||||
QIcon icon;
|
||||
};
|
||||
|
||||
static const QString constPrefix;
|
||||
|
||||
static StreamsModel * self();
|
||||
static QString favouritesDir();
|
||||
static QString modifyUrl(const QString &u, bool addPrefix=true, const QString &name=QString());
|
||||
static bool validProtocol(const QString &file);
|
||||
|
||||
StreamsModel();
|
||||
StreamsModel(QObject *parent = 0);
|
||||
~StreamsModel();
|
||||
QModelIndex index(int, int, const QModelIndex & = QModelIndex()) const;
|
||||
QModelIndex parent(const QModelIndex &) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex&) const { return 1; }
|
||||
bool hasChildren(const QModelIndex &parent) const;
|
||||
QModelIndex parent(const QModelIndex &index) const;
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const;
|
||||
int columnCount(const QModelIndex &) const;
|
||||
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 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);
|
||||
void editCategory(const QModelIndex &index, const QString &name, const QString &icon);
|
||||
void editStream(const QModelIndex &index, const QString &oldCat, const QString &newCat, const QString &name, const QString &genre, const QString &icon, const QString &url);
|
||||
void remove(const QModelIndex &index);
|
||||
void removeCategory(CategoryItem *cat);
|
||||
void removeStream(StreamItem *stream);
|
||||
void removeStream(const QString &category, const QString &name, const QString &url);
|
||||
QString name(const QString &cat, const QString &url) { return name(getCategory(cat), url); }
|
||||
bool entryExists(const QString &cat, const QString &name, const QUrl &url=QUrl()) { return entryExists(getCategory(cat), name, url); }
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
Qt::DropActions supportedDropActions() const;
|
||||
bool validProtocol(const QString &file) const;
|
||||
bool hasChildren(const QModelIndex &index) const;
|
||||
bool canFetchMore(const QModelIndex &index) const;
|
||||
void fetchMore(const QModelIndex &index);
|
||||
|
||||
void saveFavourites(bool force=false);
|
||||
bool haveFavourites() const { return !favourites->children.isEmpty(); }
|
||||
bool isFavoritesWritable() { return favouritesIsWriteable; }
|
||||
bool checkFavouritesWritable();
|
||||
void reloadFavourites();
|
||||
void removeFromFavourites(const QModelIndex &index);
|
||||
void addToFavourites(const QString &url, const QString &name);
|
||||
QString favouritesNameForUrl(const QString &u);
|
||||
bool nameExistsInFavourites(const QString &n);
|
||||
void updateFavouriteStream(Item *item);
|
||||
|
||||
bool importXml(const QString &fileName);
|
||||
bool saveXml(const QString &fileName, const QList<Item *> &items);
|
||||
|
||||
QStringList filenames(const QModelIndexList &indexes, bool addPrefix) const;
|
||||
QMimeData * mimeData(const QModelIndexList &indexes) const;
|
||||
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int col, const QModelIndex &parent);
|
||||
QStringList mimeTypes() const;
|
||||
void mark(const QList<int> &rows, bool f);
|
||||
void updateGenres();
|
||||
bool isWritable() const { return writable; }
|
||||
bool checkWritable();
|
||||
Action * getAction(const QModelIndex &idx, int num);
|
||||
const QMap<QString, QIcon> & icons();
|
||||
QIcon icon(const QString &name) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void downloading(bool);
|
||||
void updateGenres(const QSet<QString> &genres);
|
||||
void error(const QString &e);
|
||||
void loading();
|
||||
void loaded();
|
||||
void error(const QString &msg);
|
||||
|
||||
private Q_SLOTS:
|
||||
void downloadFinished();
|
||||
void jobFinished();
|
||||
void persistFavourites();
|
||||
|
||||
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);
|
||||
CategoryItem * getCategory(const QString &name, bool create=false, bool signal=false);
|
||||
QString name(CategoryItem *cat, const QString &url);
|
||||
bool entryExists(CategoryItem *cat, const QString &name, const QUrl &url=QUrl()) { return 0!=getStream(cat, name, url); }
|
||||
StreamItem * getStream(CategoryItem *cat, const QString &name, const QUrl &url);
|
||||
|
||||
private Q_SLOTS:
|
||||
void persist();
|
||||
Item * toItem(const QModelIndex &index) const { return index.isValid() ? static_cast<Item*>(index.internalPointer()) : root; }
|
||||
QList<Item *> parseRadioTimeResponse(QIODevice *dev, CategoryItem *cat);
|
||||
QList<Item *> parseIceCastResponse(QIODevice *dev, CategoryItem *cat);
|
||||
QList<Item *> parseSomaFmResponse(QIODevice *dev, CategoryItem *cat);
|
||||
QList<Item *> parseDigitallyImportedResponse(QIODevice *dev, CategoryItem *cat, const QString &origUrl);
|
||||
Item * parseRadioTimeEntry(QXmlStreamReader &doc, CategoryItem *parent);
|
||||
Item * parseIceCastEntry(QXmlStreamReader &doc, CategoryItem *parent);
|
||||
Item * parseSomaFmEntry(QXmlStreamReader &doc, CategoryItem *parent);
|
||||
void loadFavourites(const QModelIndex &index);
|
||||
bool loadXml(const QString &fileName, const QModelIndex &index);
|
||||
QList<Item *> loadXml(QIODevice *dev, bool isInternal);
|
||||
bool saveXml(QIODevice *dev, const QList<Item *> &items, bool format) const;
|
||||
|
||||
private:
|
||||
QList<CategoryItem *> items;
|
||||
mutable QMap<QString, QIcon> iconMap;
|
||||
bool writable;
|
||||
bool modified;
|
||||
QTimer *timer;
|
||||
QNetworkReply *job;
|
||||
QMap<QNetworkReply *, CategoryItem *> jobs;
|
||||
CategoryItem *root;
|
||||
CategoryItem *favourites;
|
||||
bool favouritesIsWriteable;
|
||||
bool favouritesModified;
|
||||
QTimer *favouritesSaveTimer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,6 +33,26 @@ StreamsProxyModel::StreamsProxyModel(QObject *parent)
|
||||
sort(0);
|
||||
}
|
||||
|
||||
bool StreamsProxyModel::filterAcceptsItem(const void *i, QStringList strings) const
|
||||
{
|
||||
const StreamsModel::Item *item=static_cast<const StreamsModel::Item *>(i);
|
||||
strings << item->name;
|
||||
if (matchesFilter(strings)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item->isCategory()) {
|
||||
const StreamsModel::CategoryItem *cat=static_cast<const StreamsModel::CategoryItem *>(item);
|
||||
foreach (const StreamsModel::Item *c, cat->children) {
|
||||
if (filterAcceptsItem(c, strings)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StreamsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||
{
|
||||
if (!filterEnabled) {
|
||||
@@ -41,33 +61,58 @@ bool StreamsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourc
|
||||
if (!isChildOfRoot(sourceParent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||
StreamsModel::Item *item = static_cast<StreamsModel::Item *>(index.internalPointer());
|
||||
QModelIndex idx=index.parent();
|
||||
QStringList strings;
|
||||
|
||||
// Traverse back up tree, so we get parent strings...
|
||||
while (idx.isValid()) {
|
||||
StreamsModel::Item *i = static_cast<StreamsModel::Item *>(idx.internalPointer());
|
||||
if (!i->isCategory()) {
|
||||
break;
|
||||
}
|
||||
strings << i->name;
|
||||
idx=idx.parent();
|
||||
}
|
||||
|
||||
if (item->isCategory()) {
|
||||
StreamsModel::CategoryItem *cat = static_cast<StreamsModel::CategoryItem *>(item);
|
||||
|
||||
if (!filterGenre.isEmpty() && !cat->genres.contains(filterGenre)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cat->name.contains(filterRegExp())) {
|
||||
// Check *all* children...
|
||||
if (filterAcceptsItem(item, strings)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (StreamsModel::StreamItem *s, cat->streams) {
|
||||
if (matchesFilter(QStringList() << cat->name << s->name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
StreamsModel::StreamItem *s = static_cast<StreamsModel::StreamItem *>(item);
|
||||
|
||||
if (!filterGenre.isEmpty() && !s->genres.contains(filterGenre)) {
|
||||
return false;
|
||||
}
|
||||
return matchesFilter(QStringList() << s->name);
|
||||
strings << item->name;
|
||||
return matchesFilter(strings);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StreamsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||
{
|
||||
const StreamsModel::Item * leftItem = static_cast<const StreamsModel::Item *>(left.internalPointer());
|
||||
const StreamsModel::Item * rightItem = static_cast<const StreamsModel::Item *>(right.internalPointer());
|
||||
|
||||
if (leftItem->isCategory() && !rightItem->isCategory()) {
|
||||
return true;
|
||||
}
|
||||
if (!leftItem->isCategory() && rightItem->isCategory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leftItem->isCategory() && rightItem->isCategory()) {
|
||||
const StreamsModel::CategoryItem * leftCat = static_cast<const StreamsModel::CategoryItem *>(leftItem);
|
||||
const StreamsModel::CategoryItem * rightCat = static_cast<const StreamsModel::CategoryItem *>(rightItem);
|
||||
|
||||
if (leftCat->isFavourites && !rightCat->isFavourites) {
|
||||
return true;
|
||||
}
|
||||
if (!leftCat->isFavourites && rightCat->isFavourites) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return QSortFilterProxyModel::lessThan(left, right);
|
||||
}
|
||||
|
||||
@@ -26,12 +26,15 @@
|
||||
|
||||
#include "proxymodel.h"
|
||||
|
||||
|
||||
class StreamsProxyModel : public ProxyModel
|
||||
{
|
||||
public:
|
||||
StreamsProxyModel(QObject *parent = 0);
|
||||
void setFilterGenre(const QString &genre);
|
||||
|
||||
bool filterAcceptsItem(const void *i, QStringList strings) const;
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
file(GLOB svg_files *.svg)
|
||||
file(GLOB png_files *.png)
|
||||
if (WIN32)
|
||||
install(FILES ${svg_files} ${png_files} DESTINATION ${CMAKE_INSTALL_PREFIX}/streamicons/)
|
||||
else (WIN32)
|
||||
install(FILES ${svg_files} ${png_files} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/${CMAKE_PROJECT_NAME}/streamicons/)
|
||||
endif (WIN32)
|
||||
@@ -1,15 +0,0 @@
|
||||
<svg viewBox="0 0 41.160763 47.604721" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<linearGradient>
|
||||
<stop offset="0"/>
|
||||
<stop offset="1" stop-color="#fff"/>
|
||||
</linearGradient>
|
||||
<linearGradient x1="-1.0164395e-18" x2="1" xlink:href="#linearGradient830"/>
|
||||
<radialGradient xlink:href="#linearGradient830"/>
|
||||
</defs>
|
||||
<g transform="translate(-80.59801,-338.389)">
|
||||
<path d="m94.57371,338.62098c-8.78484.20794-15.51495,6.36209-13.33392,15.78724 .00257.0111.01334.02075.01593.03186 .25605,3.25054 2.9607,5.81468 6.27666,5.81468 3.48488,0 6.30852-2.82365 6.30852-6.30853 0-3.07137-2.1907-5.63239-5.0978-6.197-1.15848-.40989-2.89596-1.34191-2.81972-2.83565 .03514-.74343.90303-2.09188 2.29401-2.77193 1.69055-.79335 3.43378-1.22266 5.19338-.86025 2.66733.48694 9.48863,5.38493 10.02036,13.87556 .30521,6.44653-3.3159,15.15023-6.85016,19.27604-5.69761,6.50335-14.85058,10.54298-13.95522,11.26294 .80363.71997 11.61001-4.21926 17.23692-10.41862 6.86685-7.4357 10.26627-13.63373 9.9407-21.17178-.19582-7.53805-6.03171-15.6992-15.22966-15.48456z" fill-rule="evenodd" stroke="#000" stroke-width=".45574"/>
|
||||
<path d="m116.85809,36.47297a9.7721,9.16135 0 1,1 -19.54421,0 9.7721,9.16135 0 1,1 19.54421,0z" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width=".894" transform="matrix(.509779,0,0,.509779,61.9591,329.3244)"/>
|
||||
<path d="m116.85809,36.47297a9.7721,9.16135 0 1,1 -19.54421,0 9.7721,9.16135 0 1,1 19.54421,0z" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width=".894" transform="matrix(.509779,0,0,.509779,61.9591,342.3694)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -1,6 +0,0 @@
|
||||
<svg viewBox="0 0 365.62958 367.73712" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Six Sided Dice</title>
|
||||
<g transform="translate(-117.1457,-272.3622)">
|
||||
<path d="m328.7338,272.3636c-1.0593-.0232-2.2036.2392-3.6545.7307l-160.7956,47.2156c-1.338.3127-1.2603.6733-.1462,1.5349l142.7427,113.9456c2.6283,2.1791 3.8646,2.4492 7.5282,1.3156l160.0647-55.4745c3.6722-1.3494 3.9274-1.6778.1464-4.1662l-140.4769-102.763c-2.1688-1.5284-3.6434-2.3049-5.4085-2.3387zm-18.3454,13.8138c3.2021-.0232 6.5824.3283 10.0863,1.0963 14.0157,3.073 23.9561,11.6383 22.1459,19.0764s-14.6352,10.9666-28.6507,7.8935-23.9562-11.5651-22.146-19.0032c1.3576-5.5785 8.9586-9.0156 18.5645-9.063zm-90.6303,27.5545c3.2021-.0232 6.6554.3281 10.1594,1.0964 14.0156,3.073 23.883,11.5652 22.0728,19.003s-14.6352,11.0396-28.6508,7.9667-23.883-11.638-22.0728-19.0761c1.3577-5.5785 8.8855-8.9426 18.4914-8.99zm137.3341,7.0164c3.202-.0232 6.6555.4013 10.1594,1.1695 14.0157,3.0728 23.8829,11.5651 22.0729,19.0031s-14.6352,10.9665-28.6508,7.8935-23.8831-11.5651-22.0729-19.0031c1.3577-5.5783 8.8855-9.0156 18.4915-9.063zm-202.8948,8.8438c-.2935.0748-.3883.5333-.5847,1.4619l-36.2522,181.3334c-.4224,1.8862-.3482,2.3536 1.3887,3.8739l137.6995,118.6962c3.2029,3.0612 3.8757,3.0218 4.3122-.7309l40.1259-183.8915c.8408-2.5054-.0249-3.8837-1.4618-5.0432l-143.7659-114.8226c-.74-.6243-1.1682-.9515-1.4618-.8772zm111.826,20.6841c3.202-.0232 6.6554.3281 10.1594,1.0965 14.0156,3.073 23.883,11.5651 22.0728,19.003s-14.6352,10.9666-28.6509,7.8937-23.8829-11.5652-22.0728-19.0031c1.3576-5.5787 8.8856-8.9426 18.4915-8.9901zm138.7959,6.0664c3.202-.0232 6.6554.3281 10.1594,1.0963 14.0156,3.0731 23.883,11.5651 22.0728,19.0032s-14.6352,11.0398-28.6509,7.9668-23.883-11.6383-22.0728-19.0763c1.3577-5.5783 8.8856-8.9423 18.4915-8.9899zm-241.7051,6.651c.5401-.0537 1.1314-.0294 1.681,0 6.5957.3492 13.738,6.5306 17.9068,16.4452 5.5583,13.2193 3.7052,28.0551-4.093,33.1091s-18.634-1.5446-24.1924-14.764-3.7054-28.0551 4.093-33.1091c1.4621-.9477 2.9845-1.5207 4.6045-1.6812zm150.6363,23.8271c3.202-.0231 6.6554.3282 10.1593,1.0965 14.0157,3.0728 23.8831,11.5651 22.0729,19.003s-14.6353,10.9666-28.6508,7.8936-23.883-11.5651-22.0728-19.0032c1.3576-5.5785 8.8855-8.9425 18.4914-8.99zm168.1777,5.0431c-.3073.0632-.7394.1709-1.2425.3654l-164.3771,57.0094c-3.348,1.3784-3.2476,1.9411-3.8007,4.4584l-40.0526,183.3069c-.136,2.6988-1.1302,3.9269 2.0465,2.4852l161.965-60.5177c3.1428-1.5036 3.7452-1.7677 4.093-4.8238l42.0261-180.749c.3482-1.2733.2638-1.7272-.6578-1.5349zm-26.6775,29.7472c4.6284.0748 8.2604,2.3262 9.8671,6.6513 3.2131,8.6497-2.9745,22.494-13.887,30.9165s-22.3679,8.2114-25.5811-.4385 2.9744-22.4941 13.8868-30.9166c5.4562-4.2113 11.0857-6.2873 15.7142-6.2127zm-199.2404,15.8604c6.6789.1708 13.9652,6.4487 18.1991,16.5182 5.5583,13.2194 3.7783,28.0551-4.0199,33.1091s-18.634-1.6175-24.1924-14.8369-3.7054-27.9823 4.093-33.0362c1.4622-.9477 2.9841-1.5209 4.6045-1.6812 .4389-.0453.8704-.0842 1.3156-.0726zm-58.6904,21.1958c6.6788.1708 13.9651,6.4488 18.1991,16.5181 5.5583,13.2194 3.7783,28.0551-4.0199,33.1093s-18.6341-1.6176-24.1924-14.837-3.7052-27.9822 4.093-33.0361c1.4621-.9477 2.9841-1.521 4.6045-1.6812 .4389-.0453.8705-.0842 1.3157-.0726zm-57.8133,20.9765c.5399-.0537 1.1313-.0273 1.6809,0 6.5957.3492 13.6649,6.6037 17.8338,16.5181 5.5583,13.2194 3.7784,27.9823-4.0198,33.0362s-18.6342-1.5446-24.1925-14.764-3.7053-28.0551 4.093-33.1091c1.4622-.9477 2.9845-1.5208 4.6047-1.6812zm254.0571,17.5413c4.529.1474 8.1393,2.3938 9.7208,6.6512 3.2134,8.6498-3.0476,22.4942-13.9599,30.9165s-22.3679,8.2115-25.5811-.4385 3.0476-22.4941 13.9599-30.9165c4.7742-3.6848 9.6414-5.7376 13.8869-6.1395 .6823-.0653 1.3264-.0937 1.9734-.0726zm-164.2308,58.6906c.54-.0537 1.1313-.0273 1.681,0 6.5956.3492 13.738,6.5305 17.9068,16.4449 5.5583,13.2193 3.7053,28.0554-4.093,33.1093s-18.561-1.5447-24.1193-14.7639-3.7784-28.0553 4.0198-33.1094c1.4622-.9474 2.9845-1.5206 4.6047-1.6809zm97.2813,19.0032c4.6285.0748 8.2603,2.2531 9.867,6.578 3.2132,8.6497-2.9744,22.4939-13.8869,30.9165s-22.3679,8.2843-25.5811-.3655 2.9744-22.4942 13.8869-30.9166c5.4562-4.2111 11.0856-6.287 15.7141-6.2123z" fill="#d00000"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 152 B |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 118 B |
|
Before Width: | Height: | Size: 947 B |
|
Before Width: | Height: | Size: 685 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 121 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 549 B |
|
Before Width: | Height: | Size: 200 B |
|
Before Width: | Height: | Size: 1001 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 842 B |
|
Before Width: | Height: | Size: 560 B |
|
Before Width: | Height: | Size: 148 B |
|
Before Width: | Height: | Size: 743 B |
|
Before Width: | Height: | Size: 115 B |
|
Before Width: | Height: | Size: 262 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 148 B |
|
Before Width: | Height: | Size: 130 B |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 151 B |
|
Before Width: | Height: | Size: 115 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 803 B |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 247 B |
|
Before Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 713 B |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 849 B |
|
Before Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 221 B |
|
Before Width: | Height: | Size: 138 B |
|
Before Width: | Height: | Size: 145 B |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 390 B |
|
Before Width: | Height: | Size: 505 B |
|
Before Width: | Height: | Size: 805 B |
|
Before Width: | Height: | Size: 119 B |
|
Before Width: | Height: | Size: 147 B |
|
Before Width: | Height: | Size: 942 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 377 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 367 B |
|
Before Width: | Height: | Size: 117 B |
|
Before Width: | Height: | Size: 545 B |
|
Before Width: | Height: | Size: 172 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 632 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 134 B |
|
Before Width: | Height: | Size: 788 B |
|
Before Width: | Height: | Size: 913 B |
|
Before Width: | Height: | Size: 410 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 996 B |
|
Before Width: | Height: | Size: 193 B |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 666 B |
|
Before Width: | Height: | Size: 235 B |
|
Before Width: | Height: | Size: 130 B |
|
Before Width: | Height: | Size: 118 B |
|
Before Width: | Height: | Size: 618 B |
|
Before Width: | Height: | Size: 1.3 KiB |