#
# Pyne main window module.
#
# The main window is 0wned by a 'user' object,
# which contains all the smelly data.
#

import utils

import os.path
from time import *
from copy import copy
import threading
import tempfile
import gtk

from pyne import *
import pynei18n
from addressbook import *
from pyneheaders import *
import pynemsg
from boxtypes import *
from boxtypes.superbox import *
import ptk.message_tree
import ptk.folder_tree
import ptk.msg_view_box
import ptk.progresswin

# specific update flavours
UPDATE_CHANGED    = 0 #default
UPDATE_ALL = 1
UPDATE_FOLDERONLY = 2

class pyne_window(gtk.Window):
	"""
	Create Pyne window
	"""
	actgroups = None
	ui = None

	def about_box(self, _a=None):
		win = gtk.Window()
		win.set_title("About "+ver_string)
		win.set_transient_for(self)

		box1 = gtk.VBox(spacing=5)
		box1.set_border_width(5)
		win.add(box1)
		box1.show()

		def _close(_button, win=win):
			win.destroy()

		logo = gtk.Image()
		logo.set_from_file(os.path.join (pyne_path,"icons","logo.xpm"))
		close_button = gtk.Button()
		close_button.connect("clicked", _close)
		close_button.add(logo)
		box1.pack_start(close_button, expand=False)
		logo.show()
		close_button.show()		

		swin = gtk.ScrolledWindow()
		swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		swin.set_shadow_type(gtk.SHADOW_IN)
		swin.set_size_request(-1, 150)

		textview = gtk.TextView()
		textview.set_editable(False)
		textview.set_wrap_mode (gtk.WRAP_WORD)
		textview.show()

		box1.pack_start(swin)
		swin.add(textview)
		swin.show()

		textbuffer = textview.get_buffer()

		textbuffer.insert(textbuffer.get_end_iter(), ver_string+"\n")
		textbuffer.insert(textbuffer.get_end_iter(), "\n")
		textbuffer.insert(textbuffer.get_end_iter(), "Written by Tom Morton <soul-less@blueyonder.co.uk>\n")
		textbuffer.insert(textbuffer.get_end_iter(), "\n")
		textbuffer.insert(textbuffer.get_end_iter(), "Visit the Pyne Homepage: www.soul-less.pwp.blueyonder.co.uk/pyne\n")
		textbuffer.insert(textbuffer.get_end_iter(), "\n")
		textbuffer.insert(textbuffer.get_end_iter(), "This program is distributed under the terms of the GNU Public License version 2.\n")
		textbuffer.insert(textbuffer.get_end_iter(), "\n")

		win.show()

	def new_window(self, _a=None, _b=None):
		"""
		Spawn a new pyne_window object.
		"""
		self.user.new_window()

	def close(self, _a=None, _b=None):
		"""
		Close this window.
		"""
		# Close subwindows
		for i in xrange(len(self.subwindows)-1, -1, -1):
			self.subwindows[i].close()
		self.user.kill_window(self.number)

	def _box_init (self, newbox):
		user = self.user
		# save changes
		newbox.save(user)
		user.save()
		# Open settings box
		newbox.setup(self.user, self)
		# Update windows
		newbox.changed = 1
		user.update(UPDATE_ALL)
	def new_folder (self, _a=None):
		newbox = storebox.storebox(self.user, self.user.get_uid("store"))
		self.user.contents.append(newbox)
		self._box_init (newbox)
	def new_mailbox (self, _a=None):
		newbox = mailbox.mailbox(self.user, self.user.get_uid("mail"))
		self.user.contents.append(newbox)
		self._box_init (newbox)
	def new_nntpbox (self, _a=None):
		newbox = nntpbox.nntpbox(self.user, self.user.get_uid("news"))
		self.user.contents.append(newbox)
		self._box_init (newbox)

	def get_folder_list_selected(self):
		"""
		Return first selected item in folder_list.
		** This may not be the folder currently showing messages  **
		** use self.opened_folder for that **
		"""
		uids = self.folder_list.get_selected_folder_uids()
		
		if len(uids) == 0:
			return None
		else:
			return self.user.get_folder_by_uid(uids[0])

	def get_message_list_selected(self):
		"""
		Return ids of selected messages in message_list as a list.
		"""
		if self.display_msg != None:
			return [ self.display_msg[1] ]
		return self.message_list.get_selected_msg_ids()

	def update_ui(self, folder, msg):
		"""
		Decide what widgets should be enabled/disabled according
		to what folder and message is open.
		"""
		def _set (group, state):
			self.actgroups[group].set_sensitive (state)
			
		# Start with them all disabled
		_set ("FolderUpdate", False)
		_set ("IsMsgFolder", False)
		_set ("MsgWithBody", False)
		_set ("MsgAny", False)
		_set ("MsgNNTP", False)
		_set ("NewMsg", False)
		_set ("EditMsg", False)
		_set ("ReplySingle", False)
		_set ("ReplyAll", False)
		_set ("FwdMsg", False)
		_set ("DelMsg", False)
		_set ("ImportMsg", False)
		_set ("FolderSelected", False)
		_set ("MsgWithoutBody", False)
		_set ("Sender2AddrBook", False)

		# No folder selected. run away
		if folder == None:
			return
		_set ("FolderSelected", True)
	
		flags = folder.get_flags()
	
		_set ("IsMsgFolder", folder.__dict__.has_key ("messages"))
		_set ("NewMsg", flags & BOX_MAKE_NEW_MSG)
		_set ("FolderUpdate", flags & BOX_UPDATE_METHOD)
		_set ("ImportMsg", flags & BOX_IMPORT_TO)

		# No message. run away
		if msg == None:
			return
		
		_set ("MsgAny", True)
		
		if msg.opts & MSG_NO_BODY:
			_set ("MsgWithoutBody", True)
			return

		_set ("MsgNNTP", isinstance(folder, nntpbox.newsgroup))

		_set ("MsgWithBody", True)
		_set ("ReplySingle", flags & BOX_REPLY_SINGLE)
		_set ("ReplyAll", flags & BOX_REPLY_GROUP)
		_set ("FwdMsg", flags & BOX_REPLY_FORWARD)
		_set ("DelMsg", flags & BOX_DEL_MESSAGE)
		# Message from some other guy. may collect address
		_set ("Sender2AddrBook", msg.senduid == None)
		# Outgoing message. may edit it
		_set ("EditMsg", msg.senduid != None)

	def message_list_popup_box(self, event):
		"""
		Popup menu for right click in message_list.
		"""
		# get selected message id
		msg_id = self.get_message_list_selected()
		if msg_id == []:
			return

		menu = self.ui.get_widget ("/PopupMsgMenu")
		menu.popup(None, None, None, event.button, event.time)

	def folder_list_popup_box(self, event):
		"""
		Popup menu for right click in folder_list.
		"""
		selected = self.get_folder_list_selected()
		if selected == None:
			return
		menu = self.ui.get_widget ("/PopupFolderMenu")
		menu.popup(None, None, None, event.button, event.time)
	
	def folder_settings(self, _a=None, _b=None):
		"""
		Change a folder's settings.
		"""
		user = self.user

		selected = self.get_folder_list_selected()
		if selected == None:
			return
		selected.setup(user, self)

	def move_folder(self, offset, _a=None):
		"""
		Move the selected folder up or down by 'offset' in the folder
		list.
		"""
		user = self.user

		# Check a folder is selected
		folder = self.get_folder_list_selected()
		if folder == None:
			return
		# Find parent object
		parent_object = user.parent_of(folder)
		# Get item number in parent's contents
		for x in xrange(0, len(parent_object.contents)):
			if parent_object.contents[x].uid == folder.uid:
				item = x
				break
		# delete it
		del parent_object.contents[item]
		# dump in new location
		parent_object.contents.insert(item+offset, folder)
		# save changes
		user.save()
		# update folder list
		user.update(UPDATE_ALL)

	def delete_folder(self, _a=None, _b=None):
		"""
		You clicked on delete folder.
		"""
		user = self.user
		
		# Check a folder is selected
		folder = self.get_folder_list_selected()
		if folder == None:
			return

		# Can't delete 'special' folders.
		if not (folder.get_flags() & BOX_ISDELETEABLE):
			return

		do_it = ptk.misc_widgets.ReturnDialog (_("Delete %s") % folder.name, \
				_("Do you really want to delete\nfolder \"%s\"?") % folder.name, \
				((gtk.STOCK_OK, 1), (gtk.STOCK_CANCEL, 0)), parent_win=self)
		
		if do_it:
			# Find parent object to delete from
			parent_object = user.parent_of(folder)
			# Get item number in parent's contents
			for x in xrange(0, len(parent_object.contents)):
				if parent_object.contents[x].uid == folder.uid:
					item = x
					break
			def _recursive_nuke_folder(folder, _r):
				if folder.__dict__.has_key("contents"):
					for child in folder.contents:
						_r(child, _r)
				folder.nuke_storage()
				
			# delete whole damn lot below it
			_recursive_nuke_folder(parent_object.contents[item], _recursive_nuke_folder)
			# delete folder
			del parent_object.contents[item]
			# Save changes
			user.save()
			# update folder list
			user.update(UPDATE_ALL)

	def sender2addrbook(self, _a=None, _b=None):
		"""
		Add sender of message to address book.
		"""
		# get selected message id
		msg_ids = self.get_message_list_selected()
		folder = self.opened_folder
	
		if msg_ids == []:
			return
		msg = folder.load_article(msg_ids[0])
		addr_box = AddressEditBox(self.user.addressbook, self)
		def test_thing(_button, addr_box=addr_box):
			addr_box.destroy()
		addr_box.ok_button.connect("clicked", test_thing)
		addr_box.add_senders_address(msg, addr_box)

	def mark_message(self, _a=None, _b=None):
		user = self.user
		# get selected message id
		msg_ids = self.get_message_list_selected()
		folder = self.opened_folder
		# apply to all selected messages
		for msg_id in msg_ids:
			# mark it
			msg = folder.load_article(msg_id)
			if msg.opts & MSG_ISMARKED:
				continue
			msg.opts = msg.opts | MSG_ISMARKED
			folder.save_article(msg)
			# update message list
			self.message_list.update_node(user, msg.opts, msg_id=msg_id)

	def unmark_message(self, _a=None, _b=None):
		user = self.user
		# get selected message id
		msg_ids = self.get_message_list_selected()
		folder = self.opened_folder
		# apply to all selected messages
		for msg_id in msg_ids:
			# unmark it
			msg = folder.load_article(msg_id)
			if not (msg.opts & MSG_ISMARKED):
				return
			msg.opts = msg.opts & (~MSG_ISMARKED)
			folder.save_article(msg)
			# update message list
			self.message_list.update_node(user, msg.opts, msg_id=msg_id)

	def reply_to_message(self, type=REPLY_AUTO, _b=None):
		"""
		Reply to sender of selected message by email.
		"""
		user = self.user
		# get selected message id
		msg_id =  self.get_message_list_selected()
		if msg_id == []:
			return
		# find outbox
		the_outbox = user.get_folder_by_uid("outbox")
		from_folder = self.opened_folder

		msg_id = msg_id[0]
		msg = from_folder.load_article(msg_id)
	
		# we can't reply to messages we don't have the body text of
		if msg.opts & MSG_NO_BODY:
			return
	
		the_outbox.do_reply(user, msg, from_folder, type, parent_win=self)

	def delete_thread(self, _a=None, _b=None):
		"""
		Delete an entire thread from a newsgroup.
		"""
		folder = self.opened_folder
		
		for msg_id in self.get_message_list_selected():
			if msg_id in folder.messages:
				folder.kill_thread(msg_id)
		folder.changed = 1
		self.user.update()
		

	def download_body(self, _a=None, _b=None):
		"""
		Download the body of a partially downloaded (headers only)
		message.
		"""
		user = self.user
		folder = self.opened_folder
		
		msg_ids = self.get_message_list_selected()
		
		pager = ptk.progresswin.ProgressWin(_("Collecting messages..."), self.user, hidetext=_("Show Logs"))
		progressbar = pager.get_progress_bar()
		
		threading.Thread(target=folder.get_rest_of_msg, args=(user, msg_ids, progressbar)).start()

	def delete_message(self, _a=None, _b=None):
		"""
		Delete selected message(s), archiving into deleted folder unless
		already there.
		"""
		user = self.user
		# get selected message id
		msg_ids = self.get_message_list_selected()
		if msg_ids == []:
			return
		# find deleted box
		deleted = user.get_folder_by_uid("deleted")
		oldfolder = self.opened_folder

		for x in msg_ids:
			# if we are deleting from the deleted folder then
			# permanently delete the message
			if oldfolder.uid != "deleted":
				msg = oldfolder.load_article(x)
				deleted.save_new_article(msg)
				oldfolder.delete_article(x)
			else:
				oldfolder.delete_article(x)
		deleted.changed = 1
		oldfolder.changed = 1	
		user.update()

	def shred_message(self, _a=None, _b=None):
		"""
		Permenently delete a message or group of messages.
		"""
		user = self.user
		#### Allow multiple selections [not yet]
		msg_ids = self.get_message_list_selected()
		folder = self.opened_folder
		if folder == None:
			return

		for x in msg_ids:
			# permanently delete
			folder.delete_article(x)
		folder.changed = 1
		user.update()

	def edit_message(self, _a=None, _b=None):
		"""
		Edit the currently selected message.
		"""
		user = self.user
		# get selected message id
		msg_id = self.get_message_list_selected()
		if msg_id == []:
			return
		folder = self.opened_folder
		msg_id = msg_id[0]
		msg = folder.load_article(msg_id)
		# You can only edit outgoing messages. stands to reason.
		if msg.senduid == None:
			return
		msg.edit(folder, user)

	def print_message(self, _a=None, _b=None):
		"""
		Print the message.
		"""
		from printmodule import print_box

		user = self.user
		# get selected message id
		msg_id = self.get_message_list_selected()
		if msg_id == []:
			return
		# You can only edit outgoing messages. stands to reason.
		folder = self.opened_folder
		if folder == None:
			return
		msg_id = msg_id[0]
		message = folder.load_article(msg_id)

		print_dialog = print_box(user, message)
		print_dialog.set_transient_for(self)
		print_dialog.grab_add()
		print_dialog.show()
		

	def new_message(self, _a=None, _b=None):
		"""
		Compose a new message.
		"""
		user = self.user
		# find folder to send from
		folder = self.opened_folder
		if folder == None:
			return
		# find outbox
		the_outbox = user.get_folder_by_uid("outbox")
		# use REPLY types...
		if isinstance(folder, nntpbox.newsgroup):
			# need to find the nntpbox parent box
			parent_folder = user.parent_of(folder)
			# preset to field to NG name
			the_outbox.new_message(user, parent_folder, REPLY_GROUP, to=folder.name)
		elif isinstance(folder, mailbox.mailbox):
			the_outbox.new_message(user, folder, REPLY_EMAIL, to="")

	def unixbox_export(self, _a=None, _b=None):
		"""
		Export messages to a unix mailbox format file.
		"""
		folder = self.opened_folder
		
		def _do_it(filename):
			if filename == None:
				return

			try:
				f = open(filename, "a")
			except IOError:
				ptk.misc_widgets.InfoBox (_("Error"), _("Could not open %s") % filename, gtk.STOCK_OK, parent_win=self)
				return

			for i in folder.messages:
				msg = folder.load_article(i)
				lines = string.split(msg.body, "\n")
			
				from_addr = utils.split_address(msg.headers["from"])[1]
				if from_addr == "":
					from_addr = "nobody@localdomain"
				f.write("From "+from_addr+time.strftime(" %a %b %d %H:%M:%S %Y\n", time.localtime(msg.date)))
				# dump lines up to start of body
				while lines[0] != "":
					f.write(lines[0]+"\n")
					del lines[0]
				# dump body. escape 'From' lines this time
				for x in lines:
					if x[:5] == "From ":
						f.write(">"+x+"\n")
					else:
						f.write(x+"\n")
				# extra \n at end
				f.write("\n")
			f.close()
		
		# open file selection box
		fsel = ptk.misc_widgets.FileSelectorBox(self.user, _("Save/Append messages to Unix mailbox"), "", _do_it)
		fsel.set_transient_for(self)
		fsel.show()
	

	def unixbox_import(self, _a=None, _b=None):
		"""
		Load all the messages in a unix (~/Mail) mailbox into the
		current folder.
		"""
		folder = self.opened_folder
		
		def _do_it(filename):
			if filename == None:
				return
			try:
				import mailbox
				f = open(filename, "r")
			except IOError:
				ptk.misc_widgets.InfoBox (_("Error"), _("Could not open %s") % filename, gtk.STOCK_OK, parent_win=self)
				return
			except ImportError:
				ptk.misc_widgets.InfoBox (_("Error"), _("Missing Python \"mailbox\" module."), gtk.STOCK_OK, parent_win=self)
				return
		
			msgs = mailbox.UnixMailbox(f)
		
			while 1:
				rfc822msg = msgs.next()
				if rfc822msg == None:
					break
				body = str(rfc822msg) + "\n" + rfc822msg.fp.read()
				# Make a pyne message from this body
				msg = pynemsg.pynemsg()
				msg.body = body
				msg.parseheaders(self.user)
				msg.date_received = int(time.time())
				if msg.headers.has_key("message-id"):
					if msg.headers["message-id"] in folder.messages:
						# don't let duplicates be added
						continue
				folder.save_new_article(msg)
			f.close()
			folder.changed = 1
			self.user.update()	
		
		# Open file selection box
		fsel = ptk.misc_widgets.FileSelectorBox(self.user, _("Load messages from a Unix mailbox"), "", _do_it)
		fsel.set_transient_for(self)
		fsel.show()
			
	def load_from_ascii(self, _a=None, _b=None):
		"""
		Load an ascii format message with headers and all that junk and
		put in the current folder.
		"""
		folder = self.opened_folder
		
		def _do_it(filename):
			if filename == None:
				return
			try:
				file = open(filename, "r")
				body = file.read()
				file.close()
			except IOError:
				ptk.misc_widgets.InfoBox (_("Error"), _("Could not open %s") % filename, gtk.STOCK_OK, parent_win=self)
				return
			msg = pynemsg.pynemsg()
			msg.body = body
			msg.parseheaders(self.user)
			msg.date_received = int(time.time())
			if msg.headers.has_key("message-id"):
				if msg.headers["message-id"] in folder.messages:
					# don't let duplicates be added
					return
			folder.save_new_article(msg)
			folder.changed = 1
			self.user.update()
	
		# Open file selection box
		fsel = ptk.misc_widgets.FileSelectorBox(self.user, _("Load ascii message"), "", _do_it)
		fsel.set_transient_for(self)
		fsel.show()
	
	def save_to_ascii(self, _a=None, _b=None):
		"""
		Save currently selected message's body to a file.
		"""
		msg_id = self.get_message_list_selected()
		folder = self.opened_folder
		if folder==None:
			pass
		if msg_id == []:
			return
		msg_id = msg_id[0]
		
		def _do_it(filename):
			if filename == None:
				return
			msg = folder.load_article(msg_id)

			try:
				file = open(filename, "w")
			except IOError:
				ptk.misc_widgets.ReturnDialog (_("Error"), _("Could not create %s") % filename, ((gtk.STOCK_OK, 0),), parent_win=self)
			else:
				file.write(msg.body)
				file.close()
		# Open file selection box
		fsel = ptk.misc_widgets.FileSelectorBox(self.user, _("Save message as"), "", _do_it)
		fsel.set_transient_for(self)
		fsel.show()

	def view_new_window(self, _a=None, _b=None):
		"""
		Open selected message in a new window.
		"""
		self.user.new_window(display_msg=(self.opened_folder, self.get_message_list_selected()[0]))

	def view_browser(self, _a=None, _b=None):
		"""
		Open selected message in browser (for crappy html emails)
		"""
		user = self.user

		msg_id = self.get_message_list_selected()
		folder = self.opened_folder
		if folder==None:
			pass
		if msg_id == []:
			return
		msg_id = msg_id[0]
		msg = folder.load_article(msg_id)
	
		# body not downloaded
		if msg.opts & MSG_NO_BODY:
			return

		filename = tempfile.mktemp(".html")

		file = open(filename, "w")
		file.write(msg.parts_text[0])
		file.close()

		# remember temporary files for cleanup time :-)
		# /me kisses pyne.py
		user.tempfiles.append(filename)
		
		user.open_url ("file://"+filename)

	def view_docs(self, _a=None, _b=None):
		"""
		Open documentation in browser.
		"""
		self.user.open_url ("file://"+os.path.join(pyne_path, "docs","index.html"))

	def updateall_mail(self, _a=None, _b=None):
		"""
		You clicked 'update' all mailboxes.
		"""
		user = self.user
		pager = ptk.progresswin.ProgressWin(_("Collecting messages..."), self.user, hidetext=_("Show Logs"), parent_win=self)
		# Update every mailbox
		def _recurse_update(folder, user=user, pager=pager):
			# nntpboxes recurse into the newsgroups for us..
			if isinstance(folder, nntpbox.newsgroup):
				return
			if (not folder.__dict__.has_key("locked")) and (folder.get_flags() & BOX_UPDATE_METHOD):
				threading.Thread(target=folder.update, args=(user,pager.get_progress_bar())).start()
		utils.recurse_apply(user.contents, _recurse_update)

	def update_mail(self, _a=None, _b=None):
		"""
		You clicked 'update' mailbox.
		"""
		user = self.user
		folder = self.get_folder_list_selected()
		if folder == None:
			return
		if not folder.__dict__.has_key("locked"):
			pager = ptk.progresswin.ProgressWin(_("Collecting messages..."), self.user, hidetext=_("Show Logs"), parent_win=self)
			func = folder.update
			threading.Thread(target=func, args=(user,pager.get_progress_bar())).start()

	def addr_book(self, _a=None, _b=None):
		"""
		Open the address book.
		"""
		user=self.user
		addr_box = AddressEditBox(user.addressbook, self)
		def test_thing(_button, addr_box=addr_box):
			addr_box.destroy()
		addr_box.ok_button.connect("clicked", test_thing)
		return addr_box

	def rot13_message(self, _a=None, _b=None):
		"""
		Rot13 the body of the currently displayed message.
		"""
		self.msg_view.rot13_redisplay(self.user)

	def search_message(self, _a=None, _b=None):
		"""
		Find instance of a phrase in the currently displayed
		message.
		"""
		self.subwindows.append( self.msg_view.search_message(self.user, self) )

	def search_messages(self, _a=None, _b=None):
		"""
		Find a message in the current mailbox containing some
		phrase.
		"""
		ptk.message_tree.search_box(self.user, self)
			
	def expand_all(self, _a=None, _b=None):
		self.message_list.expand_all()
		
	def collapse_all(self, _a=None, _b=None):
		self.message_list.collapse_all()

	def select_prev_msg(self, _a=None, _b=None):
		self.message_list.select_next(prev=1)

	def select_next_msg(self, _a=None, _b=None):
		self.message_list.select_next()
	
	def reply_email(self, _button):
		self.reply_to_message(REPLY_EMAIL)
	def reply_group(self, _button):
		self.reply_to_message(REPLY_GROUP)
	def reply_forward(self, _button):
		self.reply_to_message(REPLY_FORWARD)
	
	def preferences_box (self, _a=None):
		self.user.set_preferences(self)
	
	def setup_uimanager (self):
		# some junk
		def _folder_move_up (_a=None):
			self.move_folder (-1)
		def _folder_move_down (_a=None):
			self.move_folder (+1)

		# UIManager stuff...
		def _iconset (filename):
			return gtk.IconSet (gtk.gdk.pixbuf_new_from_file (os.path.join (pyne_path, "icons", filename)))

		self.iconfuck = gtk.IconFactory ()
		self.iconfuck.add ("icon-updateall", _iconset ("tb_updateall_mail.xpm"))
		self.iconfuck.add ("icon-updatebox", _iconset ("tb_update_mail.xpm"))
		self.iconfuck.add ("icon-msgup", _iconset ("tb_msg_up.xpm"))
		self.iconfuck.add ("icon-msgdown", _iconset ("tb_msg_down.xpm"))
		self.iconfuck.add ("icon-newmsg", _iconset ("tb_new_message.xpm"))
		self.iconfuck.add ("icon-editmsg", _iconset ("tb_edit_message.xpm"))
		self.iconfuck.add ("icon-replymsg", _iconset ("tb_reply_message.xpm"))
		self.iconfuck.add ("icon-replyall", _iconset ("tb_replyall_message.xpm"))
		self.iconfuck.add ("icon-fwdmsg", _iconset ("tb_forward_message.xpm"))
		self.iconfuck.add ("icon-delmsg", _iconset ("tb_delete_message.xpm"))
		self.iconfuck.add ("icon-shredmsg", _iconset ("tb_shred_message.xpm"))
		self.iconfuck.add ("icon-printmsg", _iconset ("tb_print_message.xpm"))
		self.iconfuck.add ("icon-addressbook", _iconset ("tb_address_book.xpm"))
		self.iconfuck.add_default ()
		
		self.actgroups = {}
		self.ui = gtk.UIManager ()

		def _actgroup_new (name, actions):
			self.actgroups[name] = gtk.ActionGroup (name)
			self.actgroups[name].add_actions (actions)
			self.ui.insert_action_group (self.actgroups[name], 0)
			
		_actgroup_new ("AlwaysOn", [
			("UpdateAll", "icon-updateall", _("Update All"), None, _("Send and recieve mail for all folders"), self.updateall_mail),
			("AddressBook", "icon-addressbook", _("Address Book"), None, _("Open address book."), self.addr_book),
			("Preferences", "gtk-preferences", _("Preferences"), None, None, self.preferences_box),
			("FileMenu", None, _("_File"), None, None),
			("FolderMenu", None, _("_Folder"), None, None),
			("FolderNewBranch", None, _("New"), None, None),
			("MessageMenu", None, _("_Message"), None, None),
			("ViewMenu", None, _("_View"), None, None),
			("OptionsMenu", None, _("_Options"), None, None),
			("HelpMenu", None, _("_Help"), None, None),
			("NewWindow", None, _("_New Window"), "<Control>n", None, self.new_window),
			("Quit", "gtk-quit", _("_Quit"), "<Control>q", None, self.close),
			("NewFolder", None, _("New Folder"), None, None, self.new_folder),
			("NewMailbox", None, _("New Mailbox"), None, None, self.new_mailbox),
			("NewNNTPBox", None, _("New NNTP Box"), None, None, self.new_nntpbox),
			("UserGuide", None, _("_User Guide"), None, None, self.view_docs),
			("AboutPyne", "gtk-about", _("_About Pyne"), None, None, self.about_box),
		])
		_actgroup_new ("FolderSelected", [
			("FolderMoveUp", None, _("Move Up"), None, None, _folder_move_up),
			("FolderMoveDown", None, _("Move Down"), None, None, _folder_move_down),
			("FolderSettings", None, _("Settings"), None, None, self.folder_settings),
			("FolderDelete", None, _("Delete"), None, None, self.delete_folder),

		])
		_actgroup_new ("ImportMsg", [
			("AsciiLoadMsg", None, _("Load Message"), None, "<Control>o", self.load_from_ascii),
			("ImportUnix", None, _("Import Unix mailbox"), None, None, self.unixbox_import),
		])
		_actgroup_new ("FolderUpdate", [
			("UpdateBox", "icon-updatebox", _("Update"), None, _("Send or receive mail for current folder only"), self.update_mail)
		])
		_actgroup_new ("IsMsgFolder", [
			("MsgUp", "icon-msgup", _("Previous Message"), "<Control>a", _("Previous Message"), self.select_prev_msg),
			("MsgDown", "icon-msgdown", _("Next Message"), "<Control>z", _("Next Message"), self.select_next_msg),
			("ExportUnix", None, _("Export to Unix mailbox"), None, None, self.unixbox_export),
			("ExpandAll", None, _("_Expand All"), "<Control>e", None, self.expand_all),
			("CollapseAll", None, _("_Collapse All"), "<Control>w", None, self.collapse_all),
			("SearchMessages", None, _("Search Messages"), None, None, self.search_messages),
		])
		_actgroup_new ("MsgAny", [
			("MarkMsg", None, _("_Mark Message"), "<Control>m", None, self.mark_message),
			("UnmarkMsg", None, _("_Unmark Message"), "<Control>u", None, self.unmark_message),
		])
		_actgroup_new ("MsgWithBody", [
			("PrintMsg", "icon-printmsg", _("Print Message"), "<Control>p", _("Print the selected message"), self.print_message),
			("AsciiSaveMsg", None, _("Save Message As"), "<Control>s", None, self.save_to_ascii),
			("MsgViewNewWin", None, _("Open in New _Window"), None, None, self.view_new_window),
			("MsgViewBrowser", None, _("Open in Browser"), "<Control>b", None, self.view_browser),
			("MsgROT13", None, _("ROT13 Body"), None, None, self.rot13_message),
			("FindInMsg", None, _("Fin_d in Message"), "<Control>f", None, self.search_message),

		])
		_actgroup_new ("MsgWithoutBody", [
			("DownloadBody", None, _("Download _Body"), None, None, self.download_body),
		])
		_actgroup_new ("MsgNNTP", [
			("DeleteThread", None, _("Delete Thread"), None, None, self.delete_thread),
		])
		_actgroup_new ("NewMsg", [
			("NewMsg", "icon-newmsg", _("New Message"), None, _("Compose a new message"), self.new_message),
		])
		_actgroup_new ("EditMsg", [
			("EditMsg", "icon-editmsg", _("Edit Message"), None, _("Edit an outgoint message"), self.edit_message),
		])
		_actgroup_new ("ReplySingle", [
			("ReplySingle", "icon-replymsg", _("Reply to sender"), None, _("Reply to sender"), self.reply_email),
		])
		_actgroup_new ("Sender2AddrBook", [
			("Sender2AddrBook", None, _("Add sender to Address Book"), None, None, self.sender2addrbook),
		])
		_actgroup_new ("ReplyAll", [
			("ReplyAll", "icon-replyall", _("Reply to group"), None, _("Reply to group"), self.reply_group)
		])
		_actgroup_new ("FwdMsg", [
			("FwdMsg", "icon-fwdmsg", _("Forward message"), None, _("Forward the message"), self.reply_forward)
		])
		_actgroup_new ("DelMsg", [
			("DelMsg", "icon-delmsg", _("Delete message"), None, _("Move message to deleted folder"), self.delete_message),
			("ShredMsg", "icon-shredmsg", _("Shred message"), None, _("Permanently delete the message"), self.shred_message),
		])
		self.ui.add_ui_from_file (os.path.join (pyne_path, "ui_mainwin.xml"))
	
	def make_toolbar(self):
		"""
		Make toolbar
		"""
		# Toolbar

		self.toolbar = self.ui.get_widget ("/ToolBar")
		#self.toolbar.set_style(gtk.TOOLBAR_BOTH)
		#self.toolbar.set_icon_size (gtk.ICON_SIZE_SMALL_TOOLBAR)
		
		#optmenu = gtk.OptionMenu()
		#menu = gtk.Menu()
		#menu.show()
		#for i in ["tom", "dick", "harry"]:
		#	menuitem = gtk.MenuItem(i)
		#	menuitem.set_data("0", i)
		#	#menuitem.connect("activate", _something)
		#	menu.add(menuitem)
		#	menuitem.show()
		#optmenu.set_menu(menu)
		#self.toolbar.append_widget(optmenu, "Default personality", "something private")
		#optmenu.show()

		self.box1.pack_start(self.toolbar, expand=False)
		self.toolbar.show()

	def make_menubar(self):
		"""
		Construct the menu bar.
		"""
		m = self.ui.get_widget ("/MenuBar")
		self.add_accel_group (self.ui.get_accel_group ())
		self.box1.pack_start (m, expand=False)
		
		def _toggle_filter(_w, num):
			if not self.filter_msgview & (0x1 << num):
				self.filter_msgview |= 0x1 << num
			else:
				self.filter_msgview &= ~ (0x1 << num)
			self.message_list.update(self.opened_folder, self.filter_msgview)
	
		# view menu
		menuitem = self.ui.get_widget ("/MenuBar/View")
		menuitem.remove_submenu ()
		menu = gtk.Menu ()
		menuitem.set_submenu (menu)
		view_filters = ["Hide read", "Hide unread", "Hide partial", "Hide full", "Hide unmarked", "Hide marked" ]
		for i in xrange(0, len(view_filters)):
			menuitem = gtk.CheckMenuItem(view_filters[i])
			menuitem.connect("toggled", _toggle_filter, i)
			menu.append(menuitem)
			menuitem.show()
		menu.show()
		
		m.show ()

	def open_message(self, iter, msg_id, mark_as_read=1, new_window=0):
		"""
		View this message.
		"""
		folder = self.message_list.cur_object
		# Mark as read
		msg = folder.load_article(msg_id)
		if mark_as_read and (not msg.opts & MSG_ISREAD) and (not msg.opts & MSG_NO_BODY):
			msg.opts = msg.opts | MSG_ISREAD
			if folder.__dict__.has_key ("num_unread"):
				folder.num_unread -= 1
				self.user.update (UPDATE_FOLDERONLY)
			folder.save_article(msg)
		# Update UI state
		self.update_ui(folder, msg)
		# change icon as appropriate
		self.message_list.update_node(self.user, msg.opts, iter=iter)
		# if the object contains messages show message
		if new_window == 0:
			# dump message to view pane
			self.msg_view.dump_msg(self.user, msg, folder)
		else:
			if msg.senduid != None:
				# outgoing message: open edit box
				msg.edit(folder, self.user)
			else:
				# else: open new window displaying message
				self.user.new_window(display_msg=(folder,msg_id))

	def update_settings (self):
		"""
		User settings have changed. Must update some ui thingies.
		"""
		self.msg_view.set_tab_pos(self.user.tab_pos)
		self.msg_view.update_settings ()
		self.update_quickview_visible ()
		if self.ui_style != self.user.ui_style:
			self.ui_style = self.user.ui_style
			self.remove (self.get_child ())

			self.build_ui ()
			self.update(self.user, UPDATE_ALL)

	def update_quickview_visible (self):
		if self.display_msg != None:
			self.msg_view_show ()
			
		if isinstance (self.opened_folder, boxtypes.nntpbox.newsgroup):
			if self.user.opts & OPT_NO_QUICKVIEW_NNTP:
				self.msg_view.hide ()
			else:
				self.msg_view.show ()
		else:
			if self.user.opts & OPT_NO_QUICKVIEW_MAIL:
				self.msg_view.hide ()
			else:
				self.msg_view.show ()

	def make_panes(self):
		"""
		Make panes like so:
		#################################
		#                               #
		#         Message List          #
		#                               #
		#################################
		#               #               #
		#   Mailboxes   # Preview Pane  #
		#               #               #
		#################################
		"""	
		def click_folder_list(w, event, ctree, self=self):
			user = self.user
			# Update message list
			mousebutton = event.button
			# Right mouse button brings popup menu
			if mousebutton == 3:
				self.folder_list_popup_box(event)
				return
			# if the object contains messages show them in
			# message list pane
			object = self.user.get_folder_by_uid(self.folder_list.user_selected)
			if object == None:
				# probably clicked on the root node
				return
			if object.__dict__.has_key("messages"):
				# mark this as the open folder. whoohoo! :-)
				# note that subfolders need the uid of
				# their parents.
				self.opened_folder = object
				self.update_quickview_visible ()
				self.message_list.update(object, self.filter_msgview)
				
				msg_ids = self.get_message_list_selected()
				if not msg_ids:
					msg = None
				else:
					msg = object.load_article(msg_ids[0])
				self.update_ui(object, msg)
			else:
				self.update_ui(object, None)

		# Dump clicked on message to the preview window
		def click_message_list(msg_tree, event, msg_id, iter, self=self):
			"""
			iter is the GtkTreeIter object for the message clicked on.
			"""
			mousebutton = event.button
			# Right mouse button brings popup menu
			if mousebutton == 3:
				self.message_list_popup_box(event)
				return
			folder = msg_tree.cur_object
			# mark as read if needed
			if msg_id != None:
				# Mark as read
				mark_as_read = 0
				if not ((self.user.opts & OPT_2CLICK_MARK) and (event.type == gtk.gdk.BUTTON_PRESS)):
					mark_as_read = 1
				if event.type == gtk.gdk._2BUTTON_PRESS:
					new_window = 1
				else:
					new_window = 0
				self.open_message(iter, msg_id, mark_as_read, new_window)
			# 'None' article
			else:
				self.msg_view.clear()
				self.update_ui(folder, None)

		def keypress_message_list(msg_tree, event, msg_id, self=self):
			user = self.user
			folder = msg_tree.cur_object
			# Open on hitting return. mark as read if needed
			if msg_id != None and event.string == '\r':
				# Mark as read
				msg = folder.load_article(msg_id)
				if not ((user.opts & OPT_2CLICK_MARK) and (event.type == gtk.gdk.BUTTON_PRESS)):
					if (not msg.opts & MSG_ISREAD) and (not msg.opts & MSG_NO_BODY):
						msg.opts = msg.opts | MSG_ISREAD
						folder.save_article(msg)
				# Update UI state
				self.update_ui(folder, msg)
				# change icon as appropriate
				msg_tree.update_node(user, msg.opts, msg_id=msg_id)
				# if the object contains messages show message
				self.msg_view.dump_msg(user, msg, folder)


		self.message_list.connect_key_press_event(keypress_message_list)
		self.message_list.connect_button_press_event(click_message_list)
		self.folder_list.connect_button_press_event(click_folder_list)
		self.msg_view = ptk.msg_view_box.msg_view_box(self.user, self)

		if self.display_msg != None:
			# Simply mainwin showing only quick view pane
			self.box1.pack_start(self.msg_view)
			self.msg_view.show()
			# Dump requested message to msg_view
			msg = self.display_msg[0].load_article(self.display_msg[1])
			self.msg_view.dump_msg(self.user, msg, self.display_msg[0])
		
		else:
			# default multi-pane setup
			mpwin = gtk.ScrolledWindow()
			mpwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
			mpwin.add(self.message_list)
			mpwin.show()
			self.message_list.show()
	
			fpwin = gtk.ScrolledWindow()
			fpwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
			fpwin.add(self.folder_list)
			fpwin.show()
			self.folder_list.show()

			if not (self.user.opts & OPT_NO_QUICKVIEW_MAIL):
				self.msg_view.show()
	
			# tabbed UI style
			if self.user.ui_style == UI_TABBED:
				# tabbed UI style
				self.notebook = gtk.Notebook()
				self.notebook.set_tab_pos(gtk.POS_TOP)
				self.box1.pack_start(self.notebook)
				self.notebook.show()

				label = gtk.Label(_("Folders"))
				self.notebook.append_page(fpwin, label)
				
				label = gtk.Label(_("Messages"))
				self.notebook.append_page(mpwin, label)

				label = gtk.Label(_("View"))
				self.notebook.append_page(self.msg_view, label)
			else:
				# Vertical pane
				self.vpaned = gtk.VPaned()
				self.box1.pack_start(self.vpaned)
				self.vpaned.set_border_width(2)
				self.vpaned.show()
				# Horizontal pane
				self.hpaned = gtk.HPaned()
				# pane layouts
				if self.user.ui_style == UI_CLASSIC:
					self.vpaned.add1(self.hpaned)
					self.vpaned.add2(self.msg_view)
					self.hpaned.add1(fpwin)
					self.hpaned.add2(mpwin)
				else:
					self.vpaned.add1(mpwin)
					self.vpaned.add2(self.hpaned)
					self.hpaned.add1(fpwin)
					self.hpaned.add2(self.msg_view)
				self.hpaned.show()
				# size panes
				self.vpaned.set_position(self.user.window_setup[self.number][VPANE_POS])
				self.hpaned.set_position(self.user.window_setup[self.number][HPANE_POS])

	def keypress (self, win, event):
		# Alt-1,2,3 change tabs in tabbed view.
		if (event.state & gtk.gdk.MOD1_MASK):
			if self.user.ui_style == UI_TABBED:
				if event.keyval == ord('1'):
					self.notebook.set_current_page(0)
				elif event.keyval == ord('2'):
					self.notebook.set_current_page(1)
				elif event.keyval == ord('3'):
					self.notebook.set_current_page(2)

	def __init__(self, user, title, size, number, display_msg=None):
		"""
		Main window initialisation.
		size: (width, height, hpane pos)
		"""
		# Parent user and window number
		self.user = user
		self.number = number
		self.display_msg = display_msg
		self.subwindows = []

		def resize(win, event, self=self, user=user):
			# Store mainwindow size
			size = (event.width, event.height, -1, -1)
			user.window_setup[self.number] = size

		#create main window
		gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
		self.set_default_size(size[0], size[1])
		self.connect("key-press-event", self.keypress)
		self.connect("delete_event", self.close)
		self.connect("configure_event", resize)
		self.set_title(title)
		
		# set icon
		i = gtk.Image()
		i.set_from_file(os.path.join (pyne_path,"icons","pyne.xpm"))
		self.set_icon(i.get_pixbuf())

		self.pane_sizes = size
		
		self.ui_style = user.ui_style
		self.build_ui ()

	def build_ui (self):
		# Box to contain the shit in the main window
		self.box1 = gtk.VBox()
		self.add(self.box1)
		self.box1.show()

		# Filter out of message view
		self.filter_msgview = 0

		# Defined early 'cause menubar/toolbar needs them
		self.folder_list = ptk.folder_tree.folder_tree(self.user)
		# Setup DND
		def dnd_drag_data_received(w, context, x, y, data, info, time, self=self):
			# get target ('pyne_msgid' or 'pyne_boxid')
			content_type = str(context.targets[0])
			user = self.user
			to_folder = self.get_folder_list_selected()
			self.update_ui(to_folder, None)
			if content_type == "pyne_msgid":
				if to_folder == None:
					return
				#if data and data.format == 8 and to_folder != None:
				from_folder = user.get_folder_by_uid(string.split(data.data, "/")[0])
				if from_folder.uid == to_folder.uid:
					return
				# evaluate to list of message ids
				msg_ids = eval( string.join( string.split(data.data, "/")[1:], "/" ) )

				for msg_id in msg_ids:
					# don't bother if it's there already
					if msg_id in to_folder.messages:
						continue
					msg = from_folder.load_article(msg_id)
					# check we are moving OUTGOING messages to the outbox
					if isinstance(to_folder, outbox.outbox):
						if msg.senduid == None:
							# moving non-outgoing message to outbox.
							# make it a reply.
							to_folder.do_reply(user, msg, from_folder, type=REPLY_AUTO, parent_win=self)
							continue
					to_folder.save_new_article(msg)
					# copy not move if from newsgroup
					if not isinstance(from_folder, nntpbox.newsgroup):
						from_folder.delete_article(msg_id)
						from_folder.changed = 1
					to_folder.changed = 1
				user.update()
			elif content_type == "pyne_boxid":
				from_folder = user.get_folder_by_uid(data.data)
				# illegal from folders. we only want to move
				# mailboxes at the moment.
				if not isinstance(from_folder, mailbox.mailbox) and \
				   not isinstance(from_folder, storebox.storebox):
					ptk.misc_widgets.ReturnDialog (_("Error"), _("You can only move mailboxes into\nother mailboxes."), ((gtk.STOCK_CANCEL, 0),), parent_win=self)
					return
				# make sure we are not moving into ourself or a child box
				def _is_child(folder, to_folder=to_folder):
					if folder is to_folder:
						return 1
				if len(utils.recurse_apply([from_folder], _is_child)) > 0:
					ptk.misc_widgets.ReturnDialog (_("Error"), _("You cannot move folders into\nthemselves or their sub-folders."), ((gtk.STOCK_CANCEL, 0),), parent_win=self)
					return
				if from_folder == to_folder:
					return
				if to_folder == None:
					# copying to root node (user.contents)
					to_folder = user
				# find parent of from_folder and remove it from
				# there
				parent_object = user.parent_of(from_folder)
				parent_object.contents.remove(from_folder)
				# append to to_folder contents
				to_folder.contents.append(from_folder)
				# save changes
				user.save()
				# big update of folderview, since its structure has changed
				user.update(UPDATE_ALL)
				
		def dnd_drag_motion(w, context, x, y, time, self=self):
			# get target ('pyne_msgid' or 'pyne_boxid')
			content_type = str(context.targets[0])
			# For some reason the last entry in the TreeView
			# cannot be selected when dragged over :-\ XXX XXX XXX
			folder_list = self.folder_list
			y = y-20  # hack to make TreeView DND selection not look
				  # too sloppy... see XXX thingy
			path = folder_list.get_path_at_pos(x, y)
			
			if path == None:
				return
			# Get folder
			iter = folder_list.get_model().get_iter(path[0])
			uid = folder_list.get_model().get_value(iter, 2)
			folder = self.user.get_folder_by_uid(uid)
			
			if content_type == "pyne_msgid":
				# only allow sensible folders :-]
				if isinstance(folder, mailbox.mailbox) or \
				   isinstance(folder, storebox.storebox) or \
				   isinstance(folder, outbox.outbox):
					# gtk selectalise it :-.
					folder_list.get_selection().select_iter(iter)
			elif content_type == "pyne_boxid":
				# only allow moving to the root node
				# and into mailboxes.
				if folder==None or \
				   isinstance(folder, mailbox.mailbox) or \
				   isinstance(folder, storebox.storebox):
					# folder==None indicates root node
					folder_list.get_selection().select_iter(iter)

		targets = [ ("pyne_msgid", 0, 0), ("pyne_boxid", 0, -1) ]
		self.folder_list.connect("drag_motion", dnd_drag_motion)
		self.folder_list.connect("drag_data_received", dnd_drag_data_received)
		self.folder_list.drag_dest_set(gtk.DEST_DEFAULT_ALL, targets, gtk.gdk.ACTION_MOVE)

		self.message_list = ptk.message_tree.message_tree(self, self.pane_sizes[0])
		# the uid of the current open folder (not necessarily the
		# selected one. just the one showing messages)
		if self.display_msg == None:
			self.opened_folder = None
		else:
			self.opened_folder = self.display_msg[0]

		self.setup_uimanager ()
		self.make_menubar()
		self.make_toolbar()
		self.make_panes()

		# Set default method states
		if self.display_msg != None:
			folder, msg_id = self.display_msg
			self.update_ui(folder, folder.load_article(msg_id))
		else:
			self.update_ui(None, None)

		self.show()

	def update(self, user, update_type):
		"""
		Fill folder_list with items from user's contents.
		"""
		if self.display_msg != None:
			# no visible folder or message lists
			return
		# update folder and message list
		if update_type == UPDATE_ALL:
			self.message_list.update(self.opened_folder, self.filter_msgview, clear=1)
			self.folder_list.update(user, update_all=1)
		elif update_type == UPDATE_FOLDERONLY:
			self.folder_list.update(user, update_all=1)
		else:
			self.message_list.update(self.opened_folder, self.filter_msgview)
			self.folder_list.update(user)



syntax highlighted by Code2HTML, v. 0.9.1