You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kdbg/kdbg/procattach.cpp

311 lines
7.3 KiB

/*
* 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 "procattach.h"
#include <tqlistview.h>
#include <tqtoolbutton.h>
#include <tqlineedit.h>
#include <kprocess.h>
#include <ctype.h>
#include <tdeapplication.h>
#include <kiconloader.h>
#include <tdelocale.h> /* i18n */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
ProcAttachPS::ProcAttachPS(TQWidget* parent) :
ProcAttachBase(parent),
m_pidCol(-1),
m_ppidCol(-1)
{
m_ps = new TDEProcess;
connect(m_ps, SIGNAL(receivedStdout(TDEProcess*, char*, int)),
this, SLOT(slotTextReceived(TDEProcess*, char*, int)));
connect(m_ps, SIGNAL(processExited(TDEProcess*)),
this, SLOT(slotPSDone()));
TQIconSet icon = SmallIconSet("clear_left");
filterClear->setIconSet(icon);
processList->setColumnWidth(0, 300);
processList->setColumnWidthMode(0, TQListView::Manual);
processList->setColumnAlignment(1, TQt::AlignRight);
processList->setColumnAlignment(2, TQt::AlignRight);
// set the command line
static const char* const psCommand[] = {
#ifdef PS_COMMAND
PS_COMMAND,
#else
"/bin/false",
#endif
0
};
for (int i = 0; psCommand[i] != 0; i++) {
*m_ps << psCommand[i];
}
runPS();
}
ProcAttachPS::~ProcAttachPS()
{
delete m_ps; // kills a running ps
}
void ProcAttachPS::runPS()
{
// clear the parse state from previous runs
m_token = "";
m_line.clear();
m_pidCol = -1;
m_ppidCol = -1;
m_ps->start(TDEProcess::NotifyOnExit, TDEProcess::Stdout);
}
void ProcAttachPS::slotTextReceived(TDEProcess*, char* buffer, int buflen)
{
const char* end = buffer+buflen;
while (buffer < end)
{
// check new line
if (*buffer == '\n')
{
// push a tokens onto the line
if (!m_token.isEmpty()) {
m_line.push_back(TQString::fromLatin1(m_token));
m_token = "";
}
// and insert the line in the list
pushLine();
m_line.clear();
++buffer;
}
// blanks: the last column gets the rest of the line, including blanks
else if ((m_pidCol < 0 || int(m_line.size()) < processList->columns()-1) &&
isspace(*buffer))
{
// push a token onto the line
if (!m_token.isEmpty()) {
m_line.push_back(TQString::fromLatin1(m_token));
m_token = "";
}
do {
++buffer;
} while (buffer < end && isspace(*buffer));
}
// tokens
else
{
const char* start = buffer;
do {
++buffer;
} while (buffer < end && !isspace(*buffer));
// append to the current token
m_token += TQCString(start, buffer-start+1); // must count the '\0'
}
}
}
void ProcAttachPS::pushLine()
{
if (m_line.size() < 3) // we need the PID, PPID, and COMMAND columns
return;
if (m_pidCol < 0)
{
// create columns if we don't have them yet
bool allocate = processList->columns() == 3;
// we assume that the last column is the command
m_line.pop_back();
for (uint i = 0; i < m_line.size(); i++) {
// we don't allocate the PID and PPID columns,
// but we need to know where in the ps output they are
if (m_line[i] == "PID") {
m_pidCol = i;
} else if (m_line[i] == "PPID") {
m_ppidCol = i;
} else if (allocate) {
processList->addColumn(m_line[i]);
// these columns are normally numbers
processList->setColumnAlignment(processList->columns()-1,
TQt::AlignRight);
}
}
}
else
{
// insert a line
// find the parent process
TQListViewItem* parent = 0;
if (m_ppidCol >= 0 && m_ppidCol < int(m_line.size())) {
parent = processList->findItem(m_line[m_ppidCol], 1);
}
// we assume that the last column is the command
TQListViewItem* item;
if (parent == 0) {
item = new TQListViewItem(processList, m_line.back());
} else {
item = new TQListViewItem(parent, m_line.back());
}
item->setOpen(true);
m_line.pop_back();
int k = 3;
for (uint i = 0; i < m_line.size(); i++)
{
// display the pid and ppid columns' contents in columns 1 and 2
if (int(i) == m_pidCol)
item->setText(1, m_line[i]);
else if (int(i) == m_ppidCol)
item->setText(2, m_line[i]);
else
item->setText(k++, m_line[i]);
}
if (m_ppidCol >= 0 && m_pidCol >= 0) { // need PID & PPID for this
/*
* It could have happened that a process was earlier inserted,
* whose parent process is the current process. Such processes
* were placed at the root. Here we go through all root items
* and check whether we must reparent them.
*/
TQListViewItem* i = processList->firstChild();
while (i != 0)
{
// advance before we reparent the item
TQListViewItem* it = i;
i = i->nextSibling();
if (it->text(2) == m_line[m_pidCol]) {
processList->takeItem(it);
item->insertItem(it);
}
}
}
}
}
void ProcAttachPS::slotPSDone()
{
filterEdited(filterEdit->text());
}
TQString ProcAttachPS::text() const
{
TQListViewItem* item = processList->selectedItem();
if (item == 0)
return TQString();
return item->text(1);
}
void ProcAttachPS::refresh()
{
if (!m_ps->isRunning())
{
processList->clear();
buttonOk->setEnabled(false); // selection was cleared
runPS();
}
}
void ProcAttachPS::filterEdited(const TQString& text)
{
TQListViewItem* i = processList->firstChild();
if (i) {
setVisibility(i, text);
}
}
/**
* Sets the visibility of \a i and
* returns whether it was made visible.
*/
bool ProcAttachPS::setVisibility(TQListViewItem* i, const TQString& text)
{
bool visible = false;
for (TQListViewItem* j = i->firstChild(); j; j = j->nextSibling())
{
if (setVisibility(j, text))
visible = true;
}
// look for text in the process name and in the PID
visible = visible || text.isEmpty() ||
i->text(0).find(text, 0, false) >= 0 ||
i->text(1).find(text) >= 0;
i->setVisible(visible);
// disable the OK button if the selected item becomes invisible
if (i->isSelected())
buttonOk->setEnabled(visible);
return visible;
}
void ProcAttachPS::selectedChanged()
{
buttonOk->setEnabled(processList->selectedItem() != 0);
}
ProcAttach::ProcAttach(TQWidget* parent) :
TQDialog(parent, "procattach", true),
m_label(this, "label"),
m_processId(this, "procid"),
m_buttonOK(this, "ok"),
m_buttonCancel(this, "cancel"),
m_layout(this, 8),
m_buttons(4)
{
TQString title = kapp->caption();
title += i18n(": Attach to process");
setCaption(title);
m_label.setMinimumSize(330, 24);
m_label.setText(i18n("Specify the process number to attach to:"));
m_processId.setMinimumSize(330, 24);
m_processId.setMaxLength(100);
m_processId.setFrame(true);
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.addWidget(&m_label);
m_layout.addWidget(&m_processId);
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_processId.setFocus();
resize(350, 120);
}
ProcAttach::~ProcAttach()
{
}
#include "procattach.moc"