1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 from python_qt_binding.QtGui import QColor
34 import os
35 import roslib
36 import rospy
37
38 from node_manager_fkie.common import get_ros_home, masteruri_from_ros
42 LOGLEVEL = 'DEFAULT'
43 LOGLEVEL_ROSCPP = 'INFO'
44 LOGLEVEL_SUPERDEBUG = 'WARN'
45 CONSOLE_FORMAT = 'DEFAULT'
46
52
54 return ['loglevel',
55 'loglevel_roscpp',
56 'loglevel_superdebug',
57 'console_format'
58 ]
59
61 return getattr(self, attribute) == getattr(self, attribute.upper())
62
64 result = []
65 if attribute == 'console_format':
66 result = [self.CONSOLE_FORMAT,
67 '[${severity}] [${time}]: ${message}',
68 '[${severity}] [${time}] [${logger}]: ${message}']
69 elif attribute == 'loglevel':
70 result = ['DEFAULT', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL']
71 elif attribute == 'loglevel_roscpp':
72 result = ['INFO', 'DEBUG', 'WARN', 'ERROR', 'FATAL']
73 elif attribute == 'loglevel_superdebug':
74 result = ['WARN', 'DEBUG', 'INFO', 'ERROR', 'FATAL']
75 if not self.is_default(attribute):
76 result.insert(0, getattr(self, attribute))
77 return result
78
81
82 USER_DEFAULT = 'robot'
83
84
85 PKG_NAME = 'node_manager_fkie'
86 PACKAGE_DIR = roslib.packages.get_pkg_dir(PKG_NAME)
87 ROBOTS_DIR = os.path.join(PACKAGE_DIR, 'images')
88 CFG_PATH = os.path.join('.node_manager', os.sep)
89 '''@ivar: configuration path to store the history.'''
90 HELP_FILE = os.path.join(PACKAGE_DIR, 'README.rst')
91 CURRENT_DIALOG_PATH = os.path.expanduser('~')
92 LOG_PATH = os.environ.get('ROS_LOG_DIR') if os.environ.get('ROS_LOG_DIR') else os.path.join(os.path.expanduser('~'), '.ros/log/')
93
94 LOG_VIEWER = "/usr/bin/less -fKLnQrSU"
95 STARTER_SCRIPT = 'rosrun node_manager_fkie remote_nm.py'
96 RESPAWN_SCRIPT = 'rosrun node_manager_fkie respawn'
97 '''
98 the script used on remote hosts to start new ROS nodes
99 '''
100
101 LAUNCH_HISTORY_FILE = 'launch.history'
102 LAUNCH_HISTORY_LENGTH = 5
103
104 PARAM_HISTORY_FILE = 'param.history'
105 PARAM_HISTORY_LENGTH = 12
106
107 CFG_REDIRECT_FILE = 'redirect'
108 CFG_FILE = 'settings.ini'
109 CFG_GUI_FILE = 'settings.ini'
110
111 TIMEOUT_CONTROL = 5
112 TIMEOUT_UPDATES = 20
113
114 SEARCH_IN_EXT = ['.launch', '.yaml', '.conf', '.cfg', '.iface', '.sync', '.test', '.xml']
115 LAUNCH_VIEW_EXT = ['.yaml', '.conf', '.cfg', '.iface', '.sync', '.test']
116
117 STORE_GEOMETRY = True
118 AUTOUPDATE = True
119 MAX_TIMEDIFF = 0.5
120
121 START_SYNC_WITH_DISCOVERY = False
122 CONFIRM_EXIT_WHEN_CLOSING = True
123 HIGHLIGHT_XML_BLOCKS = True
124 COLORIZE_HOSTS = True
125
126 SHOW_DOMAIN_SUFFIX = False
127
128 TRANSPOSE_PUB_SUB_DESCR = True
129
130 DEAFULT_HOST_COLORS = [QColor(255, 255, 235).rgb()]
131
134
136 '''
137 Loads the settings from file or sets default values if no one exists.
138 '''
139 self._terminal_emulator = None
140 self._terminal_command_arg = 'e'
141 self._masteruri = masteruri_from_ros()
142 self.CFG_PATH = os.path.join(get_ros_home(), 'node_manager')
143
144
145 if not os.path.isdir(self.CFG_PATH):
146 os.makedirs(self.CFG_PATH)
147 self._cfg_path = self.CFG_PATH
148 else:
149 settings = self.qsettings(os.path.join(self.CFG_PATH, self.CFG_REDIRECT_FILE))
150 self._cfg_path = settings.value('cfg_path', self.CFG_PATH)
151
152 self._robots_path = self.ROBOTS_DIR
153 settings = self.qsettings(self.CFG_FILE)
154 self._default_user = settings.value('default_user', self.USER_DEFAULT)
155 settings.beginGroup('default_user_hosts')
156 self._default_user_hosts = dict()
157 for k in settings.childKeys():
158 self._default_user_hosts[k] = settings.value(k, self._default_user)
159 settings.endGroup()
160 try:
161 self._launch_history_length = int(settings.value('launch_history_length', self.LAUNCH_HISTORY_LENGTH))
162 except:
163 self._launch_history_length = self.LAUNCH_HISTORY_LENGTH
164 try:
165 self._param_history_length = int(settings.value('param_history_length', self.PARAM_HISTORY_LENGTH))
166 except:
167 self._param_history_length = self.PARAM_HISTORY_LENGTH
168 self._current_dialog_path = self.CURRENT_DIALOG_PATH
169 self._log_viewer = self.LOG_VIEWER
170 self._start_remote_script = self.STARTER_SCRIPT
171 self._respawn_script = self.RESPAWN_SCRIPT
172 self._launch_view_file_ext = self.str2list(settings.value('launch_view_file_ext', ', '.join(self.LAUNCH_VIEW_EXT)))
173 self._store_geometry = self.str2bool(settings.value('store_geometry', self.STORE_GEOMETRY))
174 self.SEARCH_IN_EXT = list(set(self.SEARCH_IN_EXT) | set(self._launch_view_file_ext))
175 self._autoupdate = self.str2bool(settings.value('autoupdate', self.AUTOUPDATE))
176 self._max_timediff = float(settings.value('max_timediff', self.MAX_TIMEDIFF))
177 self._rosconsole_cfg_file = 'rosconsole.config'
178 self.logging = LoggingConfig()
179 self.logging.loglevel = settings.value('logging/level', LoggingConfig.LOGLEVEL)
180 self.logging.loglevel_roscpp = settings.value('logging/level_roscpp', LoggingConfig.LOGLEVEL_ROSCPP)
181 self.logging.loglevel_superdebug = settings.value('logging/level_superdebug', LoggingConfig.LOGLEVEL_SUPERDEBUG)
182 self.logging.console_format = settings.value('logging/rosconsole_format', LoggingConfig.CONSOLE_FORMAT)
183 self._start_sync_with_discovery = self.str2bool(settings.value('start_sync_with_discovery', self.START_SYNC_WITH_DISCOVERY))
184 self._confirm_exit_when_closing = self.str2bool(settings.value('confirm_exit_when_closing', self.CONFIRM_EXIT_WHEN_CLOSING))
185 self._highlight_xml_blocks = self.str2bool(settings.value('highlight_xml_blocks', self.HIGHLIGHT_XML_BLOCKS))
186 self._colorize_hosts = self.str2bool(settings.value('colorize_hosts', self.COLORIZE_HOSTS))
187 self._show_domain_suffix = self.str2bool(settings.value('show_domain_suffix', self.SHOW_DOMAIN_SUFFIX))
188 self._transpose_pub_sub_descr = self.str2bool(settings.value('transpose_pub_sub_descr', self.TRANSPOSE_PUB_SUB_DESCR))
189 settings.beginGroup('host_colors')
190 self._host_colors = dict()
191 for k in settings.childKeys():
192 self._host_colors[k] = settings.value(k, None)
193 settings.endGroup()
194 self.init_hosts_color_list()
195
197 return self._masteruri
198
199 @property
201 return self._cfg_path
202
203 @cfg_path.setter
218
219 @property
221 return self._robots_path
222
223 @robots_path.setter
225 if path:
226 if not os.path.isdir(path):
227 os.makedirs(path)
228 self._robots_path = path
229 settings = self.qsettings(self.CFG_FILE)
230 settings.setValue('robots_path', self._robots_path)
231
232 @property
234 return self._default_user
235
236 @default_user.setter
242
244 if host in self._default_user_hosts:
245 return self._default_user_hosts[host]
246 return self.default_user
247
253
254 @property
256 return self._launch_history_length
257
258 @launch_history_length.setter
259 - def launch_history_length(self, length):
260 self._launch_history_length = length
261 settings = self.qsettings(self.CFG_FILE)
262 settings.setValue('launch_history_length', self._launch_history_length)
263
264 @property
266 return self._param_history_length
267
268 @param_history_length.setter
269 - def param_history_length(self, length):
270 self._param_history_length = length
271 settings = self.qsettings(self.CFG_FILE)
272 settings.setValue('param_history_length', self._param_history_length)
273
274 @property
276 return self._current_dialog_path
277
278 @current_dialog_path.setter
280 self._current_dialog_path = path
281
283 return os.path.join(self.ROBOTS_DIR, '%s.png' % robot_name)
284
285 @property
287 return self._log_viewer
288
289 @log_viewer.setter
291 self._log_viewer = viewer
292
293 @property
295 return self._start_remote_script
296
297 @start_remote_script.setter
299 self._start_remote_script = script
300
301 @property
303 return self._respawn_script
304
305 @respawn_script.setter
307 self._respawn_script = script
308
309 @property
311 return self._launch_view_file_ext
312
313 @launch_view_file_ext.setter
319
320 @property
322 return self._store_geometry
323
324 @store_geometry.setter
331
332 @property
334 return self._autoupdate
335
336 @autoupdate.setter
343
344 @property
346 return self._max_timediff
347
348 @max_timediff.setter
355
357 result = os.path.join(self.LOG_PATH, '%s.%s' % (package, self._rosconsole_cfg_file))
358 with open(result, 'w') as cfg_file:
359 cfg_file.write('log4j.logger.ros=%s\n' % self.logging.loglevel)
360 cfg_file.write('log4j.logger.ros.roscpp=%s\n' % self.logging.loglevel_roscpp)
361 cfg_file.write('log4j.logger.ros.roscpp.superdebug=%s\n' % self.logging.loglevel_superdebug)
362 return result
363
365 settings = self.qsettings(self.CFG_FILE)
366 settings.setValue('logging/level', self.logging.loglevel)
367 settings.setValue('logging/level_roscpp', self.logging.loglevel_roscpp)
368 settings.setValue('logging/level_superdebug', self.logging.loglevel_superdebug)
369 settings.setValue('logging/rosconsole_format', self.logging.console_format)
370
371 @property
373 return self._start_sync_with_discovery
374
375 @start_sync_with_discovery.setter
377 v = self.str2bool(value)
378 if self._start_sync_with_discovery != v:
379 self._start_sync_with_discovery = v
380 settings = self.qsettings(self.CFG_FILE)
381 settings.setValue('start_sync_with_discovery', self._start_sync_with_discovery)
382
383 @property
385 return self._confirm_exit_when_closing
386
387 @confirm_exit_when_closing.setter
389 val = self.str2bool(value)
390 if self._confirm_exit_when_closing != val:
391 self._confirm_exit_when_closing = val
392 settings = self.qsettings(self.CFG_FILE)
393 settings.setValue('confirm_exit_when_closing', self._confirm_exit_when_closing)
394
395 @property
397 return self._highlight_xml_blocks
398
399 @highlight_xml_blocks.setter
406
407 @property
409 return self._colorize_hosts
410
411 @colorize_hosts.setter
418
419 @property
421 return self._show_domain_suffix
422
423 @show_domain_suffix.setter
424 - def show_domain_suffix(self, value):
425 val = self.str2bool(value)
426 if self._show_domain_suffix != val:
427 self._show_domain_suffix = val
428 settings = self.qsettings(self.CFG_FILE)
429 settings.setValue('show_domain_suffix', self._show_domain_suffix)
430
431 @property
433 return self._transpose_pub_sub_descr
434
435 @transpose_pub_sub_descr.setter
437 val = self.str2bool(value)
438 if self._transpose_pub_sub_descr != val:
439 self._transpose_pub_sub_descr = val
440 settings = self.qsettings(self.CFG_FILE)
441 settings.setValue('transpose_pub_sub_descr', self._transpose_pub_sub_descr)
442
456
462
464 if isinstance(v, bool):
465 return v
466 return v.lower() in ("yes", "true", "t", "1")
467
469 if isinstance(l, list):
470 return l
471 try:
472 l = l.strip('[]')
473 l = l.replace('u"', '')
474 l = l.replace('"', '')
475 l = l.replace("'", '')
476 l = l.replace(",", ' ')
477 return [str(i).strip() for i in l.split(' ') if i]
478 except:
479 return []
480
482 '''
483 Creates a command string to run with a terminal prefix
484 @param cmd: the list with a command and args
485 @type cmd: [str,..]
486 @param title: the title of the terminal
487 @type title: str
488 @return: command with a terminal prefix
489 @rtype: str
490 '''
491 noclose_str = '-hold'
492 if self._terminal_emulator is None:
493 self._terminal_emulator = ""
494 for t in ['/usr/bin/x-terminal-emulator', '/usr/bin/xterm', '/opt/x11/bin/xterm']:
495 if os.path.isfile(t) and os.access(t, os.X_OK):
496
497 if os.path.basename(os.path.realpath(t)) in ['terminator', 'gnome-terminal', 'xfce4-terminal']:
498 self._terminal_command_arg = 'x'
499 else:
500 self._terminal_command_arg = 'e'
501 if os.path.basename(os.path.realpath(t)) in ['terminator', 'gnome-terminal', 'gnome-terminal.wrapper']:
502 noclose_str = '--profile hold'
503 if noclose:
504 rospy.loginfo("If your terminal close after the execution, you can change this behavior in "
505 "profiles. You can also create a profile with name 'hold'. This profile will "
506 "be then load by node_manager.")
507 elif os.path.basename(os.path.realpath(t)) in ['xfce4-terminal']:
508 noclose_str = ''
509 self._terminal_emulator = t
510 break
511 if self._terminal_emulator == "":
512 raise Exception("No Terminal found! Please install one of ['/usr/bin/x-terminal-emulator', '/usr/bin/xterm', '/opt/x11/bin/xterm']")
513 noclose_str = noclose_str if noclose else ""
514 return '%s -T "%s" %s -%s %s' % (self._terminal_emulator, title, noclose_str, self._terminal_command_arg, ' '.join(cmd))
515
517 from python_qt_binding.QtCore import QSettings
518 path = settings_file
519 if not settings_file.startswith(os.path.sep):
520 path = os.path.join(self.cfg_path, settings_file)
521 return QSettings(path, QSettings.IniFormat)
522
524 self.DEAFULT_HOST_COLORS = [
525 QColor(255, 255, 235).rgb(),
526 QColor(87, 93, 94).rgb(),
527 QColor(205, 186, 136).rgb(),
528 QColor(249, 168, 0).rgb(),
529 QColor(232, 140, 0).rgb(),
530 QColor(175, 128, 79).rgb(),
531 QColor(221, 175, 39).rgb(),
532 QColor(227, 217, 198).rgb(),
533 QColor(186, 72, 27).rgb(),
534 QColor(246, 120, 40).rgb(),
535 QColor(255, 77, 6).rgb(),
536 QColor(89, 25, 31).rgb(),
537 QColor(216, 160, 166).rgb(),
538 QColor(129, 97, 131).rgb(),
539 QColor(196, 97, 140).rgb(),
540 QColor(118, 104, 154).rgb(),
541 QColor(188, 64, 119).rgb(),
542 QColor(0, 56, 123).rgb(),
543 QColor(15, 76, 100).rgb(),
544 QColor(0, 137, 182).rgb(),
545 QColor(99, 125, 150).rgb(),
546 QColor(5, 139, 140).rgb(),
547 QColor(34, 45, 90).rgb(),
548 QColor(60, 116, 96).rgb(),
549 QColor(54, 103, 53).rgb(),
550 QColor(80, 83, 60).rgb(),
551 QColor(17, 66, 50).rgb(),
552 QColor(108, 124, 89).rgb(),
553 QColor(97, 153, 59).rgb(),
554 QColor(185, 206, 172).rgb(),
555 QColor(0, 131, 81).rgb(),
556 QColor(126, 186, 181).rgb(),
557 QColor(0, 181, 26).rgb(),
558 QColor(122, 136, 142).rgb(),
559 QColor(108, 110, 107).rgb(),
560 QColor(118, 106, 94).rgb(),
561 QColor(56, 62, 66).rgb(),
562 QColor(128, 128, 118).rgb(),
563 QColor(127, 130, 116).rgb(),
564 QColor(197, 199, 196).rgb(),
565 QColor(137, 105, 62).rgb(),
566 QColor(112, 69, 42).rgb(),
567 QColor(141, 73, 49).rgb(),
568 QColor(90, 56, 38).rgb(),
569 QColor(233, 224, 210).rgb(),
570 QColor(236, 236, 231).rgb(),
571 QColor(43, 43, 44).rgb(),
572 QColor(121, 123, 122)
573 ]
574