#!/usr/bin/env python

# pymessage - A replacement for xmessage/gxmessage using ROX-Lib2 and 
#             Python.  Intended for use in ROX application directories.
#
# Copyright (C) 2003  Peter A. Geer
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

import sys, os, string, getopt
import findrox
findrox.version(1, 9, 0)

import rox
from rox import g

# Import wrapper classes for supported controls.
import controls

# globals
app_name = 'pymessage'
version  = '0.2.1'

long_options = ['help', 'version', 'info', 'alert', 'buttons=', 'print', 
 'default=', 'title=', 'entry=', 'combo=', 'stock-icons', 'markup', 'font=',
 'font-size=', 'fg=', 'bg=', 'file=', 'delimiter=', 'check=', 'option=',
 'text']
short_options = 'hviab:pd:t:e:c:smn:z:f:l:k:o:x'

# Functions

def mark_text(text, fnt, sz):
	marked_text = ''
	if fnt != '': marked_text += ' font_desc="' + fnt + '"'
	if sz != '': marked_text += ' size="' + sz + '"'
	if marked_text != '':
		marked_text = '<span' + marked_text + '>' + text + '</span>'
	else:
		marked_text = text
	return marked_text

def wm_del(win, ev):
	# We don't want to allow WM exits, so return true
	return True

def exit_app(button, status):
	x = eval(status)
	output_str = ''
	for ctl in control_list:
		if output_str != '':
			output_str = output_str + delimiter_string + ctl.get_print_data()
		else:
			output_str = ctl.get_print_data()
	if print_flag:
		if output_str == '':
			output_str = status
		else:
			output_str = output_str + delimiter_string + status
	print output_str
	sys.exit(x)

def help_message():
	s = """Usage: %s [options] message_text
       %s [options] --file path
    
Description: A Python/ROX replacement for gxmessage.  Displays a message box
and returns an exit code based on the button pressed.

Recognized options:

-b, --buttons=list  Required. A list of buttons for the message box.
                    This is a comma-separated string of "label:exitcode" pairs.
                    Optionally, a stock GTK+ button can be specified with the
                    pattern "label:icon:exitcode".
                    Default: "OK:OK:0"
-d, --default=label Sets the default button for the message box.  The label is
                    the same as the label used in the --buttons option.
-p, --print         Prints the exit code to STDOUT.  The exit code is appended
                    to any other output.
-t, --title=string  Sets the window title for the message box.
-e, --entry=string  Adds a text entry box to the message window.  This option 
                    can be given multiple times to add multiple entry boxes.
                    The string can be one of the following formats: "default", 
                    "label:default", or "label:name:default".  The "default" 
                    string gives the default value of the entry box, the "label"
                    is the text of a label immediately to the left of the box, 
                    and, "name" is a field name printed with the entry contents
                    as "name=contents" when the program exits.  The contents are
                    printed to STDOUT, seperated by delimiter characters, when 
						  the program exits. 
-c, --combo=string  Same as --entry, except that a combo box is used instead
                    of a text entry box.  The string format is the same, 
                    except that "default" is a comma-seperated list of combo box
                    entries.  The default is always the first entry in the 
                    list. 
-k, --check=string  Same as --entry, but adds a check box.  The 'default' string
                    is either "0" or "1" for unchecked and checked respectively.
-o, --option=string Like --combo, but creates a group of option buttons (a.k.a.
                    radio buttons) where the default string is a list of labels.
                    The default button is always the first.  The position of the
                    button in the list, starting at 0, is printed to STDOUT.
-l, --delimiter=c   Sets the delimiter character used with multiple entry, 
                    combo, and check boxes to delimit entered strings.  The 
                    default is the value of the PYMESSAGE_DELIMITER environment
						  variable or ":" if that variable is not set.
-f, --file=path     Read the message text from a file rather than the command 
                    line.  This causes any message on the command line to be
                    ignored.  Use the "-" symbol for STDIN.
-x, --text          Display the message in a TextView rather than a label.  The
                    TextView supports scroll bars and can be useful for viewing 
                    sizable files, etc.  This causes Pango markup to be ignored.
-m, --markup        Treat message_text as Pango markup instead of plain text.
                    For a list of pango markup attributes, see
             http://developer.gnome.org/doc/API/2.0/pango/PangoMarkupFormat.html
-n, --font          Set the GTK+ font for the text, e.g. "Sans 12"
-z, --font-size=n   Set the font size for the text in 1000ths of a point 
                    or as a literal like "small" or "larger".

The following cause all other options to be ignored:

-h, --help           Prints this message.
-v, --version        Prints the version number.
-s, --stock-icons    Prints the table of stock GTK+ buttons.
-i, --info           Pops up the message in a ROX info box.
-a, --alert          Pops up the message in a ROX error box.
""" % (app_name, app_name)
	return s

# main
if __name__ == '__main__':

	try:
		option_args, data_args = getopt.getopt(sys.argv[1:], short_options, long_options)
	except:
		sys.stderr.write("Error: unrecognized option.\n")
		sys.exit(1)

	# Initialize the critical variables.
	print_flag = False
	use_combo = False
	use_markup = False
	msg_file = ''
	label_font = ''
	label_font_size = ''
	label_bg = ''
	label_fg = ''
	default_button = ''
	delimiter_string = os.getenv("PYMESSAGE_DELIMITER")
	if delimiter_string == None: delimiter_string = ':'
	button_list = ['OK:OK:0']
	control_list = []
	
	# I'm indecisive about how much border I like.
	border_width = 3  

	# Don't require the message text to be in quotes.
	msg = " ".join(data_args)

	# Start making the window.  Do option-independent stuff here
	# so that we can modify the window as we add options.
	win = rox.Window()
	win.connect("delete_event", wm_del)
	win.set_resizable(True);
	win.set_border_width(border_width)
	win.set_position(g.WIN_POS_CENTER)
	vbox = g.VBox()

	msg_label = g.Label()
	msg_label.set_line_wrap(True)
	vbox.pack_start(msg_label, True, True, 10)
	
	for optpair in option_args:
		opt, arg = optpair
		if opt == '--buttons' or opt == '-b':
			button_list = string.split(arg, ',')
		elif opt == '--print' or opt == '-p':
			print_flag = True
		elif opt == '--default' or opt == '-d':
			default_button = arg
		elif opt == '--title' or opt == '-t':
			win.set_title(arg)
		elif opt == '--entry' or opt == '-e':
			control_list.append(controls.EntryWrapper(arg))
			curr_idx = len(control_list) - 1
			control_list[curr_idx].add_control(vbox)
		elif opt == '--combo' or opt == '-c':
			control_list.append(controls.ComboWrapper(arg))
			curr_idx = len(control_list) - 1
			control_list[curr_idx].add_control(vbox)
		elif opt == '--check' or opt == '-k':
			control_list.append(controls.CheckWrapper(arg))
			curr_idx = len(control_list) - 1
			control_list[curr_idx].add_control(vbox)
		elif opt == '--option' or opt == '-o':
			control_list.append(controls.OptionWrapper(arg))
			curr_idx = len(control_list) - 1
			control_list[curr_idx].add_control(vbox)
		elif opt == '--help' or opt == '-h':
			print help_message()
			sys.exit(0)
		elif opt == '--version' or opt == '-v':
			print version
			sys.exit(0)
		elif opt == '--stock-icons' or opt == '-s':
			print 'The list of valid stock icons is as follows:\n'
			print ','.join([x[6:] for x in dir(g) if x[:6] == 'STOCK_'])
			sys.exit(0)
		elif opt == '--info' or opt == '-i':
			rox.info(msg)
			sys.exit(0)
		elif opt == '--alert' or opt == '-a':
			rox.alert(msg)
			sys.exit(0)
		elif opt == '--text' or opt == '-x':
			pass
		elif opt == '--markup' or opt == '-m':
			use_markup = True
		elif opt == '--font' or opt == '-n':
			label_font = arg
		elif opt == '--font-size' or opt == '-z':
			label_font_size = arg
		elif opt == '--file' or opt == '-f':
			msg_file = arg
		elif opt == '--delimiter' or opt == '-l':
			delimiter_string = arg

	hbox = g.HBox()
	win.add(vbox)

	if msg_file != '':
		if os.path.isfile(msg_file):
			try:
				mf = open(msg_file)
			except:
				rox.croak("Cannot open message file " + msg_file)
			ln = mf.readline()
			msg = ln
			while ln != '':
				ln = mf.readline()
				msg += '\n' + ln
		elif msg_file == '-':
			try:
				msg = ''
				while True:
					msg += raw_input()
			except:
				pass
		else:
			rox.croak("Fatal error: " + msg_file + " is not a file.")
	
	marked_msg = msg
	if not use_markup:
		marked_msg = mark_text(msg, label_font, label_font_size)
	# No markup requested or used.
	if marked_msg == msg and not use_markup:
		msg_label.set_text(msg)
	# Explicit or implicit use of markup.
	else:
		try:
			msg_label.set_markup(marked_msg)
		except:
			rox.croak("Error formatting text.  Try again without formatting flags.")

	vbox.pack_start(hbox, False)

	for str in button_list:
		button_icon = ''
		try:
			caption, exit_code = string.split(str, ':')
		except:
			try:
				caption, icon_name, exit_code = string.split(str, ':')
			except IndexError:
				rox.alert("Unable to parse button definition!")
				sys.exit(1)
		try:
			button_icon = getattr(g, 'STOCK_' + icon_name.upper())
			btn = rox.ButtonMixed(button_icon, caption)
		except:
			btn = g.Button(caption)
		btn.connect('clicked', exit_app, exit_code)
		hbox.pack_start(btn, )
		if caption == default_button:
			btn.set_flags(g.CAN_DEFAULT)
			btn.grab_default()

	win.show_all()
	rox.mainloop()
