Merge pull request #5153 from nicklan/savedmanager

Add dialog for managing saved files
This commit is contained in:
John Maguire 2016-01-08 11:56:01 +00:00
commit 5d868573bc
9 changed files with 471 additions and 1 deletions

View File

@ -211,6 +211,7 @@ set(SOURCES
library/libraryview.cpp
library/libraryviewcontainer.cpp
library/librarywatcher.cpp
library/savedgroupingmanager.cpp
library/sqlrow.cpp
musicbrainz/acoustidclient.cpp
@ -512,7 +513,8 @@ set(HEADERS
library/libraryview.h
library/libraryviewcontainer.h
library/librarywatcher.h
library/savedgroupingmanager.h
musicbrainz/acoustidclient.h
musicbrainz/musicbrainzclient.h
musicbrainz/tagfetcher.h
@ -699,6 +701,7 @@ set(UI
library/libraryfilterwidget.ui
library/librarysettingspage.ui
library/libraryviewcontainer.ui
library/savedgroupingmanager.ui
playlist/dynamicplaylistcontrols.ui
playlist/playlistcontainer.ui

View File

@ -25,6 +25,7 @@
#include "ui/settingsdialog.h"
#include <QActionGroup>
#include <QInputDialog>
#include <QKeyEvent>
#include <QMenu>
#include <QRegExp>
@ -100,11 +101,17 @@ LibraryFilterWidget::LibraryFilterWidget(QWidget* parent)
connect(group_by_group_, SIGNAL(triggered(QAction*)),
SLOT(GroupByClicked(QAction*)));
connect(ui_->save_grouping, SIGNAL(triggered()), this, SLOT(SaveGroupBy()));
connect(ui_->manage_groupings, SIGNAL(triggered()), this,
SLOT(ShowGroupingManager()));
// Library config menu
library_menu_ = new QMenu(tr("Display options"), this);
library_menu_->setIcon(ui_->options->icon());
library_menu_->addMenu(filter_age_menu_);
library_menu_->addMenu(group_by_menu_);
library_menu_->addAction(ui_->save_grouping);
library_menu_->addAction(ui_->manage_groupings);
library_menu_->addSeparator();
ui_->options->setMenu(library_menu_);
@ -114,6 +121,22 @@ LibraryFilterWidget::LibraryFilterWidget(QWidget* parent)
LibraryFilterWidget::~LibraryFilterWidget() { delete ui_; }
void LibraryFilterWidget::UpdateGroupByActions() {
if (group_by_group_) {
disconnect(group_by_group_, 0, 0, 0);
delete group_by_group_;
}
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*)));
if (model_) {
CheckCurrentGrouping(model_->GetGroupBy());
}
}
QActionGroup* LibraryFilterWidget::CreateGroupByActions(QObject* parent) {
QActionGroup* ret = new QActionGroup(parent);
ret->addAction(CreateGroupByAction(
@ -139,6 +162,27 @@ QActionGroup* LibraryFilterWidget::CreateGroupByActions(QObject* parent) {
LibraryModel::Grouping(LibraryModel::GroupBy_Genre,
LibraryModel::GroupBy_Artist,
LibraryModel::GroupBy_Album)));
QAction* sep1 = new QAction(parent);
sep1->setSeparator(true);
ret->addAction(sep1);
// read saved groupings
QSettings s;
s.beginGroup(LibraryModel::kSavedGroupingsSettingsGroup);
QStringList saved = s.childKeys();
for (int i = 0; i < saved.size(); ++i) {
QByteArray bytes = s.value(saved.at(i)).toByteArray();
QDataStream ds(&bytes, QIODevice::ReadOnly);
LibraryModel::Grouping g;
ds >> g;
ret->addAction(CreateGroupByAction(saved.at(i), parent, g));
}
QAction* sep2 = new QAction(parent);
sep2->setSeparator(true);
ret->addAction(sep2);
ret->addAction(CreateGroupByAction(tr("Advanced grouping..."), parent,
LibraryModel::Grouping()));
@ -158,6 +202,24 @@ QAction* LibraryFilterWidget::CreateGroupByAction(
return ret;
}
void LibraryFilterWidget::SaveGroupBy() {
QString text =
QInputDialog::getText(this, tr("Grouping Name"), tr("Grouping name:"));
if (!text.isEmpty() && model_) {
model_->SaveGrouping(text);
UpdateGroupByActions();
}
}
void LibraryFilterWidget::ShowGroupingManager() {
if (!groupings_manager_) {
groupings_manager_.reset(new SavedGroupingManager);
}
groupings_manager_->SetFilter(this);
groupings_manager_->UpdateModel();
groupings_manager_->show();
}
void LibraryFilterWidget::FocusOnFilter(QKeyEvent* event) {
ui_->filter->setFocus();
QApplication::sendEvent(ui_->filter, event);
@ -220,6 +282,11 @@ void LibraryFilterWidget::GroupingChanged(const LibraryModel::Grouping& g) {
}
// Now make sure the correct action is checked
CheckCurrentGrouping(g);
}
void LibraryFilterWidget::CheckCurrentGrouping(
const LibraryModel::Grouping& g) {
for (QAction* action : group_by_group_->actions()) {
if (action->property("group_by").isNull()) continue;

View File

@ -23,6 +23,7 @@
#include <QWidget>
#include "librarymodel.h"
#include "savedgroupingmanager.h"
class GroupByDialog;
class SettingsDialog;
@ -51,6 +52,7 @@ class LibraryFilterWidget : public QWidget {
static QActionGroup* CreateGroupByActions(QObject* parent);
void UpdateGroupByActions();
void SetFilterHint(const QString& hint);
void SetApplyFilterToLibrary(bool filter_applies_to_model) {
filter_applies_to_model_ = filter_applies_to_model;
@ -84,6 +86,8 @@ signals:
private slots:
void GroupingChanged(const LibraryModel::Grouping& g);
void GroupByClicked(QAction* action);
void SaveGroupBy();
void ShowGroupingManager();
void FilterTextChanged(const QString& text);
void FilterDelayTimeout();
@ -91,12 +95,14 @@ signals:
private:
static QAction* CreateGroupByAction(const QString& text, QObject* parent,
const LibraryModel::Grouping& grouping);
void CheckCurrentGrouping(const LibraryModel::Grouping& g);
private:
Ui_LibraryFilterWidget* ui_;
LibraryModel* model_;
std::unique_ptr<GroupByDialog> group_by_dialog_;
std::unique_ptr<SavedGroupingManager> groupings_manager_;
SettingsDialog* settings_dialog_;
QMenu* filter_age_menu_;

View File

@ -98,6 +98,16 @@
<string>Added this month</string>
</property>
</action>
<action name="save_grouping">
<property name="text">
<string>Save current grouping</string>
</property>
</action>
<action name="manage_groupings">
<property name="text">
<string>Manage saved groupings</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -59,6 +59,7 @@ const char* LibraryModel::kSmartPlaylistsMimeType =
"application/x-clementine-smart-playlist-generator";
const char* LibraryModel::kSmartPlaylistsSettingsGroup =
"SerialisedSmartPlaylists";
const char* LibraryModel::kSavedGroupingsSettingsGroup = "SavedGroupings";
const int LibraryModel::kSmartPlaylistsVersion = 4;
const int LibraryModel::kPrettyCoverSize = 32;
const qint64 LibraryModel::kIconCacheSize = 100000000; //~100MB
@ -141,6 +142,18 @@ void LibraryModel::set_show_dividers(bool show_dividers) {
}
}
void LibraryModel::SaveGrouping(QString name) {
qLog(Debug) << "Model, save to: " << name;
QByteArray buffer;
QDataStream ds(&buffer, QIODevice::WriteOnly);
ds << group_by_;
QSettings s;
s.beginGroup(kSavedGroupingsSettingsGroup);
s.setValue(name, buffer);
}
void LibraryModel::Init(bool async) {
if (async) {
// Show a loading indicator in the model.
@ -1490,3 +1503,19 @@ void LibraryModel::TotalSongCountUpdatedSlot(int count) {
total_song_count_ = count;
emit TotalSongCountUpdated(count);
}
QDataStream& operator<<(QDataStream& s, const LibraryModel::Grouping& g) {
s << quint32(g.first) << quint32(g.second) << quint32(g.third);
return s;
}
QDataStream& operator>>(QDataStream& s, LibraryModel::Grouping& g) {
quint32 buf;
s >> buf;
g.first = LibraryModel::GroupBy(buf);
s >> buf;
g.second = LibraryModel::GroupBy(buf);
s >> buf;
g.third = LibraryModel::GroupBy(buf);
return s;
}

View File

@ -55,6 +55,7 @@ class LibraryModel : public SimpleTreeModel<LibraryItem> {
static const char* kSmartPlaylistsMimeType;
static const char* kSmartPlaylistsSettingsGroup;
static const char* kSmartPlaylistsArray;
static const char* kSavedGroupingsSettingsGroup;
static const int kSmartPlaylistsVersion;
static const int kPrettyCoverSize;
static const qint64 kIconCacheSize;
@ -161,6 +162,9 @@ class LibraryModel : public SimpleTreeModel<LibraryItem> {
// Whether or not to show letters heading in the library view
void set_show_dividers(bool show_dividers);
// Save the current grouping
void SaveGrouping(QString name);
// Utility functions for manipulating text
static QString TextOrUnknown(const QString& text);
static QString PrettyYearAlbum(int year, const QString& album);
@ -179,6 +183,7 @@ signals:
void SetFilterQueryMode(QueryOptions::QueryMode query_mode);
void SetGroupBy(const LibraryModel::Grouping& g);
const LibraryModel::Grouping& GetGroupBy() const { return group_by_; }
void Init(bool async = true);
void Reset();
void ResetAsync();
@ -300,4 +305,7 @@ signals:
Q_DECLARE_METATYPE(LibraryModel::Grouping);
QDataStream& operator<<(QDataStream& s, const LibraryModel::Grouping& g);
QDataStream& operator>>(QDataStream& s, LibraryModel::Grouping& g);
#endif // LIBRARYMODEL_H

View File

@ -0,0 +1,152 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "libraryfilterwidget.h"
#include "librarymodel.h"
#include "savedgroupingmanager.h"
#include "ui_savedgroupingmanager.h"
#include "ui/iconloader.h"
#include <QKeySequence>
#include <QList>
#include <QSettings>
#include <QStandardItem>
SavedGroupingManager::SavedGroupingManager(QWidget* parent)
: QDialog(parent),
ui_(new Ui_SavedGroupingManager),
model_(new QStandardItemModel(0, 4, this)) {
ui_->setupUi(this);
model_->setHorizontalHeaderItem(0, new QStandardItem(tr("Name")));
model_->setHorizontalHeaderItem(1, new QStandardItem(tr("First level")));
model_->setHorizontalHeaderItem(2, new QStandardItem(tr("Second Level")));
model_->setHorizontalHeaderItem(3, new QStandardItem(tr("Third Level")));
ui_->list->setModel(model_);
ui_->remove->setIcon(IconLoader::Load("edit-delete", IconLoader::Base));
ui_->remove->setEnabled(false);
ui_->remove->setShortcut(QKeySequence::Delete);
connect(ui_->list->selectionModel(),
SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
SLOT(UpdateButtonState()));
connect(ui_->remove, SIGNAL(clicked()), SLOT(Remove()));
}
SavedGroupingManager::~SavedGroupingManager() {
delete ui_;
delete model_;
}
QString SavedGroupingManager::GroupByToString(const LibraryModel::GroupBy& g) {
switch (g) {
case LibraryModel::GroupBy_None: {
return tr("None");
}
case LibraryModel::GroupBy_Artist: {
return tr("Artist");
}
case LibraryModel::GroupBy_Album: {
return tr("Album");
}
case LibraryModel::GroupBy_YearAlbum: {
return tr("Year - Album");
}
case LibraryModel::GroupBy_Year: {
return tr("Year");
}
case LibraryModel::GroupBy_Composer: {
return tr("Composer");
}
case LibraryModel::GroupBy_Genre: {
return tr("Genre");
}
case LibraryModel::GroupBy_AlbumArtist: {
return tr("Album artist");
}
case LibraryModel::GroupBy_FileType: {
return tr("File type");
}
case LibraryModel::GroupBy_Performer: {
return tr("Performer");
}
case LibraryModel::GroupBy_Grouping: {
return tr("Grouping");
}
case LibraryModel::GroupBy_Bitrate: {
return tr("Bitrate");
}
case LibraryModel::GroupBy_Disc: {
return tr("Disc");
}
case LibraryModel::GroupBy_OriginalYearAlbum: {
return tr("Original year - Album");
}
case LibraryModel::GroupBy_OriginalYear: {
return tr("Original year");
}
default: { return tr("Unknown"); }
}
}
void SavedGroupingManager::UpdateModel() {
model_->setRowCount(0); // don't use clear, it deletes headers
QSettings s;
s.beginGroup(LibraryModel::kSavedGroupingsSettingsGroup);
QStringList saved = s.childKeys();
for (int i = 0; i < saved.size(); ++i) {
QByteArray bytes = s.value(saved.at(i)).toByteArray();
QDataStream ds(&bytes, QIODevice::ReadOnly);
LibraryModel::Grouping g;
ds >> g;
QList<QStandardItem*> list;
list << new QStandardItem(saved.at(i))
<< new QStandardItem(GroupByToString(g.first))
<< new QStandardItem(GroupByToString(g.second))
<< new QStandardItem(GroupByToString(g.third));
model_->appendRow(list);
}
}
void SavedGroupingManager::Remove() {
if (ui_->list->selectionModel()->hasSelection()) {
QSettings s;
s.beginGroup(LibraryModel::kSavedGroupingsSettingsGroup);
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());
}
}
}
UpdateModel();
filter_->UpdateGroupByActions();
}
void SavedGroupingManager::UpdateButtonState() {
if (ui_->list->selectionModel()->hasSelection()) {
const QModelIndex current = ui_->list->selectionModel()->currentIndex();
ui_->remove->setEnabled(current.isValid());
} else {
ui_->remove->setEnabled(false);
}
}

View File

@ -0,0 +1,51 @@
/* This file is part of Clementine.
Copyright 2015, Nick Lanham <nick@afternight.org>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SAVEDGROUPINGMANAGER_H
#define SAVEDGROUPINGMANAGER_H
#include <QDialog>
#include <QStandardItemModel>
#include "librarymodel.h"
class Ui_SavedGroupingManager;
class LibraryFilterWidget;
class SavedGroupingManager : public QDialog {
Q_OBJECT
public:
SavedGroupingManager(QWidget* parent = nullptr);
~SavedGroupingManager();
void UpdateModel();
void SetFilter(LibraryFilterWidget* filter) { filter_ = filter; }
static QString GroupByToString(const LibraryModel::GroupBy& g);
private slots:
void UpdateButtonState();
void Remove();
private:
Ui_SavedGroupingManager* ui_;
QStandardItemModel* model_;
LibraryFilterWidget* filter_;
};
#endif // SAVEDGROUPINGMANAGER_H

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SavedGroupingManager</class>
<widget class="QDialog" name="SavedGroupingManager">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>582</width>
<height>363</height>
</rect>
</property>
<property name="windowTitle">
<string>Saved Grouping Manager</string>
</property>
<property name="windowIcon">
<iconset resource="../../data/data.qrc">
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTreeView" name="list">
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="showDropIndicator" stdset="0">
<bool>true</bool>
</property>
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<attribute name="headerVisible">
<bool>true</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="remove">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Remove</string>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="shortcut">
<string>Ctrl+Up</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../data/data.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SavedGroupingManager</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SavedGroupingManager</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>