Go to the documentation of this file.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
00031
00032
00033
00034
00035 from __future__ import division
00036
00037 import threading
00038 import time
00039
00040 import dynamic_reconfigure.client
00041 from python_qt_binding.QtCore import Qt
00042 from python_qt_binding.QtGui import QBrush, QStandardItem
00043 import rospy
00044 from rospy.exceptions import ROSException
00045 from rqt_py_common.data_items import ReadonlyItem
00046
00047 from .dynreconf_client_widget import DynreconfClientWidget
00048
00049
00050 class ParamserverConnectThread(threading.Thread):
00051 def __init__(self, parent, param_name_raw):
00052 super(ParamserverConnectThread, self).__init__()
00053 self._parent = parent
00054 self._param_name_raw = param_name_raw
00055
00056 def run(self):
00057 dynreconf_client = None
00058 try:
00059 dynreconf_client = dynamic_reconfigure.client.Client(
00060 str(self._param_name_raw), timeout=5.0)
00061 rospy.logdebug('ParamserverConnectThread dynreconf_client={}'. \
00062 format(dynreconf_client))
00063 self._parent.set_dynreconf_client(dynreconf_client)
00064 except rospy.exceptions.ROSException as e:
00065 raise type(e)(e.message +
00066 "TreenodeQstdItem. Couldn't connect to {}".format(
00067 self._param_name_raw))
00068
00069
00070 class TreenodeQstdItem(ReadonlyItem):
00071 """
00072 Extending ReadonlyItem - the display content of this item shouldn't be
00073 modified.
00074 """
00075
00076 NODE_FULLPATH = 1
00077
00078 def __init__(self, *args):
00079 """
00080 :param args[0]: str (will become 1st arg of QStandardItem)
00081 :param args[1]: integer value that indicates whether this class
00082 is node that has GRN (Graph Resource Names, see
00083 http://www.ros.org/wiki/Names). This can be None
00084 """
00085 grn_current_treenode = args[0]
00086 self._param_name_raw = grn_current_treenode
00087 self._set_param_name(grn_current_treenode)
00088 super(TreenodeQstdItem, self).__init__(grn_current_treenode)
00089
00090
00091 self._dynreconf_client = None
00092
00093 self._dynreconfclient_widget = None
00094
00095 self._is_rosnode = False
00096
00097 self._lock = None
00098 self._paramserver_connect_thread = None
00099
00100 try:
00101 if args[1]:
00102 self._is_rosnode = True
00103 except IndexError:
00104 rospy.logerr('TreenodeQstdItem IndexError')
00105
00106 def set_dynreconf_client(self, dynreconf_client):
00107 """
00108 @param dynreconf_client: dynamic_reconfigure.client.Client
00109 """
00110 self._dynreconf_client = dynreconf_client
00111 rospy.logdebug('Qitem set dynreconf_client={} param={}'.format(
00112 self._dynreconf_client,
00113 self._param_name_raw))
00114
00115 def clear_dynreconf_client(self):
00116 self._dynreconf_client = None
00117
00118 def get_dynreconf_widget(self):
00119 """
00120 @rtype: DynreconfClientWidget (QWidget)
00121 @return: None if dynreconf_client is not yet generated.
00122 @raise ROSException:
00123 """
00124
00125 if not self._dynreconfclient_widget:
00126 rospy.logdebug('get dynreconf_client={}'.format(
00127 self._dynreconf_client))
00128 rospy.logdebug('In get_dynreconf_widget 1')
00129 if not self._dynreconf_client:
00130 self.connect_param_server()
00131 rospy.logdebug('In get_dynreconf_widget 2')
00132
00133 timeout = 3 * 100
00134 loop = 0
00135
00136
00137 while self._dynreconf_client == None:
00138
00139 if timeout < loop:
00140
00141 self.setEnabled(False)
00142 raise ROSException('dynreconf client failed')
00143
00144 time.sleep(0.01)
00145 loop += 1
00146 rospy.logdebug('In get_dynreconf_widget loop#{}'.format(loop))
00147
00148 rospy.logdebug('In get_dynreconf_widget 4')
00149 self._dynreconfclient_widget = DynreconfClientWidget(
00150 self._dynreconf_client,
00151 self._param_name_raw)
00152
00153
00154
00155 self._dynreconfclient_widget.destroyed.connect(self.clear_dynreconfclient_widget)
00156 self._dynreconfclient_widget.destroyed.connect(self.disconnect_param_server)
00157 rospy.logdebug('In get_dynreconf_widget 5')
00158
00159 else:
00160 pass
00161 return self._dynreconfclient_widget
00162
00163 def clear_dynreconfclient_widget(self):
00164 self._dynreconfclient_widget = None
00165
00166 def connect_param_server(self):
00167 """
00168 Connect to parameter server using dynamic_reconfigure client.
00169 Behavior is delegated to a private method _connect_param_server, and
00170 its return value, client, is set to member variable.
00171
00172 @return void
00173 @raise ROSException:
00174 """
00175
00176 if not self._is_rosnode:
00177 rospy.logerr('connect_param_server failed due to missing ' +
00178 'ROS Node. Return with nothing.')
00179 return
00180
00181 if not self._dynreconfclient_widget:
00182 self._paramserver_connect_thread = ParamserverConnectThread(
00183 self, self._param_name_raw)
00184 self._paramserver_connect_thread.start()
00185
00186 def disconnect_param_server(self):
00187 if self._paramserver_connect_thread:
00188
00189 if self._paramserver_connect_thread.isAlive():
00190 self._paramserver_connect_thread.join(1)
00191 del self._paramserver_connect_thread
00192 self._paramserver_connect_thread = None
00193 self.clear_dynreconf_client()
00194
00195 def enable_param_items(self):
00196 """
00197 Create QStdItem per parameter and addColumn them to myself.
00198 :rtype: None if _dynreconf_client is not initiated.
00199 """
00200 if not self._dynreconfclient_widget:
00201 return None
00202 paramnames = self._dynreconfclient_widget.get_treenode_names()
00203 paramnames_items = []
00204 brush = QBrush(Qt.lightGray)
00205 for paramname in paramnames:
00206 item = ReadonlyItem(paramname)
00207 item.setBackground(brush)
00208 paramnames_items.append(item)
00209 rospy.logdebug('enable_param_items len of paramnames={}'.format(
00210 len(paramnames_items)))
00211 self.appendColumn(paramnames_items)
00212
00213 def _set_param_name(self, param_name):
00214 """
00215 :param param_name: A string formatted as GRN (Graph Resource Names, see
00216 http://www.ros.org/wiki/Names).
00217 Example: /paramname/subpara/subsubpara/...
00218 """
00219 rospy.logdebug('_set_param_name param_name={} '.format(param_name))
00220
00221
00222 self._list_treenode_names = param_name.split('/')
00223
00224
00225 del self._list_treenode_names[0]
00226
00227 self._toplevel_treenode_name = self._list_treenode_names[0]
00228
00229 rospy.logdebug('paramname={} nodename={} _list_params[-1]={}'.format(
00230 param_name, self._toplevel_treenode_name,
00231 self._list_treenode_names[-1]))
00232
00233 def get_param_name_toplv(self):
00234 """
00235 :rtype: String of the top level param name.
00236 """
00237
00238 return self._name_top
00239
00240 def get_raw_param_name(self):
00241 return self._param_name_raw
00242
00243 def get_treenode_names(self):
00244 """
00245 :rtype: List of string. Null if param
00246 """
00247
00248
00249 return self._list_treenode_names
00250
00251 def get_node_name(self):
00252 """
00253 :return: A value of single tree node (ie. NOT the fullpath node name).
00254 Ex. suppose fullpath name is /top/sub/subsub/subsubsub and you
00255 are at 2nd from top, the return value is subsub.
00256 """
00257 return self._toplevel_treenode_name
00258
00259 def type(self):
00260 return QStandardItem.UserType