Album cover art manager. So far this only displays cover art that was loaded from disk.
This commit is contained in:
parent
f9ad923f3a
commit
12273256e5
@ -62,5 +62,7 @@
|
||||
<file>schema-1.sql</file>
|
||||
<file>schema-2.sql</file>
|
||||
<file>nocover.png</file>
|
||||
<file>view-choose.png</file>
|
||||
<file>download.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
BIN
data/download.png
Normal file
BIN
data/download.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
data/view-choose.png
Normal file
BIN
data/view-choose.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 409 B |
@ -52,6 +52,8 @@ set(CLEMENTINE-SOURCES
|
||||
savedradio.cpp
|
||||
stylesheetloader.cpp
|
||||
shortcutsdialog.cpp
|
||||
albumcovermanager.cpp
|
||||
albumcoverloader.cpp
|
||||
)
|
||||
|
||||
# Header files that have Q_OBJECT in
|
||||
@ -96,6 +98,8 @@ set(CLEMENTINE-MOC-HEADERS
|
||||
addstreamdialog.h
|
||||
savedradio.h
|
||||
shortcutsdialog.h
|
||||
albumcovermanager.h
|
||||
albumcoverloader.h
|
||||
)
|
||||
|
||||
# UI files
|
||||
@ -114,6 +118,7 @@ set(CLEMENTINE-UI
|
||||
about.ui
|
||||
addstreamdialog.ui
|
||||
shortcutsdialog.ui
|
||||
albumcovermanager.ui
|
||||
)
|
||||
|
||||
# Resource files
|
||||
|
70
src/albumcoverloader.cpp
Normal file
70
src/albumcoverloader.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "albumcoverloader.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
AlbumCoverLoader::AlbumCoverLoader(QObject* parent)
|
||||
: QObject(parent),
|
||||
height_(120),
|
||||
next_id_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void AlbumCoverLoader::Clear() {
|
||||
QMutexLocker l(&mutex_);
|
||||
tasks_.clear();
|
||||
}
|
||||
|
||||
quint64 AlbumCoverLoader::LoadImageAsync(const QString& art_automatic,
|
||||
const QString& art_manual) {
|
||||
Task task;
|
||||
task.art_automatic = art_automatic;
|
||||
task.art_manual = art_manual;
|
||||
|
||||
{
|
||||
QMutexLocker l(&mutex_);
|
||||
task.id = next_id_ ++;
|
||||
tasks_.enqueue(task);
|
||||
}
|
||||
|
||||
metaObject()->invokeMethod(this, "ProcessTasks", Qt::QueuedConnection);
|
||||
|
||||
return task.id;
|
||||
}
|
||||
|
||||
void AlbumCoverLoader::ProcessTasks() {
|
||||
forever {
|
||||
// Get the next task
|
||||
Task task;
|
||||
{
|
||||
QMutexLocker l(&mutex_);
|
||||
if (tasks_.isEmpty())
|
||||
return;
|
||||
task = tasks_.dequeue();
|
||||
}
|
||||
|
||||
// Try to load the image
|
||||
QImage image;
|
||||
if (!task.art_manual.isEmpty())
|
||||
image.load(task.art_manual);
|
||||
if (!task.art_automatic.isEmpty() && image.isNull())
|
||||
image.load(task.art_automatic);
|
||||
|
||||
if (!image.isNull()) {
|
||||
// Scale the image down
|
||||
image = image.scaled(QSize(height_, height_), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
// Pad the image to height_ x height_
|
||||
QImage bigger_image(height_, height_, QImage::Format_ARGB32);
|
||||
bigger_image.fill(0);
|
||||
|
||||
QPainter p(&bigger_image);
|
||||
p.drawImage((height_ - image.width()) / 2, (height_ - image.height()) / 2,
|
||||
image);
|
||||
p.end();
|
||||
|
||||
image = bigger_image;
|
||||
}
|
||||
|
||||
emit ImageLoaded(task.id, image);
|
||||
}
|
||||
}
|
42
src/albumcoverloader.h
Normal file
42
src/albumcoverloader.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef ALBUMCOVERLOADER_H
|
||||
#define ALBUMCOVERLOADER_H
|
||||
|
||||
#include "backgroundthread.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QImage>
|
||||
#include <QMutex>
|
||||
#include <QQueue>
|
||||
|
||||
class AlbumCoverLoader : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AlbumCoverLoader(QObject* parent = 0);
|
||||
|
||||
void SetDesiredHeight(int height) { height_ = height; }
|
||||
quint64 LoadImageAsync(const QString& art_automatic, const QString& art_manual);
|
||||
|
||||
void Clear();
|
||||
|
||||
signals:
|
||||
void ImageLoaded(quint64 id, const QImage& image);
|
||||
|
||||
private slots:
|
||||
void ProcessTasks();
|
||||
|
||||
private:
|
||||
struct Task {
|
||||
quint64 id;
|
||||
QString art_automatic;
|
||||
QString art_manual;
|
||||
};
|
||||
|
||||
int height_;
|
||||
|
||||
QMutex mutex_;
|
||||
QQueue<Task> tasks_;
|
||||
quint64 next_id_;
|
||||
};
|
||||
|
||||
#endif // ALBUMCOVERLOADER_H
|
160
src/albumcovermanager.cpp
Normal file
160
src/albumcovermanager.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
#include "albumcovermanager.h"
|
||||
#include "librarybackend.h"
|
||||
#include "libraryquery.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QPainter>
|
||||
#include <QMenu>
|
||||
#include <QActionGroup>
|
||||
|
||||
const char* AlbumCoverManager::kSettingsGroup = "CoverManager";
|
||||
|
||||
AlbumCoverManager::AlbumCoverManager(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
cover_loader_(new BackgroundThread<AlbumCoverLoader>(this)),
|
||||
artist_icon_(":/artist.png"),
|
||||
all_artists_icon_(":/album.png")
|
||||
{
|
||||
ui_.setupUi(this);
|
||||
|
||||
// Get a square version of nocover.png
|
||||
QImage nocover(":/nocover.png");
|
||||
nocover = nocover.scaled(120, 120, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
QImage square_nocover(120, 120, QImage::Format_ARGB32);
|
||||
square_nocover.fill(0);
|
||||
QPainter p(&square_nocover);
|
||||
p.drawImage((120 - nocover.width()) / 2, (120 - nocover.height()) / 2, nocover);
|
||||
p.end();
|
||||
no_cover_icon_ = QPixmap::fromImage(square_nocover);
|
||||
|
||||
// View menu
|
||||
QActionGroup* filter_group = new QActionGroup(this);
|
||||
filter_all_ = filter_group->addAction("All albums");
|
||||
filter_with_covers_ = filter_group->addAction("Albums with covers");
|
||||
filter_without_covers_ = filter_group->addAction("Albums without covers");
|
||||
filter_all_->setCheckable(true);
|
||||
filter_with_covers_->setCheckable(true);
|
||||
filter_without_covers_->setCheckable(true);
|
||||
filter_group->setExclusive(true);
|
||||
filter_all_->setChecked(true);
|
||||
|
||||
QMenu* view_menu = new QMenu(this);
|
||||
view_menu->addActions(filter_group->actions());
|
||||
|
||||
ui_.view->setMenu(view_menu);
|
||||
|
||||
// Connections
|
||||
connect(cover_loader_, SIGNAL(Initialised()), SLOT(CoverLoaderInitialised()));
|
||||
connect(ui_.artists, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
|
||||
SLOT(ArtistChanged(QListWidgetItem*)));
|
||||
connect(ui_.filter, SIGNAL(textChanged(QString)), SLOT(UpdateFilter()));
|
||||
connect(filter_group, SIGNAL(triggered(QAction*)), SLOT(UpdateFilter()));
|
||||
connect(ui_.view, SIGNAL(clicked()), ui_.view, SLOT(showMenu()));
|
||||
|
||||
// Restore settings
|
||||
QSettings s;
|
||||
s.beginGroup(kSettingsGroup);
|
||||
|
||||
restoreGeometry(s.value("geometry").toByteArray());
|
||||
if (!ui_.splitter->restoreState(s.value("splitter_state").toByteArray())) {
|
||||
// Sensible default size for the artists view
|
||||
ui_.splitter->setSizes(QList<int>() << 200 << width() - 200);
|
||||
}
|
||||
|
||||
cover_loader_->start();
|
||||
}
|
||||
|
||||
void AlbumCoverManager::CoverLoaderInitialised() {
|
||||
connect(cover_loader_->Worker().get(), SIGNAL(ImageLoaded(quint64,QImage)),
|
||||
SLOT(CoverImageLoaded(quint64,QImage)));
|
||||
}
|
||||
|
||||
void AlbumCoverManager::SetBackend(boost::shared_ptr<LibraryBackend> backend) {
|
||||
backend_ = backend;
|
||||
|
||||
if (isVisible())
|
||||
Reset();
|
||||
}
|
||||
|
||||
void AlbumCoverManager::showEvent(QShowEvent *) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void AlbumCoverManager::closeEvent(QCloseEvent *) {
|
||||
QSettings s;
|
||||
s.beginGroup(kSettingsGroup);
|
||||
|
||||
s.setValue("geometry", saveGeometry());
|
||||
s.setValue("splitter_state", ui_.splitter->saveState());
|
||||
}
|
||||
|
||||
void AlbumCoverManager::Reset() {
|
||||
if (!backend_)
|
||||
return;
|
||||
|
||||
ui_.artists->clear();
|
||||
new QListWidgetItem(all_artists_icon_, "All artists", ui_.artists, All_Artists);
|
||||
|
||||
foreach (const QString& artist, backend_->GetAllArtists()) {
|
||||
if (artist.isEmpty())
|
||||
continue;
|
||||
|
||||
new QListWidgetItem(artist_icon_, artist, ui_.artists, Specific_Artist);
|
||||
}
|
||||
}
|
||||
|
||||
void AlbumCoverManager::ArtistChanged(QListWidgetItem* current) {
|
||||
if (!backend_ || !cover_loader_->Worker())
|
||||
return;
|
||||
if (!current)
|
||||
return;
|
||||
|
||||
QString artist;
|
||||
if (current->type() == Specific_Artist)
|
||||
artist = current->text();
|
||||
|
||||
ui_.albums->clear();
|
||||
cover_loading_tasks_.clear();
|
||||
cover_loader_->Worker()->Clear();
|
||||
|
||||
foreach (const LibraryBackend::AlbumArtInfo& info, backend_->GetAlbumArtInfo(artist)) {
|
||||
QListWidgetItem* item = new QListWidgetItem(no_cover_icon_, info.album_name, ui_.albums);
|
||||
|
||||
if (!info.art_automatic.isEmpty() || !info.art_manual.isEmpty()) {
|
||||
quint64 id = cover_loader_->Worker()->LoadImageAsync(
|
||||
info.art_automatic, info.art_manual);
|
||||
cover_loading_tasks_[id] = item;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateFilter();
|
||||
}
|
||||
|
||||
void AlbumCoverManager::CoverImageLoaded(quint64 id, const QImage &image) {
|
||||
if (!cover_loading_tasks_.contains(id))
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = cover_loading_tasks_.take(id);
|
||||
|
||||
if (image.isNull())
|
||||
return;
|
||||
|
||||
item->setIcon(QPixmap::fromImage(image));
|
||||
UpdateFilter();
|
||||
}
|
||||
|
||||
void AlbumCoverManager::UpdateFilter() {
|
||||
const QString filter = ui_.filter->text().toLower();
|
||||
const bool hide_with_covers = filter_without_covers_->isChecked();
|
||||
const bool hide_without_covers = filter_with_covers_->isChecked();
|
||||
|
||||
for (int i=0 ; i<ui_.albums->count() ; ++i) {
|
||||
QListWidgetItem* item = ui_.albums->item(i);
|
||||
QString text = item->text();
|
||||
bool has_cover = item->icon().cacheKey() != no_cover_icon_.cacheKey();
|
||||
|
||||
item->setHidden((!filter.isEmpty() && !text.toLower().contains(filter)) ||
|
||||
(has_cover && hide_with_covers) ||
|
||||
(!has_cover && hide_without_covers));
|
||||
}
|
||||
}
|
59
src/albumcovermanager.h
Normal file
59
src/albumcovermanager.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef ALBUMCOVERMANAGER_H
|
||||
#define ALBUMCOVERMANAGER_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QIcon>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "ui_covermanager.h"
|
||||
#include "backgroundthread.h"
|
||||
#include "albumcoverloader.h"
|
||||
|
||||
class LibraryBackend;
|
||||
|
||||
class AlbumCoverManager : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AlbumCoverManager(QWidget *parent = 0);
|
||||
|
||||
static const char* kSettingsGroup;
|
||||
|
||||
void Reset();
|
||||
|
||||
public slots:
|
||||
void SetBackend(boost::shared_ptr<LibraryBackend> backend);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *);
|
||||
void closeEvent(QCloseEvent *);
|
||||
|
||||
private slots:
|
||||
void ArtistChanged(QListWidgetItem* current);
|
||||
void CoverLoaderInitialised();
|
||||
void CoverImageLoaded(quint64 id, const QImage& image);
|
||||
void UpdateFilter();
|
||||
|
||||
private:
|
||||
enum ArtistItemType {
|
||||
All_Artists,
|
||||
Specific_Artist,
|
||||
};
|
||||
|
||||
private:
|
||||
Ui::CoverManager ui_;
|
||||
boost::shared_ptr<LibraryBackend> backend_;
|
||||
|
||||
QAction* filter_all_;
|
||||
QAction* filter_with_covers_;
|
||||
QAction* filter_without_covers_;
|
||||
|
||||
BackgroundThread<AlbumCoverLoader>* cover_loader_;
|
||||
QMap<quint64, QListWidgetItem*> cover_loading_tasks_;
|
||||
|
||||
QIcon artist_icon_;
|
||||
QIcon all_artists_icon_;
|
||||
QIcon no_cover_icon_;
|
||||
};
|
||||
|
||||
#endif // ALBUMCOVERMANAGER_H
|
175
src/albumcovermanager.ui
Normal file
175
src/albumcovermanager.ui
Normal file
@ -0,0 +1,175 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CoverManager</class>
|
||||
<widget class="QDialog" name="CoverManager">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>827</width>
|
||||
<height>662</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Cover Manager</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QListWidget" name="artists">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="clear">
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<normaloff>:/clear.png</normaloff>:/clear.png</iconset>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LineEdit" name="filter">
|
||||
<property name="hint" stdset="0">
|
||||
<string>Enter search terms here</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="view">
|
||||
<property name="text">
|
||||
<string>View</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<normaloff>:/view-choose.png</normaloff>:/view-choose.png</iconset>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::MenuButtonPopup</enum>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="fetch">
|
||||
<property name="text">
|
||||
<string>Fetch Missing Covers</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<normaloff>:/download.png</normaloff>:/download.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="albums">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>120</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="flow">
|
||||
<enum>QListView::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="isWrapping" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="resizeMode">
|
||||
<enum>QListView::Adjust</enum>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
<property name="uniformItemSizes">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>lineedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../data/data.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>clear</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>filter</receiver>
|
||||
<slot>clear()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>329</x>
|
||||
<y>13</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>367</x>
|
||||
<y>14</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>clear</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>filter</receiver>
|
||||
<slot>setFocus()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>334</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>401</x>
|
||||
<y>13</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -567,6 +567,10 @@ p, li { white-space: pre-wrap; }
|
||||
<source>&Hide tray icon</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Configure &Global Shortcuts...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiLoadingIndicator</name>
|
||||
@ -768,6 +772,109 @@ p, li { white-space: pre-wrap; }
|
||||
<source>Show a notification when I change the volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Include album art in the notification</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ShortcutsDialog</name>
|
||||
<message>
|
||||
<source>Configure Shortcuts</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play</source>
|
||||
<translation type="unfinished">Αναπαραγωγή</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pause</source>
|
||||
<translation type="unfinished">Παύση</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play/Pause</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop</source>
|
||||
<translation type="unfinished">Σταμάτημα</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Playing After Current Track</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Next Track</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Previous Track</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Increase Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decrease Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Mute Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Seek Forwards</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Seek Backwards</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shortcut</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alternate</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&Defaults</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shortcut for Selected Action</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&None</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>De&fault</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&Custom</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Non&e</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default key:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SomaFMService</name>
|
||||
|
@ -550,6 +550,10 @@ p, li { white-space: pre-wrap; }
|
||||
<source>&Hide tray icon</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Configure &Global Shortcuts...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiLoadingIndicator</name>
|
||||
@ -751,6 +755,109 @@ p, li { white-space: pre-wrap; }
|
||||
<source>Show a notification when I change the volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Include album art in the notification</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ShortcutsDialog</name>
|
||||
<message>
|
||||
<source>Configure Shortcuts</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play</source>
|
||||
<translation type="unfinished">Reproducir</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pause</source>
|
||||
<translation type="unfinished">Pausa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play/Pause</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop</source>
|
||||
<translation type="unfinished">Detener</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Playing After Current Track</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Next Track</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Previous Track</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Increase Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decrease Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Mute Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Seek Forwards</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Seek Backwards</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shortcut</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alternate</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&Defaults</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shortcut for Selected Action</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&None</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>De&fault</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&Custom</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Non&e</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default key:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SomaFMService</name>
|
||||
|
@ -545,6 +545,10 @@ p, li { white-space: pre-wrap; }
|
||||
<source>&Hide tray icon</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Configure &Global Shortcuts...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiLoadingIndicator</name>
|
||||
@ -746,6 +750,109 @@ p, li { white-space: pre-wrap; }
|
||||
<source>Show a notification when I change the volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Include album art in the notification</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ShortcutsDialog</name>
|
||||
<message>
|
||||
<source>Configure Shortcuts</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play</source>
|
||||
<translation type="unfinished">Воспроизвести</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pause</source>
|
||||
<translation type="unfinished">Пауза</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play/Pause</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop</source>
|
||||
<translation type="unfinished">Стоп</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Playing After Current Track</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Next Track</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Previous Track</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Increase Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decrease Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Mute Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Seek Forwards</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Seek Backwards</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shortcut</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alternate</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&Defaults</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shortcut for Selected Action</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&None</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>De&fault</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&Custom</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Non&e</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default key:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SomaFMService</name>
|
||||
|
@ -45,6 +45,8 @@ void Library::BackendInitialised() {
|
||||
|
||||
dir_model_->SetBackend(backend_->Worker());
|
||||
|
||||
emit BackendReady(backend_->Worker());
|
||||
|
||||
if (--waiting_for_threads_ == 0)
|
||||
Initialise();
|
||||
}
|
||||
@ -339,17 +341,17 @@ void Library::LazyPopulate(LibraryItem* item) {
|
||||
break;
|
||||
|
||||
case LibraryItem::Type_CompilationAlbum:
|
||||
foreach (const Song& song, backend_->Worker()->GetCompilationSongs(query_options_, item->key))
|
||||
foreach (const Song& song, backend_->Worker()->GetCompilationSongs(item->key, query_options_))
|
||||
CreateSongNode(false, song, item);
|
||||
break;
|
||||
|
||||
case LibraryItem::Type_Artist:
|
||||
foreach (const QString& album, backend_->Worker()->GetAlbumsByArtist(query_options_, item->key))
|
||||
foreach (const QString& album, backend_->Worker()->GetAlbumsByArtist(item->key, query_options_))
|
||||
CreateAlbumNode(false, album, item, false);
|
||||
break;
|
||||
|
||||
case LibraryItem::Type_Album:
|
||||
foreach (const Song& song, backend_->Worker()->GetSongs(query_options_, item->parent->key, item->key))
|
||||
foreach (const Song& song, backend_->Worker()->GetSongs(item->parent->key, item->key, query_options_))
|
||||
CreateSongNode(false, song, item);
|
||||
break;
|
||||
|
||||
|
@ -50,6 +50,8 @@ class Library : public SimpleTreeModel<LibraryItem> {
|
||||
void ScanStarted();
|
||||
void ScanFinished();
|
||||
|
||||
void BackendReady(boost::shared_ptr<LibraryBackend> backend);
|
||||
|
||||
public slots:
|
||||
void SetFilterAge(int age);
|
||||
void SetFilterText(const QString& text);
|
||||
|
@ -321,11 +321,17 @@ QStringList LibraryBackend::GetAllArtists(const QueryOptions& opt) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
QStringList LibraryBackend::GetAlbumsByArtist(const QueryOptions& opt, const QString& artist) {
|
||||
QStringList LibraryBackend::GetAllAlbums(const QueryOptions &opt) {
|
||||
return GetAlbumsByArtist(QString(), opt);
|
||||
}
|
||||
|
||||
QStringList LibraryBackend::GetAlbumsByArtist(const QString& artist, const QueryOptions& opt) {
|
||||
LibraryQuery query(opt);
|
||||
query.SetColumnSpec("DISTINCT album");
|
||||
query.AddCompilationRequirement(false);
|
||||
query.AddWhere("artist", artist);
|
||||
|
||||
if (!artist.isNull())
|
||||
query.AddWhere("artist", artist);
|
||||
|
||||
QSqlQuery q(query.Query(Connect()));
|
||||
q.exec();
|
||||
@ -338,7 +344,7 @@ QStringList LibraryBackend::GetAlbumsByArtist(const QueryOptions& opt, const QSt
|
||||
return ret;
|
||||
}
|
||||
|
||||
SongList LibraryBackend::GetSongs(const QueryOptions& opt, const QString& artist, const QString& album) {
|
||||
SongList LibraryBackend::GetSongs(const QString& artist, const QString& album, const QueryOptions& opt) {
|
||||
LibraryQuery query(opt);
|
||||
query.SetColumnSpec("ROWID, " + QString(Song::kColumnSpec));
|
||||
query.AddCompilationRequirement(false);
|
||||
@ -402,7 +408,7 @@ QStringList LibraryBackend::GetCompilationAlbums(const QueryOptions& opt) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
SongList LibraryBackend::GetCompilationSongs(const QueryOptions& opt, const QString& album) {
|
||||
SongList LibraryBackend::GetCompilationSongs(const QString& album, const QueryOptions& opt) {
|
||||
LibraryQuery query(opt);
|
||||
query.SetColumnSpec("ROWID, " + QString(Song::kColumnSpec));
|
||||
query.AddCompilationRequirement(true);
|
||||
@ -515,4 +521,33 @@ void LibraryBackend::UpdateCompilations(QSqlQuery& find_songs, QSqlQuery& update
|
||||
CheckErrors(update.lastError());
|
||||
}
|
||||
|
||||
QList<LibraryBackend::AlbumArtInfo>
|
||||
LibraryBackend::GetAlbumArtInfo(const QString& artist,
|
||||
const QueryOptions& opt) {
|
||||
QList<AlbumArtInfo> ret;
|
||||
LibraryQuery query(opt);
|
||||
query.SetColumnSpec("album, art_automatic, art_manual");
|
||||
query.SetOrderBy("album");
|
||||
|
||||
if (!artist.isNull())
|
||||
query.AddWhere("artist", artist);
|
||||
|
||||
QSqlQuery q(query.Query(Connect()));
|
||||
q.exec();
|
||||
if (CheckErrors(q.lastError())) return ret;
|
||||
|
||||
QString last_album;
|
||||
while (q.next()) {
|
||||
if (q.value(0).toString() == last_album)
|
||||
continue;
|
||||
|
||||
AlbumArtInfo info;
|
||||
info.album_name = q.value(0).toString();
|
||||
info.art_automatic = q.value(1).toString();
|
||||
info.art_manual = q.value(2).toString();
|
||||
ret << info;
|
||||
|
||||
last_album = info.album_name;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -9,8 +9,7 @@
|
||||
|
||||
#include "directory.h"
|
||||
#include "song.h"
|
||||
|
||||
struct QueryOptions;
|
||||
#include "libraryquery.h"
|
||||
|
||||
class LibraryBackend : public QObject {
|
||||
Q_OBJECT
|
||||
@ -18,6 +17,12 @@ class LibraryBackend : public QObject {
|
||||
public:
|
||||
LibraryBackend(QObject* parent = 0);
|
||||
|
||||
struct AlbumArtInfo {
|
||||
QString album_name;
|
||||
QString art_automatic;
|
||||
QString art_manual;
|
||||
};
|
||||
|
||||
// This actually refers to the location of the sqlite database
|
||||
static QString DefaultDirectory();
|
||||
|
||||
@ -29,13 +34,16 @@ class LibraryBackend : public QObject {
|
||||
|
||||
SongList FindSongsInDirectory(int id);
|
||||
|
||||
QStringList GetAllArtists(const QueryOptions& opt);
|
||||
QStringList GetAlbumsByArtist(const QueryOptions& opt, const QString& artist);
|
||||
SongList GetSongs(const QueryOptions& opt, const QString& artist, const QString& album);
|
||||
QStringList GetAllArtists(const QueryOptions& opt = QueryOptions());
|
||||
QStringList GetAllAlbums(const QueryOptions& opt = QueryOptions());
|
||||
QStringList GetAlbumsByArtist(const QString& artist, const QueryOptions& opt = QueryOptions());
|
||||
SongList GetSongs(const QString& artist, const QString& album, const QueryOptions& opt = QueryOptions());
|
||||
|
||||
bool HasCompilations(const QueryOptions& opt);
|
||||
QStringList GetCompilationAlbums(const QueryOptions& opt);
|
||||
SongList GetCompilationSongs(const QueryOptions& opt, const QString& album);
|
||||
bool HasCompilations(const QueryOptions& opt = QueryOptions());
|
||||
QStringList GetCompilationAlbums(const QueryOptions& opt = QueryOptions());
|
||||
SongList GetCompilationSongs(const QString& album, const QueryOptions& opt = QueryOptions());
|
||||
|
||||
QList<AlbumArtInfo> GetAlbumArtInfo(const QString& artist = QString(), const QueryOptions& opt = QueryOptions());
|
||||
|
||||
Song GetSongById(int id);
|
||||
|
||||
|
@ -53,6 +53,9 @@ QSqlQuery LibraryQuery::Query(QSqlDatabase db) const {
|
||||
if (!where_clauses_.isEmpty())
|
||||
sql += " WHERE " + where_clauses_.join(" AND ");
|
||||
|
||||
if (!order_by_.isEmpty())
|
||||
sql += " ORDER BY " + order_by_;
|
||||
|
||||
QSqlQuery q(sql, db);
|
||||
|
||||
// Bind values
|
||||
|
@ -24,6 +24,7 @@ class LibraryQuery {
|
||||
LibraryQuery(const QueryOptions& options);
|
||||
|
||||
void SetColumnSpec(const QString& spec) { column_spec_ = spec; }
|
||||
void SetOrderBy(const QString& order_by) { order_by_ = order_by; }
|
||||
void AddWhere(const QString& column, const QVariant& value);
|
||||
void AddCompilationRequirement(bool compilation);
|
||||
|
||||
@ -31,6 +32,7 @@ class LibraryQuery {
|
||||
|
||||
private:
|
||||
QString column_spec_;
|
||||
QString order_by_;
|
||||
QStringList where_clauses_;
|
||||
QVariantList bound_values_;
|
||||
};
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "about.h"
|
||||
#include "addstreamdialog.h"
|
||||
#include "stylesheetloader.h"
|
||||
#include "albumcovermanager.h"
|
||||
|
||||
#include "qxtglobalshortcut.h"
|
||||
|
||||
@ -54,6 +55,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
settings_dialog_(new SettingsDialog(this)),
|
||||
add_stream_dialog_(new AddStreamDialog(this)),
|
||||
shortcuts_dialog_(new ShortcutsDialog(this)),
|
||||
cover_manager_(new AlbumCoverManager(this)),
|
||||
playlist_menu_(new QMenu(this)),
|
||||
library_sort_model_(new QSortFilterProxyModel(this)),
|
||||
track_position_timer_(new QTimer(this))
|
||||
@ -114,6 +116,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
connect(ui_.action_add_stream, SIGNAL(triggered()), SLOT(AddStream()));
|
||||
connect(ui_.action_hide_tray_icon, SIGNAL(triggered()), SLOT(HideShowTrayIcon()));
|
||||
connect(ui_.action_global_shortcuts, SIGNAL(triggered()), shortcuts_dialog_, SLOT(show()));
|
||||
connect(ui_.action_cover_manager, SIGNAL(triggered()), cover_manager_, SLOT(show()));
|
||||
|
||||
// Give actions to buttons
|
||||
ui_.forward_button->setDefaultAction(ui_.action_next_track);
|
||||
@ -165,6 +168,8 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
connect(library_, SIGNAL(TotalSongCountUpdated(int)), ui_.library_view, SLOT(TotalSongCountUpdated(int)));
|
||||
connect(library_, SIGNAL(ScanStarted()), SLOT(LibraryScanStarted()));
|
||||
connect(library_, SIGNAL(ScanFinished()), SLOT(LibraryScanFinished()));
|
||||
connect(library_, SIGNAL(BackendReady(boost::shared_ptr<LibraryBackend>)),
|
||||
cover_manager_, SLOT(SetBackend(boost::shared_ptr<LibraryBackend>)));
|
||||
|
||||
// Age filters
|
||||
QActionGroup* filter_age_group = new QActionGroup(this);
|
||||
|
@ -22,6 +22,7 @@ class SettingsDialog;
|
||||
class About;
|
||||
class AddStreamDialog;
|
||||
class ShortcutsDialog;
|
||||
class AlbumCoverManager;
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
class SystemTrayIcon;
|
||||
@ -104,6 +105,7 @@ class MainWindow : public QMainWindow {
|
||||
SettingsDialog* settings_dialog_;
|
||||
AddStreamDialog* add_stream_dialog_;
|
||||
ShortcutsDialog* shortcuts_dialog_;
|
||||
AlbumCoverManager* cover_manager_;
|
||||
|
||||
QMenu* playlist_menu_;
|
||||
QAction* playlist_play_pause_;
|
||||
|
@ -309,7 +309,11 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="library_filter"/>
|
||||
<widget class="LineEdit" name="library_filter">
|
||||
<property name="hint" stdset="0">
|
||||
<string>Enter search terms here</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="library_options">
|
||||
@ -353,6 +357,9 @@
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -434,7 +441,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>804</width>
|
||||
<height>24</height>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuMusic">
|
||||
@ -478,8 +485,15 @@
|
||||
</property>
|
||||
<addaction name="action_about"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTools">
|
||||
<property name="title">
|
||||
<string>Tools</string>
|
||||
</property>
|
||||
<addaction name="action_cover_manager"/>
|
||||
</widget>
|
||||
<addaction name="menuMusic"/>
|
||||
<addaction name="menuPlaylist"/>
|
||||
<addaction name="menuTools"/>
|
||||
<addaction name="menuSettings"/>
|
||||
<addaction name="menuHelp"/>
|
||||
</widget>
|
||||
@ -706,9 +720,23 @@
|
||||
<string>Configure &Global Shortcuts...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_cover_manager">
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<normaloff>:/download.png</normaloff>:/download.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cover Manager</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>lineedit.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>BlockAnalyzer</class>
|
||||
<extends>QWidget</extends>
|
||||
|
11
src/src.pro
11
src/src.pro
@ -56,7 +56,9 @@ SOURCES += main.cpp \
|
||||
addstreamdialog.cpp \
|
||||
savedradio.cpp \
|
||||
stylesheetloader.cpp \
|
||||
shortcutsdialog.cpp
|
||||
shortcutsdialog.cpp \
|
||||
covermanager.cpp \
|
||||
coverloader.cpp
|
||||
HEADERS += mainwindow.h \
|
||||
player.h \
|
||||
library.h \
|
||||
@ -113,7 +115,9 @@ HEADERS += mainwindow.h \
|
||||
addstreamdialog.h \
|
||||
savedradio.h \
|
||||
stylesheetloader.h \
|
||||
shortcutsdialog.h
|
||||
shortcutsdialog.h \
|
||||
covermanager.h \
|
||||
coverloader.h
|
||||
FORMS += mainwindow.ui \
|
||||
libraryconfig.ui \
|
||||
fileview.ui \
|
||||
@ -127,7 +131,8 @@ FORMS += mainwindow.ui \
|
||||
lastfmconfigdialog.ui \
|
||||
about.ui \
|
||||
addstreamdialog.ui \
|
||||
shortcutsdialog.ui
|
||||
shortcutsdialog.ui \
|
||||
covermanager.ui
|
||||
RESOURCES += ../data/data.qrc \
|
||||
translations.qrc
|
||||
OTHER_FILES += ../data/schema.sql \
|
||||
|
Loading…
x
Reference in New Issue
Block a user