Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions alot/commands/thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,29 +533,37 @@ def apply(self, ui):
forced={'all_headers': 'toggle'},
arguments=[(['query'], {'help': 'query used to filter messages to affect',
'nargs': '*'})])
@registerCommand(
MODE, 'togglemimetree', help='disply mime tree of the message',
forced={'mimetree': 'toggle'},
arguments=[(['query'], {'help': 'query used to filter messages to affect',
'nargs': '*'})])
class ChangeDisplaymodeCommand(Command):

"""fold or unfold messages"""
repeatable = True

def __init__(self, query=None, visible=None, raw=None, all_headers=None,
**kwargs):
mimetree=None, **kwargs):
"""
:param query: notmuch query string used to filter messages to affect
:type query: str
:param visible: unfold if `True`, fold if `False`, ignore if `None`
:type visible: True, False, 'toggle' or None
:param raw: display raw message text.
:param raw: display raw message text
:type raw: True, False, 'toggle' or None
:param all_headers: show all headers (only visible if not in raw mode)
:type all_headers: True, False, 'toggle' or None
:param mimetree: show the mime tree of the message
:type mimetree: True, False, 'toggle' or None
"""
self.query = None
if query:
self.query = ' '.join(query)
self.visible = visible
self.raw = raw
self.all_headers = all_headers
self.mimetree = mimetree
Command.__init__(self, **kwargs)

def apply(self, ui):
Expand Down Expand Up @@ -584,6 +592,11 @@ def matches(msgt):
raw = not mt.display_source if self.raw == 'toggle' else self.raw
all_headers = not mt.display_all_headers \
if self.all_headers == 'toggle' else self.all_headers
if self.mimetree == 'toggle':
tbuffer.focus_selected_message()
mimetree = not mt.display_mimetree \
if self.mimetree == 'toggle' else self.mimetree


# collapse/expand depending on new 'visible' value
if visible is False:
Expand All @@ -596,6 +609,8 @@ def matches(msgt):
mt.display_source = raw
if all_headers is not None:
mt.display_all_headers = all_headers
if mimetree is not None:
mt.display_mimetree = mimetree
mt.debug()
# let the messagetree reassemble itself
mt.reassemble()
Expand Down
3 changes: 2 additions & 1 deletion alot/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,8 @@ def f((completed, pos)):
res = self._pathcompleter.complete(params, localpos)
elif self.mode == 'thread' and cmd in ['fold', 'unfold',
'togglesource',
'toggleheaders']:
'toggleheaders',
'togglemimetree']:
res = self._querycompleter.complete(params, localpos)
elif self.mode == 'thread' and cmd in ['tag', 'retag', 'untag',
'toggletags']:
Expand Down
22 changes: 22 additions & 0 deletions alot/db/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def __init__(self, dbman, msg, thread=None):
self._from = ''
self._email = None # will be read upon first use
self._attachments = None # will be read upon first use
self._mime_tree = None # will be read upon first use
self._tags = set(msg.get_tags())

def __str__(self):
Expand Down Expand Up @@ -256,3 +257,24 @@ def matches(self, querystring):
"""tests if this messages is in the resultset for `querystring`"""
searchfor = '( {} ) AND id:{}'.format(querystring, self._id)
return self._dbman.count_messages(searchfor) > 0

def get_mime_tree(self):
if not self._mime_tree:
self._mime_tree = self._get_mimetree(self.get_email())
return self._mime_tree

@classmethod
def _get_mimetree(cls, message):
label = cls._get_mime_part_info(message)
if message.is_multipart():
return label, [cls._get_mimetree(m) for m in message.get_payload()]
else:
return label, None

@staticmethod
def _get_mime_part_info(mime_part):
contenttype = mime_part.get_content_type()
filename = mime_part.get_filename() or '(no filename)'
charset = mime_part.get_content_charset() or ''
size = helper.humanize_size(len(mime_part.as_string()))
return ' '.join((contenttype, filename, charset, size))
26 changes: 25 additions & 1 deletion alot/widgets/thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import logging
import urwid
from urwidtrees import Tree, SimpleTree, CollapsibleTree
from urwidtrees import Tree, SimpleTree, CollapsibleTree, ArrowTree

from .globals import TagWidget
from .globals import AttachmentWidget
Expand Down Expand Up @@ -171,7 +171,9 @@ def __init__(self, message, odd=True):
self._all_headers_tree = None
self._default_headers_tree = None
self.display_attachments = True
self._mimetree = None
self._attachments = None
self.display_mimetree = False
self._maintree = SimpleTree(self._assemble_structure())
CollapsibleTree.__init__(self, self._maintree)

Expand All @@ -190,6 +192,7 @@ def debug(self):
logging.debug('display_source %s', self.display_source)
logging.debug('display_all_headers %s', self.display_all_headers)
logging.debug('display_attachements %s', self.display_attachments)
logging.debug('display_mimetree %s', self.display_mimetree)
logging.debug('AHT %s', str(self._all_headers_tree))
logging.debug('DHT %s', str(self._default_headers_tree))
logging.debug('MAINTREE %s', str(self._maintree._treelist))
Expand All @@ -198,6 +201,9 @@ def _assemble_structure(self):
mainstruct = []
if self.display_source:
mainstruct.append((self._get_source(), None))
elif self.display_mimetree:
mainstruct.append((self._get_headers(), None))
mainstruct.append((self._get_mimetree(), None))
else:
mainstruct.append((self._get_headers(), None))

Expand Down Expand Up @@ -311,6 +317,24 @@ def construct_header_pile(self, headers=None, normalize=True):
gaps_att = settings.get_theming_attribute('thread', 'header')
return DictList(lines, key_att, value_att, gaps_att)

def _get_mimetree(self):
if self._mimetree is None:
tree = self._message.get_mime_tree()
tree = self._text_tree_to_widget_tree(tree)
tree = SimpleTree([tree])
self._mimetree = ArrowTree(tree)
return self._mimetree

def _text_tree_to_widget_tree(self, tree):
att = settings.get_theming_attribute('thread', 'body')
att_focus = settings.get_theming_attribute('thread', 'body_focus')
label, subtrees = tree
label = FocusableText(label, att, att_focus)
if subtrees is None:
return label, None
else:
return label, [self._text_tree_to_widget_tree(s) for s in subtrees]


class ThreadTree(Tree):
"""
Expand Down