|
Server : Apache/2.2.2 (Fedora) System : Linux App1.pathumtani.go.th 2.6.20-1.2320.fc5smp #1 SMP Tue Jun 12 19:40:16 EDT 2007 i686 User : apache ( 48) PHP Version : 5.2.9 Disable Function : NONE Directory : /usr/share/printconf/util/ |
Upload File : |
#!/usr/bin/python
## system-config-printer
## Queue tree window implementation
## Copyright (C) 2001-2006 Red Hat, Inc.
## Copyright (C) 2002-2006 Tim Waugh <twaugh@redhat.com>
## 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., 675 Mass Ave, Cambridge, MA 02139, USA.
import gettext
import sys
import time
if not "/usr/share/printconf/util" in sys.path:
sys.path.append ("/usr/share/printconf/util")
domain = 'printconf'
from rhpl.translate import _, N_
import rhpl.translate as translate
translate.textdomain (domain)
def help_message ():
print """usage: system-config-printer [OPTIONS]
Options:
--add-with-url URL Add a new printer described by URL
--help Display this usage message"""
import getopt
try:
options, args = getopt.getopt (sys.argv[1:], '', ['add-with-url=', 'help'])
except getopt.error:
help_message ()
sys.exit (1)
add_with_url = None
for each in options:
if each[0] == '--help':
help_message ()
sys.exit (0)
if each[0] == '--add-with-url':
add_with_url = each[1]
import printconf_conf
try:
printconf_conf.init_queue_edit_or_die ()
except IOError:
sys.stderr.write(_("You must be root to run this program.\n"))
sys.exit (1)
import errno
import os
import signal
# GUI imports
import gnome.ui
import gtk
import gtk.glade
import gtkhtml2
import gobject
# Other modules
import cups_import
import addQueue
import editQueue
import shareQueue
import printconf_version
import pycups
gtk.glade.bindtextdomain (domain)
gnome.program_init ('system-config-printer', printconf_version.version)
pkgdata = "/usr/share/printconf/"
try:
xml = gtk.glade.XML (pkgdata + "gui/system-config-printer.glade",
domain = domain)
except:
xml = gtk.glade.XML ("system-config-printer.glade", domain = domain)
busy_cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
ready_cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)
def complain (window, msg):
"""Put up an error dialog."""
d = gtk.MessageDialog (window, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, msg)
d.set_transient_for (window)
d.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
d.run ()
d.destroy ()
class queueTree:
"""The main queue tree window."""
def __init__ (self, hidden = 0):
self.hidden = hidden
self.queue_types = [ printconf_conf.queue_types.local,
printconf_conf.queue_types.ipp,
printconf_conf.queue_types.lpd,
printconf_conf.queue_types.smb,
printconf_conf.queue_types.ncp,
printconf_conf.queue_types.jetdirect ]
self.smb_page_index = self.queue_types.\
index (printconf_conf.queue_types.smb)
self.queue_type_help_pages = [ "printconf-local-printer.html",
"printconf-ipp-printer.html",
"printconf-lpd-printer.html",
"printconf-smb-printer.html",
"printconf-ncp-printer.html",
"printconf-jetdirect-printer.html" ]
self.queue_type_names = map (lambda x: x.type_name, self.queue_types)
# Initializing foomatic is expensive, so just do it on demand.
self.foomatic_ready = 0
self.default_iter = None
self.conf = printconf_conf
self.toplevel = xml.get_widget ('queueTreeWindow')
self.toplevel.set_title (_("Printer configuration - %s") %
(os.uname()[1]))
if not hidden:
self.toplevel.show_all ()
imported = False
if cups_import.import_needed ():
self.use_foomatic ()
cups_import.import_cups_queues ()
imported = True
# Widgets.
self.local_queue_widgets = [ xml.get_widget ('edit_button'),
xml.get_widget ('delete_button'),
xml.get_widget ('edit_queue'),
xml.get_widget ('delete_queue'),
xml.get_widget ('pop_edit'),
xml.get_widget ('pop_delete'),
xml.get_widget ('pop_sharing') ]
self.existing_queue_widgets = [ xml.get_widget ('default_button'),
xml.get_widget ('set_as_default'),
xml.get_widget ('pop_set_as_default') ]
self.ascii_test = xml.get_widget ('ascii_test')
self.cups_test = xml.get_widget ('cups_test')
if not os.access ("/usr/share/cups/data/testprint.ps", os.R_OK):
self.cups_test.set_sensitive (False)
self.jpeg_test = xml.get_widget ('jpeg_test')
if not os.access ("/usr/share/gimp-print/samples/profile.jpg",os.R_OK):
self.jpeg_test.set_sensitive (False)
# Grey out these buttons until a queue is chosen.
map (lambda x: x.set_sensitive (False),
self.local_queue_widgets)
map (lambda x: x.set_sensitive (False),
self.existing_queue_widgets)
# Signals.
self.toplevel.connect ('destroy', self.destroy)
xml.signal_connect ('on_quit_activate', self.quit)
xml.signal_connect ('on_new_button_clicked', self.new_button_clicked)
xml.signal_connect ('on_new_queue_activate', self.new_button_clicked)
xml.signal_connect ('on_queue_view_cursor_changed', self.queue_chosen)
xml.signal_connect ('on_queue_view_button_press_event',
self.button_pressed)
xml.signal_connect ('on_edit_button_clicked', self.edit_button_clicked)
xml.signal_connect ('on_edit_queue_activate', self.edit_button_clicked)
xml.signal_connect ('on_pop_edit_activate', self.edit_button_clicked)
xml.signal_connect ('on_queue_view_row_activated', self.row_activated)
xml.signal_connect ('on_queue_view_row_expanded', self.row_expanded)
xml.signal_connect ('on_queue_view_row_collapsed', self.row_collapsed)
xml.signal_connect ('on_default_button_clicked',
self.default_button_clicked)
xml.signal_connect ('on_set_as_default_activate',
self.default_button_clicked)
xml.signal_connect ('on_pop_set_as_default_activate',
self.default_button_clicked)
xml.signal_connect ('on_delete_button_clicked',
self.delete_button_clicked)
xml.signal_connect ('on_delete_queue_activate',
self.delete_button_clicked)
xml.signal_connect ('on_pop_delete_activate',
self.delete_button_clicked)
xml.signal_connect ('on_apply_activate', self.apply)
xml.signal_connect ('on_apply_button_clicked', self.apply)
xml.signal_connect ('on_sharing_activate', self.sharing_button_clicked)
xml.signal_connect ('on_pop_sharing_activate',
self.sharing_button_clicked)
xml.signal_connect ('on_import_ppd_activate',
self.import_ppd_activate)
xml.signal_connect ('on_queueTreeWindow_delete_event', self.delete)
xml.signal_connect ('on_browse_help_activate', self.browse_help)
for test in [ 'on_cups_test_activate',
'on_letter_ps_test_activate',
'on_a4_ps_test_activate',
'on_ascii_test_activate',
'on_euc_test_activate',
'on_jis_test_activate',
'on_sjis_test_activate',
'on_euc_ps_test_activate',
'on_jis_ps_test_activate',
'on_sjis_ps_test_activate',
'on_duplex_test_activate',
'on_jpeg_test_activate' ]:
xml.signal_connect (test, self.test)
# TreeView columns.
self.queue_store = gtk.TreeStore (gtk.gdk.Pixbuf, str, str,
gobject.TYPE_PYOBJECT,
gtk.gdk.Pixbuf)
self.queue_store.set_sort_column_id (1, gtk.SORT_ASCENDING)
self.queue_view = xml.get_widget ('queue_view')
self.queue_view.set_model (self.queue_store)
col = gtk.TreeViewColumn (_("Queue name"), gtk.CellRendererText (),
text=1)
col.set_resizable (True)
col.set_sort_column_id (1)
self.queue_view.append_column (col)
col = gtk.TreeViewColumn (_("Shared"), gtk.CellRendererPixbuf (),
pixbuf=4)
self.queue_view.append_column (col)
col = gtk.TreeViewColumn (_("Default"), gtk.CellRendererPixbuf (),
pixbuf=0)
self.queue_view.append_column (col)
col = gtk.TreeViewColumn (_("Description"), gtk.CellRendererText (),
text=2)
col.set_resizable (True)
col.set_sort_column_id (2)
self.queue_view.append_column (col)
# Queue status pixbufs
self.pixbuf = {}
for (test, name) in [ ("printer-D.png", "printer-default"),
("printer-DS.png", "printer-default-static"),
("printer-DO.png", "printer-default-overridden"),
("printer-S.png", "printer-static"),
("printer-O.png", "printer-overridden"),
("printer-shared.png", "printer-shared"),
("printer-unshared.png", "printer-unshared")]:
self.pixbuf[name] = gtk.gdk.pixbuf_new_from_file ("%s/gui/%s" %
(pkgdata, test))
self.pixbuf["empty"] = self.pixbuf["printer-default"].copy ()
self.pixbuf["empty"].fill (0)
# Other modules.
self.addQueue = addQueue.addQueue (self, xml)
self.editQueue = editQueue.editQueue (self, xml)
self.shareQueue = shareQueue.shareQueue (self, xml)
# Find out what print spooler is currently active, so that
# we can warn if the user is changing an option that has
# no effect.
self.active_spooler = self.get_active_spooler ()
# Put the queues in the tree view.
self.populate_tree ()
# Whether we need to run the backend.
self.need_to_apply_changes (imported)
if not hidden:
# Let GTK take over.
gtk.main ()
def get_active_spooler (self):
"""Find out which print spooler is currently active."""
signal.signal (signal.SIGCHLD, signal.SIG_DFL)
f = os.popen ('LC_ALL=C /usr/sbin/alternatives --display print')
for l in f.readlines ():
if l.startswith (" link currently points to"):
which = l.split ('.')[1].strip ()
break
f.close ()
return which
#--------------------------------
# Handle the window being deleted
#--------------------------------
def delete (self, *args):
"""Callback for the window being deleted. Ask for confirmation."""
if self.need_apply:
sure = gtk.MessageDialog \
(self.toplevel, 0, gtk.MESSAGE_QUESTION,
gtk.BUTTONS_NONE,
_("Do you want to save the changes\n"
"you made to your printer configuration?"))
sure.add_button (_("_Don't save"), gtk.RESPONSE_NO)
sure.add_button (_("_Cancel"), gtk.RESPONSE_CANCEL)
sure.add_button (_("_Save"), gtk.RESPONSE_YES)
response = sure.run ()
sure.destroy ()
if (response == gtk.RESPONSE_CANCEL or
response == gtk.RESPONSE_DELETE_EVENT):
return True
if response == gtk.RESPONSE_YES:
self.apply ()
return False
def destroy (self, *args):
gtk.main_quit ()
def quit (self, *args):
if not self.delete ():
self.destroy ()
#----------------------------
# Populate the queue treeview
#----------------------------
def populate_tree (self):
"""Fill in the queue treeview from the existing configuration."""
self.name_dict, self.alias_dict = self.conf.get_queues ()
self.default_queue_name = self.conf.get_default_queue_name ()
store = self.queue_store
store.clear ()
for name in self.name_dict.keys ():
queue_dict = self.name_dict[name]
queue = queue_dict["queue"]
iter = store.append (None)
store.set_value (iter, 1, name)
try:
store.set_value (iter, 2, queue["queue_description"].value)
except:
pass
store.set_value (iter, 3, queue)
shared = "printer-unshared"
try:
for allowed in queue["sharing"]:
shared = "printer-shared"
break
except:
pass
self.queue_store.set_value (iter, 4, self.pixbuf[shared])
if name == self.default_queue_name:
pixbuf = "printer-default"
if not queue_dict["editable"]:
pixbuf = "printer-default-static"
elif queue_dict["override"]:
pixbuf = "printer-default-overridden"
self.queue_store.set_value (iter, 0, self.pixbuf[pixbuf])
self.default_iter = iter
else:
if not queue_dict["editable"]:
self.queue_store.set_value (iter, 0,
self.pixbuf["printer-static"])
elif queue_dict["override"]:
self.queue_store.set_value (iter, 0,
self.pixbuf["printer-overridden"])
self.browsed_iter = None
self.populate_browsed_queues ()
def populate_browsed_queues (self):
"""Update the list of browsed queues. Also displays error messages
for any queue that has them."""
if self.active_spooler != "cups":
return
try:
cups_queues = pycups.get_queues ()
except:
return
if not cups_queues:
return
store = self.queue_store
if self.browsed_iter:
while store.iter_has_child (self.browsed_iter):
iter = store.iter_nth_child (self.browsed_iter, 0)
store.remove (iter)
errors = {}
for each in cups_queues.keys ():
try:
if cups_queues[each].get('printer-state-message'):
err = cups_queues[each]['printer-state-message']
if self.name_dict.has_key (each):
for row in store:
i = store.get_iter (row.path)
name = store.get_value (i, 1)
if name == each:
# Ought to be a nicer way to do this.
if err and err != "Ready to print.":
errors[each] = err
description = err
else:
description = self.name_dict[name]\
["queue"]\
["queue_description"].value
store.set_value (i, 2, description)
break
# If this is one of our local queues, skip it.
if each in self.name_dict.keys ():
continue
except:
continue
if self.name_dict.has_key (each):
continue
if not self.browsed_iter:
self.browsed_iter = store.append (None)
store.set_value (self.browsed_iter, 0, self.pixbuf["empty"])
store.set_value (self.browsed_iter, 1, _("Browsed queues"))
store.set_value (self.browsed_iter, 2, "")
iter = store.append (self.browsed_iter)
pixbuf = "empty"
if each == self.default_queue_name:
pixbuf = "printer-default"
store.set_value (iter, 0, self.pixbuf[pixbuf])
store.set_value (iter, 1, each)
store.set_value (iter, 2, "")
try:
store.set_value (iter, 2,
cups_queues[each]['printer-location'])
except:
pass
try:
if errors[each]:
store.set_value (iter, 2, errors[each])
except:
pass
self.errors = errors
#----------------------------
# Greying-out the main window
#----------------------------
def busy (self):
"""Set the main window insensitive."""
try:
self.toplevel.set_sensitive (False)
self.toplevel.window.set_cursor (busy_cursor)
while gtk.events_pending ():
gtk.main_iteration ()
except:
pass
def ready (self):
"""Set the main window sensitive."""
try:
self.toplevel.window.set_cursor (ready_cursor)
self.toplevel.set_sensitive (True)
except:
pass
#-------------------------------------
# Helper functions used by this module
#-------------------------------------
def use_foomatic (self):
"""Demand-load the foomatic database. If it is already loaded,
this does nothing; otherwise it is loaded."""
if not self.foomatic_ready:
wait = xml.get_widget ('waitDialog')
wait_label = xml.get_widget ('wait_label')
wait_label.set_text (_("Loading printer information.\n"
"Please wait..."))
wait.set_transient_for (self.toplevel)
if self.hidden:
wait.set_position (gtk.WIN_POS_CENTER)
else:
wait.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
wait.show_now ()
gtk.gdk.window_process_all_updates ()
while gtk.events_pending ():
gtk.main_iteration ()
# Should get a thread to repaint this?
self.conf.foomatic_init_overview ()
wait.hide ()
self.foomatic_ready = 1
def need_to_apply_changes (self, true):
"""Called to set button sensitivity. If true is zero everything
is up to date, otherwise changes have been made that have not been
applied yet."""
if true:
self.need_apply = 1
else:
self.need_apply = 0
xml.get_widget ('apply_button').set_sensitive (true)
xml.get_widget ('apply').set_sensitive (true)
store, iter = self.queue_view.get_selection ().get_selected ()
tests_available = not true
if not iter or store.iter_has_child (iter):
tests_available = False
xml.get_widget ('test').set_sensitive (tests_available)
def queue_chosen (self, treeview):
"""Called when a queue has been chosen. All of the widgets that
act on an existing queue are made sensitive again."""
store, iter = treeview.get_selection ().get_selected ()
is_normal = self.is_normal_queue (iter)
map (lambda x: x.set_sensitive (is_normal),
self.existing_queue_widgets)
is_local = self.is_local_queue (iter)
map (lambda x: x.set_sensitive (is_local),
self.local_queue_widgets)
xml.get_widget ('test').set_sensitive (not self.need_apply and
not store.iter_has_child (iter))
if is_local:
self.populate_browsed_queues ()
def make_queue_editable (self, name):
"""Called to make an imported queue editable. Returns zero
on success."""
override = gtk.MessageDialog (self.toplevel, 0, gtk.MESSAGE_INFO,
gtk.BUTTONS_YES_NO,
_("This is an imported printer. "
"Do you want to create a local "
"override?"))
response = override.run ()
override.destroy ()
if response != gtk.RESPONSE_YES:
return 1
self.conf.override_queue (name)
pixbuf = "printer-overridden"
if name == self.default_queue_name:
pixbuf = "printer-default-overridden"
store.set_value (iter, 0, self.pixbuf[pixbuf])
return 0
def is_local_queue (self, iter):
store = self.queue_store
if store.get_value (iter, 3):
return 1
return 0
def is_normal_queue (self, iter):
store = self.queue_store
return not store.iter_has_child (iter)
#-------------------
# Create a new queue
#-------------------
def new_button_clicked (self, *args):
"""New button handler."""
self.busy ()
self.use_foomatic ()
self.addQueue.addQueueDruid ()
self.populate_browsed_queues ()
#-------------
# Edit a queue
#-------------
def edit_button_clicked (self, *args):
"""Edit button handler."""
store, iter = self.queue_view.get_selection ().get_selected ()
if not self.is_normal_queue (iter):
return
name = store.get_value (iter, 1)
queue_dict = self.name_dict[name]
if not queue_dict["editable"]:
if self.make_queue_editable (name):
return
self.busy ()
self.use_foomatic ()
if self.editQueue.editQueueDialog (iter):
self.need_to_apply_changes (True)
self.name_dict, self.alias_dict = self.conf.get_queues ()
self.populate_browsed_queues ()
#---------------------
# Double-click handler
#---------------------
def row_activated (self, view, path, column):
"""Handle double-clicks in the tree view. In the status column
treat a double-click as 'set as default'; otherwise edit the
queue."""
store = self.queue_store
iter = store.get_iter (path)
if not self.is_local_queue (iter) and not store.iter_depth (iter):
if view.row_expanded (path):
view.collapse_row (path)
else:
self.populate_browsed_queues ()
view.expand_row (path, 0)
return
if column == view.get_column (1):
self.sharing_button_clicked ()
elif column == view.get_column (2):
self.default_button_clicked ()
else:
if store.iter_depth (iter) > 0:
# Double-clicking on a browsed queue could bring
# up a box with information about it in I suppose.
return
self.edit_button_clicked ()
def row_expanded (self, view, iter, path):
try:
if self.expanding_row:
return
except:
self.expanding_row = 1
self.populate_browsed_queues ()
view.expand_row (path, 0)
del self.expanding_row
def row_collapsed (self, view, iter, path):
# Set button sensitivity
self.need_to_apply_changes (self.need_apply)
#---------------------------
# Set a queue as the default
#---------------------------
def default_button_clicked (self, *args):
"""Default button callback."""
store, iter = self.queue_view.get_selection ().get_selected ()
name = store.get_value (iter, 1)
if name == self.default_queue_name:
# Nothing to do.
return
self.conf.set_default_queue_name (name)
store.set_value (iter, 0, self.pixbuf["printer-default"])
if self.default_iter:
store.set_value (self.default_iter, 0, self.pixbuf["empty"])
self.default_queue_name = name
self.default_iter = iter
self.need_to_apply_changes (True)
if self.is_local_queue (iter):
self.populate_browsed_queues ()
#---------------------
# Queue sharing dialog
#---------------------
def sharing_button_clicked (self, *args):
"""Sharing button callback."""
self.spooler_warn_unless ("cups", self.toplevel)
store, iter = self.queue_view.get_selection ().get_selected ()
if iter:
if self.is_local_queue (iter):
name = store.get_value (iter, 1)
queue_dict = self.name_dict[name]
if not queue_dict["editable"]:
if self.make_queue_editable (name):
return
else:
iter = None
if self.shareQueue.shareQueueDialog (iter):
self.need_to_apply_changes (True)
self.populate_browsed_queues ()
# Fix up the sharing icon.
shared = "printer-unshared"
try:
for allowed in self.name_dict[name]["queue"]["sharing"]:
shared = "printer-shared"
break
except:
pass
if iter:
self.queue_store.set_value (iter, 4, self.pixbuf[shared])
#---------------
# Delete a queue
#---------------
def delete_button_clicked (self, *args):
"""Delete button callback."""
store, iter = self.queue_view.get_selection ().get_selected ()
if not self.is_normal_queue (iter):
return
name = store.get_value (iter, 1)
self.conf.delete_queue_and_fix_default (self.name_dict[name]["queue"])
self.name_dict, self.alias_dict = self.conf.get_queues ()
self.default_queue_name = self.conf.get_default_queue_name ()
store.remove (iter)
# If it was an override queue, put in the non-editable queue.
if self.name_dict.has_key (name):
queue_dict = self.name_dict[name]
iter = store.append (None)
store.set_value (iter, 1, name)
if name != self.default_queue_name:
if not queue_dict["editable"]:
store.set_value (iter, 0, self.pixbuf["printer-static"])
elif queue_dict["override"]:
store_set_value (iter, 0,
self.pixbuf["printer-overridden"])
self.fix_default_marker ()
# Since the selected queue is deleted, nothing is selected now.
# Grey out the buttons that act on an existing queue.
map (lambda x: x.set_sensitive (False),
self.existing_queue_widgets)
self.need_to_apply_changes (True)
self.populate_browsed_queues ()
def fix_default_marker (self):
"""Fix up 'default' marker."""
store = self.queue_store
iter = store.get_iter_first ()
while iter:
if store.get_value (iter, 1) == self.default_queue_name:
self.default_iter = iter
store.set_value (iter, 0, self.pixbuf["printer-default"])
break
iter = store.iter_next (iter)
#---------------------------------------
# Helper functions used by other modules
#---------------------------------------
def show_notes (self, id, driver, caller):
"""Show the printer/driver notes. This is a helper function,
used by the other modules."""
caller.busy ()
notes = self.conf.foomatic_printer_driver_lookup (id, driver)
caller.ready ()
message = _("Notes from the Linux Printing Database")
source1 = '<HTML><HEAD><META CONTENT="text/html; charset=UTF-8" HTTP-EQUIV="Content-Type"><BODY BGCOLOR="white">\n'
source1 += '<H3>' + _("Printer notes:") + '</H3>\n'
if notes:
source1 += notes.printer_comments_dict.get ("en", "")
source1 += "</BODY></HTML>\n"
source2 = '<HTML><HEAD><META CONTENT="text/html; charset=UTF-8" HTTP-EQUIV="Content-Type"><BODY BGCOLOR="white">\n'
source2 += '<H3>' + _("Driver notes:") + '</H3>\n'
if notes:
source2 += notes.driver_comments_dict.get ("en", "")
source2 += "</BODY></HTML>\n"
dialog = gtk.MessageDialog (None, 0, gtk.MESSAGE_INFO,
gtk.BUTTONS_OK, message)
html1 = gtkhtml2.Document ()
html1.clear ()
html1.open_stream ('text/html')
html1.write_stream (source1)
html1.close_stream ()
view1 = gtkhtml2.View ()
view1.set_document (html1)
view1.set_size_request (400, 200)
window1 = gtk.ScrolledWindow ()
dialog.vbox.pack_start (window1)
window1.add (view1)
html2 = gtkhtml2.Document ()
html2.clear ()
html2.open_stream ('text/html')
html2.write_stream (source2)
html2.close_stream ()
view2 = gtkhtml2.View ()
view2.set_document (html2)
view2.set_size_request (600, 200)
window2 = gtk.ScrolledWindow ()
dialog.vbox.pack_start (window2)
window2.add (view2)
dialog.set_position (gtk.WIN_POS_CENTER)
dialog.vbox.show_all()
dialog.run()
dialog.hide()
def populate_mfr_optionmenu (self, optionmenu, queue = None):
"""
Populate optionmenu with a list of manufacturer's names.
If queue is also given, the history is set to the appropriate
manufacturer. This is a helper function, used by other modules.
Returns a list corresponding to the menu items.
"""
mfr_list = self.conf.foomatic.make_model_dict_dict.keys ()
# Put in alphanumeric order, except for Generic which should
# come first.
mfr_list.sort ()
try:
mfr_list.pop (mfr_list.index ("Generic"))
except:
pass
mfr_list.insert (0, _("Generic (click to select manufacturer)"))
mfr_menu = gtk.Menu ()
for mfr in mfr_list:
menuitem = gtk.MenuItem (mfr)
mfr_menu.add (menuitem)
menuitem.show ()
menuitem.set_sensitive (True)
optionmenu.set_sensitive (True)
optionmenu.set_menu (mfr_menu)
mfr_list[0] = "Generic"
if (queue and queue["filter_type"].value ==
self.conf.drivers.foomatic.filter_type and
queue["filter_data"]["mf_type"].value ==
self.conf.drivers.foomatic.mf_type):
id = queue["filter_data"]["printer_id"].value
mfr = self.conf.foomatic.id_dict[id].make
optionmenu.set_history (mfr_list.index (mfr))
else:
optionmenu.set_history (mfr_list.index ("Generic"))
return mfr_list
def populate_model_store (self, store, queue = None, id_dict = {},
mfr = None, id = None, window = None):
"""
Set up the printer model tree. This is a helper function,
used by the other modules.
store: TreeStore to populate
queue (optional): Current queue
id_dict (opt): Dictionary of foomatic IDs to populate
mfr (opt): Manufacturer to list models for
id (opt): Foomatic ID to select
"""
if window:
window.set_cursor (busy_cursor)
while gtk.events_pending ():
gtk.main_iteration ()
selectable_iter = None
select_id = id
store.clear ()
d = self.conf.drivers.foomatic
if (queue and queue["filter_type"].value == d.filter_type and
queue["filter_data"]["mf_type"].value == d.mf_type):
select_id = queue["filter_data"]["printer_id"].value
if not mfr:
mfr = self.conf.foomatic.id_dict[select_id].make
if id and not mfr:
mfr = self.conf.foomatic.id_dict[id].make
if not mfr:
mfr = "Generic"
if mfr == "Generic":
d = self.conf.drivers.text
iter = store.append (None)
store.set_value (iter, 0, d.label)
store.set_value (iter, 1, (d, None))
if (queue and queue["filter_type"].value == d.filter_type and
queue["filter_data"]["mf_type"].value == d.mf_type):
selectable_iter = iter
d = self.conf.drivers.raw
iter = store.append (None)
store.set_value (iter, 0, d.label)
store.set_value (iter, 1, (d, None))
if queue and queue["filter_type"].value == d.filter_type:
selectable_iter = iter
d = self.conf.drivers.foomatic
models = self.conf.foomatic.make_model_dict_dict[mfr].keys ()
models.sort ()
for model in models:
iter_model = store.append (None)
store.set_value (iter_model, 0, model)
id = self.conf.foomatic.make_model_dict_dict[mfr][model].id
store.set_value (iter_model, 1, (d, id))
id_dict[id] = iter_model
if id == select_id:
selectable_iter = iter_model
# Sort the printer models the way a real person would.
def model_sort_func (store, iter_a, iter_b):
return pycups.model_sort (store.get_value (iter_a, 0),
store.get_value (iter_b, 0))
store.set_sort_column_id (0, gtk.SORT_ASCENDING)
store.set_sort_func (0, model_sort_func)
if window:
window.set_cursor (ready_cursor)
return selectable_iter
def spooler_warn_unless (self, spooler, window):
"""Warn that the option about to be modified doesn't apply
to the active spooler."""
if self.active_spooler == spooler:
return
msg = _("You are changing an option\n"
"that has no effect in the print\n"
"spooler you are using (%s).") % self.active_spooler
d = gtk.MessageDialog (window, 0, gtk.MESSAGE_WARNING,
gtk.BUTTONS_OK, msg)
d.set_position (gtk.WIN_POS_CENTER)
d.run ()
d.destroy ()
#--------------
# Apply changes
#--------------
def apply (self, *args):
"""Save changes and restart lpd service."""
self.busy ()
wait = xml.get_widget ('waitDialog')
wait_label = xml.get_widget ('wait_label')
wait_label.set_text (_("Applying changes.\n"
"Please wait..."))
wait.set_transient_for (self.toplevel)
wait.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
wait.show_now ()
gtk.gdk.window_process_all_updates ()
while gtk.events_pending ():
gtk.main_iteration ()
self.conf.save_queues ()
success = self.conf.restart_lpd ()
wait.hide ()
self.ready ()
if not success:
bad = gtk.MessageDialog (self.toplevel, 0, gtk.MESSAGE_ERROR,
gtk.BUTTONS_OK,
_("Failed to write queues."))
bad.run ()
bad.destroy ()
else:
self.need_to_apply_changes (False)
#-----------
# Run a test
#-----------
def test (self, menuitem):
"""Send a test page to the print queue."""
selection = self.queue_view.get_selection ()
store, iter = selection.get_selected ()
if store.iter_has_child (iter):
return
name = store.get_value (iter, 1)
index = menuitem.get_parent ().get_children ().index (menuitem)
page = [ "/usr/share/cups/data/testprint.ps",
"----separator----",
"testpage.ps",
"testpage-a4.ps",
"testpage.asc",
"testpage.euc",
"testpage.jis",
"testpage.sjis",
"testpage.big5",
"test-euc.ps",
"test-jis.ps",
"test-sjis.ps",
"test-big5.ps",
"duplex.asc",
"/usr/share/gimp-print/samples/profile.jpg" ][index]
label = menuitem.get_children ()[0].get_label ().replace ("_", "")
if page[0] == "/":
testfile = page
else:
testfile = pkgdata + "tests/" + page
(loglevel, logname, errorlog_start) = self.set_cups_loglevel ("debug")
self.busy ()
time.sleep (1)
self.ready ()
err = self.conf.print_test_page (name, testfile)
if err:
self.set_cups_loglevel (loglevel)
bad = gtk.MessageDialog (self.toplevel, 0, gtk.MESSAGE_ERROR,
gtk.BUTTONS_OK,
_("There was a problem sending %s\n"
"to '%s' queue:\n\n") % (label, name)
+ err)
bad.run ()
bad.destroy ()
else:
done = gtk.MessageDialog (self.toplevel, 0, gtk.MESSAGE_INFO,
gtk.BUTTONS_YES_NO,
_("Sent %s\n"
"to '%s' queue. Does it "
"look okay?") % (label, name))
response = done.run ()
done.destroy ()
(x, x, errorlog_end) = self.set_cups_loglevel (loglevel)
if response == gtk.RESPONSE_NO:
errorlog_size = errorlog_end - errorlog_start
errorlog = file (logname)
errorlog.seek (errorlog_start)
data = errorlog.read (errorlog_size)
errorlog.close ()
dialog = gtk.MessageDialog (self.toplevel, 0, gtk.MESSAGE_INFO,
gtk.BUTTONS_OK,
_("Here are the messages that "
"appeared in the error log:"))
window = gtk.ScrolledWindow ()
dialog.vbox.pack_start (window)
textview = gtk.TextView ()
buffer = gtk.TextBuffer ()
buffer.set_text (data)
textview.set_buffer (buffer)
textview.set_editable (False)
textview.set_cursor_visible (False)
window.add (textview)
dialog.show_all ()
dialog.run ()
dialog.destroy ()
self.populate_browsed_queues ()
def set_cups_loglevel (self, level):
"""Set the LogLevel setting in cupsd.conf, and return a tuple of
the old setting, the error log file name, and its size."""
if self.active_spooler != "cups":
return ("", "/dev/null", 0)
loglevel_keyword = "LogLevel "
oldlevel = "info"
errorlog_keyword = "ErrorLog "
errorlog = "/var/log/cups/error_log"
cupsd_conf_filename = "/etc/cups/cupsd.conf"
try:
cupsdconf = file (cupsd_conf_filename).readlines ()
except:
cupsdconf = []
for i in range (len (cupsdconf)):
line = cupsdconf[i]
if line.startswith (loglevel_keyword):
oldlevel = line[len (loglevel_keyword):].strip ()
cupsdconf[i] = "LogLevel %s\n" % level
if line.startswith (errorlog_keyword):
errorlog = line[len (errorlog_keyword):].strip ()
size = 0
if level != "debug":
try:
(x, x, x, x, x, x, size, x, x, x) = os.stat (errorlog)
except:
pass
# Don't adjust LogLevel for the time being; causes problems.
if 0: #if level != oldlevel:
tmp = cupsd_conf_filename + ".#system-config-printer"
out = file (tmp, "w")
out.writelines (cupsdconf)
out.close ()
try:
os.rename (tmp, cupsd_conf_filename)
os.system ("/sbin/service cups reload >/dev/null 2>/dev/null")
except:
pass
if level == "debug":
try:
(x, x, x, x, x, x, size, x, x, x) = os.stat (errorlog)
except:
pass
return (oldlevel, errorlog, size)
#------------
# Browse help
#------------
def browse_help (self, menuitem):
gnome.url_show ("file://%s/index.html" %
self.conf.conf.printconf_help_dir)
#------------
# Pop-up menu
#------------
def button_pressed (self, view, event):
"""Activate the pop-up menu on right-click."""
# Right-click?
if event.button != 3:
return
popup = xml.get_widget ("queuePopup")
popup.popup (None, None, None, event.button, event.time)
#------------
# Pop-up menu
#------------
def import_ppd_activate (self, imgmenuitem):
"""Import PPD."""
FOOMATIC_DB = "/usr/share/foomatic/db"
selector = gtk.FileChooserDialog ("Open PPD", self.toplevel,
gtk.FILE_CHOOSER_ACTION_OPEN,
(gtk.STOCK_CANCEL,
gtk.RESPONSE_CANCEL,
gtk.STOCK_OPEN,
gtk.RESPONSE_ACCEPT))
selector.set_select_multiple (False)
while True:
response = selector.run ()
if response != gtk.RESPONSE_ACCEPT:
selector.destroy ()
return
filename = selector.get_filename ()
try:
f = file (filename, "rU")
line1 = f.readline ()
if not line1.startswith ("*PPD-Adobe:"):
complain (self.toplevel,
_("'%s' does not look like a PPD file.") %
filename)
selector.destroy ()
return
break
except:
complain (self.toplevel,
_("File cannot be opened for reading."))
selector.destroy ()
return
selector.destroy ()
# Create a template printer XML
def ppd_val (s):
offset = s.find (':')
if offset == -1:
return ''
return s[1 + offset:].strip ().strip ("\"'")
mfr = None
mdl = None
for l in f.readlines ():
if l.startswith ("*Manufacturer:"):
mfr = ppd_val (l)
elif l.startswith ("*ShortNickName:"):
mdl = ppd_val (l) + " (PPD)"
if not mfr:
mfr = "[PPD]"
if not mdl:
mdl = "[PPD]"
if mdl.startswith (mfr + ' '):
mdl = mdl[1 + len (mfr):]
n = 1
while n != 0:
id = "ppd%d" % n
p = "%s/source/printer/%s.xml" % (FOOMATIC_DB, id)
if not os.path.exists (p):
break
n += 1
CUSTOM_PPD = "PPD/Custom"
ppd = "%s/%s-%s.ppd" % (CUSTOM_PPD, mfr, mdl)
ppd = ppd.replace (" ", "_")
ppd = ppd.replace ("(", "")
ppd = ppd.replace (")", "")
file (p, 'w').writelines ([ '<printer id="printer/%s">\n' % id,
' <make>%s</make>\n' % mfr,
' <model>%s</model>\n' % mdl,
' <functionality>A</functionality>\n',
' <driver>ppd</driver>\n',
' <drivers>\n',
' <driver>\n',
' <id>ppd</id>\n',
' <ppd>%s</ppd>\n' % ppd,
' </driver>\n',
' </drivers>\n',
'</printer>\n' ])
try:
os.mkdir ("%s/source/%s" % (FOOMATIC_DB, CUSTOM_PPD))
except OSError:
pass # Directory already exists
os.environ["PPD"] = filename
os.environ["COPY"] = "%s/source/%s" % (FOOMATIC_DB, ppd)
if os.system ('/bin/cp -v "$PPD" "$COPY"') != 0:
complain (self.toplevel, _("Failed to copy PPD file to %s") %
os.environ["COPY"])
return
os.environ["PPD"] = filename
if os.system ('/usr/sbin/foomatic-ppdload "$PPD" %s' % id) == 0:
self.conf.foomatic_invalidate_cache ()
self.foomatic_ready = 0
d = gtk.MessageDialog (self.toplevel, 0, gtk.MESSAGE_INFO,
gtk.BUTTONS_OK,
_("PPD imported."))
d.set_transient_for (self.toplevel)
d.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
d.run ()
d.destroy ()
else:
complain (self.toplevel, _("PPD import failed."))
if add_with_url:
if not add_with_url.startswith ("smb:"):
print "Only smb: URLs are supported by --add-with-url at present."
sys.exit (1)
toplevel = queueTree (hidden = 1)
toplevel.use_foomatic ()
toplevel.addQueue.addQueueDruid (url = add_with_url)
if toplevel.addQueue.window.get_property ("visible"):
gtk.main ()
else:
queueTree()
# Local Variables:
# py-indent-offset: 4
# End: