| 0 |      1 | /****************************************************************************
 | 
|  |      2 | **
 | 
|  |      3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
 | 
|  |      4 | ** All rights reserved.
 | 
|  |      5 | ** Contact: Nokia Corporation (qt-info@nokia.com)
 | 
|  |      6 | **
 | 
|  |      7 | ** This file is part of the test suite of the Qt Toolkit.
 | 
|  |      8 | **
 | 
|  |      9 | ** $QT_BEGIN_LICENSE:LGPL$
 | 
|  |     10 | ** No Commercial Usage
 | 
|  |     11 | ** This file contains pre-release code and may not be distributed.
 | 
|  |     12 | ** You may use this file in accordance with the terms and conditions
 | 
|  |     13 | ** contained in the Technology Preview License Agreement accompanying
 | 
|  |     14 | ** this package.
 | 
|  |     15 | **
 | 
|  |     16 | ** GNU Lesser General Public License Usage
 | 
|  |     17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
 | 
|  |     18 | ** General Public License version 2.1 as published by the Free Software
 | 
|  |     19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
 | 
|  |     20 | ** packaging of this file.  Please review the following information to
 | 
|  |     21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
 | 
|  |     22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 | 
|  |     23 | **
 | 
|  |     24 | ** In addition, as a special exception, Nokia gives you certain additional
 | 
|  |     25 | ** rights.  These rights are described in the Nokia Qt LGPL Exception
 | 
|  |     26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 | 
|  |     27 | **
 | 
|  |     28 | ** If you have questions regarding the use of this file, please contact
 | 
|  |     29 | ** Nokia at qt-info@nokia.com.
 | 
|  |     30 | **
 | 
|  |     31 | **
 | 
|  |     32 | **
 | 
|  |     33 | **
 | 
|  |     34 | **
 | 
|  |     35 | **
 | 
|  |     36 | **
 | 
|  |     37 | **
 | 
|  |     38 | ** $QT_END_LICENSE$
 | 
|  |     39 | **
 | 
|  |     40 | ****************************************************************************/
 | 
|  |     41 | 
 | 
|  |     42 | #include <QCloseEvent>
 | 
|  |     43 | #include <QFileDialog>
 | 
|  |     44 | #include <QFileInfo>
 | 
|  |     45 | #include <QHeaderView>
 | 
|  |     46 | #include <QMenu>
 | 
|  |     47 | #include <QMessageBox>
 | 
|  |     48 | #include <QProcess>
 | 
|  |     49 | #include <QSettings>
 | 
|  |     50 | #include <QTextStream>
 | 
|  |     51 | 
 | 
|  |     52 | #include "ASTItem.h"
 | 
|  |     53 | #include "FunctionSignaturesView.h"
 | 
|  |     54 | #include "Global.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"
 | 
|  |     61 | 
 | 
|  |     62 | #include "MainWindow.h"
 | 
|  |     63 | 
 | 
|  |     64 | using namespace QPatternistSDK;
 | 
|  |     65 | 
 | 
|  |     66 | MainWindow::MainWindow() : m_userTC(new UserTestCase()),
 | 
|  |     67 |                            m_currentTC(0)
 | 
|  |     68 | {
 | 
|  |     69 |     setupUi(this);
 | 
|  |     70 | 
 | 
|  |     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);
 | 
|  |     75 | 
 | 
|  |     76 |     setupActions();
 | 
|  |     77 | 
 | 
|  |     78 |     QStringList suiteHeaders;
 | 
|  |     79 |     suiteHeaders << QLatin1String("Name")
 | 
|  |     80 |                  << QLatin1String("Pass")
 | 
|  |     81 |                  << QLatin1String("Fail")
 | 
|  |     82 |                  << QLatin1String("Total");
 | 
|  |     83 | 
 | 
|  |     84 |     TreeSortFilter *const proxy = new TreeSortFilter(this);
 | 
|  |     85 |     connect(searchInput,    SIGNAL(textChanged(const QString &)),
 | 
|  |     86 |             proxy,          SLOT(setFilterFixedString(const QString &)));
 | 
|  |     87 | 
 | 
|  |     88 |     proxy->setSourceModel(new TreeModel(suiteHeaders, this));
 | 
|  |     89 |     testSuiteView->setModel(proxy);
 | 
|  |     90 | 
 | 
|  |     91 |     /* --------- Test Result View ---------- */
 | 
|  |     92 |     testResultView = new TestResultView(this);
 | 
|  |     93 |     testResultView->setAllowedAreas(Qt::AllDockWidgetAreas);
 | 
|  |     94 |     addDockWidget(Qt::RightDockWidgetArea, testResultView);
 | 
|  |     95 |     /* ----------------------------------- */
 | 
|  |     96 | 
 | 
|  |     97 |     /* --------- Test Case View ---------- */
 | 
|  |     98 |     testCaseView = new TestCaseView(this);
 | 
|  |     99 |     testCaseView->setAllowedAreas(Qt::AllDockWidgetAreas);
 | 
|  |    100 |     addDockWidget(Qt::LeftDockWidgetArea, testCaseView);
 | 
|  |    101 | 
 | 
|  |    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 |     /* ----------------------------------- */
 | 
|  |    109 | 
 | 
|  |    110 |     /* ----- Function Signature View ----- */
 | 
|  |    111 |     functionView = new FunctionSignaturesView(this);
 | 
|  |    112 |     functionView->setAllowedAreas(Qt::AllDockWidgetAreas);
 | 
|  |    113 |     addDockWidget(Qt::RightDockWidgetArea, functionView);
 | 
|  |    114 |     /* ----------------------------------- */
 | 
|  |    115 | 
 | 
|  |    116 |     /* Appears here, because the menu uses actions in the QDockWidgets. */
 | 
|  |    117 |     setupMenu();
 | 
|  |    118 | 
 | 
|  |    119 |     readSettings();
 | 
|  |    120 | 
 | 
|  |    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()));
 | 
|  |    128 | }
 | 
|  |    129 | 
 | 
|  |    130 | MainWindow::~MainWindow()
 | 
|  |    131 | {
 | 
|  |    132 |     delete m_userTC;
 | 
|  |    133 | }
 | 
|  |    134 | 
 | 
|  |    135 | QModelIndex MainWindow::sourceIndex(const QModelIndex &proxyIndex) const
 | 
|  |    136 | {
 | 
|  |    137 |     return static_cast<TreeSortFilter *>(testSuiteView->model())->mapToSource(proxyIndex);
 | 
|  |    138 | }
 | 
|  |    139 | 
 | 
|  |    140 | TreeModel *MainWindow::sourceModel() const
 | 
|  |    141 | {
 | 
|  |    142 |     const TreeSortFilter *const proxy = static_cast<TreeSortFilter *>(testSuiteView->model());
 | 
|  |    143 |     return static_cast<TreeModel *>(proxy->sourceModel());
 | 
|  |    144 | }
 | 
|  |    145 | 
 | 
|  |    146 | void MainWindow::on_testSuiteView_clicked(const QModelIndex &index)
 | 
|  |    147 | {
 | 
|  |    148 |     if(index.isValid())
 | 
|  |    149 |     {
 | 
|  |    150 |         TestItem *const node = static_cast<TestItem *>(sourceIndex(index).internalPointer());
 | 
|  |    151 |         Q_ASSERT(node);
 | 
|  |    152 | 
 | 
|  |    153 |         if(node->isFinalNode())
 | 
|  |    154 |         {
 | 
|  |    155 |             m_currentTC = static_cast<TestCase *>(node);
 | 
|  |    156 |             testCaseSelected(m_currentTC);
 | 
|  |    157 |             return;
 | 
|  |    158 |         }
 | 
|  |    159 |     }
 | 
|  |    160 | 
 | 
|  |    161 |     /* In all other cases: */
 | 
|  |    162 |     m_currentTC = 0;
 | 
|  |    163 |     testCaseSelected(0);
 | 
|  |    164 | }
 | 
|  |    165 | 
 | 
|  |    166 | void MainWindow::on_sourceInput_textChanged()
 | 
|  |    167 | {
 | 
|  |    168 |     m_userTC->setSourceCode(sourceInput->toPlainText());
 | 
|  |    169 | }
 | 
|  |    170 | 
 | 
|  |    171 | void MainWindow::on_actionOpen_triggered()
 | 
|  |    172 | {
 | 
|  |    173 |     const QString fileName(QFileDialog::getOpenFileName(this,
 | 
|  |    174 |                                                         QLatin1String("Open Test Suite Catalog"),
 | 
|  |    175 |                                                         m_previousOpenedCatalog.toLocalFile(),
 | 
|  |    176 |                                                         QLatin1String("Test Suite Catalog file (*.xml)")));
 | 
|  |    177 | 
 | 
|  |    178 |     /* "If the user presses Cancel, it returns a null string." */
 | 
|  |    179 |     if(fileName.isNull())
 | 
|  |    180 |         return;
 | 
|  |    181 | 
 | 
|  |    182 |     m_currentSuiteType = TestSuite::XQuerySuite;
 | 
|  |    183 |     openCatalog(QUrl::fromLocalFile(fileName), true, TestSuite::XQuerySuite);
 | 
|  |    184 | }
 | 
|  |    185 | 
 | 
|  |    186 | void MainWindow::on_actionOpenXSLTSCatalog_triggered()
 | 
|  |    187 | {
 | 
|  |    188 |     const QString fileName(QFileDialog::getOpenFileName(this,
 | 
|  |    189 |                                                         QLatin1String("Open Test Suite Catalog"),
 | 
|  |    190 |                                                         m_previousOpenedCatalog.toLocalFile(),
 | 
|  |    191 |                                                         QLatin1String("Test Suite Catalog file (*.xml)")));
 | 
|  |    192 | 
 | 
|  |    193 |     /* "If the user presses Cancel, it returns a null string." */
 | 
|  |    194 |     if(fileName.isNull())
 | 
|  |    195 |         return;
 | 
|  |    196 | 
 | 
|  |    197 |     m_currentSuiteType = TestSuite::XsltSuite;
 | 
|  |    198 |     openCatalog(QUrl::fromLocalFile(fileName), true, TestSuite::XsltSuite);
 | 
|  |    199 | }
 | 
|  |    200 | 
 | 
|  |    201 | void MainWindow::on_actionOpenXSDTSCatalog_triggered()
 | 
|  |    202 | {
 | 
|  |    203 |     const QString fileName(QFileDialog::getOpenFileName(this,
 | 
|  |    204 |                                                         QLatin1String("Open Test Suite Catalog"),
 | 
|  |    205 |                                                         m_previousOpenedCatalog.toLocalFile(),
 | 
|  |    206 |                                                         QLatin1String("Test Suite Catalog file (*.xml)")));
 | 
|  |    207 | 
 | 
|  |    208 |     /* "If the user presses Cancel, it returns a null string." */
 | 
|  |    209 |     if(fileName.isNull())
 | 
|  |    210 |         return;
 | 
|  |    211 | 
 | 
|  |    212 |     m_currentSuiteType = TestSuite::XsdSuite;
 | 
|  |    213 |     openCatalog(QUrl::fromLocalFile(fileName), true, TestSuite::XsdSuite);
 | 
|  |    214 | }
 | 
|  |    215 | 
 | 
|  |    216 | void MainWindow::openCatalog(const QUrl &fileName,
 | 
|  |    217 |                              const bool reportError,
 | 
|  |    218 |                              const TestSuite::SuiteType suiteType)
 | 
|  |    219 | {
 | 
|  |    220 |     setCurrentFile(fileName);
 | 
|  |    221 |     m_previousOpenedCatalog = fileName;
 | 
|  |    222 | 
 | 
|  |    223 |     QString errorMsg;
 | 
|  |    224 |     TestSuite *const loadedSuite = TestSuite::openCatalog(fileName, errorMsg, false, suiteType);
 | 
|  |    225 | 
 | 
|  |    226 |     if(!loadedSuite)
 | 
|  |    227 |     {
 | 
|  |    228 |         if(reportError)
 | 
|  |    229 |         {
 | 
|  |    230 |             QMessageBox::information(this, QLatin1String("Failed to load catalog file"),
 | 
|  |    231 |                                      errorMsg, QMessageBox::Ok);
 | 
|  |    232 |         }
 | 
|  |    233 | 
 | 
|  |    234 |         return;
 | 
|  |    235 |     }
 | 
|  |    236 | 
 | 
|  |    237 |     TreeModel *const prevModel = sourceModel();
 | 
|  |    238 |     prevModel->setRoot(loadedSuite);
 | 
|  |    239 |     m_currentTC = 0;
 | 
|  |    240 | 
 | 
|  |    241 |     testCaseCount->setText(QString::number(loadedSuite->resultSummary().second));
 | 
|  |    242 |     /* Switch to the tab containing the loaded test suite. */
 | 
|  |    243 |     sourceTab->setCurrentIndex(0);
 | 
|  |    244 | 
 | 
|  |    245 |     setWindowTitle(QCoreApplication::applicationName() +
 | 
|  |    246 |                    QLatin1String(" -- ") +
 | 
|  |    247 |                    QFileInfo(fileName.toLocalFile()).fileName());
 | 
|  |    248 | 
 | 
|  |    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. */
 | 
|  |    251 |     if(reportError)
 | 
|  |    252 |         writeSettings();
 | 
|  |    253 | }
 | 
|  |    254 | 
 | 
|  |    255 | void MainWindow::on_sourceTab_currentChanged(int index)
 | 
|  |    256 | {
 | 
|  |    257 |     if(index == 1)
 | 
|  |    258 |     {
 | 
|  |    259 |         m_currentTC = m_userTC;
 | 
|  |    260 |         testCaseSelected(m_userTC);
 | 
|  |    261 |     }
 | 
|  |    262 |     else
 | 
|  |    263 |         on_testSuiteView_clicked(testSuiteView->currentIndex());
 | 
|  |    264 | }
 | 
|  |    265 | 
 | 
|  |    266 | void MainWindow::on_actionExecute_triggered()
 | 
|  |    267 | {
 | 
|  |    268 |     Q_ASSERT(testCaseView);
 | 
|  |    269 |     TestSuite *const ts = static_cast<TestSuite *>(sourceModel()->root());
 | 
|  |    270 | 
 | 
|  |    271 |     const TestItem::ExecutionStage stage = compileOnly->isChecked() ? TestItem::CompileOnly
 | 
|  |    272 |                                                                     : TestItem::CompileAndRun;
 | 
|  |    273 | 
 | 
|  |    274 |     m_userTC->setLanguage(isXSLT20->isChecked() ? QXmlQuery::XSLT20 : QXmlQuery::XQuery10);
 | 
|  |    275 | 
 | 
|  |    276 |     if(m_currentTC)
 | 
|  |    277 |     {
 | 
|  |    278 |         const TestResult::List rlist(m_currentTC->execute(stage, ts));
 | 
|  |    279 |         Q_ASSERT(rlist.count() == 1);
 | 
|  |    280 |         const TestResult *const result = rlist.first();
 | 
|  |    281 |         Q_ASSERT(result);
 | 
|  |    282 |         testResultView->displayTestResult(result);
 | 
|  |    283 |     }
 | 
|  |    284 |     else
 | 
|  |    285 |     {
 | 
|  |    286 |         const QModelIndexList indexes = testSuiteView->selectionModel()->selectedIndexes();
 | 
|  |    287 |         for (int i = 0; i < indexes.count(); ++i) {
 | 
|  |    288 |             const QModelIndex source(sourceIndex(indexes.at(i)));
 | 
|  |    289 | 
 | 
|  |    290 |             TestItem *const ti = static_cast<TestItem *>(source.internalPointer());
 | 
|  |    291 |             if(!ti)
 | 
|  |    292 |                 return;
 | 
|  |    293 | 
 | 
|  |    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);
 | 
|  |    297 |         }
 | 
|  |    298 |     }
 | 
|  |    299 | }
 | 
|  |    300 | 
 | 
|  |    301 | void MainWindow::readSettings()
 | 
|  |    302 | {
 | 
|  |    303 |     QSettings settings;
 | 
|  |    304 | 
 | 
|  |    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();
 | 
|  |    314 | 
 | 
|  |    315 |     /* Open the previously opened catalog. */
 | 
|  |    316 |     if(!m_previousOpenedCatalog.isEmpty())
 | 
|  |    317 |     {
 | 
|  |    318 |         openCatalog(m_previousOpenedCatalog, false, m_currentSuiteType);
 | 
|  |    319 |     }
 | 
|  |    320 | 
 | 
|  |    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());
 | 
|  |    326 | 
 | 
|  |    327 |     /* Restore the selected test case/group. */
 | 
|  |    328 |     const QStringList rows(settings.value(QLatin1String("SelectedTestSuiteRow"),
 | 
|  |    329 |                                           QString())
 | 
|  |    330 |                            .toString().split(QLatin1Char(',')));
 | 
|  |    331 | 
 | 
|  |    332 |     if(!rows.isEmpty()) /* Ok, we have a selection. */
 | 
|  |    333 |     {
 | 
|  |    334 |         QAbstractItemModel *const model = testSuiteView->model();
 | 
|  |    335 |         Q_ASSERT(model);
 | 
|  |    336 |         QModelIndex p;
 | 
|  |    337 | 
 | 
|  |    338 |         for(int i = rows.count() - 1; i >= 0;  --i)
 | 
|  |    339 |         {
 | 
|  |    340 |             const QModelIndex childIndex(model->index(rows.at(i).toInt(), 0 , p));
 | 
|  |    341 | 
 | 
|  |    342 |             if(childIndex.isValid())
 | 
|  |    343 |             {
 | 
|  |    344 |                 testSuiteView->scrollTo(p); /* Work around for Qt issue #87575. */
 | 
|  |    345 |                 p = childIndex;
 | 
|  |    346 |             }
 | 
|  |    347 |         }
 | 
|  |    348 | 
 | 
|  |    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. */
 | 
|  |    352 |     }
 | 
|  |    353 | 
 | 
|  |    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());
 | 
|  |    358 | 
 | 
|  |    359 |     settings.endGroup();
 | 
|  |    360 | }
 | 
|  |    361 | 
 | 
|  |    362 | void MainWindow::writeSettings()
 | 
|  |    363 | {
 | 
|  |    364 |     QSettings settings;
 | 
|  |    365 | 
 | 
|  |    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"),
 | 
|  |    377 |                       focusURI->text());
 | 
|  |    378 |     settings.setValue(QLatin1String("isXSLT20"),
 | 
|  |    379 |                       isXSLT20->isChecked());
 | 
|  |    380 |     settings.setValue(QLatin1String("compileOnly"),
 | 
|  |    381 |                       compileOnly->isChecked());
 | 
|  |    382 | 
 | 
|  |    383 |     /* Store the selected test case/group. */
 | 
|  |    384 |     QModelIndex selected(sourceIndex(testSuiteView->currentIndex()));
 | 
|  |    385 |     if(selected.isValid())
 | 
|  |    386 |     {
 | 
|  |    387 |         QString result;
 | 
|  |    388 | 
 | 
|  |    389 |         do
 | 
|  |    390 |         {
 | 
|  |    391 |             result.append(QString::number(selected.row()));
 | 
|  |    392 |             selected = selected.parent();
 | 
|  |    393 | 
 | 
|  |    394 |             if(selected.isValid())
 | 
|  |    395 |                 result.append(QLatin1Char(','));
 | 
|  |    396 |             else
 | 
|  |    397 |                 break;
 | 
|  |    398 |         }
 | 
|  |    399 |         while(true);
 | 
|  |    400 | 
 | 
|  |    401 |         settings.setValue(QLatin1String("SelectedTestSuiteRow"), result);
 | 
|  |    402 |     }
 | 
|  |    403 | 
 | 
|  |    404 |     settings.endGroup();
 | 
|  |    405 | }
 | 
|  |    406 | 
 | 
|  |    407 | void MainWindow::setCurrentFile(const QUrl &f)
 | 
|  |    408 | {
 | 
|  |    409 |     const QString fileName(f.toLocalFile());
 | 
|  |    410 |     QSettings settings;
 | 
|  |    411 |     settings.beginGroup(QLatin1String("MainWindow"));
 | 
|  |    412 |     QStringList files(settings.value(QLatin1String("RecentFileList")).toStringList());
 | 
|  |    413 | 
 | 
|  |    414 |     files.removeAll(fileName);
 | 
|  |    415 |     files.prepend(fileName);
 | 
|  |    416 |     while(files.size() > MaximumRecentFiles)
 | 
|  |    417 |         files.removeLast();
 | 
|  |    418 | 
 | 
|  |    419 |     settings.setValue(QLatin1String("RecentFileList"), files);
 | 
|  |    420 |     settings.endGroup();
 | 
|  |    421 | 
 | 
|  |    422 |     updateRecentFileActions();
 | 
|  |    423 | }
 | 
|  |    424 | 
 | 
|  |    425 | void MainWindow::updateRecentFileActions()
 | 
|  |    426 | {
 | 
|  |    427 |     QSettings settings;
 | 
|  |    428 |     settings.beginGroup(QLatin1String("MainWindow"));
 | 
|  |    429 |     const QStringList files(settings.value(QLatin1String("RecentFileList")).toStringList());
 | 
|  |    430 |     settings.endGroup();
 | 
|  |    431 | 
 | 
|  |    432 |     const int numRecentFiles = qMin(files.size(), static_cast<int>(MaximumRecentFiles));
 | 
|  |    433 | 
 | 
|  |    434 |     for(int i = 0; i < numRecentFiles; ++i)
 | 
|  |    435 |     {
 | 
|  |    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);
 | 
|  |    440 |     }
 | 
|  |    441 | 
 | 
|  |    442 |     for(int j = numRecentFiles; j < MaximumRecentFiles; ++j)
 | 
|  |    443 |         m_recentFileActs[j]->setVisible(false);
 | 
|  |    444 | }
 | 
|  |    445 | 
 | 
|  |    446 | void MainWindow::openRecentFile()
 | 
|  |    447 | {
 | 
|  |    448 |     const QAction *const action = qobject_cast<QAction *>(sender());
 | 
|  |    449 |     if(action)
 | 
|  |    450 |         openCatalog(action->data().toUrl(), true, TestSuite::XQuerySuite);
 | 
|  |    451 | }
 | 
|  |    452 | 
 | 
|  |    453 | void MainWindow::closeEvent(QCloseEvent *ev)
 | 
|  |    454 | {
 | 
|  |    455 |     writeSettings();
 | 
|  |    456 |     ev->accept();
 | 
|  |    457 | }
 | 
|  |    458 | 
 | 
|  |    459 | void MainWindow::setupActions()
 | 
|  |    460 | {
 | 
|  |    461 |     connect(actionQuit, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
 | 
|  |    462 | 
 | 
|  |    463 |     for(int i = 0; i < MaximumRecentFiles; ++i)
 | 
|  |    464 |     {
 | 
|  |    465 |         m_recentFileActs[i] = new QAction(this);
 | 
|  |    466 |         m_recentFileActs[i]->setVisible(false);
 | 
|  |    467 |         connect(m_recentFileActs[i], SIGNAL(triggered()),
 | 
|  |    468 |                 this, SLOT(openRecentFile()));
 | 
|  |    469 |     }
 | 
|  |    470 | }
 | 
|  |    471 | 
 | 
|  |    472 | void MainWindow::setupMenu()
 | 
|  |    473 | {
 | 
|  |    474 |     QMenu *const menFile = findChild<QMenu *>(QLatin1String("menuFile"));
 | 
|  |    475 |     Q_ASSERT(menFile);
 | 
|  |    476 |     QAction *const actOpen = findChild<QAction *>(QLatin1String("actionExecute"));
 | 
|  |    477 |     Q_ASSERT(actOpen);
 | 
|  |    478 |     QMenu *const recent = new QMenu(QLatin1String("O&pen Recent"), this);
 | 
|  |    479 | 
 | 
|  |    480 |     menFile->insertMenu(actOpen, recent);
 | 
|  |    481 |     menFile->insertSeparator(actOpen);
 | 
|  |    482 | 
 | 
|  |    483 |     for(int i = 0; i < MaximumRecentFiles; ++i)
 | 
|  |    484 |         recent->addAction(m_recentFileActs[i]);
 | 
|  |    485 | 
 | 
|  |    486 |     updateRecentFileActions();
 | 
|  |    487 | 
 | 
|  |    488 |     QMenu *const menWindows = findChild<QMenu *>(QLatin1String("menuWindows"));
 | 
|  |    489 |     Q_ASSERT(menWindows);
 | 
|  |    490 | 
 | 
|  |    491 |     menWindows->addAction(testCaseView->toggleViewAction());
 | 
|  |    492 |     menWindows->addAction(testResultView->toggleViewAction());
 | 
|  |    493 |     menWindows->addAction(functionView->toggleViewAction());
 | 
|  |    494 | }
 | 
|  |    495 | 
 | 
|  |    496 | void MainWindow::on_actionRestart_triggered()
 | 
|  |    497 | {
 | 
|  |    498 |     if(QProcess::startDetached(QCoreApplication::applicationFilePath()))
 | 
|  |    499 |         QApplication::closeAllWindows();
 | 
|  |    500 |     else
 | 
|  |    501 |     {
 | 
|  |    502 |         QTextStream err(stderr);
 | 
|  |    503 |         err << "Failed to start " << qPrintable(QCoreApplication::applicationFilePath()) << endl;
 | 
|  |    504 |     }
 | 
|  |    505 | }
 | 
|  |    506 | 
 | 
|  |    507 | 
 | 
|  |    508 | // vim: et:ts=4:sw=4:sts=4
 |