def closeEvent(self, event): ''' Test the open files for changes and save this if needed. ''' changed = [] # get the names of all changed files for i in range(self.tabWidget.count()): w = self.tabWidget.widget(i) if w.document().isModified(): changed.append(self.__getTabName(w.filename)) if changed: # ask the user for save changes if self.isHidden(): buttons = MessageBox.Yes | MessageBox.No else: buttons = MessageBox.Yes | MessageBox.No | MessageBox.Cancel result = MessageBox.question(self, "Unsaved Changes", '\n\n'.join(["Save the file before closing?", '\n'.join(changed)]), buttons=buttons) if result == MessageBox.Yes: for i in range(self.tabWidget.count()): w = self.tabWidget.widget(i).save() self.graph_view.clear_cache() event.accept() elif result == MessageBox.No: event.accept() elif rospy.is_shutdown(): event.ignore() else: event.accept() if event.isAccepted(): self.storeSetting() nm.nmd().file.changed_file.disconnect(self.on_changed_file) nm.nmd().file.packages_available.connect(self._on_new_packages) self.finished_signal.emit(self.init_filenames)
def on_close_tab(self, tab_index): ''' Signal handling to close single tabs. :param int tab_index: tab index to close ''' try: doremove = True w = self.tabWidget.widget(tab_index) if w.document().isModified(): name = self.__getTabName(w.filename) result = MessageBox.question(self, "Unsaved Changes", '\n\n'.join(["Save the file before closing?", name])) if result == MessageBox.Yes: self.tabWidget.currentWidget().save() elif result == MessageBox.No: pass elif rospy.is_shutdown(): doremove = False if doremove: # remove the indexed files if w.filename in self.files: self.files.remove(w.filename) # close tab self.tabWidget.removeTab(tab_index) # close editor, if no tabs are open if not self.tabWidget.count(): self.close() self._last_search_request = None except Exception: import traceback rospy.logwarn("Error while close tab %s: %s", str(tab_index), traceback.format_exc(1)) self.upperButton.setEnabled(self.tabWidget.count() > 1)
def kill_screens(cls, node, grpc_url, auto_ok_request=True, user=None, pw=None): ''' Searches for the screen associated with the given node and kill this screens. :param str node: the name of the node those screen output to kill :param str grpc_url: the url of node manager daemon where the screen is running ''' if node is None or len(node) == 0: return False try: # get the available screens screens = nm.nmd().screen.get_screens(grpc_url, node) if screens: do_kill = True if auto_ok_request: from fkie_node_manager.detailed_msg_box import MessageBox result = MessageBox.question( None, "Kill SCREENs?", '\n'.join(list(screens.keys())), buttons=MessageBox.Ok | MessageBox.Cancel) if result == MessageBox.Ok: do_kill = True if do_kill: host = get_hostname(grpc_url) for sname, _nname in screens.items(): pid, _, _ = sname.partition('.') if pid: try: nm.nmd().monitor.kill_process( int(pid), grpc_url) # nm.starter()._kill_wo(host, int(pid), auto_ok_request, user, pw) except Exception: import traceback rospy.logwarn( "Error while kill screen (PID: %s) on host '%s': %s", utf8(pid), utf8(host), traceback.format_exc(1)) nm.nmd().screen.wipe_screens(grpc_url) # if nm.is_local(host): # SupervisedPopen([screen.SCREEN, '-wipe'], object_id='screen -wipe', description="screen: clean up the socket with -wipe") # else: # nm.ssh().ssh_exec(host, [screen.SCREEN, '-wipe'], close_stdin=True, close_stdout=True, close_stderr=True) except nm.AuthenticationRequest as e: raise nm.InteractionNeededError( e, cls.kill_screens, { 'node': node, 'grpc_url': grpc_url, 'auto_ok_request': auto_ok_request, 'user': user, 'pw': pw })
def file_changed(self, mtime): if self.file_mtime != mtime: self.file_mtime = mtime result = MessageBox.question(self, "File changed", "File was changed, reload?", buttons=MessageBox.Yes | MessageBox.No) if result == MessageBox.Yes: try: _, self.file_mtime, file_content = nm.nmd().file.get_file_content(self.filename, force=True) self.setText(file_content) self.document().setModified(False) self.textChanged.emit() except Exception as err: MessageBox.critical(self, "Error", "Cannot open launch file %s" % self.filename, utf8(err))
def save(self, force=False): ''' Saves changes to the file. :return: saved, errors, msg :rtype: bool, bool, str ''' if self.isReadOnly(): return False, True, "Cannot save, the content was not loaded properly!" if force or self.document().isModified(): try: mtime = nm.nmd().file.save_file(self.filename, self.toPlainText().encode('utf-8'), 0 if force else self.file_mtime) self.file_mtime = mtime if mtime == 0: MessageBox.warning(self, "Warning", "File not saved and not error reported: %s" % os.path.basename(self.filename)) self.document().setModified(mtime == 0) ext = os.path.splitext(self.filename) # validate the xml structure of the launch files if ext[1] in self.CONTEXT_FILE_EXT: imported = False try: from lxml import etree imported = True parser = etree.XMLParser() etree.fromstring(self.toPlainText().encode('utf-8'), parser) except Exception as e: if imported: self.markLine(e.position[0]) return True, True, utf8(e) # validate the yaml structure of yaml files elif ext[1] in self.YAML_VALIDATION_FILES: try: import ruamel.yaml ruamel.yaml.load(self.toPlainText().encode('utf-8'), Loader=ruamel.yaml.Loader) except ruamel.yaml.MarkedYAMLError as e: return True, True, "YAML validation error: %s" % e return True, False, '' except IOError as ioe: if ioe.errno in [file_item.EFILE_CHANGED, file_item.EFILE_REMOVED]: result = MessageBox.question(self, "Changed file", "%s\n%s" % (utf8(ioe), "Save anyway?"), buttons=MessageBox.Yes | MessageBox.No) if result == MessageBox.Yes: return self.save(force=True) else: return False, True, utf8(ioe) except Exception as e: print(traceback.format_exc()) return False, True, utf8(e) return False, False, ''
def mouseReleaseEvent(self, event): ''' Opens the new editor, if the user clicked on the included file and sets the default cursor. ''' if self.isReadOnly(): event.accept() return if event.modifiers() == Qt.ControlModifier or event.modifiers( ) == Qt.ShiftModifier: cursor = self.cursorForPosition(event.pos()) try: textblock = self._strip_bad_parts(cursor.block().text(), cursor.positionInBlock()) for inc_file in find_included_files(textblock, False, False, search_in_ext=[]): aval = inc_file.raw_inc_path aitems = aval.split("'") for search_for in aitems: if not search_for: continue try: rospy.logdebug("try to interpret: %s" % search_for) args_in_name = get_arg_names(search_for) resolved_args = {} # if found arg in the name, try to detect values if args_in_name: rospy.logdebug( " args %s in filename found, try to resolve..." % args_in_name) resolved_args = self.parent.graph_view.get_include_args( args_in_name, search_for, self.filename) if resolved_args: params = {} self._internal_args # create parameter dialog for key, val in resolved_args.items(): values = list(val) # add args defined in current file if key in self._internal_args and self._internal_args[ key] not in values: values.append(self._internal_args[key]) params[key] = { ':type': 'string', ':value': values } dia = ParameterDialog( params, store_geometry="open_launch_on_click") dia.setFilterVisible(False) dia.setWindowTitle('Select Parameter') if dia.exec_(): params = dia.getKeywords() search_for = replace_arg( search_for, params) else: # canceled -> cancel interpretation QTextEdit.mouseReleaseEvent(self, event) return # now resolve find-statements rospy.logdebug( " send interpret request to daemon: %s" % search_for) inc_files = nm.nmd().launch.get_interpreted_path( self.filename, text=[search_for]) for path, exists in inc_files: try: rospy.logdebug( " received interpret request from daemon: %s, exists: %d" % (path, exists)) if exists: event.setAccepted(True) self.load_request_signal.emit(path) else: _filename, file_extension = os.path.splitext( path) if file_extension in nm.settings( ).launch_view_file_ext: # create a new file, if it does not exists result = MessageBox.question( self, "File not exists", '\n\n'.join([ "Create a new file?", path ]), buttons=MessageBox.Yes | MessageBox.No) if result == MessageBox.Yes: content = '<launch>\n\n</launch>' if path.endswith( '.launch') else '' nm.nmd().file.save_file( path, content.encode(), 0) event.setAccepted(True) self.load_request_signal.emit( path) except Exception as e: MessageBox.critical(self, "Error", "File not found %s" % path, detailed_text=utf8(e)) except exceptions.ResourceNotFound as not_found: MessageBox.critical( self, "Error", "Resource not found %s" % search_for, detailed_text=utf8(not_found.error)) except Exception as err: print(traceback.format_exc()) MessageBox.critical(self, "Error", "Error while request included file %s" % self.filename, detailed_text=utf8(err)) QTextEdit.mouseReleaseEvent(self, event)