diff options
author | Patrick Totzke <patricktotzke@gmail.com> | 2018-07-08 12:50:43 +0100 |
---|---|---|
committer | Patrick Totzke <patricktotzke@gmail.com> | 2018-07-24 22:11:30 +0100 |
commit | d76de213d04807a064be1f937d1b325e6bea945d (patch) | |
tree | c2d085fd25fca8c01537d022b1ff94f910129492 /alot/widgets | |
parent | 22772b7254ddea16a4e7f63b2e8240e1354bc7a2 (diff) |
refactor widgets.search.Threadline
This factors out the method _build_part, which is used to create local
Text/Column widgets for each indivitual part of the threadline.
The method is now broken in two: one for text (= subject, authors,..)
parts and one for tags (= Columns of TagWidgets) and both those
functions are moved out of the Threadline class.
Diffstat (limited to 'alot/widgets')
-rw-r--r-- | alot/widgets/search.py | 259 |
1 files changed, 152 insertions, 107 deletions
diff --git a/alot/widgets/search.py b/alot/widgets/search.py index f89992f6..d8fffec9 100644 --- a/alot/widgets/search.py +++ b/alot/widgets/search.py @@ -28,125 +28,43 @@ class ThreadlineWidget(urwid.AttrMap): focussed = self.structure['focus'] urwid.AttrMap.__init__(self, self.columns, normal, focussed) - def _build_part(self, name, struct, minw, maxw, align): - def pad(string, shorten=None): - if maxw: - if len(string) > maxw: - if shorten: - string = shorten(string, maxw) - else: - string = string[:maxw] - if minw: - if len(string) < minw: - if align == 'left': - string = string.ljust(minw) - elif align == 'center': - string = string.center(minw) - else: - string = string.rjust(minw) - return string - - part_w = None - width = None - content = None - if name == 'date': - newest = None - datestring = '' - if self.thread: - newest = self.thread.get_newest_date() - if newest is not None: - datestring = settings.represent_datetime(newest) - content = pad(datestring) - elif name == 'mailcount': - if self.thread: - mailcountstring = "(%d)" % self.thread.get_total_messages() - else: - mailcountstring = "(?)" - content = pad(mailcountstring) - elif name == 'authors': - if self.thread: - authors = self.thread.get_authors_string() or '(None)' - else: - authors = '(None)' - content = pad(authors, shorten_author_string) - elif name == 'subject': - if self.thread: - subjectstring = self.thread.get_subject() or ' ' - else: - subjectstring = ' ' - # sanitize subject string: - subjectstring = subjectstring.replace('\n', ' ') - subjectstring = subjectstring.replace('\r', '') - content = pad(subjectstring) - elif name == 'content': - if self.thread: - msgs = self.thread.get_messages().keys() - else: - msgs = [] - # sort the most recent messages first - msgs.sort(key=lambda msg: msg.get_date(), reverse=True) - lastcontent = ' '.join([m.get_text_content() for m in msgs]) - content = pad(lastcontent.replace('\n', ' ').strip()) - - # define width and part_w in case the above produced a content string - if content: - text = urwid.Text(content, wrap='clip') - width = text.pack()[0] - part_w = AttrFlipWidget(text, struct[name]) - - # the above dealt with plain text parts, which result in (wrapped) - # urwid.Text widgets. Below we deal with the special case of taglist - # parts, which are text in an urwid.Colums widget. - - if name == 'tags': - if self.thread: - fallback_normal = struct[name]['normal'] - fallback_focus = struct[name]['focus'] - tag_widgets = sorted( - TagWidget(t, fallback_normal, fallback_focus) - for t in self.thread.get_tags()) - else: - tag_widgets = [] - cols = [] - length = -1 - for tag_widget in tag_widgets: - if not tag_widget.hidden: - wrapped_tagwidget = tag_widget - tag_width = tag_widget.width() - cols.append(('fixed', tag_width, wrapped_tagwidget)) - length += tag_width + 1 - if cols: - part_w = urwid.Columns(cols, dividechars=1) - width = length - return width, part_w - def rebuild(self): self.thread = self.dbman.get_thread(self.tid) self.widgets = [] columns = [] self.structure = settings.get_threadline_theming(self.thread) + + # create a column for every part of the threadline for partname in self.structure['parts']: + # extract min/max width, overall width, and alignment parameters minw = maxw = None width_tuple = self.structure[partname]['width'] if width_tuple is not None: if width_tuple[0] == 'fit': minw, maxw = width_tuple[1:] - align_mode = self.structure[partname]['alignment'] - width, part = self._build_part(partname, self.structure, - minw, maxw, align_mode) - if part is not None: - if isinstance(part, urwid.Columns): - for w in part.widget_list: - self.widgets.append(w) - else: - self.widgets.append(part) + alignment = self.structure[partname]['alignment'] + + # build widget(s) around this part's content and remember them so + # that self.render() may change local attributes. + if partname == 'tags': + width, part = build_tags_part(self.thread.get_tags(), + self.structure['tags']['normal'], + self.structure['tags']['focus']) + for w in part.widget_list: + self.widgets.append(w) + else: + width, part = build_text_part(partname, self.thread, + self.structure[partname], minw, + maxw, alignment) + self.widgets.append(part) + + # combine width info and widget into an urwid.Column entry + if width_tuple[0] == 'weight': + columnentry = width_tuple + (part,) + else: + columnentry = ('fixed', width, part) + columns.append(columnentry) - # compute width and align - if width_tuple[0] == 'weight': - columnentry = width_tuple + (part,) - else: - columnentry = ('fixed', width, part) - columns.append(columnentry) self.columns = urwid.Columns(columns, dividechars=1) self.original_widget = self.columns @@ -163,3 +81,130 @@ class ThreadlineWidget(urwid.AttrMap): def get_thread(self): return self.thread + + +def build_tags_part(tags, attr_normal, attr_focus): + """ + create an urwid.Columns widget (wrapped in approproate Attributes) + to display a list of tag strings, as part of a threadline. + + :param tags: list of tag strings to include + :type tags: list of str + :param attr_normal: urwid attribute to use if unfocussed + :param attr_focus: urwid attribute to use if focussed + :return: overall width in characters and a Columns widget. + :rtype: tuple[int, urwid.Columns] + """ + part_w = None + width = None + tag_widgets = [] + cols = [] + width = -1 + + # create individual TagWidgets and sort them + tag_widgets = [TagWidget(t, attr_normal, attr_focus) for t in tags] + tag_widgets = sorted(tag_widgets) + + for tag_widget in tag_widgets: + if not tag_widget.hidden: + wrapped_tagwidget = tag_widget + tag_width = tag_widget.width() + cols.append(('fixed', tag_width, wrapped_tagwidget)) + width += tag_width + 1 + if cols: + part_w = urwid.Columns(cols, dividechars=1) + return width, part_w + + +def build_text_part(name, thread, struct, minw, maxw, align): + """ + create an urwid.Text widget (wrapped in approproate Attributes) + to display a plain text parts in a threadline. + create an urwid.Columns widget (wrapped in approproate Attributes) + to display a list of tag strings, as part of a threadline. + + :param name: id of part to build + :type name: str + :param thread: the thread to get local info for + :type thread: :class:`alot.db.thread.Thread` + :param struct: theming attributes for this part, as provided by + :class:`alot.settings.theme.Theme.get_threadline_theming` + :type struct: dict + :param minw: minimal width to use + :type minw: int + :param maxw: maximal width to use + :type maxw: int + :param align: alignment of content in displayed string, if shorter. + must be "left", "right", or "center". + :type align: str + :return: overall width (in characters) and a widget. + :rtype: tuple[int, AttrFliwWidget] + """ + + # local string padding function + def pad(string, shorten=None): + if maxw: + if len(string) > maxw: + if shorten: + string = shorten(string, maxw) + else: + string = string[:maxw] + if minw: + if len(string) < minw: + if align == 'left': + string = string.ljust(minw) + elif align == 'center': + string = string.center(minw) + else: + string = string.rjust(minw) + return string + + part_w = None + width = None + content = None + if name == 'date': + newest = None + datestring = '' + if thread: + newest = thread.get_newest_date() + if newest is not None: + datestring = settings.represent_datetime(newest) + content = pad(datestring) + elif name == 'mailcount': + if thread: + mailcountstring = "(%d)" % thread.get_total_messages() + else: + mailcountstring = "(?)" + content = pad(mailcountstring) + elif name == 'authors': + if thread: + authors = thread.get_authors_string() or '(None)' + else: + authors = '(None)' + content = pad(authors, shorten_author_string) + elif name == 'subject': + if thread: + subjectstring = thread.get_subject() or ' ' + else: + subjectstring = ' ' + # sanitize subject string: + subjectstring = subjectstring.replace('\n', ' ') + subjectstring = subjectstring.replace('\r', '') + content = pad(subjectstring) + elif name == 'content': + if thread: + msgs = thread.get_messages().keys() + else: + msgs = [] + # sort the most recent messages first + msgs.sort(key=lambda msg: msg.get_date(), reverse=True) + lastcontent = ' '.join([m.get_text_content() for m in msgs]) + content = pad(lastcontent.replace('\n', ' ').strip()) + + # define width and part_w in case the above produced a content string + if content: + text = urwid.Text(content, wrap='clip') + width = text.pack()[0] + part_w = AttrFlipWidget(text, struct) + + return width, part_w |