Home | History | Annotate | Download | only in QT
      1 /*
      2  * Copyright 2012 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 "SkDebuggerGUI.h"
      9 #include "SkPicture.h"
     10 #include <QListWidgetItem>
     11 #include <QtGui>
     12 #include "sk_tool_utils.h"
     13 
     14 SkDebuggerGUI::SkDebuggerGUI(QWidget *parent) :
     15         QMainWindow(parent)
     16     , fCentralSplitter(this)
     17     , fStatusBar(this)
     18     , fToolBar(this)
     19     , fActionOpen(this)
     20     , fActionBreakpoint(this)
     21     , fActionCancel(this)
     22     , fActionClearBreakpoints(this)
     23     , fActionClearDeletes(this)
     24     , fActionClose(this)
     25     , fActionCreateBreakpoint(this)
     26     , fActionDelete(this)
     27     , fActionDirectory(this)
     28     , fActionGoToLine(this)
     29     , fActionInspector(this)
     30     , fActionSettings(this)
     31     , fActionPlay(this)
     32     , fActionPause(this)
     33     , fActionRewind(this)
     34     , fActionSave(this)
     35     , fActionSaveAs(this)
     36     , fActionShowDeletes(this)
     37     , fActionStepBack(this)
     38     , fActionStepForward(this)
     39     , fActionZoomIn(this)
     40     , fActionZoomOut(this)
     41     , fMapper(this)
     42     , fListWidget(&fCentralSplitter)
     43     , fDirectoryWidget(&fCentralSplitter)
     44     , fCanvasWidget(this, &fDebugger)
     45     , fDrawCommandGeometryWidget(&fDebugger)
     46     , fMenuBar(this)
     47     , fMenuFile(this)
     48     , fMenuNavigate(this)
     49     , fMenuView(this)
     50     , fLoading(false)
     51 {
     52     setupUi(this);
     53     fListWidget.setSelectionMode(QAbstractItemView::ExtendedSelection);
     54     connect(&fListWidget, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this,
     55             SLOT(updateDrawCommandInfo()));
     56     connect(&fActionOpen, SIGNAL(triggered()), this, SLOT(openFile()));
     57     connect(&fActionDirectory, SIGNAL(triggered()), this, SLOT(toggleDirectory()));
     58     connect(&fDirectoryWidget, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, SLOT(loadFile(QListWidgetItem *)));
     59     connect(&fDirectoryWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(populateDirectoryWidget()));
     60     connect(&fActionDelete, SIGNAL(triggered()), this, SLOT(actionDelete()));
     61     connect(&fListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(toggleBreakpoint()));
     62     connect(&fActionRewind, SIGNAL(triggered()), this, SLOT(actionRewind()));
     63     connect(&fActionPlay, SIGNAL(triggered()), this, SLOT(actionPlay()));
     64     connect(&fActionStepBack, SIGNAL(triggered()), this, SLOT(actionStepBack()));
     65     connect(&fActionStepForward, SIGNAL(triggered()), this, SLOT(actionStepForward()));
     66     connect(&fActionBreakpoint, SIGNAL(triggered()), this, SLOT(actionBreakpoints()));
     67     connect(&fActionInspector, SIGNAL(triggered()), this, SLOT(actionInspector()));
     68     connect(&fActionSettings, SIGNAL(triggered()), this, SLOT(actionSettings()));
     69     connect(&fFilter, SIGNAL(activated(QString)), this, SLOT(toggleFilter(QString)));
     70     connect(&fActionCancel, SIGNAL(triggered()), this, SLOT(actionCancel()));
     71     connect(&fActionClearBreakpoints, SIGNAL(triggered()), this, SLOT(actionClearBreakpoints()));
     72     connect(&fActionClearDeletes, SIGNAL(triggered()), this, SLOT(actionClearDeletes()));
     73     connect(&fActionClose, SIGNAL(triggered()), this, SLOT(actionClose()));
     74 #if SK_SUPPORT_GPU
     75     connect(&fSettingsWidget, SIGNAL(glSettingsChanged()), this, SLOT(actionGLSettingsChanged()));
     76 #endif
     77     connect(&fSettingsWidget, SIGNAL(rasterSettingsChanged()), this, SLOT(actionRasterSettingsChanged()));
     78     connect(&fSettingsWidget, SIGNAL(visualizationsChanged()), this, SLOT(actionVisualizationsChanged()));
     79     connect(&fSettingsWidget, SIGNAL(texFilterSettingsChanged()), this, SLOT(actionTextureFilter()));
     80     connect(&fActionPause, SIGNAL(toggled(bool)), this, SLOT(pauseDrawing(bool)));
     81     connect(&fActionCreateBreakpoint, SIGNAL(activated()), this, SLOT(toggleBreakpoint()));
     82     connect(&fActionShowDeletes, SIGNAL(triggered()), this, SLOT(showDeletes()));
     83     connect(&fCanvasWidget, SIGNAL(hitChanged(int)), this, SLOT(selectCommand(int)));
     84     connect(&fCanvasWidget, SIGNAL(hitChanged(int)), this, SLOT(updateHit(int)));
     85     connect(&fCanvasWidget, SIGNAL(scaleFactorChanged(float)), this, SLOT(actionScale(float)));
     86 
     87     connect(&fActionSaveAs, SIGNAL(triggered()), this, SLOT(actionSaveAs()));
     88     connect(&fActionSave, SIGNAL(triggered()), this, SLOT(actionSave()));
     89 
     90     fMapper.setMapping(&fActionZoomIn, SkCanvasWidget::kIn_ZoomCommand);
     91     fMapper.setMapping(&fActionZoomOut, SkCanvasWidget::kOut_ZoomCommand);
     92 
     93     connect(&fActionZoomIn, SIGNAL(triggered()), &fMapper, SLOT(map()));
     94     connect(&fActionZoomOut, SIGNAL(triggered()), &fMapper, SLOT(map()));
     95     connect(&fMapper, SIGNAL(mapped(int)), &fCanvasWidget, SLOT(zoom(int)));
     96 
     97     fViewStateFrame.setDisabled(true);
     98     fInspectorWidget.setDisabled(true);
     99     fMenuEdit.setDisabled(true);
    100     fMenuNavigate.setDisabled(true);
    101     fMenuView.setDisabled(true);
    102 }
    103 
    104 void SkDebuggerGUI::actionBreakpoints() {
    105     bool breakpointsActivated = fActionBreakpoint.isChecked();
    106     for (int row = 0; row < fListWidget.count(); row++) {
    107         QListWidgetItem *item = fListWidget.item(row);
    108         item->setHidden(item->checkState() == Qt::Unchecked && breakpointsActivated);
    109     }
    110 }
    111 
    112 void SkDebuggerGUI::showDeletes() {
    113     bool deletesActivated = fActionShowDeletes.isChecked();
    114     for (int row = 0; row < fListWidget.count(); row++) {
    115         QListWidgetItem *item = fListWidget.item(row);
    116         item->setHidden(fDebugger.isCommandVisible(row) && deletesActivated);
    117     }
    118 }
    119 
    120 void SkDebuggerGUI::actionCancel() {
    121     for (int row = 0; row < fListWidget.count(); row++) {
    122         fListWidget.item(row)->setHidden(false);
    123     }
    124 }
    125 
    126 void SkDebuggerGUI::actionClearBreakpoints() {
    127     for (int row = 0; row < fListWidget.count(); row++) {
    128         QListWidgetItem* item = fListWidget.item(row);
    129         item->setCheckState(Qt::Unchecked);
    130         item->setData(Qt::DecorationRole,
    131                 QPixmap(":/blank.png"));
    132     }
    133 }
    134 
    135 void SkDebuggerGUI::actionClearDeletes() {
    136     for (int row = 0; row < fListWidget.count(); row++) {
    137         QListWidgetItem* item = fListWidget.item(row);
    138         item->setData(Qt::UserRole + 2, QPixmap(":/blank.png"));
    139         fDebugger.setCommandVisible(row, true);
    140         fSkipCommands[row] = false;
    141     }
    142     this->updateImage();
    143 }
    144 
    145 void SkDebuggerGUI::actionClose() {
    146     this->close();
    147 }
    148 
    149 void SkDebuggerGUI::actionDelete() {
    150 
    151     for (int row = 0; row < fListWidget.count(); ++row) {
    152         QListWidgetItem* item = fListWidget.item(row);
    153 
    154         if (!item->isSelected()) {
    155             continue;
    156         }
    157 
    158         if (fDebugger.isCommandVisible(row)) {
    159             item->setData(Qt::UserRole + 2, QPixmap(":/delete.png"));
    160             fDebugger.setCommandVisible(row, false);
    161             fSkipCommands[row] = true;
    162         } else {
    163             item->setData(Qt::UserRole + 2, QPixmap(":/blank.png"));
    164             fDebugger.setCommandVisible(row, true);
    165             fSkipCommands[row] = false;
    166         }
    167     }
    168 
    169     this->updateImage();
    170 }
    171 
    172 #if SK_SUPPORT_GPU
    173 void SkDebuggerGUI::actionGLSettingsChanged() {
    174     bool isToggled = fSettingsWidget.isGLActive();
    175     if (isToggled) {
    176         fCanvasWidget.setGLSampleCount(fSettingsWidget.getGLSampleCount());
    177     }
    178     fCanvasWidget.setWidgetVisibility(SkCanvasWidget::kGPU_WidgetType, !isToggled);
    179 }
    180 #endif
    181 
    182 void SkDebuggerGUI::actionInspector() {
    183     bool newState = !fInspectorWidget.isHidden();
    184 
    185     fInspectorWidget.setHidden(newState);
    186     fViewStateFrame.setHidden(newState);
    187     fDrawCommandGeometryWidget.setHidden(newState);
    188 }
    189 
    190 void SkDebuggerGUI::actionPlay() {
    191     for (int row = fListWidget.currentRow() + 1; row < fListWidget.count();
    192             row++) {
    193         QListWidgetItem *item = fListWidget.item(row);
    194         if (item->checkState() == Qt::Checked) {
    195             fListWidget.setCurrentItem(item);
    196             return;
    197         }
    198     }
    199     fListWidget.setCurrentRow(fListWidget.count() - 1);
    200 }
    201 
    202 void SkDebuggerGUI::actionRasterSettingsChanged() {
    203     fCanvasWidget.setWidgetVisibility(SkCanvasWidget::kRaster_8888_WidgetType,
    204                                       !fSettingsWidget.isRasterEnabled());
    205     this->updateImage();
    206 }
    207 
    208 void SkDebuggerGUI::actionVisualizationsChanged() {
    209     fDebugger.setMegaViz(fSettingsWidget.isMegaVizEnabled());
    210     fDebugger.setPathOps(fSettingsWidget.isPathOpsEnabled());
    211     fDebugger.highlightCurrentCommand(fSettingsWidget.isVisibilityFilterEnabled());
    212     fDebugger.setOverdrawViz(fSettingsWidget.isOverdrawVizEnabled());
    213     this->updateImage();
    214 }
    215 
    216 void SkDebuggerGUI::actionTextureFilter() {
    217     SkFilterQuality quality;
    218     bool enabled = fSettingsWidget.getFilterOverride(&quality);
    219     fDebugger.setTexFilterOverride(enabled, quality);
    220     fCanvasWidget.update();
    221 }
    222 
    223 void SkDebuggerGUI::actionRewind() {
    224     fListWidget.setCurrentRow(0);
    225 }
    226 
    227 void SkDebuggerGUI::actionSave() {
    228     fFileName = fPath.toAscii().data();
    229     fFileName.append("/");
    230     fFileName.append(fDirectoryWidget.currentItem()->text().toAscii().data());
    231     saveToFile(fFileName);
    232 }
    233 
    234 void SkDebuggerGUI::actionSaveAs() {
    235     QString filename = QFileDialog::getSaveFileName(this, "Save File", "",
    236             "Skia Picture (*skp)");
    237     if (!filename.endsWith(".skp", Qt::CaseInsensitive)) {
    238         filename.append(".skp");
    239     }
    240     saveToFile(SkString(filename.toAscii().data()));
    241 }
    242 
    243 void SkDebuggerGUI::actionScale(float scaleFactor) {
    244     fZoomBox.setText(QString::number(scaleFactor * 100, 'f', 0).append("%"));
    245 }
    246 
    247 void SkDebuggerGUI::actionSettings() {
    248     if (fSettingsWidget.isHidden()) {
    249         fSettingsWidget.setHidden(false);
    250     } else {
    251         fSettingsWidget.setHidden(true);
    252     }
    253 }
    254 
    255 void SkDebuggerGUI::actionStepBack() {
    256     int currentRow = fListWidget.currentRow();
    257     if (currentRow != 0) {
    258         fListWidget.setCurrentRow(currentRow - 1);
    259     }
    260 }
    261 
    262 void SkDebuggerGUI::actionStepForward() {
    263     int currentRow = fListWidget.currentRow();
    264     QString curRow = QString::number(currentRow);
    265     QString curCount = QString::number(fListWidget.count());
    266     if (currentRow < fListWidget.count() - 1) {
    267         fListWidget.setCurrentRow(currentRow + 1);
    268     }
    269 }
    270 
    271 void SkDebuggerGUI::drawComplete() {
    272     SkString clipStack;
    273     fDebugger.getClipStackText(&clipStack);
    274     fInspectorWidget.setText(clipStack.c_str(), SkInspectorWidget::kClipStack_TabType);
    275 
    276     fInspectorWidget.setMatrix(fDebugger.getCurrentMatrix());
    277     fInspectorWidget.setClip(fDebugger.getCurrentClip());
    278 }
    279 
    280 void SkDebuggerGUI::saveToFile(const SkString& filename) {
    281     SkFILEWStream file(filename.c_str());
    282     sk_sp<SkPicture> copy(fDebugger.copyPicture());
    283 
    284     sk_sp<SkPixelSerializer> serializer(sk_tool_utils::MakePixelSerializer());
    285     copy->serialize(&file, serializer.get());
    286 }
    287 
    288 void SkDebuggerGUI::loadFile(QListWidgetItem *item) {
    289     if (item == nullptr) {
    290         return;
    291     }
    292 
    293     SkString fileName(fPath.toAscii().data());
    294     // don't add a '/' to files in the local directory
    295     if (fileName.size() > 0) {
    296         fileName.append("/");
    297     }
    298     fileName.append(item->text().toAscii().data());
    299 
    300     if (!fileName.equals(fFileName)) {
    301         fFileName = fileName;
    302         loadPicture(fFileName);
    303     }
    304 }
    305 
    306 void SkDebuggerGUI::openFile() {
    307     QString temp = QFileDialog::getOpenFileName(this, tr("Open File"), "",
    308             tr("Files (*.*)"));
    309     openFile(temp);
    310 }
    311 
    312 void SkDebuggerGUI::openFile(const QString &filename) {
    313     if (!filename.isEmpty()) {
    314         QFileInfo pathInfo(filename);
    315         loadPicture(SkString(filename.toAscii().data()));
    316         setupDirectoryWidget(pathInfo.path());
    317     }
    318 }
    319 
    320 void SkDebuggerGUI::pauseDrawing(bool isPaused) {
    321     fPausedRow = fListWidget.currentRow();
    322     this->updateDrawCommandInfo();
    323 }
    324 
    325 void SkDebuggerGUI::updateDrawCommandInfo() {
    326     int currentRow = -1;
    327     if (!fLoading) {
    328         currentRow = fListWidget.currentRow();
    329     }
    330     if (currentRow == -1) {
    331         fInspectorWidget.setText("", SkInspectorWidget::kDetail_TabType);
    332         fInspectorWidget.setText("", SkInspectorWidget::kClipStack_TabType);
    333         fCurrentCommandBox.setText("");
    334         fDrawCommandGeometryWidget.setDrawCommandIndex(-1);
    335     } else {
    336         this->updateImage();
    337 
    338         const SkTDArray<SkString*> *currInfo = fDebugger.getCommandInfo(currentRow);
    339 
    340         /* TODO(chudy): Add command type before parameters. Rename v
    341          * to something more informative. */
    342         if (currInfo) {
    343             QString info;
    344             info.append("<b>Parameters: </b><br/>");
    345             for (int i = 0; i < currInfo->count(); i++) {
    346                 info.append(QString((*currInfo)[i]->c_str()));
    347                 info.append("<br/>");
    348             }
    349             fInspectorWidget.setText(info, SkInspectorWidget::kDetail_TabType);
    350         }
    351 
    352         fCurrentCommandBox.setText(QString::number(currentRow));
    353 
    354         fDrawCommandGeometryWidget.setDrawCommandIndex(currentRow);
    355 
    356         fInspectorWidget.setDisabled(false);
    357         fViewStateFrame.setDisabled(false);
    358     }
    359 }
    360 
    361 void SkDebuggerGUI::selectCommand(int command) {
    362     if (this->isPaused()) {
    363         fListWidget.setCurrentRow(command);
    364     }
    365 }
    366 
    367 void SkDebuggerGUI::toggleBreakpoint() {
    368     QListWidgetItem* item = fListWidget.currentItem();
    369     if (item->checkState() == Qt::Unchecked) {
    370         item->setCheckState(Qt::Checked);
    371         item->setData(Qt::DecorationRole,
    372                 QPixmap(":/breakpoint_16x16.png"));
    373     } else {
    374         item->setCheckState(Qt::Unchecked);
    375         item->setData(Qt::DecorationRole,
    376                 QPixmap(":/blank.png"));
    377     }
    378 }
    379 
    380 void SkDebuggerGUI::toggleDirectory() {
    381     fDirectoryWidget.setHidden(!fDirectoryWidget.isHidden());
    382 }
    383 
    384 void SkDebuggerGUI::toggleFilter(QString string) {
    385     for (int row = 0; row < fListWidget.count(); row++) {
    386         QListWidgetItem *item = fListWidget.item(row);
    387         item->setHidden(item->text() != string);
    388     }
    389 }
    390 
    391 void SkDebuggerGUI::setupUi(QMainWindow *SkDebuggerGUI) {
    392     QIcon windowIcon;
    393     windowIcon.addFile(QString::fromUtf8(":/skia.png"), QSize(),
    394             QIcon::Normal, QIcon::Off);
    395     SkDebuggerGUI->setObjectName(QString::fromUtf8("SkDebuggerGUI"));
    396     SkDebuggerGUI->resize(1200, 1000);
    397     SkDebuggerGUI->setWindowIcon(windowIcon);
    398     SkDebuggerGUI->setWindowTitle("Skia Debugger");
    399 
    400     fActionOpen.setShortcuts(QKeySequence::Open);
    401     fActionOpen.setText("Open");
    402 
    403     QIcon breakpoint;
    404     breakpoint.addFile(QString::fromUtf8(":/breakpoint.png"),
    405             QSize(), QIcon::Normal, QIcon::Off);
    406     fActionBreakpoint.setShortcut(QKeySequence(tr("Ctrl+B")));
    407     fActionBreakpoint.setIcon(breakpoint);
    408     fActionBreakpoint.setText("Breakpoints");
    409     fActionBreakpoint.setCheckable(true);
    410 
    411     QIcon cancel;
    412     cancel.addFile(QString::fromUtf8(":/reload.png"), QSize(),
    413             QIcon::Normal, QIcon::Off);
    414     fActionCancel.setIcon(cancel);
    415     fActionCancel.setText("Clear Filter");
    416 
    417     fActionClearBreakpoints.setShortcut(QKeySequence(tr("Alt+B")));
    418     fActionClearBreakpoints.setText("Clear Breakpoints");
    419 
    420     fActionClearDeletes.setShortcut(QKeySequence(tr("Alt+X")));
    421     fActionClearDeletes.setText("Clear Deletes");
    422 
    423     fActionClose.setShortcuts(QKeySequence::Quit);
    424     fActionClose.setText("Exit");
    425 
    426     fActionCreateBreakpoint.setShortcut(QKeySequence(tr("B")));
    427     fActionCreateBreakpoint.setText("Set Breakpoint");
    428 
    429     fActionDelete.setShortcut(QKeySequence(tr("X")));
    430     fActionDelete.setText("Delete Command");
    431 
    432     fActionDirectory.setShortcut(QKeySequence(tr("Ctrl+D")));
    433     fActionDirectory.setText("Directory");
    434 
    435     QIcon inspector;
    436     inspector.addFile(QString::fromUtf8(":/inspector.png"),
    437             QSize(), QIcon::Normal, QIcon::Off);
    438     fActionInspector.setShortcut(QKeySequence(tr("Ctrl+I")));
    439     fActionInspector.setIcon(inspector);
    440     fActionInspector.setText("Inspector");
    441 
    442     QIcon settings;
    443     settings.addFile(QString::fromUtf8(":/inspector.png"),
    444             QSize(), QIcon::Normal, QIcon::Off);
    445     fActionSettings.setShortcut(QKeySequence(tr("Ctrl+G")));
    446     fActionSettings.setIcon(settings);
    447     fActionSettings.setText("Settings");
    448 
    449     QIcon play;
    450     play.addFile(QString::fromUtf8(":/play.png"), QSize(),
    451             QIcon::Normal, QIcon::Off);
    452     fActionPlay.setShortcut(QKeySequence(tr("Ctrl+P")));
    453     fActionPlay.setIcon(play);
    454     fActionPlay.setText("Play");
    455 
    456     QIcon pause;
    457     pause.addFile(QString::fromUtf8(":/pause.png"), QSize(),
    458             QIcon::Normal, QIcon::Off);
    459     fActionPause.setShortcut(QKeySequence(tr("Space")));
    460     fActionPause.setCheckable(true);
    461     fActionPause.setIcon(pause);
    462     fActionPause.setText("Pause");
    463 
    464     QIcon rewind;
    465     rewind.addFile(QString::fromUtf8(":/rewind.png"), QSize(),
    466             QIcon::Normal, QIcon::Off);
    467     fActionRewind.setShortcut(QKeySequence(tr("Ctrl+R")));
    468     fActionRewind.setIcon(rewind);
    469     fActionRewind.setText("Rewind");
    470 
    471     fActionSave.setShortcut(QKeySequence::Save);
    472     fActionSave.setText("Save");
    473     fActionSave.setDisabled(true);
    474     fActionSaveAs.setShortcut(QKeySequence::SaveAs);
    475     fActionSaveAs.setText("Save As");
    476     fActionSaveAs.setDisabled(true);
    477 
    478     fActionShowDeletes.setShortcut(QKeySequence(tr("Ctrl+X")));
    479     fActionShowDeletes.setText("Deleted Commands");
    480     fActionShowDeletes.setCheckable(true);
    481 
    482     QIcon stepBack;
    483     stepBack.addFile(QString::fromUtf8(":/previous.png"), QSize(),
    484             QIcon::Normal, QIcon::Off);
    485     fActionStepBack.setShortcut(QKeySequence(tr("[")));
    486     fActionStepBack.setIcon(stepBack);
    487     fActionStepBack.setText("Step Back");
    488 
    489     QIcon stepForward;
    490     stepForward.addFile(QString::fromUtf8(":/next.png"),
    491             QSize(), QIcon::Normal, QIcon::Off);
    492     fActionStepForward.setShortcut(QKeySequence(tr("]")));
    493     fActionStepForward.setIcon(stepForward);
    494     fActionStepForward.setText("Step Forward");
    495 
    496     fActionZoomIn.setShortcut(QKeySequence(tr("Ctrl+=")));
    497     fActionZoomIn.setText("Zoom In");
    498     fActionZoomOut.setShortcut(QKeySequence(tr("Ctrl+-")));
    499     fActionZoomOut.setText("Zoom Out");
    500 
    501     fListWidget.setItemDelegate(new SkListWidget(&fListWidget));
    502     fListWidget.setObjectName(QString::fromUtf8("listWidget"));
    503     fListWidget.setMinimumWidth(250);
    504 
    505     fFilter.addItem("--Filter By Available Commands--");
    506 
    507     fDirectoryWidget.setMinimumWidth(250);
    508     fDirectoryWidget.setStyleSheet("QListWidget::Item {padding: 5px;}");
    509 
    510     fCanvasWidget.setSizePolicy(QSizePolicy::Expanding,
    511             QSizePolicy::Expanding);
    512 
    513     fDrawCommandGeometryWidget.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    514 
    515     fSettingsAndImageLayout.addWidget(&fSettingsWidget);
    516 
    517     // View state group, part of inspector.
    518     fViewStateFrame.setFrameStyle(QFrame::Panel);
    519     fViewStateFrame.setLayout(&fViewStateFrameLayout);
    520     fViewStateFrameLayout.addWidget(&fViewStateGroup);
    521     fViewStateGroup.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
    522     fViewStateGroup.setTitle("View");
    523     fViewStateLayout.addRow("Zoom Level", &fZoomBox);
    524     fZoomBox.setText("100%");
    525     fZoomBox.setMinimumSize(QSize(50,25));
    526     fZoomBox.setMaximumSize(QSize(50,25));
    527     fZoomBox.setAlignment(Qt::AlignRight);
    528     fZoomBox.setReadOnly(true);
    529     fViewStateLayout.addRow("Command HitBox", &fCommandHitBox);
    530     fCommandHitBox.setText("0");
    531     fCommandHitBox.setMinimumSize(QSize(50,25));
    532     fCommandHitBox.setMaximumSize(QSize(50,25));
    533     fCommandHitBox.setAlignment(Qt::AlignRight);
    534     fCommandHitBox.setReadOnly(true);
    535     fViewStateLayout.addRow("Current Command", &fCurrentCommandBox);
    536     fCurrentCommandBox.setText("0");
    537     fCurrentCommandBox.setMinimumSize(QSize(50,25));
    538     fCurrentCommandBox.setMaximumSize(QSize(50,25));
    539     fCurrentCommandBox.setAlignment(Qt::AlignRight);
    540     fCurrentCommandBox.setReadOnly(true);
    541     fViewStateGroup.setLayout(&fViewStateLayout);
    542     fSettingsAndImageLayout.addWidget(&fViewStateFrame);
    543 
    544     fDrawCommandGeometryWidget.setToolTip("Current Command Geometry");
    545     fSettingsAndImageLayout.addWidget(&fDrawCommandGeometryWidget);
    546 
    547     fLeftColumnSplitter.addWidget(&fListWidget);
    548     fLeftColumnSplitter.addWidget(&fDirectoryWidget);
    549     fLeftColumnSplitter.setOrientation(Qt::Vertical);
    550 
    551     fCanvasSettingsAndImageLayout.setSpacing(6);
    552     fCanvasSettingsAndImageLayout.addWidget(&fCanvasWidget, 1);
    553     fCanvasSettingsAndImageLayout.addLayout(&fSettingsAndImageLayout, 0);
    554 
    555     fMainAndRightColumnLayout.setSpacing(6);
    556     fMainAndRightColumnLayout.addLayout(&fCanvasSettingsAndImageLayout, 1);
    557     fMainAndRightColumnLayout.addWidget(&fInspectorWidget, 0);
    558     fMainAndRightColumnWidget.setLayout(&fMainAndRightColumnLayout);
    559 
    560     fCentralSplitter.addWidget(&fLeftColumnSplitter);
    561     fCentralSplitter.addWidget(&fMainAndRightColumnWidget);
    562     fCentralSplitter.setStretchFactor(0, 0);
    563     fCentralSplitter.setStretchFactor(1, 1);
    564 
    565     SkDebuggerGUI->setCentralWidget(&fCentralSplitter);
    566     SkDebuggerGUI->setStatusBar(&fStatusBar);
    567 
    568     fToolBar.setIconSize(QSize(32, 32));
    569     fToolBar.setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    570     SkDebuggerGUI->addToolBar(Qt::TopToolBarArea, &fToolBar);
    571 
    572     fSpacer.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    573 
    574     fToolBar.addAction(&fActionRewind);
    575     fToolBar.addAction(&fActionStepBack);
    576     fToolBar.addAction(&fActionPause);
    577     fToolBar.addAction(&fActionStepForward);
    578     fToolBar.addAction(&fActionPlay);
    579     fToolBar.addSeparator();
    580     fToolBar.addAction(&fActionInspector);
    581     fToolBar.addAction(&fActionSettings);
    582 
    583     fToolBar.addSeparator();
    584     fToolBar.addWidget(&fSpacer);
    585     fToolBar.addWidget(&fFilter);
    586     fToolBar.addAction(&fActionCancel);
    587 
    588     fFileName = "";
    589     setupDirectoryWidget("");
    590 
    591     // Menu Bar
    592     fMenuFile.setTitle("File");
    593     fMenuFile.addAction(&fActionOpen);
    594     fMenuFile.addAction(&fActionSave);
    595     fMenuFile.addAction(&fActionSaveAs);
    596     fMenuFile.addAction(&fActionClose);
    597 
    598     fMenuEdit.setTitle("Edit");
    599     fMenuEdit.addAction(&fActionDelete);
    600     fMenuEdit.addAction(&fActionClearDeletes);
    601     fMenuEdit.addSeparator();
    602     fMenuEdit.addAction(&fActionCreateBreakpoint);
    603     fMenuEdit.addAction(&fActionClearBreakpoints);
    604 
    605     fMenuNavigate.setTitle("Navigate");
    606     fMenuNavigate.addAction(&fActionRewind);
    607     fMenuNavigate.addAction(&fActionStepBack);
    608     fMenuNavigate.addAction(&fActionStepForward);
    609     fMenuNavigate.addAction(&fActionPlay);
    610     fMenuNavigate.addAction(&fActionPause);
    611     fMenuNavigate.addAction(&fActionGoToLine);
    612 
    613     fMenuView.setTitle("View");
    614     fMenuView.addAction(&fActionBreakpoint);
    615     fMenuView.addAction(&fActionShowDeletes);
    616     fMenuView.addAction(&fActionZoomIn);
    617     fMenuView.addAction(&fActionZoomOut);
    618 
    619     fMenuWindows.setTitle("Window");
    620     fMenuWindows.addAction(&fActionInspector);
    621     fMenuWindows.addAction(&fActionSettings);
    622     fMenuWindows.addAction(&fActionDirectory);
    623 
    624     fActionGoToLine.setText("Go to Line...");
    625     fActionGoToLine.setDisabled(true);
    626     fMenuBar.addAction(fMenuFile.menuAction());
    627     fMenuBar.addAction(fMenuEdit.menuAction());
    628     fMenuBar.addAction(fMenuView.menuAction());
    629     fMenuBar.addAction(fMenuNavigate.menuAction());
    630     fMenuBar.addAction(fMenuWindows.menuAction());
    631 
    632     SkDebuggerGUI->setMenuBar(&fMenuBar);
    633     QMetaObject::connectSlotsByName(SkDebuggerGUI);
    634 }
    635 
    636 void SkDebuggerGUI::setupDirectoryWidget(const QString& path) {
    637     fPath = path;
    638     populateDirectoryWidget();
    639 
    640     // clear the existing watched directory and setup a new directory to watch
    641     if (!fDirectoryWatcher.directories().empty()) {
    642         fDirectoryWatcher.removePaths(fDirectoryWatcher.directories());
    643     }
    644     if (!path.isEmpty()) {
    645         fDirectoryWatcher.addPath(fPath);
    646     }
    647 }
    648 
    649 void SkDebuggerGUI::populateDirectoryWidget() {
    650     QDir dir(fPath);
    651     QRegExp r(".skp");
    652     const QStringList files = dir.entryList();
    653 
    654     // check if a file has been removed
    655     for (int i = fDirectoryWidget.count() - 1; i >= 0; i--) {
    656         QListWidgetItem* item = fDirectoryWidget.item(i);
    657         if (!files.contains(item->text())) {
    658             fDirectoryWidget.removeItemWidget(item);
    659             delete item;
    660         }
    661     }
    662 
    663     // add any new files
    664     Q_FOREACH (QString f, files) {
    665         if (f.contains(r) && fDirectoryWidget.findItems(f, Qt::MatchExactly).size() == 0) {
    666             fDirectoryWidget.addItem(f);
    667         }
    668     }
    669 }
    670 
    671 void SkDebuggerGUI::loadPicture(const SkString& fileName) {
    672     fFileName = fileName;
    673     fLoading = true;
    674     SkFILEStream stream(fileName.c_str());
    675 
    676     auto picture = SkPicture::MakeFromStream(&stream);
    677 
    678     if (nullptr == picture) {
    679         QMessageBox::critical(this, "Error loading file", "Couldn't read file, sorry.");
    680         return;
    681     }
    682 
    683     fCanvasWidget.resetWidgetTransform();
    684     fDebugger.loadPicture(picture.get());
    685 
    686     fSkipCommands.setCount(fDebugger.getSize());
    687     for (int i = 0; i < fSkipCommands.count(); ++i) {
    688         fSkipCommands[i] = false;
    689     }
    690 
    691     picture.reset();
    692 
    693     /* fDebugCanvas is reinitialized every load picture. Need it to retain value
    694      * of the visibility filter.
    695      * TODO(chudy): This should be deprecated since fDebugger is not
    696      * recreated.
    697      * */
    698     fDebugger.highlightCurrentCommand(fSettingsWidget.isVisibilityFilterEnabled());
    699 
    700     this->setupListWidget();
    701     this->setupComboBox();
    702     this->setupOverviewText(nullptr, 0.0, 1);
    703     fInspectorWidget.setDisabled(false);
    704     fViewStateFrame.setDisabled(false);
    705     fSettingsWidget.setDisabled(false);
    706     fMenuEdit.setDisabled(false);
    707     fMenuNavigate.setDisabled(false);
    708     fMenuView.setDisabled(false);
    709     fActionSave.setDisabled(false);
    710     fActionSaveAs.setDisabled(false);
    711     fActionPause.setChecked(false);
    712     fDrawCommandGeometryWidget.setDrawCommandIndex(-1);
    713 
    714     fLoading = false;
    715     actionPlay();
    716 }
    717 
    718 void SkDebuggerGUI::setupListWidget() {
    719 
    720     SkASSERT(!strcmp("Save",
    721                      SkDrawCommand::GetCommandString(SkDrawCommand::kSave_OpType)));
    722     SkASSERT(!strcmp("SaveLayer",
    723                      SkDrawCommand::GetCommandString(SkDrawCommand::kSaveLayer_OpType)));
    724     SkASSERT(!strcmp("Restore",
    725                      SkDrawCommand::GetCommandString(SkDrawCommand::kRestore_OpType)));
    726     SkASSERT(!strcmp("BeginDrawPicture",
    727                      SkDrawCommand::GetCommandString(SkDrawCommand::kBeginDrawPicture_OpType)));
    728     SkASSERT(!strcmp("EndDrawPicture",
    729                      SkDrawCommand::GetCommandString(SkDrawCommand::kEndDrawPicture_OpType)));
    730 
    731     fListWidget.clear();
    732     int counter = 0;
    733     int indent = 0;
    734     for (int i = 0; i < fDebugger.getSize(); i++) {
    735         QListWidgetItem *item = new QListWidgetItem();
    736         SkDrawCommand* command = fDebugger.getDrawCommandAt(i);
    737         SkString commandString = command->toString();
    738         item->setData(Qt::DisplayRole, commandString.c_str());
    739         item->setData(Qt::UserRole + 1, counter++);
    740 
    741         if (0 == strcmp("Restore", commandString.c_str()) ||
    742             0 == strcmp("EndDrawPicture", commandString.c_str())) {
    743             indent -= 10;
    744         }
    745 
    746         item->setData(Qt::UserRole + 3, indent);
    747 
    748         if (0 == strcmp("Save", commandString.c_str()) ||
    749             0 == strcmp("SaveLayer", commandString.c_str()) ||
    750             0 == strcmp("BeginDrawPicture", commandString.c_str())) {
    751             indent += 10;
    752         }
    753 
    754         item->setData(Qt::UserRole + 4, -1);
    755 
    756         fListWidget.addItem(item);
    757     }
    758 }
    759 
    760 void SkDebuggerGUI::setupOverviewText(const SkTDArray<double>* typeTimes,
    761                                       double totTime,
    762                                       int numRuns) {
    763     SkString overview;
    764     fDebugger.getOverviewText(typeTimes, totTime, &overview, numRuns);
    765     fInspectorWidget.setText(overview.c_str(), SkInspectorWidget::kOverview_TabType);
    766 }
    767 
    768 
    769 void SkDebuggerGUI::setupComboBox() {
    770     fFilter.clear();
    771     fFilter.addItem("--Filter By Available Commands--");
    772 
    773     std::map<std::string, int> map;
    774     for (int i = 0; i < fDebugger.getSize(); i++) {
    775         map[fDebugger.getDrawCommandAt(i)->toString().c_str()]++;
    776     }
    777 
    778     for (std::map<std::string, int>::iterator it = map.begin(); it != map.end();
    779          ++it) {
    780         fFilter.addItem((it->first).c_str());
    781     }
    782 
    783     // NOTE(chudy): Makes first item unselectable.
    784     QStandardItemModel* model = qobject_cast<QStandardItemModel*>(
    785             fFilter.model());
    786     QModelIndex firstIndex = model->index(0, fFilter.modelColumn(),
    787             fFilter.rootModelIndex());
    788     QStandardItem* firstItem = model->itemFromIndex(firstIndex);
    789     firstItem->setSelectable(false);
    790 }
    791 
    792 void SkDebuggerGUI::updateImage() {
    793     if (this->isPaused()) {
    794         fCanvasWidget.drawTo(fPausedRow);
    795     } else {
    796         fCanvasWidget.drawTo(fListWidget.currentRow());
    797     }
    798 }
    799 
    800 void SkDebuggerGUI::updateHit(int newHit) {
    801     fCommandHitBox.setText(QString::number(newHit));
    802 }
    803 
    804