Includes, comments and bugfixes
- Fix includes - Use common regex (Song::kCoverRemoveDisc) for removing Disc/CD from album - Remove Disc/CD from album when creating hash - Make imobiledevice support compile - Fix setting device on windows
This commit is contained in:
@@ -474,11 +474,7 @@ set(UI
|
||||
|
||||
)
|
||||
|
||||
set(RESOURCES
|
||||
../data/data.qrc
|
||||
#../data/icons.qrc
|
||||
)
|
||||
|
||||
set(RESOURCES ../data/data.qrc)
|
||||
set(OTHER_SOURCES)
|
||||
|
||||
option(USE_INSTALL_PREFIX "Look for data in CMAKE_INSTALL_PREFIX" ON)
|
||||
@@ -487,7 +483,6 @@ option(USE_INSTALL_PREFIX "Look for data in CMAKE_INSTALL_PREFIX" ON)
|
||||
|
||||
set(GST_ENGINE_SRC engine/gstengine.cpp engine/gstenginepipeline.cpp engine/gstelementdeleter.cpp)
|
||||
set(GST_ENGINE_MOC engine/gstengine.h engine/gstenginepipeline.h engine/gstelementdeleter.h)
|
||||
#set(GST_ENGINE_LIB GSTREAMER GSTREAMER_BASE GSTREAMER_APP GSTREAMER_AUDIO GSTREAMER_TAG GSTREAMER_PBUTILS GSTREAMER_QTGLIB GSTREAMER_QTGST GSTREAMER_QTGSTUI GSTREAMER_QTGSTUTILS)
|
||||
set(GST_ENGINE_LIB GSTREAMER GSTREAMER_BASE GSTREAMER_APP GSTREAMER_AUDIO GSTREAMER_TAG GSTREAMER_PBUTILS)
|
||||
#set(GST_ENGINE_LIB gstreamer-1.0 gstreamer-base-1.0 gstreamer-app-1.0 streamer-audio-1.0 gstreamer-tag-1.0 gstreamer-pbutils-1.0)
|
||||
#set(GST_ENGINE_LIB ${GSTREAMER_BASE_LIBRARIES} ${GSTREAMER_LIBRARIES} ${GSTREAMER_APP_LIBRARIES} ${GSTREAMER_TAG_LIBRARIES} ${GSTREAMER_PBUTILS_LIBRARIES})
|
||||
@@ -846,6 +841,7 @@ add_library(strawberry_lib STATIC
|
||||
target_link_libraries(strawberry_lib
|
||||
libstrawberry-common
|
||||
libstrawberry-tagreader
|
||||
#gstafc
|
||||
${GLIB_LIBRARIES}
|
||||
${GIO_LIBRARIES}
|
||||
${SHA2_LIBRARIES}
|
||||
@@ -886,7 +882,6 @@ if(HAVE_IMOBILEDEVICE)
|
||||
${IMOBILEDEVICE_LIBRARIES}
|
||||
${PLIST_LIBRARIES}
|
||||
${USBMUXD_LIBRARIES}
|
||||
gstafcsrc
|
||||
)
|
||||
link_directories(${IMOBILEDEVICE_LIBRARY_DIRS})
|
||||
link_directories(${USBMUXD_LIBRARY_DIRS})
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QGLWidget>
|
||||
#include <QVector>
|
||||
|
||||
#include "analyzer.h"
|
||||
|
||||
#include "engines/enginebase.h"
|
||||
#include "engine/enginebase.h"
|
||||
|
||||
AnalyzerBase::AnalyzerBase(QWidget* parent)
|
||||
AnalyzerBase::AnalyzerBase(QWidget *parent)
|
||||
: QGLWidget(parent), engine_(nullptr) {}
|
||||
|
||||
void AnalyzerBase::set_engine(Engine::Base* engine) {
|
||||
void AnalyzerBase::set_engine(Engine::Base *engine) {
|
||||
disconnect(engine_);
|
||||
engine_ = engine;
|
||||
if (engine_) {
|
||||
|
||||
@@ -15,14 +15,17 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "analyzerbase.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <cmath> //interpolate()
|
||||
#include <cmath>
|
||||
|
||||
#include <QEvent> //event()
|
||||
#include <QWidget>
|
||||
#include <QPainter>
|
||||
#include <QPaintEvent>
|
||||
#include <QtDebug>
|
||||
#include <QPalette>
|
||||
#include <QTimerEvent>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "analyzerbase.h"
|
||||
|
||||
#include "engine/enginebase.h"
|
||||
|
||||
@@ -45,7 +48,7 @@
|
||||
template class Analyzer::Base<QWidget>;
|
||||
#endif
|
||||
|
||||
Analyzer::Base::Base(QWidget* parent, uint scopeSize)
|
||||
Analyzer::Base::Base(QWidget *parent, uint scopeSize)
|
||||
: QWidget(parent),
|
||||
m_timeout(40) // msec
|
||||
,
|
||||
@@ -70,9 +73,9 @@ void Analyzer::Base::transform(Scope& scope) // virtual
|
||||
// values
|
||||
// scope.resize( m_fht->size() );
|
||||
|
||||
float* front = static_cast<float*>(&scope.front());
|
||||
float *front = static_cast<float*>(&scope.front());
|
||||
|
||||
float* f = new float[m_fht->size()];
|
||||
float *f = new float[m_fht->size()];
|
||||
m_fht->copy(&f[0], front);
|
||||
m_fht->logSpectrum(front, &f[0]);
|
||||
m_fht->scale(front, 1.0 / 20);
|
||||
@@ -82,7 +85,7 @@ void Analyzer::Base::transform(Scope& scope) // virtual
|
||||
|
||||
}
|
||||
|
||||
void Analyzer::Base::paintEvent(QPaintEvent* e) {
|
||||
void Analyzer::Base::paintEvent(QPaintEvent *e) {
|
||||
|
||||
QPainter p(this);
|
||||
p.fillRect(e->rect(), palette().color(QPalette::Window));
|
||||
@@ -92,8 +95,7 @@ void Analyzer::Base::paintEvent(QPaintEvent* e) {
|
||||
const Engine::Scope& thescope = m_engine->scope(m_timeout);
|
||||
int i = 0;
|
||||
|
||||
// convert to mono here - our built in analyzers need mono, but the
|
||||
// engines provide interleaved pcm
|
||||
// convert to mono here - our built in analyzers need mono, but the engines provide interleaved pcm
|
||||
for (uint x = 0; (int)x < m_fht->size(); ++x) {
|
||||
m_lastScope[x] = double(thescope[i] + thescope[i + 1]) / (2 * (1 << 15));
|
||||
i += 2;
|
||||
@@ -180,8 +182,7 @@ void Analyzer::Base::polishEvent() {
|
||||
init(); // virtual
|
||||
}
|
||||
|
||||
void Analyzer::interpolate(const Scope& inVec, Scope& outVec) // static
|
||||
{
|
||||
void Analyzer::interpolate(const Scope& inVec, Scope& outVec) {
|
||||
|
||||
double pos = 0.0;
|
||||
const double step = (double)inVec.size() / outVec.size();
|
||||
@@ -203,8 +204,7 @@ void Analyzer::interpolate(const Scope& inVec, Scope& outVec) // static
|
||||
|
||||
}
|
||||
|
||||
void Analyzer::initSin(Scope& v, const uint size) // static
|
||||
{
|
||||
void Analyzer::initSin(Scope& v, const uint size) {
|
||||
double step = (M_PI * 2) / size;
|
||||
double radian = 0;
|
||||
|
||||
@@ -214,7 +214,7 @@ void Analyzer::initSin(Scope& v, const uint size) // static
|
||||
}
|
||||
}
|
||||
|
||||
void Analyzer::Base::timerEvent(QTimerEvent* e) {
|
||||
void Analyzer::Base::timerEvent(QTimerEvent *e) {
|
||||
QWidget::timerEvent(e);
|
||||
if (e->timerId() != m_timer.timerId()) return;
|
||||
|
||||
|
||||
@@ -4,29 +4,38 @@
|
||||
#ifndef ANALYZERBASE_H
|
||||
#define ANALYZERBASE_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "analyzer/fht.h" //stack allocated and convenience
|
||||
#include "engine/engine_fwd.h"
|
||||
#include <QPixmap> //stack allocated and convenience
|
||||
#include <QBasicTimer> //stack allocated
|
||||
#include <QWidget> //baseclass
|
||||
#include <vector> //included for convenience
|
||||
#include <stdbool.h>
|
||||
#include <vector>
|
||||
|
||||
#include <QGLWidget> //baseclass
|
||||
#ifdef Q_WS_MACX
|
||||
#include <OpenGL/gl.h> //included for convenience
|
||||
#include <OpenGL/glu.h> //included for convenience
|
||||
#include <OpenGL/gl.h> //included for convenience
|
||||
#include <OpenGL/glu.h> //included for convenience
|
||||
#else
|
||||
#include <GL/gl.h> //included for convenience
|
||||
#include <GL/glu.h> //included for convenience
|
||||
#include <GL/gl.h> //included for convenience
|
||||
#include <GL/glu.h> //included for convenience
|
||||
#endif
|
||||
|
||||
class QEvent;
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QBasicTimer>
|
||||
#include <QString>
|
||||
#include <QPainter>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "analyzer/fht.h"
|
||||
#include "engine/engine_fwd.h"
|
||||
|
||||
class QHideEvent;
|
||||
class QShowEvent;
|
||||
class QTimerEvent;
|
||||
class QPaintEvent;
|
||||
class QResizeEvent;
|
||||
|
||||
namespace Analyzer {
|
||||
|
||||
|
||||
@@ -17,19 +17,32 @@
|
||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
#include <QTimer>
|
||||
#include <QBoxLayout>
|
||||
#include <QLayout>
|
||||
#include <QSignalMapper>
|
||||
#include <QSettings>
|
||||
#include <QtEvents>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "analyzercontainer.h"
|
||||
|
||||
#include "analyzerbase.h"
|
||||
#include "blockanalyzer.h"
|
||||
|
||||
#include "core/logging.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QSettings>
|
||||
#include <QTimer>
|
||||
#include <QtDebug>
|
||||
|
||||
const char* AnalyzerContainer::kSettingsGroup = "Analyzer";
|
||||
const char* AnalyzerContainer::kSettingsFramerate = "framerate";
|
||||
const char *AnalyzerContainer::kSettingsGroup = "Analyzer";
|
||||
const char *AnalyzerContainer::kSettingsFramerate = "framerate";
|
||||
|
||||
// Framerates
|
||||
const int AnalyzerContainer::kLowFramerate = 20;
|
||||
@@ -37,7 +50,7 @@ const int AnalyzerContainer::kMediumFramerate = 25;
|
||||
const int AnalyzerContainer::kHighFramerate = 30;
|
||||
const int AnalyzerContainer::kSuperHighFramerate = 60;
|
||||
|
||||
AnalyzerContainer::AnalyzerContainer(QWidget* parent)
|
||||
AnalyzerContainer::AnalyzerContainer(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
current_framerate_(kMediumFramerate),
|
||||
context_menu_(new QMenu(this)),
|
||||
@@ -51,7 +64,7 @@ AnalyzerContainer::AnalyzerContainer(QWidget* parent)
|
||||
ignore_next_click_(false),
|
||||
current_analyzer_(nullptr),
|
||||
engine_(nullptr) {
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||
setLayout(layout);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
@@ -82,19 +95,18 @@ AnalyzerContainer::AnalyzerContainer(QWidget* parent)
|
||||
Load();
|
||||
}
|
||||
|
||||
void AnalyzerContainer::SetActions(QAction* visualisation) {
|
||||
void AnalyzerContainer::SetActions(QAction *visualisation) {
|
||||
visualisation_action_ = visualisation;
|
||||
context_menu_->addAction(visualisation_action_);
|
||||
}
|
||||
|
||||
void AnalyzerContainer::mouseReleaseEvent(QMouseEvent* e) {
|
||||
void AnalyzerContainer::mouseReleaseEvent(QMouseEvent *e) {
|
||||
if (e->button() == Qt::LeftButton) {
|
||||
if (ignore_next_click_) {
|
||||
ignore_next_click_ = false;
|
||||
}
|
||||
else {
|
||||
// Might be the first click in a double click, so wait a while before
|
||||
// actually doing anything
|
||||
// Might be the first click in a double click, so wait a while before actually doing anything
|
||||
double_click_timer_->start();
|
||||
last_click_pos_ = e->globalPos();
|
||||
}
|
||||
@@ -115,11 +127,11 @@ void AnalyzerContainer::mouseDoubleClickEvent(QMouseEvent*) {
|
||||
if (visualisation_action_) visualisation_action_->trigger();
|
||||
}
|
||||
|
||||
void AnalyzerContainer::wheelEvent(QWheelEvent* e) {
|
||||
void AnalyzerContainer::wheelEvent(QWheelEvent *e) {
|
||||
emit WheelEvent(e->delta());
|
||||
}
|
||||
|
||||
void AnalyzerContainer::SetEngine(EngineBase* engine) {
|
||||
void AnalyzerContainer::SetEngine(EngineBase *engine) {
|
||||
if (current_analyzer_) current_analyzer_->set_engine(engine);
|
||||
engine_ = engine;
|
||||
}
|
||||
@@ -132,11 +144,10 @@ void AnalyzerContainer::DisableAnalyzer() {
|
||||
}
|
||||
|
||||
void AnalyzerContainer::ChangeAnalyzer(int id) {
|
||||
QObject* instance = analyzer_types_[id]->newInstance(Q_ARG(QWidget*, this));
|
||||
QObject *instance = analyzer_types_[id]->newInstance(Q_ARG(QWidget*, this));
|
||||
|
||||
if (!instance) {
|
||||
qLog(Warning) << "Couldn't intialise a new"
|
||||
<< analyzer_types_[id]->className();
|
||||
qLog(Warning) << "Couldn't intialise a new" << analyzer_types_[id]->className();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -196,8 +207,7 @@ void AnalyzerContainer::Load() {
|
||||
}
|
||||
|
||||
void AnalyzerContainer::SaveFramerate(int framerate) {
|
||||
// For now, framerate is common for all analyzers. Maybe each analyzer should
|
||||
// have its own framerate?
|
||||
// For now, framerate is common for all analyzers. Maybe each analyzer should have its own framerate?
|
||||
current_framerate_ = framerate;
|
||||
QSettings s;
|
||||
s.beginGroup(kSettingsGroup);
|
||||
@@ -212,7 +222,7 @@ void AnalyzerContainer::Save() {
|
||||
}
|
||||
|
||||
void AnalyzerContainer::AddFramerate(const QString& name, int framerate) {
|
||||
QAction* action = context_menu_framerate_->addAction(name, mapper_framerate_, SLOT(map()));
|
||||
QAction *action = context_menu_framerate_->addAction(name, mapper_framerate_, SLOT(map()));
|
||||
mapper_framerate_->setMapping(action, framerate);
|
||||
group_framerate_->addAction(action);
|
||||
framerate_list_ << framerate;
|
||||
|
||||
@@ -20,13 +20,31 @@
|
||||
#ifndef ANALYZERCONTAINER_H
|
||||
#define ANALYZERCONTAINER_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QMenu>
|
||||
#include <QSignalMapper>
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QPoint>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QSignalMapper>
|
||||
#include <QTimer>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "analyzerbase.h"
|
||||
#include "engine/engine_fwd.h"
|
||||
|
||||
class QMouseEvent;
|
||||
class QWheelEvent;
|
||||
|
||||
namespace Analyzer {
|
||||
class Base;
|
||||
} // namespace Analyzer
|
||||
|
||||
class AnalyzerContainer : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -5,12 +5,19 @@
|
||||
|
||||
#include "blockanalyzer.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QResizeEvent>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <scoped_allocator>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
#include <QPalette>
|
||||
#include <QColor>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "analyzerbase.h"
|
||||
#include "fht.h"
|
||||
|
||||
const uint BlockAnalyzer::HEIGHT = 2;
|
||||
const uint BlockAnalyzer::WIDTH = 4;
|
||||
@@ -19,10 +26,10 @@ const uint BlockAnalyzer::MIN_COLUMNS = 32; // arbituary
|
||||
const uint BlockAnalyzer::MAX_COLUMNS = 256; // must be 2**n
|
||||
const uint BlockAnalyzer::FADE_SIZE = 90;
|
||||
|
||||
const char* BlockAnalyzer::kName =
|
||||
const char *BlockAnalyzer::kName =
|
||||
QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer");
|
||||
|
||||
BlockAnalyzer::BlockAnalyzer(QWidget* parent)
|
||||
BlockAnalyzer::BlockAnalyzer(QWidget *parent)
|
||||
: Analyzer::Base(parent, 9),
|
||||
m_columns(0) // uint
|
||||
,
|
||||
@@ -43,9 +50,7 @@ BlockAnalyzer::BlockAnalyzer(QWidget* parent)
|
||||
,
|
||||
m_fade_intensity(1 << 8, 32) // vector<uint>
|
||||
{
|
||||
setMinimumSize(MIN_COLUMNS * (WIDTH + 1) - 1,
|
||||
MIN_ROWS * (HEIGHT + 1) -
|
||||
1); //-1 is padding, no drawing takes place there
|
||||
setMinimumSize(MIN_COLUMNS * (WIDTH + 1) - 1, MIN_ROWS * (HEIGHT + 1) - 1); //-1 is padding, no drawing takes place there
|
||||
setMaximumWidth(MAX_COLUMNS * (WIDTH + 1) - 1);
|
||||
|
||||
// mxcl says null pixmaps cause crashes, so let's play it safe
|
||||
@@ -54,7 +59,7 @@ BlockAnalyzer::BlockAnalyzer(QWidget* parent)
|
||||
|
||||
BlockAnalyzer::~BlockAnalyzer() {}
|
||||
|
||||
void BlockAnalyzer::resizeEvent(QResizeEvent* e) {
|
||||
void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
|
||||
QWidget::resizeEvent(e);
|
||||
|
||||
m_background = QPixmap(size());
|
||||
@@ -96,8 +101,7 @@ void BlockAnalyzer::resizeEvent(QResizeEvent* e) {
|
||||
}
|
||||
|
||||
void BlockAnalyzer::determineStep() {
|
||||
// falltime is dependent on rowcount due to our digital resolution (ie we have
|
||||
// boxes/blocks of pixels)
|
||||
// falltime is dependent on rowcount due to our digital resolution (ie we have boxes/blocks of pixels)
|
||||
// I calculated the value 30 based on some trial and error
|
||||
|
||||
// the fall time of 30 is too slow on framerates above 50fps
|
||||
@@ -119,10 +123,7 @@ void BlockAnalyzer::transform(Analyzer::Scope& s) // pure virtual
|
||||
m_fht->spectrum(front);
|
||||
m_fht->scale(front, 1.0 / 20);
|
||||
|
||||
// the second half is pretty dull, so only show it if the user has a large
|
||||
// analyzer
|
||||
// by setting to m_scope.size() if large we prevent interpolation of large
|
||||
// analyzers, this is good!
|
||||
// the second half is pretty dull, so only show it if the user has a large analyzer by setting to m_scope.size() if large we prevent interpolation of large analyzers, this is good!
|
||||
s.resize(m_scope.size() <= MAX_COLUMNS / 2 ? MAX_COLUMNS / 2 : m_scope.size());
|
||||
}
|
||||
|
||||
@@ -158,15 +159,13 @@ void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
|
||||
for (y = 0; m_scope[x] < m_yscale[y]; ++y)
|
||||
;
|
||||
|
||||
// this is opposite to what you'd think, higher than y
|
||||
// means the bar is lower than y (physically)
|
||||
// this is opposite to what you'd think, higher than y means the bar is lower than y (physically)
|
||||
if ((float)y > m_store[x])
|
||||
y = int(m_store[x] += m_step);
|
||||
else
|
||||
m_store[x] = y;
|
||||
|
||||
// if y is lower than m_fade_pos, then the bar has exceeded the height of
|
||||
// the fadeout
|
||||
// if y is lower than m_fade_pos, then the bar has exceeded the height of the fadeout
|
||||
// if the fadeout is quite faded now, then display the new one
|
||||
if (y <= m_fade_pos[x] /*|| m_fade_intensity[x] < FADE_SIZE / 3*/) {
|
||||
m_fade_pos[x] = y;
|
||||
@@ -181,8 +180,7 @@ void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
|
||||
|
||||
if (m_fade_intensity[x] == 0) m_fade_pos[x] = m_rows;
|
||||
|
||||
// REMEMBER: y is a number from 0 to m_rows, 0 means all blocks are glowing,
|
||||
// m_rows means none are
|
||||
// REMEMBER: y is a number from 0 to m_rows, 0 means all blocks are glowing, m_rows means none are
|
||||
canvas_painter.drawPixmap(x * (WIDTH + 1), y * (HEIGHT + 1) + m_y, *bar(),
|
||||
0, y * (HEIGHT + 1), bar()->width(),
|
||||
bar()->height());
|
||||
@@ -195,8 +193,7 @@ void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
|
||||
}
|
||||
|
||||
static inline void adjustToLimits(int& b, int& f, uint& amount) {
|
||||
// with a range of 0-255 and maximum adjustment of amount,
|
||||
// maximise the difference between f and b
|
||||
// with a range of 0-255 and maximum adjustment of amount, maximise the difference between f and b
|
||||
|
||||
if (b < f) {
|
||||
if (b > 255 - f) {
|
||||
|
||||
@@ -5,12 +5,21 @@
|
||||
#ifndef BLOCKANALYZER_H
|
||||
#define BLOCKANALYZER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <vector>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QString>
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
#include <QPalette>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "analyzerbase.h"
|
||||
#include <qcolor.h>
|
||||
|
||||
class QResizeEvent;
|
||||
class QMouseEvent;
|
||||
class QPalette;
|
||||
|
||||
/**
|
||||
* @author Max Howell
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fht.h"
|
||||
|
||||
FHT::FHT(int n) : m_buf(0), m_tab(0), m_log(0) {
|
||||
|
||||
@@ -20,19 +20,23 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QList>
|
||||
|
||||
#include "collection.h"
|
||||
|
||||
#include "collectionmodel.h"
|
||||
#include "collectionbackend.h"
|
||||
#include "core/application.h"
|
||||
#include "core/database.h"
|
||||
#include "core/player.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "core/taskmanager.h"
|
||||
#include "core/thread.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/utilities.h"
|
||||
#include "collection.h"
|
||||
#include "collectionwatcher.h"
|
||||
#include "collectionbackend.h"
|
||||
#include "collectionmodel.h"
|
||||
#include "playlist/playlistmanager.h"
|
||||
|
||||
const char *Collection::kSongsTable = "songs";
|
||||
const char *Collection::kDirsTable = "directories";
|
||||
@@ -47,8 +51,6 @@ Collection::Collection(Application *app, QObject *parent)
|
||||
watcher_(nullptr),
|
||||
watcher_thread_(nullptr) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
backend_ = new CollectionBackend;
|
||||
backend()->moveToThread(app->database()->thread());
|
||||
|
||||
@@ -62,8 +64,6 @@ Collection::Collection(Application *app, QObject *parent)
|
||||
}
|
||||
|
||||
Collection::~Collection() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
watcher_->deleteLater();
|
||||
watcher_thread_->exit();
|
||||
@@ -71,8 +71,6 @@ Collection::~Collection() {
|
||||
}
|
||||
|
||||
void Collection::Init() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
watcher_ = new CollectionWatcher;
|
||||
watcher_thread_ = new Thread(this);
|
||||
@@ -109,8 +107,6 @@ void Collection::PauseWatcher() { watcher_->SetRescanPausedAsync(true); }
|
||||
void Collection::ResumeWatcher() { watcher_->SetRescanPausedAsync(false); }
|
||||
|
||||
void Collection::ReloadSettings() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
watcher_->ReloadSettingsAsync();
|
||||
|
||||
@@ -118,14 +114,10 @@ void Collection::ReloadSettings() {
|
||||
|
||||
void Collection::Stopped() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
CurrentSongChanged(Song());
|
||||
}
|
||||
|
||||
void Collection::CurrentSongChanged(const Song &song) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
TagReaderReply *reply = nullptr;
|
||||
|
||||
@@ -140,8 +132,6 @@ void Collection::CurrentSongChanged(const Song &song) {
|
||||
|
||||
SongList Collection::FilterCurrentWMASong(SongList songs, Song* queued) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
for (SongList::iterator it = songs.begin(); it != songs.end(); ) {
|
||||
if (it->url() == current_wma_song_url_) {
|
||||
*queued = *it;
|
||||
|
||||
@@ -23,19 +23,18 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include "core/song.h"
|
||||
|
||||
class Application;
|
||||
class Database;
|
||||
class Thread;
|
||||
class CollectionBackend;
|
||||
class CollectionModel;
|
||||
class CollectionWatcher;
|
||||
class TaskManager;
|
||||
class Thread;
|
||||
|
||||
class Collection : public QObject {
|
||||
Q_OBJECT
|
||||
@@ -85,13 +84,11 @@ class Collection : public QObject {
|
||||
CollectionWatcher *watcher_;
|
||||
Thread *watcher_thread_;
|
||||
|
||||
// Hack: Gstreamer doesn't cope well with WMA files being rewritten while
|
||||
// being played, so we delay statistics and rating changes until the current
|
||||
// song has finished playing.
|
||||
// Hack: Gstreamer doesn't cope well with WMA files being rewritten while being played,
|
||||
// so we delay statistics and rating changes until the current song has finished playing.
|
||||
QUrl current_wma_song_url_;
|
||||
|
||||
// DB schema versions which should trigger a full collection rescan (each of
|
||||
// those with a short reason why).
|
||||
// DB schema versions which should trigger a full collection rescan (each of those with a short reason why).
|
||||
QHash<int, QString> full_rescan_revisions_;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,22 +20,32 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QSet>
|
||||
#include <QMap>
|
||||
#include <QByteArray>
|
||||
#include <QFileInfo>
|
||||
#include <QSettings>
|
||||
#include <QDateTime>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/database.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/scopedtransaction.h"
|
||||
#include "core/utilities.h"
|
||||
|
||||
#include "directory.h"
|
||||
#include "collectionbackend.h"
|
||||
#include "collectionquery.h"
|
||||
#include "sqlrow.h"
|
||||
#include "core/application.h"
|
||||
#include "core/database.h"
|
||||
#include "core/scopedtransaction.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "core/utilities.h"
|
||||
|
||||
const char *CollectionBackend::kSettingsGroup = "Collection";
|
||||
|
||||
@@ -258,6 +268,7 @@ void CollectionBackend::AddDirectory(const QString &path) {
|
||||
dir.id = q.lastInsertId().toInt();
|
||||
|
||||
emit DirectoryDiscovered(dir, SubdirectoryList());
|
||||
|
||||
}
|
||||
|
||||
void CollectionBackend::RemoveDirectory(const Directory &dir) {
|
||||
@@ -287,6 +298,7 @@ void CollectionBackend::RemoveDirectory(const Directory &dir) {
|
||||
emit DirectoryDeleted(dir);
|
||||
|
||||
transaction.Commit();
|
||||
|
||||
}
|
||||
|
||||
SongList CollectionBackend::FindSongsInDirectory(int id) {
|
||||
@@ -307,6 +319,7 @@ SongList CollectionBackend::FindSongsInDirectory(int id) {
|
||||
ret << song;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void CollectionBackend::AddOrUpdateSubdirs(const SubdirectoryList &subdirs) {
|
||||
@@ -381,8 +394,7 @@ void CollectionBackend::AddOrUpdateSongs(const SongList &songs) {
|
||||
|
||||
for (const Song &song : songs) {
|
||||
// Do a sanity check first - make sure the song's directory still exists
|
||||
// This is to fix a possible race condition when a directory is removed
|
||||
// while CollectionWatcher is scanning it.
|
||||
// This is to fix a possible race condition when a directory is removed while CollectionWatcher is scanning it.
|
||||
if (!dirs_table_.isEmpty()) {
|
||||
check_dir.bindValue(":id", song.directory_id());
|
||||
check_dir.exec();
|
||||
@@ -752,8 +764,7 @@ void CollectionBackend::UpdateCompilations() {
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
// Look for albums that have songs by more than one 'effective album artist' in the same
|
||||
// directory
|
||||
// Look for albums that have songs by more than one 'effective album artist' in the same directory
|
||||
|
||||
QSqlQuery q(db);
|
||||
q.prepare(QString("SELECT effective_albumartist, album, filename, compilation_detected FROM %1 WHERE unavailable = 0 ORDER BY album").arg(songs_table_));
|
||||
@@ -819,8 +830,7 @@ void CollectionBackend::UpdateCompilations() {
|
||||
|
||||
void CollectionBackend::UpdateCompilations(QSqlQuery &find_songs, QSqlQuery &update, SongList &deleted_songs, SongList &added_songs, const QString &album, int compilation_detected) {
|
||||
|
||||
// Get songs that were already in that album, so we can tell the model
|
||||
// they've been updated
|
||||
// Get songs that were already in that album, so we can tell the model they've been updated
|
||||
find_songs.bindValue(":album", album);
|
||||
find_songs.bindValue(":compilation_detected", int(!compilation_detected));
|
||||
find_songs.exec();
|
||||
@@ -1104,6 +1114,7 @@ void CollectionBackend::ResetStatistics(int id) {
|
||||
}
|
||||
|
||||
void CollectionBackend::DeleteAll() {
|
||||
|
||||
{
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
@@ -23,13 +23,22 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
#include <QUrl>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVector>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
|
||||
#include "directory.h"
|
||||
#include "collectionquery.h"
|
||||
#include "core/song.h"
|
||||
#include "collectionquery.h"
|
||||
#include "directory.h"
|
||||
|
||||
class Database;
|
||||
|
||||
@@ -94,11 +103,9 @@ class CollectionBackendInterface : public QObject {
|
||||
|
||||
virtual Song GetSongById(int id) = 0;
|
||||
|
||||
// Returns all sections of a song with the given filename. If there's just one section
|
||||
// the resulting list will have it's size equal to 1.
|
||||
// Returns all sections of a song with the given filename. If there's just one section the resulting list will have it's size equal to 1.
|
||||
virtual SongList GetSongsByUrl(const QUrl &url) = 0;
|
||||
// Returns a section of a song with the given filename and beginning. If the section
|
||||
// is not present in collection, returns invalid song.
|
||||
// Returns a section of a song with the given filename and beginning. If the section is not present in collection, returns invalid song.
|
||||
// Using default beginning value is suitable when searching for single-section songs.
|
||||
virtual Song GetSongByUrl(const QUrl &url, qint64 beginning = 0) = 0;
|
||||
|
||||
|
||||
@@ -20,15 +20,23 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "collectiondirectorymodel.h"
|
||||
#include "collectionbackend.h"
|
||||
#include <QObject>
|
||||
#include <QStandardItemModel>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/filesystemmusicstorage.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/musicstorage.h"
|
||||
#include "core/utilities.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "directory.h"
|
||||
#include "collectionbackend.h"
|
||||
#include "collectiondirectorymodel.h"
|
||||
|
||||
CollectionDirectoryModel::CollectionDirectoryModel(CollectionBackend* backend, QObject* parent)
|
||||
CollectionDirectoryModel::CollectionDirectoryModel(CollectionBackend *backend, QObject *parent)
|
||||
: QStandardItemModel(parent),
|
||||
dir_icon_(IconLoader::Load("document-open-folder")),
|
||||
backend_(backend)
|
||||
@@ -43,7 +51,7 @@ CollectionDirectoryModel::~CollectionDirectoryModel() {}
|
||||
|
||||
void CollectionDirectoryModel::DirectoryDiscovered(const Directory &dir) {
|
||||
|
||||
QStandardItem* item;
|
||||
QStandardItem *item;
|
||||
if (Application::kIsPortable && Utilities::UrlOnSameDriveAsStrawberry(QUrl::fromLocalFile(dir.path))) {
|
||||
item = new QStandardItem(Utilities::GetRelativePathToStrawberryBin(QUrl::fromLocalFile(dir.path)).toLocalFile());
|
||||
}
|
||||
|
||||
@@ -25,11 +25,16 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QIcon>
|
||||
#include <QObject>
|
||||
#include <QStandardItemModel>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QIcon>
|
||||
|
||||
#include "directory.h"
|
||||
class QModelIndex;
|
||||
|
||||
struct Directory;
|
||||
class CollectionBackend;
|
||||
class MusicStorage;
|
||||
|
||||
|
||||
@@ -20,23 +20,35 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QWidget>
|
||||
#include <QObject>
|
||||
#include <QDataStream>
|
||||
#include <QIODevice>
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
#include <QInputDialog>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QByteArray>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QRegExp>
|
||||
#include <QInputDialog>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
#include <QMenu>
|
||||
#include <QSettings>
|
||||
#include <QSignalMapper>
|
||||
#include <QTimer>
|
||||
#include <QToolButton>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "collectionfilterwidget.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/song.h"
|
||||
#include "collectionmodel.h"
|
||||
#include "collectionquery.h"
|
||||
#include "savedgroupingmanager.h"
|
||||
#include "collectionfilterwidget.h"
|
||||
#include "groupbydialog.h"
|
||||
#include "ui_collectionfilterwidget.h"
|
||||
#include "core/song.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "settings/settingsdialog.h"
|
||||
|
||||
CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
@@ -48,8 +60,7 @@ CollectionFilterWidget::CollectionFilterWidget(QWidget *parent)
|
||||
delay_behaviour_(DelayedOnLargeLibraries) {
|
||||
ui_->setupUi(this);
|
||||
|
||||
// Add the available fields to the tooltip here instead of the ui
|
||||
// file to prevent that they get translated by mistake.
|
||||
// Add the available fields to the tooltip here instead of the ui file to prevent that they get translated by mistake.
|
||||
QString available_fields = Song::kFtsColumns.join(", ").replace(QRegExp("\\bfts"), "");
|
||||
ui_->filter->setToolTip(ui_->filter->toolTip().arg(available_fields));
|
||||
|
||||
@@ -125,8 +136,7 @@ void CollectionFilterWidget::UpdateGroupByActions() {
|
||||
group_by_group_ = CreateGroupByActions(this);
|
||||
group_by_menu_->clear();
|
||||
group_by_menu_->addActions(group_by_group_->actions());
|
||||
connect(group_by_group_, SIGNAL(triggered(QAction*)),
|
||||
SLOT(GroupByClicked(QAction*)));
|
||||
connect(group_by_group_, SIGNAL(triggered(QAction*)), SLOT(GroupByClicked(QAction*)));
|
||||
if (model_) {
|
||||
CheckCurrentGrouping(model_->GetGroupBy());
|
||||
}
|
||||
@@ -338,10 +348,9 @@ void CollectionFilterWidget::keyReleaseEvent(QKeyEvent *e) {
|
||||
|
||||
void CollectionFilterWidget::FilterTextChanged(const QString &text) {
|
||||
|
||||
// Searching with one or two characters can be very expensive on the database
|
||||
// even with FTS, so if there are a large number of songs in the database
|
||||
// introduce a small delay before actually filtering the model, so if the
|
||||
// user is typing the first few characters of something it will be quicker.
|
||||
// Searching with one or two characters can be very expensive on the database even with FTS,
|
||||
// so if there are a large number of songs in the database introduce a small delay before actually filtering the model,
|
||||
// so if the user is typing the first few characters of something it will be quicker.
|
||||
const bool delay = (delay_behaviour_ == AlwaysDelayed) || (delay_behaviour_ == DelayedOnLargeLibraries && !text.isEmpty() && text.length() < 3 && model_->total_song_count() >= 100000);
|
||||
|
||||
if (delay) {
|
||||
|
||||
@@ -24,22 +24,29 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QMenu>
|
||||
#include <QSignalMapper>
|
||||
#include <QTimer>
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "collectionquery.h"
|
||||
#include "collectionmodel.h"
|
||||
#include "savedgroupingmanager.h"
|
||||
|
||||
class QKeyEvent;
|
||||
|
||||
class GroupByDialog;
|
||||
class SavedGroupingManager;
|
||||
class SettingsDialog;
|
||||
class Ui_CollectionFilterWidget;
|
||||
|
||||
struct QueryOptions;
|
||||
|
||||
class QMenu;
|
||||
class QActionGroup;
|
||||
class QSignalMapper;
|
||||
|
||||
class CollectionFilterWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
|
||||
#include "core/simpletreeitem.h"
|
||||
#include "core/song.h"
|
||||
|
||||
|
||||
@@ -22,32 +22,44 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <QObject>
|
||||
#include <QtGlobal>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QtAlgorithms>
|
||||
#include <QMutex>
|
||||
#include <QFuture>
|
||||
#include <QDataStream>
|
||||
#include <QMimeData>
|
||||
#include <QIODevice>
|
||||
#include <QMetaEnum>
|
||||
#include <QNetworkCacheMetaData>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QPixmapCache>
|
||||
#include <QSettings>
|
||||
#include <QByteArray>
|
||||
#include <QVariant>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include <QChar>
|
||||
#include <QRegExp>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QImage>
|
||||
#include <QPixmapCache>
|
||||
#include <QSettings>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "collectionmodel.h"
|
||||
|
||||
#include "collectionbackend.h"
|
||||
#include "collectionitem.h"
|
||||
#include "collectiondirectorymodel.h"
|
||||
#include "collectionview.h"
|
||||
#include "sqlrow.h"
|
||||
#include "core/application.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/database.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/taskmanager.h"
|
||||
#include "core/utilities.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "covermanager/albumcoverloader.h"
|
||||
#include "collectionquery.h"
|
||||
#include "collectionbackend.h"
|
||||
#include "collectiondirectorymodel.h"
|
||||
#include "collectionitem.h"
|
||||
#include "collectionmodel.h"
|
||||
#include "sqlrow.h"
|
||||
#include "playlist/playlistmanager.h"
|
||||
#include "playlist/songmimedata.h"
|
||||
#include "covermanager/albumcoverloader.h"
|
||||
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
@@ -178,11 +190,9 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
|
||||
// Hey, we've already got that one!
|
||||
if (song_nodes_.contains(song.id())) continue;
|
||||
|
||||
// Before we can add each song we need to make sure the required container
|
||||
// items already exist in the tree. These depend on which "group by"
|
||||
// settings the user has on the collection. Eg. if the user grouped by
|
||||
// artist and album, we would need to make sure nodes for the song's artist
|
||||
// and album were already in the tree.
|
||||
// Before we can add each song we need to make sure the required container items already exist in the tree.
|
||||
// These depend on which "group by" settings the user has on the collection.
|
||||
// Eg. if the user grouped by artist and album, we would need to make sure nodes for the song's artist and album were already in the tree.
|
||||
|
||||
// Find parent containers in the tree
|
||||
CollectionItem *container = root_;
|
||||
@@ -190,8 +200,7 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
|
||||
GroupBy type = group_by_[i];
|
||||
if (type == GroupBy_None) break;
|
||||
|
||||
// Special case: if the song is a compilation and the current GroupBy
|
||||
// level is Artists, then we want the Various Artists node :(
|
||||
// Special case: if the song is a compilation and the current GroupBy level is Artists, then we want the Various Artists node :(
|
||||
if (IsArtistGroupBy(type) && song.is_compilation()) {
|
||||
if (container->compilation_artist_node_ == nullptr)
|
||||
CreateCompilationArtistNode(true, container);
|
||||
@@ -240,15 +249,13 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
|
||||
container = container_nodes_[i][key];
|
||||
}
|
||||
|
||||
// If we just created the damn thing then we don't need to continue into
|
||||
// it any further because it'll get lazy-loaded properly later.
|
||||
// If we just created the damn thing then we don't need to continue into it any further because it'll get lazy-loaded properly later.
|
||||
if (!container->lazy_loaded) break;
|
||||
}
|
||||
|
||||
if (!container->lazy_loaded) continue;
|
||||
|
||||
// We've gone all the way down to the deepest level and everything was
|
||||
// already lazy loaded, so now we have to create the song in the container.
|
||||
// We've gone all the way down to the deepest level and everything was already lazy loaded, so now we have to create the song in the container.
|
||||
song_nodes_[song.id()] = ItemFromSong(GroupBy_None, true, false, container, song, -1);
|
||||
}
|
||||
|
||||
@@ -256,9 +263,8 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
|
||||
|
||||
void CollectionModel::SongsSlightlyChanged(const SongList &songs) {
|
||||
|
||||
// This is called if there was a minor change to the songs that will not
|
||||
// normally require the collection to be restructured. We can just update our
|
||||
// internal cache of Song objects without worrying about resetting the model.
|
||||
// This is called if there was a minor change to the songs that will not normally require the collection to be restructured.
|
||||
// We can just update our internal cache of Song objects without worrying about resetting the model.
|
||||
for (const Song &song : songs) {
|
||||
if (song_nodes_.contains(song.id())) {
|
||||
song_nodes_[song.id()]->metadata = song;
|
||||
@@ -285,8 +291,7 @@ CollectionItem *CollectionModel::CreateCompilationArtistNode(bool signal, Collec
|
||||
|
||||
QString CollectionModel::DividerKey(GroupBy type, CollectionItem *item) const {
|
||||
|
||||
// Items which are to be grouped under the same divider must produce the
|
||||
// same divider key. This will only get called for top-level items.
|
||||
// Items which are to be grouped under the same divider must produce the same divider key. This will only get called for top-level items.
|
||||
|
||||
if (item->sort_text.isEmpty()) return QString();
|
||||
|
||||
@@ -371,8 +376,7 @@ QString CollectionModel::DividerDisplayText(GroupBy type, const QString &key) co
|
||||
|
||||
void CollectionModel::SongsDeleted(const SongList &songs) {
|
||||
|
||||
// Delete the actual song nodes first, keeping track of each parent so we
|
||||
// might check to see if they're empty later.
|
||||
// Delete the actual song nodes first, keeping track of each parent so we might check to see if they're empty later.
|
||||
QSet<CollectionItem*> parents;
|
||||
for (const Song &song : songs) {
|
||||
if (song_nodes_.contains(song.id())) {
|
||||
@@ -386,11 +390,9 @@ void CollectionModel::SongsDeleted(const SongList &songs) {
|
||||
endRemoveRows();
|
||||
}
|
||||
else {
|
||||
// If we get here it means some of the songs we want to delete haven't
|
||||
// been lazy-loaded yet. This is bad, because it would mean that to
|
||||
// clean up empty parents we would need to lazy-load them all
|
||||
// individually to see if they're empty. This can take a very long time,
|
||||
// so better to just reset the model and be done with it.
|
||||
// If we get here it means some of the songs we want to delete haven't been lazy-loaded yet.
|
||||
// This is bad, because it would mean that to clean up empty parents we would need to lazy-load them all individually to see if they're empty.
|
||||
// This can take a very long time, so better to just reset the model and be done with it.
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
@@ -399,9 +401,8 @@ void CollectionModel::SongsDeleted(const SongList &songs) {
|
||||
// Now delete empty parents
|
||||
QSet<QString> divider_keys;
|
||||
while (!parents.isEmpty()) {
|
||||
// Since we are going to remove elements from the container, we
|
||||
// need a copy to iterate over. If we iterate over the original,
|
||||
// the behavior will be undefined.
|
||||
// Since we are going to remove elements from the container, we need a copy to iterate over.
|
||||
// If we iterate over the original, the behavior will be undefined.
|
||||
QSet<CollectionItem*> parents_copy = parents;
|
||||
for (CollectionItem *node : parents_copy) {
|
||||
parents.remove(node);
|
||||
|
||||
@@ -23,26 +23,40 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QIcon>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QFuture>
|
||||
#include <QDataStream>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QMetaType>
|
||||
#include <QMimeData>
|
||||
#include <QPair>
|
||||
#include <QSet>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QSettings>
|
||||
|
||||
#include "collectionitem.h"
|
||||
#include "collectionquery.h"
|
||||
#include "collectionwatcher.h"
|
||||
#include "sqlrow.h"
|
||||
#include "core/simpletreemodel.h"
|
||||
#include "core/song.h"
|
||||
#include "collectionquery.h"
|
||||
#include "collectionitem.h"
|
||||
#include "sqlrow.h"
|
||||
#include "covermanager/albumcoverloaderoptions.h"
|
||||
#include "engine/engine_fwd.h"
|
||||
#include "playlist/playlistmanager.h"
|
||||
|
||||
class Application;
|
||||
class AlbumCoverLoader;
|
||||
class CollectionDirectoryModel;
|
||||
class CollectionBackend;
|
||||
|
||||
class QSettings;
|
||||
class CollectionDirectoryModel;
|
||||
class CollectionItem;
|
||||
|
||||
class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
||||
Q_OBJECT
|
||||
@@ -190,8 +204,7 @@ signals:
|
||||
|
||||
private:
|
||||
// Provides some optimisations for loading the list of items in the root.
|
||||
// This gets called a lot when filtering the playlist, so it's nice to be
|
||||
// able to do it in a background thread.
|
||||
// This gets called a lot when filtering the playlist, so it's nice to be able to do it in a background thread.
|
||||
QueryResult RunQuery(CollectionItem *parent);
|
||||
void PostQuery(CollectionItem *parent, const QueryResult &result, bool signal);
|
||||
|
||||
@@ -200,25 +213,18 @@ signals:
|
||||
void BeginReset();
|
||||
|
||||
// Functions for working with queries and creating items.
|
||||
// When the model is reset or when a node is lazy-loaded the Collection
|
||||
// constructs a database query to populate the items. Filters are added
|
||||
// for each parent item, restricting the songs returned to a particular
|
||||
// album or artist for example.
|
||||
// When the model is reset or when a node is lazy-loaded the Collection constructs a database query to populate the items.
|
||||
// Filters are added for each parent item, restricting the songs returned to a particular album or artist for example.
|
||||
static void InitQuery(GroupBy type, CollectionQuery *q);
|
||||
void FilterQuery(GroupBy type, CollectionItem *item, CollectionQuery *q);
|
||||
|
||||
// Items can be created either from a query that's been run to populate a
|
||||
// node, or by a spontaneous SongsDiscovered emission from the backend.
|
||||
// Items can be created either from a query that's been run to populate a node, or by a spontaneous SongsDiscovered emission from the backend.
|
||||
CollectionItem *ItemFromQuery(GroupBy type, bool signal, bool create_divider, CollectionItem *parent, const SqlRow &row, int container_level);
|
||||
CollectionItem *ItemFromSong(GroupBy type, bool signal, bool create_divider, CollectionItem *parent, const Song &s, int container_level);
|
||||
|
||||
// The "Various Artists" node is an annoying special case.
|
||||
CollectionItem *CreateCompilationArtistNode(bool signal, CollectionItem *parent);
|
||||
|
||||
// Smart playlists are shown in another top-level node
|
||||
|
||||
void ItemFromSmartPlaylist(const QSettings &s, bool notify) const;
|
||||
|
||||
// Helpers for ItemFromQuery and ItemFromSong
|
||||
CollectionItem *InitItem(GroupBy type, bool signal, CollectionItem *parent, int container_level);
|
||||
void FinishItem(GroupBy type, bool signal, bool create_divider, CollectionItem *parent, CollectionItem *item);
|
||||
@@ -256,8 +262,7 @@ signals:
|
||||
|
||||
QIcon artist_icon_;
|
||||
QIcon album_icon_;
|
||||
// used as a generic icon to show when no cover art is found,
|
||||
// fixed to the same size as the artwork (32x32)
|
||||
// Used as a generic icon to show when no cover art is found, fixed to the same size as the artwork (32x32)
|
||||
QPixmap no_cover_icon_;
|
||||
QIcon playlists_dir_icon_;
|
||||
QIcon playlist_icon_;
|
||||
|
||||
@@ -20,10 +20,14 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include "collectionplaylistitem.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
|
||||
#include <QSettings>
|
||||
class SqlRow;
|
||||
|
||||
CollectionPlaylistItem::CollectionPlaylistItem(const QString &type)
|
||||
: PlaylistItem(type) {}
|
||||
|
||||
@@ -23,9 +23,17 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include "core/song.h"
|
||||
#include "playlist/playlistitem.h"
|
||||
|
||||
class SqlRow;
|
||||
|
||||
class CollectionPlaylistItem : public PlaylistItem {
|
||||
public:
|
||||
CollectionPlaylistItem(const QString &type);
|
||||
|
||||
@@ -20,21 +20,26 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QDateTime>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringBuilder>
|
||||
#include <QRegExp>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
|
||||
#include "collectionquery.h"
|
||||
#include "core/song.h"
|
||||
|
||||
#include <QtDebug>
|
||||
#include <QDateTime>
|
||||
#include <QSqlError>
|
||||
|
||||
QueryOptions::QueryOptions() : max_age_(-1), query_mode_(QueryMode_All) {}
|
||||
|
||||
CollectionQuery::CollectionQuery(const QueryOptions& options)
|
||||
: include_unavailable_(false), join_with_fts_(false), limit_(-1) {
|
||||
|
||||
if (!options.filter().isEmpty()) {
|
||||
// We need to munge the filter text a little bit to get it to work as
|
||||
// expected with sqlite's FTS3:
|
||||
// We need to munge the filter text a little bit to get it to work as expected with sqlite's FTS3:
|
||||
// 1) Append * to all tokens.
|
||||
// 2) Prefix "fts" to column names.
|
||||
// 3) Remove colons which don't correspond to column names.
|
||||
@@ -50,8 +55,7 @@ CollectionQuery::CollectionQuery(const QueryOptions& options)
|
||||
|
||||
if (token.contains(':')) {
|
||||
// Only prefix fts if the token is a valid column name.
|
||||
if (Song::kFtsColumns.contains("fts" + token.section(':', 0, 0),
|
||||
Qt::CaseInsensitive)) {
|
||||
if (Song::kFtsColumns.contains("fts" + token.section(':', 0, 0), Qt::CaseInsensitive)) {
|
||||
// Account for multiple colons.
|
||||
QString columntoken = token.section(':', 0, 0, QString::SectionIncludeTrailingSep);
|
||||
QString subtoken = token.section(':', 1, -1);
|
||||
@@ -82,16 +86,12 @@ CollectionQuery::CollectionQuery(const QueryOptions& options)
|
||||
bound_values_ << cutoff;
|
||||
}
|
||||
|
||||
// TODO: currently you cannot use any QueryMode other than All and fts at the
|
||||
// same time.
|
||||
// joining songs, duplicated_songs and songs_fts all together takes a huge
|
||||
// amount of
|
||||
// time. the query takes about 20 seconds on my machine then. why?
|
||||
// untagged mode could work with additional filtering but I'm disabling it
|
||||
// just to be
|
||||
// consistent - this way filtering is available only in the All mode.
|
||||
// remember though that when you fix the Duplicates + FTS cooperation, enable
|
||||
// the filtering in both Duplicates and Untagged modes.
|
||||
// TODO: Currently you cannot use any QueryMode other than All and fts at the same time.
|
||||
// Joining songs, duplicated_songs and songs_fts all together takes a huge amount of time.
|
||||
// The query takes about 20 seconds on my machine then. Why?
|
||||
// Untagged mode could work with additional filtering but I'm disabling it just to be consistent
|
||||
// this way filtering is available only in the All mode.
|
||||
// Remember though that when you fix the Duplicates + FTS cooperation, enable the filtering in both Duplicates and Untagged modes.
|
||||
duplicates_only_ = options.query_mode() == QueryOptions::QueryMode_Duplicates;
|
||||
|
||||
if (options.query_mode() == QueryOptions::QueryMode_Untagged) {
|
||||
@@ -114,7 +114,7 @@ void CollectionQuery::AddWhere(const QString &column, const QVariant &value, con
|
||||
// ignore 'literal' for IN
|
||||
if (!op.compare("IN", Qt::CaseInsensitive)) {
|
||||
QStringList final;
|
||||
for (const QString& single_value : value.toStringList()) {
|
||||
for (const QString &single_value : value.toStringList()) {
|
||||
final.append("?");
|
||||
bound_values_ << single_value;
|
||||
}
|
||||
@@ -122,8 +122,7 @@ void CollectionQuery::AddWhere(const QString &column, const QVariant &value, con
|
||||
where_clauses_ << QString("%1 IN (" + final.join(",") + ")").arg(column);
|
||||
}
|
||||
else {
|
||||
// Do integers inline - sqlite seems to get confused when you pass integers
|
||||
// to bound parameters
|
||||
// Do integers inline - sqlite seems to get confused when you pass integers to bound parameters
|
||||
if (value.type() == QVariant::Int) {
|
||||
where_clauses_ << QString("%1 %2 %3").arg(column, op, value.toString());
|
||||
}
|
||||
@@ -136,10 +135,8 @@ void CollectionQuery::AddWhere(const QString &column, const QVariant &value, con
|
||||
}
|
||||
|
||||
void CollectionQuery::AddCompilationRequirement(bool compilation) {
|
||||
// The unary + is added to prevent sqlite from using the index
|
||||
// idx_comp_artist. When joining with fts, sqlite 3.8 has a tendency
|
||||
// to use this index and thereby nesting the tables in an order
|
||||
// which gives very poor performance
|
||||
// The unary + is added to prevent sqlite from using the index idx_comp_artist.
|
||||
// When joining with fts, sqlite 3.8 has a tendency to use this index and thereby nesting the tables in an order which gives very poor performance
|
||||
|
||||
where_clauses_ << QString("+compilation_effective = %1").arg(compilation ? 1 : 0);
|
||||
|
||||
@@ -175,7 +172,7 @@ QSqlQuery CollectionQuery::Exec(QSqlDatabase db, const QString &songs_table, con
|
||||
query_.prepare(sql);
|
||||
|
||||
// Bind values
|
||||
for (const QVariant& value : bound_values_) {
|
||||
for (const QVariant &value : bound_values_) {
|
||||
query_.addBindValue(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,11 +23,14 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QString>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QVariant>
|
||||
#include <QSqlQuery>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QVariantList>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
|
||||
class Song;
|
||||
class CollectionBackend;
|
||||
@@ -36,13 +39,9 @@ class CollectionBackend;
|
||||
struct QueryOptions {
|
||||
// Modes of CollectionQuery:
|
||||
// - use the all songs table
|
||||
// - use the duplicated songs view; by duplicated we mean those songs
|
||||
// for which the (artist, album, title) tuple is found more than once
|
||||
// in the songs table
|
||||
// - use the untagged songs view; by untagged we mean those for which
|
||||
// at least one of the (artist, album, title) tags is empty
|
||||
// Please note that additional filtering based on fts table (the filter
|
||||
// attribute) won't work in Duplicates and Untagged modes.
|
||||
// - use the duplicated songs view; by duplicated we mean those songs for which the (artist, album, title) tuple is found more than once in the songs table
|
||||
// - use the untagged songs view; by untagged we mean those for which at least one of the (artist, album, title) tags is empty
|
||||
// Please note that additional filtering based on fts table (the filter attribute) won't work in Duplicates and Untagged modes.
|
||||
enum QueryMode {
|
||||
QueryMode_All,
|
||||
QueryMode_Duplicates,
|
||||
@@ -83,8 +82,7 @@ class CollectionQuery {
|
||||
// Sets an ORDER BY clause on the query.
|
||||
void SetOrderBy(const QString &order_by) { order_by_ = order_by; }
|
||||
|
||||
// Adds a fragment of WHERE clause. When executed, this Query will connect all
|
||||
// the fragments with AND operator.
|
||||
// Adds a fragment of WHERE clause. When executed, this Query will connect all the fragments with AND operator.
|
||||
// Please note that IN operator expects a QStringList as value.
|
||||
void AddWhere(const QString &column, const QVariant &value, const QString &op = "=");
|
||||
|
||||
|
||||
@@ -20,35 +20,59 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "collectionview.h"
|
||||
#include <qcoreevent.h>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QHelpEvent>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QSet>
|
||||
#include <QSettings>
|
||||
#include <QtGlobal>
|
||||
#include <QWidget>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QAbstractItemView>
|
||||
#include <QStyleOptionViewItem>
|
||||
#include <QAction>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QList>
|
||||
#include <QLocale>
|
||||
#include <QMap>
|
||||
#include <QMessageBox>
|
||||
#include <QMenu>
|
||||
#include <QMimeData>
|
||||
#include <QPainter>
|
||||
#include <QPalette>
|
||||
#include <QPen>
|
||||
#include <QPoint>
|
||||
#include <QRect>
|
||||
#include <QSet>
|
||||
#include <QSize>
|
||||
#include <QToolTip>
|
||||
#include <QTreeView>
|
||||
#include <QWhatsThis>
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QFont>
|
||||
#include <QFontMetrics>
|
||||
#include <QPixmap>
|
||||
#include <QIcon>
|
||||
#include <QLinearGradient>
|
||||
#include <QSettings>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/mimedata.h"
|
||||
#include "core/utilities.h"
|
||||
#include "collectionbackend.h"
|
||||
#include "collectiondirectorymodel.h"
|
||||
#include "collectionfilterwidget.h"
|
||||
#include "collectionmodel.h"
|
||||
#include "collectionitem.h"
|
||||
#include "collectionbackend.h"
|
||||
#include "core/application.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/mimedata.h"
|
||||
#include "core/musicstorage.h"
|
||||
#include "core/utilities.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "collectionmodel.h"
|
||||
#include "collectionview.h"
|
||||
#include "device/devicemanager.h"
|
||||
#include "device/devicestatefiltermodel.h"
|
||||
#include "dialogs/edittagdialog.h"
|
||||
#ifdef HAVE_GSTREAMER
|
||||
#include "dialogs/organisedialog.h"
|
||||
#include "dialogs/organiseerrordialog.h"
|
||||
#endif
|
||||
#include "settings/collectionsettingspage.h"
|
||||
|
||||
@@ -293,8 +317,7 @@ bool CollectionView::RestoreLevelFocus(const QModelIndex &parent) {
|
||||
}
|
||||
else if (last_selected_path_.contains(text)) {
|
||||
emit expand(current);
|
||||
// If a selected container or song were not found, we've got into a wrong subtree
|
||||
// (happens with "unknown" all the time)
|
||||
// If a selected container or song were not found, we've got into a wrong subtree (happens with "unknown" all the time)
|
||||
if (!RestoreLevelFocus(current)) {
|
||||
emit collapse(current);
|
||||
}
|
||||
@@ -312,8 +335,6 @@ bool CollectionView::RestoreLevelFocus(const QModelIndex &parent) {
|
||||
|
||||
void CollectionView::ReloadSettings() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
QSettings settings;
|
||||
|
||||
settings.beginGroup(CollectionSettingsPage::kSettingsGroup);
|
||||
@@ -330,8 +351,6 @@ void CollectionView::ReloadSettings() {
|
||||
|
||||
void CollectionView::SetApplication(Application *app) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
app_ = app;
|
||||
|
||||
ReloadSettings();
|
||||
@@ -342,8 +361,6 @@ void CollectionView::SetFilter(CollectionFilterWidget *filter) { filter_ = filte
|
||||
|
||||
void CollectionView::TotalSongCountUpdated(int count) {
|
||||
|
||||
//qLog(Debug) << __FUNCTION__ << count;
|
||||
|
||||
bool old = total_song_count_;
|
||||
total_song_count_ = count;
|
||||
if (old != total_song_count_) update();
|
||||
@@ -359,8 +376,6 @@ void CollectionView::TotalSongCountUpdated(int count) {
|
||||
|
||||
void CollectionView::TotalArtistCountUpdated(int count) {
|
||||
|
||||
//qLog(Debug) << __FUNCTION__ << count;
|
||||
|
||||
bool old = total_artist_count_;
|
||||
total_artist_count_ = count;
|
||||
if (old != total_artist_count_) update();
|
||||
@@ -376,8 +391,6 @@ void CollectionView::TotalArtistCountUpdated(int count) {
|
||||
|
||||
void CollectionView::TotalAlbumCountUpdated(int count) {
|
||||
|
||||
//qLog(Debug) << __FUNCTION__ << count;
|
||||
|
||||
bool old = total_album_count_;
|
||||
total_album_count_ = count;
|
||||
if (old != total_album_count_) update();
|
||||
@@ -393,8 +406,6 @@ void CollectionView::TotalAlbumCountUpdated(int count) {
|
||||
|
||||
void CollectionView::paintEvent(QPaintEvent *event) {
|
||||
|
||||
//qLog(Debug) << __FUNCTION__;
|
||||
|
||||
if (total_song_count_ == 0) {
|
||||
QPainter p(viewport());
|
||||
QRect rect(viewport()->rect());
|
||||
@@ -491,7 +502,6 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
||||
}
|
||||
|
||||
// TODO: check if custom plugin actions should be enabled / visible
|
||||
//const int songs_selected = smart_playlists + smart_playlists_header + regular_elements;
|
||||
const int songs_selected = regular_elements;
|
||||
const bool regular_elements_only = songs_selected == regular_elements && regular_elements > 0;
|
||||
|
||||
@@ -502,7 +512,6 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
||||
add_to_playlist_enqueue_->setEnabled(songs_selected);
|
||||
|
||||
// if neither edit_track not edit_tracks are available, we show disabled edit_track element
|
||||
//edit_track_->setVisible(!smart_playlists_only && (regular_editable <= 1));
|
||||
edit_track_->setVisible(regular_editable <= 1);
|
||||
edit_track_->setEnabled(regular_editable == 1);
|
||||
|
||||
@@ -534,9 +543,9 @@ void CollectionView::ShowInVarious(bool on) {
|
||||
|
||||
if (!context_menu_index_.isValid()) return;
|
||||
|
||||
// Map is from album name -> all artists sharing that album name, built from each selected
|
||||
// song. We put through "Various Artists" changes one album at a time, to make sure the old album
|
||||
// node gets removed (due to all children removed), before the new one gets added
|
||||
// Map is from album name -> all artists sharing that album name, built from each selected song.
|
||||
// We put through "Various Artists" changes one album at a time,
|
||||
// to make sure the old album node gets removed (due to all children removed), before the new one gets added
|
||||
QMultiMap<QString, QString> albums;
|
||||
for (const Song& song : GetSelectedSongs()) {
|
||||
if (albums.find(song.album(), song.artist()) == albums.end())
|
||||
@@ -586,16 +595,12 @@ void CollectionView::Load() {
|
||||
|
||||
void CollectionView::AddToPlaylist() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
emit AddToPlaylistSignal(model()->mimeData(selectedIndexes()));
|
||||
|
||||
}
|
||||
|
||||
void CollectionView::AddToPlaylistEnqueue() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
QMimeData *data = model()->mimeData(selectedIndexes());
|
||||
if (MimeData* mime_data = qobject_cast<MimeData*>(data)) {
|
||||
mime_data->enqueue_now_ = true;
|
||||
|
||||
@@ -24,21 +24,38 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QAbstractItemView>
|
||||
#include <QString>
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
#include <QSet>
|
||||
#include <QStyleOption>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QStyleOptionViewItem>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "core/song.h"
|
||||
#include "dialogs/edittagdialog.h"
|
||||
#include "widgets/autoexpandingtreeview.h"
|
||||
|
||||
class QContextMenuEvent;
|
||||
class QHelpEvent;
|
||||
class QMouseEvent;
|
||||
class QPaintEvent;
|
||||
|
||||
class Application;
|
||||
class CollectionFilterWidget;
|
||||
class EditTagDialog;
|
||||
#ifdef HAVE_GSTREAMER
|
||||
class OrganiseDialog;
|
||||
#endif
|
||||
|
||||
class QMimeData;
|
||||
|
||||
class CollectionItemDelegate : public QStyledItemDelegate {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -57,11 +74,8 @@ class CollectionView : public AutoExpandingTreeView {
|
||||
CollectionView(QWidget *parent = nullptr);
|
||||
~CollectionView();
|
||||
|
||||
//static const char *kSettingsGroup;
|
||||
|
||||
// Returns Songs currently selected in the collection view. Please note that the
|
||||
// selection is recursive meaning that if for example an album is selected
|
||||
// this will return all of it's songs.
|
||||
// Returns Songs currently selected in the collection view.
|
||||
// Please note that the selection is recursive meaning that if for example an album is selected this will return all of it's songs.
|
||||
SongList GetSelectedSongs() const;
|
||||
|
||||
void SetApplication(Application *app);
|
||||
|
||||
@@ -20,6 +20,11 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include "collectionfilterwidget.h"
|
||||
#include "collectionview.h"
|
||||
#include "collectionviewcontainer.h"
|
||||
#include "ui_collectionviewcontainer.h"
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
|
||||
class CollectionFilterWidget;
|
||||
|
||||
@@ -20,34 +20,42 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fileref.h>
|
||||
#include <tag.h>
|
||||
#include <QObject>
|
||||
#include <QIODevice>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QMetaObject>
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QMap>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QSettings>
|
||||
#include <QtDebug>
|
||||
|
||||
// This is defined by one of the windows headers that is included by taglib.
|
||||
#ifdef RemoveDirectory
|
||||
#undef RemoveDirectory
|
||||
#endif
|
||||
|
||||
#include "collectionwatcher.h"
|
||||
|
||||
#include "collectionbackend.h"
|
||||
#include "core/filesystemwatcherinterface.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "core/taskmanager.h"
|
||||
#include "core/utilities.h"
|
||||
#include "directory.h"
|
||||
#include "collectionbackend.h"
|
||||
#include "collectionwatcher.h"
|
||||
#include "playlistparsers/cueparser.h"
|
||||
#include "settings/collectionsettingspage.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDirIterator>
|
||||
#include <QtDebug>
|
||||
#include <QThread>
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
#include <QSettings>
|
||||
#include <QTimer>
|
||||
// This is defined by one of the windows headers that is included by taglib.
|
||||
#ifdef RemoveDirectory
|
||||
#undef RemoveDirectory
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
static const char *kNoMediaFile = ".nomedia";
|
||||
@@ -218,8 +226,7 @@ void CollectionWatcher::AddDirectory(const Directory &dir, const SubdirectoryLis
|
||||
ScanSubdirectory(dir.path, Subdirectory(), &transaction);
|
||||
}
|
||||
else {
|
||||
// We can do an incremental scan - looking at the mtimes of each
|
||||
// subdirectory and only rescan if the directory has changed.
|
||||
// We can do an incremental scan - looking at the mtimes of each subdirectory and only rescan if the directory has changed.
|
||||
ScanTransaction transaction(this, dir.id, true);
|
||||
transaction.SetKnownSubdirs(subdirs);
|
||||
transaction.AddToProgressMax(subdirs.count());
|
||||
@@ -268,8 +275,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
||||
QStringList files_on_disk;
|
||||
SubdirectoryList my_new_subdirs;
|
||||
|
||||
// If a directory is moved then only its parent gets a changed notification,
|
||||
// so we need to look and see if any of our children don't exist any more.
|
||||
// If a directory is moved then only its parent gets a changed notification, so we need to look and see if any of our children don't exist any more.
|
||||
// If one has been removed, "rescan" it to get the deleted songs
|
||||
SubdirectoryList previous_subdirs = t->GetImmediateSubdirs(path);
|
||||
for (const Subdirectory& subdir : previous_subdirs) {
|
||||
@@ -289,8 +295,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
||||
|
||||
if (child_info.isDir()) {
|
||||
if (!child_info.isHidden() && !t->HasSeenSubdir(child)) {
|
||||
// We haven't seen this subdirectory before - add it to a list and
|
||||
// later we'll tell the backend about it and scan it.
|
||||
// We haven't seen this subdirectory before - add it to a list and later we'll tell the backend about it and scan it.
|
||||
Subdirectory new_subdir;
|
||||
new_subdir.directory_id = -1;
|
||||
new_subdir.path = child;
|
||||
@@ -332,8 +337,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
||||
QFileInfo file_info(file);
|
||||
|
||||
if (!file_info.exists()) {
|
||||
// Partially fixes race condition - if file was removed between being
|
||||
// added to the list and now.
|
||||
// Partially fixes race condition - if file was removed between being added to the list and now.
|
||||
files_on_disk.removeAll(file);
|
||||
continue;
|
||||
}
|
||||
@@ -345,8 +349,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
||||
bool cue_deleted = song_cue_mtime == 0 && matching_song.has_cue();
|
||||
bool cue_added = matching_cue_mtime != 0 && !matching_song.has_cue();
|
||||
|
||||
// watch out for cue songs which have their mtime equal to
|
||||
// qMax(media_file_mtime, cue_sheet_mtime)
|
||||
// watch out for cue songs which have their mtime equal to qMax(media_file_mtime, cue_sheet_mtime)
|
||||
bool changed = (matching_song.mtime() != qMax(file_info.lastModified().toTime_t(), song_cue_mtime)) || cue_deleted || cue_added;
|
||||
|
||||
// Also want to look to see whether the album art has changed
|
||||
@@ -372,7 +375,8 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
|
||||
// nothing has changed - mark the song available without re-scanning
|
||||
if (matching_song.is_unavailable()) t->readded_songs << matching_song;
|
||||
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// The song is on disk but not in the DB
|
||||
SongList song_list = ScanNewFile(file, path, matching_cue, &cues_processed);
|
||||
|
||||
@@ -437,7 +441,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file, const QStr
|
||||
|
||||
QSet<int> used_ids;
|
||||
|
||||
// update every song that's in the cue and collection
|
||||
// Update every song that's in the cue and collection
|
||||
for (Song cue_song : cue_parser_->Load(&cue, matching_cue, path)) {
|
||||
cue_song.set_directory_id(t->dir());
|
||||
|
||||
@@ -463,9 +467,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file, const QStr
|
||||
|
||||
void CollectionWatcher::UpdateNonCueAssociatedSong(const QString &file, const Song &matching_song, const QString &image, bool cue_deleted, ScanTransaction *t) {
|
||||
|
||||
// if a cue got deleted, we turn it's first section into the new
|
||||
// 'raw' (cueless) song and we just remove the rest of the sections
|
||||
// from the collection
|
||||
// If a cue got deleted, we turn it's first section into the new 'raw' (cueless) song and we just remove the rest of the sections from the collection
|
||||
if (cue_deleted) {
|
||||
for (const Song &song :
|
||||
backend_->GetSongsByUrl(QUrl::fromLocalFile(file))) {
|
||||
@@ -490,7 +492,7 @@ SongList CollectionWatcher::ScanNewFile(const QString &file, const QString &path
|
||||
SongList song_list;
|
||||
|
||||
uint matching_cue_mtime = GetMtimeForCue(matching_cue);
|
||||
// if it's a cue - create virtual tracks
|
||||
// If it's a cue - create virtual tracks
|
||||
if (matching_cue_mtime) {
|
||||
// don't process the same cue many times
|
||||
if (cues_processed->contains(matching_cue)) return song_list;
|
||||
@@ -498,9 +500,9 @@ SongList CollectionWatcher::ScanNewFile(const QString &file, const QString &path
|
||||
QFile cue(matching_cue);
|
||||
cue.open(QIODevice::ReadOnly);
|
||||
|
||||
// Ignore FILEs pointing to other media files. Also, watch out for incorrect
|
||||
// media files. Playlist parser for CUEs considers every entry in sheet
|
||||
// valid and we don't want invalid media getting into collection!
|
||||
// Ignore FILEs pointing to other media files.
|
||||
// Also, watch out for incorrect media files.
|
||||
// Playlist parser for CUEs considers every entry in sheet valid and we don't want invalid media getting into collection!
|
||||
QString file_nfd = file.normalized(QString::NormalizationForm_D);
|
||||
for (const Song& cue_song : cue_parser_->Load(&cue, matching_cue, path)) {
|
||||
if (cue_song.url().toLocalFile().normalized(QString::NormalizationForm_D) == file_nfd) {
|
||||
@@ -533,15 +535,13 @@ void CollectionWatcher::PreserveUserSetData(const QString &file, const QString &
|
||||
|
||||
out->set_id(matching_song.id());
|
||||
|
||||
// Previous versions of Clementine incorrectly overwrote this and
|
||||
// stored it in the DB, so we can't rely on matching_song to
|
||||
// know if it has embedded artwork or not, but we can check here.
|
||||
// Previous versions of Clementine incorrectly overwrote this and stored it in the DB,
|
||||
// so we can't rely on matching_song to know if it has embedded artwork or not, but we can check here.
|
||||
if (!out->has_embedded_cover()) out->set_art_automatic(image);
|
||||
|
||||
out->MergeUserSetData(matching_song);
|
||||
|
||||
// The song was deleted from the database (e.g. due to an unmounted
|
||||
// filesystem), but has been restored.
|
||||
// The song was deleted from the database (e.g. due to an unmounted filesystem), but has been restored.
|
||||
if (matching_song.is_unavailable()) {
|
||||
qLog(Debug) << file << " unavailable song restored";
|
||||
|
||||
@@ -562,7 +562,7 @@ void CollectionWatcher::PreserveUserSetData(const QString &file, const QString &
|
||||
|
||||
uint CollectionWatcher::GetMtimeForCue(const QString &cue_path) {
|
||||
|
||||
// slight optimisation
|
||||
// Slight optimisation
|
||||
if (cue_path.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
@@ -593,7 +593,7 @@ void CollectionWatcher::RemoveDirectory(const Directory &dir) {
|
||||
watched_dirs_.remove(dir.id);
|
||||
|
||||
// Stop watching the directory's subdirectories
|
||||
for (const QString& subdir_path : subdir_mapping_.keys(dir)) {
|
||||
for (const QString &subdir_path : subdir_mapping_.keys(dir)) {
|
||||
fs_watcher_->RemovePath(subdir_path);
|
||||
subdir_mapping_.remove(subdir_path);
|
||||
}
|
||||
@@ -662,8 +662,7 @@ QString CollectionWatcher::PickBestImage(const QStringList &images) {
|
||||
QStringList filtered;
|
||||
|
||||
for (const QString &filter_text : best_image_filters_) {
|
||||
// the images in the images list are represented by a full path,
|
||||
// so we need to isolate just the filename
|
||||
// The images in the images list are represented by a full path, so we need to isolate just the filename
|
||||
for (const QString& image : images) {
|
||||
QFileInfo file_info(image);
|
||||
QString filename(file_info.fileName());
|
||||
@@ -671,14 +670,13 @@ QString CollectionWatcher::PickBestImage(const QStringList &images) {
|
||||
filtered << image;
|
||||
}
|
||||
|
||||
/* We assume the filters are give in the order best to worst, so
|
||||
if we've got a result, we go with it. Otherwise we might
|
||||
start capturing more generic rules */
|
||||
// We assume the filters are give in the order best to worst, so if we've got a result, we go with it.
|
||||
// Otherwise we might start capturing more generic rules
|
||||
if (!filtered.isEmpty()) break;
|
||||
}
|
||||
|
||||
if (filtered.isEmpty()) {
|
||||
// the filter was too restrictive, just use the original list
|
||||
// The filter was too restrictive, just use the original list
|
||||
filtered = images;
|
||||
}
|
||||
|
||||
@@ -734,7 +732,7 @@ void CollectionWatcher::ReloadSettings() {
|
||||
|
||||
best_image_filters_.clear();
|
||||
QStringList filters = s.value("cover_art_patterns", QStringList() << "front" << "cover").toStringList();
|
||||
for (const QString& filter : filters) {
|
||||
for (const QString &filter : filters) {
|
||||
QString s = filter.trimmed();
|
||||
if (!s.isEmpty()) best_image_filters_ << s;
|
||||
}
|
||||
|
||||
@@ -23,22 +23,24 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "directory.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QHash>
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QHash>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
|
||||
#include "directory.h"
|
||||
#include "core/song.h"
|
||||
|
||||
class QFileSystemWatcher;
|
||||
class QTimer;
|
||||
|
||||
class CueParser;
|
||||
class FileSystemWatcherInterface;
|
||||
class CollectionBackend;
|
||||
class FileSystemWatcherInterface;
|
||||
class TaskManager;
|
||||
class CueParser;
|
||||
|
||||
class CollectionWatcher : public QObject {
|
||||
Q_OBJECT
|
||||
@@ -76,14 +78,11 @@ signals:
|
||||
|
||||
private:
|
||||
// This class encapsulates a full or partial scan of a directory.
|
||||
// Each directory has one or more subdirectories, and any number of
|
||||
// subdirectories can be scanned during one transaction. ScanSubdirectory()
|
||||
// adds its results to the members of this transaction class, and they are
|
||||
// "committed" through calls to the CollectionBackend in the transaction's dtor.
|
||||
// The transaction also caches the list of songs in this directory according
|
||||
// to the collection. Multiple calls to FindSongsInSubdirectory during one
|
||||
// transaction will only result in one call to
|
||||
// CollectionBackend::FindSongsInDirectory.
|
||||
// Each directory has one or more subdirectories, and any number of subdirectories can be scanned during one transaction.
|
||||
// ScanSubdirectory() adds its results to the members of this transaction class,
|
||||
// and they are "committed" through calls to the CollectionBackend in the transaction's dtor.
|
||||
// The transaction also caches the list of songs in this directory according to the collection.
|
||||
// Multiple calls to FindSongsInSubdirectory during one transaction will only result in one call to CollectionBackend::FindSongsInDirectory.
|
||||
class ScanTransaction {
|
||||
public:
|
||||
ScanTransaction(CollectionWatcher *watcher, int dir, bool incremental, bool ignores_mtime = false);
|
||||
@@ -120,10 +119,9 @@ signals:
|
||||
int dir_;
|
||||
// Incremental scan enters a directory only if it has changed since the last scan.
|
||||
bool incremental_;
|
||||
// This type of scan updates every file in a folder that's
|
||||
// being scanned. Even if it detects the file hasn't changed since
|
||||
// the last scan. Also, since it's ignoring mtimes on folders too,
|
||||
// it will go as deep in the folder hierarchy as it's possible.
|
||||
// This type of scan updates every file in a folder that's being scanned.
|
||||
// Even if it detects the file hasn't changed since the last scan.
|
||||
// Also, since it's ignoring mtimes on folders too, it will go as deep in the folder hierarchy as it's possible.
|
||||
bool ignores_mtime_;
|
||||
|
||||
CollectionWatcher *watcher_;
|
||||
@@ -153,18 +151,14 @@ signals:
|
||||
uint GetMtimeForCue(const QString &cue_path);
|
||||
void PerformScan(bool incremental, bool ignore_mtimes);
|
||||
|
||||
// Updates the sections of a cue associated and altered (according to mtime)
|
||||
// media file during a scan.
|
||||
// Updates the sections of a cue associated and altered (according to mtime) media file during a scan.
|
||||
void UpdateCueAssociatedSongs(const QString &file, const QString &path, const QString &matching_cue, const QString &image, ScanTransaction *t);
|
||||
// Updates a single non-cue associated and altered (according to mtime) song
|
||||
// during a scan.
|
||||
// Updates a single non-cue associated and altered (according to mtime) song during a scan.
|
||||
void UpdateNonCueAssociatedSong(const QString &file, const Song &matching_song, const QString &image, bool cue_deleted, ScanTransaction *t);
|
||||
// Updates a new song with some metadata taken from it's equivalent old
|
||||
// song (for example rating and score).
|
||||
// Updates a new song with some metadata taken from it's equivalent old song (for example rating and score).
|
||||
void PreserveUserSetData(const QString &file, const QString &image, const Song &matching_song, Song *out, ScanTransaction *t);
|
||||
// Scans a single media file that's present on the disk but not yet in the collection.
|
||||
// It may result in a multiple files added to the collection when the media file
|
||||
// has many sections (like a CUE related media file).
|
||||
// It may result in a multiple files added to the collection when the media file has many sections (like a CUE related media file).
|
||||
SongList ScanNewFile(const QString &file, const QString &path, const QString &matching_cue, QSet<QString> *cues_processed);
|
||||
|
||||
private:
|
||||
@@ -175,11 +169,8 @@ signals:
|
||||
FileSystemWatcherInterface *fs_watcher_;
|
||||
QHash<QString, Directory> subdir_mapping_;
|
||||
|
||||
/* A list of words use to try to identify the (likely) best image
|
||||
* found in an directory to use as cover artwork.
|
||||
* e.g. using ["front", "cover"] would identify front.jpg and
|
||||
* exclude back.jpg.
|
||||
*/
|
||||
// A list of words use to try to identify the (likely) best image found in an directory to use as cover artwork.
|
||||
// e.g. using ["front", "cover"] would identify front.jpg and exclude back.jpg.
|
||||
QStringList best_image_filters_;
|
||||
|
||||
bool stop_requested_;
|
||||
|
||||
@@ -23,11 +23,10 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QMetaType>
|
||||
|
||||
class QSqlQuery;
|
||||
#include <QSqlQuery>
|
||||
|
||||
struct Directory {
|
||||
Directory() : id(-1) {}
|
||||
|
||||
@@ -22,8 +22,13 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
#include <QWidget>
|
||||
|
||||
#include "collectionmodel.h"
|
||||
#include "groupbydialog.h"
|
||||
#include "ui_groupbydialog.h"
|
||||
|
||||
@@ -31,9 +36,13 @@
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/indexed_by.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/tag.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index_container_fwd.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
|
||||
using boost::multi_index_container;
|
||||
using boost::multi_index::indexed_by;
|
||||
@@ -70,7 +79,7 @@ class GroupByDialogPrivate {
|
||||
MappingContainer mapping_;
|
||||
};
|
||||
|
||||
GroupByDialog::GroupByDialog(QWidget* parent) : QDialog(parent), ui_(new Ui_GroupByDialog), p_(new GroupByDialogPrivate) {
|
||||
GroupByDialog::GroupByDialog(QWidget *parent) : QDialog(parent), ui_(new Ui_GroupByDialog), p_(new GroupByDialogPrivate) {
|
||||
|
||||
ui_->setupUi(this);
|
||||
Reset();
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
#include <memory>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QString>
|
||||
|
||||
#include "collectionmodel.h"
|
||||
|
||||
|
||||
@@ -18,19 +18,33 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QWidget>
|
||||
#include <QStandardItemModel>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QIODevice>
|
||||
#include <QDataStream>
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QKeySequence>
|
||||
#include <QPushButton>
|
||||
#include <QTreeView>
|
||||
#include <QSettings>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "collectionfilterwidget.h"
|
||||
#include "collectionmodel.h"
|
||||
#include "savedgroupingmanager.h"
|
||||
#include "ui_savedgroupingmanager.h"
|
||||
|
||||
#include <QKeySequence>
|
||||
#include <QList>
|
||||
#include <QSettings>
|
||||
#include <QStandardItem>
|
||||
|
||||
SavedGroupingManager::SavedGroupingManager(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
ui_(new Ui_SavedGroupingManager),
|
||||
@@ -58,6 +72,7 @@ SavedGroupingManager::~SavedGroupingManager() {
|
||||
}
|
||||
|
||||
QString SavedGroupingManager::GroupByToString(const CollectionModel::GroupBy &g) {
|
||||
|
||||
switch (g) {
|
||||
case CollectionModel::GroupBy_None: {
|
||||
return tr("None");
|
||||
@@ -137,8 +152,7 @@ void SavedGroupingManager::Remove() {
|
||||
if (ui_->list->selectionModel()->hasSelection()) {
|
||||
QSettings s;
|
||||
s.beginGroup(CollectionModel::kSavedGroupingsSettingsGroup);
|
||||
for (const QModelIndex &index :
|
||||
ui_->list->selectionModel()->selectedRows()) {
|
||||
for (const QModelIndex &index : ui_->list->selectionModel()->selectedRows()) {
|
||||
if (index.isValid()) {
|
||||
qLog(Debug) << "Remove saved grouping: " << model_->item(index.row(), 0)->text();
|
||||
s.remove(model_->item(index.row(), 0)->text());
|
||||
|
||||
@@ -24,12 +24,15 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QStandardItemModel>
|
||||
#include <QString>
|
||||
|
||||
#include "collectionmodel.h"
|
||||
|
||||
class Ui_SavedGroupingManager;
|
||||
class CollectionFilterWidget;
|
||||
class Ui_SavedGroupingManager;
|
||||
|
||||
class SavedGroupingManager : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -20,12 +20,14 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "collectionquery.h"
|
||||
#include "sqlrow.h"
|
||||
|
||||
#include <QVariant>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlRecord>
|
||||
|
||||
#include "sqlrow.h"
|
||||
|
||||
#include "collectionquery.h"
|
||||
|
||||
SqlRow::SqlRow(const QSqlQuery &query) { Init(query); }
|
||||
|
||||
SqlRow::SqlRow(const CollectionQuery &query) { Init(query); }
|
||||
|
||||
@@ -25,8 +25,7 @@
|
||||
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
|
||||
class QSqlQuery;
|
||||
#include <QSqlQuery>
|
||||
|
||||
class CollectionQuery;
|
||||
|
||||
@@ -37,7 +36,7 @@ class SqlRow {
|
||||
SqlRow(const QSqlQuery &query);
|
||||
SqlRow(const CollectionQuery &query);
|
||||
|
||||
const QVariant& value(int i) const { return columns_[i]; }
|
||||
const QVariant &value(int i) const { return columns_[i]; }
|
||||
|
||||
QList<QVariant> columns_;
|
||||
|
||||
|
||||
@@ -20,11 +20,16 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "appearance.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
#include <QPalette>
|
||||
#include <QColor>
|
||||
#include <QSettings>
|
||||
|
||||
#include "appearance.h"
|
||||
#include "settings/appearancesettingspage.h"
|
||||
|
||||
const char *Appearance::kUseCustomColorSet = "use-custom-set";
|
||||
|
||||
@@ -29,17 +29,17 @@
|
||||
|
||||
class Appearance : public QObject {
|
||||
public:
|
||||
explicit Appearance(QObject* parent = nullptr);
|
||||
explicit Appearance(QObject *parent = nullptr);
|
||||
// Load the user preferred theme, which could the default system theme or a custom set of colors that user has chosen
|
||||
void LoadUserTheme();
|
||||
void ResetToSystemDefaultTheme();
|
||||
void ChangeForegroundColor(const QColor& color);
|
||||
void ChangeBackgroundColor(const QColor& color);
|
||||
void ChangeForegroundColor(const QColor &color);
|
||||
void ChangeBackgroundColor(const QColor &color);
|
||||
|
||||
static const char* kSettingsGroup;
|
||||
static const char* kUseCustomColorSet;
|
||||
static const char* kForegroundColor;
|
||||
static const char* kBackgroundColor;
|
||||
static const char *kSettingsGroup;
|
||||
static const char *kUseCustomColorSet;
|
||||
static const char *kForegroundColor;
|
||||
static const char *kBackgroundColor;
|
||||
static const QPalette kDefaultPalette;
|
||||
|
||||
private:
|
||||
|
||||
@@ -18,20 +18,27 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "application.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "core/appearance.h"
|
||||
#include "core/database.h"
|
||||
#include "application.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QString>
|
||||
|
||||
#include "core/closure.h"
|
||||
#include "core/lazy.h"
|
||||
#include "core/player.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "core/taskmanager.h"
|
||||
#include "engine/enginetype.h"
|
||||
|
||||
#include "database.h"
|
||||
#include "taskmanager.h"
|
||||
#include "player.h"
|
||||
#include "appearance.h"
|
||||
|
||||
#include "engine/enginedevice.h"
|
||||
#include "device/devicemanager.h"
|
||||
#include "collection/collectionbackend.h"
|
||||
#include "collection/collection.h"
|
||||
#include "playlist/playlistbackend.h"
|
||||
#include "playlist/playlistmanager.h"
|
||||
@@ -40,7 +47,7 @@
|
||||
#include "covermanager/currentartloader.h"
|
||||
#ifdef HAVE_LIBLASTFM
|
||||
#include "covermanager/lastfmcoverprovider.h"
|
||||
#endif // HAVE_LIBLASTFM
|
||||
#endif
|
||||
#include "covermanager/amazoncoverprovider.h"
|
||||
#include "covermanager/discogscoverprovider.h"
|
||||
#include "covermanager/musicbrainzcoverprovider.h"
|
||||
@@ -77,9 +84,9 @@ class ApplicationImpl {
|
||||
cover_providers_([=]() {
|
||||
CoverProviders *cover_providers = new CoverProviders(app);
|
||||
// Initialize the repository of cover providers.
|
||||
#ifdef HAVE_LIBLASTFM
|
||||
cover_providers->AddProvider(new LastFmCoverProvider(app));
|
||||
#endif
|
||||
#ifdef HAVE_LIBLASTFM
|
||||
cover_providers->AddProvider(new LastFmCoverProvider(app));
|
||||
#endif
|
||||
cover_providers->AddProvider(new AmazonCoverProvider(app));
|
||||
cover_providers->AddProvider(new DiscogsCoverProvider(app));
|
||||
cover_providers->AddProvider(new MusicbrainzCoverProvider(app));
|
||||
@@ -121,8 +128,7 @@ Application::Application(QObject *parent)
|
||||
Application::~Application() {
|
||||
|
||||
// It's important that the device manager is deleted before the database.
|
||||
// Deleting the database deletes all objects that have been created in its
|
||||
// thread, including some device collection backends.
|
||||
// Deleting the database deletes all objects that have been created in its thread, including some device collection backends.
|
||||
p_->device_manager_.reset();
|
||||
|
||||
for (QThread *thread : threads_) {
|
||||
@@ -151,14 +157,6 @@ void Application::MoveToThread(QObject *object, QThread *thread) {
|
||||
|
||||
void Application::AddError(const QString& message) { emit ErrorAdded(message); }
|
||||
|
||||
QString Application::language_without_region() const {
|
||||
const int underscore = language_name_.indexOf('_');
|
||||
if (underscore != -1) {
|
||||
return language_name_.left(underscore);
|
||||
}
|
||||
return language_name_;
|
||||
}
|
||||
|
||||
void Application::ReloadSettings() { emit SettingsChanged(); }
|
||||
|
||||
void Application::OpenSettingsDialogAtPage(SettingsDialog::Page page) {
|
||||
|
||||
@@ -24,29 +24,31 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
#include "settings/settingsdialog.h"
|
||||
|
||||
class TaskManager;
|
||||
class ApplicationImpl;
|
||||
class TagReaderClient;
|
||||
class Database;
|
||||
class Appearance;
|
||||
class TaskManager;
|
||||
class EngineDevice;
|
||||
class Player;
|
||||
class DeviceManager;
|
||||
class Appearance;
|
||||
class Collection;
|
||||
class PlaylistBackend;
|
||||
class PlaylistManager;
|
||||
class AlbumCoverLoader;
|
||||
class CoverProviders;
|
||||
class CurrentArtLoader;
|
||||
class CollectionBackend;
|
||||
class CollectionModel;
|
||||
class EngineDevice;
|
||||
class PlaylistBackend;
|
||||
class PlaylistManager;
|
||||
class DeviceManager;
|
||||
class CoverProviders;
|
||||
class AlbumCoverLoader;
|
||||
class CurrentArtLoader;
|
||||
|
||||
class Application : public QObject {
|
||||
Q_OBJECT
|
||||
@@ -57,11 +59,6 @@ class Application : public QObject {
|
||||
explicit Application(QObject *parent = nullptr);
|
||||
~Application();
|
||||
|
||||
const QString &language_name() const { return language_name_; }
|
||||
// Same as language_name, but remove the region code at the end if there is one
|
||||
QString language_without_region() const;
|
||||
void set_language_name(const QString &name) { language_name_ = name; }
|
||||
|
||||
TagReaderClient *tag_reader_client() const;
|
||||
Database *database() const;
|
||||
Appearance *appearance() const;
|
||||
@@ -96,7 +93,6 @@ signals:
|
||||
void SettingsDialogRequested(SettingsDialog::Page page);
|
||||
|
||||
private:
|
||||
QString language_name_;
|
||||
std::unique_ptr<ApplicationImpl> p_;
|
||||
QList<QThread*> threads_;
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
#include <QSettings>
|
||||
|
||||
|
||||
@@ -19,19 +19,25 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "commandlineoptions.h"
|
||||
#include "version.h"
|
||||
#include "core/logging.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <getopt.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QIODevice>
|
||||
#include <QDataStream>
|
||||
#include <QBuffer>
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include "commandlineoptions.h"
|
||||
#include "core/logging.h"
|
||||
|
||||
const char *CommandlineOptions::kHelpText =
|
||||
"%1: strawberry [%2] [%3]\n"
|
||||
@@ -93,7 +99,7 @@ CommandlineOptions::CommandlineOptions(int argc, char* *argv)
|
||||
RemoveArg("-session", 2);
|
||||
}
|
||||
|
||||
void CommandlineOptions::RemoveArg(const QString& starts_with, int count) {
|
||||
void CommandlineOptions::RemoveArg(const QString &starts_with, int count) {
|
||||
|
||||
for (int i = 0; i < argc_; ++i) {
|
||||
QString opt(argv_[i]);
|
||||
|
||||
@@ -23,9 +23,13 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QUrl>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
class CommandlineOptions {
|
||||
friend QDataStream &operator<<(QDataStream &s, const CommandlineOptions &a);
|
||||
|
||||
@@ -20,27 +20,36 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "database.h"
|
||||
#include "scopedtransaction.h"
|
||||
#include "core/application.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/taskmanager.h"
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <boost/scope_exit.hpp>
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QStandardPaths>
|
||||
#include <QDir>
|
||||
#include <QLibrary>
|
||||
#include <QLibraryInfo>
|
||||
#include <QSqlDriver>
|
||||
#include <QSqlQuery>
|
||||
#include <QtDebug>
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QUrl>
|
||||
#include <QMutex>
|
||||
#include <QIODevice>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QChar>
|
||||
#include <QList>
|
||||
#include <QByteArray>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
#include <QStringList>
|
||||
#include <QRegExp>
|
||||
#include <QUrl>
|
||||
#include <QSqlDriver>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlError>
|
||||
#include <QStandardPaths>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "taskmanager.h"
|
||||
#include "database.h"
|
||||
#include "application.h"
|
||||
#include "scopedtransaction.h"
|
||||
|
||||
const char *Database::kDatabaseFilename = "strawberry.db";
|
||||
const int Database::kSchemaVersion = 0;
|
||||
@@ -269,7 +278,8 @@ QSqlDatabase Database::Connect() {
|
||||
{
|
||||
|
||||
#ifdef SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
|
||||
// In case sqlite>=3.12 is compiled without -DSQLITE_ENABLE_FTS3_TOKENIZER (generally a good idea due to security reasons) the fts3 support should be enabled explicitly.
|
||||
// In case sqlite>=3.12 is compiled without -DSQLITE_ENABLE_FTS3_TOKENIZER
|
||||
// (generally a good idea due to security reasons) the fts3 support should be enabled explicitly.
|
||||
QVariant v = db.driver()->handle();
|
||||
if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*") == 0) {
|
||||
sqlite3 *handle = *static_cast<sqlite3**>(v.data());
|
||||
@@ -283,8 +293,7 @@ QSqlDatabase Database::Connect() {
|
||||
if (!set_fts_tokenizer.exec()) {
|
||||
qLog(Warning) << "Couldn't register FTS3 tokenizer : " << set_fts_tokenizer.lastError();
|
||||
}
|
||||
// Implicit invocation of ~QSqlQuery() when leaving the scope
|
||||
// to release any remaining database locks!
|
||||
// Implicit invocation of ~QSqlQuery() when leaving the scope to release any remaining database locks!
|
||||
}
|
||||
|
||||
if (db.tables().count() == 0) {
|
||||
@@ -313,8 +322,7 @@ QSqlDatabase Database::Connect() {
|
||||
UpdateMainSchema(&db);
|
||||
}
|
||||
|
||||
// We might have to initialise the schema in some attached databases now, if
|
||||
// they were deleted and don't match up with the main schema version.
|
||||
// We might have to initialise the schema in some attached databases now, if they were deleted and don't match up with the main schema version.
|
||||
for (const QString &key : attached_databases_.keys()) {
|
||||
if (attached_databases_[key].is_temporary_ && attached_databases_[key].schema_.isEmpty())
|
||||
continue;
|
||||
@@ -338,8 +346,7 @@ void Database::UpdateMainSchema(QSqlDatabase *db) {
|
||||
{
|
||||
QSqlQuery q("SELECT version FROM schema_version", *db);
|
||||
if (q.next()) schema_version = q.value(0).toInt();
|
||||
// Implicit invocation of ~QSqlQuery() when leaving the scope
|
||||
// to release any remaining database locks!
|
||||
// Implicit invocation of ~QSqlQuery() when leaving the scope to release any remaining database locks!
|
||||
}
|
||||
|
||||
startup_schema_version_ = schema_version;
|
||||
@@ -382,9 +389,8 @@ void Database::RecreateAttachedDb(const QString &database_name) {
|
||||
}
|
||||
}
|
||||
|
||||
// We can't just re-attach the database now because it needs to be done for
|
||||
// each thread. Close all the database connections, so each thread will
|
||||
// re-attach it when they next connect.
|
||||
// We can't just re-attach the database now because it needs to be done for each thread.
|
||||
// Close all the database connections, so each thread will re-attach it when they next connect.
|
||||
for (const QString &name : QSqlDatabase::connectionNames()) {
|
||||
QSqlDatabase::removeDatabase(name);
|
||||
}
|
||||
@@ -482,12 +488,9 @@ void Database::ExecSchemaCommands(QSqlDatabase &db, const QString &schema, int s
|
||||
// Run each command
|
||||
const QStringList commands(schema.split(QRegExp("; *\n\n")));
|
||||
|
||||
// We don't want this list to reflect possible DB schema changes
|
||||
// so we initialize it before executing any statements.
|
||||
// If no outer transaction is provided the song tables need to
|
||||
// be queried before beginning an inner transaction! Otherwise
|
||||
// DROP TABLE commands on song tables may fail due to database
|
||||
// locks.
|
||||
// We don't want this list to reflect possible DB schema changes so we initialize it before executing any statements.
|
||||
// If no outer transaction is provided the song tables need to be queried before beginning an inner transaction! Otherwise
|
||||
// DROP TABLE commands on song tables may fail due to database locks.
|
||||
const QStringList song_tables(SongsTables(db, schema_version));
|
||||
|
||||
if (!in_transaction) {
|
||||
@@ -505,12 +508,10 @@ void Database::ExecSongTablesCommands(QSqlDatabase &db, const QStringList &song_
|
||||
|
||||
for (const QString &command : commands) {
|
||||
// There are now lots of "songs" tables that need to have the same schema:
|
||||
// songs, magnatune_songs, and device_*_songs. We allow a magic value
|
||||
// in the schema files to update all songs tables at once.
|
||||
// songs, magnatune_songs, and device_*_songs. We allow a magic value in the schema files to update all songs tables at once.
|
||||
if (command.contains(kMagicAllSongsTables)) {
|
||||
for (const QString &table : song_tables) {
|
||||
// Another horrible hack: device songs tables don't have matching _fts
|
||||
// tables, so if this command tries to touch one, ignore it.
|
||||
// Another horrible hack: device songs tables don't have matching _fts tables, so if this command tries to touch one, ignore it.
|
||||
if (table.startsWith("device_") &&
|
||||
command.contains(QString(kMagicAllSongsTables) + "_fts")) {
|
||||
continue;
|
||||
|
||||
@@ -23,15 +23,20 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlError>
|
||||
#include <QStringList>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct sqlite3_tokenizer;
|
||||
|
||||
@@ -20,11 +20,13 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "dbusscreensaver.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QObject>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusReply>
|
||||
#include <QString>
|
||||
|
||||
#include "dbusscreensaver.h"
|
||||
|
||||
DBusScreensaver::DBusScreensaver(const QString &service, const QString &path, const QString &interface)
|
||||
: service_(service), path_(path), interface_(interface) {}
|
||||
|
||||
@@ -23,8 +23,10 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QString>
|
||||
|
||||
#include "config.h"
|
||||
#include "screensaver.h"
|
||||
|
||||
class DBusScreensaver : public Screensaver {
|
||||
|
||||
@@ -20,19 +20,21 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "deletefiles.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
#include <QtGlobal>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
|
||||
#include "musicstorage.h"
|
||||
#include "taskmanager.h"
|
||||
#include "song.h"
|
||||
#include "deletefiles.h"
|
||||
#include "musicstorage.h"
|
||||
|
||||
const int DeleteFiles::kBatchSize = 50;
|
||||
|
||||
DeleteFiles::DeleteFiles(TaskManager* task_manager, std::shared_ptr<MusicStorage> storage)
|
||||
DeleteFiles::DeleteFiles(TaskManager *task_manager, std::shared_ptr<MusicStorage> storage)
|
||||
: thread_(nullptr),
|
||||
task_manager_(task_manager),
|
||||
storage_(storage),
|
||||
@@ -91,8 +93,7 @@ void DeleteFiles::ProcessSomeFiles() {
|
||||
|
||||
emit Finished(songs_with_errors_);
|
||||
|
||||
// Move back to the original thread so deleteLater() can get called in
|
||||
// the main thread's event loop
|
||||
// Move back to the original thread so deleteLater() can get called in the main thread's event loop
|
||||
moveToThread(original_thread_);
|
||||
deleteLater();
|
||||
|
||||
|
||||
@@ -24,13 +24,17 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include "song.h"
|
||||
|
||||
class MusicStorage;
|
||||
class TaskManager;
|
||||
class MusicStorage;
|
||||
|
||||
class DeleteFiles : public QObject {
|
||||
Q_OBJECT
|
||||
@@ -41,11 +45,11 @@ class DeleteFiles : public QObject {
|
||||
|
||||
static const int kBatchSize;
|
||||
|
||||
void Start(const SongList& songs);
|
||||
void Start(const QStringList& filenames);
|
||||
void Start(const SongList &songs);
|
||||
void Start(const QStringList &filenames);
|
||||
|
||||
signals:
|
||||
void Finished(const SongList& songs_with_errors);
|
||||
void Finished(const SongList &songs_with_errors);
|
||||
|
||||
private slots:
|
||||
void ProcessSomeFiles();
|
||||
@@ -67,4 +71,3 @@ signals:
|
||||
};
|
||||
|
||||
#endif // DELETEFILES_H
|
||||
|
||||
|
||||
@@ -20,13 +20,21 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "filesystemmusicstorage.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/utilities.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "utilities.h"
|
||||
#include "song.h"
|
||||
#include "musicstorage.h"
|
||||
|
||||
#include "filesystemmusicstorage.h"
|
||||
|
||||
FilesystemMusicStorage::FilesystemMusicStorage(const QString &root)
|
||||
: root_(root) {}
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <QString>
|
||||
|
||||
#include "musicstorage.h"
|
||||
|
||||
class FilesystemMusicStorage : public virtual MusicStorage {
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "filesystemwatcherinterface.h"
|
||||
#include <QObject>
|
||||
|
||||
#include "filesystemwatcherinterface.h"
|
||||
#include "qtfslistener.h"
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
@@ -43,4 +44,3 @@ FileSystemWatcherInterface *FileSystemWatcherInterface::Create(QObject *parent)
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -24,17 +24,18 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class FileSystemWatcherInterface : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FileSystemWatcherInterface(QObject *parent = nullptr);
|
||||
virtual void Init() {}
|
||||
virtual void AddPath(const QString& path) = 0;
|
||||
virtual void RemovePath(const QString& path) = 0;
|
||||
virtual void AddPath(const QString &path) = 0;
|
||||
virtual void RemovePath(const QString &path) = 0;
|
||||
virtual void Clear() = 0;
|
||||
|
||||
static FileSystemWatcherInterface* Create(QObject *parent = nullptr);
|
||||
static FileSystemWatcherInterface *Create(QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void PathChanged(const QString &path);
|
||||
|
||||
@@ -38,9 +38,19 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QWidget>
|
||||
#include <QObject>
|
||||
#include <QLayout>
|
||||
#include <QLayoutItem>
|
||||
#include <QStyle>
|
||||
#include <QSize>
|
||||
#include <QPoint>
|
||||
#include <QRect>
|
||||
#include <QSizePolicy>
|
||||
|
||||
#include "flowlayout.h"
|
||||
|
||||
//! [1]
|
||||
FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
|
||||
: QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
|
||||
@@ -144,12 +154,10 @@ int FlowLayout::doLayout(const QRect& rect, bool testOnly) const {
|
||||
QWidget* wid = item->widget();
|
||||
int spaceX = horizontalSpacing();
|
||||
if (spaceX == -1)
|
||||
spaceX = wid->style()->layoutSpacing(
|
||||
QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
|
||||
spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
|
||||
int spaceY = verticalSpacing();
|
||||
if (spaceY == -1)
|
||||
spaceY = wid->style()->layoutSpacing(
|
||||
QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
|
||||
spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
|
||||
//! [10]
|
||||
//! [11]
|
||||
int nextX = x + item->sizeHint().width() + spaceX;
|
||||
@@ -173,10 +181,12 @@ int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const {
|
||||
QObject* parent = this->parent();
|
||||
if (!parent) {
|
||||
return -1;
|
||||
} else if (parent->isWidgetType()) {
|
||||
}
|
||||
else if (parent->isWidgetType()) {
|
||||
QWidget *pw = static_cast<QWidget *>(parent);
|
||||
return pw->style()->pixelMetric(pm, 0, pw);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return static_cast<QLayout *>(parent)->spacing();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,15 +41,20 @@
|
||||
#ifndef FLOWLAYOUT_H
|
||||
#define FLOWLAYOUT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QLayout>
|
||||
#include <QRect>
|
||||
#include <QWidget>
|
||||
#include <QStyle>
|
||||
#include <QWidgetItem>
|
||||
#include <QList>
|
||||
#include <QSize>
|
||||
#include <QLayoutItem>
|
||||
#include <QRect>
|
||||
|
||||
//! [0]
|
||||
class FlowLayout : public QLayout {
|
||||
public:
|
||||
FlowLayout(QWidget* parent, int margin = -1, int hSpacing = -1,
|
||||
int vSpacing = -1);
|
||||
FlowLayout(QWidget* parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
|
||||
FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
|
||||
~FlowLayout();
|
||||
|
||||
|
||||
@@ -22,20 +22,19 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QIcon>
|
||||
#include <QSize>
|
||||
#include <QtDebug>
|
||||
#include <QSettings>
|
||||
|
||||
#include "iconloader.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/appearance.h"
|
||||
#include "iconloader.h"
|
||||
|
||||
QList<int> IconLoader::sizes_;
|
||||
QString IconDefault(":/icons/64x64/strawberry.png");
|
||||
|
||||
void IconLoader::Init() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
sizes_.clear();
|
||||
sizes_ << 22 << 32 << 48 << 64;
|
||||
@@ -50,8 +49,6 @@ QIcon IconLoader::Load(const QString &name) {
|
||||
|
||||
QIcon ret;
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__ << name;
|
||||
|
||||
if (name.isEmpty()) {
|
||||
qLog(Warning) << "Icon name is empty!";
|
||||
ret.addFile(IconDefault, QSize(64, 64));
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#ifndef ICONLOADER_H
|
||||
#define ICONLOADER_H
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QIcon>
|
||||
|
||||
class IconLoader {
|
||||
|
||||
@@ -3,17 +3,19 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QKeySequence>
|
||||
|
||||
class MacGlobalShortcutBackend;
|
||||
class QObject;
|
||||
class QWidget;
|
||||
|
||||
class MacGlobalShortcutBackend;
|
||||
|
||||
class PlatformInterface {
|
||||
public:
|
||||
// Called when the application should show itself.
|
||||
virtual void Activate() = 0;
|
||||
virtual bool LoadUrl(const QString& url) = 0;
|
||||
virtual bool LoadUrl(const QString &url) = 0;
|
||||
|
||||
virtual ~PlatformInterface() {}
|
||||
};
|
||||
@@ -21,8 +23,8 @@ class PlatformInterface {
|
||||
namespace mac {
|
||||
|
||||
void MacMain();
|
||||
void SetShortcutHandler(MacGlobalShortcutBackend* handler);
|
||||
void SetApplicationHandler(PlatformInterface* handler);
|
||||
void SetShortcutHandler(MacGlobalShortcutBackend *handler);
|
||||
void SetApplicationHandler(PlatformInterface *handler);
|
||||
void CheckForUpdates();
|
||||
|
||||
QString GetBundlePath();
|
||||
@@ -30,7 +32,7 @@ QString GetResourcesPath();
|
||||
QString GetApplicationSupportPath();
|
||||
QString GetMusicDirectory();
|
||||
|
||||
void EnableFullScreen(const QWidget& main_window);
|
||||
void EnableFullScreen(const QWidget &main_window);
|
||||
|
||||
} // namespace mac
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#import "3rdparty/SPMediaKeyTap/SPMediaKeyTap.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "globalshortcuts.h"
|
||||
#include "mac_delegate.h"
|
||||
#include "mac_startup.h"
|
||||
@@ -49,8 +50,8 @@
|
||||
#include "macglobalshortcutbackend.h"
|
||||
#include "utilities.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/scoped_cftyperef.h"
|
||||
#include "core/scoped_nsautorelease_pool.h"
|
||||
#include "scoped_cftyperef.h"
|
||||
#include "scoped_nsautorelease_pool.h"
|
||||
|
||||
#ifdef HAVE_SPARKLE
|
||||
#import <Sparkle/SUUpdater.h>
|
||||
@@ -58,11 +59,11 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCoreApplication>
|
||||
#include <QWidget>
|
||||
#include <QDir>
|
||||
#include <QEvent>
|
||||
#include <QFile>
|
||||
#include <QSettings>
|
||||
#include <QWidget>
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
@@ -78,8 +79,7 @@ QDebug operator<<(QDebug dbg, NSObject* object) {
|
||||
@interface MacApplication : NSApplication {
|
||||
PlatformInterface* application_handler_;
|
||||
AppDelegate* delegate_;
|
||||
// shortcut_handler_ only used to temporarily save it
|
||||
// AppDelegate does all the heavy-shortcut-lifting
|
||||
// shortcut_handler_ only used to temporarily save it AppDelegate does all the heavy-shortcut-lifting
|
||||
MacGlobalShortcutBackend* shortcut_handler_;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QKeySequence>
|
||||
|
||||
#include <CoreFoundation/CFDictionary.h>
|
||||
@@ -34,5 +35,5 @@ namespace mac {
|
||||
|
||||
QKeySequence KeySequenceFromNSEvent(NSEvent* event);
|
||||
void DumpDictionary(CFDictionaryRef dict);
|
||||
float GetDevicePixelRatio(QWidget* widget);
|
||||
float GetDevicePixelRatio(QWidget *widget);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QSet>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <Foundation/NSString.h>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "core/scoped_nsobject.h"
|
||||
#include "scoped_nsobject.h"
|
||||
|
||||
MacFSListener::MacFSListener(QObject* parent)
|
||||
: FileSystemWatcherInterface(parent), run_loop_(nullptr), stream_(nullptr) {
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QObject>
|
||||
#include <QAction>
|
||||
#include <QPixmap>
|
||||
|
||||
#include "systemtrayicon.h"
|
||||
|
||||
class MacSystemTrayIconPrivate;
|
||||
|
||||
@@ -22,13 +22,12 @@
|
||||
|
||||
#include "macsystemtrayicon.h"
|
||||
|
||||
#include "core/mac_delegate.h"
|
||||
#include "core/song.h"
|
||||
#include "mac_delegate.h"
|
||||
#include "song.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QAction>
|
||||
#include <QIcon>
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
#include <AppKit/NSMenu.h>
|
||||
|
||||
@@ -21,16 +21,27 @@
|
||||
#include "config.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <memory>
|
||||
#include <time.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <unistd.h>
|
||||
#endif // Q_OS_UNIX
|
||||
#include <QObject>
|
||||
#include <QCoreApplication>
|
||||
#include <QFileDevice>
|
||||
#include <QIODevice>
|
||||
#include <QByteArray>
|
||||
#include <QNetworkProxy>
|
||||
#include <QFile>
|
||||
#include <QString>
|
||||
#include <QImage>
|
||||
#include <QSettings>
|
||||
#include <QtDebug>
|
||||
#ifdef HAVE_DBUS
|
||||
# include <QDBusArgument>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include <sys/resource.h>
|
||||
@@ -45,53 +56,26 @@
|
||||
#include <iostream>
|
||||
#endif // Q_OS_WIN32
|
||||
|
||||
#include <QObject>
|
||||
#include <QFile>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QDir>
|
||||
#include <QFont>
|
||||
#include <QLibraryInfo>
|
||||
#include <QNetworkProxyFactory>
|
||||
#include <QSslSocket>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QSysInfo>
|
||||
#include <QTextCodec>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QtDebug>
|
||||
#include <QSettings>
|
||||
#ifdef HAVE_DBUS
|
||||
#include <QDBusArgument>
|
||||
#include <QImage>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
#include "core/mpris.h"
|
||||
#include "core/mpris2.h"
|
||||
#endif
|
||||
#include "core/application.h"
|
||||
#include "core/mainwindow.h"
|
||||
#include "core/commandlineoptions.h"
|
||||
#include "core/database.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/mac_startup.h"
|
||||
#include "core/metatypes.h"
|
||||
#include "core/network.h"
|
||||
#include "core/networkproxyfactory.h"
|
||||
#include "core/song.h"
|
||||
#include "core/utilities.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/systemtrayicon.h"
|
||||
#include "core/scangiomodulepath.h"
|
||||
|
||||
#include "widgets/osd.h"
|
||||
|
||||
#include "tagreadermessages.pb.h"
|
||||
|
||||
#include "qtsingleapplication.h"
|
||||
#include "qtsinglecoreapplication.h"
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
#include "mpris.h"
|
||||
#endif
|
||||
#include "utilities.h"
|
||||
#include "metatypes.h"
|
||||
#include "iconloader.h"
|
||||
#include "mainwindow.h"
|
||||
#include "commandlineoptions.h"
|
||||
#include "systemtrayicon.h"
|
||||
#include "application.h"
|
||||
#include "networkproxyfactory.h"
|
||||
#include "scangiomodulepath.h"
|
||||
|
||||
#include "widgets/osd.h"
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
QDBusArgument &operator<<(QDBusArgument &arg, const QImage &image);
|
||||
const QDBusArgument &operator>>(const QDBusArgument &arg, QImage &image);
|
||||
|
||||
@@ -20,102 +20,112 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <cmath>
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QApplication>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QByteArray>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QFontMetrics>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QIcon>
|
||||
#include <QMimeData>
|
||||
#include <QPalette>
|
||||
#include <QTimer>
|
||||
#include <QtAlgorithms>
|
||||
#include <QKeySequence>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
#include <QShortcut>
|
||||
#include <QMessageBox>
|
||||
#include <QtEvents>
|
||||
#include <QSettings>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "core/closure.h"
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
#include <memory>
|
||||
#include <cmath>
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QCloseEvent>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QFileSystemModel>
|
||||
#include <QLinearGradient>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QSettings>
|
||||
#include <QShortcut>
|
||||
#include <QSignalMapper>
|
||||
#include <QStatusBar>
|
||||
#include <QtDebug>
|
||||
#include <QTimer>
|
||||
#include <QUndoStack>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QAction>
|
||||
#include <QList>
|
||||
#include <QModelIndex>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "core/appearance.h"
|
||||
#include "core/application.h"
|
||||
#include "core/commandlineoptions.h"
|
||||
#include "core/database.h"
|
||||
#include "core/filesystemmusicstorage.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/mac_startup.h"
|
||||
#include "core/mergedproxymodel.h"
|
||||
#include "core/mimedata.h"
|
||||
#include "core/mpris_common.h"
|
||||
#include "core/network.h"
|
||||
#include "core/player.h"
|
||||
#include "core/songloader.h"
|
||||
#include "core/stylesheetloader.h"
|
||||
#include "core/taskmanager.h"
|
||||
#include "core/timeconstants.h"
|
||||
#include "core/utilities.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/qtsystemtrayicon.h"
|
||||
#include "core/systemtrayicon.h"
|
||||
#include "core/windows7thumbbar.h"
|
||||
#include "globalshortcuts/globalshortcuts.h"
|
||||
#include "widgets/statusview.h"
|
||||
#include "utilities.h"
|
||||
#include "timeconstants.h"
|
||||
#include "commandlineoptions.h"
|
||||
#include "mimedata.h"
|
||||
#include "iconloader.h"
|
||||
#include "taskmanager.h"
|
||||
#include "song.h"
|
||||
#include "stylesheetloader.h"
|
||||
#include "systemtrayicon.h"
|
||||
#include "windows7thumbbar.h"
|
||||
#include "application.h"
|
||||
#include "database.h"
|
||||
#include "player.h"
|
||||
#include "appearance.h"
|
||||
#include "engine/enginebase.h"
|
||||
#include "engine/gstengine.h"
|
||||
#include "collection/groupbydialog.h"
|
||||
#include "dialogs/errordialog.h"
|
||||
#include "dialogs/about.h"
|
||||
#include "dialogs/console.h"
|
||||
#include "dialogs/trackselectiondialog.h"
|
||||
#include "dialogs/edittagdialog.h"
|
||||
#ifdef HAVE_GSTREAMER
|
||||
#include "dialogs/organisedialog.h"
|
||||
#endif
|
||||
#include "widgets/fancytabwidget.h"
|
||||
#include "widgets/playingwidget.h"
|
||||
#include "widgets/sliderwidget.h"
|
||||
#include "widgets/statusview.h"
|
||||
#include "widgets/fileview.h"
|
||||
#include "widgets/multiloadingindicator.h"
|
||||
#include "widgets/osd.h"
|
||||
#include "widgets/stylehelper.h"
|
||||
#include "widgets/trackslider.h"
|
||||
#include "collection/collection.h"
|
||||
#include "collection/collectionbackend.h"
|
||||
#include "collection/collectiondirectorymodel.h"
|
||||
#include "collection/collectionfilterwidget.h"
|
||||
#include "collection/collectionmodel.h"
|
||||
#include "collection/collectionquery.h"
|
||||
#include "collection/collectionview.h"
|
||||
#include "collection/collectionviewcontainer.h"
|
||||
#include "playlist/playlistbackend.h"
|
||||
#include "playlist/playlist.h"
|
||||
#include "playlist/playlistbackend.h"
|
||||
#include "playlist/playlistcontainer.h"
|
||||
#include "playlist/playlistlistcontainer.h"
|
||||
#include "playlist/playlistmanager.h"
|
||||
#include "playlist/playlistsequence.h"
|
||||
#include "playlist/playlistview.h"
|
||||
#include "playlist/queue.h"
|
||||
#include "playlist/queuemanager.h"
|
||||
#include "playlist/songplaylistitem.h"
|
||||
#include "playlistparsers/playlistparser.h"
|
||||
#include "analyzer/analyzercontainer.h"
|
||||
#include "equalizer/equalizer.h"
|
||||
#include "globalshortcuts/globalshortcuts.h"
|
||||
#include "musicbrainz/tagfetcher.h"
|
||||
#include "covermanager/albumcovermanager.h"
|
||||
#include "device/devicemanager.h"
|
||||
#include "device/devicestatefiltermodel.h"
|
||||
#include "device/deviceview.h"
|
||||
#include "device/deviceviewcontainer.h"
|
||||
#include "musicbrainz/tagfetcher.h"
|
||||
#include "equalizer/equalizer.h"
|
||||
#include "transcoder/transcodedialog.h"
|
||||
#include "dialogs/about.h"
|
||||
#include "dialogs/console.h"
|
||||
#include "dialogs/edittagdialog.h"
|
||||
#ifdef HAVE_GSTREAMER
|
||||
#include "dialogs/organisedialog.h"
|
||||
#include "dialogs/organiseerrordialog.h"
|
||||
#endif
|
||||
#include "dialogs/trackselectiondialog.h"
|
||||
#include "dialogs/errordialog.h"
|
||||
#include "widgets/fileview.h"
|
||||
#include "widgets/multiloadingindicator.h"
|
||||
#include "widgets/osd.h"
|
||||
#include "widgets/stylehelper.h"
|
||||
#include "widgets/trackslider.h"
|
||||
#include "settings/settingsdialog.h"
|
||||
#include "covermanager/albumcovermanager.h"
|
||||
|
||||
#include "settings/behavioursettingspage.h"
|
||||
#include "settings/playlistsettingspage.h"
|
||||
#include "settings/settingsdialog.h"
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include "ui/macsystemtrayicon.h"
|
||||
@@ -151,7 +161,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
device_view_(device_view_container_->view()),
|
||||
settings_dialog_(std::bind(&MainWindow::CreateSettingsDialog, this)),
|
||||
cover_manager_([=]() {
|
||||
AlbumCoverManager* cover_manager = new AlbumCoverManager(app, app->collection_backend());
|
||||
AlbumCoverManager *cover_manager = new AlbumCoverManager(app, app->collection_backend());
|
||||
cover_manager->Init();
|
||||
|
||||
// Cover manager connections
|
||||
@@ -163,13 +173,13 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
equalizer_(new Equalizer),
|
||||
#ifdef HAVE_GSTREAMER
|
||||
organise_dialog_([=]() {
|
||||
OrganiseDialog* dialog = new OrganiseDialog(app->task_manager());
|
||||
OrganiseDialog *dialog = new OrganiseDialog(app->task_manager());
|
||||
dialog->SetDestinationModel(app->collection()->model()->directory_model());
|
||||
return dialog;
|
||||
}),
|
||||
#endif
|
||||
queue_manager_([=]() {
|
||||
QueueManager* manager = new QueueManager;
|
||||
QueueManager *manager = new QueueManager;
|
||||
manager->SetPlaylistManager(app->playlist_manager());
|
||||
return manager;
|
||||
}),
|
||||
@@ -345,9 +355,6 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
connect(ui_->action_add_folder, SIGNAL(triggered()), SLOT(AddFolder()));
|
||||
connect(ui_->action_cover_manager, SIGNAL(triggered()), SLOT(ShowCoverManager()));
|
||||
connect(ui_->action_equalizer, SIGNAL(triggered()), equalizer_.get(), SLOT(show()));
|
||||
#ifdef HAVE_GSTREAMER
|
||||
//connect(ui_->action_transcode, SIGNAL(triggered()), SLOT(ShowTranscodeDialog()));
|
||||
#endif
|
||||
connect(ui_->action_jump, SIGNAL(triggered()), ui_->playlist->view(), SLOT(JumpToCurrentlyPlayingTrack()));
|
||||
connect(ui_->action_update_collection, SIGNAL(triggered()), app_->collection(), SLOT(IncrementalScan()));
|
||||
connect(ui_->action_full_collection_scan, SIGNAL(triggered()), app_->collection(), SLOT(FullScan()));
|
||||
@@ -375,7 +382,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
ui_->action_repeat_mode->setMenu(ui_->playlist_sequence->repeat_menu());
|
||||
|
||||
// Stop actions
|
||||
QMenu* stop_menu = new QMenu(this);
|
||||
QMenu *stop_menu = new QMenu(this);
|
||||
stop_menu->addAction(ui_->action_stop);
|
||||
stop_menu->addAction(ui_->action_stop_after_this_track);
|
||||
ui_->stop_button->setMenu(stop_menu);
|
||||
@@ -439,7 +446,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
connect(device_view_, SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
|
||||
|
||||
// Collection filter widget
|
||||
QActionGroup* collection_view_group = new QActionGroup(this);
|
||||
QActionGroup *collection_view_group = new QActionGroup(this);
|
||||
|
||||
collection_show_all_ = collection_view_group->addAction(tr("Show all songs"));
|
||||
collection_show_duplicates_ = collection_view_group->addAction(tr("Show only duplicates"));
|
||||
@@ -452,12 +459,12 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
|
||||
connect(collection_view_group, SIGNAL(triggered(QAction*)), SLOT(ChangeCollectionQueryMode(QAction*)));
|
||||
|
||||
QAction* collection_config_action = new QAction(IconLoader::Load("configure"), tr("Configure collection..."), this);
|
||||
QAction *collection_config_action = new QAction(IconLoader::Load("configure"), tr("Configure collection..."), this);
|
||||
connect(collection_config_action, SIGNAL(triggered()), SLOT(ShowCollectionConfig()));
|
||||
collection_view_->filter()->SetSettingsGroup(kSettingsGroup);
|
||||
collection_view_->filter()->SetCollectionModel(app_->collection()->model());
|
||||
|
||||
QAction* separator = new QAction(this);
|
||||
QAction *separator = new QAction(this);
|
||||
separator->setSeparator(true);
|
||||
|
||||
collection_view_->filter()->AddMenuAction(collection_show_all_);
|
||||
@@ -509,11 +516,10 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
ui_->action_shuffle->setShortcut(QKeySequence());
|
||||
#endif
|
||||
|
||||
// We have to add the actions on the playlist menu to this QWidget otherwise
|
||||
// their shortcut keys don't work
|
||||
// We have to add the actions on the playlist menu to this QWidget otherwise their shortcut keys don't work
|
||||
addActions(playlist_menu_->actions());
|
||||
|
||||
connect(ui_->playlist, SIGNAL(UndoRedoActionsChanged(QAction*,QAction*)), SLOT(PlaylistUndoRedoChanged(QAction*,QAction*)));
|
||||
connect(ui_->playlist, SIGNAL(UndoRedoActionsChanged(QAction*, QAction*)), SLOT(PlaylistUndoRedoChanged(QAction*, QAction*)));
|
||||
|
||||
#ifdef HAVE_GSTREAMER
|
||||
playlist_copy_to_device_->setDisabled(app_->device_manager()->connected_devices_model()->rowCount() == 0);
|
||||
@@ -539,7 +545,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
|
||||
#if (defined(Q_OS_DARWIN) && defined(HAVE_SPARKLE)) || defined(Q_OS_WIN32)
|
||||
// Add check for updates item to application menu.
|
||||
QAction* check_updates = ui_->menu_tools->addAction(tr("Check for updates..."));
|
||||
QAction *check_updates = ui_->menu_tools->addAction(tr("Check for updates..."));
|
||||
check_updates->setMenuRole(QAction::ApplicationSpecificRole);
|
||||
connect(check_updates, SIGNAL(triggered(bool)), SLOT(CheckForUpdates()));
|
||||
#endif
|
||||
@@ -602,11 +608,11 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
PlayingWidgetPositionChanged();
|
||||
|
||||
// Load theme
|
||||
// This is tricky: we need to save the default/system palette now, before
|
||||
// loading user preferred theme (which will overide it), to be able to restore it later
|
||||
// This is tricky: we need to save the default/system palette now,
|
||||
// before loading user preferred theme (which will overide it), to be able to restore it later
|
||||
const_cast<QPalette&>(Appearance::kDefaultPalette) = QApplication::palette();
|
||||
app_->appearance()->LoadUserTheme();
|
||||
StyleSheetLoader* css_loader = new StyleSheetLoader(this);
|
||||
StyleSheetLoader *css_loader = new StyleSheetLoader(this);
|
||||
css_loader->SetStyleSheet(this, ":style/mainwindow.css");
|
||||
RefreshStyleSheet();
|
||||
|
||||
@@ -643,8 +649,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
file_view_->SetPath(settings_.value("file_path", QDir::homePath()).toString());
|
||||
TabSwitched();
|
||||
|
||||
// Users often collapse one side of the splitter by mistake and don't know
|
||||
// how to restore it. This must be set after the state is restored above.
|
||||
// Users often collapse one side of the splitter by mistake and don't know how to restore it. This must be set after the state is restored above.
|
||||
ui_->splitter->setChildrenCollapsible(false);
|
||||
|
||||
ReloadSettings();
|
||||
@@ -703,8 +708,6 @@ MainWindow::~MainWindow() {
|
||||
}
|
||||
|
||||
void MainWindow::ReloadSettings() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
QSettings settings;
|
||||
|
||||
@@ -809,8 +812,9 @@ void MainWindow::VolumeChanged(int volume) {
|
||||
}
|
||||
|
||||
void MainWindow::SongChanged(const Song &song) {
|
||||
|
||||
setWindowTitle(song.PrettyTitleWithArtist() + " --- Strawberry Music Player");
|
||||
|
||||
//setWindowTitle(song.PrettyTitleWithArtist() + " --- Strawberry Music Player");
|
||||
setWindowTitle(song.PrettyTitleWithArtist());
|
||||
tray_icon_->SetProgress(0);
|
||||
|
||||
}
|
||||
@@ -837,8 +841,6 @@ void MainWindow::TrackSkipped(PlaylistItemPtr item) {
|
||||
void MainWindow::resizeEvent(QResizeEvent*) { SaveGeometry(); }
|
||||
|
||||
void MainWindow::TabSwitched() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__ << ui_->tabs->current_index() ;
|
||||
|
||||
if (ui_->tabs->current_index() > 0)
|
||||
ui_->now_playing->SetEnabled();
|
||||
@@ -850,8 +852,6 @@ void MainWindow::TabSwitched() {
|
||||
}
|
||||
|
||||
void MainWindow::SaveGeometry() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
was_maximized_ = isMaximized();
|
||||
settings_.setValue("maximized", was_maximized_);
|
||||
@@ -866,8 +866,6 @@ void MainWindow::SaveGeometry() {
|
||||
}
|
||||
|
||||
void MainWindow::SavePlaybackStatus() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
QSettings settings;
|
||||
|
||||
@@ -885,8 +883,6 @@ void MainWindow::SavePlaybackStatus() {
|
||||
}
|
||||
|
||||
void MainWindow::LoadPlaybackStatus() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
QSettings settings;
|
||||
|
||||
@@ -933,8 +929,7 @@ void MainWindow::PlayIndex(const QModelIndex &index) {
|
||||
|
||||
int row = index.row();
|
||||
if (index.model() == app_->playlist_manager()->current()->proxy()) {
|
||||
// The index was in the proxy model (might've been filtered), so we need
|
||||
// to get the actual row in the source model.
|
||||
// The index was in the proxy model (might've been filtered), so we need to get the actual row in the source model.
|
||||
row = app_->playlist_manager()->current()->proxy()->mapToSource(index).row();
|
||||
}
|
||||
|
||||
@@ -947,10 +942,8 @@ void MainWindow::PlaylistDoubleClick(const QModelIndex &index) {
|
||||
|
||||
int row = index.row();
|
||||
if (index.model() == app_->playlist_manager()->current()->proxy()) {
|
||||
// The index was in the proxy model (might've been filtered), so we need
|
||||
// to get the actual row in the source model.
|
||||
row =
|
||||
app_->playlist_manager()->current()->proxy()->mapToSource(index).row();
|
||||
// The index was in the proxy model (might've been filtered), so we need to get the actual row in the source model.
|
||||
row = app_->playlist_manager()->current()->proxy()->mapToSource(index).row();
|
||||
}
|
||||
|
||||
QModelIndexList dummyIndexList;
|
||||
@@ -1028,8 +1021,7 @@ void MainWindow::SetHiddenInTray(bool hidden) {
|
||||
|
||||
settings_.setValue("hidden", hidden);
|
||||
|
||||
// Some window managers don't remember maximized state between calls to
|
||||
// hide() and show(), so we have to remember it ourself.
|
||||
// Some window managers don't remember maximized state between calls to hide() and show(), so we have to remember it ourself.
|
||||
if (hidden) {
|
||||
//was_maximized_ = isMaximized();
|
||||
hide();
|
||||
@@ -1053,11 +1045,9 @@ void MainWindow::Seeked(qlonglong microseconds) {
|
||||
}
|
||||
|
||||
void MainWindow::UpdateTrackPosition() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
// Track position in seconds
|
||||
//Playlist* playlist = app_->playlist_manager()->active();
|
||||
//Playlist *playlist = app_->playlist_manager()->active();
|
||||
|
||||
PlaylistItemPtr item(app_->player()->GetCurrentItem());
|
||||
const int position = std::floor(float(app_->player()->engine()->position_nanosec()) / kNsecPerSec + 0.5);
|
||||
@@ -1086,7 +1076,7 @@ void MainWindow::UpdateTrackSliderPosition() {
|
||||
ui_->track_slider->SetValue(slider_position, slider_length);
|
||||
}
|
||||
|
||||
void MainWindow::ApplyAddBehaviour(MainWindow::AddBehaviour b, MimeData* data) const {
|
||||
void MainWindow::ApplyAddBehaviour(MainWindow::AddBehaviour b, MimeData *data) const {
|
||||
|
||||
switch (b) {
|
||||
case AddBehaviour_Append:
|
||||
@@ -1110,9 +1100,7 @@ void MainWindow::ApplyAddBehaviour(MainWindow::AddBehaviour b, MimeData* data) c
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::ApplyPlayBehaviour(MainWindow::PlayBehaviour b, MimeData* data) const {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
void MainWindow::ApplyPlayBehaviour(MainWindow::PlayBehaviour b, MimeData *data) const {
|
||||
|
||||
switch (b) {
|
||||
case PlayBehaviour_Always:
|
||||
@@ -1129,9 +1117,7 @@ void MainWindow::ApplyPlayBehaviour(MainWindow::PlayBehaviour b, MimeData* data)
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::AddToPlaylist(QMimeData* data) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
void MainWindow::AddToPlaylist(QMimeData *data) {
|
||||
|
||||
if (!data) return;
|
||||
|
||||
@@ -1157,15 +1143,13 @@ void MainWindow::AddToPlaylist(QMimeData* data) {
|
||||
delete data;
|
||||
}
|
||||
|
||||
void MainWindow::AddToPlaylist(QAction* action) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
void MainWindow::AddToPlaylist(QAction *action) {
|
||||
|
||||
int destination = action->data().toInt();
|
||||
PlaylistItemList items;
|
||||
|
||||
// get the selected playlist items
|
||||
for (const QModelIndex& index : ui_->playlist->view()->selectionModel()->selection().indexes()) {
|
||||
for (const QModelIndex &index : ui_->playlist->view()->selectionModel()->selection().indexes()) {
|
||||
if (index.column() != 0) continue;
|
||||
int row = app_->playlist_manager()->current()->proxy()->mapToSource(index).row();
|
||||
items << app_->playlist_manager()->current()->item_at(row);
|
||||
@@ -1198,8 +1182,6 @@ void MainWindow::AddToPlaylist(QAction* action) {
|
||||
|
||||
void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex &index) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
QModelIndex source_index = app_->playlist_manager()->current()->proxy()->mapToSource(index);
|
||||
|
||||
playlist_menu_index_ = source_index;
|
||||
@@ -1374,10 +1356,10 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
QMenu *add_to_another_menu = new QMenu(tr("Add to another playlist"), this);
|
||||
add_to_another_menu->setIcon(IconLoader::Load("list-add"));
|
||||
|
||||
for (const PlaylistBackend::Playlist& playlist : app_->playlist_backend()->GetAllOpenPlaylists()) {
|
||||
for (const PlaylistBackend::Playlist &playlist : app_->playlist_backend()->GetAllOpenPlaylists()) {
|
||||
// don't add the current playlist
|
||||
if (playlist.id != app_->playlist_manager()->current()->id()) {
|
||||
QAction* existing_playlist = new QAction(this);
|
||||
QAction *existing_playlist = new QAction(this);
|
||||
existing_playlist->setText(playlist.name);
|
||||
existing_playlist->setData(playlist.id);
|
||||
add_to_another_menu->addAction(existing_playlist);
|
||||
@@ -1386,7 +1368,7 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
|
||||
add_to_another_menu->addSeparator();
|
||||
// add to a new playlist
|
||||
QAction* new_playlist = new QAction(this);
|
||||
QAction *new_playlist = new QAction(this);
|
||||
new_playlist->setText(tr("New playlist"));
|
||||
new_playlist->setData(-1); // fake id
|
||||
add_to_another_menu->addAction(new_playlist);
|
||||
@@ -1414,7 +1396,7 @@ void MainWindow::EditTracks() {
|
||||
SongList songs;
|
||||
PlaylistItemList items;
|
||||
|
||||
for (const QModelIndex& index : ui_->playlist->view()->selectionModel()->selection().indexes()) {
|
||||
for (const QModelIndex &index : ui_->playlist->view()->selectionModel()->selection().indexes()) {
|
||||
if (index.column() != 0) continue;
|
||||
int row =app_->playlist_manager()->current()->proxy()->mapToSource(index).row();
|
||||
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(row));
|
||||
@@ -1456,7 +1438,7 @@ void MainWindow::RenumberTracks() {
|
||||
if (first_song.track() > 0) track = first_song.track();
|
||||
}
|
||||
|
||||
for (const QModelIndex& index : indexes) {
|
||||
for (const QModelIndex &index : indexes) {
|
||||
if (index.column() != 0) continue;
|
||||
|
||||
const QModelIndex source_index =app_->playlist_manager()->current()->proxy()->mapToSource(index);
|
||||
@@ -1466,7 +1448,7 @@ void MainWindow::RenumberTracks() {
|
||||
if (song.IsEditable()) {
|
||||
song.set_track(track);
|
||||
|
||||
TagReaderReply* reply =TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
|
||||
TagReaderReply *reply =TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
|
||||
|
||||
NewClosure(reply, SIGNAL(Finished(bool)), this, SLOT(SongSaveComplete(TagReaderReply*, QPersistentModelIndex)),reply, QPersistentModelIndex(source_index));
|
||||
}
|
||||
@@ -1474,7 +1456,7 @@ void MainWindow::RenumberTracks() {
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::SongSaveComplete(TagReaderReply* reply,const QPersistentModelIndex& index) {
|
||||
void MainWindow::SongSaveComplete(TagReaderReply *reply,const QPersistentModelIndex &index) {
|
||||
if (reply->is_successful() && index.isValid()) {
|
||||
app_->playlist_manager()->current()->ReloadItems(QList<int>()<< index.row());
|
||||
}
|
||||
@@ -1487,7 +1469,7 @@ void MainWindow::SelectionSetValue() {
|
||||
|
||||
QModelIndexList indexes =ui_->playlist->view()->selectionModel()->selection().indexes();
|
||||
|
||||
for (const QModelIndex& index : indexes) {
|
||||
for (const QModelIndex &index : indexes) {
|
||||
if (index.column() != 0) continue;
|
||||
|
||||
const QModelIndex source_index =app_->playlist_manager()->current()->proxy()->mapToSource(index);
|
||||
@@ -1495,7 +1477,7 @@ void MainWindow::SelectionSetValue() {
|
||||
Song song = app_->playlist_manager()->current()->item_at(row)->Metadata();
|
||||
|
||||
if (Playlist::set_column_value(song, column, column_value)) {
|
||||
TagReaderReply* reply =TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
|
||||
TagReaderReply *reply =TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
|
||||
|
||||
NewClosure(reply, SIGNAL(Finished(bool)), this, SLOT(SongSaveComplete(TagReaderReply*, QPersistentModelIndex)),reply, QPersistentModelIndex(source_index));
|
||||
}
|
||||
@@ -1507,8 +1489,7 @@ void MainWindow::EditValue() {
|
||||
|
||||
if (!current.isValid()) return;
|
||||
|
||||
// Edit the last column that was right-clicked on. If nothing's ever been
|
||||
// right clicked then look for the first editable column.
|
||||
// Edit the last column that was right-clicked on. If nothing's ever been right clicked then look for the first editable column.
|
||||
int column = playlist_menu_index_.column();
|
||||
if (column == -1) {
|
||||
for (int i = 0; i < ui_->playlist->view()->model()->columnCount(); ++i) {
|
||||
@@ -1524,15 +1505,13 @@ void MainWindow::EditValue() {
|
||||
|
||||
void MainWindow::AddFile() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
// Last used directory
|
||||
QString directory =settings_.value("add_media_path", QDir::currentPath()).toString();
|
||||
|
||||
PlaylistParser parser(app_->collection_backend());
|
||||
|
||||
// Show dialog
|
||||
QStringList file_names = QFileDialog::getOpenFileNames(this, tr("Add file"), directory,QString("%1 (%2);;%3;;%4").arg(tr("Music"), FileView::kFileFilter,parser.filters(),tr(kAllFilesFilterSpec)));
|
||||
QStringList file_names = QFileDialog::getOpenFileNames(this, tr("Add file"), directory, QString("%1 (%2);;%3;;%4").arg(tr("Music"), FileView::kFileFilter, parser.filters(), tr(kAllFilesFilterSpec)));
|
||||
|
||||
if (file_names.isEmpty()) return;
|
||||
|
||||
@@ -1541,11 +1520,11 @@ void MainWindow::AddFile() {
|
||||
|
||||
// Convert to URLs
|
||||
QList<QUrl> urls;
|
||||
for (const QString& path : file_names) {
|
||||
for (const QString &path : file_names) {
|
||||
urls << QUrl::fromLocalFile(QFileInfo(path).canonicalFilePath());
|
||||
}
|
||||
|
||||
MimeData* data = new MimeData;
|
||||
MimeData *data = new MimeData;
|
||||
data->setUrls(urls);
|
||||
AddToPlaylist(data);
|
||||
}
|
||||
@@ -1562,15 +1541,14 @@ void MainWindow::AddFolder() {
|
||||
settings_.setValue("add_folder_path", directory);
|
||||
|
||||
// Add media
|
||||
MimeData* data = new MimeData;
|
||||
MimeData *data = new MimeData;
|
||||
data->setUrls(QList<QUrl>() << QUrl::fromLocalFile(QFileInfo(directory).canonicalFilePath()));
|
||||
AddToPlaylist(data);
|
||||
}
|
||||
|
||||
void MainWindow::AddCDTracks() {
|
||||
MimeData* data = new MimeData;
|
||||
// We are putting empty data, but we specify cdda mimetype to indicate that
|
||||
// we want to load audio cd tracks
|
||||
MimeData *data = new MimeData;
|
||||
// We are putting empty data, but we specify cdda mimetype to indicate that we want to load audio cd tracks
|
||||
data->open_in_new_playlist_ = true;
|
||||
data->setData(Playlist::kCddaMimeType, QByteArray());
|
||||
AddToPlaylist(data);
|
||||
@@ -1582,7 +1560,7 @@ void MainWindow::ShowInCollection() {
|
||||
QModelIndexList proxy_indexes =ui_->playlist->view()->selectionModel()->selectedRows();
|
||||
SongList songs;
|
||||
|
||||
for (const QModelIndex& proxy_index : proxy_indexes) {
|
||||
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||
QModelIndex index =app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
|
||||
if (app_->playlist_manager()->current()->item_at(index.row())->IsLocalCollectionItem()) {
|
||||
songs << app_->playlist_manager()->current()->item_at(index.row())->Metadata();
|
||||
@@ -1600,11 +1578,11 @@ void MainWindow::PlaylistRemoveCurrent() {
|
||||
ui_->playlist->view()->RemoveSelected(false);
|
||||
}
|
||||
|
||||
void MainWindow::PlaylistEditFinished(const QModelIndex& index) {
|
||||
void MainWindow::PlaylistEditFinished(const QModelIndex &index) {
|
||||
if (index == playlist_menu_index_) SelectionSetValue();
|
||||
}
|
||||
|
||||
void MainWindow::CommandlineOptionsReceived(const QString& string_options) {
|
||||
void MainWindow::CommandlineOptionsReceived(const QString &string_options) {
|
||||
|
||||
CommandlineOptions options;
|
||||
options.Load(string_options.toLatin1());
|
||||
@@ -1617,7 +1595,7 @@ void MainWindow::CommandlineOptionsReceived(const QString& string_options) {
|
||||
CommandlineOptionsReceived(options);
|
||||
}
|
||||
|
||||
void MainWindow::CommandlineOptionsReceived(const CommandlineOptions& options) {
|
||||
void MainWindow::CommandlineOptionsReceived(const CommandlineOptions &options) {
|
||||
switch (options.player_action()) {
|
||||
case CommandlineOptions::Player_Play:
|
||||
if (options.urls().empty()) {
|
||||
@@ -1651,7 +1629,7 @@ void MainWindow::CommandlineOptionsReceived(const CommandlineOptions& options) {
|
||||
}
|
||||
|
||||
if (!options.urls().empty()) {
|
||||
MimeData* data = new MimeData;
|
||||
MimeData *data = new MimeData;
|
||||
data->setUrls(options.urls());
|
||||
// Behaviour depends on command line options, so set it here
|
||||
data->override_user_settings_ = true;
|
||||
@@ -1698,7 +1676,7 @@ void MainWindow::CommandlineOptionsReceived(const CommandlineOptions& options) {
|
||||
if (options.toggle_pretty_osd()) app_->player()->TogglePrettyOSD();
|
||||
}
|
||||
|
||||
void MainWindow::ForceShowOSD(const Song& song, const bool toggle) {
|
||||
void MainWindow::ForceShowOSD(const Song &song, const bool toggle) {
|
||||
if (toggle) {
|
||||
osd_->SetPrettyOSDToggleMode(toggle);
|
||||
}
|
||||
@@ -1709,11 +1687,11 @@ void MainWindow::Activate() {
|
||||
show();
|
||||
}
|
||||
|
||||
bool MainWindow::LoadUrl(const QString& url) {
|
||||
bool MainWindow::LoadUrl(const QString &url) {
|
||||
|
||||
if (!QFile::exists(url)) return false;
|
||||
|
||||
MimeData* data = new MimeData;
|
||||
MimeData *data = new MimeData;
|
||||
data->setUrls(QList<QUrl>() << QUrl::fromLocalFile(url));
|
||||
AddToPlaylist(data);
|
||||
|
||||
@@ -1726,7 +1704,7 @@ void MainWindow::CheckForUpdates() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::PlaylistUndoRedoChanged(QAction* undo, QAction* redo) {
|
||||
void MainWindow::PlaylistUndoRedoChanged(QAction *undo, QAction *redo) {
|
||||
|
||||
playlist_menu_->insertAction(playlist_undoredo_, undo);
|
||||
playlist_menu_->insertAction(playlist_undoredo_, redo);
|
||||
@@ -1737,7 +1715,7 @@ void MainWindow::AddFilesToTranscoder() {
|
||||
|
||||
QStringList filenames;
|
||||
|
||||
for (const QModelIndex& index : ui_->playlist->view()->selectionModel()->selection().indexes()) {
|
||||
for (const QModelIndex &index : ui_->playlist->view()->selectionModel()->selection().indexes()) {
|
||||
if (index.column() != 0) continue;
|
||||
int row =app_->playlist_manager()->current()->proxy()->mapToSource(index).row();
|
||||
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(row));
|
||||
@@ -1775,37 +1753,36 @@ void MainWindow::PlayingWidgetPositionChanged() {
|
||||
}
|
||||
|
||||
#ifdef HAVE_GSTREAMER
|
||||
void MainWindow::CopyFilesToCollection(const QList<QUrl>& urls) {
|
||||
void MainWindow::CopyFilesToCollection(const QList<QUrl> &urls) {
|
||||
organise_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||
organise_dialog_->SetUrls(urls);
|
||||
organise_dialog_->SetCopy(true);
|
||||
organise_dialog_->show();
|
||||
}
|
||||
|
||||
void MainWindow::MoveFilesToCollection(const QList<QUrl>& urls) {
|
||||
void MainWindow::MoveFilesToCollection(const QList<QUrl> &urls) {
|
||||
organise_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||
organise_dialog_->SetUrls(urls);
|
||||
organise_dialog_->SetCopy(false);
|
||||
organise_dialog_->show();
|
||||
}
|
||||
|
||||
void MainWindow::CopyFilesToDevice(const QList<QUrl>& urls) {
|
||||
void MainWindow::CopyFilesToDevice(const QList<QUrl> &urls) {
|
||||
organise_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
||||
organise_dialog_->SetCopy(true);
|
||||
if (organise_dialog_->SetUrls(urls))
|
||||
organise_dialog_->show();
|
||||
else {
|
||||
QMessageBox::warning(this, tr("Error"),
|
||||
tr("None of the selected songs were suitable for copying to a device"));
|
||||
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void MainWindow::EditFileTags(const QList<QUrl>& urls) {
|
||||
void MainWindow::EditFileTags(const QList<QUrl> &urls) {
|
||||
//EnsureEditTagDialogCreated();
|
||||
|
||||
SongList songs;
|
||||
for (const QUrl& url : urls) {
|
||||
for (const QUrl &url : urls) {
|
||||
Song song;
|
||||
song.set_url(url);
|
||||
song.set_valid(true);
|
||||
@@ -1831,9 +1808,8 @@ void MainWindow::PlaylistOrganiseSelected(bool copy) {
|
||||
QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||
SongList songs;
|
||||
|
||||
for (const QModelIndex& proxy_index : proxy_indexes) {
|
||||
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||
QModelIndex index =app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
|
||||
|
||||
songs << app_->playlist_manager()->current()->item_at(index.row())->Metadata();
|
||||
}
|
||||
|
||||
@@ -1859,7 +1835,7 @@ void MainWindow::PlaylistDelete() {
|
||||
// Get selected songs
|
||||
SongList selected_songs;
|
||||
QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||
for (const QModelIndex& proxy_index : proxy_indexes) {
|
||||
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||
QModelIndex index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
|
||||
selected_songs << app_->playlist_manager()->current()->item_at(index.row())->Metadata();
|
||||
}
|
||||
@@ -1879,7 +1855,7 @@ void MainWindow::PlaylistDelete() {
|
||||
|
||||
ui_->playlist->view()->RemoveSelected(true);
|
||||
|
||||
DeleteFiles* delete_files = new DeleteFiles(app_->task_manager(), storage);
|
||||
DeleteFiles *delete_files = new DeleteFiles(app_->task_manager(), storage);
|
||||
connect(delete_files, SIGNAL(Finished(SongList)), SLOT(DeleteFinished(SongList)));
|
||||
delete_files->Start(selected_songs);
|
||||
}
|
||||
@@ -1890,7 +1866,7 @@ void MainWindow::PlaylistOpenInBrowser() {
|
||||
QList<QUrl> urls;
|
||||
QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||
|
||||
for (const QModelIndex& proxy_index : proxy_indexes) {
|
||||
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||
const QModelIndex index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
|
||||
urls << QUrl(index.sibling(index.row(), Playlist::Column_Filename).data().toString());
|
||||
}
|
||||
@@ -1899,10 +1875,10 @@ void MainWindow::PlaylistOpenInBrowser() {
|
||||
}
|
||||
|
||||
#if 0
|
||||
void MainWindow::DeleteFinished(const SongList& songs_with_errors) {
|
||||
void MainWindow::DeleteFinished(const SongList &songs_with_errors) {
|
||||
if (songs_with_errors.isEmpty()) return;
|
||||
|
||||
OrganiseErrorDialog* dialog = new OrganiseErrorDialog(this);
|
||||
OrganiseErrorDialog *dialog = new OrganiseErrorDialog(this);
|
||||
dialog->Show(OrganiseErrorDialog::Type_Delete, songs_with_errors);
|
||||
// It deletes itself when the user closes it
|
||||
}
|
||||
@@ -1911,7 +1887,7 @@ void MainWindow::DeleteFinished(const SongList& songs_with_errors) {
|
||||
void MainWindow::PlaylistQueue() {
|
||||
|
||||
QModelIndexList indexes;
|
||||
for (const QModelIndex& proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
||||
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
||||
indexes << app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
|
||||
}
|
||||
|
||||
@@ -1936,7 +1912,7 @@ void MainWindow::PlaylistCopyToDevice() {
|
||||
QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||
SongList songs;
|
||||
|
||||
for (const QModelIndex& proxy_index : proxy_indexes) {
|
||||
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||
QModelIndex index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
|
||||
|
||||
songs << app_->playlist_manager()->current()->item_at(index.row())->Metadata();
|
||||
@@ -1953,7 +1929,7 @@ void MainWindow::PlaylistCopyToDevice() {
|
||||
}
|
||||
#endif
|
||||
|
||||
void MainWindow::ChangeCollectionQueryMode(QAction* action) {
|
||||
void MainWindow::ChangeCollectionQueryMode(QAction *action) {
|
||||
if (action == collection_show_duplicates_) {
|
||||
collection_view_->filter()->SetQueryMode(QueryOptions::QueryMode_Duplicates);
|
||||
}
|
||||
@@ -1979,9 +1955,9 @@ void MainWindow::ShowCoverManager() {
|
||||
|
||||
}
|
||||
|
||||
SettingsDialog* MainWindow::CreateSettingsDialog() {
|
||||
SettingsDialog *MainWindow::CreateSettingsDialog() {
|
||||
|
||||
SettingsDialog* settings_dialog = new SettingsDialog(app_);
|
||||
SettingsDialog *settings_dialog = new SettingsDialog(app_);
|
||||
settings_dialog->SetGlobalShortcutManager(global_shortcuts_);
|
||||
//settings_dialog->SetSongInfoView(song_info_view_);
|
||||
|
||||
@@ -2022,7 +1998,7 @@ void MainWindow::OpenSettingsDialogAtPage(SettingsDialog::Page page) {
|
||||
settings_dialog_->OpenAtPage(page);
|
||||
}
|
||||
|
||||
EditTagDialog* MainWindow::CreateEditTagDialog() {
|
||||
EditTagDialog *MainWindow::CreateEditTagDialog() {
|
||||
|
||||
EditTagDialog *edit_tag_dialog = new EditTagDialog(app_);
|
||||
connect(edit_tag_dialog, SIGNAL(accepted()), SLOT(EditTagDialogAccepted()));
|
||||
@@ -2062,7 +2038,7 @@ void MainWindow::ShowTranscodeDialog() {
|
||||
}
|
||||
#endif
|
||||
|
||||
void MainWindow::ShowErrorDialog(const QString& message) {
|
||||
void MainWindow::ShowErrorDialog(const QString &message) {
|
||||
//if (!error_dialog_) {
|
||||
// error_dialog_.reset(new ErrorDialog);
|
||||
//}
|
||||
@@ -2074,13 +2050,12 @@ void MainWindow::CheckFullRescanRevisions() {
|
||||
int from = app_->database()->startup_schema_version();
|
||||
int to = app_->database()->current_schema_version();
|
||||
|
||||
// if we're restoring DB from scratch or nothing has
|
||||
// changed, do nothing
|
||||
// if we're restoring DB from scratch or nothing has changed, do nothing
|
||||
if (from == 0 || from == to) {
|
||||
return;
|
||||
}
|
||||
|
||||
// collect all reasons
|
||||
// Collect all reasons
|
||||
QSet<QString> reasons;
|
||||
for (int i = from; i <= to; i++) {
|
||||
QString reason = app_->collection()->full_rescan_reason(i);
|
||||
@@ -2093,7 +2068,7 @@ void MainWindow::CheckFullRescanRevisions() {
|
||||
// if we have any...
|
||||
if (!reasons.isEmpty()) {
|
||||
QString message = tr("The version of Strawberry you've just updated to requires a full collection rescan because of the new features listed below:") + "<ul>";
|
||||
for(const QString& reason : reasons) {
|
||||
for(const QString &reason : reasons) {
|
||||
message += ("<li>" + reason + "</li>");
|
||||
}
|
||||
message += "</ul>" + tr("Would you like to run a full rescan right now?");
|
||||
@@ -2142,12 +2117,10 @@ void MainWindow::ShowSongInfoConfig() {
|
||||
|
||||
void MainWindow::PlaylistViewSelectionModelChanged() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
connect(ui_->playlist->view()->selectionModel(),SIGNAL(currentChanged(QModelIndex, QModelIndex)), SLOT(PlaylistCurrentChanged(QModelIndex)));
|
||||
}
|
||||
|
||||
void MainWindow::PlaylistCurrentChanged(const QModelIndex& proxy_current) {
|
||||
void MainWindow::PlaylistCurrentChanged(const QModelIndex &proxy_current) {
|
||||
const QModelIndex source_current =app_->playlist_manager()->current()->proxy()->mapToSource(proxy_current);
|
||||
|
||||
// If the user moves the current index using the keyboard and then presses
|
||||
@@ -2161,7 +2134,7 @@ void MainWindow::Raise() {
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
bool MainWindow::winEvent(MSG* msg, long*) {
|
||||
bool MainWindow::winEvent(MSG *msg, long*) {
|
||||
thumbbar_->HandleWinEvent(msg);
|
||||
return false;
|
||||
}
|
||||
@@ -2169,8 +2142,6 @@ bool MainWindow::winEvent(MSG* msg, long*) {
|
||||
|
||||
void MainWindow::Exit() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
SavePlaybackStatus();
|
||||
//settings_.setValue("show_sidebar", ui_->action_toggle_show_sidebar->isChecked());
|
||||
|
||||
@@ -2185,10 +2156,6 @@ void MainWindow::Exit() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_GSTREAMER
|
||||
//gst_deinit();
|
||||
#endif
|
||||
|
||||
qApp->quit();
|
||||
|
||||
}
|
||||
@@ -2212,7 +2179,7 @@ void MainWindow::AutoCompleteTags() {
|
||||
// Get the selected songs and start fetching tags for them
|
||||
SongList songs;
|
||||
autocomplete_tag_items_.clear();
|
||||
for (const QModelIndex& index : ui_->playlist->view()->selectionModel()->selection().indexes()) {
|
||||
for (const QModelIndex &index : ui_->playlist->view()->selectionModel()->selection().indexes()) {
|
||||
if (index.column() != 0) continue;
|
||||
int row = app_->playlist_manager()->current()->proxy()->mapToSource(index).row();
|
||||
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(row));
|
||||
@@ -2269,11 +2236,11 @@ void MainWindow::FocusCollectionTab() {
|
||||
}
|
||||
|
||||
void MainWindow::ShowConsole() {
|
||||
Console* console = new Console(app_, this);
|
||||
Console *console = new Console(app_, this);
|
||||
console->show();
|
||||
}
|
||||
|
||||
void MainWindow::keyPressEvent(QKeyEvent* event) {
|
||||
void MainWindow::keyPressEvent(QKeyEvent *event) {
|
||||
if (event->key() == Qt::Key_Space) {
|
||||
app_->player()->PlayPause();
|
||||
event->accept();
|
||||
|
||||
@@ -24,38 +24,43 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QMainWindow>
|
||||
#include <QSettings>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QAction>
|
||||
#include <QTimer>
|
||||
#include <QMenu>
|
||||
#include <QList>
|
||||
#include <QModelIndex>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QModelIndex>
|
||||
#include <QPersistentModelIndex>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QPoint>
|
||||
#include <QMimeData>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QPixmap>
|
||||
#include <QTimer>
|
||||
#include <QSettings>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "core/lazy.h"
|
||||
#include "core/mac_startup.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "engine/engine_fwd.h"
|
||||
#include "mac_startup.h"
|
||||
#include "widgets/osd.h"
|
||||
#include "collection/collectionmodel.h"
|
||||
#include "playlist/playlistitem.h"
|
||||
#ifdef HAVE_GSTREAMER
|
||||
#include "dialogs/organisedialog.h"
|
||||
#endif
|
||||
#include "settings/settingsdialog.h"
|
||||
|
||||
class StatusView;
|
||||
class About;
|
||||
class AlbumCoverManager;
|
||||
class Appearance;
|
||||
class AlbumCoverManager;;
|
||||
class Application;
|
||||
class ArtistInfoView;
|
||||
class CollectionViewContainer;
|
||||
class CommandlineOptions;
|
||||
class CoverProviders;
|
||||
class Database;
|
||||
class DeviceManager;
|
||||
class DeviceView;
|
||||
class DeviceViewContainer;
|
||||
class EditTagDialog;
|
||||
@@ -63,35 +68,26 @@ class Equalizer;
|
||||
class ErrorDialog;
|
||||
class FileView;
|
||||
class GlobalShortcuts;
|
||||
class GroupByDialog;
|
||||
class Collection;
|
||||
class CollectionViewContainer;
|
||||
class MimeData;
|
||||
class MultiLoadingIndicator;
|
||||
class OSD;
|
||||
class Player;
|
||||
class PlaylistBackend;
|
||||
class OrganiseDialog;
|
||||
class PlaylistListContainer;
|
||||
class PlaylistManager;
|
||||
class QueueManager;
|
||||
class Song;
|
||||
class StatusView;
|
||||
class SystemTrayIcon;
|
||||
class TagFetcher;
|
||||
class TaskManager;
|
||||
class TrackSelectionDialog;
|
||||
#ifdef HAVE_GSTREAMER
|
||||
class TranscodeDialog;
|
||||
#endif
|
||||
class Windows7ThumbBar;
|
||||
class Ui_MainWindow;
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
class Windows7ThumbBar;
|
||||
|
||||
class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(Application *app, SystemTrayIcon* tray_icon, OSD* osd, const CommandlineOptions& options, QWidget* parent = nullptr);
|
||||
MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, const CommandlineOptions& options, QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
static const char *kSettingsGroup;
|
||||
@@ -129,12 +125,12 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
void CommandlineOptionsReceived(const CommandlineOptions& options);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
void closeEvent(QCloseEvent* event);
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
bool winEvent(MSG* message, long* result);
|
||||
bool winEvent(MSG *message, long *result);
|
||||
#endif
|
||||
|
||||
// PlatformInterface
|
||||
@@ -174,7 +170,7 @@ signals:
|
||||
void AutoCompleteTags();
|
||||
void AutoCompleteTagsAccepted();
|
||||
#endif
|
||||
void PlaylistUndoRedoChanged(QAction* undo, QAction* redo);
|
||||
void PlaylistUndoRedoChanged(QAction *undo, QAction *redo);
|
||||
#ifdef HAVE_GSTREAMER
|
||||
void AddFilesToTranscoder();
|
||||
#endif
|
||||
@@ -189,7 +185,7 @@ signals:
|
||||
void PlaylistOpenInBrowser();
|
||||
void ShowInCollection();
|
||||
|
||||
void ChangeCollectionQueryMode(QAction* action);
|
||||
void ChangeCollectionQueryMode(QAction *action);
|
||||
|
||||
void PlayIndex(const QModelIndex& index);
|
||||
void PlaylistDoubleClick(const QModelIndex& index);
|
||||
@@ -205,8 +201,8 @@ signals:
|
||||
#endif
|
||||
void EditFileTags(const QList<QUrl>& urls);
|
||||
|
||||
void AddToPlaylist(QMimeData* data);
|
||||
void AddToPlaylist(QAction* action);
|
||||
void AddToPlaylist(QMimeData *data);
|
||||
void AddToPlaylist(QAction *action);
|
||||
|
||||
void VolumeWheelEvent(int delta);
|
||||
void ToggleShowHide();
|
||||
@@ -245,8 +241,8 @@ signals:
|
||||
void ShowQueueManager();
|
||||
void EnsureSettingsDialogCreated();
|
||||
void EnsureEditTagDialogCreated();
|
||||
SettingsDialog* CreateSettingsDialog();
|
||||
EditTagDialog* CreateEditTagDialog();
|
||||
SettingsDialog *CreateSettingsDialog();
|
||||
EditTagDialog *CreateEditTagDialog();
|
||||
void OpenSettingsDialog();
|
||||
void OpenSettingsDialogAtPage(SettingsDialog::Page page);
|
||||
|
||||
@@ -281,12 +277,12 @@ signals:
|
||||
Windows7ThumbBar *thumbbar_;
|
||||
|
||||
Application *app_;
|
||||
SystemTrayIcon * tray_icon_;
|
||||
OSD* osd_;
|
||||
SystemTrayIcon *tray_icon_;
|
||||
OSD *osd_;
|
||||
Lazy<EditTagDialog> edit_tag_dialog_;
|
||||
Lazy<About> about_dialog_;
|
||||
|
||||
GlobalShortcuts* global_shortcuts_;
|
||||
GlobalShortcuts *global_shortcuts_;
|
||||
|
||||
CollectionViewContainer *collection_view_;
|
||||
StatusView *status_view_;
|
||||
|
||||
@@ -20,21 +20,32 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "mergedproxymodel.h"
|
||||
#include "core/logging.h"
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
|
||||
#include <QObject>
|
||||
#include <QMimeData>
|
||||
#include <QStringList>
|
||||
#include <QtAlgorithms>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QAbstractProxyModel>
|
||||
|
||||
#include "mergedproxymodel.h"
|
||||
|
||||
// boost::multi_index still relies on these being in the global namespace.
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/detail/bidir_node_iterator.hpp>
|
||||
#include <boost/multi_index/detail/hash_index_iterator.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/identity.hpp>
|
||||
#include <boost/multi_index/indexed_by.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/tag.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
|
||||
using boost::multi_index::hashed_unique;
|
||||
using boost::multi_index::identity;
|
||||
@@ -44,12 +55,12 @@ using boost::multi_index::multi_index_container;
|
||||
using boost::multi_index::ordered_unique;
|
||||
using boost::multi_index::tag;
|
||||
|
||||
std::size_t hash_value(const QModelIndex& index) { return qHash(index); }
|
||||
std::size_t hash_value(const QModelIndex &index) { return qHash(index); }
|
||||
|
||||
namespace {
|
||||
|
||||
struct Mapping {
|
||||
explicit Mapping(const QModelIndex& _source_index) : source_index(_source_index) {}
|
||||
explicit Mapping(const QModelIndex &_source_index) : source_index(_source_index) {}
|
||||
|
||||
QModelIndex source_index;
|
||||
};
|
||||
@@ -73,7 +84,7 @@ class MergedProxyModelPrivate {
|
||||
MappingContainer mappings_;
|
||||
};
|
||||
|
||||
MergedProxyModel::MergedProxyModel(QObject* parent)
|
||||
MergedProxyModel::MergedProxyModel(QObject *parent)
|
||||
: QAbstractProxyModel(parent),
|
||||
resetting_model_(nullptr),
|
||||
p_(new MergedProxyModelPrivate) {}
|
||||
@@ -81,12 +92,12 @@ MergedProxyModel::MergedProxyModel(QObject* parent)
|
||||
MergedProxyModel::~MergedProxyModel() { DeleteAllMappings(); }
|
||||
|
||||
void MergedProxyModel::DeleteAllMappings() {
|
||||
const auto& begin = p_->mappings_.get<tag_by_pointer>().begin();
|
||||
const auto& end = p_->mappings_.get<tag_by_pointer>().end();
|
||||
const auto &begin = p_->mappings_.get<tag_by_pointer>().begin();
|
||||
const auto &end = p_->mappings_.get<tag_by_pointer>().end();
|
||||
qDeleteAll(begin, end);
|
||||
}
|
||||
|
||||
void MergedProxyModel::AddSubModel(const QModelIndex& source_parent, QAbstractItemModel* submodel) {
|
||||
void MergedProxyModel::AddSubModel(const QModelIndex &source_parent, QAbstractItemModel *submodel) {
|
||||
|
||||
connect(submodel, SIGNAL(modelReset()), this, SLOT(SubModelReset()));
|
||||
connect(submodel, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), this, SLOT(RowsAboutToBeInserted(QModelIndex, int, int)));
|
||||
@@ -105,13 +116,13 @@ void MergedProxyModel::AddSubModel(const QModelIndex& source_parent, QAbstractIt
|
||||
if (rows) endInsertRows();
|
||||
}
|
||||
|
||||
void MergedProxyModel::RemoveSubModel(const QModelIndex& source_parent) {
|
||||
void MergedProxyModel::RemoveSubModel(const QModelIndex &source_parent) {
|
||||
|
||||
// Find the submodel that the parent corresponded to
|
||||
QAbstractItemModel* submodel = merge_points_.key(source_parent);
|
||||
QAbstractItemModel *submodel = merge_points_.key(source_parent);
|
||||
merge_points_.remove(submodel);
|
||||
|
||||
// The submodel might have been deleted already so we must be careful not
|
||||
// to dereference it.
|
||||
// The submodel might have been deleted already so we must be careful not to dereference it.
|
||||
|
||||
// Remove all the children of the item that got deleted
|
||||
QModelIndex proxy_parent = mapFromSource(source_parent);
|
||||
@@ -129,13 +140,15 @@ void MergedProxyModel::RemoveSubModel(const QModelIndex& source_parent) {
|
||||
if ((*it)->source_index.model() == submodel) {
|
||||
delete *it;
|
||||
it = p_->mappings_.get<tag_by_pointer>().erase(it);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MergedProxyModel::setSourceModel(QAbstractItemModel* source_model) {
|
||||
void MergedProxyModel::setSourceModel(QAbstractItemModel *source_model) {
|
||||
|
||||
if (sourceModel()) {
|
||||
disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(SourceModelReset()));
|
||||
@@ -179,11 +192,10 @@ void MergedProxyModel::SourceModelReset() {
|
||||
|
||||
void MergedProxyModel::SubModelReset() {
|
||||
|
||||
QAbstractItemModel* submodel = static_cast<QAbstractItemModel*>(sender());
|
||||
QAbstractItemModel *submodel = static_cast<QAbstractItemModel*>(sender());
|
||||
|
||||
// TODO: When we require Qt 4.6, use beginResetModel() and endResetModel()
|
||||
// in CollectionModel and catch those here - that will let us do away with this
|
||||
// std::numeric_limits<int>::max() hack.
|
||||
// TODO: When we require Qt 4.6, use beginResetModel() and endResetModel() in CollectionModel and catch those here
|
||||
// that will let us do away with this std::numeric_limits<int>::max() hack.
|
||||
|
||||
// Remove all the children of the item that got deleted
|
||||
QModelIndex source_parent = merge_points_.value(submodel);
|
||||
@@ -202,7 +214,8 @@ void MergedProxyModel::SubModelReset() {
|
||||
if ((*it)->source_index.model() == submodel) {
|
||||
delete *it;
|
||||
it = p_->mappings_.get<tag_by_pointer>().erase(it);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
@@ -218,7 +231,7 @@ void MergedProxyModel::SubModelReset() {
|
||||
|
||||
}
|
||||
|
||||
QModelIndex MergedProxyModel::GetActualSourceParent(const QModelIndex& source_parent, QAbstractItemModel* model) const {
|
||||
QModelIndex MergedProxyModel::GetActualSourceParent(const QModelIndex &source_parent, QAbstractItemModel *model) const {
|
||||
|
||||
if (!source_parent.isValid() && model != sourceModel())
|
||||
return merge_points_.value(model);
|
||||
@@ -226,7 +239,7 @@ QModelIndex MergedProxyModel::GetActualSourceParent(const QModelIndex& source_pa
|
||||
|
||||
}
|
||||
|
||||
void MergedProxyModel::RowsAboutToBeInserted(const QModelIndex& source_parent, int start, int end) {
|
||||
void MergedProxyModel::RowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end) {
|
||||
beginInsertRows(mapFromSource(GetActualSourceParent(source_parent, static_cast<QAbstractItemModel*>(sender()))), start, end);
|
||||
}
|
||||
|
||||
@@ -234,7 +247,7 @@ void MergedProxyModel::RowsInserted(const QModelIndex&, int, int) {
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void MergedProxyModel::RowsAboutToBeRemoved(const QModelIndex& source_parent, int start, int end) {
|
||||
void MergedProxyModel::RowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end) {
|
||||
beginRemoveRows(mapFromSource(GetActualSourceParent(source_parent, static_cast<QAbstractItemModel*>(sender()))), start, end);
|
||||
}
|
||||
|
||||
@@ -242,13 +255,12 @@ void MergedProxyModel::RowsRemoved(const QModelIndex&, int, int) {
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
QModelIndex MergedProxyModel::mapToSource(const QModelIndex& proxy_index) const {
|
||||
QModelIndex MergedProxyModel::mapToSource(const QModelIndex &proxy_index) const {
|
||||
|
||||
if (!proxy_index.isValid()) return QModelIndex();
|
||||
|
||||
Mapping* mapping = static_cast<Mapping*>(proxy_index.internalPointer());
|
||||
if (p_->mappings_.get<tag_by_pointer>().find(mapping) ==
|
||||
p_->mappings_.get<tag_by_pointer>().end())
|
||||
Mapping *mapping = static_cast<Mapping*>(proxy_index.internalPointer());
|
||||
if (p_->mappings_.get<tag_by_pointer>().find(mapping) == p_->mappings_.get<tag_by_pointer>().end())
|
||||
return QModelIndex();
|
||||
if (mapping->source_index.model() == resetting_model_) return QModelIndex();
|
||||
|
||||
@@ -256,17 +268,18 @@ QModelIndex MergedProxyModel::mapToSource(const QModelIndex& proxy_index) const
|
||||
|
||||
}
|
||||
|
||||
QModelIndex MergedProxyModel::mapFromSource(const QModelIndex& source_index) const {
|
||||
QModelIndex MergedProxyModel::mapFromSource(const QModelIndex &source_index) const {
|
||||
|
||||
if (!source_index.isValid()) return QModelIndex();
|
||||
if (source_index.model() == resetting_model_) return QModelIndex();
|
||||
|
||||
// Add a mapping if we don't have one already
|
||||
const auto& it = p_->mappings_.get<tag_by_source>().find(source_index);
|
||||
Mapping* mapping;
|
||||
const auto &it = p_->mappings_.get<tag_by_source>().find(source_index);
|
||||
Mapping *mapping;
|
||||
if (it != p_->mappings_.get<tag_by_source>().end()) {
|
||||
mapping = *it;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
mapping = new Mapping(source_index);
|
||||
const_cast<MergedProxyModel*>(this)->p_->mappings_.insert(mapping);
|
||||
}
|
||||
@@ -284,7 +297,7 @@ QModelIndex MergedProxyModel::index(int row, int column, const QModelIndex &pare
|
||||
}
|
||||
else {
|
||||
QModelIndex source_parent = mapToSource(parent);
|
||||
const QAbstractItemModel* child_model = merge_points_.key(source_parent);
|
||||
const QAbstractItemModel *child_model = merge_points_.key(source_parent);
|
||||
|
||||
if (child_model)
|
||||
source_index = child_model->index(row, column, QModelIndex());
|
||||
@@ -296,7 +309,7 @@ QModelIndex MergedProxyModel::index(int row, int column, const QModelIndex &pare
|
||||
|
||||
}
|
||||
|
||||
QModelIndex MergedProxyModel::parent(const QModelIndex& child) const {
|
||||
QModelIndex MergedProxyModel::parent(const QModelIndex &child) const {
|
||||
|
||||
QModelIndex source_child = mapToSource(child);
|
||||
if (source_child.model() == sourceModel())
|
||||
@@ -310,17 +323,16 @@ QModelIndex MergedProxyModel::parent(const QModelIndex& child) const {
|
||||
|
||||
}
|
||||
|
||||
int MergedProxyModel::rowCount(const QModelIndex& parent) const {
|
||||
int MergedProxyModel::rowCount(const QModelIndex &parent) const {
|
||||
|
||||
if (!parent.isValid()) return sourceModel()->rowCount(QModelIndex());
|
||||
|
||||
QModelIndex source_parent = mapToSource(parent);
|
||||
if (!IsKnownModel(source_parent.model())) return 0;
|
||||
|
||||
const QAbstractItemModel* child_model = merge_points_.key(source_parent);
|
||||
const QAbstractItemModel *child_model = merge_points_.key(source_parent);
|
||||
if (child_model) {
|
||||
// Query the source model but disregard what it says, so it gets a chance
|
||||
// to lazy load
|
||||
// Query the source model but disregard what it says, so it gets a chance to lazy load
|
||||
source_parent.model()->rowCount(source_parent);
|
||||
|
||||
return child_model->rowCount(QModelIndex());
|
||||
@@ -330,34 +342,34 @@ int MergedProxyModel::rowCount(const QModelIndex& parent) const {
|
||||
|
||||
}
|
||||
|
||||
int MergedProxyModel::columnCount(const QModelIndex& parent) const {
|
||||
int MergedProxyModel::columnCount(const QModelIndex &parent) const {
|
||||
|
||||
if (!parent.isValid()) return sourceModel()->columnCount(QModelIndex());
|
||||
|
||||
QModelIndex source_parent = mapToSource(parent);
|
||||
if (!IsKnownModel(source_parent.model())) return 0;
|
||||
|
||||
const QAbstractItemModel* child_model = merge_points_.key(source_parent);
|
||||
const QAbstractItemModel *child_model = merge_points_.key(source_parent);
|
||||
if (child_model) return child_model->columnCount(QModelIndex());
|
||||
return source_parent.model()->columnCount(source_parent);
|
||||
|
||||
}
|
||||
|
||||
bool MergedProxyModel::hasChildren(const QModelIndex& parent) const {
|
||||
bool MergedProxyModel::hasChildren(const QModelIndex &parent) const {
|
||||
|
||||
if (!parent.isValid()) return sourceModel()->hasChildren(QModelIndex());
|
||||
|
||||
QModelIndex source_parent = mapToSource(parent);
|
||||
if (!IsKnownModel(source_parent.model())) return false;
|
||||
|
||||
const QAbstractItemModel* child_model = merge_points_.key(source_parent);
|
||||
const QAbstractItemModel *child_model = merge_points_.key(source_parent);
|
||||
|
||||
if (child_model) return child_model->hasChildren(QModelIndex()) || source_parent.model()->hasChildren(source_parent);
|
||||
return source_parent.model()->hasChildren(source_parent);
|
||||
|
||||
}
|
||||
|
||||
QVariant MergedProxyModel::data(const QModelIndex& proxyIndex, int role) const {
|
||||
QVariant MergedProxyModel::data(const QModelIndex &proxyIndex, int role) const {
|
||||
|
||||
QModelIndex source_index = mapToSource(proxyIndex);
|
||||
if (!IsKnownModel(source_index.model())) return QVariant();
|
||||
@@ -366,7 +378,7 @@ QVariant MergedProxyModel::data(const QModelIndex& proxyIndex, int role) const {
|
||||
|
||||
}
|
||||
|
||||
QMap<int, QVariant> MergedProxyModel::itemData(const QModelIndex& proxy_index) const {
|
||||
QMap<int, QVariant> MergedProxyModel::itemData(const QModelIndex &proxy_index) const {
|
||||
|
||||
QModelIndex source_index = mapToSource(proxy_index);
|
||||
|
||||
@@ -375,7 +387,7 @@ QMap<int, QVariant> MergedProxyModel::itemData(const QModelIndex& proxy_index) c
|
||||
|
||||
}
|
||||
|
||||
Qt::ItemFlags MergedProxyModel::flags(const QModelIndex& index) const {
|
||||
Qt::ItemFlags MergedProxyModel::flags(const QModelIndex &index) const {
|
||||
|
||||
QModelIndex source_index = mapToSource(index);
|
||||
|
||||
@@ -384,7 +396,7 @@ Qt::ItemFlags MergedProxyModel::flags(const QModelIndex& index) const {
|
||||
|
||||
}
|
||||
|
||||
bool MergedProxyModel::setData(const QModelIndex& index, const QVariant& value, int role) {
|
||||
bool MergedProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) {
|
||||
|
||||
QModelIndex source_index = mapToSource(index);
|
||||
|
||||
@@ -399,7 +411,7 @@ QStringList MergedProxyModel::mimeTypes() const {
|
||||
QStringList ret;
|
||||
ret << sourceModel()->mimeTypes();
|
||||
|
||||
for (const QAbstractItemModel* model : merge_points_.keys()) {
|
||||
for (const QAbstractItemModel *model : merge_points_.keys()) {
|
||||
ret << model->mimeTypes();
|
||||
}
|
||||
|
||||
@@ -407,12 +419,12 @@ QStringList MergedProxyModel::mimeTypes() const {
|
||||
|
||||
}
|
||||
|
||||
QMimeData* MergedProxyModel::mimeData(const QModelIndexList& indexes) const {
|
||||
QMimeData *MergedProxyModel::mimeData(const QModelIndexList &indexes) const {
|
||||
|
||||
if (indexes.isEmpty()) return 0;
|
||||
|
||||
// Only ask the first index's model
|
||||
const QAbstractItemModel* model = mapToSource(indexes[0]).model();
|
||||
const QAbstractItemModel *model = mapToSource(indexes[0]).model();
|
||||
if (!model) {
|
||||
return 0;
|
||||
}
|
||||
@@ -420,7 +432,7 @@ QMimeData* MergedProxyModel::mimeData(const QModelIndexList& indexes) const {
|
||||
// Only ask about the indexes that are actually in that model
|
||||
QModelIndexList indexes_in_model;
|
||||
|
||||
for (const QModelIndex& proxy_index : indexes) {
|
||||
for (const QModelIndex &proxy_index : indexes) {
|
||||
QModelIndex source_index = mapToSource(proxy_index);
|
||||
if (source_index.model() != model) continue;
|
||||
indexes_in_model << source_index;
|
||||
@@ -430,7 +442,7 @@ QMimeData* MergedProxyModel::mimeData(const QModelIndexList& indexes) const {
|
||||
|
||||
}
|
||||
|
||||
bool MergedProxyModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) {
|
||||
bool MergedProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) {
|
||||
|
||||
if (!parent.isValid()) {
|
||||
return false;
|
||||
@@ -440,7 +452,7 @@ bool MergedProxyModel::dropMimeData(const QMimeData* data, Qt::DropAction action
|
||||
|
||||
}
|
||||
|
||||
QModelIndex MergedProxyModel::FindSourceParent(const QModelIndex& proxy_index) const {
|
||||
QModelIndex MergedProxyModel::FindSourceParent(const QModelIndex &proxy_index) const {
|
||||
|
||||
if (!proxy_index.isValid()) return QModelIndex();
|
||||
|
||||
@@ -450,7 +462,7 @@ QModelIndex MergedProxyModel::FindSourceParent(const QModelIndex& proxy_index) c
|
||||
|
||||
}
|
||||
|
||||
bool MergedProxyModel::canFetchMore(const QModelIndex& parent) const {
|
||||
bool MergedProxyModel::canFetchMore(const QModelIndex &parent) const {
|
||||
|
||||
QModelIndex source_index = mapToSource(parent);
|
||||
|
||||
@@ -460,7 +472,7 @@ bool MergedProxyModel::canFetchMore(const QModelIndex& parent) const {
|
||||
|
||||
}
|
||||
|
||||
void MergedProxyModel::fetchMore(const QModelIndex& parent) {
|
||||
void MergedProxyModel::fetchMore(const QModelIndex &parent) {
|
||||
|
||||
QModelIndex source_index = mapToSource(parent);
|
||||
|
||||
@@ -471,27 +483,26 @@ void MergedProxyModel::fetchMore(const QModelIndex& parent) {
|
||||
|
||||
}
|
||||
|
||||
QAbstractItemModel* MergedProxyModel::GetModel(const QModelIndex& source_index) const {
|
||||
QAbstractItemModel *MergedProxyModel::GetModel(const QModelIndex &source_index) const {
|
||||
|
||||
// This is essentially const_cast<QAbstractItemModel*>(source_index.model()),
|
||||
// but without the const_cast
|
||||
const QAbstractItemModel* const_model = source_index.model();
|
||||
// This is essentially const_cast<QAbstractItemModel*>(source_index.model()), but without the const_cast
|
||||
const QAbstractItemModel *const_model = source_index.model();
|
||||
if (const_model == sourceModel()) return sourceModel();
|
||||
for (QAbstractItemModel* submodel : merge_points_.keys()) {
|
||||
for (QAbstractItemModel *submodel : merge_points_.keys()) {
|
||||
if (submodel == const_model) return submodel;
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
void MergedProxyModel::DataChanged(const QModelIndex& top_left, const QModelIndex& bottom_right) {
|
||||
void MergedProxyModel::DataChanged(const QModelIndex &top_left, const QModelIndex &bottom_right) {
|
||||
emit dataChanged(mapFromSource(top_left), mapFromSource(bottom_right));
|
||||
}
|
||||
|
||||
void MergedProxyModel::LayoutAboutToBeChanged() {
|
||||
|
||||
old_merge_points_.clear();
|
||||
for (QAbstractItemModel* key : merge_points_.keys()) {
|
||||
for (QAbstractItemModel *key : merge_points_.keys()) {
|
||||
old_merge_points_[key] = merge_points_.value(key);
|
||||
}
|
||||
|
||||
@@ -499,7 +510,7 @@ void MergedProxyModel::LayoutAboutToBeChanged() {
|
||||
|
||||
void MergedProxyModel::LayoutChanged() {
|
||||
|
||||
for (QAbstractItemModel* key : merge_points_.keys()) {
|
||||
for (QAbstractItemModel *key : merge_points_.keys()) {
|
||||
if (!old_merge_points_.contains(key)) continue;
|
||||
|
||||
const int old_row = old_merge_points_[key].row();
|
||||
@@ -514,29 +525,28 @@ void MergedProxyModel::LayoutChanged() {
|
||||
|
||||
}
|
||||
|
||||
bool MergedProxyModel::IsKnownModel(const QAbstractItemModel* model) const {
|
||||
bool MergedProxyModel::IsKnownModel(const QAbstractItemModel *model) const {
|
||||
|
||||
if (model == this || model == sourceModel() ||
|
||||
merge_points_.contains(const_cast<QAbstractItemModel*>(model)))
|
||||
if (model == this || model == sourceModel() || merge_points_.contains(const_cast<QAbstractItemModel*>(model)))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
QModelIndexList MergedProxyModel::mapFromSource(const QModelIndexList& source_indexes) const {
|
||||
QModelIndexList MergedProxyModel::mapFromSource(const QModelIndexList &source_indexes) const {
|
||||
|
||||
QModelIndexList ret;
|
||||
for (const QModelIndex& index : source_indexes) {
|
||||
for (const QModelIndex &index : source_indexes) {
|
||||
ret << mapFromSource(index);
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
QModelIndexList MergedProxyModel::mapToSource(const QModelIndexList& proxy_indexes) const {
|
||||
QModelIndexList MergedProxyModel::mapToSource(const QModelIndexList &proxy_indexes) const {
|
||||
|
||||
QModelIndexList ret;
|
||||
for (const QModelIndex& index : proxy_indexes) {
|
||||
for (const QModelIndex &index : proxy_indexes) {
|
||||
ret << mapToSource(index);
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -24,10 +24,21 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <cstddef>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QMimeData>
|
||||
#include <QModelIndex>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QAbstractProxyModel>
|
||||
#include <QPersistentModelIndex>
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
std::size_t hash_value(const QModelIndex& index);
|
||||
std::size_t hash_value(const QModelIndex &index);
|
||||
|
||||
class MergedProxyModelPrivate;
|
||||
|
||||
@@ -35,71 +46,68 @@ class MergedProxyModel : public QAbstractProxyModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MergedProxyModel(QObject* parent = nullptr);
|
||||
explicit MergedProxyModel(QObject *parent = nullptr);
|
||||
~MergedProxyModel();
|
||||
|
||||
// Make another model appear as a child of the given item in the source model.
|
||||
void AddSubModel(const QModelIndex& source_parent, QAbstractItemModel* submodel);
|
||||
void RemoveSubModel(const QModelIndex& source_parent);
|
||||
void AddSubModel(const QModelIndex &source_parent, QAbstractItemModel *submodel);
|
||||
void RemoveSubModel(const QModelIndex &source_parent);
|
||||
|
||||
// Find the item in the source model that is the parent of the model
|
||||
// containing proxy_index. If proxy_index is in the source model, then
|
||||
// this just returns mapToSource(proxy_index).
|
||||
QModelIndex FindSourceParent(const QModelIndex& proxy_index) const;
|
||||
// Find the item in the source model that is the parent of the model containing proxy_index.
|
||||
// If proxy_index is in the source model, then this just returns mapToSource(proxy_index).
|
||||
QModelIndex FindSourceParent(const QModelIndex &proxy_index) const;
|
||||
|
||||
// QAbstractItemModel
|
||||
QModelIndex index(int row, int column, const QModelIndex& parent) const;
|
||||
QModelIndex parent(const QModelIndex& child) const;
|
||||
int rowCount(const QModelIndex& parent) const;
|
||||
int columnCount(const QModelIndex& parent) const;
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const;
|
||||
QModelIndex parent(const QModelIndex &child) const;
|
||||
int rowCount(const QModelIndex &parent) const;
|
||||
int columnCount(const QModelIndex &parent) const;
|
||||
QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const;
|
||||
bool hasChildren(const QModelIndex& parent) const;
|
||||
QMap<int, QVariant> itemData(const QModelIndex& proxyIndex) const;
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||
bool setData(const QModelIndex& index, const QVariant& value, int role);
|
||||
bool hasChildren(const QModelIndex &parent) const;
|
||||
QMap<int, QVariant> itemData(const QModelIndex &proxyIndex) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role);
|
||||
QStringList mimeTypes() const;
|
||||
QMimeData* mimeData(const QModelIndexList& indexes) const;
|
||||
bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent);
|
||||
bool canFetchMore(const QModelIndex& parent) const;
|
||||
void fetchMore(const QModelIndex& parent);
|
||||
QMimeData *mimeData(const QModelIndexList &indexes) const;
|
||||
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
|
||||
bool canFetchMore(const QModelIndex &parent) const;
|
||||
void fetchMore(const QModelIndex &parent);
|
||||
|
||||
// QAbstractProxyModel
|
||||
// Note that these implementations of map{To,From}Source will not always
|
||||
// give you an index in sourceModel(), you might get an index in one of the
|
||||
// child models instead.
|
||||
QModelIndex mapFromSource(const QModelIndex& sourceIndex) const;
|
||||
QModelIndex mapToSource(const QModelIndex& proxyIndex) const;
|
||||
void setSourceModel(QAbstractItemModel* sourceModel);
|
||||
// Note that these implementations of map{To,From}Source will not always give you an index in sourceModel(),
|
||||
// you might get an index in one of the child models instead.
|
||||
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
|
||||
QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
|
||||
void setSourceModel(QAbstractItemModel *sourceModel);
|
||||
|
||||
// Convenience functions that call map{To,From}Source multiple times.
|
||||
QModelIndexList mapFromSource(const QModelIndexList& source_indexes) const;
|
||||
QModelIndexList mapToSource(const QModelIndexList& proxy_indexes) const;
|
||||
QModelIndexList mapFromSource(const QModelIndexList &source_indexes) const;
|
||||
QModelIndexList mapToSource(const QModelIndexList &proxy_indexes) const;
|
||||
|
||||
signals:
|
||||
void SubModelReset(const QModelIndex& root, QAbstractItemModel* model);
|
||||
void SubModelReset(const QModelIndex &root, QAbstractItemModel *model);
|
||||
|
||||
private slots:
|
||||
void SourceModelReset();
|
||||
void SubModelReset();
|
||||
|
||||
void RowsAboutToBeInserted(const QModelIndex& source_parent, int start, int end);
|
||||
void RowsInserted(const QModelIndex& source_parent, int start, int end);
|
||||
void RowsAboutToBeRemoved(const QModelIndex& source_parent, int start, int end);
|
||||
void RowsRemoved(const QModelIndex& source_parent, int start, int end);
|
||||
void DataChanged(const QModelIndex& top_left, const QModelIndex& bottom_right);
|
||||
void RowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end);
|
||||
void RowsInserted(const QModelIndex &source_parent, int start, int end);
|
||||
void RowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end);
|
||||
void RowsRemoved(const QModelIndex &source_parent, int start, int end);
|
||||
void DataChanged(const QModelIndex &top_left, const QModelIndex &bottom_right);
|
||||
|
||||
void LayoutAboutToBeChanged();
|
||||
void LayoutChanged();
|
||||
|
||||
private:
|
||||
QModelIndex GetActualSourceParent(const QModelIndex& source_parent,
|
||||
QAbstractItemModel* model) const;
|
||||
QAbstractItemModel* GetModel(const QModelIndex& source_index) const;
|
||||
QModelIndex GetActualSourceParent(const QModelIndex &source_parent, QAbstractItemModel *model) const;
|
||||
QAbstractItemModel *GetModel(const QModelIndex &source_index) const;
|
||||
void DeleteAllMappings();
|
||||
bool IsKnownModel(const QAbstractItemModel* model) const;
|
||||
bool IsKnownModel(const QAbstractItemModel *model) const;
|
||||
|
||||
QMap<QAbstractItemModel*, QPersistentModelIndex> merge_points_;
|
||||
QAbstractItemModel* resetting_model_;
|
||||
QAbstractItemModel *resetting_model_;
|
||||
|
||||
QMap<QAbstractItemModel*, QModelIndex> old_merge_points_;
|
||||
|
||||
|
||||
@@ -18,48 +18,70 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "metatypes.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkCookie>
|
||||
|
||||
#include "metatypes.h"
|
||||
|
||||
#ifdef HAVE_GSTREAMER
|
||||
# include <gst/gstbuffer.h>
|
||||
# include <gst/gstelement.h>
|
||||
#endif
|
||||
|
||||
#include <QAbstractSocket>
|
||||
#include <QMetaType>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QByteArray>
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QNetworkCookie>
|
||||
#include <QNetworkReply>
|
||||
#ifdef HAVE_DBUS
|
||||
# include <QDBusMetaType>
|
||||
#endif
|
||||
|
||||
#include "song.h"
|
||||
|
||||
#include "engine/engine_fwd.h"
|
||||
#include "engine/enginebase.h"
|
||||
#include "engine/enginetype.h"
|
||||
#ifdef HAVE_GSTREAMER
|
||||
# include "engine/gstengine.h"
|
||||
# include "engine/gstenginepipeline.h"
|
||||
#endif
|
||||
#include "collection/directory.h"
|
||||
#include "playlist/playlist.h"
|
||||
#include "equalizer/equalizer.h"
|
||||
#include "playlist/playlistitem.h"
|
||||
#include "playlist/playlistsequence.h"
|
||||
#include "covermanager/albumcoverfetcher.h"
|
||||
#include "equalizer/equalizer.h"
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
#include <QDBusMetaType>
|
||||
#include "core/mpris2.h"
|
||||
#include "dbus/metatypes.h"
|
||||
#endif
|
||||
|
||||
class QNetworkReply;
|
||||
#ifdef HAVE_GSTREAMER
|
||||
class GstEnginePipeline;
|
||||
# include "mpris2.h"
|
||||
# include "dbus/metatypes.h"
|
||||
#endif
|
||||
|
||||
void RegisterMetaTypes() {
|
||||
//qRegisterMetaType<CollapsibleInfoPane::Data>("CollapsibleInfoPane::Data");
|
||||
|
||||
qRegisterMetaType<const char*>("const char*");
|
||||
qRegisterMetaType<CoverSearchResult>("CoverSearchResult");
|
||||
qRegisterMetaType<CoverSearchResults>("CoverSearchResults");
|
||||
qRegisterMetaType<QList<int>>("QList<int>");
|
||||
qRegisterMetaType<QList<QUrl>>("QList<QUrl>");
|
||||
qRegisterMetaType<QAbstractSocket::SocketState>();
|
||||
qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState");
|
||||
qRegisterMetaType<QNetworkCookie>("QNetworkCookie");
|
||||
qRegisterMetaType<QList<QNetworkCookie> >("QList<QNetworkCookie>");
|
||||
qRegisterMetaType<QNetworkReply*>("QNetworkReply*");
|
||||
qRegisterMetaType<QNetworkReply**>("QNetworkReply**");
|
||||
qRegisterMetaTypeStreamOperators<QMap<int, int> >("ColumnAlignmentMap");
|
||||
qRegisterMetaType<Directory>("Directory");
|
||||
qRegisterMetaType<DirectoryList>("DirectoryList");
|
||||
qRegisterMetaType<Subdirectory>("Subdirectory");
|
||||
qRegisterMetaType<SubdirectoryList>("SubdirectoryList");
|
||||
qRegisterMetaType<Song>("Song");
|
||||
qRegisterMetaType<QList<Song> >("QList<Song>");
|
||||
qRegisterMetaType<SongList>("SongList");
|
||||
qRegisterMetaType<Engine::EngineType>("EngineType");
|
||||
qRegisterMetaType<Engine::SimpleMetaBundle>("Engine::SimpleMetaBundle");
|
||||
qRegisterMetaType<Engine::State>("Engine::State");
|
||||
qRegisterMetaType<Engine::TrackChangeFlags>("Engine::TrackChangeFlags");
|
||||
qRegisterMetaType<Equalizer::Params>("Equalizer::Params");
|
||||
qRegisterMetaType<EngineBase::OutputDetails>("EngineBase::OutputDetails");
|
||||
#ifdef HAVE_GSTREAMER
|
||||
qRegisterMetaType<GstBuffer*>("GstBuffer*");
|
||||
@@ -68,36 +90,22 @@ void RegisterMetaTypes() {
|
||||
#endif
|
||||
qRegisterMetaType<PlaylistItemList>("PlaylistItemList");
|
||||
qRegisterMetaType<PlaylistItemPtr>("PlaylistItemPtr");
|
||||
qRegisterMetaType<QList<CoverSearchResult> >("QList<CoverSearchResult>");
|
||||
qRegisterMetaType<QList<int>>("QList<int>");
|
||||
qRegisterMetaType<QList<PlaylistItemPtr> >("QList<PlaylistItemPtr>");
|
||||
qRegisterMetaType<PlaylistSequence::RepeatMode>("PlaylistSequence::RepeatMode");
|
||||
qRegisterMetaType<PlaylistSequence::ShuffleMode>("PlaylistSequence::ShuffleMode");
|
||||
qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState");
|
||||
qRegisterMetaType<QList<QNetworkCookie> >("QList<QNetworkCookie>");
|
||||
qRegisterMetaType<QList<Song> >("QList<Song>");
|
||||
qRegisterMetaType<QNetworkCookie>("QNetworkCookie");
|
||||
qRegisterMetaType<QNetworkReply*>("QNetworkReply*");
|
||||
qRegisterMetaType<QNetworkReply**>("QNetworkReply**");
|
||||
qRegisterMetaType<SongList>("SongList");
|
||||
qRegisterMetaType<Song>("Song");
|
||||
qRegisterMetaType<CoverSearchResult>("CoverSearchResult");
|
||||
qRegisterMetaType<QList<CoverSearchResult> >("QList<CoverSearchResult>");
|
||||
qRegisterMetaType<CoverSearchResults>("CoverSearchResults");
|
||||
qRegisterMetaType<Equalizer::Params>("Equalizer::Params");
|
||||
qRegisterMetaTypeStreamOperators<Equalizer::Params>("Equalizer::Params");
|
||||
qRegisterMetaTypeStreamOperators<QMap<int, int> >("ColumnAlignmentMap");
|
||||
qRegisterMetaType<SubdirectoryList>("SubdirectoryList");
|
||||
qRegisterMetaType<Subdirectory>("Subdirectory");
|
||||
qRegisterMetaType<QList<QUrl>>("QList<QUrl>");
|
||||
qRegisterMetaType<QAbstractSocket::SocketState>();
|
||||
|
||||
qRegisterMetaType<Engine::EngineType>("EngineType");
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
qDBusRegisterMetaType<QList<QByteArray>>();
|
||||
qDBusRegisterMetaType<QImage>();
|
||||
qDBusRegisterMetaType<TrackMetadata>();
|
||||
qDBusRegisterMetaType<TrackIds>();
|
||||
qDBusRegisterMetaType<QList<QByteArray>>();
|
||||
qDBusRegisterMetaType<MprisPlaylist>();
|
||||
qDBusRegisterMetaType<MaybePlaylist>();
|
||||
qDBusRegisterMetaType<MprisPlaylistList>();
|
||||
qDBusRegisterMetaType<MaybePlaylist>();
|
||||
qDBusRegisterMetaType<InterfacesAndProperties>();
|
||||
qDBusRegisterMetaType<ManagedObjectList>();
|
||||
#endif
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QMimeData>
|
||||
#include <QString>
|
||||
|
||||
class MimeData : public QMimeData {
|
||||
Q_OBJECT
|
||||
@@ -41,13 +43,11 @@ class MimeData : public QMimeData {
|
||||
// If this is set then MainWindow will not touch any of the other flags.
|
||||
bool override_user_settings_;
|
||||
|
||||
// If this is set then the playlist will be cleared before these songs
|
||||
// are inserted.
|
||||
// If this is set then the playlist will be cleared before these songs are inserted.
|
||||
bool clear_first_;
|
||||
|
||||
// If this is set then the first item that is inserted will start playing
|
||||
// immediately. Note: this is always overridden with the user's preference
|
||||
// if the MimeData goes via MainWindow, unless you set override_user_settings_.
|
||||
// If this is set then the first item that is inserted will start playing immediately.
|
||||
// Note: this is always overridden with the user's preference if the MimeData goes via MainWindow, unless you set override_user_settings_.
|
||||
bool play_now_;
|
||||
|
||||
// If this is set then the items are added to the queue after being inserted.
|
||||
@@ -59,14 +59,12 @@ class MimeData : public QMimeData {
|
||||
// This serves as a name for the new playlist in 'open_in_new_playlist_' mode.
|
||||
QString name_for_new_playlist_;
|
||||
|
||||
// This can be set if this MimeData goes via MainWindow (ie. it is created
|
||||
// manually in a double-click). The MainWindow will set the above flags to
|
||||
// the defaults set by the user.
|
||||
// This can be set if this MimeData goes via MainWindow (ie. it is created manually in a double-click).
|
||||
// The MainWindow will set the above flags to the defaults set by the user.
|
||||
bool from_doubleclick_;
|
||||
|
||||
// Returns a pretty name for a playlist containing songs described by this MimeData
|
||||
// object. By pretty name we mean the value of 'name_for_new_playlist_' or generic
|
||||
// "Playlist" string if the 'name_for_new_playlist_' attribute is empty.
|
||||
// Returns a pretty name for a playlist containing songs described by this MimeData object.
|
||||
// By pretty name we mean the value of 'name_for_new_playlist_' or generic "Playlist" string if the 'name_for_new_playlist_' attribute is empty.
|
||||
QString get_name_for_new_playlist() {
|
||||
return name_for_new_playlist_.isEmpty() ? tr("Playlist") : name_for_new_playlist_;
|
||||
}
|
||||
|
||||
@@ -18,15 +18,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "mpris.h"
|
||||
#include "mpris2.h"
|
||||
|
||||
namespace mpris {
|
||||
|
||||
Mpris::Mpris(Application* app, QObject* parent) : QObject(parent), mpris2_(new mpris::Mpris2(app, this)) {
|
||||
Mpris::Mpris(Application *app, QObject *parent) : QObject(parent), mpris2_(new mpris::Mpris2(app, this)) {
|
||||
connect(mpris2_, SIGNAL(RaiseMainWindow()), SIGNAL(RaiseMainWindow()));
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class Application;
|
||||
|
||||
|
||||
@@ -20,30 +20,48 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCoreApplication>
|
||||
#include <QObject>
|
||||
#include <QFile>
|
||||
#include <QList>
|
||||
#include <QJsonArray>
|
||||
#include <QVariant>
|
||||
#include <QVariantMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QDBusConnection>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusArgument>
|
||||
#include <QDBusObjectPath>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/logging.h"
|
||||
|
||||
#include "mpris_common.h"
|
||||
#include "mpris2.h"
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/mainwindow.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/mpris_common.h"
|
||||
#include "core/mpris2_player.h"
|
||||
#include "core/mpris2_playlists.h"
|
||||
#include "core/mpris2_root.h"
|
||||
#include "core/mpris2_tracklist.h"
|
||||
#include "core/player.h"
|
||||
#include "core/timeconstants.h"
|
||||
#include "timeconstants.h"
|
||||
#include "song.h"
|
||||
#include "application.h"
|
||||
#include "player.h"
|
||||
#include "engine/enginebase.h"
|
||||
#include "playlist/playlist.h"
|
||||
#include "playlist/playlistitem.h"
|
||||
#include "playlist/playlistmanager.h"
|
||||
#include "playlist/playlistsequence.h"
|
||||
#include "covermanager/currentartloader.h"
|
||||
|
||||
#include <core/mpris2_player.h>
|
||||
#include <core/mpris2_playlists.h>
|
||||
#include <core/mpris2_root.h>
|
||||
#include <core/mpris2_tracklist.h>
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument &arg, const MprisPlaylist &playlist) {
|
||||
arg.beginStructure();
|
||||
arg << playlist.id << playlist.name << playlist.icon;
|
||||
@@ -75,11 +93,11 @@ const QDBusArgument &operator>> (const QDBusArgument &arg, MaybePlaylist &playli
|
||||
|
||||
namespace mpris {
|
||||
|
||||
const char* Mpris2::kMprisObjectPath = "/org/mpris/MediaPlayer2";
|
||||
const char* Mpris2::kServiceName = "org.mpris.MediaPlayer2.strawberry";
|
||||
const char* Mpris2::kFreedesktopPath = "org.freedesktop.DBus.Properties";
|
||||
const char *Mpris2::kMprisObjectPath = "/org/mpris/MediaPlayer2";
|
||||
const char *Mpris2::kServiceName = "org.mpris.MediaPlayer2.strawberry";
|
||||
const char *Mpris2::kFreedesktopPath = "org.freedesktop.DBus.Properties";
|
||||
|
||||
Mpris2::Mpris2(Application* app, QObject* parent) : QObject(parent), app_(app) {
|
||||
Mpris2::Mpris2(Application *app, QObject *parent) : QObject(parent), app_(app) {
|
||||
|
||||
new Mpris2Root(this);
|
||||
new Mpris2TrackList(this);
|
||||
@@ -184,8 +202,7 @@ QString Mpris2::DesktopEntryAbsolutePath() const {
|
||||
xdg_data_dirs.append("/usr/share/");
|
||||
|
||||
for (const QString &directory : xdg_data_dirs) {
|
||||
QString path = QString("%1/applications/%2.desktop").arg(
|
||||
directory, QApplication::applicationName().toLower());
|
||||
QString path = QString("%1/applications/%2.desktop").arg(directory, QApplication::applicationName().toLower());
|
||||
if (QFile::exists(path)) return path;
|
||||
}
|
||||
return QString();
|
||||
@@ -276,9 +293,11 @@ void Mpris2::SetLoopStatus(const QString &value) {
|
||||
|
||||
if (value == "None") {
|
||||
mode = PlaylistSequence::Repeat_Off;
|
||||
} else if (value == "Track") {
|
||||
}
|
||||
else if (value == "Track") {
|
||||
mode = PlaylistSequence::Repeat_Track;
|
||||
} else if (value == "Playlist") {
|
||||
}
|
||||
else if (value == "Playlist") {
|
||||
mode = PlaylistSequence::Repeat_Playlist;
|
||||
}
|
||||
|
||||
@@ -312,8 +331,7 @@ QString Mpris2::current_track_id() const {
|
||||
return QString("/org/strawberry/strawberrymusicplayer/Track/%1").arg(QString::number(app_->playlist_manager()->active()->current_row()));
|
||||
}
|
||||
|
||||
// We send Metadata change notification as soon as the process of
|
||||
// changing song starts...
|
||||
// We send Metadata change notification as soon as the process of changing song starts...
|
||||
void Mpris2::CurrentSongChanged(const Song &song) {
|
||||
|
||||
ArtLoaded(song, "");
|
||||
@@ -367,8 +385,7 @@ bool Mpris2::CanPlay() const {
|
||||
return app_->playlist_manager()->active() && app_->playlist_manager()->active()->rowCount() != 0 && !(app_->player()->GetState() == Engine::Playing);
|
||||
}
|
||||
|
||||
// This one's a bit different than MPRIS 1 - we want this to be true even when
|
||||
// the song is already paused or stopped.
|
||||
// This one's a bit different than MPRIS 1 - we want this to be true even when the song is already paused or stopped.
|
||||
bool Mpris2::CanPause() const {
|
||||
return (app_->player()->GetCurrentItem() && app_->player()->GetState() == Engine::Playing && !(app_->player()->GetCurrentItem()->options() & PlaylistItem::PauseDisabled)) || PlaybackStatus() == "Paused" || PlaybackStatus() == "Stopped";
|
||||
}
|
||||
@@ -474,7 +491,7 @@ QDBusObjectPath MakePlaylistPath(int id) {
|
||||
MaybePlaylist Mpris2::ActivePlaylist() const {
|
||||
|
||||
MaybePlaylist maybe_playlist;
|
||||
Playlist* current_playlist = app_->playlist_manager()->current();
|
||||
Playlist *current_playlist = app_->playlist_manager()->current();
|
||||
maybe_playlist.valid = current_playlist;
|
||||
if (!current_playlist) {
|
||||
return maybe_playlist;
|
||||
@@ -511,7 +528,7 @@ void Mpris2::ActivatePlaylist(const QDBusObjectPath &playlist_id) {
|
||||
MprisPlaylistList Mpris2::GetPlaylists(quint32 index, quint32 max_count, const QString &order, bool reverse_order) {
|
||||
|
||||
MprisPlaylistList ret;
|
||||
for (Playlist* p : app_->playlist_manager()->GetAllPlaylists()) {
|
||||
for (Playlist *p : app_->playlist_manager()->GetAllPlaylists()) {
|
||||
MprisPlaylist mpris_playlist;
|
||||
mpris_playlist.id = MakePlaylistPath(p->id());
|
||||
mpris_playlist.name = app_->playlist_manager()->GetPlaylistName(p->id());
|
||||
@@ -526,7 +543,7 @@ MprisPlaylistList Mpris2::GetPlaylists(quint32 index, quint32 max_count, const Q
|
||||
|
||||
}
|
||||
|
||||
void Mpris2::PlaylistChanged(Playlist* playlist) {
|
||||
void Mpris2::PlaylistChanged(Playlist *playlist) {
|
||||
|
||||
MprisPlaylist mpris_playlist;
|
||||
mpris_playlist.id = MakePlaylistPath(playlist->id());
|
||||
@@ -535,9 +552,8 @@ void Mpris2::PlaylistChanged(Playlist* playlist) {
|
||||
|
||||
}
|
||||
|
||||
void Mpris2::PlaylistCollectionChanged(Playlist* playlist) {
|
||||
void Mpris2::PlaylistCollectionChanged(Playlist *playlist) {
|
||||
EmitNotification("PlaylistCount", "", "org.mpris.MediaPlayer2.Playlists");
|
||||
}
|
||||
|
||||
} // namespace mpris
|
||||
|
||||
|
||||
@@ -23,14 +23,28 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlist/playlistitem.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QMetaObject>
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QMetaType>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QImage>
|
||||
#include <QVector>
|
||||
#include <QtDBus>
|
||||
#include <QDBusArgument>
|
||||
#include <qdbusextratypes.h>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "engine/engine_fwd.h"
|
||||
|
||||
class Application;
|
||||
class MainWindow;
|
||||
class Song;
|
||||
class Playlist;
|
||||
|
||||
typedef QList<QVariantMap> TrackMetadata;
|
||||
|
||||
@@ -23,10 +23,11 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QVariantMap>
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
namespace mpris {
|
||||
|
||||
|
||||
@@ -20,12 +20,16 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "multisortfilterproxy.h"
|
||||
#include "core/logging.h"
|
||||
|
||||
#include <QDate>
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QModelIndex>
|
||||
#include <QMetaType>
|
||||
#include <QDateTime>
|
||||
#include <QTime>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
|
||||
#include "multisortfilterproxy.h"
|
||||
|
||||
MultiSortFilterProxy::MultiSortFilterProxy(QObject *parent)
|
||||
: QSortFilterProxyModel(parent) {}
|
||||
@@ -62,8 +66,7 @@ static inline int DoCompare(T left, T right) {
|
||||
|
||||
int MultiSortFilterProxy::Compare(const QVariant &left, const QVariant &right) const {
|
||||
|
||||
// Copied from the QSortFilterProxyModel::lessThan implementation, but returns
|
||||
// -1, 0 or 1 instead of true or false.
|
||||
// Copied from the QSortFilterProxyModel::lessThan implementation, but returns -1, 0 or 1 instead of true or false.
|
||||
switch (left.userType()) {
|
||||
case QVariant::Invalid: return (right.type() != QVariant::Invalid) ? -1 : 0;
|
||||
case QVariant::Int: return DoCompare(left.toInt(), right.toInt());
|
||||
|
||||
@@ -23,7 +23,14 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QModelIndex>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QPair>
|
||||
|
||||
class MultiSortFilterProxy : public QSortFilterProxyModel {
|
||||
public:
|
||||
|
||||
@@ -18,11 +18,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "musicstorage.h"
|
||||
|
||||
MusicStorage::MusicStorage()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -23,12 +23,15 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "song.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
|
||||
#include "song.h"
|
||||
|
||||
class MusicStorage {
|
||||
public:
|
||||
|
||||
@@ -20,17 +20,23 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "network.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QCoreApplication>
|
||||
#include <QObject>
|
||||
#include <QStandardPaths>
|
||||
#include <QDir>
|
||||
#include <QMutex>
|
||||
#include <QIODevice>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QNetworkCacheMetaData>
|
||||
#include <QAbstractNetworkCache>
|
||||
|
||||
#include "core/closure.h"
|
||||
#include "core/logging.h"
|
||||
#include "network.h"
|
||||
|
||||
QMutex ThreadSafeNetworkDiskCache::sMutex;
|
||||
QNetworkDiskCache *ThreadSafeNetworkDiskCache::sCache = nullptr;
|
||||
|
||||
@@ -23,12 +23,26 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QAbstractNetworkCache>
|
||||
#include <QMutex>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <stdbool.h>
|
||||
|
||||
class QNetworkDiskCache;
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QIODevice>
|
||||
#include <QMap>
|
||||
#include <QByteArray>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QNetworkCacheMetaData>
|
||||
#include <QAbstractNetworkCache>
|
||||
#include <QtEvents>
|
||||
|
||||
class QTimerEvent;
|
||||
|
||||
class ThreadSafeNetworkDiskCache : public QAbstractNetworkCache {
|
||||
public:
|
||||
|
||||
@@ -20,16 +20,20 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "networkproxyfactory.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <QMutexLocker>
|
||||
#include <QSettings>
|
||||
#include <QtGlobal>
|
||||
#include <QMutex>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QNetworkProxy>
|
||||
#include <QtDebug>
|
||||
#include <QSettings>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "networkproxyfactory.h"
|
||||
|
||||
NetworkProxyFactory *NetworkProxyFactory::sInstance = nullptr;
|
||||
const char *NetworkProxyFactory::kSettingsGroup = "NetworkProxy";
|
||||
@@ -40,8 +44,7 @@ NetworkProxyFactory::NetworkProxyFactory()
|
||||
port_(8080),
|
||||
use_authentication_(false) {
|
||||
#ifdef Q_OS_LINUX
|
||||
// Linux uses environment variables to pass proxy configuration information,
|
||||
// which systemProxyForQuery doesn't support for some reason.
|
||||
// Linux uses environment variables to pass proxy configuration information, which systemProxyForQuery doesn't support for some reason.
|
||||
|
||||
QStringList urls;
|
||||
urls << QString::fromLocal8Bit(getenv("HTTP_PROXY"));
|
||||
|
||||
@@ -23,9 +23,15 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QMutex>
|
||||
#include <QNetworkProxyFactory>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QNetworkProxy>
|
||||
#include <QNetworkProxyFactory>
|
||||
|
||||
class NetworkProxyFactory : public QNetworkProxyFactory {
|
||||
public:
|
||||
|
||||
@@ -18,23 +18,26 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "organise.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <QDir>
|
||||
#include <QtGlobal>
|
||||
#include <QThread>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QTimer>
|
||||
#include <QThread>
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
#include <QUrl>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "musicstorage.h"
|
||||
#include "taskmanager.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "core/utilities.h"
|
||||
#include "utilities.h"
|
||||
#include "taskmanager.h"
|
||||
#include "musicstorage.h"
|
||||
#include "organise.h"
|
||||
#include "transcoder/transcoder.h"
|
||||
|
||||
class OrganiseFormat;
|
||||
|
||||
using std::placeholders::_1;
|
||||
|
||||
@@ -112,8 +115,7 @@ void Organise::ProcessSomeFiles() {
|
||||
|
||||
emit Finished(files_with_errors_);
|
||||
|
||||
// Move back to the original thread so deleteLater() can get called in
|
||||
// the main thread's event loop
|
||||
// Move back to the original thread so deleteLater() can get called in the main thread's event loop
|
||||
moveToThread(original_thread_);
|
||||
deleteLater();
|
||||
|
||||
@@ -165,9 +167,8 @@ void Organise::ProcessSomeFiles() {
|
||||
|
||||
qLog(Debug) << "Transcoding to" << task.transcoded_filename_;
|
||||
|
||||
// Start the transcoding - this will happen in the background and
|
||||
// FileTranscoded() will get called when it's done. At that point the
|
||||
// task will get re-added to the pending queue with the new filename.
|
||||
// Start the transcoding - this will happen in the background and FileTranscoded() will get called when it's done.
|
||||
// At that point the task will get re-added to the pending queue with the new filename.
|
||||
transcoder_->AddJob(task.song_info_.song_.url().toLocalFile(), preset, task.transcoded_filename_);
|
||||
transcoder_->Start();
|
||||
continue;
|
||||
@@ -223,9 +224,7 @@ Song::FileType Organise::CheckTranscode(Song::FileType original_type) const {
|
||||
|
||||
if (format != Song::Type_Unknown) return format;
|
||||
|
||||
// The user hasn't visited the device properties page yet to set a
|
||||
// preferred format for the device, so we have to pick the best
|
||||
// available one.
|
||||
// The user hasn't visited the device properties page yet to set a preferred format for the device, so we have to pick the best available one.
|
||||
return Transcoder::PickBestFormat(supported_filetypes_);
|
||||
}
|
||||
return Song::Type_Unknown;
|
||||
@@ -251,9 +250,8 @@ void Organise::UpdateProgress() {
|
||||
tasks_transcoding_[filename].transcode_progress_ = transcode_progress[filename];
|
||||
}
|
||||
|
||||
// Count the progress of all tasks that are in the queue. Files that need
|
||||
// transcoding total 50 for the transcode and 50 for the copy, files that
|
||||
// only need to be copied total 100.
|
||||
// Count the progress of all tasks that are in the queue.
|
||||
// Files that need transcoding total 50 for the transcode and 50 for the copy, files that only need to be copied total 100.
|
||||
int progress = tasks_complete_ * 100;
|
||||
|
||||
for (const Task &task : tasks_pending_) {
|
||||
|
||||
@@ -24,16 +24,27 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QBasicTimer>
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QTemporaryFile>
|
||||
#include <QBasicTimer>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QVector>
|
||||
|
||||
#include "core/song.h"
|
||||
#include "organiseformat.h"
|
||||
#include "transcoder/transcoder.h"
|
||||
|
||||
class QTimerEvent;
|
||||
|
||||
class MusicStorage;
|
||||
class TaskManager;
|
||||
class Transcoder;
|
||||
|
||||
class Organise : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -20,17 +20,30 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "organiseformat.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QApplication>
|
||||
#include <QFileInfo>
|
||||
#include <QPalette>
|
||||
#include <QList>
|
||||
#include <QChar>
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
#include <QStringList>
|
||||
#include <QRegExp>
|
||||
#include <QUrl>
|
||||
#include <QColor>
|
||||
#include <QPalette>
|
||||
#include <QValidator>
|
||||
#include <QTextEdit>
|
||||
#include <QTextFormat>
|
||||
|
||||
#include "core/arraysize.h"
|
||||
#include "core/timeconstants.h"
|
||||
#include "core/utilities.h"
|
||||
#include "core/logging.h"
|
||||
|
||||
#include "timeconstants.h"
|
||||
#include "utilities.h"
|
||||
#include "song.h"
|
||||
#include "organiseformat.h"
|
||||
|
||||
class QTextDocument;
|
||||
|
||||
const char *OrganiseFormat::kTagPattern = "\\%([a-zA-Z]*)";
|
||||
const char *OrganiseFormat::kBlockPattern = "\\{([^{}]+)\\}";
|
||||
@@ -95,11 +108,8 @@ QString OrganiseFormat::GetFilenameForSong(const Song &song) const {
|
||||
QString filename = ParseBlock(format_, song);
|
||||
|
||||
if (QFileInfo(filename).completeBaseName().isEmpty()) {
|
||||
// Avoid having empty filenames, or filenames with extension only: in this
|
||||
// case, keep the original filename.
|
||||
// We remove the extension from "filename" if it exists, as
|
||||
// song.basefilename()
|
||||
// also contains the extension.
|
||||
// Avoid having empty filenames, or filenames with extension only: in this case, keep the original filename.
|
||||
// We remove the extension from "filename" if it exists, as song.basefilename() also contains the extension.
|
||||
filename =
|
||||
Utilities::PathWithoutFilenameExtension(filename) + song.basefilename();
|
||||
}
|
||||
@@ -112,7 +122,8 @@ QString OrganiseFormat::GetFilenameForSong(const Song &song) const {
|
||||
const QCharRef c = filename[i];
|
||||
if (c < 128) {
|
||||
stripped.append(c);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
const QString decomposition = c.decomposition();
|
||||
if (!decomposition.isEmpty() && decomposition[0] < 128)
|
||||
stripped.append(decomposition[0]);
|
||||
|
||||
@@ -23,19 +23,26 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QColor>
|
||||
#include <QTextDocument>
|
||||
#include <QTextEdit>
|
||||
#include <QSyntaxHighlighter>
|
||||
#include <QValidator>
|
||||
#include <QTextEdit>
|
||||
|
||||
#include "core/song.h"
|
||||
class Song;
|
||||
|
||||
class OrganiseFormat {
|
||||
|
||||
public:
|
||||
explicit OrganiseFormat(const QString &format = QString());
|
||||
|
||||
static const char* kTagPattern;
|
||||
static const char* kBlockPattern;
|
||||
static const char *kTagPattern;
|
||||
static const char *kBlockPattern;
|
||||
static const QStringList kKnownTags;
|
||||
static const char kInvalidFatCharacters[];
|
||||
static const int kInvalidFatCharactersCount;
|
||||
@@ -57,7 +64,7 @@ class OrganiseFormat {
|
||||
|
||||
class Validator : public QValidator {
|
||||
public:
|
||||
explicit Validator(QObject* parent = nullptr);
|
||||
explicit Validator(QObject *parent = nullptr);
|
||||
QValidator::State validate(QString &format, int &pos) const;
|
||||
};
|
||||
|
||||
@@ -70,14 +77,14 @@ class OrganiseFormat {
|
||||
static const QRgb kInvalidTagColorDark;
|
||||
static const QRgb kBlockColorDark;
|
||||
|
||||
explicit SyntaxHighlighter(QObject* parent = nullptr);
|
||||
explicit SyntaxHighlighter(QTextEdit* parent);
|
||||
explicit SyntaxHighlighter(QTextDocument* parent);
|
||||
explicit SyntaxHighlighter(QObject *parent = nullptr);
|
||||
explicit SyntaxHighlighter(QTextEdit *parent);
|
||||
explicit SyntaxHighlighter(QTextDocument *parent);
|
||||
void highlightBlock(const QString &format);
|
||||
};
|
||||
|
||||
private:
|
||||
QString ParseBlock(QString block, const Song &song, bool* any_empty = nullptr) const;
|
||||
QString ParseBlock(QString block, const Song &song, bool *any_empty = nullptr) const;
|
||||
QString TagValue(const QString &tag, const Song &song) const;
|
||||
|
||||
QString format_;
|
||||
|
||||
@@ -18,23 +18,33 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "player.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "player.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QDateTime>
|
||||
#include <QSettings>
|
||||
#include <QtDebug>
|
||||
#include <QtConcurrentRun>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/urlhandler.h"
|
||||
#include "core/timeconstants.h"
|
||||
#include "engine/enginetype.h"
|
||||
|
||||
#include "song.h"
|
||||
#include "timeconstants.h"
|
||||
#include "urlhandler.h"
|
||||
#include "application.h"
|
||||
|
||||
#include "engine/enginebase.h"
|
||||
#include "engine/enginedevice.h"
|
||||
#include "engine/enginetype.h"
|
||||
|
||||
#ifdef HAVE_GSTREAMER
|
||||
# include "engine/gstengine.h"
|
||||
@@ -53,10 +63,9 @@
|
||||
#include "playlist/playlist.h"
|
||||
#include "playlist/playlistitem.h"
|
||||
#include "playlist/playlistmanager.h"
|
||||
|
||||
#include "analyzer/analyzercontainer.h"
|
||||
#include "playlist/playlistsequence.h"
|
||||
#include "equalizer/equalizer.h"
|
||||
|
||||
#include "analyzer/analyzercontainer.h"
|
||||
#include "settings/backendsettingspage.h"
|
||||
#include "settings/behavioursettingspage.h"
|
||||
#include "settings/playlistsettingspage.h"
|
||||
@@ -76,8 +85,6 @@ Player::Player(Application *app, QObject *parent)
|
||||
menu_previousmode_(PreviousBehaviour_DontRestart),
|
||||
seek_step_sec_(10)
|
||||
{
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
QSettings s;
|
||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
||||
@@ -101,8 +108,6 @@ Player::Player(Application *app, QObject *parent)
|
||||
Player::~Player() {}
|
||||
|
||||
EngineBase *Player::CreateEngine(Engine::EngineType enginetype) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
bool engine = false;
|
||||
EngineBase *enginebase = nullptr;
|
||||
@@ -170,8 +175,6 @@ EngineBase *Player::CreateEngine(Engine::EngineType enginetype) {
|
||||
|
||||
void Player::Init() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
connect(engine_.get(), SIGNAL(Error(QString)), SIGNAL(Error(QString)));
|
||||
connect(engine_.get(), SIGNAL(ValidSongRequested(QUrl)), SLOT(ValidSongRequested(QUrl)));
|
||||
connect(engine_.get(), SIGNAL(InvalidSongRequested(QUrl)), SLOT(InvalidSongRequested(QUrl)));
|
||||
@@ -213,8 +216,6 @@ void Player::SetEqualizer(Equalizer *equalizer) {
|
||||
|
||||
void Player::ReloadSettings() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
QSettings s;
|
||||
|
||||
s.beginGroup(PlaylistSettingsPage::kSettingsGroup);
|
||||
@@ -230,8 +231,6 @@ void Player::ReloadSettings() {
|
||||
}
|
||||
|
||||
void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
// Might've been an async load, so check we're still on the same item
|
||||
shared_ptr<PlaylistItem> item = app_->playlist_manager()->active()->current_item();
|
||||
@@ -254,8 +253,7 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
|
||||
|
||||
qLog(Debug) << "URL handler for" << result.original_url_ << "returned" << result.media_url_;
|
||||
|
||||
// If there was no length info in song's metadata, use the one provided by
|
||||
// URL handler, if there is one
|
||||
// If there was no length info in song's metadata, use the one provided by URL handler, if there is one
|
||||
if (item->Metadata().length_nanosec() <= 0 && result.length_nanosec_ != -1) {
|
||||
Song song = item->Metadata();
|
||||
song.set_length_nanosec(result.length_nanosec_);
|
||||
@@ -281,8 +279,6 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
|
||||
void Player::Next() { NextInternal(Engine::Manual); }
|
||||
|
||||
void Player::NextInternal(Engine::TrackChangeFlags change) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
if (HandleStopAfter()) return;
|
||||
|
||||
@@ -303,8 +299,6 @@ void Player::NextInternal(Engine::TrackChangeFlags change) {
|
||||
}
|
||||
|
||||
void Player::NextItem(Engine::TrackChangeFlags change) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
Playlist *active_playlist = app_->playlist_manager()->active();
|
||||
|
||||
@@ -313,8 +307,7 @@ void Player::NextItem(Engine::TrackChangeFlags change) {
|
||||
const PlaylistSequence::RepeatMode repeat_mode = active_playlist->sequence()->repeat_mode();
|
||||
if (repeat_mode != PlaylistSequence::Repeat_Off) {
|
||||
if ((repeat_mode == PlaylistSequence::Repeat_Track && nb_errors_received_ >= 3) || (nb_errors_received_ >= app_->playlist_manager()->active()->proxy()->rowCount())) {
|
||||
// We received too many "Error" state changes: probably looping over a
|
||||
// playlist which contains only unavailable elements: stop now.
|
||||
// We received too many "Error" state changes: probably looping over a playlist which contains only unavailable elements: stop now.
|
||||
nb_errors_received_ = 0;
|
||||
Stop();
|
||||
return;
|
||||
@@ -338,12 +331,9 @@ void Player::NextItem(Engine::TrackChangeFlags change) {
|
||||
}
|
||||
|
||||
bool Player::HandleStopAfter() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
if (app_->playlist_manager()->active()->stop_after_current()) {
|
||||
// Find what the next track would've been, and mark that one as current
|
||||
// so it plays next time the user presses Play.
|
||||
// Find what the next track would've been, and mark that one as current so it plays next time the user presses Play.
|
||||
const int next_row = app_->playlist_manager()->active()->next_row();
|
||||
if (next_row != -1) {
|
||||
app_->playlist_manager()->active()->set_current_row(next_row, true);
|
||||
@@ -358,8 +348,6 @@ bool Player::HandleStopAfter() {
|
||||
}
|
||||
|
||||
void Player::TrackEnded() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
if (HandleStopAfter()) return;
|
||||
|
||||
@@ -372,8 +360,6 @@ void Player::TrackEnded() {
|
||||
|
||||
void Player::PlayPause() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
switch (engine_->state()) {
|
||||
case Engine::Paused:
|
||||
engine_->Unpause();
|
||||
@@ -504,7 +490,7 @@ void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle)
|
||||
|
||||
if (change == Engine::Manual && engine_->position_nanosec() != engine_->length_nanosec()) {
|
||||
emit TrackSkipped(current_item_);
|
||||
const QUrl& url = current_item_->Url();
|
||||
const QUrl &url = current_item_->Url();
|
||||
if (url_handlers_.contains(url.scheme())) {
|
||||
url_handlers_[url.scheme()]->TrackSkipped();
|
||||
}
|
||||
@@ -541,8 +527,7 @@ void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle)
|
||||
}
|
||||
|
||||
void Player::CurrentMetadataChanged(const Song &metadata) {
|
||||
// those things might have changed (especially when a previously invalid
|
||||
// song was reloaded) so we push the latest version into Engine
|
||||
// those things might have changed (especially when a previously invalid song was reloaded) so we push the latest version into Engine
|
||||
engine_->RefreshMarkers(metadata.beginning_nanosec(), metadata.end_nanosec());
|
||||
|
||||
}
|
||||
@@ -551,8 +536,7 @@ void Player::SeekTo(int seconds) {
|
||||
|
||||
const qint64 length_nanosec = engine_->length_nanosec();
|
||||
|
||||
// If the length is 0 then either there is no song playing, or the song isn't
|
||||
// seekable.
|
||||
// If the length is 0 then either there is no song playing, or the song isn't seekable.
|
||||
if (length_nanosec <= 0) {
|
||||
return;
|
||||
}
|
||||
@@ -581,8 +565,7 @@ void Player::EngineMetadataReceived(const Engine::SimpleMetaBundle &bundle) {
|
||||
|
||||
Engine::SimpleMetaBundle bundle_copy = bundle;
|
||||
|
||||
// Maybe the metadata is from icycast and has "Artist - Title" shoved
|
||||
// together in the title field.
|
||||
// Maybe the metadata is from icycast and has "Artist - Title" shoved together in the title field.
|
||||
const int dash_pos = bundle_copy.title.indexOf('-');
|
||||
if (dash_pos != -1 && bundle_copy.artist.isEmpty()) {
|
||||
// Split on " - " if it exists, otherwise split on "-".
|
||||
@@ -654,10 +637,8 @@ void Player::TogglePrettyOSD() {
|
||||
|
||||
void Player::TrackAboutToEnd() {
|
||||
|
||||
// If the current track was from a URL handler then it might have special
|
||||
// behaviour to queue up a subsequent track. We don't want to preload (and
|
||||
// scrobble) the next item in the playlist if it's just going to be stopped
|
||||
// again immediately after.
|
||||
// If the current track was from a URL handler then it might have special behaviour to queue up a subsequent track.
|
||||
// We don't want to preload (and scrobble) the next item in the playlist if it's just going to be stopped again immediately after.
|
||||
if (app_->playlist_manager()->active()->current_item()) {
|
||||
const QUrl url = app_->playlist_manager()->active()->current_item()->Url();
|
||||
if (url_handlers_.contains(url.scheme())) {
|
||||
@@ -674,24 +655,20 @@ void Player::TrackAboutToEnd() {
|
||||
}
|
||||
|
||||
if (engine_->is_autocrossfade_enabled()) {
|
||||
// Crossfade is on, so just start playing the next track. The current one
|
||||
// will fade out, and the new one will fade in
|
||||
// Crossfade is on, so just start playing the next track. The current one will fade out, and the new one will fade in
|
||||
|
||||
// But, if there's no next track and we don't want to fade out, then do
|
||||
// nothing and just let the track finish to completion.
|
||||
// But, if there's no next track and we don't want to fade out, then do nothing and just let the track finish to completion.
|
||||
if (!engine_->is_fadeout_enabled() && !has_next_row) return;
|
||||
|
||||
// If the next track is on the same album (or same cue file), and the
|
||||
// user doesn't want to crossfade between tracks on the same album, then
|
||||
// don't do this automatic crossfading.
|
||||
// If the next track is on the same album (or same cue file),
|
||||
// and the user doesn't want to crossfade between tracks on the same album, then don't do this automatic crossfading.
|
||||
if (engine_->crossfade_same_album() || !has_next_row || !next_item || !current_item_->Metadata().IsOnSameAlbum(next_item->Metadata())) {
|
||||
TrackEnded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Crossfade is off, so start preloading the next track so we don't get a
|
||||
// gap between songs.
|
||||
// Crossfade is off, so start preloading the next track so we don't get a gap between songs.
|
||||
if (!has_next_row || !next_item) return;
|
||||
|
||||
QUrl url = next_item->Url();
|
||||
@@ -726,8 +703,8 @@ void Player::InvalidSongRequested(const QUrl &url) {
|
||||
|
||||
// first send the notification to others...
|
||||
emit SongChangeRequestProcessed(url, false);
|
||||
// ... and now when our listeners have completed their processing of the
|
||||
// current item we can change the current item by skipping to the next song
|
||||
// ... and now when our listeners have completed their processing of the current item we can change
|
||||
// the current item by skipping to the next song
|
||||
//NextItem(Engine::Auto);
|
||||
|
||||
}
|
||||
|
||||
@@ -24,26 +24,30 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QMap>
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QSettings>
|
||||
|
||||
#include "config.h"
|
||||
#include "core/song.h"
|
||||
#include "core/urlhandler.h"
|
||||
#include "covermanager/albumcoverloader.h"
|
||||
#include "urlhandler.h"
|
||||
#include "engine/engine_fwd.h"
|
||||
#include "engine/enginetype.h"
|
||||
#include "engine/enginedevice.h"
|
||||
#include "playlist/playlistitem.h"
|
||||
#include "analyzer/analyzercontainer.h"
|
||||
#include "equalizer/equalizer.h"
|
||||
|
||||
class Application;
|
||||
class Song;
|
||||
class AnalyzerContainer;
|
||||
class Equalizer;
|
||||
|
||||
namespace Engine {
|
||||
struct SimpleMetaBundle;
|
||||
} // namespace Engine
|
||||
|
||||
class PlayerInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -66,8 +70,7 @@ class PlayerInterface : public QObject {
|
||||
// Manual track change to the specified track
|
||||
virtual void PlayAt(int i, Engine::TrackChangeFlags change, bool reshuffle) = 0;
|
||||
|
||||
// If there's currently a song playing, pause it, otherwise play the track
|
||||
// that was playing last, or the first one on the playlist
|
||||
// If there's currently a song playing, pause it, otherwise play the track that was playing last, or the first one on the playlist
|
||||
virtual void PlayPause() = 0;
|
||||
virtual void RestartOrPrevious() = 0;
|
||||
|
||||
@@ -103,8 +106,8 @@ signals:
|
||||
// Emitted when there's a manual change to the current's track position.
|
||||
void Seeked(qlonglong microseconds);
|
||||
|
||||
// Emitted when Player has processed a request to play another song. This contains
|
||||
// the URL of the song and a flag saying whether it was able to play the song.
|
||||
// Emitted when Player has processed a request to play another song.
|
||||
// This contains the URL of the song and a flag saying whether it was able to play the song.
|
||||
void SongChangeRequestProcessed(const QUrl &url, bool valid);
|
||||
|
||||
// The toggle parameter is true when user requests to toggle visibility for Pretty OSD
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2012, David Sansome <me@davidsansome.com>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Strawberry is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QHASH_QURL_H
|
||||
#define QHASH_QURL_H
|
||||
|
||||
#include <QUrl>
|
||||
|
||||
#if QT_VERSION < 0x040700
|
||||
inline uint qHash(const QUrl& url) { return qHash(url.toEncoded()); }
|
||||
#endif
|
||||
|
||||
#endif // QHASH_QURL_H
|
||||
|
||||
@@ -20,9 +20,10 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "qtfslistener.h"
|
||||
#include <QString>
|
||||
|
||||
#include <QStringList>
|
||||
#include "filesystemwatcherinterface.h"
|
||||
#include "qtfslistener.h"
|
||||
|
||||
QtFSListener::QtFSListener(QObject *parent) : FileSystemWatcherInterface(parent), watcher_(this) {
|
||||
|
||||
@@ -40,4 +41,3 @@ void QtFSListener::Clear() {
|
||||
watcher_.removePaths(watcher_.directories());
|
||||
watcher_.removePaths(watcher_.files());
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,11 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "filesystemwatcherinterface.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QString>
|
||||
|
||||
#include "filesystemwatcherinterface.h"
|
||||
|
||||
class QtFSListener : public FileSystemWatcherInterface {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -20,19 +20,22 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "iconloader.h"
|
||||
#include "qtsystemtrayicon.h"
|
||||
|
||||
#include "core/song.h"
|
||||
#include "core/logging.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QCoreApplication>
|
||||
#include <QTextDocument>
|
||||
#include <QStringBuilder>
|
||||
#include <QMenu>
|
||||
#include <QFile>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QWheelEvent>
|
||||
#include <QAction>
|
||||
#include <QIODevice>
|
||||
#include <QFile>
|
||||
#include <QMenu>
|
||||
#include <QIcon>
|
||||
#include <QString>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "song.h"
|
||||
#include "iconloader.h"
|
||||
|
||||
#include "systemtrayicon.h"
|
||||
#include "qtsystemtrayicon.h"
|
||||
|
||||
QtSystemTrayIcon::QtSystemTrayIcon(QObject *parent)
|
||||
: SystemTrayIcon(parent),
|
||||
@@ -44,8 +47,6 @@ QtSystemTrayIcon::QtSystemTrayIcon(QObject *parent)
|
||||
action_mute_(nullptr)
|
||||
{
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
QIcon theme_icon = IconLoader::Load("strawberry-panel");
|
||||
QIcon theme_icon_grey = IconLoader::Load("strawberry-panel-grey");
|
||||
|
||||
@@ -79,8 +80,6 @@ QtSystemTrayIcon::~QtSystemTrayIcon() {
|
||||
|
||||
bool QtSystemTrayIcon::eventFilter(QObject *object, QEvent *event) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
if (QObject::eventFilter(object, event)) return true;
|
||||
|
||||
if (object != tray_) return false;
|
||||
@@ -90,7 +89,8 @@ bool QtSystemTrayIcon::eventFilter(QObject *object, QEvent *event) {
|
||||
if (e->modifiers() == Qt::ShiftModifier) {
|
||||
if (e->delta() > 0) {
|
||||
emit SeekForward();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
emit SeekBackward();
|
||||
}
|
||||
}
|
||||
@@ -113,12 +113,9 @@ bool QtSystemTrayIcon::eventFilter(QObject *object, QEvent *event) {
|
||||
}
|
||||
|
||||
void QtSystemTrayIcon::SetupMenu(QAction *previous, QAction *play, QAction *stop, QAction *stop_after, QAction *next, QAction *mute, QAction *quit) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
// Creating new actions and connecting them to old ones. This allows us to
|
||||
// use old actions without displaying shortcuts that can not be used when
|
||||
// Strawberry's window is hidden
|
||||
// Creating new actions and connecting them to old ones.
|
||||
// This allows us to use old actions without displaying shortcuts that can not be used when Strawberry's window is hidden
|
||||
menu_->addAction(previous->icon(), previous->text(), previous, SLOT(trigger()));
|
||||
action_play_pause_ = menu_->addAction(play->icon(), play->text(), play, SLOT(trigger()));
|
||||
action_stop_ = menu_->addAction(stop->icon(), stop->text(), stop, SLOT(trigger()));
|
||||
@@ -140,8 +137,6 @@ void QtSystemTrayIcon::SetupMenu(QAction *previous, QAction *play, QAction *stop
|
||||
|
||||
void QtSystemTrayIcon::Clicked(QSystemTrayIcon::ActivationReason reason) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
switch (reason) {
|
||||
case QSystemTrayIcon::DoubleClick:
|
||||
case QSystemTrayIcon::Trigger:
|
||||
|
||||
@@ -23,24 +23,36 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QString>
|
||||
#include <QPixmap>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "systemtrayicon.h"
|
||||
|
||||
#include <QSystemTrayIcon>
|
||||
class QEvent;
|
||||
|
||||
class Song;
|
||||
|
||||
class QtSystemTrayIcon : public SystemTrayIcon {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QtSystemTrayIcon(QObject* parent = nullptr);
|
||||
QtSystemTrayIcon(QObject *parent = nullptr);
|
||||
~QtSystemTrayIcon();
|
||||
|
||||
void SetupMenu(QAction* previous, QAction *play, QAction *stop, QAction *stop_after, QAction *next, QAction *mute, QAction *quit);
|
||||
void SetupMenu(QAction *previous, QAction *play, QAction *stop, QAction *stop_after, QAction *next, QAction *mute, QAction *quit);
|
||||
bool IsVisible() const;
|
||||
void SetVisible(bool visible);
|
||||
|
||||
void ShowPopup(const QString &summary, const QString &message, int timeout);
|
||||
|
||||
void SetNowPlaying(const Song& song, const QString& image_path);
|
||||
void SetNowPlaying(const Song &song, const QString &image_path);
|
||||
void ClearNowPlaying();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -18,23 +18,24 @@
|
||||
*
|
||||
*/
|
||||
|
||||
//#ifdef HAVE_GIO
|
||||
//#undef signals // Clashes with GIO, and not needed in this file
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/logging.h"
|
||||
|
||||
//namespace {
|
||||
|
||||
void ScanGIOModulePath() {
|
||||
QString gio_module_path;
|
||||
|
||||
#if defined(Q_OS_WIN32)
|
||||
gio_module_path = QCoreApplication::applicationDirPath() + "/gio-modules";
|
||||
gio_module_path = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/gio-modules");
|
||||
#endif
|
||||
|
||||
if (!gio_module_path.isEmpty()) {
|
||||
@@ -43,6 +44,3 @@ void ScanGIOModulePath() {
|
||||
g_io_modules_scan_all_in_directory(bytes.data());
|
||||
}
|
||||
}
|
||||
|
||||
//} // namespace
|
||||
//#endif // HAVE_GIO
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "scopedtransaction.h"
|
||||
#include "core/logging.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <QSqlDatabase>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "scopedtransaction.h"
|
||||
|
||||
ScopedTransaction::ScopedTransaction(QSqlDatabase* db)
|
||||
: db_(db), pending_(true) {
|
||||
|
||||
@@ -23,22 +23,22 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
class QSqlDatabase;
|
||||
#include <QSqlDatabase>
|
||||
|
||||
// Opens a transaction on a database.
|
||||
// Rolls back the transaction if the object goes out of scope before Commit()
|
||||
// is called.
|
||||
// Rolls back the transaction if the object goes out of scope before Commit() is called.
|
||||
class ScopedTransaction : boost::noncopyable {
|
||||
public:
|
||||
ScopedTransaction(QSqlDatabase* db);
|
||||
ScopedTransaction(QSqlDatabase *db);
|
||||
~ScopedTransaction();
|
||||
|
||||
void Commit();
|
||||
|
||||
private:
|
||||
QSqlDatabase* db_;
|
||||
QSqlDatabase *db_;
|
||||
bool pending_;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,22 +20,19 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#ifdef HAVE_DBUS
|
||||
# include <QDBusConnection>
|
||||
# include <QDBusConnectionInterface>
|
||||
# include <QDBusReply>
|
||||
# include "dbusscreensaver.h"
|
||||
#endif
|
||||
|
||||
#include "screensaver.h"
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
#include "dbusscreensaver.h"
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusConnectionInterface>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include "macscreensaver.h"
|
||||
#endif
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
const char *Screensaver::kGnomeService = "org.gnome.ScreenSaver";
|
||||
const char *Screensaver::kGnomePath = "/";
|
||||
const char *Screensaver::kGnomeInterface = "org.gnome.ScreenSaver";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user