Tulip  5.7.4
Large graphs analysis and drawing
PluginModel.h
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 ///@cond DOXYGEN_HIDDEN
20 
21 #ifndef PLUGINMODEL_H
22 #define PLUGINMODEL_H
23 
24 #include <algorithm>
25 
26 #include <QIcon>
27 #include <QFont>
28 #include <QWidget>
29 
30 #include <tulip/TulipModel.h>
31 #include <tulip/TlpQtTools.h>
32 #include <tulip/PluginLister.h>
33 
34 #include <string>
35 
36 namespace tlp {
37 /*
38  * @brief Build and manage a Qt Model of a list of plugins
39  */
40 class TLP_QT_SCOPE SimplePluginListModel : public tlp::TulipModel {
41 private:
42  QList<std::string> _list;
43 
44 public:
45  SimplePluginListModel(const std::list<std::string> &plugins, QObject *parent = nullptr);
46  ~SimplePluginListModel() override;
47  int columnCount(const QModelIndex & = QModelIndex()) const override;
48  int rowCount(const QModelIndex &parent = QModelIndex()) const override;
49  QModelIndex parent(const QModelIndex &) const override;
50  QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
51  QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
52  QList<std::string> plugins() const;
53  std::string pluginName(const QModelIndex &index) const;
54 };
55 
56 template <typename PLUGIN>
57 class PluginModel : public tlp::TulipModel {
58  struct TreeItem {
59  TreeItem(QString name, QString info = "", TreeItem *parent = nullptr)
60  : name(name), info(info), parent(parent) {}
61  virtual ~TreeItem() {
62  qDeleteAll(children);
63  }
64  TreeItem *addChild(QString name, QString info = "") {
65  TreeItem *result = new TreeItem(name, info, this);
66  children.push_back(result);
67  return result;
68  }
69 
70  QString name;
71  QString info;
72  TreeItem *parent;
73  QList<TreeItem *> children;
74  };
75  TreeItem *_root;
76 
77  // FIXME: Non-optimized piece of crap, should be fixed
78  void buildTree() {
79  delete _root;
80  _root = new TreeItem("root");
81  QMap<QString, QMap<QString, QStringList>> pluginTree;
82  std::list<std::string> plugins = PluginLister::availablePlugins<PLUGIN>();
83 
84  for (std::list<std::string>::iterator it = plugins.begin(); it != plugins.end(); ++it) {
85  std::string name = *it;
86  const Plugin &plugin = PluginLister::pluginInformation(name);
87  pluginTree[tlp::tlpStringToQString(plugin.category())]
88  [tlp::tlpStringToQString(plugin.group())]
89  .append(tlp::tlpStringToQString(name));
90  }
91 
92  for (const QString &cat : pluginTree.keys()) {
93  TreeItem *catItem = _root->addChild(cat);
94 
95  for (const QString &group : pluginTree[cat].keys()) {
96  TreeItem *groupItem = catItem;
97 
98  if ((!group.isEmpty()) && (pluginTree[cat].keys().size() > 1))
99  groupItem = catItem->addChild(group);
100 
101  // sort in case insensitive alphabetic order
102  std::sort(pluginTree[cat][group].begin(), pluginTree[cat][group].end(), QStringCaseCmp);
103 
104  for (const QString &alg : pluginTree[cat][group]) {
106 
107  // set info only if they contain more than one word
108  if (info.find(' ') != std::string::npos)
109  groupItem->addChild(alg, tlp::tlpStringToQString(info));
110  else
111  groupItem->addChild(alg);
112  }
113  }
114  }
115  }
116 
117  QList<int> indexHierarchy(TreeItem *item) const {
118  QList<int> result;
119  TreeItem *parent = item->parent;
120  TreeItem *child = item;
121 
122  while (child != _root) {
123  result.push_front(parent->children.indexOf(child));
124  parent = parent->parent;
125  child = child->parent;
126  }
127 
128  return result;
129  }
130 
131 public:
132  explicit PluginModel(QObject *parent = nullptr) : TulipModel(parent), _root(nullptr) {
133  buildTree();
134  }
135  ~PluginModel() override {
136  delete _root;
137  }
138 
139  int rowCount(const QModelIndex &parent = QModelIndex()) const override {
140  TreeItem *item = _root;
141 
142  if (parent.isValid())
143  item = static_cast<TreeItem *>(parent.internalPointer());
144 
145  return item->children.size();
146  }
147 
148  int columnCount(const QModelIndex & = QModelIndex()) const override {
149  return 1;
150  }
151 
152  QModelIndex parent(const QModelIndex &child) const override {
153  if (!child.isValid())
154  return QModelIndex();
155 
156  TreeItem *childItem = static_cast<TreeItem *>(child.internalPointer());
157 
158  if (childItem->parent == _root)
159  return QModelIndex();
160 
161  QList<int> indexes = indexHierarchy(childItem->parent);
162  int row = indexes[indexes.size() - 1];
163  return createIndex(row, child.column(), childItem->parent);
164  }
165 
166  QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override {
167  TreeItem *parentItem = _root;
168 
169  if (parent.isValid()) {
170  parentItem = static_cast<TreeItem *>(parent.internalPointer());
171  }
172 
173  if (row >= parentItem->children.size())
174  return QModelIndex();
175 
176  return createIndex(row, column, parentItem->children[row]);
177  }
178 
179  QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
180  TreeItem *item = static_cast<TreeItem *>(index.internalPointer());
181 
182  if (role == Qt::DisplayRole)
183  return item->name;
184  else if (role == Qt::ToolTipRole) {
185  if (item->info.isEmpty())
186  return item->name;
187  else
188  return QString("<table><tr><td><b>%1</b></td></tr><tr><td><i>%2</i></td></tr></table>")
189  .arg(item->name)
190  .arg(item->info);
191  } else if (role == Qt::FontRole && !index.parent().parent().isValid()) {
192  QFont f;
193  QWidget *p = dynamic_cast<QWidget *>(QAbstractItemModel::parent());
194  if (p)
195  f = p->font();
196 
197  f.setBold(true);
198  return f;
199  } else if (role == Qt::DecorationRole && item->children.isEmpty() &&
201  QIcon icon(tlp::tlpStringToQString(
203  return icon;
204  }
205 
206  return QVariant();
207  }
208 
209  Qt::ItemFlags flags(const QModelIndex &index) const override {
210  Qt::ItemFlags result(QAbstractItemModel::flags(index));
211 
212  if (index.isValid()) {
213  TreeItem *item = static_cast<TreeItem *>(index.internalPointer());
214 
215  if (!PluginLister::pluginExists<PLUGIN>(tlp::QStringToTlpString(item->name)))
216  result = Qt::ItemIsEnabled;
217  }
218 
219  return result;
220  }
221 };
222 } // namespace tlp
223 
224 #endif // PLUGINMODEL_H
225 ///@endcond
virtual std::string info() const =0
Information about the plug-in, from the plug-in author. This information can contains anything,...
virtual std::string icon() const
The icon (preferably a thumbnail) of the plugin.
static const Plugin & pluginInformation(const std::string &name)
Gets more detailed information about one specific plug-in.
static bool pluginExists(const std::string &pluginName)
Checks if a plugin of a given type is loaded This method checks the plugin "pluginName" is currently ...
Definition: PluginLister.h:85
std::string QStringToTlpString(const QString &toConvert)
Convert a QString to a Tulip UTF-8 encoded std::string.
Definition: TlpQtTools.h:50
bool QStringCaseCmp(const QString &s1, const QString &s2)
Case insensitive comparison of two QStrings.
Definition: TlpQtTools.h:63
QString tlpStringToQString(const std::string &toConvert)
Convert a Tulip UTF-8 encoded std::string to a QString.
Definition: TlpQtTools.h:56