/* * Copyright Johannes Sixt * This file is licensed under the GNU General Public License Version 2. * See the file COPYING in the toplevel directory of the source directory. */ #include #include /* i18n */ #include #include #include #include #include #include #include #include "debugger.h" #include "brkpt.h" #include "dbgdriver.h" #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mydebug.h" class BreakpointItem : public TQListViewItem, public Breakpoint { public: BreakpointItem(TQListView* list, const Breakpoint& bp); void updateFrom(const Breakpoint& bp); void display(); /* sets icon and visible texts */ bool enabled() const { return Breakpoint::enabled; } }; BreakpointTable::BreakpointTable(TQWidget* parent, const char* name) : TQWidget(parent, name), m_debugger(0), m_bpEdit(this, "bpedit"), m_list(this, "bptable"), m_btAddBP(this, "addbp"), m_btAddWP(this, "addwp"), m_btRemove(this, "remove"), m_btEnaDis(this, "enadis"), m_btViewCode(this, "view"), m_btConditional(this, "conditional"), m_layout(this, 8), m_listandedit(8), m_buttons(8) { m_bpEdit.setMinimumSize(m_bpEdit.sizeHint()); connect(&m_bpEdit, SIGNAL(returnPressed()), this, SLOT(addBP())); initListAndIcons(); connect(&m_list, SIGNAL(currentChanged(TQListViewItem*)), SLOT(updateUI())); // double click on item is same as View code connect(&m_list, SIGNAL(doubleClicked(TQListViewItem*)), this, SLOT(viewBP())); // need mouse button events m_list.viewport()->installEventFilter(this); m_btAddBP.setText(i18n("Add &Breakpoint")); m_btAddBP.setMinimumSize(m_btAddBP.sizeHint()); connect(&m_btAddBP, SIGNAL(clicked()), this, SLOT(addBP())); m_btAddWP.setText(i18n("Add &Watchpoint")); m_btAddWP.setMinimumSize(m_btAddWP.sizeHint()); connect(&m_btAddWP, SIGNAL(clicked()), this, SLOT(addWP())); m_btRemove.setText(i18n("&Remove")); m_btRemove.setMinimumSize(m_btRemove.sizeHint()); connect(&m_btRemove, SIGNAL(clicked()), this, SLOT(removeBP())); // the Enable/Disable button changes its label m_btEnaDis.setText(i18n("&Disable")); // make a dummy button to get the size of the alternate label { TQSize size = m_btEnaDis.sizeHint(); TQPushButton dummy(this); dummy.setText(i18n("&Enable")); TQSize sizeAlt = dummy.sizeHint(); if (sizeAlt.width() > size.width()) size.setWidth(sizeAlt.width()); if (sizeAlt.height() > size.height()) size.setHeight(sizeAlt.height()); m_btEnaDis.setMinimumSize(size); } connect(&m_btEnaDis, SIGNAL(clicked()), this, SLOT(enadisBP())); m_btViewCode.setText(i18n("&View Code")); m_btViewCode.setMinimumSize(m_btViewCode.sizeHint()); connect(&m_btViewCode, SIGNAL(clicked()), this, SLOT(viewBP())); m_btConditional.setText(i18n("&Conditional...")); m_btConditional.setMinimumSize(m_btConditional.sizeHint()); connect(&m_btConditional, SIGNAL(clicked()), this, SLOT(conditionalBP())); m_layout.addLayout(&m_listandedit, 10); m_layout.addLayout(&m_buttons); m_listandedit.addWidget(&m_bpEdit); m_listandedit.addWidget(&m_list, 10); m_buttons.addWidget(&m_btAddBP); m_buttons.addWidget(&m_btAddWP); m_buttons.addWidget(&m_btRemove); m_buttons.addWidget(&m_btEnaDis); m_buttons.addWidget(&m_btViewCode); m_buttons.addWidget(&m_btConditional); m_buttons.addStretch(10); m_layout.activate(); resize(350, 300); m_bpEdit.setFocus(); } BreakpointTable::~BreakpointTable() { } void BreakpointTable::updateBreakList() { std::list deletedItems; for (TQListViewItem* it = m_list.firstChild(); it != 0; it = it->nextSibling()) { deletedItems.push_back(static_cast(it)); } // get the new list for (KDebugger::BrkptROIterator bp = m_debugger->breakpointsBegin(); bp != m_debugger->breakpointsEnd(); ++bp) { // look up this item for (std::list::iterator o = deletedItems.begin(); o != deletedItems.end(); ++o) { if ((*o)->id == bp->id) { (*o)->updateFrom(*bp); deletedItems.erase(o); /* don't delete */ goto nextItem; } } // not in the list; add it new BreakpointItem(&m_list, *bp); nextItem:; } // delete all untouched breakpoints while (!deletedItems.empty()) { delete deletedItems.front(); deletedItems.pop_front(); } } BreakpointItem::BreakpointItem(TQListView* list, const Breakpoint& bp) : TQListViewItem(list), Breakpoint(bp) { display(); } void BreakpointItem::updateFrom(const Breakpoint& bp) { Breakpoint::operator=(bp); /* assign new values */ display(); } void BreakpointTable::addBP() { // set a breakpoint at the specified text TQString bpText = m_bpEdit.text(); bpText = bpText.stripWhiteSpace(); if (m_debugger->isReady()) { Breakpoint* bp = new Breakpoint; bp->text = bpText; m_debugger->setBreakpoint(bp, false); } } void BreakpointTable::addWP() { // set a watchpoint for the specified expression TQString wpExpr = m_bpEdit.text(); wpExpr = wpExpr.stripWhiteSpace(); if (m_debugger->isReady()) { Breakpoint* bp = new Breakpoint; bp->type = Breakpoint::watchpoint; bp->text = wpExpr; m_debugger->setBreakpoint(bp, false); } } void BreakpointTable::removeBP() { BreakpointItem* bp = static_cast(m_list.currentItem()); if (bp != 0) { m_debugger->deleteBreakpoint(bp->id); // note that bp may be deleted by now // (if bp was an orphaned breakpoint) } } void BreakpointTable::enadisBP() { BreakpointItem* bp = static_cast(m_list.currentItem()); if (bp != 0) { m_debugger->enableDisableBreakpoint(bp->id); } } void BreakpointTable::viewBP() { BreakpointItem* bp = static_cast(m_list.currentItem()); if (bp == 0) return; emit activateFileLine(bp->fileName, bp->lineNo, bp->address); } void BreakpointTable::updateUI() { bool enableChkpt = m_debugger->canChangeBreakpoints(); m_btAddBP.setEnabled(enableChkpt); m_btAddWP.setEnabled(enableChkpt); BreakpointItem* bp = static_cast(m_list.currentItem()); m_btViewCode.setEnabled(bp != 0); if (bp == 0) { enableChkpt = false; } else { if (bp->enabled()) { m_btEnaDis.setText(i18n("&Disable")); } else { m_btEnaDis.setText(i18n("&Enable")); } } m_btRemove.setEnabled(enableChkpt); m_btEnaDis.setEnabled(enableChkpt); m_btConditional.setEnabled(enableChkpt); } bool BreakpointTable::eventFilter(TQObject* ob, TQEvent* ev) { if (ev->type() == TQEvent::MouseButtonPress) { TQMouseEvent* mev = static_cast(ev); if (mev->button() == MidButton) { // enable or disable the clicked-on item BreakpointItem* bp = static_cast(m_list.itemAt(mev->pos())); if (bp != 0) { m_debugger->enableDisableBreakpoint(bp->id); } return true; } } return TQWidget::eventFilter(ob, ev); } class ConditionalDlg : public TQDialog { public: ConditionalDlg(TQWidget* parent); ~ConditionalDlg(); void setCondition(const TQString& text) { m_condition.setText(text); } TQString condition() { return m_condition.text(); } void setIgnoreCount(uint count); uint ignoreCount(); protected: TQLabel m_conditionLabel; TQLineEdit m_condition; TQLabel m_ignoreLabel; TQLineEdit m_ignoreCount; TQPushButton m_buttonOK; TQPushButton m_buttonCancel; TQVBoxLayout m_layout; TQGridLayout m_inputs; TQHBoxLayout m_buttons; }; void BreakpointTable::conditionalBP() { BreakpointItem* bp = static_cast(m_list.currentItem()); if (bp == 0) return; /* * Important: we must not keep a pointer to the Breakpoint around, * since it may vanish while the modal dialog is open through other * user interactions (like clicking at the breakpoint in the source * window)! */ int id = bp->id; ConditionalDlg dlg(this); dlg.setCondition(bp->condition); dlg.setIgnoreCount(bp->ignoreCount); if (dlg.exec() != TQDialog::Accepted) return; TQString conditionInput = dlg.condition(); int ignoreCount = dlg.ignoreCount(); m_debugger->conditionalBreakpoint(id, conditionInput, ignoreCount); } void BreakpointTable::initListAndIcons() { m_list.addColumn(i18n("Location"), 220); m_list.addColumn(i18n("Address"), 65); m_list.addColumn(i18n("Hits"), 30); m_list.addColumn(i18n("Ignore"), 30); m_list.addColumn(i18n("Condition"), 200); m_list.setMinimumSize(200, 100); m_list.setSorting(-1); // add pixmaps TQPixmap brkena = UserIcon("brkena.xpm"); TQPixmap brkdis = UserIcon("brkdis.xpm"); TQPixmap watchena = UserIcon("watchena.xpm"); TQPixmap watchdis = UserIcon("watchdis.xpm"); TQPixmap brktmp = UserIcon("brktmp.xpm"); TQPixmap brkcond = UserIcon("brkcond.xpm"); TQPixmap brkorph = UserIcon("brkorph.xpm"); /* * There are 32 different pixmaps: The basic enabled or disabled * breakpoint, plus an optional overlaid brktmp icon plus an optional * overlaid brkcond icon, plus an optional overlaid brkorph icon. Then * the same sequence for watchpoints. */ m_icons.resize(32); TQPixmap canvas(16,16); for (int i = 0; i < 32; i++) { { TQPainter p(&canvas); // clear canvas p.fillRect(0,0, canvas.width(),canvas.height(), cyan); // basic icon if (i & 1) { p.drawPixmap(1,1, (i & 8) ? watchena : brkena); } else { p.drawPixmap(1,1, (i & 8) ? watchdis : brkdis); } // temporary overlay if (i & 2) { p.drawPixmap(1,1, brktmp); } // conditional overlay if (i & 4) { p.drawPixmap(1,1, brkcond); } // orphan overlay if (i & 16) { p.drawPixmap(1,1, brkorph); } } canvas.setMask(canvas.createHeuristicMask()); m_icons[i] = canvas; } } void BreakpointItem::display() { BreakpointTable* lb = static_cast(listView()->parent()); /* breakpoint icon code; keep order the same as in BreakpointTable::initListAndIcons */ int code = enabled() ? 1 : 0; if (temporary) code += 2; if (!condition.isEmpty() || ignoreCount > 0) code += 4; if (type == watchpoint) code += 8; if (isOrphaned()) code += 16; setPixmap(0, lb->m_icons[code]); // more breakpoint info if (!location.isEmpty()) { setText(0, location); } else if (!Breakpoint::text.isEmpty()) { setText(0, Breakpoint::text); } else if (!fileName.isEmpty()) { // use only the file name portion TQString file = fileName; int slash = file.findRev('/'); if (slash >= 0) { file = file.mid(slash+1); } // correct zero-based line-numbers setText(0, file + ":" + TQString::number(lineNo+1)); } else { setText(0, "*" + address.asString()); } int c = 0; setText(++c, address.asString()); TQString tmp; if (hitCount == 0) { setText(++c, TQString()); } else { tmp.setNum(hitCount); setText(++c, tmp); } if (ignoreCount == 0) { setText(++c, TQString()); } else { tmp.setNum(ignoreCount); setText(++c, tmp); } if (condition.isEmpty()) { setText(++c, TQString()); } else { setText(++c, condition); } } ConditionalDlg::ConditionalDlg(TQWidget* parent) : TQDialog(parent, "conditional", true), m_conditionLabel(this, "condLabel"), m_condition(this, "condition"), m_ignoreLabel(this, "ignoreLabel"), m_ignoreCount(this, "ignoreCount"), m_buttonOK(this, "ok"), m_buttonCancel(this, "cancel"), m_layout(this, 10), m_inputs(2, 2, 10), m_buttons(4) { TQString title = kapp->caption(); title += i18n(": Conditional breakpoint"); setCaption(title); m_conditionLabel.setText(i18n("&Condition:")); m_conditionLabel.setMinimumSize(m_conditionLabel.sizeHint()); m_ignoreLabel.setText(i18n("Ignore &next hits:")); m_ignoreLabel.setMinimumSize(m_ignoreLabel.sizeHint()); m_condition.setMinimumSize(150, 24); m_condition.setMaxLength(10000); m_condition.setFrame(true); m_ignoreCount.setMinimumSize(150, 24); m_ignoreCount.setMaxLength(10000); m_ignoreCount.setFrame(true); m_conditionLabel.setBuddy(&m_condition); m_ignoreLabel.setBuddy(&m_ignoreCount); m_buttonOK.setMinimumSize(100, 30); connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept())); m_buttonOK.setText(i18n("OK")); m_buttonOK.setDefault(true); m_buttonCancel.setMinimumSize(100, 30); connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject())); m_buttonCancel.setText(i18n("Cancel")); m_layout.addLayout(&m_inputs); m_inputs.addWidget(&m_conditionLabel, 0, 0); m_inputs.addWidget(&m_condition, 0, 1); m_inputs.addWidget(&m_ignoreLabel, 1, 0); m_inputs.addWidget(&m_ignoreCount, 1, 1); m_inputs.setColStretch(1, 10); m_layout.addLayout(&m_buttons); m_layout.addStretch(10); m_buttons.addStretch(10); m_buttons.addWidget(&m_buttonOK); m_buttons.addSpacing(40); m_buttons.addWidget(&m_buttonCancel); m_buttons.addStretch(10); m_layout.activate(); m_condition.setFocus(); resize(400, 100); } ConditionalDlg::~ConditionalDlg() { } uint ConditionalDlg::ignoreCount() { bool ok; TQString input = m_ignoreCount.text(); uint result = input.toUInt(&ok); return ok ? result : 0; } void ConditionalDlg::setIgnoreCount(uint count) { TQString text; // set empty if ignore count is zero if (count > 0) { text.setNum(count); } m_ignoreCount.setText(text); } #include "brkpt.moc"