Attach to Process dialog: Obey the filter on refresh.
[kdbg.git] / kdbg / procattach.cpp
blob8df6a84b3bb159187ca3cb4cfd9fc135e0193f9a
1 // $Id$
3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include "procattach.h"
7 #include <qlistview.h>
8 #include <qtoolbutton.h>
9 #include <qlineedit.h>
10 #include <kprocess.h>
11 #include <ctype.h>
12 #include <kapp.h>
13 #include <kiconloader.h>
14 #include <klocale.h> /* i18n */
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
20 ProcAttachPS::ProcAttachPS(QWidget* parent) :
21 ProcAttachBase(parent),
22 m_pidCol(-1),
23 m_ppidCol(-1)
25 m_ps = new KProcess;
26 connect(m_ps, SIGNAL(receivedStdout(KProcess*, char*, int)),
27 this, SLOT(slotTextReceived(KProcess*, char*, int)));
28 connect(m_ps, SIGNAL(processExited(KProcess*)),
29 this, SLOT(slotPSDone()));
31 QIconSet icon = SmallIconSet("clear_left");
32 filterClear->setIconSet(icon);
34 processList->setColumnWidth(0, 300);
35 processList->setColumnWidthMode(0, QListView::Manual);
36 processList->setColumnAlignment(1, Qt::AlignRight);
37 processList->setColumnAlignment(2, Qt::AlignRight);
39 // set the command line
40 static const char* const psCommand[] = {
41 #ifdef PS_COMMAND
42 PS_COMMAND,
43 #else
44 "/bin/false",
45 #endif
48 for (int i = 0; psCommand[i] != 0; i++) {
49 *m_ps << psCommand[i];
52 runPS();
55 ProcAttachPS::~ProcAttachPS()
57 delete m_ps; // kills a running ps
60 void ProcAttachPS::runPS()
62 // clear the parse state from previous runs
63 m_token = "";
64 m_line.clear();
65 m_pidCol = -1;
66 m_ppidCol = -1;
68 m_ps->start(KProcess::NotifyOnExit, KProcess::Stdout);
71 void ProcAttachPS::slotTextReceived(KProcess*, char* buffer, int buflen)
73 const char* end = buffer+buflen;
74 while (buffer < end)
76 // check new line
77 if (*buffer == '\n')
79 // push a tokens onto the line
80 if (!m_token.isEmpty()) {
81 m_line.push_back(QString::fromLatin1(m_token));
82 m_token = "";
84 // and insert the line in the list
85 pushLine();
86 m_line.clear();
87 ++buffer;
89 // blanks: the last column gets the rest of the line, including blanks
90 else if ((m_pidCol < 0 || int(m_line.size()) < processList->columns()-1) &&
91 isspace(*buffer))
93 // push a token onto the line
94 if (!m_token.isEmpty()) {
95 m_line.push_back(QString::fromLatin1(m_token));
96 m_token = "";
98 do {
99 ++buffer;
100 } while (buffer < end && isspace(*buffer));
102 // tokens
103 else
105 const char* start = buffer;
106 do {
107 ++buffer;
108 } while (buffer < end && !isspace(*buffer));
109 // append to the current token
110 m_token += QCString(start, buffer-start+1); // must count the '\0'
115 void ProcAttachPS::pushLine()
117 if (m_line.size() < 3) // we need the PID, PPID, and COMMAND columns
118 return;
120 if (m_pidCol < 0)
122 // create columns if we don't have them yet
123 bool allocate = processList->columns() == 3;
125 // we assume that the last column is the command
126 m_line.pop_back();
128 for (uint i = 0; i < m_line.size(); i++) {
129 // we don't allocate the PID and PPID columns,
130 // but we need to know where in the ps output they are
131 if (m_line[i] == "PID") {
132 m_pidCol = i;
133 } else if (m_line[i] == "PPID") {
134 m_ppidCol = i;
135 } else if (allocate) {
136 processList->addColumn(m_line[i]);
137 // these columns are normally numbers
138 processList->setColumnAlignment(processList->columns()-1,
139 Qt::AlignRight);
143 else
145 // insert a line
146 // find the parent process
147 QListViewItem* parent = 0;
148 if (m_ppidCol >= 0 && m_ppidCol < int(m_line.size())) {
149 parent = processList->findItem(m_line[m_ppidCol], 1);
152 // we assume that the last column is the command
153 QListViewItem* item;
154 if (parent == 0) {
155 item = new QListViewItem(processList, m_line.back());
156 } else {
157 item = new QListViewItem(parent, m_line.back());
159 item->setOpen(true);
160 m_line.pop_back();
161 int k = 3;
162 for (uint i = 0; i < m_line.size(); i++)
164 // display the pid and ppid columns' contents in columns 1 and 2
165 if (int(i) == m_pidCol)
166 item->setText(1, m_line[i]);
167 else if (int(i) == m_ppidCol)
168 item->setText(2, m_line[i]);
169 else
170 item->setText(k++, m_line[i]);
173 if (m_ppidCol >= 0 && m_pidCol >= 0) { // need PID & PPID for this
175 * It could have happened that a process was earlier inserted,
176 * whose parent process is the current process. Such processes
177 * were placed at the root. Here we go through all root items
178 * and check whether we must reparent them.
180 QListViewItem* i = processList->firstChild();
181 while (i != 0)
183 // advance before we reparent the item
184 QListViewItem* it = i;
185 i = i->nextSibling();
186 if (it->text(2) == m_line[m_pidCol]) {
187 processList->takeItem(it);
188 item->insertItem(it);
195 void ProcAttachPS::slotPSDone()
197 filterEdited(filterEdit->text());
200 QString ProcAttachPS::text() const
202 QListViewItem* item = processList->selectedItem();
204 if (item == 0)
205 return QString();
207 return item->text(1);
210 void ProcAttachPS::refresh()
212 if (!m_ps->isRunning())
214 processList->clear();
215 runPS();
219 void ProcAttachPS::filterEdited(const QString& text)
221 QListViewItem* i = processList->firstChild();
222 setVisibility(i, text);
226 * Sets the visibility of \a i and
227 * returns whether it was made visible.
229 bool ProcAttachPS::setVisibility(QListViewItem* i, const QString& text)
231 bool visible = false;
232 for (QListViewItem* j = i->firstChild(); j; j = j->nextSibling())
234 if (setVisibility(j, text))
235 visible = true;
237 // look for text in the process name and in the PID
238 visible = visible || text.isEmpty() ||
239 i->text(0).find(text, 0, false) >= 0 ||
240 i->text(1).find(text) >= 0;
242 i->setVisible(visible);
244 return visible;
248 ProcAttach::ProcAttach(QWidget* parent) :
249 QDialog(parent, "procattach", true),
250 m_label(this, "label"),
251 m_processId(this, "procid"),
252 m_buttonOK(this, "ok"),
253 m_buttonCancel(this, "cancel"),
254 m_layout(this, 8),
255 m_buttons(4)
257 QString title = kapp->caption();
258 title += i18n(": Attach to process");
259 setCaption(title);
261 m_label.setMinimumSize(330, 24);
262 m_label.setText(i18n("Specify the process number to attach to:"));
264 m_processId.setMinimumSize(330, 24);
265 m_processId.setMaxLength(100);
266 m_processId.setFrame(true);
268 m_buttonOK.setMinimumSize(100, 30);
269 connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
270 m_buttonOK.setText(i18n("OK"));
271 m_buttonOK.setDefault(true);
273 m_buttonCancel.setMinimumSize(100, 30);
274 connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
275 m_buttonCancel.setText(i18n("Cancel"));
277 m_layout.addWidget(&m_label);
278 m_layout.addWidget(&m_processId);
279 m_layout.addLayout(&m_buttons);
280 m_layout.addStretch(10);
281 m_buttons.addStretch(10);
282 m_buttons.addWidget(&m_buttonOK);
283 m_buttons.addSpacing(40);
284 m_buttons.addWidget(&m_buttonCancel);
285 m_buttons.addStretch(10);
287 m_layout.activate();
289 m_processId.setFocus();
290 resize(350, 120);
293 ProcAttach::~ProcAttach()