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.QtWidgets import (QLabel, QHBoxLayout, QSplitter,
00042                                          QVBoxLayout, QWidget)
00043 
00044 from rqt_reconfigure import logging
00045 from rqt_reconfigure.node_selector_widget import NodeSelectorWidget
00046 from rqt_reconfigure.paramedit_widget import ParameditWidget
00047 from rqt_reconfigure.text_filter import TextFilter
00048 from rqt_reconfigure.text_filter_widget import TextFilterWidget
00049 import rospy
00050 
00051 class ParamWidget(QWidget):
00052     _TITLE_PLUGIN = 'Dynamic Reconfigure'
00053 
00054     # To be connected to PluginContainerWidget
00055     sig_sysmsg = Signal(str)
00056     sig_sysprogress = Signal(str)
00057 
00058     # To make selections from CLA
00059     sig_selected = Signal(str)
00060 
00061     def __init__(self, context, node=None):
00062         """
00063         This class is intended to be called by rqt plugin framework class.
00064         Currently (12/12/2012) the whole widget is splitted into 2 panes:
00065         one on left allows you to choose the node(s) you work on. Right side
00066         pane lets you work with the parameters associated with the node(s) you
00067         select on the left.
00068 
00069         (12/27/2012) Despite the pkg name is changed to rqt_reconfigure to
00070         reflect the available functionality, file & class names remain
00071         'param', expecting all the parameters will become handle-able.
00072         """
00073 
00074         super(ParamWidget, self).__init__()
00075         self.setObjectName(self._TITLE_PLUGIN)
00076         self.setWindowTitle(self._TITLE_PLUGIN)
00077 
00078         rp = rospkg.RosPack()
00079 
00080         #TODO: .ui file needs to replace the GUI components declaration
00081         #            below. For unknown reason, referring to another .ui files
00082         #            from a .ui that is used in this class failed. So for now,
00083         #            I decided not use .ui in this class.
00084         #            If someone can tackle this I'd appreciate.
00085         _hlayout_top = QHBoxLayout(self)
00086         _hlayout_top.setContentsMargins(QMargins(0, 0, 0, 0))
00087         self._splitter = QSplitter(self)
00088         _hlayout_top.addWidget(self._splitter)
00089 
00090         _vlayout_nodesel_widget = QWidget()
00091         _vlayout_nodesel_side = QVBoxLayout()
00092         _hlayout_filter_widget = QWidget(self)
00093         _hlayout_filter = QHBoxLayout()
00094         self._text_filter = TextFilter()
00095         self.filter_lineedit = TextFilterWidget(self._text_filter, rp)
00096         self.filterkey_label = QLabel("&Filter key:")
00097         self.filterkey_label.setBuddy(self.filter_lineedit)
00098         _hlayout_filter.addWidget(self.filterkey_label)
00099         _hlayout_filter.addWidget(self.filter_lineedit)
00100         _hlayout_filter_widget.setLayout(_hlayout_filter)
00101         self._nodesel_widget = NodeSelectorWidget(self, rp, self.sig_sysmsg)
00102         _vlayout_nodesel_side.addWidget(_hlayout_filter_widget)
00103         _vlayout_nodesel_side.addWidget(self._nodesel_widget)
00104         _vlayout_nodesel_side.setSpacing(1)
00105         _vlayout_nodesel_widget.setLayout(_vlayout_nodesel_side)
00106 
00107         reconf_widget = ParameditWidget(rp)
00108 
00109         self._splitter.insertWidget(0, _vlayout_nodesel_widget)
00110         self._splitter.insertWidget(1, reconf_widget)
00111         # 1st column, _vlayout_nodesel_widget, to minimize width.
00112         # 2nd col to keep the possible max width.
00113         self._splitter.setStretchFactor(0, 0)
00114         self._splitter.setStretchFactor(1, 1)
00115 
00116         # Signal from paramedit widget to node selector widget.
00117         reconf_widget.sig_node_disabled_selected.connect(
00118                                        self._nodesel_widget.node_deselected)
00119         # Pass name of node to editor widget
00120         self._nodesel_widget.sig_node_selected.connect(
00121                                                      reconf_widget.show_reconf)
00122 
00123         if not node:
00124             title = self._TITLE_PLUGIN
00125         else:
00126             title = self._TITLE_PLUGIN + ' %s' % node
00127         self.setObjectName(title)
00128 
00129         #Connect filter signal-slots.
00130         self._text_filter.filter_changed_signal.connect(
00131                                             self._filter_key_changed)
00132 
00133         # Open any clients indicated from command line
00134         self.sig_selected.connect(self._nodesel_widget.node_selected)
00135         for rn in [rospy.resolve_name(c) for c in context.argv()]:
00136             if rn in self._nodesel_widget.get_paramitems():
00137                 self.sig_selected.emit(rn)
00138             else:
00139                 logging.warn('Could not find a dynamic reconfigure client named \'%s\'', str(rn))
00140 
00141     def shutdown(self):
00142         #TODO: Needs implemented. Trigger dynamic_reconfigure to unlatch
00143         #            subscriber.
00144         pass
00145 
00146     def save_settings(self, plugin_settings, instance_settings):
00147         instance_settings.set_value('splitter', self._splitter.saveState())
00148 
00149     def restore_settings(self, plugin_settings, instance_settings):
00150         if instance_settings.contains('splitter'):
00151             self._splitter.restoreState(instance_settings.value('splitter'))
00152         else:
00153             self._splitter.setSizes([100, 100, 200])
00154 
00155     def get_filter_text(self):
00156         """
00157         :rtype: QString
00158         """
00159         return self.filter_lineedit.text()
00160 
00161     def _filter_key_changed(self):
00162         self._nodesel_widget.set_filter(self._text_filter)
00163 
00164     #TODO: This method should be integrated into common architecture. I just
00165     # can't think of how to do so within current design.
00166     def emit_sysmsg(self, msg_str):
00167         self.sig_sysmsg.emit(msg_str)
00168 
00169 
00170 if __name__ == '__main__':
00171     # main should be used only for debug purpose.
00172     # This launches this QWidget as a standalone rqt gui.
00173     from rqt_gui.main import Main
00174 
00175     main = Main()
00176     sys.exit(main.main(sys.argv, standalone='rqt_reconfigure'))


rqt_reconfigure
Author(s): Isaac Saito, Ze'ev Klapow
autogenerated on Sat Jul 6 2019 03:49:38