class ChangeStateDialog(Overlay): def __init__(self, underlying, juju_state, on_success, on_cancel): import cloudinstall.charms charm_modules = [import_module('cloudinstall.charms.' + mname) for (_, mname, _) in pkgutil.iter_modules(cloudinstall.charms.__path__)] charm_classes = sorted([m.__charm_class__ for m in charm_modules], key=attrgetter('deploy_priority')) self.boxes = [] first_index = 0 for i, charm_class in enumerate(charm_classes): charm = charm_class(juju_state=juju_state) if charm.name() and not first_index: first_index = i r = CheckBox(charm.name()) r.text_label = charm.name() self.boxes.append(r) wrapped_boxes = _wrap_focus(self.boxes) def ok(button): selected = filter(lambda r: r.get_state(), self.boxes) on_success([s.text_label for s in selected]) def cancel(button): on_cancel() bs = [Button("Ok", ok), Button("Cancel", cancel)] wrapped_buttons = _wrap_focus(bs) self.buttons = Columns(wrapped_buttons) self.items = ListBox(wrapped_boxes) self.items.set_focus(first_index) ba = BoxAdapter(self.items, height=len(wrapped_boxes)) self.lb = ListBox([ba, self.count_editor, self.buttons]) root = LineBox(self.lb, title="Select new charm") root = AttrMap(root, "dialog") Overlay.__init__(self, root, underlying, 'center', 30, 'middle', len(wrapped_boxes) + 4) def keypress(self, size, key): if key == 'tab': if self.lb.get_focus()[0] == self.buttons: self.keypress(size, 'page up') else: self.keypress(size, 'page down') return Overlay.keypress(self, size, key)
class SearchDialog(Dialog):#{{{ title = "SearchDialog" subtitle = "GenericWindow" _items = [] def __init__(self, **kwargs):#{{{ self.search_box = SearchBox() self.items_count = Text("", align='right') self.search_items = SimpleListWalker(self._null_list_item()) connect_signal(self.search_items, "modified", self._update_items_count) self.search_list = ListBox(self.search_items) connect_signal(self.search_box, "edit-done", self.on_edit_done) connect_signal(self.search_box, "edit-cancel", lambda w: self.quit()) connect_signal(self.search_box, "change", lambda sb, term: self.set_search_term(term)) self._constr = self.get_item_constructor() self.multiple_selection = kwargs.pop('multiple_selection', False) self._selected_items = OrderedSet([]) opts = { 'height': kwargs.get('height', None), 'width': kwargs.get('width', ('relative', 90)), 'title': kwargs.get('title', self.title), 'subtitle': kwargs.get('subtitle', self.subtitle), 'compact_header': kwargs.get('compact_header', True), } kwargs.update(opts) self.pile = Pile([ ('fixed', 15, AttrMap(self.search_list, 'dialog.search.item')), Columns([ AttrMap(self.search_box, 'dialog.search.input'), ('fixed', 1, AttrMap(Divider(), 'dialog.search.input')), ('fixed', 4, AttrMap(self.items_count, 'dialog.search.input')), ]), ], focus_item=0) self.__super.__init__(self.pile, **kwargs) self.attr_style = "dialog.search" self.title_attr_style = "dialog.search.title" self.subtitle_attr_style = "dialog.search.subtitle" #}}} def keypress(self, key):#{{{ if key == 'insert' and self.multiple_selection: if self.pile.get_focus().original_widget is self.search_list: wid, pos = self.search_list.get_focus() else: pos = 0 current_item = self.search_items[pos] article = self.get_data_for(pos) current_item.original_widget.selected = not current_item.original_widget.selected if current_item.original_widget.selected: current_item.attr_map = {None: 'dialog.search.item.selected'} current_item.focus_map = {None: 'dialog.search.item.focus.selected'} self._selected_items.add(article) else: current_item.attr_map = {None: 'dialog.search.item'} current_item.focus_map = {None: 'dialog.search.item.focus'} self._selected_items.discard(article) self.search_list.set_focus(pos+1) self._update_items_count() #}}} def on_edit_done(self, widget, text):#{{{ result = [] if self.pile.get_focus().original_widget is self.search_list: wid, pos = self.search_list.get_focus() else: pos = 0 if self.multiple_selection: result = list(self._selected_items) if len(result) < 1: if self.get_data_for(pos): result = [self.get_data_for(pos)] self.dialog_result = result self.quit() #}}} def set_search_term(self, term):#{{{ self._clear_search_items() query = self.get_query(term) if query is not None: self._items = tuple(query[:150]) if len(self._items) > 0: l_items = map(self._constr, self._items) for i in l_items: i.set_search_box(self.search_box) self.search_items.extend([AttrMap(i, 'dialog.search.item',\ 'dialog.search.item.focus') for i in l_items]) if self.multiple_selection: for a in (self._selected_items & set(self._items)): idx = self._items.index(a) self.search_items[idx].attr_map = {None: 'dialog.search.item.selected'} self.search_items[idx].focus_map = {None: 'dialog.search.item.focus.selected'} self.search_items[idx].original_widget.selected = True return self.search_items.extend(self._null_list_item()) #}}} def _clear_search_items(self):#{{{ self.search_items[:] = [] self._update_items_count() #}}} def _null_list_item(self):#{{{ null = SearchListItem([Text("")]) null.set_search_box(self.search_box) return [null] #}}} def _update_items_count(self):#{{{ if len(self.search_items) > 149: self.items_count.set_text("+150") else: self.items_count.set_text("") selected_count = len(self._selected_items) if selected_count > 0: self._title_widget.set_text(self.title + (" (+%d)" % selected_count)) else: self._title_widget.set_text(self.title) #}}} def get_data_for(self, index):#{{{ try: return self._items[index] except IndexError as e: # index out of range return None #}}} def get_query(self, term):#{{{ raise NotImplementedError("This must be implemented by subclass") #}}} def get_item_constructor(self):#{{{ return None
class TreeBox(WidgetWrap): """ A widget that displays a given :class:`Tree`. This is essentially a :class:`ListBox` with the ability to move the focus based on directions in the Tree and to collapse/expand subtrees if possible. TreeBox interprets `left/right` as well as `page up/`page down` to move the focus to parent/first child and next/previous sibling respectively. All other keys are passed to the underlying ListBox. """ def __init__(self, tree, focus=None): """ :param tree: tree of widgets to be displayed. :type tree: Tree :param focus: initially focussed position """ self._tree = tree self._walker = TreeListWalker(tree) self._outer_list = ListBox(self._walker) if focus is not None: self._outer_list.set_focus(focus) self.__super.__init__(self._outer_list) # Widget API def get_focus(self): return self._outer_list.get_focus() def set_focus(self, pos): return self._outer_list.set_focus(pos) def refresh(self): self._walker.clear_cache() signals.emit_signal(self._walker, "modified") def keypress(self, size, key): key = self._outer_list.keypress(size, key) if key in [ 'left', 'right', '[', ']', '-', '+', 'C', 'E', ]: if key == 'left': self.focus_parent() elif key == 'right': self.focus_first_child() elif key == '[': self.focus_prev_sibling() elif key == ']': self.focus_next_sibling() elif key == '-': self.collapse_focussed() elif key == '+': self.expand_focussed() elif key == 'C': self.collapse_all() elif key == 'E': self.expand_all() # This is a hack around ListBox misbehaving: # it seems impossible to set the focus without calling keypress as # otherwise the change becomes visible only after the next render() return self._outer_list.keypress(size, None) else: return self._outer_list.keypress(size, key) # Collapse operations def collapse_focussed(self): """ Collapse currently focussed position; works only if the underlying tree allows it. """ if implementsCollapseAPI(self._tree): w, focuspos = self.get_focus() self._tree.collapse(focuspos) self._walker.clear_cache() self.refresh() def expand_focussed(self): """ Expand currently focussed position; works only if the underlying tree allows it. """ if implementsCollapseAPI(self._tree): w, focuspos = self.get_focus() self._tree.expand(focuspos) self._walker.clear_cache() self.refresh() def collapse_all(self): """ Collapse all positions; works only if the underlying tree allows it. """ if implementsCollapseAPI(self._tree): self._tree.collapse_all() self.set_focus(self._tree.root) self._walker.clear_cache() self.refresh() def expand_all(self): """ Expand all positions; works only if the underlying tree allows it. """ if implementsCollapseAPI(self._tree): self._tree.expand_all() self._walker.clear_cache() self.refresh() # Tree based focus movement def focus_parent(self): """move focus to parent node of currently focussed one""" w, focuspos = self.get_focus() parent = self._tree.parent_position(focuspos) if parent is not None: self.set_focus(parent) def focus_first_child(self): """move focus to first child of currently focussed one""" w, focuspos = self.get_focus() child = self._tree.first_child_position(focuspos) if child is not None: self.set_focus(child) def focus_last_child(self): """move focus to last child of currently focussed one""" w, focuspos = self.get_focus() child = self._tree.last_child_position(focuspos) if child is not None: self.set_focus(child) def focus_next_sibling(self): """move focus to next sibling of currently focussed one""" w, focuspos = self.get_focus() sib = self._tree.next_sibling_position(focuspos) if sib is not None: self.set_focus(sib) def focus_prev_sibling(self): """move focus to previous sibling of currently focussed one""" w, focuspos = self.get_focus() sib = self._tree.prev_sibling_position(focuspos) if sib is not None: self.set_focus(sib) def focus_next(self): """move focus to next position (DFO)""" w, focuspos = self.get_focus() next = self._tree.next_position(focuspos) if next is not None: self.set_focus(next) def focus_prev(self): """move focus to previous position (DFO)""" w, focuspos = self.get_focus() prev = self._tree.prev_position(focuspos) if prev is not None: self.set_focus(prev)
class TreeBox(WidgetWrap): """ A widget representing something in a nested tree display. This is essentially a ListBox with the ability to move the focus based on directions in the Tree. TreeBox interprets `left/right` as well as page `up/down` to move the focus to parent/first child and next/previous sibling respectively. All other keys are passed to the underlying ListBox. """ _selectable = True def __init__(self, walker, **kwargs): """ :param walker: tree of widgets to be displayed. In case we are given a raw `TreeWalker`, it will be used though `TreeListWalker` which means no decoration. :type walker: TreeWalker or TreeListWalker """ if not isinstance(walker, TreeListWalker): walker = TreeListWalker(walker) self._walker = walker self._outer_list = ListBox(walker) self.__super.__init__(self._outer_list) # Widget API def get_focus(self): return self._outer_list.get_focus() def keypress(self, size, key): key = self._outer_list.keypress(size, key) if key in ['left', 'right', '[', ']', '-', '+', 'C', 'E']: if key == 'left': self.focus_parent() elif key == 'right': self.focus_first_child() elif key == '[': self.focus_prev_sibling() elif key == ']': self.focus_next_sibling() if isinstance(self._walker, CollapseMixin): if key == '-': w, focuspos = self._walker.get_focus() self._walker.collapse(focuspos) elif key == '+': w, focuspos = self._walker.get_focus() self._walker.expand(focuspos) elif key == 'C': self._walker.collapse_all() elif key == 'E': self._walker.expand_all() # This is a hack around ListBox misbehaving: # it seems impossible to set the focus without calling keypress as # otherwise the change becomes visible only after the next render() return self._outer_list.keypress(size, None) else: return self._outer_list.keypress(size, key) # Tree based focus movement def focus_parent(self): w, focuspos = self._walker.get_focus() parent = self._walker.parent_position(focuspos) if parent is not None: self._outer_list.set_focus(parent) def focus_first_child(self): w, focuspos = self._walker.get_focus() child = self._walker.first_child_position(focuspos) if child is not None: self._outer_list.set_focus(child) def focus_next_sibling(self): w, focuspos = self._walker.get_focus() sib = self._walker.next_sibling_position(focuspos) if sib is not None: self._outer_list.set_focus(sib) def focus_prev_sibling(self): w, focuspos = self._walker.get_focus() sib = self._walker.prev_sibling_position(focuspos) if sib is not None: self._outer_list.set_focus(sib)
class TreeBox(WidgetWrap): """ A widget that displays a given :class:`Tree`. This is essentially a :class:`ListBox` with the ability to move the focus based on directions in the Tree and to collapse/expand subtrees if possible. TreeBox interprets `left/right` as well as `page up/`page down` to move the focus to parent/first child and next/previous sibling respectively. All other keys are passed to the underlying ListBox. """ def __init__(self, tree, focus=None): """ :param tree: tree of widgets to be displayed. :type tree: Tree :param focus: initially focussed position """ self._tree = tree self._walker = TreeListWalker(tree) self._outer_list = ListBox(self._walker) if focus is not None: self._outer_list.set_focus(focus) self.__super.__init__(self._outer_list) # Widget API def get_focus(self): return self._outer_list.get_focus() def set_focus(self, pos): return self._outer_list.set_focus(pos) def refresh(self): self._walker.clear_cache() signals.emit_signal(self._walker, "modified") def keypress(self, size, key): key = self._outer_list.keypress(size, key) if key in ["left", "right", "[", "]", "-", "+", "C", "E"]: if key == "left": self.focus_parent() elif key == "right": self.focus_first_child() elif key == "[": self.focus_prev_sibling() elif key == "]": self.focus_next_sibling() elif key == "-": self.collapse_focussed() elif key == "+": self.expand_focussed() elif key == "C": self.collapse_all() elif key == "E": self.expand_all() # This is a hack around ListBox misbehaving: # it seems impossible to set the focus without calling keypress as # otherwise the change becomes visible only after the next render() return self._outer_list.keypress(size, None) else: return self._outer_list.keypress(size, key) # Collapse operations def collapse_focussed(self): """ Collapse currently focussed position; works only if the underlying tree allows it. """ if implementsCollapseAPI(self._tree): w, focuspos = self.get_focus() self._tree.collapse(focuspos) self._walker.clear_cache() self.refresh() def expand_focussed(self): """ Expand currently focussed position; works only if the underlying tree allows it. """ if implementsCollapseAPI(self._tree): w, focuspos = self.get_focus() self._tree.expand(focuspos) self._walker.clear_cache() self.refresh() def collapse_all(self): """ Collapse all positions; works only if the underlying tree allows it. """ if implementsCollapseAPI(self._tree): self._tree.collapse_all() self.set_focus(self._tree.root) self._walker.clear_cache() self.refresh() def expand_all(self): """ Expand all positions; works only if the underlying tree allows it. """ if implementsCollapseAPI(self._tree): self._tree.expand_all() self._walker.clear_cache() self.refresh() # Tree based focus movement def focus_parent(self): """move focus to parent node of currently focussed one""" w, focuspos = self.get_focus() parent = self._tree.parent_position(focuspos) if parent is not None: self.set_focus(parent) def focus_first_child(self): """move focus to first child of currently focussed one""" w, focuspos = self.get_focus() child = self._tree.first_child_position(focuspos) if child is not None: self.set_focus(child) def focus_last_child(self): """move focus to last child of currently focussed one""" w, focuspos = self.get_focus() child = self._tree.last_child_position(focuspos) if child is not None: self.set_focus(child) def focus_next_sibling(self): """move focus to next sibling of currently focussed one""" w, focuspos = self.get_focus() sib = self._tree.next_sibling_position(focuspos) if sib is not None: self.set_focus(sib) def focus_prev_sibling(self): """move focus to previous sibling of currently focussed one""" w, focuspos = self.get_focus() sib = self._tree.prev_sibling_position(focuspos) if sib is not None: self.set_focus(sib) def focus_next(self): """move focus to next position (DFO)""" w, focuspos = self.get_focus() next = self._tree.next_position(focuspos) if next is not None: self.set_focus(next) def focus_prev(self): """move focus to previous position (DFO)""" w, focuspos = self.get_focus() prev = self._tree.prev_position(focuspos) if prev is not None: self.set_focus(prev)
class LogDisplay(BoxWidget): def __init__(self, parser, encoding): self.parser = parser self.encoding = encoding self.find = {'ref': '', 'text': ''} self.isolate_filter = (None, None) self.line_collection = None self.jump_stack = [] self.expansions = {} self.show_sip_level = 2 self.show_ladder = False self.show_only_filtered = False self.show_verbose = True self.show_channel = True self.line_no_before_isolate = 0 self.showing_help = False self.walker = LogLineWalker([('Select call on the left side', None)], self.jump, self.expand, self.isolate) self.header = AttrWrap(Text([('key', 'F6'), ' Log']), 'bar') self.listbox = ListBox(self.walker) self.frame = Frame(self.listbox, header=self.header) def render(self, size, focus=False): return self.frame.render(size, focus) def keypress(self, size, key): return self.frame.keypress(size, key) def set_line_collection(self, line_collection): self.jump_stack = [] self.line_collection = line_collection self.walker.lines = line_collection.lines self.walker.set_focus(0) lc, mc = len(line_collection.lines), line_collection.match_count self.header.set_text([ ('key', 'F6'), ' Log lines: %d, matches: %s | ' % (lc, mc), ('key', 's'), '/', ('key', 'S'), ' toggle sip messages/ladders | ', ('key', 'n'), '/', ('key', 'N'), ' next/previous | ', ('key', 'f'), ' toggle filter | ', ('key', 'i'), '/', ('key', 'I'), ' isolate/un-isolate | ', ('key', 'enter'), '/', ('key', 'backspace'), ' jump/back | ', ('key', 'space'), ' expand/collapse', ]) self.line_collection.set_filter(self.show_only_filtered) def help(self): if self.showing_help: self.refresh_log() else: lc = LineCollection({}) for markup in HELP: lc.add(markup) self.set_line_collection(lc) self.showing_help = not self.showing_help @property def compiled_find(self): find_text = self.find['text'] if find_text and len(find_text) > 2: try: find_text = re.compile(find_text) except Exception as e: log.debug('Invalid RE %r: %s', find_text, e) # noinspection PyDictCreation find_map = {self.find['ref']: 'find1'} # possibly override find_map[find_text] = {'style': 'find2', 'jump': True} return find_map def load_result(self, ref): self.isolate_filter = (None, None) self.find['ref'] = ref self.refresh_log() def toggle_filter(self): if not self.line_collection or self.listbox.get_focus()[0] is None: return self.jump_stack = [] self.expansions = {} self.show_only_filtered = not self.show_only_filtered self.listbox.set_focus(0) self.line_collection.set_filter(self.show_only_filtered) self.listbox.set_focus(0) def toggle_sip(self): self.jump_stack = [] self.expansions = {} self.show_sip_level = (self.show_sip_level + 1) % 3 def jump(self, where): cur = self.listbox.get_focus()[1] if where == 'home': self.listbox.set_focus(0) elif where == 'end': self.listbox.set_focus(len(self.line_collection.lines) - 1) elif where == 'next': if self.show_only_filtered: return for line_no in self.line_collection.line_numbers_with_needle: pos = self.line_collection.line_number_map.get(line_no) # + 1 if pos > cur: self.listbox.set_focus(pos) break elif where == 'previous': if self.show_only_filtered: return collection = self.line_collection.line_numbers_with_needle for i in range(len(collection) - 1, -1, -1): line_no = collection[i] pos = self.line_collection.line_number_map.get(line_no) # + 1 if pos < cur: self.listbox.set_focus(pos) break elif where == -1: # Jump back from where we came if self.jump_stack: pos = self.jump_stack.pop() self.listbox.set_focus(pos) else: pos = self.line_collection.line_number_map.get(where) if pos and pos != cur: self.jump_stack.append(cur) self.listbox.set_focus(pos) def expand(self, tag): if self.show_ladder: return # No effect when showing all ladders cur = self.listbox.get_focus()[1] ref_type, ref = ref_tag(tag) # Collapse if ref in self.expansions: old, markups = self.expansions[ref] self.line_collection.remove(old, len(markups)) del self.expansions[ref] self.listbox.set_focus(cur) return # Expand markups = [] if ref_type == 'call_id': dialog = self.parser.find_obj(ref_type, ref) markups = message_sequence_chart(dialog) markups = [[' ' * 9] + m for m in markups] # indent elif ref_type == 'sip_ref': sip = self.parser.find_obj(ref_type, ref) instructions = sip_payload_instructions(sip) markups = [(s, m) for (_l, s, m) in instructions] elif ref_type == 'chan': channel = self.parser.find_obj(ref_type, ref) markups = dial_chart(channel) markups = [[' ' * 9] + m for m in markups] # indent if markups: self.expansions[ref] = (cur + 1, markups) self.line_collection.insert(cur + 1, markups) self.listbox.set_focus(cur) def isolate(self, tag): ref_type, ref = ref_tag(tag) if ref_type and ref: self.line_no_before_isolate = self.listbox.get_focus()[1] self.isolate_filter = (ref_type, ref) self.refresh_log() else: self.isolate_filter = (None, None) self.refresh_log(focus_line=self.line_no_before_isolate) def refresh_log(self, focus_line=False): groups, objects = self.parser.get_linked_objects( self.find['ref'], self.isolate_filter) old_pos = self.listbox.get_focus()[1] warning_count = 0 error_count = 0 lc = LineCollection(self.compiled_find) if objects: # Prepare markup for "Overview" section lc.add([('section', 'Overview ')]) # must be a list for group in groups: tab, tab2 = '= ', ' ' for line_no, what, obj in group.overview: markup = obj dialog = None tag = None if what == 'dialog': sip = obj dialog = sip.dialog style = get_sip_style(sip) if dialog: dialog_status = dialog.dialog_status or '' dialog_ack = dialog.dialog_ack or '' dialog_bye = dialog.bye_addr or '' else: dialog_status = '' dialog_ack = '' dialog_bye = '' markup = [ ('', ' '), ('line-no', '%07d' % (line_no + 1)), ('', ' '), ('mute', '[%s] ' % sip.when), (style, sip.request or sip.status or '?'), ('', ' %s -> %s ' % (sip.from_num, sip.to_num)), ('sip-status', '%s' % (dialog_status or ' ')), ('', ' '), ('sip-method', '%s' % (dialog_ack or ' ')), ] if dialog and dialog.timeout: markup.extend([('', ' '), ('sip-timeout', 'TIMEOUT')]) if dialog_bye: markup.extend([ ('', ' '), ('sip-bye2', 'BYE'), ('mute', ' from '), ('mute', dialog_bye), ]) markup.append(('sip-call-id', ' %s' % sip.call_id)) tag = {'call_id': sip.call_id} elif what == 'channel': channel = obj markup = [('line-no', '%07d' % (line_no + 1)), ('', ' '), ('mute', '[%s] ' % channel.when), ('channel-name', channel.name)] for phone in set(channel.extensions): markup.append(('', ' ')) markup.append(('', phone)) if channel.clid_num: markup.append(('channel-phone', ' (clid:%s)' % channel.clid_num)) for i, app in enumerate(channel.apps): dial_style = get_dial_status_style(app.status) markup.append(('mute', '; ' if i else ': ')) markup.append(('mute', '%s ' % app.app_name)) markup.append(('', app.data or ' ')) markup.append(('mute', ' ')) markup.append((dial_style, app.status)) tag = {'chan': channel.name} elif what == 'astcall': acall = obj markup = [('line-no', '%07d' % (line_no + 1)), ('', ' '), ('mute', '[%s] ' % acall.when), ('acall-id', acall.acall_id)] tag = {'acall_id': acall.acall_id} lc.add(['%s%s%s ' % (tab, what, tab2), markup or '?'], tag=tag) if dialog and dialog.timeout: timeout_line_no, timeout_when = dialog.timeout markup = [('', ' '), ('line-no', '%07d' % (timeout_line_no + 1)), ('mute', ' [%s] ' % timeout_when), ('sip-timeout', 'TIMEOUT')] lc.add(['%s%s%s ' % (tab, ' ', tab2), markup]) if dialog and self.show_ladder: for markup in message_sequence_chart(dialog): lc.add([' ' * 9] + markup) tab, tab2 = ' - ', ' ' lc.add('') # Prepare markup for "Log" section flat = objects.items() flat.sort() lc.add(('section', 'Log')) old_line_no = None for line_no, (style, obj) in flat: # Text is kept as bytes, convert to unicode only when displaying if isinstance(obj, _bytes3): obj = obj.decode(self.encoding, errors='replace') if old_line_no is not None and old_line_no + 1 != line_no: # If Missing single unimportant line, omit "..." if not (style == 'sip' and old_line_no + 2 == line_no): lc.add(('mute', '...')) old_line_no = line_no if style == 'sip': if self.show_sip_level == 0: continue sip = obj line_no = sip.line_no tag = None markup = [('sip-intro', '==== %s ' % sip.when), ('elapsed', '(ela: %s) ' % sip.elapsed_sec)] if self.show_sip_level == 1: if sip.request: markup.append((get_sip_style(sip), str(sip))) else: markup.append(('sip-status', str(sip))) # Adding tag also allows message expansion tag = {'sip_ref': sip.ref} if sip.attempt_no: markup.append( ('sip-retransmit', 'ATTEMPT #%s' % sip.attempt_no)) markup.append(('', ' %s ' % sip.direction)) # markup.append(('sip-direction', ' ')) if sip.direction == 'IN': markup.append(('sip-addr', '%s' % sip.recipient_addr)) markup.append(('', ' <- ')) markup.append(('sip-addr', '%s' % sip.sender_addr)) else: markup.append(('sip-addr', '%s' % sip.sender_addr)) markup.append(('', ' -> ')) markup.append(('sip-addr', '%s' % sip.recipient_addr)) lc.add(markup, tag=tag) if self.show_sip_level == 1: continue instructions = sip_payload_instructions(sip) # We use line_no again on purpose # noinspection PyAssignmentToLoopOrWithParameter for line_no, sty2, markup in instructions: lc.add((sty2, markup), line_no) elif style == 'channel': if self.show_channel: lc.add((style, obj), line_no, { 'Dial': 'asterisk-app', 'Queue': 'asterisk-app', }) elif self.show_verbose: if b'WARNING' in obj: lc.add(('warning', obj), line_no) warning_count += 1 if b'ERROR' in obj: lc.add(('error', obj), line_no) error_count += 1 else: lc.add((style, obj), line_no) old_line_no = line_no if warning_count: lc.lines[0][0].append( ('warning', ' Warnings: %d ' % warning_count)) if error_count: lc.lines[0][0].append(('error', ' Errors: %d ' % error_count)) self.set_line_collection(lc) if focus_line: focus_line = focus_line if isinstance(focus_line, int) else old_pos try: self.listbox.set_focus(focus_line, 'above') except IndexError: pass