Tulip  5.2.1
Large graphs analysis and drawing
CSVGraphImport.h
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 ///@cond DOXYGEN_HIDDEN
20 
21 #ifndef CSVGRAPHIMPORT_H
22 #define CSVGRAPHIMPORT_H
23 
24 #include <tulip/CSVContentHandler.h>
25 #include <tulip/Graph.h>
26 #include <tulip/tulipconf.h>
27 
28 #include <QMessageBox>
29 
30 namespace tlp {
31 class PropertyInterface;
32 
33 /**
34  * @brief Store import parameters for a CSV file column.
35  *
36  * Contains all the parameters defined by user for a given CSV column (the name of the column, its
37  *data type and if user want to import it).
38  **/
39 class TLP_QT_SCOPE CSVColumn {
40 public:
41  CSVColumn(const std::string &columnName = "", const std::string &columnType = "")
42  : _used(true), _name(columnName), _type(columnType), _valueSeparator(0) {}
43 
44  /**
45  * @brief Get the name of the column.
46  **/
47  const std::string &name() const {
48  return _name;
49  }
50 
51  /**
52  * @brief Tells if the property marked for import.
53  **/
54  bool isUsed() const {
55  return _used;
56  }
57 
58  /**
59  * @brief Return the property data type.
60  **/
61  const std::string &dataType() const {
62  return _type;
63  }
64 
65  bool needMultiValues() const {
66  return _valueSeparator != 0;
67  }
68 
69  char getMultiValueSeparator() const {
70  return _valueSeparator;
71  }
72 
73  // possible actions
74  // the two first ones indicate an exception
75  enum Action { ASSIGN_NO_VALUE = 0, SKIP_ROW = 1, ASSIGN_VALUE = 2 };
76 
77  struct Exception {
78  std::string value;
79  Action action;
80  Exception(const std::string &v, Action a) : value(v), action(a) {}
81  };
82 
83  void addException(const std::string &value, Action action) {
84  _exceptions.emplace_back(value, action);
85  }
86 
87  void clearExceptions() {
88  _exceptions.clear();
89  }
90 
91  // look for a specific exception defined for token
92  Action getActionForToken(const std::string &token) {
93  for (const Exception &exception : _exceptions) {
94  if (exception.value == token)
95  return exception.action;
96  }
97  return Action::ASSIGN_VALUE;
98  }
99 
100 protected:
101  bool _used;
102  std::string _name;
103  std::string _type;
104  char _valueSeparator;
105  std::vector<Exception> _exceptions;
106 };
107 /**
108  * @brief Store all the advanced import parameters for the CSV file.
109  *
110  * Store the information about columns and rows to import.
111  * Use this object to configure the import process of a CSVImportGraph object.
112  **/
113 class TLP_QT_SCOPE CSVImportParameters {
114 public:
115  CSVImportParameters(unsigned int fromLine = 0, unsigned int toLine = UINT_MAX,
116  const std::vector<CSVColumn *> &columns = std::vector<CSVColumn *>());
117  virtual ~CSVImportParameters();
118 
119  /**
120  * @brief Return the number of column.
121  **/
122  unsigned int columnNumber() const;
123 
124  /**
125  * @brief return true if the column is marked for import
126  **/
127  bool importColumn(unsigned int column) const;
128  /**
129  * @brief Get the column name
130  **/
131  std::string getColumnName(unsigned int column) const;
132  /**
133  * @brief Get the column data type
134  **/
135  std::string getColumnDataType(unsigned int column) const;
136 
137  /**
138  * @brief Get the column separator for multiple values
139  **/
140  char getColumnMultiValueSeparator(unsigned int column) const;
141 
142  /**
143  * @brief Get the column action according to the given token
144  **/
145  CSVColumn::Action getColumnActionForToken(unsigned int column, const std::string &token) const;
146 
147  /**
148  * @brief Return the index of the first line to import
149  **/
150  unsigned int getFirstLineIndex() const;
151  /**
152  * @brief Return the index of the last line to import
153  **/
154  unsigned int getLastLineIndex() const;
155  /**
156  * @brief Return true if the given row is between the first row to import and the last row to
157  *import
158  **/
159  bool importRow(unsigned int row) const;
160 
161 private:
162  unsigned int fromLine;
163  unsigned int toLine;
164  std::vector<CSVColumn *> columns;
165 };
166 
167 /**
168  * @brief Interface to map CSV rows to graph elements.
169  *
170  * To build the mapping user had to parse the CSV file.
171  * @code
172  * CSVParser *parser;
173  * CSVToGraphDataMapping *mapping;
174  * parser->parse(mapping);
175  * //Now the mapping has been built.
176  * //Get the element for the first row.
177  * pair<tlp::ElementType,unsigned int> element = mapping->getElementForRow(0);
178  * @endcode
179  **/
180 class TLP_QT_SCOPE CSVToGraphDataMapping {
181 public:
182  virtual ~CSVToGraphDataMapping() {}
183  virtual std::pair<tlp::ElementType, std::vector<unsigned int>>
184  getElementsForRow(const std::vector<std::vector<std::string>> &tokens) = 0;
185  virtual void init(unsigned int rowNumber) = 0;
186 };
187 
188 /**
189  * @brief Abstract class handling node or edge mapping between a CSV column and a graph property.
190  *
191  * Be sure there is a property with the given name in the graph or an error will occur.
192  * Automatically handle CSV file parsing just implements the buildIndexForRow function to fill the
193  *rowToGraphId map with the right graph element.
194  **/
195 class TLP_QT_SCOPE AbstractCSVToGraphDataMapping : public CSVToGraphDataMapping {
196 public:
197  AbstractCSVToGraphDataMapping(tlp::Graph *graph, tlp::ElementType type,
198  const std::vector<unsigned int> &columnIds,
199  const std::vector<std::string> &propertyNames);
200  ~AbstractCSVToGraphDataMapping() override {}
201 
202  void init(unsigned int rowNumber) override;
203  std::pair<tlp::ElementType, std::vector<unsigned int>>
204  getElementsForRow(const std::vector<std::vector<std::string>> &tokens) override;
205 
206 protected:
207  /**
208  * @brief Create a new element if no elements for the given row was found.
209  * @return Return the graph element id or UINT_MAX if no new element is created.
210  **/
211  virtual unsigned int buildIndexForRow(unsigned int row, const std::vector<std::string> &keys) = 0;
212 
213 protected:
214  TLP_HASH_MAP<std::string, unsigned int> valueToId;
215  tlp::Graph *graph;
216  tlp::ElementType type;
217  std::vector<unsigned int> columnIds;
218  std::vector<tlp::PropertyInterface *> keyProperties;
219 };
220 /**
221  * @brief Map each row of the CSV file on a new node.
222  **/
223 class TLP_QT_SCOPE CSVToNewNodeIdMapping : public CSVToGraphDataMapping {
224 public:
225  CSVToNewNodeIdMapping(tlp::Graph *graph);
226  void init(unsigned int rowNumber) override;
227  std::pair<tlp::ElementType, std::vector<unsigned int>>
228  getElementsForRow(const std::vector<std::vector<std::string>> &tokens) override;
229 
230 private:
231  tlp::Graph *graph;
232 };
233 
234 /**
235  * @brief Try to map CSV file rows to nodes according to value between a CSV column and a graph
236  *property.
237  *
238  * Be sure there is a property with the given name in the graph before using it.
239  **/
240 class TLP_QT_SCOPE CSVToGraphNodeIdMapping : public AbstractCSVToGraphDataMapping {
241 public:
242  /**
243  * @param graph The graph where the nodes will be searched.
244  * @param columnIndex The index of the column with the ids in the CSV file.
245  * @param propertyName The name of the property to search ids.
246  * @param firstRow The first row to search ids.
247  * @param lastRow The last row to search ids.
248  * @param createNode If set to true if there is no node for an id in the CSV file a new node will
249  *be created for this id.
250  **/
251  CSVToGraphNodeIdMapping(tlp::Graph *graph, const std::vector<unsigned int> &columnIds,
252  const std::vector<std::string> &propertyNames, bool createNode = false);
253  void init(unsigned int rowNumber) override;
254 
255 protected:
256  unsigned int buildIndexForRow(unsigned int row, const std::vector<std::string> &keys) override;
257 
258 private:
259  bool createMissingNodes;
260 };
261 /**
262  * @brief Try to map CSV file rows to edges according to value between a CSV column and a graph
263  *property.
264  *
265  * Be sure there is a property with the given name in the graph before using it.
266  **/
267 class TLP_QT_SCOPE CSVToGraphEdgeIdMapping : public AbstractCSVToGraphDataMapping {
268 public:
269  /**
270  * @param graph The graph where the edges will be searched.
271  * @param columnIndex The index of the column with the ids in the CSV file.
272  * @param propertyName The name of the property to search ids.
273  * @param firstRow The first row to search ids.
274  * @param lastRow The last row to search ids.
275  **/
276  CSVToGraphEdgeIdMapping(tlp::Graph *graph, const std::vector<unsigned int> &columnIds,
277  const std::vector<std::string> &propertyNames);
278 
279 protected:
280  unsigned int buildIndexForRow(unsigned int row, const std::vector<std::string> &keys) override;
281 };
282 
283 /**
284  * @brief Try to map CSV file rows to edges according to edge source and destination.
285  *
286  * For each row in the CSV file create an edge in the graph between source and destination nodes.
287  *Find source node by comparing id in the source CSV column and destination node by comparing id in
288  *the destination CSV column.
289  **/
290 class TLP_QT_SCOPE CSVToGraphEdgeSrcTgtMapping : public CSVToGraphDataMapping {
291 public:
292  /**
293  * @param graph The graph where the edges will be searched.
294  * @param srcColumnIndex The index of the column with the source node id in the CSV file.
295  * @param tgtColumnIndex The index of the column with the taret node id in the CSV file.
296  * @param srcPropertyName The name of the property to search source node id.
297  * @param tgtPropertyName The name of the property to search target node id.
298  * @param firstRow The first row to search ids.
299  * @param lastRow The last row to search ids.
300  * @param createMissinElements If true create source node, destination node if one of them is not
301  *found in the graph.
302  **/
303  CSVToGraphEdgeSrcTgtMapping(tlp::Graph *graph, const std::vector<unsigned int> &srcColumnIds,
304  const std::vector<unsigned int> &tgtColumnIds,
305  const std::vector<std::string> &srcPropNames,
306  const std::vector<std::string> &tgtPropNames,
307  bool createMissinElements = false);
308  std::pair<tlp::ElementType, unsigned int> getElementForRow(unsigned int row);
309  void init(unsigned int lineNumbers) override;
310  std::pair<tlp::ElementType, std::vector<unsigned int>>
311  getElementsForRow(const std::vector<std::vector<std::string>> &tokens) override;
312 
313 private:
314  tlp::Graph *graph;
315  TLP_HASH_MAP<std::string, unsigned int> srcValueToId;
316  TLP_HASH_MAP<std::string, unsigned int> tgtValueToId;
317  std::vector<unsigned int> srcColumnIds;
318  std::vector<unsigned int> tgtColumnIds;
319  std::vector<tlp::PropertyInterface *> srcProperties;
320  std::vector<tlp::PropertyInterface *> tgtProperties;
321  bool sameSrcTgtProperties;
322  bool buildMissingElements;
323 };
324 
325 /**
326  * @brief Interface to perform mapping between CSV columns and graph properties during the CSV
327  *import process.
328  *
329  **/
330 class TLP_QT_SCOPE CSVImportColumnToGraphPropertyMapping {
331 public:
332  virtual ~CSVImportColumnToGraphPropertyMapping() {}
333  /**
334  * @brief Return the property corresponding to the column index.
335  * @param column The index of the column.
336  * @param token The current token. May be needed to determine column data type.
337  *
338  * The token parameter is used to guess property type if needed.
339  **/
340  virtual tlp::PropertyInterface *getPropertyInterface(unsigned int column,
341  const std::string &token) = 0;
342 };
343 
344 /**
345  * @brief Proxy to handle all the properties operations like access, creation, data type detection
346  *during the CSV parsing process.
347  *
348  * Try to guess the type of the property in function of the first token
349  * if user don't tell which type the property is.
350  **/
351 class TLP_QT_SCOPE CSVImportColumnToGraphPropertyMappingProxy
352  : public CSVImportColumnToGraphPropertyMapping {
353 public:
354  CSVImportColumnToGraphPropertyMappingProxy(tlp::Graph *graph,
355  const CSVImportParameters &importParameters,
356  QWidget *parent = nullptr);
357  ~CSVImportColumnToGraphPropertyMappingProxy() override {}
358  tlp::PropertyInterface *getPropertyInterface(unsigned int column,
359  const std::string &token) override;
360 
361 private:
362  tlp::Graph *graph;
363  CSVImportParameters importParameters;
364  TLP_HASH_MAP<unsigned int, tlp::PropertyInterface *> propertiesBuffer;
365  QMessageBox::StandardButton overwritePropertiesButton;
366  QWidget *parent;
367  PropertyInterface *generateApproximateProperty(const std::string &name, const std::string &type);
368 };
369 
370 /**
371  * @brief Manage all the CSV import process. Use the mapping object to find the graph element in
372  *function of the row and the propertiesManager to find the property corresponding to the column.
373  * The import parameters are used to filter the rows and the columns to import.
374  **/
375 class TLP_QT_SCOPE CSVGraphImport : public tlp::CSVContentHandler {
376 public:
377  CSVGraphImport(CSVToGraphDataMapping *mapping,
378  CSVImportColumnToGraphPropertyMapping *propertiesManager,
379  const CSVImportParameters &importParameters);
380  ~CSVGraphImport() override;
381  bool begin() override;
382  bool line(unsigned int row, const std::vector<std::string> &lineTokens) override;
383  bool end(unsigned int rowNumber, unsigned int columnNumber) override;
384 
385 protected:
386  CSVToGraphDataMapping *mapping;
387  CSVImportColumnToGraphPropertyMapping *propertiesManager;
388  CSVImportParameters importParameters;
389 };
390 } // namespace tlp
391 #endif // CSVGRAPHIMPORT_H
392 ///@endcond
PropertyInterface describes the interface of a graph property.
ElementType
Definition: Graph.h:48