QxRunner Library Version 0.9.2
QxRunner Library: Examples

Examples

The demo program shipped with the QxRunner library can be used as the starting point for developping a QxRunner based program. It subclasses RunnerModel and RunnerItem and uses a Runner instance in the main program to launch the GUI. The model constructs a tree structure of runner items which randomly generate a result of type QxRunner::RunnerResult. An item also reports the location of where in the code the result was created and supplies a related result message.

See also:
For a deeper insight into the details of the model/view framework and how to create a basic model to use with Qt's standard view classes see the Simple Tree Model Example provided with the Qt installation. And, yes, much of this example documentation uses slightly modified text from that Qt example.

The Demo Model

Demo Model Header File

The constructor takes an argument containing the data that the model will share with views. The name() method returns the model name used by QxRunner for display in the about box and as the identifier for the settings file. The model's internal data structure is populated with DemoItem instances by the setupModelData() helper method. The model isn't designed to add data to the model after it is constructed and set up.

00001 #ifndef DEMOMODEL_H
00002 #define DEMOMODEL_H
00003 
00004 #include <qxrunner/runnermodel.h>
00005 #include <QStringList>
00006 
00007 using namespace QxRunner;
00008 
00009 class DemoModel : public RunnerModel
00010 {
00011     Q_OBJECT
00012 
00013 public:  // Operations
00014 
00015     DemoModel(const QStringList& data, QObject* parent = 0);
00016 
00017     ~DemoModel();
00018 
00019     QString name() const;
00020     
00021 private:  // Operations
00022 
00023     void setupModelData(const QStringList& itemList, RunnerItem* parent);
00024 };
00025 
00026 #endif // DEMOMODEL_H

Demo Model Implementation File

The constructor creates the root item for the model. This item only contains horizontal header data. It is also used to reference the internal data structure that contains the model data, and it is used to represent an imaginary parent of top-level items in the model. The model's internal data structure is populated with items by the setupModelData() function. The destructor does nothing, it relies on the parent RunnerModel destructor who deletes the root item and all of its descendants when the model is destroyed.

The setupModelData() method sets up the initial data in the model. It iterates over a list of 'keywords' which define the position of an item in the tree strucuture and the related item name. Of course this is a very simple model and is only intended for demonstrational purposes.

The keyword meanings are:

00001 #include "demomodel.h"
00002 #include "demoitem.h"
00003 
00004 DemoModel::DemoModel(const QStringList& data, QObject* parent)
00005          : RunnerModel(parent)
00006 {
00007     // Data for column headers is stored in the root item.
00008     QList<QVariant> rootData;
00009     rootData << tr("Item Name") << tr("Result") << tr("Message")
00010              << tr("File Name") << tr("Line Number");
00011 
00012     setRootItem(new DemoItem(rootData));
00013 
00014     // Fill the model items.
00015     setupModelData(data, rootItem());
00016 }
00017 
00018 DemoModel::~DemoModel()
00019 {
00020     // Remove destructor if it doesn't class specific cleanup.
00021 }
00022 
00023 QString DemoModel::name() const
00024 {
00025     return tr("Demo");
00026 }
00027 
00028 void DemoModel::setupModelData(const QStringList& itemList, RunnerItem* parent)
00029 {
00030     QList<DemoItem*> parents;
00031 
00032     DemoItem* item;
00033     QString token;
00034     QList<QVariant> columnData;
00035 
00036     QList<QString>::const_iterator it = itemList.constBegin();
00037 
00038     for (; it != itemList.constEnd(); ++it)
00039     {
00040         token = *it;
00041 
00042         // First column has the item name, remaining columns are empty.
00043         it++;
00044         columnData.clear();
00045         columnData << *it;
00046 
00047         // Note: Appending empty columns is not needed since the runner
00048         // item constructor takes care of it.
00049         // -> columnData << "" << "" << "" << "";       
00050 
00051         if (token == "L0")
00052         {
00053             item = new DemoItem(columnData, parent);
00054             parent->appendChild(item);
00055 
00056             parents.clear();
00057             parents << item;
00058         }
00059         else if (token == "CH")
00060         {
00061             parents.last()->appendChild(new DemoItem(columnData, parents.last()));
00062         }
00063         else if (token == "L1")
00064         {
00065             item = parents.first();
00066             parents.clear();
00067             parents << item;
00068 
00069             item = new DemoItem(columnData, parents.last());
00070             parents.last()->appendChild(item);
00071 
00072             parents << item;
00073         }
00074         else
00075         {
00076             item = new DemoItem(columnData, parents.last());
00077             parents.last()->appendChild(item);
00078 
00079             parents << item;
00080         }
00081     }
00082 }

The Demo Item

Demo Item Header File

The constructor is used to record the item's parent and the data associated with each column. The abstract run() method from the parent RunnerItem class must be reimplemented and contains the custom code that gets executed when the items are run by QxRunner.

00001 #ifndef DEMOITEM_H
00002 #define DEMOITEM_H
00003 
00004 #include <qxrunner/runneritem.h>
00005 
00006 using namespace QxRunner;
00007 
00008 class DemoItem : public RunnerItem
00009 {
00010 public: // Operations
00011 
00012     DemoItem(const QList<QVariant>& data, RunnerItem* parent = 0);
00013     
00014     ~DemoItem();
00015 
00016     int run();
00017 };
00018 
00019 #endif // DEMOITEM_H

Demo Item Implementation File

The constructor simply calls the parent RunnerItem constructor. The destructor does nothing, it relies on the parent RunnerItem destructor who ensures that all child items get deleted.

The run() method first checks whether it is a parent item or not (see The Runner Model). Only leafs have custom logic for execution. If it is a child the method randomly creates a result type and fills related data into the item columns. A special case is the unhandled exception which gets caught by the model. The commented out code at the beginning was used during development to slow down item execution.

00001 #include "demoitem.h"
00002 
00003 #include <QCoreApplication>
00004 #include <stdlib.h>
00005 
00006 DemoItem::DemoItem(const QList<QVariant>& data, RunnerItem* parent)
00007         : RunnerItem(data, parent)
00008 {
00009 
00010 }
00011 
00012 DemoItem::~DemoItem()
00013 {
00014     // Remove destructor if it doesn't class specific cleanup.
00015 }
00016 
00017 int DemoItem::run()
00018 {
00019     if (child(0))
00020     {
00021         return QxRunner::NoResult;  // Have nothing to do as a parent
00022     }
00023 
00024     //Mimick some processing.
00025     //for (int i = 0; i < 30000; i++)
00026     //{
00027     //  QCoreApplication::processEvents();
00028     //}
00029 
00030     QString msg;
00031     QString line;
00032 
00033     // Randomly generated result.
00034     switch (rand() % 6)
00035     {
00036         case 0:
00037             msg = "Run completed successfully.";
00038             line.setNum(__LINE__);
00039             setResult(QxRunner::RunSuccess);
00040             break;
00041 
00042         case 1:
00043             msg = "Run completed with an information.";
00044             line.setNum(__LINE__);
00045             setResult(QxRunner::RunInfo);
00046             break;
00047 
00048         case 2:
00049             msg = "Run completed with a warning.";
00050             line.setNum(__LINE__);
00051             setResult(QxRunner::RunWarning);
00052             break;
00053 
00054         case 3:
00055             msg = "Run completed with an error.";
00056             line.setNum(__LINE__);
00057             setResult(QxRunner::RunError);
00058             break;
00059 
00060         case 4:
00061             msg = "Run completed with a fatal error.";
00062             line.setNum(__LINE__);
00063             setResult(QxRunner::RunFatal);
00064             break;
00065 
00066         case 5:
00067             // This gets caught by the caller as a fallback, but actually
00068             // all exceptions should get handled in the run() method.
00069             throw 0;
00070             break;
00071     }
00072 
00073     // Fill item with resulting data.
00074     setData(2, msg);
00075     setData(3, __FILE__);
00076     setData(4, line);
00077 
00078     return result();
00079 }

The Demo Main Program

The main program is straightforward:

00001 #include "demomodel.h"
00002 
00003 #include <QApplication>
00004 #include <qxrunner/runner.h>
00005 
00006 QStringList demoItems();            // Helper function
00007 
00008 int main(int argc, char *argv[])
00009 {
00010     QApplication app(argc, argv);
00011 
00012     DemoModel model(demoItems());   // Setup the data
00013 
00014     QxRunner::Runner runner(&model);
00015     runner.run();
00016 
00017     return 0;
00018 }
00019 
00020 // Creates a list of items for the model.
00021 QStringList demoItems()
00022 {
00023     QStringList itemList;
00024 
00025     itemList << "L0" << "Group 1";
00026     itemList << "CH" << "Demo item 1a";
00027     itemList << "CH" << "Demo item 1b";
00028     itemList << "CH" << "Demo item 1c";
00029     itemList << "CH" << "Demo item 1d";
00030 
00031     itemList << "L0" << "Group 2";
00032     itemList << "CH" << "Demo item 2a";
00033     itemList << "CH" << "Demo item 2b";
00034     itemList << "CH" << "Demo item 2c";
00035     itemList << "CH" << "Demo item 2d";
00036 
00037     itemList << "L0" << "Group 3";
00038     itemList << "CH" << "Demo item 3a";
00039     itemList << "CH" << "Demo item 3b";
00040     itemList << "CH" << "Demo item 3c";
00041     itemList << "CH" << "Demo item 3d";
00042 
00043     itemList << "L1" << "Group 3.1";
00044     itemList << "CH" << "Demo item 3.1a";
00045     itemList << "CH" << "Demo item 3.1b";
00046     itemList << "CH" << "Demo item 3.1c";
00047     itemList << "CH" << "Demo item 3.1d";
00048 
00049     itemList << "L2" << "Group 3.1.1";
00050     itemList << "CH" << "Demo item 3.1.1a";
00051     itemList << "CH" << "Demo item 3.1.1b";
00052     itemList << "CH" << "Demo item 3.1.1c";
00053     itemList << "CH" << "Demo item 3.1.1d";
00054 
00055     itemList << "L2" << "Group 3.2";
00056     itemList << "CH" << "Demo item 3.2a";
00057     itemList << "CH" << "Demo item 3.2b";
00058     itemList << "CH" << "Demo item 3.2c";
00059     itemList << "CH" << "Demo item 3.2d";
00060 
00061     itemList << "L3" << "Group 3.2.1";
00062     itemList << "CH" << "Demo item 3.2.1a";
00063     itemList << "CH" << "Demo item 3.2.1b";
00064     itemList << "CH" << "Demo item 3.2.1c";
00065     itemList << "CH" << "Demo item 3.2.1d";
00066 
00067     itemList << "L0" << "Demo item 4";
00068 
00069     itemList << "L0" << "Group 5";
00070     itemList << "CH" << "Demo item 5a";
00071     itemList << "CH" << "Demo item 5b";
00072     itemList << "CH" << "Demo item 5c";
00073     itemList << "CH" << "Demo item 5d";
00074 
00075     itemList << "L0" << "Demo item 6";
00076     itemList << "L0" << "Demo item 7";
00077 
00078     return itemList;
00079 }