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
MainWindow()12 MainWindow::MainWindow() {
13 this->createActions();
14 this->createStatusBar();
15 this->createDockWindows();
16
17 this->setWindowTitle("MDB Viz");
18
19 this->readSettings();
20 this->setUnifiedTitleAndToolBarOnMac(true);
21 }
22
openFile()23 void MainWindow::openFile() {
24 QString fileName = QFileDialog::getOpenFileName(this);
25 if (!fileName.isEmpty()) {
26 this->loadFile(fileName);
27 }
28 }
29
setupOpsTaskWidget()30 void MainWindow::setupOpsTaskWidget() {
31 fOpsTaskWidget->clear();
32
33 QTreeWidgetItem* item = nullptr;
34 SkTDArray<QTreeWidgetItem*> parents;
35
36 for (int i = 0; i < fModel.numOps(); i++) {
37 item = new QTreeWidgetItem();
38
39 item->setText(0, QString::number(i));
40 item->setData(0, Qt::UserRole, i);
41 item->setText(1, fModel.getOpName(i));
42
43 if (fModel.isHierarchyPop(i)) {
44 parents.pop();
45 }
46
47 if (parents.isEmpty()) {
48 fOpsTaskWidget->addTopLevelItem(item);
49 } else {
50 parents.top()->addChild(item);
51 }
52
53 if (fModel.isHierarchyPush(i)) {
54 *parents.push() = item;
55 }
56 }
57
58 fOpsTaskWidget->setCurrentItem(item);
59 fOpsTaskWidget->expandToDepth(100);
60 }
61
presentCurrentRenderState()62 void MainWindow::presentCurrentRenderState() {
63 fImage = QImage((uchar*)fModel.getPixels(), fModel.width(), fModel.height(),
64 QImage::Format_RGBA8888);
65 fImageLabel->setPixmap(QPixmap::fromImage(fImage));
66 }
67
loadFile(const QString & fileName)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
84 Model::ErrorCode err = fModel.load(str.c_str());
85 if (Model::ErrorCode::kOK != err) {
86 this->statusBar()->showMessage(Model::ErrorString(err));
87 return;
88 }
89
90 this->setupOpsTaskWidget();
91 this->presentCurrentRenderState();
92
93 #ifndef QT_NO_CURSOR
94 QApplication::restoreOverrideCursor();
95 #endif
96 }
97
98
about()99 void MainWindow::about() {
100 QMessageBox::about(this, "About MDB Viz", "Visualize MDB");
101 }
102
createActions()103 void MainWindow::createActions() {
104
105 // File menu
106 QMenu* fileMenu = this->menuBar()->addMenu(tr("&File"));
107 QToolBar* fileToolBar = this->addToolBar(tr("File"));
108
109 const QIcon openIcon = QIcon::fromTheme("document-open", QIcon(":/images/open.png"));
110 QAction* openAct = new QAction(openIcon, tr("&Open..."), this);
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"));
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"));
134 }
135
onCurrentItemChanged(QTreeWidgetItem * cur,QTreeWidgetItem *)136 void MainWindow::onCurrentItemChanged(QTreeWidgetItem* cur, QTreeWidgetItem* /* prev */) {
137 int currentRow = cur->data(0, Qt::UserRole).toInt();
138 fModel.setCurOp(currentRow);
139 this->presentCurrentRenderState();
140 }
141
createStatusBar()142 void MainWindow::createStatusBar() {
143 this->statusBar()->showMessage(tr("Ready"));
144 }
145
createDockWindows()146 void MainWindow::createDockWindows() {
147
148 // Op List Window
149 {
150 QDockWidget* opsTaskDock = new QDockWidget("Ops", this);
151 opsTaskDock->setAllowedAreas(Qt::LeftDockWidgetArea);
152
153 fOpsTaskWidget = new QTreeWidget(opsTaskDock);
154
155 QTreeWidgetItem* headerItem = new QTreeWidgetItem;
156 headerItem->setText(0, "Index");
157 headerItem->setText(1, "Op Name");
158 fOpsTaskWidget->setHeaderItem(headerItem);
159
160 fOpsTaskWidget->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
161 fOpsTaskWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
162
163 opsTaskDock->setWidget(fOpsTaskWidget);
164 this->addDockWidget(Qt::LeftDockWidgetArea, opsTaskDock);
165
166 fViewMenu->addAction(opsTaskDock->toggleViewAction());
167
168 connect(fOpsTaskWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
169 this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
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
179 fImage = QImage(1024, 1024, QImage::Format_RGBA8888);
180 fImage.fill(0);
181 fImageLabel->setPixmap(QPixmap::fromImage(fImage));
182
183 mainCanvasDock->setWidget(fImageLabel);
184 this->addDockWidget(Qt::RightDockWidgetArea, mainCanvasDock);
185
186 fViewMenu->addAction(mainCanvasDock->toggleViewAction());
187 }
188 }
189
readSettings()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
writeSettings()203 void MainWindow::writeSettings() {
204 QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
205 settings.setValue("geometry", this->saveGeometry());
206 }
207