1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QCloseEvent>
43 #include <QFileDialog>
45 #include <QHeaderView>
47 #include <QMessageBox>
50 #include <QTextStream>
53 #include "FunctionSignaturesView.h"
55 #include "TestCaseView.h"
56 #include "TestResultView.h"
57 #include "TestSuite.h"
58 #include "TreeModel.h"
59 #include "TreeSortFilter.h"
60 #include "UserTestCase.h"
62 #include "MainWindow.h"
64 using namespace QPatternistSDK;
66 MainWindow::MainWindow() : m_userTC(new UserTestCase()),
71 /* I want to do this in Designer.. */
72 testSuiteView->header()->setSortIndicator(0, Qt::AscendingOrder);
73 testSuiteView->header()->setSortIndicatorShown(true);
74 testSuiteView->header()->setClickable(true);
78 QStringList suiteHeaders;
79 suiteHeaders << QLatin1String("Name")
80 << QLatin1String("Pass")
81 << QLatin1String("Fail")
82 << QLatin1String("Total");
84 TreeSortFilter *const proxy = new TreeSortFilter(this);
85 connect(searchInput, SIGNAL(textChanged(const QString &)),
86 proxy, SLOT(setFilterFixedString(const QString &)));
88 proxy->setSourceModel(new TreeModel(suiteHeaders, this));
89 testSuiteView->setModel(proxy);
91 /* --------- Test Result View ---------- */
92 testResultView = new TestResultView(this);
93 testResultView->setAllowedAreas(Qt::AllDockWidgetAreas);
94 addDockWidget(Qt::RightDockWidgetArea, testResultView);
95 /* ----------------------------------- */
97 /* --------- Test Case View ---------- */
98 testCaseView = new TestCaseView(this);
99 testCaseView->setAllowedAreas(Qt::AllDockWidgetAreas);
100 addDockWidget(Qt::LeftDockWidgetArea, testCaseView);
102 connect(this, SIGNAL(testCaseSelected(TestCase *const)),
103 testCaseView, SLOT(displayTestCase(TestCase *const)));
104 connect(this, SIGNAL(testCaseSelected(TestCase *const)),
105 testResultView, SLOT(displayTestResult(TestCase *const)));
106 connect(focusURI, SIGNAL(textChanged(const QString &)),
107 m_userTC, SLOT(focusDocumentChanged(const QString &)));
108 /* ----------------------------------- */
110 /* ----- Function Signature View ----- */
111 functionView = new FunctionSignaturesView(this);
112 functionView->setAllowedAreas(Qt::AllDockWidgetAreas);
113 addDockWidget(Qt::RightDockWidgetArea, functionView);
114 /* ----------------------------------- */
116 /* Appears here, because the menu uses actions in the QDockWidgets. */
121 /* Connect this after readSettings(), otherwise readSettings() triggers writeSettings(). */
122 connect(sourceTab, SIGNAL(currentChanged(int)),
123 SLOT(writeSettings()));
124 connect(testSuiteView, SIGNAL(clicked(const QModelIndex &)),
125 SLOT(writeSettings()));
126 connect(sourceInput, SIGNAL(textChanged()),
127 SLOT(writeSettings()));
130 MainWindow::~MainWindow()
135 QModelIndex MainWindow::sourceIndex(const QModelIndex &proxyIndex) const
137 return static_cast<TreeSortFilter *>(testSuiteView->model())->mapToSource(proxyIndex);
140 TreeModel *MainWindow::sourceModel() const
142 const TreeSortFilter *const proxy = static_cast<TreeSortFilter *>(testSuiteView->model());
143 return static_cast<TreeModel *>(proxy->sourceModel());
146 void MainWindow::on_testSuiteView_clicked(const QModelIndex &index)
150 TestItem *const node = static_cast<TestItem *>(sourceIndex(index).internalPointer());
153 if(node->isFinalNode())
155 m_currentTC = static_cast<TestCase *>(node);
156 testCaseSelected(m_currentTC);
161 /* In all other cases: */
166 void MainWindow::on_sourceInput_textChanged()
168 m_userTC->setSourceCode(sourceInput->toPlainText());
171 void MainWindow::on_actionOpen_triggered()
173 const QString fileName(QFileDialog::getOpenFileName(this,
174 QLatin1String("Open Test Suite Catalog"),
175 m_previousOpenedCatalog.toLocalFile(),
176 QLatin1String("Test Suite Catalog file (*.xml)")));
178 /* "If the user presses Cancel, it returns a null string." */
179 if(fileName.isNull())
182 m_currentSuiteType = TestSuite::XQuerySuite;
183 openCatalog(QUrl::fromLocalFile(fileName), true, TestSuite::XQuerySuite);
186 void MainWindow::on_actionOpenXSLTSCatalog_triggered()
188 const QString fileName(QFileDialog::getOpenFileName(this,
189 QLatin1String("Open Test Suite Catalog"),
190 m_previousOpenedCatalog.toLocalFile(),
191 QLatin1String("Test Suite Catalog file (*.xml)")));
193 /* "If the user presses Cancel, it returns a null string." */
194 if(fileName.isNull())
197 m_currentSuiteType = TestSuite::XsltSuite;
198 openCatalog(QUrl::fromLocalFile(fileName), true, TestSuite::XsltSuite);
201 void MainWindow::on_actionOpenXSDTSCatalog_triggered()
203 const QString fileName(QFileDialog::getOpenFileName(this,
204 QLatin1String("Open Test Suite Catalog"),
205 m_previousOpenedCatalog.toLocalFile(),
206 QLatin1String("Test Suite Catalog file (*.xml)")));
208 /* "If the user presses Cancel, it returns a null string." */
209 if(fileName.isNull())
212 m_currentSuiteType = TestSuite::XsdSuite;
213 openCatalog(QUrl::fromLocalFile(fileName), true, TestSuite::XsdSuite);
216 void MainWindow::openCatalog(const QUrl &fileName,
217 const bool reportError,
218 const TestSuite::SuiteType suiteType)
220 setCurrentFile(fileName);
221 m_previousOpenedCatalog = fileName;
224 TestSuite *const loadedSuite = TestSuite::openCatalog(fileName, errorMsg, false, suiteType);
230 QMessageBox::information(this, QLatin1String("Failed to load catalog file"),
231 errorMsg, QMessageBox::Ok);
237 TreeModel *const prevModel = sourceModel();
238 prevModel->setRoot(loadedSuite);
241 testCaseCount->setText(QString::number(loadedSuite->resultSummary().second));
242 /* Switch to the tab containing the loaded test suite. */
243 sourceTab->setCurrentIndex(0);
245 setWindowTitle(QCoreApplication::applicationName() +
246 QLatin1String(" -- ") +
247 QFileInfo(fileName.toLocalFile()).fileName());
249 /* @p reportError is set when not auto-loading on startup, and
250 * we only want to save when the user opens from the GUI. */
255 void MainWindow::on_sourceTab_currentChanged(int index)
259 m_currentTC = m_userTC;
260 testCaseSelected(m_userTC);
263 on_testSuiteView_clicked(testSuiteView->currentIndex());
266 void MainWindow::on_actionExecute_triggered()
268 Q_ASSERT(testCaseView);
269 TestSuite *const ts = static_cast<TestSuite *>(sourceModel()->root());
271 const TestItem::ExecutionStage stage = compileOnly->isChecked() ? TestItem::CompileOnly
272 : TestItem::CompileAndRun;
274 m_userTC->setLanguage(isXSLT20->isChecked() ? QXmlQuery::XSLT20 : QXmlQuery::XQuery10);
278 const TestResult::List rlist(m_currentTC->execute(stage, ts));
279 Q_ASSERT(rlist.count() == 1);
280 const TestResult *const result = rlist.first();
282 testResultView->displayTestResult(result);
286 const QModelIndexList indexes = testSuiteView->selectionModel()->selectedIndexes();
287 for (int i = 0; i < indexes.count(); ++i) {
288 const QModelIndex source(sourceIndex(indexes.at(i)));
290 TestItem *const ti = static_cast<TestItem *>(source.internalPointer());
294 /* ti is a TestGroup. It now executes its children, changed(TreeItem *) signals is
295 * emitted which the view receives, and thus updates. */
296 ti->execute(stage, ts);
301 void MainWindow::readSettings()
305 settings.beginGroup(QLatin1String("MainWindow"));
306 restoreState(settings.value(QLatin1String("state")).toByteArray(), Global::versionNumber);
307 resize(settings.value(QLatin1String("size"), QSize(400, 400)).toSize());
308 move(settings.value(QLatin1String("pos"), QPoint(200, 200)).toPoint());
309 m_previousOpenedCatalog = settings.value(QLatin1String("PreviousOpenedCatalogFile")).toUrl();
310 focusURI->setText(settings.value(QLatin1String("focusURI")).toString());
311 isXSLT20->setChecked(settings.value(QLatin1String("isXSLT20")).toBool());
312 compileOnly->setChecked(settings.value(QLatin1String("compileOnly")).toBool());
313 m_currentSuiteType = (TestSuite::SuiteType)settings.value(QLatin1String("PreviousSuiteType"), isXSLT20->isChecked() ? TestSuite::XsltSuite : TestSuite::XQuerySuite).toInt();
315 /* Open the previously opened catalog. */
316 if(!m_previousOpenedCatalog.isEmpty())
318 openCatalog(m_previousOpenedCatalog, false, m_currentSuiteType);
321 sourceInput->setPlainText(settings.value(QLatin1String("sourceInput")).toString());
322 testResultView->resultViewSelection->setCurrentIndex(
323 settings.value(QLatin1String("ResultViewMethod"), 0).toInt());
324 testResultView->outputStack->setCurrentIndex(settings.value(
325 QLatin1String("ResultViewMethod"), 0).toInt());
327 /* Restore the selected test case/group. */
328 const QStringList rows(settings.value(QLatin1String("SelectedTestSuiteRow"),
330 .toString().split(QLatin1Char(',')));
332 if(!rows.isEmpty()) /* Ok, we have a selection. */
334 QAbstractItemModel *const model = testSuiteView->model();
338 for(int i = rows.count() - 1; i >= 0; --i)
340 const QModelIndex childIndex(model->index(rows.at(i).toInt(), 0 , p));
342 if(childIndex.isValid())
344 testSuiteView->scrollTo(p); /* Work around for Qt issue #87575. */
349 testSuiteView->scrollTo(p); /* Scrolls to it. */
350 testSuiteView->setCurrentIndex(p); /* Selects it. */
351 on_testSuiteView_clicked(p); /* Loads the test case in the Test Case View. */
354 /* Do it here. In this way the user-entered test case gets selected, if that tab
355 * was previously used. */
356 sourceTab->setCurrentIndex(settings.value(QLatin1String("SelectedTab"), 0).toInt());
357 on_sourceTab_currentChanged(sourceTab->currentIndex());
362 void MainWindow::writeSettings()
366 settings.beginGroup(QLatin1String("MainWindow"));
367 settings.setValue(QLatin1String("state"), saveState(Global::versionNumber));
368 settings.setValue(QLatin1String("pos"), pos());
369 settings.setValue(QLatin1String("size"), size());
370 settings.setValue(QLatin1String("sourceInput"), sourceInput->toPlainText());
371 settings.setValue(QLatin1String("PreviousOpenedCatalogFile"), m_previousOpenedCatalog);
372 settings.setValue(QLatin1String("PreviousSuiteType"), m_currentSuiteType);
373 settings.setValue(QLatin1String("SelectedTab"), sourceTab->currentIndex());
374 settings.setValue(QLatin1String("ResultViewMethod"),
375 testResultView->resultViewSelection->currentIndex());
376 settings.setValue(QLatin1String("focusURI"),
378 settings.setValue(QLatin1String("isXSLT20"),
379 isXSLT20->isChecked());
380 settings.setValue(QLatin1String("compileOnly"),
381 compileOnly->isChecked());
383 /* Store the selected test case/group. */
384 QModelIndex selected(sourceIndex(testSuiteView->currentIndex()));
385 if(selected.isValid())
391 result.append(QString::number(selected.row()));
392 selected = selected.parent();
394 if(selected.isValid())
395 result.append(QLatin1Char(','));
401 settings.setValue(QLatin1String("SelectedTestSuiteRow"), result);
407 void MainWindow::setCurrentFile(const QUrl &f)
409 const QString fileName(f.toLocalFile());
411 settings.beginGroup(QLatin1String("MainWindow"));
412 QStringList files(settings.value(QLatin1String("RecentFileList")).toStringList());
414 files.removeAll(fileName);
415 files.prepend(fileName);
416 while(files.size() > MaximumRecentFiles)
419 settings.setValue(QLatin1String("RecentFileList"), files);
422 updateRecentFileActions();
425 void MainWindow::updateRecentFileActions()
428 settings.beginGroup(QLatin1String("MainWindow"));
429 const QStringList files(settings.value(QLatin1String("RecentFileList")).toStringList());
432 const int numRecentFiles = qMin(files.size(), static_cast<int>(MaximumRecentFiles));
434 for(int i = 0; i < numRecentFiles; ++i)
436 const QString text(QString::fromLatin1("&%1 %2").arg(i + 1).arg(QFileInfo(files[i]).filePath()));
437 m_recentFileActs[i]->setText(text);
438 m_recentFileActs[i]->setData(QUrl::fromLocalFile(files[i]));
439 m_recentFileActs[i]->setVisible(true);
442 for(int j = numRecentFiles; j < MaximumRecentFiles; ++j)
443 m_recentFileActs[j]->setVisible(false);
446 void MainWindow::openRecentFile()
448 const QAction *const action = qobject_cast<QAction *>(sender());
450 openCatalog(action->data().toUrl(), true, TestSuite::XQuerySuite);
453 void MainWindow::closeEvent(QCloseEvent *ev)
459 void MainWindow::setupActions()
461 connect(actionQuit, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
463 for(int i = 0; i < MaximumRecentFiles; ++i)
465 m_recentFileActs[i] = new QAction(this);
466 m_recentFileActs[i]->setVisible(false);
467 connect(m_recentFileActs[i], SIGNAL(triggered()),
468 this, SLOT(openRecentFile()));
472 void MainWindow::setupMenu()
474 QMenu *const menFile = findChild<QMenu *>(QLatin1String("menuFile"));
476 QAction *const actOpen = findChild<QAction *>(QLatin1String("actionExecute"));
478 QMenu *const recent = new QMenu(QLatin1String("O&pen Recent"), this);
480 menFile->insertMenu(actOpen, recent);
481 menFile->insertSeparator(actOpen);
483 for(int i = 0; i < MaximumRecentFiles; ++i)
484 recent->addAction(m_recentFileActs[i]);
486 updateRecentFileActions();
488 QMenu *const menWindows = findChild<QMenu *>(QLatin1String("menuWindows"));
489 Q_ASSERT(menWindows);
491 menWindows->addAction(testCaseView->toggleViewAction());
492 menWindows->addAction(testResultView->toggleViewAction());
493 menWindows->addAction(functionView->toggleViewAction());
496 void MainWindow::on_actionRestart_triggered()
498 if(QProcess::startDetached(QCoreApplication::applicationFilePath()))
499 QApplication::closeAllWindows();
502 QTextStream err(stderr);
503 err << "Failed to start " << qPrintable(QCoreApplication::applicationFilePath()) << endl;
508 // vim: et:ts=4:sw=4:sts=4