#!/usr/bin/python

#     foomatic-gui - GNOME2 interface to the foomatic printing system
#     Copyright (C) 2002-05 Chris Lawrence <lawrencc@debian.org>
#
#     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
#
# $Id: foomatic-gui,v 1.64 2008/10/03 11:18:22 lordsutch Exp $

from __future__ import generators

import warnings
warnings.filterwarnings("ignore", category=FutureWarning)

DEBUG = False

import foomatic
import sys
import os
import urlparse

import cgi

APP = 'foomatic-gui'
VERSION = foomatic.__version__
COPYRIGHT = u"Copyright \u00a9 2002-05 Chris Lawrence"
SHAREDIR = '/usr/share/'+APP

TESTPAGE = os.path.join(SHAREDIR, 'testpage.ps')
if not os.path.exists(TESTPAGE):
    TESTPAGE = './testpage.ps'

LOGO = '/usr/share/pixmaps/foomatic-gui-logo.png'
if not os.path.exists(LOGO):
    LOGO = 'foomatic-gui-logo.png'

# Interface to foomatic-configure
from foomatic import foomatic, detect

# GNOME/Gtk stuff
#import pygtk
#pygtk.require("2.0")

import gtk
import gtk.glade, gobject, gnome, bonobo.ui, gnome.ui, pango
gnome.init(APP, VERSION)

try:
    import gnomevfs
except:
    import gnome.vfs
    gnomevfs = gnome.vfs
    
import tempfile
import gtkhtml2

import new
import types
import string
import re

# i18n
DIR = '/usr/share/locale'

import locale, gettext
locale.setlocale (locale.LC_ALL, '')
gettext.bindtextdomain (APP, DIR)
gettext.textdomain (APP)
gettext.install (APP, DIR, unicode=1)
gtk.glade.bindtextdomain (APP, DIR)
gtk.glade.textdomain (APP)

# Probably conservative
valid_queue_chars = string.ascii_letters+string.digits+'_'
invalidre = re.compile(r'([^A-Za-z0-9_])')

def fetch_uri(uri):
    return foomatic.get_ppd_content(uri)

def make_queuename(model):
    model = model.lower().replace(' ', '_')
    newmod = invalidre.sub('', model)
    return newmod

class NoQueueSelected(Exception):
    pass

# Busy/non-busy cursors
busy_cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
ready_cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)

class GUI(gtk.glade.XML):
    # Thoroughly lazy code :-)
    def __getattr__(self, attr):
        try:
            return self.get_widget(attr)
        except:
            raise AttributeError, attr

    def __init__(self):
        if os.path.exists('foomatic-gui.glade'):
            gtk.glade.XML.__init__(self, 'foomatic-gui.glade')
        else:
            gtk.glade.XML.__init__(self, os.path.join(SHAREDIR, 'foomatic-gui.glade'))

        if True:
            callbacks = {}
            class_methods = self.__class__.__dict__
            for (method, val) in class_methods.items():
                if isinstance(val, types.FunctionType):
                    callbacks[method]=new.instancemethod(val, self, self.__class__)

            self.signal_autoconnect(callbacks)
        else:
            self.signal_autoconnect()

        self.mfgpageselectedrow = None
        
        view = self.treeview1
        self.model = gtk.ListStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING,
                                   gobject.TYPE_STRING, gobject.TYPE_INT)
        view.set_model(self.model)
        renderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_('Name'), renderer, text=1, weight=3)
        view.append_column(column)
        column = gtk.TreeViewColumn(_('Description'), renderer, text=2, weight=3)
        view.append_column(column)
        selection = view.get_selection()
        selection.connect('changed', self.fix_buttons)

        view = self.iface_treeview
        self.iface_model = gtk.ListStore(gobject.TYPE_PYOBJECT,
                                         gobject.TYPE_STRING,
                                         gobject.TYPE_STRING)
        view.set_model(self.iface_model)
        renderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_('Device'), renderer, text=1)
        view.append_column(column)
        column = gtk.TreeViewColumn(_('Description'), renderer, text=2)
        view.append_column(column)
        selection = view.get_selection()
        selection.connect('changed', self.fix_iface_buttons)

        view = self.maker_treeview
        self.maker_model = gtk.ListStore(gobject.TYPE_STRING)
        view.set_model(self.maker_model)
        renderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_('Manufacturer'), renderer, text=0)
        view.append_column(column)
        selection = view.get_selection()
        selection.connect('changed', self.on_maker_treeview_changed_row)
        selection.connect('changed', self.fix_mfgpage_buttons)

        view = self.model_treeview
        self.model_model = gtk.ListStore(gobject.TYPE_STRING,
                                         gobject.TYPE_PYOBJECT)
        view.set_model(self.model_model)
        renderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_('Printer Model'), renderer, text=0)
        view.append_column(column)
        selection = view.get_selection()
        selection.connect('changed', self.fix_mfgpage_buttons)

        view = self.driver_treeview
        self.driver_model = gtk.ListStore(gobject.TYPE_PYOBJECT,
                                          gobject.TYPE_STRING,
                                          gobject.TYPE_STRING)
        view.set_model(self.driver_model)
        renderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_('Driver'), renderer, text=1)
        view.append_column(column)
        # At some point, we should add parsing of driver descriptions
        #renderer = gtk.CellRendererText()
        #column = gtk.TreeViewColumn('Description', renderer, text=1)
        #view.append_column(column)
        selection = view.get_selection()
        selection.connect('changed', self.fix_driverpage_buttons)

        htmlview = gtkhtml2.View()
        self.printinfo = gtkhtml2.Document()
        self.printinfo.connect('link-clicked', self.link_clicked)
        htmlview.connect("on_url", self.on_url)
        self.printinfo.connect("request-url", self.request_url)
        htmlview.get_vadjustment().set_value(0)
        self.printinfowin.set_hadjustment(htmlview.get_hadjustment())
        self.printinfowin.set_vadjustment(htmlview.get_vadjustment())
        self.printinfo.clear()
        htmlview.set_document(self.printinfo)
        self.printinfowin.add(htmlview)
        self.printinfowin.show_all()
        self.printinfowin.set_sensitive(False)

        # Splash screen? - this will take a few seconds
        self.printdb = foomatic.get_printer_db()
        if not self.printdb:
            print >> sys.stderr, 'Unable to read printer database.'
            raise SystemExit
        self.setup_mfg_page()

        self.fix_buttons()
        self.setup_list()

        if os.getuid():
            # Disable add/configure buttons
            for button in (self.add_button, self.rem_button, self.prop_button,
                           self.add_printer1, self.remove_printer1,
                           self.properties1):
                button.set_sensitive(False)

        self.logo = gtk.gdk.pixbuf_new_from_file(LOGO)
        gtk.window_set_default_icon_list(self.logo)
        
        self.mainWindow.show()

    def set_status(self, fmt, *args):
        self.appbar1.set_status(fmt % args)
        self.redraw()

    def redraw(self):
        while gtk.events_pending():
            gtk.main_iteration(False)

    # Perhaps unnecessary?
    def hide_window(self, win, *args):
        win.hide()
        return True

    def win_busy(self, win):
        win.set_sensitive(False)
        if win.window:
            win.window.set_cursor(busy_cursor)
        self.redraw()

    def win_ready(self, win):
        if win.window:
            win.window.set_cursor(ready_cursor)
        win.set_sensitive(True)

    def busy(self):
        self.win_busy(self.mainWindow)

    def ready(self, *args):
        self.win_ready(self.mainWindow)

    on_optionsDialog_hide = on_queuewin_hide = ready
    
    def on_about1_activate(self, *args):
        about = gnome.ui.About(
            APP, VERSION, COPYRIGHT,
            _("Universal Printer Configuration System for GNOME"),
            ['Chris Lawrence <lawrencc@debian.org>',
             _('pysmb was written by Tim Waugh <twaugh@redhat.com>.'),
             _('Foomatic development is coordinated by Grant Taylor '
               'and Till Kamppeter.')],
            None, None, self.logo)
        about.show()
        
    def on_mainWindow_delete_event(self, *args):
        gtk.main_quit()

    def setup_list(self, selected=None):
        if not selected:
            try:
                selqueue = self.get_selected_queue()['name']
            except:
                selqueue = None

        self.model.clear()
        queueinfo = foomatic.get_printer_queues()
        if not queueinfo:
            print >> sys.stderr, 'Unable to get printer queue list.'
            raise SystemExit
            
        self.queueinfo = queueinfo
        self.spooler = foomatic.guess_spooler(queueinfo)

        for (i, queue) in enumerate(queueinfo.queues):
            qname = queue['name']
            location = queue.get('location', '')
            description = queue.get('description', '')
            if location and description:
                loc = '%s (%s)' % (queue['description'], queue['location'])
            else:
                loc = description or location

            if qname == queueinfo.defqueue:
                weight = pango.WEIGHT_BOLD
                loc += _(' (default queue)')
                if not selected and not selqueue:
                    selected = i
            else:
                weight = pango.WEIGHT_NORMAL

            if not selected and selqueue and qname == selqueue:
                selected = i
            
            iterator = self.model.append()
            self.model.set(iterator, 0, queue, 1, queue['name'], 2, loc,
                           3, weight)
        # Select something
	if selected:
            self.treeview1.get_selection().select_path((selected,))

    def fix_buttons(self, *args):
        model, iterator = self.treeview1.get_selection().get_selected()
        try:
            queue = self.get_selected_queue()
            enabled = True
        except NoQueueSelected:
            queue = None
            enabled = False

        modstuff = enabled
        if os.getuid():
            modstuff = False
            
        for button in (self.rem_button, self.prop_button,
                       self.remove_printer1, self.properties1):
            button.set_sensitive(modstuff)
            
        for button in [self.ptp_button, 
                       self.makedef_button, self.print_test_page1,
                       self.makedefault]:
            button.set_sensitive(enabled)

        if queue:
            enabled = queue.get('_foomatic', False)

        for button in [self.set_options1, self.options_button]:
            button.set_sensitive(enabled)

    def get_selected_queue(self):
        model, iterator = self.treeview1.get_selection().get_selected()
        try:
            return model.get_value(iterator, 0)
        except TypeError:
            raise NoQueueSelected

    def on_ptp_button_clicked(self, *args):
        try:
            queue = self.get_selected_queue()
        except NoQueueSelected:
            return
        qname = queue['name']
        
        self.set_status(_('Sending test page to %s.'), qname)
        foomatic.send_test_page(TESTPAGE, queue)
        self.set_status(_('Test page sent to %s.'), qname)

    def on_makedef_button_clicked(self, *args):
        try:
            queue = self.get_selected_queue()['name']
        except NoQueueSelected:
            return
        self.set_status(_('Changing default printer to %s.'), queue)
        foomatic.set_default_queue(queue)
        self.setup_list()
        self.set_status(_('Default printer changed to %s.'), queue)

    def on_rem_button_clicked(self, *args):
        try:
            queue = self.get_selected_queue()['name']
        except NoQueueSelected:
            return
        # Probably should have a confirmation dialog
        self.set_status(_('Removing printer queue %s.'), queue)
        foomatic.remove_queue(queue)
        self.setup_list()
        self.set_status(_('Printer queue %s removed.'), queue)

    def on_add_button_clicked(self, *args):
        self.busy()
        self.druid1.set_page(self.druidpagestart1)
        # Not sure why I need this, but I do...
        self.druidpagestart1.show()
        self.druidpagefinish1.show()
        self.queue = {}
        self.queuename.set_sensitive(True)
        self.fillin_queue_info()
        self.queuewin.set_title(_('Add Printer'))
        self.druid1.set_buttons_sensitive(False, True, True, True)
        self.queuewin.show()

    def on_prop_button_clicked(self, *args):
        try:
            queue = self.get_selected_queue()
        except NoQueueSelected:
            return
        self.busy()
        self.queue = queue
        self.druidpagestart1.show()
        self.druidpagefinish1.show()
        self.ppdfile.gtk_entry().set_text('')

        self.druid1.set_page(self.connectionpage)
        self.fix_iface_buttons()

        self.queuename.set_sensitive(False)
        self.fillin_queue_info()
        self.update_printer_connections()

        conn = queue.get('connect', '')
        
        self.queuewin.set_title(_('Modify Printer'))
        self.queuewin.show()

        for (i, iterator) in enumerate(self.iface_model):
            device = iterator[0][0]
            if device == conn or conn.endswith(device):
                self.iface_treeview.get_selection().select_path((i,))
                self.iface_treeview.scroll_to_cell((i,), None, True, 0.5, 0)

    def fillin_queue_info(self):
        self.queuename.set_text(self.queue.get('name', ''))
        self.interface.set_text(self.queue.get('connect', ''))
        self.printerlocation.set_text(self.queue.get('location', ''))
        self.printerdesc.set_text(self.queue.get('description') or '')

    def on_druidpagestart1_next(self, *args):
        self.update_printer_connections()
        self.ppdfile.gtk_entry().set_text('')
        self.druid1.set_page(self.connectionpage)
        self.fix_iface_buttons()
        return True

    def on_network_detect_clicked(self, *args):
        self.update_printer_connections(remote=True)

    def update_printer_connections(self, remote=False):
        self.win_busy(self.queuewin)
        self.set_status(_('Updating printer connections...'))
        view = self.iface_treeview
        model = self.iface_model
        model.clear()
        view.get_selection().unselect_all()
        conns = detect.printer_connections(remote)
        for printer in conns:
            iterator = model.append()
            model.set(iterator, 0, printer, 1, printer[2], 2, printer[3])

        iface = self.interface.get_text()
        if iface:
            proto = (urlparse.urlsplit(iface)[0]).upper()
            printer = (iface, {}, proto+' queue', iface)
            iterator = model.append()
            model.set(iterator, 0, printer, 1, printer[2], 2, printer[3])

        self.set_status(_('Done'))
        self.win_ready(self.queuewin)

    def fix_iface_buttons(self, *args):
        model, iterator = self.iface_treeview.get_selection().get_selected()
        isnew = not self.queue
        enabled = bool(iterator)
        
        self.druid1.set_buttons_sensitive(isnew, enabled, True, True)

    def on_printerdetails_back(self, *args):
        if self.interface.get_property('sensitive'):
            return False
        self.druid1.set_page(self.connectionpage)
        return True

    def on_manualconn_clicked(self, *args):
        self.interface.set_sensitive(True)
        self.druid1.set_page(self.interfacepage)

    def on_connectionpage_next(self, *args):
        model, iterator = self.iface_treeview.get_selection().get_selected()
        if not iterator:
            return True

        # Information about the printer we think this is
        self.pdbinfo = {}
        self.pdriver = ''

        if self.queue:
            printerid = self.queue.get('printer')
            if printerid:
                self.pdbinfo = self.printdb.printers.get(printerid)
                self.pdriver = self.queue.get('driver')
            
        item = model.get_value(iterator, 0)
        device, detected, iface = item[:3]
        if device:
            self.interface.set_text(device)
            self.interface.set_sensitive(False)
            if detected and not self.queue:
                self.queue['description'] = desc = detected.get('description', '')
                self.queue['location'] = iface
                self.queue['name'] = make_queuename(detected.get('model', ''))
                self.queue['connect'] = device
                self.fillin_queue_info()

                mfg = detected.get('manufacturer', '')
                model = detected.get('model', '')
                if desc:
                    self.pdbinfo = self.printdb.autodetect_ids.get(desc)
                    if self.pdbinfo:
                        self.pdriver = self.pdbinfo.get('driver')
                
                if not self.pdbinfo and mfg and model:
                    self.pdbinfo = self.printdb.autodetect_ids.get((mfg,model))
                    if self.pdbinfo:
                        self.pdriver = self.pdbinfo.get('driver')

                if not self.pdbinfo:
                    # Try the detected manufacturer and model info,
                    # normalized to upper case
                    mfg = mfg.upper()
                    model = model.upper()

                    self.pdbinfo = self.printdb.cmakes.get(mfg, {}).get(model)
                    if self.pdbinfo:
                        self.pdriver = self.pdbinfo.get('driver')

            if self.pdriver == 'gimp-print':
                if self.pdbinfo and 'gimp-print-ijs' in self.pdbinfo.get('drivers'):
                    self.pdriver = 'gimp-print-ijs'

            self.druid1.set_page(self.printerdetails)
            self.fix_printerdetails_buttons()
            return True

        self.interface.set_sensitive(True)
        return False

    def setup_mfg_page(self, *args):
        view = self.maker_treeview
        model = self.maker_model
        model.clear()
        self.set_status(_('Updating printer listing...'))
        makes = self.printdb.makes.keys()
        makes.sort()
        for maker in makes:
            iterator = model.append()
            model.set(iterator, 0, maker)
        self.set_status(_('Done'))

    def fix_printerdetails_buttons(self, *args):
        enabled = bool(self.queuename.get_text())
        self.druid1.set_buttons_sensitive(True, enabled, True, True)
        return True

    def on_printerdetails_prepare(self, *args):
        self.fix_printerdetails_buttons()

    def on_printerdetails_next(self, *args):
        selob = self.maker_treeview.get_selection()
        selob.unselect_all()
        self.oldmake = None
        self.druid1.set_page(self.mfgpage)
        if self.pdbinfo:
            known_mfg = self.pdbinfo.get('make')
            for (i, iterator) in enumerate(self.maker_model):
                maker = iterator[0]
                if maker == known_mfg:
                    selob.select_path((i,))
                    self.maker_treeview.scroll_to_cell((i,), None, True, 0.5, 0)
                    self.oldmake = known_mfg
        self.fix_mfgpage_buttons()
        self.redraw()
        return True
    
    def fix_mfgpage_buttons(self, *args):
        printinfo = None
        pathname = self.ppdfile.get_full_path(True)
        enabled = (pathname and os.path.isfile(pathname)) or False

        selected = self.model_treeview.get_selection().get_selected_rows()
        if self.mfgpageselectedrow:
            changed = (selected != self.mfgpageselectedrow)
        else:
            changed = True

        #print changed, selected, self.mfgpageselectedrow
        self.mfgpageselectedrow = selected
        if selected[1]:
            enabled = True
            
        if selected[1] and changed:
            model, iterator = self.model_treeview.get_selection().get_selected()
            if iterator:
                pdriver = model.get_value(iterator, 1)
                pid = pdriver['id']
                printdata = foomatic.get_printer_info(pid)
                # XXX: Don't hardcode the language
                comments = printdata.comments.get('en', '').strip()
                # Remove multiple spaces, since Pango renders them
                comments = re.sub(r'[ \t]+', ' ', comments)
                printinfo = _('<p>Information about this printer from <a href="http://www.linuxprinting.org/show_printer.cgi?recnum=%s">LinuxPrinting.org</a>:</p>') % pid

                mechinfo = printdata.mechanism
                ptype = mechinfo.get('type', '')
                if ptype:
                    ptype = _(ptype)

                if mechinfo.get('color', False):
                    dbinfo = _('Colour %s printer, ') % ptype
                else:
                    dbinfo = _('Black and white %s printer, ') % ptype

                dpi = mechinfo.get('resolution', {}).get('dpi')
                if dpi:
                    dbinfo += _('max %d&times;%d dpi, ') % (
                        dpi['x'], dpi['y'])
                func = printdata.functionality
                dbinfo += {
                    'A' : _('works <span style="color: green">perfectly</span>'),
                    'B' : _('works <span style="color: green">mostly</span>'),
                    'D' : _('works <span style="color: orange">partially</span>'),
                    'F' : _('is a <span style="color: red">paperweight</span> (does not work)'),
                    }.get(func, _('functionality unknown'))

                printinfo += '<p>'+dbinfo+'.</p>'
                printinfo += comments
                if printdata.url:
                    printinfo += _('<p><a href="%s">Manufacturer\'s information</a>.</p>') % cgi.escape(printdata.url.strip(), 1)
                if pdriver.get('drivers'):
                    enabled = True

        self.druid1.set_buttons_sensitive(True, enabled, True, True)

        if changed:
            self.printinfo.clear()
            if printinfo:
                self.printinfo.open_stream('text/html')
                html = '''<html><head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    </head><body>%s</body></html>''' % printinfo
                html = html.encode('utf-8')
                self.printinfo.write_stream(html)
                self.printinfo.close_stream()
                va = self.printinfowin.get_vadjustment()
                va.set_value(va.lower)
                self.printinfowin.set_sensitive(True)
            else:
                self.printinfowin.set_sensitive(False)

    def dummy(self):
        # Put strings here that we need translated that don't actually
        # appear in foomatic-gui
        _("inkjet")
        _("laser")
        _('thermal transfer')
        _('dot-matrix')
        _('LED')

    def on_maker_treeview_changed_row(self, selob):
        model, iterator = selob.get_selected()
        if not iterator:
            self.model_model.clear()
            self.oldmake = None
            return

        make = model.get_value(iterator, 0)
        if make == self.oldmake:
            return
        self.oldmake = make

        # Clear the printinfo when we change rows
        self.printinfo.clear()
        self.printinfowin.set_sensitive(False)

        view = self.model_treeview
        model = self.model_model
        model.clear()
        self.set_status(_('Updating printer listing...'))
        printer_models = self.printdb.makes[make].items()
        printer_models.sort()
        for (x, y) in printer_models:
            iterator = model.append()
            model.set(iterator, 0, x, 1, y)
        self.set_status(_('Done'))

        selob = self.model_treeview.get_selection()
        selob.unselect_all()
        if self.pdbinfo and self.pdbinfo.get('make') == make:
            known_model = self.pdbinfo.get('model')
            for (i, iterator) in enumerate(self.model_model):
                if iterator[0] == known_model:
                    selob.select_path((i,))
                    self.model_treeview.scroll_to_cell((i,), None, True, 0.5, 0)
                    break
        else:
            #selob.select_path((0,))
            self.model_treeview.scroll_to_cell((0,), None, True, 0.5, 0)

    def on_mfgpage_next(self, *args):
        ppdfile = self.ppdfile.get_full_path(True)
        if ppdfile:
            self.druidpagefinish1.show()
            self.druid1.set_page(self.druidpagefinish1)
            return True
        
        selob = self.model_treeview.get_selection()
        model, iterator = selob.get_selected()
        if not iterator:
            return True
        
        printer = model.get_value(iterator, 1)
        pid = self.queue['printer'] = printer['id']
        
        printdata = foomatic.get_printer_info(pid)

        drivers = printer['drivers']
        if not drivers:
            self.druid1.set_page(self.mfgpage)
            return True
            
        best_driver = printer.get('driver', drivers[0])
        if best_driver == 'gimp-print' and 'gimp-print-ijs' in drivers:
            best_driver = 'gimp-print-ijs'
        
        sel_driver = self.queue.get('driver', '')
        
        view = self.driver_treeview
        model = self.driver_model
        model.clear()
        self.set_status(_('Updating driver listing...'))
        drivers.sort()
        best = selected = None

        # Skip the gimp-print driver
        try:
            drivers.remove('gimp-print')
        except:
            pass
        
        for (i, driver) in enumerate(drivers):
            iterator = model.append()
            driver_info = driver
            if driver == best_driver:
                if driver != 'Postscript' or not printdata.ppd:
                    driver_info += _(' (recommended)')
                best = i
            if driver == sel_driver:
                selected = i
                
            model.set(iterator, 0, driver, 1, driver_info, 2,
                      '(description here)')

        if ('Postscript' in drivers) and printdata.ppd:
            iterator = model.append()
            driver = 'ppd:'+printdata.ppd
            driver_info = 'Postscript using manufacturer PPD file'
            if best_driver == 'Postscript':
                best = len(drivers)
                driver_info += _(' (recommended)')
                
            model.set(iterator, 0, driver, 1, driver_info, 2,
                      '(description here)')
            
        self.set_status(_('Done'))

        selob = self.driver_treeview.get_selection()
        selob.unselect_all()

        if (selected is not None) or (best is not None):
            row = (selected or best)
            selob.select_path((row,))
            self.driver_treeview.scroll_to_cell((row,), None, True, 0.5, 0)
        
        self.druid1.set_page(self.driverpage)
        self.fix_driverpage_buttons()
        return True

    def fix_modelpage_buttons(self, *args):

        model, iterator = self.model_treeview.get_selection().get_selected()
        enabled = bool(iterator)
        self.druid1.set_buttons_sensitive(True, enabled, True, True)

    def fix_driverpage_buttons(self, *args):
        model, iterator = self.driver_treeview.get_selection().get_selected()
        enabled = bool(iterator)
        self.druid1.set_buttons_sensitive(True, enabled, True, True)

    # This is a bit of a hack to get around a goofy Druid bug that seems
    # to make it get stuck on the last standard page
    def on_driverpage_next(self, *args):
        selob = self.driver_treeview.get_selection()
        model, iterator = selob.get_selected()
        if not iterator:
            return True

        self.druid1.set_page(self.druidpagefinish1)
        self.druidpagefinish1.show()
        return True
        
    def on_druid1_cancel(self, *args):
        self.queuewin.hide()

    def on_druidpagefinish1_back(self, *args):
        if self.ppdfile.get_full_path(True):
            self.druid1.set_page(self.mfgpage)
            return True
        return False

    def on_druidpagefinish1_finish(self, *args):
        # 'printer' is already set above; grab all of this from the pages
        tfname = None
        self.queue['ppdfile'] = self.ppdfile.get_full_path(True)
        if not self.queue['ppdfile']:
            selob = self.driver_treeview.get_selection()
            model, iterator = selob.get_selected()
            d = self.queue['driver'] = model.get_value(iterator, 0)
            if d.startswith('ppd:'):
                # Fetch the PPD file from the Internet and use it
                uri = d[4:]
                data = fetch_uri(uri)
                if data:
                    (tfh, tfname) = tempfile.mkstemp(text=True, suffix=".ppd",
                                                     prefix="foomatic-")
                    tf = os.fdopen(tfh, 'w+')
                    tf.write(data)
                    tf.close()
                    self.queue['ppdfile'] = tfname
                else:
                    box = gtk.MessageDialog(
                        self.queuewin, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR,
                        gtk.BUTTONS_CLOSE,
                        _('Unable to retrieve PPD file from %s' % uri))
                    box.run()
                    box.destroy()
                    self.druid1.set_page(self.driverpage)
                    return

        self.queue['connect'] = self.interface.get_text()
        self.queue['description'] = self.printerdesc.get_text()
        self.queue['name'] = make_queuename(self.queuename.get_text())
        self.queue['location'] = self.printerlocation.get_text()

        if self.spooler == 'cups':
            os.system('touch /etc/cups/printers.conf')
        if DEBUG:
            print self.queue
        foomatic.setup_queue(self.queue)
        self.setup_list()

        # Reload cups... new filters don't work otherwise :-/
        if self.spooler == 'cups':
            # If we're on a recent Debian, use invoke-rc.d to make the admin
            # happier
            if os.path.exists('/usr/sbin/invoke-rc.d'):
                os.system('/usr/sbin/invoke-rc.d cups reload')
            else:
                # Add other distributions' locations here
                for init in ['/etc/init.d/cups']:
                    if os.path.exists(init):
                        os.system('%s reload' % init)

        if tfname and not DEBUG:
            os.unlink(tfname)
        self.queuewin.hide()

    def on_options_button_clicked(self, *args):
        try:
            queue = self.get_selected_queue()
        except NoQueueSelected:
            return

        self.set_status(_('Setting printer options...'))
        self.busy()
        self.optionsLabel.set_label(
            _('<b>Default options for printer %s</b>:') % queue['name'])

        options = foomatic.get_printer_options(queue)
        if not options or 'args' not in options:
            self.set_status(_('No arguments found!  (Is this a foomatic queue?)'))
            self.ready()
            return
        
        groupedargs, defaults, labels = \
                     foomatic.organize_printer_options(options)
        optwidgets = {}
        flatargs = {}
        for (group, args) in groupedargs.iteritems():
            flatargs.update(dict(args))

        notebook = gtk.Notebook()

        ordered = groupedargs.items()
        ordered.sort()
        for (group, args) in ordered:
            if not len(args):
                continue

            if group:
                glabel = group
            else:
                glabel = _('Miscellaneous Options')

            grouplabel = gtk.Label(glabel)
            grid = gtk.Table(rows=len(args), columns=2)

            for (row, (arg, vals)) in enumerate(args):
                label = labels[arg]
                l = gtk.Label(label+': ')
                # Right-align the label
                l.set_alignment(xalign=1, yalign=0.5)
                otype = options['args_byname'][arg]['type']
                if otype in ('int', 'float') and isinstance(vals, tuple):
                    default = float(defaults[arg])
                    low, high = vals
                    if otype == 'int':
                        adj = gtk.Adjustment(default, int(low), int(high),
                                             1, 10)
                        w = gtk.SpinButton(adj, 1, 0)
                        w.set_snap_to_ticks(True)
                    else:
                        adj = gtk.Adjustment(default, float(low), float(high),
                                             0.1, 1.0)
                        w = gtk.SpinButton(adj, 0.1, 2)
                        w.set_snap_to_ticks(False)
                    w.set_numeric(True)
                else:
                    # Use the human-readable comments as the entries
                    # in the menu
                    valmap = dict(vals)
                    default = valmap.get(defaults[arg])
                    w = gtk.combo_box_new_text()
                    for (i, x) in enumerate(vals):
                        w.append_text(unicode(x[1]))
                        if default == x[1]:
                            w.set_active(i)
                optwidgets[arg] = w
                grid.attach(l, 0, 1, row, row+1, yoptions=0)
                l.show()
                grid.attach(w, 1, 2, row, row+1, yoptions=0)
                w.show()

            grid.show()
            notebook.append_page(grid, grouplabel)

        if len(ordered) == 1:
            notebook.set_show_tabs(False)

        notebook.set_scrollable(True)

        notebook.show()
        self.optiongroupbox.pack_end(notebook)
        self.optionsDialog.show()
        response = self.optionsDialog.run()
        self.optionsDialog.hide()
        if response == gtk.RESPONSE_OK:
            # Grab the options
            option_settings = {}
            for (arg, widget) in optwidgets.iteritems():
                vals = flatargs[arg]
                otype = options['args_byname'][arg]['type']
                if otype == 'int':
                    setting = widget.get_value_as_int()
                elif otype == 'float':
                    setting = widget.get_value()
                else:
                    selected = widget.get_active()
                    if selected >= 0:
                        setting = vals[selected][0]
                    else:
                        setting = None
                #print arg, setting
                if setting is not None and setting != defaults[arg]:
                    option_settings[arg] = setting

            #print option_settings
            ppdfile = None
            if 'model' not in options:
                ppdfile = model['ppdfile']
            
            # Set the options
            foomatic.set_printer_options(queue, option_settings,
                                         ppdfile=ppdfile)
            self.set_status(_('Default printer options now set.'))
        else:
            self.set_status(_('Printer options dialog canceled.'))

        # Get rid of these boxes
        #for box in boxes:
        #    box.destroy()
        notebook.destroy()
        self.ready()
        return

    # Menu aliases
    on_print_test_page1_activate = on_ptp_button_clicked
    on_makedefault_activate = on_makedef_button_clicked
    on_remove_printer1_activate = on_rem_button_clicked
    on_add_printer1_activate = on_add_button_clicked
    on_properties1_activate = on_prop_button_clicked
    on_quit1_activate = on_mainWindow_delete_event
    on_set_options1_activate = on_options_button_clicked

    # HTML Stuff - currently not much here
    def on_url(self, view, url):
        return

    def link_clicked(self, document, link):
        link = link.strip()
        gnome.url_show(link)
        return

    def request_url(self, document, url, stream):
        return

def main():
    app = GUI()
    gtk.main()

main()

#print fetch_uri('http://www.linuxprinting.org/download/PPD/HP/mono_laser/HP_LaserJet_1200.ppd')
