summaryrefslogtreecommitdiff
path: root/ui/devmgr4.py
diff options
context:
space:
mode:
authorJinkun Jang <jinkun.jang@samsung.com>2013-03-13 01:42:35 +0900
committerJinkun Jang <jinkun.jang@samsung.com>2013-03-13 01:42:35 +0900
commit72835b3d805ac6c7cdaac7d3aff107567e938314 (patch)
tree0f2a04dc3d0672c0960a62804c6e7758673e393c /ui/devmgr4.py
parenteb5e5ee9adb02776056d1b4494f66150a2fc45f1 (diff)
downloadhplip-72835b3d805ac6c7cdaac7d3aff107567e938314.tar.gz
hplip-72835b3d805ac6c7cdaac7d3aff107567e938314.tar.bz2
hplip-72835b3d805ac6c7cdaac7d3aff107567e938314.zip
Tizen 2.1 base
Diffstat (limited to 'ui/devmgr4.py')
-rw-r--r--ui/devmgr4.py3258
1 files changed, 3258 insertions, 0 deletions
diff --git a/ui/devmgr4.py b/ui/devmgr4.py
new file mode 100644
index 0000000..8a33558
--- /dev/null
+++ b/ui/devmgr4.py
@@ -0,0 +1,3258 @@
+# -*- coding: utf-8 -*-
+#
+# (c) Copyright 2001-2009 Hewlett-Packard Development Company, L.P.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Authors: Don Welch, Pete Parks, Naga Samrat Chowdary Narla,
+#
+
+from __future__ import generators
+
+# Std Lib
+import sys
+import time
+import os
+import gzip
+import select
+import struct
+import threading
+import Queue
+
+# Local
+from base.g import *
+from base import device, utils, pml, maint, pkit
+from prnt import cups
+from base.codes import *
+from ui_utils import load_pixmap
+from installer.core_install import *
+
+# Qt
+from qt import *
+
+# Main form
+from devmgr4_base import DevMgr4_base
+
+# Scrollviews
+from scrollview import ScrollView
+from scrollprintsettings import ScrollPrintSettingsView
+
+# Alignment and ColorCal forms
+from alignform import AlignForm
+from aligntype6form1 import AlignType6Form1
+from aligntype6form2 import AlignType6Form2
+from paperedgealignform import PaperEdgeAlignForm
+from colorcalform import ColorCalForm # Type 1 color cal
+from coloradjform import ColorAdjForm # Type 5 and 6 color adj
+from colorcalform2 import ColorCalForm2 # Type 2 color cal
+from colorcal4form import ColorCal4Form # Type 4 color cal
+from align10form import Align10Form # Type 10 and 11 alignment
+from align13form import Align13Form # Type 13 alignment
+
+# Misc forms
+from loadpaperform import LoadPaperForm
+from settingsdialog import SettingsDialog
+from aboutdlg import AboutDlg
+from cleaningform import CleaningForm
+from cleaningform2 import CleaningForm2
+from waitform import WaitForm
+from faxsettingsform import FaxSettingsForm
+from nodevicesform import NoDevicesForm
+from settingsdialog import SettingsDialog
+from firmwaredialog import FirmwareDialog
+
+# all in seconds
+MIN_AUTO_REFRESH_RATE = 5
+MAX_AUTO_REFRESH_RATE = 60
+DEF_AUTO_REFRESH_RATE = 30
+
+
+devices = {} # { Device_URI : device.Device(), ... }
+devices_lock = threading.RLock()
+
+RESPONSE_START = 1
+RESPONSE_DONE = 2
+
+# ***********************************************************************************
+#
+# LISTVIEW/UTILITY UI CLASSES
+#
+# ***********************************************************************************
+
+class IconViewToolTip(QToolTip):
+ def __init__(self, parent, tooltip_text):
+ QToolTip.__init__(self, parent.viewport())
+ self.parent = parent
+
+
+ def maybeTip(self, pos):
+ abs_coords = QPoint(pos.x() + self.parent.contentsX(),
+ pos.y() + self.parent.contentsY())
+
+ item = self.parent.findItem(abs_coords)
+
+ if item is not None and item.tooltip_text:
+ rel_coords = QRect()
+ rel_coords.setX(pos.x())
+ rel_coords.setY(pos.y())
+ i = item.rect()
+ rel_coords.setWidth(i.width())
+ rel_coords.setHeight(i.height())
+ self.tip(rel_coords, item.tooltip_text)
+
+
+
+class FuncViewItem(QIconViewItem):
+ def __init__(self, parent, text, pixmap, tooltip_text, cmd):
+ QIconViewItem.__init__(self, parent, text, pixmap)
+ self.tooltip_text = tooltip_text
+ self.cmd = cmd
+
+ self.tooltip = IconViewToolTip(parent, tooltip_text)
+
+
+
+class DeviceViewItem(QIconViewItem):
+ def __init__(self, parent, text, pixmap, device_uri, is_avail=True):
+ QIconViewItem.__init__(self, parent, text, pixmap)
+ self.device_uri = device_uri
+ self.is_avail = is_avail
+
+
+
+class SuppliesListViewItem(QListViewItem):
+ def __init__(self, parent, pixmap, desc, part_no, level_pixmap, status):
+ QListViewItem.__init__(self, parent, '', desc, part_no, '', status)
+ if pixmap is not None:
+ self.setPixmap(0, pixmap)
+ if level_pixmap is not None:
+ self.setPixmap(3, level_pixmap)
+
+ def paintCell(self, p, cg, c, w, a):
+ color = QColorGroup(cg)
+ pos = self.listView().itemPos(self)
+ h = self.totalHeight()
+
+ if (pos/h) % 2:
+ color.setColor(QColorGroup.Base, QColor(220, 228, 249))
+
+ QListViewItem.paintCell(self, p, color, c, w, a)
+
+
+
+class PasswordDialog(QDialog):
+ def __init__(self,prompt, parent=None, name=None, modal=0, fl=0):
+ QDialog.__init__(self,parent,name,modal,fl)
+ self.prompt = prompt
+
+ if not name:
+ self.setName("PasswordDialog")
+
+ passwordDlg_baseLayout = QGridLayout(self,1,1,11,6,"passwordDlg_baseLayout")
+
+ self.promptTextLabel = QLabel(self,"promptTextLabel")
+ passwordDlg_baseLayout.addMultiCellWidget(self.promptTextLabel,0,0,0,1)
+
+ self.usernameTextLabel = QLabel(self,"usernameTextLabel")
+ passwordDlg_baseLayout.addMultiCellWidget(self.usernameTextLabel,1,1,0,1)
+
+ self.usernameLineEdit = QLineEdit(self,"usernameLineEdit")
+ self.usernameLineEdit.setEchoMode(QLineEdit.Normal)
+ passwordDlg_baseLayout.addMultiCellWidget(self.usernameLineEdit,1,1,1,2)
+
+ self.passwordTextLabel = QLabel(self,"passwordTextLabel")
+ passwordDlg_baseLayout.addMultiCellWidget(self.passwordTextLabel,2,2,0,1)
+
+ self.passwordLineEdit = QLineEdit(self,"passwordLineEdit")
+ self.passwordLineEdit.setEchoMode(QLineEdit.Password)
+ passwordDlg_baseLayout.addMultiCellWidget(self.passwordLineEdit,2,2,1,2)
+
+ self.okPushButton = QPushButton(self,"okPushButton")
+ passwordDlg_baseLayout.addWidget(self.okPushButton,3,2)
+
+ self.languageChange()
+
+ self.resize(QSize(420,163).expandedTo(self.minimumSizeHint()))
+ self.clearWState(Qt.WState_Polished)
+
+ self.connect(self.okPushButton,SIGNAL("clicked()"),self.accept)
+ self.connect(self.passwordLineEdit,SIGNAL("returnPressed()"),self.accept)
+ def getUsername(self):
+ return unicode(self.usernameLineEdit.text())
+
+ def getPassword(self):
+ return unicode(self.passwordLineEdit.text())
+
+ def languageChange(self):
+ self.setCaption(self.__tr("HP Device Manager - Enter Username/Password"))
+ self.promptTextLabel.setText(self.__tr(self.prompt))
+ self.usernameTextLabel.setText(self.__tr("Username"))
+ self.passwordTextLabel.setText(self.__tr("Password"))
+ self.okPushButton.setText(self.__tr("OK"))
+
+ def __tr(self,s,c = None):
+ return qApp.translate("PasswordDialog",s,c)
+
+
+
+class ScrollDialog(QDialog):
+ def __init__(self, scrollview_cls, cur_device, cur_printer, service,
+ parent = None, name=None, modal=0, fl=0):
+
+ QDialog.__init__(self,parent,name,modal,fl)
+
+ if not name:
+ self.setName("ScrollDialog")
+
+ self.setSizeGripEnabled(1)
+ ScrollDialogLayout = QGridLayout(self,1,1,11,6,"ScrollDialogLayout")
+ Layout1 = QHBoxLayout(None,0,6,"Layout1")
+ Horizontal_Spacing2 = QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
+ Layout1.addItem(Horizontal_Spacing2)
+ self.buttonOk = QPushButton(self,"buttonOk")
+ self.buttonOk.setAutoDefault(1)
+ self.buttonOk.setDefault(1)
+ Layout1.addWidget(self.buttonOk)
+ ScrollDialogLayout.addLayout(Layout1,1,0)
+
+ self.scrollview = scrollview_cls(service, self)
+ ScrollDialogLayout.addWidget(self.scrollview,0,0)
+
+ self.scrollview.onDeviceChange(cur_device)
+ self.scrollview.onPrinterChange(cur_printer)
+ self.languageChange()
+
+ self.resize(QSize(520,457).expandedTo(self.minimumSizeHint()))
+ self.clearWState(Qt.WState_Polished)
+ self.connect(self.buttonOk,SIGNAL("clicked()"),self.accept)
+
+
+ def languageChange(self):
+ self.setCaption(self.__tr("HP Device Manager"))
+ self.buttonOk.setText(self.__tr("Close"))
+ self.buttonOk.setAccel(QKeySequence(QString.null))
+
+ def __tr(self,s,c = None):
+ return qApp.translate("ScrollDialog",s,c)
+
+
+def showPasswordUI(prompt):
+ try:
+ dlg = PasswordDialog(prompt, None)
+
+ if dlg.exec_loop() == QDialog.Accepted:
+ return (dlg.getUsername(), dlg.getPassword())
+
+ finally:
+ pass
+
+ return ("", "")
+
+
+class StatusListViewItem(QListViewItem):
+ def __init__(self, parent, pixmap, ess, tt, event_code, job_id, username):
+ QListViewItem.__init__(self, parent, '', ess, tt, event_code, job_id, username)
+ self.setPixmap(0, pixmap)
+
+ def paintCell(self, p, cg, c, w, a):
+ color = QColorGroup(cg)
+ pos = self.listView().itemPos(self)
+ h = self.totalHeight()
+ row = pos/2
+
+ if row % 2:
+ color.setColor(QColorGroup.Base, QColor(220, 228, 249))
+
+ QListViewItem.paintCell(self, p, color, c, w, a)
+
+
+
+class JobListViewItem(QCheckListItem):
+ def __init__(self, parent, pixmap, desc, status, job_id):
+ QCheckListItem.__init__(self, parent, '', QCheckListItem.CheckBox)
+ self.job_id = job_id
+ self.setPixmap(1, pixmap)
+ self.setText(2, desc)
+ self.setText(3, status)
+ self.setText(4, job_id)
+
+ def paintCell(self, p, cg, c, w, a):
+ color = QColorGroup(cg)
+ pos = self.listView().itemPos(self)
+ h = self.totalHeight()
+
+ if (pos/h) % 2:
+ color.setColor(QColorGroup.Base, QColor(220, 228, 249))
+
+ QCheckListItem.paintCell(self, p, color, c, w, a)
+
+
+
+class JobInfoDialog(QDialog):
+ def __init__(self, text, parent=None, name=None, modal=0, fl=0):
+ QDialog.__init__(self, parent, name, modal, fl)
+
+ if not name:
+ self.setName("JobInfoDialog")
+
+ Form1Layout = QGridLayout(self,1,1,11,6,"Form1Layout")
+ spacer6 = QSpacerItem(371,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
+ Form1Layout.addItem(spacer6,1,0)
+ self.pushButton4 = QPushButton(self,"pushButton4")
+ Form1Layout.addWidget(self.pushButton4,1,1)
+ self.textEdit = QTextEdit(self,"textEdit")
+ Form1Layout.addMultiCellWidget(self.textEdit,0,0,0,1)
+
+ self.languageChange()
+
+ self.resize(QSize(571,542).expandedTo(self.minimumSizeHint()))
+ self.clearWState(Qt.WState_Polished)
+
+ self.connect(self.pushButton4,SIGNAL("clicked()"),self.close)
+
+ self.textEdit.setText(text)
+
+
+ def languageChange(self):
+ self.setCaption(self.__tr("HP Device Manager - Job Log"))
+ self.pushButton4.setText(self.__tr("Close"))
+
+
+ def __tr(self,s,c = None):
+ return qApp.translate("JobInfoDialog",s,c)
+
+
+# ***********************************************************************************
+#
+# DEVICE UPDATE THREAD
+#
+# ***********************************************************************************
+
+
+class UpdateThread(QThread):
+ def __init__(self, response_queue=None, request_queue=None):
+ self.response_queue = response_queue # update queue -> main window
+ self.request_queue = request_queue # main window -> update queue
+
+ QThread.__init__(self)
+
+ def run(self):
+ while True:
+ dev = self.request_queue.get(True)
+
+ if dev is None:
+ log.debug("Update thread: exit")
+ break
+
+ log.debug("Update thread start: %s" % dev.device_uri)
+
+ try:
+ #print "THREAD LOCK ACQUIRE"
+ devices_lock.acquire()
+ #print "THREAD LOCK ACQUIRE - OK"
+ self.response_queue.put((RESPONSE_START, dev.device_uri))
+ log.debug(log.bold("Update: %s %s %s" % ("*"*20, dev.device_uri, "*"*20)))
+
+ if dev.supported:
+ try:
+ dev.open()
+ except Error, e:
+ log.warn(e.msg)
+
+ time.sleep(0.1)
+
+ if dev.device_state == DEVICE_STATE_NOT_FOUND:
+ dev.error_state = ERROR_STATE_ERROR
+ else:
+ try:
+ dev.queryDevice()
+
+ except Error, e:
+ log.error("Query device error (%s)." % e.msg)
+ dev.error_state = ERROR_STATE_ERROR
+
+ finally:
+ dev.close()
+ #print "THREAD LOCK RELEASE"
+ devices_lock.release()
+
+ log.debug("Device state = %d" % dev.device_state)
+ log.debug("Status code = %d" % dev.status_code)
+ log.debug("Error state = %d" % dev.error_state)
+
+ log.debug("Update thread end: %s" % dev.device_uri)
+
+ self.response_queue.put((RESPONSE_DONE, dev.device_uri))
+
+
+# ***********************************************************************************
+#
+# MAINWINDOW
+#
+# ***********************************************************************************
+
+class DevMgr4(DevMgr4_base):
+ def __init__(self, read_pipe=None, toolbox_version='0.0',
+ initial_device_uri=None, disable_dbus=False,
+ parent=None, name=None, fl = 0):
+
+
+ # Distro insformation
+ core = CoreInstall(MODE_CHECK)
+# core.init()
+ self.Is_autoInstaller_distro = core.is_auto_installer_support()
+ self.Latest_ver= user_conf.get('upgrade', 'latest_available_version')
+ installed_version=sys_conf.get('hplip','version')
+ if utils.Is_HPLIP_older_version(installed_version, self.Latest_ver):
+ DevMgr4_base.__init__(self, parent, name, fl,self.Latest_ver,self.Is_autoInstaller_distro)
+ else:
+ self.Latest_ver = ""
+ DevMgr4_base.__init__(self, parent, name, fl,self.Latest_ver,self.Is_autoInstaller_distro)
+ log.debug("Initializing toolbox UI (Qt3)...")
+ log.debug("HPLIP Version: %s" % prop.installed_version)
+
+ self.disable_dbus = disable_dbus
+ self.toolbox_version = toolbox_version
+ self.cur_device_uri = user_conf.get('last_used', 'device_uri')
+ self.device_vars = {}
+ self.num_devices = 0
+ self.cur_device = None
+ self.rescanning = False
+ self.initial_device_uri = initial_device_uri
+
+ # dbus setup
+ if not self.disable_dbus:
+ self.dbus_avail, self.service, session_bus = device.init_dbus()
+
+ if not self.dbus_avail:
+ self.FailureUI("<b>Error</b><p>hp-systray must be running to get device status. hp-systray requires dbus support. Device status will not be available.")
+ else:
+ log.debug("dbus enabled")
+
+ else:
+ log.debug("dbus disabled")
+ self.dbus_avail, self.service = False, None
+
+
+ # Update thread setup
+ self.request_queue = Queue.Queue()
+ self.response_queue = Queue.Queue()
+ self.update_thread = UpdateThread(self.response_queue, self.request_queue)
+ self.update_thread.start()
+
+ # Pipe from toolbox/dbus setup
+ self.fmt = "80s80sI32sI80sf"
+ self.fmt_size = struct.calcsize(self.fmt)
+
+ if read_pipe is not None and not disable_dbus:
+ log.debug("Setting up read_pipe")
+ self.notifier = QSocketNotifier(read_pipe, QSocketNotifier.Read)
+ QObject.connect(self.notifier, SIGNAL("activated(int)"), self.notifier_activated)
+
+ # Application icon
+ self.setIcon(load_pixmap('hp_logo', '128x128'))
+
+ # User settings
+ self.user_settings = utils.UserSettings()
+ self.cmd_fab = self.user_settings.cmd_fab
+ log.debug("FAB command: %s" % self.cmd_fab)
+
+ if not self.user_settings.auto_refresh:
+ self.autoRefresh.toggle()
+
+ # Other initialization
+ self.InitPixmaps()
+ self.InitMisc()
+ self.InitUI()
+
+ cups.setPasswordCallback(showPasswordUI)
+
+ if not prop.doc_build:
+ self.helpContentsAction.setEnabled(False)
+
+ self.allow_auto_refresh = True
+ QTimer.singleShot(0, self.InitialUpdate)
+
+
+ # ***********************************************************************************
+ #
+ # INIT
+ #
+ # ***********************************************************************************
+
+ def InitPixmaps(self):
+ self.func_icons_cached = False
+ self.func_icons = {}
+ self.device_icons = {}
+
+ # TODO: Use Qt pixmap cache for all pixmaps?
+
+ # Device icon list overlays
+ self.warning_pix = load_pixmap('warning', '16x16')
+ self.error_pix = load_pixmap('error', '16x16')
+ self.ok_pix = load_pixmap('ok', '16x16')
+ self.lowink_pix = load_pixmap('inkdrop', '16x16')
+ self.lowtoner_pix = load_pixmap('toner', '16x16')
+ self.busy_pix = load_pixmap('busy', '16x16')
+ self.lowpaper_pix = load_pixmap('paper', '16x16')
+ self.refresh_pix = load_pixmap('refresh', '16x16')
+ self.refresh1_pix = load_pixmap('refresh1', '16x16')
+ self.fax_icon = load_pixmap('fax2', 'other')
+ self.idle_pix = load_pixmap('idle', '16x16')
+ self.scan_pix = load_pixmap("scan", '16x16')
+ self.print_pix = load_pixmap("print", '16x16')
+ self.sendfax_pix =load_pixmap("fax", '16x16')
+ self.pcard_pix = load_pixmap("pcard", '16x16')
+ self.makecopies_pix = load_pixmap("makecopies", '16x16')
+ self.help_pix = load_pixmap("help", '16x16')
+
+
+ # pixmaps: (inkjet, laserjet)
+ self.SMALL_ICONS = { ERROR_STATE_CLEAR : (None, None),
+ ERROR_STATE_BUSY : (self.busy_pix, self.busy_pix),
+ ERROR_STATE_ERROR : (self.error_pix, self.error_pix),
+ ERROR_STATE_LOW_SUPPLIES : (self.lowink_pix, self.lowtoner_pix),
+ ERROR_STATE_OK : (self.ok_pix, self.ok_pix),
+ ERROR_STATE_WARNING : (self.warning_pix, self.warning_pix),
+ ERROR_STATE_LOW_PAPER: (self.lowpaper_pix, self.lowpaper_pix),
+ ERROR_STATE_PRINTING : (self.busy_pix, self.busy_pix),
+ ERROR_STATE_SCANNING : (self.busy_pix, self.busy_pix),
+ ERROR_STATE_PHOTOCARD : (self.busy_pix, self.busy_pix),
+ ERROR_STATE_FAXING : (self.busy_pix, self.busy_pix),
+ ERROR_STATE_COPYING : (self.busy_pix, self.busy_pix),
+ ERROR_STATE_REFRESHING : (self.refresh1_pix, self.refresh1_pix),
+ }
+
+ self.STATUS_ICONS = { ERROR_STATE_CLEAR : (self.idle_pix, self.idle_pix),
+ ERROR_STATE_BUSY : (self.busy_pix, self.busy_pix),
+ ERROR_STATE_ERROR : (self.error_pix, self.error_pix),
+ ERROR_STATE_LOW_SUPPLIES : (self.lowink_pix, self.lowtoner_pix),
+ ERROR_STATE_OK : (self.ok_pix, self.ok_pix),
+ ERROR_STATE_WARNING : (self.warning_pix, self.warning_pix),
+ ERROR_STATE_LOW_PAPER: (self.lowpaper_pix, self.lowpaper_pix),
+ ERROR_STATE_PRINTING : (self.print_pix, self.print_pix),
+ ERROR_STATE_SCANNING : (self.scan_pix, self.scan_pix),
+ ERROR_STATE_PHOTOCARD : (self.pcard_pix, self.print_pix),
+ ERROR_STATE_FAXING : (self.sendfax_pix, self.sendfax_pix),
+ ERROR_STATE_COPYING : (self.makecopies_pix, self.makecopies_pix),
+ }
+
+
+
+ def InitUI(self):
+ # Setup device icon list
+ self.DeviceList.setAutoArrange(True)
+ self.DeviceList.setSorting(True)
+
+ # Setup main menu
+ self.deviceRescanAction.setIconSet(QIconSet(self.refresh1_pix))
+ self.deviceRefreshAll.setIconSet(QIconSet(self.refresh_pix))
+ self.deviceInstallAction.setIconSet(QIconSet(load_pixmap('list_add', '16x16')))
+ self.deviceRemoveAction.setIconSet(QIconSet(load_pixmap('list_remove', '16x16')))
+ self.settingsConfigure.setIconSet(QIconSet(load_pixmap('settings', '16x16')))
+ self.helpContentsAction.setIconSet(QIconSet(self.help_pix))
+
+ # Setup toolbar
+ self.deviceRescanAction.addTo(self.Toolbar)
+ self.deviceRefreshAll.addTo(self.Toolbar)
+ self.Toolbar.addSeparator()
+ self.deviceInstallAction.addTo(self.Toolbar)
+ self.deviceRemoveAction.addTo(self.Toolbar)
+ self.Toolbar.addSeparator()
+ self.settingsConfigure.addTo(self.Toolbar)
+ self.helpContentsAction.addTo(self.Toolbar)
+
+ # Init tabs/controls
+ self.InitFuncsTab()
+ self.InitStatusTab()
+ self.InitSuppliesTab()
+ self.InitPrintSettingsTab()
+ self.InitPrintControlTab()
+
+ # Resize the splitter so that the device list starts as a single column
+ self.splitter2.setSizes([120, 700])
+
+
+
+ def InitMisc(self):
+ self.unit_names = { "year" : (self.__tr("year"), self.__tr("years")),
+ "month" : (self.__tr("month"), self.__tr("months")),
+ "week" : (self.__tr("week"), self.__tr("weeks")),
+ "day" : (self.__tr("day"), self.__tr("days")),
+ "hour" : (self.__tr("hour"), self.__tr("hours")),
+ "minute" : (self.__tr("minute"), self.__tr("minutes")),
+ "second" : (self.__tr("second"), self.__tr("seconds")),
+ }
+
+ self.num_repr = { 1 : self.__tr("one"),
+ 2 : self.__tr("two"),
+ 3 : self.__tr("three"),
+ 4 : self.__tr("four"),
+ 5 : self.__tr("five"),
+ 6 : self.__tr("six"),
+ 7 : self.__tr("seven"),
+ 8 : self.__tr("eight"),
+ 9 : self.__tr("nine"),
+ 10 : self.__tr("ten"),
+ 11 : self.__tr("eleven"),
+ 12 : self.__tr("twelve")
+ }
+
+ if self.Latest_ver is "":
+ self.TabIndex = { self.FunctionsTab: self.UpdateFuncsTab,
+ self.StatusTab: self.UpdateStatusTab,
+ self.SuppliesTab: self.UpdateSuppliesTab,
+ self.PrintSettingsTab: self.UpdatePrintSettingsTab,
+ self.PrintJobsTab: self.UpdatePrintControlTab,
+ }
+ else:
+ self.TabIndex = { self.FunctionsTab: self.UpdateFuncsTab,
+ self.StatusTab: self.UpdateStatusTab,
+ self.SuppliesTab: self.UpdateSuppliesTab,
+ self.PrintSettingsTab: self.UpdatePrintSettingsTab,
+ self.PrintJobsTab: self.UpdatePrintControlTab,
+ self.UpgradeTab:self.UpdateUpgradeTab,
+ }
+
+
+
+ def InitialUpdate(self):
+ self.RescanDevices()
+
+ cont = True
+ if self.initial_device_uri is not None:
+ if not self.ActivateDevice(self.initial_device_uri):
+ log.error("Device %s not found" % self.initial_device_uri)
+ cont = False
+
+ self.refresh_timer = QTimer(self, "RefreshTimer")
+ self.connect(self.refresh_timer, SIGNAL('timeout()'), self.TimedRefresh)
+
+ if MIN_AUTO_REFRESH_RATE <= self.user_settings.auto_refresh_rate <= MAX_AUTO_REFRESH_RATE:
+ self.refresh_timer.start(self.user_settings.auto_refresh_rate * 1000)
+
+ self.update_timer = QTimer(self)
+ self.connect(self.update_timer, SIGNAL("timeout()"), self.ThreadUpdate)
+ self.update_timer.start(500)
+
+
+ def ActivateDevice(self, device_uri):
+ log.debug(log.bold("Activate: %s %s %s" % ("*"*20, device_uri, "*"*20)))
+ d = self.DeviceList.firstItem()
+ found = False
+
+ while d is not None:
+ if d.device_uri == device_uri:
+ found = True
+ self.DeviceList.setSelected(d, True)
+ self.DeviceList.setCurrentItem(d)
+ break
+
+ d = d.nextItem()
+
+ return found
+
+
+
+ # ***********************************************************************************
+ #
+ # UPDATES/NOTIFICATIONS
+ #
+ # ***********************************************************************************
+
+ def notifier_activated(self, sock): # dbus message has arrived
+ m = ''
+ while True:
+ ready = select.select([sock], [], [], 0.1)
+
+ if ready[0]:
+ m = ''.join([m, os.read(sock, self.fmt_size)])
+ if len(m) == self.fmt_size:
+ if self.cur_device is None or self.rescanning:
+ return
+
+ event = device.Event(*struct.unpack(self.fmt, m))
+ desc = device.queryString(event.event_code)
+ error_state = STATUS_TO_ERROR_STATE_MAP.get(event.event_code, ERROR_STATE_CLEAR)
+ log.debug("Status event: %s (%d)" % (event.device_uri, event.event_code))
+
+ if event.event_code > EVENT_MAX_USER_EVENT:
+
+ if event.event_code == EVENT_HISTORY_UPDATE: # 9003
+ log.debug("History update: %s" % event.device_uri)
+
+ if not self.rescanning:
+ dev = self.findDeviceByURI(event.device_uri)
+
+ self.UpdateHistory(dev)
+ self.UpdateDevice(dev)
+
+ elif event.event_code == EVENT_CUPS_QUEUES_CHANGED:
+ pass
+
+ elif event.event_code == EVENT_RAISE_DEVICE_MANAGER: # 9001
+ log.debug("Raise requested")
+ self.showNormal()
+ self.setActiveWindow()
+ self.raiseW()
+
+ else:
+ log.debug("Ignored")
+
+ else:
+ break
+
+
+ def TimedRefresh(self):
+ if not self.rescanning and self.user_settings.auto_refresh and self.allow_auto_refresh:
+ log.debug("Refresh timer...")
+ self.CleanupChildren()
+
+ if self.user_settings.auto_refresh_type == 0:
+ self.RequestDeviceUpdate()
+ else:
+ self.RescanDevices()
+
+
+ def ThreadUpdate(self): # periodically check for updates from update thread
+ if not self.response_queue.empty():
+ response_code, device_uri = self.response_queue.get()
+
+ if response_code == RESPONSE_START:
+ self.statusBar().message(self.__tr("Updating %1...").arg(device_uri))
+ qApp.processEvents()
+
+ elif response_code == RESPONSE_DONE:
+ self.statusBar().message(QString("%1 (%2)").arg(self.cur_device_uri).\
+ arg(', '.join(self.cur_device.cups_printers)))
+
+ dev = self.findDeviceByURI(device_uri)
+
+ if dev is not None:
+ self.UpdateHistory(dev)
+ self.UpdateDevice(dev)
+
+ qApp.processEvents()
+
+ if self.response_queue.empty() and self.request_queue.empty():
+ self.UpdateTitle()
+ # Disable thread timer until more items placed in request queue?
+
+
+ # ***********************************************************************************
+ #
+ # TAB/DEVICE CHANGE SLOTS
+ #
+ # ***********************************************************************************
+
+ def Tabs_currentChanged(self, tab=None):
+ """ Called when the active tab changes.
+ Update newly displayed tab.
+ """
+
+ if tab is None:
+ tab = self.Tabs.currentPage()
+
+ try:
+ self.TabIndex[tab]()
+ except AttributeError:
+ pass
+
+ def Tabs_deviceChanged(self, tab=None):
+ """ Called when the device changes.
+ Update the currently displayed tab.
+ """
+ if tab is None:
+ tab = self.Tabs.currentPage()
+
+ self.TabIndex[tab]()
+
+
+ # ***********************************************************************************
+ #
+ # DEVICE ICON LIST/DEVICE UPDATE(S)
+ #
+ # ***********************************************************************************
+
+ def DeviceList_onItem(self, a0):
+ pass
+
+
+ def deviceRescanAction_activated(self):
+ self.deviceRescanAction.setEnabled(False)
+ self.RequestDeviceUpdate()
+ self.deviceRescanAction.setEnabled(True)
+
+
+ def deviceRefreshAll_activated(self):
+ self.RescanDevices()
+
+
+ def DeviceList_clicked(self,a0):
+ pass
+
+
+ def CreatePixmap(self, dev=None):
+ if dev is None:
+ dev = self.cur_device
+
+ try:
+ dev.icon
+ except AttributeError:
+ dev.icon = "default_printer"
+
+ try:
+ self.device_icons[dev.icon]
+ except:
+ self.device_icons[dev.icon] = load_pixmap(dev.icon, 'devices')
+
+ pix = self.device_icons[dev.icon]
+
+ w, h = pix.width(), pix.height()
+ error_state = dev.error_state
+ icon = QPixmap(w, h)
+ p = QPainter(icon)
+ p.eraseRect(0, 0, icon.width(), icon.height())
+ p.drawPixmap(0, 0, pix)
+
+ try:
+ tech_type = dev.tech_type
+ except AttributeError:
+ tech_type = TECH_TYPE_NONE
+
+ if dev.device_type == DEVICE_TYPE_FAX:
+ p.drawPixmap(w - self.fax_icon.width(), 0, self.fax_icon)
+
+ if error_state != ERROR_STATE_CLEAR:
+ if tech_type in (TECH_TYPE_COLOR_INK, TECH_TYPE_MONO_INK):
+ status_icon = self.SMALL_ICONS[error_state][0] # ink
+ else:
+ status_icon = self.SMALL_ICONS[error_state][1] # laser
+
+ if status_icon is not None:
+ p.drawPixmap(0, 0, status_icon)
+
+ p.end()
+
+ return icon
+
+
+ def DeviceListRefresh(self):
+ global devices
+ log.debug("Rescanning device list...")
+
+ if not self.rescanning:
+ self.setCaption(self.__tr("Refreshing Device List - HP Device Manager"))
+ self.statusBar().message(self.__tr("Refreshing device list..."))
+
+ self.rescanning = True
+ self.cups_devices = device.getSupportedCUPSDevices(['hp', 'hpfax'])
+
+ devices_lock.acquire()
+
+ try:
+ adds = []
+ for d in self.cups_devices:
+ if d not in devices:
+ adds.append(d)
+
+ log.debug("Adds: %s" % ','.join(adds))
+
+ removals = []
+ for d in devices:
+ if d not in self.cups_devices:
+ removals.append(d)
+
+ log.debug("Removals (1): %s" % ','.join(removals))
+
+ updates = []
+ for d in devices:
+ if d not in adds and d not in removals:
+ updates.append(d)
+
+ log.debug("Updates: %s" % ','.join(updates))
+
+
+ for d in adds:
+ log.debug("adding: %s" % d)
+ try:
+ dev = device.Device(d, service=self.service, callback=self.callback,
+ disable_dbus=self.disable_dbus)
+ except Error:
+ log.error("Unexpected error in Device class.")
+ log.exception()
+
+ if not dev.supported:
+ log.debug("Unsupported model - removing device.")
+ removals.append(d)
+ continue
+
+ self.CheckForDeviceSettingsUI(dev)
+ icon = self.CreatePixmap(dev)
+
+ if dev.device_type == DEVICE_TYPE_FAX:
+ DeviceViewItem(self.DeviceList, self.__tr("%1 (Fax)").arg(dev.model_ui),
+ icon, d)
+ else:
+ if dev.fax_type:
+ DeviceViewItem(self.DeviceList, self.__tr("%1 (Printer)").arg(dev.model_ui),
+ icon, d)
+ else:
+ DeviceViewItem(self.DeviceList, dev.model_ui,
+ icon, d)
+
+ devices[d] = dev
+
+ log.debug("Removals (2): %s" % ','.join(removals))
+
+ for d in removals:
+ item = self.DeviceList.firstItem()
+ log.debug("removing: %s" % d)
+
+ try:
+ del devices[d]
+ except KeyError:
+ pass
+
+
+ while item is not None:
+ if item.device_uri == d:
+ self.DeviceList.takeItem(item)
+ break
+
+ item = item.nextItem()
+
+ qApp.processEvents()
+
+ self.DeviceList.adjustItems()
+ self.DeviceList.updateGeometry()
+ qApp.processEvents()
+
+ if len(devices):
+ for tab in self.TabIndex:
+ self.Tabs.setTabEnabled(tab, True)
+
+ if self.cur_device_uri:
+ item = first_item = self.DeviceList.firstItem()
+
+ while item is not None:
+ qApp.processEvents()
+ if item.device_uri == self.cur_device_uri:
+ self.DeviceList.setCurrentItem(item)
+ self.DeviceList.setSelected(item, True)
+ self.statusBar().message(self.cur_device_uri)
+ break
+
+ item = item.nextItem()
+
+ else:
+ self.cur_device = None
+ self.cur_device_uri = ''
+
+ if self.cur_device is None:
+ self.cur_device_uri = self.DeviceList.firstItem().device_uri
+ self.cur_device = devices[self.cur_device_uri]
+ self.DeviceList.setCurrentItem(self.DeviceList.firstItem())
+
+ self.Tabs.setTabEnabled(self.SuppliesTab, self.cur_device.device_type == DEVICE_TYPE_PRINTER and
+ self.cur_device.error_state != ERROR_STATE_ERROR)
+
+ self.UpdatePrinterCombos()
+
+ user_conf.set('last_used', 'device_uri', self.cur_device_uri)
+
+ for d in updates + adds:
+ if d not in removals:
+ self.RequestDeviceUpdate(devices[d])
+
+ else:
+ self.cur_device = None
+ self.deviceRescanAction.setEnabled(False)
+ self.deviceRemoveAction.setEnabled(False)
+ self.rescanning = False
+ self.statusBar().message(self.__tr("Press F6 to refresh."))
+
+ for tab in self.TabIndex:
+ self.Tabs.setTabEnabled(tab, False)
+
+ dlg = NoDevicesForm(self, "", True)
+ dlg.show()
+
+ finally:
+ self.rescanning = False
+ devices_lock.release()
+
+ self.deviceRescanAction.setEnabled(True)
+ self.deviceRemoveAction.setEnabled(True)
+
+
+
+ def UpdateTitle(self):
+ if self.cur_device.device_type == DEVICE_TYPE_FAX:
+ self.setCaption(self.__tr("HP Device Manager - %1 (Fax)").arg(self.cur_device.model_ui))
+ else:
+ if self.cur_device.fax_type:
+ self.setCaption(self.__tr("HP Device Manager - %1 (Printer)").arg(self.cur_device.model_ui))
+ else:
+ self.setCaption(self.__tr("HP Device Manager - %1").arg(self.cur_device.model_ui))
+
+
+ def UpdateDeviceByURI(self, device_uri):
+ return self.UpdateDevice(self.findDeviceByURI(device_uri))
+
+
+ def UpdateDevice(self, dev=None, update_tab=True):
+ """ Update the device icon and currently displayed tab.
+ """
+ if dev is None:
+ dev = self.cur_device
+
+ log.debug("UpdateDevice(%s)" % dev.device_uri)
+
+ item = self.findItem(dev)
+
+ if item is not None:
+ item.setPixmap(self.CreatePixmap(dev))
+
+ if dev is self.cur_device and dev.error_state == ERROR_STATE_ERROR:
+ self.Tabs.setCurrentPage(1)
+
+ if dev is self.cur_device and update_tab:
+ self.UpdatePrinterCombos()
+ self.TabIndex[self.Tabs.currentPage()]()
+
+ qApp.processEvents()
+
+
+ def DeviceList_currentChanged(self, i):
+ if i is not None: # and not self.rescanning:
+ self.cur_device_uri = self.DeviceList.currentItem().device_uri
+ self.cur_device = devices[self.cur_device_uri]
+ user_conf.set('last_used', 'device_uri', self.cur_device_uri)
+
+ self.Tabs.setTabEnabled(self.SuppliesTab, self.cur_device.device_type == DEVICE_TYPE_PRINTER and
+ self.cur_device.error_state != ERROR_STATE_ERROR)
+
+ self.UpdateDevice()
+ self.UpdateTitle()
+
+
+ def findItem(self, dev):
+ if dev is None:
+ dev = self.cur_device
+
+ return self.findItemByURI(dev.device_uri)
+
+
+ def findItemByURI(self, device_uri):
+ item = self.DeviceList.firstItem()
+
+ while item is not None:
+ if item.device_uri == device_uri:
+ return item
+ item = item.nextItem()
+
+
+ def findDeviceByURI(self, device_uri):
+ try:
+ return devices[device_uri]
+ except:
+ return None
+
+
+ def RequestDeviceUpdate(self, dev=None, item=None):
+ """ Submit device update request to update thread. """
+
+ if dev is None:
+ dev = self.cur_device
+
+ if dev is not None:
+ #log.debug("RequestDeviceUpdate(%s)" % dev.device_uri)
+ dev.error_state = ERROR_STATE_REFRESHING
+ self.UpdateDevice(dev, update_tab=False)
+ qApp.processEvents()
+
+ self.request_queue.put(dev)
+
+
+ def RescanDevices(self):
+ #log.debug("RescanDevices()")
+ if not self.rescanning:
+ self.deviceRefreshAll.setEnabled(False)
+ try:
+ self.DeviceListRefresh()
+ finally:
+ self.deviceRefreshAll.setEnabled(True)
+
+
+ def callback(self):
+ qApp.processEvents()
+
+
+ # ***********************************************************************************
+ #
+ # DEVICE LIST RIGHT CLICK
+ #
+ # ***********************************************************************************
+
+ def DeviceList_rightButtonClicked(self, item, pos):
+ popup = QPopupMenu(self)
+
+ if item is not None and item is self.DeviceList.currentItem():
+ if self.cur_device.error_state != ERROR_STATE_ERROR:
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ popup.insertItem(self.__tr("Print..."), self.PrintButton_clicked)
+
+ if self.cur_device.scan_type:
+ popup.insertItem(self.__tr("Scan..."), self.ScanButton_clicked)
+
+ if self.cur_device.pcard_type:
+ popup.insertItem(self.__tr("Access Photo Cards..."), self.PCardButton_clicked)
+
+ if self.cur_device.copy_type:
+ popup.insertItem(self.__tr("Make Copies..."), self.MakeCopiesButton_clicked)
+
+ elif self.cur_device.device_type == DEVICE_TYPE_FAX:
+ if self.cur_device.fax_type:
+ popup.insertItem(self.__tr("Send Fax..."), self.SendFaxButton_clicked)
+
+ popup.insertSeparator()
+
+ if self.cur_device.device_settings_ui is not None:
+ popup.insertItem(self.__tr("Device Settings..."), self.deviceSettingsButton_clicked)
+
+ if not self.rescanning:
+ popup.insertItem(self.__tr("Refresh Device"), self.deviceRescanAction_activated)
+
+ if not self.rescanning:
+ popup.insertItem(self.__tr("Refresh All"), self.deviceRefreshAll_activated)
+
+ popup.popup(pos)
+
+
+ # ***********************************************************************************
+ #
+ # PRINTER NAME COMBOS
+ #
+ # ***********************************************************************************
+
+ def updatePrinterList(self):
+ if self.cur_device is not None and \
+ self.cur_device.supported:
+
+ printers = cups.getPrinters()
+ self.cur_device.cups_printers = []
+
+ for p in printers:
+ if p.device_uri == self.cur_device_uri:
+ self.cur_device.cups_printers.append(p.name)
+
+
+ def UpdatePrinterCombos(self):
+ self.PrintSettingsPrinterCombo.clear()
+ self.PrintJobPrinterCombo.clear()
+
+ if self.cur_device is not None and \
+ self.cur_device.supported:
+
+ for c in self.cur_device.cups_printers:
+ self.PrintSettingsPrinterCombo.insertItem(c.decode("utf-8"))
+ self.PrintJobPrinterCombo.insertItem(c.decode("utf-8"))
+
+ self.cur_printer = unicode(self.PrintSettingsPrinterCombo.currentText())
+
+ def PrintSettingsPrinterCombo_activated(self, s):
+ self.cur_printer = unicode(s)
+ self.PrintJobPrinterCombo.setCurrentText(self.cur_printer.encode("latin1")) # TODO: ?
+ return self.PrinterCombo_activated(self.cur_printer)
+
+ def PrintJobPrinterCombo_activated(self, s):
+ self.cur_printer = unicode(s)
+ self.PrintSettingsPrinterCombo.setCurrentText(self.cur_printer.encode("latin1")) # TODO: ?
+ return self.PrinterCombo_activated(self.cur_printer)
+
+ def PrinterCombo_activated(self, printer):
+ self.TabIndex[self.Tabs.currentPage()]()
+ self.UpdatePrintSettingsTabPrinter()
+
+
+
+ # ***********************************************************************************
+ #
+ # FUNCTIONS/ACTION TAB
+ #
+ # ***********************************************************************************
+
+ def InitFuncsTab(self):
+ self.click_lock = None
+
+ def UpdateFuncsTab(self):
+ self.iconList.clear()
+
+ d = self.cur_device
+
+ if d is not None:
+
+ avail = d.device_state != DEVICE_STATE_NOT_FOUND and d.supported
+ fax = d.fax_type and prop.fax_build and d.device_type == DEVICE_TYPE_FAX and \
+ sys.hexversion >= 0x020300f0 and avail
+ printer = d.device_type == DEVICE_TYPE_PRINTER and avail
+ req_plugin = d.plugin == PLUGIN_REQUIRED
+ opt_plugin = d.plugin == PLUGIN_OPTIONAL
+
+ hplip_conf = ConfigParser.ConfigParser()
+ fp = open("/etc/hp/hplip.conf", "r")
+ hplip_conf.readfp(fp)
+ fp.close()
+
+ try:
+ plugin_installed = utils.to_bool(hplip_conf.get("hplip", "plugin"))
+ except ConfigParser.NoOptionError:
+ plugin_installed = False
+
+ if d.plugin:
+ if req_plugin and plugin_installed:
+ x = self.__tr("Download and install<br>required plugin (already installed).")
+
+ elif req_plugin and not plugin_installed:
+ x = self.__tr("Download and install<br>required plugin (needs installation).")
+
+ elif opt_plugin and plugin_installed:
+ x = self.__tr("Download and install<br>optional plugin (already installed).")
+
+ elif opt_plugin and not plugin_installed:
+ x = self.__tr("Download and install<br>optional plugin (needs installation).")
+
+ else:
+ x = ''
+
+
+ self.ICONS = [
+
+ # PRINTER
+
+ (lambda : printer, # filter func
+ self.__tr("Print"), # Text
+ "print", # Icon
+ self.__tr("Print documents or files."), # Tooltip
+ self.user_settings.cmd_print), # command/action
+
+ (lambda : d.scan_type and prop.scan_build and \
+ d.device_type == DEVICE_TYPE_PRINTER and avail,
+ self.__tr("Scan"),
+ "scan",
+ self.__tr("Scan a document, image, or photograph.<br>"),
+ self.user_settings.cmd_scan),
+
+ (lambda : d.copy_type and d.device_type == DEVICE_TYPE_PRINTER and avail,
+ self.__tr("Make Copies"),
+ "makecopies",
+ self.__tr("Make copies on the device controlled by the PC.<br>"),
+ self.user_settings.cmd_copy),
+
+ (lambda : d.pcard_type and d.device_type == DEVICE_TYPE_PRINTER and avail,
+ self.__tr("Unload Photo Card"),
+ "makecopies",
+ self.__tr("Copy images from the device's photo card to the PC."),
+ self.PCardButton_clicked),
+
+ # FAX
+
+ (lambda: fax,
+ self.__tr("Send Fax"),
+ "fax",
+ self.__tr("Send a fax from the PC."),
+ self.user_settings.cmd_fax),
+
+ (lambda: fax,
+ self.__tr("Fax Setup"),
+ "fax_setup",
+ self.__tr("Fax support must be setup before you can send faxes."),
+ self.faxSettingsButton_clicked),
+
+ (lambda: fax,
+ self.__tr("Fax Address Book"),
+ "fab",
+ self.__tr("Setup fax phone numbers to use when sending faxes from the PC."),
+ self.cmd_fab),
+
+ # SETTINGS/TOOLS
+
+ (lambda : self.cur_device.device_settings_ui is not None and avail,
+ self.__tr("Device Settings"),
+ "settings",
+ self.__tr("Your device has special device settings.<br>You may alter these settings here."),
+ self.deviceSettingsButton_clicked),
+
+ (lambda : printer,
+ self.__tr("Print Test Page"),
+ "testpage",
+ self.__tr("Print a test page to test the setup of your printer."),
+ self.PrintTestPageButton_clicked),
+
+ (lambda : True,
+ self.__tr("View Printer (Queue) Information"),
+ "cups",
+ self.__tr("View the printers (queues) installed in CUPS."),
+ self.viewPrinterInformation),
+
+ (lambda : True,
+ self.__tr("View Device Information"),
+ "info",
+ self.__tr("This information is primarily useful for <br>debugging and troubleshooting (advanced)."),
+ self.viewInformation),
+
+ (lambda: printer and d.align_type,
+ self.__tr("Align Cartridges (Print Heads)"),
+ "align",
+ self.__tr("This will improve the quality of output when a new cartridge is installed."),
+ self.AlignPensButton_clicked),
+
+ (lambda: printer and d.clean_type,
+ self.__tr("Clean Cartridges"),
+ "clean",
+ self.__tr("You only need to perform this action if you are<br>having problems with poor printout quality due to clogged ink nozzles."),
+ self.CleanPensButton_clicked),
+
+ (lambda: printer and d.color_cal_type and d.color_cal_type == COLOR_CAL_TYPE_TYPHOON,
+ self.__tr("Color Calibration"),
+ "colorcal",
+ self.__tr("Use this procedure to optimimize your printer's color output<br>(requires glossy photo paper)."),
+ self.ColorCalibrationButton_clicked),
+
+ (lambda: printer and d.color_cal_type and d.color_cal_type != COLOR_CAL_TYPE_TYPHOON,
+ self.__tr("Color Calibration"),
+ "colorcal",
+ self.__tr("Use this procedure to optimimize your printer's color output."),
+ self.ColorCalibrationButton_clicked),
+
+ (lambda: printer and d.linefeed_cal_type,
+ self.__tr("Line Feed Calibration"),
+ "linefeed_cal",
+ self.__tr("Use line feed calibration to optimize print quality<br>(to remove gaps in the printed output)."),
+ self.linefeedCalibration),
+
+ (lambda: printer and d.pq_diag_type,
+ self.__tr("Print Diagnostic Page"),
+ "pq_diag",
+ self.__tr("Your printer can print a test page <br>to help diagnose print quality problems."),
+ self.pqDiag),
+
+ # FIRMWARE
+
+ (lambda : printer and d.fw_download,
+ self.__tr("Download Firmware"),
+ "firmware",
+ self.__tr("Download firmware to your printer <br>(required on some devices after each power-up)."),
+ self.ShowFirmwareDlg),
+
+ # PLUGIN
+
+ (lambda : req_plugin,
+ self.__tr("Install Required Plugin"),
+ "plugin",
+ x, #self.__tr("Download and install the HPLIP plugin."),
+ self.downloadPlugin),
+
+ (lambda : opt_plugin,
+ self.__tr("Install Optional Plugin"),
+ "plugin",
+ x, #self.__tr("Download and install the HPLIP plugin."),
+ self.downloadPlugin),
+
+ # HELP/WEBSITE
+
+ (lambda : True,
+ self.__tr("Visit HPLIP Website"),
+ "hp_logo",
+ self.__tr("Visit HPLIP website."),
+ self.viewSupport),
+
+ (lambda : True,
+ self.__tr("Help"),
+ "help",
+ self.__tr("View HPLIP help."),
+ self.viewHelp),
+ ]
+
+ if not self.func_icons_cached:
+ for filter, text, icon, tooltip, cmd in self.ICONS:
+ self.func_icons[icon] = load_pixmap(icon, '32x32')
+ self.func_icons_cached = True
+
+ for filter, text, icon, tooltip, cmd in self.ICONS:
+ if filter is not None:
+ if not filter():
+ continue
+
+ FuncViewItem(self.iconList, text,
+ self.func_icons[icon],
+ tooltip,
+ cmd)
+
+
+ def downloadPlugin(self):
+ ok, sudo_ok = pkit.run_plugin_command(self.cur_device.plugin == PLUGIN_REQUIRED, self.cur_device.mq['plugin-reason'])
+ if not sudo_ok:
+ QMessageBox.critical(self,
+ self.caption(),
+ self.__tr("<b>Unable to find an appropriate su/sudo utility to run hp-plugin.</b><p>Install kdesu, gnomesu, or gksu.</p>"),
+ QMessageBox.Ok,
+ QMessageBox.NoButton,
+ QMessageBox.NoButton)
+ else:
+ self.UpdateFuncsTab()
+
+
+ def iconList_clicked(self, item):
+ return self.RunFuncCmd(item)
+
+
+ def RunFuncCmd(self, item):
+ if item is not None and self.click_lock is not item:
+ try:
+ item.cmd()
+ except TypeError:
+ self.RunCommand(item.cmd)
+
+ self.click_lock = item
+ QTimer.singleShot(1000, self.UnlockClick)
+
+
+ def UnlockClick(self):
+ self.click_lock = None
+
+
+ def RunFuncCmdContext(self):
+ return self.RunFuncCmd(self.iconList.currentItem())
+
+
+ def iconList_contextMenuRequested(self, item, pos):
+ if item is not None and item is self.iconList.currentItem():
+ popup = QPopupMenu(self)
+ popup.insertItem(self.__tr("Open..."), self.RunFuncCmdContext)
+ popup.popup(pos)
+
+
+ def iconList_returnPressed(self, item):
+ return self.RunFuncCmd(item)
+
+
+ def deviceSettingsButton_clicked(self):
+ try:
+ self.cur_device.open()
+ self.cur_device.device_settings_ui(self.cur_device, self)
+ finally:
+ self.cur_device.close()
+
+
+ def setupDevice_activated(self):
+ try:
+ self.cur_device.open()
+ self.cur_device.device_settings_ui(self.cur_device, self)
+ finally:
+ self.cur_device.close()
+
+
+ def PrintButton_clicked(self):
+ self.RunCommand(self.user_settings.cmd_print)
+
+
+ def ScanButton_clicked(self):
+ self.RunCommand(self.user_settings.cmd_scan)
+
+
+ def PCardButton_clicked(self):
+ if self.cur_device.pcard_type == PCARD_TYPE_MLC:
+ self.RunCommand(self.user_settings.cmd_pcard)
+
+ elif self.cur_device.pcard_type == PCARD_TYPE_USB_MASS_STORAGE:
+ self.FailureUI(self.__tr("<p><b>Photocards on your printer are only available by mounting them as drives using USB mass storage.</b><p>Please refer to your distribution's documentation for setup and usage instructions."))
+
+
+ def SendFaxButton_clicked(self):
+ self.RunCommand(self.user_settings.cmd_fax)
+
+
+ def MakeCopiesButton_clicked(self):
+ self.RunCommand(self.user_settings.cmd_copy)
+
+
+ def ConfigureFeaturesButton_clicked(self):
+ self.settingsConfigure_activated(2)
+
+
+ def viewInformation(self):
+ dlg = ScrollDialog(ScrollDeviceInfoView, self.cur_device, self.cur_printer, self.service, self)
+ dlg.exec_loop()
+
+
+ def viewPrinterInformation(self):
+ dlg = ScrollDialog(ScrollPrinterInfoView, self.cur_device, self.cur_printer, self.service, self)
+ dlg.exec_loop()
+
+
+ def viewHelp(self):
+ f = "http://hplip.sf.net"
+
+ if prop.doc_build:
+ g = os.path.join(sys_conf.get('dirs', 'doc'), 'index.html')
+ if os.path.exists(g):
+ f = "file://%s" % g
+
+ log.debug(f)
+ utils.openURL(f)
+
+
+ def viewSupport(self):
+ f = "http://hplip.sf.net"
+ log.debug(f)
+ utils.openURL(f)
+
+
+ def pqDiag(self):
+ d = self.cur_device
+ pq_diag = d.pq_diag_type
+
+ try:
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+
+ try:
+ d.open()
+ except Error:
+ self.CheckDeviceUI()
+ else:
+ if d.isIdleAndNoError():
+ QApplication.restoreOverrideCursor()
+
+ if pq_diag == 1:
+ maint.printQualityDiagType1(d, self.LoadPaperUI)
+
+ elif pq_diag == 2:
+ maint.printQualityDiagType2(d, self.LoadPaperUI)
+
+ else:
+ self.CheckDeviceUI()
+
+ finally:
+ d.close()
+ QApplication.restoreOverrideCursor()
+
+
+ def linefeedCalibration(self):
+ d = self.cur_device
+ linefeed_type = d.linefeed_cal_type
+
+ try:
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+
+ try:
+ d.open()
+ except Error:
+ self.CheckDeviceUI()
+ else:
+ if d.isIdleAndNoError():
+ QApplication.restoreOverrideCursor()
+
+ if linefeed_type == 1:
+ maint.linefeedCalType1(d, self.LoadPaperUI)
+
+ elif linefeed_type == 2:
+ maint.linefeedCalType2(d, self.LoadPaperUI)
+
+ else:
+ self.CheckDeviceUI()
+
+ finally:
+ d.close()
+ QApplication.restoreOverrideCursor()
+
+
+ def downloadFirmware(self):
+ d = self.cur_device
+ ok = False
+
+ try:
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+ d.open()
+
+ if d.isIdleAndNoError():
+ ok = d.downloadFirmware()
+
+ finally:
+ d.close()
+ QApplication.restoreOverrideCursor()
+
+ if not ok:
+ self.FailureUI(self.__tr("<b>An error occured downloading firmware file.</b><p>Please check your printer and ensure that the HPLIP plugin has been installed."))
+
+
+ def CheckDeviceUI(self):
+ self.FailureUI(self.__tr("<b>Device is busy or in an error state.</b><p>Please check device and try again."))
+
+
+ def LoadPaperUI(self):
+ if LoadPaperForm(self).exec_loop() == QDialog.Accepted:
+ return True
+ return False
+
+
+ def AlignmentNumberUI(self, letter, hortvert, colors, line_count, choice_count):
+ dlg = AlignForm(self, letter, hortvert, colors, line_count, choice_count)
+ if dlg.exec_loop() == QDialog.Accepted:
+ return True, dlg.value
+ else:
+ return False, 0
+
+
+ def PaperEdgeUI(self, maximum):
+ dlg = PaperEdgeAlignForm(self)
+ if dlg.exec_loop() == QDialog.Accepted:
+ return True, dlg.value
+ else:
+ return False, 0
+
+
+ def BothPensRequiredUI(self):
+ self.WarningUI(self.__tr("<p><b>Both cartridges are required for alignment.</b><p>Please install both cartridges and try again."))
+
+
+ def InvalidPenUI(self):
+ self.WarningUI(self.__tr("<p><b>One or more cartiridges are missing from the printer.</b><p>Please install cartridge(s) and try again."))
+
+
+ def PhotoPenRequiredUI(self):
+ self.WarningUI(self.__tr("<p><b>Both the photo and color cartridges must be inserted into the printer to perform color calibration.</b><p>If you are planning on printing with the photo cartridge, please insert it and try again."))
+
+
+ def PhotoPenRequiredUI2(self):
+ self.WarningUI(self.__tr("<p><b>Both the photo (regular photo or photo blue) and color cartridges must be inserted into the printer to perform color calibration.</b><p>If you are planning on printing with the photo or photo blue cartridge, please insert it and try again."))
+
+
+ def NotPhotoOnlyRequired(self): # Type 11
+ self.WarningUI(self.__tr("<p><b>Cannot align with only the photo cartridge installed.</b><p>Please install other cartridges and try again."))
+
+
+ def AioUI1(self):
+ dlg = AlignType6Form1(self)
+ return dlg.exec_loop() == QDialog.Accepted
+
+
+ def AioUI2(self):
+ AlignType6Form2(self).exec_loop()
+
+
+ def Align10and11UI(self, pattern, align_type):
+ dlg = Align10Form(pattern, align_type, self)
+ dlg.exec_loop()
+ return dlg.getValues()
+
+
+ def Align13UI(self):
+ dlg = Align13Form(self)
+ dlg.exec_loop()
+ return True
+
+
+ def AlignPensButton_clicked(self):
+ d = self.cur_device
+ align_type = d.align_type
+
+ log.debug("Align: %s %s (type=%d) %s" % ("*"*20, self.cur_device.device_uri, align_type, "*"*20))
+
+ try:
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+
+ try:
+ d.open()
+ except Error:
+ self.CheckDeviceUI()
+ else:
+ if d.isIdleAndNoError():
+ QApplication.restoreOverrideCursor()
+
+ if align_type == ALIGN_TYPE_AUTO:
+ maint.AlignType1(d, self.LoadPaperUI)
+
+ elif align_type == ALIGN_TYPE_8XX:
+ maint.AlignType2(d, self.LoadPaperUI, self.AlignmentNumberUI,
+ self.BothPensRequiredUI)
+
+ elif align_type in (ALIGN_TYPE_9XX,ALIGN_TYPE_9XX_NO_EDGE_ALIGN):
+ maint.AlignType3(d, self.LoadPaperUI, self.AlignmentNumberUI,
+ self.PaperEdgeUI, align_type)
+
+ elif align_type in (ALIGN_TYPE_LIDIL_0_3_8, ALIGN_TYPE_LIDIL_0_4_3, ALIGN_TYPE_LIDIL_VIP):
+ maint.AlignxBow(d, align_type, self.LoadPaperUI, self.AlignmentNumberUI,
+ self.PaperEdgeUI, self.InvalidPenUI, self.ColorAdjUI)
+
+ elif align_type == ALIGN_TYPE_LIDIL_AIO:
+ maint.AlignType6(d, self.AioUI1, self.AioUI2, self.LoadPaperUI)
+
+ elif align_type == ALIGN_TYPE_DESKJET_450:
+ maint.AlignType8(d, self.LoadPaperUI, self.AlignmentNumberUI)
+
+ elif align_type == ALIGN_TYPE_LBOW:
+ maint.AlignType10(d, self.LoadPaperUI, self.Align10and11UI)
+
+ elif align_type == ALIGN_TYPE_LIDIL_0_5_4:
+ maint.AlignType11(d, self.LoadPaperUI, self.Align10and11UI, self.NotPhotoOnlyRequired)
+
+ elif align_type == ALIGN_TYPE_OJ_PRO:
+ maint.AlignType12(d, self.LoadPaperUI)
+
+ elif align_type == ALIGN_TYPE_AIO:
+ maint.AlignType13(d, self.LoadPaperUI, self.Align13UI)
+
+ elif align_type == ALIGN_TYPE_LEDM:
+ maint.AlignType15(d, self.LoadPaperUI, self.Align13UI)
+
+ elif align_type == ALIGN_TYPE_LEDM_MANUAL:
+ maint.AlignType16(d, self.LoadPaperUI, self.AlignmentNumberUI)
+
+ elif align_type == ALIGN_TYPE_LEDM_FF_CC_0:
+ maint.AlignType17(d, self.LoadPaperUI, self.Align13UI)
+ else:
+ self.CheckDeviceUI()
+
+ finally:
+ d.close()
+ QApplication.restoreOverrideCursor()
+
+
+ def ColorAdjUI(self, line, maximum=0):
+ dlg = ColorAdjForm(self, line)
+ if dlg.exec_loop() == QDialog.Accepted:
+ return True, dlg.value
+ else:
+ return False, 0
+
+
+ def ColorCalUI(self):
+ dlg = ColorCalForm(self)
+ if dlg.exec_loop() == QDialog.Accepted:
+ return True, dlg.value
+ else:
+ return False, 0
+
+
+ def ColorCalUI2(self):
+ dlg = ColorCalForm2(self)
+ if dlg.exec_loop() == QDialog.Accepted:
+ return True, dlg.value
+ else:
+ return False, 0
+
+
+ def ColorCalUI4(self):
+ dlg = ColorCal4Form(self)
+ if dlg.exec_loop() == QDialog.Accepted:
+ return True, dlg.values
+ else:
+ return False, None
+
+
+ def ColorCalibrationButton_clicked(self):
+ d = self.cur_device
+ color_cal_type = d.color_cal_type
+ log.debug("Color-cal: %s %s (type=%d) %s" % ("*"*20, self.cur_device.device_uri, color_cal_type, "*"*20))
+
+ if color_cal_type == COLOR_CAL_TYPE_TYPHOON:
+ dlg = ScrollDialog(ScrollColorCalView, self.cur_device, self.cur_printer, self.service, self)
+ dlg.exec_loop()
+ else:
+ try:
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+
+ try:
+ d.open()
+ except Error:
+ self.CheckDeviceUI()
+ else:
+ if d.isIdleAndNoError():
+ QApplication.restoreOverrideCursor()
+
+ if color_cal_type == COLOR_CAL_TYPE_DESKJET_450:
+ maint.colorCalType1(d, self.LoadPaperUI, self.ColorCalUI,
+ self.PhotoPenRequiredUI)
+
+ elif color_cal_type == COLOR_CAL_TYPE_MALIBU_CRICK:
+ maint.colorCalType2(d, self.LoadPaperUI, self.ColorCalUI2,
+ self.InvalidPenUI)
+
+ elif color_cal_type == COLOR_CAL_TYPE_STRINGRAY_LONGBOW_TORNADO:
+ maint.colorCalType3(d, self.LoadPaperUI, self.ColorAdjUI,
+ self.PhotoPenRequiredUI2)
+
+ elif color_cal_type == COLOR_CAL_TYPE_CONNERY:
+ maint.colorCalType4(d, self.LoadPaperUI, self.ColorCalUI4,
+ self.WaitUI)
+
+ elif color_cal_type == COLOR_CAL_TYPE_COUSTEAU:
+ maint.colorCalType5(d, self.LoadPaperUI)
+
+ elif color_cal_type == COLOR_CAL_TYPE_CARRIER:
+ maint.colorCalType6(d, self.LoadPaperUI)
+
+ else:
+ self.CheckDeviceUI()
+
+ finally:
+ d.close()
+ QApplication.restoreOverrideCursor()
+
+
+ def PrintTestPageButton_clicked(self):
+ dlg = ScrollDialog(ScrollTestpageView, self.cur_device, self.cur_printer, self.service, self)
+ dlg.exec_loop()
+
+
+ def CleanUI1(self):
+ return CleaningForm(self, self.cur_device, 1).exec_loop() == QDialog.Accepted
+
+
+ def CleanUI2(self):
+ return CleaningForm(self, self.cur_device, 2).exec_loop() == QDialog.Accepted
+
+
+ def CleanUI3(self):
+ CleaningForm2(self).exec_loop()
+ return True
+
+
+ def WaitUI(self, seconds):
+ WaitForm(seconds, None, self).exec_loop()
+
+
+ def CleanPensButton_clicked(self):
+ d = self.cur_device
+ clean_type = d.clean_type
+ log.debug("Clean: %s %s (type=%d) %s" % ("*"*20, self.cur_device.device_uri, clean_type, "*"*20))
+
+ try:
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+
+ try:
+ d.open()
+ except Error:
+ self.CheckDeviceUI()
+ else:
+ if d.isIdleAndNoError():
+ QApplication.restoreOverrideCursor()
+
+ if clean_type == CLEAN_TYPE_PCL:
+ maint.cleaning(d, clean_type, maint.cleanType1, maint.primeType1,
+ maint.wipeAndSpitType1, self.LoadPaperUI,
+ self.CleanUI1, self.CleanUI2, self.CleanUI3,
+ self.WaitUI)
+
+ elif clean_type == CLEAN_TYPE_LIDIL:
+ maint.cleaning(d, clean_type, maint.cleanType2, maint.primeType2,
+ maint.wipeAndSpitType2, self.LoadPaperUI,
+ self.CleanUI1, self.CleanUI2, self.CleanUI3,
+ self.WaitUI)
+
+ elif clean_type == CLEAN_TYPE_PCL_WITH_PRINTOUT:
+ maint.cleaning(d, clean_type, maint.cleanType1, maint.primeType1,
+ maint.wipeAndSpitType1, self.LoadPaperUI,
+ self.CleanUI1, self.CleanUI2, self.CleanUI3,
+ self.WaitUI)
+ else:
+ self.CheckDeviceUI()
+
+ finally:
+ d.close()
+ QApplication.restoreOverrideCursor()
+
+
+ def OpenEmbeddedBrowserButton_clicked(self):
+ utils.openURL("http://%s" % self.cur_device.host)
+
+
+ def faxAddressBookButton_clicked(self):
+ self.RunCommand(self.cmd_fab)
+
+
+ def faxSettingsButton_clicked(self):
+ try:
+ try:
+ self.cur_device.open()
+ except Error:
+ self.CheckDeviceUI()
+ else:
+ try:
+ result_code, fax_num = self.cur_device.getPML(pml.OID_FAX_LOCAL_PHONE_NUM)
+ except Error:
+ log.error("PML failure.")
+ self.FailureUI(self.__tr("<p><b>Operation failed. Device busy.</b>"))
+ return
+
+ fax_num = str(fax_num)
+
+ try:
+ result_code, name = self.cur_device.getPML(pml.OID_FAX_STATION_NAME)
+ except Error:
+ log.error("PML failure.")
+ self.FailureUI(self.__tr("<p><b>Operation failed. Device busy.</b>"))
+ return
+
+ name = str(name)
+
+ dlg = FaxSettingsForm(self.cur_device, fax_num, name, self)
+ dlg.exec_loop()
+
+ finally:
+ self.cur_device.close()
+
+
+ def addressBookButton_clicked(self):
+ self.RunCommand(self.cmd_fab)
+
+
+ def ShowFirmwareDlg(self):
+ dlg = FirmwareDialog(self, self.cur_device_uri)
+ dlg.show()
+ return dlg.exec_loop() == QDialog.Accepted
+
+ # ***********************************************************************************
+ #
+ # STATUS TAB
+ #
+ # ***********************************************************************************
+
+ def InitStatusTab(self):
+ self.statusListView.setSorting(-1)
+ self.statusListView.setColumnText(0, QString(""))
+ #self.statusListView.setColumnWidthMode(0, QListView.Manual)
+ self.statusListView.setColumnWidth(0, 16)
+
+
+ def UpdateStatusTab(self):
+ #log.debug("UpdateStatusTab()")
+ self.UpdateHistory()
+ self.UpdatePanel()
+ self.UpdateStatusList()
+
+
+ def UpdatePanel(self):
+ if self.cur_device is not None and \
+ self.cur_device.hist and \
+ self.cur_device.supported:
+
+ dq = self.cur_device.dq
+
+ if dq.get('panel', 0) == 1:
+ line1 = dq.get('panel-line1', '')
+ line2 = dq.get('panel-line2', '')
+ else:
+ try:
+ line1 = device.queryString(self.cur_device.hist[0].event_code)
+ except (AttributeError, TypeError):
+ line1 = ''
+
+ line2 = ''
+
+ pm = load_pixmap('panel_lcd', 'other')
+
+ p = QPainter()
+ p.begin(pm)
+ p.setPen(QColor(0, 0, 0))
+ p.setFont(self.font())
+
+ x, y_line1, y_line2 = 10, 17, 33
+
+ # TODO: Scroll long lines
+ p.drawText(x, y_line1, line1)
+ p.drawText(x, y_line2, line2)
+ p.end()
+
+ self.panel.setPixmap(pm)
+
+ else:
+ self.panel.setPixmap(load_pixmap('panel_lcd', 'other'))
+
+
+ def UpdateHistory(self, dev=None):
+ if self.dbus_avail:
+ if dev is None:
+ dev = self.cur_device
+
+ return dev.queryHistory()
+
+ self.cur_device.hist = [self.cur_device.last_event]
+
+
+
+ def UpdateStatusList(self):
+ self.statusListView.clear()
+ row = 0
+ hist = self.cur_device.hist[:]
+
+ if hist:
+ hist.reverse()
+ row = len(hist)-1
+
+ for e in hist:
+ if e is None:
+ continue
+
+ ess = device.queryString(e.event_code, 0)
+ esl = device.queryString(e.event_code, 1)
+
+ if row == 0:
+ desc = self.__tr("(most recent)")
+
+ else:
+ desc = self.getTimeDeltaDesc(e.timedate)
+
+ dt = QDateTime()
+ dt.setTime_t(int(e.timedate), Qt.LocalTime)
+
+ # TODO: In Qt4.x, use QLocale.toString(date, format)
+ tt = QString("%1 %2").arg(dt.toString()).arg(desc)
+
+ if e.job_id:
+ job_id = unicode(e.job_id)
+ else:
+ job_id = u''
+
+ error_state = STATUS_TO_ERROR_STATE_MAP.get(e.event_code, ERROR_STATE_CLEAR)
+ tech_type = self.cur_device.tech_type
+
+ try:
+ if tech_type in (TECH_TYPE_COLOR_INK, TECH_TYPE_MONO_INK):
+ status_pix = self.STATUS_ICONS[error_state][0] # ink
+ else:
+ status_pix = self.STATUS_ICONS[error_state][1] # laser
+ except KeyError:
+ status_pix = self.STATUS_ICONS[ERROR_STATE_CLEAR][0]
+
+ StatusListViewItem(self.statusListView, status_pix, ess, tt, unicode(e.event_code),
+ job_id, unicode(e.username))
+
+ row -= 1
+
+ i = self.statusListView.firstChild()
+ if i is not None:
+ self.statusListView.setCurrentItem(i)
+
+
+ def getTimeDeltaDesc(self, past):
+ t1 = QDateTime()
+ t1.setTime_t(int(past))
+ t2 = QDateTime.currentDateTime()
+ delta = t1.secsTo(t2)
+ return self.__tr("(about %1 ago)").arg(self.stringify(delta))
+
+
+ # "Nicely readable timedelta"
+ # Credit: Bjorn Lindqvist
+ # ASPN Python Recipe 498062
+ # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/498062
+ # Note: Modified from recipe
+ def seconds_in_units(self, seconds):
+ unit_limits = [("year", 31536000),
+ ("month", 2592000),
+ ("week", 604800),
+ ("day", 86400),
+ ("hour", 3600),
+ ("minute", 60)]
+
+ for unit_name, limit in unit_limits:
+ if seconds >= limit:
+ amount = int(round(float(seconds) / limit))
+ return amount, unit_name
+
+ return seconds, "second"
+
+
+ def stringify(self, seconds):
+ amount, unit_name = self.seconds_in_units(seconds)
+
+ try:
+ i18n_amount = self.num_repr[amount]
+ except KeyError:
+ i18n_amount = unicode(amount)
+
+ if amount == 1:
+ i18n_unit = self.unit_names[unit_name][0]
+ else:
+ i18n_unit = self.unit_names[unit_name][1]
+
+ return QString("%1 %2").arg(i18n_amount).arg(i18n_unit)
+
+
+
+
+ # ***********************************************************************************
+ #
+ # SUPPLIES TAB
+ #
+ # ***********************************************************************************
+
+ def InitSuppliesTab(self):
+ self.pix_battery = load_pixmap('battery', '16x16')
+
+ yellow = "#ffff00"
+ light_yellow = "#ffffcc"
+ cyan = "#00ffff"
+ light_cyan = "#ccffff"
+ magenta = "#ff00ff"
+ light_magenta = "#ffccff"
+ black = "#000000"
+ blue = "#0000ff"
+ dark_grey = "#808080"
+ light_grey = "#c0c0c0"
+
+ self.TYPE_TO_PIX_MAP = {
+ AGENT_TYPE_UNSPECIFIED : [black],
+ AGENT_TYPE_BLACK: [black],
+ AGENT_TYPE_CMY: [cyan, magenta, yellow],
+ AGENT_TYPE_KCM: [light_cyan, light_magenta, light_yellow],
+ AGENT_TYPE_GGK: [dark_grey],
+ AGENT_TYPE_YELLOW: [yellow],
+ AGENT_TYPE_MAGENTA: [magenta],
+ AGENT_TYPE_CYAN : [cyan],
+ AGENT_TYPE_CYAN_LOW: [light_cyan],
+ AGENT_TYPE_YELLOW_LOW: [light_yellow],
+ AGENT_TYPE_MAGENTA_LOW: [light_magenta],
+ AGENT_TYPE_BLUE: [blue],
+ AGENT_TYPE_KCMY_CM: [yellow, cyan, magenta],
+ AGENT_TYPE_LC_LM: [light_cyan, light_magenta],
+ #AGENT_TYPE_Y_M: [yellow, magenta],
+ #AGENT_TYPE_C_K: [black, cyan],
+ AGENT_TYPE_LG_PK: [light_grey, dark_grey],
+ AGENT_TYPE_LG: [light_grey],
+ AGENT_TYPE_G: [dark_grey],
+ AGENT_TYPE_PG: [light_grey],
+ AGENT_TYPE_C_M: [cyan, magenta],
+ AGENT_TYPE_K_Y: [black, yellow],
+ }
+
+ self.suppliesList.setSorting(-1)
+ self.suppliesList.setColumnText(0, QString(""))
+ #self.suppliesList.setColumnWidthMode(0, QListView.Manual)
+ self.suppliesList.setColumnWidth(0, 16)
+ self.suppliesList.setColumnWidth(3, 100)
+
+
+ def UpdateSuppliesTab(self):
+ #log.debug("UpdateSuppliesTab()")
+
+ self.suppliesList.clear()
+
+ if self.cur_device is not None and \
+ self.cur_device.supported and \
+ self.cur_device.status_type != STATUS_TYPE_NONE and \
+ self.cur_device.device_state != DEVICE_STATE_NOT_FOUND:
+
+ try:
+ self.cur_device.sorted_supplies
+ except AttributeError:
+ self.cur_device.sorted_supplies = []
+
+ if not self.cur_device.sorted_supplies:
+ a = 1
+ while True:
+ try:
+ agent_type = int(self.cur_device.dq['agent%d-type' % a])
+ agent_kind = int(self.cur_device.dq['agent%d-kind' % a])
+ agent_sku = self.cur_device.dq['agent%d-sku' % a]
+ except KeyError:
+ break
+ else:
+ self.cur_device.sorted_supplies.append((a, agent_kind, agent_type, agent_sku))
+
+ a += 1
+
+ self.cur_device.sorted_supplies.sort(lambda x, y: cmp(x[1], y[1]) or cmp(x[3], y[3]), reverse=True)
+
+
+ for x in self.cur_device.sorted_supplies:
+ a, agent_kind, agent_type, agent_sku = x
+ agent_level = int(self.cur_device.dq['agent%d-level' % a])
+ agent_desc = self.cur_device.dq['agent%d-desc' % a]
+ agent_health_desc = self.cur_device.dq['agent%d-health-desc' % a]
+
+ # Bar graph level
+ level_pixmap = None
+ if agent_kind in (AGENT_KIND_SUPPLY,
+ AGENT_KIND_HEAD,
+ AGENT_KIND_HEAD_AND_SUPPLY,
+ AGENT_KIND_TONER_CARTRIDGE,
+ AGENT_KIND_MAINT_KIT,
+ AGENT_KIND_ADF_KIT,
+ AGENT_KIND_INT_BATTERY,
+ AGENT_KIND_DRUM_KIT,
+ ):
+
+ level_pixmap = self.createBarGraph(agent_level, agent_type)
+
+ # Color icon
+ pixmap = None
+ if agent_kind in (AGENT_KIND_SUPPLY,
+ AGENT_KIND_HEAD,
+ AGENT_KIND_HEAD_AND_SUPPLY,
+ AGENT_KIND_TONER_CARTRIDGE,
+ #AGENT_KIND_MAINT_KIT,
+ #AGENT_KIND_ADF_KIT,
+ AGENT_KIND_INT_BATTERY,
+ #AGENT_KIND_DRUM_KIT,
+ ):
+
+ pixmap = self.getIcon(agent_kind, agent_type)
+
+
+ SuppliesListViewItem(self.suppliesList, pixmap, agent_desc,
+ agent_sku, level_pixmap, agent_health_desc)
+
+ i = self.suppliesList.firstChild()
+ if i is not None:
+ self.suppliesList.setCurrentItem(i)
+
+
+
+
+ def getIcon(self, agent_kind, agent_type):
+ if agent_kind in (AGENT_KIND_SUPPLY,
+ AGENT_KIND_HEAD,
+ AGENT_KIND_HEAD_AND_SUPPLY,
+ AGENT_KIND_TONER_CARTRIDGE):
+
+ map = self.TYPE_TO_PIX_MAP[agent_type]
+
+ if isinstance(map, list):
+ map_len = len(map)
+ pix = QPixmap(16, 16) #, -1, QPixmap.DefaultOptim)
+ pix.fill(qApp.palette().color(QPalette.Active, QColorGroup.Background))
+ p = QPainter()
+ p.begin(pix)
+ p.setBackgroundMode(Qt.OpaqueMode)
+
+ if map_len == 1:
+ p.setPen(QColor(map[0]))
+ p.setBrush(QBrush(QColor(map[0]), Qt.SolidPattern))
+ p.drawPie(2, 2, 10, 10, 0, 5760)
+
+ elif map_len == 2:
+ p.setPen(QColor(map[0]))
+ p.setBrush(QBrush(QColor(map[0]), Qt.SolidPattern))
+ p.drawPie(2, 4, 8, 8, 0, 5760)
+
+ p.setPen(QColor(map[1]))
+ p.setBrush(QBrush(QColor(map[1]), Qt.SolidPattern))
+ p.drawPie(6, 4, 8, 8, 0, 5760)
+
+ elif map_len == 3:
+ p.setPen(QColor(map[2]))
+ p.setBrush(QBrush(QColor(map[2]), Qt.SolidPattern))
+ p.drawPie(6, 6, 8, 8, 0, 5760)
+
+ p.setPen(QColor(map[1]))
+ p.setBrush(QBrush(QColor(map[1]), Qt.SolidPattern))
+ p.drawPie(2, 6, 8, 8, 0, 5760)
+
+ p.setPen(QColor(map[0]))
+ p.setBrush(QBrush(QColor(map[0]), Qt.SolidPattern))
+ p.drawPie(4, 2, 8, 8, 0, 5760)
+
+ p.end()
+ return pix
+
+ else:
+ return map
+
+ elif agent_kind == AGENT_KIND_INT_BATTERY:
+ return self.pix_battery
+
+
+ def createBarGraph(self, percent, agent_type, w=100, h=18):
+ fw = w/100*percent
+ px = QPixmap(w, h)
+ px.fill(qApp.palette().color(QPalette.Active, QColorGroup.Background))
+
+ pp = QPainter(px)
+ pp.setPen(Qt.black)
+ pp.setBackgroundColor(qApp.palette().color(QPalette.Active, QColorGroup.Base))
+
+ map = self.TYPE_TO_PIX_MAP[agent_type]
+ map_len = len(map)
+
+ if map_len == 1 or map_len > 3:
+ pp.fillRect(0, 0, fw, h, QBrush(QColor(map[0])))
+
+ elif map_len == 2:
+ h2 = h / 2
+ pp.fillRect(0, 0, fw, h2, QBrush(QColor(map[0])))
+ pp.fillRect(0, h2, fw, h, QBrush(QColor(map[1])))
+
+ elif map_len == 3:
+ h3 = h / 3
+ h23 = 2 * h3
+ pp.fillRect(0, 0, fw, h3, QBrush(QColor(map[0])))
+ pp.fillRect(0, h3, fw, h23, QBrush(QColor(map[1])))
+ pp.fillRect(0, h23, fw, h, QBrush(QColor(map[2])))
+
+ # draw black frame
+ pp.drawRect(0, 0, w, h)
+
+ if percent > 75 and agent_type in \
+ (AGENT_TYPE_BLACK, AGENT_TYPE_UNSPECIFIED, AGENT_TYPE_BLUE):
+ pp.setPen(Qt.white)
+
+ # 75% ticks
+ w1 = 3 * w / 4
+ h6 = h / 6
+ pp.drawLine(w1, 0, w1, h6)
+ pp.drawLine(w1, h, w1, h-h6)
+
+ if percent > 50 and agent_type in \
+ (AGENT_TYPE_BLACK, AGENT_TYPE_UNSPECIFIED, AGENT_TYPE_BLUE):
+ pp.setPen(Qt.white)
+
+ # 50% ticks
+ w2 = w / 2
+ h4 = h / 4
+ pp.drawLine(w2, 0, w2, h4)
+ pp.drawLine(w2, h, w2, h-h4)
+
+ if percent > 25 and agent_type in \
+ (AGENT_TYPE_BLACK, AGENT_TYPE_UNSPECIFIED, AGENT_TYPE_BLUE):
+ pp.setPen(Qt.white)
+
+ # 25% ticks
+ w4 = w / 4
+ pp.drawLine(w4, 0, w4, h6)
+ pp.drawLine(w4, h, w4, h-h6)
+
+ return px
+
+
+
+ # ***********************************************************************************
+ #
+ # PRINTER SETTINGS TAB
+ #
+ # ***********************************************************************************
+
+ def InitPrintSettingsTab(self): # Add Scrolling Print Settings
+ PrintJobsTabLayout = QGridLayout(self.PrintSettingsTab,1,1,11,6,"PrintJobsTabLayout")
+
+ self.PrintSettingsList = ScrollPrintSettingsView(self.service, self.PrintSettingsTab, "PrintSettingsView")
+ PrintJobsTabLayout.addMultiCellWidget(self.PrintSettingsList,1,1,0,3)
+
+ self.PrintSettingsPrinterCombo = QComboBox(0,self.PrintSettingsTab,"comboBox5")
+
+ self.PrintSettingsPrinterCombo.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed,0,0,
+ self.PrintSettingsPrinterCombo.sizePolicy().hasHeightForWidth()))
+
+ PrintJobsTabLayout.addWidget(self.PrintSettingsPrinterCombo, 0, 2)
+
+ self.settingTextLabel = QLabel(self.PrintSettingsTab,"self.settingTextLabel")
+ PrintJobsTabLayout.addWidget(self.settingTextLabel,0,1)
+
+ self.settingTextLabel.setText(self.__tr("Printer Name:"))
+
+ spacer34 = QSpacerItem(20,20,QSizePolicy.Preferred, QSizePolicy.Minimum)
+ PrintJobsTabLayout.addItem(spacer34,0,3)
+
+ spacer35 = QSpacerItem(20,20,QSizePolicy.Preferred, QSizePolicy.Minimum)
+ PrintJobsTabLayout.addItem(spacer35,0,0)
+
+ self.connect(self.PrintSettingsPrinterCombo, SIGNAL("activated(const QString&)"),
+ self.PrintSettingsPrinterCombo_activated)
+
+
+ def UpdatePrintSettingsTab(self):
+ #log.debug("UpdatePrintSettingsTab()")
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ self.settingTextLabel.setText(self.__tr("Printer Name:"))
+ else:
+ self.settingTextLabel.setText(self.__tr("Fax Name:"))
+
+ self.PrintSettingsList.onDeviceChange(self.cur_device)
+
+
+ def UpdatePrintSettingsTabPrinter(self):
+ self.PrintSettingsList.onPrinterChange(self.cur_printer)
+
+
+ # ***********************************************************************************
+ #
+ # PRINTER CONTROL TAB
+ #
+ # ***********************************************************************************
+
+ def InitPrintControlTab(self):
+ self.JOB_STATES = { cups.IPP_JOB_PENDING : self.__tr("Pending"),
+ cups.IPP_JOB_HELD : self.__tr("On hold"),
+ cups.IPP_JOB_PROCESSING : self.__tr("Printing"),
+ cups.IPP_JOB_STOPPED : self.__tr("Stopped"),
+ cups.IPP_JOB_CANCELLED : self.__tr("Canceled"),
+ cups.IPP_JOB_ABORTED : self.__tr("Aborted"),
+ cups.IPP_JOB_COMPLETED : self.__tr("Completed"),
+ }
+
+ self.cancelToolButton.setIconSet(QIconSet(load_pixmap('cancel', '16x16')))
+ self.infoToolButton.setIconSet(QIconSet(load_pixmap('info', '16x16')))
+
+ self.JOB_STATE_ICONS = { cups.IPP_JOB_PENDING: self.busy_pix,
+ cups.IPP_JOB_HELD : self.busy_pix,
+ cups.IPP_JOB_PROCESSING : self.print_pix,
+ cups.IPP_JOB_STOPPED : self.warning_pix,
+ cups.IPP_JOB_CANCELLED : self.warning_pix,
+ cups.IPP_JOB_ABORTED : self.error_pix,
+ cups.IPP_JOB_COMPLETED : self.ok_pix,
+ }
+
+ self.jobList.setSorting(-1)
+ self.jobList.setColumnText(0, QString(""))
+ #self.jobList.setColumnWidthMode(0, QListView.Manual)
+ self.jobList.setColumnWidth(0, 16)
+ self.jobList.setColumnText(1, QString(""))
+ #self.jobList.setColumnWidthMode(1, QListView.Manual)
+ self.jobList.setColumnWidth(1, 16)
+ self.jobList.setColumnWidth(2, 300)
+ self.cancelToolButton.setEnabled(False)
+ self.infoToolButton.setEnabled(False)
+
+ self.printer_state = cups.IPP_PRINTER_STATE_IDLE
+
+ # TODO: Check queues at startup and send events if stopped or rejecting
+
+
+ def UpdatePrintControlTab(self):
+ #log.debug("UpdatePrintControlTab()")
+
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ self.printerTextLabel.setText(self.__tr("Printer Name:"))
+
+ else:
+ self.printerTextLabel.setText(self.__tr("Fax Name:"))
+
+ self.jobList.clear()
+ self.UpdatePrintController()
+
+ jobs = cups.getJobs()
+ num_jobs = 0
+ for j in jobs:
+ if j.dest.decode('utf-8') == unicode(self.cur_printer):
+ num_jobs += 1
+
+ for j in jobs:
+ if j.dest == self.cur_printer:
+ JobListViewItem(self.jobList, self.JOB_STATE_ICONS[j.state],
+ j.title, self.JOB_STATES[j.state], unicode(j.id))
+
+ i = self.jobList.firstChild()
+ if i is not None:
+ self.jobList.setCurrentItem(i)
+
+
+ def jobList_clicked(self, i):
+ num = 0
+ item = self.jobList.firstChild()
+ while item is not None:
+ if item.isOn():
+ num += 1
+
+ item = item.nextSibling()
+
+ self.cancelToolButton.setEnabled(num)
+ self.infoToolButton.setEnabled(num == 1)
+
+
+ def infoToolButton_clicked(self):
+ item = self.jobList.firstChild()
+ while item is not None:
+ if item.isOn():
+ return self.showJobInfoDialog(item)
+
+ item = item.nextSibling()
+
+
+ def cancelToolButton_clicked(self):
+ self.cancelCheckedJobs()
+
+
+ def jobList_contextMenuRequested(self, item, pos, a2):
+ if item is not None and item is self.jobList.currentItem():
+ popup = QPopupMenu(self)
+
+ popup.insertItem(self.__tr("Cancel Job"), self.cancelJob)
+ popup.insertSeparator()
+ popup.insertItem(self.__tr("View Job Log (advanced)..."), self.getJobInfo)
+
+ popup.popup(pos)
+
+
+ def cancelJob(self):
+ item = self.jobList.currentItem()
+
+ if item is not None:
+ self.cur_device.cancelJob(int(item.job_id))
+
+
+ def getJobInfo(self):
+ return self.showJobInfoDialog(self.jobList.currentItem())
+
+
+ def showJobInfoDialog(self, item):
+ if item is not None:
+ text = cups.getPrintJobErrorLog(int(item.job_id))
+
+ if text:
+ dlg = JobInfoDialog(text, self)
+ dlg.setCaption(self.__tr("HP Device Manager - Job Log - %1 - Job %2").\
+ arg(self.cur_printer).arg(unicode(item.job_id)))
+
+ dlg.exec_loop()
+
+ else:
+ self.FailureUI(self.__tr("<b>No log output found.</b><p>If the print job is stopped or the printer is rejecting jobs, there might not be any output. Also, you will receive more output in the CUPS LogLevel is set to 'debug'."))
+
+
+ def UpdatePrintController(self):
+ # default printer
+ self.defaultPushButton.setText(self.__tr("Set as Default"))
+
+ default_printer = cups.getDefaultPrinter()
+ if default_printer is not None:
+ default_printer = default_printer.decode('utf8')
+
+ if default_printer == self.cur_printer:
+ s = self.__tr("SET AS DEFAULT")
+ self.defaultPushButton.setEnabled(False)
+
+ else:
+ s = self.__tr("NOT SET AS DEFAULT")
+ self.defaultPushButton.setEnabled(True)
+
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ QToolTip.add(self.defaultPushButton, self.__tr("The printer is currently: %1").arg(s))
+
+ else:
+ QToolTip.add(self.defaultPushButton, self.__tr("The fax is currently: %1").arg(s))
+
+ self.printer_state = cups.IPP_PRINTER_STATE_IDLE
+
+ cups_printers = cups.getPrinters()
+
+ for p in cups_printers:
+ if p.name.decode('utf-8') == self.cur_printer:
+ self.printer_state = p.state
+ self.printer_accepting = p.accepting
+ break
+
+ # start/stop
+ if self.printer_state == cups.IPP_PRINTER_STATE_IDLE:
+ s = self.__tr("IDLE")
+
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ self.stopstartPushButton.setText(self.__tr("Stop Printer"))
+
+ else:
+ self.stopstartPushButton.setText(self.__tr("Stop Fax"))
+
+ elif self.printer_state == cups.IPP_PRINTER_STATE_PROCESSING:
+ s = self.__tr("PROCESSING")
+
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ self.stopstartPushButton.setText(self.__tr("Stop Printer"))
+
+ else:
+ self.stopstartPushButton.setText(self.__tr("Stop Fax"))
+ else:
+ s = self.__tr("STOPPED")
+
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ self.stopstartPushButton.setText(self.__tr("Start Printer"))
+
+ else:
+ self.stopstartPushButton.setText(self.__tr("Start Fax"))
+
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ QToolTip.add(self.stopstartPushButton, self.__tr("The printer is currently: %1").arg(s))
+
+ else:
+ QToolTip.add(self.stopstartPushButton, self.__tr("The fax is currently: %1").arg(s))
+
+ # reject/accept
+ if self.printer_accepting:
+ s = self.__tr("ACCEPTING JOBS")
+ self.rejectacceptPushButton.setText(self.__tr("Reject Jobs"))
+
+ else:
+ s = self.__tr("REJECTING JOBS")
+ self.rejectacceptPushButton.setText(self.__tr("Accept Jobs"))
+
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ QToolTip.add(self.rejectacceptPushButton, self.__tr("The printer is currently: %1").arg(s))
+
+ else:
+ QToolTip.add(self.rejectacceptPushButton, self.__tr("The fax is currently: %1").arg(s))
+
+
+ def stopstartPushButton_clicked(self):
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+ try:
+ if self.printer_state in (cups.IPP_PRINTER_STATE_IDLE, cups.IPP_PRINTER_STATE_PROCESSING):
+ result = cups.stop(self.cur_printer)
+ if result:
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ e = EVENT_PRINTER_QUEUE_STOPPED
+ else:
+ e = EVENT_FAX_QUEUE_STOPPED
+
+ else:
+ result = cups.start(self.cur_printer)
+ if result:
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ e = EVENT_PRINTER_QUEUE_STARTED
+ else:
+ e = EVENT_FAX_QUEUE_STARTED
+
+ if result:
+ self.UpdatePrintController()
+ self.cur_device.sendEvent(e, self.cur_printer)
+ else:
+ log.error("Start/Stop printer operation failed")
+ self.FailureUI(self.__tr("<b>Start/Stop printer operation failed.</b><p>Try after add user to \"lp\" group."))
+
+ finally:
+ QApplication.restoreOverrideCursor()
+
+
+ def rejectacceptPushButton_clicked(self):
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+ try:
+ if self.printer_accepting:
+ result = cups.reject(self.cur_printer)
+ if result:
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ e = EVENT_PRINTER_QUEUE_REJECTING_JOBS
+ else:
+ e = EVENT_FAX_QUEUE_REJECTING_JOBS
+
+ else:
+ result = cups.accept(self.cur_printer)
+ if result:
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ e = EVENT_PRINTER_QUEUE_ACCEPTING_JOBS
+ else:
+ e = EVENT_FAX_QUEUE_ACCEPTING_JOBS
+
+ if result:
+ self.UpdatePrintController()
+ self.cur_device.sendEvent(e, self.cur_printer)
+ else:
+ log.error("Reject/Accept jobs operation failed")
+ self.FailureUI(self.__tr("<b>Accept/Reject printer operation failed.</b><p>Try after add user to \"lp\" group."))
+
+ finally:
+ QApplication.restoreOverrideCursor()
+
+
+ def defaultPushButton_clicked(self):
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+ try:
+ result = cups.setDefaultPrinter(self.cur_printer.encode('utf8'))
+ if not result:
+ log.error("Set default printer failed.")
+ self.FailureUI(self.__tr("<b>Set default printer operation failed.</b><p>Try after add user to \"lp\" group."))
+ else:
+ self.UpdatePrintController()
+ if self.cur_device.device_type == DEVICE_TYPE_PRINTER:
+ e = EVENT_PRINTER_QUEUE_SET_AS_DEFAULT
+ else:
+ e = EVENT_FAX_QUEUE_SET_AS_DEFAULT
+
+ self.cur_device.sendEvent(e, self.cur_printer)
+
+ finally:
+ QApplication.restoreOverrideCursor()
+
+
+ def cancelCheckedJobs(self):
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+ try:
+ item = self.jobList.firstChild()
+ while item is not None:
+ if item.isOn():
+ self.cur_device.cancelJob(int(item.job_id))
+
+ item = item.nextSibling()
+
+ finally:
+ QApplication.restoreOverrideCursor()
+
+ self.UpdatePrintControlTab()
+
+ def UpdateUpgradeTab(self):
+ log.debug("Upgrade Tab is pressed")
+ self.InstallPushButton_lock = False
+
+ def InstallPushButton_clicked(self):
+ if self.InstallPushButton_lock is True:
+ return
+
+ if self.Is_autoInstaller_distro:
+ self.InstallPushButton.setEnabled(False)
+ terminal_cmd = utils.get_terminal()
+ if terminal_cmd is not None and utils.which("hp-upgrade"):
+ cmd = terminal_cmd + " 'hp-upgrade'"
+ log.debug("cmd = %s " %cmd)
+ os.system(cmd)
+ else:
+ log.error("Failed to run hp-upgrade command from terminal =%s "%terminal_cmd)
+ self.InstallPushButton.setEnabled(True)
+ else:
+ self.InstallPushButton_lock = True
+ utils.openURL("http://hplipopensource.com/hplip-web/install/manual/index.html")
+ QTimer.singleShot(1000, self.InstallPushButton_unlock)
+
+ def InstallPushButton_unlock(self):
+ self.InstallPushButton_lock = False
+
+ # ***********************************************************************************
+ #
+ # EXIT/CHILD CLEANUP
+ #
+ # ***********************************************************************************
+
+ def closeEvent(self, event):
+ self.Cleanup()
+ self.request_queue.put(None)
+ event.accept()
+
+
+ def Cleanup(self):
+ self.request_queue.put(None)
+ self.CleanupChildren()
+ if not self.update_thread.wait(5000):
+ self.update_thread.terminate()
+
+
+ def CleanupChildren(self):
+ log.debug("Cleaning up child processes.")
+ try:
+ os.waitpid(-1, os.WNOHANG)
+ except OSError:
+ pass
+
+
+ # ***********************************************************************************
+ #
+ # DEVICE SETTINGS PLUGIN
+ #
+ # ***********************************************************************************
+
+ def CheckForDeviceSettingsUI(self, dev):
+ dev.device_settings_ui = None
+ name = '.'.join(['plugins', dev.model])
+ log.debug("Attempting to load plugin: %s" % name)
+ try:
+ mod = __import__(name, globals(), locals(), [])
+ except ImportError:
+ log.debug("No plugin found.")
+ return
+ else:
+ components = name.split('.')
+ for c in components[1:]:
+ mod = getattr(mod, c)
+ log.debug("Loaded: %s" % repr(mod))
+ dev.device_settings_ui = mod.settingsUI
+
+
+ # ***********************************************************************************
+ #
+ # SETTINGS DIALOG
+ #
+ # ***********************************************************************************
+
+ def settingsConfigure_activated(self, tab_to_show=0):
+ dlg = SettingsDialog(self)
+ dlg.TabWidget.setCurrentPage(tab_to_show)
+
+ if dlg.exec_loop() == QDialog.Accepted:
+ old_auto_refresh = self.user_settings.auto_refresh_rate
+ self.user_settings.load()
+
+ if self.user_settings.auto_refresh and old_auto_refresh != self.user_settings.auto_refresh_rate:
+ self.refresh_timer.changeInterval(self.user_settings.auto_refresh_rate * 1000)
+
+ if old_auto_refresh != self.user_settings.auto_refresh:
+ self.autoRefresh.toggle()
+
+
+ # ***********************************************************************************
+ #
+ # SETUP/REMOVE
+ #
+ # ***********************************************************************************
+
+ def deviceInstallAction_activated(self):
+ if utils.which('hp-setup'):
+ cmd = 'hp-setup -u'
+ else:
+ cmd = 'python ./setup.py --gui'
+
+ log.debug(cmd)
+ utils.run(cmd, log_output=True, password_func=None, timeout=1)
+ self.RescanDevices()
+
+
+ def deviceRemoveAction_activated(self):
+ if self.cur_device is not None:
+ x = QMessageBox.critical(self,
+ self.caption(),
+ self.__tr("<b>Annoying Confirmation: Are you sure you want to remove this device?</b>"),
+ QMessageBox.Yes,
+ QMessageBox.No | QMessageBox.Default,
+ QMessageBox.NoButton)
+ if x == QMessageBox.Yes:
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+ print_uri = self.cur_device.device_uri
+ fax_uri = print_uri.replace('hp:', 'hpfax:')
+
+ log.debug(print_uri)
+ log.debug(fax_uri)
+
+ self.cups_devices = device.getSupportedCUPSDevices(['hp', 'hpfax'])
+
+ for d in self.cups_devices:
+ if d in (print_uri, fax_uri):
+ for p in self.cups_devices[d]:
+ log.debug("Removing %s" % p)
+ r = cups.delPrinter(p)
+ if r == 0:
+ self.FailureUI(self.__tr("<p><b>Delete printer queue fails.</b><p>Try after add user to \"lp\" group."))
+
+ self.cur_device = None
+ self.cur_device_uri = ''
+ user_conf.set('last_used', 'device_uri', '')
+ QApplication.restoreOverrideCursor()
+
+ self.RescanDevices()
+
+
+ # ***********************************************************************************
+ #
+ # MISC
+ #
+ # ***********************************************************************************
+
+
+ def RunCommand(self, cmd, macro_char='%'):
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+
+ try:
+ if len(cmd) == 0:
+ self.FailureUI(self.__tr("<p><b>Unable to run command. No command specified.</b><p>Use <pre>Configure...</pre> to specify a command to run."))
+ log.error("No command specified. Use settings to configure commands.")
+ else:
+ log.debug("Run: %s %s (%s) %s" % ("*"*20, cmd, self.cur_device_uri, "*"*20))
+ log.debug(cmd)
+
+ try:
+ cmd = ''.join([self.cur_device.device_vars.get(x, x) \
+ for x in cmd.split(macro_char)])
+ except AttributeError:
+ pass
+
+ log.debug(cmd)
+
+ path = cmd.split()[0]
+ args = cmd.split()
+
+ log.debug(path)
+ log.debug(args)
+
+ self.CleanupChildren()
+ os.spawnvp(os.P_NOWAIT, path, args)
+ qApp.processEvents()
+
+ finally:
+ QApplication.restoreOverrideCursor()
+
+
+ def helpContents(self):
+ f = "http://hplip.sf.net"
+
+ if prop.doc_build:
+ g = os.path.join(sys_conf.get('dirs', 'doc'), 'index.html')
+ if os.path.exists(g):
+ f = "file://%s" % g
+
+ log.debug(f)
+ utils.openURL(f)
+
+
+ def helpAbout(self):
+ dlg = AboutDlg(self)
+ dlg.VersionText.setText(prop.version)
+ dlg.ToolboxVersionText.setText(self.toolbox_version + " (Qt3)")
+ dlg.exec_loop()
+
+
+ def FailureUI(self, error_text):
+ QMessageBox.critical(self,
+ self.caption(),
+ error_text,
+ QMessageBox.Ok,
+ QMessageBox.NoButton,
+ QMessageBox.NoButton)
+
+
+ def WarningUI(self, msg):
+ QMessageBox.warning(self,
+ self.caption(),
+ msg,
+ QMessageBox.Ok,
+ QMessageBox.NoButton,
+ QMessageBox.NoButton)
+
+
+ def __tr(self,s,c = None):
+ return qApp.translate("DevMgr4",s,c)
+
+
+
+# ***********************************************************************************
+#
+# ScrollDeviceInfoView (View Device Information)
+#
+# ***********************************************************************************
+
+class ScrollDeviceInfoView(ScrollView):
+ def __init__(self, service, parent=None, form=None, name=None, fl=0):
+ ScrollView.__init__(self, service, parent, name, fl)
+
+
+ def fillControls(self):
+ ScrollView.fillControls(self)
+ self.addDeviceInfo()
+ self.maximizeControl()
+
+
+ def addDeviceInfo(self):
+ self.addGroupHeading("info_title", self.__tr("Device Information"))
+
+ widget = self.getWidget()
+
+ layout37 = QGridLayout(widget,1,1,5,10,"layout37")
+
+ self.infoListView = QListView(widget,"fileListView")
+ self.infoListView.addColumn(self.__tr("Static/Dynamic"))
+ self.infoListView.addColumn(self.__tr("Key"))
+ self.infoListView.addColumn(self.__tr("Value"))
+ self.infoListView.setAllColumnsShowFocus(1)
+ self.infoListView.setShowSortIndicator(1)
+ self.infoListView.setColumnWidth(0, 50)
+ self.infoListView.setColumnWidth(1, 150)
+ self.infoListView.setColumnWidth(2, 300)
+ self.infoListView.setItemMargin(2)
+ self.infoListView.setSorting(-1)
+
+ layout37.addMultiCellWidget(self.infoListView,1,1,0,3)
+
+ mq_keys = self.cur_device.mq.keys()
+ mq_keys.sort()
+ mq_keys.reverse()
+ for key,i in zip(mq_keys, range(len(mq_keys))):
+ QListViewItem(self.infoListView, self.__tr("Static"), key, str(self.cur_device.mq[key]))
+
+ dq_keys = self.cur_device.dq.keys()
+ dq_keys.sort()
+ dq_keys.reverse()
+ for key,i in zip(dq_keys, range(len(dq_keys))):
+ QListViewItem(self.infoListView, self.__tr("Dynamic"), key, str(self.cur_device.dq[key]))
+
+ self.addWidget(widget, "file_list", maximize=True)
+
+
+ def __tr(self,s,c = None):
+ return qApp.translate("ScrollDeviceInfoView",s,c)
+
+
+
+# ***********************************************************************************
+#
+# ScrollTestpageView (Print Test Page)
+#
+# ***********************************************************************************
+
+class ScrollTestpageView(ScrollView):
+ def __init__(self, service, parent=None, form=None, name=None, fl=0):
+ ScrollView.__init__(self, service, parent, name, fl)
+ self.dialog = parent
+
+
+ def fillControls(self):
+ ScrollView.fillControls(self)
+
+ if self.addPrinterFaxList():
+ self.addTestpageType()
+
+ self.addLoadPaper()
+
+ self.printButton = self.addActionButton("bottom_nav", self.__tr("Print Test Page"),
+ self.printButton_clicked, 'print.png', None)
+
+
+ def addTestpageType(self):
+ self.addGroupHeading("testpage_type", self.__tr("Test Page Type"))
+ widget = self.getWidget()
+
+ Form4Layout = QGridLayout(widget,1,1,5,10,"Form4Layout")
+
+ self.buttonGroup3 = QButtonGroup(widget,"buttonGroup3")
+ self.buttonGroup3.setLineWidth(0)
+ self.buttonGroup3.setColumnLayout(0,Qt.Vertical)
+ self.buttonGroup3.layout().setSpacing(5)
+ self.buttonGroup3.layout().setMargin(10)
+
+ buttonGroup3Layout = QGridLayout(self.buttonGroup3.layout())
+ buttonGroup3Layout.setAlignment(Qt.AlignTop)
+
+ self.radioButton6 = QRadioButton(self.buttonGroup3,"radioButton6")
+ self.radioButton6.setEnabled(False)
+ buttonGroup3Layout.addWidget(self.radioButton6,1,0)
+
+ self.radioButton5 = QRadioButton(self.buttonGroup3,"radioButton5")
+ self.radioButton5.setChecked(1)
+ buttonGroup3Layout.addWidget(self.radioButton5,0,0)
+
+ Form4Layout.addWidget(self.buttonGroup3,0,0)
+
+ self.radioButton6.setText(self.__tr("Printer diagnostic page (does not test print driver)"))
+ self.radioButton5.setText(self.__tr("HPLIP test page (tests print driver)"))
+
+ self.addWidget(widget, "page_type")
+
+
+ def printButton_clicked(self):
+ d = self.cur_device
+ printer_name = self.cur_printer
+ printed = False
+
+ try:
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+
+ try:
+ d.open()
+ except Error:
+ self.CheckDeviceUI()
+ else:
+ try:
+ if d.isIdleAndNoError():
+ QApplication.restoreOverrideCursor()
+ d.close()
+
+ d.printTestPage(printer_name)
+ printed = True
+
+ else:
+ d.close()
+ self.CheckDeviceUI()
+ except Error:
+ self.CheckDeviceUI()
+
+ finally:
+ QApplication.restoreOverrideCursor()
+
+ if printed:
+ QMessageBox.information(self,
+ self.caption(),
+ self.__tr("<p><b>A test page should be printing on your printer.</b><p>If the page fails to print, please visit http://hplip.sourceforge.net for troubleshooting and support."),
+ QMessageBox.Ok,
+ QMessageBox.NoButton,
+ QMessageBox.NoButton)
+
+ self.dialog.accept()
+
+
+ def CheckDeviceUI(self):
+ self.FailureUI(self.__tr("<b>Device is busy or in an error state.</b><p>Please check device and try again."))
+
+
+ def FailureUI(self, error_text):
+ QMessageBox.critical(self,
+ self.caption(),
+ error_text,
+ QMessageBox.Ok,
+ QMessageBox.NoButton,
+ QMessageBox.NoButton)
+
+
+ def __tr(self,s,c = None):
+ return qApp.translate("ScrollTestpageView",s,c)
+
+# ***********************************************************************************
+#
+# ScrollPrinterInfoView (View Device Information)
+#
+# ***********************************************************************************
+
+class ScrollPrinterInfoView(ScrollView):
+ def __init__(self, service, parent = None, form=None, name = None,fl = 0):
+ ScrollView.__init__(self, service, parent, name, fl)
+
+
+ def fillControls(self):
+ ScrollView.fillControls(self)
+
+ printers = []
+ for p in self.printers:
+ if p.device_uri == self.cur_device.device_uri:
+ printers.append(p)
+
+ if not printers:
+ self.addGroupHeading("error_title", self.__tr("No printers found for this device."))
+ else:
+ for p in printers:
+ self.addPrinterInfo(p)
+
+ self.maximizeControl()
+
+
+ def addPrinterInfo(self, p):
+ self.addGroupHeading(p.name, p.name)
+ widget = self.getWidget()
+
+ layout1 = QVBoxLayout(widget,5,10,"layout1")
+
+ textLabel2 = QLabel(widget,"textLabel2")
+
+ if p.device_uri.startswith("hpfax:"):
+ s = self.__tr("Fax")
+ else:
+ s = self.__tr("Printer")
+
+ textLabel2.setText(self.__tr("Type: %1").arg(s))
+ layout1.addWidget(textLabel2)
+
+ textLabel3 = QLabel(widget,"textLabel3")
+ textLabel3.setText(self.__tr("Location: %1").arg(p.location))
+ layout1.addWidget(textLabel3)
+
+ textLabel4 = QLabel(widget,"textLabel4")
+ textLabel4.setText(self.__tr("Description/Info: %1").arg(p.info))
+ layout1.addWidget(textLabel4)
+
+ textLabel5 = QLabel(widget,"textLabel5")
+
+ if p.state == cups.IPP_PRINTER_STATE_IDLE:
+ s = self.__tr("Idle")
+ elif p.state == cups.IPP_PRINTER_STATE_PROCESSING:
+ s = self.__tr("Processing")
+ elif p.state == cups.IPP_PRINTER_STATE_STOPPED:
+ s = self.__tr("Stopped")
+ else:
+ s = self.__tr("Unknown")
+
+ textLabel5.setText(self.__tr("State: %1").arg(s))
+ layout1.addWidget(textLabel5)
+
+ textLabel6 = QLabel(widget,"textLabel6")
+ textLabel6.setText(self.__tr("PPD/Driver: %1").arg(p.makemodel))
+ layout1.addWidget(textLabel6)
+
+ textLabel7 = QLabel(widget,"textLabel7")
+ textLabel7.setText(self.__tr("CUPS/IPP Printer URI: %1").arg(p.printer_uri))
+ layout1.addWidget(textLabel7)
+
+ self.addWidget(widget, p.name)
+
+
+ def __tr(self,s,c = None):
+ return qApp.translate("ScrollPrinterInfoView",s,c)
+
+
+
+
+# ***********************************************************************************
+#
+# Color cal type 7
+#
+# ***********************************************************************************
+
+class ScrollColorCalView(ScrollView):
+ def __init__(self, service, parent = None, form=None, name = None,fl = 0):
+ ScrollView.__init__(self, service, parent, name, fl)
+ self.dialog = parent
+
+
+ def fillControls(self):
+ ScrollView.fillControls(self)
+ self.addLoadPaper(PAPER_TYPE_HP_ADV_PHOTO)
+
+ self.printButton = self.addActionButton("bottom_nav", self.__tr("Perform Color Calibration"),
+ self.colorcalButton_clicked, 'print.png', None)
+
+
+ def colorcalButton_clicked(self):
+ d = self.cur_device
+ printer_name = self.cur_printer
+ printed = False
+
+ try:
+ QApplication.setOverrideCursor(QApplication.waitCursor)
+
+ try:
+ d.open()
+ except Error:
+ self.CheckDeviceUI()
+ else:
+ if d.isIdleAndNoError():
+ QApplication.restoreOverrideCursor()
+ d.close()
+
+ d.setPML(pml.OID_PRINT_INTERNAL_PAGE, pml.PRINT_INTERNAL_PAGE_AUTOMATIC_COLOR_CALIBRATION)
+ printed = True
+
+ else:
+ d.close()
+ self.CheckDeviceUI()
+
+ finally:
+ QApplication.restoreOverrideCursor()
+
+ if printed:
+ QMessageBox.information(self,
+ self.caption(),
+ self.__tr("<p><b>A test page should be printing on your printer.</b><p>If the page fails to print, please visit http://hplip.sourceforge.net for troubleshooting and support."),
+ QMessageBox.Ok,
+ QMessageBox.NoButton,
+ QMessageBox.NoButton)
+
+ self.dialog.accept()
+
+
+ def CheckDeviceUI(self):
+ self.FailureUI(self.__tr("<b>Device is busy or in an error state.</b><p>Please check device and try again."))
+
+
+ def FailureUI(self, error_text):
+ QMessageBox.critical(self,
+ self.caption(),
+ error_text,
+ QMessageBox.Ok,
+ QMessageBox.NoButton,
+ QMessageBox.NoButton)
+
+
+ def __tr(self,s,c = None):
+ return qApp.translate("ScrollColorCalView",s,c)