Robert Phillips | a6d2d70 | 2017-09-01 12:17:03 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2017 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #include <QtWidgets> |
| 9 | |
| 10 | #include "MainWindow.h" |
| 11 | |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 12 | MainWindow::MainWindow() { |
Robert Phillips | a6d2d70 | 2017-09-01 12:17:03 -0400 | [diff] [blame] | 13 | this->createActions(); |
| 14 | this->createStatusBar(); |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 15 | this->createDockWindows(); |
| 16 | |
| 17 | this->setWindowTitle("MDB Viz"); |
| 18 | |
Robert Phillips | a6d2d70 | 2017-09-01 12:17:03 -0400 | [diff] [blame] | 19 | this->readSettings(); |
| 20 | this->setUnifiedTitleAndToolBarOnMac(true); |
| 21 | } |
| 22 | |
| 23 | void MainWindow::openFile() { |
| 24 | QString fileName = QFileDialog::getOpenFileName(this); |
| 25 | if (!fileName.isEmpty()) { |
| 26 | this->loadFile(fileName); |
| 27 | } |
| 28 | } |
| 29 | |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 30 | void MainWindow::setupOpListWidget() { |
| 31 | fOpListWidget->clear(); |
| 32 | |
Robert Phillips | 276066b | 2017-09-06 17:17:44 -0400 | [diff] [blame] | 33 | QTreeWidgetItem* item = nullptr; |
| 34 | SkTDArray<QTreeWidgetItem*> parents; |
| 35 | |
Robert Phillips | deaf568 | 2017-09-06 13:07:21 -0400 | [diff] [blame] | 36 | for (int i = 0; i < fModel.numOps(); i++) { |
Robert Phillips | 276066b | 2017-09-06 17:17:44 -0400 | [diff] [blame] | 37 | item = new QTreeWidgetItem(); |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 38 | |
Robert Phillips | 276066b | 2017-09-06 17:17:44 -0400 | [diff] [blame] | 39 | item->setText(0, QString::number(i)); |
| 40 | item->setData(0, Qt::UserRole, i); |
| 41 | item->setText(1, fModel.getOpName(i)); |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 42 | |
Robert Phillips | 276066b | 2017-09-06 17:17:44 -0400 | [diff] [blame] | 43 | if (fModel.isHierarchyPop(i)) { |
| 44 | parents.pop(); |
| 45 | } |
| 46 | |
| 47 | if (parents.isEmpty()) { |
| 48 | fOpListWidget->addTopLevelItem(item); |
| 49 | } else { |
| 50 | parents.top()->addChild(item); |
| 51 | } |
| 52 | |
| 53 | if (fModel.isHierarchyPush(i)) { |
| 54 | *parents.push() = item; |
| 55 | } |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 56 | } |
Robert Phillips | deaf568 | 2017-09-06 13:07:21 -0400 | [diff] [blame] | 57 | |
Robert Phillips | 276066b | 2017-09-06 17:17:44 -0400 | [diff] [blame] | 58 | fOpListWidget->setCurrentItem(item); |
| 59 | fOpListWidget->expandToDepth(100); |
Robert Phillips | deaf568 | 2017-09-06 13:07:21 -0400 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | void MainWindow::presentCurrentRenderState() { |
| 63 | fImage = QImage((uchar*)fModel.getPixels(), fModel.width(), fModel.height(), |
| 64 | QImage::Format_RGBA8888); |
| 65 | fImageLabel->setPixmap(QPixmap::fromImage(fImage)); |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 66 | } |
| 67 | |
Robert Phillips | a6d2d70 | 2017-09-01 12:17:03 -0400 | [diff] [blame] | 68 | void MainWindow::loadFile(const QString &fileName) { |
| 69 | QFile file(fileName); |
| 70 | if (!file.open(QFile::ReadOnly | QFile::Text)) { |
| 71 | QMessageBox::warning(this, tr("MDB Viz"), |
| 72 | tr("Cannot read file %1:\n%2.") |
| 73 | .arg(QDir::toNativeSeparators(fileName), file.errorString())); |
| 74 | return; |
| 75 | } |
| 76 | |
| 77 | QTextStream in(&file); |
| 78 | #ifndef QT_NO_CURSOR |
| 79 | QApplication::setOverrideCursor(Qt::WaitCursor); |
| 80 | #endif |
| 81 | |
| 82 | std::string str = file.fileName().toLocal8Bit().constData(); |
| 83 | |
Robert Phillips | deaf568 | 2017-09-06 13:07:21 -0400 | [diff] [blame] | 84 | Model::ErrorCode err = fModel.load(str.c_str()); |
| 85 | if (Model::ErrorCode::kOK != err) { |
| 86 | this->statusBar()->showMessage(Model::ErrorString(err)); |
Robert Phillips | a6d2d70 | 2017-09-01 12:17:03 -0400 | [diff] [blame] | 87 | return; |
| 88 | } |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 89 | |
| 90 | this->setupOpListWidget(); |
Robert Phillips | deaf568 | 2017-09-06 13:07:21 -0400 | [diff] [blame] | 91 | this->presentCurrentRenderState(); |
Robert Phillips | a6d2d70 | 2017-09-01 12:17:03 -0400 | [diff] [blame] | 92 | |
| 93 | #ifndef QT_NO_CURSOR |
| 94 | QApplication::restoreOverrideCursor(); |
| 95 | #endif |
| 96 | } |
| 97 | |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 98 | |
| 99 | void MainWindow::about() { |
| 100 | QMessageBox::about(this, "About MDB Viz", "Visualize MDB"); |
| 101 | } |
| 102 | |
Robert Phillips | a6d2d70 | 2017-09-01 12:17:03 -0400 | [diff] [blame] | 103 | void MainWindow::createActions() { |
| 104 | |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 105 | // File menu |
| 106 | QMenu* fileMenu = this->menuBar()->addMenu(tr("&File")); |
| 107 | QToolBar* fileToolBar = this->addToolBar(tr("File")); |
Robert Phillips | a6d2d70 | 2017-09-01 12:17:03 -0400 | [diff] [blame] | 108 | |
| 109 | const QIcon openIcon = QIcon::fromTheme("document-open", QIcon(":/images/open.png")); |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 110 | QAction* openAct = new QAction(openIcon, tr("&Open..."), this); |
Robert Phillips | a6d2d70 | 2017-09-01 12:17:03 -0400 | [diff] [blame] | 111 | openAct->setShortcuts(QKeySequence::Open); |
| 112 | openAct->setStatusTip(tr("Open an existing file")); |
| 113 | connect(openAct, &QAction::triggered, this, &MainWindow::openFile); |
| 114 | fileMenu->addAction(openAct); |
| 115 | fileToolBar->addAction(openAct); |
| 116 | |
| 117 | fileMenu->addSeparator(); |
| 118 | |
| 119 | const QIcon exitIcon = QIcon::fromTheme("application-exit"); |
| 120 | QAction *exitAct = fileMenu->addAction(exitIcon, tr("E&xit"), this, &QWidget::close); |
| 121 | exitAct->setShortcuts(QKeySequence::Quit); |
| 122 | exitAct->setStatusTip(tr("Exit the application")); |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 123 | |
| 124 | // View menu |
| 125 | fViewMenu = this->menuBar()->addMenu(tr("&View")); |
| 126 | |
| 127 | // Help menu |
| 128 | this->menuBar()->addSeparator(); |
| 129 | |
| 130 | QMenu* helpMenu = this->menuBar()->addMenu(tr("&Help")); |
| 131 | |
| 132 | QAction *aboutAct = helpMenu->addAction(tr("&About"), this, &MainWindow::about); |
| 133 | aboutAct->setStatusTip(tr("Show the application's About box")); |
Robert Phillips | a6d2d70 | 2017-09-01 12:17:03 -0400 | [diff] [blame] | 134 | } |
| 135 | |
Robert Phillips | 276066b | 2017-09-06 17:17:44 -0400 | [diff] [blame] | 136 | void MainWindow::onCurrentItemChanged(QTreeWidgetItem* cur, QTreeWidgetItem* /* prev */) { |
| 137 | int currentRow = cur->data(0, Qt::UserRole).toInt(); |
Robert Phillips | deaf568 | 2017-09-06 13:07:21 -0400 | [diff] [blame] | 138 | fModel.setCurOp(currentRow); |
| 139 | this->presentCurrentRenderState(); |
| 140 | } |
| 141 | |
Robert Phillips | a6d2d70 | 2017-09-01 12:17:03 -0400 | [diff] [blame] | 142 | void MainWindow::createStatusBar() { |
| 143 | this->statusBar()->showMessage(tr("Ready")); |
| 144 | } |
| 145 | |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 146 | void MainWindow::createDockWindows() { |
| 147 | |
| 148 | // Op List Window |
| 149 | { |
| 150 | QDockWidget* opListDock = new QDockWidget("Ops", this); |
| 151 | opListDock->setAllowedAreas(Qt::LeftDockWidgetArea); |
| 152 | |
Robert Phillips | 276066b | 2017-09-06 17:17:44 -0400 | [diff] [blame] | 153 | fOpListWidget = new QTreeWidget(opListDock); |
| 154 | |
| 155 | QTreeWidgetItem* headerItem = new QTreeWidgetItem; |
| 156 | headerItem->setText(0, "Index"); |
| 157 | headerItem->setText(1, "Op Name"); |
| 158 | fOpListWidget->setHeaderItem(headerItem); |
| 159 | |
| 160 | fOpListWidget->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); |
| 161 | fOpListWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 162 | |
| 163 | opListDock->setWidget(fOpListWidget); |
| 164 | this->addDockWidget(Qt::LeftDockWidgetArea, opListDock); |
| 165 | |
| 166 | fViewMenu->addAction(opListDock->toggleViewAction()); |
Robert Phillips | deaf568 | 2017-09-06 13:07:21 -0400 | [diff] [blame] | 167 | |
Robert Phillips | 276066b | 2017-09-06 17:17:44 -0400 | [diff] [blame] | 168 | connect(fOpListWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), |
| 169 | this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 170 | } |
| 171 | |
| 172 | // Main canvas Window |
| 173 | { |
| 174 | QDockWidget* mainCanvasDock = new QDockWidget("Main Canvas", this); |
| 175 | mainCanvasDock->setAllowedAreas(Qt::RightDockWidgetArea); |
| 176 | |
| 177 | fImageLabel = new QLabel(mainCanvasDock); |
| 178 | |
Robert Phillips | 276066b | 2017-09-06 17:17:44 -0400 | [diff] [blame] | 179 | fImage = QImage(1024, 1024, QImage::Format_RGBA8888); |
| 180 | fImage.fill(0); |
| 181 | fImageLabel->setPixmap(QPixmap::fromImage(fImage)); |
| 182 | |
Robert Phillips | 5fccf9d | 2017-09-05 15:10:12 -0400 | [diff] [blame] | 183 | mainCanvasDock->setWidget(fImageLabel); |
| 184 | this->addDockWidget(Qt::RightDockWidgetArea, mainCanvasDock); |
| 185 | |
| 186 | fViewMenu->addAction(mainCanvasDock->toggleViewAction()); |
| 187 | } |
| 188 | } |
| 189 | |
Robert Phillips | a6d2d70 | 2017-09-01 12:17:03 -0400 | [diff] [blame] | 190 | void MainWindow::readSettings() { |
| 191 | QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); |
| 192 | const QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray(); |
| 193 | if (geometry.isEmpty()) { |
| 194 | const QRect availableGeometry = QApplication::desktop()->availableGeometry(this); |
| 195 | resize(availableGeometry.width() / 3, availableGeometry.height() / 2); |
| 196 | move((availableGeometry.width() - width()) / 2, |
| 197 | (availableGeometry.height() - height()) / 2); |
| 198 | } else { |
| 199 | this->restoreGeometry(geometry); |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | void MainWindow::writeSettings() { |
| 204 | QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); |
| 205 | settings.setValue("geometry", this->saveGeometry()); |
| 206 | } |