Reference documentation for deal.II version 8.4.2
xml_parameter_reader.cpp
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2010 - 2013 by Martin Steigemann and Wolfgang Bangerth
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #include <QtGui>
18 
19 #include "xml_parameter_reader.h"
20 
21 
22 namespace dealii
23 {
24  namespace ParameterGui
25  {
26  XMLParameterReader::XMLParameterReader(QTreeWidget *tree_widget)
27  : tree_widget(tree_widget)
28  {
29  QStyle * style = tree_widget->style();
30 
31  subsection_icon.addPixmap(style->standardPixmap(QStyle::SP_DirClosedIcon), QIcon::Normal, QIcon::Off);
32  subsection_icon.addPixmap(style->standardPixmap(QStyle::SP_DirOpenIcon), QIcon::Normal, QIcon::On);
33 
34  parameter_icon.addPixmap(style->standardPixmap(QStyle::SP_FileIcon));
35  }
36 
37 
38 
39  bool XMLParameterReader::read_xml_file(QIODevice *device)
40  {
41  xml.setDevice(device);
42 
43  // We look for a StartElement "ParameterHandler"
44  // and start parsing after this.
45  // <ParameterHandler>
46  // <subsection>
47  // ...
48  // </subsection>
49  // </ParameterHandler>
50 
51  while (xml.readNext() != QXmlStreamReader::Invalid)
52  {
53  if (xml.isStartElement())
54  if (xml.name() == "ParameterHandler")
55  {
57 
58  return !xml.error();;
59  };
60  };
61 
62  xml.raiseError(QObject::tr("The file is not an ParameterHandler XML file."));
63 
64  return !xml.error();
65  }
66 
67 
68 
70  {
71  return QObject::tr("%1\nLine %2, column %3")
72  .arg(xml.errorString())
73  .arg(xml.lineNumber())
74  .arg(xml.columnNumber());
75  }
76 
77 
78 
80  {
81  Q_ASSERT(xml.isStartElement() && xml.name() == "ParameterHandler");
82 
83  while (xml.readNext() != QXmlStreamReader::Invalid) // go to the next <start_element>
84  { // if it is the closing element of ParameterHandler,
85  if (xml.isEndElement() && xml.name() == "ParameterHandler")
86  break; // break the loop
87 
88  if (xml.isStartElement()) // if it is a start element
89  read_subsection_element(0); // it must be a subsection or a parameter
90  };
91  }
92 
93 
94 
95  void XMLParameterReader::read_subsection_element(QTreeWidgetItem *parent)
96  {
97  // The structure of the parameter file is assumed to be of the form
98  //
99  // <subsection>
100  // <subsection>
101  // ...
102  // <parameter>
103  // <value> ... </value>
104  // ...
105  // <pattern_description> ... </pattern_description>
106  // </parameter>
107  // <parameter>
108  // ...
109  // </parameter>
110  // ...
111  // </subsection>
112  // <subsection>
113  // ...
114  // </subsection>
115  // ...
116  // </subsection>
117  //
118  // Any subsection has a user-specified name also any parameter, but we do not know
119  // the userspecified names and we can not assume anything. So, when parsing the file,
120  // we do not know, if the actual <start_element> is a <subsection> or a <parameter>
121  // in a subsection. To decide, if the element is a subsection- or a parameter-name,
122  // we assume, that if the next <start_element> is <value>, we have a <parameter>
123  // and a parameter has the entries <value>, <default_value>, <documentation>,
124  // <pattern> and <pattern_description>
125 
126  Q_ASSERT(xml.isStartElement()); // the actual element is <subsection>
127 
128  QTreeWidgetItem * subsection = create_child_item(parent); // create a new subsection in the tree
129 
130  subsection->setIcon(0, subsection_icon); // set the icon,
131  subsection->setText(0, demangle(xml.name().toString())); // the name
132 
133  tree_widget->setItemExpanded(subsection, 0); // and the folder is not expanded
134 
135  while (xml.readNext() != QXmlStreamReader::Invalid) // read the next element
136  {
137  if (xml.isEndElement()) // if the next element is </subsection>, break the loop
138  break;
139 
140  if (xml.isStartElement()) // if it is a start element
141  {
142  if (xml.name() == "value") // it can be <value>, then we have found a parameter,
143  {
144  subsection->setFlags(subsection->flags() | Qt::ItemIsEditable); // values can be edited,
145  read_parameter_element (subsection);
146  }
147  else // or it can be a new <subsection>
148  {
149  subsection->setFlags(subsection->flags() | Qt::NoItemFlags); // subsections can not be edited,
150  read_subsection_element (subsection);
151  };
152  };
153  };
154  }
155 
156 
157 
158  void XMLParameterReader::read_parameter_element(QTreeWidgetItem *parent)
159  {
160  Q_ASSERT(xml.isStartElement() && xml.name() == "value"); // the actual element is <value>,
161  // then we have found a parameter-item
162  QString value = xml.readElementText(); // read the element text
163  parent->setText(1, value); // and store as text to the item
164  parent->setIcon(0, parameter_icon); // change the icon of parent
165 
166  while (xml.readNext() != QXmlStreamReader::Invalid) // go to the next <start_element>
167  {
168  if (xml.isStartElement())
169  {
170  if (xml.isStartElement() && xml.name() == "default_value") // if it is <default_value>
171  {
172  QString default_value = xml.readElementText(); // store it
173  parent->setText(2, default_value);
174  }
175  else if (xml.isStartElement() && xml.name() == "documentation") // if it is <documentation>
176  {
177  QString documentation = xml.readElementText(); // store it
178  parent->setText(3, documentation);
179 
180  if (!documentation.isEmpty()) // if there is a documentation,
181  {
182  parent->setToolTip(0, "Documentation: " + documentation); // set Documentation as ToolTip for both columns
183  parent->setToolTip(1, "Documentation: " + documentation);
184  parent->setStatusTip(0, "Documentation: " + documentation); // and as StatusTip for the first column also
185  };
186  }
187  else if (xml.isStartElement() && xml.name() == "pattern") // if it is <pattern>
188  {
189  QString pattern = xml.readElementText(); // store it as text
190  parent->setText(4, pattern); // we only need this value
191  // for writing back to XML later
192  }
193  else if (xml.isStartElement() && xml.name() == "pattern_description") // if it is <pattern_description>
194  {
195  QString pattern_description = xml.readElementText(); // store it as text
196  parent->setText(5, pattern_description);
197  // show the type and default
198  // in the StatusLine
199  parent->setStatusTip(1, "Type: " + pattern_description + " Default: " + parent->text(2));
200 
201  // in order to store values as correct data types,
202  // we check the following types in the pattern_description:
203 
204  QRegExp rx_string("\\b(Anything|FileName|DirectoryName|Selection|List|MultipleSelection)\\b"),
205  rx_integer("\\b(Integer)\\b"),
206  rx_double("\\b(Float|Floating|Double)\\b"),
207  rx_bool("\\b(Selection true|false)\\b");
208 
209  if (rx_string.indexIn (pattern_description) != -1) // the type "Anything" or "Filename"
210  {
211  QString value = parent->text(1); // store as a QString
212 
213  parent->setData(1, Qt::EditRole, value); // and set the data in the item
214  parent->setData(1, Qt::DisplayRole, value);
215  }
216  else if (rx_integer.indexIn (pattern_description) != -1) // if the tpye is "Integer"
217  {
218  QString text = parent->text(1);
219 
220  bool ok = true;
221 
222  int value = text.toInt(&ok); // we convert the string to int
223 
224  if (ok) // and store
225  {
226  parent->setData(1, Qt::EditRole, value);
227  parent->setData(1, Qt::DisplayRole, value);
228  }
229  else // otherwise raise an error
230  xml.raiseError(QObject::tr("Cannot convert integer type to integer!"));
231  }
232  else if (rx_double.indexIn (pattern_description) != -1) // the same with "Float"
233  {
234  QString text = parent->text(1);
235 
236  bool ok = true;
237 
238  double value = text.toDouble(&ok);
239 
240  if (ok)
241  {
242  parent->setData(1, Qt::EditRole, value);
243  parent->setData(1, Qt::DisplayRole, value);
244  }
245  else
246  xml.raiseError(QObject::tr("Cannot convert double type to double!"));
247  };
248 
249  if (rx_bool.indexIn (pattern_description) != -1) // and booleans
250  {
251  QRegExp test(parent->text(1));
252 
253  bool value = true;
254 
255  if (test.exactMatch("true"))
256  value = true;
257  else if (test.exactMatch("false"))
258  value = false;
259  else
260  xml.raiseError(QObject::tr("Cannot convert boolen type to boolean!"));
261 
262  parent->setText(1, ""); // this is needed because we use
263  parent->setData(1, Qt::EditRole, value); // for booleans the standard
264  parent->setData(1, Qt::DisplayRole, value); // delegate
265  };
266 
267  break; // and break the loop
268  }
269  else
270  { // if there is any other element, raise an error
271  xml.raiseError(QObject::tr("Incomplete or unknown Parameter!"));
272  break; // and break the loop, here
273  }; // we assume the special structure
274  }; // of the parameter-file!
275  };
276  }
277 
278 
279 
280  QTreeWidgetItem *XMLParameterReader::create_child_item(QTreeWidgetItem *item)
281  {
282  QTreeWidgetItem * child_item; // create a new child-item
283 
284  if (item)
285  child_item = new QTreeWidgetItem(item); // if item is not empty,
286  else // append the new item as a child
287  child_item = new QTreeWidgetItem(tree_widget); // otherwise create a new item
288  // in the tree
289 
290  child_item->setData(0, Qt::DisplayRole, xml.name().toString()); // set xml.tag_name as data
291  child_item->setText(0, xml.name().toString()); // set xml.tag_name as data
292 
293  return child_item;
294  }
295 
296 
297 
298  QString XMLParameterReader::demangle (const QString &s)
299  {
300  std::string s_temp (s.toStdString()); // this function is copied from the ParameterHandler class
301 
302  std::string u;
303  u.reserve (s_temp.size());
304 
305  for (unsigned int i=0; i<s_temp.size(); ++i)
306  if (s_temp[i] != '_')
307  u.push_back (s_temp[i]);
308  else
309  {
310  Q_ASSERT (i+2 < s_temp.size());
311 
312  unsigned char c = 0;
313  switch (s_temp[i+1])
314  {
315  case '0': c = 0 * 16; break;
316  case '1': c = 1 * 16; break;
317  case '2': c = 2 * 16; break;
318  case '3': c = 3 * 16; break;
319  case '4': c = 4 * 16; break;
320  case '5': c = 5 * 16; break;
321  case '6': c = 6 * 16; break;
322  case '7': c = 7 * 16; break;
323  case '8': c = 8 * 16; break;
324  case '9': c = 9 * 16; break;
325  case 'a': c = 10 * 16; break;
326  case 'b': c = 11 * 16; break;
327  case 'c': c = 12 * 16; break;
328  case 'd': c = 13 * 16; break;
329  case 'e': c = 14 * 16; break;
330  case 'f': c = 15 * 16; break;
331  default:
332  Q_ASSERT (false);
333  }
334  switch (s_temp[i+2])
335  {
336  case '0': c += 0; break;
337  case '1': c += 1; break;
338  case '2': c += 2; break;
339  case '3': c += 3; break;
340  case '4': c += 4; break;
341  case '5': c += 5; break;
342  case '6': c += 6; break;
343  case '7': c += 7; break;
344  case '8': c += 8; break;
345  case '9': c += 9; break;
346  case 'a': c += 10; break;
347  case 'b': c += 11; break;
348  case 'c': c += 12; break;
349  case 'd': c += 13; break;
350  case 'e': c += 14; break;
351  case 'f': c += 15; break;
352  default:
353  Q_ASSERT (false);
354  }
355 
356  u.push_back (static_cast<char>(c));
357 
358  // skip the two characters
359  i += 2;
360  }
361 
362  QString v (u.c_str());
363 
364  return v;
365  }
366  }
367 }
368 
QTreeWidgetItem * create_child_item(QTreeWidgetItem *item)
void read_parameter_element(QTreeWidgetItem *parent)
void read_subsection_element(QTreeWidgetItem *parent)