/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** Commercial Usage ** ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at http://qt.nokia.com/contact. ** **************************************************************************/ #include "mainwindow.h" #include "gdbdebugger.h" #include "gdboutputwindow.h" #include "lean.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace GdbDebugger; using namespace GdbDebugger::Internal; /////////////////////////////////////////////////////////////////////// // // LocationMark // /////////////////////////////////////////////////////////////////////// #ifdef USE_BASETEXTEDITOR class LocationMark : public TextEditor::ITextMark { public: LocationMark() { m_editor = 0; } ~LocationMark() { qDebug() << "LOCATIONMARK DESTRUCTOR" << m_editor; } QIcon icon() const; QColor color() const; void contextMenu(const QPoint &/*position*/) {} void toggle() {} void updateLineNumber(int /*line*/) {} void removedFromEditor() { m_editor = 0; } TextViewer *editor() const { return m_editor.data(); } void setEditor(TextViewer *editor); void updateBlock(const QTextBlock &) {} void documentClosing() {} private: QPointer m_editor; }; void LocationMark::setEditor(TextViewer *editor) { if (m_editor) m_editor->markableInterface()->removeMark(this); if (editor) m_editor = editor; else m_editor = 0; } QIcon LocationMark::icon() const { static const QIcon icon(":/gdbdebugger/images/location.svg"); return icon; } QColor LocationMark::color() const { return QColor(255, 255, 0, 20); } LocationMark *theLocationMark() { static LocationMark *mark = new LocationMark; return mark; } #endif /////////////////////////////////////////////////////////////////////////// // // MainWindow // /////////////////////////////////////////////////////////////////////////// MainWindow::MainWindow() { m_manager = new DebuggerManager; m_manager->initialize(); m_manager->createDockWidgets(); m_manager->setSimpleDockWidgetArrangement(); setCentralWidget(m_manager->mainWindow()); // // Source code view // m_textViewers = new QTabWidget(m_manager->mainWindow()); m_textViewers->setObjectName("Editors"); m_textViewers->setElideMode(Qt::ElideLeft); //setCentralWidget(m_textViewers); m_manager->mainWindow()->setCentralWidget(m_textViewers); setGeometry(QRect(0, 0, 800, 600)); // // Actions // m_fileOpenAction = new QAction(tr("Open file"), this); m_fileOpenAction->setShortcut(QKeySequence(tr("Ctrl+O"))); m_quitAction = new QAction(tr("Quit"), this); m_quitAction->setShortcut(QKeySequence(tr("Ctrl+Q"))); #if 0 m_startDebuggerAction = new QAction(tr("Run to main()"), this); m_startDebuggerAction->setShortcut(QKeySequence(tr("Ctrl+F5"))); connect(m_startDebuggerAction, SIGNAL(triggered()), this, SLOT(startDebuggerRequest())); connect(m_resetAction, SIGNAL(triggered()), m_manager, SLOT(resetDebugger())); connect(m_watchAction, SIGNAL(triggered()), m_manager, SLOT(addToWatchWindow())); connect(m_breakAction, SIGNAL(triggered()), this, SLOT(toggleBreakpoint())); #endif m_manager->m_continueAction->setShortcut(QKeySequence(tr("F5"))); m_manager->m_stopAction->setShortcut(QKeySequence(tr("Shift+F5"))); //m_resetAction = new QAction(tr("Reset Debugger"), this); //m_resetAction->setShortcut(QKeySequence(tr("Ctrl+Shift+F5"))); m_manager->m_nextAction->setShortcut(QKeySequence(tr("F6"))); m_manager->m_stepAction->setShortcut(QKeySequence(tr("F7"))); m_manager->m_nextIAction->setShortcut(QKeySequence(tr("Shift+F6"))); m_manager->m_stepIAction->setShortcut(QKeySequence(tr("Shift+F9"))); m_manager->m_stepOutAction->setShortcut(QKeySequence(tr("Shift+F7"))); m_manager->m_runToLineAction->setShortcut(QKeySequence(tr("Shift+F8"))); //m_manager->m_jumpToLineAction->setShortcut(QKeySequence(tr("Shift+F8"))); m_manager->m_breakAction->setShortcut(QKeySequence(tr("F8"))); m_manager->m_watchAction->setShortcut(QKeySequence(tr("ALT+D,ALT+W"))); // // Files // QDockWidget *filesDock = new QDockWidget(this); filesDock->setObjectName("FilesDock"); filesDock->setGeometry(QRect(0, 0, 200, 200)); filesDock->setWindowTitle(tr("Files")); filesDock->setAllowedAreas(Qt::AllDockWidgetAreas); addDockWidget(Qt::LeftDockWidgetArea, filesDock); m_filesModel = new QStandardItemModel(this); m_filesWindow = new QTreeView(this); m_filesWindow->setModel(m_filesModel); m_filesWindow->header()->hide(); m_filesWindow->setRootIsDecorated(false); filesDock->setWidget(m_filesWindow); connect(m_filesWindow, SIGNAL(activated(QModelIndex)), this, SLOT(changeCurrentFile(QModelIndex))); connect(m_filesWindow, SIGNAL(clicked(QModelIndex)), this, SLOT(changeCurrentFile(QModelIndex))); // // Menubar // QMenu *fileMenu = new QMenu(menuBar()); fileMenu->setTitle(tr("File")); fileMenu->addAction(m_fileOpenAction); fileMenu->addSeparator(); fileMenu->addAction(m_quitAction); menuBar()->addMenu(fileMenu); QMenu *debugMenu = new QMenu(menuBar()); debugMenu->setTitle(tr("Debug")); debugMenu->addAction(m_manager->m_continueAction); debugMenu->addAction(m_manager->m_stopAction); debugMenu->addSeparator(); debugMenu->addAction(m_manager->m_nextAction); debugMenu->addAction(m_manager->m_stepAction); debugMenu->addAction(m_manager->m_nextIAction); debugMenu->addAction(m_manager->m_stepIAction); debugMenu->addAction(m_manager->m_stepOutAction); debugMenu->addAction(m_manager->m_runToLineAction); debugMenu->addAction(m_manager->m_runToFunctionAction); debugMenu->addAction(m_manager->m_jumpToLineAction); debugMenu->addSeparator(); debugMenu->addAction(m_manager->m_breakAction); //debugMenu->addAction(m_startDebuggerAction); menuBar()->addMenu(debugMenu); // // Toolbar // QToolBar *toolbar = m_manager->createToolBar(); toolbar->setObjectName("ToolBar"); addToolBar(Qt::TopToolBarArea, toolbar); // // Statusbar // QStatusBar *statusbar = new QStatusBar(this); statusbar->setObjectName("StatusBar"); statusbar->setGeometry(QRect(0, 578, 800, 22)); setStatusBar(statusbar); show(); restoreState(settings().value("MainWindow/State").toByteArray()); setGeometry(settings().value("MainWindow/Geometry").toRect()); connect(m_fileOpenAction, SIGNAL(triggered()), this, SLOT(fileOpen())); connect(m_quitAction, SIGNAL(triggered()), this, SLOT(quit())); connect(m_manager, SIGNAL(resetLocationRequested()), this, SLOT(resetLocation())); connect(m_manager, SIGNAL(gotoLocationRequested(QString,int,bool)), this, SLOT(gotoLocation(QString,int,bool))); connect(m_manager, SIGNAL(dataDumpersUnavailable()), this, SLOT(handleDataDumpersUnavailable())); // Application interaction connect(m_manager, SIGNAL(currentTextEditorRequested(QString*,int*,QObject**)), this, SLOT(queryCurrentTextEditor(QString*,int*,QObject**))); } MainWindow::~MainWindow() { settings().setValue("MainWindow/State", saveState()); settings().setValue("MainWindow/Geometry", geometry()); settings().sync(); } QSettings &MainWindow::settings() { static QSettings s("Nokia", "Qdb"); return s; } void MainWindow::loadFile(const QString &fileName) { QFileInfo fi(fileName); if (fi.isExecutable() && !fileName.endsWith(".cpp") && !fileName.endsWith(".h")) { m_executable = fileName; QStandardItem *item = new QStandardItem(fileName); QStandardItem *childItem = new QStandardItem(""); item->appendRow(childItem); // force [+] on item item->setToolTip(fi.absoluteFilePath()); //m_fileModel->appendRow(item); } else { (void)findOrCreateTextViewer(fileName); } } void MainWindow::loadFiles(const QStringList &fileNames) { if (fileNames.isEmpty()) return; foreach (const QString &fileName, fileNames) loadFile(fileName); startDebuggingRequest(); } void MainWindow::startDebuggingRequest() { if (m_manager->m_startIsContinue) { m_manager->continueInferior(); return; } m_manager->settings()->m_autoRun = true; m_manager->settings()->m_autoQuit = true; m_manager->settings()->m_gdbCmd = "gdb"; m_manager->settings()->m_breakOnMain = "gdb"; qDebug() << "START REQUEST"; if (m_executable.isEmpty()) { QMessageBox::warning(0, tr("Not a runnable project"), tr("The current startup project can not be run.")); return; } StartData sd; sd.outputFile = m_executable; //Project *pro = project(); //sd.outputFile = pro->executable(pro->activeConfiguration()); // NBS TODO pid // pid = pe->configLanguage( // ProjectExplorer::Constants::P_RUNNINGPID, langID).toString(); // sd.env = pro->environment(pro->activeConfiguration()).toStringList(); // sd.workingDir = pro->workingDirectory(pro->activeConfiguration()); // sd.processArgs = pro->executableArguments(pro->activeConfiguration()); // const QFileInfo editorFile(textViewer->file()->fileName()); // sd.currentEditorDir = editorFile.dir().absolutePath(); m_manager->startDebuggerAndRunInferior(sd); } void MainWindow::startDebuggerRequest() { // FIXME: Ignored StartData sd; sd.outputFile = m_executable; //Project *pro = project(); //sd.outputFile = pro->executable(pro->activeConfiguration()); // NBS TODO pid // pid = pe->configLanguage( // ProjectExplorer::Constants::P_RUNNINGPID, langID).toString(); // sd.env = pro->environment(pro->activeConfiguration()).toStringList(); // sd.workingDir = pro->workingDirectory(pro->activeConfiguration()); // sd.processArgs = pro->executableArguments(pro->activeConfiguration()); // const QFileInfo editorFile(textViewer->file()->fileName()); // sd.currentEditorDir = editorFile.dir().absolutePath(); m_manager->m_settings->m_autoRun = false; m_manager->m_settings->m_autoQuit = true; m_manager->startDebuggerAndRunInferior(sd); } void MainWindow::jumpToExec() { #if 0 TextViewer *editor = currentTextViewer(); if (!editor) return; int lineNumber = editor->currentLine(); QString fileName = editor->file()->fileName(); if (fileName.isEmpty()) return; m_manager->jumpToLineExec(fileName, lineNumber); #endif } void MainWindow::runToExec() { #if 0 TextViewer *editor = currentTextViewer(); if (!editor) return; int lineNumber = editor->currentLine(); QString fileName = editor->file()->fileName(); if (fileName.isEmpty()) return; m_manager->runToLineExec(fileName, lineNumber); #endif } void MainWindow::showStatusMessage(const QString &msg, int timeout) { statusBar()->showMessage(msg, timeout); } void MainWindow::resetLocation() { TextViewer *textViewer = currentTextViewer(); if (!textViewer) return; const int blockNumber = m_textBlockFromName.value(textViewer, -1); if (blockNumber == 1) return; const QTextBlock &block = textViewer->document()->findBlockByNumber(blockNumber); if (block.isValid()) { QTextCursor cursor(block); //QTextBlockFormat format = block.blockFormat(); //format.setBackground(QColor(200, 200, 250)); cursor.setBlockFormat(QTextBlockFormat()); textViewer->setTextCursor(cursor); textViewer->centerCursor(); } #ifdef USE_BASETEXTEDITOR if (TextViewer *editor = theLocationMark()->editor()) editor->markableInterface()->removeMark(theLocationMark()); theLocationMark()->setEditor(0); #endif } void MainWindow::gotoLocation(const QString &fileName, int line, bool setMarker) { //qDebug() << "GOTO " << fileName << line << setMarker; Q_UNUSED(setMarker) TextViewer *textViewer = findOrCreateTextViewer(fileName); m_textViewers->setCurrentWidget(textViewer); const int blockNumber = line - 1; const QTextBlock &block = textViewer->document()->findBlockByNumber(blockNumber); if (block.isValid()) { QTextCursor cursor(block); QTextBlockFormat format = block.blockFormat(); format.setBackground(QColor(230, 200, 200)); cursor.setBlockFormat(format); textViewer->setTextCursor(cursor); textViewer->centerCursor(); m_textBlockFromName[textViewer] = blockNumber; #ifdef USE_BASETEXTEDITOR if (line >= 1) { if (setMarker) { theLocationMark()->setEditor(textViewer); textViewer->markableInterface()->addMark(theLocationMark(), line); } textViewer->gotoLine(line + 8); textViewer->gotoLine(line); // FIXME: editor->centerCursor(); } #endif } else { qDebug() << "INVALID BLOCK FOR LINE " << line << " IN " << fileName; } } void MainWindow::quit() { m_manager->exitDebugger(); close(); } void MainWindow::fileOpen() { QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), settings().value("FileOpen/LastDir").toString() // filterQString & filter = QString(), //QString * selectedFilter = 0, Options options = 0 ); settings().setValue("FileOpen/LastDir", QFileInfo(fileName).dir().dirName()); if (fileName.isEmpty()) return; loadFile(fileName); } void MainWindow::queryCurrentTextEditor(QString *fileName, int *line, QObject **object) { //Core::IEditor *editor = core->editorManager()->currentEditor(); //*textEditor = qobject_cast(current); TextViewer *textEditor = currentTextViewer(); if (fileName) *fileName = textEditor->fileName(); if (line) *line = textEditor->currentLine(); if (object) *object = textEditor; } TextViewer *MainWindow::findOrCreateTextViewer(const QString &fileName) { TextViewer *textViewer = m_textViewerFromName.value(fileName); if (textViewer) return textViewer; textViewer = new TextViewer(this); textViewer->open(fileName); textViewer->setReadOnly(true); m_textViewerFromName[fileName] = textViewer; m_textViewers->addTab(textViewer, fileName); m_textViewers->setCurrentWidget(textViewer); if (m_filesModel->findItems(fileName).isEmpty()) m_filesModel->appendRow(new QStandardItem(fileName)); //m_manager->textEditorOpened(textViewer->editableInterface()); return textViewer; } TextViewer *MainWindow::currentTextViewer() { return qobject_cast(m_textViewers->currentWidget()); } void MainWindow::changeCurrentFile(const QModelIndex &idx) { QString fileName = m_filesModel->data(idx).toString(); m_textViewers->setCurrentWidget(findOrCreateTextViewer(fileName)); } void MainWindow::handleDataDumpersUnavailable() { QMessageBox::warning(this, tr("Cannot find special data dumpers"), tr("The debugged binary does not contain information needed for " "nice display of Qt data types.\n\n" "Make sure you use something like\n\n" "SOURCES *= .../ide/main/bin/gdbmacros/gdbmacros.cpp\n\n" "in your .pro file.") ); }