summaryrefslogtreecommitdiff
path: root/alot/buffers
diff options
context:
space:
mode:
Diffstat (limited to 'alot/buffers')
-rw-r--r--alot/buffers/thread.py137
1 files changed, 76 insertions, 61 deletions
diff --git a/alot/buffers/thread.py b/alot/buffers/thread.py
index 8615b37d..c60b123c 100644
--- a/alot/buffers/thread.py
+++ b/alot/buffers/thread.py
@@ -18,7 +18,20 @@ class ThreadBuffer(Buffer):
modename = 'thread'
- _msg_widgets = None
+ # list of the widgets containing the message body
+ # indexed by its depth-first position in the thread tree
+ _msg_widgets = None
+ # widget showing the thread tree
+ _msgtree_widget = None
+
+ # WidgetPlaceholder that wraps currently displayed message
+ _cur_msg_holder = None
+ # WidgetPlaceholder that wraps current divider
+ _divider_holder = None
+
+ # divider widgets placed between the thread tree and the message
+ _divider_up = None
+ _divider_down = None
def __init__(self, ui, thread):
"""
@@ -27,10 +40,29 @@ class ThreadBuffer(Buffer):
:param thread: thread to display
:type thread: :class:`~alot.db.Thread`
"""
- self.thread = thread
-
+ self.thread = thread
self._indent_width = settings.get('thread_indent_replies')
+
+ # create the widgets composing the buffer
+ self._msgtree_widget = urwid.ListBox(urwid.SimpleFocusListWalker([]))
+ self._divider_up = urwid.Divider('↑')
+ self._divider_down = urwid.Divider('↓')
+ self._divider_holder = urwid.WidgetPlaceholder(self._divider_up)
+ self._cur_msg_holder = urwid.WidgetPlaceholder(urwid.SolidFill())
+
+ self.body = urwid.Pile([
+ # 0 is a dummy value and is overridden later rebuild()
+ ('weight', 0, self._msgtree_widget),
+ ('pack', self._divider_holder),
+ # fixed weight for the message body
+ # TODO: should it depend on the message body length (or perhaps something else)?
+ ('weight', 50, self._cur_msg_holder),
+ ])
+
+ urwid.connect_signal(self._msgtree_widget.body, "modified", self._update_cur_msg)
+
self.rebuild()
+
super().__init__(ui, self.body)
def __str__(self):
@@ -38,6 +70,12 @@ class ThreadBuffer(Buffer):
self.thread.total_messages,
's' * (self.thread.total_messages > 1))
+ def _update_cur_msg(self):
+ pos = self._msgtree_widget.body.focus
+ if pos is not None and pos < len(self._msg_widgets):
+ logging.debug('displaying message %s ', pos)
+ self._cur_msg_holder.original_widget = self._msg_widgets[pos]
+
def translated_tags_str(self, intersection=False):
tags = self.thread.get_tags(intersection=intersection)
trans = [settings.get_tagstring_representation(tag)['translated']
@@ -55,27 +93,35 @@ class ThreadBuffer(Buffer):
return info
def rebuild(self):
+ self._msg_widgets = []
+ self._msgtree_widget.body.clear()
+ self._cur_msg_holder.original_widget = urwid.SolidFill()
+
try:
self.thread.refresh()
except NonexistantObjectError:
- self.body = urwid.SolidFill()
return
- self._msg_widgets = []
-
- body_walker = urwid.SimpleFocusListWalker([])
+ list_walker = self._msgtree_widget.body
for pos, msg in enumerate(self.thread.message_list):
- msg_wgt = MessageWidget(msg, pos & 1)
- wgt = ThreadNode(msg_wgt, self.thread, pos, self._indent_width)
+ msg_wgt = MessageWidget(msg)
+ wgt = ThreadNode(msg, self.thread, pos, self._indent_width)
self._msg_widgets.append(msg_wgt)
- body_walker.append(wgt)
+ list_walker.append(wgt)
+
+ # the weight given to the thread-tree widget is equal to the number of
+ # messages in it, up to the limit of 50 (when it is equal to the message
+ # body widget)
+ tree_weight = min(len(self._msg_widgets), 50)
+ self.body.contents[0] = (self._msgtree_widget, ('weight', tree_weight))
- self.body = urwid.ListBox(body_walker)
+ if len(self._msg_widgets) > 0:
+ self._cur_msg_holder.original_widget = self._msg_widgets[0]
def get_selected_message_position(self):
"""Return position of focussed message in the thread tree."""
- return self.body.focus_position
+ return self._msgtree_widget.focus_position
def get_selected_message_widget(self):
"""Return currently focused :class:`MessageWidget`."""
@@ -107,7 +153,7 @@ class ThreadBuffer(Buffer):
def set_focus(self, pos):
"Set the focus in the underlying body widget."
logging.debug('setting focus to %s ', pos)
- self.body.set_focus(pos)
+ self._msgtree_widget.set_focus(pos)
def focus_first(self):
"""set focus to first message of thread"""
@@ -193,51 +239,20 @@ class ThreadBuffer(Buffer):
"""focus previous matching message in depth first order"""
self._focus_property(lambda x: x.get_message().matches(querystring), -1)
- def focus_next_unfolded(self):
- """focus next unfolded message in depth first order"""
- self._focus_property(lambda x: x.display_content, 1)
-
- def focus_prev_unfolded(self):
- """focus previous unfolded message in depth first order"""
- self._focus_property(lambda x: x.display_content, -1)
-
- def expand(self, msgpos):
- """expand message at given position"""
- self.body.body[msgpos].expand()
-
- def expand_all(self):
- """expand all messages in thread"""
- for msg in self.message_widgets():
- msg.expand()
-
- def collapse(self, msgpos):
- """collapse message at given position"""
- self.body.body[msgpos].collapse()
- self.focus_selected_message()
-
- def collapse_all(self):
- """collapse all messages in thread"""
- for msg in self.message_widgets():
- msg.collapse()
- self.focus_selected_message()
-
- def unfold_matching(self, querystring, focus_first=True):
- """
- expand all messages that match a given querystring.
-
- :param querystring: query to match
- :type querystring: str
- :param focus_first: set the focus to the first matching message
- :type focus_first: bool
- """
- focus_set = False
- first = None
- for pos, msg_wgt in enumerate(self.message_widgets()):
- msg = msg_wgt.get_message()
- if msg.matches(querystring):
- msg_wgt.expand()
- if focus_first and not focus_set:
- self.set_focus(pos)
- focus_set = True
- else:
- msg_wgt.collapse()
+ def focus_thread_widget(self):
+ """set focus on the thread widget"""
+ logging.debug('setting focus to thread widget')
+ self.body.focus_position = 0
+ self._divider_holder.original_widget = self._divider_up
+ def focus_msg_widget(self):
+ """set focus on the message widget"""
+ logging.debug('setting focus to message widget')
+ self.body.focus_position = 2
+ self._divider_holder.original_widget = self._divider_down
+ def focus_toggle(self):
+ if self.body.focus_position == 0:
+ self.focus_msg_widget()
+ elif self.body.focus_position == 2:
+ self.focus_thread_widget()
+ else:
+ raise ValueError('Invalid focus position: %s' % str(self.body.focus_position))