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