00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <swri_profiler_tools/profile_tree_widget.h>
00031
00032 #include <QVBoxLayout>
00033 #include <QTreeWidget>
00034 #include <QMenu>
00035
00036 #include <swri_profiler_tools/profile_database.h>
00037 #include <swri_profiler_tools/profile.h>
00038
00039 namespace swri_profiler_tools
00040 {
00041 enum ProfileTreeTypes {
00042 ProfileNodeType = QTreeWidgetItem::UserType,
00043 };
00044
00045 enum ProfileTreeRoles {
00046 ProfileKeyRole = Qt::UserRole,
00047 NodeKeyRole,
00048 };
00049
00050 ProfileTreeWidget::ProfileTreeWidget(QWidget *parent)
00051 :
00052 QWidget(parent),
00053 db_(NULL)
00054 {
00055 tree_widget_ = new QTreeWidget(this);
00056 tree_widget_->setFont(QFont("Ubuntu Mono", 9));
00057 tree_widget_->setContextMenuPolicy(Qt::CustomContextMenu);
00058 tree_widget_->setExpandsOnDoubleClick(false);
00059
00060 QObject::connect(tree_widget_, SIGNAL(customContextMenuRequested(const QPoint&)),
00061 this, SLOT(handleTreeContextMenuRequest(const QPoint&)));
00062
00063 QObject::connect(tree_widget_, SIGNAL(itemActivated(QTreeWidgetItem*, int)),
00064 this, SLOT(handleItemActivated(QTreeWidgetItem*, int)));
00065
00066 auto *main_layout = new QVBoxLayout();
00067 main_layout->addWidget(tree_widget_);
00068 main_layout->setContentsMargins(0,0,0,0);
00069 setLayout(main_layout);
00070 }
00071
00072 ProfileTreeWidget::~ProfileTreeWidget()
00073 {
00074 }
00075
00076 void ProfileTreeWidget::setDatabase(ProfileDatabase *db)
00077 {
00078 if (db_) {
00079
00080
00081 qWarning("ProfileTreeWidget: Cannot change the profile database.");
00082 return;
00083 }
00084
00085 db_ = db;
00086
00087 synchronizeWidget();
00088
00089 QObject::connect(db_, SIGNAL(profileModified(int)),
00090 this, SLOT(handleProfileAdded(int)));
00091 QObject::connect(db_, SIGNAL(profileAdded(int)),
00092 this, SLOT(handleProfileAdded(int)));
00093 QObject::connect(db_, SIGNAL(nodesAdded(int)),
00094 this, SLOT(handleNodesAdded(int)));
00095 }
00096
00097 void ProfileTreeWidget::handleProfileAdded(int profile_key)
00098 {
00099
00100 synchronizeWidget();
00101 }
00102
00103 void ProfileTreeWidget::handleNodesAdded(int profile_key)
00104 {
00105
00106 synchronizeWidget();
00107 }
00108
00109 void ProfileTreeWidget::synchronizeWidget()
00110 {
00111 tree_widget_->clear();
00112 items_.clear();
00113
00114 if (!db_) {
00115 return;
00116 }
00117
00118 std::vector<int> keys = db_->profileKeys();
00119 for (auto key : keys) {
00120 addProfile(key);
00121 }
00122 }
00123
00124 void ProfileTreeWidget::addProfile(int profile_key)
00125 {
00126 const Profile &profile = db_->profile(profile_key);
00127 if (!profile.isValid()) {
00128 qWarning("Invald profile for key %d.", profile_key);
00129 return;
00130 }
00131
00132 QTreeWidgetItem *item = new QTreeWidgetItem(ProfileNodeType);
00133
00134
00135
00136 item->setText(0, profile.name());
00137 item->setData(0, ProfileKeyRole, profile_key);
00138 item->setData(0, NodeKeyRole, profile.rootKey());
00139 tree_widget_->addTopLevelItem(item);
00140 items_[DatabaseKey(profile.profileKey(), profile.rootKey())] = item;
00141
00142 for (auto child_key : profile.rootNode().childKeys()) {
00143 addNode(item, profile, child_key);
00144 }
00145
00146 if (active_key_.isValid()) {
00147 if (items_.count(active_key_)) {
00148 markItemActive(active_key_);
00149 } else {
00150 active_key_ = DatabaseKey();
00151 emit activeNodeChanged(-1,-1);
00152 }
00153 }
00154 }
00155
00156 void ProfileTreeWidget::addNode(QTreeWidgetItem *parent,
00157 const Profile &profile,
00158 const int node_key)
00159 {
00160 const ProfileNode &node = profile.node(node_key);
00161 if (!node.isValid()) {
00162 qWarning("Invalid node for key %d", node_key);
00163 return;
00164 }
00165
00166 QTreeWidgetItem *item = new QTreeWidgetItem(ProfileNodeType);
00167 item->setText(0, node.name());
00168 item->setData(0, ProfileKeyRole, profile.profileKey());
00169 item->setData(0, NodeKeyRole, node.nodeKey());
00170 parent->addChild(item);
00171 items_[DatabaseKey(profile.profileKey(), node.nodeKey())] = item;
00172
00173 for (auto child_key : node.childKeys()) {
00174 addNode(item, profile, child_key);
00175 }
00176 }
00177
00178 void ProfileTreeWidget::handleTreeContextMenuRequest(const QPoint &pos)
00179 {
00180 QTreeWidgetItem *item = tree_widget_->itemAt(pos);
00181
00182 auto menu = new QMenu(this);
00183 auto expand_all_action = menu->addAction("Expand All");
00184 QObject::connect(expand_all_action, SIGNAL(triggered()),
00185 tree_widget_, SLOT(expandAll()));
00186
00187 auto collapse_all_action = menu->addAction("Collapse All");
00188 QObject::connect(collapse_all_action, SIGNAL(triggered()),
00189 tree_widget_, SLOT(collapseAll()));
00190
00191 menu->popup(tree_widget_->mapToGlobal(pos));
00192 QObject::connect(menu, SIGNAL(aboutToHide()), menu, SLOT(deleteLater()));
00193
00194 if (!item) {
00195 qWarning("No item under mouse");
00196 } else if (item->type() == ProfileNodeType) {
00197 int profile_key = item->data(0, ProfileKeyRole).toInt();
00198 int node_key = item->data(0, NodeKeyRole).toInt();
00199 qWarning("node %d--%d", profile_key, node_key);
00200 } else {
00201 qWarning("Unknown item type: %d", item->type());
00202 }
00203 }
00204
00205 void ProfileTreeWidget::handleItemActivated(QTreeWidgetItem *item, int column)
00206 {
00207 if (item->type() == ProfileNodeType) {
00208 int profile_key = item->data(0, ProfileKeyRole).toInt();
00209 int node_key = item->data(0, NodeKeyRole).toInt();
00210 setActiveNode(profile_key, node_key);
00211 }
00212 }
00213
00214 QString ProfileTreeWidget::nameForKey(const DatabaseKey &key) const
00215 {
00216 if (!key.isValid()) {
00217 return "<INVALID KEY>";
00218 }
00219
00220 const Profile &profile = db_->profile(key.profileKey());
00221 if (key.nodeKey() == profile.rootKey()) {
00222 return profile.name();
00223 } else {
00224 return profile.node(key.nodeKey()).name();
00225 }
00226 }
00227
00228 void ProfileTreeWidget::markItemActive(const DatabaseKey &key)
00229 {
00230 if (items_.count(key) == 0) {
00231 return;
00232 }
00233
00234 items_.at(key)->setText(0, "[" + nameForKey(key) + "]");
00235 }
00236
00237 void ProfileTreeWidget::markItemInactive(const DatabaseKey &key)
00238 {
00239 if (items_.count(key) == 0) {
00240 return;
00241 }
00242
00243 items_.at(key)->setText(0, nameForKey(key));
00244 }
00245
00246 void ProfileTreeWidget::setActiveNode(int profile_key, int node_key)
00247 {
00248 const DatabaseKey new_key(profile_key, node_key);
00249 if (new_key == active_key_) {
00250 return;
00251 }
00252
00253 markItemInactive(active_key_);
00254 active_key_ = new_key;
00255 markItemActive(active_key_);
00256 emit activeNodeChanged(profile_key, node_key);
00257 }
00258 }