[MDBViz] Switch from a QListView to a QTreeView for the ops

This lets us open & close groups and automates the hierarchy.

Change-Id: Ib6f0850a49b793d824fc25aa16be78e6a1a93d9e
Reviewed-on: https://skia-review.googlesource.com/43280
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 6796850..1c328b0 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1736,6 +1736,7 @@
       ]
       include_dirs = [
         "$skia_qt_path/include",
+        "$skia_qt_path/include/QtCore",
         "$skia_qt_path/include/QtWidgets",
         "tools",
         "tools/debugger",
diff --git a/tools/mdbviz/Model.cpp b/tools/mdbviz/Model.cpp
index a3f8e1a..c292956 100644
--- a/tools/mdbviz/Model.cpp
+++ b/tools/mdbviz/Model.cpp
@@ -61,10 +61,25 @@
     return kStrings[(int)err];
 }
 
-const char* Model::getOpName(int index) {
+const char* Model::getOpName(int index) const {
     return SkDrawCommand::GetCommandString(fOps[index]->getType());
 }
 
+bool Model::isHierarchyPush(int index) const {
+    SkDrawCommand::OpType type = fOps[index]->getType();
+
+    return SkDrawCommand::kSave_OpType == type ||
+           SkDrawCommand::kSaveLayer_OpType == type ||
+           SkDrawCommand::kBeginDrawPicture_OpType == type;
+}
+
+bool Model::isHierarchyPop(int index) const {
+    SkDrawCommand::OpType type = fOps[index]->getType();
+
+    return SkDrawCommand::kRestore_OpType == type ||
+           SkDrawCommand::kEndDrawPicture_OpType == type;
+}
+
 void Model::setCurOp(int curOp) {
     SkASSERT(curOp < fOps.count());
 
@@ -96,5 +111,6 @@
     for (int i = 0; i < fOps.count(); ++i) {
         delete fOps[i];
     }
+    fOps.reset();
     fCurOp = 0;
 }
diff --git a/tools/mdbviz/Model.h b/tools/mdbviz/Model.h
index 773c148..8448701 100644
--- a/tools/mdbviz/Model.h
+++ b/tools/mdbviz/Model.h
@@ -35,7 +35,10 @@
     int curOp() const { return fCurOp; }
 
     int numOps() const { return fOps.count(); }
-    const char* getOpName(int index);
+    const char* getOpName(int index) const;
+
+    bool isHierarchyPush(int index) const;
+    bool isHierarchyPop(int index) const;
 
     // Get the bits visually representing the current rendering state
     void* getPixels() const { return fBM.getPixels(); }
diff --git a/tools/mdbviz/mainwindow.cpp b/tools/mdbviz/mainwindow.cpp
index c09ad09..5f5746b 100644
--- a/tools/mdbviz/mainwindow.cpp
+++ b/tools/mdbviz/mainwindow.cpp
@@ -30,15 +30,33 @@
 void MainWindow::setupOpListWidget() {
     fOpListWidget->clear();
 
+    QTreeWidgetItem* item = nullptr;
+    SkTDArray<QTreeWidgetItem*> parents;
+
     for (int i = 0; i < fModel.numOps(); i++) {
-        QListWidgetItem *item = new QListWidgetItem();
+        item = new QTreeWidgetItem();
 
-        item->setData(Qt::DisplayRole, fModel.getOpName(i));
+        item->setText(0, QString::number(i));
+        item->setData(0, Qt::UserRole, i);
+        item->setText(1, fModel.getOpName(i));
 
-        fOpListWidget->addItem(item);
+        if (fModel.isHierarchyPop(i)) {
+            parents.pop();
+        }
+
+        if (parents.isEmpty()) {
+            fOpListWidget->addTopLevelItem(item);
+        } else {
+            parents.top()->addChild(item);
+        }
+
+        if (fModel.isHierarchyPush(i)) {
+            *parents.push() = item;
+        }
     }
 
-    fOpListWidget->setCurrentRow(fModel.numOps()-1);
+    fOpListWidget->setCurrentItem(item);
+    fOpListWidget->expandToDepth(100);
 }
 
 void MainWindow::presentCurrentRenderState() {
@@ -115,7 +133,8 @@
     aboutAct->setStatusTip(tr("Show the application's About box"));
 }
 
-void MainWindow::onCurrentRowChanged(int currentRow) {
+void MainWindow::onCurrentItemChanged(QTreeWidgetItem* cur, QTreeWidgetItem* /* prev */) {
+    int currentRow = cur->data(0, Qt::UserRole).toInt();
     fModel.setCurOp(currentRow);
     this->presentCurrentRenderState();
 }
@@ -131,14 +150,23 @@
         QDockWidget* opListDock = new QDockWidget("Ops", this);
         opListDock->setAllowedAreas(Qt::LeftDockWidgetArea);
 
-        fOpListWidget = new QListWidget(opListDock);
+        fOpListWidget = new QTreeWidget(opListDock);
+
+        QTreeWidgetItem* headerItem = new QTreeWidgetItem;
+        headerItem->setText(0, "Index");
+        headerItem->setText(1, "Op Name");
+        fOpListWidget->setHeaderItem(headerItem);
+
+        fOpListWidget->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+        fOpListWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
 
         opListDock->setWidget(fOpListWidget);
         this->addDockWidget(Qt::LeftDockWidgetArea, opListDock);
 
         fViewMenu->addAction(opListDock->toggleViewAction());
 
-        connect(fOpListWidget, SIGNAL(currentRowChanged(int)), this, SLOT(onCurrentRowChanged(int)));
+        connect(fOpListWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
+                this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
     }
 
     // Main canvas Window
@@ -148,6 +176,10 @@
 
         fImageLabel = new QLabel(mainCanvasDock);
 
+        fImage = QImage(1024, 1024, QImage::Format_RGBA8888);
+        fImage.fill(0);
+        fImageLabel->setPixmap(QPixmap::fromImage(fImage));
+
         mainCanvasDock->setWidget(fImageLabel);
         this->addDockWidget(Qt::RightDockWidgetArea, mainCanvasDock);
 
diff --git a/tools/mdbviz/mainwindow.h b/tools/mdbviz/mainwindow.h
index 59e7b98..9a7e9db 100644
--- a/tools/mdbviz/mainwindow.h
+++ b/tools/mdbviz/mainwindow.h
@@ -14,8 +14,9 @@
 #include "Model.h"
 
 class QLabel;
-class QListWidget;
 class QMenu;
+class QTreeWidget;
+class QTreeWidgetItem;
 
 
 class MainWindow : public QMainWindow {
@@ -27,7 +28,7 @@
 private slots:
     void openFile();
     void about();
-    void onCurrentRowChanged(int currentRow);
+    void onCurrentItemChanged(QTreeWidgetItem* cur, QTreeWidgetItem* prev);
 
 private:
     void loadFile(const QString &fileName);
@@ -45,7 +46,7 @@
     QImage  fImage;
     QLabel* fImageLabel;
 
-    QListWidget* fOpListWidget;
+    QTreeWidget* fOpListWidget;
 
     QMenu* fViewMenu;