1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2011-02-14
7 * Description : pick label widget
8 *
9 * Copyright (C) 2011-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10 *
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software Foundation;
14 * either version 2, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * ============================================================ */
23
24 #include "picklabelwidget.h"
25
26 // Qt includes
27
28 #include <QPainter>
29 #include <QIcon>
30 #include <QLayout>
31 #include <QLabel>
32 #include <QButtonGroup>
33 #include <QWidgetAction>
34 #include <QFontMetrics>
35 #include <QFont>
36 #include <QToolButton>
37 #include <QApplication>
38
39 // KDE includes
40
41 #include <klocalizedstring.h>
42 #include <kactioncollection.h>
43
44 // Local includes
45
46 #include "dlayoutbox.h"
47 #include "dxmlguiwindow.h"
48 #include "dexpanderbox.h"
49
50 namespace Digikam
51 {
52
53 class Q_DECL_HIDDEN PickLabelWidget::Private
54 {
55
56 public:
57
Private()58 explicit Private()
59 : pickBtns (nullptr),
60 desc (nullptr),
61 btnNone (nullptr),
62 btnRej (nullptr),
63 btnPndg (nullptr),
64 btnAccpt (nullptr),
65 descBox (nullptr),
66 shortcut (nullptr)
67 {
68 }
69
70 QButtonGroup* pickBtns;
71
72 QLabel* desc;
73
74 QToolButton* btnNone;
75 QToolButton* btnRej;
76 QToolButton* btnPndg;
77 QToolButton* btnAccpt;
78
79 DHBox* descBox;
80
81 DAdjustableLabel* shortcut;
82 };
83
PickLabelWidget(QWidget * const parent)84 PickLabelWidget::PickLabelWidget(QWidget* const parent)
85 : DVBox(parent),
86 d (new Private)
87 {
88 setAttribute(Qt::WA_DeleteOnClose);
89 setFocusPolicy(Qt::NoFocus);
90
91 DHBox* const hbox = new DHBox(this);
92 hbox->setContentsMargins(QMargins());
93 hbox->setSpacing(0);
94
95 d->btnNone = new QToolButton(hbox);
96 d->btnNone->setCheckable(true);
97 d->btnNone->setFocusPolicy(Qt::NoFocus);
98 d->btnNone->setIcon(buildIcon(NoPickLabel));
99 d->btnNone->installEventFilter(this);
100
101 d->btnRej = new QToolButton(hbox);
102 d->btnRej->setCheckable(true);
103 d->btnRej->setFocusPolicy(Qt::NoFocus);
104 d->btnRej->setIcon(buildIcon(RejectedLabel));
105 d->btnRej->installEventFilter(this);
106
107 d->btnPndg = new QToolButton(hbox);
108 d->btnPndg->setCheckable(true);
109 d->btnPndg->setFocusPolicy(Qt::NoFocus);
110 d->btnPndg->setIcon(buildIcon(PendingLabel));
111 d->btnPndg->installEventFilter(this);
112
113 d->btnAccpt = new QToolButton(hbox);
114 d->btnAccpt->setCheckable(true);
115 d->btnAccpt->setFocusPolicy(Qt::NoFocus);
116 d->btnAccpt->setIcon(buildIcon(AcceptedLabel));
117 d->btnAccpt->installEventFilter(this);
118
119 d->pickBtns = new QButtonGroup(hbox);
120 d->pickBtns->addButton(d->btnNone, NoPickLabel);
121 d->pickBtns->addButton(d->btnRej, RejectedLabel);
122 d->pickBtns->addButton(d->btnPndg, PendingLabel);
123 d->pickBtns->addButton(d->btnAccpt, AcceptedLabel);
124
125 d->descBox = new DHBox(this);
126 d->descBox->setContentsMargins(QMargins());
127 d->descBox->setSpacing(0);
128 d->desc = new QLabel(d->descBox);
129 d->shortcut = new DAdjustableLabel(d->descBox);
130 QFont fnt = d->shortcut->font();
131 fnt.setItalic(true);
132 d->shortcut->setFont(fnt);
133 d->shortcut->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
134 d->shortcut->setWordWrap(false);
135
136 setSpacing(0);
137 setContentsMargins(QMargins());
138 setPickLabels(QList<PickLabel>() << NoPickLabel);
139 setDescriptionBoxVisible(true);
140 setButtonsExclusive(true);
141
142 // -------------------------------------------------------------
143
144 connect(d->pickBtns, SIGNAL(buttonReleased(int)),
145 this, SIGNAL(signalPickLabelChanged(int)));
146 }
147
~PickLabelWidget()148 PickLabelWidget::~PickLabelWidget()
149 {
150 delete d;
151 }
152
setDescriptionBoxVisible(bool b)153 void PickLabelWidget::setDescriptionBoxVisible(bool b)
154 {
155 d->descBox->setVisible(b);
156
157 if (!b)
158 {
159 foreach (QAbstractButton* const btn, d->pickBtns->buttons())
160 {
161 PickLabel id = (PickLabel)(d->pickBtns->id(btn));
162 btn->setToolTip(labelPickName(id));
163 }
164 }
165 }
166
setButtonsExclusive(bool b)167 void PickLabelWidget::setButtonsExclusive(bool b)
168 {
169 d->pickBtns->setExclusive(b);
170 }
171
updateDescription(PickLabel label)172 void PickLabelWidget::updateDescription(PickLabel label)
173 {
174 d->desc->setText(labelPickName(label));
175
176 DXmlGuiWindow* const app = dynamic_cast<DXmlGuiWindow*>(qApp->activeWindow());
177
178 if (app)
179 {
180 QAction* const ac = app->actionCollection()->action(QString::fromLatin1("pickshortcut-%1").arg(label));
181
182 if (ac)
183 {
184 d->shortcut->setAdjustedText(ac->shortcut().toString());
185 }
186 }
187 }
188
eventFilter(QObject * obj,QEvent * ev)189 bool PickLabelWidget::eventFilter(QObject* obj, QEvent* ev)
190 {
191 if (obj == d->btnNone)
192 {
193 if (ev->type() == QEvent::Enter)
194 {
195 updateDescription(NoPickLabel);
196 return false;
197 }
198 }
199
200 if (obj == d->btnRej)
201 {
202 if (ev->type() == QEvent::Enter)
203 {
204 updateDescription(RejectedLabel);
205 return false;
206 }
207 }
208
209 if (obj == d->btnPndg)
210 {
211 if (ev->type() == QEvent::Enter)
212 {
213 updateDescription(PendingLabel);
214 return false;
215 }
216 }
217
218 if (obj == d->btnAccpt)
219 {
220 if (ev->type() == QEvent::Enter)
221 {
222 updateDescription(AcceptedLabel);
223 return false;
224 }
225 }
226
227 // pass the event on to the parent class
228
229 return DVBox::eventFilter(obj, ev);
230 }
231
setPickLabels(const QList<PickLabel> & list)232 void PickLabelWidget::setPickLabels(const QList<PickLabel>& list)
233 {
234 foreach (QAbstractButton* const btn, d->pickBtns->buttons())
235 {
236 PickLabel id = (PickLabel)(d->pickBtns->id(btn));
237 btn->setChecked(list.contains(id));
238 updateDescription(id);
239 }
240 }
241
colorLabels() const242 QList<PickLabel> PickLabelWidget::colorLabels() const
243 {
244 QList<PickLabel> list;
245
246 foreach (QAbstractButton* const btn, d->pickBtns->buttons())
247 {
248 if (btn && btn->isChecked())
249 list.append((PickLabel)(d->pickBtns->id(btn)));
250 }
251
252 return list;
253 }
254
buildIcon(PickLabel label)255 QIcon PickLabelWidget::buildIcon(PickLabel label)
256 {
257 switch (label)
258 {
259 case RejectedLabel:
260 return QIcon::fromTheme(QLatin1String("flag-red"));
261 break;
262
263 case PendingLabel:
264 return QIcon::fromTheme(QLatin1String("flag-yellow"));
265 break;
266
267 case AcceptedLabel:
268 return QIcon::fromTheme(QLatin1String("flag-green"));
269 break;
270
271 default:
272 break;
273 }
274
275 // default : NoPickLabel
276
277 return QIcon::fromTheme(QLatin1String("flag-black"));
278 }
279
labelPickName(PickLabel label)280 QString PickLabelWidget::labelPickName(PickLabel label)
281 {
282 QString name;
283
284 switch (label)
285 {
286 case RejectedLabel:
287 name = i18nc("@info: pick label name", "Rejected");
288 break;
289
290 case PendingLabel:
291 name = i18nc("@info: pick label name", "Pending");
292 break;
293
294 case AcceptedLabel:
295 name = i18nc("@info: pick label name", "Accepted");
296 break;
297
298 default: // NoPickLabel
299 name = i18nc("@info: pick label name", "None");
300 break;
301 }
302
303 return name;
304 }
305
306 // -----------------------------------------------------------------------------
307
308 class Q_DECL_HIDDEN PickLabelSelector::Private
309 {
310
311 public:
312
Private()313 explicit Private()
314 : plw(nullptr)
315 {
316 }
317
318 PickLabelWidget* plw;
319 };
320
PickLabelSelector(QWidget * const parent)321 PickLabelSelector::PickLabelSelector(QWidget* const parent)
322 : QPushButton(parent),
323 d (new Private)
324 {
325 QMenu* const popup = new QMenu(this);
326 setMenu(popup);
327
328 QWidgetAction* const action = new QWidgetAction(this);
329 d->plw = new PickLabelWidget(this);
330 action->setDefaultWidget(d->plw);
331 popup->addAction(action);
332 slotPickLabelChanged(NoPickLabel);
333
334 connect(d->plw, SIGNAL(signalPickLabelChanged(int)),
335 this, SLOT(slotPickLabelChanged(int)));
336 }
337
~PickLabelSelector()338 PickLabelSelector::~PickLabelSelector()
339 {
340 delete d;
341 }
342
pickLabelWidget() const343 PickLabelWidget* PickLabelSelector::pickLabelWidget() const
344 {
345 return d->plw;
346 }
347
setPickLabel(PickLabel label)348 void PickLabelSelector::setPickLabel(PickLabel label)
349 {
350 d->plw->setPickLabels(QList<PickLabel>() << label);
351 slotPickLabelChanged(label);
352 }
353
colorLabel()354 PickLabel PickLabelSelector::colorLabel()
355 {
356 QList<PickLabel> list = d->plw->colorLabels();
357
358 if (!list.isEmpty())
359 {
360 return list.first();
361 }
362
363 return NoPickLabel;
364 }
365
slotPickLabelChanged(int id)366 void PickLabelSelector::slotPickLabelChanged(int id)
367 {
368 setText(QString());
369 setIcon(d->plw->buildIcon((PickLabel)id));
370 setToolTip(i18nc("@info: pick lablel selector", "Pick Label: %1", d->plw->labelPickName((PickLabel)id)));
371 menu()->close();
372
373 emit signalPickLabelChanged(id);
374 }
375
376 // -----------------------------------------------------------------------------
377
PickLabelMenuAction(QMenu * const parent)378 PickLabelMenuAction::PickLabelMenuAction(QMenu* const parent)
379 : QMenu(parent)
380 {
381 setTitle(i18nc("@title: pick label menu", "Pick"));
382 QWidgetAction* const wa = new QWidgetAction(this);
383 PickLabelWidget* const plw = new PickLabelWidget(parent);
384 wa->setDefaultWidget(plw);
385 addAction(wa);
386
387 connect(plw, SIGNAL(signalPickLabelChanged(int)),
388 this, SIGNAL(signalPickLabelChanged(int)));
389
390 connect(plw, SIGNAL(signalPickLabelChanged(int)),
391 parent, SLOT(close()));
392 }
393
~PickLabelMenuAction()394 PickLabelMenuAction::~PickLabelMenuAction()
395 {
396 }
397
398 } // namespace Digikam
399