1 /*
2 * Cantata
3 *
4 * Copyright (c) 2011-2020 Craig Drummond <craig.p.drummond@gmail.com>
5 *
6 * ----
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include "dialog.h"
25 #include "configuration.h"
26 #include "utils.h"
27 #include "monoicon.h"
28 #ifdef Q_OS_MAC
29 #include "osxstyle.h"
30 #endif
31 #include "icon.h"
32 #include "acceleratormanager.h"
33 #include <QDialogButtonBox>
34 #include <QPushButton>
35 #include <QBoxLayout>
36 #include <QSettings>
37 #include <QStyle>
38
Dialog(QWidget * parent,const QString & name,const QSize & defSize)39 Dialog::Dialog(QWidget *parent, const QString &name, const QSize &defSize)
40 : QDialog(parent)
41 , defButton(0)
42 , buttonTypes(0)
43 , mw(nullptr)
44 , buttonBox(nullptr)
45 , shown(false)
46 {
47 if (!name.isEmpty()) {
48 setObjectName(name);
49 Configuration cfg(name);
50 cfgSize=cfg.get("size", QSize());
51 if (!cfgSize.isEmpty()) {
52 QDialog::resize(cfgSize);
53 } else if (!defSize.isEmpty()) {
54 QDialog::resize(defSize);
55 }
56 }
57 #ifdef Q_OS_MAC
58 setWindowIcon(QIcon());
59 #endif
60 }
61
~Dialog()62 Dialog::~Dialog()
63 {
64 if (!objectName().isEmpty() && size()!=cfgSize) {
65 Configuration cfg(objectName());
66 cfg.set("size", size());
67 }
68 #ifdef Q_OS_MAC
69 OSXStyle::self()->removeWindow(this);
70 #endif
71 }
72
resize(const QSize & sz)73 void Dialog::resize(const QSize &sz)
74 {
75 if (cfgSize.isEmpty()) {
76 QDialog::resize(sz);
77 cfgSize=sz;
78 }
79 }
80
81 #ifdef Q_OS_MAC
ButtonProxyStyle()82 Dialog::ButtonProxyStyle::ButtonProxyStyle()
83 : QProxyStyle()
84 {
85 setBaseStyle(qApp->style());
86 }
87
styleHint(StyleHint stylehint,const QStyleOption * opt,const QWidget * widget,QStyleHintReturn * returnData) const88 int Dialog::ButtonProxyStyle::styleHint(StyleHint stylehint, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *returnData) const
89 {
90 if (QStyle::SH_DialogButtonLayout==stylehint) {
91 return QDialogButtonBox::GnomeLayout;
92 } else {
93 return QProxyStyle::styleHint(stylehint, opt, widget, returnData);
94 }
95 }
96
buttonProxyStyle()97 Dialog::ButtonProxyStyle * Dialog::buttonProxyStyle()
98 {
99 static ButtonProxyStyle *style=0;
100 if (!style) {
101 style=new ButtonProxyStyle();
102 }
103 return style;
104 }
105 #endif
106
monoIcon(const GuiItem & i)107 static QIcon monoIcon(const GuiItem &i)
108 {
109 static QColor col(QColor::Invalid);
110
111 if (!i.red && !col.isValid()) {
112 col=Utils::monoIconColor();
113 }
114 return MonoIcon::icon((FontAwesome::icon)i.monoIcon, i.red ? MonoIcon::constRed : col,
115 i.red ? MonoIcon::constRed : QColor(QColor::Invalid));
116 }
117
118 namespace StdGuiItem {
ok()119 GuiItem ok() { return GuiItem(QObject::tr("&OK"), FontAwesome::check); }
cancel()120 GuiItem cancel() { return GuiItem(QObject::tr("&Cancel"), FontAwesome::ban); }
yes()121 GuiItem yes() { return GuiItem(QObject::tr("&Yes"), FontAwesome::check); }
no()122 GuiItem no() { return GuiItem(QObject::tr("&No"), FontAwesome::times, true); }
discard()123 GuiItem discard() { return GuiItem(QObject::tr("&Discard"), FontAwesome::trash, true); }
save()124 GuiItem save() { return GuiItem(QObject::tr("&Save"), FontAwesome::save); }
apply()125 GuiItem apply() { return GuiItem(QObject::tr("&Apply"), FontAwesome::check); }
close()126 GuiItem close() { return GuiItem(QObject::tr("&Close"), FontAwesome::close, true); }
help()127 GuiItem help() { return GuiItem(QObject::tr("&Help"), FontAwesome::lifering); }
overwrite()128 GuiItem overwrite() { return GuiItem(QObject::tr("&Overwrite")); }
reset()129 GuiItem reset() { return GuiItem(QObject::tr("&Reset"), FontAwesome::undo); }
cont()130 GuiItem cont() { return GuiItem(QObject::tr("&Continue"), FontAwesome::arrowright); }
del()131 GuiItem del() { return GuiItem(QObject::tr("&Delete"), FontAwesome::trash, true); }
stop()132 GuiItem stop() { return GuiItem(QObject::tr("&Stop"), FontAwesome::times); }
remove()133 GuiItem remove() { return GuiItem(QObject::tr("&Remove"), FontAwesome::remove); }
back(bool useRtl)134 GuiItem back(bool useRtl) { return GuiItem(QObject::tr("&Previous"), useRtl && QApplication::isRightToLeft() ? FontAwesome::chevronright : FontAwesome::chevronleft); }
forward(bool useRtl)135 GuiItem forward(bool useRtl) { return GuiItem(QObject::tr("&Next"), useRtl && QApplication::isRightToLeft() ? FontAwesome::chevronleft : FontAwesome::chevronright); }
136
standardNames()137 QSet<QString> standardNames()
138 {
139 static QSet<QString> names;
140 if (names.isEmpty()) {
141 QStringList strings = QStringList() << ok().text << cancel().text << yes().text << no().text << discard().text << save().text << apply().text
142 << close().text << help().text << overwrite().text << reset().text << cont().text << del().text
143 << stop().text << remove().text << back().text << forward().text;
144
145 for (QString s: strings) {
146 names.insert(s.remove("&"));
147 }
148 }
149 return names;
150 }
151
152 }
153
mapType(int btn)154 static QDialogButtonBox::StandardButton mapType(int btn) {
155 switch (btn) {
156 case Dialog::Help: return QDialogButtonBox::Help;
157 case Dialog::Ok: return QDialogButtonBox::Ok;
158 case Dialog::Apply: return QDialogButtonBox::Apply;
159 case Dialog::Cancel: return QDialogButtonBox::Cancel;
160 case Dialog::Close: return QDialogButtonBox::Close;
161 case Dialog::No: return QDialogButtonBox::No;
162 case Dialog::Yes: return QDialogButtonBox::Yes;
163 case Dialog::Reset: return QDialogButtonBox::Reset;
164 default: return QDialogButtonBox::NoButton;
165 }
166 }
167
setButtons(ButtonCodes buttons)168 void Dialog::setButtons(ButtonCodes buttons)
169 {
170 if (buttonBox && buttons==buttonTypes) {
171 return;
172 }
173
174 QFlags<QDialogButtonBox::StandardButton> btns;
175 if (buttons&Help) {
176 btns|=QDialogButtonBox::Help;
177 }
178 if (buttons&Ok) {
179 btns|=QDialogButtonBox::Ok;
180 }
181 if (buttons&Apply) {
182 btns|=QDialogButtonBox::Apply;
183 }
184 if (buttons&Cancel) {
185 btns|=QDialogButtonBox::Cancel;
186 }
187 if (buttons&Close) {
188 btns|=QDialogButtonBox::Close;
189 }
190 if (buttons&No) {
191 btns|=QDialogButtonBox::No;
192 }
193 if (buttons&Yes) {
194 btns|=QDialogButtonBox::Yes;
195 }
196 if (buttons&Reset) {
197 btns|=QDialogButtonBox::Reset;
198 }
199
200 buttonTypes=(int)btns;
201 bool needToCreate=true;
202 if (buttonBox) {
203 needToCreate=false;
204 buttonBox->clear();
205 buttonBox->setStandardButtons(btns);
206 userButtons.clear();
207 } else {
208 buttonBox = new QDialogButtonBox(btns, Qt::Horizontal, this);
209 #ifdef Q_OS_MAC
210 buttonBox->setStyle(buttonProxyStyle());
211 #endif
212 }
213
214 if (buttons&Help) {
215 setButtonGuiItem(QDialogButtonBox::Help, StdGuiItem::help());
216 }
217 if (buttons&Ok) {
218 setButtonGuiItem(QDialogButtonBox::Ok, StdGuiItem::ok());
219 }
220 if (buttons&Apply) {
221 setButtonGuiItem(QDialogButtonBox::Apply, StdGuiItem::apply());
222 }
223 if (buttons&Cancel) {
224 setButtonGuiItem(QDialogButtonBox::Cancel, StdGuiItem::cancel());
225 }
226 if (buttons&Close) {
227 setButtonGuiItem(QDialogButtonBox::Close, StdGuiItem::close());
228 }
229 if (buttons&No) {
230 setButtonGuiItem(QDialogButtonBox::No, StdGuiItem::no());
231 }
232 if (buttons&Yes) {
233 setButtonGuiItem(QDialogButtonBox::Yes, StdGuiItem::yes());
234 }
235 if (buttons&Reset) {
236 setButtonGuiItem(QDialogButtonBox::Reset, StdGuiItem::reset());
237 }
238
239 if (buttons&User3) {
240 QPushButton *button=new QPushButton(buttonBox);
241 userButtons.insert(User3, button);
242 buttonBox->addButton(button, QDialogButtonBox::ActionRole);
243 }
244 if (buttons&User2) {
245 QPushButton *button=new QPushButton(buttonBox);
246 userButtons.insert(User2, button);
247 buttonBox->addButton(button, QDialogButtonBox::ActionRole);
248 }
249 if (buttons&User1) {
250 QPushButton *button=new QPushButton(buttonBox);
251 userButtons.insert(User1, button);
252 buttonBox->addButton(button, QDialogButtonBox::ActionRole);
253 }
254
255 if (needToCreate && mw && buttonBox) {
256 create();
257 }
258 }
259
setDefaultButton(ButtonCode button)260 void Dialog::setDefaultButton(ButtonCode button)
261 {
262 QAbstractButton *b=getButton(button);
263 if (b) {
264 qobject_cast<QPushButton *>(b)->setDefault(true);
265 }
266 defButton=button;
267 }
268
setButtonText(ButtonCode button,const QString & text)269 void Dialog::setButtonText(ButtonCode button, const QString &text)
270 {
271 QAbstractButton *b=getButton(button);
272 if (b) {
273 b->setText(text);
274 }
275 }
276
setButtonGuiItem(ButtonCode button,const GuiItem & item)277 void Dialog::setButtonGuiItem(ButtonCode button, const GuiItem &item)
278 {
279 QAbstractButton *b=getButton(button);
280 if (b) {
281 b->setText(item.text);
282 if (style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons)) {
283 if (!item.icon.isEmpty()) {
284 b->setIcon(Icon::get(item.icon));
285 } else if (item.monoIcon>0) {
286 b->setIcon(monoIcon(item));
287 } else {
288 b->setIcon(QIcon());
289 }
290 }
291 }
292 }
293
setButtonGuiItem(QDialogButtonBox::StandardButton button,const GuiItem & item)294 void Dialog::setButtonGuiItem(QDialogButtonBox::StandardButton button, const GuiItem &item)
295 {
296 QAbstractButton *b=buttonBox->button(button);
297 if (b) {
298 b->setText(item.text);
299 if (style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons)) {
300 if (!item.icon.isEmpty()) {
301 b->setIcon(Icon::get(item.icon));
302 } else if (item.monoIcon>0) {
303 b->setIcon(monoIcon(item));
304 } else {
305 b->setIcon(QIcon());
306 }
307 }
308 }
309 }
310
setButtonMenu(ButtonCode button,QMenu * menu,ButtonPopupMode popupmode)311 void Dialog::setButtonMenu(ButtonCode button, QMenu *menu, ButtonPopupMode popupmode)
312 {
313 Q_UNUSED(popupmode)
314 QAbstractButton *b=getButton(button);
315 if (b) {
316 qobject_cast<QPushButton *>(b)->setMenu(menu);
317 }
318 }
319
enableButton(ButtonCode button,bool enable)320 void Dialog::enableButton(ButtonCode button, bool enable)
321 {
322 QAbstractButton *b=getButton(button);
323 if (b) {
324 b->setEnabled(enable);
325 }
326 }
327
isButtonEnabled(ButtonCode button)328 bool Dialog::isButtonEnabled(ButtonCode button)
329 {
330 QAbstractButton *b=getButton(button);
331 return b ? b->isEnabled() : false;
332 }
333
setMainWidget(QWidget * widget)334 void Dialog::setMainWidget(QWidget *widget)
335 {
336 if (mw) {
337 return;
338 }
339 mw=widget;
340 if (mw && buttonBox) {
341 create();
342 }
343 }
344
slotButtonClicked(int button)345 void Dialog::slotButtonClicked(int button)
346 {
347 switch (button) {
348 case Ok: accept(); break;
349 case Cancel: reject(); break;
350 case Close: reject(); break;
351 default: break;
352 }
353 }
354
buttonPressed(QAbstractButton * button)355 void Dialog::buttonPressed(QAbstractButton *button)
356 {
357 if (buttonTypes&QDialogButtonBox::Help && button==buttonBox->button(QDialogButtonBox::Help)) {
358 slotButtonClicked(Help);
359 } else if (buttonTypes&QDialogButtonBox::Ok && button==buttonBox->button(QDialogButtonBox::Ok)) {
360 slotButtonClicked(Ok);
361 } else if (buttonTypes&QDialogButtonBox::Apply && button==buttonBox->button(QDialogButtonBox::Apply)) {
362 slotButtonClicked(Apply);
363 } else if (buttonTypes&QDialogButtonBox::Cancel && button==buttonBox->button(QDialogButtonBox::Cancel)) {
364 slotButtonClicked(Cancel);
365 } else if (buttonTypes&QDialogButtonBox::Close && button==buttonBox->button(QDialogButtonBox::Close)) {
366 slotButtonClicked(Close);
367 } else if (buttonTypes&QDialogButtonBox::No && button==buttonBox->button(QDialogButtonBox::No)) {
368 slotButtonClicked(No);
369 } else if (buttonTypes&QDialogButtonBox::Yes && button==buttonBox->button(QDialogButtonBox::Yes)) {
370 slotButtonClicked(Yes);
371 } else if (buttonTypes&QDialogButtonBox::Reset && button==buttonBox->button(QDialogButtonBox::Reset)) {
372 slotButtonClicked(Reset);
373 } else if (userButtons.contains(User1) && userButtons[User1]==button) {
374 slotButtonClicked(User1);
375 } else if (userButtons.contains(User2) && userButtons[User2]==button) {
376 slotButtonClicked(User2);
377 } else if (userButtons.contains(User3) && userButtons[User3]==button) {
378 slotButtonClicked(User3);
379 }
380 }
381
create()382 void Dialog::create()
383 {
384 QBoxLayout *layout=new QBoxLayout(QBoxLayout::TopToBottom, this);
385 layout->addWidget(mw);
386 layout->addWidget(buttonBox);
387 connect(buttonBox, SIGNAL(clicked(QAbstractButton *)), this, SLOT(buttonPressed(QAbstractButton *)));
388 }
389
getButton(ButtonCode button)390 QAbstractButton *Dialog::getButton(ButtonCode button)
391 {
392 QDialogButtonBox::StandardButton mapped=mapType(button);
393 QAbstractButton *b=QDialogButtonBox::NoButton==mapped ? nullptr : buttonBox->button(mapped);
394 if (!b && userButtons.contains(button)) {
395 b=userButtons[button];
396 }
397 return b;
398 }
399
showEvent(QShowEvent * e)400 void Dialog::showEvent(QShowEvent *e)
401 {
402 if (!shown) {
403 shown=true;
404 AcceleratorManager::manage(this);
405 if (defButton) {
406 setDefaultButton((ButtonCode)defButton);
407 }
408 if (buttonBox && mw) {
409 QSize mwSize=mw->minimumSize();
410 if (mwSize.width()<16 || mwSize.height()<16) {
411 mwSize=mw->minimumSizeHint();
412 }
413 if (mwSize.width()>15 && mwSize.height()>15) {
414 setMinimumHeight(qMax(minimumHeight(), buttonBox->height()+layout()->spacing()+mwSize.height()+(2*layout()->margin())));
415 setMinimumWidth(qMax(minimumWidth(), mwSize.width()+(2*layout()->margin())));
416 }
417 }
418 }
419 #ifdef Q_OS_MAC
420 if (!isModal()) {
421 OSXStyle::self()->addWindow(this);
422 }
423 #endif
424 QDialog::showEvent(e);
425 }
426
427 #ifdef Q_OS_MAC
hideEvent(QHideEvent * e)428 void Dialog::hideEvent(QHideEvent *e)
429 {
430 OSXStyle::self()->removeWindow(this);
431 QDialog::hideEvent(e);
432 }
433
closeEvent(QCloseEvent * e)434 void Dialog::closeEvent(QCloseEvent *e)
435 {
436 OSXStyle::self()->removeWindow(this);
437 QDialog::closeEvent(e);
438 }
439 #endif
440
441 #include "moc_dialog.cpp"
442