mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-26 11:52:54 +00:00
322 lines
12 KiB
C++
322 lines
12 KiB
C++
/*
|
|
* This file is part of KDevelop
|
|
*
|
|
* Copyright 2008 Vladimir Prus <ghost@cs.msu.su>
|
|
* Copyright 2013 Vlas Puhov <vlas.puhov@mail.ru>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public
|
|
* License along with this program; if not, write to the
|
|
* Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "breakpointwidget.h"
|
|
|
|
#include <QHBoxLayout>
|
|
#include <QSplitter>
|
|
#include <QTableView>
|
|
#include <QHeaderView>
|
|
#include <QMenu>
|
|
#include <QContextMenuEvent>
|
|
|
|
#include <KIcon>
|
|
#include <KLocalizedString>
|
|
#include <KPassivePopup>
|
|
#include <KDebug>
|
|
|
|
#include "breakpointdetails.h"
|
|
#include "../breakpoint/breakpoint.h"
|
|
#include "../breakpoint/breakpointmodel.h"
|
|
#include <interfaces/idebugcontroller.h>
|
|
#include <util/autoorientedsplitter.h>
|
|
|
|
#define IF_DEBUG(x)
|
|
#include <interfaces/icore.h>
|
|
#include <interfaces/idocumentcontroller.h>
|
|
#include <util/placeholderitemproxymodel.h>
|
|
|
|
using namespace KDevelop;
|
|
|
|
BreakpointWidget::BreakpointWidget(IDebugController *controller, QWidget *parent)
|
|
: QWidget(parent), m_firstShow(true), m_debugController(controller),
|
|
breakpointDisableAll_(0), breakpointEnableAll_(0), breakpointRemoveAll_(0)
|
|
{
|
|
setWindowTitle(i18nc("@title:window", "Debugger Breakpoints"));
|
|
setWhatsThis(i18nc("@info:whatsthis", "Displays a list of breakpoints with "
|
|
"their current status. Clicking on a "
|
|
"breakpoint item allows you to change "
|
|
"the breakpoint and will take you "
|
|
"to the source in the editor window."));
|
|
setWindowIcon( KIcon("process-stop") );
|
|
|
|
QHBoxLayout *layout = new QHBoxLayout(this);
|
|
layout->setMargin(0);
|
|
QSplitter *s = new AutoOrientedSplitter(this);
|
|
layout->addWidget(s);
|
|
m_splitter = s;
|
|
|
|
m_breakpointsView = new QTableView(s);
|
|
m_breakpointsView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
m_breakpointsView->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
m_breakpointsView->horizontalHeader()->setHighlightSections(false);
|
|
m_breakpointsView->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
|
details_ = new BreakpointDetails(s);
|
|
|
|
s->setStretchFactor(0, 2);
|
|
|
|
m_breakpointsView->verticalHeader()->hide();
|
|
|
|
PlaceholderItemProxyModel* proxyModel = new PlaceholderItemProxyModel(this);
|
|
proxyModel->setSourceModel(m_debugController->breakpointModel());
|
|
proxyModel->setColumnHint(Breakpoint::LocationColumn, i18n("New code breakpoint ..."));
|
|
proxyModel->setColumnHint(Breakpoint::ConditionColumn, i18n("Enter condition ..."));
|
|
m_breakpointsView->setModel(proxyModel);
|
|
connect(proxyModel, SIGNAL(dataInserted(int, QVariant)), SLOT(slotDataInserted(int, QVariant)));
|
|
m_proxyModel = proxyModel;
|
|
|
|
connect(m_breakpointsView, SIGNAL(activated(QModelIndex)), this, SLOT(slotOpenFile(QModelIndex)));
|
|
connect(m_breakpointsView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(slotUpdateBreakpointDetail()));
|
|
connect(m_debugController->breakpointModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(slotUpdateBreakpointDetail()));
|
|
connect(m_debugController->breakpointModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(slotUpdateBreakpointDetail()));
|
|
connect(m_debugController->breakpointModel(), SIGNAL(modelReset()), SLOT(slotUpdateBreakpointDetail()));
|
|
connect(m_debugController->breakpointModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(slotUpdateBreakpointDetail()));
|
|
|
|
|
|
connect(m_debugController->breakpointModel(),
|
|
SIGNAL(hit(KDevelop::Breakpoint*)),
|
|
SLOT(breakpointHit(KDevelop::Breakpoint*)));
|
|
|
|
connect(m_debugController->breakpointModel(),
|
|
SIGNAL(error(KDevelop::Breakpoint*,QString,int)),
|
|
SLOT(breakpointError(KDevelop::Breakpoint*,QString,int)));
|
|
|
|
setupPopupMenu();
|
|
}
|
|
|
|
void BreakpointWidget::setupPopupMenu()
|
|
{
|
|
popup_ = new QMenu(this);
|
|
|
|
QMenu* newBreakpoint = popup_->addMenu( i18nc("New breakpoint", "&New") );
|
|
newBreakpoint->setIcon(KIcon("list-add"));
|
|
|
|
QAction* action = newBreakpoint->addAction(
|
|
i18nc("Code breakpoint", "&Code"),
|
|
this,
|
|
SLOT(slotAddBlankBreakpoint()) );
|
|
// Use this action also to provide a local shortcut
|
|
action->setShortcut(QKeySequence(Qt::Key_B + Qt::CTRL,
|
|
Qt::Key_C));
|
|
addAction(action);
|
|
|
|
newBreakpoint->addAction(
|
|
i18nc("Data breakpoint", "Data &Write"),
|
|
this, SLOT(slotAddBlankWatchpoint()));
|
|
newBreakpoint->addAction(
|
|
i18nc("Data read breakpoint", "Data &Read"),
|
|
this, SLOT(slotAddBlankReadWatchpoint()));
|
|
newBreakpoint->addAction(
|
|
i18nc("Data access breakpoint", "Data &Access"),
|
|
this, SLOT(slotAddBlankAccessWatchpoint()));
|
|
|
|
QAction* breakpointDelete = popup_->addAction(
|
|
KIcon("edit-delete"),
|
|
i18n( "&Delete" ),
|
|
this,
|
|
SLOT(slotRemoveBreakpoint()));
|
|
breakpointDelete->setShortcut(Qt::Key_Delete);
|
|
breakpointDelete->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
|
addAction(breakpointDelete);
|
|
|
|
|
|
popup_->addSeparator();
|
|
breakpointDisableAll_ = popup_->addAction(i18n("Disable &All"), this, SLOT(slotDisableAllBreakpoints()));
|
|
breakpointEnableAll_ = popup_->addAction(i18n("&Enable All"), this, SLOT(slotEnableAllBreakpoints()));
|
|
breakpointRemoveAll_ = popup_->addAction(i18n("&Remove All"), this, SLOT(slotRemoveAllBreakpoints()));
|
|
|
|
connect(popup_,SIGNAL(aboutToShow()), this, SLOT(slotPopupMenuAboutToShow()));
|
|
}
|
|
|
|
|
|
void BreakpointWidget::contextMenuEvent(QContextMenuEvent* event)
|
|
{
|
|
popup_->popup(event->globalPos());
|
|
}
|
|
|
|
void BreakpointWidget::slotPopupMenuAboutToShow()
|
|
{
|
|
if (m_debugController->breakpointModel()->rowCount() < 2) {
|
|
breakpointDisableAll_->setDisabled(true);
|
|
breakpointEnableAll_->setDisabled(true);
|
|
breakpointRemoveAll_->setDisabled(true);
|
|
} else {
|
|
breakpointRemoveAll_->setEnabled(true);
|
|
bool allDisabled = true;
|
|
bool allEnabled = true;
|
|
for (int i = 0; i < m_debugController->breakpointModel()->rowCount() - 1 ; i++) {
|
|
Breakpoint *bp = m_debugController->breakpointModel()->breakpoint(i);
|
|
if (bp->enabled())
|
|
allDisabled = false;
|
|
else
|
|
allEnabled = false;
|
|
}
|
|
breakpointDisableAll_->setDisabled(allDisabled);
|
|
breakpointEnableAll_->setDisabled(allEnabled);
|
|
}
|
|
|
|
}
|
|
|
|
void BreakpointWidget::showEvent(QShowEvent *)
|
|
{
|
|
if (m_firstShow) {
|
|
QHeaderView* header = m_breakpointsView->horizontalHeader();
|
|
|
|
for (int i = 0; i < m_breakpointsView->model()->columnCount(); ++i) {
|
|
if(i == Breakpoint::LocationColumn){
|
|
continue;
|
|
}
|
|
m_breakpointsView->resizeColumnToContents(i);
|
|
}
|
|
//for some reasons sometimes width can be very small about 200... But it doesn't matter as we use tooltip anyway.
|
|
int width = m_breakpointsView->size().width();
|
|
|
|
header->resizeSection(Breakpoint::LocationColumn, width > 400 ? width/2 : header->sectionSize(Breakpoint::LocationColumn)*2 );
|
|
m_firstShow = false;
|
|
}
|
|
}
|
|
|
|
void BreakpointWidget::edit(KDevelop::Breakpoint *n)
|
|
{
|
|
QModelIndex index = m_proxyModel->mapFromSource(m_debugController->breakpointModel()->breakpointIndex(n, Breakpoint::LocationColumn));
|
|
m_breakpointsView->setCurrentIndex(index);
|
|
m_breakpointsView->edit(index);
|
|
}
|
|
|
|
void BreakpointWidget::slotDataInserted(int column, const QVariant& value)
|
|
{
|
|
Breakpoint* breakpoint = m_debugController->breakpointModel()->addCodeBreakpoint();
|
|
breakpoint->setData(column, value);
|
|
}
|
|
|
|
void BreakpointWidget::slotAddBlankBreakpoint()
|
|
{
|
|
edit(m_debugController->breakpointModel()->addCodeBreakpoint());
|
|
}
|
|
|
|
void BreakpointWidget::slotAddBlankWatchpoint()
|
|
{
|
|
edit(m_debugController->breakpointModel()->addWatchpoint());
|
|
}
|
|
|
|
void BreakpointWidget::slotAddBlankReadWatchpoint()
|
|
{
|
|
edit(m_debugController->breakpointModel()->addReadWatchpoint());
|
|
}
|
|
|
|
|
|
void KDevelop::BreakpointWidget::slotAddBlankAccessWatchpoint()
|
|
{
|
|
edit(m_debugController->breakpointModel()->addAccessWatchpoint());
|
|
}
|
|
|
|
|
|
void BreakpointWidget::slotRemoveBreakpoint()
|
|
{
|
|
QItemSelectionModel* sel = m_breakpointsView->selectionModel();
|
|
QModelIndexList selected = sel->selectedIndexes();
|
|
IF_DEBUG( kDebug() << selected; )
|
|
if (!selected.isEmpty()) {
|
|
m_debugController->breakpointModel()->removeRow(selected.first().row());
|
|
}
|
|
}
|
|
|
|
void BreakpointWidget::slotRemoveAllBreakpoints()
|
|
{
|
|
m_debugController->breakpointModel()->removeRows(0, m_debugController->breakpointModel()->rowCount());
|
|
}
|
|
|
|
|
|
void BreakpointWidget::slotUpdateBreakpointDetail()
|
|
{
|
|
QModelIndexList selected = m_breakpointsView->selectionModel()->selectedIndexes();
|
|
IF_DEBUG( kDebug() << selected; )
|
|
if (selected.isEmpty()) {
|
|
details_->setItem(0);
|
|
} else {
|
|
details_->setItem(m_debugController->breakpointModel()->breakpoint(selected.first().row()));
|
|
}
|
|
}
|
|
|
|
void BreakpointWidget::breakpointHit(KDevelop::Breakpoint* b)
|
|
{
|
|
IF_DEBUG( kDebug() << b; )
|
|
const QModelIndex index = m_proxyModel->mapFromSource(m_debugController->breakpointModel()->breakpointIndex(b, 0));
|
|
m_breakpointsView->selectionModel()->select(
|
|
index,
|
|
QItemSelectionModel::Rows
|
|
| QItemSelectionModel::ClearAndSelect);
|
|
}
|
|
|
|
void BreakpointWidget::breakpointError(KDevelop::Breakpoint* b, const QString& msg, int column)
|
|
{
|
|
IF_DEBUG( kDebug() << b << msg << column; )
|
|
|
|
// FIXME: we probably should prevent this error notification during
|
|
// initial setting of breakpoint, to avoid a cloud of popups.
|
|
if (!m_breakpointsView->isVisible())
|
|
return;
|
|
|
|
const QModelIndex index = m_proxyModel->mapFromSource(m_debugController->breakpointModel()->breakpointIndex(b, column));
|
|
QPoint p = m_breakpointsView->visualRect(index).topLeft();
|
|
p = m_breakpointsView->mapToGlobal(p);
|
|
|
|
KPassivePopup *pop = new KPassivePopup(m_breakpointsView);
|
|
pop->setPopupStyle(KPassivePopup::Boxed);
|
|
pop->setAutoDelete(true);
|
|
// FIXME: the icon, too.
|
|
pop->setView("", msg);
|
|
pop->setTimeout(-1);
|
|
pop->show(p);
|
|
}
|
|
|
|
void BreakpointWidget::slotOpenFile(const QModelIndex& breakpointIdx)
|
|
{
|
|
if (breakpointIdx.column() != Breakpoint::LocationColumn){
|
|
return;
|
|
}
|
|
Breakpoint *bp = m_debugController->breakpointModel()->breakpoint(breakpointIdx.row());
|
|
if (!bp || bp->line() == -1 || bp->url().isEmpty() ){
|
|
return;
|
|
}
|
|
|
|
ICore::self()->documentController()->openDocument(bp->url().pathOrUrl(KUrl::RemoveTrailingSlash), KTextEditor::Cursor(bp->line(), 0), IDocumentController::DoNotFocus);
|
|
}
|
|
|
|
void BreakpointWidget::slotDisableAllBreakpoints()
|
|
{
|
|
for (int i = 0; i < m_debugController->breakpointModel()->rowCount() - 1 ; i++) {
|
|
Breakpoint *bp = m_debugController->breakpointModel()->breakpoint(i);
|
|
bp->setData(Breakpoint::EnableColumn, Qt::Unchecked);
|
|
}
|
|
}
|
|
|
|
void BreakpointWidget::slotEnableAllBreakpoints()
|
|
{
|
|
for (int i = 0; i < m_debugController->breakpointModel()->rowCount() - 1 ; i++) {
|
|
Breakpoint *bp = m_debugController->breakpointModel()->breakpoint(i);
|
|
bp->setData(Breakpoint::EnableColumn, Qt::Checked);
|
|
}
|
|
}
|
|
|
|
|
|
#include "moc_breakpointwidget.cpp"
|