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