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