/* * 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 #include #include #include #include #include #include #include /* 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"