## $Id: msg.py,v 1.91 2002/05/22 14:33:01 kjetilja Exp $
## System modules
from gtk import *
from gnome.ui import *
import gnome.mime
import rfc822, string, mimify
import os, cStringIO
## Local modules
import folderops, fileops, edit, headers, mime, addresslist, privacy, fonts
from prefs import MSG_SIZE
## Try to load the GtkHTML rendering widget
try:
from html import HtmlWindow
gtkhtml_present = 1
except:
gtkhtml_present = 0
## Error messages from the GUI
err1 = """Error opening destination file"""
err2 = """No viewer specified for type '%s'
Define a viewer, or save the attachment and view manually"""
err3 = """Unable to store attachment file"""
err4 = """Unable to start viewer: %s"""
err5 = """Unable to save attachment as %s"""
##
##
## Message (view) window class
##
##
class MsgWindow:
##
## Method __init__ (self, folder window instance, msg instance)
##
## Message widget constructor.
##
##
def __init__(self, fld, msg, inline):
self.fld = fld
self.prefs = fld.prefs
self.msg = msg
self.hdr = msg.headers
self.multipart = 0
self.mime = 0
self.inline = inline
self.tmpfiles = []
self.privacy = self.fld.privacy
self.gtkhtml = gtkhtml_present and self.prefs.gtkhtml
# Font styles
self.bold_font = load_font(fonts.BOLD_FONT)
self.normal_font = load_font(fonts.NORMAL_FONT)
# Make a separate window to play in
self.vbox = GtkVBox()
self.vbox.show()
# View inline
if not inline:
self.win = GnomeApp('Pygmy Viewer', ':Pygmy - View Mail Message')
self.win.set_wmclass('pygmy viewer', ':Pygmy - View Mail Message')
self.win.set_border_width(5)
self.win.connect_after('size_allocate', self.resize)
apply(self.win.set_default_size, self.prefs.size[MSG_SIZE])
self.win.set_contents(self.vbox)
self.win.show()
self.win.create_menus(self.create_menu())
self.win.create_toolbar(self.create_toolbar())
else:
self.win = None
self.fld.vpaned.pack2(self.vbox)
# Initialize window
self.init_msg_window()
# Setup the headers
self.init_contents()
# Set viewpoint to start of text widget
if not self.gtkhtml:
self.msg_text.get_vadjustment().set_value(0)
# Make the text widget grab focus if not inline viewer
if not inline:
self.msg_text.grab_focus()
# View more headers if configured
self.prefs.more = not self.prefs.more
self.more_toggle()
## Catch resize events which are saved later
def resize(self, w=None, a=None, c=None):
size = w.get_allocation()
if w == self.win:
self.prefs.size[MSG_SIZE] = size[2:4]
##
## Method create_menu (self)
##
## Create the menu elements.
##
##
def create_menu(self):
from prefix import PYGMY_ICONDIR
file_menu = [
UIINFO_ITEM_STOCK('Save As...', None, self.saveas, STOCK_MENU_SAVE_AS),
UIINFO_SEPARATOR,
UIINFO_ITEM_STOCK('Close', None, self.destroy, STOCK_MENU_QUIT)
]
edit_menu = [
UIINFO_ITEM_STOCK('Cut', None, self.edit_cut, STOCK_MENU_CUT),
UIINFO_ITEM_STOCK('Copy', None, self.edit_copy, STOCK_MENU_COPY),
UIINFO_ITEM_STOCK('Paste', None, self.edit_paste, STOCK_MENU_PASTE),
UIINFO_SEPARATOR,
UIINFO_ITEM_STOCK('Select All', None, self.sel_all, STOCK_MENU_BLANK),
]
msg_menu = [
UIINFO_ITEM_STOCK('Reply', None, self.reply_callback,
STOCK_MENU_MAIL_RPL),
UIINFO_ITEM_STOCK('Reply All', None, self.replyall_callback,
PYGMY_ICONDIR+"/reply_to_all_menu.xpm"),
UIINFO_ITEM_STOCK('Forward', None, self.fwd_callback,
STOCK_MENU_MAIL_FWD),
UIINFO_ITEM_STOCK('View All Headers', None, self.all_headers,
STOCK_MENU_BLANK),
UIINFO_SEPARATOR,
UIINFO_ITEM_STOCK('Previous', None, self.prev_msg_callback,
STOCK_MENU_BACK),
UIINFO_ITEM_STOCK('Next', None, self.next_msg_callback,
STOCK_MENU_FORWARD),
]
menu_info = [
UIINFO_SUBTREE('File', file_menu),
UIINFO_SUBTREE('Edit', edit_menu),
UIINFO_SUBTREE('Message', msg_menu),
]
return menu_info
##
## Method create_toolbar (self)
##
## Create the toolbar elements.
##
##
def create_toolbar(self):
from prefix import PYGMY_ICONDIR
toolbar_info = [
UIINFO_ITEM_STOCK('Reply', None, self.reply_callback,
STOCK_PIXMAP_MAIL_RPL),
UIINFO_ITEM_STOCK('Reply All', None, self.replyall_callback,
PYGMY_ICONDIR+"/reply_to_all.xpm"),
UIINFO_ITEM_STOCK('Forward', None, self.fwd_callback,
STOCK_PIXMAP_MAIL_FWD),
UIINFO_SEPARATOR,
UIINFO_ITEM_STOCK('Previous', None, self.prev_msg_callback,
STOCK_PIXMAP_BACK),
UIINFO_ITEM_STOCK('Next', None, self.next_msg_callback,
STOCK_PIXMAP_FORWARD),
UIINFO_SEPARATOR,
UIINFO_ITEM_STOCK('Headers', None, self.all_headers,
STOCK_PIXMAP_MAIL),
UIINFO_SEPARATOR,
UIINFO_ITEM_STOCK('Close', None, self.destroy,
STOCK_PIXMAP_CLOSE),
]
return toolbar_info
##
## Method next_msg_callback ()
##
def next_msg_callback(self, button):
# This is to be able to browse from folder view window
if self.fld.fdisp.selection == []:
if self.fld.numrows >= 1: self.fld.row = -1
else: return
else:
self.fld.row = self.fld.fdisp.selection[0]
if self.fld.row+1 < self.fld.numrows:
self.fld.row = self.fld.row + 1
self.fld.fdisp.unselect_row(self.fld.row-1, 0)
self.fld.fdisp.select_row(self.fld.row, 0)
self.fld.fdisp.moveto(row=self.fld.row)
self.fld.view_mail(self.fld.row, inline=0, msgwin=self)
self.msg_text.grab_focus()
##
## Method prev_msg_callback ()
##
def prev_msg_callback(self, button):
# This is to be able to browse from folder view window
if self.fld.fdisp.selection == []:
return
self.fld.row = self.fld.fdisp.selection[0]
if self.fld.row-1 >= 0:
self.fld.row = self.fld.row - 1
self.fld.fdisp.unselect_row(self.fld.row+1, 0)
self.fld.fdisp.select_row(self.fld.row, 0)
self.fld.fdisp.moveto(row=self.fld.row)
self.fld.view_mail(self.fld.row, inline=0, msgwin=self)
self.msg_text.grab_focus()
##
## Method saveas (self, b)
##
## Save the currently viewed message to disk.
##
##
def saveas(self, button=None):
import fileops
fname = fileops.getfilename( self.prefs.filepaths, '', 'Save message to file...', 'save-message')
if fname == None: return
try:
f = open(fname, 'w')
except:
# Unable to open file, show error
w = GnomeErrorDialog(err1)
w.set_parent(self.win)
w.show()
else:
# Blast the message into the file
import types
if type(self.msg.fp) != types.FileType:
f.write(self.msg.fp.getvalue())
else:
pathname = folderops.get_folder_pathname(self.prefs.folders, self.msg.mbox)
m = open(pathname)
m.seek(self.msg.start)
f.write(m.read(self.msg.stop-self.msg.start))
m.close()
f.close()
##
## Method {sel|usel}_all (self, b)
##
## Select/Unselect all functions.
##
##
def sel_all(self, b):
if not self.gtkhtml:
self.msg_text.select_region(0, self.msg_text.get_length())
else:
print 'not implemented for gtkhtml yet'
##
## Method edit_{cut|copy|paste} (self, b)
##
## Clipboard functions.
##
##
def edit_cut(self, b):
if not self.gtkhtml:
self.msg_text.cut_clipboard()
else:
print 'not implemented for gtkhtml yet'
def edit_copy(self, b):
if not self.gtkhtml:
self.msg_text.copy_clipboard()
else:
print 'not implemented for gtkhtml yet'
def edit_paste(self, b):
if not self.gtkhtml:
self.msg_text.paste_clipboard()
else:
print 'not implemented for gtkhtml yet'
## Reply callback
def reply_callback(self, button=None):
edtwin = edit.EditWindow(self.fld, edit.REPLY, self.msg)
edtwin.setup_widgets()
self.destroy()
## Forward callback
def fwd_callback(self, button=None):
edtwin = edit.EditWindow(self.fld, edit.FORW, self.msg)
edtwin.setup_widgets()
self.destroy()
## Reply all callback
def replyall_callback(self, button=None):
edtwin = edit.EditWindow(self.fld, edit.REPLYALL, self.msg)
edtwin.setup_widgets()
self.destroy()
## View all headers callback
def all_headers(self, button=None):
headers.HeaderWindow(self.hdr, self.win)
## Construct the buttons used for attachments
def open_att_button(self, next, t):
# Open attachment button
w = GnomeStock(STOCK_MENU_OPEN)
w.show()
h = GtkVBox()
h.show()
h.add(w)
b = GtkButton()
b.show()
b.add(h)
b.set_border_width(1)
b.set_relief(RELIEF_NONE)
b.connect('clicked', self.view_gnome)
t.attach(b, 1, 2, next, next+1, xoptions=0, yoptions=0,
xpadding=3)
def save_att_button(self, next, t):
w = GnomeStock(STOCK_MENU_SAVE)
w.show()
h = GtkVBox()
h.show()
h.add(w)
b = GtkButton()
b.show()
b.add(h)
b.set_border_width(1)
b.set_relief(RELIEF_NONE)
b.connect('clicked', self.save)
t.attach(b, 2, 3, next, next+1, xoptions=0, yoptions=0,
xpadding=3)
##
## Method init_contents ()
##
def init_contents(self):
msg = self.msg
fld = self.fld
self.current_attachment = None
self.attachments = []
# Update the folder index status field
status = folderops.STATUS_READ
# Set message status to 'read' if this message is unread
if msg.msg_unread:
pathname = folderops.get_folder_pathname(fld.prefs.folders,
msg.mbox)
folderops.update_folder_index_status(pathname, str(msg.start),
status)
pos, rest = fld.fdisp.get_row_data(fld.row)
rest[0] = status
fld.fdisp.set_row_data(fld.row, (pos,rest))
fld.fdisp.set_text(fld.row, 3, status)
style = fld.fdisp.get_style().copy()
style.font = fld.sub_nfont
fld.fdisp.set_row_style(fld.row, style)
# Shortcut some references
m = self.msg
f = self.fld
# Construct To: string
to = rfc822.AddressList(m.getheader('to'))
tostr = []
for i in to.addresslist: tostr.append(i[1])
if len(tostr) == 0 or (len(tostr) != 0 and tostr[0] == None):
# To: is missing, insert the email address in the default account instead
if self.prefs.defacc:
tostr = [self.prefs.accounts[self.prefs.defacc][1]]
else:
if len(self.prefs.accounts) > 0:
tostr = [self.prefs.accounts.keys()[0][1]]
else:
tostr = "<Unknown>"
self.e4.set_text(mimify.mime_decode_header(string.join(tostr, ', '))[:70])
# Construct Cc: string
cc = rfc822.AddressList(m.getheader('cc'))
ccstr = []
for i in cc.addresslist: ccstr.append(i[1])
if len(ccstr) != 0 and ccstr[0] != None:
ccstr = string.join(ccstr, ', ')
self.e5.set_text(mimify.mime_decode_header(ccstr)[:70])
if self.prefs.more:
self.l2.show()
self.e5.show()
self.has_cc = 1
else:
self.e5.set_text('')
self.e5.hide()
self.l2.hide()
self.has_cc = 0
# Get from, subject and date
self.frm = folderops.get_from(m)
self.mail_field = self.frm
sub = folderops.get_subject(m)
date = m.getheader('date') or ''
# Insert default header entries
self.e1.set_text(mimify.mime_decode_header(sub)[:60])
self.e2.set_text(mimify.mime_decode_header('%s <%s>' %\
(self.frm[0], self.frm[1])))
self.e3.set_text(date)
# Clear the text area
if not self.gtkhtml:
self.msg_text.freeze()
self.msg_text.delete_text(0, -1) # Clear
else:
self.msg_text.load_empty()
# Container for attachments that are not viewed inline
if not hasattr(self, 't'):
t = GtkTable(1,3,0)
c = GtkOptionMenu()
t.attach(c, 0,1,0,1, xpadding=4, ypadding=3)
self.t = t
self.c = c
self.vbox.pack_start(t, expand=0)
# Open attachment button
self.open_att_button(0, t)
# Save attachment button
self.save_att_button(0, t)
else:
t = self.t
c = self.c
t.show()
c.show()
menu = GtkMenu()
menu.show()
# Check for messages types, single or multipart
if m.getmaintype() == 'multipart':
self.multipart = 1
self.mime = 0
# Multipart message
try:
p = mime.find_all_parts(m.getbodyparts(), new_parts=[])
except SystemError:
# Unable to parse the mail
self.insert_body_text("This mail has malformed content", 'text/plain')
self.msg_text.thaw()
t.hide()
return
total_num = len(p)
if total_num == 0:
# Mail is multipart but we cannot find the parts, show error
self.insert_body_text("This mail has malformed content", 'text/plain')
self.msg_text.thaw()
t.hide()
return
current_num = 1
first_not_inline = None
for sm in p:
type = sm.gettype()
shown = 0
# Display some types inline
if type == 'text/plain' or type == 'text/html':
# Plain text, print in the message window
shown = 1
try:
txt = sm.getbodytext()
except:
txt = 'Message contains null-bytes and will not be displayed'
# Check if message has been encrypted or signed
txt = self.privacy.handle_read(txt, self.init_contents)
self.insert_body_text(txt, type)
del txt
elif type == 'application/pgp-signature':
# Do not search for boundaries here since they may be invalid
# when the mime-type is specified
try:
txt = sm.getbodytext()
except:
txt = 'Message contains null-bytes and will not be displayed'
self.privacy.decrypt(txt)
del txt
# Register the first attachment which is not inline
if first_not_inline == None and shown == 0:
first_not_inline = current_num - 1
name = mimify.mime_decode_header((sm.getparam('name') or sm.getparam('filename') or\
edit.NONAME))[:40]
if len(name) > 36:
namestr = ".." + name[-36:]
else:
namestr = name
menustr = "%s (%s, part %d of %d)" % (namestr, type,
current_num, total_num)
if shown:
menustr = menustr + ", shown"
i = GtkMenuItem(menustr)
i.show()
i.connect('activate', self.set_current_attachment, (name, type, sm))
menu.append(i)
self.attachments.append((name, type, sm))
current_num = current_num + 1
# Ensure the attachment menu index is actually set
if first_not_inline == None:
first_not_inline = 0
# Set the default entry in the attachment menu
menu.set_active(first_not_inline)
# Set current attachment
self.current_attachment = self.attachments[first_not_inline]
c.set_menu(menu)
t.queue_draw()
self.vbox.queue_resize()
self.vbox.queue_draw()
else:
# We have a single part, possibly mime-encoded message
valid_types = ['text/plain', 'text/html']
type = m.gettype() or 'text/plain'
shown = type in valid_types
self.mime = 1
self.multipart = 0
# Need to add a backref here
m.fp.seek(m.startofbody)
self.body = m.fp.read(m.stop-m.startofbody)
type = m.gettype()
name = mimify.mime_decode_header((m.getparam('name') or m.getparam('filename') or\
edit.NONAME))[:40]
if len(name) > 36:
namestr = ".." + name[-36:]
else:
namestr = name
menustr = "%s (%s, part 1 of 1)" % (namestr, type)
if shown:
menustr = menustr + ", shown"
i = GtkMenuItem(menustr)
i.show()
i.connect('activate', self.set_current_attachment, (name, type, m))
menu.append(i)
self.attachments.append((name, type, m))
# Set current attachment
self.current_attachment = self.attachments[0]
c.set_menu(menu)
t.queue_draw()
self.vbox.queue_resize()
self.vbox.queue_draw()
# Decode encoded messages
encoding = m.getencoding()
if encoding == 'quoted-printable':
self.body = mime.decode_quoted_printable(self.body)
elif encoding == 'base64':
self.body = mime.decode_base64(self.body)
# Insert message if it can be viewed inside
if shown:
self.body = self.privacy.handle_read(self.body, self.init_contents)
self.insert_body_text(self.body, type)
if self.gtkhtml:
self.msg_text.end_insert()
self.msg_text.thaw()
def set_current_attachment(self, button, name):
self.current_attachment = name
def insert_body_text(self, text, type):
if not self.gtkhtml:
self.msg_text.insert(None, None, None, text)
else:
self.msg_text.insert(text, type)
##
## Method save (self, button)
##
## Save an attachment to disk.
##
##
def save(self, button):
# Get a filename to save as
name, type, message = self.current_attachment
attname = mimify.mime_decode_header(message.getparam('name') or message.getparam('filename') or '')
savename = fileops.getfilename( self.prefs.filepaths, attname or 'unnamed', 'Save attachment as...', 'save-attachment' )
if savename == None:
# No filename given
return
try:
f = open(savename, 'w')
except:
w = GnomeErrorDialog(err5 % savename)
w.set_parent(self.fld.win)
w.show()
return
# Save the thing to disk
if self.mime:
body = self.body
else:
body = message.getbodytext()
f.write(body)
f.close()
##
## Method view_gnome (self, button)
##
## View an attachment, creates temp file and starts viewer app.
##
##
def view_gnome(self, button):
name, type, message = self.current_attachment
# Insert name if no name is specified
if name == edit.NONAME:
name = 'unnamed'
# Make a temporary file with the attachment contents
import tempfile
fn = tempfile.mktemp()+os.path.basename(name)
try:
f = open(fn, 'w')
except:
w = GnomeErrorDialog(err3)
w.set_parent(self.fld.win)
w.show()
return
if self.mime:
body = self.body
else:
body = message.getbodytext()
f.write(body)
f.close()
# Log the file to be deleted when the widget exits
self.tmpfiles.append(fn)
# Determine mime-type and which application to invoke
if type == 'message/rfc822':
# Instantiate another message viewer window and throw in
# the message for display
m = mime.Message(cStringIO.StringIO(body), 0, len(body))
m.msg_unread = 0
MsgWindow(self.fld, m, 0)
return
else:
# Use the regular method of finding the name/application
gtype = gnome.mime.type_or_default_of_file(os.path.basename(name), type)
gtypekeys = gnome.mime.get_keys(gtype)
if 'open' in gtypekeys:
prog = gnome.mime.program(gtype)
if not prog:
w = GnomeErrorDialog(err2 % type)
w.set_parent(self.fld.win)
w.show()
return
else:
w = GnomeErrorDialog(err2 % type)
w.set_parent(self.fld.win)
w.show()
return
# Strip off %f at the end of the programs name
prog = prog[:-2]
cmd = prog + "'" + fn + "' 2>/dev/null &"
# Lauch program
os.system(cmd)
##
## Method destroy (self)
##
## Destructor, clean up window stuff.
##
##
def destroy(self, button=None):
# Take out the main stuff and mime
self.msg_text.destroy()
self.ht.destroy()
self.swin.destroy()
if self.multipart or self.mime:
try: self.t.destroy()
except: pass
self.t = None
self.vbox.destroy()
del self.msg
# Remove the body text cache
try: del self.body
except: pass
# Remove attachments
try: self.attachments = []
except: pass
self.current_attachment = None
# Wipe out temporary files
for file in self.tmpfiles:
try: os.unlink(file)
except: pass
self.tmpfiles = []
# Crunch the message window and update the pane of inline
if self.inline:
self.fld.msgwin = None
self.fld.vpaned.set_position(-1)
else:
self.win.destroy()
##
## Method display_headers (self)
##
## Create widgets for viewing header contents.
##
##
def display_headers(self):
t = GtkTable(4,3,0)
t.set_border_width(3)
t.show()
self.ht = t
self.vbox.pack_start(self.ht, expand=FALSE)
l = GtkLabel("Subject")
l.set_alignment(0.0, 0.5)
style = l.get_style().copy()
style.font = self.bold_font
l.set_style(style)
l.show()
t.attach(l, 0,1,0,1, xoptions=FILL, xpadding=3)
self.e1 = GtkLabel()
self.e1.set_alignment(0.0, 0.5)
self.e1.show()
t.attach(self.e1, 1,2,0,1, xoptions=EXPAND|FILL, xpadding=10)
if self.inline:
w = GnomeStock(STOCK_MENU_CLOSE)
w.show()
h = GtkVBox()
h.show()
h.add(w)
b = GtkButton()
b.show()
b.add(h)
b.set_relief(RELIEF_NONE)
b.set_border_width(0)
b.connect('clicked', self.destroy)
t.attach(b, 2,3,0,1, xoptions=0)
l = GtkLabel("From")
l.set_alignment(0.0, 0.5)
style = l.get_style().copy()
style.font = self.bold_font
l.set_style(style)
l.show()
t.attach(l, 0,1,1,2, xoptions=FILL, xpadding=3)
self.e2 = GtkLabel()
self.e2.set_alignment(0.0, 0.5)
self.e2.show()
b = GtkButton()
b.show()
b.add(self.e2)
b.set_relief(RELIEF_NONE)
b.set_border_width(0)
b.connect('clicked', self.add_to_address)
t.attach(b, 1,2,1,2, xoptions=EXPAND|FILL, xpadding=7)
w = GnomeStock(STOCK_MENU_DOWN)
w.show()
h = GtkVBox()
h.show()
h.add(w)
b = GtkButton()
b.show()
b.add(h)
b.set_relief(RELIEF_NONE)
b.connect('clicked', self.more_toggle)
t.attach(b, 2,3,1,2, xoptions=0)
# Optional headers
self.l0 = GtkLabel("Date")
self.l0.set_alignment(0.0, 0.5)
style = self.l0.get_style().copy()
style.font = self.bold_font
self.l0.set_style(style)
self.e3 = GtkLabel()
self.e3.set_alignment(0.0, 0.5)
self.ht.attach(self.l0, 0,1,2,3, xoptions=FILL, xpadding=3)
self.ht.attach(self.e3, 1,2,2,3, xoptions=EXPAND|FILL, xpadding=10)
self.l1 = GtkLabel("To")
self.l1.set_alignment(0.0, 0.5)
style = self.l1.get_style().copy()
style.font = self.bold_font
self.l1.set_style(style)
self.e4 = GtkLabel()
self.e4.set_alignment(0.0, 0.5)
self.ht.attach(self.l1, 0,1,3,4, xoptions=FILL, xpadding=3)
self.ht.attach(self.e4, 1,2,3,4, xoptions=EXPAND|FILL, xpadding=10)
self.l2 = GtkLabel("Cc")
self.l2.set_alignment(0.0, 0.5)
style = self.l2.get_style().copy()
style.font = self.bold_font
self.l2.set_style(style)
self.e5 = GtkLabel()
self.e5.set_alignment(0.0, 0.5)
self.ht.attach(self.l2, 0,1,4,5, xoptions=FILL, xpadding=3)
self.ht.attach(self.e5, 1,2,4,5, xoptions=EXPAND|FILL, xpadding=10)
##
## Method more_toggle (self, button=None)
##
## Toggle whether to give extended header list.
##
##
def more_toggle(self, button=None):
if not self.prefs.more:
if self.has_cc:
self.e5.show()
self.l2.show()
self.e4.show()
self.l1.show()
self.e3.show()
self.l0.show()
self.prefs.more = 1
w = GnomeStock(STOCK_MENU_UP)
w.show()
h = GtkVBox()
h.show()
h.add(w)
b = GtkButton()
b.show()
b.add(h)
b.set_relief(RELIEF_NONE)
b.connect('clicked', self.more_toggle)
self.ht.attach(b, 2,3,1,2, xoptions=0)
else:
if self.has_cc:
self.e5.hide()
self.l2.hide()
self.e4.hide()
self.l1.hide()
self.e3.hide()
self.l0.hide()
self.prefs.more = 0
w = GnomeStock(STOCK_MENU_DOWN)
w.show()
h = GtkVBox()
h.show()
h.add(w)
b = GtkButton()
b.show()
b.add(h)
b.set_relief(RELIEF_NONE)
b.connect('clicked', self.more_toggle)
self.ht.attach(b, 2,3,1,2, xoptions=0)
self.ht.queue_resize()
##
## Method init_msg_window (self)
##
## Initialize message display window.
##
##
def init_msg_window(self):
# Build the header widget
self.display_headers()
# Message body widget
if self.gtkhtml:
self.msg_text = HtmlWindow(self)
else:
self.msg_text = GtkText()
self.msg_text.set_editable(FALSE)
self.msg_text.set_word_wrap(TRUE)
self.msg_text.show()
style = self.msg_text.get_style().copy()
style.font = load_font(self.prefs.msg_font)
self.msg_text.set_style(style)
# Crank text widget into a scrolledwindow
self.swin = GtkScrolledWindow()
self.swin.set_policy(POLICY_NEVER, POLICY_AUTOMATIC)
self.vbox.pack_start(self.swin)
self.swin.add(self.msg_text)
self.swin.show()
##
##
## Method add_to_address ()
##
def add_to_address(self, button=None):
# Launch address list window
adr = addresslist.AddressListWindow(self.fld, None, self.win)
# Update GUI to ensure we get the list window up before the popup
while events_pending():
mainiteration(FALSE)
# Force a popup with the name and address filled in
adr.add_name_and_edit(self.frm[0], self.frm[1])
syntax highlighted by Code2HTML, v. 0.9.1