Showing posts with label qt. Show all posts
Showing posts with label qt. Show all posts

Monday, May 27, 2013

Simple tool to visualize connections between signals and slots in Qt

This very simple and stupid tool visualizes connections between signals and slots and signals and signals in Qt. It takes one command line parameter namely the path to the project which should get visualized. From this path it goes down recursively and parses every *.cxx, *.cpp, *.hxx and *.hpp file if it can find a connection with the following signature

connect\s*\((.+)\s*,\s*SIGNAL\((.+)\)\s*,\s*(.+)\s*,\s*(?:SLOT|SIGNAL)\((.+)\)\s*\)\s*\)

If it finds this signature (comments count as well) it generates a DOT (http://www.graphviz.org/) file. This graph can be visualized for example here or the command line tools generate an image. Because DOT tries to minimize the height of the graph a sightly better result can be achieved with the command line from here.
The this keyword will be replaced by the file name because otherwise DOT would connect all of them. The label of the edge is the signal in the first line and the slot (or signal) in the second one.

#include <QString>
#include <QDir>
#include <QDebug>
#include <QFileInfo>
#include <QFileInfoList>
#include <QIODevice>
#include <iostream>

void IterateDirs(QDir dir);

int main(int argc,char* argv[])
{
  bool foundSite = false;
  QString site;
  for(int i = 1; i < argc; ++i)
  {
    if(std::string(argv[i]) == "--path" || std::string(argv[i]) == "-p")
    {
      ++i;
      if (i < argc)
        site = argv[i];
      else
        break;
      foundSite = true;
      continue;
    }
  }
  if (argc < 3 || !foundSite)
  {
    std::cerr << "Usage: ConVis --path <projectpath>" << std::endl;
    return EXIT_FAILURE;
  }
  QDir dir(site);
  std::cout << "digraph connections {\nconstraint=\"false\" minlen=2\n";
  IterateDirs(dir);
  std::cout << "}\n";
  return EXIT_SUCCESS;
}

int i = 0;

void IterateDirs(QDir dir)
{
  QStringList filter;
  filter << "*.cxx" << "*.hxx" << "*.cpp" << "*.hpp";
  QFileInfoList files = dir.entryInfoList(filter, QDir::AllDirs |
                                          QDir::NoDotAndDotDot | QDir::Files);
  QFileInfoList::const_iterator it = files.constBegin();
  QFileInfoList::const_iterator en = files.constEnd();
  while (it != en)
  {
    QFileInfo info = *it;
    //qDebug() << info.isDir() << info.absoluteFilePath() << info.isFile();
    if (info.isDir())
      IterateDirs(QDir(info.absoluteFilePath()));
    else if (info.isFile())
    {
      QFile f(info.absoluteFilePath());
      f.open(QIODevice::ReadOnly);
      QString content = f.readAll();
      f.close();
      QRegExp r("connect\\s*\\((.+)\\s*,\\s*SIGNAL\\((.+)\\)\\s*,\\s*(.+)\\s*,"
                "\\s*(?:SLOT|SIGNAL)\\((.+)\\)\\s*\\)\\s*\\)");
      r.setMinimal(true);
      bool output = r.indexIn(content) != -1;
      if (output)
        std::cout << "subgraph cluster_" << i << "{\n";
      while (r.indexIn(content) != -1)
      {
        //qDebug() << r.capturedTexts();
        QStringList l = r.capturedTexts();
        if (l.at(1).trimmed() == "this")
          l.replace(1, info.fileName());
        if (l.at(3).trimmed() == "this")
          l.replace(3, info.fileName());
        std::cout << "\"" << l.at(1).trimmed().toStdString() << "\" -> \""
                          << l.at(3).trimmed().toStdString()
                          << "\" [color=\"green\"" << " label=\""
                          << l.at(2).trimmed().toStdString() << "\\n"
                          << l.at(4).trimmed().append(")").toStdString()
                          << "\" style=\"solid\" labeldistance=2];\n";
        content = content.mid(r.indexIn(content) + r.matchedLength());
      }
      if (output)
        std::cout << "label=\"" << info.fileName().toStdString() << "\"\n}\n";
      ++i;
    }
    ++it;
  }
}

Sunday, October 30, 2011

Class generator out of JSON definitions

This is my first tool I like to offer. I started to write a Plasma Widget (Plasmoids) which is able to show my streams of Google+ on my Desktop. Unfortunately Google does not have an API for C++. It would be possible to write the Plasmoids in other languages like Python but because my knowledge of Python is very poor I decided to use C++. The data from Google+ is provided as JSON objects. Therefore I needed a compiler which is able to generates classes directly from the definition from Google+. For example the definition for a comment looks like that:

{
  "kind": "plus#comment",
  "id": string,
  "published": datetime,
  "updated": datetime,
  "actor": {
    "id": string,
    "displayName": string,
    "url": string,
    "image": {
      "url": string
    }
  },
  "verb": "post",
  "object": {
    "objectType": "comment",
    "content": string
  },
  "selfLink": string,
  "inReplyTo": [
    {
      "id": string,
      "url": string
    }
  ]
}

The tool is now able to create objects out of this definition and of course out of all other definitions similar to that. It is possible to generate classes for Qt and Java. It should be easy to extend this to other languages without very much effort.
The tool uses JavaCC to parse the JSON definition.

If something has to be changed on the grammar rules, I recommend the Eclipse plugin for JavaCC which one can find at http://eclipse-javacc.sourceforge.net/ If one just needs to add other languages there is no need for JavaCC and all changes can be done directly in the Java sources.

To use the tool, download the jar file from http://141.3.80.191/~mehrwald/JSONClassGenerator.jar
In the command line type:
java -jar JSONClassGenerator.jar <FileToParse> <ObjectName> <PathToSave> (Qt|Java) [<FileToParse> <ObjectName> <PathToSave> (Qt|Java)...]

If one needs to change something or add another language please find the sources at http://141.3.80.191/~mehrwald/JSONClassGenerator_src.zip

I would appreciate all sorts of comments to this tool. If you have questions do not hesitate to ask me.