1 /* This file is part of Clementine.
2    Copyright 2011, 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 "globalsearch.h"
19 #include "globalsearchsettingspage.h"
20 #include "core/logging.h"
21 #include "ui/iconloader.h"
22 #include "ui/settingsdialog.h"
23 #include "ui_globalsearchsettingspage.h"
24 
25 #include <algorithm>
26 
27 #include <QSettings>
28 
GlobalSearchSettingsPage(SettingsDialog * dialog)29 GlobalSearchSettingsPage::GlobalSearchSettingsPage(SettingsDialog* dialog)
30     : SettingsPage(dialog), ui_(new Ui::GlobalSearchSettingsPage) {
31   ui_->setupUi(this);
32   setWindowIcon(IconLoader::Load("search", IconLoader::Base));
33 
34   ui_->sources->header()->setSectionResizeMode(0, QHeaderView::Stretch);
35   ui_->sources->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
36 
37   warning_icon_ = IconLoader::Load("dialog-warning", IconLoader::Base);
38 
39   connect(ui_->up, SIGNAL(clicked()), SLOT(MoveUp()));
40   connect(ui_->down, SIGNAL(clicked()), SLOT(MoveDown()));
41   connect(ui_->configure, SIGNAL(clicked()), SLOT(ConfigureProvider()));
42   connect(ui_->sources,
43           SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
44           SLOT(CurrentProviderChanged(QTreeWidgetItem*)));
45 }
46 
~GlobalSearchSettingsPage()47 GlobalSearchSettingsPage::~GlobalSearchSettingsPage() {}
48 
CompareProviderId(SearchProvider * left,SearchProvider * right)49 static bool CompareProviderId(SearchProvider* left, SearchProvider* right) {
50   return left->id() < right->id();
51 }
52 
Load()53 void GlobalSearchSettingsPage::Load() {
54   QSettings s;
55   s.beginGroup(GlobalSearch::kSettingsGroup);
56 
57   GlobalSearch* engine = dialog()->global_search();
58   QList<SearchProvider*> providers = engine->providers();
59 
60   // Sort the list of providers alphabetically (by id) initially, so any that
61   // aren't in the provider_order list will take this order.
62   std::sort(providers.begin(), providers.end(), CompareProviderId);
63 
64   // Add the ones in the configured list first
65   ui_->sources->clear();
66   for (const QString& id :
67        s.value("provider_order", QStringList() << "library").toStringList()) {
68     // Find a matching provider for this id
69     for (QList<SearchProvider*>::iterator it = providers.begin();
70          it != providers.end(); ++it) {
71       if ((*it)->id() == id) {
72         AddProviderItem(engine, *it);
73         providers.erase(it);
74         break;
75       }
76     }
77   }
78 
79   // Now add any others that are remaining
80   for (SearchProvider* provider : providers) {
81     AddProviderItem(engine, provider);
82   }
83 
84   ui_->show_providers->setChecked(s.value("show_providers", true).toBool());
85   ui_->show_suggestions->setChecked(s.value("show_suggestions", true).toBool());
86 }
87 
AddProviderItem(GlobalSearch * engine,SearchProvider * provider)88 void GlobalSearchSettingsPage::AddProviderItem(GlobalSearch* engine,
89                                                SearchProvider* provider) {
90   QTreeWidgetItem* item = new QTreeWidgetItem;
91   item->setText(0, provider->name());
92   item->setIcon(0, provider->icon());
93   item->setData(0, Qt::UserRole, QVariant::fromValue(provider));
94 
95   UpdateLoggedInState(engine, item, true);
96 
97   ui_->sources->invisibleRootItem()->addChild(item);
98 }
99 
UpdateLoggedInState(GlobalSearch * engine,QTreeWidgetItem * item,bool set_checked_state)100 void GlobalSearchSettingsPage::UpdateLoggedInState(GlobalSearch* engine,
101                                                    QTreeWidgetItem* item,
102                                                    bool set_checked_state) {
103   SearchProvider* provider =
104       item->data(0, Qt::UserRole).value<SearchProvider*>();
105 
106   const bool enabled = engine->is_provider_enabled(provider);
107   const bool logged_in = provider->IsLoggedIn();
108 
109   Qt::CheckState check_state =
110       logged_in && enabled ? Qt::Checked : Qt::Unchecked;
111   Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
112   if (logged_in) flags |= Qt::ItemIsUserCheckable;
113 
114   if (set_checked_state) item->setData(0, Qt::CheckStateRole, check_state);
115   item->setFlags(flags);
116 
117   if (logged_in) {
118     item->setIcon(1, QIcon());
119     item->setText(1, QString());
120   } else {
121     item->setIcon(1, warning_icon_);
122     item->setText(1, tr("Not logged in") + "    ");
123   }
124 }
125 
Save()126 void GlobalSearchSettingsPage::Save() {
127   QSettings s;
128   s.beginGroup(GlobalSearch::kSettingsGroup);
129 
130   QStringList provider_order;
131 
132   for (int i = 0; i < ui_->sources->invisibleRootItem()->childCount(); ++i) {
133     const QTreeWidgetItem* item = ui_->sources->invisibleRootItem()->child(i);
134     const SearchProvider* provider =
135         item->data(0, Qt::UserRole).value<SearchProvider*>();
136 
137     provider_order << provider->id();
138 
139     // Only save the enabled state for this provider if it's logged in.
140     if (item->flags() & Qt::ItemIsUserCheckable) {
141       s.setValue("enabled_" + provider->id(),
142                  item->data(0, Qt::CheckStateRole).toInt() == Qt::Checked);
143     }
144   }
145 
146   s.setValue("provider_order", provider_order);
147   s.setValue("show_providers", ui_->show_providers->isChecked());
148   s.setValue("show_suggestions", ui_->show_suggestions->isChecked());
149 }
150 
MoveUp()151 void GlobalSearchSettingsPage::MoveUp() { MoveCurrentItem(-1); }
152 
MoveDown()153 void GlobalSearchSettingsPage::MoveDown() { MoveCurrentItem(+1); }
154 
MoveCurrentItem(int d)155 void GlobalSearchSettingsPage::MoveCurrentItem(int d) {
156   QTreeWidgetItem* item = ui_->sources->currentItem();
157   if (!item) return;
158 
159   QTreeWidgetItem* root = ui_->sources->invisibleRootItem();
160 
161   const int row = root->indexOfChild(item);
162   const int new_row = qBound(0, row + d, root->childCount());
163 
164   if (row == new_row) return;
165 
166   root->removeChild(item);
167   root->insertChild(new_row, item);
168 
169   ui_->sources->setCurrentItem(item);
170 }
171 
ConfigureProvider()172 void GlobalSearchSettingsPage::ConfigureProvider() {
173   QTreeWidgetItem* item = ui_->sources->currentItem();
174   if (!item) return;
175 
176   SearchProvider* provider =
177       item->data(0, Qt::UserRole).value<SearchProvider*>();
178   provider->ShowConfig();
179 }
180 
CurrentProviderChanged(QTreeWidgetItem * item)181 void GlobalSearchSettingsPage::CurrentProviderChanged(QTreeWidgetItem* item) {
182   if (!item) return;
183 
184   QTreeWidgetItem* root = ui_->sources->invisibleRootItem();
185   SearchProvider* provider =
186       item->data(0, Qt::UserRole).value<SearchProvider*>();
187   const int row = root->indexOfChild(item);
188 
189   ui_->up->setEnabled(row != 0);
190   ui_->down->setEnabled(row != root->childCount() - 1);
191   ui_->configure->setEnabled(provider->can_show_config());
192 }
193 
showEvent(QShowEvent * e)194 void GlobalSearchSettingsPage::showEvent(QShowEvent* e) {
195   QWidget::showEvent(e);
196 
197   // Update the logged-in state of each item when we come back to this page in
198   // the dialog.
199   for (int i = 0; i < ui_->sources->invisibleRootItem()->childCount(); ++i) {
200     UpdateLoggedInState(dialog()->global_search(),
201                         ui_->sources->invisibleRootItem()->child(i), false);
202   }
203 }
204