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.
qps-packaging/src/pstable.cpp

604 lines
15 KiB

/*
* pstable.cpp
* This file is part of qps -- Qt-based visual process status monitor
*
* Copyright 1997-1999 Mattias Engdegård
*
* 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.
*/
// ** toooo complex,so need new Design ... should be more simple.. (by
// fasthyun@magicn.com)
#include "proc.h"
#include "pstable.h"
#include "misc.h"
///#include <limits.h>
#include <QApplication>
#include <QClipboard>
#include <QToolTip>
// When a subtree is folded away, selections inside it disappear to prevent
// unexpected behaviour
static void clear_subtree_selections(Procinfo *p)
{
for (int i = 0; i < p->table_children.size(); i++)
{
Procinfo *c = p->table_children[i];
c->selected = false;
clear_subtree_selections(c);
}
}
// SLOT :
// connect(this, SIGNAL(titleClicked(int)), SLOT(setSortColumn(int)));
void Pstable::setSortColumn(int col)
{
procview->setSortColumn(col, false);
setSortedCol(col); // void HeadedTable::setSortedCol(int col)
refresh(); // rebuild table
}
// AWKWARD
// sync Procview and HeadedTable set sorted column of table to procview->sortcol
// called by 1. Pstable::moveCol(int col, int place)
void Pstable::set_sortcol()
{
for (int i = 0; i < procview->cats.size(); i++)
{
if (procview->cats[i] == procview->sortcat)
{
HeadedTable::setSortedCol(i); // HeadedTable
return;
}
}
setSortedCol(-1);
}
// for Optimization
int Pstable::sizeHintForColumn(int col) const
{
// int aw=fontMetrics().averageCharWidth();
int aw = fontMetrics().width("0");
int cat_idx = procview->cats[col]->index;
// if(col==0) printf("col.idx=%d
// %s\n",cat_idx,procview->cats[col]->name);
switch (cat_idx)
{
// only COMMON Field
// case F_PID :
case F_RSS:
case F_SIZE:
case F_TTY:
return aw * 6;
case F_MEM:
case F_START:
case F_CPU: // PCPU
return aw * 6 + 2;
case F_TIME:
return aw * 5;
case F_WCPU:
case F_NICE:
return aw * 5;
case F_CMD:
return -(aw * 20);
case F_USER:
// case F_USER : return aw*10;
case F_CMDLINE:
default:
return -1;
}
return -1;
}
// inner
QString Pstable::title(int col)
{
if (col >= procview->cats.size())
{
qDebug("Qps Bug!: title() over col !! %d\n", col);
return "";
}
return procview->cats[col]->name;
}
// TESTING
void Pstable::overpaintCell(QPainter *p, int row, int col, int xpos)
{
if (col != 0)
return;
if (procview->cats[col]->id != F_CMD)
return;
int w;
Procinfo *pi = procview->linear_procs[row];
int n = pi->nthreads;
if (n == 1)
return;
#ifdef LINUX
if (pi->pid != pi->tgid)
return; // LINUX
#endif
w = p->fontMetrics().width(text(row, col));
QFont font = p->font();
int size = font.pointSize(); // point size
if (size <= 0)
return; // saver!
int h = body->cellHeight();
h = p->fontMetrics().height(); // return pixel
int msize = h * 3.0 / 8.0;
// printf("DEBUG: height=%d, msize=%d\n",h,msize);
if (h <= 11)
return; // saver!
if (msize < 6)
msize = 6;
// font.setPointSize(msize); // not pixel!
font.setPixelSize(msize); // not pixel!
p->setFont(font);
p->drawText(xpos + w + 2, msize + msize / 3, QString::number(n));
font.setPointSize(size);
p->setFont(font);
}
//
QString Pstable::text(int row, int col)
{
if (col >= procview->cats.size())
{
qDebug("Qps Bug!: text() over col !! %d\n", col);
return "";
}
return procview->cats[col]->string(procview->linear_procs[row]);
}
int Pstable::totalRow() //???
{
return procview->linear_procs.size();
}
int Pstable::colWidth(int col)
{
// this is -1 for variable width fields, htable keeps track of it
if (col >= procview->cats.size())
{
qDebug("Qps Bug!: colWidth() over col !! %d\n", col);
return -1;
}
return procview->cats[col]->width();
}
int Pstable::alignment(int col)
{
// qDebug("debug:alignment()\n");
Category *cat = procview->cats[col];
return cat->alignment();
}
// virtual of HeadedTable
void Pstable::setSelected(int row, bool flag)
{
/// qDebug("debug:Pstable::setSelected()\n");
Procinfo *pi = procview->linear_procs[row];
if (pi->selected != flag)
{
pi->selected = flag;
// body->repaintRow(row); // TEMP trick..
}
}
// virtual
bool Pstable::isSelected(int row)
{
Procinfo *pi = procview->linear_procs[row];
return pi->selected; // VALGRIND
}
int Pstable::rowDepth(int row)
{
Procinfo *pi = procview->linear_procs[row];
if (pi)
return pi->level; // VALGRIND segfault
qDebug("Qps bug: over row %d!!!\n", row);
return 0;
}
bool Pstable::lastChild(int row)
{
Procinfo *pi = procview->linear_procs[row];
if (pi)
return pi->lastchild;
qDebug("Qps bug: over row %d!!!\n", row);
return 0;
}
// Segfault !!!!
// return not PPID ! just virtual parent in tree
int Pstable::parentRow(int row)
{
return procview->linear_procs[row]->parent_row;
/* int ppid= procview->linear_procs[row]->ppid;
Procinfo *pi= procview->getProcinfoByPID(ppid);
if(pi) return ppid;
else return -1; */
}
// DRAFT tooltip
QString Pstable::tipText(int col)
{
Category *cat = procview->cats[col];
QString s(cat->help);
// trick
if (cat->index == F_STAT)
s.append("\n(R =Running, S =Sleeping, T =sTopped, Z=Zombie)");
if (cat->index == F_PLCY)
s.append("\n(TS =Time Sharing)");
// if(cat->index == F_RSS);
// s.append("\nRSS = CODE + DATA + SHARE\n"
// "RSS = TRS + DRS + SHARE\n");
/// s.append("\n(RSS = TRS + DRS)");
if (cat == procview->sortcat)
s.append(procview->reversed ? "\n(sorted backwards)" : "\n(sorted)");
// printf("size=%d\n",s.capacity());
return s;
}
void Pstable::showTip(QPoint p, int idx)
{
QToolTip::showText(p, tipText(idx));
}
extern TFrame *infobox; // testing
// SLOT
void Pstable::mouseOutOfCell() { infobox->hide(); }
// TEST
void Pstable::mouseOnCell(int row, int col)
{
// printf("cursor on (%d,%d)\n",row,col);
Category *cat = procview->cats[col];
QString s = "";
return;
// below TEST code!
if (cat->index == F_USER)
{
Procinfo *pi = procview->linear_procs[row];
s = pi->username;
}
else
{
infobox->hide();
return;
}
if (infobox != NULL)
{
// p.setY(p.y() + geometry().y());
// p.setY(QCursor::pos().y() - geometry().y());
// p.setY(QCursor::pos().y() - frameGeometry().y());
// p.setX(QCursor::pos().x() - frameGeometry().x());
// QPoint p=QCursor::pos();
// if(htable->numSelected()>=2)
infobox->show();
infobox->setPos();
if (s > 0)
{
infobox->setText(s);
}
else
infobox->hide();
}
// char *str=htable->total_selectedRow(col);
}
void Pstable::leaveEvent(QEvent *) {}
// DRAFT who call?
// void TableBody::mouseMoveEvent(QMouseEvent *e)
char *Pstable::total_selectedRow(int col)
{
static char buff[48];
char mem_str[48];
std::string name;
int index;
if (procview->cats.size() <= col or col < 0)
return 0; // col == -1
index = procview->cats[col]->index;
switch (index)
{
case F_SIZE:
name = "total SIZE: ";
break;
case F_RSS:
name = "total RSS: ";
break;
#ifdef LINUX
case F_TRS:
name = "total Text: ";
break;
case F_DRS:
name = "total Data: ";
break;
case F_STACK:
name = "total STACK: ";
break;
#endif
default:
return 0;
}
int total = 0;
int rows = procview->linear_procs.size();
for (int i = 0; i < rows; i++)
if (procview->linear_procs[i]->selected)
{
switch (index)
{
case F_SIZE:
total += procview->linear_procs[i]->size;
break;
case F_RSS:
total += procview->linear_procs[i]->resident;
break;
#ifdef LINUX
case F_TRS:
total += procview->linear_procs[i]->trs;
break;
case F_DRS:
total += procview->linear_procs[i]->drs;
break;
case F_STACK:
total += procview->linear_procs[i]->stack;
break;
#endif
}
}
mem_string(total, mem_str); // misc.h
strcpy(buff, name.c_str());
strcat(buff, mem_str);
// sqDebug(buff,"total:%s",total);
return buff;
}
// col
// colMoved(col, place);
Pstable::Pstable(QWidget *parent, Procview *pv) : HeadedTable(parent, 0)
{
procview = pv;
// connect(this, SIGNAL(selectionChanged(const Svec<int>
//*)),SLOT(selection_update(const Svec<int> *))); //DEL?
// connect(this,
// SIGNAL(selectionChanged()),SLOT(selection_update())); //
// when procinfo clicked
connect(this, SIGNAL(titleClicked(int)), SLOT(setSortColumn(int)));
connect(this, SIGNAL(foldSubTree(int)), SLOT(subtree_folded(int)));
connect(head, SIGNAL(toolTip(QPoint, int)), this,
SLOT(showTip(QPoint, int)));
connect(this, SIGNAL(flyOnCell(int, int)), SLOT(mouseOnCell(int, int)));
connect(this, SIGNAL(outOfCell()), SLOT(mouseOutOfCell()));
}
// who call this ? : from qps.cpp
void Pstable::setProcview(Procview *pv) { procview = pv; }
HeadedTable::NodeState Pstable::folded(int row)
{
Procinfo *p = procview->linear_procs[row];
return (p->table_children.size() > 0) ? (p->hidekids ? Closed : Open)
: Leaf;
}
// slot: called when selection changes
// called by
// 1.void HeadedTable::selectionNotify()
/*
void Pstable::selection_update(const Svec<int> *rows)
{
//CLIPBOARD
qDebug("debug:selection_update()\n");
for(int i = 0; i < rows->size(); i++) {
int row = (*rows)[i];
procview->linear_procs[row]->selected = isSelected(row); //
WRONG !!!
}
qps->update_menu_selection_status();
if(numSelected() > 0 && qps->pids_to_selection) {
// set the X11 selection to "PID1 PID2 PID3 ..."
QString s, num;
int n = numRows();
for(int i = 0; i < n; i++) {
if(isSelected(i)) {
num.setNum(procview->linear_procs[i]->pid);
s.append(num);
if(i < n - 1)
s.append(" ");
}
}
// important: this mustn't be called non-interactively since Qt
uses
// the selection time of the last mouse or keyboard event
//// QApplication::clipboard()->setText(s);
}
} */
// call by
// 1.void Qps::set_table_mode(bool treemode)
// slot: changes table mode
void Pstable::setTreeMode(bool treemode)
{
// qDebug("Pstable::setTreeMode() %d , procview.treeview
// =%d\n",treemode,procview->treeview);
// no more HeadedTable::setTreeMode(treemode);
HeadedTable::setTreeMode(treemode);
procview->treeview = treemode;
procview->fieldArrange();
set_sortcol();
refresh(); //==rebuild();
}
//
bool Pstable::columnMovable(int col)
{
if (treemode)
{
if (col == 0)
return false;
}
if (procview->cats[col]->index == F_CMDLINE)
return false;
return true;
}
// called by HeadedTable
// Description : FIELD movement by mouse drag to place From col
// virtual HeadedTable::moveCol(col,place);
void Pstable::moveCol(int col, int place)
{
// qDebug("Pstable::moveCol\n");
procview->moveColumn(col, place);
set_sortcol(); //???
procview->fieldArrange();
// update();
refresh(); // width size changed ,...
return;
// updateColWidth(place); updateColWidth(col);// TEMP
}
// NEED Check !!
// Slot: called when a subtree is opened or closed
// row = row number of sheet
void Pstable::subtree_folded(int row)
{
Procinfo *p = procview->linear_procs[row];
p->hidekids = !p->hidekids;
if (p->hidekids)
clear_subtree_selections(p); // *** important
refresh(); // tree rebuild only
return;
// ???
Procinfo *nextp =
(row < numRows() - 1) ? procview->linear_procs[row + 1] : 0;
if (!p->hidekids)
{
// Show as much as possible of the opened subtree
int r = row + 1;
while (r < numRows() && procview->linear_procs[r] != nextp)
r++;
// setAutoUpdate(FALSE);
showRange(row, r - 1);
// setAutoUpdate(TRUE);
}
// This is a stopgap solution; it would be better to have htable
// take care of the hiding of subtrees and repaint only the rows under
// the line hidden
}
// DRAFT CODE:
// 1.procview->refresh: proc.refresh, rebuild
// 2.resetwidth
// 3.repaint
// called by
// 1.void Qps::refresh()
void STATUSBAR_SETCOUNT(int n);
static int kgen = 123;
void Pstable::checkTableModel()
{
// int size=procview->linear_procs.size();
// if(size!=numRows())
{
// printf("Warnning: this is the bug.. wrong! %d
//%d\n",size,numRows());
}
if (procview->current_gen != kgen)
{
// printf("Warnning: maybe this is the bug.. wrong!
//%d
//%d\n",kgen,procview->current_gen);
// setAutoUpdate(false); // ********** important for
// GUI-thread
// HeadedTable::setTreeMode(procview->treeview);
procview->rebuild(); // for Table
setNumRows(procview->linear_procs.size()); // 1.
// qDebug("Pstable setTreeMode =%d , procview.treeview
//=%d\n",treemode,procview->treeview);
setNumCols(procview->cats.size()); // 2. resetWidths()
kgen = procview->current_gen;
// setAutoUpdate(true);
}
}
// paintEvent();
void Pstable::refresh()
{
// qDebug("Pstable:refresh()");
// procview->refresh(); -> move to Qps::refresh()
// qDebug("catsize=%d\n",procview->cats.size());
procview->rebuild(); // for Table
setNumRows(procview->linear_procs.size()); // 1.
setNumCols(procview->cats.size()); // 2. resetWidths() UNINITIAL
kgen = procview->current_gen;
// checkTableModel();
repaint_changed();
/*
if(true)
{
int count=0,trow=0;
for(int row = 0; row < nrows; row++)
if(isSelected(row))
{
count++;
trow=row;
}
if (count == 1)
centerVertically(trow);
} */
STATUSBAR_SETCOUNT(procview->num_process);
}