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