Merge branch 'master' into c++11
This commit is contained in:
commit
767965a2f4
|
@ -183,31 +183,39 @@ static const unsigned int KeyTbl[] = {
|
|||
|
||||
// numeric and function keypad keys
|
||||
|
||||
XK_KP_Space, Qt::Key_Space,
|
||||
XK_KP_Tab, Qt::Key_Tab,
|
||||
XK_KP_Enter, Qt::Key_Enter,
|
||||
//XK_KP_F1, Qt::Key_F1,
|
||||
//XK_KP_F2, Qt::Key_F2,
|
||||
//XK_KP_F3, Qt::Key_F3,
|
||||
//XK_KP_F4, Qt::Key_F4,
|
||||
XK_KP_Home, Qt::Key_Home,
|
||||
XK_KP_Left, Qt::Key_Left,
|
||||
XK_KP_Up, Qt::Key_Up,
|
||||
XK_KP_Right, Qt::Key_Right,
|
||||
XK_KP_Down, Qt::Key_Down,
|
||||
XK_KP_Prior, Qt::Key_PageUp,
|
||||
XK_KP_Next, Qt::Key_PageDown,
|
||||
XK_KP_End, Qt::Key_End,
|
||||
XK_KP_Begin, Qt::Key_Clear,
|
||||
XK_KP_Insert, Qt::Key_Insert,
|
||||
XK_KP_Delete, Qt::Key_Delete,
|
||||
XK_KP_Equal, Qt::Key_Equal,
|
||||
XK_KP_Multiply, Qt::Key_Asterisk,
|
||||
XK_KP_Add, Qt::Key_Plus,
|
||||
XK_KP_Separator, Qt::Key_Comma,
|
||||
XK_KP_Subtract, Qt::Key_Minus,
|
||||
XK_KP_Decimal, Qt::Key_Period,
|
||||
XK_KP_Divide, Qt::Key_Slash,
|
||||
|
||||
// special and additional keys
|
||||
|
||||
XK_Clear, Qt::Key_Clear,
|
||||
XK_Delete, Qt::Key_Delete,
|
||||
XK_space, Qt::Key_Space,
|
||||
XK_exclam, Qt::Key_Exclam,
|
||||
XK_quotedbl, Qt::Key_QuoteDbl,
|
||||
XK_numbersign, Qt::Key_NumberSign,
|
||||
XK_dollar, Qt::Key_Dollar,
|
||||
XK_percent, Qt::Key_Percent,
|
||||
XK_ampersand, Qt::Key_Ampersand,
|
||||
XK_apostrophe, Qt::Key_Apostrophe,
|
||||
XK_parenleft, Qt::Key_ParenLeft,
|
||||
XK_parenright, Qt::Key_ParenRight,
|
||||
XK_asterisk, Qt::Key_Asterisk,
|
||||
XK_plus, Qt::Key_Plus,
|
||||
XK_comma, Qt::Key_Comma,
|
||||
XK_minus, Qt::Key_Minus,
|
||||
XK_period, Qt::Key_Period,
|
||||
XK_slash, Qt::Key_Slash,
|
||||
XK_colon, Qt::Key_Colon,
|
||||
XK_semicolon, Qt::Key_Semicolon,
|
||||
XK_less, Qt::Key_Less,
|
||||
XK_equal, Qt::Key_Equal,
|
||||
XK_greater, Qt::Key_Greater,
|
||||
XK_question, Qt::Key_Question,
|
||||
XK_bracketleft, Qt::Key_BracketLeft,
|
||||
XK_backslash, Qt::Key_Backslash,
|
||||
XK_bracketright, Qt::Key_BracketRight,
|
||||
XK_asciicircum, Qt::Key_AsciiCircum,
|
||||
XK_underscore, Qt::Key_Underscore,
|
||||
|
||||
// International input method support keys
|
||||
|
||||
|
|
|
@ -96,11 +96,9 @@ find_path(SPARSEHASH_INCLUDE_DIRS google/sparsetable)
|
|||
# distros. If the user seems to want Drive support (ie. they have sparsehash
|
||||
# installed and haven't disabled drive), and has an old taglib, compile our
|
||||
# internal one and use that instead.
|
||||
option(USE_BUILTIN_TAGLIB "If the system's version of Taglib is too old for Google Drive support, compile our builtin version instead" ON)
|
||||
if (USE_BUILTIN_TAGLIB AND
|
||||
(NOT "${ENABLE_GOOGLE_DRIVE}" STREQUAL "OFF") AND
|
||||
SPARSEHASH_INCLUDE_DIRS AND
|
||||
TAGLIB_VERSION VERSION_LESS 1.8)
|
||||
option(USE_BUILTIN_TAGLIB "If the system's version of Taglib is too old, compile our builtin version instead" ON)
|
||||
if (USE_BUILTIN_TAGLIB AND TAGLIB_VERSION VERSION_LESS 1.8)
|
||||
message(STATUS "Using builtin taglib because your system's version is too old")
|
||||
set(TAGLIB_VERSION 1.9.1)
|
||||
set(TAGLIB_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/3rdparty/taglib/headers/taglib/;${CMAKE_BINARY_DIR}/3rdparty/taglib/headers/")
|
||||
set(TAGLIB_LIBRARY_DIRS "")
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
Clementine
|
||||
==========
|
||||
|
||||
Clementine is a modern music player and library organizer for Windows, Linux and Mac OS X.
|
||||
|
||||
- Website: http://www.clementine-player.org/
|
||||
- Github: https://github.com/clementine-player/Clementine
|
||||
- Buildbot: http://buildbot.clementine-player.org/grid
|
||||
- Latest developer builds: http://builds.clementine-player.org/
|
||||
|
||||
Compiling from source
|
||||
---------------------
|
||||
|
||||
Get the code (if you haven't already):
|
||||
|
||||
git clone https://github.com/clementine-player/Clementine.git && cd Clementine
|
||||
|
||||
Compile and install:
|
||||
|
||||
cd bin
|
||||
cmake ..
|
||||
make -j8
|
||||
sudo make install
|
||||
|
||||
See the Wiki for more instructions and a list of dependencies:
|
||||
https://github.com/clementine-player/Clementine/wiki/Compiling-from-Source
|
|
@ -1027,9 +1027,13 @@ optional_source(HAVE_AUDIOCD
|
|||
SOURCES
|
||||
devices/cddadevice.cpp
|
||||
devices/cddalister.cpp
|
||||
ui/ripcd.cpp
|
||||
HEADERS
|
||||
devices/cddadevice.h
|
||||
devices/cddalister.h
|
||||
ui/ripcd.h
|
||||
UI
|
||||
ui/ripcd.ui
|
||||
)
|
||||
|
||||
# mtp device
|
||||
|
|
|
@ -451,4 +451,12 @@ void EnableFullScreen(const QWidget& main_window) {
|
|||
[window setCollectionBehavior: kFullScreenPrimary];
|
||||
}
|
||||
|
||||
float GetDevicePixelRatio(QWidget* widget) {
|
||||
NSView* view = reinterpret_cast<NSView*>(widget->winId());
|
||||
if ([[view window] respondsToSelector: @selector(backingScaleFactor)]) {
|
||||
return [[view window] backingScaleFactor];
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
} // namespace mac
|
||||
|
|
|
@ -29,5 +29,6 @@ namespace mac {
|
|||
|
||||
QKeySequence KeySequenceFromNSEvent(NSEvent* event);
|
||||
void DumpDictionary(CFDictionaryRef dict);
|
||||
float GetDevicePixelRatio(QWidget* widget);
|
||||
|
||||
}
|
||||
|
|
|
@ -797,7 +797,7 @@ void Song::BindToQuery(QSqlQuery *query) const {
|
|||
&& Utilities::UrlOnSameDriveAsClementine(d->url_)) {
|
||||
query->bindValue(":filename", Utilities::GetRelativePathToClementineBin(d->url_));
|
||||
} else {
|
||||
query->bindValue(":filename", d->url_);
|
||||
query->bindValue(":filename", d->url_.toEncoded());
|
||||
}
|
||||
|
||||
query->bindValue(":mtime", notnullintval(d->mtime_));
|
||||
|
|
|
@ -33,16 +33,17 @@
|
|||
#include "config.h"
|
||||
#include "core/concurrentrun.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/song.h"
|
||||
#include "core/player.h"
|
||||
#include "core/signalchecker.h"
|
||||
#include "core/song.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "core/timeconstants.h"
|
||||
#include "internet/fixlastfm.h"
|
||||
#include "internet/internetmodel.h"
|
||||
#include "library/librarybackend.h"
|
||||
#include "library/sqlrow.h"
|
||||
#include "playlistparsers/parserbase.h"
|
||||
#include "playlistparsers/cueparser.h"
|
||||
#include "playlistparsers/parserbase.h"
|
||||
#include "playlistparsers/playlistparser.h"
|
||||
#include "podcasts/podcastparser.h"
|
||||
#include "podcasts/podcastservice.h"
|
||||
|
@ -52,7 +53,9 @@
|
|||
QSet<QString> SongLoader::sRawUriSchemes;
|
||||
const int SongLoader::kDefaultTimeout = 5000;
|
||||
|
||||
SongLoader::SongLoader(LibraryBackendInterface* library, QObject *parent)
|
||||
SongLoader::SongLoader(LibraryBackendInterface* library,
|
||||
const Player* player,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
timeout_timer_(new QTimer(this)),
|
||||
playlist_parser_(new PlaylistParser(library, this)),
|
||||
|
@ -63,7 +66,8 @@ SongLoader::SongLoader(LibraryBackendInterface* library, QObject *parent)
|
|||
success_(false),
|
||||
parser_(NULL),
|
||||
is_podcast_(false),
|
||||
library_(library)
|
||||
library_(library),
|
||||
player_(player)
|
||||
{
|
||||
if (sRawUriSchemes.isEmpty()) {
|
||||
sRawUriSchemes << "udp" << "mms" << "mmsh" << "mmst" << "mmsu" << "rtsp"
|
||||
|
@ -91,9 +95,10 @@ SongLoader::Result SongLoader::Load(const QUrl& url) {
|
|||
return LoadLocal(url_.toLocalFile());
|
||||
}
|
||||
|
||||
if (sRawUriSchemes.contains(url_.scheme())) {
|
||||
// The URI scheme indicates that it can't possibly be a playlist, so add
|
||||
// it as a raw stream.
|
||||
if (sRawUriSchemes.contains(url_.scheme()) ||
|
||||
player_->HandlerForUrl(url) != nullptr) {
|
||||
// The URI scheme indicates that it can't possibly be a playlist, or we have
|
||||
// a custom handler for the URL, so add it as a raw stream.
|
||||
AddAsRawStream();
|
||||
return Success;
|
||||
}
|
||||
|
|
|
@ -33,13 +33,15 @@
|
|||
class CueParser;
|
||||
class LibraryBackendInterface;
|
||||
class ParserBase;
|
||||
class Player;
|
||||
class PlaylistParser;
|
||||
class PodcastParser;
|
||||
|
||||
class SongLoader : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SongLoader(LibraryBackendInterface* library, QObject* parent = 0);
|
||||
SongLoader(LibraryBackendInterface* library, const Player* player,
|
||||
QObject* parent = 0);
|
||||
~SongLoader();
|
||||
|
||||
enum Result {
|
||||
|
@ -130,6 +132,7 @@ private:
|
|||
bool is_podcast_;
|
||||
QByteArray buffer_;
|
||||
LibraryBackendInterface* library_;
|
||||
const Player* player_;
|
||||
|
||||
boost::shared_ptr<GstElement> pipeline_;
|
||||
|
||||
|
|
|
@ -457,9 +457,9 @@ QByteArray Sha256(const QByteArray& data) {
|
|||
}
|
||||
|
||||
// File must not be open and will be closed afterwards!
|
||||
QByteArray Md5File(QFile &file) {
|
||||
QByteArray Sha1File(QFile &file) {
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||
QByteArray data;
|
||||
|
||||
while(!file.atEnd()) {
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace Utilities {
|
|||
QByteArray HmacSha256(const QByteArray& key, const QByteArray& data);
|
||||
QByteArray HmacSha1(const QByteArray& key, const QByteArray& data);
|
||||
QByteArray Sha256(const QByteArray& data);
|
||||
QByteArray Md5File(QFile& file);
|
||||
QByteArray Sha1File(QFile& file);
|
||||
QByteArray Sha1CoverHash(const QString& artist, const QString& album);
|
||||
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ using boost::scoped_ptr;
|
|||
|
||||
namespace {
|
||||
|
||||
static const char* kServiceName = "Skydrive";
|
||||
static const char* kServiceName = "OneDrive";
|
||||
static const char* kServiceId = "skydrive";
|
||||
static const char* kSettingsGroup = "Skydrive";
|
||||
|
||||
|
|
|
@ -212,6 +212,10 @@ void LibraryFilterWidget::SetQueryMode(QueryOptions::QueryMode query_mode) {
|
|||
model_->SetFilterQueryMode(query_mode);
|
||||
}
|
||||
|
||||
void LibraryFilterWidget::ShowInLibrary(const QString& search) {
|
||||
ui_->filter->setText(search);
|
||||
}
|
||||
|
||||
void LibraryFilterWidget::SetAgeFilterEnabled(bool enabled) {
|
||||
filter_age_menu_->setEnabled(enabled);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ class LibraryFilterWidget : public QWidget {
|
|||
void SetDelayBehaviour(DelayBehaviour behaviour) { delay_behaviour_ = behaviour; }
|
||||
void SetAgeFilterEnabled(bool enabled);
|
||||
void SetGroupByEnabled(bool enabled);
|
||||
void ShowInLibrary(const QString& search);
|
||||
|
||||
QMenu* menu() const { return library_menu_; }
|
||||
void AddMenuAction(QAction* action);
|
||||
|
|
|
@ -39,20 +39,38 @@ LibraryQuery::LibraryQuery(const QueryOptions& options)
|
|||
// 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.
|
||||
|
||||
// Split on whitespace
|
||||
QStringList tokens(options.filter().split(QRegExp("\\s+")));
|
||||
QStringList tokens(options.filter().split(
|
||||
QRegExp("\\s+"), QString::SkipEmptyParts));
|
||||
QString query;
|
||||
foreach (QString token, tokens) {
|
||||
token.remove('(');
|
||||
token.remove(')');
|
||||
token.remove('"');
|
||||
token.replace('-', ' ');
|
||||
|
||||
if (token.contains(':'))
|
||||
query += "fts" + token + "* ";
|
||||
else
|
||||
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)) {
|
||||
// Account for multiple colons.
|
||||
QString columntoken = token.section(
|
||||
':', 0, 0, QString::SectionIncludeTrailingSep);
|
||||
QString subtoken = token.section(':', 1, -1);
|
||||
subtoken.replace(":", " ");
|
||||
subtoken = subtoken.trimmed();
|
||||
query += "fts" + columntoken + subtoken + "* ";
|
||||
} else {
|
||||
token.replace(":", " ");
|
||||
token = token.trimmed();
|
||||
query += token + "* ";
|
||||
}
|
||||
} else {
|
||||
query += token + "* ";
|
||||
}
|
||||
}
|
||||
|
||||
where_clauses_ << "fts.%fts_table_noprefix MATCH ?";
|
||||
bound_values_ << query;
|
||||
|
|
|
@ -642,9 +642,9 @@ void OutgoingDataCreator::SendSingleSong(RemoteClient* client, const Song &song,
|
|||
// Open the file
|
||||
QFile file(song.url().toLocalFile());
|
||||
|
||||
// Get md5 for file
|
||||
QByteArray md5 = Utilities::Md5File(file).toHex();
|
||||
qLog(Debug) << "md5 for file" << song.url().toLocalFile() << "=" << md5;
|
||||
// Get sha1 for file
|
||||
QByteArray sha1 = Utilities::Sha1File(file).toHex();
|
||||
qLog(Debug) << "sha1 for file" << song.url().toLocalFile() << "=" << sha1;
|
||||
|
||||
file.open(QIODevice::ReadOnly);
|
||||
|
||||
|
@ -670,7 +670,7 @@ void OutgoingDataCreator::SendSingleSong(RemoteClient* client, const Song &song,
|
|||
chunk->set_file_number(song_no);
|
||||
chunk->set_size(file.size());
|
||||
chunk->set_data(data.data(), data.size());
|
||||
chunk->set_file_hash(md5.data(), md5.size());
|
||||
chunk->set_file_hash(sha1.data(), sha1.size());
|
||||
|
||||
// On the first chunk send the metadata, so the client knows
|
||||
// what file it receives.
|
||||
|
@ -753,9 +753,9 @@ void OutgoingDataCreator::SendLibrary(RemoteClient *client) {
|
|||
// Open the file
|
||||
QFile file(temp_file_name);
|
||||
|
||||
// Get the md5 hash
|
||||
QByteArray md5 = Utilities::Md5File(file).toHex();
|
||||
qLog(Debug) << "Library md5" << md5;
|
||||
// Get the sha1 hash
|
||||
QByteArray sha1 = Utilities::Sha1File(file).toHex();
|
||||
qLog(Debug) << "Library sha1" << sha1;
|
||||
|
||||
file.open(QIODevice::ReadOnly);
|
||||
|
||||
|
@ -777,7 +777,7 @@ void OutgoingDataCreator::SendLibrary(RemoteClient *client) {
|
|||
chunk->set_chunk_number(chunk_number);
|
||||
chunk->set_size(file.size());
|
||||
chunk->set_data(data.data(), data.size());
|
||||
chunk->set_file_hash(md5.data(), md5.size());
|
||||
chunk->set_file_hash(sha1.data(), sha1.size());
|
||||
|
||||
// Send data directly to the client
|
||||
client->SendData(&msg);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "songloaderinserter.h"
|
||||
#include "songmimedata.h"
|
||||
#include "songplaylistitem.h"
|
||||
#include "core/application.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/modelfuturewatcher.h"
|
||||
|
@ -761,7 +762,8 @@ bool Playlist::dropMimeData(const QMimeData* data, Qt::DropAction action, int ro
|
|||
}
|
||||
}
|
||||
} else if (data->hasFormat(kCddaMimeType)) {
|
||||
SongLoaderInserter* inserter = new SongLoaderInserter(task_manager_, library_);
|
||||
SongLoaderInserter* inserter = new SongLoaderInserter(
|
||||
task_manager_, library_, backend_->app()->player());
|
||||
connect(inserter, SIGNAL(Error(QString)), SIGNAL(LoadTracksError(QString)));
|
||||
inserter->LoadAudioCD(this, row, play_now, enqueue_now);
|
||||
} else if (data->hasUrls()) {
|
||||
|
@ -773,7 +775,8 @@ bool Playlist::dropMimeData(const QMimeData* data, Qt::DropAction action, int ro
|
|||
}
|
||||
|
||||
void Playlist::InsertUrls(const QList<QUrl> &urls, int pos, bool play_now, bool enqueue) {
|
||||
SongLoaderInserter* inserter = new SongLoaderInserter(task_manager_, library_);
|
||||
SongLoaderInserter* inserter = new SongLoaderInserter(
|
||||
task_manager_, library_, backend_->app()->player());
|
||||
connect(inserter, SIGNAL(Error(QString)), SIGNAL(LoadTracksError(QString)));
|
||||
|
||||
inserter->Load(this, pos, play_now, enqueue, urls);
|
||||
|
|
|
@ -78,6 +78,8 @@ class PlaylistBackend : public QObject {
|
|||
void FavoritePlaylist(int id, bool is_favorite);
|
||||
void RemovePlaylist(int id);
|
||||
|
||||
Application* app() const { return app_; }
|
||||
|
||||
public slots:
|
||||
void SavePlaylist(int playlist, const PlaylistItemList& items,
|
||||
int last_played, smart_playlists::GeneratorPtr dynamic);
|
||||
|
|
|
@ -16,13 +16,6 @@
|
|||
*/
|
||||
|
||||
#include "playlistdelegates.h"
|
||||
#include "queue.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/player.h"
|
||||
#include "core/utilities.h"
|
||||
#include "library/librarybackend.h"
|
||||
#include "widgets/trackslider.h"
|
||||
#include "ui/iconloader.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
|
@ -39,6 +32,18 @@
|
|||
#include <QWhatsThis>
|
||||
#include <QtConcurrentRun>
|
||||
|
||||
#include "queue.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/player.h"
|
||||
#include "core/utilities.h"
|
||||
#include "library/librarybackend.h"
|
||||
#include "widgets/trackslider.h"
|
||||
#include "ui/iconloader.h"
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include "core/mac_utilities.h"
|
||||
#endif // Q_OS_DARWIN
|
||||
|
||||
const int QueuedItemDelegate::kQueueBoxBorder = 1;
|
||||
const int QueuedItemDelegate::kQueueBoxCornerRadius = 3;
|
||||
const int QueuedItemDelegate::kQueueBoxLength = 30;
|
||||
|
@ -492,8 +497,14 @@ void SongSourceDelegate::paint(
|
|||
const QUrl& url = index.data().toUrl();
|
||||
QPixmap pixmap = LookupPixmap(url, option_copy.decorationSize);
|
||||
|
||||
float device_pixel_ratio = 1.0f;
|
||||
#ifdef Q_OS_DARWIN
|
||||
QWidget* parent_widget = reinterpret_cast<QWidget*>(parent());
|
||||
device_pixel_ratio = mac::GetDevicePixelRatio(parent_widget);
|
||||
#endif
|
||||
|
||||
// Draw the pixmap in the middle of the rectangle
|
||||
QRect draw_rect(QPoint(0, 0), option_copy.decorationSize);
|
||||
QRect draw_rect(QPoint(0, 0), option_copy.decorationSize / device_pixel_ratio);
|
||||
draw_rect.moveCenter(option_copy.rect.center());
|
||||
|
||||
painter->drawPixmap(draw_rect, pixmap);
|
||||
|
|
|
@ -156,7 +156,7 @@ void PlaylistManager::New(const QString& name, const SongList& songs,
|
|||
|
||||
void PlaylistManager::Load(const QString& filename) {
|
||||
QUrl url = QUrl::fromLocalFile(filename);
|
||||
SongLoader* loader = new SongLoader(library_backend_, this);
|
||||
SongLoader* loader = new SongLoader(library_backend_, app_->player(), this);
|
||||
connect(loader, SIGNAL(LoadFinished(bool)), SLOT(LoadFinished(bool)));
|
||||
SongLoader::Result result = loader->Load(url);
|
||||
QFileInfo info(filename);
|
||||
|
|
|
@ -1254,3 +1254,24 @@ void PlaylistView::FadePreviousBackgroundImage(qreal value) {
|
|||
void PlaylistView::PlayerStopped() {
|
||||
CurrentSongChanged(Song(), QString(), QImage());
|
||||
}
|
||||
|
||||
void PlaylistView::focusInEvent(QFocusEvent* event) {
|
||||
QTreeView::focusInEvent(event);
|
||||
|
||||
if (event->reason() == Qt::TabFocusReason ||
|
||||
event->reason() == Qt::BacktabFocusReason) {
|
||||
// If there's a current item but no selection it probably means the list was
|
||||
// filtered, and the selected item does not match the filter. If there's
|
||||
// only 1 item in the view it is now impossible to select that item without
|
||||
// using the mouse.
|
||||
const QModelIndex& current = selectionModel()->currentIndex();
|
||||
if (current.isValid() &&
|
||||
selectionModel()->selectedIndexes().isEmpty()) {
|
||||
QItemSelection new_selection(
|
||||
current.sibling(current.row(), 0),
|
||||
current.sibling(current.row(),
|
||||
current.model()->columnCount(current.parent()) - 1));
|
||||
selectionModel()->select(new_selection, QItemSelectionModel::Select);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,6 +134,7 @@ class PlaylistView : public QTreeView {
|
|||
void dropEvent(QDropEvent *event);
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
bool eventFilter(QObject* object, QEvent* event);
|
||||
void focusInEvent(QFocusEvent* event);
|
||||
|
||||
// QAbstractScrollArea
|
||||
void scrollContentsBy(int dx, int dy);
|
||||
|
|
|
@ -23,8 +23,9 @@
|
|||
#include "core/songloader.h"
|
||||
#include "core/taskmanager.h"
|
||||
|
||||
SongLoaderInserter::SongLoaderInserter(
|
||||
TaskManager* task_manager, LibraryBackendInterface* library)
|
||||
SongLoaderInserter::SongLoaderInserter(TaskManager* task_manager,
|
||||
LibraryBackendInterface* library,
|
||||
const Player* player)
|
||||
: task_manager_(task_manager),
|
||||
destination_(NULL),
|
||||
row_(-1),
|
||||
|
@ -32,7 +33,8 @@ SongLoaderInserter::SongLoaderInserter(
|
|||
enqueue_(false),
|
||||
async_load_id_(0),
|
||||
async_progress_(0),
|
||||
library_(library) {
|
||||
library_(library),
|
||||
player_(player) {
|
||||
}
|
||||
|
||||
SongLoaderInserter::~SongLoaderInserter() {
|
||||
|
@ -53,7 +55,7 @@ void SongLoaderInserter::Load(Playlist *destination,
|
|||
destination, SLOT(UpdateItems(const SongList&)));
|
||||
|
||||
foreach (const QUrl& url, urls) {
|
||||
SongLoader* loader = new SongLoader(library_, this);
|
||||
SongLoader* loader = new SongLoader(library_, player_, this);
|
||||
|
||||
// we're connecting this before we're even sure if this is an async load
|
||||
// to avoid race conditions (signal emission before we're listening to it)
|
||||
|
@ -92,7 +94,7 @@ void SongLoaderInserter::LoadAudioCD(Playlist *destination,
|
|||
play_now_ = play_now;
|
||||
enqueue_ = enqueue;
|
||||
|
||||
SongLoader *loader = new SongLoader(library_, this);
|
||||
SongLoader* loader = new SongLoader(library_, player_, this);
|
||||
connect(loader, SIGNAL(LoadFinished(bool)), SLOT(AudioCDTagsLoaded(bool)));
|
||||
qLog(Info) << "Loading audio CD...";
|
||||
SongLoader::Result ret = loader->LoadAudioCD();
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "core/song.h"
|
||||
|
||||
class LibraryBackendInterface;
|
||||
class Player;
|
||||
class Playlist;
|
||||
class SongLoader;
|
||||
class TaskManager;
|
||||
|
@ -34,7 +35,9 @@ class QModelIndex;
|
|||
class SongLoaderInserter : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SongLoaderInserter(TaskManager* task_manager, LibraryBackendInterface* library);
|
||||
SongLoaderInserter(TaskManager* task_manager,
|
||||
LibraryBackendInterface* library,
|
||||
const Player* player);
|
||||
~SongLoaderInserter();
|
||||
|
||||
void Load(Playlist* destination, int row, bool play_now, bool enqueue,
|
||||
|
@ -70,6 +73,7 @@ private:
|
|||
int async_load_id_;
|
||||
int async_progress_;
|
||||
LibraryBackendInterface* library_;
|
||||
const Player* player_;
|
||||
};
|
||||
|
||||
#endif // SONGLOADERINSERTER_H
|
||||
|
|
|
@ -27,6 +27,12 @@
|
|||
#include <QRegExp>
|
||||
#include <QSet>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <time.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
class Application;
|
||||
class PodcastBackend;
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ void UltimateLyricsProvider::LyricsFetched() {
|
|||
|
||||
// Apply exclude rules
|
||||
foreach (const Rule& rule, exclude_rules_) {
|
||||
ApplyExcludeRule(rule, &lyrics);
|
||||
ApplyExcludeRule(rule, &content);
|
||||
}
|
||||
|
||||
if (!content.isEmpty() and HTMLHasAlphaNumeric(content)) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "transcoderoptionsdialog.h"
|
||||
#include "ui_transcodedialog.h"
|
||||
#include "ui_transcodelogdialog.h"
|
||||
#include "ui/iconloader.h"
|
||||
#include "ui/mainwindow.h"
|
||||
#include "widgets/fileview.h"
|
||||
|
||||
|
@ -35,6 +36,7 @@
|
|||
|
||||
const char* TranscodeDialog::kSettingsGroup = "Transcoder";
|
||||
const int TranscodeDialog::kProgressInterval = 500;
|
||||
const int TranscodeDialog::kMaxDestinationItems = 10;
|
||||
|
||||
static bool ComparePresetsByName(const TranscoderPreset& left,
|
||||
const TranscoderPreset& right) {
|
||||
|
@ -103,6 +105,8 @@ TranscodeDialog::TranscodeDialog(QWidget *parent)
|
|||
connect(close_button_, SIGNAL(clicked()), SLOT(hide()));
|
||||
connect(ui_->details, SIGNAL(clicked()), log_dialog_, SLOT(show()));
|
||||
connect(ui_->options, SIGNAL(clicked()), SLOT(Options()));
|
||||
connect(ui_->select, SIGNAL(clicked()), SLOT(AddDestination()));
|
||||
|
||||
|
||||
connect(transcoder_, SIGNAL(JobComplete(QString,bool)), SLOT(JobComplete(QString,bool)));
|
||||
connect(transcoder_, SIGNAL(LogLine(QString)), SLOT(LogLine(QString)));
|
||||
|
@ -138,7 +142,8 @@ void TranscodeDialog::Start() {
|
|||
// Add jobs to the transcoder
|
||||
for (int i=0 ; i<file_model->rowCount() ; ++i) {
|
||||
QString filename = file_model->index(i, 0).data(Qt::UserRole).toString();
|
||||
transcoder_->AddJob(filename, preset);
|
||||
QString outfilename = GetOutputFileName(filename, preset);
|
||||
transcoder_->AddJob(filename, preset, outfilename);
|
||||
}
|
||||
|
||||
// Set up the progressbar
|
||||
|
@ -265,3 +270,50 @@ void TranscodeDialog::Options() {
|
|||
dialog.exec();
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a folder to the destination box.
|
||||
void TranscodeDialog::AddDestination() {
|
||||
int index = ui_->destination->currentIndex();
|
||||
QString initial_dir = (!ui_->destination->itemData(index).isNull() ?
|
||||
ui_->destination->itemData(index).toString() :
|
||||
QDir::homePath());
|
||||
QString dir = QFileDialog::getExistingDirectory(
|
||||
this, tr("Add folder"), initial_dir);
|
||||
|
||||
if (!dir.isEmpty()) {
|
||||
// Keep only a finite number of items in the box.
|
||||
while (ui_->destination->count() >= kMaxDestinationItems) {
|
||||
ui_->destination->removeItem(1); // The oldest folder item.
|
||||
}
|
||||
|
||||
QIcon icon = IconLoader::Load("folder");
|
||||
QVariant data = QVariant::fromValue(dir);
|
||||
// Do not insert duplicates.
|
||||
int duplicate_index = ui_->destination->findData(data);
|
||||
if (duplicate_index == -1) {
|
||||
ui_->destination->addItem(icon, dir, data);
|
||||
ui_->destination->setCurrentIndex(ui_->destination->count() - 1);
|
||||
} else {
|
||||
ui_->destination->setCurrentIndex(duplicate_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the rightmost non-empty part of 'path'.
|
||||
QString TranscodeDialog::TrimPath(const QString& path) const {
|
||||
return path.section('/', -1, -1, QString::SectionSkipEmpty);
|
||||
}
|
||||
|
||||
QString TranscodeDialog::GetOutputFileName(const QString& input,
|
||||
const TranscoderPreset &preset) const {
|
||||
QString path = ui_->destination->itemData(
|
||||
ui_->destination->currentIndex()).toString();
|
||||
if (path.isEmpty()) {
|
||||
// Keep the original path.
|
||||
return input.section('.', 0, -2) + '.' + preset.extension_;
|
||||
} else {
|
||||
QString file_name = TrimPath(input);
|
||||
file_name = file_name.section('.', 0, -2);
|
||||
return path + '/' + file_name + '.' + preset.extension_;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ class Transcoder;
|
|||
class Ui_TranscodeDialog;
|
||||
class Ui_TranscodeLogDialog;
|
||||
|
||||
struct TranscoderPreset;
|
||||
|
||||
class TranscodeDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -34,6 +36,7 @@ class TranscodeDialog : public QDialog {
|
|||
|
||||
static const char* kSettingsGroup;
|
||||
static const int kProgressInterval;
|
||||
static const int kMaxDestinationItems;
|
||||
|
||||
void SetFilenames(const QStringList& filenames);
|
||||
|
||||
|
@ -49,11 +52,15 @@ class TranscodeDialog : public QDialog {
|
|||
void LogLine(const QString& message);
|
||||
void AllJobsComplete();
|
||||
void Options();
|
||||
void AddDestination();
|
||||
|
||||
private:
|
||||
void SetWorking(bool working);
|
||||
void UpdateStatusText();
|
||||
void UpdateProgress();
|
||||
QString TrimPath(const QString& path) const;
|
||||
QString GetOutputFileName(const QString& input,
|
||||
const TranscoderPreset& preset) const;
|
||||
|
||||
private:
|
||||
Ui_TranscodeDialog* ui_;
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
<property name="title">
|
||||
<string>Output options</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
|
@ -107,8 +107,6 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QComboBox" name="format">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
|
@ -118,15 +116,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="options">
|
||||
<property name="text">
|
||||
<string>Options...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
|
@ -136,6 +132,15 @@
|
|||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="destination">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Alongside the originals</string>
|
||||
|
@ -143,6 +148,13 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="select">
|
||||
<property name="text">
|
||||
<string>Select...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -196,7 +208,6 @@
|
|||
<tabstop>add</tabstop>
|
||||
<tabstop>remove</tabstop>
|
||||
<tabstop>format</tabstop>
|
||||
<tabstop>destination</tabstop>
|
||||
<tabstop>button_box</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
|
|
|
@ -297,7 +297,7 @@ void Transcoder::AddJob(const QString& input,
|
|||
// Never overwrite existing files
|
||||
if (QFile::exists(job.output)) {
|
||||
for (int i=0 ; ; ++i) {
|
||||
QString new_filename = QString("%1.%2").arg(job.output).arg(i);
|
||||
QString new_filename = QString("%1.%2.%3").arg(job.output.section('.',0,-2)).arg(i).arg(preset.extension_);
|
||||
if (!QFile::exists(new_filename)) {
|
||||
job.output = new_filename;
|
||||
break;
|
||||
|
@ -331,8 +331,10 @@ Transcoder::StartJobStatus Transcoder::MaybeStartNextJob() {
|
|||
}
|
||||
|
||||
Job job = queued_jobs_.takeFirst();
|
||||
if (StartJob(job))
|
||||
if (StartJob(job)) {
|
||||
emit(JobOutputName(job.output));
|
||||
return StartedSuccessfully;
|
||||
}
|
||||
|
||||
emit JobComplete(job.input, false);
|
||||
return FailedToStart;
|
||||
|
|
|
@ -75,6 +75,7 @@ class Transcoder : public QObject {
|
|||
void JobComplete(const QString& filename, bool success);
|
||||
void LogLine(const QString& message);
|
||||
void AllJobsComplete();
|
||||
void JobOutputName(const QString& filename);
|
||||
|
||||
protected:
|
||||
bool event(QEvent* e);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -27,10 +27,11 @@ class AlbumCoverFetcher;
|
|||
class AlbumCoverSearcher;
|
||||
class Application;
|
||||
class CoverFromURLDialog;
|
||||
class CoverSearchStatistics;
|
||||
class QFileDialog;
|
||||
class Song;
|
||||
|
||||
struct CoverSearchStatistics;
|
||||
|
||||
// Controller for the common album cover related menu options.
|
||||
class AlbumCoverChoiceController : public QWidget {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -125,6 +125,8 @@ void Equalizer::LoadDefaultPresets() {
|
|||
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Live"), Params(-25, 0, 20, 25, 30, 30, 20, 15, 15, 10));
|
||||
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Party"), Params(35, 35, 0, 0, 0, 0, 0, 0, 35, 35));
|
||||
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Pop"), Params(-10, 25, 35, 40, 25, -5, -15, -15, -10, -10));
|
||||
// Psychedelic equalizer created by Devyn Collier Johnson
|
||||
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Psychedelic"), Params(100, 100, 0, 40, 0, 67, 79, 0, 30, -100, 37));
|
||||
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Reggae"), Params(0, 0, -5, -30, 0, -35, -35, 0, 0, 0));
|
||||
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Rock"), Params(40, 25, -30, -40, -20, 20, 45, 55, 55, 55));
|
||||
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Soft"), Params(25, 10, -5, -15, -5, 20, 45, 50, 55, 60));
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue