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 "SkForceLinking.h"
     10 #include "SkGraphics.h"
     11 #include "SkImageDecoder.h"
     12 #include <QListWidgetItem>
     13 #include "PictureRenderer.h"
     14 #include "SkPicturePlayback.h"
     15 #include "SkPictureRecord.h"
     16 #include "SkPictureData.h"
     17 
     18 __SK_FORCE_IMAGE_DECODER_LINKING;
     19 
     20 #if defined(SK_BUILD_FOR_WIN32)
     21     #include "SysTimer_windows.h"
     22 #elif defined(SK_BUILD_FOR_MAC)
     23     #include "SysTimer_mach.h"
     24 #elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
     25     #include "SysTimer_posix.h"
     26 #else
     27     #include "SysTimer_c.h"
     28 #endif
     29 
     30 
     31 SkDebuggerGUI::SkDebuggerGUI(QWidget *parent) :
     32         QMainWindow(parent)
     33     , fCentralSplitter(this)
     34     , fStatusBar(this)
     35     , fToolBar(this)
     36     , fActionOpen(this)
     37     , fActionBreakpoint(this)
     38     , fActionToggleIndexStyle(this)
     39     , fActionProfile(this)
     40     , fActionCancel(this)
     41     , fActionClearBreakpoints(this)
     42     , fActionClearDeletes(this)
     43     , fActionClose(this)
     44     , fActionCreateBreakpoint(this)
     45     , fActionDelete(this)
     46     , fActionDirectory(this)
     47     , fActionGoToLine(this)
     48     , fActionInspector(this)
     49     , fActionSettings(this)
     50     , fActionPlay(this)
     51     , fActionPause(this)
     52     , fActionRewind(this)
     53     , fActionSave(this)
     54     , fActionSaveAs(this)
     55     , fActionShowDeletes(this)
     56     , fActionStepBack(this)
     57     , fActionStepForward(this)
     58     , fActionZoomIn(this)
     59     , fActionZoomOut(this)
     60     , fMapper(this)
     61     , fListWidget(&fCentralSplitter)
     62     , fDirectoryWidget(&fCentralSplitter)
     63     , fCanvasWidget(this, &fDebugger)
     64     , fImageWidget(&fDebugger)
     65     , fMenuBar(this)
     66     , fMenuFile(this)
     67     , fMenuNavigate(this)
     68     , fMenuView(this)
     69     , fBreakpointsActivated(false)
     70     , fIndexStyleToggle(false)
     71     , fDeletesActivated(false)
     72     , fPause(false)
     73     , fLoading(false)
     74 {
     75     setupUi(this);
     76     fListWidget.setSelectionMode(QAbstractItemView::ExtendedSelection);
     77     connect(&fListWidget, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, SLOT(registerListClick(QListWidgetItem *)));
     78     connect(&fActionOpen, SIGNAL(triggered()), this, SLOT(openFile()));
     79     connect(&fActionDirectory, SIGNAL(triggered()), this, SLOT(toggleDirectory()));
     80     connect(&fDirectoryWidget, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, SLOT(loadFile(QListWidgetItem *)));
     81     connect(&fActionDelete, SIGNAL(triggered()), this, SLOT(actionDelete()));
     82     connect(&fListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(toggleBreakpoint()));
     83     connect(&fActionRewind, SIGNAL(triggered()), this, SLOT(actionRewind()));
     84     connect(&fActionPlay, SIGNAL(triggered()), this, SLOT(actionPlay()));
     85     connect(&fActionStepBack, SIGNAL(triggered()), this, SLOT(actionStepBack()));
     86     connect(&fActionStepForward, SIGNAL(triggered()), this, SLOT(actionStepForward()));
     87     connect(&fActionBreakpoint, SIGNAL(triggered()), this, SLOT(actionBreakpoints()));
     88     connect(&fActionToggleIndexStyle, SIGNAL(triggered()), this, SLOT(actionToggleIndexStyle()));
     89     connect(&fActionInspector, SIGNAL(triggered()), this, SLOT(actionInspector()));
     90     connect(&fActionSettings, SIGNAL(triggered()), this, SLOT(actionSettings()));
     91     connect(&fFilter, SIGNAL(activated(QString)), this, SLOT(toggleFilter(QString)));
     92     connect(&fActionProfile, SIGNAL(triggered()), this, SLOT(actionProfile()));
     93     connect(&fActionCancel, SIGNAL(triggered()), this, SLOT(actionCancel()));
     94     connect(&fActionClearBreakpoints, SIGNAL(triggered()), this, SLOT(actionClearBreakpoints()));
     95     connect(&fActionClearDeletes, SIGNAL(triggered()), this, SLOT(actionClearDeletes()));
     96     connect(&fActionClose, SIGNAL(triggered()), this, SLOT(actionClose()));
     97     connect(&fSettingsWidget, SIGNAL(visibilityFilterChanged()), this, SLOT(actionCommandFilter()));
     98 #if SK_SUPPORT_GPU
     99     connect(&fSettingsWidget, SIGNAL(glSettingsChanged()), this, SLOT(actionGLWidget()));
    100 #endif
    101     connect(&fSettingsWidget, SIGNAL(texFilterSettingsChanged()), this, SLOT(actionTextureFilter()));
    102     connect(fSettingsWidget.getRasterCheckBox(), SIGNAL(toggled(bool)), this, SLOT(actionRasterWidget(bool)));
    103     connect(fSettingsWidget.getOverdrawVizCheckBox(), SIGNAL(toggled(bool)), this, SLOT(actionOverdrawVizWidget(bool)));
    104     connect(fSettingsWidget.getMegaVizCheckBox(), SIGNAL(toggled(bool)), this, SLOT(actionMegaVizWidget(bool)));
    105     connect(fSettingsWidget.getPathOpsCheckBox(), SIGNAL(toggled(bool)), this, SLOT(actionPathOpsWidget(bool)));
    106     connect(&fActionPause, SIGNAL(toggled(bool)), this, SLOT(pauseDrawing(bool)));
    107     connect(&fActionCreateBreakpoint, SIGNAL(activated()), this, SLOT(toggleBreakpoint()));
    108     connect(&fActionShowDeletes, SIGNAL(triggered()), this, SLOT(showDeletes()));
    109     connect(&fCanvasWidget, SIGNAL(hitChanged(int)), this, SLOT(selectCommand(int)));
    110     connect(&fCanvasWidget, SIGNAL(hitChanged(int)), &fSettingsWidget, SLOT(updateHit(int)));
    111     connect(&fCanvasWidget, SIGNAL(scaleFactorChanged(float)), this, SLOT(actionScale(float)));
    112     connect(&fCanvasWidget, SIGNAL(commandChanged(int)), &fSettingsWidget, SLOT(updateCommand(int)));
    113     connect(&fActionSaveAs, SIGNAL(triggered()), this, SLOT(actionSaveAs()));
    114     connect(&fActionSave, SIGNAL(triggered()), this, SLOT(actionSave()));
    115 
    116     fMapper.setMapping(&fActionZoomIn, SkCanvasWidget::kIn_ZoomCommand);
    117     fMapper.setMapping(&fActionZoomOut, SkCanvasWidget::kOut_ZoomCommand);
    118 
    119     connect(&fActionZoomIn, SIGNAL(triggered()), &fMapper, SLOT(map()));
    120     connect(&fActionZoomOut, SIGNAL(triggered()), &fMapper, SLOT(map()));
    121     connect(&fMapper, SIGNAL(mapped(int)), &fCanvasWidget, SLOT(zoom(int)));
    122 
    123     fInspectorWidget.setDisabled(true);
    124     fMenuEdit.setDisabled(true);
    125     fMenuNavigate.setDisabled(true);
    126     fMenuView.setDisabled(true);
    127 
    128     SkGraphics::Init();
    129 }
    130 
    131 SkDebuggerGUI::~SkDebuggerGUI() {
    132     SkGraphics::Term();
    133 }
    134 
    135 void SkDebuggerGUI::actionBreakpoints() {
    136     fBreakpointsActivated = !fBreakpointsActivated;
    137     for (int row = 0; row < fListWidget.count(); row++) {
    138         QListWidgetItem *item = fListWidget.item(row);
    139         item->setHidden(item->checkState() == Qt::Unchecked && fBreakpointsActivated);
    140     }
    141 }
    142 
    143 void SkDebuggerGUI::actionToggleIndexStyle() {
    144     fIndexStyleToggle = !fIndexStyleToggle;
    145     SkListWidget* list = (SkListWidget*) fListWidget.itemDelegate();
    146     list->setIndexStyle(fIndexStyleToggle ? SkListWidget::kIndex_IndexStyle :
    147                                             SkListWidget::kOffset_IndexStyle);
    148     fListWidget.update();
    149 }
    150 
    151 void SkDebuggerGUI::showDeletes() {
    152     fDeletesActivated = !fDeletesActivated;
    153     for (int row = 0; row < fListWidget.count(); row++) {
    154         QListWidgetItem *item = fListWidget.item(row);
    155         item->setHidden(fDebugger.isCommandVisible(row) && fDeletesActivated);
    156     }
    157 }
    158 
    159 // The timed picture playback just steps through every operation timing
    160 // each one individually. Note that each picture should be replayed multiple
    161 // times (via calls to 'draw') before each command's time is accessed via 'time'.
    162 class SkTimedPicturePlayback : public SkPicturePlayback {
    163 public:
    164 
    165     SkTimedPicturePlayback(const SkPicture* picture, const SkTDArray<bool>& deletedCommands)
    166         : INHERITED(picture)
    167         , fSkipCommands(deletedCommands)
    168         , fTot(0.0)
    169         , fCurCommand(0) {
    170         fTimes.setCount(deletedCommands.count());
    171         fTypeTimes.setCount(LAST_DRAWTYPE_ENUM+1);
    172         this->resetTimes();
    173     }
    174 
    175     virtual void draw(SkCanvas* canvas, SkDrawPictureCallback* callback) SK_OVERRIDE {
    176         AutoResetOpID aroi(this);
    177         SkASSERT(0 == fCurOffset);
    178 
    179         SkReader32 reader(fPictureData->opData()->bytes(), fPictureData->opData()->size());
    180 
    181         // Record this, so we can concat w/ it if we encounter a setMatrix()
    182         SkMatrix initialMatrix = canvas->getTotalMatrix();
    183 
    184         SkAutoCanvasRestore acr(canvas, false);
    185 
    186         int opIndex = -1;
    187 
    188         while (!reader.eof()) {
    189             if (callback && callback->abortDrawing()) {
    190                 return;
    191             }
    192 
    193             fCurOffset = reader.offset();
    194             uint32_t size;
    195             DrawType op = ReadOpAndSize(&reader, &size);
    196             if (NOOP == op) {
    197                 // NOOPs are to be ignored - do not propagate them any further
    198                 reader.setOffset(fCurOffset + size);
    199                 continue;
    200             }
    201 
    202             opIndex++;
    203 
    204             if (this->preDraw(opIndex, op)) {
    205                 // This operation is disabled in the debugger's GUI
    206                 reader.setOffset(fCurOffset + size);
    207                 continue;
    208             }
    209 
    210             this->handleOp(&reader, op, size, canvas, initialMatrix);
    211 
    212             this->postDraw(opIndex);
    213         }
    214     }
    215 
    216     void resetTimes() {
    217         for (int i = 0; i < fTimes.count(); ++i) {
    218             fTimes[i] = 0.0;
    219         }
    220         for (int i = 0; i < fTypeTimes.count(); ++i) {
    221             fTypeTimes[i] = 0.0f;
    222         }
    223         fTot = 0.0;
    224     }
    225 
    226     int count() const { return fTimes.count(); }
    227 
    228     // Return the fraction of the total time consumed by the index-th operation
    229     double time(int index) const { return fTimes[index] / fTot; }
    230 
    231     const SkTDArray<double>* typeTimes() const { return &fTypeTimes; }
    232 
    233     double totTime() const { return fTot; }
    234 
    235 protected:
    236     SysTimer fTimer;
    237     SkTDArray<bool> fSkipCommands; // has the command been deleted in the GUI?
    238     SkTDArray<double> fTimes;   // sum of time consumed for each command
    239     SkTDArray<double> fTypeTimes; // sum of time consumed for each type of command (e.g., drawPath)
    240     double fTot;                // total of all times in 'fTimes'
    241 
    242     int fCurType;
    243     int fCurCommand;            // the current command being executed/timed
    244 
    245     bool preDraw(int opIndex, int type) {
    246         fCurCommand = opIndex;
    247 
    248         if (fSkipCommands[fCurCommand]) {
    249             return true;
    250         }
    251 
    252         fCurType = type;
    253         // The SkDebugCanvas doesn't recognize these types. This class needs to
    254         // convert or else we'll wind up with a mismatch between the type counts
    255         // the debugger displays and the profile times.
    256         if (DRAW_POS_TEXT_TOP_BOTTOM == type) {
    257             fCurType = DRAW_POS_TEXT;
    258         } else if (DRAW_POS_TEXT_H_TOP_BOTTOM == type) {
    259             fCurType = DRAW_POS_TEXT_H;
    260         }
    261 
    262 #if defined(SK_BUILD_FOR_WIN32)
    263         // CPU timer doesn't work well on Windows
    264         fTimer.startWall();
    265 #else
    266         fTimer.startCpu();
    267 #endif
    268 
    269         return false;
    270     }
    271 
    272     void postDraw(int opIndex) {
    273 #if defined(SK_BUILD_FOR_WIN32)
    274         // CPU timer doesn't work well on Windows
    275         double time = fTimer.endWall();
    276 #else
    277         double time = fTimer.endCpu();
    278 #endif
    279 
    280         SkASSERT(opIndex == fCurCommand);
    281         SkASSERT(fCurType <= LAST_DRAWTYPE_ENUM);
    282 
    283         fTimes[fCurCommand] += time;
    284         fTypeTimes[fCurType] += time;
    285         fTot += time;
    286     }
    287 
    288 private:
    289     typedef SkPicturePlayback INHERITED;
    290 };
    291 
    292 #if 0
    293 // Wrap SkPicture to allow installation of an SkTimedPicturePlayback object
    294 class SkTimedPicture : public SkPicture {
    295 public:
    296     static SkTimedPicture* CreateTimedPicture(SkStream* stream,
    297                                               SkPicture::InstallPixelRefProc proc,
    298                                               const SkTDArray<bool>& deletedCommands) {
    299         SkPictInfo info;
    300         if (!InternalOnly_StreamIsSKP(stream, &info)) {
    301             return NULL;
    302         }
    303 
    304         // Check to see if there is a playback to recreate.
    305         if (stream->readBool()) {
    306             SkTimedPicturePlayback* playback = SkTimedPicturePlayback::CreateFromStream(
    307                                                                 stream,
    308                                                                 info, proc,
    309                                                                 deletedCommands);
    310             if (NULL == playback) {
    311                 return NULL;
    312             }
    313 
    314             return SkNEW_ARGS(SkTimedPicture, (playback, info.fWidth, info.fHeight));
    315         }
    316 
    317         return NULL;
    318     }
    319 
    320     void resetTimes() { ((SkTimedPicturePlayback*) fData.get())->resetTimes(); }
    321 
    322     int count() const { return ((SkTimedPicturePlayback*) fData.get())->count(); }
    323 
    324     // return the fraction of the total time this command consumed
    325     double time(int index) const { return ((SkTimedPicturePlayback*) fData.get())->time(index); }
    326 
    327     const SkTDArray<double>* typeTimes() const { return ((SkTimedPicturePlayback*) fData.get())->typeTimes(); }
    328 
    329     double totTime() const { return ((SkTimedPicturePlayback*) fData.get())->totTime(); }
    330 
    331 private:
    332     // disallow default ctor b.c. we don't have a good way to setup the fData ptr
    333     SkTimedPicture();
    334     // Private ctor only used by CreateTimedPicture, which has created the playback.
    335     SkTimedPicture(SkTimedPicturePlayback* playback, int width, int height)
    336         : INHERITED(playback, width, height) {}
    337     // disallow the copy ctor - enabling would require copying code from SkPicture
    338     SkTimedPicture(const SkTimedPicture& src);
    339 
    340     typedef SkPicture INHERITED;
    341 };
    342 #endif
    343 
    344 // This is a simplification of PictureBenchmark's run with the addition of
    345 // clearing of the times after the first pass (in resetTimes)
    346 void SkDebuggerGUI::run(const SkPicture* pict,
    347                         sk_tools::PictureRenderer* renderer,
    348                         int repeats) {
    349     SkASSERT(pict);
    350     if (NULL == pict) {
    351         return;
    352     }
    353 
    354     SkASSERT(renderer != NULL);
    355     if (NULL == renderer) {
    356         return;
    357     }
    358 
    359     renderer->init(pict, NULL, NULL, NULL, false);
    360 
    361     renderer->setup();
    362     renderer->render();
    363     renderer->resetState(true);    // flush, swapBuffers and Finish
    364 
    365 #if 0
    366     // We throw this away the first batch of times to remove first time effects (such as paging in this program)
    367     pict->resetTimes();
    368 #endif
    369 
    370     for (int i = 0; i < repeats; ++i) {
    371         renderer->setup();
    372         renderer->render();
    373         renderer->resetState(false);  // flush & swapBuffers, but don't Finish
    374     }
    375     renderer->resetState(true);    // flush, swapBuffers and Finish
    376 
    377     renderer->end();
    378 }
    379 
    380 void SkDebuggerGUI::actionProfile() {
    381     // In order to profile we pass the command offsets (that were read-in
    382     // in loadPicture by the SkOffsetPicture) to an SkTimedPlaybackPicture.
    383     // The SkTimedPlaybackPicture in turn passes the offsets to an
    384     // SkTimedPicturePlayback object which uses them to track the performance
    385     // of individual commands.
    386     if (fFileName.isEmpty()) {
    387         return;
    388     }
    389 
    390     SkFILEStream inputStream;
    391 
    392     inputStream.setPath(fFileName.c_str());
    393     if (!inputStream.isValid()) {
    394         return;
    395     }
    396 
    397     SkAutoTUnref<SkPicture> picture(SkPicture::CreateFromStream(&inputStream,
    398                                         &SkImageDecoder::DecodeMemory)); // , fSkipCommands));
    399     if (NULL == picture.get()) {
    400         return;
    401     }
    402 
    403 
    404 #if 0
    405 
    406     // For now this #if allows switching between tiled and simple rendering
    407     // modes. Eventually this will be accomplished via the GUI
    408 #if 0
    409     // With the current batch of SysTimers, profiling in tiled mode
    410     // gets swamped by the timing overhead:
    411     //
    412     //                       tile mode           simple mode
    413     // debugger                64.2ms              12.8ms
    414     // bench_pictures          16.9ms              12.4ms
    415     //
    416     // This is b.c. in tiled mode each command is called many more times
    417     // but typically does less work on each invocation (due to clipping)
    418     sk_tools::TiledPictureRenderer* renderer = NULL;
    419 
    420     renderer = SkNEW(sk_tools::TiledPictureRenderer);
    421     renderer->setTileWidth(256);
    422     renderer->setTileHeight(256);
    423 #else
    424     sk_tools::SimplePictureRenderer* renderer = NULL;
    425 
    426     renderer = SkNEW(sk_tools::SimplePictureRenderer);
    427 
    428 #if SK_SUPPORT_GPU
    429     if (fSettingsWidget.isGLActive()) {
    430         renderer->setDeviceType(sk_tools::PictureRenderer::kGPU_DeviceType);
    431         renderer->setSampleCount(fSettingsWidget.getGLSampleCount());
    432     }
    433 #endif
    434 
    435 #endif
    436 
    437     static const int kNumRepeats = 10;
    438 
    439     run(picture.get(), renderer, kNumRepeats);
    440 
    441     SkASSERT(picture->count() == fListWidget.count());
    442 
    443     // extract the individual command times from the SkTimedPlaybackPicture
    444     for (int i = 0; i < picture->count(); ++i) {
    445         double temp = picture->time(i);
    446 
    447         QListWidgetItem* item = fListWidget.item(i);
    448 
    449         item->setData(Qt::UserRole + 4, 100.0*temp);
    450     }
    451 
    452     setupOverviewText(picture->typeTimes(), picture->totTime(), kNumRepeats);
    453     setupClipStackText();
    454 
    455 #endif
    456 }
    457 
    458 void SkDebuggerGUI::actionCancel() {
    459     for (int row = 0; row < fListWidget.count(); row++) {
    460         fListWidget.item(row)->setHidden(false);
    461     }
    462 }
    463 
    464 void SkDebuggerGUI::actionClearBreakpoints() {
    465     for (int row = 0; row < fListWidget.count(); row++) {
    466         QListWidgetItem* item = fListWidget.item(row);
    467         item->setCheckState(Qt::Unchecked);
    468         item->setData(Qt::DecorationRole,
    469                 QPixmap(":/blank.png"));
    470     }
    471 }
    472 
    473 void SkDebuggerGUI::actionClearDeletes() {
    474     for (int row = 0; row < fListWidget.count(); row++) {
    475         QListWidgetItem* item = fListWidget.item(row);
    476         item->setData(Qt::UserRole + 2, QPixmap(":/blank.png"));
    477         fDebugger.setCommandVisible(row, true);
    478         fSkipCommands[row] = false;
    479     }
    480     if (fPause) {
    481         fCanvasWidget.drawTo(fPausedRow);
    482         fImageWidget.draw();
    483     } else {
    484         fCanvasWidget.drawTo(fListWidget.currentRow());
    485         fImageWidget.draw();
    486     }
    487 }
    488 
    489 void SkDebuggerGUI::actionCommandFilter() {
    490     fDebugger.highlightCurrentCommand(fSettingsWidget.getVisibilityFilter());
    491     fCanvasWidget.drawTo(fListWidget.currentRow());
    492     fImageWidget.draw();
    493 }
    494 
    495 void SkDebuggerGUI::actionClose() {
    496     this->close();
    497 }
    498 
    499 void SkDebuggerGUI::actionDelete() {
    500 
    501     for (int row = 0; row < fListWidget.count(); ++row) {
    502         QListWidgetItem* item = fListWidget.item(row);
    503 
    504         if (!item->isSelected()) {
    505             continue;
    506         }
    507 
    508         if (fDebugger.isCommandVisible(row)) {
    509             item->setData(Qt::UserRole + 2, QPixmap(":/delete.png"));
    510             fDebugger.setCommandVisible(row, false);
    511             fSkipCommands[row] = true;
    512         } else {
    513             item->setData(Qt::UserRole + 2, QPixmap(":/blank.png"));
    514             fDebugger.setCommandVisible(row, true);
    515             fSkipCommands[row] = false;
    516         }
    517     }
    518 
    519     int currentRow = fListWidget.currentRow();
    520 
    521     if (fPause) {
    522         fCanvasWidget.drawTo(fPausedRow);
    523         fImageWidget.draw();
    524     } else {
    525         fCanvasWidget.drawTo(currentRow);
    526         fImageWidget.draw();
    527     }
    528 }
    529 
    530 #if SK_SUPPORT_GPU
    531 void SkDebuggerGUI::actionGLWidget() {
    532     bool isToggled = fSettingsWidget.isGLActive();
    533     if (isToggled) {
    534         fCanvasWidget.setGLSampleCount(fSettingsWidget.getGLSampleCount());
    535     }
    536     fCanvasWidget.setWidgetVisibility(SkCanvasWidget::kGPU_WidgetType, !isToggled);
    537 }
    538 #endif
    539 
    540 void SkDebuggerGUI::actionInspector() {
    541     if (fInspectorWidget.isHidden()) {
    542         fInspectorWidget.setHidden(false);
    543         fImageWidget.setHidden(false);
    544     } else {
    545         fInspectorWidget.setHidden(true);
    546         fImageWidget.setHidden(true);
    547     }
    548 }
    549 
    550 void SkDebuggerGUI::actionPlay() {
    551     for (int row = fListWidget.currentRow() + 1; row < fListWidget.count();
    552             row++) {
    553         QListWidgetItem *item = fListWidget.item(row);
    554         if (item->checkState() == Qt::Checked) {
    555             fListWidget.setCurrentItem(item);
    556             return;
    557         }
    558     }
    559     fListWidget.setCurrentRow(fListWidget.count() - 1);
    560 }
    561 
    562 void SkDebuggerGUI::actionRasterWidget(bool isToggled) {
    563     fCanvasWidget.setWidgetVisibility(SkCanvasWidget::kRaster_8888_WidgetType, !isToggled);
    564 }
    565 
    566 void SkDebuggerGUI::actionOverdrawVizWidget(bool isToggled) {
    567     fDebugger.setOverdrawViz(isToggled);
    568     fCanvasWidget.update();
    569 }
    570 
    571 void SkDebuggerGUI::actionMegaVizWidget(bool isToggled) {
    572     fDebugger.setMegaViz(isToggled);
    573     fCanvasWidget.update();
    574 }
    575 
    576 void SkDebuggerGUI::actionPathOpsWidget(bool isToggled) {
    577     fDebugger.setPathOps(isToggled);
    578     fCanvasWidget.update();
    579 }
    580 
    581 void SkDebuggerGUI::actionTextureFilter() {
    582     SkPaint::FilterLevel level;
    583     bool enabled = fSettingsWidget.getFilterOverride(&level);
    584     fDebugger.setTexFilterOverride(enabled, level);
    585     fCanvasWidget.update();
    586 }
    587 
    588 void SkDebuggerGUI::actionRewind() {
    589     fListWidget.setCurrentRow(0);
    590 }
    591 
    592 void SkDebuggerGUI::actionSave() {
    593     fFileName = fPath.toAscii().data();
    594     fFileName.append("/");
    595     fFileName.append(fDirectoryWidget.currentItem()->text().toAscii().data());
    596     saveToFile(fFileName);
    597 }
    598 
    599 void SkDebuggerGUI::actionSaveAs() {
    600     QString filename = QFileDialog::getSaveFileName(this, "Save File", "",
    601             "Skia Picture (*skp)");
    602     if (!filename.endsWith(".skp", Qt::CaseInsensitive)) {
    603         filename.append(".skp");
    604     }
    605     saveToFile(SkString(filename.toAscii().data()));
    606 }
    607 
    608 void SkDebuggerGUI::actionScale(float scaleFactor) {
    609     fSettingsWidget.setZoomText(scaleFactor);
    610 }
    611 
    612 void SkDebuggerGUI::actionSettings() {
    613     if (fSettingsWidget.isHidden()) {
    614         fSettingsWidget.setHidden(false);
    615     } else {
    616         fSettingsWidget.setHidden(true);
    617     }
    618 }
    619 
    620 void SkDebuggerGUI::actionStepBack() {
    621     int currentRow = fListWidget.currentRow();
    622     if (currentRow != 0) {
    623         fListWidget.setCurrentRow(currentRow - 1);
    624     }
    625 }
    626 
    627 void SkDebuggerGUI::actionStepForward() {
    628     int currentRow = fListWidget.currentRow();
    629     QString curRow = QString::number(currentRow);
    630     QString curCount = QString::number(fListWidget.count());
    631     if (currentRow < fListWidget.count() - 1) {
    632         fListWidget.setCurrentRow(currentRow + 1);
    633     }
    634 }
    635 
    636 void SkDebuggerGUI::drawComplete() {
    637     fInspectorWidget.setMatrix(fDebugger.getCurrentMatrix());
    638     fInspectorWidget.setClip(fDebugger.getCurrentClip());
    639 }
    640 
    641 void SkDebuggerGUI::saveToFile(const SkString& filename) {
    642     SkFILEWStream file(filename.c_str());
    643     SkAutoTUnref<SkPicture> copy(fDebugger.copyPicture());
    644 
    645     copy->serialize(&file);
    646 }
    647 
    648 void SkDebuggerGUI::loadFile(QListWidgetItem *item) {
    649     if (fDirectoryWidgetActive) {
    650         fFileName = fPath.toAscii().data();
    651         // don't add a '/' to files in the local directory
    652         if (fFileName.size() > 0) {
    653             fFileName.append("/");
    654         }
    655         fFileName.append(item->text().toAscii().data());
    656         loadPicture(fFileName);
    657     }
    658 }
    659 
    660 void SkDebuggerGUI::openFile() {
    661     QString temp = QFileDialog::getOpenFileName(this, tr("Open File"), "",
    662             tr("Files (*.*)"));
    663     openFile(temp);
    664 }
    665 
    666 void SkDebuggerGUI::openFile(const QString &filename) {
    667     fDirectoryWidgetActive = false;
    668     if (!filename.isEmpty()) {
    669         QFileInfo pathInfo(filename);
    670         loadPicture(SkString(filename.toAscii().data()));
    671         setupDirectoryWidget(pathInfo.path());
    672     }
    673     fDirectoryWidgetActive = true;
    674 }
    675 
    676 void SkDebuggerGUI::pauseDrawing(bool isPaused) {
    677     fPause = isPaused;
    678     fPausedRow = fListWidget.currentRow();
    679     fCanvasWidget.drawTo(fPausedRow);
    680     fImageWidget.draw();
    681 }
    682 
    683 void SkDebuggerGUI::registerListClick(QListWidgetItem *item) {
    684     if(!fLoading) {
    685         int currentRow = fListWidget.currentRow();
    686 
    687         if (currentRow != -1) {
    688             if (!fPause) {
    689                 fCanvasWidget.drawTo(currentRow);
    690                 fImageWidget.draw();
    691             }
    692             SkTDArray<SkString*> *currInfo = fDebugger.getCommandInfo(
    693                     currentRow);
    694 
    695             /* TODO(chudy): Add command type before parameters. Rename v
    696              * to something more informative. */
    697             if (currInfo) {
    698                 QString info;
    699                 info.append("<b>Parameters: </b><br/>");
    700                 for (int i = 0; i < currInfo->count(); i++) {
    701 
    702                     info.append(QString((*currInfo)[i]->c_str()));
    703                     info.append("<br/>");
    704                 }
    705                 fInspectorWidget.setText(info, SkInspectorWidget::kDetail_TabType);
    706                 fInspectorWidget.setDisabled(false);
    707             }
    708             setupClipStackText();
    709         }
    710 
    711     }
    712 }
    713 
    714 void SkDebuggerGUI::selectCommand(int command) {
    715     if (fPause) {
    716         fListWidget.setCurrentRow(command);
    717     }
    718 }
    719 
    720 void SkDebuggerGUI::toggleBreakpoint() {
    721     QListWidgetItem* item = fListWidget.currentItem();
    722     if (item->checkState() == Qt::Unchecked) {
    723         item->setCheckState(Qt::Checked);
    724         item->setData(Qt::DecorationRole,
    725                 QPixmap(":/breakpoint_16x16.png"));
    726     } else {
    727         item->setCheckState(Qt::Unchecked);
    728         item->setData(Qt::DecorationRole,
    729                 QPixmap(":/blank.png"));
    730     }
    731 }
    732 
    733 void SkDebuggerGUI::toggleDirectory() {
    734     fDirectoryWidget.setHidden(!fDirectoryWidget.isHidden());
    735 }
    736 
    737 void SkDebuggerGUI::toggleFilter(QString string) {
    738     for (int row = 0; row < fListWidget.count(); row++) {
    739         QListWidgetItem *item = fListWidget.item(row);
    740         item->setHidden(item->text() != string);
    741     }
    742 }
    743 
    744 void SkDebuggerGUI::setupUi(QMainWindow *SkDebuggerGUI) {
    745     QIcon windowIcon;
    746     windowIcon.addFile(QString::fromUtf8(":/skia.png"), QSize(),
    747             QIcon::Normal, QIcon::Off);
    748     SkDebuggerGUI->setObjectName(QString::fromUtf8("SkDebuggerGUI"));
    749     SkDebuggerGUI->resize(1200, 1000);
    750     SkDebuggerGUI->setWindowIcon(windowIcon);
    751     SkDebuggerGUI->setWindowTitle("Skia Debugger");
    752 
    753     fActionOpen.setShortcuts(QKeySequence::Open);
    754     fActionOpen.setText("Open");
    755 
    756     QIcon breakpoint;
    757     breakpoint.addFile(QString::fromUtf8(":/breakpoint.png"),
    758             QSize(), QIcon::Normal, QIcon::Off);
    759     fActionBreakpoint.setShortcut(QKeySequence(tr("Ctrl+B")));
    760     fActionBreakpoint.setIcon(breakpoint);
    761     fActionBreakpoint.setText("Breakpoints");
    762 
    763     fActionToggleIndexStyle.setShortcut(QKeySequence(tr("Ctrl+T")));
    764     fActionToggleIndexStyle.setText("Toggle Index Style");
    765 
    766     QIcon cancel;
    767     cancel.addFile(QString::fromUtf8(":/reload.png"), QSize(),
    768             QIcon::Normal, QIcon::Off);
    769     fActionCancel.setIcon(cancel);
    770     fActionCancel.setText("Clear Filter");
    771 
    772     fActionClearBreakpoints.setShortcut(QKeySequence(tr("Alt+B")));
    773     fActionClearBreakpoints.setText("Clear Breakpoints");
    774 
    775     fActionClearDeletes.setShortcut(QKeySequence(tr("Alt+X")));
    776     fActionClearDeletes.setText("Clear Deletes");
    777 
    778     fActionClose.setShortcuts(QKeySequence::Quit);
    779     fActionClose.setText("Exit");
    780 
    781     fActionCreateBreakpoint.setShortcut(QKeySequence(tr("B")));
    782     fActionCreateBreakpoint.setText("Set Breakpoint");
    783 
    784     fActionDelete.setShortcut(QKeySequence(tr("X")));
    785     fActionDelete.setText("Delete Command");
    786 
    787     fActionDirectory.setShortcut(QKeySequence(tr("Ctrl+D")));
    788     fActionDirectory.setText("Directory");
    789 
    790     QIcon profile;
    791     profile.addFile(QString::fromUtf8(":/profile.png"), QSize(),
    792                     QIcon::Normal, QIcon::Off);
    793     fActionProfile.setIcon(profile);
    794     fActionProfile.setText("Profile");
    795     fActionProfile.setDisabled(true);
    796 
    797     QIcon inspector;
    798     inspector.addFile(QString::fromUtf8(":/inspector.png"),
    799             QSize(), QIcon::Normal, QIcon::Off);
    800     fActionInspector.setShortcut(QKeySequence(tr("Ctrl+I")));
    801     fActionInspector.setIcon(inspector);
    802     fActionInspector.setText("Inspector");
    803 
    804     QIcon settings;
    805     settings.addFile(QString::fromUtf8(":/inspector.png"),
    806             QSize(), QIcon::Normal, QIcon::Off);
    807     fActionSettings.setShortcut(QKeySequence(tr("Ctrl+G")));
    808     fActionSettings.setIcon(settings);
    809     fActionSettings.setText("Settings");
    810 
    811     QIcon play;
    812     play.addFile(QString::fromUtf8(":/play.png"), QSize(),
    813             QIcon::Normal, QIcon::Off);
    814     fActionPlay.setShortcut(QKeySequence(tr("Ctrl+P")));
    815     fActionPlay.setIcon(play);
    816     fActionPlay.setText("Play");
    817 
    818     QIcon pause;
    819     pause.addFile(QString::fromUtf8(":/pause.png"), QSize(),
    820             QIcon::Normal, QIcon::Off);
    821     fActionPause.setShortcut(QKeySequence(tr("Space")));
    822     fActionPause.setCheckable(true);
    823     fActionPause.setIcon(pause);
    824     fActionPause.setText("Pause");
    825 
    826     QIcon rewind;
    827     rewind.addFile(QString::fromUtf8(":/rewind.png"), QSize(),
    828             QIcon::Normal, QIcon::Off);
    829     fActionRewind.setShortcut(QKeySequence(tr("Ctrl+R")));
    830     fActionRewind.setIcon(rewind);
    831     fActionRewind.setText("Rewind");
    832 
    833     fActionSave.setShortcut(QKeySequence::Save);
    834     fActionSave.setText("Save");
    835     fActionSave.setDisabled(true);
    836     fActionSaveAs.setShortcut(QKeySequence::SaveAs);
    837     fActionSaveAs.setText("Save As");
    838     fActionSaveAs.setDisabled(true);
    839 
    840     fActionShowDeletes.setShortcut(QKeySequence(tr("Ctrl+X")));
    841     fActionShowDeletes.setText("Deleted Commands");
    842 
    843     QIcon stepBack;
    844     stepBack.addFile(QString::fromUtf8(":/previous.png"), QSize(),
    845             QIcon::Normal, QIcon::Off);
    846     fActionStepBack.setShortcut(QKeySequence(tr("[")));
    847     fActionStepBack.setIcon(stepBack);
    848     fActionStepBack.setText("Step Back");
    849 
    850     QIcon stepForward;
    851     stepForward.addFile(QString::fromUtf8(":/next.png"),
    852             QSize(), QIcon::Normal, QIcon::Off);
    853     fActionStepForward.setShortcut(QKeySequence(tr("]")));
    854     fActionStepForward.setIcon(stepForward);
    855     fActionStepForward.setText("Step Forward");
    856 
    857     fActionZoomIn.setShortcut(QKeySequence(tr("Ctrl+=")));
    858     fActionZoomIn.setText("Zoom In");
    859     fActionZoomOut.setShortcut(QKeySequence(tr("Ctrl+-")));
    860     fActionZoomOut.setText("Zoom Out");
    861 
    862     fListWidget.setItemDelegate(new SkListWidget(&fListWidget));
    863     fListWidget.setObjectName(QString::fromUtf8("listWidget"));
    864     fListWidget.setMinimumWidth(250);
    865 
    866     fFilter.addItem("--Filter By Available Commands--");
    867 
    868     fDirectoryWidget.setMinimumWidth(250);
    869     fDirectoryWidget.setStyleSheet("QListWidget::Item {padding: 5px;}");
    870 
    871     fCanvasWidget.setSizePolicy(QSizePolicy::Expanding,
    872             QSizePolicy::Expanding);
    873 
    874     fImageWidget.setFixedSize(SkImageWidget::kImageWidgetWidth,
    875                               SkImageWidget::kImageWidgetHeight);
    876 
    877     fInspectorWidget.setSizePolicy(QSizePolicy::Expanding,
    878             QSizePolicy::Expanding);
    879     fInspectorWidget.setMaximumHeight(300);
    880 
    881     fSettingsAndImageLayout.setSpacing(6);
    882     fSettingsAndImageLayout.addWidget(&fSettingsWidget);
    883     fSettingsAndImageLayout.addWidget(&fImageWidget);
    884 
    885     fSettingsWidget.setSizePolicy(QSizePolicy::Expanding,
    886             QSizePolicy::Expanding);
    887     fSettingsWidget.setMaximumWidth(250);
    888 
    889     fLeftColumnSplitter.addWidget(&fListWidget);
    890     fLeftColumnSplitter.addWidget(&fDirectoryWidget);
    891     fLeftColumnSplitter.setOrientation(Qt::Vertical);
    892 
    893     fCanvasSettingsAndImageLayout.setSpacing(6);
    894     fCanvasSettingsAndImageLayout.addWidget(&fCanvasWidget);
    895     fCanvasSettingsAndImageLayout.addLayout(&fSettingsAndImageLayout);
    896 
    897     fMainAndRightColumnLayout.setSpacing(6);
    898     fMainAndRightColumnLayout.addLayout(&fCanvasSettingsAndImageLayout);
    899     fMainAndRightColumnLayout.addWidget(&fInspectorWidget);
    900     fMainAndRightColumnWidget.setLayout(&fMainAndRightColumnLayout);
    901 
    902     fCentralSplitter.addWidget(&fLeftColumnSplitter);
    903     fCentralSplitter.addWidget(&fMainAndRightColumnWidget);
    904     fCentralSplitter.setStretchFactor(0, 0);
    905     fCentralSplitter.setStretchFactor(1, 1);
    906 
    907     SkDebuggerGUI->setCentralWidget(&fCentralSplitter);
    908     SkDebuggerGUI->setStatusBar(&fStatusBar);
    909 
    910     fToolBar.setIconSize(QSize(32, 32));
    911     fToolBar.setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    912     SkDebuggerGUI->addToolBar(Qt::TopToolBarArea, &fToolBar);
    913 
    914     fSpacer.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    915 
    916     fToolBar.addAction(&fActionRewind);
    917     fToolBar.addAction(&fActionStepBack);
    918     fToolBar.addAction(&fActionPause);
    919     fToolBar.addAction(&fActionStepForward);
    920     fToolBar.addAction(&fActionPlay);
    921     fToolBar.addSeparator();
    922     fToolBar.addAction(&fActionInspector);
    923     fToolBar.addAction(&fActionSettings);
    924     fToolBar.addSeparator();
    925     fToolBar.addAction(&fActionProfile);
    926 
    927     fToolBar.addSeparator();
    928     fToolBar.addWidget(&fSpacer);
    929     fToolBar.addWidget(&fFilter);
    930     fToolBar.addAction(&fActionCancel);
    931 
    932     // TODO(chudy): Remove static call.
    933     fDirectoryWidgetActive = false;
    934     fFileName = "";
    935     setupDirectoryWidget("");
    936     fDirectoryWidgetActive = true;
    937 
    938     // Menu Bar
    939     fMenuFile.setTitle("File");
    940     fMenuFile.addAction(&fActionOpen);
    941     fMenuFile.addAction(&fActionSave);
    942     fMenuFile.addAction(&fActionSaveAs);
    943     fMenuFile.addAction(&fActionClose);
    944 
    945     fMenuEdit.setTitle("Edit");
    946     fMenuEdit.addAction(&fActionDelete);
    947     fMenuEdit.addAction(&fActionClearDeletes);
    948     fMenuEdit.addSeparator();
    949     fMenuEdit.addAction(&fActionCreateBreakpoint);
    950     fMenuEdit.addAction(&fActionClearBreakpoints);
    951 
    952     fMenuNavigate.setTitle("Navigate");
    953     fMenuNavigate.addAction(&fActionRewind);
    954     fMenuNavigate.addAction(&fActionStepBack);
    955     fMenuNavigate.addAction(&fActionStepForward);
    956     fMenuNavigate.addAction(&fActionPlay);
    957     fMenuNavigate.addAction(&fActionPause);
    958     fMenuNavigate.addAction(&fActionGoToLine);
    959 
    960     fMenuView.setTitle("View");
    961     fMenuView.addAction(&fActionBreakpoint);
    962     fMenuView.addAction(&fActionShowDeletes);
    963     fMenuView.addAction(&fActionToggleIndexStyle);
    964     fMenuView.addAction(&fActionZoomIn);
    965     fMenuView.addAction(&fActionZoomOut);
    966 
    967     fMenuWindows.setTitle("Window");
    968     fMenuWindows.addAction(&fActionInspector);
    969     fMenuWindows.addAction(&fActionSettings);
    970     fMenuWindows.addAction(&fActionDirectory);
    971 
    972     fActionGoToLine.setText("Go to Line...");
    973     fActionGoToLine.setDisabled(true);
    974     fMenuBar.addAction(fMenuFile.menuAction());
    975     fMenuBar.addAction(fMenuEdit.menuAction());
    976     fMenuBar.addAction(fMenuView.menuAction());
    977     fMenuBar.addAction(fMenuNavigate.menuAction());
    978     fMenuBar.addAction(fMenuWindows.menuAction());
    979 
    980     fPause = false;
    981 
    982     SkDebuggerGUI->setMenuBar(&fMenuBar);
    983     QMetaObject::connectSlotsByName(SkDebuggerGUI);
    984 }
    985 
    986 void SkDebuggerGUI::setupDirectoryWidget(const QString& path) {
    987     fPath = path;
    988     QDir dir(path);
    989     QRegExp r(".skp");
    990     fDirectoryWidget.clear();
    991     const QStringList files = dir.entryList();
    992     foreach (QString f, files) {
    993         if (f.contains(r))
    994             fDirectoryWidget.addItem(f);
    995     }
    996 }
    997 
    998 void SkDebuggerGUI::loadPicture(const SkString& fileName) {
    999     fFileName = fileName;
   1000     fLoading = true;
   1001     SkStream* stream = SkNEW_ARGS(SkFILEStream, (fileName.c_str()));
   1002 
   1003     SkPicture* picture = SkPicture::CreateFromStream(stream);
   1004 
   1005     if (NULL == picture) {
   1006         QMessageBox::critical(this, "Error loading file", "Couldn't read file, sorry.");
   1007         SkSafeUnref(stream);
   1008         return;
   1009     }
   1010 
   1011     fCanvasWidget.resetWidgetTransform();
   1012     fDebugger.loadPicture(picture);
   1013 
   1014     fSkipCommands.setCount(fDebugger.getSize());
   1015     for (int i = 0; i < fSkipCommands.count(); ++i) {
   1016         fSkipCommands[i] = false;
   1017     }
   1018 
   1019     SkSafeUnref(stream);
   1020     SkSafeUnref(picture);
   1021 
   1022     // Will this automatically clear out due to nature of refcnt?
   1023     SkTArray<SkString>* commands = fDebugger.getDrawCommandsAsStrings();
   1024     SkTDArray<size_t>* offsets = fDebugger.getDrawCommandOffsets();
   1025     SkASSERT(commands->count() == offsets->count());
   1026 
   1027     fActionProfile.setDisabled(false);
   1028 
   1029     /* fDebugCanvas is reinitialized every load picture. Need it to retain value
   1030      * of the visibility filter.
   1031      * TODO(chudy): This should be deprecated since fDebugger is not
   1032      * recreated.
   1033      * */
   1034     fDebugger.highlightCurrentCommand(fSettingsWidget.getVisibilityFilter());
   1035 
   1036     this->setupListWidget(commands, offsets);
   1037     this->setupComboBox(commands);
   1038     this->setupOverviewText(NULL, 0.0, 1);
   1039     fInspectorWidget.setDisabled(false);
   1040     fSettingsWidget.setDisabled(false);
   1041     fMenuEdit.setDisabled(false);
   1042     fMenuNavigate.setDisabled(false);
   1043     fMenuView.setDisabled(false);
   1044     fActionSave.setDisabled(false);
   1045     fActionSaveAs.setDisabled(false);
   1046     fLoading = false;
   1047     actionPlay();
   1048 }
   1049 
   1050 void SkDebuggerGUI::setupListWidget(SkTArray<SkString>* commands, SkTDArray<size_t>* offsets) {
   1051     SkASSERT(commands->count() == offsets->count());
   1052     fListWidget.clear();
   1053     int counter = 0;
   1054     int indent = 0;
   1055     for (int i = 0; i < commands->count(); i++) {
   1056         QListWidgetItem *item = new QListWidgetItem();
   1057         item->setData(Qt::DisplayRole, (*commands)[i].c_str());
   1058         item->setData(Qt::UserRole + 1, counter++);
   1059 
   1060         if (0 == strcmp("Restore", (*commands)[i].c_str()) ||
   1061             0 == strcmp("EndCommentGroup", (*commands)[i].c_str()) ||
   1062             0 == strcmp("PopCull", (*commands)[i].c_str())) {
   1063             indent -= 10;
   1064         }
   1065 
   1066         item->setData(Qt::UserRole + 3, indent);
   1067 
   1068         if (0 == strcmp("Save", (*commands)[i].c_str()) ||
   1069             0 == strcmp("Save Layer", (*commands)[i].c_str()) ||
   1070             0 == strcmp("BeginCommentGroup", (*commands)[i].c_str()) ||
   1071             0 == strcmp("PushCull", (*commands)[i].c_str())) {
   1072             indent += 10;
   1073         }
   1074 
   1075         item->setData(Qt::UserRole + 4, -1);
   1076         item->setData(Qt::UserRole + 5, (int)(*offsets)[i]);
   1077 
   1078         fListWidget.addItem(item);
   1079     }
   1080 }
   1081 
   1082 void SkDebuggerGUI::setupOverviewText(const SkTDArray<double>* typeTimes,
   1083                                       double totTime,
   1084                                       int numRuns) {
   1085     SkString overview;
   1086     fDebugger.getOverviewText(typeTimes, totTime, &overview, numRuns);
   1087     fInspectorWidget.setText(overview.c_str(), SkInspectorWidget::kOverview_TabType);
   1088 }
   1089 
   1090 void SkDebuggerGUI::setupClipStackText() {
   1091     SkString clipStack;
   1092     fDebugger.getClipStackText(&clipStack);
   1093     fInspectorWidget.setText(clipStack.c_str(), SkInspectorWidget::kClipStack_TabType);
   1094 }
   1095 
   1096 void SkDebuggerGUI::setupComboBox(SkTArray<SkString>* command) {
   1097     fFilter.clear();
   1098     fFilter.addItem("--Filter By Available Commands--");
   1099 
   1100     std::map<std::string, int> map;
   1101     for (int i = 0; i < command->count(); i++) {
   1102         map[(*command)[i].c_str()]++;
   1103     }
   1104 
   1105     for (std::map<std::string, int>::iterator it = map.begin(); it != map.end();
   1106          ++it) {
   1107         fFilter.addItem((it->first).c_str());
   1108     }
   1109 
   1110     // NOTE(chudy): Makes first item unselectable.
   1111     QStandardItemModel* model = qobject_cast<QStandardItemModel*>(
   1112             fFilter.model());
   1113     QModelIndex firstIndex = model->index(0, fFilter.modelColumn(),
   1114             fFilter.rootModelIndex());
   1115     QStandardItem* firstItem = model->itemFromIndex(firstIndex);
   1116     firstItem->setSelectable(false);
   1117 }
   1118