241 lines
6.9 KiB
C++
241 lines
6.9 KiB
C++
#include "piintrospector.h"
|
|
#include <QClipboard>
|
|
#include <QScrollBar>
|
|
#include "pifile.h"
|
|
#include "pitime.h"
|
|
#include "pidir.h"
|
|
#include "pichunkstream.h"
|
|
#include "ccm_piintrospector.h"
|
|
|
|
#include <cxxabi.h>
|
|
const QString demangle(const char * name) {
|
|
int status = -4;
|
|
char * res = abi::__cxa_demangle(name, NULL, NULL, &status);
|
|
QString ret((status == 0) ? res : name);
|
|
free(res);
|
|
return ret;
|
|
}
|
|
|
|
|
|
enum ColumnContainers {
|
|
ccType,
|
|
ccCount,
|
|
ccItems,
|
|
ccBytesAllocated,
|
|
ccBytesUsed,
|
|
};
|
|
|
|
enum ColumnObjects {
|
|
coClassName,
|
|
coName,
|
|
coParents,
|
|
coQueuedEvents,
|
|
};
|
|
|
|
|
|
QPIIntrospector::QPIIntrospector(QWidget * parent): EMainWindow(parent), peer("__introspection_client__") {
|
|
setupUi(this);
|
|
request_timer = 0;
|
|
session.setFile("qpiintrospector_session.conf");
|
|
#if QT_VERSION >= 0x050000
|
|
//treeContainers->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
|
#else
|
|
//treeContainers->header()->setResizeMode(QHeaderView::ResizeToContents);
|
|
#endif
|
|
CONNECTU_QUEUED(&peer, peerConnectedEvent, this, peersChanged, this);
|
|
CONNECTU_QUEUED(&peer, peerDisconnectedEvent, this, peersChanged, this);
|
|
CONNECTU_QUEUED(&peer, dataReceivedEvent, this, peerReceived, this);
|
|
CONNECTU(&peer, peerConnectedEvent, this, reqProcPIEvents);
|
|
CONNECTU(&peer, peerDisconnectedEvent, this, reqProcPIEvents);
|
|
CONNECTU(&peer, dataReceivedEvent, this, reqProcPIEvents);
|
|
PICodeInfo::EnumInfo * ei = PICodeInfo::enumsInfo->value("PIIntrospection::InfoTypes");
|
|
if (ei) {
|
|
piForeachC (PICodeInfo::EnumeratorInfo & e, ei->members) {
|
|
QCheckBox * cb = new QCheckBox(PI2QString(e.name.mid(2)));
|
|
cb->setProperty("__value__", e.value);
|
|
layoutRequestFlags->addWidget(cb);
|
|
}
|
|
}
|
|
//startTimer(100);
|
|
session.addEntry(this);
|
|
session.load();
|
|
peer.start();
|
|
}
|
|
|
|
|
|
QPIIntrospector::~QPIIntrospector() {
|
|
session.save();
|
|
peer.stop();
|
|
}
|
|
|
|
|
|
void QPIIntrospector::changeEvent(QEvent * e) {
|
|
EMainWindow::changeEvent(e);
|
|
switch (e->type()) {
|
|
case QEvent::LanguageChange:
|
|
retranslateUi(this);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void QPIIntrospector::timerEvent(QTimerEvent * e) {
|
|
if (e->timerId() == request_timer)
|
|
buttonRequest->click();
|
|
}
|
|
|
|
|
|
void QPIIntrospector::buildTree(QByteArray d) {
|
|
/*PIVector<PIIntrospectionThreads::ThreadInfo> threads;
|
|
PIByteArray pd = Q2PIByteArray(d);
|
|
pd >> threads;
|
|
treeContainers->clear();
|
|
piForeachC (PIIntrospectionThreads::ThreadInfo & t, threads) {
|
|
QTreeWidgetItem * ti = new QTreeWidgetItem();
|
|
ti->setText(0, QString(PI2QString(t.name) + " (%1)").arg(t.id));
|
|
treeContainers->addTopLevelItem(ti);
|
|
}*/
|
|
}
|
|
|
|
|
|
void QPIIntrospector::procRequestTimer() {
|
|
if (request_timer != 0) killTimer(request_timer);
|
|
request_timer = 0;
|
|
if (!checkRequestTimer->isChecked()) return;
|
|
request_timer = startTimer(1000 / spinRequestTimerHz->value());
|
|
}
|
|
|
|
|
|
void QPIIntrospector::buildDumpSection(QTreeWidgetItem * pi, PIString & str) {
|
|
}
|
|
|
|
|
|
void QPIIntrospector::showInfo(const PIIntrospection::ProcessInfo & info) {
|
|
PIString s;
|
|
s << info.execCommand << "\n";
|
|
s << info.execDateTime.toString() << "\n";
|
|
s << info.OS_name << "(" << info.OS_version << ", " << info.architecture << ")\n";
|
|
s << info.user << "\n";
|
|
s << info.build_options.join(", ");
|
|
labelInfo->setText(PI2QString(s));
|
|
}
|
|
|
|
|
|
void QPIIntrospector::showContainers(const PIMap<uint, PIIntrospectionContainers::Type> & data, const PIMap<uint, PIString> & typenames) {
|
|
int vpos = treeContainers->verticalScrollBar()->value();
|
|
treeContainers->clear();
|
|
for (auto i = data.constBegin(); i != data.constEnd(); ++i) {
|
|
QTreeWidgetItem * ti = new QTreeWidgetItem();
|
|
ti->setText(ccType, demangle(typenames.value(i.key(), PIString::fromNumber(i.key())).dataAscii()));
|
|
ti->setText(ccCount, QString::number(i.value().count));
|
|
ti->setText(ccItems, QString::number(i.value().items));
|
|
ti->setText(ccBytesAllocated, PI2QString(PIString::readableSize(i.value().bytes_allocated)));
|
|
ti->setText(ccBytesUsed, PI2QString(PIString::readableSize(i.value().bytes_used)));
|
|
treeContainers->addTopLevelItem(ti);
|
|
}
|
|
treeContainers->verticalScrollBar()->setValue(vpos);
|
|
}
|
|
|
|
|
|
void QPIIntrospector::showObjects(const PIVector<PIIntrospection::ObjectInfo> & objects) {
|
|
QHash<QString, int> stat;
|
|
|
|
int vpos = treeObjects->verticalScrollBar()->value();
|
|
treeObjects->clear();
|
|
piForeachC (PIIntrospection::ObjectInfo & i, objects) {
|
|
stat[PI2QString(i.classname)]++;
|
|
QTreeWidgetItem * ti = new QTreeWidgetItem();
|
|
ti->setText(coClassName, PI2QString(i.classname));
|
|
ti->setText(coName, PI2QString(i.name));
|
|
ti->setText(coParents, PI2QString(i.parents.join(":")));
|
|
ti->setText(coQueuedEvents, QString::number(i.queued_events));
|
|
treeObjects->addTopLevelItem(ti);
|
|
}
|
|
treeObjects->verticalScrollBar()->setValue(vpos);
|
|
|
|
vpos = treeObjectsStat->verticalScrollBar()->value();
|
|
treeObjectsStat->clear();
|
|
for (auto i = stat.constBegin(); i != stat.constEnd(); ++i) {
|
|
QTreeWidgetItem * ti = new QTreeWidgetItem();
|
|
ti->setText(0, i.key());
|
|
ti->setText(1, QString::number(i.value()));
|
|
treeObjectsStat->addTopLevelItem(ti);
|
|
}
|
|
treeObjectsStat->verticalScrollBar()->setValue(vpos);
|
|
}
|
|
|
|
|
|
void QPIIntrospector::on_listApp_currentRowChanged(int r) {
|
|
if (r < 0) cur_server.clear();
|
|
else cur_server = Q2PIString(listApp->item(r)->text());
|
|
}
|
|
|
|
|
|
void QPIIntrospector::peerReceived(const PIString & from, const PIByteArray & data) {
|
|
if (from != cur_server) return;
|
|
//piCout << "rec" << data.size();
|
|
PIByteArray ba(data);
|
|
if (ba.size_s() < 4) return;
|
|
uint sign(0); ba >> sign;
|
|
if (sign != PIIntrospection::sign) return;
|
|
PIChunkStream cs(ba);
|
|
PIByteArray pba;
|
|
while (!cs.atEnd()) {
|
|
switch (cs.read()) {
|
|
case 1: {
|
|
cs.get(pba);
|
|
PIIntrospection::ProcessInfo info;
|
|
PIIntrospection::unpackInfo(pba, info);
|
|
showInfo(info);
|
|
} break;
|
|
case 2: {
|
|
cs.get(pba);
|
|
PIMap<uint, PIIntrospectionContainers::Type> data;
|
|
PIMap<uint, PIString> typenames;
|
|
PIIntrospection::unpackContainers(pba, data, typenames);
|
|
showContainers(data, typenames);
|
|
} break;
|
|
case 4: {
|
|
cs.get(pba);
|
|
PIVector<PIIntrospection::ObjectInfo> objects;
|
|
PIIntrospection::unpackObjects(pba, objects);
|
|
showObjects(objects);
|
|
} break;
|
|
default: break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void QPIIntrospector::peersChanged(const PIString & name) {
|
|
listApp->blockSignals(true);
|
|
QString cs = listApp->currentItem() ? listApp->currentItem()->text() : "";
|
|
listApp->clear();
|
|
peer.lock();
|
|
piForeachC (PIPeer::PeerInfo & p, peer.allPeers()) {
|
|
QString pn = PI2QString(p.name);
|
|
listApp->addItem(pn);
|
|
if (pn == cs)
|
|
listApp->setCurrentRow(listApp->count() - 1);
|
|
}
|
|
peer.unlock();
|
|
listApp->blockSignals(false);
|
|
}
|
|
|
|
|
|
void QPIIntrospector::on_buttonRequest_clicked() {
|
|
if (cur_server.isEmpty()) return;
|
|
PIIntrospection::RequiredInfo info;
|
|
for (int i = 0; i < layoutRequestFlags->count(); ++i) {
|
|
QCheckBox * cb = qobject_cast<QCheckBox*>(layoutRequestFlags->itemAt(i)->widget());
|
|
if (!cb) continue;
|
|
if (!cb->isChecked()) continue;
|
|
info.types |= cb->property("__value__").toInt();
|
|
}
|
|
PIByteArray ba;
|
|
ba << PIIntrospection::sign << info;
|
|
peer.send(cur_server, ba);
|
|
}
|