home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/env python
-
- #############################################################################
- ##
- ## Copyright (C) 2007 Canonical Ltd
- ## Author: Jonathan Riddell <jriddell@ubuntu.com>
- ##
- ## Includes code from System Config Printer
- ## Copyright (C) 2007 Tim Waugh <twaugh@redhat.com>
- ## Copyright (C) 2007 Red Hat, Inc.
- ##
- ## 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, see <http://www.gnu.org/licenses/>.
- ##
- #############################################################################
-
- MIN_REFRESH_INTERVAL = 1 # seconds
- domain="system-config-printer"
- import locale
-
- pkgdata = '/usr/share/' + domain
-
- import sys, os, time, traceback, re, tempfile, httplib
- #tempfile
- import thread
-
- if os.path.exists("system-config-printer.ui"):
- APPDIR="."
- else:
- APPDIR="/usr/share/system-config-printer"
-
- #load modules from system-config-printer-common (debug, smburi), change path here if you have it installed elsewhere
- SYSTEM_CONFIG_PRINTER_DIR = "/usr/share/system-config-printer"
- if os.path.exists(SYSTEM_CONFIG_PRINTER_DIR + "/debug.py"):
- sys.path.append(SYSTEM_CONFIG_PRINTER_DIR)
-
- from PyQt4.QtCore import *
- from PyQt4.QtGui import *
- from PyQt4 import uic
-
- import gettext
- gettext.textdomain(domain)
- def _(string):
- return unicode(gettext.gettext(string), "utf-8")
-
- def translate(self, prop):
- """reimplement method from uic to change it to use gettext"""
- if prop.get("notr", None) == "true":
- return self._cstring(prop)
- else:
- if prop.text is None:
- return ""
- text = prop.text.encode("UTF-8")
- return _(text)
-
- uic.properties.Properties._string = translate
-
- import cups
- cups.require ("1.9.27")
-
- # These come from system-config-printer
- import config
- import cupshelpers #, options
- from smburi import SMBURI
- from debug import *
-
- import dbus
- import dbus.mainloop.qt
- import dbus.service
-
- ellipsis = unichr(0x2026)
-
- try:
- try_CUPS_SERVER_REMOTE_ANY = cups.CUPS_SERVER_REMOTE_ANY
- except AttributeError:
- # cups module was compiled with CUPS < 1.3
- try_CUPS_SERVER_REMOTE_ANY = "_remote_any"
-
- def validDeviceURI (uri):
- """Returns True is the provided URI is valid."""
- if uri.find (":/") > 0:
- return True
- return False
-
- class GUI(QWidget):
- """our main class is the main window"""
-
- printer_states = { cups.IPP_PRINTER_IDLE: _("Idle"),
- cups.IPP_PRINTER_PROCESSING: _("Processing"),
- cups.IPP_PRINTER_BUSY: _("Busy"),
- cups.IPP_PRINTER_STOPPED: _("Stopped") }
-
- def __init__(self, start_printer = None, change_ppd = False):
- QWidget.__init__(self)
-
- try:
- self.language = locale.getlocale(locale.LC_MESSAGES)
- self.encoding = locale.getlocale(locale.LC_CTYPE)
- except:
- nonfatalException()
- os.environ['LC_ALL'] = 'C'
- locale.setlocale (locale.LC_ALL, "")
- self.language = locale.getlocale(locale.LC_MESSAGES)
- self.encoding = locale.getlocale(locale.LC_CTYPE)
-
- self.printer = None
- self.conflicts = set() # of options
- self.connect_server = (self.printer and self.printer.getServer()) \
- or cups.getServer()
- self.connect_user = cups.getUser()
- self.password = '' #FIXME not in Gnome version
- self.passwd_retry = False #FIXME not in Gnome version
- self.widget_data_setting = {} #FIXME not in Gnome version
- #FIXMEcups.setPasswordCB(self.cupsPasswdCallback)
- ##self.server_is_publishing = False #FIXME new in Gnome version
-
- self.changed = set() # of options
-
- self.servers = set((self.connect_server,))
-
- try:
- self.cups = cups.Connection()
- except RuntimeError:
- self.cups = None
-
- """
- self.mainWindow = QWidget()
- uic.loadUi(APPDIR + "/" + "system-config-printer.ui", self.mainWindow)
- self.mainWindow.show()
- """
- #self.mainWindow = QWidget()
- uic.loadUi(APPDIR + "/" + "system-config-printer.ui", self)
- self.show()
-
- # New Printer Dialog
- self.newPrinterGUI = np = NewPrinterGUI(self)
- #np.NewPrinterWindow.set_transient_for(self.MainWindow)
-
- self.setConnected()
-
- self.connect(self.mainlist, SIGNAL("itemSelectionChanged()"), self.on_tvMainList_cursor_changed)
- self.connect(self.mainlist, SIGNAL("currentItemChanged (QTreeWidgetItem*, QTreeWidgetItem*)"), self.on_tvMainList_changed)
- self.connect(self.chkServerBrowse, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
- self.connect(self.chkServerShare, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
- self.connect(self.chkServerShareAny, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
- self.connect(self.chkServerRemoteAdmin, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
- self.connect(self.chkServerAllowCancelAll, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
- self.connect(self.chkServerLogDebug, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
-
- self.connect(self.btnNewClass, SIGNAL("clicked()"), self.on_new_class_activate)
- self.connect(self.btnNewPrinter, SIGNAL("clicked()"), self.on_new_printer_activate)
-
- self.connect(self.entPDescription, SIGNAL("textEdited(const QString&)"), self.on_printer_changed)
- self.connect(self.entPLocation, SIGNAL("textEdited(const QString&)"), self.on_printer_changed)
- self.connect(self.entPDevice, SIGNAL("textEdited(const QString&)"), self.on_printer_changed)
- self.connect(self.chkPEnabled, SIGNAL("stateChanged(int)"), self.on_printer_changed)
- self.connect(self.chkPAccepting, SIGNAL("stateChanged(int)"), self.on_printer_changed)
- self.connect(self.chkPShared, SIGNAL("stateChanged(int)"), self.on_printer_changed)
- self.connect(self.cmbPErrorPolicy, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed)
- self.connect(self.cmbPOperationPolicy, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed)
- self.connect(self.cmbPStartBanner, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed)
- self.connect(self.cmbPEndBanner, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed)
- #self.connect(self.rbtnPAllow, SIGNAL("toggled(bool)"), self.on_printer_changed)
-
- try:
- self.populateList(start_printer, change_ppd)
- except cups.HTTPError, (s,):
- self.cups = None
- self.setConnected()
- self.populateList()
- self.show_HTTP_Error(s)
-
- self.mainlist.header().hide()
-
- #hide some bits until implemented
- self.btnNewPrinterNetwork.hide()
- self.newPrinterNetworkLabel.hide()
- self.btnNewPrinterSpecial.hide()
- self.newPrinterSpecialLabel.hide()
- self.btnNewPrinter.setText(_("New Printer"))
- self.btnPrinterPropertiesApply.setIcon(QIcon(APPDIR + "/dialog-ok-apply.png"))
- self.btnRevert.setIcon(QIcon(APPDIR + "/document-revert.png"))
- self.newPrinterLabel.hide()
- #(obsolete) only show settings until ready for the rest
- #self.mainlist.hide()
- self.mainlist.setCurrentItem(self.settingsItem)
- #FIXME hide labels until implemented
- self.lblPOptions.hide()
- self.lblPInstallOptions.hide()
-
- self.setWindowIcon(QIcon(APPDIR + "/printer-128.png"))
-
- # now called dests_iconview_item_activated() in the Gnome version
- def on_tvMainList_cursor_changed(self):
- if self.changed:
- # The unapplied changes for this item have not been saved,
- # and the user just pressed "Cancel".
- #FIXME, should offer dialog prompting to save or cancel here
- return
- items = self.mainlist.selectedItems()
- if len(items) < 1:
- return
- item = items[0]
- #FIXME only show settings until ready for the rest
- #item = self.settingsItem
- type = str(item.text(1))
- name = str(item.text(0))
- #name, type = self.getSelectedItem()
- #model, self.mainListSelected = self.tvMainList.get_selection().get_selected()
- #Save the values incase it gets deselected
- self.mainListSelectedType = type
- self.mainListSelectedName = name
- item_selected = True
- if type == "New":
- #self.ntbkMain.set_current_page(0)
- self.ntbkMain.setCurrentIndex(0)
- elif type == "Settings":
- #self.ntbkMain.set_current_page(0)
- self.ntbkMain.setCurrentIndex(1)
- if self.cups:
- self.fillServerTab()
- else:
- # No connection to CUPS. Make sure the Apply/Revert buttons
- # are not sensitive.
- self.setDataButtonState()
- item_selected = False
- elif type in ['Printer', 'Class']:
- try:
- self.fillPrinterTab(name)
- self.fillPrinterOptions()
- self.setDataButtonState()
- except RuntimeError:
- # Perhaps cupsGetPPD2 failed for a browsed printer.
- self.ntbkMain.setCurrentIndex(3)
- #self.ntbkMain.set_current_page(2)
- return
-
- #self.ntbkMain.set_current_page(1)
- self.ntbkMain.setCurrentIndex(2)
- elif type == "None":
- #self.ntbkMain.set_current_page(2)
- self.ntbkMain.setCurrentIndex(3)
- self.setDataButtonState()
- item_selected = False
-
- """FIXME, copy button
- is_local = item_selected and not self.printers[name].discovered
- for widget in [self.copy, self.btnCopy]:
- widget.set_sensitive(item_selected)
- for widget in [self.delete, self.btnDelete]:
- widget.set_sensitive(is_local)
- """
-
- def printer_properties_response(self):
- name, type = self.getSelectedItem()
- if type in ("Printer", "Class"):
- return self.save_printer(self.printer)
- elif type == "Settings":
- return self.save_serversettings()
-
- def on_tvMainList_changed(self, new, old):
- """about to change, offer to save"""
- if self.changed:
- answer = QMessageBox.question(self, "Save Changes", "Do you want to save changes?", QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, QMessageBox.Save)
- if answer == QMessageBox.Save:
- self.printer_properties_response()
- elif answer == QMessageBox.Discard:
- self.changed = set() # avoid asking the user
-
- def busy (self, win = None):
- try:
- if not win:
- win = self
- win.setCursor(Qt.WaitCursor)
- QApplication.processEvents()
- except:
- nonfatalException ()
-
- def ready (self, win = None):
- try:
- if not win:
- win = self
- win.setCursor(Qt.ArrowCursor)
- QApplication.processEvents()
- except:
- nonfatalException ()
-
- def setConnected(self):
- connected = bool(self.cups)
-
- host = cups.getServer()
-
- if host[0] == '/':
- host = 'localhost'
- self.setWindowTitle(_("Printer configuration - %s") % host)
-
- if connected:
- status_msg = _("Connected to %s") % host
- else:
- status_msg = _("Not connected")
- #FIXME do we want a statusbar?
- #self.statusbarMain.push(self.status_context_id, status_msg)
-
- for widget in (#FIXMEself.btnNewPrinter, self.btnNewClass,
- #self.new_printer, self.new_class,
- self.chkServerBrowse, self.chkServerShare,
- self.chkServerRemoteAdmin,
- self.chkServerAllowCancelAll,
- self.chkServerLogDebug):
- widget.setEnabled(connected)
-
- sharing = self.chkServerShare.isChecked ()
- self.chkServerShareAny.setEnabled (sharing)
-
- try:
- del self.server_settings
- except:
- pass
-
- def populateList(self, start_printer = None, change_ppd = False):
- #FIXMEold_name, old_type = self.getSelectedItem()
- old_name = ""
- old_type = ""
-
- select_path = None
-
- if self.cups:
- try:
- # get Printers
- self.printers = cupshelpers.getPrinters(self.cups)
-
- # Get default printer.
- try:
- self.default_printer = self.cups.getDefault ()
- except AttributeError: # getDefault appeared in pycups-1.9.31
- # This fetches the list of printers and classes *again*,
- # just to find out the default printer.
- dests = self.cups.getDests ()
- if dests.has_key ((None,None)):
- self.default_printer = dests[(None,None)].name
- else:
- self.default_printer = None
- except cups.IPPError, (e, m):
- self.show_IPP_Error(e, m)
- self.printers = {}
- self.default_printer = None
- else:
- self.printers = {}
- self.default_printer = None
-
- 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()
-
- if (old_name != "" and
- (not old_name in local_printers) and
- (not old_name in local_classes) and
- (not old_name in remote_printers) and
- (not old_name in remote_classes)):
- # The previously selected printer no longer exists.
- old_name = ""
-
- if (self.default_printer != None and
- start_printer == None and
- old_name == ""):
- start_printer = self.default_printer
-
- if not start_printer:
- start_printer = old_name
-
- 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
- """
- self.mainlist.clear()
- QTreeWidgetItem(self.mainlist, ["New Printer", 'New'])
- self.settingsItem = QTreeWidgetItem(self.mainlist, ["Server Settings", 'Settings'])
-
- # 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
-
- #self.mainlist.addTopLevelItem(QTreeWidgetItem(self.mainlist, text))
- rootTreeItem = QTreeWidgetItem(self.mainlist, [text, name])
- #iter = self.mainlist.append(None, (text, name))
- #path = self.mainlist.get_path(iter)
-
- for printer_name in printers:
- if start_printer == None:
- start_printer = printer_name
- treeItem = QTreeWidgetItem(rootTreeItem, [printer_name, "Printer"])
- #p_iter = self.mainlist.append(iter, (printer_name, "Printer"))
- if printer_name==start_printer:
- treeItem.setSelected(True)
- expanded[name] = True
- if expanded[name]:
- rootTreeItem.setExpanded(True)
- #self.tvMainList.expand_row(path, False)
- self.on_tvMainList_cursor_changed()
- self.setDataButtonState()
-
- """FIXME
- if change_ppd:
- self.on_btnChangePPD_clicked (self.btnChangePPD)
- """
-
- #TODO
- # Connect to Server
-
- def on_printer_changed(self, text):
- widget = self.sender()
- if not widget: #method called as a method not a slot
- return
- if isinstance(widget, QCheckBox):
- value = widget.isChecked()
- elif isinstance(widget, QLineEdit):
- value = unicode(widget.text())
- elif isinstance(widget, QRadioButton):
- value = widget.isChecked()
- elif isinstance(widget, QComboBox):
- value = unicode(widget.currentText())
- 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, #FIXME access control tab
- }
-
- old_value = old_values[widget]
-
- if old_value == value:
- self.changed.discard(widget)
- else:
- self.changed.add(widget)
- self.setDataButtonState()
-
- #TODO
- # Access control
-
- #TODO
- # Server side options
-
- # set buttons sensitivity
- def setDataButtonState(self):
- try: # Might not be a printer selected
- possible = (self.ppd and
- not bool (self.changed) and
- self.printer.enabled and
- not self.printer.rejecting)
-
- self.btnPrintTestPage.setEnabled(possible)
-
- commands = (self.printer.type & cups.CUPS_PRINTER_COMMANDS) != 0
- self.btnSelfTest.setEnabled(commands and possible)
- self.btnCleanHeads.setEnabled(commands and possible)
- except:
- debugprint ("exception in setDataButtonState")
- pass
-
- installablebold = False
- optionsbold = False
- if self.conflicts:
- debugprint ("Conflicts detected")
- self.btnConflict.show()
- for option in self.conflicts:
- if option.tab_label == self.lblPInstallOptions:
- installablebold = True
- else:
- optionsbold = True
- else:
- self.btnConflict.hide()
- installabletext = _("Installable Options")
- optionstext = _("Printer Options")
- if installablebold:
- installabletext = "<b>%s</b>" % installabletext
- if optionsbold:
- optionstext = "<b>%s</b>" % optionstext
- self.lblPInstallOptions.setText(installabletext)
- self.lblPOptions.setText(optionstext)
-
- """ FIXME
- store = self.tvPrinterProperties.get_model ()
- if store:
- for n in range (self.ntbkPrinter.get_n_pages ()):
- page = self.ntbkPrinter.get_nth_page (n)
- label = self.ntbkPrinter.get_tab_label (page)
- if label == self.lblPInstallOptions:
- iter = store.get_iter ((n,))
- store.set_value (iter, 0, installabletext)
- elif label == self.lblPOptions:
- iter = store.get_iter ((n,))
- store.set_value (iter, 0, optionstext)
- """
-
- self.btnPrinterPropertiesApply.setEnabled(len (self.changed) > 0)
- self.btnRevert.setEnabled(len (self.changed) > 0)
-
- def save_printer(self, printer, saveall=False):
- class_deleted = 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)
-
- #FIXME classes
- if printer.is_class:
- pass
- """
- # 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
- class_deleted = 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 = unicode(self.entPLocation.text())
- info = unicode(self.entPDescription.text())
- device_uri = unicode(self.entPDevice.text())
- if device_uri.find (ellipsis) != -1:
- # The URI is sanitized and not editable.
- device_uri = printer.device_uri
-
- enabled = self.chkPEnabled.isChecked()
- accepting = self.chkPAccepting.isChecked()
- shared = self.chkPShared.isChecked()
-
- 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 = unicode(self.cmbPStartBanner.currentText())
- job_sheet_end = unicode(self.cmbPEndBanner.currentText())
- error_policy = unicode(self.cmbPErrorPolicy.currentText())
- op_policy = unicode(self.cmbPOperationPolicy.currentText())
-
- 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)
-
- """FIXME TODO access
- 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
- if not self.__dict__.has_key ("server_settings"):
- # We can authenticate with the server correctly at this point,
- # but we have never fetched the server settings to see whether
- # the server is publishing shared printers. Fetch the settings
- # now so that we can update the "not published" label if necessary.
- try:
- self.server_settings = self.cups.adminGetServerSettings()
- except:
- nonfatalException()
-
- if class_deleted:
- self.populateList ()
- else:
- # 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()
-
- @pyqtSignature("")
- def on_btnPrintTestPage_clicked(self):
- if self.test_button_cancels:
- jobs = self.printer.testsQueued ()
- for job in jobs:
- debugprint ("Canceling 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:
- # if we have a page size specific custom test page, use it;
- # otherwise use cups' default one
- custom_testpage = None
- opt = self.ppd.findOption ("PageSize")
- if opt:
- custom_testpage = os.path.join(pkgdata, 'testpage-%s.ps' % opt.defchoice.lower())
-
- if custom_testpage and os.path.exists(custom_testpage):
- debugprint ('Printing custom test page ' + custom_testpage)
- job_id = self.cups.printTestPage(self.printer.name,
- file=custom_testpage)
- else:
- debugprint ('Printing default test page')
- job_id = self.cups.printTestPage(self.printer.name)
-
- self.setTestButton (self.printer)
- QMessageBox.information(self, _("Submitted"), _("Test page submitted as "
- "job %d") % job_id)
- except cups.IPPError, (e, msg):
- if (e == cups.IPP_NOT_AUTHORIZED and
- self.connect_server != 'localhost' and
- self.connect_server[0] != '/'):
- 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)
-
- def maintenance_command (self, command):
- (tmpfd, tmpfname) = tempfile.mkstemp ()
- os.write (tmpfd, "#CUPS-COMMAND\n%s\n" % command)
- os.close (tmpfd)
- try:
- format = "application/vnd.cups-command"
- job_id = self.cups.printTestPage (self.printer.name,
- format=format,
- file=tmpfname,
- user=self.connect_user)
- self.lblInfo.set_markup ('<span weight="bold" size="larger">' +
- _("Submitted") + '</span>\n\n' +
- _("Maintenance command submitted as "
- "job %d") % job_id)
- self.InfoDialog.set_transient_for (self.MainWindow)
- 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)
-
- @pyqtSignature("")
- def on_btnSelfTest_clicked(self):
- self.maintenance_command ("PrintSelfTestPage")
-
- @pyqtSignature("")
- def on_btnCleanHeads_clicked(self):
- self.maintenance_command ("Clean all")
-
- def fillComboBox(self, combobox, values, value):
- combobox.clear()
- for nr, val in enumerate(values):
- combobox.addItem(val)
- if val == value:
- combobox.setCurrentIndex(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
- printer.getAttributes ()
-
- editable = not self.printer.discovered
- editablePPD = not self.printer.remote
-
- try:
- self.ppd = printer.getPPD()
- except cups.IPPError, (e, m):
- # Some IPP error other than IPP_NOT_FOUND.
- self.show_IPP_Error(e, m)
- # Treat it as a raw queue.
- self.ppd = False
- except RuntimeError:
- # The underlying cupsGetPPD2() function returned NULL without
- # setting an IPP error, so it'll be something like a failed
- # connection.
- #FIXME show a dialogue
- debugprint("Error!")
- """
- self.lblError.set_markup('<span weight="bold" size="larger">' +
- _("Error") + '</span>\n\n' +
- _("There was a problem connecting to "
- "the CUPS server."))
- self.ErrorDialog.set_transient_for(self.MainWindow)
- self.ErrorDialog.run()
- self.ErrorDialog.hide()
- """
- raise
-
- for widget in (self.entPDescription, self.entPLocation,
- self.entPDevice):
- widget.setReadOnly(not editable)
-
- for widget in (self.btnSelectDevice, self.btnChangePPD):
- """,FIXME
- 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):
- """
- widget.setEnabled(editable)
-
- # Description page
- self.entPDescription.setText(printer.info)
- self.entPLocation.setText(printer.location)
- #obsolete self.lblPMakeModel.setText(printer.make_and_model)
- #obsolete self.lblPState.setText(printer.state_description)
-
- uri = printer.device_uri
- if uri.startswith("smb://"):
- (group, host, share,
- user, password) = SMBURI (uri=uri[6:]).separate ()
- if password:
- uri = "smb://"
- if len (user) or len (password):
- uri += ellipsis
- uri += SMBURI (group=group, host=host, share=share).get_uri ()
- self.entPDevice.setEnabled(False)
- else:
- self.entPDevice.setEnabled(True)
- self.entPDevice.setText(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()
-
-
- # default printer
- self.btnPMakeDefault.setEnabled(not printer.default)
- if printer.default:
- self.lblPDefault.setText(_("This is the default printer"))
- elif self.default_printer:
- self.lblPDefault.setText(self.default_printer)
- else:
- self.lblPDefault.setText(_("No default printer set."))
-
- self.setTestButton (printer)
-
- # Policy tab
- # ----------
-
- # State
- self.chkPEnabled.setChecked(printer.enabled)
- self.chkPAccepting.setChecked(not printer.rejecting)
- self.chkPShared.setChecked(printer.is_shared)
- try:
- if printer.is_shared:
- flag = cups.CUPS_SERVER_SHARE_PRINTERS
- publishing = int (self.server_settings[flag])
- if publishing:
- self.lblNotPublished.hide()
- else:
- self.lblNotPublished.show()
- else:
- self.lblNotPublished.hide()
- except:
- self.lblNotPublished.hide()
-
- # Job sheets
- self.cmbPStartBanner.setEnabled(editable)
- self.cmbPEndBanner.setEnabled(editable)
-
- # Policies
- self.cmbPErrorPolicy.setEnabled(editable)
- self.cmbPOperationPolicy.setEnabled(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 (Job options)
- self.server_side_options = {}
- for option in self.job_options_widgets.values ():
- if option.name == "media" and self.ppd:
- # Slightly special case because the 'system default'
- # (i.e. what you get when you press Reset) depends
- # on the printer's PageSize.
- opt = self.ppd.findOption ("PageSize")
- if opt:
- option.set_default (opt.defchoice)
-
- option_editable = editable
- try:
- value = self.printer.attributes[option.name]
- except KeyError:
- option.reinit (None)
- else:
- try:
- if self.printer.possible_attributes.has_key (option.name):
- supported = self.printer.\
- possible_attributes[option.name][1]
- # Set the option widget.
- # In CUPS 1.3.x the orientation-requested-default
- # attribute may have the value None; this means there
- # is no value set. This suits our needs here, as None
- # resets the option to the system default and makes the
- # Reset button insensitive.
- option.reinit (value, supported=supported)
- else:
- option.reinit (value)
-
- self.server_side_options[option.name] = option
- except:
- option_editable = False
- self.lblError.set_markup ('<span weight="bold" ' +
- 'size="larger">' +
- _("Error") + '</span>\n\n' +
- _("Option '%s' has value '%s' "
- "and cannot be edited.") %
- (option.name, value))
- self.ErrorDialog.set_transient_for (self.MainWindow)
- self.ErrorDialog.run()
- self.ErrorDialog.hide()
- option.widget.set_sensitive (option_editable)
- if not editable:
- option.button.set_sensitive (False)
- self.other_job_options = []
- self.draw_other_job_options (editable=editable)
- for option in self.printer.attributes.keys ():
- if self.server_side_options.has_key (option):
- continue
- supported = ""
- if self.printer.possible_attributes.has_key (option):
- supported = self.printer.possible_attributes[option][1]
- self.add_job_option (option, value=self.printer.attributes[option],
- supported=supported, is_new=False,
- editable=editable)
- self.entNewJobOption.set_text ('')
- self.entNewJobOption.set_sensitive (editable)
- self.btnNewJobOption.set_sensitive (False)
-
- 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, editablePPD)
-
- """
- self.changed = set() # of options
- self.updatePrinterProperties ()
- self.setDataButtonState()
-
- def fillPrinterOptions(self):
- return #FIXME TODO options tabs
-
- #In Gnome is now on_delete_activate(self, UNUSED):
- @pyqtSignature("")
- def on_btnDelete_clicked(self):
- name, type = self.getSelectedItem()
- print name
-
- # Confirm
- if type == "Printer":
- message_format = _("Really delete printer %s?")
- else:
- message_format = _("Really delete class %s?")
-
- cancel = QMessageBox.question(self,"",
- message_format % name,
- _("&Yes"), _("&No"),
- QString(), 0, 1)
-
- if cancel:
- return
- try:
- self.cups.deletePrinter(name)
- except cups.IPPError, (e, msg):
- self.show_IPP_Error(e, msg)
-
- self.changed = set()
- self.populateList()
- self.mainlist.setCurrentItem(self.mainlist.itemAt(0,0))
-
- #in Gnome side is now set_default_printer (self, name):
- @pyqtSignature("")
- def on_btnPMakeDefault_clicked(self):
- try:
- self.cups.setDefault(self.printer.name)
- except cups.IPPError, (e, msg):
- self.show_IPP_Error(e, msg)
- return
-
- # Also need to check system-wide lpoptions because that's how
- # previous Fedora versions set the default (bug #217395).
- (tmpfd, tmpfname) = tempfile.mkstemp ()
- success = False
- try:
- resource = "/admin/conf/lpoptions"
- self.cups.getFile(resource, tmpfname)
- #success = True
- except cups.HTTPError, (s,):
- try:
- os.remove (tmpfname)
- except OSError:
- pass
-
- if s != cups.HTTP_NOT_FOUND:
- self.show_HTTP_Error(s)
- return
-
- if success:
- lines = file (tmpfname).readlines ()
- changed = False
- i = 0
- for line in lines:
- if line.startswith ("Default "):
- # This is the system-wide default.
- name = line.split (' ')[1]
- if name != self.printer.name:
- # Stop it from over-riding the server default.
- lines[i] = "Dest " + line[8:]
- changed = True
- i += 1
-
- if changed:
- file (tmpfname, 'w').writelines (lines)
- try:
- self.cups.putFile (resource, tmpfname)
- except cups.HTTPError, (s,):
- os.remove (tmpfname)
- print s
- self.show_HTTP_Error(s)
- return
-
- # Now reconnect because the server needs to reload.
- self.reconnect ()
-
- try:
- os.remove (tmpfname)
- except OSError:
- pass
-
- try:
- self.populateList()
- except cups.HTTPError, (s,):
- self.cups = None
- self.setConnected()
- self.populateList()
- self.show_HTTP_Error(s)
-
- ##########################################################################
- ### Server settings
- ##########################################################################
-
- def fillServerTab(self):
- self.changed = set()
- try:
- self.server_settings = self.cups.adminGetServerSettings()
- except cups.IPPError, (e, m):
- #FIXME
- 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.chkServerShareAny, try_CUPS_SERVER_REMOTE_ANY),
- (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)
- self.widget_data_setting[widget] = setting
- self.disconnect(widget, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
- if self.server_settings.has_key(setting):
- widget.setChecked(int(self.server_settings[setting]))
- widget.setEnabled(True)
- else:
- widget.setChecked(False)
- widget.setEnabled(False)
- self.connect(widget, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
- self.setDataButtonState()
- # Set sensitivity of 'Allow printing from the Internet'.
- self.on_server_changed (self.chkServerShare) # (any will do here)
-
- def on_server_widget_changed(self, value):
- self.on_server_changed(self.sender())
-
- def on_server_changed(self, widget):
- #setting = widget.get_data("setting")
- #print "widget_data_setting " + str(self.widget_data_setting)
- #print "widget " + str(widget)
- setting = self.widget_data_setting[widget]
- if self.server_settings.has_key (setting):
- if str(int(widget.isChecked())) == self.server_settings[setting]:
- self.changed.discard(widget)
- else:
- self.changed.add(widget)
-
- sharing = self.chkServerShare.isChecked ()
- self.chkServerShareAny.setEnabled (
- sharing and self.server_settings.has_key(try_CUPS_SERVER_REMOTE_ANY))
-
- 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.chkServerShareAny, try_CUPS_SERVER_REMOTE_ANY),
- (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.isChecked()))
- try:
- self.cups.adminSetServerSettings(setting_dict)
- except cups.IPPError, (e, m):
- self.show_IPP_Error(e, m)
- return True
- except RuntimeError, s:
- self.show_IPP_Error(None, s)
- 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 ()
-
- # Refresh the server settings in case they have changed in the
- # mean time.
- try:
- self.fillServerTab()
- except:
- nonfatalException()
-
- # ====================================================================
- # == New Printer Dialog ==============================================
- # ====================================================================
-
- # new printer
- def on_new_printer_activate(self):
- self.busy()
- self.newPrinterGUI.init("printer")
- self.ready()
-
- # new class
- def on_new_class_activate(self):
- self.newPrinterGUI.init("class")
-
- @pyqtSignature("")
- def on_btnSelectDevice_clicked(self):
- self.newPrinterGUI.init("device")
-
- @pyqtSignature("")
- def on_btnChangePPD_clicked(self):
- self.busy(self)
- self.newPrinterGUI.init("ppd")
- self.ready(self)
-
- def checkNPName(self, name):
- if not name: return False
- name = name.lower()
- for printer in self.printers.values():
- if not printer.discovered and printer.name.lower()==name:
- return False
- return True
-
- def makeNameUnique(self, name):
- """Make a suggested queue name valid and unique."""
- name = name.replace (" ", "_")
- name = name.replace ("/", "_")
- name = name.replace ("#", "_")
- if not self.checkNPName (name):
- suffix=2
- while not self.checkNPName (name + str (suffix)):
- suffix += 1
- if suffix == 100:
- break
- name += str (suffix)
- return name
-
- #TODO
- ## Watcher interface helpers
-
- @pyqtSignature("")
- def on_btnRevert_clicked(self):
- self.changed = set() # avoid asking the user
- self.on_tvMainList_cursor_changed()
-
- @pyqtSignature("")
- def on_btnPrinterPropertiesApply_clicked(self):
- err = self.printer_properties_response()
- if not err:
- self.populateList()
- else:
- nonfatalException()
-
- def show_IPP_Error(self, exception, message):
- if exception == cups.IPP_NOT_AUTHORIZED:
- QMessageBox.critical(self, _('Not authorized'), _('The password may be incorrect.'))
- else:
- QMessageBox.critical(self, _('CUPS server error'), _("There was an error during the CUPS "\
- "operation: '%s'.") % message)
- def show_HTTP_Error(self, status):
- if (status == cups.HTTP_UNAUTHORIZED or
- status == cups.HTTP_FORBIDDEN):
- QMessageBox.critical(self, _('Not authorized'),
- _('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")
- elif status == -1:
- msg = _("Not connected")
- 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
- QMessageBox.critical(self, _('CUPS server error'), _("There was an HTTP error: %s.") % msg)
-
- def getSelectedItem(self):
- return str(self.mainListSelectedName).decode ('utf-8'), str(self.mainListSelectedType)
- """
- items = self.mainlist.selectedItems()
- if len(items) < 1:
- return ("", 'None')
- item = items[0]
- name = item.text(0)
- type = item.text(1)
- name = str(name).decode ('utf-8')
- return name.strip(), type
- """
-
- def reconnect (self):
- """Reconnect to CUPS after the server has reloaded."""
- # libcups would handle the reconnection if we just told it to
- # do something, for example fetching a list of classes.
- # However, our local authentication certificate would be
- # invalidated by a server restart, so it is better for us to
- # handle the reconnection ourselves.
-
- # Disconnect.
- self.cups = None
- self.setConnected()
-
- cups.setServer(self.connect_server)
- cups.setUser(self.connect_user)
- attempt = 1
- while attempt <= 5:
- try:
- self.cups = cups.Connection ()
- break
- except RuntimeError:
- # Connection failed.
- time.sleep(1)
- attempt += 1
-
- self.setConnected()
- self.passwd_retry = False
-
- def updatePrinterProperties(self):
- debugprint ("update printer properties")
- printer = self.printer
- self.lblPMakeModel.setText(printer.make_and_model)
- state = self.printer_states.get (printer.state, _("Unknown"))
- reason = printer.other_attributes.get ('printer-state-message', '')
- if len (reason) > 0:
- state += ' - ' + reason
- self.lblPState.setText(state)
- if len (self.changed) == 0:
- debugprint ("no changes yet: full printer properties update")
- # State
- self.chkPEnabled.setEnabled(printer.enabled)
- self.chkPAccepting.setEnabled(not printer.rejecting)
- self.chkPShared.setEnabled(printer.is_shared)
-
- # 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)
-
- # Policies
- self.fillComboBox(self.cmbPErrorPolicy,
- printer.error_policy_supported,
- printer.error_policy)
- self.fillComboBox(self.cmbPOperationPolicy,
- printer.op_policy_supported,
- printer.op_policy)
-
- """
- # Access control
- self.rbtnPAllow.set_active(printer.default_allow)
- self.rbtnPDeny.set_active(not printer.default_allow)
- self.setPUsers(printer.except_users)
- """
-
- def setTestButton (self, printer):
- if printer.testsQueued ():
- self.test_button_cancels = True
- self.btnPrintTestPage.setText(_('Cancel Tests'))
- self.btnPrintTestPage.setEnabled(True)
- else:
- self.test_button_cancels = False
- self.btnPrintTestPage.setText(_('Print Test Page'))
- self.setDataButtonState()
-
- def getCurrentClassMembers(self, listwidget):
- count = listwidget.count()
- result = []
- for i in range(count):
- result.append(listwidget.item(i).text())
- result.sort()
- return result
-
- def moveClassMembers(self, treeview_from, treeview_to):
- rows = treeview_from.selectedItems()
- for row in rows:
- treeview_from.takeItem(treeview_from.row(row))
- treeview_to.addItem(row)
-
- # Password handling
-
- #FIXME obsolete?
- def cupsPasswdCallback(self, querystring):
- return "" #FIXME
- if self.passwd_retry or len(self.password) == 0:
- waiting = self.WaitWindow.get_property('visible')
- if waiting:
- self.WaitWindow.hide ()
- 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 waiting:
- self.WaitWindow.show ()
- while gtk.events_pending ():
- gtk.main_iteration ()
- 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
-
- class NewPrinterGUI(QDialog):
-
- new_printer_device_tabs = {
- "parallel" : 0, # empty tab
- "usb" : 0,
- "hal" : 0,
- "beh" : 0,
- "hp" : 0,
- "hpfax" : 0,
- "socket": 2,
- "ipp" : 3,
- "http" : 3,
- "lpd" : 4,
- "scsi" : 5,
- "serial" : 6,
- "smb" : 7,
- }
-
- ntbkNewPrinterPages = {
- "name" : 0,
- "device" : 1,
- "make" : 2,
- "model" : 3,
- "class-members" : 4,
- "downloadable" : -1,
- }
-
- def __init__(self, mainapp):
- QDialog.__init__(self, mainapp)
- self.mainapp = mainapp
- self.language = mainapp.language
- self.dialog_mode = ""
-
- self.WaitWindow = QMessageBox(self.mainapp)
- self.WaitWindow.setStandardButtons(QMessageBox.NoButton)
-
- uic.loadUi(APPDIR + "/" + "new-printer.ui", self)
-
- self.connect(self.tvNPDevices, SIGNAL("itemSelectionChanged()"), self.on_tvNPDevices_cursor_changed)
- self.connect(self.tvNPMakes, SIGNAL("itemSelectionChanged()"), self.on_tvNPMakes_cursor_changed)
- self.connect(self.tvNPModels, SIGNAL("itemSelectionChanged()"), self.on_tvNPModels_cursor_changed)
- self.connect(self.entNPTDevice, SIGNAL("textEdited(const QString&)"), self.on_entNPTDevice_changed)
- # self.connect(self.entNPTIPPHostname, SIGNAL("textEdited(const QString&)"), self.on_entNPTIPPHostname_changed)
- # self.connect(self.entNPTIPPQueuename, SIGNAL("textEdited(const QString&)"), self.on_entNPTIPPQueuename_changed)
- self.connect(self.entSMBURI, SIGNAL("textEdited(const QString&)"), self.on_entSMBURI_changed)
- self.rbtnSMBAuthPrompt.setChecked(True)
- self.on_rbtnSMBAuthSet_toggled(False)
- self.connect(self.rbtnSMBAuthSet, SIGNAL("toggled(bool)"), self.on_rbtnSMBAuthSet_toggled)
- self.rbtnNPFoomatic.setChecked(True)
- self.connect(self.rbtnNPFoomatic, SIGNAL("toggled(bool)"), self.on_rbtnNPFoomatic_toggled)
-
- self.options = {} # keyword -> Option object
- self.changed = set()
- self.conflicts = set()
- self.ppd = None
-
- # Synchronisation objects.
- self.ppds_lock = thread.allocate_lock()
- self.devices_lock = thread.allocate_lock()
- self.smb_lock = thread.allocate_lock()
- self.ipp_lock = thread.allocate_lock()
- self.drivers_lock = thread.allocate_lock()
-
- #self.connect(self.btnNCAddMember, SIGNAL("clicked()"), self.slot_btnNCAddMember_clicked)
- #self.connect(self.btnNCDelMember, SIGNAL("clicked()"), self.slot_btnNCDelMember_clicked)
-
- """
- # share with mainapp
- self.WaitWindow = mainapp.WaitWindow
- self.lblWait = mainapp.lblWait
- self.busy = mainapp.busy
- self.ready = mainapp.ready
- self.show_IPP_Error = mainapp.show_IPP_Error
- self.show_HTTP_Error = mainapp.show_HTTP_Error
- """
-
- # Optionally disable downloadable driver support.
- if not config.DOWNLOADABLE_DRIVER_SUPPORT:
- self.rbtnNPDownloadableDriverSearch.setEnabled(False)
- self.downloadableDriverSearchFrame.hide()
-
- """
- # Set up OpenPrinting widgets.
- self.openprinting = openprinting.OpenPrinting ()
- self.openprinting_query_handle = None
- combobox = self.cmbNPDownloadableDriverFoundPrinters
- cell = gtk.CellRendererText()
- combobox.pack_start (cell, True)
- combobox.add_attribute(cell, 'text', 0)
-
- # 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.SMBBrowseDialog.set_transient_for(self.NewPrinterWindow)
-
- # IPP browser
- self.ipp_store = gtk.TreeStore (str, # queue
- str, # location
- gobject.TYPE_PYOBJECT) # dict
- self.tvIPPBrowser.set_model (self.ipp_store)
- self.ipp_store.set_sort_column_id (0, gtk.SORT_ASCENDING)
-
- # IPP list columns
- col = gtk.TreeViewColumn (_("Queue"), gtk.CellRendererText (),
- text=0)
- col.set_resizable (True)
- col.set_sort_column_id (0)
- self.tvIPPBrowser.append_column (col)
-
- col = gtk.TreeViewColumn (_("Location"), gtk.CellRendererText (),
- text=1)
- self.tvIPPBrowser.append_column (col)
- self.IPPBrowseDialog.set_transient_for(self.NewPrinterWindow)
-
- self.tvNPDriversTooltips = TreeViewTooltips(self.tvNPDrivers, self.NPDriversTooltips)
-
- ppd_filter = gtk.FileFilter()
- ppd_filter.set_name(_("PostScript Printer Description files (*.ppd, *.PPD, *.ppd.gz, *.PPD.gz, *.PPD.GZ)"))
- ppd_filter.add_pattern("*.ppd")
- ppd_filter.add_pattern("*.PPD")
- ppd_filter.add_pattern("*.ppd.gz")
- ppd_filter.add_pattern("*.PPD.gz")
- ppd_filter.add_pattern("*.PPD.GZ")
- self.filechooserPPD.add_filter(ppd_filter)
-
- ppd_filter = gtk.FileFilter()
- ppd_filter.set_name(_("All files (*)"))
- ppd_filter.add_pattern("*")
- self.filechooserPPD.add_filter(ppd_filter)
-
- self.xml.signal_autoconnect(self)
- """
-
- #FIXME hide bits which are not yet implemented
- self.btnSMBBrowse.hide()
- self.btnSMBVerify.hide()
- self.btnIPPFindQueue.hide()
- self.btnIPPVerify.hide()
- self.btnNPTLpdProbe.hide()
-
- 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()
-
- return
-
- def setDataButtonState(self):
- self.btnNPForward.setEnabled(not bool(self.conflicts))
-
- def init(self, dialog_mode):
- self.dialog_mode = dialog_mode
- self.options = {} # keyword -> Option object
- self.changed = set()
- self.conflicts = set()
-
- """
- combobox = self.cmbNPDownloadableDriverFoundPrinters
- combobox.set_model (gtk.ListStore (str, str))
- self.entNPDownloadableDriverSearch.set_text ('')
- button = self.btnNPDownloadableDriverSearch
- label = button.get_children ()[0].get_children ()[0].get_children ()[1]
- self.btnNPDownloadableDriverSearch_label = label
- label.set_text (_("Search"))
- """
-
- if self.dialog_mode == "printer":
- self.setWindowTitle(_("New Printer"))
- # Start on devices page (1, not 0)
- self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["device"])
- self.fillDeviceTab()
- self.on_rbtnNPFoomatic_toggled()
- # Start fetching information from CUPS in the background
- self.new_printer_PPDs_loaded = False
- self.queryPPDs ()
-
- elif self.dialog_mode == "class":
- self.setWindowTitle(_("New Class"))
- self.fillNewClassMembers()
- # Start on name page
- self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["name"])
- elif self.dialog_mode == "device":
- self.setWindowTitle(_("Change Device URI"))
- self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["device"])
- self.queryDevices ()
- self.loadPPDs()
- self.fillDeviceTab(self.mainapp.printer.device_uri)
- # Start fetching information from CUPS in the background
- self.new_printer_PPDs_loaded = False
- self.queryPPDs ()
- elif self.dialog_mode == "ppd":
- self.setWindowTitle(_("Change Driver"))
- self.ntbkNewPrinter.setCurrentIndex(2)
- self.on_rbtnNPFoomatic_toggled()
-
- self.auto_model = ""
- ppd = self.mainapp.ppd
- if ppd:
- attr = ppd.findAttr("Manufacturer")
- if attr:
- self.auto_make = attr.value
- else:
- self.auto_make = ""
- attr = ppd.findAttr("ModelName")
- if not attr: attr = ppd.findAttr("ShortNickName")
- if not attr: attr = 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.loadPPDs ()
- self.fillMakeList()
-
- if self.dialog_mode in ("printer", "class"):
- self.entNPName.setText (self.mainapp.makeNameUnique(self.dialog_mode))
- #FIXMEself.entNPName.grab_focus()
- for widget in [self.entNPLocation,
- self.entNPDescription]: #,
- #self.entSMBURI, self.entSMBUsername,
- #self.entSMBPassword, self.entNPTDirectJetHostname]:
- widget.setText('')
-
- try:
- p = os.popen ('/bin/hostname', 'r')
- hostname = p.read ().strip ()
- p.close ()
- self.entNPLocation.setText(hostname)
- except:
- nonfatalException ()
-
- self.entNPTDirectJetPort.setText('9100')
- self.setNPButtons()
- self.exec_()
-
- # get PPDs
-
- def queryPPDs(self):
- debugprint ("queryPPDs")
- if not self.ppds_lock.acquire(0):
- debugprint ("queryPPDs: in progress")
- return
- debugprint ("Lock acquired for PPDs thread")
- # Start new thread
- thread.start_new_thread (self.getPPDs_thread, (self.language[0],))
- debugprint ("PPDs thread started")
-
- def getPPDs_thread(self, language):
- try:
- debugprint ("Connecting (PPDs)")
- cups.setServer (self.mainapp.connect_server)
- cups.setUser (self.mainapp.connect_user)
- cups.setPasswordCB (self.mainapp.cupsPasswdCallback)
- # cups.setEncryption (...)
- c = cups.Connection ()
- debugprint ("Fetching PPDs")
- ppds_dict = c.getPPDs()
- self.ppds_result = cupshelpers.ppds.PPDs(ppds_dict,
- language=language)
- debugprint ("Closing connection (PPDs)")
- del c
- except cups.IPPError, (e, msg):
- self.ppds_result = cups.IPPError (e, msg)
- except:
- nonfatalException()
- self.ppds_result = { }
-
- debugprint ("Releasing PPDs lock")
- self.ppds_lock.release ()
-
- def fetchPPDs(self, parent=None):
- debugprint ("fetchPPDs")
- self.queryPPDs()
- time.sleep (0.1)
-
- # Keep the UI refreshed while we wait for the devices to load.
- waiting = False
- while (self.ppds_lock.locked()):
- if not waiting:
- waiting = True
- self.WaitWindow.setText('<b>' +
- _('Searching') + '</b><br /><br />' +
- _('Searching for drivers'))
- self.WaitWindow.show ()
-
- QApplication.processEvents()
-
- time.sleep (0.1)
-
- if waiting:
- self.WaitWindow.hide ()
-
- debugprint ("Got PPDs")
- result = self.ppds_result # atomic operation
- if isinstance (result, cups.IPPError):
- # Propagate exception.
- raise result
- return result
-
- def loadPPDs(self, parent=None):
- try:
- return self.ppds
- except:
- self.ppds = self.fetchPPDs (parent=parent)
- return self.ppds
-
- def dropPPDs(self):
- try:
- del self.ppds
- except:
- pass
-
- # Class members
-
- def fillNewClassMembers(self):
- self.tvNCMembers.clear()
- self.tvNCNotMembers.clear()
- for printer in self.mainapp.printers.itervalues():
- self.tvNCNotMembers.addItem(printer.name)
-
- @pyqtSignature("")
- def on_btnNCAddMember_clicked(self):
- self.mainapp.moveClassMembers(self.tvNCNotMembers, self.tvNCMembers)
- self.btnNPApply.setEnabled(
- bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers)))
-
- @pyqtSignature("")
- def on_btnNCDelMember_clicked(self):
- self.mainapp.moveClassMembers(self.tvNCMembers, self.tvNCNotMembers)
- self.btnNPApply.setEnabled(
- bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers)))
-
- @pyqtSignature("")
- def on_btnNPBack_clicked(self):
- self.nextNPTab(-1)
-
- @pyqtSignature("")
- def on_btnNPForward_clicked(self):
- self.nextNPTab()
-
- def nextNPTab(self, step=1):
- page_nr = self.ntbkNewPrinter.currentIndex()
-
- if self.dialog_mode == "class":
- #order = [0, 4, 5]
- order = [self.ntbkNewPrinterPages["name"], self.ntbkNewPrinterPages["class-members"]]
- elif self.dialog_mode == "printer":
- #self.busy(self)
- if page_nr == 1: # Device (first page)
- # Choose an appropriate name.
- name = 'printer'
- try:
- if self.device.id:
- name = self.device.id_dict["MDL"]
- name = self.mainapp.makeNameUnique (name)
- self.entNPName.setText(name)
- except:
- nonfatalException ()
- self.auto_make, self.auto_model = None, None
- self.device.uri = self.getDeviceURI()
- if self.device.type in ("socket", "lpd", "ipp", "bluetooth"):
- host = self.getNetworkPrinterMakeModel(self.device)
- faxuri = None
- if host:
- faxuri = self.get_hplip_uri_for_network_printer(host,
- "fax")
- if faxuri:
- ##FIXME
- dialog = gtk.Dialog(self.device.info,
- self.NewPrinterWindow,
- gtk.DIALOG_MODAL |
- gtk.DIALOG_DESTROY_WITH_PARENT,
- (_("Printer"), 1,
- _("Fax"), 2))
- label = gtk.Label(_("This printer supports both "
- "printing and sending faxes. "
- "Which functionality should be "
- "used for this queue?"))
- dialog.vbox.pack_start(label, True, True, 0)
- label.show()
- queue_type = dialog.run()
- dialog.destroy()
- if (queue_type == 2):
- self.device.id_dict = \
- self.get_hpfax_device_id(faxuri)
- self.device.uri = faxuri
- self.auto_make = self.device.id_dict["MFG"]
- self.auto_model = self.device.id_dict["MDL"]
- self.device.id = "MFG:" + self.auto_make + \
- ";MDL:" + self.auto_model + \
- ";DES:" + \
- self.device.id_dict["DES"] + ";"
- uri = self.device.uri
- if uri and uri.startswith ("smb://"):
- uri = SMBURI (uri=uri[6:]).sanitize_uri ()
-
- # Try to access the PPD, in this case our detected IPP
- # printer is a queue on a remote CUPS server which is
- # not automatically set up on our local CUPS server
- # (for example DNS-SD broadcasted queue from Mac OS X)
- self.remotecupsqueue = None
- res = re.search ("ipp://(\S+(:\d+|))/printers/(\S+)", uri)
- if res:
- resg = res.groups()
- try:
- conn = httplib.HTTPConnection(resg[0])
- conn.request("GET", "/printers/%s.ppd" % resg[2])
- resp = conn.getresponse()
- if resp.status == 200: self.remotecupsqueue = resg[2]
- except:
- debugprint("exception in getting remotecupsqueue")
- pass
-
- # We also want to fetch the printer-info and
- # printer-location attributes, to pre-fill those
- # fields for this new queue.
- oldserver = cups.getServer()
- oldport = cups.getPort()
- try:
- cups.setServer (resg[0])
- if len (resg[1]) > 0:
- cups.setPort (int (resg[1]))
- else:
- cups.setPort (631)
-
- c = cups.Connection ()
- r = ['printer-info', 'printer-location']
- attrs = c.getPrinterAttributes (uri=uri,
- requested_attributes=r)
- info = attrs.get ('printer-info', '')
- location = attrs.get ('printer-location', '')
- if len (info) > 0:
- self.entNPDescription.setText(info)
- if len (location) > 0:
- self.entNPLocation.setText(location)
- except:
- nonfatalException ()
-
- cups.setServer (oldserver)
- cups.setPort (oldport)
-
- if (not self.remotecupsqueue and
- not self.new_printer_PPDs_loaded):
- try:
- self.loadPPDs(self)
- except cups.IPPError, (e, msg):
- #self.ready (self)
- self.show_IPP_Error(e, msg)
- return
- except:
- self.ready (self)
- return
- self.new_printer_PPDs_loaded = True
-
- ppdname = None
- try:
- if self.remotecupsqueue:
- # We have a remote CUPS queue, let the client queue
- # stay raw so that the driver on the server gets used
- ppdname = 'raw'
- self.ppd = ppdname
- name = self.remotecupsqueue
- name = self.mainapp.makeNameUnique (name)
- self.entNPName.setText(name)
- elif self.device.id:
- id_dict = self.device.id_dict
- (status, ppdname) = self.ppds.\
- getPPDNameFromDeviceID (id_dict["MFG"],
- id_dict["MDL"],
- id_dict["DES"],
- id_dict["CMD"],
- self.device.uri)
- else:
- (status, ppdname) = self.ppds.\
- getPPDNameFromDeviceID ("Generic",
- "Printer",
- "Generic Printer",
- [],
- self.device.uri)
-
- if ppdname and not self.remotecupsqueue:
- ppddict = self.ppds.getInfoFromPPDName (ppdname)
- make_model = ppddict['ppd-make-and-model']
- (make, model) = \
- cupshelpers.ppds.ppdMakeModelSplit (make_model)
- self.auto_make = make
- self.auto_model = model
- except:
- nonfatalException ()
- if not self.remotecupsqueue:
- self.fillMakeList()
- elif page_nr == 3: # Model has been selected
- if not self.device.id:
- # Choose an appropriate name when no Device ID
- # is available, based on the model the user has
- # selected.
- try:
- items = self.tvNPModels.selectedItems()
- name = unicode(items[0].text())
- name = self.mainapp.makeNameUnique (name)
- self.entNPName.setText(name)
- except:
- nonfatalException ()
-
- ##self.ready (self.NewPrinterWindow)
- if self.remotecupsqueue:
- order = [1, 0]
- elif self.rbtnNPFoomatic.isChecked():
- order = [1, 2, 3, 6, 0]
- elif self.rbtnNPPPD.isChecked():
- order = [1, 2, 6, 0]
- else:
- # Downloadable driver
- order = [1, 2, 7, 6, 0]
- elif self.dialog_mode == "device":
- order = [1]
- elif self.dialog_mode == "ppd":
- self.rbtnChangePPDasIs.setChecked(True)
- if self.rbtnNPFoomatic.isChecked():
- order = [2, 3, 5, 6]
- elif self.rbtnNPPPD.isChecked():
- order = [2, 5, 6]
- else:
- # Downloadable driver
- order = [2, 7, 5, 6]
-
- next_page_nr = order[order.index(page_nr)+step]
-
- # fill Installable Options tab
- if next_page_nr == 6 and step > 0:
- #TODO Prepare Installable Options screen.
- self.ppd = self.getNPPPD()
- """FIXME todo
- if next_page_nr == 6:
- # Prepare Installable Options screen.
- if isinstance(self.ppd, cups.PPD):
- self.fillNPInstallableOptions()
- else:
- self.installable_options = None
- # Put a label there explaining why the page is empty.
- ppd = self.ppd
- self.ppd = None
- self.fillNPInstallableOptions()
- self.ppd = ppd
-
- # step over if empty and not in PPD mode
- if self.dialog_mode != "ppd" and not self.installable_options:
- next_page_nr = order[order.index(next_page_nr)+1]
- """
- next_page_nr = order[order.index(next_page_nr)+1]
- self.installable_options = False
- # Step over empty Installable Options tab
- if next_page_nr == 6 and not self.installable_options and step<0:
- next_page_nr = order[order.index(next_page_nr)-1]
-
- if next_page_nr == 7: # About to show downloadable drivers
- if self.drivers_lock.locked ():
- # Still searching for drivers.
- self.lblWait.set_markup ('<span weight="bold" size="larger">' +
- _('Searching') + '</span>\n\n' +
- _('Searching for drivers'))
- self.WaitWindow.set_transient_for (self.NewPrinterWindow)
- self.WaitWindow.show ()
- self.busy(self)
-
- # Keep the UI refreshed while we wait for the drivers
- # query to complete.
- while self.drivers_lock.locked ():
- while gtk.events_pending ():
- gtk.main_iteration ()
- time.sleep (0.1)
-
- self.ready (self.NewPrinterWindow)
- self.WaitWindow.hide ()
-
- self.fillDownloadableDrivers()
-
- self.ntbkNewPrinter.setCurrentIndex(next_page_nr)
-
- self.setNPButtons()
-
- def setNPButtons(self):
- nr = self.ntbkNewPrinter.currentIndex()
-
- if self.dialog_mode == "device":
- self.btnNPBack.hide()
- self.btnNPForward.hide()
- self.btnNPApply.show()
- uri = self.getDeviceURI ()
- self.btnNPApply.setEnabled(validDeviceURI (uri))
- return
-
- if self.dialog_mode == "ppd":
- if nr == 5: # Apply
- if not self.installable_options:
- # There are no installable options, so this is the
- # last page.
- debugprint ("No installable options")
- self.btnNPForward.hide ()
- self.btnNPApply.show ()
- else:
- self.btnNPForward.show ()
- self.btnNPApply.hide ()
- return
- elif nr == 6:
- self.btnNPForward.hide()
- self.btnNPApply.show()
- return
- else:
- self.btnNPForward.show()
- self.btnNPApply.hide()
- if nr == 2:
- self.btnNPBack.hide()
- self.btnNPForward.show()
- downloadable_selected = False
- if self.rbtnNPDownloadableDriverSearch.isChecked():
- combobox = self.cmbNPDownloadableDriverFoundPrinters
- iter = combobox.get_active_iter () #FIXME
- if iter and combobox.get_model ().get_value (iter, 1):
- downloadable_selected = True
-
- self.btnNPForward.setEnabled(bool(
- self.rbtnNPFoomatic.isChecked() or
- self.filechooserPPD.get_filename() or
- downloadable_selected))
- return
- else:
- self.btnNPBack.show()
-
- # class/printer
-
- if nr == 1: # Device
- valid = False
- try:
- uri = self.getDeviceURI ()
- valid = validDeviceURI (uri)
- except:
- pass
- self.btnNPForward.setEnabled(valid)
- self.btnNPBack.hide ()
- else:
- self.btnNPBack.show()
-
- self.btnNPForward.show()
- self.btnNPApply.hide()
-
- if nr == 0: # Name
- self.btnNPBack.show()
- if self.dialog_mode == "class":
- self.btnNPForward.setEnabled(True)
- if self.dialog_mode == "printer":
- self.btnNPForward.hide()
- self.btnNPApply.show()
- self.btnNPApply.setEnabled(
- self.mainapp.checkNPName(unicode(self.entNPName.text())))
- if nr == 2: # Make/PPD file
- downloadable_selected = False
- if self.rbtnNPDownloadableDriverSearch.isChecked():
- combobox = self.cmbNPDownloadableDriverFoundPrinters
- iter = combobox.get_active_iter () #FIXME
- if iter and combobox.get_model ().get_value (iter, 1):
- downloadable_selected = True
-
- self.btnNPForward.setEnabled(bool(
- self.rbtnNPFoomatic.isChecked() or
- self.filechooserPPD.get_filename() or
- downloadable_selected))
- if nr == 3: # Model/Driver
- iter = self.tvNPDrivers.currentItem()
- self.btnNPForward.setEnabled(bool(iter))
- if nr == 4: # Class Members
- self.btnNPForward.hide()
- self.btnNPApply.show()
- self.btnNPApply.setEnabled(self.tvNCMembers.count() > 0)
- if nr == 7: # Downloadable drivers
- if self.ntbkNPDownloadableDriverProperties.get_current_page() == 1: #FIXME
- accepted = self.rbtnNPDownloadLicenseYes.get_active ()
- else:
- treeview = self.tvNPDownloadableDrivers
- model, iter = treeview.get_selection ().get_selected ()
- accepted = (iter != None)
-
- self.btnNPForward.set_sensitive(accepted)
-
- def getDevices_thread(self):
- try:
- debugprint ("Connecting (devices)")
- cups.setServer (self.mainapp.connect_server)
- #cups.setUser (self.mainapp.connect_user)
- cups.setUser ("jr")
- cups.setPasswordCB (self.mainapp.cupsPasswdCallback)
- # cups.setEncryption (...)
- c = cups.Connection ()
- debugprint ("Fetching devices")
- self.devices_result = cupshelpers.getDevices(c)
- except cups.IPPError, (e, msg):
- self.devices_result = cups.IPPError (e, msg)
- except:
- debugprint ("Exception in getDevices_thread")
- self.devices_result = {}
-
- try:
- debugprint ("Closing connection (devices)")
- del c
- except:
- pass
-
- debugprint ("Releasing devices lock")
- self.devices_lock.release ()
-
- # Device URI
- def queryDevices(self):
- if not self.devices_lock.acquire(0):
- debugprint ("queryDevices: in progress")
- return
- debugprint ("Lock acquired for devices thread")
- # Start new thread
- thread.start_new_thread (self.getDevices_thread, ())
- #self.getDevices_thread()
- debugprint ("Devices thread started")
-
- def fetchDevices(self, parent=None):
- debugprint ("fetchDevices")
- self.queryDevices ()
- time.sleep (0.1)
-
- # Keep the UI refreshed while we wait for the devices to load.
- waiting = False
- while (self.devices_lock.locked()):
- if not waiting:
- waiting = True
- self.WaitWindow.setText ('<b>' +
- _('Searching') + '</b><br/><br/>' +
- _('Searching for printers'))
- #if not parent:
- # parent = self.mainapp.MainWindow
- #self.WaitWindow.set_transient_for (parent)
- #self.WaitWindow.show ()
- self.WaitWindow.show()
-
- QApplication.processEvents()
-
- time.sleep (0.1)
-
- if waiting:
- #self.WaitWindow.hide ()
- self.WaitWindow.hide()
-
- debugprint ("Got devices")
- result = self.devices_result # atomic operation
- if isinstance (result, cups.IPPError):
- # Propagate exception.
- raise result
- return result
-
- def get_hpfax_device_id(self, faxuri):
- os.environ["URI"] = faxuri
- cmd = 'LC_ALL=C DISPLAY= hp-info -d "${URI}"'
- debugprint (faxuri + ": " + cmd)
- try:
- p = subprocess.Popen (cmd, shell=True,
- stdin=file("/dev/null"),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- (stdout, stderr) = p.communicate ()
- except:
- # Problem executing command.
- return None
-
- for line in stdout.split ("\n"):
- if line.find ("fax-type") == -1:
- continue
- faxtype = -1
- res = re.search ("(\d+)", line)
- if res:
- resg = res.groups()
- faxtype = resg[0]
- if faxtype >= 0: break
- if faxtype < 0:
- return None
- elif faxtype == 4:
- return cupshelpers.parseDeviceID ('MFG:HP;MDL:Fax 2;DES:HP Fax 2;')
- else:
- return cupshelpers.parseDeviceID ('MFG:HP;MDL:Fax;DES:HP Fax;')
-
- def get_hplip_uri_for_network_printer(self, host, mode):
- os.environ["HOST"] = host
- if mode == "print": mod = "-c"
- elif mode == "fax": mod = "-f"
- else: mod = "-c"
- cmd = 'hp-makeuri ' + mod + ' "${HOST}"'
- debugprint (host + ": " + cmd)
- uri = None
- try:
- p = subprocess.Popen (cmd, shell=True,
- stdin=file("/dev/null"),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- (stdout, stderr) = p.communicate ()
- except:
- # Problem executing command.
- return None
-
- uri = stdout.strip ()
- return uri
-
- def getNetworkPrinterMakeModel(self, device):
- # Determine host name/IP
- host = None
- s = device.uri.find ("://")
- if s != -1:
- s += 3
- e = device.uri[s:].find (":")
- if e == -1: e = device.uri[s:].find ("/")
- if e == -1: e = device.uri[s:].find ("?")
- if e == -1: e = len (device.uri)
- host = device.uri[s:s+e]
- # Try to get make and model via SNMP
- if host:
- os.environ["HOST"] = host
- cmd = '/usr/lib/cups/backend/snmp "${HOST}"'
- debugprint (host + ": " + cmd)
- stdout = None
- try:
- p = subprocess.Popen (cmd, shell=True,
- stdin=file("/dev/null"),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- (stdout, stderr) = p.communicate ()
- except:
- # Problem executing command.
- pass
-
- if stdout != None:
- mm = re.sub("^\s*\S+\s+\S+\s+\"", "", stdout)
- mm = re.sub("\"\s+.*$", "", mm)
- if mm and mm != "": device.make_and_model = mm
- # Extract make and model and create a pseudo device ID, so
- # that a PPD/driver can be assigned to the device
- make_and_model = None
- if len (device.make_and_model) > 7:
- make_and_model = device.make_and_model
- elif len (device.info) > 7:
- make_and_model = device.info
- make_and_model = re.sub("\s*(\(|\d+\.\d+\.\d+\.\d+).*$", "", make_and_model)
- if make_and_model and not device.id:
- mk = None
- md = None
- (mk, md) = cupshelpers.ppds.ppdMakeModelSplit (make_and_model)
- device.id = "MFG:" + mk + ";MDL:" + md + ";DES:" + mk + " " + md + ";"
- device.id_dict = cupshelpers.parseDeviceID (device.id)
- # Check whether the device is supported by HPLIP and replace
- # its URI by an HPLIP URI
- if host:
- hplipuri = self.get_hplip_uri_for_network_printer(host, "print")
- if hplipuri:
- device.uri = hplipuri
- s = hplipuri.find ("/usb/")
- if s == -1: s = hplipuri.find ("/par/")
- if s == -1: s = hplipuri.find ("/net/")
- if s != -1:
- s += 5
- e = hplipuri[s:].find ("?")
- if e == -1: e = len (hplipuri)
- mdl = hplipuri[s:s+e].replace ("_", " ")
- if mdl.startswith ("hp ") or mdl.startswith ("HP "):
- mdl = mdl[3:]
- device.make_and_model = "HP " + mdl
- device.id = "MFG:HP;MDL:" + mdl + ";DES:HP " + mdl + ";"
- device.id_dict = cupshelpers.parseDeviceID (device.id)
- # Return the host name/IP for further actions
- return host
-
- def fillDeviceTab(self, current_uri=None, query=True):
- if query:
- try:
- devices = self.fetchDevices()
- except cups.IPPError, (e, msg):
- self.show_IPP_Error(e, msg)
- devices = {}
- except:
- nonfatalException()
- devices = {}
-
- if current_uri:
- if devices.has_key (current_uri):
- current = devices.pop(current_uri)
- else:
- current = cupshelpers.Device (current_uri)
- current.info = "Current device"
-
- self.devices = devices.values()
-
- for device in self.devices:
- if device.type == "usb":
- # Find USB URIs with corresponding HPLIP URIs and mark them
- # for deleting, so that the user will only get the HPLIP
- # URIs for full device support in the list
- ser = None
- s = device.uri.find ("?serial=")
- if s != -1:
- s += 8
- e = device.uri[s:].find ("?")
- if e == -1: e = len (device.uri)
- ser = device.uri[s:s+e]
- mod = None
- s = device.uri[6:].find ("/")
- if s != -1:
- s += 7
- e = device.uri[s:].find ("?")
- if e == -1: e = len (device.uri)
- mod = device.uri[s:s+e].lower ().replace ("%20", "_")
- if mod.startswith ("hp_"):
- mod = mod[3:]
- matchfound = 0
- for hpdevice in self.devices:
- hpser = None
- hpmod = None
- uri = hpdevice.uri
- if not uri.startswith ("hp:"): continue
- if ser:
- s = uri.find ("?serial=")
- if s != -1:
- s += 8
- e = uri[s:].find ("?")
- if e == -1: e = len (uri)
- hpser = uri[s:s+e]
- if hpser != ser: continue
- matchfound = 1
- if mod and not (ser and hpser):
- s = uri.find ("/usb/")
- if s != -1:
- s += 5
- e = uri[s:].find ("?")
- if e == -1: e = len (uri)
- hpmod = uri[s:s+e].lower ()
- if hpmod.startswith ("hp_"):
- hpmod = hpmod[3:]
- if hpmod != mod: continue
- matchfound = 1
- if matchfound == 1: break
- if matchfound == 1:
- device.uri = "delete"
- if device.type == "hal":
- # Remove HAL USB URIs, for these printers there are already
- # USB URIs
- if device.uri.startswith("hal:///org/freedesktop/Hal/devices/usb_device"):
- device.uri = "delete"
- if device.type == "socket":
- # Remove default port to more easily find duplicate URIs
- device.uri = device.uri.replace (":9100", "")
- try:
- ## XXX This needs to be moved to *after* the device is
- # selected. Looping through all the network printers like
- # this is far too slow.
- if False and device.type in ("socket", "lpd", "ipp", "bluetooth"):
- host = self.getNetworkPrinterMakeModel(device)
- faxuri = None
- if host:
- faxuri = self.get_hplip_uri_for_network_printer(host,
- "fax")
- if faxuri:
- self.devices.append(cupshelpers.Device(faxuri,
- **{'device-class' : "direct",
- 'device-info' : device.info + " HP Fax HPLIP",
- 'device-device-make-and-model' : "HP Fax",
- 'device-id' : "MFG:HP;MDL:Fax;DES:HP Fax;"}))
- if device.uri.startswith ("hp:"):
- device.type = "hp"
- device.info += (" HPLIP")
- except:
- nonfatalException ()
- # Mark duplicate URIs for deletion
- for i in range (len (self.devices)):
- for j in range (len (self.devices)):
- if i == j: continue
- device1 = self.devices[i]
- device2 = self.devices[j]
- if device1.uri == "delete" or device2.uri == "delete":
- continue
- if device1.uri == device2.uri:
- # Keep the one with the longer (better) device ID
- if (not device1.id):
- device1.uri = "delete"
- elif (not device2.id):
- device2.uri = "delete"
- elif (len (device1.id) < len (device2.id)):
- device1.uri = "delete"
- else:
- device2.uri = "delete"
- self.devices = filter(lambda x: x.uri not in ("hp:/no_device_found",
- "hpfax:/no_device_found",
- "hp", "hpfax",
- "hal", "beh",
- "scsi", "http", "delete"),
- self.devices)
- self.devices.sort()
-
- self.devices.append(cupshelpers.Device('',
- **{'device-info' :_("Other")}))
- if current_uri:
- current.info += _(" (Current)")
- self.devices.insert(0, current)
- self.device = current
- self.tvNPDevices.clear()
-
- for device in self.devices:
- self.tvNPDevices.addItem(device.info)
-
- #self.tvNPDevices.get_selection().select_path(0)
- self.tvNPDevices.setCurrentRow(0)
- self.on_tvNPDevices_cursor_changed()
-
- def on_entNPTDevice_changed(self, entry):
- self.setNPButtons()
-
- #TODO
- ## SMB browsing
- def on_entSMBURI_changed (self, text):
- uri = unicode(text)
- (group, host, share, user, password) = SMBURI (uri=uri).separate ()
- if user:
- self.entSMBUsername.setText(user)
- if password:
- self.entSMBPassword.setText(password)
- if user or password:
- uri = SMBURI (group=group, host=host, share=share).get_uri ()
- self.entSMBURI.setText(uri)
- self.rbtnSMBAuthSet.setChecked(True)
- elif unicode(self.entSMBUsername.text()) == '':
- self.rbtnSMBAuthPrompt.setChecked(True)
-
- self.btnSMBVerify.setEnabled(bool(uri))
-
- def on_rbtnSMBAuthSet_toggled(self, ticked):
- self.tblSMBAuth.setEnabled(ticked)
-
- def on_entNPTIPPHostname_textChanged(self):
- valid = len (self.entNPTIPPHostname.text ()) > 0
- self.btnIPPFindQueue.setEnabled(valid)
- self.update_IPP_URI_label ()
-
- ### IPP Browsing
- def update_IPP_URI_label(self):
- hostname = unicode(self.entNPTIPPHostname.text())
- queue = unicode(self.entNPTIPPQueuename.text())
- valid = len (hostname) > 0 and queue != '/printers/'
-
- if valid:
- uri = "ipp://%s%s" % (hostname, queue)
- self.lblIPPURI.setText(uri)
- self.lblIPPURI.show ()
- self.entNPTIPPQueuename.show ()
- else:
- self.lblIPPURI.hide ()
-
- self.btnIPPVerify.setEnabled(valid)
- self.setNPButtons ()
-
- #FIXME this seems totally different from the Gnome one
- @pyqtSignature("")
- def on_btnIPPFindQueue_clicked(self):
- self.IPPBrowseBox.clear()
- host = str(self.entNPTIPPHostname.text())
- cups.setServer (host)
- printers = classes = {}
- try:
- c = cups.Connection()
- printers = c.getPrinters ()
- classes = c.getClasses ()
- del c
- except RuntimeError:
- pass
- except cups.IPP_Error, (e, msg):
- pass
-
- for printer, dict in printers.iteritems ():
-
- self.IPPBrowseBox.addItem(printer)
- # store.set_value (iter, 0, printer)
- # store.set_value (iter, 1, dict.get ('printer-location', ''))
- # store.set_value (iter, 2, dict)
- for pclass, dict in classes.iteritems ():
- pass
- # iter = store.append (None)
- # store.set_value (iter, 0, pclass)
- # store.set_value (iter, 1, dict.get ('printer-location', ''))
- # store.set_value (iter, 2, dict)
-
- if len (printers) + len (classes) == 0:
- # Display 'No queues' dialog
- QMessageBox.information(self, _("No queues"),_("There are no queues available."))
-
- def on_tvNPDevices_cursor_changed(self):
- device = self.devices[self.tvNPDevices.currentRow()]
- self.device = device
- self.lblNPDeviceDescription.setText('')
- page = self.new_printer_device_tabs.get(device.type, 1)
- self.ntbkNPType.setCurrentIndex(page)
-
- type = device.type
- url = device.uri.split(":", 1)[-1]
- if page == 0:
- # This is the "no options" page, with just a label to describe
- # the selected device.
- if device.type == "parallel":
- text = _("A printer connected to the parallel port.")
- elif device.type == "usb":
- text = _("A printer connected to a USB port.")
- elif device.type == "hp":
- text = _("HPLIP software driving a printer, "
- "or the printer function of a multi-function device.")
- elif device.type == "hpfax":
- text = _("HPLIP software driving a fax machine, "
- "or the fax function of a multi-function device.")
- elif device.type == "hal":
- text = _("Local printer detected by the "
- "Hardware Abstraction Layer (HAL).")
- else:
- text = device.uri
-
- self.lblNPDeviceDescription.setText(text)
- elif device.type=="socket":
- if device.uri.startswith ("socket"):
- host = device.uri[9:]
- i = host.find (":")
- if i != -1:
- port = int (host[i + 1:])
- host = host[:i]
- else:
- port = 9100
-
- self.entNPTDirectJetHostname.setText(host)
- self.entNPTDirectJetPort.setText(str (port))
- elif 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"):
- if (device.uri.startswith ("ipp:") or
- device.uri.startswith ("http:")):
- match = re.match ("(ipp|https?)://([^/]+)(.*)", device.uri)
- if match:
- server = match.group (2)
- printer = match.group (3)
- else:
- server = ""
- printer = ""
-
- self.entNPTIPPHostname.setText(server)
- self.entNPTIPPQueuename.setText(printer)
- self.lblIPPURI.setText(device.uri)
- self.lblIPPURI.show()
- self.entNPTIPPQueuename.show()
- else:
- self.entNPTIPPHostname.setText('')
- self.entNPTIPPQueuename.setText('/printers/')
- self.entNPTIPPQueuename.show()
- self.lblIPPURI.hide()
- elif device.type=="lpd":
- if device.uri.startswith ("lpd"):
- host = device.uri[6:]
- i = host.find ("/")
- if i != -1:
- printer = host[i + 1:]
- host = host[:i]
- else:
- printer = ""
- self.cmbentNPTLpdHost.addItem(host)
- self.cmbentNPTLpdQueue.addItem(printer)
- elif device.uri == "lpd":
- pass
- elif device.uri == "smb":
- self.entSMBURI.setText('')
- self.btnSMBVerify.setEnabled(False)
- elif device.type == "smb":
- self.entSMBUsername.setText('')
- self.entSMBPassword.setText('')
- self.entSMBURI.set_text(device.uri[6:])
- self.btnSMBVerify.setEnabled(True)
- else:
- self.entNPTDevice.setText(device.uri)
-
- self.setNPButtons()
-
- def getDeviceURI(self):
- type = self.device.type
- if type == "socket": # DirectJet
- host = unicode(self.entNPTDirectJetHostname.text())
- port = unicode(self.entNPTDirectJetPort.text())
- device = "socket://" + host
- if port:
- device = device + ':' + port
- elif type in ("http", "ipp"): # IPP
- if self.lblIPPURI.isVisible:
- device = unicode(self.lblIPPURI.text())
- else:
- device = "ipp"
- elif type == "lpd": # LPD
- host = unicode(self.cmbentNPTLpdHost.currentText())
- printer = unicode(self.cmbentNPTLpdQueue.currentText())
- 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 = unicode(self.entSMBURI.text())
- (group, host, share, u, p) = SMBURI (uri=uri).separate ()
- user = ''
- password = ''
- if self.rbtnSMBAuthSet.isChecked():
- user = unicode(self.entSMBUsername.text())
- password = unicode(self.entSMBPassword.text())
- uri = SMBURI (group=group, host=host, share=share,
- user=user, password=password).get_uri ()
- device = "smb://" + uri
- elif not self.device.is_class:
- device = self.device.uri
- else:
- device = str(self.entNPTDevice.text())
- return device
- # class/printer
-
- if nr == self.ntbkNewPrinterPages["device"]: # Device
- valid = False
- try:
- uri = self.getDeviceURI ()
- valid = validDeviceURI (uri)
- except:
- debugprint("exception in getDeviceURI()")
- pass
- self.btnNPForward.setEnabled(valid)
- self.btnNPBack.hide ()
- else:
- self.btnNPBack.show()
-
- self.btnNPForward.show()
- self.btnNPApply.hide()
-
- if nr == self.ntbkNewPrinterPages["name"]: # Name
- self.btnNPBack.show()
- if self.dialog_mode == "printer":
- self.btnNPForward.hide()
- self.btnNPApply.show()
- self.btnNPApply.setEnabled(
- self.mainapp.checkNPName(self.entNPName.getText()))
- if nr == self.ntbkNewPrinterPages["make"]: # Make/PPD file
- downloadable_selected = False
- if self.rbtnNPDownloadableDriverSearch.get_active ():
- combobox = self.cmbNPDownloadableDriverFoundPrinters
- iter = combobox.get_active_iter ()
- if iter and combobox.get_model ().get_value (iter, 1):
- downloadable_selected = True
-
- self.btnNPForward.setEnabled(bool(
- self.rbtnNPFoomatic.get_active() or
- self.filechooserPPD.get_filename() or
- downloadable_selected))
- if nr == self.ntbkNewPrinterPages["model"]: # Model/Driver
- model, iter = self.tvNPDrivers.get_selection().get_selected()
- self.btnNPForward.set_sensitive(bool(iter))
- if nr == self.ntbkNewPrinterPages["class-members"]: # Class Members
- self.btnNPForward.hide()
- self.btnNPApply.show()
- self.btnNPApply.setEnabled(
- bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers)))
- if nr == self.ntbkNewPrinterPages["downloadable"]: # Downloadable drivers
- if self.ntbkNPDownloadableDriverProperties.get_current_page() == 1:
- accepted = self.rbtnNPDownloadLicenseYes.get_active ()
- else:
- accepted = True
-
- self.btnNPForward.set_sensitive(accepted)
-
- # PPD
-
- def on_rbtnNPFoomatic_toggled(self):
- rbtn1 = self.rbtnNPFoomatic.isChecked()
- rbtn2 = self.rbtnNPPPD.isChecked()
- rbtn3 = self.rbtnNPDownloadableDriverSearch.isChecked()
- self.tvNPMakes.setEnabled(rbtn1)
- self.filechooserPPD.setEnabled(rbtn2)
-
- """FIXME
- if not rbtn3 and self.openprinting_query_handle:
- # Need to cancel a search in progress.
- self.openprinting.cancelOperation (self.openprinting_query_handle)
- self.openprinting_query_handle = None
- self.btnNPDownloadableDriverSearch_label.setText(_("Search"))
- # Clear printer list.
- self.cmbNPDownloadableDriverFoundPrinters.clear()
- """
-
- for widget in [self.entNPDownloadableDriverSearch,
- self.cmbNPDownloadableDriverFoundPrinters]:
- widget.setEnabled(rbtn3)
- self.btnNPDownloadableDriverSearch.\
- setEnabled(rbtn3 and (self.openprinting_query_handle == None))
-
- self.setNPButtons()
-
- # PPD from foomatic
-
- def fillMakeList(self):
- makes = self.ppds.getMakes()
- self.tvNPMakes.clear()
- found = False
- index = 0
- for make in makes:
- self.tvNPMakes.addItem(make)
- index = index + 1
- if make==self.auto_make:
- self.tvNPMakes.setCurrentRow(index-1)
- found = True
-
- self.on_tvNPMakes_cursor_changed()
-
- def on_tvNPMakes_cursor_changed(self):
- items = self.tvNPMakes.selectedItems()
- if len(items) > 0:
- self.NPMake = unicode(items[0].text())
- self.fillModelList()
-
- def fillModelList(self):
- models = self.ppds.getModels(self.NPMake)
- self.tvNPModels.clear()
- selected = False
- index = 0
- selected = False
- for pmodel in models:
- self.tvNPModels.addItem(pmodel)
- if self.NPMake==self.auto_make and pmodel==self.auto_model:
- self.tvNPModels.setCurrentRow(index)
- selected = True
- index = index + 1
- if not selected:
- self.tvNPModels.setCurrentRow(0)
- ##self.tvNPModels.columns_autosize()
- self.on_tvNPModels_cursor_changed()
-
- def fillDriverList(self, pmake, pmodel):
- self.NPModel = pmodel
- self.tvNPDrivers.clear()
-
- ppds = self.ppds.getInfoFromModel(pmake, pmodel)
-
- self.NPDrivers = self.ppds.orderPPDNamesByPreference(ppds.keys())
- for i in range (len(self.NPDrivers)):
- ppd = ppds[self.NPDrivers[i]]
- driver = ppd["ppd-make-and-model"]
- driver = driver.replace(" (recommended)", "")
-
- try:
- lpostfix = " [%s]" % ppd["ppd-natural-language"]
- driver += lpostfix
- except KeyError:
- pass
-
- if i == 0:
- self.tvNPDrivers.addItem(driver + _(" (recommended)"))
- self.tvNPDrivers.setCurrentRow(0)
- else:
- self.tvNPDrivers.addItem(driver)
- ##self.tvNPDrivers.columns_autosize()
-
- def on_tvNPModels_cursor_changed(self):
- items = self.tvNPModels.selectedItems()
- if len(items) > 0:
- pmodel = unicode(items[0].text())
- self.fillDriverList(self.NPMake, pmodel)
-
- def getNPPPD(self):
- try:
- if self.rbtnNPFoomatic.isChecked():
- #items = self.tvNPDrivers.selectedItems()
- #nr = unicode(items[0])
- nr = self.tvNPDrivers.currentRow()
- ppd = self.NPDrivers[nr]
- elif self.rbtnNPPPD.isChecked():
- ppd = cups.PPD(unicode(self.filechooserPPD.getText()))
- else:
- """FIXME
- # PPD of the driver downloaded from OpenPrinting XXX
- treeview = self.tvNPDownloadableDrivers
- model, iter = treeview.get_selection ().get_selected ()
- driver = model.get_value (iter, 1)
- if driver.has_key ('ppds'):
- # Only need to download a PPD.
- file_to_download = driver
- """
-
- ppd = "XXX"
-
- except RuntimeError, e:
- if self.rbtnNPFoomatic.isChecked():
- # Foomatic database problem of some sort.
- err_title = _('Database error')
- err_text = _("The '%s' driver cannot be "
- "used with printer '%s %s'.")
- 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.
- err = _("You will need to install the '%s' package "
- "in order to use this driver.") % \
- "gutenprint-foomatic"
- else:
- err = err_text % (driver, self.NPMake, self.NPModel)
- elif self.rbtnNPPPD.isChecked():
- # This error came from trying to open the PPD file.
- err_title = _('PPD error')
- filename = self.filechooserPPD.get_filename()
- err = _('Failed to read PPD file. Possible reason '
- 'follows:') + '\n'
- os.environ["PPD"] = filename
- # We want this to be in the current natural language,
- # so we intentionally don't set LC_ALL=C here.
- p = os.popen ('/usr/bin/cupstestppd -rvv "$PPD"', 'r')
- output = p.readlines ()
- p.close ()
- err += reduce (lambda x, y: x + y, output)
- else:
- # Failed to get PPD downloaded from OpenPrinting XXX
- err_title = _('Downloadable drivers')
- err_text = _("Support for downloadable "
- "drivers is not yet completed.")
-
- error_text = ('<span weight="bold" size="larger">' +
- err_title + '</span>\n\n' + err)
- QMessageBox.critical(self, err_title, error_text)
- return None
-
- if isinstance(ppd, str) or isinstance(ppd, unicode):
- try:
- if (ppd != "raw"):
- f = self.mainapp.cups.getServerPPD(ppd)
- ppd = cups.PPD(f)
- os.unlink(f)
- except AttributeError:
- nonfatalException()
- debugprint ("pycups function getServerPPD not available: never mind")
- except RuntimeError:
- nonfatalException()
- debugprint ("libcups from CUPS 1.3 not available: never mind")
- except cups.IPPError:
- nonfatalException()
- debugprint ("CUPS 1.3 server not available: never mind")
-
- return ppd
-
- # Create new Printer
- @pyqtSignature("")
- def on_btnNPApply_clicked(self):
- if self.dialog_mode in ("class", "printer"):
- name = unicode(self.entNPName.text())
- location = unicode(self.entNPLocation.text())
- info = unicode(self.entNPDescription.text())
- else:
- name = self.mainapp.printer.name
-
- # Whether to check for missing drivers.
- check = False
- checkppd = None
- ppd = self.ppd
-
- if self.dialog_mode=="class":
- members = self.mainapp.getCurrentClassMembers(self.tvNCMembers)
- try:
- for member in members:
- self.passwd_retry = False # use cached Passwd
- self.mainapp.cups.addPrinterToClass(str(member), name)
- except cups.IPPError, (e, msg):
- self.show_IPP_Error(e, msg)
- return
- elif self.dialog_mode=="printer":
- self.device.uri = unicode(self.device.uri)
- uri = None
- if self.device.uri:
- uri = self.device.uri
- else:
- uri = self.getDeviceURI()
- if not self.ppd: # XXX needed?
- # Go back to previous page to re-select driver.
- self.nextNPTab(-1)
- return
-
- # write Installable Options to ppd
- for option in self.options.itervalues():
- option.writeback()
-
- #self.busy(self)
- self.WaitWindow.setText('<b>' +
- _('Adding') + '</b><br /><br />' +
- _('Adding printer'))
- #self.WaitWindow.set_transient_for (self.NewPrinterWindow)
- self.WaitWindow.show ()
- QApplication.processEvents()
- try:
- self.passwd_retry = False # use cached Passwd
- if isinstance(ppd, str) or isinstance(ppd, unicode):
- self.mainapp.cups.addPrinter(name, ppdname=ppd,
- device=uri, info=info, location=location)
- check = True
- elif ppd is None: # raw queue
- self.mainapp.cups.addPrinter(name, device=uri,
- info=info, location=location)
- else:
- cupshelpers.setPPDPageSize(ppd, self.language[0])
- self.mainapp.cups.addPrinter(name, ppd=ppd,
- device=uri, info=info, location=location)
- check = True
- checkppd = ppd
- cupshelpers.activateNewPrinter (self.mainapp.cups, name)
- except cups.IPPError, (e, msg):
- #self.ready(self)
- self.WaitWindow.hide ()
- self.show_IPP_Error(e, msg)
- return
- except:
- ##self.ready (self.NewPrinterWindow)
- self.WaitWindow.hide ()
- fatalException (1)
- self.WaitWindow.hide ()
- ##self.ready (self.NewPrinterWindow)
- #comment
- if self.dialog_mode in ("class", "printer"):
- try:
- self.passwd_retry = False # use cached Passwd
- self.mainapp.cups.setPrinterLocation(name, location)
- self.passwd_retry = False # use cached Passwd
- self.mainapp.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.mainapp.cups.addPrinter(name, device=uri)
- except cups.IPPError, (e, msg):
- self.show_IPP_Error(e, msg)
- return
- elif self.dialog_mode == "ppd":
- if not ppd:
- ppd = self.ppd = self.getNPPPD()
- 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.isChecked():
- # 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.mainapp.cups.addPrinter(name, ppdname='raw')
- except cups.IPPError, (e, msg):
- self.show_IPP_Error(e, msg)
- try:
- self.mainapp.cups.addPrinter(name, ppdname=ppd)
- except cups.IPPError, (e, msg):
- self.show_IPP_Error(e, msg)
- return
-
- try:
- filename = self.mainapp.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.isChecked():
- cupshelpers.copyPPDOptions(self.mainapp.ppd, ppd) # XXX
- else:
- # write Installable Options to ppd
- for option in self.options.itervalues():
- option.writeback()
- cupshelpers.setPPDPageSize(ppd, self.language[0])
-
- try:
- self.mainapp.cups.addPrinter(name, ppd=ppd)
- except cups.IPPError, (e, msg):
- self.show_IPP_Error(e, msg)
-
- if not raw:
- check = True
- checkppd = ppd
-
- self.accept()
- self.mainapp.populateList(start_printer=name)
- if check:
- try:
- self.checkDriverExists (name, ppd=checkppd)
- except:
- nonfatalException()
-
- # Also check to see whether the media option has become
- # invalid. This can happen if it had previously been
- # explicitly set to a page size that is not offered with
- # the new PPD (see bug #441836).
- """
- try:
- option = self.mainapp.server_side_options['media']
- if option.get_current_value () == None:
- debugprint ("Invalid media option: resetting")
- option.reset ()
- self.mainapp.changed.add (option)
- self.mainapp.save_printer (self.mainapp.printer)
- except KeyError:
- pass
- except:
- print "exception in check to see whether the media option has become invalid"
- nonfatalException()
- """
-
- 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.mainapp.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)
-
- (pkgs, exes) = cupshelpers.missingPackagesAndExecutables (ppd)
- if len (pkgs) > 0 or len (exes) > 0:
- # We didn't find a necessary executable. Complain.
- install = "/usr/bin/system-install-packages"
- if len (pkgs) > 0 and os.access (install, os.X_OK):
- pkg = pkgs[0]
- install_text = ('<span weight="bold" size="larger">' +
- _('Install driver') + '</span>\n\n' +
- _("Printer '%s' requires the %s package but "
- "it is not currently installed.") %
- (name, pkg))
- dialog = self.InstallDialog
- self.lblInstall.set_markup(install_text)
- 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, (exes + pkgs)[0]))
- QMessageBox.error(self, "", error_text)
-
- """
- if pkg and response == gtk.RESPONSE_OK:
- # Install the package.
- def wait_child (sig, stack):
- (pid, status) = os.wait ()
-
- signal.signal (signal.SIGCHLD, wait_child)
- pid = os.fork ()
- if pid == 0:
- # Child.
- try:
- os.execv (install, [install, pkg])
- except:
- pass
- sys.exit (1)
- elif pid == -1:
- pass # should handle error
- """
-
- #FIXME obsolete?
- def on_entNPTIPPQueuename_textChanged(self, ent):
- self.update_IPP_URI_label ()
-
- #FIXME obsolete?
- def on_IPPBrowseBox_currentTextChanged(self, text):
- self.update_IPP_URI_label()
-
- #FIXME not in gnome?
- @pyqtSignature("")
- def on_btnNPCancel_clicked(self):
- self.hide()
- #end of class NewPrinterGUI
-
- if __name__ == "__main__":
- """start the application. TODO, gtk frontend does clever things here to not start the GUI until it has to"""
- app = QApplication(sys.argv)
- applet = GUI()
- sys.exit(app.exec_())
-