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 "iconloader.h"
19 #include "notificationssettingspage.h"
20 #include "settingsdialog.h"
21 #include "ui_notificationssettingspage.h"
22 #include "ui/iconloader.h"
23 #include "widgets/osdpretty.h"
24 
25 #include <QColorDialog>
26 #include <QFontDialog>
27 #include <QMenu>
28 #include <QToolTip>
29 
NotificationsSettingsPage(SettingsDialog * dialog)30 NotificationsSettingsPage::NotificationsSettingsPage(SettingsDialog* dialog)
31     : SettingsPage(dialog),
32       ui_(new Ui_NotificationsSettingsPage),
33       pretty_popup_(new OSDPretty(OSDPretty::Mode_Draggable)) {
34   ui_->setupUi(this);
35   setWindowIcon(IconLoader::Load("help-hint", IconLoader::Base));
36 
37   QIcon nocover = IconLoader::Load("nocover", IconLoader::Other);
38   pretty_popup_->SetMessage(tr("OSD Preview"), tr("Drag to reposition"),
39                             nocover.pixmap(nocover.availableSizes().last())
40                                    .toImage());
41 
42   ui_->notifications_bg_preset->setItemData(0, QColor(OSDPretty::kPresetBlue),
43                                             Qt::DecorationRole);
44   ui_->notifications_bg_preset->setItemData(1, QColor(OSDPretty::kPresetOrange),
45                                             Qt::DecorationRole);
46 
47   // Create and populate the helper menus
48   QMenu* menu = new QMenu(this);
49   menu->addAction(ui_->action_artist);
50   menu->addAction(ui_->action_album);
51   menu->addAction(ui_->action_title);
52   menu->addAction(ui_->action_albumartist);
53   menu->addAction(ui_->action_year);
54   menu->addAction(ui_->action_composer);
55   menu->addAction(ui_->action_performer);
56   menu->addAction(ui_->action_grouping);
57   menu->addAction(ui_->action_length);
58   menu->addAction(ui_->action_disc);
59   menu->addAction(ui_->action_track);
60   menu->addAction(ui_->action_genre);
61   menu->addAction(ui_->action_playcount);
62   menu->addAction(ui_->action_skipcount);
63   menu->addAction(ui_->action_filename);
64   menu->addAction(ui_->action_rating);
65   menu->addAction(ui_->action_score);
66   menu->addSeparator();
67   menu->addAction(ui_->action_newline);
68   ui_->notifications_exp_chooser1->setMenu(menu);
69   ui_->notifications_exp_chooser2->setMenu(menu);
70   ui_->notifications_exp_chooser1->setPopupMode(QToolButton::InstantPopup);
71   ui_->notifications_exp_chooser2->setPopupMode(QToolButton::InstantPopup);
72   // We need this because by default menus don't show tooltips
73   connect(menu, SIGNAL(hovered(QAction*)), SLOT(ShowMenuTooltip(QAction*)));
74 
75   connect(ui_->notifications_none, SIGNAL(toggled(bool)),
76           SLOT(NotificationTypeChanged()));
77   connect(ui_->notifications_native, SIGNAL(toggled(bool)),
78           SLOT(NotificationTypeChanged()));
79   connect(ui_->notifications_tray, SIGNAL(toggled(bool)),
80           SLOT(NotificationTypeChanged()));
81   connect(ui_->notifications_pretty, SIGNAL(toggled(bool)),
82           SLOT(NotificationTypeChanged()));
83   connect(ui_->notifications_opacity, SIGNAL(valueChanged(int)),
84           SLOT(PrettyOpacityChanged(int)));
85   connect(ui_->notifications_bg_preset, SIGNAL(activated(int)),
86           SLOT(PrettyColorPresetChanged(int)));
87   connect(ui_->notifications_fg_choose, SIGNAL(clicked()),
88           SLOT(ChooseFgColor()));
89   connect(ui_->notifications_font_choose, SIGNAL(clicked()),
90           SLOT(ChooseFont()));
91   connect(ui_->notifications_exp_chooser1, SIGNAL(triggered(QAction*)),
92           SLOT(InsertVariableFirstLine(QAction*)));
93   connect(ui_->notifications_exp_chooser2, SIGNAL(triggered(QAction*)),
94           SLOT(InsertVariableSecondLine(QAction*)));
95   connect(ui_->notifications_disable_duration, SIGNAL(toggled(bool)),
96           ui_->notifications_duration, SLOT(setDisabled(bool)));
97 
98   if (!OSD::SupportsNativeNotifications())
99     ui_->notifications_native->setEnabled(false);
100   if (!OSD::SupportsTrayPopups()) ui_->notifications_tray->setEnabled(false);
101 
102   connect(ui_->notifications_pretty, SIGNAL(toggled(bool)),
103           SLOT(UpdatePopupVisible()));
104 
105   connect(ui_->notifications_custom_text_enabled, SIGNAL(toggled(bool)),
106           SLOT(NotificationCustomTextChanged(bool)));
107   connect(ui_->notifications_preview, SIGNAL(clicked()),
108           SLOT(PrepareNotificationPreview()));
109 
110   // Icons
111   ui_->notifications_exp_chooser1->setIcon(IconLoader::Load("list-add", IconLoader::Base));
112   ui_->notifications_exp_chooser2->setIcon(IconLoader::Load("list-add", IconLoader::Base));
113 }
114 
~NotificationsSettingsPage()115 NotificationsSettingsPage::~NotificationsSettingsPage() {
116   delete pretty_popup_;
117   delete ui_;
118 }
119 
showEvent(QShowEvent *)120 void NotificationsSettingsPage::showEvent(QShowEvent*) { UpdatePopupVisible(); }
121 
hideEvent(QHideEvent *)122 void NotificationsSettingsPage::hideEvent(QHideEvent*) { UpdatePopupVisible(); }
123 
Load()124 void NotificationsSettingsPage::Load() {
125   QSettings s;
126 
127   s.beginGroup(OSD::kSettingsGroup);
128   OSD::Behaviour osd_behaviour =
129       OSD::Behaviour(s.value("Behaviour", OSD::Native).toInt());
130   switch (osd_behaviour) {
131     case OSD::Native:
132       if (OSD::SupportsNativeNotifications()) {
133         ui_->notifications_native->setChecked(true);
134         break;
135       }
136     // Fallthrough
137 
138     case OSD::Pretty:
139       ui_->notifications_pretty->setChecked(true);
140       break;
141 
142     case OSD::TrayPopup:
143       if (OSD::SupportsTrayPopups()) {
144         ui_->notifications_tray->setChecked(true);
145         break;
146       }
147     // Fallthrough
148 
149     case OSD::Disabled:
150     default:
151       ui_->notifications_none->setChecked(true);
152       break;
153   }
154   ui_->notifications_duration->setValue(s.value("Timeout", 5000).toInt() /
155                                         1000);
156   ui_->notifications_volume->setChecked(
157       s.value("ShowOnVolumeChange", false).toBool());
158   ui_->notifications_play_mode->setChecked(
159       s.value("ShowOnPlayModeChange", true).toBool());
160   ui_->notifications_pause->setChecked(
161       s.value("ShowOnPausePlayback", true).toBool());
162   ui_->notifications_art->setChecked(s.value("ShowArt", true).toBool());
163   ui_->notifications_custom_text_enabled->setChecked(
164       s.value("CustomTextEnabled", false).toBool());
165   ui_->notifications_custom_text1->setText(s.value("CustomText1").toString());
166   ui_->notifications_custom_text2->setText(s.value("CustomText2").toString());
167   s.endGroup();
168 
169 #ifdef Q_OS_DARWIN
170   ui_->notifications_options->setEnabled(
171       ui_->notifications_pretty->isChecked());
172 #endif
173 
174   // Pretty OSD
175   pretty_popup_->ReloadSettings();
176   ui_->notifications_opacity->setValue(pretty_popup_->background_opacity() *
177                                        100);
178 
179   QRgb color = pretty_popup_->background_color();
180   if (color == OSDPretty::kPresetBlue)
181     ui_->notifications_bg_preset->setCurrentIndex(0);
182   else if (color == OSDPretty::kPresetOrange)
183     ui_->notifications_bg_preset->setCurrentIndex(1);
184   else
185     ui_->notifications_bg_preset->setCurrentIndex(2);
186   ui_->notifications_bg_preset->setItemData(2, QColor(color),
187                                             Qt::DecorationRole);
188   ui_->notifications_disable_duration->setChecked(
189       pretty_popup_->disable_duration());
190   UpdatePopupVisible();
191 }
192 
Save()193 void NotificationsSettingsPage::Save() {
194   QSettings s;
195 
196   OSD::Behaviour osd_behaviour = OSD::Disabled;
197   if (ui_->notifications_none->isChecked())
198     osd_behaviour = OSD::Disabled;
199   else if (ui_->notifications_native->isChecked())
200     osd_behaviour = OSD::Native;
201   else if (ui_->notifications_tray->isChecked())
202     osd_behaviour = OSD::TrayPopup;
203   else if (ui_->notifications_pretty->isChecked())
204     osd_behaviour = OSD::Pretty;
205 
206   s.beginGroup(OSD::kSettingsGroup);
207   s.setValue("Behaviour", int(osd_behaviour));
208   s.setValue("Timeout", ui_->notifications_duration->value() * 1000);
209   s.setValue("ShowOnVolumeChange", ui_->notifications_volume->isChecked());
210   s.setValue("ShowOnPlayModeChange", ui_->notifications_play_mode->isChecked());
211   s.setValue("ShowOnPausePlayback", ui_->notifications_pause->isChecked());
212   s.setValue("ShowArt", ui_->notifications_art->isChecked());
213   s.setValue("CustomTextEnabled",
214              ui_->notifications_custom_text_enabled->isChecked());
215   s.setValue("CustomText1", ui_->notifications_custom_text1->text());
216   s.setValue("CustomText2", ui_->notifications_custom_text2->text());
217   s.endGroup();
218 
219   s.beginGroup(OSDPretty::kSettingsGroup);
220   s.setValue("foreground_color", pretty_popup_->foreground_color());
221   s.setValue("background_color", pretty_popup_->background_color());
222   s.setValue("background_opacity", pretty_popup_->background_opacity());
223   s.setValue("popup_display", pretty_popup_->popup_display());
224   s.setValue("popup_pos", pretty_popup_->popup_pos());
225   s.setValue("font", pretty_popup_->font().toString());
226   s.setValue("disable_duration",
227              ui_->notifications_disable_duration->isChecked());
228   s.endGroup();
229 }
230 
PrettyOpacityChanged(int value)231 void NotificationsSettingsPage::PrettyOpacityChanged(int value) {
232   pretty_popup_->set_background_opacity(qreal(value) / 100.0);
233 }
234 
UpdatePopupVisible()235 void NotificationsSettingsPage::UpdatePopupVisible() {
236   pretty_popup_->setVisible(isVisible() &&
237                             ui_->notifications_pretty->isChecked());
238 }
239 
PrettyColorPresetChanged(int index)240 void NotificationsSettingsPage::PrettyColorPresetChanged(int index) {
241   if (dialog()->is_loading_settings()) return;
242 
243   switch (index) {
244     case 0:
245       pretty_popup_->set_background_color(OSDPretty::kPresetBlue);
246       break;
247 
248     case 1:
249       pretty_popup_->set_background_color(OSDPretty::kPresetOrange);
250       break;
251 
252     case 2:
253     default:
254       ChooseBgColor();
255       break;
256   }
257 }
258 
ChooseBgColor()259 void NotificationsSettingsPage::ChooseBgColor() {
260   QColor color =
261       QColorDialog::getColor(pretty_popup_->background_color(), this);
262   if (!color.isValid()) return;
263 
264   pretty_popup_->set_background_color(color.rgb());
265   ui_->notifications_bg_preset->setItemData(2, color, Qt::DecorationRole);
266 }
267 
ChooseFgColor()268 void NotificationsSettingsPage::ChooseFgColor() {
269   QColor color =
270       QColorDialog::getColor(pretty_popup_->foreground_color(), this);
271   if (!color.isValid()) return;
272 
273   pretty_popup_->set_foreground_color(color.rgb());
274 }
275 
ChooseFont()276 void NotificationsSettingsPage::ChooseFont() {
277   bool ok;
278   QFont font = QFontDialog::getFont(&ok, pretty_popup_->font(), this);
279   if (ok) pretty_popup_->set_font(font);
280 }
281 
NotificationCustomTextChanged(bool enabled)282 void NotificationsSettingsPage::NotificationCustomTextChanged(bool enabled) {
283   ui_->notifications_custom_text1->setEnabled(enabled);
284   ui_->notifications_custom_text2->setEnabled(enabled);
285   ui_->notifications_exp_chooser1->setEnabled(enabled);
286   ui_->notifications_exp_chooser2->setEnabled(enabled);
287   ui_->notifications_preview->setEnabled(enabled);
288   ui_->label_19->setEnabled(enabled);
289   ui_->label_20->setEnabled(enabled);
290 }
291 
PrepareNotificationPreview()292 void NotificationsSettingsPage::PrepareNotificationPreview() {
293   OSD::Behaviour notificationType = OSD::Disabled;
294   if (ui_->notifications_native->isChecked()) {
295     notificationType = OSD::Native;
296   } else if (ui_->notifications_pretty->isChecked()) {
297     notificationType = OSD::Pretty;
298   } else if (ui_->notifications_tray->isChecked()) {
299     notificationType = OSD::TrayPopup;
300   }
301 
302   // If user changes timeout or other options, that won't be reflected in the
303   // preview
304   emit NotificationPreview(notificationType,
305                            ui_->notifications_custom_text1->text(),
306                            ui_->notifications_custom_text2->text());
307 }
308 
InsertVariableFirstLine(QAction * action)309 void NotificationsSettingsPage::InsertVariableFirstLine(QAction* action) {
310   // We use action name, therefore those shouldn't be translatable
311   ui_->notifications_custom_text1->insert(action->text());
312 }
313 
InsertVariableSecondLine(QAction * action)314 void NotificationsSettingsPage::InsertVariableSecondLine(QAction* action) {
315   // We use action name, therefore those shouldn't be translatable
316   ui_->notifications_custom_text2->insert(action->text());
317 }
318 
ShowMenuTooltip(QAction * action)319 void NotificationsSettingsPage::ShowMenuTooltip(QAction* action) {
320   QToolTip::showText(QCursor::pos(), action->toolTip());
321 }
322 
NotificationTypeChanged()323 void NotificationsSettingsPage::NotificationTypeChanged() {
324   bool enabled = !ui_->notifications_none->isChecked();
325   bool pretty = ui_->notifications_pretty->isChecked();
326 
327   ui_->notifications_general->setEnabled(enabled);
328   ui_->notifications_pretty_group->setEnabled(pretty);
329   ui_->notifications_custom_text_group->setEnabled(enabled);
330 
331 #ifdef Q_OS_DARWIN
332   ui_->notifications_options->setEnabled(pretty);
333 #endif
334   ui_->notifications_duration->setEnabled(
335       !pretty || (pretty && !ui_->notifications_disable_duration->isChecked()));
336   ui_->notifications_disable_duration->setEnabled(pretty);
337 }
338