1 // This file is part of the SpeedCrunch project
2 // Copyright (C) 2007 Ariya Hidayat <ariya@kde.org>
3 // Copyright (C) 2008, 2009, 2010, 2011, 2016 @heldercorreia
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; see the file COPYING.  If not, write to
17 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 // Boston, MA 02110-1301, USA.
19 
20 #include "gui/constantswidget.h"
21 
22 #include "core/constants.h"
23 #include "core/settings.h"
24 
25 #include <QEvent>
26 #include <QTimer>
27 #include <QComboBox>
28 #include <QHBoxLayout>
29 #include <QHeaderView>
30 #include <QLabel>
31 #include <QLineEdit>
32 #include <QTreeWidget>
33 #include <QVBoxLayout>
34 
35 #include <algorithm>
36 
ConstantsWidget(QWidget * parent)37 ConstantsWidget::ConstantsWidget(QWidget* parent)
38     : QWidget(parent)
39 {
40     m_categoryLabel = new QLabel(this);
41     m_category = new QComboBox(this);
42     m_category->setEditable(false);
43     m_category->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
44 
45     connect(m_category, SIGNAL(activated(int)), SLOT(filter()));
46 
47     QWidget* categoryBox = new QWidget(this);
48     QHBoxLayout* categoryLayout = new QHBoxLayout;
49     categoryBox->setLayout(categoryLayout);
50     categoryLayout->addWidget(m_categoryLabel);
51     categoryLayout->addWidget(m_category);
52     categoryLayout->setMargin(0);
53 
54     m_label = new QLabel(this);
55 
56     m_filter = new QLineEdit(this);
57     m_filter->setMinimumWidth(fontMetrics().width('X') * 10);
58 
59     connect(m_filter, SIGNAL(textChanged(const QString &)), SLOT(triggerFilter()));
60 
61     QWidget* searchBox = new QWidget(this);
62     QHBoxLayout* searchLayout = new QHBoxLayout;
63     searchBox->setLayout(searchLayout);
64     searchLayout->addWidget(m_label);
65     searchLayout->addWidget(m_filter);
66     searchLayout->setMargin(0);
67 
68     m_list = new QTreeWidget(this);
69     m_list->setAutoScroll(true);
70     m_list->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
71     m_list->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
72     m_list->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
73     m_list->setColumnCount(3);
74     m_list->setRootIsDecorated(false);
75     m_list->setMouseTracking(true);
76     m_list->setEditTriggers(QTreeWidget::NoEditTriggers);
77     m_list->setSelectionBehavior(QTreeWidget::SelectRows);
78     m_list->setAlternatingRowColors(true);
79     m_list->setCursor(QCursor(Qt::PointingHandCursor));
80 
81     connect(m_list, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(handleItem(QTreeWidgetItem*)));
82 
83     QVBoxLayout* layout = new QVBoxLayout;
84     setLayout(layout);
85     layout->setMargin(3);
86     layout->addWidget(categoryBox);
87     layout->addWidget(searchBox);
88     layout->addWidget(m_list);
89 
90     m_filterTimer = new QTimer(this);
91     m_filterTimer->setInterval(500);
92     m_filterTimer->setSingleShot(true);
93     connect(m_filterTimer, SIGNAL(timeout()), SLOT(filter()));
94 
95     m_noMatchLabel = new QLabel(this);
96     m_noMatchLabel->setAlignment(Qt::AlignCenter);
97     m_noMatchLabel->adjustSize();
98     m_noMatchLabel->hide();
99 
100     retranslateText();
101 
102     setFocusProxy(m_filter);
103 
104     filter();
105 }
106 
~ConstantsWidget()107 ConstantsWidget::~ConstantsWidget()
108 {
109     m_filterTimer->stop();
110 }
111 
handleRadixCharacterChange()112 void ConstantsWidget::handleRadixCharacterChange()
113 {
114     updateList();
115 }
116 
retranslateText()117 void ConstantsWidget::retranslateText()
118 {
119     m_categoryLabel->setText(tr("Category"));
120     m_label->setText(tr("Search"));
121     m_noMatchLabel->setText(tr("No match found"));
122 
123     QStringList titles;
124     const QString name = tr("Name");
125     const QString value = tr("Value");
126     const QString unit = tr("Unit");
127     if (layoutDirection() == Qt::LeftToRight)
128         titles << name << value << unit;
129     else
130         titles << name << unit << value;
131     m_list->setHeaderLabels(titles);
132 
133     updateList();
134 }
135 
filter()136 void ConstantsWidget::filter()
137 {
138     const QList<Constant> &clist = Constants::instance()->list();
139     const char radixChar = Settings::instance()->radixCharacter();
140     QString term = m_filter->text();
141 
142     m_filterTimer->stop();
143     setUpdatesEnabled(false);
144 
145     QString chosenCategory = m_category->currentText();
146 
147     m_list->clear();
148     for (int k = 0; k < clist.count(); ++k) {
149         QStringList str;
150         str << clist.at(k).name;
151 
152         QString radCh = (radixChar != '.') ?
153             QString(clist.at(k).value).replace('.', radixChar)
154             : clist.at(k).value;
155 
156         if (layoutDirection() == Qt::RightToLeft) {
157             str << clist.at(k).unit + QChar(0x200e); // Unicode LRM
158             str << radCh;
159         } else {
160             str << radCh;
161             str << clist.at(k).unit;
162         }
163 
164         str << clist.at(k).name.toUpper();
165         str << QString("");
166 
167         bool include = (chosenCategory == tr("All")) ?
168             true : (clist.at(k).category == chosenCategory);
169 
170         if (!include)
171             continue;
172 
173         QTreeWidgetItem* item = nullptr;
174         if (term.isEmpty())
175             item = new QTreeWidgetItem(m_list, str);
176         else
177             if (str.at(0).contains(term, Qt::CaseInsensitive))
178                 item = new QTreeWidgetItem(m_list, str);
179         if (item) {
180             QString tip;
181             tip += QString(QChar(0x200E));
182             tip += QString("<b>%1</b><br>%2").arg( clist.at(k).name, clist.at(k).value);
183             tip += QString(QChar(0x200E));
184             if (!clist.at(k).unit.isEmpty())
185                 tip.append(" ").append(clist.at(k).unit);
186             if (radixChar != '.')
187                 tip.replace('.', radixChar);
188             tip += QString(QChar(0x200E));
189             item->setToolTip(0, tip);
190             item->setToolTip(1, tip);
191             item->setToolTip(2, tip);
192 
193             if (layoutDirection() == Qt::RightToLeft) {
194                 item->setTextAlignment(1, Qt::AlignRight);
195                 item->setTextAlignment(2, Qt::AlignLeft);
196             } else {
197                 item->setTextAlignment(1, Qt::AlignLeft);
198                 item->setTextAlignment(2, Qt::AlignLeft);
199             }
200         }
201     }
202 
203     m_list->resizeColumnToContents(0);
204     m_list->resizeColumnToContents(1);
205     m_list->resizeColumnToContents(2);
206 
207     if (m_list->topLevelItemCount() > 0) {
208         m_noMatchLabel->hide();
209         m_list->sortItems(0, Qt::AscendingOrder);
210     } else {
211         m_noMatchLabel->setGeometry(m_list->geometry());
212         m_noMatchLabel->show();
213         m_noMatchLabel->raise();
214     }
215 
216     setUpdatesEnabled(true);
217 }
218 
handleItem(QTreeWidgetItem * item)219 void ConstantsWidget::handleItem(QTreeWidgetItem* item)
220 {
221     const auto& l = Constants::instance()->list();
222     auto found = std::find_if(l.begin(), l.end(), [&](const Constant& c) {
223         return item->text(0) == c.name;
224     });
225     emit constantSelected(found->value);
226 }
227 
triggerFilter()228 void ConstantsWidget::triggerFilter()
229 {
230     m_filterTimer->stop();
231     m_filterTimer->start();
232 }
233 
updateList()234 void ConstantsWidget::updateList()
235 {
236     m_category->clear();
237     Constants::instance()->retranslateText();
238     m_category->addItems(Constants::instance()->categories());
239     m_category->insertItem(0, tr("All"));
240     m_category->setCurrentIndex(0);
241     filter();
242 }
243 
changeEvent(QEvent * e)244 void ConstantsWidget::changeEvent(QEvent* e)
245 {
246     if (e->type() == QEvent::LanguageChange) {
247         Constants::instance()->retranslateText();
248         retranslateText();
249     }
250     else
251         QWidget::changeEvent(e);
252 }
253 
254