1 /* This file is part of Clementine.
2    Copyright 2010, David Sansome <me@davidsansome.com>
3 
4    Clementine is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8 
9    Clementine is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with Clementine.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include "core/logging.h"
19 #include "querywizardplugin.h"
20 #include "ui_wizardfinishpage.h"
21 #include "wizard.h"
22 #include "wizardplugin.h"
23 
24 #include <QLabel>
25 #include <QRadioButton>
26 #include <QVBoxLayout>
27 
28 namespace smart_playlists {
29 
30 class Wizard::TypePage : public QWizardPage {
31  public:
TypePage(QWidget * parent)32   TypePage(QWidget* parent) : QWizardPage(parent), next_id_(-1) {}
33 
nextId() const34   int nextId() const { return next_id_; }
35   int next_id_;
36 };
37 
38 class Wizard::FinishPage : public QWizardPage {
39  public:
FinishPage(QWidget * parent)40   FinishPage(QWidget* parent)
41       : QWizardPage(parent), ui_(new Ui_SmartPlaylistWizardFinishPage) {
42     ui_->setupUi(this);
43     connect(ui_->name, SIGNAL(textChanged(QString)), SIGNAL(completeChanged()));
44   }
45 
~FinishPage()46   ~FinishPage() { delete ui_; }
47 
nextId() const48   int nextId() const { return -1; }
isComplete() const49   bool isComplete() const { return !ui_->name->text().isEmpty(); }
50 
51   Ui_SmartPlaylistWizardFinishPage* ui_;
52 };
53 
Wizard(Application * app,LibraryBackend * library,QWidget * parent)54 Wizard::Wizard(Application* app, LibraryBackend* library, QWidget* parent)
55     : QWizard(parent),
56       app_(app),
57       library_(library),
58       type_page_(new TypePage(this)),
59       finish_page_(new FinishPage(this)),
60       type_index_(-1) {
61   setWindowIcon(QIcon(":/icon.png"));
62   setWindowTitle(tr("Smart playlist"));
63   resize(788, 628);
64 
65 #ifdef Q_OS_MAC
66   // MacStyle leaves an ugly empty space on the left side of the dialog.
67   setWizardStyle(QWizard::ClassicStyle);
68 #endif  // Q_OS_MAC
69 
70   // Type page
71   type_page_->setTitle(tr("Playlist type"));
72   type_page_->setSubTitle(
73       tr("A smart playlist is a dynamic list of songs that come from your "
74          "library.  There are different types of smart playlist that offer "
75          "different ways of selecting songs."));
76   type_page_->setStyleSheet(
77       "QRadioButton { font-weight: bold; }"
78       "QLabel { margin-bottom: 1em; margin-left: 24px; }");
79   addPage(type_page_);
80 
81   // Finish page
82   finish_page_->setTitle(tr("Finish"));
83   finish_page_->setSubTitle(tr("Choose a name for your smart playlist"));
84   finish_id_ = addPage(finish_page_);
85 
86   new QVBoxLayout(type_page_);
87   AddPlugin(new QueryWizardPlugin(app_, library_, this));
88 
89   // Skip the type page - remove this when we have more than one type
90   setStartId(2);
91 }
92 
~Wizard()93 Wizard::~Wizard() { qDeleteAll(plugins_); }
94 
SetGenerator(GeneratorPtr gen)95 void Wizard::SetGenerator(GeneratorPtr gen) {
96   // Find the right type and jump to the start page
97   for (int i = 0; i < plugins_.count(); ++i) {
98     if (plugins_[i]->type() == gen->type()) {
99       TypeChanged(i);
100       // TODO: Put this back in when the setStartId is removed from the ctor
101       // next();
102       break;
103     }
104   }
105 
106   // Set the name
107   finish_page_->ui_->name->setText(gen->name());
108   finish_page_->ui_->dynamic->setChecked(gen->is_dynamic());
109 
110   if (type_index_ == -1) {
111     qLog(Error) << "Plugin was not found for generator type" << gen->type();
112     return;
113   }
114 
115   // Tell the plugin to load
116   plugins_[type_index_]->SetGenerator(gen);
117 }
118 
AddPlugin(WizardPlugin * plugin)119 void Wizard::AddPlugin(WizardPlugin* plugin) {
120   const int index = plugins_.count();
121   plugins_ << plugin;
122   plugin->Init(this, finish_id_);
123 
124   // Create the radio button
125   QRadioButton* radio_button = new QRadioButton(plugin->name(), type_page_);
126   QLabel* description = new QLabel(plugin->description(), type_page_);
127   type_page_->layout()->addWidget(radio_button);
128   type_page_->layout()->addWidget(description);
129 
130   connect(radio_button, &QRadioButton::clicked,
131           [this, index]() { TypeChanged(index); });
132 
133   if (index == 0) {
134     radio_button->setChecked(true);
135     TypeChanged(0);
136   }
137 }
138 
TypeChanged(int index)139 void Wizard::TypeChanged(int index) {
140   type_index_ = index;
141   type_page_->next_id_ = plugins_[type_index_]->start_page();
142 }
143 
CreateGenerator() const144 GeneratorPtr Wizard::CreateGenerator() const {
145   GeneratorPtr ret;
146   if (type_index_ == -1) return ret;
147 
148   ret = plugins_[type_index_]->CreateGenerator();
149   if (!ret) return ret;
150 
151   ret->set_name(finish_page_->ui_->name->text());
152   ret->set_dynamic(finish_page_->ui_->dynamic->isChecked());
153   return ret;
154 }
155 
initializePage(int id)156 void Wizard::initializePage(int id) {
157   if (id == finish_id_) {
158     finish_page_->ui_->dynamic_container->setEnabled(
159         plugins_[type_index_]->is_dynamic());
160   }
161   QWizard::initializePage(id);
162 }
163 
164 }  // namespace
165