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