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

Source Code for Module node_manager_fkie.topic_list_model

  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 re 
 34  import rospy 
 35  from python_qt_binding.QtCore import Qt 
 36  from python_qt_binding.QtGui import QIcon, QStandardItem, QStandardItemModel 
 37   
 38  from detailed_msg_box import MessageBox 
 39  from master_discovery_fkie.master_info import TopicInfo 
 40   
 41  from node_manager_fkie.common import lnamespace, namespace, normns, utf8 
 42  import node_manager_fkie as nm 
43 44 45 -class TopicItem(QStandardItem):
46 ''' 47 The topic item stored in the topic model. This class stores the topic as 48 U{master_discovery_fkie.TopicInfo<http://docs.ros.org/kinetic/api/master_discovery_fkie/html/modules.html#master_discovery_fkie.master_info.TopicInfo>}. 49 The name of the topic represented in HTML. 50 ''' 51 52 ITEM_TYPE = QStandardItem.UserType + 36 53 NAME_ROLE = Qt.UserRole + 1 54 NODENAMES_ROLE = Qt.UserRole + 2 55 COL_PUB = 1 56 COL_SUB = 2 57 COL_TYPE = 3 58
59 - def __init__(self, name, topic=None, parent=None):
60 ''' 61 Initialize the topic item. 62 :param str name: the topic name 63 :param topic: the topic info 64 :type topic: U{master_discovery_fkie.TopicInfo<http://docs.ros.org/kinetic/api/master_discovery_fkie/html/modules.html#master_discovery_fkie.master_info.TopicInfo>} 65 ''' 66 QStandardItem.__init__(self, name) 67 self._parent_item = parent 68 self._publish_thread = None 69 self.topic = TopicInfo(name) if topic is None else topic 70 '''@ivar: topic as U{master_discovery_fkie.TopicInfo<http://docs.ros.org/kinetic/api/master_discovery_fkie/html/modules.html#master_discovery_fkie.master_info.TopicInfo>}.''' 71 self._with_namespace = rospy.names.SEP in name
72 73 # def __del__(self): 74 # print "delete TOPIC", self.__topic.name 75 76 @property
77 - def name(self):
78 return self.text()
79 80 @name.setter
81 - def name(self, new_name):
82 self.setText(new_name)
83 84 @property
85 - def topic_type_str(self):
86 return self.topic.type
87 88 @property
89 - def parent_item(self):
90 return self._parent_item
91 92 @parent_item.setter
93 - def parent_item(self, parent_item):
94 self._parent_item = parent_item 95 if parent_item is None: 96 self.setText(self.text()) 97 self._with_namespace = rospy.names.SEP in self.text() 98 else: 99 new_name = self.text().replace(parent_item.get_namespace(), '', 1) 100 self.setText(new_name) 101 self._with_namespace = rospy.names.SEP in new_name
102 103 @property
104 - def with_namespace(self):
105 ''' 106 Returns `True` if the topic name contains a '/' in his name 107 108 :rtype: bool 109 ''' 110 return self._with_namespace
111
112 - def update_view(self, topic_info=None):
113 ''' 114 Updates the view 115 ''' 116 if topic_info is not None: 117 self.topic = topic_info 118 self.updatePublisherView() 119 self.updateSubscriberView() 120 self.updateTypeView()
121
122 - def updatePublisherView(self):
123 ''' 124 Updates the representation of the column contains the publisher state. 125 ''' 126 if self.parent_item is not None: 127 cfg_col = self.parent_item.child(self.row(), TopicItem.COL_PUB) 128 if cfg_col is not None and isinstance(cfg_col, QStandardItem): 129 cfg_col.setText(str(len(self.topic.publisherNodes))) 130 tooltip = ''.join(['<h4>', 'Publisher [', self.topic.name, ']:</h4><dl>']) 131 for p in self.topic.publisherNodes: 132 tooltip = ''.join([tooltip, '<dt>', p, '</dt>']) 133 tooltip = ''.join([tooltip, '</dl>']) 134 if len(self.topic.publisherNodes) > 0: 135 cfg_col.setToolTip(''.join(['<div>', tooltip, '</div>']))
136
137 - def updateSubscriberView(self):
138 ''' 139 Updates the representation of the column contains the subscriber state. 140 ''' 141 if self.parent_item is not None: 142 cfg_col = self.parent_item.child(self.row(), TopicItem.COL_SUB) 143 if cfg_col is not None and isinstance(cfg_col, QStandardItem): 144 cfg_col.setText(str(len(self.topic.subscriberNodes))) 145 tooltip = ''.join(['<h4>', 'Subscriber [', self.topic.name, ']:</h4><dl>']) 146 for p in self.topic.subscriberNodes: 147 tooltip = ''.join([tooltip, '<dt>', p, '</dt>']) 148 tooltip = ''.join([tooltip, '</dl>']) 149 if len(self.topic.subscriberNodes) > 0: 150 cfg_col.setToolTip(''.join(['<div>', tooltip, '</div>']))
151
152 - def updateTypeView(self):
153 ''' 154 Updates the representation of the column contains the type of the topic. 155 ''' 156 if self.parent_item is not None: 157 cfg_col = self.parent_item.child(self.row(), TopicItem.COL_TYPE) 158 if cfg_col is not None and isinstance(cfg_col, QStandardItem): 159 cfg_col.setText(self.topic.type if self.topic.type and self.topic.type != 'None' else 'unknown type')
160 # removed tooltip for clarity!!! 161 # if not self.topic.type is None and not cfg_col.toolTip(): 162 # return 163 # # removed tooltip for clarity !!! 164 # # tooltip = '' 165 # try: 166 # mclass = roslib.message.get_message_class(self.topic.type) 167 # # tooltip = utf8(mclass) 168 # if not mclass is None: 169 # # tooltip = utf8(mclass.__slots__) 170 # for f in mclass.__slots__: 171 # idx = mclass.__slots__.index(f) 172 # idtype = mclass._slot_types[idx] 173 # base_type = roslib.msgs.base_msg_type(idtype) 174 # primitive = "unknown" 175 # if base_type in roslib.msgs.PRIMITIVE_TYPES: 176 # primitive = "primitive" 177 # else: 178 # try: 179 # list_msg_class = roslib.message.get_message_class(base_type) 180 # primitive = "class", list_msg_class.__slots__ 181 # except ValueError: 182 # pass 183 # # tooltip = ''.join([tooltip, '\n\t', utf8(f), ': ', utf8(idtype), ' (', utf8(primitive),')']) 184 # except ValueError: 185 # pass 186 # cfg_col.setToolTip(tooltip) 187
188 - def _on_wait_for_publishing(self):
189 self.updateIconView(QIcon(':/icons/state_off.png'))
190
191 - def _on_partial_publishing(self):
192 self.updateIconView(QIcon(':/icons/state_part.png'))
193
194 - def _on_publishing(self):
195 self.updateIconView(QIcon(':/icons/state_run.png'))
196
197 - def _publish_finished(self):
198 self._publish_thread = None 199 self.setIcon(QIcon())
200
201 - def show_error_msg(self, msg):
202 MessageBox.warning(self, "Publish error", 203 'Error while publish to %s' % self.topic.name, 204 tr(utf8(msg)))
205
206 - def type(self):
207 return TopicItem.ITEM_TYPE
208
209 - def data(self, role):
210 if role == self.NAME_ROLE: 211 return self.topic.name 212 elif role == self.NODENAMES_ROLE: 213 return utf8(self.topic.publisherNodes) + utf8(self.topic.subscriberNodes) 214 else: 215 return QStandardItem.data(self, role)
216 217 @classmethod
218 - def create_item_list(self, topic, root):
219 ''' 220 Creates the list of the items from topic. This list is used for the 221 visualization of topic data as a table row. 222 :param str topic: the topic name 223 :param root: The parent QStandardItem 224 :type root: U{QStandardItem<https://srinikom.github.io/pyside-docs/PySide/QtGui/QStandardItem.html>} 225 :return: the list for the representation as a row 226 :rtype: C{[L{TopicItem} or U{QStandardItem<https://srinikom.github.io/pyside-docs/PySide/QtGui/QStandardItem.html>}, ...]} 227 ''' 228 items = [] 229 item = TopicItem(topic.name, topic, parent=root) 230 items.append(item) 231 pubItem = QStandardItem() 232 # TopicItem.updatePublisherView(topic, pubItem) 233 items.append(pubItem) 234 subItem = QStandardItem() 235 # TopicItem.updateSubscriberView(topic, subItem) 236 items.append(subItem) 237 typeItem = QStandardItem() 238 # TopicItem.updateTypeView(topic, typeItem) 239 items.append(typeItem) 240 return items
241
242 - def __eq__(self, item):
243 ''' 244 Compares the name of topic. 245 ''' 246 if isinstance(item, str) or isinstance(item, unicode): 247 return self.topic.name.lower() == item.lower() 248 elif not (item is None): 249 return self.topic.name.lower() == item.topic.name.lower() 250 return False
251 #
252 # def __gt__(self, item): 253 # ''' 254 # Compares the name of topic. 255 # ''' 256 # if isinstance(item, str) or isinstance(item, unicode): 257 # return self.topic.name.lower() > item.lower() 258 # elif not (item is None): 259 # return self.topic.name.lower() > item.topic.name.lower() 260 # return False 261 262 263 # ############################################################################### 264 # ############# GrouptItem ############## 265 # ############################################################################### 266 -class TopicGroupItem(QStandardItem):
267 ''' 268 The TopicGroupItem stores the information about a group of nodes. 269 ''' 270 ITEM_TYPE = Qt.UserRole + 35 271
272 - def __init__(self, name, parent=None, is_group=False):
273 ''' 274 Initialize the TopicGroupItem object with given values. 275 276 :param str name: the name of the group 277 :param parent: the parent item. In most cases this is the HostItem. The variable is used to determine the different columns of the NodeItem. 278 :type parent: :class:`QtGui.QStandardItem` <https://srinikom.github.io/pyside-docs/PySide/QtGui/QStandardItem.html> 279 :param bool is_group: True if this is a capability group. In other case it is a namespace group. 280 ''' 281 dname = name 282 if is_group: 283 dname = '{%s}' % name 284 elif name != rospy.names.SEP: 285 dname = '%s/' % name 286 else: 287 dname = 'topics@master/' 288 QStandardItem.__init__(self, dname) 289 self.parent_item = parent 290 self._name = name 291 self._is_group = is_group 292 self.is_system_group = name == 'SYSTEM'
293 294 @property
295 - def name(self):
296 ''' 297 The name of this group. 298 299 :rtype: str 300 ''' 301 return self._name
302 303 @name.setter
304 - def name(self, new_name):
305 ''' 306 Set the new name of this group and updates the displayed name of the item. 307 308 :param str new_name: The new name of the group. Used also to identify the group. 309 ''' 310 self._name = new_name 311 if self._is_group: 312 self.setText('{' + self._name + '}') 313 else: 314 self.setText(self._name + '/')
315 316 @property
317 - def is_group(self):
318 return self._is_group
319
320 - def get_namespace(self):
321 name = self._name 322 if type(self) == TopicGroupItem and self._is_group: 323 name = namespace(self._name) 324 result = name 325 if self.parent_item is not None and type(self.parent_item) != QStandardItem: 326 result = normns(self.parent_item.get_namespace() + rospy.names.SEP) + normns(result + rospy.names.SEP) 327 return normns(result)
328
329 - def count_topics(self):
330 ''' 331 :retrun: Returns count of nodes inside this group. 332 :rtype: int 333 ''' 334 result = 0 335 for i in range(self.rowCount()): 336 item = self.child(i) 337 if isinstance(item, TopicGroupItem): 338 result += item.count_nodes() 339 elif isinstance(item, TopicItem): 340 result += 1 341 return result
342
343 - def get_topic_items_by_name(self, topic_name, recursive=True):
344 ''' 345 Since the same node can be included by different groups, this method searches 346 for all nodes with given name and returns these items. 347 348 :param str topic_name: The name of the topic 349 :param bool recursive: Searches in (sub) groups 350 :return: The list with node items. 351 :rtype: list(:class:`QtGui.QStandardItem` <https://srinikom.github.io/pyside-docs/PySide/QtGui/QStandardItem.html>) 352 ''' 353 result = [] 354 for i in range(self.rowCount()): 355 item = self.child(i) 356 if isinstance(item, TopicGroupItem): 357 if recursive: 358 result[len(result):] = item.get_topic_items_by_name(topic_name) 359 elif isinstance(item, TopicItem) and item == topic_name: 360 return [item] 361 return result
362
363 - def get_topic_items(self, recursive=True):
364 ''' 365 Returns all nodes in this group and subgroups. 366 367 :param bool recursive: returns the nodes of the subgroups 368 :return: The list with node items. 369 :rtype: list(:class:`QtGui.QStandardItem` <https://srinikom.github.io/pyside-docs/PySide/QtGui/QStandardItem.html>) 370 ''' 371 result = [] 372 for i in range(self.rowCount()): 373 item = self.child(i) 374 if isinstance(item, TopicGroupItem): 375 if recursive: 376 result[len(result):] = item.get_topic_items() 377 elif isinstance(item, TopicItem): 378 result.append(item) 379 return result
380 381 @classmethod
382 - def create_item_list(self, name, parent, is_group):
383 ''' 384 Creates the list of the items for this group. This list is used for the 385 visualization of group data as a table row. 386 387 :param str name: the group name 388 :return: the list for the representation as a row 389 :rtype: C{[L{TopicGroupItem} or U{QStandardItem<https://srinikom.github.io/pyside-docs/PySide/QtGui/QStandardItem.html>}, ...]} 390 ''' 391 items = [] 392 item = TopicGroupItem(name, parent, is_group) 393 items.append(item) 394 pubItem = QStandardItem() 395 items.append(pubItem) 396 subItem = QStandardItem() 397 items.append(subItem) 398 typeItem = QStandardItem() 399 items.append(typeItem) 400 return items
401
402 - def get_group_item(self, group_name, is_group=True, nocreate=False):
403 ''' 404 Returns a TopicGroupItem with given name. If no group with this name exists, a 405 new one will be created. The given name will be split by slashes if exists 406 and subgroups are created. 407 408 :param str group_name: the name of the group 409 :param bool is_group: True if it is a capability group. False if a namespace group. (Default: True) 410 :param bool nocreate: avoid creation of new group if not exists. (Default: False) 411 :return: The group with given name of None if `nocreate` is True and group not exists. 412 :rtype: :class:`TopicGroupItem` 413 ''' 414 lns, rns = group_name, '' 415 if nm.settings().group_nodes_by_namespace: 416 lns, rns = lnamespace(group_name) 417 if lns == rospy.names.SEP: 418 lns, rns = lnamespace(rns) 419 if lns == rospy.names.SEP: 420 return self 421 for i in range(self.rowCount()): 422 item = self.child(i) 423 if isinstance(item, TopicGroupItem): 424 if item == lns: 425 if rns: 426 return item.get_group_item(rns, is_group) 427 return item 428 elif item > lns and not nocreate: 429 items = TopicGroupItem.create_item_list(lns, self, is_group=(is_group and not rns)) 430 self.insertRow(i, items) 431 if rns: 432 return items[0].get_group_item(rns, is_group) 433 return items[0] 434 if nocreate: 435 return None 436 items = TopicGroupItem.create_item_list(lns, self, is_group=(is_group and not rns)) 437 self.appendRow(items) 438 if rns: 439 return items[0].get_group_item(rns, is_group) 440 return items[0]
441
442 - def add_node(self, topic):
443 ''' 444 Adds a new topic with given name. 445 446 :param topic: the TopicInfo of the node to create 447 :type topic: :class:`TopicInfo` 448 ''' 449 group_item = self 450 if nm.settings().group_nodes_by_namespace: 451 ns = namespace(topic.name) 452 if ns != rospy.names.SEP: 453 # insert in the group 454 group_item = self.get_group_item(ns, False) 455 # append new topic row 456 new_item_row = TopicItem.create_item_list(topic, self) 457 group_item._add_row(new_item_row)
458
459 - def _add_row(self, row):
460 self.appendRow(row) 461 row[0].parent_item = self 462 row[0].update_view()
463
464 - def clearup(self, fixed_node_names=None):
465 ''' 466 Removes not running and not configured nodes. 467 468 :param list(str) fixed_node_names: If the list is not None, the node not in the list are set to not running! 469 ''' 470 self._clearup(fixed_node_names) 471 self._clearup_reinsert() 472 self._clearup_riseup()
473
474 - def _clearup(self, fixed_node_names=None):
475 ''' 476 Removes not running and not configured nodes. 477 478 :param list(str) fixed_node_names: If the list is not None, the node not in the list are set to not running! 479 ''' 480 removed = False 481 # move running nodes without configuration to the upper layer, remove not running and duplicate nodes 482 for i in reversed(range(self.rowCount())): 483 item = self.child(i) 484 if isinstance(item, TopicItem): 485 pass 486 else: # if type(item) == TopicGroupItem: 487 removed = item._clearup(fixed_node_names) or removed 488 if self.rowCount() == 0 and self.parent_item is not None: 489 self.parent_item._remove_group(self.name) 490 return removed
491
492 - def _clearup_reinsert(self):
493 inserted = False 494 for i in reversed(range(self.rowCount())): 495 item = self.child(i) 496 if isinstance(item, TopicItem): 497 if item.with_namespace: 498 group_item = self.get_group_item(namespace(item.name), False, nocreate=True) 499 if group_item is not None and group_item != self: 500 inserted = True 501 row = self.takeRow(i) 502 group_item._add_row(row) 503 else: 504 inserted = item._clearup_reinsert() or inserted 505 return inserted
506
507 - def _clearup_riseup(self):
508 changed = False 509 for i in reversed(range(self.rowCount())): 510 item = self.child(i) 511 if isinstance(item, TopicItem): 512 # remove group if only one node is inside 513 if self.rowCount() == 1: 514 if not self.is_group and not type(self) == QStandardItem: 515 changed = True 516 row = self.takeRow(i) 517 if self.parent_item is not None: 518 self.parent_item._add_row(row) 519 self.parent_item._remove_group(self.name) 520 self.parent_item._clearup_riseup() 521 else: 522 changed = item._clearup_riseup() or changed 523 return changed
524
525 - def _remove_group(self, name):
526 for i in reversed(range(self.rowCount())): 527 item = self.child(i) 528 if type(item) == TopicGroupItem and item == name and item.rowCount() == 0: 529 self.removeRow(i)
530
531 - def remove_node(self, name):
532 removed = False 533 for i in range(self.rowCount()): 534 item = self.child(i) 535 if type(item) == TopicItem and item == name: 536 self.removeRow(i) 537 removed = True 538 break 539 elif type(item) == TopicGroupItem: 540 removed = item.remove_node(name) 541 if removed: 542 break 543 if removed and self.rowCount() == 0: 544 if type(self.parent_item) == TopicGroupItem: 545 self.parent_item._remove_group(self.name) 546 return removed
547
548 - def update_topic_view(self, updated_topics, topics):
549 for i in range(self.rowCount()): 550 item = self.child(i) 551 if type(item) == TopicItem: 552 if item.topic.name in updated_topics: 553 item.update_view(topics[item.topic.name]) 554 elif type(item) == TopicGroupItem: 555 item.update_topic_view(updated_topics, topics)
556
557 - def index_from_names(self, publisher, subscriber):
558 ''' 559 Returns for given topics the list of QModelIndex in this model. 560 561 :param [str] publisher: the list of publisher topics 562 :param [str] subscriber: the list of subscriber topics 563 :return: the list of QModelIndex 564 :rtype: [QtCore.QModelIndex] 565 ''' 566 result = [] 567 for i in range(self.rowCount()): 568 item = self.child(i) 569 if type(item) == TopicGroupItem: 570 result[len(result):] = item.index_from_names(publisher, subscriber) 571 elif type(item) == TopicItem: 572 if item.topic.name in publisher: 573 result.append(item.index()) 574 result.append(self.child(i, 1).index()) # select also the publishers column 575 if item.topic.name in subscriber: 576 result.append(item.index()) 577 result.append(self.child(i, 2).index()) # select also the subscribers column 578 return result
579
580 - def type(self):
582
583 - def __eq__(self, item):
584 ''' 585 Compares the name of the group. 586 ''' 587 if isinstance(item, str) or isinstance(item, unicode): 588 return self.name.lower() == item.lower() 589 elif not (item is None): 590 return self.name.lower() == item.name.lower() 591 return False
592
593 - def __ne__(self, item):
594 return not (self == item)
595
596 - def __gt__(self, item):
597 ''' 598 Compares the name of the group. 599 ''' 600 if isinstance(item, str) or isinstance(item, unicode): 601 # put the group with SYSTEM nodes at the end 602 if self.is_system_group: 603 if self.name.lower() != item.lower(): 604 return True 605 elif item.lower() == 'system': 606 return False 607 return self.name.lower() > item.lower() 608 elif not (item is None): 609 # put the group with SYSTEM nodes at the end 610 if item.is_system_group: 611 if self.name.lower() != item.lower(): 612 return True 613 elif self.is_syste_group: 614 return False 615 return self.name.lower() > item.name.lower() 616 return False
617
618 619 -class TopicModel(QStandardItemModel):
620 ''' 621 The model to manage the list with topics in ROS network. 622 ''' 623 header = [('Name', 300), 624 ('Publisher', 50), 625 ('Subscriber', 50), 626 ('Type', -1)] 627 ''':ivar: the list with columns C{[(name, width), ...]}''' 628
629 - def __init__(self):
630 ''' 631 Creates a new list model. 632 ''' 633 QStandardItemModel.__init__(self) 634 self.setColumnCount(len(TopicModel.header)) 635 self.setHorizontalHeaderLabels([label for label, _ in TopicModel.header]) 636 topics = ['/rosout', '/rosout_agg', '/diagnostics_agg'] 637 def_list = ['\A' + n.strip().replace('*', '.*') + '\Z' for n in topics] 638 self._re_cap_systopics = re.compile('|'.join(def_list), re.I) 639 self.pyqt_workaround = dict() # workaround for using with PyQt: store the python object to keep the defined attributes in the TopicItem subclass 640 root_items = TopicGroupItem.create_item_list(rospy.names.SEP, self.invisibleRootItem(), False) 641 self.invisibleRootItem().appendRow(root_items) 642 self._pyqt_workaround_add(rospy.names.SEP, root_items[0])
643
644 - def flags(self, index):
645 ''' 646 :param index: parent of the list 647 :type index: QtCore.QModelIndex<https://srinikom.github.io/pyside-docs/PySide/QtCore/QModelIndex.html> 648 :return: Flag or the requested item 649 :rtype: QtCore.Qt.ItemFlag<https://srinikom.github.io/pyside-docs/PySide/QtCore/Qt.html> 650 :see: http://www.pyside.org/docs/pyside-1.0.1/PySide/QtCore/Qt.html 651 ''' 652 if not index.isValid(): 653 return Qt.NoItemFlags 654 return Qt.ItemIsEnabled | Qt.ItemIsSelectable
655
656 - def get_cap_group(self, topic_name):
657 match = False 658 try: 659 match = self._re_cap_systopics.match(topic_name) 660 except Exception: 661 pass 662 if match: 663 root = self.get_root_group() 664 for i in range(root.rowCount()): 665 item = root.child(i) 666 if type(item) == TopicGroupItem: 667 if item == 'SYSTEM' and item.is_group: 668 return item 669 items = TopicGroupItem.create_item_list('SYSTEM', root, True) 670 root.appendRow(items) 671 self.pyqt_workaround['{SYSTEM}'] = items[0] 672 return items[0] 673 return None
674
675 - def get_root_group(self):
676 root = self.invisibleRootItem() 677 for i in range(root.rowCount()): 678 item = root.child(i) 679 if type(item) == TopicGroupItem: 680 if item == rospy.names.SEP: 681 return item 682 return None
683
684 - def updateModelData(self, topics, added_topics, updated_topics, removed_topics):
685 ''' 686 Updates the topics model. New topic will be inserted in sorting order. Not 687 available topics removed from the model. 688 689 :param topics: The dictionary with topics 690 :type topics: {topic name : U{master_discovery_fkie.TopicInfo<http://docs.ros.org/kinetic/api/master_discovery_fkie/html/modules.html#master_discovery_fkie.master_info.TopicInfo>}} 691 :param added_topics: the list of new topics in the :topics: list 692 :type added_topics: list or set 693 :param updated_topics: the list of updated topics in the :topics: list 694 :type updated_topics: list or set 695 :param removed_topics: the list of removed topics in the :topics: list 696 :type removed_topics: list or set 697 ''' 698 # first: remove topics 699 parents = set() 700 for rm_topic in removed_topics: 701 new_parent = self._remove_node(rm_topic) 702 if type(new_parent) == TopicGroupItem: 703 parents.add(new_parent) 704 for parent in parents: 705 parent.clearup() 706 # second: update the existing items 707 root = self.invisibleRootItem() 708 for i in reversed(range(root.rowCount())): 709 item = root.child(i) 710 if type(item) == TopicGroupItem: 711 item.update_topic_view(updated_topics, topics) 712 # cputimes = os.times() 713 # cputime_init = cputimes[0] + cputimes[1] 714 # insert other items in sorted order 715 # last: add new topics 716 for topic_name in added_topics: 717 try: 718 topic = topics[topic_name] 719 # first: add to system group 720 sys_group = self.get_cap_group(topic_name) 721 if sys_group is not None: 722 sys_group.add_node(topic) 723 else: 724 # second add to the root group 725 root_group = self.get_root_group() 726 if root_group is not None: 727 root_group.add_node(topic) 728 except Exception: 729 import traceback 730 print traceback.format_exc() 731 pass
732 # cputimes = os.times() 733 # cputime = cputimes[0] + cputimes[1] - cputime_init 734 # print " update topic ", cputime, ", topic count:", len(topics) 735
736 - def index_from_names(self, publisher, subscriber):
737 ''' 738 Returns for given topics the list of QModelIndex in this model. 739 740 :param [str] publisher: the list of publisher topics 741 :param [str] subscriber: the list of subscriber topics 742 :return: the list of QModelIndex 743 :rtype: [QtCore.QModelIndex] 744 ''' 745 result = [] 746 root = self.invisibleRootItem() 747 for i in range(root.rowCount()): 748 item = root.child(i) 749 if type(item) == TopicGroupItem: 750 result[len(result):] = item.index_from_names(publisher, subscriber) 751 elif type(item) == TopicItem: 752 if item.topic.name in publisher: 753 result.append(item.index()) 754 result.append(self.child(i, 1).index()) # select also the publishers column 755 if item.topic.name in subscriber: 756 result.append(item.index()) 757 result.append(self.child(i, 2).index()) # select also the subscribers column 758 return result
759
760 - def _remove_node(self, name):
761 root = self.invisibleRootItem() 762 for i in range(root.rowCount()): 763 item = root.child(i) 764 if type(item) == TopicGroupItem: 765 parent = item.remove_node(name) 766 if parent is not None: 767 return parent 768 return None
769
770 - def _pyqt_workaround_add(self, name, item):
771 self.pyqt_workaround[name] = item # workaround for using with PyQt: store the python object to keep the defined attributes in the TopicItem subclass
772
773 - def _pyqt_workaround_rem(self, name):
774 try: 775 del self.pyqt_workaround[name] # workaround for using with PyQt: store the python object to keep the defined attributes in the TopicItem subclass 776 except Exception: 777 pass
778