Tulip 5.7.1
Large graphs analysis and drawing
Loading...
Searching...
No Matches
TulipItemEditorCreators.cxx
1/*
2 *
3 * This file is part of Tulip (https://tulip.labri.fr)
4 *
5 * Authors: David Auber and the Tulip development Team
6 * from LaBRI, University of Bordeaux
7 *
8 * Tulip is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation, either version 3
11 * of the License, or (at your option) any later version.
12 *
13 * Tulip 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.
16 * See the GNU General Public License for more details.
17 *
18 */
19#include <sstream>
20#include <climits>
21#include <cfloat>
22
23#include <QSet>
24#include <QLineEdit>
25#include <QTextEdit>
26#include <QComboBox>
27#include <QPainter>
28#include <QDoubleSpinBox>
29#include <QMainWindow>
30
31#include <tulip/DataSet.h>
32#include <tulip/VectorEditor.h>
33#include <tulip/GraphPropertiesModel.h>
34#include <tulip/TlpQtTools.h>
35#include <tulip/TulipMetaTypes.h>
36#include <tulip/ScientificDoubleSpinBox.h>
37#include <tulip/Perspective.h>
38
39namespace tlp {
40
41template <typename T>
42QWidget *NumberEditorCreator<T>::createWidget(QWidget *parent) const {
43 QDoubleSpinBox *dsb = nullptr;
44
45 // emulate a QSpinBox for integer types
46 if (typeid(T).name() == typeid(tlp::IntegerType).name() ||
47 typeid(T).name() == typeid(tlp::UnsignedIntegerType).name() ||
48 typeid(T).name() == typeid(tlp::LongType).name()) {
49 dsb = new QDoubleSpinBox(parent);
50 dsb->setDecimals(0);
51 // otherwise for floating point number types
52 } else {
53 // use a dedicated QDoubleSpinBox supporting scientific notation
54 dsb = new tlp::ScientificDoubleSpinBox(parent);
55 // force the use of dot character for decimal separator
56 dsb->setLocale(QLocale(QLocale::C));
57 }
58
59 // set correct range of values according to type
60 if (typeid(T).name() == typeid(tlp::IntegerType).name()) {
61 dsb->setRange(-INT_MAX, INT_MAX);
62 } else if (typeid(T).name() == typeid(tlp::UnsignedIntegerType).name()) {
63 dsb->setRange(0, UINT_MAX);
64 } else if (typeid(T).name() == typeid(tlp::LongType).name()) {
65 dsb->setRange(static_cast<double>(-LONG_MAX), static_cast<double>(LONG_MAX));
66 } else if (typeid(T).name() == typeid(tlp::FloatType).name()) {
67 dsb->setRange(-FLT_MAX, FLT_MAX);
68 } else {
69 dsb->setRange(-DBL_MAX, DBL_MAX);
70 }
71
72 return dsb;
73}
74
75template <typename T>
76void NumberEditorCreator<T>::setEditorData(QWidget *editor, const QVariant &data, bool,
77 tlp::Graph *) {
78 static_cast<QDoubleSpinBox *>(editor)->setValue(data.value<typename T::RealType>());
79}
80
81template <typename T>
82QVariant NumberEditorCreator<T>::editorData(QWidget *editor, tlp::Graph *) {
83 QVariant result;
84 result.setValue(
85 static_cast<typename T::RealType>(static_cast<QDoubleSpinBox *>(editor)->value()));
86 return result;
87}
88
89template <typename T>
90QWidget *LineEditEditorCreator<T>::createWidget(QWidget *parent) const {
91 return new QLineEdit(parent);
92}
93
94template <typename T>
95void LineEditEditorCreator<T>::setEditorData(QWidget *editor, const QVariant &data, bool,
96 tlp::Graph *) {
97 typename T::RealType val = data.value<typename T::RealType>();
98 static_cast<QLineEdit *>(editor)->setText(tlpStringToQString(T::toString(val)));
99 static_cast<QLineEdit *>(editor)->selectAll();
100}
101
102template <typename T>
103QVariant LineEditEditorCreator<T>::editorData(QWidget *editor, tlp::Graph *) {
104 std::string strVal = QStringToTlpString(static_cast<QLineEdit *>(editor)->text());
105 QVariant result;
106 typename T::RealType val;
107
108 if (T::fromString(val, strVal))
109 result.setValue(val);
110
111 return result;
112}
113
114template <typename T>
115QWidget *MultiLinesEditEditorCreator<T>::createWidget(QWidget *parent) const {
116 QTextEdit *edit = new QTextEdit(parent);
117 edit->setFocusPolicy(Qt::StrongFocus);
118 edit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
119 edit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
120 return edit;
121}
122
123template <typename T>
124void MultiLinesEditEditorCreator<T>::setEditorData(QWidget *editor, const QVariant &data, bool,
125 tlp::Graph *) {
126 typename T::RealType val = data.value<typename T::RealType>();
127 static_cast<QTextEdit *>(editor)->setPlainText(tlpStringToQString(T::toString(val)));
128 static_cast<QTextEdit *>(editor)->selectAll();
129}
130
131template <typename T>
132QVariant MultiLinesEditEditorCreator<T>::editorData(QWidget *editor, tlp::Graph *) {
133 std::string strVal = QStringToTlpString(static_cast<QTextEdit *>(editor)->toPlainText());
134 QVariant result;
135 typename T::RealType val;
136
137 if (T::fromString(val, strVal))
138 result.setValue(val);
139
140 return result;
141}
142
143template <typename T>
144QSize MultiLinesEditEditorCreator<T>::sizeHint(const QStyleOptionViewItem &option,
145 const QModelIndex &index) const {
146 QVariant data = index.model()->data(index);
147 typename T::RealType val = data.value<typename T::RealType>();
148 QString valS = tlpStringToQString(T::toString(val));
149 QStringList lines = valS.split(QLatin1Char('\n'));
150 QFontMetrics fontMetrics(option.font);
151 int height = 0;
152 int width = 0;
153
154 for (int i = 0; i < lines.count(); ++i) {
155 QRect textBB = fontMetrics.boundingRect(lines.at(i));
156 height += fontMetrics.boundingRect("|").height();
157 width = std::max(width, textBB.width());
158 }
159
160 // restrict column width in case of really large string to display
161 width = std::min(width, 500);
162
163 return QSize(width + 15, height + 5);
164}
165
166template <typename T>
167bool MultiLinesEditEditorCreator<T>::paint(QPainter *painter, const QStyleOptionViewItem &option,
168 const QVariant &data, const QModelIndex &index) const {
169 TulipItemEditorCreator::paint(painter, option, data, index);
170 QRect rect = option.rect;
171 typename T::RealType val = data.value<typename T::RealType>();
172 QString valS = tlpStringToQString(T::toString(val));
173 QStringList lines = valS.split(QLatin1Char('\n'));
174
175 if (option.state.testFlag(QStyle::State_Selected) && option.showDecorationSelected) {
176 painter->setPen(option.palette.highlightedText().color());
177 painter->setBrush(option.palette.highlightedText());
178 } else {
179 painter->setPen(option.palette.text().color());
180 painter->setBrush(option.palette.text());
181 }
182
183 for (int i = 0; i < lines.count(); ++i) {
184 painter->drawText(rect.x(), rect.y() + i * rect.height() / lines.count(), rect.width(),
185 rect.height() / lines.count(), Qt::AlignLeft | Qt::AlignVCenter, lines.at(i));
186 }
187
188 return true;
189}
190
191template <typename PROPTYPE>
192QWidget *PropertyEditorCreator<PROPTYPE>::createWidget(QWidget *parent) const {
193 return new QComboBox(parent);
194}
195
196template <typename PROPTYPE>
197void PropertyEditorCreator<PROPTYPE>::setEditorData(QWidget *w, const QVariant &val,
198 bool isMandatory, tlp::Graph *g) {
199 if (g == nullptr) {
200 w->setEnabled(false);
201 return;
202 }
203
204 PROPTYPE *prop = val.value<PROPTYPE *>();
205 QComboBox *combo = static_cast<QComboBox *>(w);
206 GraphPropertiesModel<PROPTYPE> *model = nullptr;
207
208 if (isMandatory)
209 model = new GraphPropertiesModel<PROPTYPE>(g, false, combo);
210 else
211 model = new GraphPropertiesModel<PROPTYPE>(QObject::tr("Select a property"), g, false, combo);
212
213 combo->setModel(model);
214 combo->setCurrentIndex(model->rowOf(prop));
215}
216
217template <typename PROPTYPE>
218QVariant PropertyEditorCreator<PROPTYPE>::editorData(QWidget *w, tlp::Graph *g) {
219 if (g == nullptr)
220 return QVariant();
221
222 QComboBox *combo = static_cast<QComboBox *>(w);
223 GraphPropertiesModel<PROPTYPE> *model =
224 static_cast<GraphPropertiesModel<PROPTYPE> *>(combo->model());
225 QVariant var = model->data(model->index(combo->currentIndex(), 0), TulipModel::PropertyRole);
227 PROPTYPE *prop = static_cast<PROPTYPE *>(pi);
228 return QVariant::fromValue<PROPTYPE *>(prop);
229}
230
231template <typename PROPTYPE>
232QString PropertyEditorCreator<PROPTYPE>::displayText(const QVariant &v) const {
233 PROPTYPE *prop = v.value<PROPTYPE *>();
234
235 if (prop == nullptr)
236 return QObject::tr("Select a property");
237
238 return tlpStringToQString(prop->getName());
239}
240
241template <typename ElementType>
242QWidget *VectorEditorCreator<ElementType>::createWidget(QWidget *) const {
243 VectorEditor *w = new VectorEditor(
244 tlp::Perspective::instance() ? tlp::Perspective::instance()->mainWindow()->centralWidget()
245 : nullptr);
246 w->setWindowFlags(Qt::Dialog);
247 w->setWindowModality(Qt::ApplicationModal);
248 return w;
249}
250
251template <typename ElementType>
252void VectorEditorCreator<ElementType>::setEditorData(QWidget *editor, const QVariant &v, bool,
253 tlp::Graph *) {
254 QVector<QVariant> editorData;
255 std::vector<ElementType> vect = v.value<std::vector<ElementType>>();
256
257 for (size_t i = 0; i < vect.size(); ++i) {
258 editorData.push_back(QVariant::fromValue<ElementType>(vect[i]));
259 }
260
261 static_cast<VectorEditor *>(editor)->setVector(editorData, qMetaTypeId<ElementType>());
262
263 static_cast<VectorEditor *>(editor)->move(QCursor::pos());
264}
265
266template <typename ElementType>
267QVariant VectorEditorCreator<ElementType>::editorData(QWidget *editor, tlp::Graph *) {
268 std::vector<ElementType> result;
269 QVector<QVariant> editorData = static_cast<VectorEditor *>(editor)->vector();
270
271 for (const QVariant &v : editorData)
272 result.push_back(v.value<ElementType>());
273
274 return QVariant::fromValue<std::vector<ElementType>>(result);
275}
276
277// the template below is only used for displayText method implementation
278template <typename T>
279struct DisplayVectorDataType : public DataType {
280 DisplayVectorDataType(void *value) : DataType(value) {}
281 ~DisplayVectorDataType() override {}
282 DataType *clone() const override {
283 return nullptr;
284 }
285
286 std::string getTypeName() const override {
287 return std::string(typeid(std::vector<T>).name());
288 }
289};
290
291template <typename ElementType>
292QString VectorEditorCreator<ElementType>::displayText(const QVariant &data) const {
293 std::vector<ElementType> v = data.value<std::vector<ElementType>>();
294
295 if (v.empty())
296 return QString();
297
298 // use a DataTypeSerializer if any
299 DataTypeSerializer *dts = DataSet::typenameToSerializer(std::string(typeid(v).name()));
300
301 if (dts) {
302 DisplayVectorDataType<ElementType> dt(&v);
303
304 std::stringstream sstr;
305 dts->writeData(sstr, &dt);
306
307 std::string str = sstr.str();
308
309 QString qstr = tlpStringToQString(str);
310
311 return truncateText(qstr);
312 }
313
314 if (v.size() == 1)
315 return QString("1 element");
316
317 return QString::number(v.size()) + QObject::tr(" elements");
318}
319} // namespace tlp
static DataTypeSerializer * typenameToSerializer(const std::string &name)
static tlp::Perspective * instance()
PropertyInterface describes the interface of a graph property.
std::string QStringToTlpString(const QString &toConvert)
Convert a QString to a Tulip UTF-8 encoded std::string.
Definition: TlpQtTools.h:49
QString tlpStringToQString(const std::string &toConvert)
Convert a Tulip UTF-8 encoded std::string to a QString.
Definition: TlpQtTools.h:55
ElementType
Definition: Graph.h:50
void * value
The actual pointer to the element's data.
Definition: DataSet.h:86