Don't keep compiling/run if something failed.
[kdevelopdvcssupport.git] / veritas / itestrunner.cpp
blob20bfa33f98b0acf03d9907411c5566c6c552c4ea
1 /*
2 * This file is part of KDevelop
3 * Copyright 2008 Manuel Breugelmans <mbr.nxi@gmail.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA.
21 // veritas
22 #include "itestrunner.h"
23 #include "itestframework.h"
24 #include "internal/toolviewdata.h"
25 #include "test.h"
26 #include "internal/selectionstore.h"
27 #include "ui_runnerwindow.h"
29 #include "internal/runnermodel.h"
30 #include "internal/resultsmodel.h"
31 #include "internal/runnerwindow.h"
33 // Qt - KDE
34 #include <KAboutData>
35 #include <KDebug>
36 #include <KSelectAction>
37 #include <QDockWidget>
38 #include <QWidget>
40 // kdevelop
41 #include "interfaces/icore.h"
42 #include "interfaces/iproject.h"
43 #include "interfaces/iprojectcontroller.h"
44 #include "interfaces/iuicontroller.h"
45 #include "sublime/area.h"
46 #include "sublime/controller.h"
47 #include "sublime/mainwindow.h"
48 #include "sublime/tooldocument.h"
49 #include "sublime/view.h"
51 Q_DECLARE_METATYPE(KDevelop::IProject*)
53 using Sublime::Area;
54 using Sublime::Document;
55 using Sublime::ToolDocument;
56 using Sublime::View;
58 using KDevelop::ICore;
59 using KDevelop::IProject;
60 using KDevelop::IProjectController;
61 using KDevelop::IToolViewFactory;
62 using KDevelop::IUiController;
64 using Veritas::Test;
65 using Veritas::RunnerModel;
66 using Veritas::RunnerWindow;
67 using Veritas::ResultsModel;
68 using Veritas::ITestRunner;
69 using Veritas::ITestFramework;
71 class ITestRunner::Private
73 public:
74 Private() :
75 window(0),
76 selectedProject(0),
77 resultsView(0),
78 resultsArea(0),
79 previousRoot(0)
82 ~Private() {
83 delete resultsModel;
86 RunnerWindow* window;
87 IProject* selectedProject;
88 Sublime::View *resultsView;
89 Sublime::Area *resultsArea;
90 ResultsModel *resultsModel;
91 Test* previousRoot;
92 ITestFramework* framework;
93 ITestRunner* self;
95 QString resultsViewId() const {
96 Q_ASSERT(g_toolViewStore.contains(framework));
97 ToolViewData& tvd = g_toolViewStore[framework];
98 int id = tvd.runner2id[self];
99 return QString("org.kdevelop.%1ResultsView%2").arg(framework->name()).arg(id);
104 ITestRunner::ITestRunner(ITestFramework* framework)
105 : QObject(0), d(new ITestRunner::Private)
107 d->self = this;
108 d->framework = framework;
109 Q_ASSERT(g_toolViewStore.contains(framework));
110 ToolViewData& tvd = g_toolViewStore[framework];
111 tvd.runner2id[this] = tvd.runnerToolCounter;
112 tvd.runnerToolCounter++;
114 QStringList resultHeaders;
115 resultHeaders << i18n("Test") << i18n("Message")
116 << i18n("File") << i18n("Line");
117 d->resultsModel = new ResultsModel(resultHeaders, this);
118 d->window = new RunnerWindow(d->resultsModel);
120 connect(this, SIGNAL(registerFinished(Veritas::Test*)),
121 this, SLOT(setupToolView(Veritas::Test*)));
124 void ITestRunner::setupToolView(Veritas::Test* root)
126 if (!root) { kDebug() << "root null"; return; }
127 if (d->previousRoot) {
128 SelectionStore ss;
129 ss.saveTree(d->previousRoot);
130 ss.restoreTree(root);
132 d->previousRoot = root;
133 RunnerModel* model = new RunnerModel;
134 model->setRootItem(root);
135 model->setExpectedResults(Veritas::RunError);
136 d->window->setModel(model);
137 d->window->runnerView()->setRootIsDecorated(false);
138 d->window->resetProgressBar();
139 if (!d->resultsView) spawnResultsView();
142 ITestRunner::~ITestRunner()
144 delete d;
147 QWidget* ITestRunner::resultsWidget()
149 return d->window->resultsWidget();
152 void ITestRunner::removeResultsView()
154 if (d->resultsView && d->resultsArea) {
155 d->resultsArea->removeToolView(d->resultsView);
159 QWidget* ITestRunner::runnerWidget()
161 IProjectController* ipc = ICore::self()->projectController();
162 foreach(IProject* proj, ipc->projects()) {
163 d->window->addProjectToPopup(proj);
165 connect(ipc, SIGNAL(projectOpened(KDevelop::IProject*)),
166 d->window, SLOT(addProjectToPopup(KDevelop::IProject*)));
167 connect(ipc, SIGNAL(projectClosed(KDevelop::IProject*)),
168 d->window, SLOT(rmProjectFromPopup(KDevelop::IProject*)));
170 connect(d->window->projectPopup(), SIGNAL(triggered(QAction*)),
171 this, SLOT(setSelected(QAction*)));
173 connect(d->window->ui()->actionReload, SIGNAL(triggered(bool)),
174 this, SLOT(reload()));
176 connect(d->window, SIGNAL(openVerbose(Veritas::Test*)),
177 this, SLOT(openVerbose(Veritas::Test*)));
178 reload();
179 return d->window;
183 /*! TODO rename this a bit. just make reload() pure virtual instead of registerTests */
184 void ITestRunner::reload()
186 registerTests(); // implemented by concrete plugins
189 IProject* ITestRunner::project() const
191 return d->selectedProject;
194 void ITestRunner::setSelected(QAction* action)
196 kDebug() << action->data().value<IProject*>();
197 d->selectedProject = action->data().value<IProject*>();
200 namespace {
201 class Filter : public QObject
203 public:
204 Filter(QObject* parent) : QObject(parent), m_parent(parent) {}
205 virtual ~Filter() {}
206 bool eventFilter(QObject* obj, QEvent* event) {
207 if (event->type() == QEvent::ContextMenu) return true;
208 if (m_parent) return m_parent->eventFilter(obj, event);
209 return false;
211 QObject* m_parent;
214 class ResultsViewFactory: public KDevelop::IToolViewFactory
216 public:
217 ResultsViewFactory(const QString& id, ITestRunner *runner): m_runner(runner), m_id(id) {}
219 virtual QWidget* create(QWidget *parent = 0) {
220 Q_UNUSED(parent);
221 return m_runner->resultsWidget();
222 // TODO this is bad. Currently only a single
223 // resultsWidget is ever created, which means
224 // that multiple resultsviews for a particular
225 // runnertoolview will segfault kdevelop.
226 // Introducing multiple resultViews requires
227 // changes in RunnerWindow. Luckily a user
228 // cannot close nor create multiple ones, so
229 // the situation above is impossible.
231 virtual Qt::DockWidgetArea defaultPosition() {
232 return Qt::BottomDockWidgetArea;
234 virtual QString id() const {
235 return m_id;
237 virtual void viewCreated(Sublime::View* view) {
238 QWidget* w = view->widget();
239 if (!w) return;
240 QObject* p = w->parent();
241 if (!p) return;
242 QDockWidget* d = qobject_cast<QDockWidget*>(p);
243 if (!d) return;
244 d->setFeatures(d->features() & 0xfffc);
245 Filter* f = new Filter(d);
246 d->installEventFilter(f);
249 private:
250 ITestRunner *m_runner;
251 QString m_id;
254 namespace
256 class UiToolViewFactory: public Sublime::ToolFactory
258 public:
259 UiToolViewFactory(IToolViewFactory *factory): m_factory(factory) {}
260 ~UiToolViewFactory() { delete m_factory; }
261 virtual QWidget* create(Sublime::ToolDocument *doc, QWidget *parent = 0) {
262 Q_UNUSED(doc);
263 return m_factory->create(parent);
265 QList<QAction*> toolBarActions(QWidget* viewWidget) const {
266 Q_UNUSED(viewWidget);
267 //return m_factory->toolBarActions(viewWidget);
268 return QList<QAction*>();
270 QString id() const { return m_factory->id(); }
272 private:
273 IToolViewFactory *m_factory;
277 class ResultsViewFinder
279 public:
280 ResultsViewFinder(const QString& id) : m_id(id), found(false) {}
281 Area::WalkerMode operator()(View *view, Sublime::Position position) {
282 Q_UNUSED(position);
283 Document* doc = view->document();
284 if (m_id == doc->documentSpecifier()) {
285 found = true;
286 return Area::StopWalker;
287 } else {
288 return Area::ContinueWalker;
291 QString m_id;
292 bool found;
295 void ITestRunner::spawnResultsView()
297 // only allow a single view.
298 IUiController* uic = ICore::self()->uiController();
299 Sublime::Controller* ctr = uic->controller();
300 foreach(Area* a, ctr->allAreas()) {
301 ResultsViewFinder rvf(d->resultsViewId());
302 a->walkToolViews(rvf, Sublime::AllPositions);
303 if (rvf.found) {
304 kDebug() << "Not adding twice, found a resultsview for this runner.";
305 return;
309 // these tool views should not show up in the 'Add Tool View' dialog.
310 // either use the ugly code below or fix this in UiController.
311 //uic->addToolView("Test Results", new ResultsViewFactory(resultsViewId(), this));
313 // this is bad. might want to make this available in IUiController
314 ResultsViewFactory* fac = new ResultsViewFactory(d->resultsViewId(), this);
315 QList<Sublime::MainWindow*> mws = ctr->mainWindows();
316 if (mws.isEmpty() || !mws[0]) {
317 kDebug() << "No mainwindow not adding results view.";
318 return;
321 Sublime::MainWindow* mw = mws[0]; // just take the first one.
322 d->resultsArea = mw->area();
323 ToolDocument *doc = new ToolDocument(QString("Test Results"), ctr, new UiToolViewFactory(fac));
324 d->resultsView = doc->createView();
325 Sublime::Position pos = Sublime::dockAreaToPosition(fac->defaultPosition());
326 d->resultsArea->addToolView(d->resultsView, pos);
327 connect(d->resultsView, SIGNAL(raise(Sublime::View*)),
328 ctr, SLOT(raiseToolView(Sublime::View*)));
329 fac->viewCreated(d->resultsView);
332 #include "itestrunner.moc"