Viewing file: system-config-printer.py (101.46 KB) -rwxr-xr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
#!/bin/env python
## system-config-printer
## Copyright (C) 2006, 2007, 2008 Red Hat, Inc. ## Copyright (C) 2006 Florian Festi <ffesti@redhat.com> ## Copyright (C) 2006, 2007, 2008 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.
# config is generated from config.py.in by configure import config
import sys, os, tempfile, time import signal, thread try: import gtk.glade except RuntimeError, e: print "system-config-printer:", e print "This is a graphical application and requires DISPLAY to be set." sys.exit (1)
if len(sys.argv)>1 and sys.argv[1] == '--help': print ("\nThis is system-config-printer, " \ "a CUPS server configuration program.\n") sys.exit (0)
import cups import pysmb import cupshelpers, options import gobject # for TYPE_STRING and TYPE_PYOBJECT from optionwidgets import OptionWidget from foomatic import Foomatic from nametree import BuildTree from cupsd import CupsConfig import probe_printer import gtk_label_autowrap
domain='system-config-printer' import locale locale.setlocale (locale.LC_ALL, "") from rhpl.translate import _, N_ import rhpl.translate as translate translate.textdomain (domain) gtk.glade.bindtextdomain (domain) pkgdata = '/usr/share/' + domain glade_file = pkgdata + '/' + domain + '.glade' sys.path.append (pkgdata)
busy_cursor = gtk.gdk.Cursor(gtk.gdk.WATCH) ready_cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR) ellipsis = unichr(0x2026)
def percentEncode (text): """Percent-encode ASCII text ready for inclusion in a URI.""" l = len (text) i = 0 while i < l: c = text[i] a = ord (c) if (a <= 0x1f or a == 0x7f or c == ' ' or '<>#%"'.find (c) != -1 or '{}|\^[]`'.find (c) != -1): pre = text[:i] post = text[i + 1:] text = pre + "%" + ("%2X" % a) + post i += 2 l += 2 i += 1 return text
def percentDecode (text): """Percent-decode URI text to ASCII.""" l = len (text) r = 0 w = '' xdigs = "0123456789abcdef" while r < l: if r + 2 < l and text[r] == '%': c10 = xdigs.find (text[r + 1].lower ()) if c10 != -1: c01 = xdigs.find (text[r + 2].lower ()) if c01 != -1: w += chr (c10 * 0x10 + c01) r += 3 else: w += text[r] r += 1 return w
class GUI:
def __init__(self):
self.language = locale.getlocale(locale.LC_MESSAGES) self.encoding = locale.getlocale(locale.LC_CTYPE) self.printer = None self.conflicts = set() # of options self.password = '' self.passwd_retry = False cups.setPasswordCB(self.cupsPasswdCallback)
self.changed = set() # of options
self.servers = set(("localhost",))
try: self.cups = cups.Connection() except RuntimeError: self.cups = None
# WIDGETS # ======= try: #raise ValueError # uncomment for development self.xml = gtk.glade.XML(glade_file, domain = domain) except: self.xml = gtk.glade.XML(domain + '.glade', domain = domain)
self.getWidgets("MainWindow", "tvMainList", "ntbkMain", "statusbarMain", "btnNewPrinter", "btnNewClass", "btnCopy", "btnDelete", "new_printer", "new_class", "copy", "delete", "btnGotoServer",
"btnApply", "btnRevert", "btnConflict",
"chkServerBrowse", "chkServerShare", "chkServerRemoteAdmin", "chkServerAllowCancelAll", "chkServerLogDebug",
"ntbkPrinter", "entPDescription", "entPLocation", "lblPMakeModel", "lblPMakeModel2", "lblPState", "entPDevice", "lblPDevice2", "btnSelectDevice", "btnChangePPD", "chkPEnabled", "chkPAccepting", "chkPShared", "btnPMakeDefault", "lblPDefault", "btnPrintTestPage", "cmbPStartBanner", "cmbPEndBanner", "cmbPErrorPolicy", "cmbPOperationPolicy",
"rbtnPAllow", "rbtnPDeny", "tvPUsers", "entPUser", "btnPAddUser", "btnPDelUser",
"swPInstallOptions", "vbPInstallOptions", "swPOptions", "lblPOptions", "vbPOptions", "algnClassMembers", "vbClassMembers", "lblClassMembers", "tvClassMembers", "tvClassNotMembers", "btnClassAddMember", "btnClassDelMember", "cmbentNewOption", "tblServerOptions", "btnNewOption", "ConnectDialog", "chkEncrypted", "cmbServername", "entUser", "ConnectingDialog", "lblConnecting", "PasswordDialog", "lblPasswordPrompt", "entPasswd",
"ErrorDialog", "lblError", "InfoDialog", "lblInfo",
"ApplyDialog",
"NewPrinterWindow", "ntbkNewPrinter", "btnNPBack", "btnNPForward", "btnNPApply", "entNPName", "entNPDescription", "entNPLocation", "tvNPDevices", "ntbkNPType", "cmbNPTSerialBaud", "cmbNPTSerialParity", "cmbNPTSerialBits", "cmbNPTSerialFlow", "cmbentNPTLpdHost", "cmbentNPTLpdQueue", "entNPTIPPHostname", "entNPTIPPPrintername", "entNPTDirectJetHostname", "entNPTDirectJetPort", "entNPTIPPHostname", "entNPTIPPPrintername", "entSMBURI", "tvSMBBrowser", "entSMBUsername", "entSMBPassword", "entNPTDevice", "tvNCMembers", "tvNCNotMembers", "rbtnNPPPD", "tvNPMakes", "rbtnNPFoomatic", "filechooserPPD", "tvNPModels", "tvNPDrivers", "lblNPPDescription", "lblNPDDescription", "lblNPPPDDescription", "frmNPPDescription", "frmNPDDescription", "frmNPPPDDescription", "rbtnChangePPDasIs", "lblNPApply", "NewPrinterName", "entCopyName", "btnCopyOk",
"AboutDialog", "lblVersion", "lblCopyright", "lblAuthors", )
# Set up "About" dialog strings. vertext = self.lblVersion.get_text () self.lblVersion.set_text (vertext % config.VERSION) self.lblCopyright.set_text (_("Copyright 2006 Red Hat, Inc.")) self.lblAuthors.set_text ("Florian Festi, Tim Waugh")
self.static_tabs = 3
gtk_label_autowrap.set_autowrap(self.NewPrinterWindow)
self.status_context_id = self.statusbarMain.get_context_id( "Connection") self.setConnected() self.ntbkMain.set_show_tabs(False) self.ntbkNewPrinter.set_show_tabs(False) self.ntbkNPType.set_show_tabs(False) self.prompt_primary = self.lblPasswordPrompt.get_label ()
# Paint Description labels black on white for label in (self.lblNPPDescription, self.lblNPDDescription, self.lblNPPPDDescription): parent = label.get_parent() parent.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(65535, 65535, 65535))
# Setup main list column = gtk.TreeViewColumn() cell = gtk.CellRendererText() cell.markup = True column.pack_start(cell, True) self.tvMainList.append_column(column) self.mainlist = gtk.TreeStore(str, str) self.tvMainList.set_model(self.mainlist) column.set_attributes(cell, text=0) selection = self.tvMainList.get_selection() selection.set_mode(gtk.SELECTION_BROWSE) selection.set_select_function(self.maySelectItem)
self.mainlist.append(None, (_("Server Settings"), 'Settings'))
self.tooltips = gtk.Tooltips() self.tooltips.enable()
# setup some lists m = gtk.SELECTION_MULTIPLE s = gtk.SELECTION_SINGLE for name, treeview, selection_mode in ( (_("Members of this Class"), self.tvClassMembers, m), (_("Others"), self.tvClassNotMembers, m), (_("Members of this Class"), self.tvNCMembers, m), (_("Others"), self.tvNCNotMembers, m), (_("Devices"), self.tvNPDevices, s), (_("Makes"), self.tvNPMakes,s), (_("Models"), self.tvNPModels,s), (_("Drivers"), self.tvNPDrivers,s), (_("Users"), self.tvPUsers, m), ): model = gtk.ListStore(str) cell = gtk.CellRendererText() column = gtk.TreeViewColumn(name, cell, text=0) treeview.set_model(model) treeview.append_column(column) treeview.get_selection().set_mode(selection_mode)
ppd_filter = gtk.FileFilter() ppd_filter.set_name(_("PostScript Printer Description (*.ppd[.gz])")) ppd_filter.add_pattern("*.ppd") ppd_filter.add_pattern("*.PPD") ppd_filter.add_pattern("*.ppd.gz") self.filechooserPPD.add_filter(ppd_filter)
self.conflict_dialog = gtk.MessageDialog( parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_OK) # SMB browser self.smb_store = gtk.TreeStore (str, # host or share str, # comment gobject.TYPE_PYOBJECT, # domain dict gobject.TYPE_PYOBJECT) # host dict self.tvSMBBrowser.set_model (self.smb_store) self.smb_store.set_sort_column_id (0, gtk.SORT_ASCENDING)
# SMB list columns col = gtk.TreeViewColumn (_("Share"), gtk.CellRendererText (), text=0) col.set_resizable (True) col.set_sort_column_id (0) self.tvSMBBrowser.append_column (col)
col = gtk.TreeViewColumn (_("Comment"), gtk.CellRendererText (), text=1) self.tvSMBBrowser.append_column (col) slct = self.tvSMBBrowser.get_selection () slct.set_select_function (self.smb_select_function) self.xml.signal_autoconnect(self)
try: self.populateList() except cups.HTTPError, (s,): self.cups = None self.setConnected() self.populateList() self.show_HTTP_Error(s) def getWidgets(self, *names): for name in names: widget = self.xml.get_widget(name) if widget is None: raise ValueError, "Widget '%s' not found" % name setattr(self, name, widget)
def busy (self, win = None): if not win: win = self.MainWindow win.window.set_cursor (busy_cursor) while gtk.events_pending (): gtk.main_iteration () def ready (self, win = None): if not win: win = self.MainWindow win.window.set_cursor (ready_cursor) while gtk.events_pending (): gtk.main_iteration () def loadFoomatic(self): try: return self.foomatic except: self.foomatic = Foomatic() # this works on the local db self.foomatic.addCupsPPDs(self.cups.getPPDs(), self.cups) return self.foomatic
def unloadFoomatic(self): try: del self.foomatic except: pass
def setConnected(self): connected = bool(self.cups)
host = cups.getServer()
if host[0] == '/': host = 'localhost' self.MainWindow.set_title(_("Printer configuration - %s") % host)
if connected: status_msg = _("Connected to %s") % host else: status_msg = _("Not connected") self.statusbarMain.push(self.status_context_id, status_msg)
for widget in (self.btnNewPrinter, self.btnNewClass, self.new_printer, self.new_class, self.chkServerBrowse, self.chkServerShare, self.chkServerRemoteAdmin, self.chkServerAllowCancelAll, self.chkServerLogDebug): widget.set_sensitive(connected) def getServers(self): self.servers.discard(None) known_servers = list(self.servers) known_servers.sort() return known_servers
def populateList(self): old_name, old_type = self.getSelectedItem()
select_path = None
# get Printers if self.cups: try: self.printers = cupshelpers.getPrinters(self.cups) except cups.IPPError, (e, m): self.show_IPP_Error(e, m) self.printers = {} else: self.printers = {} self.default_printer = ""
local_printers = [] local_classes = [] remote_printers = [] remote_classes = []
for name, printer in self.printers.iteritems(): if printer.default: self.default_printer = name self.servers.add(printer.getServer())
if printer.remote: if printer.is_class: remote_classes.append(name) else: remote_printers.append(name) else: if printer.is_class: local_classes.append(name) else: local_printers.append(name)
local_printers.sort() local_classes.sort() remote_printers.sort() remote_classes.sort()
expanded = { "_printers" : True, "_classes" : True, "_remote_printers" : True, "_remote_classes" : True, }
# remove old printers/classes iter = self.mainlist.get_iter_first() iter = self.mainlist.iter_next(iter) # step over server settings while iter: entry = self.mainlist.get_value(iter, 1) path = self.mainlist.get_path(iter) expanded[entry] = self.tvMainList.row_expanded(path) more_entries = self.mainlist.remove(iter) if not more_entries: break # add new for printers, text, name in ( (local_printers, _("Local Printers"), "_printers"), (local_classes, _("Local Classes"), "_classes"), (remote_printers, _("Remote Printers"), "_remote_printers"), (remote_classes, _("Remote Classes"), "_remote_classes")): if not printers: continue iter = self.mainlist.append(None, (text, name)) path = self.mainlist.get_path(iter)
for printer_name in printers: p_iter = self.mainlist.append(iter, (printer_name, "Printer")) if printer_name==old_name: select_path = self.mainlist.get_path(p_iter) if expanded[name]: self.tvMainList.expand_row(path, False) # Selection selection = self.tvMainList.get_selection() if select_path: selection.select_path(select_path) else: selection.unselect_all()
self.on_tvMainList_cursor_changed(self.tvMainList)
def maySelectItem(self, selection): result = self.mainlist.get_value( self.mainlist.get_iter(selection), 1) if result[0] == "_": return False if self.changed: response = self.ApplyDialog.run() self.ApplyDialog.hide() err = False if response == gtk.RESPONSE_APPLY: err = self.apply() self.changed = False if err or response == gtk.RESPONSE_CANCEL: return False return True
def getSelectedItem(self): model, iter = self.tvMainList.get_selection().get_selected() if iter is None: return ("", 'None') name, type = model.get_value(iter, 0), model.get_value(iter, 1) return name.strip(), type
# Connect to Server
def on_connect_activate(self, widget): # check for unapplied changes if self.changed: response = self.ApplyDialog.run() self.ApplyDialog.hide() err = False if response == gtk.RESPONSE_APPLY: err = self.apply() if err or response == gtk.RESPONSE_CANCEL: return
# Use browsed queues to build up a list of known IPP servers servers = self.getServers() current_server = (self.printer and self.printer.getServer()) \ or cups.getServer()
store = gtk.ListStore (gobject.TYPE_STRING) self.cmbServername.set_model(store) for server in servers: self.cmbServername.append_text(server) self.cmbServername.show()
self.cmbServername.child.set_text (current_server) self.entUser.set_text (cups.getUser()) self.chkEncrypted.set_active (cups.getEncryption() == cups.HTTP_ENCRYPT_ALWAYS)
self.cmbServername.grab_focus () self.ConnectDialog.set_transient_for (self.MainWindow) response = self.ConnectDialog.run()
self.ConnectDialog.hide()
if response != gtk.RESPONSE_OK: return
if self.chkEncrypted.get_active(): cups.setEncryption(cups.HTTP_ENCRYPT_ALWAYS) else: cups.setEncryption(cups.HTTP_ENCRYPT_IF_REQUESTED)
servername = self.cmbServername.child.get_text() user = self.entUser.get_text()
self.lblConnecting.set_text(_("Connecting to Server:\n%s") % servername) self.unloadFoomatic() self.ConnectingDialog.show() self.connect_thread = thread.start_new_thread( self.connect, (servername, user))
def on_cancel_connect_clicked(self, widget): """ Stop connection to new server (Doesn't really stop but sets flag for the connecting thread to ignore the connection) """ self.connect_thread = None self.ConnectingDialog.hide()
def connect(self, servername, user): """ Open a connection to a new server. Is executed in a separate thread! """ cups.setServer(servername) cups.setPasswordCB(self.cupsPasswdCallback) # cups.setEncryption (...)
if user: cups.setUser(user) self.password = ''
try: connection = cups.Connection() foomatic = Foomatic() foomatic.addCupsPPDs(connection.getPPDs(), connection) except RuntimeError, s: if self.connect_thread != thread.get_ident(): return gtk.gdk.threads_enter() self.ConnectingDialog.hide() self.show_IPP_Error(None, s) gtk.gdk.threads_leave() return except cups.IPPError, (e, s): if self.connect_thread != thread.get_ident(): return gtk.gdk.threads_enter() self.ConnectingDialog.hide() self.show_IPP_Error(e, s) gtk.gdk.threads_leave() return
if self.connect_thread != thread.get_ident(): return gtk.gdk.threads_enter()
try: self.foomatic = foomatic self.ConnectingDialog.hide() self.cups = connection self.setConnected() self.populateList() except cups.HTTPError, (s,): self.cups = None self.setConnected() self.populateList() self.show_HTTP_Error(s)
gtk.gdk.threads_leave()
def reconnect (self): """Reconnect to CUPS after the server has reloaded.""" # libcups will handle the reconnection; we just need to tell it # to do something. self.cups.getClasses ()
def on_btnCancelConnect_clicked(self, widget): """Close Connect dialog""" self.ConnectWindow.hide()
# Password handling
def cupsPasswdCallback(self, querystring): if self.passwd_retry or len(self.password) == 0: self.lblPasswordPrompt.set_label (self.prompt_primary + querystring) self.PasswordDialog.set_transient_for (self.MainWindow) self.entPasswd.grab_focus ()
result = self.PasswordDialog.run() self.PasswordDialog.hide() if result == gtk.RESPONSE_OK: self.password = self.entPasswd.get_text() else: self.password = '' self.passwd_retry = False else: self.passwd_retry = True return self.password def on_btnPasswdOk_clicked(self, widget): self.PasswordDialog.response(0)
def on_btnPasswdCancel_clicked(self, widget): self.PasswordDialog.response(1)
# refresh def on_btnRefresh_clicked(self, button): self.populateList()
# Unapplied changes dialog
def on_btnApplyApply_clicked(self, button): self.ApplyDialog.response(gtk.RESPONSE_APPLY)
def on_btnApplyCancel_clicked(self, button): self.ApplyDialog.response(gtk.RESPONSE_CANCEL)
def on_btnApplyDiscard_clicked(self, button): self.ApplyDialog.response(gtk.RESPONSE_REJECT)
# Data handling
def on_printer_changed(self, widget): if isinstance(widget, gtk.CheckButton): value = widget.get_active() elif isinstance(widget, gtk.Entry): value = widget.get_text() elif isinstance(widget, gtk.RadioButton): value = widget.get_active() elif isinstance(widget, gtk.ComboBox): value = widget.get_active_text() else: raise ValueError, "Widget type not supported (yet)"
p = self.printer old_values = { self.entPDescription : p.info, self.entPLocation : p.location, self.entPDevice : p.device_uri, self.chkPEnabled : p.enabled, self.chkPAccepting : not p.rejecting, self.chkPShared : p.is_shared, self.cmbPStartBanner : p.job_sheet_start, self.cmbPEndBanner : p.job_sheet_end, self.cmbPErrorPolicy : p.error_policy, self.cmbPOperationPolicy : p.op_policy, self.rbtnPAllow: p.default_allow, } old_value = old_values[widget] if old_value == value: self.changed.discard(widget) else: self.changed.add(widget) self.setDataButtonState() def option_changed(self, option): if option.is_changed(): self.changed.add(option) else: self.changed.discard(option)
if option.conflicts: self.conflicts.add(option) else: self.conflicts.discard(option) self.setDataButtonState()
# Access control def getPUsers(self): """return list of usernames from the GUI""" model = self.tvPUsers.get_model() result = [] model.foreach(lambda model, path, iter: result.append(model.get(iter, 0)[0])) result.sort() return result
def setPUsers(self, users): """write list of usernames inot the GUI""" model = self.tvPUsers.get_model() model.clear() for user in users: model.append((user,)) self.on_entPUser_changed(self.entPUser) self.on_tvPUsers_cursor_changed(self.tvPUsers)
def checkPUsersChanged(self): """check if users in GUI and printer are different and set self.changed""" if self.getPUsers() != self.printer.except_users: self.changed.add(self.tvPUsers) else: self.changed.discard(self.tvPUsers)
self.on_tvPUsers_cursor_changed(self.tvPUsers) self.setDataButtonState()
def on_btnPAddUser_clicked(self, button): user = self.entPUser.get_text() if user: self.tvPUsers.get_model().insert(0, (user,)) self.entPUser.set_text("") self.checkPUsersChanged() def on_btnPDelUser_clicked(self, button): model, rows = self.tvPUsers.get_selection().get_selected_rows() rows = [gtk.TreeRowReference(model, row) for row in rows] for row in rows: path = row.get_path() iter = model.get_iter(path) model.remove(iter) self.checkPUsersChanged()
def on_entPUser_changed(self, widget): self.btnPAddUser.set_sensitive(bool(widget.get_text()))
def on_tvPUsers_cursor_changed(self, widget): model, rows = widget.get_selection().get_selected_rows() self.btnPDelUser.set_sensitive(bool(rows))
# Server side options
def add_option(self, name, value, supported, is_new=False, editable=True): option = options.OptionWidget(name, value, supported, self.option_changed) option.is_new = is_new rows = self.tblServerOptions.get_property("n-rows") self.tblServerOptions.resize(rows+1, 3) self.tblServerOptions.attach(option.label, 0, 1, rows, rows+1, xoptions=gtk.FILL, yoptions=gtk.FILL) option.label.set_alignment(0.0, 0.0) option.label.set_padding(5, 5) align = gtk.Alignment() align.add(option.selector) option.align = align self.tblServerOptions.attach(align, 1, 2, rows, rows+1, xoptions=gtk.FILL, yoptions=0) option.selector.set_sensitive(editable) if editable: # remove button btn = gtk.Button(stock="gtk-remove") btn.connect("clicked", self.removeOption_clicked) btn.set_data("pyobject", option) align = gtk.Alignment() align.add(btn) self.tblServerOptions.attach(align, 2, 3, rows, rows+1, xoptions=0, yoptions=gtk.FILL) option.remove_button = align self.server_side_options[name] = option if name in self.changed: # was deleted before option.is_new = False self.changed.discard(name) if option.is_changed(): self.changed.add(option)
def removeOption_clicked(self, button): option = button.get_data("pyobject") self.tblServerOptions.remove(option.label) self.tblServerOptions.remove(option.align) self.tblServerOptions.remove(option.remove_button) if option.is_new: self.changed.discard(option) else: # keep name as reminder that option got deleted self.changed.add(option.name) del self.server_side_options[option.name]
# re add to combobox if option.name in self.printer.possible_attributes: for nr, row in enumerate(self.cmbentNewOption.get_model()): if row[0] > option.name: self.cmbentNewOption.insert_text(nr, option.name) break self.setDataButtonState()
def on_btnNewOption_clicked(self, button): name = self.cmbentNewOption.get_active_text() if name in self.printer.possible_attributes: value, supported = self.printer.possible_attributes[name] else: value, supported = "", "" self.add_option(name, value, supported, is_new=True) self.tblServerOptions.show_all() active = self.cmbentNewOption.get_active() if active >= 0: self.cmbentNewOption.remove_text(active) self.cmbentNewOption.set_active(-1) self.on_cmbentNewOption_changed(self.cmbentNewOption) self.setDataButtonState()
def on_cmbentNewOption_changed(self, widget): text = self.cmbentNewOption.get_active_text() active = bool(text) and text not in self.server_side_options self.btnNewOption.set_sensitive(active)
# set Apply/Revert buttons sensitive def setDataButtonState(self): for button in [self.btnApply, self.btnRevert]: button.set_sensitive(bool(self.changed) and not bool(self.conflicts))
try: # Might not be a printer selected if not self.test_button_cancels: self.btnPrintTestPage.set_sensitive (not bool (self.changed) and self.printer.enabled and not self.printer.rejecting) except: pass
if self.conflicts: self.btnConflict.show() else: self.btnConflict.hide()
def on_btnConflict_clicked(self, button): message = _("There are conflicting options.\n" "Changes can only be applied after\n" "these conflictes are resolved.") self.conflict_dialog.set_markup(message) self.conflict_dialog.run() self.conflict_dialog.hide()
# Apply Changes def on_btnApply_clicked(self, widget): err = self.apply() if not err: self.populateList() else: pass # XXX def apply(self): name, type = self.getSelectedItem() if type in ("Printer", "Class"): return self.save_printer(self.printer) elif type == "Settings": return self.save_serversettings() def show_IPP_Error(self, exception, message): if exception == cups.IPP_NOT_AUTHORIZED: error_text = ('<span weight="bold" size="larger">' + _('Not authorized') + '</span>\n\n' + _('The password may be incorrect.')) else: error_text = ('<span weight="bold" size="larger">' + _('CUPS server error') + '</span>\n\n' + _("There was an error during the CUPS "\ "operation: '%s'.")) % message self.lblError.set_markup(error_text) self.ErrorDialog.set_transient_for (self.MainWindow) self.ErrorDialog.run() self.ErrorDialog.hide() def show_HTTP_Error(self, status): if (status == cups.HTTP_UNAUTHORIZED or status == cups.HTTP_FORBIDDEN): error_text = ('<span weight="bold" size="larger">' + _('Not authorized') + '</span>\n\n' + _('The password may be incorrect, or the ' 'server may be configured to deny ' 'remote administration.')) else: if status == cups.HTTP_BAD_REQUEST: msg = _("Bad request") elif status == cups.HTTP_NOT_FOUND: msg = _("Not found") elif status == cups.HTTP_REQUEST_TIMEOUT: msg = _("Request timeout") elif status == cups.HTTP_UPGRADE_REQUIRED: msg = _("Upgrade required") elif status == cups.HTTP_SERVER_ERROR: msg = _("Server error") else: msg = _("status %d") % status
error_text = ('<span weight="bold" size="larger">' + _('CUPS server error') + '</span>\n\n' + _("There was an HTTP error: %s.")) % msg self.lblError.set_markup(error_text) self.ErrorDialog.set_transient_for (self.MainWindow) self.ErrorDialog.run() self.ErrorDialog.hide() def save_printer(self, printer, saveall=False): name = printer.name try: if not printer.is_class and self.ppd: self.getPrinterSettings() if self.ppd.nondefaultsMarked() or saveall: self.passwd_retry = False # use cached Passwd self.cups.addPrinter(name, ppd=self.ppd)
if printer.is_class: # update member list new_members = self.getCurrentClassMembers(self.tvClassMembers) if not new_members: dialog = gtk.MessageDialog( flags=0, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_YES_NO, message_format=_("This will delete this class!")) dialog.format_secondary_text(_("Proceed anyway?")) result = dialog.run() dialog.destroy() if result==gtk.RESPONSE_NO: return True
# update member list old_members = printer.class_members[:] for member in new_members: if member in old_members: old_members.remove(member) else: self.cups.addPrinterToClass(member, name) for member in old_members: self.cups.deletePrinterFromClass(member, name)
location = self.entPLocation.get_text() info = self.entPDescription.get_text() device_uri = self.entPDevice.get_text() if device_uri.find (ellipsis) != -1: # The URI is sanitized and not editable. device_uri = printer.device_uri
enabled = self.chkPEnabled.get_active() accepting = self.chkPAccepting.get_active() shared = self.chkPShared.get_active()
if info!=printer.info or saveall: self.passwd_retry = False # use cached Passwd self.cups.setPrinterInfo(name, info) if location!=printer.location or saveall: self.passwd_retry = False # use cached Passwd self.cups.setPrinterLocation(name, location) if (not printer.is_class and (device_uri!=printer.device_uri or saveall)): self.passwd_retry = False # use cached Passwd self.cups.setPrinterDevice(name, device_uri)
if enabled != printer.enabled or saveall: self.passwd_retry = False # use cached Passwd self.printer.setEnabled(enabled) if accepting == printer.rejecting or saveall: self.passwd_retry = False # use cached Passwd self.printer.setAccepting(accepting) if shared != printer.is_shared or saveall: self.passwd_retry = False # use cached Passwd self.printer.setShared(shared) job_sheet_start = self.cmbPStartBanner.get_active_text() job_sheet_end = self.cmbPEndBanner.get_active_text() error_policy = self.cmbPErrorPolicy.get_active_text() op_policy = self.cmbPOperationPolicy.get_active_text()
if (job_sheet_start != printer.job_sheet_start or job_sheet_end != printer.job_sheet_end) or saveall: self.passwd_retry = False # use cached Passwd printer.setJobSheets(job_sheet_start, job_sheet_end) if error_policy != printer.error_policy or saveall: self.passwd_retry = False # use cached Passwd printer.setErrorPolicy(error_policy) if op_policy != printer.op_policy or saveall: self.passwd_retry = False # use cached Passwd printer.setOperationPolicy(op_policy)
default_allow = self.rbtnPAllow.get_active() except_users = self.getPUsers()
if (default_allow != printer.default_allow or except_users != printer.except_users) or saveall: self.passwd_retry = False # use cached Passwd printer.setAccess(default_allow, except_users)
for option in printer.attributes: if option not in self.server_side_options: printer.unsetOption(option) for option in self.server_side_options.itervalues(): if option.is_changed or saveall: printer.setOption(option.name, option.get_current_value())
except cups.IPPError, (e, s): self.show_IPP_Error(e, s) return True self.changed = set() # of options
# Update our copy of the printer's settings. printers = cupshelpers.getPrinters (self.cups) this_printer = { name: printers[name] } self.printers.update (this_printer)
return False
def getPrinterSettings(self): #self.ppd.markDefaults() for option in self.options.itervalues(): option.writeback()
# revert changes
def on_btnRevert_clicked(self, button): self.changed = set() # avoid asking the user self.on_tvMainList_cursor_changed(self.tvMainList)
# set default printer def on_btnPMakeDefault_clicked(self, button): try: self.cups.setDefault(self.printer.name) except cups.IPPError, (e, msg): self.show_IPP_Error(e, msg) self.populateList()
# print test page def on_btnPrintTestPage_clicked(self, button): if self.test_button_cancels: jobs = self.printer.testsQueued () for job in jobs: print "Cancelling job %s" % job try: self.cups.cancelJob (job) except cups.IPPError, (e, msg): self.show_IPP_Error(e, msg) self.setTestButton (self.printer) return try: job_id = self.cups.printTestPage(self.printer.name) self.lblInfo.set_markup ('<span weight="bold" size="larger">' + _("Submitted") + '</span>\n\n' + _("Test page submitted as " "job %d") % job_id) self.InfoDialog.set_transient_for (self.MainWindow) self.setTestButton (self.printer) self.InfoDialog.run () self.InfoDialog.hide () except cups.IPPError, (e, msg): if (e == cups.IPP_NOT_AUTHORIZED and self.printer.name != 'localhost'): self.lblError.set_markup ('<span weight="bold" size="larger">'+ _("Not possible") + '</span>\n\n' + _("The remote server did not accept " "the print job, most likely " "because the printer is not " "shared.")) self.ErrorDialog.set_transient_for (self.MainWindow) self.ErrorDialog.run () self.ErrorDialog.hide () else: self.show_IPP_Error(e, msg)
# select Item
def on_tvMainList_cursor_changed(self, list): name, type = self.getSelectedItem() model, self.mainListSelected = self.tvMainList.get_selection().get_selected() item_selected = True if type == "Settings": self.ntbkMain.set_current_page(0) if self.cups: self.fillServerTab() item_selected = False elif type in ['Printer', 'Class']: self.fillPrinterTab(name) self.ntbkMain.set_current_page(1) elif type == "None": self.ntbkMain.set_current_page(2) self.setDataButtonState() item_selected = False
is_local = item_selected and not self.printers[name].remote for widget in [self.copy, self.delete, self.btnCopy, self.btnDelete]: widget.set_sensitive(is_local)
def fillComboBox(self, combobox, values, value): combobox.get_model().clear() for nr, val in enumerate(values): combobox.append_text(val) if val == value: combobox.set_active(nr)
def fillPrinterTab(self, name): self.changed = set() # of options self.options = {} # keyword -> Option object self.conflicts = set() # of options
printer = self.printers[name] self.printer = printer
editable = not self.printer.remote
try: self.ppd = printer.getPPD() except cups.IPPError, (e, m): self.show_IPP_Error(e, m) self.ppd = False
for widget in (self.entPDescription, self.entPLocation, self.entPDevice, self.btnSelectDevice, self.btnChangePPD, self.chkPEnabled, self.chkPAccepting, self.chkPShared, self.cmbPStartBanner, self.cmbPEndBanner, self.cmbPErrorPolicy, self.cmbPOperationPolicy, self.rbtnPAllow, self.rbtnPDeny, self.tvPUsers, self.entPUser, self.btnPAddUser, self.btnPDelUser, self.cmbentNewOption): widget.set_sensitive(editable)
# Description page self.entPDescription.set_text(printer.info) self.entPLocation.set_text(printer.location) self.lblPMakeModel.set_text(printer.make_and_model) self.lblPState.set_text(printer.state_description)
uri = printer.device_uri if uri.startswith("smb://"): group, host, share, user, password = self.parse_SMBURI(uri[6:]) if password: uri = "smb://" if len (user) or len (password): uri += ellipsis uri += self.construct_SMBURI(group, host, share) self.entPDevice.set_sensitive(False) self.entPDevice.set_text(uri) self.changed.discard(self.entPDevice) # Hide make/model and Device URI for classes for widget in (self.lblPMakeModel2, self.lblPMakeModel, self.btnChangePPD, self.lblPDevice2, self.entPDevice, self.btnSelectDevice): if printer.is_class: widget.hide() else: widget.show()
self.chkPEnabled.set_active(printer.enabled) self.chkPAccepting.set_active(not printer.rejecting) self.chkPShared.set_active(printer.is_shared)
# default printer self.btnPMakeDefault.set_sensitive(not printer.default) if printer.default: self.lblPDefault.set_text(_("This is the default printer")) elif self.default_printer: self.lblPDefault.set_text(_("Default printer is %s") % self.default_printer) else: self.lblPDefault.set_text(_("No default printer set."))
self.setTestButton (printer)
# Policy tab # ---------- # Job sheets self.fillComboBox(self.cmbPStartBanner, printer.job_sheets_supported, printer.job_sheet_start), self.fillComboBox(self.cmbPEndBanner, printer.job_sheets_supported, printer.job_sheet_end) self.cmbPStartBanner.set_sensitive(editable) self.cmbPEndBanner.set_sensitive(editable)
# Policies self.fillComboBox(self.cmbPErrorPolicy, printer.error_policy_supported, printer.error_policy) self.fillComboBox(self.cmbPOperationPolicy, printer.op_policy_supported, printer.op_policy) self.cmbPErrorPolicy.set_sensitive(editable) self.cmbPOperationPolicy.set_sensitive(editable)
# Access control self.rbtnPAllow.set_active(printer.default_allow) self.rbtnPDeny.set_active(not printer.default_allow) self.setPUsers(printer.except_users)
self.entPUser.set_text("")
# Server side options
self.server_side_options = {} self.cmbentNewOption.get_model().clear() self.cmbentNewOption.get_child().set_text("") self.btnNewOption.set_sensitive(False) attrs = self.printer.possible_attributes.keys() attrs.sort() for attr in attrs: if attr not in self.printer.attributes: self.cmbentNewOption.append_text(attr)
self.tblServerOptions.resize(1, 3) for child in self.tblServerOptions.get_children(): self.tblServerOptions.remove(child)
attrs = printer.attributes.keys() attrs.sort() for attr in attrs: value = printer.attributes[attr] if attr in printer.possible_attributes: supported = printer.possible_attributes[attr][1] else: supported = "" self.add_option(attr, value, supported, is_new=False, editable=editable)
self.tblServerOptions.show_all() self.tblServerOptions.queue_draw()
if printer.is_class: # remove InstallOptions tab tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions) if tab_nr != -1: self.ntbkPrinter.remove_page(tab_nr) self.fillClassMembers(name, editable) else: # real Printer self.fillPrinterOptions(name, editable)
self.setDataButtonState()
def setTestButton (self, printer): if printer.testsQueued (): self.test_button_cancels = True self.btnPrintTestPage.set_label (_('Cancel Tests')) self.btnPrintTestPage.set_sensitive (True) else: self.test_button_cancels = False self.btnPrintTestPage.set_label (_('Print Test Page')) self.setDataButtonState ()
def fillPrinterOptions(self, name, editable): # remove Class membership tab tab_nr = self.ntbkPrinter.page_num(self.algnClassMembers) if tab_nr != -1: self.ntbkPrinter.remove_page(tab_nr)
# clean Installable Options Tab for widget in self.vbPInstallOptions.get_children(): self.vbPInstallOptions.remove(widget)
# clean Options Tab for widget in self.vbPOptions.get_children(): self.vbPOptions.remove(widget) # insert Options Tab if self.ntbkPrinter.page_num(self.swPOptions) == -1: self.ntbkPrinter.insert_page( self.swPOptions, self.lblPOptions, self.static_tabs)
if not self.ppd: tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions) if tab_nr != -1: self.ntbkPrinter.remove_page(tab_nr) tab_nr = self.ntbkPrinter.page_num(self.swPOptions) if tab_nr != -1: self.ntbkPrinter.remove_page(tab_nr) return ppd = self.ppd ppd.markDefaults()
hasInstallableOptions = False # build option tabs for group in ppd.optionGroups: if group.name == "InstallableOptions": hasInstallableOptions = True container = self.vbPInstallOptions tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions) if tab_nr == -1: self.ntbkPrinter.insert_page( self.swPInstallOptions, gtk.Label(group.text), self.static_tabs) else: frame = gtk.Frame("<b>%s</b>" % group.text) frame.get_label_widget().set_use_markup(True) frame.set_shadow_type (gtk.SHADOW_NONE) self.vbPOptions.pack_start (frame, False, False, 0) container = gtk.Alignment (0.5, 0.5, 1.0, 1.0) container.set_padding (0, 0, 12, 0) frame.add (container)
table = gtk.Table(1, 3, False) table.set_col_spacing(0, 6) container.add(table)
rows = 0 for nr, option in enumerate(group.options): if option.keyword == "PageRegion": continue rows += 1 table.resize (rows, 3) o = OptionWidget(option, ppd, self) table.attach(o.conflictIcon, 0, 1, nr, nr+1, 0, 0, 0, 0)
hbox = gtk.HBox() if o.label: a = gtk.Alignment (0.5, 0.5, 1.0, 1.0) a.set_padding (0, 0, 0, 6) a.add (o.label) table.attach(a, 1, 2, nr, nr+1, gtk.FILL, 0, 0, 0) table.attach(hbox, 2, 3, nr, nr+1, gtk.FILL, 0, 0, 0) else: table.attach(hbox, 1, 3, nr, nr+1, gtk.FILL, 0, 0, 0) hbox.pack_start(o.selector, False) self.options[option.keyword] = o o.selector.set_sensitive(editable)
# remove Installable Options tab if not needed if not hasInstallableOptions: tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions) if tab_nr != -1: self.ntbkPrinter.remove_page(tab_nr)
# check for conflicts for option in self.options.itervalues(): conflicts = option.checkConflicts() if conflicts: self.conflicts.add(option)
self.swPInstallOptions.show_all() self.swPOptions.show_all()
# Class members def fillClassMembers(self, name, editable): printer = self.printers[name]
self.btnClassAddMember.set_sensitive(editable) self.btnClassDelMember.set_sensitive(editable)
# remove Options tab tab_nr = self.ntbkPrinter.page_num(self.swPOptions) if tab_nr != -1: self.ntbkPrinter.remove_page(tab_nr)
# insert Member Tab if self.ntbkPrinter.page_num(self.algnClassMembers) == -1: self.ntbkPrinter.insert_page( self.algnClassMembers, self.lblClassMembers, self.static_tabs)
model_members = self.tvClassMembers.get_model() model_not_members = self.tvClassNotMembers.get_model() model_members.clear() model_not_members.clear()
names = self.printers.keys() names.sort() for name in names: p = self.printers[name] if p is not printer: if name in printer.class_members: model_members.append((name, )) else: model_not_members.append((name, )) def on_btnClassAddMember_clicked(self, button): self.moveClassMembers(self.tvClassNotMembers, self.tvClassMembers) if self.getCurrentClassMembers(self.tvClassMembers) != self.printer.class_members: self.changed.add(self.tvClassMembers) else: self.changed.discard(self.tvClassMembers) self.setDataButtonState() def on_btnClassDelMember_clicked(self, button): self.moveClassMembers(self.tvClassMembers, self.tvClassNotMembers) if self.getCurrentClassMembers(self.tvClassMembers) != self.printer.class_members: self.changed.add(self.tvClassMembers) else: self.changed.discard(self.tvClassMembers) self.setDataButtonState() def moveClassMembers(self, treeview_from, treeview_to): selection = treeview_from.get_selection() model_from, rows = selection.get_selected_rows() rows = [gtk.TreeRowReference(model_from, row) for row in rows]
model_to = treeview_to.get_model() for row in rows: path = row.get_path() iter = model_from.get_iter(path) row_data = model_from.get(iter, 0) model_to.append(row_data) model_from.remove(iter)
def getCurrentClassMembers(self, treeview): model = treeview.get_model() iter = model.get_iter_root() result = [] while iter: result.append(model.get(iter, 0)[0]) iter = model.iter_next(iter) result.sort() return result
# Quit def on_quit_activate(self, widget, event=None): # check for unapplied changes if self.changed: response = self.ApplyDialog.run() self.ApplyDialog.hide() err = False if response == gtk.RESPONSE_APPLY: err = self.apply() if err or response == gtk.RESPONSE_CANCEL: return gtk.main_quit()
# Copy def on_copy_activate(self, widget): # check for unapplied changes if self.changed: response = self.ApplyDialog.run() self.ApplyDialog.hide() err = False
if response == gtk.RESPONSE_REJECT: self.changed = set() # avoid asking the user self.on_tvMainList_cursor_changed(self.tvMainList) elif response == gtk.RESPONSE_APPLY: err = self.apply() if err or response == gtk.RESPONSE_CANCEL: return
self.entCopyName.set_text(self.printer.name) result = self.NewPrinterName.run() self.NewPrinterName.hide()
if result == gtk.RESPONSE_CANCEL: return
self.printer.name = self.entCopyName.get_text() self.printer.class_members = [] # for classes make shure all members # will get added self.save_printer(self.printer, saveall=True) self.populateList()
def on_entCopyName_changed(self, widget): # restrict text = widget.get_text() new_text = text new_text = new_text.replace("/", "") new_text = new_text.replace("#", "") new_text = new_text.replace(" ", "") if text!=new_text: widget.set_text(new_text) self.btnCopyOk.set_sensitive( self.check_NPName(new_text))
# Delete
def on_delete_activate(self, widget): name, type = self.getSelectedItem()
# Confirm dialog = gtk.MessageDialog( self.MainWindow, buttons=gtk.BUTTONS_OK_CANCEL, message_format=_("Really delete %s %s?") % (_(type), name)) result = dialog.run() dialog.destroy()
if result == gtk.RESPONSE_CANCEL: return
try: self.cups.deletePrinter(name) except cups.IPPError, (e, msg): self.show_IPP_Error(e, msg)
self.changed = set() self.populateList()
# About dialog def on_about_activate(self, widget): self.AboutDialog.run() self.AboutDialog.hide()
# ==================================================================== # == New Printer Dialog ============================================== # ====================================================================
new_printer_device_tabs = { "parallel" : 0, # empty tab "usb" : 0, "hal" : 0, "beh" : 0, "hp" : 0, "socket": 2, "ipp" : 3, "http" : 3, "lpd" : 4, "scsi" : 5, "serial" : 6, "smb" : 7, }
# new printer def on_new_printer_activate(self, widget): self.dialog_mode = "printer" self.NewPrinterWindow.set_title(_("New Printer")) self.on_rbtnNPFoomatic_toggled(self.rbtnNPFoomatic)
self.initNewPrinterWindow()
# new class def on_new_class_activate(self, widget): self.dialog_mode = "class" self.NewPrinterWindow.set_title(_("New Class"))
self.fillNewClassMembers()
self.initNewPrinterWindow()
# change device def on_btnSelectDevice_clicked(self, button): self.busy (self.MainWindow) self.loadFoomatic() self.dialog_mode = "device" self.initNewPrinterWindow() self.NewPrinterWindow.set_title(_("Change Device URI"))
self.ntbkNewPrinter.set_current_page(1) self.fillDeviceTab(self.printer.device_uri)
self.initNewPrinterWindow() self.ready (self.MainWindow)
# change PPD def on_btnChangePPD_clicked(self, button): self.busy (self.MainWindow) self.loadFoomatic() self.dialog_mode = "ppd" self.initNewPrinterWindow() self.NewPrinterWindow.set_title(_("Change Driver"))
self.ntbkNewPrinter.set_current_page(2) self.on_rbtnNPFoomatic_toggled(self.rbtnNPFoomatic)
self.auto_model = "" if self.ppd: attr = self.ppd.findAttr("Manufacturer") if attr: self.auto_make = attr.value else: self.auto_make = "" attr = self.ppd.findAttr("ModelName") if not attr: attr = self.ppd.findAttr("ShortNickName") if not attr: attr = self.ppd.findAttr("NickName") if attr: if attr.value.startswith(self.auto_make): self.auto_model = attr.value[len(self.auto_make):].strip () else: try: self.auto_model = attr.value.split(" ", 1)[1] except IndexError: self.auto_model = "" else: self.auto_model = "" else: # Special CUPS names for a raw queue. self.auto_make = 'Raw' self.auto_model = 'Queue'
self.fillMakeList() self.initNewPrinterWindow() self.ready (self.MainWindow)
def initNewPrinterWindow(self): if self.dialog_mode in ("printer", "class"): self.ntbkNewPrinter.set_current_page(0) self.entNPName.set_text ('printer') self.entNPName.grab_focus() for widget in [self.entNPLocation, self.entNPDescription, self.entSMBURI, self.entSMBUsername, self.entSMBPassword, self.entNPTDirectJetHostname]: widget.set_text('')
self.entNPTDirectJetPort.set_text('9100') self.setNPButtons() self.NewPrinterWindow.set_transient_for(self.MainWindow) self.NewPrinterWindow.show()
# Class members
def fillNewClassMembers(self): model = self.tvNCMembers.get_model() model.clear() model = self.tvNCNotMembers.get_model() model.clear() for printer in self.printers.itervalues(): model.append((printer.name,))
def on_btnNCAddMember_clicked(self, button): self.moveClassMembers(self.tvNCNotMembers, self.tvNCMembers) self.btnNPForward.set_sensitive( bool(self.getCurrentClassMembers(self.tvNCMembers))) def on_btnNCDelMember_clicked(self, button): self.moveClassMembers(self.tvNCMembers, self.tvNCNotMembers) self.btnNPForward.set_sensitive( bool(self.getCurrentClassMembers(self.tvNCMembers)))
# Navigation buttons
def on_NPCancel(self, widget, event=None): self.NewPrinterWindow.hide() return True
def on_btnNPBack_clicked(self, widget): self.nextNPTab(-1)
def on_btnNPForward_clicked(self, widget): self.nextNPTab()
def nextNPTab(self, step=1): page_nr = self.ntbkNewPrinter.get_current_page() if self.dialog_mode == "class": order = [0, 4, 5] elif self.dialog_mode == "printer": self.busy (self.NewPrinterWindow) self.loadFoomatic() if page_nr == 0: self.fillDeviceTab() self.fillMakeList() self.ready (self.NewPrinterWindow) if self.rbtnNPFoomatic.get_active(): order = [0, 1, 2, 3, 5] else: order = [0, 1, 2, 5] elif self.dialog_mode == "device": order = [1] elif self.dialog_mode == "ppd": if self.rbtnNPFoomatic.get_active(): order = [2, 3, 6] else: order = [2, 6] page_nr = self.ntbkNewPrinter.set_current_page( order[order.index(page_nr)+step]) self.setNPButtons()
def setNPButtons(self): nr = self.ntbkNewPrinter.get_current_page()
if self.dialog_mode == "device": self.btnNPBack.hide() self.btnNPForward.hide() self.btnNPApply.show() return
if self.dialog_mode == "ppd": if nr == 6: # Apply self.btnNPForward.hide() self.btnNPApply.show() return else: self.btnNPForward.show() self.btnNPApply.hide() if nr == 2: self.btnNPBack.hide() self.btnNPForward.show() self.btnNPForward.set_sensitive(True) return else: self.btnNPBack.show()
# class/printer
if nr == 0: # name self.btnNPBack.hide() self.btnNPForward.set_sensitive( self.check_NPName(self.entNPName.get_text())) else: self.btnNPBack.show() if nr == 1: # Device self.btnNPForward.set_sensitive(True) if nr == 2: # Make/PPD file self.btnNPForward.set_sensitive(bool( self.rbtnNPFoomatic.get_active() or self.filechooserPPD.get_filename())) if nr == 3: # Model/Driver model, iter = self.tvNPDrivers.get_selection().get_selected() self.btnNPForward.set_sensitive(bool(iter)) if nr == 4: # Class Members self.btnNPForward.set_sensitive( bool(self.getCurrentClassMembers(self.tvNCMembers))) if nr == 5: # Apply self.btnNPForward.hide() self.btnNPApply.show() self.fillNPApply() else: self.btnNPForward.show() self.btnNPApply.hide() def check_NPName(self, name): if not name: return False name = name.lower() for printer in self.printers.values(): if not printer.remote and printer.name.lower()==name: return False return True def on_entNPName_changed(self, widget): # restrict text = widget.get_text() new_text = text new_text = new_text.replace("/", "") new_text = new_text.replace("#", "") new_text = new_text.replace(" ", "") if text!=new_text: widget.set_text(new_text) self.btnNPForward.set_sensitive( self.check_NPName(new_text))
# Device URI
def fillDeviceTab(self, current_uri=None): try: devices = cupshelpers.getDevices(self.cups, current_uri) except cups.IPPError, (e, msg): self.show_IPP_Error(e, msg) devices = {} if current_uri: current = devices.pop(current_uri) devices = devices.values() devices.sort() self.devices = filter(lambda x: x.uri not in ("hp:/no_device_found", "hpfax:/no_device_found", "hal", "beh", "scsi", "http"), devices)
self.devices.append(cupshelpers.Device('', **{'device-info' :_("Other")})) if current_uri: current.info += _(" (Current)") self.devices.insert(0, current) model = self.tvNPDevices.get_model() model.clear()
for device in self.devices: model.append((device.info,)) self.tvNPDevices.get_selection().select_path(0) self.on_tvNPDevices_cursor_changed(self.tvNPDevices)
def browse_smb_hosts (self): """Initialise the SMB tree store.""" store = self.smb_store store.clear ()
self.busy(self.NewPrinterWindow) iter = None domains = pysmb.get_domain_list () for domain in domains.keys (): d = domains[domain] iter = store.append (None) store.set_value (iter, 0, d['DOMAIN']) store.set_value (iter, 2, d)
if iter: dummy = store.append (iter) self.ready(self.NewPrinterWindow)
def smb_select_function (self, path): """Don't allow this path to be selected unless it is a leaf.""" iter = self.smb_store.get_iter (path) return not self.smb_store.iter_has_child (iter)
def on_tvSMBBrowser_row_activated (self, view, path, column): """Handle double-clicks in the SMB tree view.""" store = self.smb_store iter = store.get_iter (path) if store.iter_depth (iter) == 2: # This is a share, not a host. return
if view.row_expanded (path): view.collapse_row (path) else: self.on_tvSMBBrowser_row_expanded (view, iter, path)
def on_tvSMBBrowser_row_expanded (self, view, iter, path): """Handler for expanding a row in the SMB tree view.""" store = self.smb_store if len (path) == 2: # Click on host, look for shares try: if self.expanding_row: return except: self.expanding_row = 1
host = store.get_value (iter, 3) if host: self.busy (self.NewPrinterWindow) printers = pysmb.get_printer_list (host) while store.iter_has_child (iter): i = store.iter_nth_child (iter, 0) store.remove (i) for printer in printers.keys(): i = store.append (iter) store.set_value (i, 0, printer) store.set_value (i, 1, printers[printer]) self.ready (self.NewPrinterWindow)
view.expand_row (path, 1) del self.expanding_row else: # Click on domain, look for hosts try: if self.expanding_row: return except: self.expanding_row = 1
domain = store.get_value (iter, 2) if domain: self.busy (self.NewPrinterWindow) hosts = pysmb.get_host_list (domain['IP']) while store.iter_has_child (iter): i = store.iter_nth_child (iter, 0) store.remove (i) i = None for host in hosts.keys(): h = hosts[host] i = store.append (iter) store.set_value (i, 0, h['NAME']) store.set_value (i, 3, h) if i: dummy = store.append (i) self.ready (self.NewPrinterWindow) view.expand_row (path, 0) del self.expanding_row
def parse_SMBURI (self, uri): user = '' password = '' auth = uri.find ('@') if auth != -1: u = uri[:auth].find(':') if u != -1: user = uri[:u] password = uri[u + 1:auth] else: user = uri[:auth] uri = uri[auth + 1:] sep = uri.count ('/') group = '' if sep == 2: g = uri.find('/') group = uri[:g] uri = uri[g + 1:] if sep < 1: host = 'localhost' else: h = uri.find('/') host = uri[:h] uri = uri[h + 1:] p = host.find(':') if p != -1: host = host[:p] share = uri return (group, host, share, percentDecode (user), percentDecode (password))
def construct_SMBURI (self, group, host, share, user = '', password = ''): uri_password = '' if password: uri_password = ':' + percentEncode (password) if user: uri_password += '@' return "%s%s%s/%s/%s" % (percentEncode (user), uri_password, group, host, share)
def on_entSMBURI_changed (self, ent): try: if self.ignore_signals: return except: pass
uri = ent.get_text () (group, host, share, user, password) = self.parse_SMBURI (uri) if user: self.entSMBUsername.set_text (user) if password: self.entSMBPassword.set_text (password) self.tvSMBBrowser.get_selection ().unselect_all () if user or password: ent.set_text(self.construct_SMBURI(group, host, share))
def on_tvSMBBrowser_cursor_changed (self, view): store, iter = view.get_selection ().get_selected () if not iter or store.iter_depth(iter) != 2: return
parent_iter = store.iter_parent (iter) domain_iter = store.iter_parent (parent_iter) group = store.get_value (domain_iter, 0) host = store.get_value (parent_iter, 0) share = store.get_value (iter, 0) uri = self.construct_SMBURI (group, host, share) self.ignore_signals = True # Avoid 'changed' signal from Entry self.entSMBURI.set_text (uri) del self.ignore_signals
def on_btnSMBVerify_clicked(self, button): uri = self.entSMBURI.get_text () (group, host, share, u, p) = self.parse_SMBURI (uri) user = self.entSMBUsername.get_text () passwd = self.entSMBPassword.get_text () accessible = pysmb.printer_share_accessible ("//%s/%s" % (host, share), group = group, user = user, passwd = passwd) if accessible: self.lblInfo.set_markup ('<span weight="bold" size="larger">' + _("Verified") + '</span>\n\n' + _("This print share is accessible.")) self.InfoDialog.set_transient_for (self.NewPrinterWindow) self.InfoDialog.run() self.InfoDialog.hide () return
self.lblError.set_markup ('<span weight="bold" size="larger">' + _("Inaccessible") + '</span>\n\n' + _("This print share is not accessible.")) self.ErrorDialog.set_transient_for (self.NewPrinterWindow) self.ErrorDialog.run() self.ErrorDialog.hide ()
def on_tvNPDevices_cursor_changed(self, widget): model, iter = widget.get_selection().get_selected() path = model.get_path(iter) device = self.devices[path[0]] self.device = device self.ntbkNPType.set_current_page( self.new_printer_device_tabs.get(device.type, 1))
type = device.type url = device.uri.split(":", 1)[-1] if device.type=="serial": if not device.is_class: options = device.uri.split("?")[1] options = options.split("+") option_dict = {} for option in options: name, value = option.split("=") option_dict[name] = value for widget, name, optionvalues in ( (self.cmbNPTSerialBaud, "baud", None), (self.cmbNPTSerialBits, "bits", None), (self.cmbNPTSerialParity, "parity", ["none", "odd", "even"]), (self.cmbNPTSerialFlow, "flow", ["none", "soft", "hard", "hard"])): if option_dict.has_key(name): # option given in URI? if optionvalues is None: # use text in widget model = widget.get_model() iter = model.get_iter_first() nr = 0 while iter: value = model.get(iter,0)[0] if value == option_dict[name]: widget.set_active(nr) break iter = model.iter_next(iter) nr += 1 else: # use optionvalues nr = optionvalues.index( option_dict[name]) widget.set_active(nr+1) # compensate "Default" else: widget.set_active(0) # XXX FILL TABS FOR VALID DEVICE URIs elif device.type in ("ipp", "http"): server = "" printer = "" if url[:2] == "//": p = url[2:] t = p.find ('/') if t != -1: server = p[:t] p = p[t + 1:]
# Skip over 'printers/' or 'classes/' t = p.find ('/') if t != -1: printer = p[t + 1:]
self.entNPTIPPHostname.set_text(server) self.entNPTIPPPrintername.set_text(printer) elif device.type == "lpd": pass # XXX elif device.uri == "smb": self.entSMBURI.set_text('') self.browse_smb_hosts () elif device.type == "smb": self.entSMBURI.set_text(device.uri[6:]) else: self.entNPTDevice.set_text(device.uri)
self.auto_make, self.auto_model = None, None
printer_name = self.foomatic.getPrinterFromCupsDevice(self.device) if printer_name: printer = self.foomatic.getPrinter(printer_name) if printer: self.auto_make, self.auto_model = printer.make, printer.model self.fillMakeList()
def on_btnNPTLpdProbe_clicked(self, button): # read hostname, probe, fill printer names hostname = self.cmbentNPTLpdHost.get_active_text() server = probe_printer.LpdServer(hostname) printers = server.probe() model = self.cmbentNPTLpdQueue.get_model() model.clear() for printer in printers: self.cmbentNPTLpdQueue.append_text(printer) if printers: self.cmbentNPTLpdQueue.set_active(0) def getDeviceURI(self): type = self.device.type if type == "socket": # DirectJet host = self.entNPTDirectJetHostname.get_text() port = self.entNPTDirectJetPort.get_text() device = "socket://" + host if port: device = device + ':' + port elif type in ("http", "ipp"): # IPP host = self.entNPTIPPHostname.get_text() printer = self.entNPTIPPPrintername.get_text() device = "ipp://" + host if printer: device = device + "/printers/" + printer elif type == "lpd": # LPD host = self.cmbentNPTLpdHost.get_active_text() printer = self.cmbentNPTLpdQueue.get_active_text() device = "lpd://" + host if printer: device = device + "/" + printer elif type == "parallel": # Parallel device = self.device.uri elif type == "scsi": # SCSII device = "" elif type == "serial": # Serial options = [] for widget, name, optionvalues in ( (self.cmbNPTSerialBaud, "baud", None), (self.cmbNPTSerialBits, "bits", None), (self.cmbNPTSerialParity, "parity", ("none", "odd", "even")), (self.cmbNPTSerialFlow, "flow", ("none", "soft", "hard", "hard"))): nr = widget.get_active() if nr: if optionvalues is not None: option = optionvalues[nr-1] else: option = widget.get_active_text() options.append(name + "=" + option) options = "+".join(options) device = self.device.uri.split("?")[0] #"serial:/dev/ttyS%s" if options: device = device + "?" + options elif type == "smb": uri = self.entSMBURI.get_text () (group, host, share, u, p) = self.parse_SMBURI (uri) user = self.entSMBUsername.get_text () password = self.entSMBPassword.get_text () uri = self.construct_SMBURI (group, host, share, user, password) device = "smb://" + uri elif not self.device.is_class: device = self.device.uri else: device = self.entNPTDevice.get_text() return device # PPD
def on_rbtnNPFoomatic_toggled(self, widget): foo = self.rbtnNPFoomatic.get_active() self.tvNPMakes.set_sensitive(foo) self.filechooserPPD.set_sensitive(not foo) self.setNPButtons()
def on_filechooserPPD_selection_changed(self, widget): self.setNPButtons()
# PPD from foomatic
def fillMakeList(self): makes = self.foomatic.getMakes() model = self.tvNPMakes.get_model() model.clear() found = False for make in makes: iter = model.append((make,)) if make==self.auto_make: self.tvNPMakes.get_selection().select_iter(iter) path = model.get_path(iter) self.tvNPMakes.scroll_to_cell(path, None, True, 0.5, 0.5) found = True
if not found: self.tvNPMakes.get_selection().select_path(0) self.tvNPMakes.scroll_to_cell(0, None, True, 0.0, 0.0) self.on_tvNPMakes_cursor_changed(self.tvNPMakes) #tree = BuildTree(names, 3, 3) #tree.name = maker #self._fillPPDList(None, tree) #names = [] #for printername in self.foomatic.get_printers(): # printer = self.foomatic.get_printer(printername) # names.append(printer.make + " " + printer.model) #names.sort(cups.modelSort) #tree = BuildTree(names, mindepth=3, minwidth=3)
#self._fillPPDList(None, tree)
#def _fillPPDList(self, iter, treenode): # if treenode.name: # iter = self.tvNPDriversModel.append(iter, (treenode.name,)) # for leaf in treenode.leafs: # self._fillPPDList(iter, leaf)
def on_tvNPMakes_cursor_changed(self, widget): model, iter = self.tvNPMakes.get_selection().get_selected() self.NPMake = model.get(iter, 0)[0] self.fillModelList()
def fillModelList(self): models = self.foomatic.getModels(self.NPMake) model = self.tvNPModels.get_model() model.clear() selected = False for pmodel in models: iter = model.append((pmodel,)) if self.NPMake==self.auto_make and pmodel==self.auto_model: path = model.get_path(iter) self.tvNPModels.scroll_to_cell(path, None, True, 0.5, 0.5) self.tvNPModels.get_selection().select_iter(iter) selected = True if not selected: self.tvNPModels.get_selection().select_path(0) self.tvNPModels.scroll_to_cell(0, None, True, 0.0, 0.0) self.on_tvNPModels_cursor_changed(self.tvNPModels) def fillDriverList(self, printer): model = self.tvNPDrivers.get_model() model.clear() self.NPDrivers = printer.drivers.keys() self.NPDrivers.sort() found = False remote_driver="foomatic:%s-%s.ppd" % (printer.name, printer.driver) for driver in self.NPDrivers: if (driver==printer.driver or ((not found) and driver == remote_driver)): iter = model.append((driver + _(" (recommended)"),)) path = model.get_path(iter) self.tvNPDrivers.get_selection().select_path(path) self.tvNPDrivers.scroll_to_cell(path, None, True, 0.5, 0.5) found = True else: model.append((driver, ))
if not found: self.tvNPDrivers.get_selection().select_path(0) def on_tvNPModels_cursor_changed(self, widget): model, iter = widget.get_selection().get_selected() pmodel = model.get(iter, 0)[0] printer = self.foomatic.getMakeModel(self.NPMake, pmodel) self.NPModel = pmodel self.fillDriverList(printer)
if self.frmNPPDescription.flags() & gtk.VISIBLE: self.lblNPPDescription.set_markup(printer.getCommentPango( self.language, "en")) self.on_tvNPDrivers_cursor_changed(self.tvNPDrivers)
def on_tvNPDrivers_cursor_changed(self, widget): if ((self.frmNPDDescription.flags() & gtk.VISIBLE) or (self.frmNPPPDDescription.flags() & gtk.VISIBLE)): model, iter = widget.get_selection().get_selected() if iter is None: self.lblNPDDescription.set_markup('') self.lblNPPPDDescription.set_markup('') else: nr = model.get_path(iter)[0] drivername = self.NPDrivers[nr] if self.frmNPDDescription.flags() & gtk.VISIBLE: driver = self.foomatic.getDriver (drivername) self.lblNPDDescription.set_markup( driver.getCommentPango(self.language, "en")) if self.frmNPPPDDescription.flags() & gtk.VISIBLE: printer = self.foomatic.getMakeModel (self.NPMake, self.NPModel) ppd = printer.drivers[drivername] if (not ppd or ppd.startswith ("foomatic:")): markup = _("This PPD is generated by foomatic.") elif (ppd.startswith ("foomatic-db-ppds/") or ppd.startswith ("PPD/")): markup = _("This PPD is provided by the manufacturer " "and is included with the foomatic " "package.") else: try: fppd = self.foomatic.ppds[ppd] markup = fppd['ppd-make-and-model'] + '\n' except KeyError: markup += _("This PPD is provided by CUPS.")
self.lblNPPPDDescription.set_markup (markup) self.setNPButtons()
# toggle Comments
def on_tglNPShowPrinterDescription_toggled(self, widget): if widget.get_active(): self.frmNPPDescription.show() self.on_tvNPModels_cursor_changed(self.tvNPModels) else: self.frmNPPDescription.hide() def on_tglNPShowDriverDescription_toggled(self, widget): if widget.get_active(): self.frmNPDDescription.show() self.on_tvNPDrivers_cursor_changed(self.tvNPDrivers) else: self.frmNPDDescription.hide()
def on_tglNPShowPPDInfo_toggled(self, widget): if widget.get_active(): self.frmNPPPDDescription.show() self.on_tvNPDrivers_cursor_changed(self.tvNPDrivers) else: self.frmNPPPDDescription.hide()
def getNPPPD(self): if self.rbtnNPFoomatic.get_active(): model, iter = self.tvNPDrivers.get_selection().get_selected() nr = model.get_path(iter)[0] driver = self.NPDrivers[nr] printer = self.foomatic.getMakeModel(self.NPMake, self.NPModel) return printer.getPPD(driver) else: return cups.PPD(self.filechooserPPD.get_filename())
def fillNPApply(self): name = self.entNPName.get_text() if self.dialog_mode=="class": # XXX msg = _("Going to create a new class %s.") % name else: # XXX uri = self.getDeviceURI()
# Don't reveal SMB authentication details. if uri[:6] == "smb://": (group, host, share, u, p) = self.parse_SMBURI (uri[6:]) uri = "smb://" if len (u) or len (p): uri += ellipsis uri += self.construct_SMBURI (group, host, share)
msg = _( """Going to create a new printer %s at %s. """ ) % (name, uri) self.lblNPApply.set_markup(msg) # Create new Printer def on_btnNPApply_clicked(self, widget): if self.dialog_mode in ("class", "printer"): name = self.entNPName.get_text() location = self.entNPLocation.get_text() info = self.entNPDescription.get_text() else: name = self.printer.name
# Whether to check for missing drivers. check = False checkppd = None
DBErr_title = _('Database error') DBErr_text = _("The '%s' driver cannot be used with printer '%s %s'.")
def get_PPD_but_handle_errors (): try: ppd = self.getNPPPD() except RuntimeError, e: model, iter = self.tvNPDrivers.get_selection().get_selected() nr = model.get_path(iter)[0] driver = self.NPDrivers[nr] if driver.startswith ("gutenprint"): # This printer references some XML that is not installed # by default. Point the user at the package they need # to install. DBErr = _("You will need to install the '%s' package " "in order to use this driver.") % \ "gutenprint-foomatic" else: DBErr = DBErr_text % (driver, self.NPMake, self.NPModel)
error_text = ('<span weight="bold" size="larger">' + DBErr_title + '</span>\n\n' + DBErr) self.lblError.set_markup(error_text) self.ErrorDialog.set_transient_for(self.NewPrinterWindow) self.ErrorDialog.run() self.ErrorDialog.hide() return None return ppd
if self.dialog_mode=="class": members = self.getCurrentClassMembers(self.tvNCMembers) try: for member in members: self.passwd_retry = False # use cached Passwd self.cups.addPrinterToClass(member, name) except cups.IPPError, (e, msg): self.show_IPP_Error(e, msg) return elif self.dialog_mode=="printer": uri = self.getDeviceURI() ppd = get_PPD_but_handle_errors () if not ppd: # Go back to previous page to re-select driver. self.nextNPTab(-1) return try: self.passwd_retry = False # use cached Passwd if isinstance(ppd, str) or isinstance(ppd, unicode): self.cups.addPrinter(name, ppdname=ppd, device=uri, info=info, location=location) check = True elif ppd is None: # raw queue self.cups.addPrinter(name, device=uri, info=info, location=location) else: cupshelpers.setPPDPageSize(ppd, self.language[0]) self.cups.addPrinter(name, ppd=ppd, device=uri, info=info, location=location) check = True checkppd = ppd
self.cups.enablePrinter (name) self.cups.acceptJobs (name) except cups.IPPError, (e, msg): self.show_IPP_Error(e, msg) return if self.dialog_mode in ("class", "printer"): try: self.passwd_retry = False # use cached Passwd self.cups.setPrinterLocation(name, location) self.passwd_retry = False # use cached Passwd self.cups.setPrinterInfo(name, info) except cups.IPPError, (e, msg): self.show_IPP_Error(e, msg) return elif self.dialog_mode == "device": try: uri = self.getDeviceURI() self.passwd_retry = False # use cached Passwd self.cups.addPrinter(name, device=uri) except cups.IPPError, (e, msg): self.show_IPP_Error(e, msg) return elif self.dialog_mode == "ppd": ppd = get_PPD_but_handle_errors () if not ppd: # Go back to previous page to re-select driver. self.nextNPTab(-1) return
# set ppd on server and retrieve it # cups doesn't offer a way to just download a ppd ;(= raw = False if isinstance(ppd, str) or isinstance(ppd, unicode): if self.rbtnChangePPDasIs.get_active(): # To use the PPD as-is we need to prevent CUPS copying # the old options over. Do this by setting it to a # raw queue (no PPD) first. try: self.passwd_retry = False # use cached Passwd self.cups.addPrinter(name, ppdname='raw') except cups.IPPError, (e, msg): self.show_IPP_Error(e, msg) try: self.passwd_retry = False # use cached Passwd self.cups.addPrinter(name, ppdname=ppd) except cups.IPPError, (e, msg): self.show_IPP_Error(e, msg) return
try: self.passwd_retry = False # use cached Passwd filename = self.cups.getPPD(name) ppd = cups.PPD(filename) os.unlink(filename) except cups.IPPError, (e, msg): if e == cups.IPP_NOT_FOUND: raw = True else: self.show_IPP_Error(e, msg) return else: # We have an actual PPD to upload, not just a name. if not self.rbtnChangePPDasIs.get_active(): cupshelpers.copyPPDOptions(self.ppd, ppd) else: cupshelpers.setPPDPageSize(ppd, self.language[0])
try: self.passwd_retry = False # use cached Passwd self.cups.addPrinter(name, ppd=ppd) except cups.IPPError, (e, msg): self.show_IPP_Error(e, msg)
if not raw: check = True checkppd = ppd
self.NewPrinterWindow.hide() self.populateList() if check: self.checkDriverExists (name, ppd=checkppd)
def checkDriverExists(self, name, ppd=None): """Check that the driver for an existing queue actually exists, and prompt to install the appropriate package if not.
ppd: cups.PPD object, if already created"""
# Is this queue on the local machine? If not, we can't check # anything at all. server = cups.getServer () if not (server == 'localhost' or server == '127.0.0.1' or server == '::1' or server[0] == '/'): return
# Fetch the PPD if we haven't already. if not ppd: try: filename = self.cups.getPPD(name) except cups.IPPError, (e, msg): if e == cups.IPP_NOT_FOUND: # This is a raw queue. Nothing to check. return else: self.show_IPP_Error(e, msg) return
ppd = cups.PPD(filename) os.unlink(filename)
# How to check that something exists in a path: def pathcheck (name, path="/usr/bin:/bin"): # Strip out foomatic '%'-style place-holders. p = name.find ('%') if p != -1: name = name[:p] if len (name) == 0: return "true" if name[0] == '/': if os.access (name, os.X_OK): print "%s: found" % name return name else: print "%s: NOT found" % name return None if name.find ("=") != -1: return "builtin" if name in [ ":", ".", "[", "alias", "bind", "break", "cd", "continue", "declare", "echo", "else", "eval", "exec", "exit", "export", "fi", "if", "kill", "let", "local", "popd", "printf", "pushd", "pwd", "read", "readonly", "set", "shift", "shopt", "source", "test", "then", "trap", "type", "ulimit", "umask", "unalias", "unset", "wait" ]: return "builtin" for component in path.split (':'): file = component.rstrip (os.path.sep) + os.path.sep + name if os.access (file, os.X_OK): print "%s: found" % file return file print "%s: NOT found in %s" % (name,path) return None
# Find a 'FoomaticRIPCommandLine' attribute. exepath = None attr = ppd.findAttr ('FoomaticRIPCommandLine') if attr: # Foomatic RIP command line to check. cmdline = attr.value.replace ('&&\n', '') cmdline = cmdline.replace ('"', '"') cmdline = cmdline.replace ('<', '<') cmdline = cmdline.replace ('>', '>') if (cmdline.find ("(") != -1 or cmdline.find ("&") != -1): # Don't try to handle sub-shells or unreplaced HTML entities. cmdline = ""
# Strip out foomatic '%'-style place-holders pipes = cmdline.split (';') for pipe in pipes: cmds = pipe.strip ().split ('|') for cmd in cmds: args = cmd.strip ().split (' ') exe = args[0] exepath = pathcheck (exe) if not exepath: break
# Main executable found. But if it's 'gs', # perhaps there is an IJS server we also need # to check. if os.path.basename (exepath) == 'gs': argn = len (args) argi = 1 search = "-sIjsServer=" while argi < argn: arg = args[argi] if arg.startswith (search): exe = arg[len (search):] exepath = pathcheck (exe) break
argi += 1
if not exepath: # Next pipe. break
if exepath or not attr: # Look for '*cupsFilter' lines in the PPD and check that # the filters are installed. (tmpfd, tmpfname) = tempfile.mkstemp () ppd.writeFd (tmpfd) search = "*cupsFilter:" for line in file (tmpfname).readlines (): if line.startswith (search): line = line[len (search):].strip ().strip ('"') try: (mimetype, cost, exe) = line.split (' ') except: continue
exepath = pathcheck (exe, "/usr/lib/cups/filter:" "/usr/lib64/cups/filter")
if exe and not exepath: # We didn't find a necessary executable. Complain. pkgs = { # Foomatic command line executables 'gs': 'ghostscript', 'perl': 'perl', 'foo2oak-wrapper': None, 'pnm2ppa': 'pnm2ppa', # IJS servers (used by foomatic) 'hpijs': 'hpijs', 'ijsgutenprint.5.0': 'gutenprint', # CUPS filters 'rastertogutenprint.5.0': 'gutenprint', 'commandtoepson': 'gimp-print-cups', 'commandtocanon': 'gimp-print-cups', 'rastertoprinter': 'gimp-print-cups', } try: pkg = pkgs[exe] except: pkg = None
if pkg: print "%s included in package %s" % (exe, pkg) error_text = ('<span weight="bold" size="larger">' + _('Missing driver') + '</span>\n\n' + _("Printer '%s' requires the %s package but " "it is not currently installed. Please " "install it before using this printer.") % (name, pkg)) else: error_text = ('<span weight="bold" size="larger">' + _('Missing driver') + '</span>\n\n' + _("Printer '%s' requires the '%s' program but " "it is not currently installed. Please " "install it before using this printer.") % (name, exe)) self.lblError.set_markup(error_text) self.ErrorDialog.set_transient_for (self.MainWindow) self.ErrorDialog.run() self.ErrorDialog.hide()
########################################################################## ### Server settings ##########################################################################
def fillServerTab(self): self.changed = set() try: self.server_settings = self.cups.adminGetServerSettings() except cups.IPPError, (e, m): self.show_IPP_Error(e, m) self.tvMainList.get_selection().unselect_all() self.on_tvMainList_cursor_changed(self.tvMainList) return
for widget, setting in [ (self.chkServerBrowse, cups.CUPS_SERVER_REMOTE_PRINTERS), (self.chkServerShare, cups.CUPS_SERVER_SHARE_PRINTERS), (self.chkServerRemoteAdmin, cups.CUPS_SERVER_REMOTE_ADMIN), (self.chkServerAllowCancelAll, cups.CUPS_SERVER_USER_CANCEL_ANY), (self.chkServerLogDebug, cups.CUPS_SERVER_DEBUG_LOGGING),]: widget.set_data("setting", setting) if self.server_settings.has_key(setting): widget.set_active(int(self.server_settings[setting])) widget.show() else: widget.hide() self.setDataButtonState() def on_server_changed(self, widget): if (str(int(widget.get_active())) == self.server_settings[widget.get_data("setting")]): self.changed.discard(widget) else: self.changed.add(widget) self.setDataButtonState()
def save_serversettings(self): setting_dict = self.server_settings.copy() for widget, setting in [ (self.chkServerBrowse, cups.CUPS_SERVER_REMOTE_PRINTERS), (self.chkServerShare, cups.CUPS_SERVER_SHARE_PRINTERS), (self.chkServerRemoteAdmin, cups.CUPS_SERVER_REMOTE_ADMIN), (self.chkServerAllowCancelAll, cups.CUPS_SERVER_USER_CANCEL_ANY), (self.chkServerLogDebug, cups.CUPS_SERVER_DEBUG_LOGGING),]: if not self.server_settings.has_key(setting): continue setting_dict[setting] = str(int(widget.get_active())) try: self.cups.adminSetServerSettings(setting_dict) except cups.IPPError, (e, m): self.show_IPP_Error(e, m) return True self.changed = set() self.setDataButtonState() time.sleep(1) # give the server a chance to process our request
# Now reconnect, in case the server needed to reload. self.reconnect ()
def main(): # The default configuration requires root for administration. cups.setUser ("root") gtk.gdk.threads_init() gtk.gdk.threads_enter()
mainwindow = GUI() if gtk.__dict__.has_key("main"): gtk.main() else: gtk.mainloop()
gtk.gdk.threads_leave()
if __name__ == "__main__": main()
|