Package node_manager_fkie :: Module progress_queue
[frames] | no frames]

Source Code for Module node_manager_fkie.progress_queue

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2012, Fraunhofer FKIE/US, Alexander Tiderko 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Fraunhofer nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32   
 33  import threading 
 34  from python_qt_binding import QtCore 
 35  from python_qt_binding import QtGui 
 36   
 37  import rospy 
 38   
 39  import node_manager_fkie as nm 
 40  from detailed_msg_box import WarningMessageBox, DetailedError 
 41   
42 -class InteractionNeededError(Exception):
43 ''' 44 request: AuthenticationRequest 45 '''
46 - def __init__(self, request, method, args):
47 Exception.__init__(self) 48 self.method = method 49 self.request = request 50 self.args = args
51
52 - def __str__(self):
53 return "InteractionNeededError"
54 55
56 -class ProgressQueue(QtCore.QObject):
57
58 - def __init__(self, progress_frame, progress_bar, progress_cancel_button):
59 QtCore.QObject.__init__(self) 60 self.__ignore_err_list = [] 61 self.__progress_queue = [] 62 self.__running = False 63 self._progress_frame = progress_frame 64 self._progress_bar = progress_bar 65 self._progress_cancel_button = progress_cancel_button 66 progress_frame.setVisible(False) 67 progress_cancel_button.clicked.connect(self._on_progress_canceled)
68
69 - def stop(self):
70 try: 71 val = self._progress_bar.value() 72 if val < len(self.__progress_queue): 73 print " Shutdown progress queue..." 74 thread = self.__progress_queue[val] 75 self.__progress_queue = [] 76 thread.join(3) 77 print " Progress queue is off!" 78 except: 79 pass
80 81
82 - def add2queue(self, id, descr, target=None, args=()):
83 pt = ProgressThread(id, descr, target, args) 84 pt.finished_signal.connect(self._progress_thread_finished) 85 pt.error_signal.connect(self._progress_thread_error) 86 pt.request_interact_signal.connect(self._on_request_interact) 87 self.__progress_queue.append(pt) 88 self._progress_bar.setMaximum(len(self.__progress_queue))
89
90 - def start(self):
91 if not self.__running and self.__progress_queue: 92 self._progress_frame.setVisible(True) 93 self.__running = True 94 self._progress_bar.setToolTip(self.__progress_queue[0].descr) 95 dscr_len = self._progress_bar.size().width()/10 96 self._progress_bar.setFormat(''.join(['%v/%m - ', self.__progress_queue[0].descr[0:dscr_len]])) 97 self._progress_bar.setValue(0) 98 self.__progress_queue[0].start()
99
100 - def count(self):
101 return len(self.__progress_queue)
102
103 - def has_id(self, id):
104 ''' 105 Searches the current and planed threads for given id and returns `True` if 106 one is found. 107 ''' 108 for th in self.__progress_queue: 109 if th.id() == id: 110 return True 111 return False
112
113 - def _progress_thread_finished(self, id):
114 try: 115 val = self._progress_bar.value() 116 # be on the safe side that the finished thread is the first thread in the queue (avoid calls from canceled threads) 117 if id == self.__progress_queue[val].id(): 118 val = val + 1 119 th = self.__progress_queue[val] 120 self._progress_bar.setToolTip(th.descr) 121 dscr_len = self._progress_bar.size().width()/10 122 self._progress_bar.setFormat(''.join(['%v/%m - ', th.descr[0:dscr_len]])) 123 self.__progress_queue[val].start() 124 self._progress_bar.setValue(val) 125 #'print "PG finished ok", id 126 except: 127 #'print "PG finished err", id 128 for thread in self.__progress_queue: 129 thread.join(1) 130 self._progress_frame.setVisible(False) 131 self.__running = False 132 #'print "PG finished delete all..." 133 self.__progress_queue = []
134 #'print "PG finished delete all ok" 135
136 - def _progress_thread_error(self, id, title, msg, detailed_msg):
137 if detailed_msg in self.__ignore_err_list: 138 self._progress_thread_finished(id) 139 return 140 btns = (QtGui.QMessageBox.Ignore) 141 if len(self.__progress_queue) > 1: 142 btns = (QtGui.QMessageBox.Ignore|QtGui.QMessageBox.Abort) 143 res = WarningMessageBox(QtGui.QMessageBox.Warning, title, msg, detailed_msg, 144 buttons=btns ).exec_() 145 if res == QtGui.QMessageBox.Abort: 146 self.__progress_queue = [] 147 self._progress_frame.setVisible(False) 148 self.__running = False 149 else: 150 if res == 1 or res == 0: # HACK: the number is returned, if "Don't show again" is pressed, instead 'QtGui.QMessageBox.HelpRole' (4) 151 self.__ignore_err_list.append(detailed_msg) 152 self._progress_thread_finished(id)
153
154 - def _on_progress_canceled(self):
155 try: 156 # self.__progress_queue[self._progress_bar.value()].wait() 157 if self.__progress_queue: 158 try: 159 self.__progress_queue[self._progress_bar.value()].finished_signal.disconnect(self._progress_thread_finished) 160 self.__progress_queue[self._progress_bar.value()].error_signal.disconnect(self._progress_thread_error) 161 self.__progress_queue[self._progress_bar.value()].request_interact_signal.disconnect(self._on_request_interact) 162 # self.__progress_queue[self._progress_bar.value()].terminate() 163 except: 164 # print str(self.__progress_queue[self._progress_bar.value()].getName()), 'could not be terminated' 165 pass 166 self.__progress_queue = [] 167 self._progress_frame.setVisible(False) 168 self.__running = False 169 except: 170 import traceback 171 print traceback.format_exc()
172
173 - def _on_request_interact(self, id, descr, req):
174 ''' 175 If the interaction of the user is needed a message dialog must be exceuted 176 in the main Qt thread. The requests are done by different request exceptinos. 177 These are handled by this method. 178 ''' 179 if isinstance(req.request, nm.AuthenticationRequest): 180 res, user, pw = nm.ssh()._requestPW(req.request.user, req.request.host) 181 if not res: 182 self._on_progress_canceled() 183 return 184 pt = ProgressThread(id, descr, req.method, (req.args+(user, pw))) 185 pt.finished_signal.connect(self._progress_thread_finished) 186 pt.error_signal.connect(self._progress_thread_error) 187 pt.request_interact_signal.connect(self._on_request_interact) 188 pt.start() 189 elif isinstance(req.request, nm.ScreenSelectionRequest): 190 from select_dialog import SelectDialog 191 items, ok = SelectDialog.getValue('Show screen', '', req.request.choices.keys(), False) 192 if not items: 193 self._progress_thread_finished(id) 194 return 195 res = [req.request.choices[i] for i in items] 196 pt = ProgressThread(id, descr, req.method, (req.args+(res,))) 197 pt.finished_signal.connect(self._progress_thread_finished) 198 pt.error_signal.connect(self._progress_thread_error) 199 pt.request_interact_signal.connect(self._on_request_interact) 200 pt.start() 201 elif isinstance(req.request, nm.BinarySelectionRequest): 202 from select_dialog import SelectDialog 203 items, ok = SelectDialog.getValue('Multiple executables', '', req.request.choices, True) 204 if not items: 205 self._progress_thread_finished(id) 206 return 207 res = items[0] 208 pt = ProgressThread(id, descr, req.method, (req.args+(res,))) 209 pt.finished_signal.connect(self._progress_thread_finished) 210 pt.error_signal.connect(self._progress_thread_error) 211 pt.request_interact_signal.connect(self._on_request_interact) 212 pt.start() 213 elif isinstance(req.request, nm.LaunchArgsSelectionRequest): 214 from parameter_dialog import ParameterDialog 215 inputDia = ParameterDialog(req.request.args_dict) 216 inputDia.setFilterVisible(False) 217 inputDia.setWindowTitle(''.join(['Enter the argv for ', req.request.launchfile])) 218 if inputDia.exec_(): 219 params = inputDia.getKeywords() 220 argv = [] 221 for p,v in params.items(): 222 if v: 223 argv.append(''.join([p, ':=', v])) 224 res = argv 225 pt = ProgressThread(id, descr, req.method, (req.args+(argv,))) 226 pt.finished_signal.connect(self._progress_thread_finished) 227 pt.error_signal.connect(self._progress_thread_error) 228 pt.request_interact_signal.connect(self._on_request_interact) 229 pt.start() 230 else: 231 self._progress_thread_finished(id) 232 return
233 234 235
236 -class ProgressThread(QtCore.QObject, threading.Thread):
237 ''' 238 A thread to execute a method in a thread. 239 ''' 240 finished_signal = QtCore.Signal(str) 241 ''' 242 @ivar: finished_signal is a signal, which is emitted, if the thread is finished. 243 ''' 244 245 error_signal = QtCore.Signal(str, str, str, str) 246 ''' 247 @ivar: error_signal is a signal (id, title, error message, detailed error message), which is emitted, 248 if an error while run of the thread was occurred. 249 ''' 250 251 request_interact_signal = QtCore.Signal(str, str, InteractionNeededError) 252
253 - def __init__(self, id, descr='', target=None, args=()):
254 QtCore.QObject.__init__(self) 255 threading.Thread.__init__(self) 256 self._id = id 257 self.descr = descr 258 self._target = target 259 self._args = args 260 self.setDaemon(True)
261
262 - def id(self):
263 return self._id
264
265 - def run(self):
266 ''' 267 ''' 268 try: 269 if not self._target is None: 270 #'print "PG call " 271 #'print " .. ", self._target 272 #print " -- args:", self._args 273 if 'pqid' in self._target.func_code.co_varnames: 274 self._target(*self._args, pqid=self._id) 275 else: 276 self._target(*self._args) 277 #print "PG call finished" 278 self.finished_signal.emit(self._id) 279 else: 280 self.error_signal.emit(self._id, 'No target specified') 281 except InteractionNeededError as e: 282 self.request_interact_signal.emit(self._id, self.descr, e) 283 except DetailedError as e: 284 self.error_signal.emit(self._id, e.title, e.value, e.detailed_text) 285 except: 286 import traceback 287 # print traceback.print_exc() 288 formatted_lines = traceback.format_exc().splitlines() 289 last_line = formatted_lines[-1] 290 index = 1 291 while not last_line and len(formatted_lines) > index: 292 index += 1 293 last_line = formatted_lines[-index] 294 rospy.logwarn("%s failed:\n\t%s", str(self.descr), last_line) 295 self.error_signal.emit(self._id, 'Progress Job Error', str(self.descr)+" failed:\n"+last_line, traceback.format_exc())
296