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
SkDebuggerGUI(QWidget * parent)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
actionBreakpoints()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
showDeletes()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)
run(const SkPicture * pict,sk_tools::PictureRenderer * renderer,int repeats)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
actionProfile()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
actionCancel()189 void SkDebuggerGUI::actionCancel() {
190 for (int row = 0; row < fListWidget.count(); row++) {
191 fListWidget.item(row)->setHidden(false);
192 }
193 }
194
actionClearBreakpoints()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
actionClearDeletes()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
actionClose()214 void SkDebuggerGUI::actionClose() {
215 this->close();
216 }
217
actionDelete()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
actionGLSettingsChanged()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
actionInspector()251 void SkDebuggerGUI::actionInspector() {
252 bool newState = !fInspectorWidget.isHidden();
253
254 fInspectorWidget.setHidden(newState);
255 fViewStateFrame.setHidden(newState);
256 fDrawCommandGeometryWidget.setHidden(newState);
257 }
258
actionPlay()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
actionRasterSettingsChanged()271 void SkDebuggerGUI::actionRasterSettingsChanged() {
272 fCanvasWidget.setWidgetVisibility(SkCanvasWidget::kRaster_8888_WidgetType,
273 !fSettingsWidget.isRasterEnabled());
274 fDebugger.setOverdrawViz(fSettingsWidget.isOverdrawVizEnabled());
275 this->updateImage();
276 }
277
actionVisualizationsChanged()278 void SkDebuggerGUI::actionVisualizationsChanged() {
279 fDebugger.setMegaViz(fSettingsWidget.isMegaVizEnabled());
280 fDebugger.setPathOps(fSettingsWidget.isPathOpsEnabled());
281 fDebugger.highlightCurrentCommand(fSettingsWidget.isVisibilityFilterEnabled());
282 this->updateImage();
283 }
284
actionTextureFilter()285 void SkDebuggerGUI::actionTextureFilter() {
286 SkFilterQuality quality;
287 bool enabled = fSettingsWidget.getFilterOverride(&quality);
288 fDebugger.setTexFilterOverride(enabled, quality);
289 fCanvasWidget.update();
290 }
291
actionRewind()292 void SkDebuggerGUI::actionRewind() {
293 fListWidget.setCurrentRow(0);
294 }
295
actionSave()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
actionSaveAs()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
actionScale(float scaleFactor)312 void SkDebuggerGUI::actionScale(float scaleFactor) {
313 fZoomBox.setText(QString::number(scaleFactor * 100, 'f', 0).append("%"));
314 }
315
actionSettings()316 void SkDebuggerGUI::actionSettings() {
317 if (fSettingsWidget.isHidden()) {
318 fSettingsWidget.setHidden(false);
319 } else {
320 fSettingsWidget.setHidden(true);
321 }
322 }
323
actionStepBack()324 void SkDebuggerGUI::actionStepBack() {
325 int currentRow = fListWidget.currentRow();
326 if (currentRow != 0) {
327 fListWidget.setCurrentRow(currentRow - 1);
328 }
329 }
330
actionStepForward()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
drawComplete()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
saveToFile(const SkString & filename)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
loadFile(QListWidgetItem * item)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
openFile()369 void SkDebuggerGUI::openFile() {
370 QString temp = QFileDialog::getOpenFileName(this, tr("Open File"), "",
371 tr("Files (*.*)"));
372 openFile(temp);
373 }
374
openFile(const QString & filename)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
pauseDrawing(bool isPaused)385 void SkDebuggerGUI::pauseDrawing(bool isPaused) {
386 fPausedRow = fListWidget.currentRow();
387 this->updateDrawCommandInfo();
388 }
389
updateDrawCommandInfo()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
selectCommand(int command)426 void SkDebuggerGUI::selectCommand(int command) {
427 if (this->isPaused()) {
428 fListWidget.setCurrentRow(command);
429 }
430 }
431
toggleBreakpoint()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
toggleDirectory()445 void SkDebuggerGUI::toggleDirectory() {
446 fDirectoryWidget.setHidden(!fDirectoryWidget.isHidden());
447 }
448
toggleFilter(QString string)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
setupUi(QMainWindow * SkDebuggerGUI)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
setupDirectoryWidget(const QString & path)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
loadPicture(const SkString & fileName)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
setupListWidget()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
setupOverviewText(const SkTDArray<double> * typeTimes,double totTime,int numRuns)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
setupComboBox()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
updateImage()854 void SkDebuggerGUI::updateImage() {
855 if (this->isPaused()) {
856 fCanvasWidget.drawTo(fPausedRow);
857 } else {
858 fCanvasWidget.drawTo(fListWidget.currentRow());
859 }
860 }
861
updateHit(int newHit)862 void SkDebuggerGUI::updateHit(int newHit) {
863 fCommandHitBox.setText(QString::number(newHit));
864 }
865
866