mirror of
https://github.com/clementine-player/Clementine
synced 2025-01-31 11:35:24 +01:00
Python bindings for LibraryView + new UI hook for plugins: the view's context menu
support for IN operator in LibraryQuery.AddWhere
This commit is contained in:
parent
1a959b136c
commit
07739d6c68
@ -71,8 +71,17 @@ void LibraryQuery::AddWhere(const QString& column, const QVariant& value, const
|
||||
if (value.type() == QVariant::Int)
|
||||
where_clauses_ << QString("%1 %2 %3").arg(column, op, value.toString());
|
||||
else {
|
||||
where_clauses_ << QString("%1 %2 ?").arg(column, op);
|
||||
bound_values_ << value;
|
||||
if(!op.compare("IN", Qt::CaseInsensitive)) {
|
||||
QStringList final;
|
||||
foreach(const QString& old, value.toStringList()) {
|
||||
final << "'" + QString(old).replace("'", "''") + "'";
|
||||
}
|
||||
|
||||
where_clauses_ << QString("%1 IN (%3)").arg(column, final.join(","));
|
||||
} else {
|
||||
where_clauses_ << QString("%1 %2 ?").arg(column, op);
|
||||
bound_values_ << value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,6 +92,7 @@ void LibraryQuery::AddCompilationRequirement(bool compilation) {
|
||||
QSqlError LibraryQuery::Exec(QSqlDatabase db, const QString& songs_table,
|
||||
const QString& fts_table) {
|
||||
QString sql;
|
||||
|
||||
if (join_with_fts_) {
|
||||
sql = QString("SELECT %1 FROM %2 INNER JOIN %3 AS fts ON %2.ROWID = fts.ROWID")
|
||||
.arg(column_spec_, songs_table, fts_table);
|
||||
@ -103,6 +113,7 @@ QSqlError LibraryQuery::Exec(QSqlDatabase db, const QString& songs_table,
|
||||
sql.replace("%songs_table", songs_table);
|
||||
sql.replace("%fts_table_noprefix", fts_table.section('.', -1, -1));
|
||||
sql.replace("%fts_table", fts_table);
|
||||
|
||||
query_ = QSqlQuery(sql, db);
|
||||
|
||||
// Bind values
|
||||
|
@ -42,6 +42,9 @@ class LibraryQuery {
|
||||
|
||||
void SetColumnSpec(const QString& spec) { column_spec_ = spec; }
|
||||
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.
|
||||
// Please note that IN operator expects a QStringList as value.
|
||||
void AddWhere(const QString& column, const QVariant& value, const QString& op = "=");
|
||||
void AddCompilationRequirement(bool compilation);
|
||||
void SetLimit(int limit) { limit_ = limit; }
|
||||
|
@ -96,6 +96,46 @@ LibraryView::LibraryView(QWidget* parent)
|
||||
|
||||
ReloadSettings();
|
||||
setStyleSheet("QTreeView::item{padding-top:1px;}");
|
||||
|
||||
context_menu_ = new QMenu(this);
|
||||
load_ = context_menu_->addAction(IconLoader::Load("media-playback-start"),
|
||||
tr("Load"), this, SLOT(Load()));
|
||||
add_to_playlist_ = context_menu_->addAction(IconLoader::Load("media-playback-start"),
|
||||
tr("Add to playlist"), this, SLOT(AddToPlaylist()));
|
||||
add_to_playlist_enqueue_ = context_menu_->addAction(IconLoader::Load("media-playback-start"),
|
||||
tr("Enqueue to playlist"), this, SLOT(AddToPlaylistEnqueue()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
new_smart_playlist_ = context_menu_->addAction(IconLoader::Load("document-new"),
|
||||
tr("New smart playlist..."), this, SLOT(NewSmartPlaylist()));
|
||||
edit_smart_playlist_ = context_menu_->addAction(IconLoader::Load("edit-rename"),
|
||||
tr("Edit smart playlist..."), this, SLOT(EditSmartPlaylist()));
|
||||
delete_smart_playlist_ = context_menu_->addAction(IconLoader::Load("edit-delete"),
|
||||
tr("Delete smart playlist"), this, SLOT(DeleteSmartPlaylist()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
organise_ = context_menu_->addAction(IconLoader::Load("edit-copy"),
|
||||
tr("Organise files..."), this, SLOT(Organise()));
|
||||
copy_to_device_ = context_menu_->addAction(IconLoader::Load("multimedia-player-ipod-mini-blue"),
|
||||
tr("Copy to device..."), this, SLOT(CopyToDevice()));
|
||||
// this will get finalized later
|
||||
copy_to_device_->setDisabled(true);
|
||||
delete_ = context_menu_->addAction(IconLoader::Load("edit-delete"),
|
||||
tr("Delete from disk..."), this, SLOT(Delete()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
edit_track_ = context_menu_->addAction(IconLoader::Load("edit-rename"),
|
||||
tr("Edit track information..."), this, SLOT(EditTracks()));
|
||||
edit_tracks_ = context_menu_->addAction(IconLoader::Load("edit-rename"),
|
||||
tr("Edit tracks information..."), this, SLOT(EditTracks()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
show_in_various_ = context_menu_->addAction(
|
||||
tr("Show in various artists"), this, SLOT(ShowInVarious()));
|
||||
no_show_in_various_ = context_menu_->addAction(
|
||||
tr("Don't show in various artists"), this, SLOT(NoShowInVarious()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
}
|
||||
|
||||
LibraryView::~LibraryView() {
|
||||
@ -123,6 +163,11 @@ void LibraryView::SetLibrary(LibraryModel *library) {
|
||||
|
||||
void LibraryView::SetDeviceManager(DeviceManager *device_manager) {
|
||||
devices_ = device_manager;
|
||||
|
||||
// lazy finalization
|
||||
copy_to_device_->setDisabled(devices_->connected_devices_model()->rowCount() == 0);
|
||||
connect(devices_->connected_devices_model(), SIGNAL(IsEmptyChanged(bool)),
|
||||
copy_to_device_, SLOT(setDisabled(bool)));
|
||||
}
|
||||
|
||||
void LibraryView::TotalSongCountUpdated(int count) {
|
||||
@ -176,48 +221,6 @@ void LibraryView::mouseReleaseEvent(QMouseEvent* e) {
|
||||
}
|
||||
|
||||
void LibraryView::contextMenuEvent(QContextMenuEvent *e) {
|
||||
if (!context_menu_) {
|
||||
context_menu_ = new QMenu(this);
|
||||
load_ = context_menu_->addAction(IconLoader::Load("media-playback-start"),
|
||||
tr("Load"), this, SLOT(Load()));
|
||||
add_to_playlist_ = context_menu_->addAction(IconLoader::Load("media-playback-start"),
|
||||
tr("Add to playlist"), this, SLOT(AddToPlaylist()));
|
||||
add_to_playlist_enqueue_ = context_menu_->addAction(IconLoader::Load("media-playback-start"),
|
||||
tr("Enqueue to playlist"), this, SLOT(AddToPlaylistEnqueue()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
new_smart_playlist_ = context_menu_->addAction(IconLoader::Load("document-new"),
|
||||
tr("New smart playlist..."), this, SLOT(NewSmartPlaylist()));
|
||||
edit_smart_playlist_ = context_menu_->addAction(IconLoader::Load("edit-rename"),
|
||||
tr("Edit smart playlist..."), this, SLOT(EditSmartPlaylist()));
|
||||
delete_smart_playlist_ = context_menu_->addAction(IconLoader::Load("edit-delete"),
|
||||
tr("Delete smart playlist"), this, SLOT(DeleteSmartPlaylist()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
organise_ = context_menu_->addAction(IconLoader::Load("edit-copy"),
|
||||
tr("Organise files..."), this, SLOT(Organise()));
|
||||
copy_to_device_ = context_menu_->addAction(IconLoader::Load("multimedia-player-ipod-mini-blue"),
|
||||
tr("Copy to device..."), this, SLOT(CopyToDevice()));
|
||||
delete_ = context_menu_->addAction(IconLoader::Load("edit-delete"),
|
||||
tr("Delete from disk..."), this, SLOT(Delete()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
edit_track_ = context_menu_->addAction(IconLoader::Load("edit-rename"),
|
||||
tr("Edit track information..."), this, SLOT(EditTracks()));
|
||||
edit_tracks_ = context_menu_->addAction(IconLoader::Load("edit-rename"),
|
||||
tr("Edit tracks information..."), this, SLOT(EditTracks()));
|
||||
|
||||
context_menu_->addSeparator();
|
||||
show_in_various_ = context_menu_->addAction(
|
||||
tr("Show in various artists"), this, SLOT(ShowInVarious()));
|
||||
no_show_in_various_ = context_menu_->addAction(
|
||||
tr("Don't show in various artists"), this, SLOT(NoShowInVarious()));
|
||||
|
||||
copy_to_device_->setDisabled(devices_->connected_devices_model()->rowCount() == 0);
|
||||
connect(devices_->connected_devices_model(), SIGNAL(IsEmptyChanged(bool)),
|
||||
copy_to_device_, SLOT(setDisabled(bool)));
|
||||
}
|
||||
|
||||
context_menu_index_ = indexAt(e->pos());
|
||||
if (!context_menu_index_.isValid())
|
||||
return;
|
||||
@ -225,6 +228,7 @@ void LibraryView::contextMenuEvent(QContextMenuEvent *e) {
|
||||
context_menu_index_ = qobject_cast<QSortFilterProxyModel*>(model())
|
||||
->mapToSource(context_menu_index_);
|
||||
|
||||
// TODO: check if custom plugin actions should be enabled / visible
|
||||
const int type = library_->data(context_menu_index_, LibraryModel::Role_Type).toInt();
|
||||
const bool enable_various = type == LibraryItem::Type_Container ||
|
||||
type == LibraryItem::Type_Song;
|
||||
|
@ -50,6 +50,11 @@ class LibraryView : public AutoExpandingTreeView {
|
||||
|
||||
static const char* kSettingsGroup;
|
||||
|
||||
// Returns Songs currently selected in the library 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 SetTaskManager(TaskManager* task_manager);
|
||||
void SetLibrary(LibraryModel* library);
|
||||
void SetDeviceManager(DeviceManager* device_manager);
|
||||
@ -58,6 +63,8 @@ class LibraryView : public AutoExpandingTreeView {
|
||||
void keyboardSearch(const QString &search);
|
||||
void scrollTo(const QModelIndex& index, ScrollHint hint = EnsureVisible);
|
||||
|
||||
QMenu* context_menu() const { return context_menu_; }
|
||||
|
||||
public slots:
|
||||
void TotalSongCountUpdated(int count);
|
||||
void ReloadSettings();
|
||||
@ -99,7 +106,6 @@ class LibraryView : public AutoExpandingTreeView {
|
||||
private:
|
||||
void RecheckIsEmpty();
|
||||
void ShowInVarious(bool on);
|
||||
SongList GetSelectedSongs() const;
|
||||
|
||||
private:
|
||||
LibraryModel* library_;
|
||||
|
7
src/scripting/python/autoexpandingtreeview.sip
Normal file
7
src/scripting/python/autoexpandingtreeview.sip
Normal file
@ -0,0 +1,7 @@
|
||||
class AutoExpandingTreeView : QTreeView {
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "widgets/autoexpandingtreeview.h"
|
||||
%End
|
||||
|
||||
};
|
@ -4,11 +4,13 @@
|
||||
%Import QtGui/QtGuimod.sip
|
||||
%Import QtNetwork/QtNetworkmod.sip
|
||||
|
||||
%Include autoexpandingtreeview.sip
|
||||
%Include directory.sip
|
||||
%Include engine_fwd.sip
|
||||
%Include iconloader.sip
|
||||
%Include librarybackend.sip
|
||||
%Include libraryquery.sip
|
||||
%Include libraryview.sip
|
||||
%Include mergedproxymodel.sip
|
||||
%Include network.sip
|
||||
%Include parserbase.sip
|
||||
|
10
src/scripting/python/libraryview.sip
Normal file
10
src/scripting/python/libraryview.sip
Normal file
@ -0,0 +1,10 @@
|
||||
class LibraryView : AutoExpandingTreeView {
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "library/libraryview.h"
|
||||
%End
|
||||
|
||||
public:
|
||||
SongList GetSelectedSongs() const;
|
||||
|
||||
};
|
@ -114,6 +114,7 @@ Script* PythonEngine::CreateScript(const ScriptInfo& info) {
|
||||
AddObject(manager()->data().settings_dialog_, sipType_SettingsDialog, "settings_dialog");
|
||||
AddObject(manager()->data().radio_model_, sipType_RadioModel, "radio_model");
|
||||
AddObject(manager()->ui(), sipType_UIInterface, "ui");
|
||||
AddObject(manager()->data().library_view_, sipType_LibraryView, "library_view");
|
||||
AddObject(this, sipType_PythonEngine, "pythonengine");
|
||||
|
||||
// Create a module for scripts
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
class LanguageEngine;
|
||||
class Library;
|
||||
class LibraryView;
|
||||
class Player;
|
||||
class PlaylistManager;
|
||||
class RadioModel;
|
||||
@ -57,10 +58,11 @@ public:
|
||||
|
||||
struct GlobalData {
|
||||
GlobalData() {}
|
||||
GlobalData(Library* library, Player* player, PlaylistManager* playlists,
|
||||
TaskManager* task_manager, SettingsDialog* settings_dialog,
|
||||
RadioModel* radio_model)
|
||||
GlobalData(Library* library, LibraryView* library_view, Player* player,
|
||||
PlaylistManager* playlists, TaskManager* task_manager,
|
||||
SettingsDialog* settings_dialog, RadioModel* radio_model)
|
||||
: library_(library),
|
||||
library_view_(library_view),
|
||||
player_(player),
|
||||
playlists_(playlists),
|
||||
task_manager_(task_manager),
|
||||
@ -69,6 +71,7 @@ public:
|
||||
{}
|
||||
|
||||
Library* library_;
|
||||
LibraryView* library_view_;
|
||||
Player* player_;
|
||||
PlaylistManager* playlists_;
|
||||
TaskManager* task_manager_;
|
||||
|
@ -72,15 +72,15 @@ msgstr ""
|
||||
msgid "%1: Wiimotedev module"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
#, c-format, qt-plural-format
|
||||
msgid "%n failed"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
#, c-format, qt-plural-format
|
||||
msgid "%n finished"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
#, c-format, qt-plural-format
|
||||
msgid "%n remaining"
|
||||
msgstr ""
|
||||
|
||||
@ -2513,7 +2513,7 @@ msgstr ""
|
||||
msgid "Zero"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
#, c-format, qt-plural-format
|
||||
msgid "add %n songs"
|
||||
msgstr ""
|
||||
|
||||
@ -2572,7 +2572,7 @@ msgstr ""
|
||||
msgid "options"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
#, c-format, qt-plural-format
|
||||
msgid "remove %n songs"
|
||||
msgstr ""
|
||||
|
||||
|
@ -587,6 +587,7 @@ MainWindow::MainWindow(
|
||||
scripts_->ui()->RegisterActionLocation("tools_menu", ui_->menu_tools, ui_->action_update_library);
|
||||
scripts_->ui()->RegisterActionLocation("extras_menu", ui_->menu_extras, NULL);
|
||||
scripts_->ui()->RegisterActionLocation("help_menu", ui_->menu_help, NULL);
|
||||
scripts_->ui()->RegisterActionLocation("library_context_menu", library_view_->view()->context_menu(), NULL);
|
||||
|
||||
// Load theme
|
||||
StyleSheetLoader* css_loader = new StyleSheetLoader(this);
|
||||
@ -645,8 +646,8 @@ MainWindow::MainWindow(
|
||||
#endif
|
||||
|
||||
scripts_->Init(ScriptManager::GlobalData(
|
||||
library_, player_, playlists_, task_manager_, settings_dialog_.get(),
|
||||
radio_model_));
|
||||
library_, library_view_->view(), player_, playlists_,
|
||||
task_manager_, settings_dialog_.get(), radio_model_));
|
||||
connect(ui_->action_script_manager, SIGNAL(triggered()), SLOT(ShowScriptDialog()));
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user