tests/auto/xmlpatternsview/view/MainWindow.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/xmlpatternsview/view/MainWindow.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,508 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCloseEvent>
+#include <QFileDialog>
+#include <QFileInfo>
+#include <QHeaderView>
+#include <QMenu>
+#include <QMessageBox>
+#include <QProcess>
+#include <QSettings>
+#include <QTextStream>
+
+#include "ASTItem.h"
+#include "FunctionSignaturesView.h"
+#include "Global.h"
+#include "TestCaseView.h"
+#include "TestResultView.h"
+#include "TestSuite.h"
+#include "TreeModel.h"
+#include "TreeSortFilter.h"
+#include "UserTestCase.h"
+
+#include "MainWindow.h"
+
+using namespace QPatternistSDK;
+
+MainWindow::MainWindow() : m_userTC(new UserTestCase()),
+                           m_currentTC(0)
+{
+    setupUi(this);
+
+    /* I want to do this in Designer.. */
+    testSuiteView->header()->setSortIndicator(0, Qt::AscendingOrder);
+    testSuiteView->header()->setSortIndicatorShown(true);
+    testSuiteView->header()->setClickable(true);
+
+    setupActions();
+
+    QStringList suiteHeaders;
+    suiteHeaders << QLatin1String("Name")
+                 << QLatin1String("Pass")
+                 << QLatin1String("Fail")
+                 << QLatin1String("Total");
+
+    TreeSortFilter *const proxy = new TreeSortFilter(this);
+    connect(searchInput,    SIGNAL(textChanged(const QString &)),
+            proxy,          SLOT(setFilterFixedString(const QString &)));
+
+    proxy->setSourceModel(new TreeModel(suiteHeaders, this));
+    testSuiteView->setModel(proxy);
+
+    /* --------- Test Result View ---------- */
+    testResultView = new TestResultView(this);
+    testResultView->setAllowedAreas(Qt::AllDockWidgetAreas);
+    addDockWidget(Qt::RightDockWidgetArea, testResultView);
+    /* ----------------------------------- */
+
+    /* --------- Test Case View ---------- */
+    testCaseView = new TestCaseView(this);
+    testCaseView->setAllowedAreas(Qt::AllDockWidgetAreas);
+    addDockWidget(Qt::LeftDockWidgetArea, testCaseView);
+
+    connect(this,           SIGNAL(testCaseSelected(TestCase *const)),
+            testCaseView,   SLOT(displayTestCase(TestCase *const)));
+    connect(this,           SIGNAL(testCaseSelected(TestCase *const)),
+            testResultView, SLOT(displayTestResult(TestCase *const)));
+    connect(focusURI,       SIGNAL(textChanged(const QString &)),
+            m_userTC,       SLOT(focusDocumentChanged(const QString &)));
+    /* ----------------------------------- */
+
+    /* ----- Function Signature View ----- */
+    functionView = new FunctionSignaturesView(this);
+    functionView->setAllowedAreas(Qt::AllDockWidgetAreas);
+    addDockWidget(Qt::RightDockWidgetArea, functionView);
+    /* ----------------------------------- */
+
+    /* Appears here, because the menu uses actions in the QDockWidgets. */
+    setupMenu();
+
+    readSettings();
+
+    /* Connect this after readSettings(), otherwise readSettings() triggers writeSettings(). */
+    connect(sourceTab,      SIGNAL(currentChanged(int)),
+                            SLOT(writeSettings()));
+    connect(testSuiteView,  SIGNAL(clicked(const QModelIndex &)),
+                            SLOT(writeSettings()));
+    connect(sourceInput,    SIGNAL(textChanged()),
+                            SLOT(writeSettings()));
+}
+
+MainWindow::~MainWindow()
+{
+    delete m_userTC;
+}
+
+QModelIndex MainWindow::sourceIndex(const QModelIndex &proxyIndex) const
+{
+    return static_cast<TreeSortFilter *>(testSuiteView->model())->mapToSource(proxyIndex);
+}
+
+TreeModel *MainWindow::sourceModel() const
+{
+    const TreeSortFilter *const proxy = static_cast<TreeSortFilter *>(testSuiteView->model());
+    return static_cast<TreeModel *>(proxy->sourceModel());
+}
+
+void MainWindow::on_testSuiteView_clicked(const QModelIndex &index)
+{
+    if(index.isValid())
+    {
+        TestItem *const node = static_cast<TestItem *>(sourceIndex(index).internalPointer());
+        Q_ASSERT(node);
+
+        if(node->isFinalNode())
+        {
+            m_currentTC = static_cast<TestCase *>(node);
+            testCaseSelected(m_currentTC);
+            return;
+        }
+    }
+
+    /* In all other cases: */
+    m_currentTC = 0;
+    testCaseSelected(0);
+}
+
+void MainWindow::on_sourceInput_textChanged()
+{
+    m_userTC->setSourceCode(sourceInput->toPlainText());
+}
+
+void MainWindow::on_actionOpen_triggered()
+{
+    const QString fileName(QFileDialog::getOpenFileName(this,
+                                                        QLatin1String("Open Test Suite Catalog"),
+                                                        m_previousOpenedCatalog.toLocalFile(),
+                                                        QLatin1String("Test Suite Catalog file (*.xml)")));
+
+    /* "If the user presses Cancel, it returns a null string." */
+    if(fileName.isNull())
+        return;
+
+    m_currentSuiteType = TestSuite::XQuerySuite;
+    openCatalog(QUrl::fromLocalFile(fileName), true, TestSuite::XQuerySuite);
+}
+
+void MainWindow::on_actionOpenXSLTSCatalog_triggered()
+{
+    const QString fileName(QFileDialog::getOpenFileName(this,
+                                                        QLatin1String("Open Test Suite Catalog"),
+                                                        m_previousOpenedCatalog.toLocalFile(),
+                                                        QLatin1String("Test Suite Catalog file (*.xml)")));
+
+    /* "If the user presses Cancel, it returns a null string." */
+    if(fileName.isNull())
+        return;
+
+    m_currentSuiteType = TestSuite::XsltSuite;
+    openCatalog(QUrl::fromLocalFile(fileName), true, TestSuite::XsltSuite);
+}
+
+void MainWindow::on_actionOpenXSDTSCatalog_triggered()
+{
+    const QString fileName(QFileDialog::getOpenFileName(this,
+                                                        QLatin1String("Open Test Suite Catalog"),
+                                                        m_previousOpenedCatalog.toLocalFile(),
+                                                        QLatin1String("Test Suite Catalog file (*.xml)")));
+
+    /* "If the user presses Cancel, it returns a null string." */
+    if(fileName.isNull())
+        return;
+
+    m_currentSuiteType = TestSuite::XsdSuite;
+    openCatalog(QUrl::fromLocalFile(fileName), true, TestSuite::XsdSuite);
+}
+
+void MainWindow::openCatalog(const QUrl &fileName,
+                             const bool reportError,
+                             const TestSuite::SuiteType suiteType)
+{
+    setCurrentFile(fileName);
+    m_previousOpenedCatalog = fileName;
+
+    QString errorMsg;
+    TestSuite *const loadedSuite = TestSuite::openCatalog(fileName, errorMsg, false, suiteType);
+
+    if(!loadedSuite)
+    {
+        if(reportError)
+        {
+            QMessageBox::information(this, QLatin1String("Failed to load catalog file"),
+                                     errorMsg, QMessageBox::Ok);
+        }
+
+        return;
+    }
+
+    TreeModel *const prevModel = sourceModel();
+    prevModel->setRoot(loadedSuite);
+    m_currentTC = 0;
+
+    testCaseCount->setText(QString::number(loadedSuite->resultSummary().second));
+    /* Switch to the tab containing the loaded test suite. */
+    sourceTab->setCurrentIndex(0);
+
+    setWindowTitle(QCoreApplication::applicationName() +
+                   QLatin1String(" -- ") +
+                   QFileInfo(fileName.toLocalFile()).fileName());
+
+    /* @p reportError is set when not auto-loading on startup, and
+     * we only want to save when the user opens from the GUI. */
+    if(reportError)
+        writeSettings();
+}
+
+void MainWindow::on_sourceTab_currentChanged(int index)
+{
+    if(index == 1)
+    {
+        m_currentTC = m_userTC;
+        testCaseSelected(m_userTC);
+    }
+    else
+        on_testSuiteView_clicked(testSuiteView->currentIndex());
+}
+
+void MainWindow::on_actionExecute_triggered()
+{
+    Q_ASSERT(testCaseView);
+    TestSuite *const ts = static_cast<TestSuite *>(sourceModel()->root());
+
+    const TestItem::ExecutionStage stage = compileOnly->isChecked() ? TestItem::CompileOnly
+                                                                    : TestItem::CompileAndRun;
+
+    m_userTC->setLanguage(isXSLT20->isChecked() ? QXmlQuery::XSLT20 : QXmlQuery::XQuery10);
+
+    if(m_currentTC)
+    {
+        const TestResult::List rlist(m_currentTC->execute(stage, ts));
+        Q_ASSERT(rlist.count() == 1);
+        const TestResult *const result = rlist.first();
+        Q_ASSERT(result);
+        testResultView->displayTestResult(result);
+    }
+    else
+    {
+        const QModelIndexList indexes = testSuiteView->selectionModel()->selectedIndexes();
+        for (int i = 0; i < indexes.count(); ++i) {
+            const QModelIndex source(sourceIndex(indexes.at(i)));
+
+            TestItem *const ti = static_cast<TestItem *>(source.internalPointer());
+            if(!ti)
+                return;
+
+            /* ti is a TestGroup. It now executes its children, changed(TreeItem *) signals is
+             * emitted which the view receives, and thus updates. */
+            ti->execute(stage, ts);
+        }
+    }
+}
+
+void MainWindow::readSettings()
+{
+    QSettings settings;
+
+    settings.beginGroup(QLatin1String("MainWindow"));
+    restoreState(settings.value(QLatin1String("state")).toByteArray(), Global::versionNumber);
+    resize(settings.value(QLatin1String("size"), QSize(400, 400)).toSize());
+    move(settings.value(QLatin1String("pos"), QPoint(200, 200)).toPoint());
+    m_previousOpenedCatalog = settings.value(QLatin1String("PreviousOpenedCatalogFile")).toUrl();
+    focusURI->setText(settings.value(QLatin1String("focusURI")).toString());
+    isXSLT20->setChecked(settings.value(QLatin1String("isXSLT20")).toBool());
+    compileOnly->setChecked(settings.value(QLatin1String("compileOnly")).toBool());
+    m_currentSuiteType = (TestSuite::SuiteType)settings.value(QLatin1String("PreviousSuiteType"), isXSLT20->isChecked() ? TestSuite::XsltSuite : TestSuite::XQuerySuite).toInt();
+
+    /* Open the previously opened catalog. */
+    if(!m_previousOpenedCatalog.isEmpty())
+    {
+        openCatalog(m_previousOpenedCatalog, false, m_currentSuiteType);
+    }
+
+    sourceInput->setPlainText(settings.value(QLatin1String("sourceInput")).toString());
+    testResultView->resultViewSelection->setCurrentIndex(
+            settings.value(QLatin1String("ResultViewMethod"), 0).toInt());
+    testResultView->outputStack->setCurrentIndex(settings.value(
+            QLatin1String("ResultViewMethod"), 0).toInt());
+
+    /* Restore the selected test case/group. */
+    const QStringList rows(settings.value(QLatin1String("SelectedTestSuiteRow"),
+                                          QString())
+                           .toString().split(QLatin1Char(',')));
+
+    if(!rows.isEmpty()) /* Ok, we have a selection. */
+    {
+        QAbstractItemModel *const model = testSuiteView->model();
+        Q_ASSERT(model);
+        QModelIndex p;
+
+        for(int i = rows.count() - 1; i >= 0;  --i)
+        {
+            const QModelIndex childIndex(model->index(rows.at(i).toInt(), 0 , p));
+
+            if(childIndex.isValid())
+            {
+                testSuiteView->scrollTo(p); /* Work around for Qt issue #87575. */
+                p = childIndex;
+            }
+        }
+
+        testSuiteView->scrollTo(p); /* Scrolls to it. */
+        testSuiteView->setCurrentIndex(p); /* Selects it. */
+        on_testSuiteView_clicked(p); /* Loads the test case in the Test Case View. */
+    }
+
+    /* Do it here. In this way the user-entered test case gets selected, if that tab
+     * was previously used. */
+    sourceTab->setCurrentIndex(settings.value(QLatin1String("SelectedTab"), 0).toInt());
+    on_sourceTab_currentChanged(sourceTab->currentIndex());
+
+    settings.endGroup();
+}
+
+void MainWindow::writeSettings()
+{
+    QSettings settings;
+
+    settings.beginGroup(QLatin1String("MainWindow"));
+    settings.setValue(QLatin1String("state"), saveState(Global::versionNumber));
+    settings.setValue(QLatin1String("pos"), pos());
+    settings.setValue(QLatin1String("size"), size());
+    settings.setValue(QLatin1String("sourceInput"), sourceInput->toPlainText());
+    settings.setValue(QLatin1String("PreviousOpenedCatalogFile"), m_previousOpenedCatalog);
+    settings.setValue(QLatin1String("PreviousSuiteType"), m_currentSuiteType);
+    settings.setValue(QLatin1String("SelectedTab"), sourceTab->currentIndex());
+    settings.setValue(QLatin1String("ResultViewMethod"),
+                      testResultView->resultViewSelection->currentIndex());
+    settings.setValue(QLatin1String("focusURI"),
+                      focusURI->text());
+    settings.setValue(QLatin1String("isXSLT20"),
+                      isXSLT20->isChecked());
+    settings.setValue(QLatin1String("compileOnly"),
+                      compileOnly->isChecked());
+
+    /* Store the selected test case/group. */
+    QModelIndex selected(sourceIndex(testSuiteView->currentIndex()));
+    if(selected.isValid())
+    {
+        QString result;
+
+        do
+        {
+            result.append(QString::number(selected.row()));
+            selected = selected.parent();
+
+            if(selected.isValid())
+                result.append(QLatin1Char(','));
+            else
+                break;
+        }
+        while(true);
+
+        settings.setValue(QLatin1String("SelectedTestSuiteRow"), result);
+    }
+
+    settings.endGroup();
+}
+
+void MainWindow::setCurrentFile(const QUrl &f)
+{
+    const QString fileName(f.toLocalFile());
+    QSettings settings;
+    settings.beginGroup(QLatin1String("MainWindow"));
+    QStringList files(settings.value(QLatin1String("RecentFileList")).toStringList());
+
+    files.removeAll(fileName);
+    files.prepend(fileName);
+    while(files.size() > MaximumRecentFiles)
+        files.removeLast();
+
+    settings.setValue(QLatin1String("RecentFileList"), files);
+    settings.endGroup();
+
+    updateRecentFileActions();
+}
+
+void MainWindow::updateRecentFileActions()
+{
+    QSettings settings;
+    settings.beginGroup(QLatin1String("MainWindow"));
+    const QStringList files(settings.value(QLatin1String("RecentFileList")).toStringList());
+    settings.endGroup();
+
+    const int numRecentFiles = qMin(files.size(), static_cast<int>(MaximumRecentFiles));
+
+    for(int i = 0; i < numRecentFiles; ++i)
+    {
+        const QString text(QString::fromLatin1("&%1 %2").arg(i + 1).arg(QFileInfo(files[i]).filePath()));
+        m_recentFileActs[i]->setText(text);
+        m_recentFileActs[i]->setData(QUrl::fromLocalFile(files[i]));
+        m_recentFileActs[i]->setVisible(true);
+    }
+
+    for(int j = numRecentFiles; j < MaximumRecentFiles; ++j)
+        m_recentFileActs[j]->setVisible(false);
+}
+
+void MainWindow::openRecentFile()
+{
+    const QAction *const action = qobject_cast<QAction *>(sender());
+    if(action)
+        openCatalog(action->data().toUrl(), true, TestSuite::XQuerySuite);
+}
+
+void MainWindow::closeEvent(QCloseEvent *ev)
+{
+    writeSettings();
+    ev->accept();
+}
+
+void MainWindow::setupActions()
+{
+    connect(actionQuit, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
+
+    for(int i = 0; i < MaximumRecentFiles; ++i)
+    {
+        m_recentFileActs[i] = new QAction(this);
+        m_recentFileActs[i]->setVisible(false);
+        connect(m_recentFileActs[i], SIGNAL(triggered()),
+                this, SLOT(openRecentFile()));
+    }
+}
+
+void MainWindow::setupMenu()
+{
+    QMenu *const menFile = findChild<QMenu *>(QLatin1String("menuFile"));
+    Q_ASSERT(menFile);
+    QAction *const actOpen = findChild<QAction *>(QLatin1String("actionExecute"));
+    Q_ASSERT(actOpen);
+    QMenu *const recent = new QMenu(QLatin1String("O&pen Recent"), this);
+
+    menFile->insertMenu(actOpen, recent);
+    menFile->insertSeparator(actOpen);
+
+    for(int i = 0; i < MaximumRecentFiles; ++i)
+        recent->addAction(m_recentFileActs[i]);
+
+    updateRecentFileActions();
+
+    QMenu *const menWindows = findChild<QMenu *>(QLatin1String("menuWindows"));
+    Q_ASSERT(menWindows);
+
+    menWindows->addAction(testCaseView->toggleViewAction());
+    menWindows->addAction(testResultView->toggleViewAction());
+    menWindows->addAction(functionView->toggleViewAction());
+}
+
+void MainWindow::on_actionRestart_triggered()
+{
+    if(QProcess::startDetached(QCoreApplication::applicationFilePath()))
+        QApplication::closeAllWindows();
+    else
+    {
+        QTextStream err(stderr);
+        err << "Failed to start " << qPrintable(QCoreApplication::applicationFilePath()) << endl;
+    }
+}
+
+
+// vim: et:ts=4:sw=4:sts=4