#!/usr/bin/env python
# $Id: xlist,v 1.8 2004/10/20 08:20:06 davep Exp $

from Tkinter import *
import re, sys, getopt, string, dp_io
import editone_a

DEF_font = 'arial 14'
split_on_spaces = 0

class XLister(Frame):
    def __init__(self, master=None, allow_new_item_p=True):
	Frame.__init__(self, master)
	self.title("")
	self.sel_desel = 's'	# does <Return> sel or desel?
	self.exit_req = 0	# 'semaphore' that we want to exit
	self.create_widgets()
	self.pack(fill=BOTH, expand=TRUE) # pack now so we can play with
        self.exit_rc = 0
        self.allow_new_item_p = allow_new_item_p
	# the widget before its filled
	self.fill_listbox(allow_new_item_p)
	for k in "xXqQDd":
	    self.bind_all("<Alt-%c>" % k,
			  self.emit_and_exit_event)
	for k in "xXqQDd":
	    self.bind_all("<Control-%c>" % k,
			  self.emit_and_exit_event)

    def title(self, title_anno):
	self.master.title("xlist " + title_anno)

    def exit(self):
	sys.exit(self.exit_rc)
		
    def dump_event(self, event):
	print `event`
	print event.__dict__

    def emit_selection(self):
        sellist = self.listbox.curselection()
        new_item = `self.listbox.size() - 1`
        for item in sellist:
            if item == new_item:
                continue
            s = self.listbox.get(item)
            print s

    def emit_and_exit(self):
	self.exit_req = 1
	self.emit_selection()
	self.exit()

    def emit_and_exit_event(self, event):
	if event.char in "qQ":
	    self.clear_selection()
	self.emit_and_exit()

    def listbox_take_focus(self, event=None):
	self.listbox.focus()

    def clear_selection(self):
	self.listbox.select_clear(0, END)

    def create_buttonbar(self):
	bb = self.buttonbar = Frame(self)
	self.exit_button = Button(bb, text="Done", 
				  command=self.emit_and_exit)
	self.exit_button.pack(side=LEFT, expand=TRUE)
	self.clear_button = Button(bb, text="Clear",
				   command=self.clear_selection)
	self.clear_button.pack(side=LEFT, expand=TRUE)
	self.edit_button = Button(bb, text="Edit",
				   command=self.do_edit_entry)
	self.edit_button.pack(side=LEFT, expand=TRUE)
	self.buttonbar.pack(side=TOP, fill=X, expand=FALSE)

    def do_edit_entry(self):
	item_num = self.listbox.index('active')
	dp_io.cdebug(1, "item_num: {}, size: {}\n",
                     item_num, self.listbox.size())
	curselection = self.listbox.curselection()
	if item_num == self.listbox.size() - 1:
	    new = 1
	    s = ''
	else:
	    new = 0
	    s = self.listbox.get('active')

	e = editone_a.EditOne(self, default=s, prompt='', title='Edit Item')
        dp_io.cdebug(1, "e: {}\n", e)
	s = e.go()
	dp_io.cdebug(1, "s: {}\n", s)
	if s:
	    self.listbox.delete(item_num)
	    self.listbox.insert(item_num, s)
	    if new:
		self.listbox.insert(END, '*** NEW ***')
	del e

    def edit_entry(self, event):
	self.do_edit_entry()

    def create_scrollbox(self):
	sb = self.scrollbox = Frame(self)
	sb.pack(side=TOP, expand=TRUE, fill=BOTH)
	self.yscroll = Scrollbar(sb)
	self.yscroll['takefocus'] = 0
	self.xscroll = Scrollbar(sb, orient='horizontal')
	self.xscroll['takefocus'] = 0
	self.listbox = Listbox(sb,
                               font=DEF_font,
			       selectmode=sel_mode,
			       selectborderwidth=1,
			       yscroll=self.yscroll.set,
			       xscroll=self.xscroll.set)
	self.xscroll.pack(side=BOTTOM, fill=X)
	self.listbox.pack(side=LEFT, expand=TRUE, fill=BOTH)
	self.yscroll.pack(side=RIGHT, fill=Y)
	self.yscroll['command'] = self.listbox.yview
	self.xscroll['command'] = self.listbox.xview
	self.listbox.focus()
	self.listbox.bind('<1>', self.listbox_take_focus, add='+')
	self.listbox.bind('<Double-1>', self.edit_entry)
        self.listbox.bind('<Return>', self.emit_and_exit_event)

    def sel_or_desel_pattern(self, sel):
	self.sel_desel = sel
	self.pf_label['text'] = self.make_pflabel()
	p = re.compile(self.pf_pattern.get())
	if sel == 's':
	    func = self.listbox.select_set
	else:
	    func = self.listbox.select_clear
	for item in range(self.listbox.size()):
	    l = self.listbox.get(item)
	    if p.search(l) >= 0:
		func(item, item)
				
    def resel(self, event):
	self.sel_or_desel_pattern(self.sel_desel)
	
    def select_pattern(self):
	self.sel_or_desel_pattern('s')

    def select_pattern_event(self, event):
	self.pf_select.invoke()

    def deselect_pattern(self):
	self.sel_or_desel_pattern('d')

    def deselect_pattern_event(self, event):
	self.pf_deselect.invoke()

    def make_pflabel(self):
	return "Pattern(%s):" % self.sel_desel

    def create_patternframe(self):
	pf = self.patternframe = Frame(self)
	self.pf_label = Label(pf, 
			      text=self.make_pflabel())
	self.pf_label.pack(side=LEFT)
	self.pf_pattern = Entry(pf)
	self.pf_pattern.bind('<Return>', self.resel)

	self.pf_pattern.pack(side=LEFT, expand=TRUE, fill=X)
	self.pf_select = Button(pf, text='Select',
			      command=self.select_pattern)

	self.pf_select.pack(side=LEFT)
	self.pf_deselect = Button(pf, text='Deselect',
			      command=self.deselect_pattern)
	self.pf_deselect.pack(side=LEFT)
	pf.pack(side=TOP, expand=FALSE, fill=X)
	self.pf_pattern.bind('<Control-s>', 
			     self.select_pattern_event)
	self.pf_pattern.bind('<Control-d>', 
			     self.deselect_pattern_event)

    def create_widgets(self):
	self.create_buttonbar() 
	self.create_patternframe()
	self.create_scrollbox()
        self.listbox_take_focus()

    def fill_listbox(self, allow_new_item_p=True):
	if not sys.stdin.isatty():
	    self.title("reading...")
	    while 1:
		line = sys.stdin.readline()
		if not line or self.exit_req:
		    break
		try:
		    while line[-1] in "\r\n":
			line = line[:-1]
		except IndexError:
		    pass
                if split_on_spaces:
                    llist = string.split(line)
                else:
                    llist = [line]
                for line in llist:
                    self.listbox.insert(END, line)
		self.listbox.update()
            if allow_new_item_p:
                self.listbox.insert(END, '*** NEW ***')
	self.title("ready.")

#
###################################
#
sel_mode = EXTENDED
if __name__ == "__main__":
    debug_level = 0
    verbose_level = 0
    allow_new_item_p = True
    options, args = getopt.getopt(sys.argv[1:], 'nsef:wdD:vV:')
    for o, v in options:
        # print 'o>%s<, v>%s<' % (o, v)
        if o == '-s':
            sel_mode = SINGLE
            continue
        if o == '-e':
            sel_mode = EXTENDED
            continue
        if o == '-f':
            DEF_font = v
            continue
        if o == '-w':
            split_on_spaces = 1
            continue
        if o == '-d':
            debug_level = debug_level + 1
            continue
        if o == '-D':
            debug_level = eval(v)
            continue
        if o == '-v':
            verbose_level = verbose_level + 1
            continue
        if o == '-V':
            verbose_level = eval(v)
            continue
        if o == '-n':
            allow_new_item_p = False
            continue

    if debug_level >= 0:
        dp_io.set_debug_level(debug_level, enable_debugging_p=True)
    if verbose_level > 0:
        dp_io.set_verbose_level(verbose, enable=True)

    dp_io.cdebug(1, "debug_level: {}\n", debug_level)
    app = XLister(allow_new_item_p=allow_new_item_p)
    app.mainloop()
    sys.exit(0)
    
