profile_tree_widget.cpp
Go to the documentation of this file.
00001 // *****************************************************************************
00002 //
00003 // Copyright (c) 2015, Southwest Research Institute® (SwRI®)
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
00008 //     * Redistributions of source code must retain the above copyright
00009 //       notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above copyright
00011 //       notice, this list of conditions and the following disclaimer in the
00012 //       documentation and/or other materials provided with the distribution.
00013 //     * Neither the name of Southwest Research Institute® (SwRI®) nor the
00014 //       names of its contributors may be used to endorse or promote products
00015 //       derived from this software without specific prior written permission.
00016 //
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020 // ARE DISCLAIMED. IN NO EVENT SHALL Southwest Research Institute® BE LIABLE 
00021 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
00022 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
00023 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
00024 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00025 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00026 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00027 // DAMAGE.
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     // note(exjohnson): we can implement this later if desired, but
00080     // currently no use case for it.
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   // We can optimize these to be specific later if necessary.
00100   synchronizeWidget();
00101 }
00102 
00103 void ProfileTreeWidget::handleNodesAdded(int profile_key)
00104 {
00105   // We can optimize these to be specific later if necessary.
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 }  // namespace swri_profiler_tools


swri_profiler_tools
Author(s):
autogenerated on Sat Apr 27 2019 03:08:49