From 4cb37753660d4e1c10b7ebacebc8187f63e5bdb0 Mon Sep 17 00:00:00 2001 From: Mattias Andersson Date: Mon, 6 Jan 2014 14:25:04 +0100 Subject: [PATCH 01/19] Show an OSD notification when 'Stop after this track' is toggled --- src/playlist/playlist.cpp | 5 +++++ src/playlist/playlist.h | 3 +++ src/ui/mainwindow.cpp | 6 ++++++ src/widgets/osd.cpp | 10 ++++++++++ src/widgets/osd.h | 1 + 5 files changed, 25 insertions(+) diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index ea07cca42..df67a084d 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -1524,6 +1524,11 @@ void Playlist::StopAfter(int row) { else stop_after_ = index(row, 0); + // stop_after_.isValid() == true when there there is a stop placed + // somewhere on the playlist. Emit a StopAfterToggled signal that + // reflects this. + emit StopAfterToggled(stop_after_.isValid()); + if (old_stop_after.isValid()) emit dataChanged(old_stop_after, old_stop_after.sibling(old_stop_after.row(), ColumnCount-1)); if (stop_after_.isValid()) diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index 8a24ce7f8..e1c4dacf8 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -306,6 +306,9 @@ class Playlist : public QAbstractListModel { void EditingFinished(const QModelIndex& index); void PlayRequested(const QModelIndex& index); + // Signals that stop playing after track was toggled. + void StopAfterToggled(bool stop); + // Signals that the underlying list of items was changed, meaning that // something was added to it, removed from it or the ordering changed. void PlaylistChanged(); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 639704564..4f2b8a422 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -690,6 +690,12 @@ MainWindow::MainWindow(Application* app, app_->playlist_manager()->Init(app_->library_backend(), app_->playlist_backend(), ui_->playlist_sequence, ui_->playlist); + // Connect the playlist signal "StopAfterToggled with the + // StopAfterToggle OSD slot. This must be done after the playlist + // has been initialized. + connect(app_->playlist_manager()->current(), SIGNAL(StopAfterToggled(bool)), + osd_, SLOT(StopAfterToggle(bool))); + // We need to connect these global shortcuts here after the playlist have been initialized connect(global_shortcuts_, SIGNAL(CycleShuffleMode()), app_->playlist_manager()->sequence(), SLOT(CycleShuffleMode())); connect(global_shortcuts_, SIGNAL(CycleRepeatMode()), app_->playlist_manager()->sequence(), SLOT(CycleRepeatMode())); diff --git a/src/widgets/osd.cpp b/src/widgets/osd.cpp index 9e40ff1d9..b71e651f1 100644 --- a/src/widgets/osd.cpp +++ b/src/widgets/osd.cpp @@ -166,6 +166,16 @@ void OSD::Stopped() { ShowMessage(QCoreApplication::applicationName(), tr("Stopped")); } +void OSD::StopAfterToggle(bool stop) { + if (stop) { + ShowMessage(QCoreApplication::applicationName(), + tr("Stop playing after track: On")); + } else { + ShowMessage(QCoreApplication::applicationName(), + tr("Stop playing after track: Off")); + } +} + void OSD::PlaylistFinished() { // We get a PlaylistFinished followed by a Stopped from the player ignore_next_stopped_ = true; diff --git a/src/widgets/osd.h b/src/widgets/osd.h index dddd7648e..d7783e88a 100644 --- a/src/widgets/osd.h +++ b/src/widgets/osd.h @@ -71,6 +71,7 @@ class OSD : public QObject { void Paused(); void Stopped(); + void StopAfterToggle(bool stop); void PlaylistFinished(); void VolumeChanged(int value); void MagnatuneDownloadFinished(const QStringList& albums); From b0e6062a4ace3f619335b07db61c74674cfe40cf Mon Sep 17 00:00:00 2001 From: Mattias Andersson Date: Mon, 6 Jan 2014 23:50:16 +0100 Subject: [PATCH 02/19] Fix comments and reduce translator's burden. --- src/playlist/playlist.cpp | 2 +- src/ui/mainwindow.cpp | 4 +--- src/widgets/osd.cpp | 9 ++------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index df67a084d..c19d883a0 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -1524,7 +1524,7 @@ void Playlist::StopAfter(int row) { else stop_after_ = index(row, 0); - // stop_after_.isValid() == true when there there is a stop placed + // stop_after_.isValid() == true when there is a stop placed // somewhere on the playlist. Emit a StopAfterToggled signal that // reflects this. emit StopAfterToggled(stop_after_.isValid()); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 4f2b8a422..d3246d9d2 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -690,9 +690,7 @@ MainWindow::MainWindow(Application* app, app_->playlist_manager()->Init(app_->library_backend(), app_->playlist_backend(), ui_->playlist_sequence, ui_->playlist); - // Connect the playlist signal "StopAfterToggled with the - // StopAfterToggle OSD slot. This must be done after the playlist - // has been initialized. + // This connection must be done after the playlist has been initialized. connect(app_->playlist_manager()->current(), SIGNAL(StopAfterToggled(bool)), osd_, SLOT(StopAfterToggle(bool))); diff --git a/src/widgets/osd.cpp b/src/widgets/osd.cpp index b71e651f1..c2dfe8b81 100644 --- a/src/widgets/osd.cpp +++ b/src/widgets/osd.cpp @@ -167,13 +167,8 @@ void OSD::Stopped() { } void OSD::StopAfterToggle(bool stop) { - if (stop) { - ShowMessage(QCoreApplication::applicationName(), - tr("Stop playing after track: On")); - } else { - ShowMessage(QCoreApplication::applicationName(), - tr("Stop playing after track: Off")); - } + ShowMessage(QCoreApplication::applicationName(), + tr("Stop playing after track: %1").arg(stop ? tr("On") : tr("Off"))); } void OSD::PlaylistFinished() { From 42b0ec73df0dbd39c2faf2dfc24d1b1af5b6bc02 Mon Sep 17 00:00:00 2001 From: Mattias Andersson Date: Tue, 7 Jan 2014 11:46:39 +0100 Subject: [PATCH 03/19] Move the emission of the signal StopAfterToggled to MainWindow::StopAfterCurrent. --- src/playlist/playlist.cpp | 5 ----- src/playlist/playlist.h | 3 --- src/ui/mainwindow.cpp | 5 +++-- src/ui/mainwindow.h | 4 ++++ 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index c19d883a0..ea07cca42 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -1524,11 +1524,6 @@ void Playlist::StopAfter(int row) { else stop_after_ = index(row, 0); - // stop_after_.isValid() == true when there is a stop placed - // somewhere on the playlist. Emit a StopAfterToggled signal that - // reflects this. - emit StopAfterToggled(stop_after_.isValid()); - if (old_stop_after.isValid()) emit dataChanged(old_stop_after, old_stop_after.sibling(old_stop_after.row(), ColumnCount-1)); if (stop_after_.isValid()) diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index e1c4dacf8..8a24ce7f8 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -306,9 +306,6 @@ class Playlist : public QAbstractListModel { void EditingFinished(const QModelIndex& index); void PlayRequested(const QModelIndex& index); - // Signals that stop playing after track was toggled. - void StopAfterToggled(bool stop); - // Signals that the underlying list of items was changed, meaning that // something was added to it, removed from it or the ordering changed. void PlaylistChanged(); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index d3246d9d2..f4eaa950d 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -690,8 +690,8 @@ MainWindow::MainWindow(Application* app, app_->playlist_manager()->Init(app_->library_backend(), app_->playlist_backend(), ui_->playlist_sequence, ui_->playlist); - // This connection must be done after the playlist has been initialized. - connect(app_->playlist_manager()->current(), SIGNAL(StopAfterToggled(bool)), + // This connection must be done after the playlists have been initialized. + connect(this, SIGNAL(StopAfterToggled(bool)), osd_, SLOT(StopAfterToggle(bool))); // We need to connect these global shortcuts here after the playlist have been initialized @@ -1063,6 +1063,7 @@ void MainWindow::ToggleShowHide() { void MainWindow::StopAfterCurrent() { app_->playlist_manager()->current()->StopAfter(app_->playlist_manager()->current()->current_row()); + emit StopAfterToggled(app_->playlist_manager()->current()->stop_after_current()); } void MainWindow::closeEvent(QCloseEvent* event) { diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 8779e84ee..039edb4cd 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -134,6 +134,10 @@ class MainWindow : public QMainWindow, public PlatformInterface { void Activate(); bool LoadUrl(const QString& url); + signals: + // Signals that stop playing after track was toggled. + void StopAfterToggled(bool stop); + private slots: void FilePathChanged(const QString& path); From 8ac1d9a2bd4942737ae6c588ce3c331fa1fbf082 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Wed, 8 Jan 2014 12:05:48 +0100 Subject: [PATCH 04/19] s/class/struct/ --- src/ui/albumcoverchoicecontroller.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/albumcoverchoicecontroller.h b/src/ui/albumcoverchoicecontroller.h index 7da216e66..b7e574fe7 100644 --- a/src/ui/albumcoverchoicecontroller.h +++ b/src/ui/albumcoverchoicecontroller.h @@ -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 From 4872766f8024562571758edef41c2e384c057f13 Mon Sep 17 00:00:00 2001 From: Mattias Andersson Date: Wed, 8 Jan 2014 14:11:21 +0100 Subject: [PATCH 05/19] Target the active playlist when setting 'Stop after this track' via global shortcut or system tray. --- src/ui/mainwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index f4eaa950d..4810c6c06 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -1062,8 +1062,8 @@ void MainWindow::ToggleShowHide() { } void MainWindow::StopAfterCurrent() { - app_->playlist_manager()->current()->StopAfter(app_->playlist_manager()->current()->current_row()); - emit StopAfterToggled(app_->playlist_manager()->current()->stop_after_current()); + app_->playlist_manager()->active()->StopAfter(app_->playlist_manager()->active()->current_row()); + emit StopAfterToggled(app_->playlist_manager()->active()->stop_after_current()); } void MainWindow::closeEvent(QCloseEvent* event) { From 906cf542721ee28ba3724aca6ca800501284de1d Mon Sep 17 00:00:00 2001 From: David Sansome Date: Thu, 9 Jan 2014 20:00:33 +1100 Subject: [PATCH 06/19] Add a README file. Fixes #4085 --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..8202b1933 --- /dev/null +++ b/README.md @@ -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 From 55b0d00e0248baaf45ed469ad12f10e3b0e9941d Mon Sep 17 00:00:00 2001 From: John Maguire Date: Thu, 9 Jan 2014 15:41:51 +0100 Subject: [PATCH 07/19] Update playback counter font. Fixes #4082 --- src/widgets/trackslider.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/trackslider.cpp b/src/widgets/trackslider.cpp index 3fcc26d3d..4fcfce247 100644 --- a/src/widgets/trackslider.cpp +++ b/src/widgets/trackslider.cpp @@ -38,7 +38,7 @@ TrackSlider::TrackSlider(QWidget* parent) { ui_->setupUi(this); - QFont font("Courier"); + QFont font("Comic Sans MS"); ui_->elapsed->setFont(font); ui_->remaining->setFont(font); From 1a972e0f3639df3cb1a6a64b65d7a9d3e972f912 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 10 Jan 2014 16:57:32 +0100 Subject: [PATCH 08/19] Fix rendering of source icons in playlist view on retina OS X 10.9 --- src/core/mac_startup.mm | 8 ++++++++ src/core/mac_utilities.h | 1 + src/playlist/playlistdelegates.cpp | 27 +++++++++++++++++++-------- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/core/mac_startup.mm b/src/core/mac_startup.mm index d9836377f..4a89677e7 100644 --- a/src/core/mac_startup.mm +++ b/src/core/mac_startup.mm @@ -451,4 +451,12 @@ void EnableFullScreen(const QWidget& main_window) { [window setCollectionBehavior: kFullScreenPrimary]; } +float GetDevicePixelRatio(QWidget* widget) { + NSView* view = reinterpret_cast(widget->winId()); + if ([[view window] respondsToSelector: @selector(backingScaleFactor)]) { + return [[view window] backingScaleFactor]; + } + return 1.0f; +} + } // namespace mac diff --git a/src/core/mac_utilities.h b/src/core/mac_utilities.h index 9ad84e1fb..fadaab0fd 100644 --- a/src/core/mac_utilities.h +++ b/src/core/mac_utilities.h @@ -29,5 +29,6 @@ namespace mac { QKeySequence KeySequenceFromNSEvent(NSEvent* event); void DumpDictionary(CFDictionaryRef dict); +float GetDevicePixelRatio(QWidget* widget); } diff --git a/src/playlist/playlistdelegates.cpp b/src/playlist/playlistdelegates.cpp index 752b556eb..b49b46ee3 100644 --- a/src/playlist/playlistdelegates.cpp +++ b/src/playlist/playlistdelegates.cpp @@ -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 #include @@ -39,6 +32,18 @@ #include #include +#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(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); From 509a6af788fccf32c962e439c4a207e746809835 Mon Sep 17 00:00:00 2001 From: Andrew Udvare Date: Sat, 11 Jan 2014 00:45:13 -0800 Subject: [PATCH 09/19] In the tag editor, make the reset button appear on the left side for RTL text; #2673 --- src/widgets/lineedit.cpp | 25 +++++++++++++++++++++---- src/widgets/lineedit.h | 7 ++++++- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/widgets/lineedit.cpp b/src/widgets/lineedit.cpp index 91dc7a494..4d8f9ef5e 100644 --- a/src/widgets/lineedit.cpp +++ b/src/widgets/lineedit.cpp @@ -32,7 +32,8 @@ ExtendedEditor::ExtendedEditor(QWidget* widget, int extra_right_padding, reset_button_(new QToolButton(widget)), extra_right_padding_(extra_right_padding), draw_hint_(draw_hint), - font_point_size_(widget->font().pointSizeF() - 1) + font_point_size_(widget->font().pointSizeF() - 1), + is_rtl_(false) { clear_button_->setIcon(IconLoader::Load("edit-clear-locationbar-ltr")); clear_button_->setIconSize(QSize(16, 16)); @@ -118,15 +119,23 @@ void ExtendedEditor::Paint(QPaintDevice* device) { } } else { clear_button_->setVisible(has_clear_button_); + Resize(); } } void ExtendedEditor::Resize() { const QSize sz = clear_button_->sizeHint(); const int frame_width = widget_->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); - clear_button_->move(frame_width, (widget_->rect().height() - sz.height()) / 2); - reset_button_->move(widget_->width() - frame_width - sz.width() - extra_right_padding_, - (widget_->rect().height() - sz.height()) / 2); + const int y = (widget_->rect().height() - sz.height()) / 2; + + if (!is_rtl_) { + clear_button_->move(frame_width, y); + reset_button_->move(widget_->width() - frame_width - sz.width() - extra_right_padding_, y); + } + else { + clear_button_->move(frame_width, y); + reset_button_->move((has_clear_button() ? sz.width() + 4 : 0) + frame_width, y); + } } @@ -137,6 +146,14 @@ LineEdit::LineEdit(QWidget* parent) connect(reset_button_, SIGNAL(clicked()), SIGNAL(Reset())); } +void LineEdit::set_text(const QString& text) { + QLineEdit::setText(text); + + // For some reason Qt will detect any text with LTR at the end as LTR, so instead + // compare only the first character + set_rtl(QString(1, text.at(0)).isRightToLeft()); +} + void LineEdit::paintEvent(QPaintEvent* e) { QLineEdit::paintEvent(e); Paint(this); diff --git a/src/widgets/lineedit.h b/src/widgets/lineedit.h index 1ac623b24..2806a2fa4 100644 --- a/src/widgets/lineedit.h +++ b/src/widgets/lineedit.h @@ -69,6 +69,9 @@ public: qreal font_point_size() const { return font_point_size_; } void set_font_point_size(qreal size) { font_point_size_ = size; } + bool is_rtl() const { return is_rtl_; }; + void set_rtl(bool rtl) { is_rtl_ = rtl; } + protected: void Paint(QPaintDevice* device); void Resize(); @@ -86,6 +89,7 @@ protected: int extra_right_padding_; bool draw_hint_; qreal font_point_size_; + bool is_rtl_; }; class LineEdit : public QLineEdit, @@ -95,6 +99,7 @@ class LineEdit : public QLineEdit, Q_PROPERTY(qreal font_point_size READ font_point_size WRITE set_font_point_size); Q_PROPERTY(bool has_clear_button READ has_clear_button WRITE set_clear_button); Q_PROPERTY(bool has_reset_button READ has_reset_button WRITE set_reset_button); + Q_PROPERTY(bool is_rtl READ is_rtl WRITE set_rtl); public: LineEdit(QWidget* parent = 0); @@ -102,7 +107,7 @@ public: // ExtendedEditor void set_focus() { QLineEdit::setFocus(); } QString text() const { return QLineEdit::text(); } - void set_text(const QString& text) { QLineEdit::setText(text); } + void set_text(const QString& text); void set_enabled(bool enabled) { QLineEdit::setEnabled(enabled); } protected: From 294023cf2d93a1a8bc0df4e56830cc88420e23ab Mon Sep 17 00:00:00 2001 From: Mattias Andersson Date: Sat, 11 Jan 2014 01:04:59 +0100 Subject: [PATCH 10/19] Add the ability to choose destination folder in the transcoder dialog. --- src/transcoder/transcodedialog.cpp | 47 +++++++++++++++++++++++++++++- src/transcoder/transcodedialog.h | 6 ++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/transcoder/transcodedialog.cpp b/src/transcoder/transcodedialog.cpp index d2e11b5e1..9886f4ba2 100644 --- a/src/transcoder/transcodedialog.cpp +++ b/src/transcoder/transcodedialog.cpp @@ -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" @@ -95,6 +96,12 @@ TranscodeDialog::TranscodeDialog(QWidget *parent) cancel_button_->hide(); ui_->progress_group->hide(); + // Add a destination. + QIcon icon = IconLoader::Load("folder"); + QVariant data = QVariant::fromValue(QDir::homePath()); + QString text = TrimPath(data.toString()); + ui_->destination->addItem(icon, text, data); + // Connect stuff connect(ui_->add, SIGNAL(clicked()), SLOT(Add())); connect(ui_->remove, SIGNAL(clicked()), SLOT(Remove())); @@ -103,6 +110,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_->destination, SIGNAL(activated(int)), + SLOT(SetDestination(int))); connect(transcoder_, SIGNAL(JobComplete(QString,bool)), SLOT(JobComplete(QString,bool))); connect(transcoder_, SIGNAL(LogLine(QString)), SLOT(LogLine(QString))); @@ -138,7 +147,8 @@ void TranscodeDialog::Start() { // Add jobs to the transcoder for (int i=0 ; irowCount() ; ++i) { QString filename = file_model->index(i, 0).data(Qt::UserRole).toString(); - transcoder_->AddJob(filename, preset); + QString outfilename = SetOutputFileName(filename, preset); + transcoder_->AddJob(filename, preset, outfilename); } // Set up the progressbar @@ -265,3 +275,38 @@ void TranscodeDialog::Options() { dialog.exec(); } } + +void TranscodeDialog::SetDestination(int index) { + if (!ui_->destination->itemData(index).isNull()) { + QString dir = QFileDialog::getExistingDirectory( + this, tr("Choose folder"), + ui_->destination->itemData(index).toString()); + // Do not update the QComboBox if the user canceled the dialog. + if (!dir.isEmpty()) { + QVariant data = QVariant::fromValue(dir); + QString text = TrimPath(dir); + ui_->destination->setItemText(index, text); + ui_->destination->setItemData(index, data); + } + } +} + +// Returns the rightmost non-empty part of 'path'. +QString TranscodeDialog::TrimPath(const QString& path) { + return path.section('/', -1, -1, QString::SectionSkipEmpty); +} + +QString TranscodeDialog::SetOutputFileName(const QString& input, + const TranscoderPreset &preset) { + 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_; + } +} diff --git a/src/transcoder/transcodedialog.h b/src/transcoder/transcodedialog.h index ebf70d204..a88097ef7 100644 --- a/src/transcoder/transcodedialog.h +++ b/src/transcoder/transcodedialog.h @@ -25,6 +25,8 @@ class Transcoder; class Ui_TranscodeDialog; class Ui_TranscodeLogDialog; +struct TranscoderPreset; + class TranscodeDialog : public QDialog { Q_OBJECT @@ -49,11 +51,15 @@ class TranscodeDialog : public QDialog { void LogLine(const QString& message); void AllJobsComplete(); void Options(); + void SetDestination(int index); private: void SetWorking(bool working); void UpdateStatusText(); void UpdateProgress(); + QString TrimPath(const QString& path); + QString SetOutputFileName(const QString& input, + const TranscoderPreset& preset); private: Ui_TranscodeDialog* ui_; From d46e0bacc625dd7e143dc226e7009b48e928cf1d Mon Sep 17 00:00:00 2001 From: Andrew Udvare Date: Sat, 11 Jan 2014 03:45:45 -0800 Subject: [PATCH 11/19] Test for string length --- src/widgets/lineedit.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/widgets/lineedit.cpp b/src/widgets/lineedit.cpp index 4d8f9ef5e..7a21b40dc 100644 --- a/src/widgets/lineedit.cpp +++ b/src/widgets/lineedit.cpp @@ -151,7 +151,9 @@ void LineEdit::set_text(const QString& text) { // For some reason Qt will detect any text with LTR at the end as LTR, so instead // compare only the first character - set_rtl(QString(1, text.at(0)).isRightToLeft()); + if (text.length()) { + set_rtl(QString(text.at(0)).isRightToLeft()); + } } void LineEdit::paintEvent(QPaintEvent* e) { From 71aeda07f79adc52e841fa412469aec879c46f48 Mon Sep 17 00:00:00 2001 From: Andrew Udvare Date: Sat, 11 Jan 2014 03:46:15 -0800 Subject: [PATCH 12/19] Formatting --- src/widgets/lineedit.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/widgets/lineedit.cpp b/src/widgets/lineedit.cpp index 7a21b40dc..abd141fd6 100644 --- a/src/widgets/lineedit.cpp +++ b/src/widgets/lineedit.cpp @@ -131,8 +131,7 @@ void ExtendedEditor::Resize() { if (!is_rtl_) { clear_button_->move(frame_width, y); reset_button_->move(widget_->width() - frame_width - sz.width() - extra_right_padding_, y); - } - else { + } else { clear_button_->move(frame_width, y); reset_button_->move((has_clear_button() ? sz.width() + 4 : 0) + frame_width, y); } From fecdae0be3ee4505072ab266ee0ed2b365f8ee2a Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sat, 11 Jan 2014 22:47:35 +1100 Subject: [PATCH 13/19] Add mp2 to the list of extensions shown in the files tab. Fixes #4103 --- src/widgets/fileview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/fileview.cpp b/src/widgets/fileview.cpp index 7fd83d9ac..6a62a2e56 100644 --- a/src/widgets/fileview.cpp +++ b/src/widgets/fileview.cpp @@ -32,7 +32,7 @@ const char* FileView::kFileFilter = "*.mp3 *.ogg *.flac *.mpc *.m4a *.aac *.wma " "*.mp4 *.spx *.wav *.m3u *.m3u8 *.pls *.xspf " "*.asx *.asxini *.cue *.ape *.wv *.mka *.opus " - "*.oga *.mka"; + "*.oga *.mka *.mp2"; FileView::FileView(QWidget* parent) : QWidget(parent), From 59f033a5837f9a9f5cbe874381284922003db9da Mon Sep 17 00:00:00 2001 From: Andrew Udvare Date: Sat, 11 Jan 2014 04:01:08 -0800 Subject: [PATCH 14/19] Make is_rtl()/set_rtl() methods private --- src/widgets/lineedit.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/widgets/lineedit.h b/src/widgets/lineedit.h index 2806a2fa4..d915e9a30 100644 --- a/src/widgets/lineedit.h +++ b/src/widgets/lineedit.h @@ -69,9 +69,6 @@ public: qreal font_point_size() const { return font_point_size_; } void set_font_point_size(qreal size) { font_point_size_ = size; } - bool is_rtl() const { return is_rtl_; }; - void set_rtl(bool rtl) { is_rtl_ = rtl; } - protected: void Paint(QPaintDevice* device); void Resize(); @@ -99,7 +96,6 @@ class LineEdit : public QLineEdit, Q_PROPERTY(qreal font_point_size READ font_point_size WRITE set_font_point_size); Q_PROPERTY(bool has_clear_button READ has_clear_button WRITE set_clear_button); Q_PROPERTY(bool has_reset_button READ has_reset_button WRITE set_reset_button); - Q_PROPERTY(bool is_rtl READ is_rtl WRITE set_rtl); public: LineEdit(QWidget* parent = 0); @@ -114,6 +110,10 @@ protected: void paintEvent(QPaintEvent*); void resizeEvent(QResizeEvent*); +private: + bool is_rtl() const { return is_rtl_; }; + void set_rtl(bool rtl) { is_rtl_ = rtl; } + signals: void Reset(); }; From f201a9925bb7b58a4fd3144805497e7c0e3bfc7f Mon Sep 17 00:00:00 2001 From: Andrew Udvare Date: Sat, 11 Jan 2014 05:13:28 -0800 Subject: [PATCH 15/19] Remove trailing semicolon --- src/widgets/lineedit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/lineedit.h b/src/widgets/lineedit.h index d915e9a30..615b8b74a 100644 --- a/src/widgets/lineedit.h +++ b/src/widgets/lineedit.h @@ -111,7 +111,7 @@ protected: void resizeEvent(QResizeEvent*); private: - bool is_rtl() const { return is_rtl_; }; + bool is_rtl() const { return is_rtl_; } void set_rtl(bool rtl) { is_rtl_ = rtl; } signals: From ad0f8a6f9015f0814a3ced851963079eab0bbaf1 Mon Sep 17 00:00:00 2001 From: goetzc Date: Sat, 11 Jan 2014 15:03:32 -0500 Subject: [PATCH 16/19] playlist context menu entry: Show in library --- src/library/libraryfilterwidget.cpp | 4 ++++ src/library/libraryfilterwidget.h | 1 + src/ui/mainwindow.cpp | 19 +++++++++++++++++++ src/ui/mainwindow.h | 2 ++ 4 files changed, 26 insertions(+) diff --git a/src/library/libraryfilterwidget.cpp b/src/library/libraryfilterwidget.cpp index b30df6d5b..3f866149b 100644 --- a/src/library/libraryfilterwidget.cpp +++ b/src/library/libraryfilterwidget.cpp @@ -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); } diff --git a/src/library/libraryfilterwidget.h b/src/library/libraryfilterwidget.h index 572bb1185..255e35685 100644 --- a/src/library/libraryfilterwidget.h +++ b/src/library/libraryfilterwidget.h @@ -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); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 4810c6c06..387276150 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -509,6 +509,7 @@ MainWindow::MainWindow(Application* app, playlist_copy_to_device_ = playlist_menu_->addAction(IconLoader::Load("multimedia-player-ipod-mini-blue"), tr("Copy to device..."), this, SLOT(PlaylistCopyToDevice())); playlist_delete_ = playlist_menu_->addAction(IconLoader::Load("edit-delete"), tr("Delete from disk..."), this, SLOT(PlaylistDelete())); playlist_open_in_browser_ = playlist_menu_->addAction(IconLoader::Load("document-open-folder"), tr("Show in file browser..."), this, SLOT(PlaylistOpenInBrowser())); + playlist_show_in_library_ = playlist_menu_->addAction(IconLoader::Load("edit-find"), tr("Show in library..."), this, SLOT(ShowInLibrary())); playlist_menu_->addSeparator(); playlistitem_actions_separator_ = playlist_menu_->addSeparator(); playlist_menu_->addAction(ui_->action_clear_playlist); @@ -1360,6 +1361,7 @@ void MainWindow::PlaylistRightClick(const QPoint& global_pos, const QModelIndex& ui_->action_edit_value->setVisible(editable); ui_->action_remove_from_playlist->setEnabled(!selection.isEmpty()); + playlist_show_in_library_->setVisible(false); playlist_copy_to_library_->setVisible(false); playlist_move_to_library_->setVisible(false); playlist_organise_->setVisible(false); @@ -1408,6 +1410,7 @@ void MainWindow::PlaylistRightClick(const QPoint& global_pos, const QModelIndex& PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row()); if (item->IsLocalLibraryItem() && item->Metadata().id() != -1) { playlist_organise_->setVisible(editable); + playlist_show_in_library_->setVisible(editable); } else { playlist_copy_to_library_->setVisible(editable); playlist_move_to_library_->setVisible(editable); @@ -1676,6 +1679,22 @@ void MainWindow::AddCDTracks() { AddToPlaylist(data); } +void MainWindow::ShowInLibrary() { + // Show the first valid selected track artist/album in LibraryView + QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows(); + SongList songs; + + foreach (const QModelIndex& proxy_index, proxy_indexes) { + QModelIndex index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index); + if (app_->playlist_manager()->current()->item_at(index.row())->IsLocalLibraryItem()) { + songs << app_->playlist_manager()->current()->item_at(index.row())->Metadata(); + break; + } + } + QString search = "artist:"+songs[0].artist()+" album:"+songs[0].album(); + library_view_->filter()->ShowInLibrary(search); +} + void MainWindow::PlaylistRemoveCurrent() { ui_->playlist->view()->RemoveSelected(); } diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 039edb4cd..a06482227 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -171,6 +171,7 @@ class MainWindow : public QMainWindow, public PlatformInterface { void PlaylistOrganiseSelected(bool copy); void PlaylistDelete(); void PlaylistOpenInBrowser(); + void ShowInLibrary(); void ChangeLibraryQueryMode(QAction* action); @@ -329,6 +330,7 @@ class MainWindow : public QMainWindow, public PlatformInterface { QAction* playlist_stop_after_; QAction* playlist_undoredo_; QAction* playlist_organise_; + QAction* playlist_show_in_library_; QAction* playlist_copy_to_library_; QAction* playlist_move_to_library_; QAction* playlist_copy_to_device_; From a11270f74981d79eec37e6c195b2b7ace35d8732 Mon Sep 17 00:00:00 2001 From: Andrew Udvare Date: Sat, 11 Jan 2014 12:48:52 -0800 Subject: [PATCH 17/19] Use isEmpty() instead of length() --- src/widgets/lineedit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/lineedit.cpp b/src/widgets/lineedit.cpp index abd141fd6..3cf1262a8 100644 --- a/src/widgets/lineedit.cpp +++ b/src/widgets/lineedit.cpp @@ -150,7 +150,7 @@ void LineEdit::set_text(const QString& text) { // For some reason Qt will detect any text with LTR at the end as LTR, so instead // compare only the first character - if (text.length()) { + if (!text.isEmpty()) { set_rtl(QString(text.at(0)).isRightToLeft()); } } From 773258af99e295d8203a90e2649bb90b88606d10 Mon Sep 17 00:00:00 2001 From: Andrew Udvare Date: Sat, 11 Jan 2014 12:56:39 -0800 Subject: [PATCH 18/19] Both cases move the clear button to the same position --- src/widgets/lineedit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widgets/lineedit.cpp b/src/widgets/lineedit.cpp index 3cf1262a8..718627e4a 100644 --- a/src/widgets/lineedit.cpp +++ b/src/widgets/lineedit.cpp @@ -128,11 +128,11 @@ void ExtendedEditor::Resize() { const int frame_width = widget_->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); const int y = (widget_->rect().height() - sz.height()) / 2; + clear_button_->move(frame_width, y); + if (!is_rtl_) { - clear_button_->move(frame_width, y); reset_button_->move(widget_->width() - frame_width - sz.width() - extra_right_padding_, y); } else { - clear_button_->move(frame_width, y); reset_button_->move((has_clear_button() ? sz.width() + 4 : 0) + frame_width, y); } } From 9647636ab718524fa6e804f1a4d8c7bcac4c40ae Mon Sep 17 00:00:00 2001 From: Mattias Andersson Date: Sat, 11 Jan 2014 18:59:54 +0100 Subject: [PATCH 19/19] Adjust the ui and clean up code. The selection of a destination folder is now done by pressing the button 'Select...'. The last selected folders along with the option 'Alongside the originals' are available in the box 'destination'. The methods TranscodeDialog::TrimPath and TranscodeDialog::GetOutputFileName are now const. Minor formatting fixes. --- src/transcoder/transcodedialog.cpp | 57 +++++++++++++++++------------- src/transcoder/transcodedialog.h | 9 ++--- src/transcoder/transcodedialog.ui | 53 ++++++++++++++++----------- 3 files changed, 69 insertions(+), 50 deletions(-) diff --git a/src/transcoder/transcodedialog.cpp b/src/transcoder/transcodedialog.cpp index 9886f4ba2..fc1cb2edd 100644 --- a/src/transcoder/transcodedialog.cpp +++ b/src/transcoder/transcodedialog.cpp @@ -36,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) { @@ -96,12 +97,6 @@ TranscodeDialog::TranscodeDialog(QWidget *parent) cancel_button_->hide(); ui_->progress_group->hide(); - // Add a destination. - QIcon icon = IconLoader::Load("folder"); - QVariant data = QVariant::fromValue(QDir::homePath()); - QString text = TrimPath(data.toString()); - ui_->destination->addItem(icon, text, data); - // Connect stuff connect(ui_->add, SIGNAL(clicked()), SLOT(Add())); connect(ui_->remove, SIGNAL(clicked()), SLOT(Remove())); @@ -110,8 +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_->destination, SIGNAL(activated(int)), - SLOT(SetDestination(int))); + 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))); @@ -147,7 +142,7 @@ void TranscodeDialog::Start() { // Add jobs to the transcoder for (int i=0 ; irowCount() ; ++i) { QString filename = file_model->index(i, 0).data(Qt::UserRole).toString(); - QString outfilename = SetOutputFileName(filename, preset); + QString outfilename = GetOutputFileName(filename, preset); transcoder_->AddJob(filename, preset, outfilename); } @@ -276,35 +271,47 @@ void TranscodeDialog::Options() { } } -void TranscodeDialog::SetDestination(int index) { - if (!ui_->destination->itemData(index).isNull()) { - QString dir = QFileDialog::getExistingDirectory( - this, tr("Choose folder"), - ui_->destination->itemData(index).toString()); - // Do not update the QComboBox if the user canceled the dialog. - if (!dir.isEmpty()) { - QVariant data = QVariant::fromValue(dir); - QString text = TrimPath(dir); - ui_->destination->setItemText(index, text); - ui_->destination->setItemData(index, data); +// 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) { +QString TranscodeDialog::TrimPath(const QString& path) const { return path.section('/', -1, -1, QString::SectionSkipEmpty); } -QString TranscodeDialog::SetOutputFileName(const QString& input, - const TranscoderPreset &preset) { +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 { + } else { QString file_name = TrimPath(input); file_name = file_name.section('.', 0, -2); return path + '/' + file_name + '.' + preset.extension_; diff --git a/src/transcoder/transcodedialog.h b/src/transcoder/transcodedialog.h index a88097ef7..5be060def 100644 --- a/src/transcoder/transcodedialog.h +++ b/src/transcoder/transcodedialog.h @@ -36,6 +36,7 @@ class TranscodeDialog : public QDialog { static const char* kSettingsGroup; static const int kProgressInterval; + static const int kMaxDestinationItems; void SetFilenames(const QStringList& filenames); @@ -51,15 +52,15 @@ class TranscodeDialog : public QDialog { void LogLine(const QString& message); void AllJobsComplete(); void Options(); - void SetDestination(int index); + void AddDestination(); private: void SetWorking(bool working); void UpdateStatusText(); void UpdateProgress(); - QString TrimPath(const QString& path); - QString SetOutputFileName(const QString& input, - const TranscoderPreset& preset); + QString TrimPath(const QString& path) const; + QString GetOutputFileName(const QString& input, + const TranscoderPreset& preset) const; private: Ui_TranscodeDialog* ui_; diff --git a/src/transcoder/transcodedialog.ui b/src/transcoder/transcodedialog.ui index 2a0e6e956..d6daedd05 100644 --- a/src/transcoder/transcodedialog.ui +++ b/src/transcoder/transcodedialog.ui @@ -98,7 +98,7 @@ Output options - + @@ -107,25 +107,21 @@ - - - - - - 0 - 0 - - - - - - - - Options... - - - - + + + + 0 + 0 + + + + + + + + Options... + + @@ -136,6 +132,15 @@ + + true + + + + 0 + 0 + + Alongside the originals @@ -143,6 +148,13 @@ + + + + Select... + + + @@ -196,7 +208,6 @@ add remove format - destination button_box