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 try:
35 from python_qt_binding.QtGui import QMessageBox
36 except:
37 from python_qt_binding.QtWidgets import QMessageBox
38 import threading
39
40 import rospy
41
42 from node_manager_fkie.detailed_msg_box import WarningMessageBox, DetailedError
43 import node_manager_fkie as nm
44
45
47 '''
48 request: AuthenticationRequest
49 '''
50
51 - def __init__(self, request, method, args):
52 Exception.__init__(self)
53 self.method = method
54 self.request = request
55 self.args = args
56
58 return "InteractionNeededError"
59
60
62 '''
63 The queue provides a threaded execution of given tasks.
64 '''
65
66 - def __init__(self, progress_frame, progress_bar, progress_cancel_button):
67 QObject.__init__(self)
68 self.__ignore_err_list = []
69 self.__progress_queue = []
70 self.__running = False
71 self._progress_frame = progress_frame
72 self._progress_bar = progress_bar
73 self._progress_cancel_button = progress_cancel_button
74 progress_frame.setVisible(False)
75 progress_cancel_button.clicked.connect(self._on_progress_canceled)
76
78 '''
79 Deletes all queued tasks and wait 3 seconds for the end of current running
80 thread.
81 '''
82 try:
83 val = self._progress_bar.value()
84 if val < len(self.__progress_queue):
85 print " Shutdown progress queue..."
86 thread = self.__progress_queue[val]
87 self.__progress_queue = []
88 thread.join(3)
89 print " Progress queue is off!"
90 except:
91 pass
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
166 if detailed_msg in self.__ignore_err_list:
167 self._progress_thread_finished(ident)
168 return
169 btns = (QMessageBox.Ignore)
170 if len(self.__progress_queue) > 1:
171 btns = (QMessageBox.Ignore | QMessageBox.Abort)
172 res = WarningMessageBox(QMessageBox.Warning, title, msg, detailed_msg,
173 buttons=btns).exec_()
174 if res == QMessageBox.Abort:
175 self.__progress_queue = []
176 self._progress_frame.setVisible(False)
177 self.__running = False
178 else:
179
180
181 if res == 1 or res == 0:
182 self.__ignore_err_list.append(detailed_msg)
183 self._progress_thread_finished(ident)
184
186 try:
187 if self.__progress_queue:
188 try:
189 pthread = self.__progress_queue[self._progress_bar.value()]
190 pthread.finished_signal.disconnect(self._progress_thread_finished)
191 pthread.error_signal.disconnect(self._progress_thread_error)
192 pthread.request_interact_signal.disconnect(self._on_request_interact)
193
194 except:
195 pass
196 self.__progress_queue = []
197 self._progress_frame.setVisible(False)
198 self.__running = False
199 except:
200 import traceback
201 print traceback.format_exc(1)
202
204 '''
205 If the interaction of the user is needed a message dialog must be exceuted
206 in the main Qt thread. The requests are done by different request exceptinos.
207 These are handled by this method.
208 '''
209 if isinstance(req.request, nm.AuthenticationRequest):
210 res, user, pw = nm.ssh()._requestPW(req.request.user, req.request.host)
211 if not res:
212 self._on_progress_canceled()
213 return
214 if req.args and isinstance(req.args[0], nm.AdvRunCfg):
215 req.args[0].user = user
216 req.args[0].pw = pw
217 else:
218 req.args = req.args + (user, pw)
219 pt = ProgressThread(ident, descr, req.method, (req.args))
220 pt.finished_signal.connect(self._progress_thread_finished)
221 pt.error_signal.connect(self._progress_thread_error)
222 pt.request_interact_signal.connect(self._on_request_interact)
223 pt.start()
224 elif isinstance(req.request, nm.ScreenSelectionRequest):
225 from node_manager_fkie.select_dialog import SelectDialog
226 items, _ = SelectDialog.getValue('Show screen', '', req.request.choices.keys(), False)
227 if not items:
228 self._progress_thread_finished(ident)
229 return
230 res = [req.request.choices[i] for i in items]
231 pt = ProgressThread(ident, descr, req.method, (req.args + (res,)))
232 pt.finished_signal.connect(self._progress_thread_finished)
233 pt.error_signal.connect(self._progress_thread_error)
234 pt.request_interact_signal.connect(self._on_request_interact)
235 pt.start()
236 elif isinstance(req.request, nm.BinarySelectionRequest):
237 from node_manager_fkie.select_dialog import SelectDialog
238 items, _ = SelectDialog.getValue('Multiple executables', '', req.request.choices, True)
239 if not items:
240 self._progress_thread_finished(ident)
241 return
242 res = items[0]
243 if req.args and isinstance(req.args[0], nm.AdvRunCfg):
244 req.args[0].executable = res
245 else:
246 req.args = req.args + (res,)
247 pt = ProgressThread(ident, descr, req.method, (req.args))
248 pt.finished_signal.connect(self._progress_thread_finished)
249 pt.error_signal.connect(self._progress_thread_error)
250 pt.request_interact_signal.connect(self._on_request_interact)
251 pt.start()
252 elif isinstance(req.request, nm.LaunchArgsSelectionRequest):
253 from node_manager_fkie.parameter_dialog import ParameterDialog
254 input_dia = ParameterDialog(req.request.args_dict)
255 input_dia.setFilterVisible(False)
256 input_dia.setWindowTitle('Enter the argv for %s' % req.request.launchfile)
257 if input_dia.exec_():
258 params = input_dia.getKeywords()
259 argv = []
260 for prm, val in params.items():
261 if val:
262 argv.append('%s:=%s' % (prm, val))
263 res = argv
264 pt = ProgressThread(ident, descr, req.method, (req.args + (argv,)))
265 pt.finished_signal.connect(self._progress_thread_finished)
266 pt.error_signal.connect(self._progress_thread_error)
267 pt.request_interact_signal.connect(self._on_request_interact)
268 pt.start()
269 else:
270 self._progress_thread_finished(ident)
271 return
272
273
275 '''
276 A thread to execute a method in a thread.
277 '''
278 finished_signal = Signal(str)
279 '''
280 @ivar: finished_signal is a signal, which is emitted, if the thread is finished.
281 '''
282
283 error_signal = Signal(str, str, str, str)
284 '''
285 @ivar: error_signal is a signal (id, title, error message, detailed error message),
286 which is emitted, if an error while run of the thread was occurred.
287 '''
288
289 request_interact_signal = Signal(str, str, InteractionNeededError)
290
291 - def __init__(self, ident, descr='', target=None, args=()):
292 QObject.__init__(self)
293 threading.Thread.__init__(self)
294 self._id = ident
295 self.descr = descr
296 self._target = target
297 self._args = args
298 self.setDaemon(True)
299
302
304 '''
305 '''
306 try:
307 if self._target is not None:
308 if 'pqid' in self._target.func_code.co_varnames:
309 self._target(*self._args, pqid=self._id)
310 else:
311 self._target(*self._args)
312 self.finished_signal.emit(self._id)
313 else:
314 self.error_signal.emit(self._id, 'No target specified')
315 except InteractionNeededError as ine:
316 self.request_interact_signal.emit(self._id, self.descr, ine)
317 except DetailedError as err:
318 self.error_signal.emit(self._id, err.title, err.value, err.detailed_text)
319 except:
320 import traceback
321
322 formatted_lines = traceback.format_exc(1).splitlines()
323 last_line = formatted_lines[-1]
324 index = 1
325 while not last_line and len(formatted_lines) > index:
326 index += 1
327 last_line = formatted_lines[-index]
328 rospy.logwarn("%s failed:\n\t%s", str(self.descr), last_line)
329 self.error_signal.emit(self._id, 'Progress Job Error',
330 "%s failed:\n%s" % (str(self.descr), last_line),
331 traceback.format_exc(4))
332