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:
Jonas Kvinge 2018-05-01 00:41:33 +02:00
parent fccbd6790c
commit e337b7933b
518 changed files with 7003 additions and 4693 deletions

View File

@ -1,4 +1,4 @@
#include <QtGui/QApplication>
#include <QApplication>
#include "gallery.h"
int main(int argc, char *argv[])

View File

@ -3,6 +3,7 @@
#include <QWidget>
#include <QPointer>
#include <QString>
class QButtonPrivate;
class QButton : public QWidget

View File

@ -20,12 +20,19 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "qbutton.h"
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QPointer>
#include <QString>
#include <QPixmap>
#include <QAbstractButton>
#include <QBoxLayout>
#include <QPushButton>
#include <QToolBar>
#include <QToolButton>
#include <QPushButton>
#include <QVBoxLayout>
#include "qbutton.h"
class QButtonPrivate : public QObject
{

View File

@ -21,8 +21,9 @@ THE SOFTWARE.
*/
#include <Foundation/NSString.h>
#include <QByteArray>
#include <QString>
#include <QVBoxLayout>
#include <QBoxLayout>
#include <QMacCocoaViewContainer>
static inline NSString* fromQString(const QString &string)

View File

@ -17,8 +17,7 @@ public:
Aqua = 12
};
explicit QProgressIndicatorSpinning(QWidget *parent,
Thickness thickness = Default);
explicit QProgressIndicatorSpinning(QWidget *parent, Thickness thickness = Default);
public slots:
void animate(bool animate = true);
private:

View File

@ -20,11 +20,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "qprogressindicatorspinning.h"
#include <QVBoxLayout>
#include <QMovie>
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QBoxLayout>
#include <QLabel>
#include <QMovie>
#include <QPointer>
#include <QSize>
#include "qprogressindicatorspinning.h"
class QProgressIndicatorSpinningPrivate : public QObject
{

View File

@ -2,7 +2,11 @@
#define QSEARCHFIELD_H
#include <QWidget>
#include <QObject>
#include <QPointer>
#include <QString>
#include <QEvent>
#include <QResizeEvent>
class QSearchFieldPrivate;
class QSearchField : public QWidget

View File

@ -20,18 +20,22 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "qsearchfield.h"
#include "../../src/core/iconloader.h"
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QApplication>
#include <QEvent>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QToolButton>
#include <QPointer>
#include <QString>
#include <QIcon>
#include <QSize>
#include <QStyle>
#include <QLineEdit>
#include <QBoxLayout>
#include <QToolButton>
#include <QtEvents>
#include <QDir>
#include <QDebug>
#include "../../src/core/iconloader.h"
#include "qsearchfield.h"
class QSearchFieldPrivate : public QObject
{

View File

@ -41,24 +41,31 @@
#include "qsql_sqlite.h"
#include <qcoreapplication.h>
#include <qvariant.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
#include <qsqlindex.h>
#include <qsqlquery.h>
#include <qstringlist.h>
#include <qvector.h>
#include <qdebug.h>
#if defined Q_OS_WIN
# include <qt_windows.h>
#include <qt_windows.h>
#else
# include <unistd.h>
#include <unistd.h>
#endif
#include <stddef.h>
#include <sqlite3.h>
#include <QObject>
#include <QCoreApplication>
#include <QByteArray>
#include <QVariant>
#include <QString>
#include <QStringList>
#include <QChar>
#include <QList>
#include <QMetaType>
#include <QVector>
#include <QSqlError>
#include <QSqlField>
#include <QSqlQuery>
#include <QSqlResult>
#include <QSqlRecord>
Q_DECLARE_OPAQUE_POINTER(sqlite3*)
Q_DECLARE_METATYPE(sqlite3*)
@ -98,16 +105,11 @@ static QVariant::Type qGetColumnType(const QString &tpName)
return QVariant::String;
}
static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::ErrorType type,
int errorCode = -1)
{
return QSqlError(descr,
QString(reinterpret_cast<const QChar *>(sqlite3_errmsg16(access))),
type, errorCode);
static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::ErrorType type, int errorCode = -1) {
return QSqlError(descr, QString(reinterpret_cast<const QChar *>(sqlite3_errmsg16(access))), type, errorCode);
}
class QSQLiteDriverPrivate
{
class QSQLiteDriverPrivate {
public:
inline QSQLiteDriverPrivate() : access(0) {}
sqlite3 *access;
@ -115,8 +117,7 @@ public:
};
class QSQLiteResultPrivate
{
class QSQLiteResultPrivate {
public:
QSQLiteResultPrivate(QSQLiteResult *res);
void cleanup();
@ -141,8 +142,7 @@ QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult* res) : q(res), access(
{
}
void QSQLiteResultPrivate::cleanup()
{
void QSQLiteResultPrivate::cleanup() {
finalize();
rInf.clear();
skippedStatus = false;
@ -152,17 +152,14 @@ void QSQLiteResultPrivate::cleanup()
q->cleanup();
}
void QSQLiteResultPrivate::finalize()
{
if (!stmt)
return;
void QSQLiteResultPrivate::finalize() {
if (!stmt) return;
sqlite3_finalize(stmt);
stmt = 0;
}
void QSQLiteResultPrivate::initColumns(bool emptyResultset)
{
void QSQLiteResultPrivate::initColumns(bool emptyResultset) {
int nCols = sqlite3_column_count(stmt);
if (nCols <= 0)
return;
@ -170,13 +167,10 @@ void QSQLiteResultPrivate::initColumns(bool emptyResultset)
q->init(nCols);
for (int i = 0; i < nCols; ++i) {
QString colName = QString(reinterpret_cast<const QChar *>(
sqlite3_column_name16(stmt, i))
).remove(QLatin1Char('"'));
QString colName = QString(reinterpret_cast<const QChar *>(sqlite3_column_name16(stmt, i))).remove(QLatin1Char('"'));
// must use typeName for resolving the type to match QSqliteDriver::record
QString typeName = QString(reinterpret_cast<const QChar *>(
sqlite3_column_decltype16(stmt, i)));
QString typeName = QString(reinterpret_cast<const QChar *>(sqlite3_column_decltype16(stmt, i)));
// sqlite3_column_type is documented to have undefined behavior if the result set is empty
int stp = emptyResultset ? -1 : sqlite3_column_type(stmt, i);
@ -184,7 +178,8 @@ void QSQLiteResultPrivate::initColumns(bool emptyResultset)
if (!typeName.isEmpty()) {
fieldType = qGetColumnType(typeName);
} else {
}
else {
// Get the proper type for the field based on stp value
switch (stp) {
case SQLITE_INTEGER:
@ -213,8 +208,7 @@ void QSQLiteResultPrivate::initColumns(bool emptyResultset)
}
}
bool QSQLiteResultPrivate::fetchNext(ClementineSqlCachedResult::ValueCache &values, int idx, bool initialFetch)
{
bool QSQLiteResultPrivate::fetchNext(ClementineSqlCachedResult::ValueCache &values, int idx, bool initialFetch) {
int res;
int i;
@ -234,8 +228,7 @@ bool QSQLiteResultPrivate::fetchNext(ClementineSqlCachedResult::ValueCache &valu
}
if (!stmt) {
q->setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"),
QCoreApplication::translate("QSQLiteResult", "No query"), QSqlError::ConnectionError));
q->setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"), QCoreApplication::translate("QSQLiteResult", "No query"), QSqlError::ConnectionError));
q->setAt(QSql::AfterLastRow);
return false;
}
@ -252,9 +245,7 @@ bool QSQLiteResultPrivate::fetchNext(ClementineSqlCachedResult::ValueCache &valu
for (i = 0; i < rInf.count(); ++i) {
switch (sqlite3_column_type(stmt, i)) {
case SQLITE_BLOB:
values[i + idx] = QByteArray(static_cast<const char *>(
sqlite3_column_blob(stmt, i)),
sqlite3_column_bytes(stmt, i));
values[i + idx] = QByteArray(static_cast<const char *>(sqlite3_column_blob(stmt, i)), sqlite3_column_bytes(stmt, i));
break;
case SQLITE_INTEGER:
values[i + idx] = sqlite3_column_int64(stmt, i);
@ -278,9 +269,7 @@ bool QSQLiteResultPrivate::fetchNext(ClementineSqlCachedResult::ValueCache &valu
values[i + idx] = QVariant(QVariant::String);
break;
default:
values[i + idx] = QString(reinterpret_cast<const QChar *>(
sqlite3_column_text16(stmt, i)),
sqlite3_column_bytes16(stmt, i) / sizeof(QChar));
values[i + idx] = QString(reinterpret_cast<const QChar *>(sqlite3_column_text16(stmt, i)), sqlite3_column_bytes16(stmt, i) / sizeof(QChar));
break;
}
}
@ -297,16 +286,14 @@ bool QSQLiteResultPrivate::fetchNext(ClementineSqlCachedResult::ValueCache &valu
// SQLITE_ERROR is a generic error code and we must call sqlite3_reset()
// to get the specific error message.
res = sqlite3_reset(stmt);
q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult",
"Unable to fetch row"), QSqlError::ConnectionError, res));
q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"), QSqlError::ConnectionError, res));
q->setAt(QSql::AfterLastRow);
return false;
case SQLITE_MISUSE:
case SQLITE_BUSY:
default:
// something wrong, don't get col info, but still return false
q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult",
"Unable to fetch row"), QSqlError::ConnectionError, res));
q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"), QSqlError::ConnectionError, res));
sqlite3_reset(stmt);
q->setAt(QSql::AfterLastRow);
return false;
@ -315,15 +302,13 @@ bool QSQLiteResultPrivate::fetchNext(ClementineSqlCachedResult::ValueCache &valu
}
QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db)
: ClementineSqlCachedResult(db)
{
: ClementineSqlCachedResult(db) {
d = new QSQLiteResultPrivate(this);
d->access = db->d->access;
db->d->results.append(this);
}
QSQLiteResult::~QSQLiteResult()
{
QSQLiteResult::~QSQLiteResult() {
const QSqlDriver *sqlDriver = driver();
if (sqlDriver)
qobject_cast<const QSQLiteDriver *>(sqlDriver)->d->results.removeOne(this);
@ -331,20 +316,17 @@ QSQLiteResult::~QSQLiteResult()
delete d;
}
void QSQLiteResult::virtual_hook(int id, void *data)
{
void QSQLiteResult::virtual_hook(int id, void *data) {
ClementineSqlCachedResult::virtual_hook(id, data);
}
bool QSQLiteResult::reset(const QString &query)
{
bool QSQLiteResult::reset(const QString &query) {
if (!prepare(query))
return false;
return exec();
}
bool QSQLiteResult::prepare(const QString &query)
{
bool QSQLiteResult::prepare(const QString &query) {
if (!driver() || !driver()->isOpen() || driver()->isOpenError())
return false;
@ -355,29 +337,25 @@ bool QSQLiteResult::prepare(const QString &query)
const void *pzTail = NULL;
#if (SQLITE_VERSION_NUMBER >= 3003011)
int res = sqlite3_prepare16_v2(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
&d->stmt, &pzTail);
int res = sqlite3_prepare16_v2(d->access, query.constData(), (query.size() + 1) * sizeof(QChar), &d->stmt, &pzTail);
#else
int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
&d->stmt, &pzTail);
int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar), &d->stmt, &pzTail);
#endif
if (res != SQLITE_OK) {
setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
"Unable to execute statement"), QSqlError::StatementError, res));
setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", "Unable to execute statement"), QSqlError::StatementError, res));
d->finalize();
return false;
} else if (pzTail && !QString(reinterpret_cast<const QChar *>(pzTail)).trimmed().isEmpty()) {
setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
"Unable to execute multiple statements at a time"), QSqlError::StatementError, SQLITE_MISUSE));
}
else if (pzTail && !QString(reinterpret_cast<const QChar *>(pzTail)).trimmed().isEmpty()) {
setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", "Unable to execute multiple statements at a time"), QSqlError::StatementError, SQLITE_MISUSE));
d->finalize();
return false;
}
return true;
}
bool QSQLiteResult::exec()
{
bool QSQLiteResult::exec() {
const QVector<QVariant> values = boundValues();
d->skippedStatus = false;
@ -388,8 +366,7 @@ bool QSQLiteResult::exec()
int res = sqlite3_reset(d->stmt);
if (res != SQLITE_OK) {
setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
"Unable to reset statement"), QSqlError::StatementError, res));
setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", "Unable to reset statement"), QSqlError::StatementError, res));
d->finalize();
return false;
}
@ -401,7 +378,8 @@ bool QSQLiteResult::exec()
if (value.isNull()) {
res = sqlite3_bind_null(d->stmt, i + 1);
} else {
}
else {
switch (value.type()) {
case QVariant::ByteArray: {
const QByteArray *ba = static_cast<const QByteArray*>(value.constData());
@ -434,13 +412,13 @@ bool QSQLiteResult::exec()
}
}
if (res != SQLITE_OK) {
setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
"Unable to bind parameters"), QSqlError::StatementError, res));
setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", "Unable to bind parameters"), QSqlError::StatementError, res));
d->finalize();
return false;
}
}
} else {
}
else {
setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult",
"Parameter count mismatch") + QString::number(paramCount, 10) + "/" + QString::number(values.count(), 10), QString(), QSqlError::StatementError));
return false;
@ -456,23 +434,19 @@ bool QSQLiteResult::exec()
return true;
}
bool QSQLiteResult::gotoNext(ClementineSqlCachedResult::ValueCache& row, int idx)
{
bool QSQLiteResult::gotoNext(ClementineSqlCachedResult::ValueCache& row, int idx) {
return d->fetchNext(row, idx, false);
}
int QSQLiteResult::size()
{
int QSQLiteResult::size() {
return -1;
}
int QSQLiteResult::numRowsAffected()
{
int QSQLiteResult::numRowsAffected() {
return sqlite3_changes(d->access);
}
QVariant QSQLiteResult::lastInsertId() const
{
QVariant QSQLiteResult::lastInsertId() const {
if (isActive()) {
qint64 id = sqlite3_last_insert_rowid(d->access);
if (id)
@ -481,35 +455,30 @@ QVariant QSQLiteResult::lastInsertId() const
return QVariant();
}
QSqlRecord QSQLiteResult::record() const
{
QSqlRecord QSQLiteResult::record() const {
if (!isActive() || !isSelect())
return QSqlRecord();
return d->rInf;
}
void QSQLiteResult::detachFromResultSet()
{
void QSQLiteResult::detachFromResultSet() {
if (d->stmt)
sqlite3_reset(d->stmt);
}
QVariant QSQLiteResult::handle() const
{
QVariant QSQLiteResult::handle() const {
return QVariant::fromValue(d->stmt);
}
/////////////////////////////////////////////////////////
QSQLiteDriver::QSQLiteDriver(QObject * parent)
: QSqlDriver(parent)
{
: QSqlDriver(parent) {
d = new QSQLiteDriverPrivate();
}
QSQLiteDriver::QSQLiteDriver(sqlite3 *connection, QObject *parent)
: QSqlDriver(parent)
{
: QSqlDriver(parent) {
d = new QSQLiteDriverPrivate();
d->access = connection;
setOpen(true);
@ -579,87 +548,77 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c
setOpen(true);
setOpenError(false);
return true;
} else {
}
else {
if (d->access) {
sqlite3_close(d->access);
d->access = 0;
}
setLastError(qMakeError(d->access, tr("Error opening database"),
QSqlError::ConnectionError));
setLastError(qMakeError(d->access, tr("Error opening database"), QSqlError::ConnectionError));
setOpenError(true);
return false;
}
}
void QSQLiteDriver::close()
{
void QSQLiteDriver::close() {
if (isOpen()) {
foreach (QSQLiteResult *result, d->results) {
result->d->finalize();
}
if (sqlite3_close(d->access) != SQLITE_OK)
setLastError(qMakeError(d->access, tr("Error closing database"),
QSqlError::ConnectionError));
setLastError(qMakeError(d->access, tr("Error closing database"), QSqlError::ConnectionError));
d->access = 0;
setOpen(false);
setOpenError(false);
}
}
QSqlResult *QSQLiteDriver::createResult() const
{
QSqlResult *QSQLiteDriver::createResult() const {
return new QSQLiteResult(this);
}
bool QSQLiteDriver::beginTransaction()
{
bool QSQLiteDriver::beginTransaction() {
if (!isOpen() || isOpenError())
return false;
QSqlQuery q(createResult());
if (!q.exec(QLatin1String("BEGIN"))) {
setLastError(QSqlError(tr("Unable to begin transaction"),
q.lastError().databaseText(), QSqlError::TransactionError));
setLastError(QSqlError(tr("Unable to begin transaction"), q.lastError().databaseText(), QSqlError::TransactionError));
return false;
}
return true;
}
bool QSQLiteDriver::commitTransaction()
{
bool QSQLiteDriver::commitTransaction() {
if (!isOpen() || isOpenError())
return false;
QSqlQuery q(createResult());
if (!q.exec(QLatin1String("COMMIT"))) {
setLastError(QSqlError(tr("Unable to commit transaction"),
q.lastError().databaseText(), QSqlError::TransactionError));
setLastError(QSqlError(tr("Unable to commit transaction"), q.lastError().databaseText(), QSqlError::TransactionError));
return false;
}
return true;
}
bool QSQLiteDriver::rollbackTransaction()
{
bool QSQLiteDriver::rollbackTransaction() {
if (!isOpen() || isOpenError())
return false;
QSqlQuery q(createResult());
if (!q.exec(QLatin1String("ROLLBACK"))) {
setLastError(QSqlError(tr("Unable to rollback transaction"),
q.lastError().databaseText(), QSqlError::TransactionError));
setLastError(QSqlError(tr("Unable to rollback transaction"), q.lastError().databaseText(), QSqlError::TransactionError));
return false;
}
return true;
}
QStringList QSQLiteDriver::tables(QSql::TableType type) const
{
QStringList QSQLiteDriver::tables(QSql::TableType type) const {
QStringList res;
if (!isOpen())
return res;
@ -691,8 +650,7 @@ QStringList QSQLiteDriver::tables(QSql::TableType type) const
return res;
}
static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false)
{
static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false) {
QString schema;
QString table(tableName);
int indexOfSeparator = tableName.indexOf(QLatin1Char('.'));
@ -720,8 +678,7 @@ static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool only
return ind;
}
QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const
{
QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const {
if (!isOpen())
return QSqlIndex();
@ -734,8 +691,7 @@ QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const
return qGetTableInfo(q, table, true);
}
QSqlRecord QSQLiteDriver::record(const QString &tbl) const
{
QSqlRecord QSQLiteDriver::record(const QString &tbl) const {
if (!isOpen())
return QSqlRecord();
@ -748,13 +704,11 @@ QSqlRecord QSQLiteDriver::record(const QString &tbl) const
return qGetTableInfo(q, table);
}
QVariant QSQLiteDriver::handle() const
{
QVariant QSQLiteDriver::handle() const {
return QVariant::fromValue(d->access);
}
QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
{
QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const {
Q_UNUSED(type);
return _q_escapeIdentifier(identifier);
}

View File

@ -42,8 +42,17 @@
#ifndef QSQL_SQLITE_H
#define QSQL_SQLITE_H
#include <QtSql/qsqldriver.h>
#include <QtSql/qsqlresult.h>
#include <QtGlobal>
#include <QObject>
#include <QVariant>
#include <QString>
#include <QStringList>
#include <QSql>
#include <QSqlDriver>
#include <QSqlIndex>
#include <QSqlRecord>
#include <QSqlResult>
#include "sqlcachedresult.h"
struct sqlite3;
@ -57,16 +66,16 @@ struct sqlite3;
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QSQLiteDriver;
class QSQLiteDriverPrivate;
class QSQLiteResultPrivate;
class QSQLiteDriver;
class QSQLiteResult : public ClementineSqlCachedResult
{
friend class QSQLiteDriver;
friend class QSQLiteResultPrivate;
public:
explicit QSQLiteResult(const QSQLiteDriver* db);
explicit QSQLiteResult(const QSQLiteDriver *db);
~QSQLiteResult();
QVariant handle() const;
@ -83,7 +92,7 @@ protected:
void virtual_hook(int id, void *data);
private:
QSQLiteResultPrivate* d;
QSQLiteResultPrivate *d;
};
class Q_EXPORT_SQLDRIVER_SQLITE QSQLiteDriver : public QSqlDriver
@ -95,12 +104,7 @@ public:
explicit QSQLiteDriver(sqlite3 *connection, QObject *parent = 0);
~QSQLiteDriver();
bool hasFeature(DriverFeature f) const;
bool open(const QString & db,
const QString & user,
const QString & password,
const QString & host,
int port,
const QString & connOpts);
bool open(const QString & db, const QString & user, const QString & password, const QString & host, int port, const QString & connOpts);
void close();
QSqlResult *createResult() const;
bool beginTransaction();
@ -114,7 +118,7 @@ public:
QString escapeIdentifier(const QString &identifier, IdentifierType) const;
private:
QSQLiteDriverPrivate* d;
QSQLiteDriverPrivate *d;
};
QT_END_NAMESPACE

View File

@ -31,8 +31,13 @@
**
****************************************************************************/
#include <QString>
#include <QSqlDriver>
#include "smain.h"
#include "qsql_sqlite.h"
QT_BEGIN_NAMESPACE
QSQLiteDriverPlugin::QSQLiteDriverPlugin()
@ -40,8 +45,7 @@ QSQLiteDriverPlugin::QSQLiteDriverPlugin()
{
}
QSqlDriver* QSQLiteDriverPlugin::create(const QString &name)
{
QSqlDriver *QSQLiteDriverPlugin::create(const QString &name) {
if (name == QLatin1String("QSQLITE")) {
QSQLiteDriver* driver = new QSQLiteDriver();
return driver;

View File

@ -31,9 +31,11 @@
**
****************************************************************************/
#include <qsqldriverplugin.h>
#include <qstringlist.h>
#include "qsql_sqlite.h"
#include <QtGlobal>
#include <QObject>
#include <QString>
#include <QSqlDriver>
#include <QSqlDriverPlugin>
QT_BEGIN_NAMESPACE
@ -45,7 +47,7 @@ class QSQLiteDriverPlugin : public QSqlDriverPlugin
public:
QSQLiteDriverPlugin();
QSqlDriver* create(const QString &);
QSqlDriver *create(const QString &);
};
QT_END_NAMESPACE

View File

@ -39,9 +39,9 @@
**
****************************************************************************/
#include <qvariant.h>
#include <qdatetime.h>
#include <qvector.h>
#include <QVariant>
#include <QSqlResult>
#include <QSqlDriver>
#include "sqlcachedresult.h"
@ -61,8 +61,7 @@ QT_BEGIN_NAMESPACE
static const uint initial_cache_size = 128;
class ClementineSqlCachedResultPrivate
{
class ClementineSqlCachedResultPrivate {
public:
ClementineSqlCachedResultPrivate();
bool canSeek(int i) const;
@ -84,8 +83,7 @@ ClementineSqlCachedResultPrivate::ClementineSqlCachedResultPrivate():
{
}
void ClementineSqlCachedResultPrivate::cleanup()
{
void ClementineSqlCachedResultPrivate::cleanup() {
cache.clear();
forwardOnly = false;
atEnd = false;
@ -93,8 +91,7 @@ void ClementineSqlCachedResultPrivate::cleanup()
rowCacheEnd = 0;
}
void ClementineSqlCachedResultPrivate::init(int count, bool fo)
{
void ClementineSqlCachedResultPrivate::init(int count, bool fo) {
Q_ASSERT(count);
cleanup();
forwardOnly = fo;
@ -102,13 +99,13 @@ void ClementineSqlCachedResultPrivate::init(int count, bool fo)
if (fo) {
cache.resize(count);
rowCacheEnd = count;
} else {
}
else {
cache.resize(initial_cache_size * count);
}
}
int ClementineSqlCachedResultPrivate::nextIndex()
{
int ClementineSqlCachedResultPrivate::nextIndex() {
if (forwardOnly)
return 0;
int newIdx = rowCacheEnd;
@ -119,15 +116,13 @@ int ClementineSqlCachedResultPrivate::nextIndex()
return newIdx;
}
bool ClementineSqlCachedResultPrivate::canSeek(int i) const
{
bool ClementineSqlCachedResultPrivate::canSeek(int i) const {
if (forwardOnly || i < 0)
return false;
return rowCacheEnd >= (i + 1) * colCount;
}
void ClementineSqlCachedResultPrivate::revertLast()
{
void ClementineSqlCachedResultPrivate::revertLast() {
if (forwardOnly)
return;
rowCacheEnd -= colCount;
@ -142,23 +137,19 @@ inline int ClementineSqlCachedResultPrivate::cacheCount() const
//////////////
ClementineSqlCachedResult::ClementineSqlCachedResult(const QSqlDriver * db): QSqlResult (db)
{
ClementineSqlCachedResult::ClementineSqlCachedResult(const QSqlDriver * db): QSqlResult (db) {
d = new ClementineSqlCachedResultPrivate();
}
ClementineSqlCachedResult::~ClementineSqlCachedResult()
{
ClementineSqlCachedResult::~ClementineSqlCachedResult() {
delete d;
}
void ClementineSqlCachedResult::init(int colCount)
{
void ClementineSqlCachedResult::init(int colCount) {
d->init(colCount, isForwardOnly());
}
bool ClementineSqlCachedResult::fetch(int i)
{
bool ClementineSqlCachedResult::fetch(int i) {
if ((!isActive()) || (i < 0))
return false;
if (at() == i)
@ -195,8 +186,7 @@ bool ClementineSqlCachedResult::fetch(int i)
return true;
}
bool ClementineSqlCachedResult::fetchNext()
{
bool ClementineSqlCachedResult::fetchNext() {
if (d->canSeek(at() + 1)) {
setAt(at() + 1);
return true;
@ -204,13 +194,11 @@ bool ClementineSqlCachedResult::fetchNext()
return cacheNext();
}
bool ClementineSqlCachedResult::fetchPrevious()
{
bool ClementineSqlCachedResult::fetchPrevious() {
return fetch(at() - 1);
}
bool ClementineSqlCachedResult::fetchFirst()
{
bool ClementineSqlCachedResult::fetchFirst() {
if (d->forwardOnly && at() != QSql::BeforeFirstRow) {
return false;
}
@ -221,8 +209,7 @@ bool ClementineSqlCachedResult::fetchFirst()
return cacheNext();
}
bool ClementineSqlCachedResult::fetchLast()
{
bool ClementineSqlCachedResult::fetchLast() {
if (d->atEnd) {
if (d->forwardOnly)
return false;
@ -236,13 +223,13 @@ bool ClementineSqlCachedResult::fetchLast()
if (d->forwardOnly && at() == QSql::AfterLastRow) {
setAt(i);
return true;
} else {
}
else {
return fetch(i);
}
}
QVariant ClementineSqlCachedResult::data(int i)
{
QVariant ClementineSqlCachedResult::data(int i) {
int idx = d->forwardOnly ? i : at() * d->colCount + i;
if (i >= d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd)
return QVariant();
@ -250,8 +237,7 @@ QVariant ClementineSqlCachedResult::data(int i)
return d->cache.at(idx);
}
bool ClementineSqlCachedResult::isNull(int i)
{
bool ClementineSqlCachedResult::isNull(int i) {
int idx = d->forwardOnly ? i : at() * d->colCount + i;
if (i > d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd)
return true;
@ -259,22 +245,20 @@ bool ClementineSqlCachedResult::isNull(int i)
return d->cache.at(idx).isNull();
}
void ClementineSqlCachedResult::cleanup()
{
void ClementineSqlCachedResult::cleanup() {
setAt(QSql::BeforeFirstRow);
setActive(false);
d->cleanup();
}
void ClementineSqlCachedResult::clearValues()
{
void ClementineSqlCachedResult::clearValues() {
setAt(QSql::BeforeFirstRow);
d->rowCacheEnd = 0;
d->atEnd = false;
}
bool ClementineSqlCachedResult::cacheNext()
{
bool ClementineSqlCachedResult::cacheNext() {
if (d->atEnd)
return false;
@ -292,28 +276,23 @@ bool ClementineSqlCachedResult::cacheNext()
return true;
}
int ClementineSqlCachedResult::colCount() const
{
int ClementineSqlCachedResult::colCount() const {
return d->colCount;
}
ClementineSqlCachedResult::ValueCache &ClementineSqlCachedResult::cache()
{
ClementineSqlCachedResult::ValueCache &ClementineSqlCachedResult::cache() {
return d->cache;
}
void ClementineSqlCachedResult::virtual_hook(int id, void *data)
{
void ClementineSqlCachedResult::virtual_hook(int id, void *data) {
QSqlResult::virtual_hook(id, data);
}
void ClementineSqlCachedResult::detachFromResultSet()
{
void ClementineSqlCachedResult::detachFromResultSet() {
cleanup();
}
void ClementineSqlCachedResult::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy)
{
void ClementineSqlCachedResult::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy) {
QSqlResult::setNumericalPrecisionPolicy(policy);
cleanup();
}

View File

@ -53,13 +53,15 @@
// We mean it.
//
#include <QtSql/qsqlresult.h>
#include <QtGlobal>
#include <QVariant>
#include <QVector>
#include <QSql>
#include <QSqlDriver>
#include <QSqlResult>
QT_BEGIN_NAMESPACE
class QVariant;
template <typename T> class QVector;
class ClementineSqlCachedResultPrivate;
class ClementineSqlCachedResult: public QSqlResult

View File

@ -39,14 +39,27 @@
#include "qtlocalpeer.h"
#include <QCoreApplication>
#include <QTime>
#include <QDataStream>
#include <unistd.h>
#include <QtGlobal>
#include <QCoreApplication>
#include <QObject>
#include <QAbstractSocket>
#include <QByteArray>
#include <QChar>
#include <QDataStream>
#include <QDir>
#include <QFile>
#include <QIODevice>
#include <QLocalServer>
#include <QLocalSocket>
#include <QRegExp>
#if defined(Q_OS_WIN)
#include <QLibrary>
#include <qt_windows.h>
#include <QLibrary>
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
static PProcessIdToSessionId pProcessIdToSessionId = 0;
#endif

View File

@ -40,9 +40,9 @@
#ifndef QTLOCALPEER_H
#define QTLOCALPEER_H
#include <QObject>
#include <QString>
#include <QLocalServer>
#include <QLocalSocket>
#include <QDir>
#include "qtlockedfile.h"

View File

@ -37,6 +37,9 @@
**
****************************************************************************/
#include <QFile>
#include <QString>
#include "qtlockedfile.h"
/*!

View File

@ -42,7 +42,7 @@
#include <QFile>
#ifdef Q_OS_WIN
#include <QtCore/QVector>
#include <QVector>
#endif
#if defined(Q_WS_WIN) || defined(Q_OS_WIN)

View File

@ -37,9 +37,10 @@
**
****************************************************************************/
#include <QFileInfo>
#include "qtlockedfile.h"
#include <qt_windows.h>
#include <QFileInfo>
#define MUTEX_PREFIX "QtLockedFile mutex "
// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS

View File

@ -39,8 +39,12 @@
#include "qtsingleapplication.h"
#include "qtlocalpeer.h"
#include <QApplication>
#include <QWidget>
#include <QString>
#include "qtlocalpeer.h"
/*!
\class QtSingleApplication qtsingleapplication.h

View File

@ -40,8 +40,11 @@
#ifndef QTSINGLEAPPLICATION_H
#define QTSINGLEAPPLICATION_H
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QApplication>
#include <QString>
class QtLocalPeer;
#if defined(Q_WS_WIN) || defined(Q_OS_WIN32)

View File

@ -37,6 +37,9 @@
**
****************************************************************************/
#include <QCoreApplication>
#include <QString>
#include <QFlags>
#include "qtsinglecoreapplication.h"
#include "qtlocalpeer.h"
@ -70,8 +73,7 @@
*/
QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
: QCoreApplication(argc, argv)
{
: QCoreApplication(argc, argv) {
peer = new QtLocalPeer(this);
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
}
@ -83,8 +85,7 @@ QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
QCoreAppliation constructor.
*/
QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
: QCoreApplication(argc, argv)
{
: QCoreApplication(argc, argv) {
peer = new QtLocalPeer(this, appId);
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
}
@ -101,8 +102,7 @@ QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc
\sa sendMessage()
*/
bool QtSingleCoreApplication::isRunning()
{
bool QtSingleCoreApplication::isRunning() {
return peer->isClient();
}
@ -121,8 +121,7 @@ bool QtSingleCoreApplication::isRunning()
\sa isRunning(), messageReceived()
*/
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
{
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout) {
return peer->sendMessage(message, timeout);
}
@ -132,8 +131,7 @@ bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
identifier will be regarded as instances of the same application.
*/
QString QtSingleCoreApplication::id() const
{
QString QtSingleCoreApplication::id() const {
return peer->applicationId();
}

View File

@ -41,6 +41,8 @@
#define QTSINGLECOREAPPLICATION_H
#include <QCoreApplication>
#include <QObject>
#include <QString>
class QtLocalPeer;

View File

@ -29,10 +29,14 @@
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#include "qxtglobalshortcut_p.h"
#include <QtGlobal>
#include <QAbstractEventDispatcher>
#include <QHash>
#include <QPair>
#include <QtDebug>
#include "qxtglobalshortcut_p.h"
bool QxtGlobalShortcutPrivate::error = false;
#ifndef Q_WS_MAC
int QxtGlobalShortcutPrivate::ref = 0;

View File

@ -31,9 +31,12 @@
#define QXTGLOBALSHORTCUT_H
#include "qxtglobal.h"
#include <QObject>
#include <QKeySequence>
#include <QString>
#include "qxtglobal.h"
class QxtGlobalShortcutPrivate;
class QXT_GUI_EXPORT QxtGlobalShortcut : public QObject

View File

@ -32,12 +32,21 @@
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
# include <QX11Info>
#else
# include <QApplication>
# include <qpa/qplatformnativeinterface.h>
# include <xcb/xcb.h>
# include <QApplication>
#endif
#include <QVector>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <xcb/xproto.h>
#include <QtGlobal>
#include <QByteArray>
#include <QGuiApplication>
#include <QKeySequence>
#include <QString>
#include <QVector>
#include "keymapper_x11.h"
namespace {

View File

@ -31,8 +31,9 @@
*
*/
#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */
#include <assert.h> /* assert() */
#include <string.h>
#include <assert.h>
#include "sha2.h"
/*

View File

@ -35,6 +35,8 @@
#ifndef __STRAWBERRY_SHA2_H__
#define __STRAWBERRY_SHA2_H__
#include <stddef.h>
/*
* Import u_intXX_t size_t type definitions from system headers. You
* may need to change this, or define these things yourself in this

View File

@ -96,21 +96,19 @@ pkg_check_modules(GSTREAMER_APP gstreamer-app-1.0)
pkg_check_modules(GSTREAMER_AUDIO gstreamer-audio-1.0)
pkg_check_modules(GSTREAMER_TAG gstreamer-tag-1.0)
pkg_check_modules(GSTREAMER_PBUTILS gstreamer-pbutils-1.0)
#pkg_check_modules(GSTREAMER_QTGLIB Qt5GLib-2.0)
#pkg_check_modules(GSTREAMER_QTGST Qt5GStreamer-1.0)
#pkg_check_modules(GSTREAMER_QTGSTUI Qt5GStreamerUi-1.0)
#pkg_check_modules(GSTREAMER_QTGSTUTILS Qt5GStreamerUtils-1.0)
pkg_check_modules(LIBXINE libxine)
pkg_check_modules(LIBVLC libvlc)
pkg_check_modules(PHONON phonon4qt5)
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
pkg_check_modules(LIBMTP libmtp>=1.0)
pkg_check_modules(LIBPULSE libpulse)
pkg_check_modules(LIBXML libxml-2.0)
pkg_check_modules(TAGLIB REQUIRED taglib>=1.8)
pkg_check_modules(SQLITE REQUIRED sqlite3>=3.7)
pkg_check_modules(LIBGLU REQUIRED glu)
pkg_check_modules(IMOBILEDEVICE libimobiledevice-1.0)
pkg_check_modules(USBMUXD libusbmuxd)
pkg_check_modules(PLIST libplist)
find_library(PROTOBUF_STATIC_LIBRARY libprotobuf.a libprotobuf)
@ -178,10 +176,6 @@ include_directories(${GSTREAMER_AUDIO_INCLUDE_DIRS})
include_directories(${GSTREAMER_BASE_INCLUDE_DIRS})
include_directories(${GSTREAMER_TAG_INCLUDE_DIRS})
include_directories(${GSTREAMER_PBUTILS_INCLUDE_DIRS})
#include_directories(${GSTREAMER_QTGLIB})
#include_directories(${GSTREAMER_QTGST})
#include_directories(${GSTREAMER_QTGSTUI})
#include_directories(${GSTREAMER_QTGSTUTILS})
if (WIN32)
# RC compiler
@ -194,9 +188,30 @@ add_definitions(-DQT_NO_CAST_TO_ASCII -DQT_STRICT_ITERATORS)
# Optional bits
if(WIN32)
option(ENABLE_WIN32_CONSOLE "Show the windows console even outside Debug mode" OFF)
option(ENABLE_WIN32_CONSOLE "Show the windows console even outside Debug mode" ON)
endif(WIN32)
optional_component(GSTREAMER ON "Engine: GStreamer backend"
DEPENDS "gstreamer-1.0" GSTREAMER_FOUND
DEPENDS "gstreamer-base-1.0" GSTREAMER_BASE_FOUND
DEPENDS "gstreamer-app-1.0" GSTREAMER_APP_FOUND
DEPENDS "gstreamer-audio-1.0" GSTREAMER_AUDIO_FOUND
DEPENDS "gstreamer-tag-1.0" GSTREAMER_TAG_FOUND
DEPENDS "gstreamer-pbutils-1.0" GSTREAMER_PBUTILS_FOUND
)
optional_component(XINE ON "Engine: Xine backend"
DEPENDS "libxine" LIBXINE_FOUND
)
optional_component(VLC ON "Engine: VLC backend"
DEPENDS "libvlc" LIBVLC_FOUND
)
optional_component(PHONON OFF "Engine: Phonon backend"
DEPENDS "phonon4qt5" PHONON4QT5_FOUND
)
optional_component(AUDIOCD ON "Devices: Audio CD support"
DEPENDS "libcdio" CDIO_FOUND
)
@ -262,7 +277,7 @@ else(WIN32)
endif(WIN32)
# Remove GLU and GL from the link line - they're not really required and don't exist on my mingw toolchain
#list(REMOVE_ITEM QT_LIBRARIES "-lGLU -lGL")
list(REMOVE_ITEM QT_LIBRARIES "-lGLU -lGL")
# QSqlLiteDriver:
# We do this because we can't guarantee that the driver shipped with Qt exposes the raw sqlite3 functions required for FTS support.
@ -323,6 +338,10 @@ endif()
# Qocoa
add_subdirectory(3rdparty/qocoa)
#if(IMOBILEDEVICE_FOUND AND PLIST_FOUND)
#add_subdirectory(ext/gstafc)
#endif(IMOBILEDEVICE_FOUND AND PLIST_FOUND)
# Subdirectories
add_subdirectory(src)
if (WIN32)

5
TODO
View File

@ -1,5 +0,0 @@
Strawberry Music Player
=======================
TODO
- Finalize / Improve status/context

View File

@ -62,8 +62,7 @@ function(optional_component name default description)
elseif(${testing_deps})
string(REPLACE " " ";" arglist "${arg}")
if(${arglist})
# We have to do this instead of if(NOT ${arg}) so that tests may contain
# "NOT" themselves.
# We have to do this instead of if(NOT ${arg}) so that tests may contain "NOT" themselves.
else()
list(APPEND missing_deps "${current_dep_name}")
set(testing_deps FALSE)

View File

@ -15,6 +15,11 @@
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QObject>
#include <QList>
#include <QTimer>
#include <QGenericArgument>
#include "closure.h"
#include "core/timeconstants.h"

View File

@ -18,15 +18,20 @@
#ifndef CLOSURE_H
#define CLOSURE_H
#include <chrono>
#include <functional>
#include <memory>
#include <chrono>
#include <QtGlobal>
#include <QObject>
#include <QFuture>
#include <QFutureWatcher>
#include <QMetaObject>
#include <QMetaMethod>
#include <QObject>
#include <QSharedPointer>
#include <QByteArray>
#include <QString>
#include <QList>
#include <QTimer>
namespace _detail {
@ -40,11 +45,11 @@ class ClosureBase {
virtual void Invoke() = 0;
// Tests only.
ObjectHelper* helper() const;
ObjectHelper *helper() const;
protected:
explicit ClosureBase(ObjectHelper*);
ObjectHelper* helper_;
ObjectHelper *helper_;
private:
Q_DISABLE_COPY(ClosureBase);
@ -56,7 +61,7 @@ class ClosureBase {
class ObjectHelper : public QObject {
Q_OBJECT
public:
ObjectHelper(QObject* parent, const char* signal, ClosureBase* closure);
ObjectHelper(QObject *parent, const char *signal, ClosureBase *closure);
private slots:
void Invoked();
@ -72,12 +77,12 @@ class ObjectHelper : public QObject {
void Unpack(QList<QGenericArgument>*);
template <typename Arg>
void Unpack(QList<QGenericArgument>* list, const Arg& arg) {
void Unpack(QList<QGenericArgument> *list, const Arg &arg) {
list->append(Q_ARG(Arg, arg));
}
template <typename Head, typename... Tail>
void Unpack(QList<QGenericArgument>* list, const Head& head, const Tail&... tail) {
void Unpack(QList<QGenericArgument> *list, const Head &head, const Tail&... tail) {
Unpack(list, head);
Unpack(list, tail...);
}
@ -86,16 +91,16 @@ template <typename... Args>
class Closure : public ClosureBase {
public:
Closure(
QObject* sender,
const char* signal,
QObject* receiver,
const char* slot,
QObject *sender,
const char *signal,
QObject *receiver,
const char *slot,
const Args&... args)
: ClosureBase(new ObjectHelper(sender, signal, this)),
// std::bind is the easiest way to store an argument list.
function_(std::bind(&Closure<Args...>::Call, this, args...)),
receiver_(receiver) {
const QMetaObject* meta_receiver = receiver->metaObject();
const QMetaObject *meta_receiver = receiver->metaObject();
QByteArray normalised_slot = QMetaObject::normalizedSignature(slot + 1);
const int index = meta_receiver->indexOfSlot(normalised_slot.constData());
Q_ASSERT(index != -1);
@ -127,7 +132,7 @@ class Closure : public ClosureBase {
}
std::function<void()> function_;
QObject* receiver_;
QObject *receiver_;
QMetaMethod slot_;
};
@ -136,9 +141,9 @@ class SharedClosure : public Closure<Args...> {
public:
SharedClosure(
QSharedPointer<T> sender,
const char* signal,
QObject* receiver,
const char* slot,
const char *signal,
QObject *receiver,
const char *slot,
const Args&... args)
: Closure<Args...>(
sender.data(),
@ -155,8 +160,7 @@ class SharedClosure : public Closure<Args...> {
class CallbackClosure : public ClosureBase {
public:
CallbackClosure(QObject* sender, const char* signal,
std::function<void()> callback);
CallbackClosure(QObject *sender, const char *signal, std::function<void()> callback);
virtual void Invoke();
@ -167,11 +171,11 @@ class CallbackClosure : public ClosureBase {
} // namespace _detail
template <typename... Args>
_detail::ClosureBase* NewClosure(
QObject* sender,
const char* signal,
QObject* receiver,
const char* slot,
_detail::ClosureBase *NewClosure(
QObject *sender,
const char *signal,
QObject *receiver,
const char *slot,
const Args&... args) {
return new _detail::Closure<Args...>(
sender, signal, receiver, slot, args...);
@ -179,64 +183,64 @@ _detail::ClosureBase* NewClosure(
// QSharedPointer variant
template <typename T, typename... Args>
_detail::ClosureBase* NewClosure(
_detail::ClosureBase *NewClosure(
QSharedPointer<T> sender,
const char* signal,
QObject* receiver,
const char* slot,
const char *signal,
QObject *receiver,
const char *slot,
const Args&... args) {
return new _detail::SharedClosure<T, Args...>(
sender, signal, receiver, slot, args...);
}
_detail::ClosureBase* NewClosure(QObject* sender, const char* signal, std::function<void()> callback);
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::function<void()> callback);
template <typename... Args>
_detail::ClosureBase* NewClosure(QObject* sender, const char* signal, std::function<void(Args...)> callback, const Args&... args) {
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::function<void(Args...)> callback, const Args&... args) {
return NewClosure(sender, signal, std::bind(callback, args...));
}
template <typename... Args>
_detail::ClosureBase* NewClosure(
QObject* sender,
const char* signal,
_detail::ClosureBase *NewClosure(
QObject *sender,
const char *signal,
void (*callback)(Args...),
const Args&... args) {
return NewClosure(sender, signal, std::bind(callback, args...));
}
template <typename T, typename Unused, typename... Args>
_detail::ClosureBase* NewClosure(
QObject* sender,
const char* signal,
T* receiver, Unused (T::*callback)(Args...),
_detail::ClosureBase *NewClosure(
QObject *sender,
const char *signal,
T *receiver, Unused (T::*callback)(Args...),
const Args&... args) {
return NewClosure(sender, signal, std::bind(callback, receiver, args...));
}
template <typename T, typename... Args>
_detail::ClosureBase* NewClosure(QFuture<T> future, QObject* receiver, const char* slot, const Args&... args) {
QFutureWatcher<T>* watcher = new QFutureWatcher<T>;
_detail::ClosureBase *NewClosure(QFuture<T> future, QObject *receiver, const char *slot, const Args&... args) {
QFutureWatcher<T> *watcher = new QFutureWatcher<T>;
watcher->setFuture(future);
QObject::connect(watcher, SIGNAL(finished()), watcher, SLOT(deleteLater()));
return NewClosure(watcher, SIGNAL(finished()), receiver, slot, args...);
}
template <typename T, typename F, typename... Args>
_detail::ClosureBase* NewClosure(QFuture<T> future, const F& callback, const Args&... args) {
QFutureWatcher<T>* watcher = new QFutureWatcher<T>;
_detail::ClosureBase *NewClosure(QFuture<T> future, const F &callback, const Args&... args) {
QFutureWatcher<T> *watcher = new QFutureWatcher<T>;
watcher->setFuture(future);
QObject::connect(watcher, SIGNAL(finished()), watcher, SLOT(deleteLater()));
return NewClosure(watcher, SIGNAL(finished()), callback, args...);
}
void DoAfter(QObject* receiver, const char* slot, int msec);
void DoAfter(QObject *receiver, const char *slot, int msec);
void DoAfter(std::function<void()> callback, std::chrono::milliseconds msec);
void DoInAMinuteOrSo(QObject* receiver, const char* slot);
void DoInAMinuteOrSo(QObject *receiver, const char *slot);
template <typename R, typename P>
void DoAfter(std::function<void()> callback, std::chrono::duration<R, P> duration) {
QTimer* timer = new QTimer;
QTimer *timer = new QTimer;
timer->setSingleShot(true);
NewClosure(timer, SIGNAL(timeout()), callback);
QObject::connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater()));

View File

@ -55,9 +55,7 @@ class ThreadFunctorBase : public QFutureInterface<ReturnType>, public QRunnable
this->reportStarted();
Q_ASSERT(thread_pool);
QFuture<ReturnType> future = this->future();
thread_pool->start(this, 0 /* priority: currently we do not support
changing the priority. Might be added later
if needed */);
thread_pool->start(this, 0 /* priority: currently we do not support changing the priority. Might be added later if needed */);
return future;
}
@ -67,8 +65,7 @@ class ThreadFunctorBase : public QFutureInterface<ReturnType>, public QRunnable
template <typename ReturnType, typename... Args>
class ThreadFunctor : public ThreadFunctorBase<ReturnType> {
public:
ThreadFunctor(std::function<ReturnType (Args...)> function,
Args... args)
ThreadFunctor(std::function<ReturnType (Args...)> function, Args... args)
: function_(std::bind(function, args...)) {
}
@ -85,8 +82,7 @@ class ThreadFunctor : public ThreadFunctorBase<ReturnType> {
template <typename... Args>
class ThreadFunctor <void, Args...> : public ThreadFunctorBase<void> {
public:
ThreadFunctor(std::function<void (Args...)> function,
Args... args)
ThreadFunctor(std::function<void (Args...)> function, Args... args)
: function_(std::bind(function, args...)) {
}
@ -107,30 +103,20 @@ namespace ConcurrentRun {
// Empty argument form.
template <typename ReturnType>
QFuture<ReturnType> Run(
QThreadPool* threadpool,
std::function<ReturnType ()> function) {
QFuture<ReturnType> Run(QThreadPool* threadpool, std::function<ReturnType ()> function) {
return (new ThreadFunctor<ReturnType>(function))->Start(threadpool);
}
// Function object with arguments form.
template <typename ReturnType, typename... Args>
QFuture<ReturnType> Run(
QThreadPool* threadpool,
std::function<ReturnType (Args...)> function,
const Args&... args) {
return (new ThreadFunctor<ReturnType, Args...>(
function, args...))->Start(threadpool);
QFuture<ReturnType> Run(QThreadPool* threadpool, std::function<ReturnType (Args...)> function, const Args&... args) {
return (new ThreadFunctor<ReturnType, Args...>(function, args...))->Start(threadpool);
}
// Support passing C function pointers instead of function objects.
template <typename ReturnType, typename... Args>
QFuture<ReturnType> Run(
QThreadPool* threadpool,
ReturnType (*function) (Args...),
const Args&... args) {
return Run(
threadpool, std::function<ReturnType (Args...)>(function), args...);
QFuture<ReturnType> Run(QThreadPool* threadpool, ReturnType (*function) (Args...), const Args&... args) {
return Run(threadpool, std::function<ReturnType (Args...)>(function), args...);
}
}

View File

@ -14,21 +14,28 @@
limitations under the License.
*/
#include <glib.h>
#include <iostream>
#include <QtGlobal>
#include <QByteArray>
#include <QList>
#include <QMap>
#include <QString>
#include <QStringList>
#include <QRegExp>
#include <QDateTime>
#include <QIODevice>
#include <QtMessageHandler>
#include <QMessageLogContext>
#include <cxxabi.h>
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#ifdef Q_OS_UNIX
#include <execinfo.h>
#endif
#include <QCoreApplication>
#include <QDateTime>
#include <QStringList>
#include <QtMessageHandler>
#include "logging.h"
namespace logging {
@ -75,7 +82,7 @@ static void MessageHandler(QtMsgType type, const QMessageLogContext &context, co
default: level = Level_Debug; break;
}
for (const QString& line : message.split('\n')) {
for (const QString &line : message.split('\n')) {
CreateLogger(level, "unknown", -1) << line.toLocal8Bit().constData();
}

View File

@ -18,8 +18,10 @@
#define LOGGING_H
#include <chrono>
#include <string>
#include <QtGlobal>
#include <QIODevice>
#include <QString>
#include <QDebug>
#ifdef QT_NO_DEBUG_STREAM
@ -61,30 +63,30 @@ enum Level {
void DumpStackTrace();
QString ParsePrettyFunction(const char* pretty_function);
QString ParsePrettyFunction(const char *pretty_function);
QDebug CreateLogger(Level level, const QString &class_name, int line);
QDebug CreateLoggerFatal(int line, const char* class_name);
QDebug CreateLoggerError(int line, const char* class_name);
QDebug CreateLoggerFatal(int line, const char *class_name);
QDebug CreateLoggerError(int line, const char *class_name);
#ifdef QT_NO_WARNING_OUTPUT
QNoDebug CreateLoggerWarning(int, const char*);
#else
QDebug CreateLoggerWarning(int line, const char* class_name);
QDebug CreateLoggerWarning(int line, const char *class_name);
#endif // QT_NO_WARNING_OUTPUT
#ifdef QT_NO_DEBUG_OUTPUT
QNoDebug CreateLoggerInfo(int, const char*);
QNoDebug CreateLoggerDebug(int, const char*);
#else
QDebug CreateLoggerInfo(int line, const char* class_name);
QDebug CreateLoggerDebug(int line, const char* class_name);
QDebug CreateLoggerInfo(int line, const char *class_name);
QDebug CreateLoggerDebug(int line, const char *class_name);
#endif // QT_NO_DEBUG_OUTPUT
void GLog(const char* domain, int level, const char* message, void* user_data);
void GLog(const char *domain, int level, const char *message, void *user_data);
extern const char* kDefaultLogLevels;
extern const char *kDefaultLogLevels;
}
QDebug operator<<(QDebug debug, std::chrono::seconds secs);

View File

@ -15,11 +15,15 @@
*/
#include "messagehandler.h"
#include "core/logging.h"
#include <QObject>
#include <QAbstractSocket>
#include <QLocalSocket>
#include <QDataStream>
#include <QIODevice>
#include <QLocalSocket>
#include <QByteArray>
#include "core/logging.h"
_MessageHandlerBase::_MessageHandlerBase(QIODevice *device, QObject *parent)
: QObject(parent),

View File

@ -18,21 +18,21 @@
#ifndef MESSAGEHANDLER_H
#define MESSAGEHANDLER_H
#include <QBuffer>
#include <QMap>
#include <QMutex>
#include <QMutexLocker>
#include <string>
#include <QtGlobal>
#include <QObject>
#include <QSemaphore>
#include <QThread>
#include <QIODevice>
#include <QBuffer>
#include <QByteArray>
#include <QMap>
#include <QString>
#include <QLocalSocket>
#include <QAbstractSocket>
#include "core/logging.h"
#include "core/messagereply.h"
class QAbstractSocket;
class QIODevice;
class QLocalSocket;
#define QStringFromStdString(x) QString::fromUtf8(x.data(), x.size())
#define DataCommaSizeFromQString(x) x.toUtf8().constData(), x.toUtf8().length()
@ -45,27 +45,27 @@ class _MessageHandlerBase : public QObject {
public:
// device can be NULL, in which case you must call SetDevice before writing
// any messages.
_MessageHandlerBase(QIODevice* device, QObject* parent);
_MessageHandlerBase(QIODevice *device, QObject *parent);
void SetDevice(QIODevice* device);
void SetDevice(QIODevice *device);
// After this is true, messages cannot be sent to the handler any more.
bool is_device_closed() const { return is_device_closed_; }
protected slots:
void WriteMessage(const QByteArray& data);
void WriteMessage(const QByteArray &data);
void DeviceReadyRead();
virtual void DeviceClosed();
protected:
virtual bool RawMessageArrived(const QByteArray& data) = 0;
virtual bool RawMessageArrived(const QByteArray &data) = 0;
virtual void AbortAll() = 0;
protected:
typedef bool (QAbstractSocket::*FlushAbstractSocket)();
typedef bool (QLocalSocket::*FlushLocalSocket)();
QIODevice* device_;
QIODevice *device_;
FlushAbstractSocket flush_abstract_socket_;
FlushLocalSocket flush_local_socket_;
@ -82,7 +82,7 @@ protected:
template <typename MT>
class AbstractMessageHandler : public _MessageHandlerBase {
public:
AbstractMessageHandler(QIODevice* device, QObject* parent);
AbstractMessageHandler(QIODevice *device, QObject *parent);
~AbstractMessageHandler() { AbortAll(); }
typedef MT MessageType;
@ -90,27 +90,27 @@ public:
// Serialises the message and writes it to the socket. This version MUST be
// called from the thread in which the AbstractMessageHandler was created.
void SendMessage(const MessageType& message);
void SendMessage(const MessageType &message);
// Serialises the message and writes it to the socket. This version may be
// called from any thread.
void SendMessageAsync(const MessageType& message);
void SendMessageAsync(const MessageType &message);
// Sends the request message inside and takes ownership of the MessageReply.
// The MessageReply's Finished() signal will be emitted when a reply arrives
// with the same ID. Must be called from my thread.
void SendRequest(ReplyType* reply);
void SendRequest(ReplyType *reply);
// Sets the "id" field of reply to the same as the request, and sends the
// reply on the socket. Used on the worker side.
void SendReply(const MessageType& request, MessageType* reply);
void SendReply(const MessageType &request, MessageType *reply);
protected:
// Called when a message is received from the socket.
virtual void MessageArrived(const MessageType& message) {}
virtual void MessageArrived(const MessageType &message) {}
// _MessageHandlerBase
bool RawMessageArrived(const QByteArray& data);
bool RawMessageArrived(const QByteArray &data);
void AbortAll();
private:
@ -118,12 +118,11 @@ private:
};
template <typename MT>
AbstractMessageHandler<MT>::AbstractMessageHandler(QIODevice* device,
QObject* parent)
AbstractMessageHandler<MT>::AbstractMessageHandler(QIODevice *device, QObject *parent)
: _MessageHandlerBase(device, parent) {}
template <typename MT>
void AbstractMessageHandler<MT>::SendMessage(const MessageType& message) {
void AbstractMessageHandler<MT>::SendMessage(const MessageType &message) {
Q_ASSERT(QThread::currentThread() == thread());
std::string data = message.SerializeAsString();
@ -131,33 +130,32 @@ void AbstractMessageHandler<MT>::SendMessage(const MessageType& message) {
}
template <typename MT>
void AbstractMessageHandler<MT>::SendMessageAsync(const MessageType& message) {
void AbstractMessageHandler<MT>::SendMessageAsync(const MessageType &message) {
std::string data = message.SerializeAsString();
metaObject()->invokeMethod(this, "WriteMessage", Qt::QueuedConnection,
Q_ARG(QByteArray, QByteArray(data.data(), data.size())));
}
template<typename MT>
void AbstractMessageHandler<MT>::SendRequest(ReplyType* reply) {
void AbstractMessageHandler<MT>::SendRequest(ReplyType *reply) {
pending_replies_[reply->id()] = reply;
SendMessage(reply->request_message());
}
template<typename MT>
void AbstractMessageHandler<MT>::SendReply(const MessageType& request,
MessageType* reply) {
void AbstractMessageHandler<MT>::SendReply(const MessageType &request, MessageType *reply) {
reply->set_id(request.id());
SendMessage(*reply);
}
template<typename MT>
bool AbstractMessageHandler<MT>::RawMessageArrived(const QByteArray& data) {
bool AbstractMessageHandler<MT>::RawMessageArrived(const QByteArray &data) {
MessageType message;
if (!message.ParseFromArray(data.constData(), data.size())) {
return false;
}
ReplyType* reply = pending_replies_.take(message.id());
ReplyType *reply = pending_replies_.take(message.id());
if (reply) {
// This is a reply to a message that we created earlier.
@ -171,7 +169,7 @@ bool AbstractMessageHandler<MT>::RawMessageArrived(const QByteArray& data) {
template<typename MT>
void AbstractMessageHandler<MT>::AbortAll() {
for (ReplyType* reply : pending_replies_) {
for (ReplyType *reply : pending_replies_) {
reply->Abort();
}
pending_replies_.clear();

View File

@ -17,6 +17,11 @@
#include "messagereply.h"
#include <QObject>
#include <QtDebug>
#include "core/logging.h"
_MessageReplyBase::_MessageReplyBase(QObject *parent)
: QObject(parent), finished_(false), success_(false) {}

View File

@ -18,26 +18,26 @@
#ifndef MESSAGEREPLY_H
#define MESSAGEREPLY_H
#include <QtGlobal>
#include <QObject>
#include <QSemaphore>
#include <QString>
#include "core/logging.h"
// Base QObject for a reply future class that is returned immediately for
// requests that will occur in the background. Similar to QNetworkReply.
// Use MessageReply instead.
// Base QObject for a reply future class that is returned immediately for requests that will occur in the background.
// Similar to QNetworkReply. Use MessageReply instead.
class _MessageReplyBase : public QObject {
Q_OBJECT
public:
_MessageReplyBase(QObject* parent = nullptr);
_MessageReplyBase(QObject *parent = nullptr);
virtual int id() const = 0;
bool is_finished() const { return finished_; }
bool is_successful() const { return success_; }
// Waits for the reply to finish by waiting on a semaphore. Never call this
// from the MessageHandler's thread or it will block forever.
// Waits for the reply to finish by waiting on a semaphore. Never call this from the MessageHandler's thread or it will block forever.
// Returns true if the call was successful.
bool WaitForFinished();
@ -58,7 +58,7 @@ protected:
template <typename MessageType>
class MessageReply : public _MessageReplyBase {
public:
MessageReply(const MessageType& request_message, QObject* parent = nullptr);
MessageReply(const MessageType& request_message, QObject *parent = nullptr);
int id() const { return request_message_.id(); }
const MessageType& request_message() const { return request_message_; }
@ -73,8 +73,7 @@ private:
template<typename MessageType>
MessageReply<MessageType>::MessageReply(const MessageType& request_message,
QObject* parent)
MessageReply<MessageType>::MessageReply(const MessageType& request_message, QObject *parent)
: _MessageReplyBase(parent)
{
request_message_.MergeFrom(request_message);
@ -94,4 +93,3 @@ void MessageReply<MessageType>::SetReply(const MessageType& message) {
}
#endif // MESSAGEREPLY_H

View File

@ -17,6 +17,7 @@
#include "waitforsignal.h"
#include <QObject>
#include <QEventLoop>
void WaitForSignal(QObject *sender, const char *signal) {

View File

@ -15,6 +15,8 @@
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QObject>
#include "workerpool.h"
_WorkerPoolBase::_WorkerPoolBase(QObject *parent) : QObject(parent) {}

View File

@ -18,32 +18,37 @@
#ifndef WORKERPOOL_H
#define WORKERPOOL_H
#include <QAtomicInt>
#include <QCoreApplication>
#include <QFile>
#include <QLocalServer>
#include <QLocalSocket>
#include <QMutex>
#include <stddef.h>
#include <QtGlobal>
#include <QObject>
#include <QCoreApplication>
#include <QThread>
#include <QMutex>
#include <QProcess>
#include <QQueue>
#include <QThread>
#include <QFile>
#include <QList>
#include <QLocalServer>
#include <QLocalSocket>
#include <QString>
#include <QStringList>
#include <QAtomicInt>
#include "core/closure.h"
#include "core/logging.h"
class QLocalSocket;
// Base class containing signals and slots - required because moc doesn't do
// templated objects.
// Base class containing signals and slots - required because moc doesn't do templated objects.
class _WorkerPoolBase : public QObject {
Q_OBJECT
public:
_WorkerPoolBase(QObject* parent = nullptr);
_WorkerPoolBase(QObject *parent = nullptr);
signals:
// Emitted when a worker failed to start. This usually happens when the
// worker wasn't found, or couldn't be executed.
// Emitted when a worker failed to start. This usually happens when the worker wasn't found, or couldn't be executed.
void WorkerFailedToStart();
protected slots:
@ -54,45 +59,41 @@ protected slots:
};
// Manages a pool of one or more external processes. A local socket server is
// started for each process, and the address is passed to the process as
// argv[1]. The process is expected to connect back to the socket server, and
// when it does a HandlerType is created for it.
// Manages a pool of one or more external processes.
// A local socket server is started for each process, and the address is passed to the process as argv[1].
// The process is expected to connect back to the socket server, and when it does a HandlerType is created for it.
// Instances of HandlerType are created in the WorkerPool's thread.
template <typename HandlerType>
class WorkerPool : public _WorkerPoolBase {
public:
WorkerPool(QObject* parent = nullptr);
WorkerPool(QObject *parent = nullptr);
~WorkerPool();
typedef typename HandlerType::MessageType MessageType;
typedef typename HandlerType::ReplyType ReplyType;
// Sets the name of the worker executable. This is looked for first in the
// current directory, and then in $PATH. You must call this before calling
// Start().
void SetExecutableName(const QString& executable_name);
// Sets the name of the worker executable. This is looked for first in the current directory, and then in $PATH.
// You must call this before calling Start().
void SetExecutableName(const QString &executable_name);
// Sets the number of worker process to use. Defaults to
// 1 <= (processors / 2) <= 2.
// Sets the number of worker process to use. Defaults to 1 <= (processors / 2) <= 2.
void SetWorkerCount(int count);
// Sets the prefix to use for the local server (on unix this is a named pipe
// in /tmp). Defaults to QApplication::applicationName(). A random number
// is appended to this name when creating each server.
void SetLocalServerName(const QString& local_server_name);
// Sets the prefix to use for the local server (on unix this is a named pipe in /tmp).
// Defaults to QApplication::applicationName().
// A random number is appended to this name when creating each server.
void SetLocalServerName(const QString &local_server_name);
// Starts all workers.
void Start();
// Fills in the message's "id" field and creates a reply future. The message
// is queued and the WorkerPool's thread will send it to the next available
// worker. Can be called from any thread.
ReplyType* SendMessageWithReply(MessageType* message);
// Fills in the message's "id" field and creates a reply future.
// The message is queued and the WorkerPool's thread will send it to the next available worker.
// Can be called from any thread.
ReplyType *SendMessageWithReply(MessageType *message);
protected:
// These are all reimplemented slots, they are called on the WorkerPool's
// thread.
// These are all reimplemented slots, they are called on the WorkerPool's thread.
void DoStart();
void NewConnection();
void ProcessError(QProcess::ProcessError error);
@ -105,14 +106,14 @@ private:
QLocalServer *local_server_;
QLocalSocket *local_socket_;
QProcess *process_;
HandlerType* handler_;
HandlerType *handler_;
};
// Must only ever be called on my thread.
void StartOneWorker(Worker* worker);
void StartOneWorker(Worker *worker);
template <typename T>
Worker* FindWorker(T Worker::*member, T value) {
Worker *FindWorker(T Worker::*member, T value) {
for (typename QList<Worker>::iterator it = workers_.begin() ;
it != workers_.end() ; ++it) {
if ((*it).*member == value) {
@ -123,7 +124,7 @@ private:
}
template <typename T>
void DeleteQObjectPointerLater(T** p) {
void DeleteQObjectPointerLater(T **p) {
if (*p) {
(*p)->deleteLater();
*p = NULL;
@ -131,13 +132,11 @@ private:
}
// Creates a new reply future for the request with the next sequential ID,
// and sets the request's ID to the ID of the reply. Can be called from any
// thread
ReplyType* NewReply(MessageType* message);
// and sets the request's ID to the ID of the reply. Can be called from any thread
ReplyType *NewReply(MessageType *message);
// Returns the next handler, or NULL if there isn't one. Must be called from
// my thread.
HandlerType* NextHandler() const;
// Returns the next handler, or NULL if there isn't one. Must be called from my thread.
HandlerType *NextHandler() const;
private:
QString local_server_name_;
@ -156,7 +155,7 @@ private:
template <typename HandlerType>
WorkerPool<HandlerType>::WorkerPool(QObject* parent)
WorkerPool<HandlerType>::WorkerPool(QObject *parent)
: _WorkerPoolBase(parent),
next_worker_(0),
next_id_(0)
@ -170,7 +169,7 @@ WorkerPool<HandlerType>::WorkerPool(QObject* parent)
template <typename HandlerType>
WorkerPool<HandlerType>::~WorkerPool() {
for (const Worker& worker : workers_) {
for (const Worker &worker : workers_) {
if (worker.local_socket_ && worker.process_) {
disconnect(worker.process_, SIGNAL(error(QProcess::ProcessError)), this, SLOT(ProcessError(QProcess::ProcessError)));
@ -190,7 +189,7 @@ WorkerPool<HandlerType>::~WorkerPool() {
}
}
for (ReplyType* reply : message_queue_) {
for (ReplyType *reply : message_queue_) {
reply->Abort();
}
}
@ -202,13 +201,13 @@ void WorkerPool<HandlerType>::SetWorkerCount(int count) {
}
template <typename HandlerType>
void WorkerPool<HandlerType>::SetLocalServerName(const QString& local_server_name) {
void WorkerPool<HandlerType>::SetLocalServerName(const QString &local_server_name) {
Q_ASSERT(workers_.isEmpty());
local_server_name_ = local_server_name;
}
template <typename HandlerType>
void WorkerPool<HandlerType>::SetExecutableName(const QString& executable_name) {
void WorkerPool<HandlerType>::SetExecutableName(const QString &executable_name) {
Q_ASSERT(workers_.isEmpty());
executable_name_ = executable_name;
}
@ -233,7 +232,7 @@ void WorkerPool<HandlerType>::DoStart() {
search_path << qApp->applicationDirPath() + "/../PlugIns";
#endif
for (const QString& path_prefix : search_path) {
for (const QString &path_prefix : search_path) {
const QString executable_path = path_prefix + "/" + executable_name_;
if (QFile::exists(executable_path)) {
executable_path_ = executable_path;
@ -290,7 +289,7 @@ void WorkerPool<HandlerType>::NewConnection() {
QLocalServer *server = qobject_cast<QLocalServer*>(sender());
// Find the worker with this server.
Worker* worker = FindWorker(&Worker::local_server_, server);
Worker *worker = FindWorker(&Worker::local_server_, server);
if (!worker) return;
qLog(Debug) << "Worker" << worker << "connected to" << server->fullServerName();
@ -322,9 +321,8 @@ void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
switch (error) {
case QProcess::FailedToStart:
// Failed to start errors are bad - it usually means the worker isn't
// installed. Don't restart the process, but tell our owner, who will
// probably want to do something fatal.
// Failed to start errors are bad - it usually means the worker isn't installed.
// Don't restart the process, but tell our owner, who will probably want to do something fatal.
qLog(Error) << "Worker failed to start";
emit WorkerFailedToStart();
break;
@ -339,7 +337,7 @@ void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
template <typename HandlerType>
typename WorkerPool<HandlerType>::ReplyType*
WorkerPool<HandlerType>::NewReply(MessageType* message) {
WorkerPool<HandlerType>::NewReply(MessageType *message) {
const int id = next_id_.fetchAndAddOrdered(1);
message->set_id(id);
@ -348,8 +346,8 @@ WorkerPool<HandlerType>::NewReply(MessageType* message) {
template <typename HandlerType>
typename WorkerPool<HandlerType>::ReplyType*
WorkerPool<HandlerType>::SendMessageWithReply(MessageType* message) {
ReplyType* reply = NewReply(message);
WorkerPool<HandlerType>::SendMessageWithReply(MessageType *message) {
ReplyType *reply = NewReply(message);
// Add the pending reply to the queue
{
@ -371,7 +369,7 @@ void WorkerPool<HandlerType>::SendQueuedMessages() {
ReplyType *reply = message_queue_.dequeue();
// Find a worker for this message
HandlerType* handler = NextHandler();
HandlerType *handler = NextHandler();
if (!handler) {
// No available handlers - put the message on the front of the queue.
message_queue_.prepend(reply);

View File

@ -15,12 +15,15 @@
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include "fmpsparser.h"
#include "config.h"
#include <functional>
#include <QStringList>
#include <QtDebug>
#include <QList>
#include <QVariant>
#include <QString>
#include "fmpsparser.h"
using std::placeholders::_1;
using std::placeholders::_2;
@ -114,8 +117,7 @@ int FMPSParser::ParseListListRef(const QStringRef &data, Result *ret) const {
return ParseContainer<';'>(data, std::bind(&FMPSParser::ParseListRef, this, _1, _2), ret);
}
// Convenience functions that take QStrings instead of QStringRefs. Use the
// QStringRef versions if possible, they're faster.
// Convenience functions that take QStrings instead of QStringRefs. Use the QStringRef versions if possible, they're faster.
int FMPSParser::ParseValue(const QString &data, QVariant *ret) const {
return ParseValueRef(QStringRef(&data), ret);
}

View File

@ -18,8 +18,13 @@
#ifndef FMPSPARSER_H
#define FMPSPARSER_H
#include "config.h"
#include <QList>
#include <QMetaType>
#include <QVariant>
#include <QString>
#include <QRegExp>
#include <QVariantList>
class FMPSParser {
public:
@ -30,7 +35,7 @@ public:
typedef QList<QVariantList> Result;
// Parses a FMPS value and returns true on success.
bool Parse(const QString& data);
bool Parse(const QString &data);
// Gets the result of the last successful Parse.
Result result() const { return result_; }

View File

@ -15,50 +15,75 @@
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "tagreader.h"
#include <memory>
#include <QCoreApplication>
#include <QDateTime>
#include <QFileInfo>
#include <QNetworkAccessManager>
#include <QTextCodec>
#include <QUrl>
#include <QVector>
#include <aifffile.h>
#include <asffile.h>
#include <attachedpictureframe.h>
#include <commentsframe.h>
#include <fileref.h>
#include <audioproperties.h>
#include <flacfile.h>
#include <flacproperties.h>
#include <id3v2tag.h>
#include <mp4file.h>
#include <mp4tag.h>
#include <mpcfile.h>
#include <mpegfile.h>
#include <oggfile.h>
#ifdef TAGLIB_HAS_OPUS
#include <opusfile.h>
#endif
#include <oggflacfile.h>
#include <popularimeterframe.h>
#include <speexfile.h>
#include <tag.h>
#include <textidentificationframe.h>
#include <trueaudiofile.h>
#include <tstring.h>
#include <vorbisfile.h>
#include <wavfile.h>
#include <list>
#include <map>
#include <utility>
#include <sys/stat.h>
#include "fmpsparser.h"
#include <taglib/taglib.h>
#include <taglib/taglib_config.h>
#include <taglib/fileref.h>
#include <taglib/tbytevector.h>
#include <taglib/tfile.h>
#include <taglib/tlist.h>
#include <taglib/tstring.h>
#include <taglib/tstringlist.h>
#include <taglib/audioproperties.h>
#include <taglib/trueaudiofile.h>
#include <taglib/attachedpictureframe.h>
#include <taglib/textidentificationframe.h>
#include <taglib/xiphcomment.h>
#include <taglib/commentsframe.h>
#include <taglib/tag.h>
#include <taglib/id3v2tag.h>
#include "taglib/id3v2frame.h"
#include <taglib/flacfile.h>
#include <taglib/oggflacfile.h>
#include <taglib/flacproperties.h>
#include <taglib/flacpicture.h>
#include <taglib/vorbisfile.h>
#include <taglib/speexfile.h>
#include <taglib/wavfile.h>
#include <taglib/aifffile.h>
#include <taglib/asffile.h>
#include "taglib/asftag.h"
#include "taglib/asfattribute.h"
#include "taglib/asfproperties.h"
#include <taglib/mp4file.h>
#include <taglib/mp4tag.h>
#include "taglib/mp4item.h"
#include <taglib/mp4coverart.h>
#include <taglib/mp4properties.h>
#include <taglib/mpcfile.h>
#include <taglib/mpegfile.h>
#ifdef TAGLIB_HAS_OPUS
#include <taglib/opusfile.h>
#endif
#include <QtGlobal>
#include <QFile>
#include <QFileInfo>
#include <QList>
#include <QByteArray>
#include <QDateTime>
#include <QVariant>
#include <QString>
#include <QUrl>
#include <QTextCodec>
#include <QVector>
#include <QNetworkAccessManager>
#include <QtDebug>
#include "core/logging.h"
#include "core/messagehandler.h"
#include "fmpsparser.h"
#include "core/timeconstants.h"
// Taglib added support for FLAC pictures in 1.7.0
@ -71,12 +96,12 @@
class FileRefFactory {
public:
virtual ~FileRefFactory() {}
virtual TagLib::FileRef *GetFileRef(const QString& filename) = 0;
virtual TagLib::FileRef *GetFileRef(const QString &filename) = 0;
};
class TagLibFileRefFactory : public FileRefFactory {
public:
virtual TagLib::FileRef *GetFileRef(const QString& filename) {
virtual TagLib::FileRef *GetFileRef(const QString &filename) {
#ifdef Q_OS_WIN32
return new TagLib::FileRef(filename.toStdWString().c_str());
#else
@ -87,11 +112,11 @@ class TagLibFileRefFactory : public FileRefFactory {
namespace {
TagLib::String StdStringToTaglibString(const std::string& s) {
TagLib::String StdStringToTaglibString(const std::string &s) {
return TagLib::String(s.c_str(), TagLib::String::UTF8);
}
TagLib::String QStringToTaglibString(const QString& s) {
TagLib::String QStringToTaglibString(const QString &s) {
return TagLib::String(s.toUtf8().constData(), TagLib::String::UTF8);
}
@ -508,8 +533,7 @@ bool TagReader::SaveFile(const QString &filename, const pb::tagreader::SongMetad
}
// Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same way;
// apart, so we keep specific behavior for some formats by adding another
// "else if" block above.
// apart, so we keep specific behavior for some formats by adding another "else if" block above.
if (TagLib::Ogg::XiphComment *tag = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
SetVorbisComments(tag, song);
}
@ -625,9 +649,7 @@ QByteArray TagReader::LoadEmbeddedArt(const QString &filename) const {
TagLib::Ogg::FieldListMap map = xiph_comment->fieldListMap();
#if TAGLIB_MAJOR_VERSION <= 1 && TAGLIB_MINOR_VERSION < 11
// Other than the below mentioned non-standard COVERART,
// METADATA_BLOCK_PICTURE
// is the proposed tag for cover pictures.
// Other than the below mentioned non-standard COVERART, METADATA_BLOCK_PICTURE is the proposed tag for cover pictures.
// (see http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE)
if (map.contains("METADATA_BLOCK_PICTURE")) {
TagLib::StringList pict_list = map["METADATA_BLOCK_PICTURE"];
@ -687,10 +709,10 @@ QByteArray TagReader::LoadEmbeddedArt(const QString &filename) const {
TagLib::MP4::File *aac_file = dynamic_cast<TagLib::MP4::File*>(ref.file());
if (aac_file) {
TagLib::MP4::Tag *tag = aac_file->tag();
const TagLib::MP4::ItemListMap& items = tag->itemListMap();
const TagLib::MP4::ItemListMap &items = tag->itemListMap();
TagLib::MP4::ItemListMap::ConstIterator it = items.find("covr");
if (it != items.end()) {
const TagLib::MP4::CoverArtList& art_list = it->second.toCoverArtList();
const TagLib::MP4::CoverArtList &art_list = it->second.toCoverArtList();
if (!art_list.isEmpty()) {
// Just take the first one for now

View File

@ -18,18 +18,19 @@
#ifndef TAGREADER_H
#define TAGREADER_H
#include "config.h"
#include <string>
#include <QByteArray>
#include <QString>
#include <QNetworkAccessManager>
#include <QTextCodec>
#include <taglib/xiphcomment.h>
#include "config.h"
#include "tagreadermessages.pb.h"
class QNetworkAccessManager;
class QString;
class QTextCodec;
class QUrl;
namespace TagLib {
class FileRef;
class String;
@ -44,15 +45,14 @@ class FileRefFactory;
/**
* This class holds all useful methods to read and write tags from/to files.
* You should not use it directly in the main process but rather use a
* TagReaderWorker process (using TagReaderClient)
* You should not use it directly in the main process but rather use a TagReaderWorker process (using TagReaderClient)
*/
class TagReader {
public:
TagReader();
void ReadFile(const QString& filename, pb::tagreader::SongMetadata *song) const;
bool SaveFile(const QString& filename, const pb::tagreader::SongMetadata &song) const;
void ReadFile(const QString &filename, pb::tagreader::SongMetadata *song) const;
bool SaveFile(const QString &filename, const pb::tagreader::SongMetadata &song) const;
bool IsMediaFile(const QString &filename) const;
QByteArray LoadEmbeddedArt(const QString &filename) const;

View File

@ -15,16 +15,23 @@
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tagreaderworker.h"
#include "core/logging.h"
#include "config.h"
#include <sys/time.h>
#include <iostream>
#include <QtGlobal>
#include <QCoreApplication>
#include <QList>
#include <QLocalSocket>
#include <QSsl>
#include <QSslCertificate>
#include <QSslSocket>
#include <QStringList>
#include <QtDebug>
#include <iostream>
#include <sys/time.h>
#include "core/logging.h"
#include "tagreaderworker.h"
int main(int argc, char **argv) {

View File

@ -15,15 +15,16 @@
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tagreaderworker.h"
#include "config.h"
#include <string>
#include <QCoreApplication>
#include <QDateTime>
#include <QFileInfo>
#include <QNetworkAccessManager>
#include <QTextCodec>
#include <QUrl>
#include <QObject>
#include <QIODevice>
#include <QByteArray>
#include "tagreaderworker.h"
TagReaderWorker::TagReaderWorker(QIODevice *socket, QObject *parent)
: AbstractMessageHandler<pb::tagreader::Message>(socket, parent)

View File

@ -19,9 +19,15 @@
#define TAGREADERWORKER_H
#include "config.h"
#include <stddef.h>
#include <QObject>
#include <QIODevice>
#include "core/messagehandler.h"
#include "tagreader.h"
#include "tagreadermessages.pb.h"
#include "core/messagehandler.h"
class TagReaderWorker : public AbstractMessageHandler<pb::tagreader::Message> {
public:

View File

@ -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})

View File

@ -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_) {

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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_;
};

View File

@ -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());

View File

@ -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;

View File

@ -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());
}

View File

@ -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;

View File

@ -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) {

View File

@ -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

View File

@ -23,9 +23,6 @@
#include "config.h"
#include <QString>
#include <QList>
#include "core/simpletreeitem.h"
#include "core/song.h"

View File

@ -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);

View File

@ -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_;

View File

@ -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) {}

View File

@ -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);

View File

@ -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);
}

View File

@ -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 = "=");

View File

@ -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;

View File

@ -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);

View File

@ -20,6 +20,11 @@
#include "config.h"
#include <QWidget>
#include <QKeyEvent>
#include "collectionfilterwidget.h"
#include "collectionview.h"
#include "collectionviewcontainer.h"
#include "ui_collectionviewcontainer.h"

View File

@ -23,6 +23,7 @@
#include "config.h"
#include <QObject>
#include <QWidget>
class CollectionFilterWidget;

View File

@ -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;
}

View File

@ -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_;

View File

@ -23,11 +23,10 @@
#include "config.h"
#include <QMetaType>
#include <QList>
#include <QString>
#include <QMetaType>
class QSqlQuery;
#include <QSqlQuery>
struct Directory {
Directory() : id(-1) {}

View File

@ -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();

View File

@ -26,6 +26,9 @@
#include <memory>
#include <QDialog>
#include <QObject>
#include <QWidget>
#include <QString>
#include "collectionmodel.h"

View File

@ -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());

View File

@ -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

View File

@ -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); }

View File

@ -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_;

View File

@ -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";

View File

@ -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:

View File

@ -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) {

View File

@ -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_;

View File

@ -23,6 +23,8 @@
#include "config.h"
#include <QList>
#include <QString>
#include <QDateTime>
#include <QSettings>

View File

@ -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]);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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) {}

View File

@ -23,8 +23,10 @@
#include "config.h"
#include <QtGlobal>
#include <QString>
#include "config.h"
#include "screensaver.h"
class DBusScreensaver : public Screensaver {

View File

@ -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();

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More