• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdesdk API Reference
  • KDE Home
  • Contact Us
 

umbrello/umbrello

  • sources
  • kde-4.12
  • kdesdk
  • umbrello
  • umbrello
import_rose.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * This program is free software; you can redistribute it and/or modify *
3  * it under the terms of the GNU General Public License as published by *
4  * the Free Software Foundation; either version 2 of the License, or *
5  * (at your option) any later version. *
6  * *
7  * copyright (C) 2006-2013 *
8  * Umbrello UML Modeller Authors <umbrello-devel@kde.org> *
9  ***************************************************************************/
10 
11 // own header
12 #include "import_rose.h"
13 
14 // app includes
15 #include "debug_utils.h"
16 #include "petalnode.h"
17 #include "petaltree2uml.h"
18 
19 // kde includes
20 #include <klocale.h>
21 
22 // qt includes
23 #include <QMessageBox>
24 #include <QRegExp>
25 #include <QString>
26 #include <QStringList>
27 #include <QTextStream>
28 
29 namespace Import_Rose {
30 
31 uint nClosures; // Multiple closing parentheses may appear on a single
32  // line. The parsing is done line-by-line and using
33  // recursive descent. This means that we can only handle
34  // _one_ closing parenthesis at a time, i.e. the closing
35  // of the currently parsed node. Since we may see more
36  // closing parentheses than we can handle, we need a
37  // counter indicating how many additional node closings
38  // have been seen.
39 
40 uint linum; // line number
41 QString g_methodName;
42 
43 void methodName(const QString& m)
44 {
45  g_methodName = m;
46 }
47 
51 QString loc()
52 {
53  return "Import_Rose::" + g_methodName + " line " + QString::number(linum) + ": ";
54 }
55 
59 QStringList scan(const QString& lin)
60 {
61  QStringList result;
62  QString line = lin.trimmed();
63  if (line.isEmpty())
64  return result; // empty
65  QString lexeme;
66  const uint len = line.length();
67  bool inString = false;
68  for (uint i = 0; i < len; ++i) {
69  QChar c = line[i];
70  if (c == '"') {
71  lexeme += c;
72  if (inString) {
73  result.append(lexeme);
74  lexeme.clear();
75  }
76  inString = !inString;
77  } else if (inString ||
78  c.isLetterOrNumber() || c == '_' || c == '@') {
79  lexeme += c;
80  } else {
81  if (!lexeme.isEmpty()) {
82  result.append(lexeme);
83  lexeme.clear();
84  }
85  if (! c.isSpace()) {
86  result.append(QString(c));
87  }
88  }
89  }
90  if (!lexeme.isEmpty())
91  result.append(lexeme);
92  return result;
93 }
94 
98 QString shift(QStringList& l)
99 {
100  QString first = l.first();
101  l.pop_front();
102  return first;
103 }
104 
108 bool checkClosing(QStringList& tokens)
109 {
110  if (tokens.count() == 0)
111  return false;
112  if (tokens.last() == ")") {
113  // For a single closing parenthesis, we just return true.
114  // But if there are more closing parentheses, we need to increment
115  // nClosures for each scope.
116  tokens.pop_back();
117  while (tokens.count() && tokens.last() == ")") {
118  nClosures++;
119  tokens.pop_back();
120  }
121  return true;
122  }
123  return false;
124 }
125 
131 bool isImmediateValue(QString s)
132 {
133  return s.contains(QRegExp("^[\\d\\-\"]"));
134 }
135 
148 QString extractImmediateValues(QStringList& l)
149 {
150  if (l.count() == 0)
151  return QString();
152  if (l.first() == "(")
153  l.pop_front();
154  QString result;
155  bool start = true;
156  while (l.count() && isImmediateValue(l.first())) {
157  if (start)
158  start = false;
159  else
160  result += ' ';
161  result += shift(l);
162  if (l.first() == ",")
163  l.pop_front();
164  }
165  if (l.first() == ")")
166  l.pop_front();
167  while (l.count() && l.first() == ")") {
168  nClosures++;
169  l.pop_front();
170  }
171  return result;
172 }
173 
174 QString collectVerbatimText(QTextStream& stream)
175 {
176  QString result;
177  QString line;
178  methodName("collectVerbatimText");
179  while (!(line = stream.readLine()).isNull()) {
180  linum++;
181  line = line.trimmed();
182  if (line.isEmpty() || line.startsWith(')'))
183  break;
184  if (line[0] != '|') {
185  uError() << loc() << "expecting '|' at start of verbatim text";
186  return QString();
187  } else {
188  result += line.mid(1) + '\n';
189  }
190  }
191  if (line.isNull()) {
192  uError() << loc() << "premature EOF";
193  return QString();
194  }
195  if (! line.isEmpty()) {
196  for (int i = 0; i < line.length(); ++i) {
197  const QChar& clParenth = line[i];
198  if (clParenth != ')') {
199  uError() << loc() << "expected ')', found: " << clParenth;
200  return QString();
201  }
202  nClosures++;
203  }
204  }
205  return result;
206 }
207 
228 QString extractValue(QStringList& l, QTextStream& stream)
229 {
230  methodName("extractValue");
231  if (l.count() == 0)
232  return QString();
233  if (l.first() == "(")
234  l.pop_front();
235  if (l.first() != "value")
236  return QString();
237  l.pop_front(); // remove "value"
238  l.pop_front(); // remove the value type: could be e.g. "Text" or "cardinality"
239  QString result;
240  if (l.count() == 0) { // expect verbatim text to follow on subsequent lines
241  QString text = collectVerbatimText(stream);
242  nClosures--; // expect own closure
243  return text;
244  } else {
245  result = shift(l);
246  if (l.first() != ")") {
247  uError() << loc() << "expecting closing parenthesis";
248  return result;
249  }
250  l.pop_front();
251  }
252  while (l.count() && l.first() == ")") {
253  nClosures++;
254  l.pop_front();
255  }
256  return result;
257 }
258 
266 PetalNode *readAttributes(QStringList initialArgs, QTextStream& stream)
267 {
268  methodName("readAttributes");
269  if (initialArgs.count() == 0) {
270  uError() << loc() << "initialArgs is empty";
271  return NULL;
272  }
273  PetalNode::NodeType nt;
274  QString type = shift(initialArgs);
275  if (type == "object")
276  nt = PetalNode::nt_object;
277  else if (type == "list")
278  nt = PetalNode::nt_list;
279  else {
280  uError() << loc() << "unknown node type " << type;
281  return NULL;
282  }
283  PetalNode *node = new PetalNode(nt);
284  bool seenClosing = checkClosing(initialArgs);
285  node->setInitialArgs(initialArgs);
286  if (seenClosing)
287  return node;
288  PetalNode::NameValueList attrs;
289  QString line;
290  while (!(line = stream.readLine()).isNull()) {
291  linum++;
292  line = line.trimmed();
293  if (line.isEmpty())
294  continue;
295  QStringList tokens = scan(line);
296  QString stringOrNodeOpener = shift(tokens);
297  QString name;
298  if (nt == PetalNode::nt_object && !stringOrNodeOpener.contains(QRegExp("^[A-Za-z]"))) {
299  uError() << loc() << "unexpected line " << line;
300  return NULL;
301  }
302  PetalNode::StringOrNode value;
303  if (nt == PetalNode::nt_object) {
304  name = stringOrNodeOpener;
305  if (tokens.count() == 0) { // expect verbatim text to follow on subsequent lines
306  value.string = collectVerbatimText(stream);
307  PetalNode::NameValue attr(name, value);
308  attrs.append(attr);
309  if (nClosures) {
310  // Decrement nClosures exactly once, namely for the own scope.
311  // Each recursion of readAttributes() is only responsible for
312  // its own scope. I.e. each further scope closing is handled by
313  // an outer recursion in case of multiple closing parentheses.
314  nClosures--;
315  break;
316  }
317  continue;
318  }
319  stringOrNodeOpener = shift(tokens);
320  } else if (stringOrNodeOpener != "(") {
321  value.string = stringOrNodeOpener;
322  PetalNode::NameValue attr;
323  attr.second = value;
324  attrs.append(attr);
325  if (tokens.count() && tokens.first() != ")") {
326  uDebug() << loc()
327  << "NYI - immediate list entry with more than one item";
328  }
329  if (checkClosing(tokens))
330  break;
331  continue;
332  }
333  if (stringOrNodeOpener == "(") {
334  QString nxt = tokens.first();
335  if (isImmediateValue(nxt)) {
336  value.string = extractImmediateValues(tokens);
337  } else if (nxt == "value" || nxt.startsWith('\"')) {
338  value.string = extractValue(tokens, stream);
339  } else {
340  value.node = readAttributes(tokens, stream);
341  if (value.node == NULL)
342  return NULL;
343  }
344  PetalNode::NameValue attr(name, value);
345  attrs.append(attr);
346  if (nClosures) {
347  // Decrement nClosures exactly once, namely for the own scope.
348  // Each recursion of readAttributes() is only responsible for
349  // its own scope. I.e. each further scope closing is handled by
350  // an outer recursion in case of multiple closing parentheses.
351  nClosures--;
352  break;
353  }
354  } else {
355  value.string = stringOrNodeOpener;
356  bool seenClosing = checkClosing(tokens);
357  PetalNode::NameValue attr(name, value);
358  attrs.append(attr);
359  if (seenClosing) {
360  break;
361  }
362  }
363  }
364  node->setAttributes(attrs);
365  return node;
366 }
367 
374 bool loadFromMDL(QIODevice& file)
375 {
376  QTextStream stream(&file);
377  stream.setCodec("ISO 8859-1");
378  QString line;
379  PetalNode *root = NULL;
380  linum = 0;
381  while (!(line = stream.readLine()).isNull()) {
382  linum++;
383  if (line.contains(QRegExp("^\\s*\\(object Petal"))) {
384  bool finish = false;
385  while (!(line = stream.readLine()).isNull()) {
386  linum++; // CHECK: do we need petal version info?
387  if (line.contains(')')) {
388  finish = true;
389  line = line.replace(QLatin1String(")"),QLatin1String(""));
390  }
391  QStringList a = line.trimmed().split(QRegExp("\\s+"));
392  if (a.size() == 2) {
393  if (a[0] == "charSet" && a[1] == "134")
394  stream.setCodec("GB18030");
395  }
396  if (finish)
397  break;
398  }
399  if (line.isNull())
400  break;
401  } else {
402  QRegExp objectRx("^\\s*\\(object ");
403  if (line.contains(objectRx)) {
404  nClosures = 0;
405  QStringList initialArgs = scan(line);
406  initialArgs.pop_front(); // remove opening parenthesis
407  root = readAttributes(initialArgs, stream);
408  }
409  }
410  }
411  file.close();
412  if (root == NULL)
413  return false;
414  return petalTree2Uml(root);
415 }
416 
417 }
418 
petaltree2uml.h
Import_Rose::scan
QStringList scan(const QString &lin)
Split a line into lexemes.
Definition: import_rose.cpp:59
Import_Rose::shift
QString shift(QStringList &l)
Emulate perl shift().
Definition: import_rose.cpp:98
Import_Rose::isImmediateValue
bool isImmediateValue(QString s)
Immediate values are numbers or quoted strings.
Definition: import_rose.cpp:131
Import_Rose::checkClosing
bool checkClosing(QStringList &tokens)
Check for closing of one or more scopes.
Definition: import_rose.cpp:108
Import_Rose::linum
uint linum
Definition: import_rose.cpp:40
Import_Rose::extractValue
QString extractValue(QStringList &l, QTextStream &stream)
Extract the stripped down value from a (value ...) element.
Definition: import_rose.cpp:228
petalnode.h
PetalNode::NodeType
NodeType
Definition: petalnode.h:58
debug_utils.h
PetalNode
Rose petal node - parse tree for model import.
Definition: petalnode.h:39
import_rose.h
PetalNode::setAttributes
void setAttributes(NameValueList vl)
Definition: petalnode.cpp:57
PetalNode::setInitialArgs
void setInitialArgs(const QStringList &args)
Definition: petalnode.cpp:52
Import_Rose::loadFromMDL
bool loadFromMDL(QIODevice &file)
Parse a file into the PetalNode internal tree representation and then create Umbrello objects by trav...
Definition: import_rose.cpp:374
Import_Rose::nClosures
uint nClosures
Definition: import_rose.cpp:31
Import_Rose::readAttributes
PetalNode * readAttributes(QStringList initialArgs, QTextStream &stream)
Read attributes of a node.
Definition: import_rose.cpp:266
Import_Rose::g_methodName
QString g_methodName
Definition: import_rose.cpp:41
Import_Rose::loc
QString loc()
Auxiliary function for diagnostics: Return current location.
Definition: import_rose.cpp:51
uDebug
#define uDebug()
Definition: debug_utils.h:95
PetalNode::NameValue
QPair< QString, StringOrNode > NameValue
Definition: petalnode.h:55
Import_Rose::extractImmediateValues
QString extractImmediateValues(QStringList &l)
Extract immediate values out of `l'.
Definition: import_rose.cpp:148
Import_Rose::petalTree2Uml
bool petalTree2Uml(PetalNode *root)
This is really an auxiliary method for loadFromMDL() but is kept in a separate file to reflect that i...
Definition: petaltree2uml.cpp:601
PetalNode::nt_object
Definition: petalnode.h:58
Import_Rose::methodName
void methodName(const QString &m)
Definition: import_rose.cpp:43
Import_Rose::collectVerbatimText
QString collectVerbatimText(QTextStream &stream)
Definition: import_rose.cpp:174
uError
#define uError()
Definition: debug_utils.h:96
PetalNode::StringOrNode
Use `string' if it is not empty.
Definition: petalnode.h:48
PetalNode::StringOrNode::node
PetalNode * node
Definition: petalnode.h:50
PetalNode::NameValueList
QList< NameValue > NameValueList
Definition: petalnode.h:56
PetalNode::nt_list
Definition: petalnode.h:58
PetalNode::StringOrNode::string
QString string
Definition: petalnode.h:49
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 23:05:59 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

umbrello/umbrello

Skip menu "umbrello/umbrello"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdesdk API Reference

Skip menu "kdesdk API Reference"
  • kapptemplate
  • kcachegrind
  • kompare
  • lokalize
  • okteta
  • umbrello
  •   umbrello

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal