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