param_widget.py
Go to the documentation of this file.
00001 # Software License Agreement (BSD License)
00002 #
00003 # Copyright (c) 2012, Willow Garage, Inc.
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
00008 # are met:
00009 #
00010 #  * Redistributions of source code must retain the above copyright
00011 #    notice, this list of conditions and the following disclaimer.
00012 #  * Redistributions in binary form must reproduce the above
00013 #    copyright notice, this list of conditions and the following
00014 #    disclaimer in the documentation and/or other materials provided
00015 #    with the distribution.
00016 #  * Neither the name of Willow Garage, Inc. nor the names of its
00017 #    contributors may be used to endorse or promote products derived
00018 #    from this software without specific prior written permission.
00019 #
00020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 # POSSIBILITY OF SUCH DAMAGE.
00032 #
00033 # Author: Isaac Saito
00034 
00035 from __future__ import division
00036 
00037 import rospkg
00038 import sys
00039 
00040 from python_qt_binding.QtCore import Signal, QMargins
00041 from python_qt_binding.QtGui import (QLabel, QHBoxLayout, QSplitter,
00042                                      QVBoxLayout, QWidget, QItemSelectionModel)
00043 
00044 from rqt_reconfigure.node_selector_widget import NodeSelectorWidget
00045 from rqt_reconfigure.paramedit_widget import ParameditWidget
00046 from rqt_reconfigure.text_filter import TextFilter
00047 from rqt_reconfigure.text_filter_widget import TextFilterWidget
00048 import rospy
00049 
00050 class ParamWidget(QWidget):
00051     _TITLE_PLUGIN = 'Dynamic Reconfigure'
00052 
00053     # To be connected to PluginContainerWidget
00054     sig_sysmsg = Signal(str)
00055     sig_sysprogress = Signal(str)
00056 
00057     # To make selections from CLA
00058     sig_selected = Signal(str)
00059 
00060     def __init__(self, context, node=None):
00061         """
00062         This class is intended to be called by rqt plugin framework class.
00063         Currently (12/12/2012) the whole widget is splitted into 2 panes:
00064         one on left allows you to choose the node(s) you work on. Right side
00065         pane lets you work with the parameters associated with the node(s) you
00066         select on the left.
00067 
00068         (12/27/2012) Despite the pkg name is changed to rqt_reconfigure to
00069         reflect the available functionality, file & class names remain
00070         'param', expecting all the parameters will become handle-able.
00071         """
00072 
00073         super(ParamWidget, self).__init__()
00074         self.setObjectName(self._TITLE_PLUGIN)
00075         self.setWindowTitle(self._TITLE_PLUGIN)
00076 
00077         rp = rospkg.RosPack()
00078 
00079         #TODO: .ui file needs to replace the GUI components declaration
00080         #            below. For unknown reason, referring to another .ui files
00081         #            from a .ui that is used in this class failed. So for now,
00082         #            I decided not use .ui in this class.
00083         #            If someone can tackle this I'd appreciate.
00084         _hlayout_top = QHBoxLayout(self)
00085         _hlayout_top.setContentsMargins(QMargins(0, 0, 0, 0))
00086         self._splitter = QSplitter(self)
00087         _hlayout_top.addWidget(self._splitter)
00088 
00089         _vlayout_nodesel_widget = QWidget()
00090         _vlayout_nodesel_side = QVBoxLayout()
00091         _hlayout_filter_widget = QWidget(self)
00092         _hlayout_filter = QHBoxLayout()
00093         self._text_filter = TextFilter()
00094         self.filter_lineedit = TextFilterWidget(self._text_filter, rp)
00095         self.filterkey_label = QLabel("&Filter key:")
00096         self.filterkey_label.setBuddy(self.filter_lineedit)
00097         _hlayout_filter.addWidget(self.filterkey_label)
00098         _hlayout_filter.addWidget(self.filter_lineedit)
00099         _hlayout_filter_widget.setLayout(_hlayout_filter)
00100         self._nodesel_widget = NodeSelectorWidget(self, rp, self.sig_sysmsg)
00101         _vlayout_nodesel_side.addWidget(_hlayout_filter_widget)
00102         _vlayout_nodesel_side.addWidget(self._nodesel_widget)
00103         _vlayout_nodesel_side.setSpacing(1)
00104         _vlayout_nodesel_widget.setLayout(_vlayout_nodesel_side)
00105 
00106         reconf_widget = ParameditWidget(rp)
00107 
00108         self._splitter.insertWidget(0, _vlayout_nodesel_widget)
00109         self._splitter.insertWidget(1, reconf_widget)
00110         # 1st column, _vlayout_nodesel_widget, to minimize width.
00111         # 2nd col to keep the possible max width.
00112         self._splitter.setStretchFactor(0, 0)
00113         self._splitter.setStretchFactor(1, 1)
00114 
00115         # Signal from paramedit widget to node selector widget.
00116         reconf_widget.sig_node_disabled_selected.connect(
00117                                        self._nodesel_widget.node_deselected)
00118         # Pass name of node to editor widget
00119         self._nodesel_widget.sig_node_selected.connect(
00120                                                      reconf_widget.show_reconf)
00121 
00122         if not node:
00123             title = self._TITLE_PLUGIN
00124         else:
00125             title = self._TITLE_PLUGIN + ' %s' % node
00126         self.setObjectName(title)
00127 
00128         #Connect filter signal-slots.
00129         self._text_filter.filter_changed_signal.connect(
00130                                             self._filter_key_changed)
00131 
00132         # Open any clients indicated from command line
00133         self.sig_selected.connect(self._nodesel_widget.node_selected)
00134         for rn in [rospy.resolve_name(c) for c in context.argv()]:
00135             if rn in self._nodesel_widget.get_paramitems():
00136                 self.sig_selected.emit(rn)
00137             else:
00138                 rospy.logwarn('Could not find a dynamic reconfigure client named \'%s\'', str(rn))
00139 
00140     def shutdown(self):
00141         #TODO: Needs implemented. Trigger dynamic_reconfigure to unlatch
00142         #            subscriber.
00143         pass
00144 
00145     def save_settings(self, plugin_settings, instance_settings):
00146         instance_settings.set_value('splitter', self._splitter.saveState())
00147 
00148     def restore_settings(self, plugin_settings, instance_settings):
00149         if instance_settings.contains('splitter'):
00150             self._splitter.restoreState(instance_settings.value('splitter'))
00151         else:
00152             self._splitter.setSizes([100, 100, 200])
00153 
00154     def get_filter_text(self):
00155         """
00156         :rtype: QString
00157         """
00158         return self.filter_lineedit.text()
00159 
00160     def _filter_key_changed(self):
00161         self._nodesel_widget.set_filter(self._text_filter)
00162 
00163     #TODO: This method should be integrated into common architecture. I just
00164     # can't think of how to do so within current design.
00165     def emit_sysmsg(self, msg_str):
00166         self.sig_sysmsg.emit(msg_str)
00167 
00168 
00169 if __name__ == '__main__':
00170     # main should be used only for debug purpose.
00171     # This launches this QWidget as a standalone rqt gui.
00172     from rqt_gui.main import Main
00173 
00174     main = Main()
00175     sys.exit(main.main(sys.argv, standalone='rqt_reconfigure'))


rqt_reconfigure
Author(s): Isaac Saito, Ze'ev Klapow
autogenerated on Mon Oct 6 2014 07:15:23