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.QtCore import QObject, Signal
34 import threading
35
36 import rospy
37
38 from node_manager_fkie.common import utf8
39 from node_manager_fkie.detailed_msg_box import MessageBox, DetailedError
40 import node_manager_fkie as nm
41
42
44 '''
45 request: AuthenticationRequest
46 '''
47
48 - def __init__(self, request, method, args):
49 Exception.__init__(self)
50 self.method = method
51 self.request = request
52 self.args = args
53
55 return "InteractionNeededError"
56
57
59 '''
60 The queue provides a threaded execution of given tasks.
61 '''
62 no_screen_error_signal = Signal(str, str)
63
64 - def __init__(self, progress_frame, progress_bar, progress_cancel_button, name=''):
65 QObject.__init__(self)
66 self.__progress_queue = []
67 self.__running = False
68 self._name = name
69 self._progress_frame = progress_frame
70 self._progress_bar = progress_bar
71 self._progress_cancel_button = progress_cancel_button
72 progress_frame.setVisible(False)
73 progress_cancel_button.clicked.connect(self._on_progress_canceled)
74
76 '''
77 Deletes all queued tasks and wait 3 seconds for the end of current running
78 thread.
79 '''
80 try:
81 val = self._progress_bar.value()
82 if val < len(self.__progress_queue):
83 print " Stop progress queue '%s'..." % self._name
84 thread = self.__progress_queue[val]
85 self.__progress_queue = []
86 if thread.is_alive():
87 thread.join(3)
88 print " Progress queue '%s' stopped!" % self._name
89 except Exception:
90 import traceback
91 print utf8(traceback.format_exc())
92
93 - def add2queue(self, ident, descr, target=None, args=()):
94 '''
95 Adds new task to the queue. After the task was added you need call start().
96 :param ident: the unique identification string
97 :type ident: str
98 :param descr: the description of the task
99 :type descr: str
100 :param target: is the callable object to be invoked in a new thread.
101 Defaults to None, meaning nothing is called.
102 :param args: is the argument tuple for the target invocation. Defaults to ()
103 '''
104 pthread = ProgressThread(ident, descr, target, args)
105 pthread.finished_signal.connect(self._progress_thread_finished)
106 pthread.error_signal.connect(self._progress_thread_error)
107 pthread.request_interact_signal.connect(self._on_request_interact)
108 self.__progress_queue.append(pthread)
109 self._progress_bar.setMaximum(len(self.__progress_queue))
110
112 '''
113 Starts the execution of tasks in the queue.
114 '''
115 if not self.__running and self.__progress_queue:
116 self._progress_frame.setVisible(True)
117 self.__running = True
118 self._progress_bar.setToolTip(self.__progress_queue[0].descr)
119 dscr_len = self._progress_bar.size().width() / 10
120 self._progress_bar.setFormat(''.join(['%v/%m - ', self.__progress_queue[0].descr[0:dscr_len]]))
121 self._progress_bar.setValue(0)
122 self.__progress_queue[0].start()
123
125 '''
126 :return: the count of tasks in the queue
127 :rtype: int
128 '''
129 return len(self.__progress_queue)
130
132 '''
133 Searches the current and planed threads for given id and returns `True` if
134 one is found.
135 '''
136 for thread in self.__progress_queue:
137 if thread.id() == ident:
138 return True
139 return False
140
142 try:
143 val = self._progress_bar.value()
144
145
146 if ident == self.__progress_queue[val].id():
147 val = val + 1
148 th = self.__progress_queue[val]
149 self._progress_bar.setToolTip(th.descr)
150 dscr_len = self._progress_bar.size().width() / 10
151 self._progress_bar.setFormat(''.join(['%v/%m - ', th.descr[0:dscr_len]]))
152 self.__progress_queue[val].start()
153 self._progress_bar.setValue(val)
154
155 except:
156
157 for thread in self.__progress_queue:
158 thread.join(1)
159 self._progress_frame.setVisible(False)
160 self.__running = False
161
162 self.__progress_queue = []
163
164
176
178 try:
179 if self.__progress_queue:
180 try:
181 pthread = self.__progress_queue[self._progress_bar.value()]
182 pthread.finished_signal.disconnect(self._progress_thread_finished)
183 pthread.error_signal.disconnect(self._progress_thread_error)
184 pthread.request_interact_signal.disconnect(self._on_request_interact)
185
186 except:
187 pass
188 self.__progress_queue = []
189 self._progress_frame.setVisible(False)
190 self.__running = False
191 except:
192 import traceback
193 print utf8(traceback.format_exc(1))
194
196 '''
197 If the interaction of the user is needed a message dialog must be exceuted
198 in the main Qt thread. The requests are done by different request exceptinos.
199 These are handled by this method.
200 '''
201 if isinstance(req.request, nm.AuthenticationRequest):
202 res, user, pw = nm.ssh()._requestPW(req.request.user, req.request.host)
203 if not res:
204 self._on_progress_canceled()
205 return
206 if req.args and isinstance(req.args[0], nm.AdvRunCfg):
207 req.args[0].user = user
208 req.args[0].pw = pw
209 else:
210 req.args = req.args + (user, pw)
211 pt = ProgressThread(ident, descr, req.method, (req.args))
212 pt.finished_signal.connect(self._progress_thread_finished)
213 pt.error_signal.connect(self._progress_thread_error)
214 pt.request_interact_signal.connect(self._on_request_interact)
215 pt.start()
216 elif isinstance(req.request, nm.ScreenSelectionRequest):
217 from node_manager_fkie.select_dialog import SelectDialog
218 items, _ = SelectDialog.getValue('Show screen', '', req.request.choices.keys(), False)
219 if not items:
220 self._progress_thread_finished(ident)
221 return
222 res = [req.request.choices[i] for i in items]
223 pt = ProgressThread(ident, descr, req.method, (req.args + (res,)))
224 pt.finished_signal.connect(self._progress_thread_finished)
225 pt.error_signal.connect(self._progress_thread_error)
226 pt.request_interact_signal.connect(self._on_request_interact)
227 pt.start()
228 elif isinstance(req.request, nm.BinarySelectionRequest):
229 from node_manager_fkie.select_dialog import SelectDialog
230 items, _ = SelectDialog.getValue('Multiple executables', '', req.request.choices, True)
231 if not items:
232 self._progress_thread_finished(ident)
233 return
234 res = items[0]
235 if req.args and isinstance(req.args[0], nm.AdvRunCfg):
236 req.args[0].executable = res
237 else:
238 req.args = req.args + (res,)
239 pt = ProgressThread(ident, descr, req.method, (req.args))
240 pt.finished_signal.connect(self._progress_thread_finished)
241 pt.error_signal.connect(self._progress_thread_error)
242 pt.request_interact_signal.connect(self._on_request_interact)
243 pt.start()
244 elif isinstance(req.request, nm.LaunchArgsSelectionRequest):
245 from node_manager_fkie.parameter_dialog import ParameterDialog
246 input_dia = ParameterDialog(req.request.args_dict)
247 input_dia.setFilterVisible(False)
248 input_dia.setWindowTitle('Enter the argv for %s' % req.request.launchfile)
249 if input_dia.exec_():
250 params = input_dia.getKeywords()
251 argv = []
252 for prm, val in params.items():
253 if val:
254 argv.append('%s:=%s' % (prm, val))
255 res = argv
256 pt = ProgressThread(ident, descr, req.method, (req.args + (argv,)))
257 pt.finished_signal.connect(self._progress_thread_finished)
258 pt.error_signal.connect(self._progress_thread_error)
259 pt.request_interact_signal.connect(self._on_request_interact)
260 pt.start()
261 else:
262 self._progress_thread_finished(ident)
263 return
264 elif isinstance(req.request, nm.NoScreenOpenLogRequest):
265 self.no_screen_error_signal.emit(req.request. node, req.request.host)
266 self._progress_thread_finished(ident)
267
268
270 '''
271 A thread to execute a method in a thread.
272 '''
273 finished_signal = Signal(str)
274 '''
275 @ivar: finished_signal is a signal, which is emitted, if the thread is finished.
276 '''
277
278 error_signal = Signal(str, str, str, str)
279 '''
280 @ivar: error_signal is a signal (id, title, error message, detailed error message),
281 which is emitted, if an error while run of the thread was occurred.
282 '''
283
284 request_interact_signal = Signal(str, str, InteractionNeededError)
285
286 - def __init__(self, ident, descr='', target=None, args=()):
287 QObject.__init__(self)
288 threading.Thread.__init__(self)
289 self._id = ident
290 self.descr = descr
291 self._target = target
292 self._args = args
293 self.setDaemon(True)
294
297
299 '''
300 '''
301 try:
302 if self._target is not None:
303 if 'pqid' in self._target.func_code.co_varnames:
304 self._target(*self._args, pqid=self._id)
305 else:
306 self._target(*self._args)
307 self.finished_signal.emit(self._id)
308 else:
309 self.error_signal.emit(self._id, 'No target specified')
310 except InteractionNeededError as ine:
311 self.request_interact_signal.emit(self._id, self.descr, ine)
312 except DetailedError as err:
313 self.error_signal.emit(self._id, err.title, err.value, err.detailed_text)
314 except Exception:
315 import traceback
316
317 formatted_lines = traceback.format_exc(1).splitlines()
318 last_line = formatted_lines[-1]
319 index = 1
320 while not last_line and len(formatted_lines) > index:
321 index += 1
322 last_line = formatted_lines[-index]
323 self.error_signal.emit(self._id, 'Progress Job Error',
324 "%s failed:\n%s" % (utf8(self.descr), utf8(last_line)),
325 utf8(traceback.format_exc(4)))
326 rospy.logwarn("%s failed:\n\t%s", utf8(self.descr), utf8(last_line))
327