• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SkDebuggerGUI(QWidget * parent)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 
actionBreakpoints()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 
showDeletes()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 
actionCancel()120 void SkDebuggerGUI::actionCancel() {
121     for (int row = 0; row < fListWidget.count(); row++) {
122         fListWidget.item(row)->setHidden(false);
123     }
124 }
125 
actionClearBreakpoints()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 
actionClearDeletes()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 
actionClose()145 void SkDebuggerGUI::actionClose() {
146     this->close();
147 }
148 
actionDelete()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
actionGLSettingsChanged()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 
actionInspector()182 void SkDebuggerGUI::actionInspector() {
183     bool newState = !fInspectorWidget.isHidden();
184 
185     fInspectorWidget.setHidden(newState);
186     fViewStateFrame.setHidden(newState);
187     fDrawCommandGeometryWidget.setHidden(newState);
188 }
189 
actionPlay()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 
actionRasterSettingsChanged()202 void SkDebuggerGUI::actionRasterSettingsChanged() {
203     fCanvasWidget.setWidgetVisibility(SkCanvasWidget::kRaster_8888_WidgetType,
204                                       !fSettingsWidget.isRasterEnabled());
205     this->updateImage();
206 }
207 
actionVisualizationsChanged()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 
actionTextureFilter()216 void SkDebuggerGUI::actionTextureFilter() {
217     SkFilterQuality quality;
218     bool enabled = fSettingsWidget.getFilterOverride(&quality);
219     fDebugger.setTexFilterOverride(enabled, quality);
220     fCanvasWidget.update();
221 }
222 
actionRewind()223 void SkDebuggerGUI::actionRewind() {
224     fListWidget.setCurrentRow(0);
225 }
226 
actionSave()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 
actionSaveAs()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 
actionScale(float scaleFactor)243 void SkDebuggerGUI::actionScale(float scaleFactor) {
244     fZoomBox.setText(QString::number(scaleFactor * 100, 'f', 0).append("%"));
245 }
246 
actionSettings()247 void SkDebuggerGUI::actionSettings() {
248     if (fSettingsWidget.isHidden()) {
249         fSettingsWidget.setHidden(false);
250     } else {
251         fSettingsWidget.setHidden(true);
252     }
253 }
254 
actionStepBack()255 void SkDebuggerGUI::actionStepBack() {
256     int currentRow = fListWidget.currentRow();
257     if (currentRow != 0) {
258         fListWidget.setCurrentRow(currentRow - 1);
259     }
260 }
261 
actionStepForward()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 
drawComplete()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 
saveToFile(const SkString & filename)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 
loadFile(QListWidgetItem * item)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 
openFile()306 void SkDebuggerGUI::openFile() {
307     QString temp = QFileDialog::getOpenFileName(this, tr("Open File"), "",
308             tr("Files (*.*)"));
309     openFile(temp);
310 }
311 
openFile(const QString & filename)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 
pauseDrawing(bool isPaused)320 void SkDebuggerGUI::pauseDrawing(bool isPaused) {
321     fPausedRow = fListWidget.currentRow();
322     this->updateDrawCommandInfo();
323 }
324 
updateDrawCommandInfo()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 
selectCommand(int command)361 void SkDebuggerGUI::selectCommand(int command) {
362     if (this->isPaused()) {
363         fListWidget.setCurrentRow(command);
364     }
365 }
366 
toggleBreakpoint()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 
toggleDirectory()380 void SkDebuggerGUI::toggleDirectory() {
381     fDirectoryWidget.setHidden(!fDirectoryWidget.isHidden());
382 }
383 
toggleFilter(QString string)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 
setupUi(QMainWindow * SkDebuggerGUI)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 
setupDirectoryWidget(const QString & path)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 
populateDirectoryWidget()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 
loadPicture(const SkString & fileName)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 
setupListWidget()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 
setupOverviewText(const SkTDArray<double> * typeTimes,double totTime,int numRuns)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 
setupComboBox()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 
updateImage()792 void SkDebuggerGUI::updateImage() {
793     if (this->isPaused()) {
794         fCanvasWidget.drawTo(fPausedRow);
795     } else {
796         fCanvasWidget.drawTo(fListWidget.currentRow());
797     }
798 }
799 
updateHit(int newHit)800 void SkDebuggerGUI::updateHit(int newHit) {
801     fCommandHitBox.setText(QString::number(newHit));
802 }
803 
804