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

Source Code for Module node_manager_fkie.sync_dialog

  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  from python_qt_binding import QtGui 
 34  from python_qt_binding import QtCore 
 35   
 36  import os 
 37  import threading 
 38   
 39  import node_manager_fkie as nm 
 40  from common import is_package 
 41  from detailed_msg_box import WarningMessageBox 
 42  from xml_editor import Editor 
43 44 -class SyncHighlighter(QtGui.QSyntaxHighlighter):
45 ''' 46 Enabled the syntax highlightning for the sync interface. 47 ''' 48
49 - def __init__(self, parent=None):
50 QtGui.QSyntaxHighlighter.__init__(self, parent) 51 self.rules = [] 52 self.commentStart = QtCore.QRegExp("#") 53 self.commentEnd = QtCore.QRegExp("\n") 54 self.commentFormat = QtGui.QTextCharFormat() 55 self.commentFormat.setFontItalic(True) 56 self.commentFormat.setForeground(QtCore.Qt.darkGray) 57 f = QtGui.QTextCharFormat() 58 r = QtCore.QRegExp() 59 r.setMinimal(True) 60 f.setFontWeight(QtGui.QFont.Normal) 61 f.setForeground (QtCore.Qt.darkBlue) 62 tagList = ["\\bignore_hosts\\b", "\\bsync_hosts\\b", 63 "\\bignore_nodes\\b", "\\bsync_nodes\\b", 64 "\\bignore_topics\\b", "\\bsync_topics\\b", 65 "\\bignore_services\\b", "\\bsync_services\\b", 66 "\\bsync_topics_on_demand\\b", "\\bsync_remote_nodes\\b"] 67 for tag in tagList: 68 r.setPattern(tag) 69 self.rules.append((QtCore.QRegExp(r), QtGui.QTextCharFormat(f))) 70 71 f.setForeground(QtCore.Qt.darkGreen) 72 f.setFontWeight(QtGui.QFont.Bold) 73 attrList = ["\\b\\*|\\*\\B|\\/\\*"] 74 for attr in attrList: 75 r.setPattern(attr) 76 self.rules.append((QtCore.QRegExp(r), QtGui.QTextCharFormat(f)))
77 78 # f.setForeground(QtCore.Qt.red) 79 # f.setFontWeight(QtGui.QFont.Bold) 80 # attrList = ["\\s\\*"] 81 # for attr in attrList: 82 # r.setPattern(attr) 83 # self.rules.append((QtCore.QRegExp(r), QtGui.QTextCharFormat(f))) 84 85
86 - def highlightBlock(self, text):
87 for pattern, format in self.rules: 88 index = pattern.indexIn(text) 89 while index >= 0: 90 length = pattern.matchedLength() 91 self.setFormat(index, length, format) 92 index = pattern.indexIn(text, index + length) 93 94 self.setCurrentBlockState(0) 95 startIndex = 0 96 if self.previousBlockState() != 1: 97 startIndex = self.commentStart.indexIn(text) 98 if startIndex >= 0: 99 commentLength = len(text) - startIndex 100 self.setFormat(startIndex, commentLength, self.commentFormat)
101
102 103 -class SyncDialog(QtGui.QDialog):
104 ''' 105 A dialog to set the sync options. 106 ''' 107
108 - def __init__(self, parent=None):
109 QtGui.QDialog.__init__(self, parent) 110 # self.host = host 111 self.setWindowTitle('Sync') 112 self.verticalLayout = QtGui.QVBoxLayout(self) 113 self.verticalLayout.setObjectName("verticalLayout") 114 self.resize(350,190) 115 116 self.toolButton_SyncAll = QtGui.QToolButton(self) 117 sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) 118 sizePolicy.setHorizontalStretch(0) 119 sizePolicy.setVerticalStretch(2) 120 sizePolicy.setHeightForWidth(self.toolButton_SyncAll.sizePolicy().hasHeightForWidth()) 121 self.toolButton_SyncAll.setSizePolicy(sizePolicy) 122 self.toolButton_SyncAll.setObjectName("toolButton_SyncAll") 123 self.verticalLayout.addWidget(self.toolButton_SyncAll) 124 self.toolButton_SyncAll.setText(QtGui.QApplication.translate("Form", "Sync All", None, QtGui.QApplication.UnicodeUTF8)) 125 self.toolButton_SyncAll.clicked.connect(self._on_sync_all_clicked) 126 127 self.toolButton_SyncAllAnyMsg = QtGui.QToolButton(self) 128 sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) 129 sizePolicy.setHorizontalStretch(0) 130 sizePolicy.setVerticalStretch(1) 131 sizePolicy.setHeightForWidth(self.toolButton_SyncAllAnyMsg.sizePolicy().hasHeightForWidth()) 132 self.toolButton_SyncAllAnyMsg.setSizePolicy(sizePolicy) 133 self.toolButton_SyncAllAnyMsg.setObjectName("toolButton_SyncAllAnyMsg") 134 self.verticalLayout.addWidget(self.toolButton_SyncAllAnyMsg) 135 self.toolButton_SyncAllAnyMsg.setText(QtGui.QApplication.translate("Form", "Sync all (+AnyMsg)", None, QtGui.QApplication.UnicodeUTF8)) 136 self.toolButton_SyncAllAnyMsg.clicked.connect(self._on_sync_all_anymsg_clicked) 137 138 self.toolButton_SyncTopicOnDemand = QtGui.QToolButton(self) 139 sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) 140 sizePolicy.setHorizontalStretch(0) 141 sizePolicy.setVerticalStretch(1) 142 sizePolicy.setHeightForWidth(self.toolButton_SyncTopicOnDemand.sizePolicy().hasHeightForWidth()) 143 self.toolButton_SyncTopicOnDemand.setSizePolicy(sizePolicy) 144 self.toolButton_SyncTopicOnDemand.setObjectName("toolButton_SyncTopicOnDemand") 145 self.verticalLayout.addWidget(self.toolButton_SyncTopicOnDemand) 146 self.toolButton_SyncTopicOnDemand.setText(QtGui.QApplication.translate("Form", "Sync only topics on demand", None, QtGui.QApplication.UnicodeUTF8)) 147 self.toolButton_SyncTopicOnDemand.clicked.connect(self._on_sync_topics_on_demand_clicked) 148 149 self.toolButton_SelectInterface = QtGui.QToolButton(self) 150 sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) 151 sizePolicy.setHorizontalStretch(0) 152 sizePolicy.setVerticalStretch(1) 153 sizePolicy.setHeightForWidth(self.toolButton_SelectInterface.sizePolicy().hasHeightForWidth()) 154 self.toolButton_SelectInterface.setSizePolicy(sizePolicy) 155 self.toolButton_SelectInterface.setObjectName("toolButton_SelectInterface") 156 self.verticalLayout.addWidget(self.toolButton_SelectInterface) 157 self.toolButton_SelectInterface.setText(QtGui.QApplication.translate("Form", "Select an interface", None, QtGui.QApplication.UnicodeUTF8)) 158 self.toolButton_SelectInterface.clicked.connect(self._on_select_interface_clicked) 159 160 self.interface_field = QtGui.QComboBox(self) 161 self.interface_field.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically) 162 self.interface_field.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)) 163 self.interface_field.setEditable(True) 164 self.interface_field.setVisible(False) 165 self.interface_field.setObjectName("interface_field") 166 self.verticalLayout.addWidget(self.interface_field) 167 self.interface_field.currentIndexChanged[str].connect(self._on_interface_selected) 168 169 self.toolButton_EditInterface = QtGui.QToolButton(self) 170 sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) 171 sizePolicy.setHorizontalStretch(0) 172 sizePolicy.setVerticalStretch(1) 173 sizePolicy.setHeightForWidth(self.toolButton_EditInterface.sizePolicy().hasHeightForWidth()) 174 self.toolButton_EditInterface.setSizePolicy(sizePolicy) 175 self.toolButton_EditInterface.setObjectName("toolButton_EditInterface") 176 self.verticalLayout.addWidget(self.toolButton_EditInterface) 177 self.toolButton_EditInterface.setText(QtGui.QApplication.translate("Form", "Edit selected interface", None, QtGui.QApplication.UnicodeUTF8)) 178 self.toolButton_EditInterface.clicked.connect(self._on_edit_interface_clicked) 179 self.toolButton_EditInterface.setVisible(False) 180 181 self.toolButton_CreateInterface = QtGui.QToolButton(self) 182 sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) 183 sizePolicy.setHorizontalStretch(0) 184 sizePolicy.setVerticalStretch(1) 185 sizePolicy.setHeightForWidth(self.toolButton_CreateInterface.sizePolicy().hasHeightForWidth()) 186 self.toolButton_CreateInterface.setSizePolicy(sizePolicy) 187 self.toolButton_CreateInterface.setObjectName("toolButton_CreateInterface") 188 self.verticalLayout.addWidget(self.toolButton_CreateInterface) 189 self.toolButton_CreateInterface.setText(QtGui.QApplication.translate("Form", "Create an interface", None, QtGui.QApplication.UnicodeUTF8)) 190 self.toolButton_CreateInterface.clicked.connect(self._on_create_interface_clicked) 191 self.toolButton_CreateInterface.setVisible(False) 192 193 self.textedit = Editor('', self) 194 hl = SyncHighlighter(self.textedit.document()) 195 sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) 196 self.textedit.setSizePolicy(sizePolicy) 197 self.textedit.setObjectName("syncedit") 198 self.verticalLayout.addWidget(self.textedit) 199 self.textedit.setVisible(False) 200 201 202 self._fill_interface_thread = None 203 self._interfaces_files = None 204 self._sync_args = [] 205 self._interface_filename = None 206 207 self.buttonBox = QtGui.QDialogButtonBox(self) 208 self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel) 209 self.buttonBox.setOrientation(QtCore.Qt.Horizontal) 210 self.buttonBox.setObjectName("buttonBox") 211 self.verticalLayout.addWidget(self.buttonBox) 212 QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), self.accept) 213 QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), self.reject) 214 215 self._new_iface = True
216 217 @property
218 - def sync_args(self):
219 return self._sync_args
220 221 @property
222 - def interface_filename(self):
223 return self._interface_filename
224 225
226 - def _on_sync_all_clicked(self):
227 self.setResult(QtGui.QDialog.Accepted) 228 self._sync_args = [] 229 self._sync_args.append(''.join(['_interface_url:=', "'.'"])) 230 self._sync_args.append(''.join(['_sync_topics_on_demand:=', 'False'])) 231 self._sync_args.append(''.join(['_ignore_hosts:=', '[]'])) 232 self._sync_args.append(''.join(['_sync_hosts:=', '[]'])) 233 self._sync_args.append(''.join(['_ignore_nodes:=', '[]'])) 234 self._sync_args.append(''.join(['_sync_nodes:=', '[]'])) 235 self._sync_args.append(''.join(['_ignore_topics:=', '[]'])) 236 self._sync_args.append(''.join(['_sync_topics:=', '[]'])) 237 self._sync_args.append(''.join(['_ignore_services:=', '[]'])) 238 self._sync_args.append(''.join(['_sync_services:=', '[]'])) 239 self._sync_args.append(''.join(['_sync_remote_nodes:=', 'False'])) 240 self._interface_filename = None 241 self.accept()
242
244 self._sync_args = [] 245 self._sync_args.append(''.join(['_interface_url:=', "'.'"])) 246 self._sync_args.append(''.join(['_sync_topics_on_demand:=', 'True'])) 247 self._sync_args.append(''.join(['_ignore_hosts:=', '[]'])) 248 self._sync_args.append(''.join(['_sync_hosts:=', '[]'])) 249 self._sync_args.append(''.join(['_ignore_nodes:=', '[]'])) 250 self._sync_args.append(''.join(['_sync_nodes:=', '[]'])) 251 self._sync_args.append(''.join(['_ignore_topics:=', '[]'])) 252 self._sync_args.append(''.join(['_sync_topics:=', '[/*]'])) 253 self._sync_args.append(''.join(['_ignore_services:=', '[]'])) 254 self._sync_args.append(''.join(['_sync_services:=', '[]'])) 255 self._sync_args.append(''.join(['_sync_remote_nodes:=', 'False'])) 256 self._interface_filename = None 257 self.accept()
258
260 self._sync_args = [] 261 self._sync_args.append(''.join(['_interface_url:=', "'.'"])) 262 self._sync_args.append(''.join(['_sync_topics_on_demand:=', 'True'])) 263 self._sync_args.append(''.join(['_ignore_hosts:=', '[]'])) 264 self._sync_args.append(''.join(['_sync_hosts:=', '[]'])) 265 self._sync_args.append(''.join(['_ignore_nodes:=', '[]'])) 266 self._sync_args.append(''.join(['_sync_nodes:=', '[]'])) 267 self._sync_args.append(''.join(['_ignore_topics:=', '[]'])) 268 self._sync_args.append(''.join(['_sync_topics:=', '[/only_on_demand]'])) 269 self._sync_args.append(''.join(['_ignore_services:=', '[/*]'])) 270 self._sync_args.append(''.join(['_sync_services:=', '[]'])) 271 self._sync_args.append(''.join(['_sync_remote_nodes:=', 'False'])) 272 self._interface_filename = None 273 self.accept()
274
276 self.toolButton_SyncAll.setVisible(False) 277 self.toolButton_SyncAllAnyMsg.setVisible(False) 278 self.toolButton_SyncTopicOnDemand.setVisible(False) 279 self.toolButton_SelectInterface.setVisible(False) 280 self.interface_field.setVisible(True) 281 self.toolButton_CreateInterface.setVisible(True) 282 self.toolButton_EditInterface.setVisible(True) 283 self.toolButton_EditInterface.setEnabled(False) 284 self.textedit.setVisible(False) 285 # # fill the interfaces 286 if self._interfaces_files is None: 287 self.interface_field.addItems(['interface searching...']) 288 self.interface_field.setCurrentIndex(0) 289 self._fill_interface_thread = threading.Thread(target=self._fill_interfaces) 290 self._fill_interface_thread.start() 291 else: 292 self.toolButton_EditInterface.setEnabled(self._interfaces_files.has_key(self.interface_field.currentText())) 293 self.buttonBox.clear() 294 self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok|QtGui.QDialogButtonBox.Cancel) 295 self.interface_field.setFocus(QtCore.Qt.TabFocusReason) 296 self.resize(350,80)
297
298 - def _fill_interfaces(self):
299 if self._interfaces_files is None: 300 self.root_paths = [os.path.normpath(p) for p in os.getenv("ROS_PACKAGE_PATH").split(':')] 301 self._interfaces_files = {} 302 for p in self.root_paths: 303 ret = self._getInterfaces(p) 304 self._interfaces_files = dict(ret.items() + self._interfaces_files.items()) 305 self.interface_field.clear() 306 self.interface_field.clearEditText() 307 self.interface_field.addItems(self._interfaces_files.keys())
308
309 - def _on_interface_selected(self, interface):
310 if self._interfaces_files and self._interfaces_files.has_key(interface): 311 self._sync_args = [] 312 self._sync_args.append(''.join(['_interface_url:=', interface])) 313 self.toolButton_EditInterface.setEnabled(True) 314 else: 315 self.toolButton_EditInterface.setEnabled(False)
316
317 - def accept(self):
318 if self.textedit.isVisible(): 319 try: 320 tmp_file = os.path.join(nm.screen().LOG_PATH, 'tmp_sync_interface.sync') 321 with open(tmp_file, 'w+') as f: 322 iface = f.write(self.textedit.toPlainText()) 323 from master_discovery_fkie.common import read_interface 324 read_interface(tmp_file) 325 if not self._new_iface and self._interfaces_files.has_key(self.interface_field.currentText()): 326 fileName = self._interfaces_files[self.interface_field.currentText()] 327 else: 328 fileName, selectedFilter = QtGui.QFileDialog.getSaveFileName(self, 'Save sync interface', '/home', "Sync Files (*.sync)") 329 if fileName: 330 with open(fileName, 'w+') as f: 331 self._interface_filename = fileName 332 iface = f.write(self.textedit.toPlainText()) 333 if self._new_iface: 334 self.interface_field.clear() 335 self._interfaces_files = None 336 self._on_select_interface_clicked() 337 # QtGui.QDialog.accept(self) 338 # self.resetView() 339 except Exception as e: 340 WarningMessageBox(QtGui.QMessageBox.Warning, "Create sync interface", 341 "Error while create interface", 342 str(e)).exec_() 343 elif self.interface_field.isVisible(): 344 interface = self.interface_field.currentText() 345 if self._interfaces_files and self._interfaces_files.has_key(interface): 346 self._interface_filename = self._interfaces_files[interface] 347 self._sync_args = [] 348 self._sync_args.append(''.join(['_interface_url:=', interface])) 349 QtGui.QDialog.accept(self) 350 self.resetView() 351 else: 352 QtGui.QDialog.accept(self) 353 self.resetView()
354 355
356 - def reject(self):
357 if self.textedit.isVisible(): 358 self._on_select_interface_clicked() 359 else: 360 QtGui.QDialog.reject(self) 361 self.resetView()
362
364 self._new_iface = True 365 self.interface_field.setVisible(False) 366 self.toolButton_CreateInterface.setVisible(False) 367 self.toolButton_EditInterface.setVisible(False) 368 self.textedit.setVisible(True) 369 self.textedit.setText("# The ignore_* lists will be processed first.\n" 370 "# For ignore/sync nodes, topics or services\n" 371 "# use follow declaration:\n" 372 "#{param name}: \n" 373 "# - {ros name}\n" 374 "# or for selected hosts:\n" 375 "# - {host name}:\n" 376 "# - {ros name}\n\n" 377 "# you can use follow wildcard: '*', but not as a first character\n" 378 "ignore_hosts:\n" 379 "sync_hosts:\n\n" 380 "ignore_nodes:\n" 381 "sync_nodes:\n\n" 382 "ignore_topics:\n" 383 "sync_topics:\n\n" 384 "ignore_services:\n" 385 " - /*get_loggers\n" 386 " - /*set_logger_level\n" 387 "sync_services:\n\n" 388 "# If sync_topics_on_demand is True the local subscribed and published topics\n" 389 "# are synchronized with remote even if they are not in the sync_* list.\n" 390 "sync_topics_on_demand: False\n\n" 391 "# The nodes which are running not at the same host as the ROS master are not\n" 392 "# synchronized by default. Use sync_remote_nodes to sync these nodes also.\n" 393 "sync_remote_nodes: False\n\n" 394 ) 395 self.resize(350,300)
396
398 self._new_iface = False 399 self.interface_field.setVisible(False) 400 self.toolButton_CreateInterface.setVisible(False) 401 self.toolButton_EditInterface.setVisible(False) 402 self.textedit.setVisible(True) 403 if self._interfaces_files.has_key(self.interface_field.currentText()): 404 try: 405 with open(self._interfaces_files[self.interface_field.currentText()], 'rw') as f: 406 iface = f.read() 407 self.textedit.setText(iface) 408 except Exception as e: 409 WarningMessageBox(QtGui.QMessageBox.Warning, "Edit sync interface", 410 "Error while open interface", 411 str(e)).exec_() 412 self.resize(350,300)
413
414 - def resetView(self):
415 self.toolButton_SyncAll.setVisible(True) 416 self.toolButton_SyncAllAnyMsg.setVisible(True) 417 self.toolButton_SyncTopicOnDemand.setVisible(True) 418 self.toolButton_SelectInterface.setVisible(True) 419 self.interface_field.setVisible(False) 420 self.toolButton_CreateInterface.setVisible(False) 421 self.toolButton_EditInterface.setVisible(False) 422 self.textedit.setVisible(False) 423 self.buttonBox.clear() 424 self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel) 425 self.resize(350,160)
426
427 - def _getInterfaces(self, path, package=None):
428 result = {} 429 if os.path.isdir(path): 430 fileList = os.listdir(path) 431 # set package, if it is currently None and one found 432 if not package: 433 # detect package 434 if is_package(fileList): 435 package = os.path.basename(path) 436 for f in fileList: 437 ret = self._getInterfaces(os.path.join(path, f), package) 438 result = dict(ret.items() + result.items()) 439 elif package and os.path.isfile(path) and path.endswith('.sync'): 440 # create a selection for binaries 441 return {''.join(['pkg://', package, '///', os.path.basename(path)]) : path} 442 return result
443