umbrello API Documentation

import_rose.cpp

00001 /***************************************************************************
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  *   copyright (C) 2006                                                    *
00009  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00010  ***************************************************************************/
00011 
00012 // own header
00013 #include "import_rose.h"
00014 
00015 // qt includes
00016 #include <qstring.h>
00017 #include <qtextstream.h>
00018 #include <qptrlist.h>
00019 #include <qstringlist.h>
00020 #include <qregexp.h>
00021 #include <qmessagebox.h>
00022 #include <klocale.h>
00023 #include <kdebug.h>
00024 // app includes
00025 #include "petalnode.h"
00026 #include "petaltree2uml.h"
00027 #include "umlnamespace.h"  // only for the KDE4 compatibility macros
00028 
00029 namespace Import_Rose {
00030 
00031 typedef QPtrList<PetalNode> PetalNodeList;
00032 
00033 uint nClosures; // Multiple closing parentheses may appear on a single
00034                 // line. The parsing is done line-by-line and using
00035                 // recursive descent. This means that we can only handle
00036                 // _one_ closing parenthesis at a time, i.e. the closing
00037                 // of the currently parsed node. Since we may see more
00038                 // closing parentheses than we can handle, we need a
00039                 // counter indicating how many additional node closings
00040                 // have been seen.
00041 
00042 uint linum;  // line number
00043 QString g_methodName;
00044 void methodName(const QString& m) {
00045     g_methodName = m;
00046 }
00050 QString loc() {
00051     return "Import_Rose::" + g_methodName + " line " + QString::number(linum) + ": ";
00052 }
00053 
00057 QStringList scan(const QString& lin) {
00058     QStringList result;
00059     QString line = lin.stripWhiteSpace();
00060     if (line.isEmpty())
00061         return result;  // empty
00062     QString lexeme;
00063     const uint len = line.length();
00064     bool inString = false;
00065     for (uint i = 0; i < len; i++) {
00066         QChar c = line[i];
00067         if (c == '"') {
00068             lexeme += c;
00069             if (inString) {
00070                 result.append(lexeme);
00071                 lexeme = QString::null;
00072             }
00073             inString = !inString;
00074         } else if (inString ||
00075                    c.isLetterOrNumber() || c == '_' || c == '@') {
00076             lexeme += c;
00077         } else {
00078             if (!lexeme.isEmpty()) {
00079                 result.append(lexeme);
00080                 lexeme = QString::null;
00081             }
00082             if (! c.isSpace()) {
00083                 result.append(QString(c));
00084             }
00085         }
00086     }
00087     if (!lexeme.isEmpty())
00088         result.append(lexeme);
00089     return result;
00090 }
00091 
00095 QString shift(QStringList& l) {
00096     QString first = l.first();
00097     l.pop_front();
00098     return first;
00099 }
00100 
00104 bool checkClosing(QStringList& tokens) {
00105     if (tokens.count() == 0)
00106         return false;
00107     if (tokens.last() == ")") {
00108         // For a single closing parenthesis, we just return true.
00109         // But if there are more closing parentheses, we need to increment
00110         // nClosures for each scope.
00111         tokens.pop_back();
00112         while (tokens.count() && tokens.last() == ")") {
00113             nClosures++;
00114             tokens.pop_back();
00115         }
00116         return true;
00117     }
00118     return false;
00119 }
00120 
00126 bool isImmediateValue(QString s) {
00127     return s.contains(QRegExp("^[\\d\\-\"]"));
00128 }
00129 
00142 QString extractImmediateValues(QStringList& l) {
00143     if (l.count() == 0)
00144         return QString::null;
00145     if (l.first() == "(")
00146         l.pop_front();
00147     QString result;
00148     bool start = true;
00149     while (l.count() && isImmediateValue(l.first())) {
00150         if (start)
00151             start = false;
00152         else
00153             result += ' ';
00154         result += shift(l);
00155         if (l.first() == ",")
00156             l.pop_front();
00157     }
00158     if (l.first() == ")")
00159         l.pop_front();
00160     while (l.count() && l.first() == ")") {
00161         nClosures++;
00162         l.pop_front();
00163     }
00164     return result;
00165 }
00166 
00167 QString collectVerbatimText(QTextStream& stream) {
00168     QString result;
00169     QString line;
00170     methodName("collectVerbatimText");
00171     while (!(line = stream.readLine()).isNull()) {
00172         linum++;
00173         line = line.stripWhiteSpace();
00174         if (line.isEmpty() || line.startsWith(")"))
00175             break;
00176         if (line[0] != '|') {
00177             kError() << loc() << "expecting '|' at start of verbatim text" << endl;
00178             return QString::null;
00179         } else {
00180             result += line.mid(1) + "\n";
00181         }
00182     }
00183     if (line.isNull()) {
00184         kError() << loc() << "premature EOF" << endl;
00185         return QString::null;
00186     }
00187     if (! line.isEmpty()) {
00188         for (uint i = 0; i < line.length(); i++) {
00189             const QChar& clParenth = line[i];
00190             if (clParenth != ')') {
00191                 kError() << loc() << "expected ')', found: " << clParenth << endl;
00192                 return QString::null;
00193             }
00194             nClosures++;
00195         }
00196     }
00197     return result;
00198 }
00199 
00220 QString extractValue(QStringList& l, QTextStream& stream) {
00221     methodName("extractValue");
00222     if (l.count() == 0)
00223         return QString::null;
00224     if (l.first() == "(")
00225         l.pop_front();
00226     if (l.first() != "value")
00227         return QString::null;
00228     l.pop_front();  // remove "value"
00229     l.pop_front();  // remove the value type: could be e.g. "Text" or "cardinality"
00230     QString result;
00231     if (l.count() == 0) {  // expect verbatim text to follow on subsequent lines
00232         QString text = collectVerbatimText(stream);
00233         nClosures--;  // expect own closure
00234         return text;
00235     } else {
00236         result = shift(l);
00237         if (l.first() != ")") {
00238             kError() << loc() << "expecting closing parenthesis" << endl;
00239             return result;
00240         }
00241         l.pop_front();
00242     }
00243     while (l.count() && l.first() == ")") {
00244         nClosures++;
00245         l.pop_front();
00246     }
00247     return result;
00248 }
00249 
00257 PetalNode *readAttributes(QStringList initialArgs, QTextStream& stream) {
00258     methodName("readAttributes");
00259     if (initialArgs.count() == 0) {
00260         kError() << loc() << "initialArgs is empty" << endl;
00261         return NULL;
00262     }
00263     PetalNode::NodeType nt;
00264     QString type = shift(initialArgs);
00265     if (type == "object")
00266         nt = PetalNode::nt_object;
00267     else if (type == "list")
00268         nt = PetalNode::nt_list;
00269     else {
00270         kError() << loc() << "unknown node type " << type << endl;
00271         return NULL;
00272     }
00273     PetalNode *node = new PetalNode(nt);
00274     bool seenClosing = checkClosing(initialArgs);
00275     node->setInitialArgs(initialArgs);
00276     if (seenClosing)
00277         return node;
00278     PetalNode::NameValueList attrs;
00279     QString line;
00280     while (!(line = stream.readLine()).isNull()) {
00281         linum++;
00282         line = line.stripWhiteSpace();
00283         if (line.isEmpty())
00284             continue;
00285         QStringList tokens = scan(line);
00286         QString stringOrNodeOpener = shift(tokens);
00287         QString name;
00288         if (nt == PetalNode::nt_object && !stringOrNodeOpener.contains(QRegExp("^[A-Za-z]"))) {
00289             kError() << loc() << "unexpected line " << line << endl;
00290             return NULL;
00291         }
00292         PetalNode::StringOrNode value;
00293         if (nt == PetalNode::nt_object) {
00294             name = stringOrNodeOpener;
00295             if (tokens.count() == 0) {  // expect verbatim text to follow on subsequent lines
00296                 value.string = collectVerbatimText(stream);
00297                 PetalNode::NameValue attr(name, value);
00298                 attrs.append(attr);
00299                 if (nClosures) {
00300                     // Decrement nClosures exactly once, namely for the own scope.
00301                     // Each recursion of readAttributes() is only responsible for
00302                     // its own scope. I.e. each further scope closing is handled by
00303                     // an outer recursion in case of multiple closing parentheses.
00304                     nClosures--;
00305                     break;
00306                 }
00307                 continue;
00308             }
00309             stringOrNodeOpener = shift(tokens);
00310         } else if (stringOrNodeOpener != "(") {
00311             value.string = stringOrNodeOpener;
00312             PetalNode::NameValue attr(QString::null, value);
00313             attrs.append(attr);
00314             if (tokens.count() && tokens.first() != ")") {
00315                 kDebug() << loc()
00316                     << "NYI - immediate list entry with more than one item" << endl;
00317             }
00318             if (checkClosing(tokens))
00319                 break;
00320             continue;
00321         }
00322         if (stringOrNodeOpener == "(") {
00323             QString nxt = tokens.first();
00324             if (isImmediateValue(nxt)) {
00325                 value.string = extractImmediateValues(tokens);
00326             } else if (nxt == "value" || nxt.startsWith("\"")) {
00327                 value.string = extractValue(tokens, stream);
00328             } else {
00329                 value.node = readAttributes(tokens, stream);
00330                 if (value.node == NULL)
00331                     return NULL;
00332             }
00333             PetalNode::NameValue attr(name, value);
00334             attrs.append(attr);
00335             if (nClosures) {
00336                 // Decrement nClosures exactly once, namely for the own scope.
00337                 // Each recursion of readAttributes() is only responsible for
00338                 // its own scope. I.e. each further scope closing is handled by
00339                 // an outer recursion in case of multiple closing parentheses.
00340                 nClosures--;
00341                 break;
00342             }
00343         } else {
00344             value.string = stringOrNodeOpener;
00345             bool seenClosing = checkClosing(tokens);
00346             PetalNode::NameValue attr(name, value);
00347             attrs.append(attr);
00348             if (seenClosing) {
00349                 break;
00350             }
00351         }
00352     }
00353     node->setAttributes(attrs);
00354     return node;
00355 }
00356 
00357 bool loadFromMDL(QIODevice& file) {
00358     QTextStream stream(&file);
00359     QString line;
00360     PetalNode *root = NULL;
00361     linum = 0;
00362     while (!(line = stream.readLine()).isNull()) {
00363         linum++;
00364         if (line.contains( QRegExp("^\\s*\\(object Petal") )) {
00365             while (!(line = stream.readLine()).isNull() && !line.contains(')')) {
00366                 linum++; // CHECK: do we need petal version info?
00367             }
00368             if (line.isNull())
00369                 break;
00370         } else {
00371             QRegExp objectRx("^\\s*\\(object ");
00372             if (line.contains(objectRx)) {
00373                 nClosures = 0;
00374                 QStringList initialArgs = scan(line);
00375                 initialArgs.pop_front();  // remove opening parenthesis
00376                 root = readAttributes(initialArgs, stream);
00377             }
00378         }
00379     }
00380     file.close();
00381     if (root == NULL)
00382         return false;
00383     return petalTree2Uml(root);
00384 }
00385 
00386 }
00387 
KDE Logo
This file is part of the documentation for umbrello Version 3.1.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 26 08:07:57 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003