1# -*- coding: utf-8 -*- 2# 3# (c) Copyright 2001-2015 HP Development Company, L.P. 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 2 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program; if not, write to the Free Software 17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18# 19# Authors: Don Welch, Naga Samrat Chowdary Narla 20# 21 22#from __future__ import generators 23 24# Std Lib 25import sys 26import time 27import os 28import gzip 29import select 30import struct 31import signal 32from base.sixext.moves import configparser 33# Local 34from base.g import * 35from base import device, utils, pml, maint, models, pkit, os_utils 36from prnt import cups 37from base.sixext import PY3 38from base.codes import * 39from .ui_utils import * 40import hpmudext 41from installer.core_install import * 42# Qt 43from PyQt5.QtCore import * 44from PyQt5.QtGui import * 45from PyQt5.QtWidgets import * 46import collections 47 48# dbus 49try: 50 import dbus 51 from dbus.mainloop.glib import DBusGMainLoop 52 from dbus import lowlevel 53except ImportError: 54 log.error("Unable to load DBus libraries. Please check your installation and try again.") 55 if PY3: # Workaround due to incomplete Python3 support in Linux distros. 56 log.error("Please upgrade your python installation to the latest available version.") 57 sys.exit(1) 58 59import warnings 60# Ignore: .../dbus/connection.py:242: DeprecationWarning: object.__init__() takes no parameters 61# (occurring on Python 2.6/dBus 0.83/Ubuntu 9.04) 62warnings.simplefilter("ignore", DeprecationWarning) 63 64 65# Main form 66from .devmgr5_base import Ui_MainWindow 67from .devmgr_ext import Ui_MainWindow_Derived 68# Aux. dialogs 69from .faxsetupdialog import FaxSetupDialog 70from .plugindialog import PluginDialog 71from .firmwaredialog import FirmwareDialog 72from .aligndialog import AlignDialog 73from .printdialog import PrintDialog 74from .makecopiesdialog import MakeCopiesDialog 75from .sendfaxdialog import SendFaxDialog 76from .fabwindow import FABWindow 77from .devicesetupdialog import DeviceSetupDialog 78from .printtestpagedialog import PrintTestPageDialog 79from .infodialog import InfoDialog 80from .cleandialog import CleanDialog 81from .colorcaldialog import ColorCalDialog 82from .linefeedcaldialog import LineFeedCalDialog 83from .pqdiagdialog import PQDiagDialog 84from .nodevicesdialog import NoDevicesDialog 85from .aboutdialog import AboutDialog 86 87# Other forms and controls 88from .settingsdialog import SettingsDialog 89from .printsettingstoolbox import PrintSettingsToolbox 90 91 92from base import os_utils 93 94# all in seconds 95MIN_AUTO_REFRESH_RATE = 5 96MAX_AUTO_REFRESH_RATE = 60 97DEF_AUTO_REFRESH_RATE = 30 98 99 100device_list = {} # { Device_URI : device.Device(), ... } 101model_obj = models.ModelData() # Used to convert dbus xformed data back to plain Python types 102 103 104# *********************************************************************************** 105# 106# ITEM/UTILITY UI CLASSES 107# 108# *********************************************************************************** 109 110 111class FuncViewItem(QListWidgetItem): 112 def __init__(self, parent, text, pixmap, tooltip_text, cmd): 113 QListWidgetItem.__init__(self, QIcon(pixmap), text, parent) 114 self.tooltip_text = tooltip_text 115 self.cmd = cmd 116 117# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 118 119class DeviceViewItem(QListWidgetItem): 120 def __init__(self, parent, text, pixmap, device_uri, is_avail=True): 121 QListWidgetItem.__init__(self, QIcon(pixmap), text, parent) 122 self.device_uri = device_uri 123 self.is_avail = is_avail 124 self.setTextAlignment(Qt.AlignHCenter) 125 126# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 127 128class PluginInstall(QObject): 129 def __init__(self, parent, plugin_type, plugin_installed): 130 self.parent = parent 131 self.plugin_type = plugin_type 132 self.plugin_installed = plugin_installed 133 134 135 def exec_(self): 136 install_plugin = True 137 138 if self.plugin_installed: 139 install_plugin = QMessageBox.warning(self.parent, 140 self.parent.windowTitle(), 141 self.__tr("<b>The HPLIP plugin is already installed.</b><p>Do you want to continue and re-install it?"), 142 QMessageBox.Yes, 143 QMessageBox.No, 144 QMessageBox.NoButton) == QMessageBox.Yes 145 146 if install_plugin: 147 ok, sudo_ok = pkit.run_plugin_command(self.plugin_type == PLUGIN_REQUIRED, self.parent.cur_device.mq['plugin-reason']) 148 if not sudo_ok: 149 QMessageBox.critical(self.parent, 150 self.parent.windowTitle(), 151 self.__tr("<b>Unable to find an appropriate su/sudo utility to run hp-plugin.</b><p>Install kdesu, gnomesu, or gksu.</p>"), 152 QMessageBox.Ok, 153 QMessageBox.NoButton, 154 QMessageBox.NoButton) 155 156 157 def __tr(self,s,c = None): 158 return qApp.translate("DevMgr5",s,c) 159 160 161 162# *********************************************************************************** 163# 164# MAINWINDOW 165# 166# *********************************************************************************** 167 168''' 169class Ui_MainWindow_Derived(Ui_MainWindow): 170 def setupUi(self, MainWindow, latest_available_version, Is_autoInstaller_distro): 171 super().setupUi(MainWindow) 172 self.DiagnoseQueueAction = QAction(MainWindow) 173 self.DiagnoseQueueAction.setObjectName("DiagnoseQueueAction") 174 self.DiagnoseHPLIPAction = QAction(MainWindow) 175 self.DiagnoseHPLIPAction.setObjectName("DiagnoseHPLIPAction") 176 177 self.latest_available_version = latest_available_version 178 self.Is_autoInstaller_distro = Is_autoInstaller_distro 179 if self.latest_available_version is not "": 180 self.tab_3 = QWidget() 181 self.tab_3.setObjectName("tab_3") 182 self.label = QLabel(self.tab_3) 183 self.label.setGeometry(QRect(30, 45, 300, 17)) 184 self.label.setObjectName("label") 185 if self.Is_autoInstaller_distro: 186 self.InstallLatestButton = QPushButton(self.tab_3) 187 self.InstallLatestButton.setGeometry(QRect(351, 40, 96, 27)) 188 self.InstallLatestButton.setObjectName("pushButton") 189 else: 190 self.ManualInstalllabel = QLabel(self.tab_3) 191 self.ManualInstalllabel.setGeometry(QRect(30, 70,300, 45)) 192 self.ManualInstalllabel.setObjectName("label") 193 self.InstallLatestButton = QPushButton(self.tab_3) 194 self.InstallLatestButton.setGeometry(QRect(295, 80, 110, 25)) 195 self.InstallLatestButton.setObjectName("pushButton") 196 self.Tabs.addTab(self.tab_3, "") 197 # super().setupUi(MainWindow) 198 199 def retranslateUi(self, MainWindow): 200 super().retranslateUi(MainWindow) 201 if self.latest_available_version is not "": 202 self.label.setText(QtGui.QApplication.translate("MainWindow", "New version of HPLIP-%s is available"%self.latest_available_version, None)) 203 self.Tabs.setTabText(self.Tabs.indexOf(self.tab_3), QtGui.QApplication.translate("MainWindow", "Upgrade", None)) 204 if self.Is_autoInstaller_distro: 205 self.InstallLatestButton.setText(QtGui.QApplication.translate("MainWindow", "Install now", None)) 206 else: 207 msg="Please install manually as mentioned in " 208 self.ManualInstalllabel.setText(QtGui.QApplication.translate("MainWindow", msg, None)) 209 self.InstallLatestButton.setText(QtGui.QApplication.translate("MainWindow", "HPLIP website", None)) 210''' 211 212class DevMgr5(Ui_MainWindow_Derived, Ui_MainWindow, QMainWindow): 213 def __init__(self, toolbox_version, initial_device_uri=None, 214 dbus_loop=None, parent=None, name=None, fl=0): 215 216 # QMainWindow.__init__(self, parent) 217 super(DevMgr5, self).__init__(parent) 218 219 log.debug("Initializing toolbox UI (Qt5)...") 220 log.debug("HPLIP Version: %s" % prop.installed_version) 221 222 223 self.toolbox_version = toolbox_version 224 self.initial_device_uri = initial_device_uri 225 self.device_vars = {} 226 self.num_devices = 0 227 self.cur_device = None 228 self.cur_printer = None 229 self.updating = False 230 self.init_failed = False 231 self.service = None 232 self.Is_autoInstaller_distro = False # True-->tier1(supports auto installation). False--> tier2(manual installation) 233 234 # Distro insformation 235 core = CoreInstall(MODE_CHECK) 236# core.init() 237 self.Is_autoInstaller_distro = core.is_auto_installer_support() 238 # User settings 239 self.user_settings = UserSettings() 240 self.user_settings.load() 241 self.user_settings.debug() 242 self.cur_device_uri = self.user_settings.last_used_device_uri 243 installed_version=sys_conf.get('hplip','version') 244 if not utils.Is_HPLIP_older_version( installed_version, self.user_settings.latest_available_version): 245 self.setupUi(self,"",self.Is_autoInstaller_distro) 246 else: 247 self.setupUi(self, self.user_settings.latest_available_version,self.Is_autoInstaller_distro) 248 249 # Other initialization 250 self.initDBus() 251 self.initPixmaps() 252 self.initMisc() 253 self.initUI() 254 255 cups.setPasswordCallback(showPasswordUI) 256 257 if not prop.doc_build: 258 self.ContentsAction.setEnabled(False) 259 260 self.allow_auto_refresh = True 261 QTimer.singleShot(0, self.initalUpdate) 262 263 264 # *********************************************************************************** 265 # 266 # INIT 267 # 268 # *********************************************************************************** 269 270 # TODO: Make sbus init mandatory success, else exit 271 def initDBus(self): 272 self.dbus_loop = DBusGMainLoop(set_as_default=True) 273 self.dbus_avail, self.service, self.session_bus = device.init_dbus(self.dbus_loop) 274 275 if not self.dbus_avail: 276 log.error("dBus initialization error. Exiting.") 277 self.init_failed = True 278 return 279 280 # Receive events from the session bus 281 self.session_bus.add_signal_receiver(self.handleSessionSignal, sender_keyword='sender', 282 destination_keyword='dest', interface_keyword='interface', 283 member_keyword='member', path_keyword='path') 284 285 286 def initPixmaps(self): 287 self.func_icons_cached = False 288 self.func_icons = {} 289 self.device_icons = {} 290 291 # Application icon 292 self.setWindowIcon(QIcon(load_pixmap('hp_logo', '128x128'))) 293 294 self.fax_icon = load_pixmap("fax2", "other") 295 296 297 def initUI(self): 298 # Setup device icon list 299 self.DeviceList.setSortingEnabled(True) 300 self.DeviceList.setContextMenuPolicy(Qt.CustomContextMenu) 301 self.setDeviceListViewMode(QListView.IconMode) 302 303 self.ViewAsIconsAction.triggered.connect(lambda: self.setDeviceListViewMode(QListView.IconMode)) 304 self.ViewAsListAction.triggered.connect(lambda: self.setDeviceListViewMode(QListView.ListMode)) 305 306 self.DeviceList.customContextMenuRequested["const QPoint &"].connect(self.DeviceList_customContextMenuRequested) 307 308 # Setup main menu 309 self.DeviceRefreshAction.setIcon(QIcon(load_pixmap("refresh1", "16x16"))) 310 self.DeviceRefreshAction.triggered.connect(self.DeviceRefreshAction_activated) 311 312 self.RefreshAllAction.setIcon(QIcon(load_pixmap("refresh", "16x16"))) 313 self.RefreshAllAction.triggered.connect(self.RefreshAllAction_activated) 314 315 self.SetupDeviceAction.setIcon(QIcon(load_pixmap('list_add', '16x16'))) 316 self.SetupDeviceAction.triggered.connect(self.SetupDeviceAction_activated) 317 318 self.RemoveDeviceAction.setIcon(QIcon(load_pixmap('list_remove', '16x16'))) 319 self.RemoveDeviceAction.triggered.connect(self.RemoveDeviceAction_activated) 320 321 self.PreferencesAction.setIcon(QIcon(load_pixmap('settings', '16x16'))) 322 self.PreferencesAction.triggered.connect(self.PreferencesAction_activated) 323 324 self.DiagnoseQueueAction.setIcon(QIcon(load_pixmap('warning', '16x16'))) 325 self.DiagnoseQueueAction.triggered.connect(self.DiagnoseQueueAction_activated) 326 327 self.DiagnoseHPLIPAction.setIcon(QIcon(load_pixmap('troubleshoot', '16x16'))) 328 self.DiagnoseHPLIPAction.triggered.connect(self.DiagnoseHPLIP_activated) 329 330 self.ContentsAction.setIcon(QIcon(load_pixmap("help", "16x16"))) 331 self.ContentsAction.triggered.connect(self.helpContents) 332 333 self.QuitAction.setIcon(QIcon(load_pixmap("quit", "16x16"))) 334 self.QuitAction.triggered.connect(self.quit) 335 336 self.AboutAction.triggered.connect(self.helpAbout) 337 338 self.PrintControlPrinterNameCombo.activated["const QString &"].connect(self.PrintControlPrinterNameCombo_activated) 339 self.PrintSettingsPrinterNameCombo.activated["const QString &"].connect(self.PrintSettingsPrinterNameCombo_activated) 340 signal.signal(signal.SIGINT, signal.SIG_IGN) 341 342 343 # Init tabs/controls 344 self.initActionsTab() 345 self.initStatusTab() 346 self.initSuppliesTab() 347 self.initPrintSettingsTab() 348 self.initPrintControlTab() 349 350 351 self.Tabs.currentChanged[int].connect(self.Tabs_currentChanged) 352 353 # Resize the splitter so that the device list starts as a single column 354 self.splitter.setSizes([80, 600]) 355 356 # Setup the Device List 357 self.DeviceList.setIconSize(QSize(60, 60)) 358 self.DeviceList.currentItemChanged["QListWidgetItem *", "QListWidgetItem *"].connect(self.DeviceList_currentChanged) 359 360 361 def initMisc(self): 362 self.TabIndex = { 0: self.updateActionsTab, 363 1: self.updateStatusTab, 364 2: self.updateSuppliesTab, 365 3: self.updatePrintSettingsTab, 366 4: self.updatePrintControlTab, 367 5:self.updateHPLIPupgrade, 368 } 369 370 # docs 371 self.docs = "http://hplip.sf.net" 372 373 if prop.doc_build: 374 g = os.path.join(sys_conf.get('dirs', 'doc'), 'index.html') 375 if os.path.exists(g): 376 self.docs = "file://%s" % g 377 378 # support 379 self.support = "https://launchpad.net/hplip" 380 381 382 383 def initalUpdate(self): 384 if self.init_failed: 385 self.close() 386 return 387 388 self.rescanDevices() 389 390 cont = True 391 if self.initial_device_uri is not None: 392 if not self.activateDevice(self.initial_device_uri): 393 log.error("Device %s not found" % self.initial_device_uri) 394 cont = False 395 396 if self.cur_printer: 397 self.getPrinterState() 398 399 if self.printer_state == cups.IPP_PRINTER_STATE_STOPPED: 400 self.cur_device.sendEvent(EVENT_PRINTER_QUEUE_STOPPED, self.cur_printer) 401 402 if not self.printer_accepting: 403 self.cur_device.sendEvent(EVENT_PRINTER_QUEUE_REJECTING_JOBS, self.cur_printer) 404 405 406 def activateDevice(self, device_uri): 407 log.debug(log.bold("Activate: %s %s %s" % ("*"*20, device_uri, "*"*20))) 408 index = 0 409 d = self.DeviceList.item(index) #firstItem() 410 found = False 411 412 while d is not None: 413 if d.device_uri == device_uri: 414 found = True 415 self.DeviceList.setSelected(d, True) 416 self.DeviceList.setCurrentItem(d) 417 break 418 419 index += 1 420 d = self.DeviceList.item(index) 421 422 return found 423 424 425 426 # *********************************************************************************** 427 # 428 # UPDATES/NOTIFICATIONS 429 # 430 # *********************************************************************************** 431 432 def handleSessionSignal(self, *args, **kwds): 433 if kwds['interface'] == 'com.hplip.Toolbox' and \ 434 kwds['member'] == 'Event': 435 436 log.debug("Handling event...") 437 event = device.Event(*args[:6]) 438 event.debug() 439 440 if event.event_code < EVENT_MIN_USER_EVENT: 441 pass 442 443 elif event.event_code == EVENT_DEVICE_UPDATE_REPLY: 444 log.debug("EVENT_DEVICE_UPDATE_REPLY (%s)" % event.device_uri) 445 dev = self.findDeviceByURI(event.device_uri) 446 447 if dev is not None: 448 try: 449 self.service.GetStatus(event.device_uri, reply_handler=self.handleStatusReply, 450 error_handler=self.handleStatusError) 451 452 except dbus.exceptions.DBusException as e: 453 log.error("dbus call to GetStatus() failed.") 454 455 elif event.event_code == EVENT_USER_CONFIGURATION_CHANGED: 456 log.debug("EVENT_USER_CONFIGURATION_CHANGED") 457 self.user_settings.load() 458 459 elif event.event_code == EVENT_HISTORY_UPDATE: 460 log.debug("EVENT_HISTORY_UPDATE (%s)" % event.device_uri) 461 dev = self.findDeviceByURI(event.device_uri) 462 if dev is not None: 463 self.updateHistory(dev) 464 465 elif event.event_code == EVENT_SYSTEMTRAY_EXIT: 466 log.debug("EVENT_SYSTEMTRAY_EXIT") 467 log.warn("HPLIP Status Service was closed. HPLIP Device Manager will now exit.") 468 cups.releaseCupsInstance() 469 self.close() 470 471 elif event.event_code == EVENT_RAISE_DEVICE_MANAGER: 472 log.debug("EVENT_RAISE_DEVICE_MANAGER") 473 self.showNormal() 474 self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive) 475 self.raise_() 476 477 elif event.event_code in (EVENT_DEVICE_START_POLLING, 478 EVENT_DEVICE_STOP_POLLING, 479 EVENT_POLLING_REQUEST): 480 pass 481 482 else: 483 log.error("Unhandled event: %d" % event.event_code) 484 485 486 def handleStatusReply(self, device_uri, data): 487 dev = self.findDeviceByURI(device_uri) 488 if dev is not None: 489 t = {} 490 for key in data: 491 value = model_obj.convert_data(str(key), str(data[key])) 492 t.setdefault(key, value) 493 494 dev.dq = t.copy() 495 for d in dev.dq: 496 dev.__dict__[d.replace('-','_')] = dev.dq[d] 497 498 self.updateDevice(dev) 499 500 501 def handleStatusError(self, e): 502 log.error(str(e)) 503 504 505 def updateHistory(self, dev=None): 506 if dev is None: 507 dev = self.cur_device 508 509 try: 510 self.service.GetHistory(dev.device_uri, reply_handler=self.handleHistoryReply, 511 error_handler=self.handleHistoryError) 512 except dbus.exceptions.DBusException as e: 513 log.error("dbus call to GetHistory() failed.") 514 515 516 def handleHistoryReply(self, device_uri, history): 517 dev = self.findDeviceByURI(device_uri) 518 if dev is not None: 519 result = [] 520 history.reverse() 521 522 for h in history: 523 result.append(device.Event(*tuple(h))) 524 525 try: 526 self.error_code = result[0].event_code 527 except IndexError: 528 self.error_code = STATUS_UNKNOWN 529 530 dev.error_state = STATUS_TO_ERROR_STATE_MAP.get(self.error_code, ERROR_STATE_CLEAR) 531 dev.hist = result 532 533 self.updateDevice(dev) 534 535 536 def handleHistoryError(self, e): 537 log.error(str(e)) 538 539 540 def sendMessage(self, device_uri, printer_name, event_code, username=prop.username, 541 job_id=0, title=''): 542 543 device.Event(device_uri, printer_name, event_code, username, 544 job_id, title).send_via_dbus(self.session_bus) 545 546 547 def timedRefresh(self): 548 if not self.updating and self.user_settings.auto_refresh and self.allow_auto_refresh: 549 log.debug("Refresh timer...") 550 self.cleanupChildren() 551 552 if self.user_settings.auto_refresh_type == 0: 553 self.requestDeviceUpdate() 554 else: 555 self.rescanDevices() 556 557 558 # *********************************************************************************** 559 # 560 # TAB/DEVICE CHANGE SLOTS 561 # 562 # *********************************************************************************** 563 564 def Tabs_currentChanged(self, tab=0): 565 """ Called when the active tab changes. 566 Update newly displayed tab. 567 """ 568 if self.cur_device is not None: 569 self.TabIndex[tab]() 570 571 def updateAllTabs(self): 572 for tab in self.TabIndex: 573 self.TabIndex[tab]() 574 575 576 def updateCurrentTab(self): 577 log.debug("updateCurrentTab()") 578 self.TabIndex[self.Tabs.currentIndex()]() 579 580 581 582 # *********************************************************************************** 583 # 584 # DEVICE ICON LIST/DEVICE UPDATE(S) 585 # 586 # *********************************************************************************** 587 588 589 def DeviceRefreshAction_activated(self): 590 self.DeviceRefreshAction.setEnabled(False) 591 self.requestDeviceUpdate() 592 self.DeviceRefreshAction.setEnabled(True) 593 594 595 def RefreshAllAction_activated(self): 596 self.rescanDevices() 597 598 599 def setDeviceListViewMode(self, mode): 600 if mode == QListView.ListMode: 601 self.DeviceList.setViewMode(QListView.ListMode) 602 self.ViewAsListAction.setEnabled(False) 603 self.ViewAsIconsAction.setEnabled(True) 604 else: 605 self.DeviceList.setViewMode(QListView.IconMode) 606 self.ViewAsListAction.setEnabled(True) 607 self.ViewAsIconsAction.setEnabled(False) 608 609 610 def createDeviceIcon(self, dev=None): 611 if dev is None: 612 dev = self.cur_device 613 614 try: 615 dev.icon 616 except AttributeError: 617 dev.icon = "default_printer" 618 619 try: 620 self.device_icons[dev.icon] 621 except: 622 self.device_icons[dev.icon] = load_pixmap(dev.icon, 'devices') 623 624 pix = self.device_icons[dev.icon] 625 626 w, h = pix.width(), pix.height() 627 error_state = dev.error_state 628 icon = QPixmap(w, h) 629 p = QPainter(icon) 630 p.eraseRect(0, 0, icon.width(), icon.height()) 631 p.drawPixmap(0, 0, pix) 632 633 try: 634 tech_type = dev.tech_type 635 except AttributeError: 636 tech_type = TECH_TYPE_NONE 637 638 if dev.device_type == DEVICE_TYPE_FAX: 639 p.drawPixmap(w - self.fax_icon.width(), 0, self.fax_icon) 640 641 if error_state != ERROR_STATE_CLEAR: 642 if tech_type in (TECH_TYPE_COLOR_INK, TECH_TYPE_MONO_INK): 643 status_icon = getStatusOverlayIcon(error_state)[0] # ink 644 else: 645 status_icon = getStatusOverlayIcon(error_state)[1] # laser 646 647 if status_icon is not None: 648 p.drawPixmap(0, 0, status_icon) 649 650 p.end() 651 return icon 652 653 654 def refreshDeviceList(self): 655 global devices 656 log.debug("Rescanning device list...") 657 658 if 1: 659 beginWaitCursor() 660 self.updating = True 661 662 self.setWindowTitle(self.__tr("Refreshing Device List - HP Device Manager")) 663 self.statusBar().showMessage(self.__tr("Refreshing device list...")) 664 665 self.cups_devices = device.getSupportedCUPSDevices(['hp', 'hpfax']) 666 667 current = None 668 669 try: 670 adds = [] 671 for d in self.cups_devices: 672 if d not in device_list: 673 adds.append(d) 674 675 log.debug("Adds: %s" % ','.join(adds)) 676 677 removals = [] 678 for d in device_list: 679 if d not in self.cups_devices: 680 removals.append(d) 681 682 log.debug("Removals (1): %s" % ','.join(removals)) 683 684 updates = [] 685 for d in device_list: 686 if d not in adds and d not in removals: 687 updates.append(d) 688 689 log.debug("Updates: %s" % ','.join(updates)) 690 691 for d in adds: 692 log.debug("adding: %s" % d) 693 # Note: Do not perform any I/O with this device. 694 dev = device.Device(d, service=self.service, disable_dbus=False) 695 696 if not dev.supported: 697 log.debug("Unsupported model - removing device.") 698 removals.append(d) 699 continue 700 701 icon = self.createDeviceIcon(dev) 702 703 if dev.device_type == DEVICE_TYPE_FAX: 704 DeviceViewItem(self.DeviceList, self.__tr("%s (Fax)"%dev.model_ui), 705 icon, d) 706 else: 707 if dev.fax_type: 708 DeviceViewItem(self.DeviceList, self.__tr("%s (Printer)"%dev.model_ui), 709 icon, d) 710 else: 711 DeviceViewItem(self.DeviceList, dev.model_ui, 712 icon, d) 713 714 device_list[d] = dev 715 716 log.debug("Removals (2): %s" % ','.join(removals)) 717 removed_device=None 718 for d in removals: 719 removed_device = d 720 index = self.DeviceList.count()-1 721 item = self.DeviceList.item(index) 722 log.debug("removing: %s" % d) 723 724 try: 725 del device_list[d] 726 except KeyError: 727 pass 728 729 while index >= 0 and item is not None: 730 if item.device_uri == d: 731 self.DeviceList.takeItem(index) 732 break 733 734 index -= 1 735 item = self.DeviceList.item(index) 736 737 qApp.processEvents() 738 739 self.DeviceList.updateGeometry() 740 qApp.processEvents() 741 742 if len(device_list): 743 for tab in self.TabIndex: 744 self.Tabs.setTabEnabled(tab, True) 745 746 if self.cur_device_uri: 747 index = 0 748 item = first_item = self.DeviceList.item(index) 749 750 while item is not None: 751 qApp.processEvents() 752 if item.device_uri == self.cur_device_uri: 753 current = item 754 self.statusBar().showMessage(self.cur_device_uri) 755 break 756 757 index += 1 758 item = self.DeviceList.item(index) 759 760 else: 761 self.cur_device = None 762 self.cur_device_uri = '' 763 764 if self.cur_device is None: 765 i = self.DeviceList.item(0) 766 if i is not None: 767 self.cur_device_uri = i.device_uri 768 self.cur_device = device_list[self.cur_device_uri] 769 current = i 770 771 self.updatePrinterCombos() 772 773 if self.cur_device_uri: 774 #user_conf.set('last_used', 'device_uri',self.cur_device_uri) 775 self.user_settings.last_used_device_uri = self.cur_device_uri 776 self.user_settings.save() 777 778 for d in updates + adds: 779 if d not in removals: 780 self.requestDeviceUpdate(device_list[d]) 781 782 else: # no devices 783 self.cur_device = None 784 self.DeviceRefreshAction.setEnabled(False) 785 self.RemoveDeviceAction.setEnabled(False) 786 #self.DiagnoseQueueAction.setEnabled(False) 787 self.updating = False 788 self.statusBar().showMessage(self.__tr("Press F6 to refresh.")) 789 790 for tab in self.TabIndex: 791 self.Tabs.setTabEnabled(tab, False) 792 793 endWaitCursor() 794 795 dlg = NoDevicesDialog(self) 796 dlg.exec_() 797 798 finally: 799 self.updating = False 800 endWaitCursor() 801 802 if current is not None: 803 self.DeviceList.setCurrentItem(current) 804 805 self.DeviceRefreshAction.setEnabled(True) 806 807 if self.cur_device is not None: 808 self.RemoveDeviceAction.setEnabled(True) 809 #self.DiagnoseQueueAction.setEnabled(True) 810 811 self.statusBar().showMessage(self.cur_device_uri) 812 self.updateWindowTitle() 813 814 815 def updateWindowTitle(self): 816 if self.cur_device.device_type == DEVICE_TYPE_FAX: 817 self.setWindowTitle(self.__tr("HP Device Manager - %s (Fax)"%self.cur_device.model_ui)) 818 else: 819 if self.cur_device.fax_type: 820 self.setWindowTitle(self.__tr("HP Device Manager - %s (Printer)"%self.cur_device.model_ui)) 821 else: 822 self.setWindowTitle(self.__tr("HP Device Manager - %s"%self.cur_device.model_ui)) 823 824 self.statusBar().showMessage(self.cur_device_uri) 825 826 827 def updateDeviceByURI(self, device_uri): 828 return self.updateDevice(self.findDeviceByURI(device_uri)) 829 830 831 def updateDevice(self, dev=None, update_tab=True): 832 833 """ Update the device icon and currently displayed tab. 834 """ 835 if dev is None: 836 dev = self.cur_device 837 838 log.debug("updateDevice(%s)" % dev.device_uri) 839 840 item = self.findItem(dev) 841 842 if item is not None: 843 item.setIcon(QIcon(self.createDeviceIcon(dev))) 844 845 if dev is self.cur_device and update_tab: 846 self.updatePrinterCombos() 847 self.updateCurrentTab() 848 self.statusBar().showMessage(self.cur_device_uri) 849 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 850 self.Tabs.setTabText(self.Tabs.indexOf(self.Settings), QApplication.translate("MainWindow", "Print Settings", None)) 851 self.Tabs.setTabText(self.Tabs.indexOf(self.Control), QApplication.translate("MainWindow", "Printer Control", None)) 852 else: 853 self.Tabs.setTabText(self.Tabs.indexOf(self.Settings), QApplication.translate("MainWindow", "Fax Settings", None)) 854 self.Tabs.setTabText(self.Tabs.indexOf(self.Control), QApplication.translate("MainWindow", "Fax Control", None)) 855 856 857 def DeviceList_currentChanged(self, i, j): 858 if i is not None and not self.updating: 859 self.cur_device_uri = self.DeviceList.currentItem().device_uri 860 self.cur_device = device_list[self.cur_device_uri] 861 #user_conf.set('last_used', 'device_uri', self.cur_device_uri) 862 self.user_settings.last_used_device_uri = self.cur_device_uri 863 self.user_settings.save() 864 865 self.updateDevice() 866 self.updateWindowTitle() 867 868 869 def findItem(self, dev): 870 if dev is None: 871 dev = self.cur_device 872 873 return self.findItemByURI(dev.device_uri) 874 875 876 def findItemByURI(self, device_uri): 877 index = 0 878 item = self.DeviceList.item(index) 879 880 while item is not None: 881 if item.device_uri == device_uri: 882 return item 883 884 index += 1 885 item = self.DeviceList.item(index) 886 887 888 def findDeviceByURI(self, device_uri): 889 try: 890 return device_list[device_uri] 891 except: 892 return None 893 894 895 def requestDeviceUpdate(self, dev=None, item=None): 896 """ Submit device update request to update thread. """ 897 898 if dev is None: 899 dev = self.cur_device 900 901 if dev is not None: 902 dev.error_state = ERROR_STATE_REFRESHING 903 self.updateDevice(dev, update_tab=False) 904 905 self.sendMessage(dev.device_uri, '', EVENT_DEVICE_UPDATE_REQUESTED) 906 907 908 def rescanDevices(self): 909 """ Rescan and update all devices. """ 910 if not self.updating: 911 self.RefreshAllAction.setEnabled(False) 912 try: 913 self.refreshDeviceList() 914 finally: 915 self.RefreshAllAction.setEnabled(True) 916 917 918 def callback(self): 919 qApp.processEvents() 920 921 922 # *********************************************************************************** 923 # 924 # DEVICE LIST RIGHT CLICK 925 # 926 # *********************************************************************************** 927 928 def DeviceList_customContextMenuRequested(self, p): 929 d = self.cur_device 930 931 if d is not None: 932 avail = d.device_state != DEVICE_STATE_NOT_FOUND and d.supported 933 printer = d.device_type == DEVICE_TYPE_PRINTER and avail 934 935 fax = d.fax_type > FAX_TYPE_NONE and prop.fax_build and d.device_type == DEVICE_TYPE_FAX and \ 936 sys.hexversion >= 0x020300f0 and avail 937 938 scan = d.scan_type > SCAN_TYPE_NONE and prop.scan_build and \ 939 printer and self.user_settings.cmd_scan 940 941 cpy = d.copy_type > COPY_TYPE_NONE and printer 942 943 popup = QMenu(self) 944 945 item = self.DeviceList.currentItem() 946 if item is not None: 947 if self.cur_device.error_state != ERROR_STATE_ERROR: 948 if printer: 949 popup.addAction(self.__tr("Print..."), lambda: self.contextMenuFunc(PrintDialog(self, self.cur_printer))) 950 951 if scan: 952 popup.addAction(self.__tr("Scan..."), lambda: self.contextMenuFunc(self.user_settings.cmd_scan)) #self.ScanButton_clicked) 953 954 if cpy: 955 popup.addAction(self.__tr("Make Copies..."), lambda: MakeCopiesDialog(self, self.cur_device_uri)) #self.MakeCopiesButton_clicked) 956 957 else: # self.cur_device.device_type == DEVICE_TYPE_FAX: 958 if fax: 959 popup.addAction(self.__tr("Send Fax..."), lambda: self.contextMenuFunc(SendFaxDialog(self, self.cur_printer, self.cur_device_uri))) #self.SendFaxButton_clicked) 960 961 popup.addSeparator() 962 963 if not self.updating: 964 popup.addAction(self.__tr("Refresh Device"), self.requestDeviceUpdate) #self.DeviceRefreshAction_activated) 965 966 if not self.updating: 967 popup.addAction(self.__tr("Refresh All"), self.rescanDevices) #self.RefreshAllAction_activated) 968 969 popup.addSeparator() 970 971 if self.DeviceList.viewMode() == QListView.IconMode: 972 popup.addAction(self.__tr("View as List"), lambda: self.setDeviceListViewMode(QListView.ListMode)) 973 else: 974 popup.addAction(self.__tr("View as Icons"), lambda: self.setDeviceListViewMode(QListView.IconMode)) 975 976 popup.exec_(self.DeviceList.mapToGlobal(p)) 977 978 979 def contextMenuFunc(self, f): 980 self.sendMessage('', '', EVENT_DEVICE_STOP_POLLING) 981 try: 982 try: 983 f.exec_() # Dialog 984 except AttributeError: 985 beginWaitCursor() 986 987 if f.split(':')[0] in ('http', 'https', 'file'): 988 log.debug("Opening browser to: %s" % f) 989 utils.openURL(f) 990 else: 991 self.runExternalCommand(f) 992 993 QTimer.singleShot(1000, self.unlockClick) 994 finally: 995 self.sendMessage('', '', EVENT_DEVICE_START_POLLING) 996 997 998 999 # *********************************************************************************** 1000 # 1001 # PRINTER NAME COMBOS 1002 # 1003 # *********************************************************************************** 1004 1005 1006 def updatePrinterCombos(self): 1007 self.PrintSettingsPrinterNameCombo.clear() 1008 self.PrintControlPrinterNameCombo.clear() 1009 1010 if self.cur_device is not None and \ 1011 self.cur_device.supported: 1012 1013 self.cur_device.updateCUPSPrinters() 1014 1015 for c in self.cur_device.cups_printers: 1016 self.PrintSettingsPrinterNameCombo.insertItem(0, c) 1017 self.PrintControlPrinterNameCombo.insertItem(0, c) 1018 1019 self.cur_printer = to_unicode(self.PrintSettingsPrinterNameCombo.currentText()) 1020 1021 1022 def PrintSettingsPrinterNameCombo_activated(self, s): 1023 self.cur_printer = to_unicode(s) 1024 self.updateCurrentTab() 1025 1026 1027 def PrintControlPrinterNameCombo_activated(self, s): 1028 self.cur_printer = to_unicode(s) 1029 self.updateCurrentTab() 1030 1031 1032 1033 # *********************************************************************************** 1034 # 1035 # FUNCTIONS/ACTION TAB 1036 # 1037 # *********************************************************************************** 1038 1039 def initActionsTab(self): 1040 self.click_lock = None 1041 self.ActionsList.setIconSize(QSize(32, 32)) 1042 self.ActionsList.itemClicked["QListWidgetItem *"].connect(self.ActionsList_clicked) 1043 self.ActionsList.itemDoubleClicked["QListWidgetItem *"].connect(self.ActionsList_clicked) 1044 1045 1046 def updateActionsTab(self): 1047 beginWaitCursor() 1048 try: 1049 self.ActionsList.clear() 1050 1051 d = self.cur_device 1052 1053 if d is not None: 1054 avail = d.device_state != DEVICE_STATE_NOT_FOUND and d.supported 1055 fax = d.fax_type > FAX_TYPE_NONE and prop.fax_build and d.device_type == DEVICE_TYPE_FAX and \ 1056 sys.hexversion >= 0x020300f0 and avail 1057 printer = d.device_type == DEVICE_TYPE_PRINTER and avail 1058 scan = d.scan_type > SCAN_TYPE_NONE and prop.scan_build and \ 1059 printer and self.user_settings.cmd_scan 1060 cpy = d.copy_type > COPY_TYPE_NONE and printer 1061 req_plugin = d.plugin == PLUGIN_REQUIRED 1062 opt_plugin = d.plugin == PLUGIN_OPTIONAL 1063 1064 try: 1065 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \ 1066 device.parseDeviceURI(self.cur_device_uri) 1067 except Error: 1068 return 1069 1070 hplip_conf = configparser.ConfigParser() 1071 fp = open("/usr/local/etc/hp/hplip.conf", "r") 1072 hplip_conf.readfp(fp) 1073 fp.close() 1074 1075 try: 1076 plugin_installed = utils.to_bool(hplip_conf.get("hplip", "plugin")) 1077 except configparser.NoOptionError: 1078 plugin_installed = False 1079 1080 if d.plugin != PLUGIN_NONE: 1081 if req_plugin and plugin_installed: 1082 x = self.__tr("Download and install<br>required plugin (already installed).") 1083 1084 elif req_plugin and not plugin_installed: 1085 x = self.__tr("Download and install<br>required plugin (needs installation).") 1086 1087 elif opt_plugin and plugin_installed: 1088 x = self.__tr("Download and install<br>optional plugin (already installed).") 1089 1090 elif opt_plugin and not plugin_installed: 1091 x = self.__tr("Download and install<br>optional plugin (needs installation).") 1092 1093 else: 1094 x = '' 1095 1096 # TODO: Cache this data structure 1097 # -- add a field that specifies if the icon should always show, or only when device is avail. 1098 # TODO: Tooltips 1099 # TODO: Right-click icon/list view menu 1100 1101 self.ICONS = [ 1102 1103 # PRINTER 1104 1105 (lambda : printer, 1106 self.__tr("Print"), # Text 1107 "print", # Icon 1108 self.__tr("Print documents or files."), # Tooltip 1109 lambda : PrintDialog(self, self.cur_printer)), # command/action 1110 1111 (lambda :scan, 1112 self.__tr("Scan"), 1113 "scan", 1114 self.__tr("Scan a document, image, or photograph.<br>"), 1115 self.user_settings.cmd_scan), 1116 1117 (lambda : cpy, 1118 self.__tr("Make Copies"), 1119 "makecopies", 1120 self.__tr("Make copies on the device controlled by the PC.<br>"), 1121 lambda : MakeCopiesDialog(self, self.cur_device_uri)), 1122 1123 # FAX 1124 1125 (lambda: fax, 1126 self.__tr("Send Fax"), 1127 "fax", 1128 self.__tr("Send a fax from the PC."), 1129 lambda : SendFaxDialog(self, self.cur_printer, self.cur_device_uri)), 1130 1131 (lambda: fax, 1132 self.__tr("Fax Setup"), 1133 "fax_setup", 1134 self.__tr("Fax support must be setup before you can send faxes."), 1135 lambda : FaxSetupDialog(self, self.cur_device_uri)), 1136 1137 (lambda: fax and self.user_settings.cmd_fab, 1138 self.__tr("Fax Address Book"), 1139 "fab", 1140 self.__tr("Setup fax phone numbers to use when sending faxes from the PC."), 1141 self.user_settings.cmd_fab), 1142 1143 # SETTINGS/TOOLS 1144 1145 (lambda : d.power_settings != POWER_SETTINGS_NONE and avail, 1146 self.__tr("Device Settings"), 1147 "settings", 1148 self.__tr("Your device has special device settings.<br>You may alter these settings here."), 1149 lambda : DeviceSetupDialog(self, self.cur_device_uri)), 1150 1151 (lambda : printer, 1152 self.__tr("Print Test Page"), 1153 "testpage", 1154 self.__tr("Print a test page to test the setup of your printer."), 1155 lambda : PrintTestPageDialog(self, self.cur_printer)), 1156 1157 (lambda : True, 1158 self.__tr("View Printer and Device Information"), 1159 "cups", 1160 self.__tr("View information about the device and all its CUPS queues."), 1161 lambda : InfoDialog(self, self.cur_device_uri)), 1162 1163 (lambda: printer and d.align_type != ALIGN_TYPE_NONE, 1164 self.__tr("Align Cartridges (Print Heads)"), 1165 "align", 1166 self.__tr("This will improve the quality of output when a new cartridge is installed."), 1167 lambda : AlignDialog(self, self.cur_device_uri)), 1168 1169 (lambda: printer and d.clean_type != CLEAN_TYPE_NONE, 1170 self.__tr("Clean Printheads"), 1171 "clean", 1172 self.__tr("You only need to perform this action if you are<br>having problems with poor printout quality due to clogged ink nozzles."), 1173 lambda : CleanDialog(self, self.cur_device_uri)), 1174 1175 (lambda: printer and d.color_cal_type != COLOR_CAL_TYPE_NONE and d.color_cal_type == COLOR_CAL_TYPE_TYPHOON, 1176 self.__tr("Color Calibration"), 1177 "colorcal", 1178 self.__tr("Use this procedure to optimimize your printer's color output<br>(requires glossy photo paper)."), 1179 lambda : ColorCalDialog(self, self.cur_device_uri)), 1180 1181 (lambda: printer and d.color_cal_type != COLOR_CAL_TYPE_NONE and d.color_cal_type != COLOR_CAL_TYPE_TYPHOON, 1182 self.__tr("Color Calibration"), 1183 "colorcal", 1184 self.__tr("Use this procedure to optimimize your printer's color output."), 1185 lambda : ColorCalDialog(self, self.cur_device_uri)), 1186 1187 (lambda: printer and d.linefeed_cal_type != LINEFEED_CAL_TYPE_NONE, 1188 self.__tr("Line Feed Calibration"), 1189 "linefeed_cal", 1190 self.__tr("Use line feed calibration to optimize print quality<br>(to remove gaps in the printed output)."), 1191 lambda : LineFeedCalDialog(self, self.cur_device_uri)), 1192 1193 (lambda: printer and d.pq_diag_type != PQ_DIAG_TYPE_NONE, 1194 self.__tr("Print Diagnostic Page"), 1195 "pq_diag", 1196 self.__tr("Your printer can print a test page <br>to help diagnose print quality problems."), 1197 lambda : PQDiagDialog(self, self.cur_device_uri)), 1198 1199 (lambda: printer and d.wifi_config >= WIFI_CONFIG_USB_XML and bus == 'usb', 1200 self.__tr("Wireless/wifi setup using USB"), 1201 "wireless", 1202 self.__tr("Configure your wireless capable printer using a temporary USB connection."), 1203 'hp-wificonfig -d %s' % self.cur_device_uri), 1204 1205 # FIRMWARE 1206 1207 (lambda : printer and d.fw_download , 1208 self.__tr("Download Firmware"), 1209 "firmware", 1210 self.__tr("Download firmware to your printer <br>(required on some devices after each power-up)."), 1211 lambda : FirmwareDialog(self, self.cur_device_uri)), 1212 1213 # PLUGIN 1214 1215 (lambda : printer and req_plugin, 1216 self.__tr("Install Required Plugin"), 1217 "plugin", 1218 x, 1219 lambda : PluginInstall(self, d.plugin, plugin_installed)), 1220 1221 (lambda : printer and opt_plugin, 1222 self.__tr("Install Optional Plugin"), 1223 "plugin", 1224 x, 1225 lambda : PluginInstall(self, d.plugin, plugin_installed)), 1226 1227 # EWS 1228 1229 (lambda : printer and d.embedded_server_type > EWS_NONE and bus == 'net', 1230 self.__tr("Open printer's web page in a browser"), 1231 "ews", 1232 self.__tr("The printer's web page has supply, status, and other information."), 1233 openEWS(host, zc)), 1234 1235 # HELP/WEBSITE 1236 1237 (lambda : True, 1238 self.__tr("Visit HPLIP Support Website"), 1239 "hp_logo", 1240 self.__tr("Visit HPLIP Support Website."), 1241 self.support), 1242 1243 (lambda : True, 1244 self.__tr("Help"), 1245 "help", 1246 self.__tr("View HPLIP help."), 1247 self.docs), 1248 1249 ] 1250 1251 if not self.func_icons_cached: 1252 for filte, text, icon, tooltip, cmd in self.ICONS: 1253 self.func_icons[icon] = load_pixmap(icon, '32x32') 1254 self.func_icons_cached = True 1255 1256 for fltr, text, icon, tooltip, cmd in self.ICONS: 1257 if fltr is not None: 1258 if not fltr(): 1259 continue 1260 1261 FuncViewItem(self.ActionsList, text, 1262 self.func_icons[icon], 1263 tooltip, 1264 cmd) 1265 finally: 1266 endWaitCursor() 1267 1268 1269 def ActionsList_clicked(self, item): 1270 if item is not None and self.click_lock is not item: 1271 self.click_lock = item 1272 if item.cmd and isinstance(item.cmd, collections.Callable): 1273 dlg = item.cmd() 1274 self.sendMessage('', '', EVENT_DEVICE_STOP_POLLING) 1275 try: 1276 dlg.exec_() 1277 finally: 1278 self.sendMessage('', '', EVENT_DEVICE_START_POLLING) 1279 1280 else: 1281 beginWaitCursor() 1282 if item.cmd.split(':')[0] in ('http', 'https', 'file'): 1283 log.debug("Opening browser to: %s" % item.cmd) 1284 utils.openURL(item.cmd) 1285 else: 1286 self.runExternalCommand(str(item.cmd)) 1287 1288 QTimer.singleShot(1000, self.unlockClick) 1289 1290 1291 def unlockClick(self): 1292 self.click_lock = None 1293 endWaitCursor() 1294 1295 1296 def ActionsList_customContextMenuRequested(self, p): 1297 print(p) 1298 #pass 1299 1300 1301 # *********************************************************************************** 1302 # 1303 # STATUS TAB 1304 # 1305 # *********************************************************************************** 1306 1307 def initStatusTab(self): 1308 self.StatusTable.setColumnCount(0) 1309 self.status_headers = [self.__tr(""), self.__tr("Status"), self.__tr("Date and Time"), 1310 self.__tr("Code"), self.__tr("Job ID"), self.__tr("Description")] 1311 1312 1313 def updateStatusTab(self): 1314 self.updateStatusLCD() 1315 self.updateStatusTable() 1316 1317 1318 def updateStatusLCD(self): 1319 if self.cur_device is not None and \ 1320 self.cur_device.hist and \ 1321 self.cur_device.supported: 1322 1323 dq = self.cur_device.dq 1324 1325 if dq.get('panel', 0) == 1: 1326 line1 = dq.get('panel-line1', '') 1327 line2 = dq.get('panel-line2', '') 1328 else: 1329 try: 1330 line1 = device.queryString(self.cur_device.hist[0].event_code) 1331 except (AttributeError, TypeError): 1332 line1 = '' 1333 1334 line2 = '' 1335 1336 self.drawStatusLCD(line1, line2) 1337 1338 else: 1339 if self.cur_device.status_type == STATUS_TYPE_NONE: 1340 self.drawStatusLCD(self.__tr("Status information not"), self.__tr("available for this device.")) 1341 1342 elif not self.cur_device.supported: 1343 self.drawStatusLCD(self.__tr("Device not supported.")) 1344 1345 elif not self.cur_device.hist: 1346 self.drawStatusLCD(self.__tr("No status history available.")) 1347 1348 else: 1349 self.drawStatusLCD() 1350 1351 1352 def drawStatusLCD(self, line1='', line2=''): 1353 pm = load_pixmap('panel_lcd', 'other') 1354 1355 p = QPainter() 1356 p.begin(pm) 1357 p.setPen(QColor(0, 0, 0)) 1358 p.setFont(self.font()) 1359 1360 x, y_line1, y_line2 = 10, 17, 33 1361 1362 # TODO: Scroll long lines 1363 if line1: 1364 p.drawText(x, y_line1, line1) 1365 1366 if line2: 1367 p.drawText(x, y_line2, line2) 1368 1369 p.end() 1370 1371 self.LCD.setPixmap(pm) 1372 1373 1374 1375 def updateStatusTable(self): 1376 self.StatusTable.clear() 1377 flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled 1378 1379 row = 0 1380 hist = self.cur_device.hist[:] 1381 1382 if hist: 1383 self.StatusTable.setRowCount(len(hist)) 1384 self.StatusTable.setColumnCount(len(self.status_headers)) 1385 self.StatusTable.setHorizontalHeaderLabels(self.status_headers) 1386 self.StatusTable.verticalHeader().hide() 1387 self.StatusTable.horizontalHeader().show() 1388 1389 hist.reverse() 1390 row = len(hist)-1 1391 1392 for e in hist: 1393 if e is None: 1394 continue 1395 1396 ess = device.queryString(e.event_code, 0) 1397 esl = device.queryString(e.event_code, 1) 1398 1399 if row == 0: 1400 desc = self.__tr("(most recent)") 1401 1402 else: 1403 desc = getTimeDeltaDesc(e.timedate) 1404 1405 dt = QDateTime() 1406 dt.setTime_t(int(e.timedate)) #, Qt.LocalTime) 1407 1408 # TODO: In Qt4.x, use QLocale.toString(date, format) 1409 tt = str("%s %s"%(dt.toString(),desc)) 1410 1411 if e.job_id: 1412 job_id = to_unicode(e.job_id) 1413 else: 1414 job_id = to_unicode('') 1415 1416 error_state = STATUS_TO_ERROR_STATE_MAP.get(e.event_code, ERROR_STATE_CLEAR) 1417 tech_type = self.cur_device.tech_type 1418 1419 if tech_type in (TECH_TYPE_COLOR_INK, TECH_TYPE_MONO_INK): 1420 status_pix = getStatusListIcon(error_state)[0] # ink 1421 else: 1422 status_pix = getStatusListIcon(error_state)[1] # laser 1423 1424 event_code = to_unicode(e.event_code) 1425 1426 i = QTableWidgetItem(QIcon(status_pix), self.__tr("")) 1427 i.setFlags(flags) 1428 self.StatusTable.setItem(row, 0, i) 1429 1430 for col, t in [(1, ess), (2, tt), (3, event_code), (4, job_id), (5, esl)]: 1431 i = QTableWidgetItem(str(t)) 1432 i.setFlags(flags) 1433 1434 self.StatusTable.setItem(row, col, i) 1435 1436 row -= 1 1437 1438 self.StatusTable.resizeColumnsToContents() 1439 self.StatusTable.setColumnWidth(0, 24) 1440 1441 else: 1442 self.StatusTable.setRowCount(1) 1443 self.StatusTable.setColumnCount(2) 1444 self.StatusTable.setHorizontalHeaderLabels(["", ""]) 1445 self.StatusTable.verticalHeader().hide() 1446 self.StatusTable.horizontalHeader().hide() 1447 1448 flags = Qt.ItemIsEnabled 1449 1450 pixmap = getStatusListIcon(ERROR_STATE_ERROR)[0] 1451 i = QTableWidgetItem(QIcon(pixmap), self.__tr("")) 1452 i.setFlags(flags) 1453 self.StatusTable.setItem(row, 0, i) 1454 1455 i = QTableWidgetItem(self.__tr("Status information not available for this device.")) 1456 i.setFlags(flags) 1457 self.StatusTable.setItem(0, 1, i) 1458 1459 self.StatusTable.resizeColumnsToContents() 1460 self.StatusTable.setColumnWidth(0, 24) 1461 1462 1463 # *********************************************************************************** 1464 # 1465 # SUPPLIES TAB 1466 # 1467 # *********************************************************************************** 1468 1469 def initSuppliesTab(self): 1470 self.pix_battery = load_pixmap('battery', '16x16') 1471 1472 yellow = "#ffff00" 1473 light_yellow = "#ffffcc" 1474 cyan = "#00ffff" 1475 light_cyan = "#ccffff" 1476 magenta = "#ff00ff" 1477 light_magenta = "#ffccff" 1478 black = "#000000" 1479 blue = "#0000ff" 1480 gray = "#808080" 1481 dark_gray = "#a9a9a9" 1482 light_gray = "#c0c0c0" 1483 red = "#ff0000" 1484 1485 self.TYPE_TO_PIX_MAP = { 1486 AGENT_TYPE_UNSPECIFIED : [black], 1487 AGENT_TYPE_BLACK: [black], 1488 AGENT_TYPE_MATTE_BLACK : [black], 1489 AGENT_TYPE_PHOTO_BLACK : [dark_gray], 1490 AGENT_TYPE_BLACK_B8800: [black], 1491 AGENT_TYPE_CMY: [cyan, magenta, yellow], 1492 AGENT_TYPE_KCM: [light_cyan, light_magenta, light_yellow], 1493 AGENT_TYPE_GGK: [dark_gray], 1494 AGENT_TYPE_YELLOW: [yellow], 1495 AGENT_TYPE_MAGENTA: [magenta], 1496 AGENT_TYPE_CYAN : [cyan], 1497 AGENT_TYPE_CYAN_LOW: [light_cyan], 1498 AGENT_TYPE_YELLOW_LOW: [light_yellow], 1499 AGENT_TYPE_MAGENTA_LOW: [light_magenta], 1500 AGENT_TYPE_BLUE: [blue], 1501 AGENT_TYPE_KCMY_CM: [yellow, cyan, magenta], 1502 AGENT_TYPE_LC_LM: [light_cyan, light_magenta], 1503 #AGENT_TYPE_Y_M: [yellow, magenta], 1504 #AGENT_TYPE_C_K: [black, cyan], 1505 AGENT_TYPE_LG_PK: [light_gray, dark_gray], 1506 AGENT_TYPE_LG: [light_gray], 1507 AGENT_TYPE_G: [gray], 1508 AGENT_TYPE_DG: [dark_gray], 1509 AGENT_TYPE_PG: [light_gray], 1510 AGENT_TYPE_C_M: [cyan, magenta], 1511 AGENT_TYPE_K_Y: [black, yellow], 1512 AGENT_TYPE_LC: [light_cyan], 1513 AGENT_TYPE_RED : [red], 1514 } 1515 1516 self.supplies_headers = [self.__tr(""), self.__tr("Description"), 1517 self.__tr("HP Part No."), self.__tr("Approx. Level"), 1518 self.__tr("Status")] 1519 1520 1521 def updateSuppliesTab(self): 1522 beginWaitCursor() 1523 flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled 1524 1525 try: 1526 self.SuppliesTable.clear() 1527 self.SuppliesTable.setRowCount(0) 1528 self.SuppliesTable.setColumnCount(0) 1529 1530 if self.cur_device is not None and \ 1531 self.cur_device.supported and \ 1532 self.cur_device.status_type != STATUS_TYPE_NONE and \ 1533 self.cur_device.device_state != DEVICE_STATE_NOT_FOUND: 1534 self.cur_device.sorted_supplies = [] 1535 a = 1 1536 while True: 1537 try: 1538 agent_type = int(self.cur_device.dq['agent%d-type' % a]) 1539 agent_kind = int(self.cur_device.dq['agent%d-kind' % a]) 1540 agent_sku = self.cur_device.dq['agent%d-sku' % a] 1541 except KeyError: 1542 break 1543 else: 1544 self.cur_device.sorted_supplies.append((a, agent_kind, agent_type, agent_sku)) 1545 1546 a += 1 1547 1548 self.cur_device.sorted_supplies.sort(key=utils.cmp_to_key(utils.levelsCmp)) 1549 1550 self.SuppliesTable.setRowCount(len(self.cur_device.sorted_supplies)) 1551 self.SuppliesTable.setColumnCount(len(self.supplies_headers)) 1552 self.SuppliesTable.setHorizontalHeaderLabels(self.supplies_headers) 1553 self.SuppliesTable.verticalHeader().hide() 1554 self.SuppliesTable.horizontalHeader().show() 1555 self.SuppliesTable.setIconSize(QSize(100, 18)) 1556 1557 for row, x in enumerate(self.cur_device.sorted_supplies): 1558 a, agent_kind, agent_type, agent_sku = x 1559 try: 1560 agent_level = int(self.cur_device.dq['agent%d-level' % a]) 1561 agent_desc = self.cur_device.dq['agent%d-desc' % a] 1562 agent_health_desc = self.cur_device.dq['agent%d-health-desc' % a] 1563 except KeyError: 1564 break 1565 # Bar graph level 1566 level_pixmap = None 1567 if agent_kind in (AGENT_KIND_SUPPLY, 1568 #AGENT_KIND_HEAD, 1569 AGENT_KIND_HEAD_AND_SUPPLY, 1570 AGENT_KIND_TONER_CARTRIDGE, 1571 AGENT_KIND_MAINT_KIT, 1572 AGENT_KIND_ADF_KIT, 1573 AGENT_KIND_INT_BATTERY, 1574 AGENT_KIND_DRUM_KIT, 1575 ): 1576 1577 level_pixmap = self.createStatusLevelGraphic(agent_level, agent_type) 1578 1579 # Color icon 1580 pixmap = None 1581 if agent_kind in (AGENT_KIND_SUPPLY, 1582 AGENT_KIND_HEAD, 1583 AGENT_KIND_HEAD_AND_SUPPLY, 1584 AGENT_KIND_TONER_CARTRIDGE, 1585 #AGENT_KIND_MAINT_KIT, 1586 #AGENT_KIND_ADF_KIT, 1587 AGENT_KIND_INT_BATTERY, 1588 #AGENT_KIND_DRUM_KIT, 1589 ): 1590 1591 pixmap = self.getStatusIcon(agent_kind, agent_type) 1592 1593 if pixmap is not None: 1594 i = QTableWidgetItem(QIcon(pixmap), self.__tr("")) 1595 i.setFlags(flags) 1596 self.SuppliesTable.setItem(row, 0, i) 1597 1598 for col, t in [(1, agent_desc), (2, agent_sku), (4, agent_health_desc)]: 1599 i = QTableWidgetItem(str(t)) 1600 i.setFlags(flags) 1601 self.SuppliesTable.setItem(row, col, i) 1602 1603 if level_pixmap is not None: 1604 i = QTableWidgetItem(QIcon(level_pixmap), self.__tr("")) 1605 i.setFlags(flags) 1606 self.SuppliesTable.setItem(row, 3, i) 1607 1608 self.SuppliesTable.resizeColumnsToContents() 1609 self.SuppliesTable.setColumnWidth(0, 24) 1610 self.SuppliesTable.setColumnWidth(3, 120) 1611 1612 else: # No supplies info 1613 log.warning("Supplies information not available for this device.") 1614 flags = Qt.ItemIsEnabled 1615 self.SuppliesTable.setRowCount(1) 1616 self.SuppliesTable.setColumnCount(2) 1617 self.SuppliesTable.setHorizontalHeaderLabels(["", ""]) 1618 self.SuppliesTable.verticalHeader().hide() 1619 self.SuppliesTable.horizontalHeader().hide() 1620 1621 i = QTableWidgetItem(self.__tr("Supplies information not available for this device.")) 1622 i.setFlags(flags) 1623 self.SuppliesTable.setItem(0, 1, i) 1624 1625 pixmap = getStatusListIcon(ERROR_STATE_ERROR)[0] 1626 i = QTableWidgetItem(QIcon(pixmap), self.__tr("")) 1627 i.setFlags(flags) 1628 self.SuppliesTable.setItem(0, 0, i) 1629 1630 self.SuppliesTable.resizeColumnsToContents() 1631 self.SuppliesTable.setColumnWidth(0, 24) 1632 1633 finally: 1634 endWaitCursor() 1635 1636 1637 def getStatusIcon(self, agent_kind, agent_type): 1638 if agent_kind in (AGENT_KIND_SUPPLY, 1639 AGENT_KIND_HEAD, 1640 AGENT_KIND_HEAD_AND_SUPPLY, 1641 AGENT_KIND_TONER_CARTRIDGE): 1642 1643 map = self.TYPE_TO_PIX_MAP[agent_type] 1644 1645 if isinstance(map, list): 1646 map_len = len(map) 1647 pix = QPixmap(16, 16) 1648 pix.fill(QColor(0, 0, 0, 0)) 1649 p = QPainter() 1650 1651 p.begin(pix) 1652 p.setRenderHint(QPainter.Antialiasing) 1653 1654 if map_len == 1: 1655 p.setPen(QColor(map[0])) 1656 p.setBrush(QBrush(QColor(map[0]), Qt.SolidPattern)) 1657 p.drawPie(2, 2, 10, 10, 0, 5760) 1658 1659 elif map_len == 2: 1660 p.setPen(QColor(map[0])) 1661 p.setBrush(QBrush(QColor(map[0]), Qt.SolidPattern)) 1662 p.drawPie(2, 4, 8, 8, 0, 5760) 1663 1664 p.setPen(QColor(map[1])) 1665 p.setBrush(QBrush(QColor(map[1]), Qt.SolidPattern)) 1666 p.drawPie(6, 4, 8, 8, 0, 5760) 1667 1668 elif map_len == 3: 1669 p.setPen(QColor(map[2])) 1670 p.setBrush(QBrush(QColor(map[2]), Qt.SolidPattern)) 1671 p.drawPie(6, 6, 8, 8, 0, 5760) 1672 1673 p.setPen(QColor(map[1])) 1674 p.setBrush(QBrush(QColor(map[1]), Qt.SolidPattern)) 1675 p.drawPie(2, 6, 8, 8, 0, 5760) 1676 1677 p.setPen(QColor(map[0])) 1678 p.setBrush(QBrush(QColor(map[0]), Qt.SolidPattern)) 1679 p.drawPie(4, 2, 8, 8, 0, 5760) 1680 1681 p.end() 1682 return pix 1683 1684 else: 1685 return map 1686 1687 elif agent_kind == AGENT_KIND_INT_BATTERY: 1688 return self.pix_battery 1689 1690 1691 def createStatusLevelGraphic(self, percent, agent_type, w=100, h=18): 1692 if percent: 1693 fw = w/100*percent 1694 else: 1695 fw = 0 1696 1697 px = QPixmap(w, h) 1698 px.fill(QColor(0, 0, 0, 0)) 1699 pp = QPainter() 1700 pp.begin(px) 1701 pp.setRenderHint(QPainter.Antialiasing) 1702 pp.setPen(Qt.black) 1703 1704 map = self.TYPE_TO_PIX_MAP[agent_type] 1705 map_len = len(map) 1706 1707 if map_len == 1 or map_len > 3: 1708 pp.fillRect(0, 0, fw, h, QBrush(QColor(map[0]))) 1709 1710 elif map_len == 2: 1711 h2 = h / 2 1712 pp.fillRect(0, 0, fw, h2, QBrush(QColor(map[0]))) 1713 pp.fillRect(0, h2, fw, h, QBrush(QColor(map[1]))) 1714 1715 elif map_len == 3: 1716 h3 = h / 3 1717 h23 = 2 * h3 1718 pp.fillRect(0, 0, fw, h3, QBrush(QColor(map[0]))) 1719 pp.fillRect(0, h3, fw, h23, QBrush(QColor(map[1]))) 1720 pp.fillRect(0, h23, fw, h, QBrush(QColor(map[2]))) 1721 1722 # draw black frame 1723 pp.drawRect(0, 0, w, h) 1724 1725 if percent > 75 and agent_type in \ 1726 (AGENT_TYPE_BLACK, AGENT_TYPE_UNSPECIFIED, AGENT_TYPE_BLUE): 1727 pp.setPen(Qt.white) 1728 1729 # 75% ticks 1730 w1 = 3 * w / 4 1731 h6 = h / 6 1732 pp.drawLine(w1, 0, w1, h6) 1733 pp.drawLine(w1, h, w1, h-h6) 1734 1735 if percent > 50 and agent_type in \ 1736 (AGENT_TYPE_BLACK, AGENT_TYPE_UNSPECIFIED, AGENT_TYPE_BLUE): 1737 pp.setPen(Qt.white) 1738 1739 # 50% ticks 1740 w2 = w / 2 1741 h4 = h / 4 1742 pp.drawLine(w2, 0, w2, h4) 1743 pp.drawLine(w2, h, w2, h-h4) 1744 1745 if percent > 25 and agent_type in \ 1746 (AGENT_TYPE_BLACK, AGENT_TYPE_UNSPECIFIED, AGENT_TYPE_BLUE): 1747 pp.setPen(Qt.white) 1748 1749 # 25% ticks 1750 w4 = w / 4 1751 pp.drawLine(w4, 0, w4, h6) 1752 pp.drawLine(w4, h, w4, h-h6) 1753 1754 pp.end() 1755 1756 return px 1757 1758 1759 1760 # *********************************************************************************** 1761 # 1762 # PRINTER SETTINGS TAB 1763 # 1764 # *********************************************************************************** 1765 1766 def initPrintSettingsTab(self): 1767 pass 1768 1769 1770 def updatePrintSettingsTab(self): 1771 beginWaitCursor() 1772 try: 1773 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 1774 self.PrintSettingsPrinterNameLabel.setText(self.__tr("Printer Name:")) 1775 else: 1776 self.PrintSettingsPrinterNameLabel.setText(self.__tr("Fax Name:")) 1777 1778 self.PrintSettingsToolbox.updateUi(self.cur_device, self.cur_printer) 1779 finally: 1780 endWaitCursor() 1781 1782 1783 # *********************************************************************************** 1784 # 1785 # PRINTER CONTROL TAB 1786 # 1787 # *********************************************************************************** 1788 1789 def initPrintControlTab(self): 1790 self.JOB_STATES = { cups.IPP_JOB_PENDING : self.__tr("Pending"), 1791 cups.IPP_JOB_HELD : self.__tr("On hold"), 1792 cups.IPP_JOB_PROCESSING : self.__tr("Printing"), 1793 cups.IPP_JOB_STOPPED : self.__tr("Stopped"), 1794 cups.IPP_JOB_CANCELLED : self.__tr("Canceled"), 1795 cups.IPP_JOB_ABORTED : self.__tr("Aborted"), 1796 cups.IPP_JOB_COMPLETED : self.__tr("Completed"), 1797 } 1798 1799 self.CancelJobButton.setIcon(QIcon(load_pixmap('cancel', '16x16'))) 1800 self.RefreshButton.setIcon(QIcon(load_pixmap('refresh', '16x16'))) 1801 1802 self.JOB_STATE_ICONS = { cups.IPP_JOB_PENDING: QIcon(load_pixmap("busy", "16x16")), 1803 cups.IPP_JOB_HELD : QIcon(load_pixmap("busy", "16x16")), 1804 cups.IPP_JOB_PROCESSING : QIcon(load_pixmap("print", "16x16")), 1805 cups.IPP_JOB_STOPPED : QIcon(load_pixmap("warning", "16x16")), 1806 cups.IPP_JOB_CANCELLED : QIcon(load_pixmap("warning", "16x16")), 1807 cups.IPP_JOB_ABORTED : QIcon(load_pixmap("error", "16x16")), 1808 cups.IPP_JOB_COMPLETED : QIcon(load_pixmap("ok", "16x16")), 1809 } 1810 1811 self.StartStopButton.clicked.connect(self.StartStopButton_clicked) 1812 self.AcceptRejectButton.clicked.connect(self.AcceptRejectButton_clicked) 1813 self.SetDefaultButton.clicked.connect(self.SetDefaultButton_clicked) 1814 self.CancelJobButton.clicked.connect(self.CancelJobButton_clicked) 1815 self.RefreshButton.clicked.connect(self.RefreshButton_clicked) 1816 1817 self.job_headers = [self.__tr("Status"), self.__tr("Title/Description"), self.__tr("Job ID")] 1818 1819 # TODO: Check queues at startup and send events if stopped or rejecting 1820 1821 1822 def initUpgradeTab(self): 1823 self.InstallLatestButton.clicked.connect(self.InstallLatestButton_clicked) 1824 self.InstallLatestButton_lock = False 1825 1826 1827 def InstallLatestButton_clicked(self): 1828 if self.InstallLatestButton_lock is True: 1829 return 1830 if self.Is_autoInstaller_distro: 1831 self.InstallLatestButton.setEnabled(False) 1832 terminal_cmd = utils.get_terminal() 1833 if terminal_cmd is not None and utils.which("hp-upgrade"): 1834 cmd = terminal_cmd + " 'hp-upgrade -w'" 1835 os_utils.execute(cmd) 1836 else: 1837 log.error("Failed to run hp-upgrade command from terminal =%s "%terminal_cmd) 1838 self.InstallLatestButton.setEnabled(True) 1839 else: 1840 self.InstallLatestButton_lock = True 1841 utils.openURL("http://hplipopensource.com/hplip-web/install/manual/index.html") 1842 QTimer.singleShot(1000, self.InstallLatestButton_unlock) 1843 1844 1845 def InstallLatestButton_unlock(self): 1846 self.InstallLatestButton_lock = False 1847 1848 1849 def CancelJobButton_clicked(self): 1850 item = self.JobTable.currentItem() 1851 1852 if item is not None: 1853 job_id, ok = value_int(item.data(Qt.UserRole)) 1854 if ok and job_id: 1855 self.cur_device.cancelJob(job_id) 1856 QTimer.singleShot(1000, self.updatePrintControlTab) 1857 1858 1859 def RefreshButton_clicked(self): 1860 self.updatePrintControlTab() 1861 1862 def updateHPLIPupgrade(self): 1863 self.initUpgradeTab() 1864 1865 1866 1867 1868 def updatePrintControlTab(self): 1869 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 1870 self.PrintControlPrinterNameLabel.setText(self.__tr("Printer Name:")) 1871 self.groupBox.setTitle(QApplication.translate("MainWindow", "Printer Queue Control", None)) 1872 else: 1873 self.PrintControlPrinterNameLabel.setText(self.__tr("Fax Name:")) 1874 self.groupBox.setTitle(QApplication.translate("MainWindow", "Fax Queue Control", None)) 1875 1876 self.JobTable.clear() 1877 self.JobTable.setRowCount(0) 1878 self.JobTable.setColumnCount(0) 1879 self.updatePrintController() 1880 flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled 1881 jobs = cups.getJobs() 1882 num_jobs = 0 1883 for j in jobs: 1884 if j.dest == self.cur_printer: 1885 num_jobs += 1 1886 1887 if num_jobs: 1888 self.CancelJobButton.setEnabled(True) 1889 self.JobTable.setRowCount(num_jobs) 1890 self.JobTable.setColumnCount(len(self.job_headers)) 1891 self.JobTable.setHorizontalHeaderLabels(self.job_headers) 1892 1893 for row, j in enumerate(jobs): 1894 if j.dest == self.cur_printer: 1895 i = QTableWidgetItem(self.JOB_STATE_ICONS[j.state], self.JOB_STATES[j.state]) 1896 i.setData(Qt.UserRole, j.id) 1897 i.setFlags(flags) 1898 self.JobTable.setItem(row, 0, i) 1899 1900 i = QTableWidgetItem(j.title) 1901 i.setFlags(flags) 1902 self.JobTable.setItem(row, 1, i) 1903 1904 i = QTableWidgetItem(to_unicode(j.id)) 1905 i.setFlags(flags) 1906 self.JobTable.setItem(row, 2, i) 1907 1908 1909 self.JobTable.setCurrentCell(0, 0) 1910 self.JobTable.resizeColumnsToContents() 1911 1912 else: 1913 self.CancelJobButton.setEnabled(False) 1914 1915 1916 def getPrinterState(self): 1917 self.printer_state = cups.IPP_PRINTER_STATE_IDLE 1918 self.printer_accepting = True 1919 cups_printers = cups.getPrinters() 1920 1921 for p in cups_printers: 1922 if p.name == self.cur_printer: 1923 self.printer_state = p.state 1924 self.printer_accepting = p.accepting 1925 break 1926 1927 1928 def updatePrintController(self): 1929 # default printer 1930 self.SetDefaultButton.setText(self.__tr("Set as Default")) 1931 1932 default_printer = cups.getDefaultPrinter() 1933 1934 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 1935 device_string = "Printer" 1936 else: 1937 device_string = "Fax" 1938 1939 if default_printer == self.cur_printer: 1940 self.SetDefaultLabel.setText(self.__tr("Default %s"%device_string)) 1941 self.SetDefaultIcon.setPixmap(load_pixmap("ok", "16x16")) 1942 self.SetDefaultButton.setEnabled(False) 1943 1944 else: 1945 self.SetDefaultLabel.setText(self.__tr("Not Default %s"%device_string)) 1946 self.SetDefaultIcon.setPixmap(load_pixmap("info", "16x16")) 1947 self.SetDefaultButton.setEnabled(True) 1948 1949 self.getPrinterState() 1950 1951 # start/stop 1952 if self.printer_state == cups.IPP_PRINTER_STATE_IDLE: 1953 self.StartStopLabel.setText(self.__tr("Started/Idle")) 1954 self.StartStopIcon.setPixmap(load_pixmap("idle", "16x16")) 1955 self.StartStopButton.setText(self.__tr("Stop %s"%device_string)) 1956 1957 1958 elif self.printer_state == cups.IPP_PRINTER_STATE_PROCESSING: 1959 self.StartStopLabel.setText(self.__tr("Started/Processing")) 1960 self.StartStopIcon.setPixmap(load_pixmap("busy", "16x16")) 1961 self.StartStopButton.setText(self.__tr("Stop %s"%device_string)) 1962 1963 else: 1964 self.StartStopLabel.setText(self.__tr("Stopped")) 1965 self.StartStopIcon.setPixmap(load_pixmap("warning", "16x16")) 1966 self.StartStopButton.setText(self.__tr("Start %s"%device_string)) 1967 1968 # reject/accept 1969 if self.printer_accepting: 1970 self.AcceptRejectLabel.setText(self.__tr("Accepting Jobs")) 1971 self.AcceptRejectIcon.setPixmap(load_pixmap("idle", "16x16")) 1972 self.AcceptRejectButton.setText(self.__tr("Reject Jobs")) 1973 1974 else: 1975 self.AcceptRejectLabel.setText(self.__tr("Rejecting Jobs")) 1976 self.AcceptRejectIcon.setPixmap(load_pixmap("warning", "16x16")) 1977 self.AcceptRejectButton.setText(self.__tr("Accept Jobs")) 1978 1979 1980 1981 def StartStopButton_clicked(self): 1982 beginWaitCursor() 1983 try: 1984 if self.printer_state in (cups.IPP_PRINTER_STATE_IDLE, cups.IPP_PRINTER_STATE_PROCESSING): 1985 result, result_str = cups.cups_operation(cups.stop, GUI_MODE, 'qt4', self, self.cur_printer) 1986 if result == cups.IPP_OK: 1987 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 1988 e = EVENT_PRINTER_QUEUE_STOPPED 1989 else: 1990 e = EVENT_FAX_QUEUE_STOPPED 1991 1992 else: 1993 result, result_str = cups.cups_operation(cups.start, GUI_MODE, 'qt4', self, self.cur_printer) 1994 if result == cups.IPP_OK: 1995 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 1996 e = EVENT_PRINTER_QUEUE_STARTED 1997 else: 1998 e = EVENT_FAX_QUEUE_STARTED 1999 2000 if result == cups.IPP_OK: 2001 self.updatePrintController() 2002 self.cur_device.sendEvent(e, self.cur_printer) 2003 else: 2004 FailureUI(self, self.__tr("<b>Start/Stop printer queue operation fails. </b><p>Error : %s"%result_str)) 2005 cups.releaseCupsInstance() 2006 2007 finally: 2008 endWaitCursor() 2009 2010 2011 2012 def AcceptRejectButton_clicked(self): 2013 beginWaitCursor() 2014 try: 2015 if self.printer_accepting: 2016 result, result_str = cups.cups_operation(cups.reject, GUI_MODE, 'qt4', self, self.cur_printer) 2017 if result == cups.IPP_OK: 2018 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 2019 e = EVENT_PRINTER_QUEUE_REJECTING_JOBS 2020 else: 2021 e = EVENT_FAX_QUEUE_REJECTING_JOBS 2022 2023 else: 2024 result, result_str = cups.cups_operation(cups.accept, GUI_MODE, 'qt4', self, self.cur_printer) 2025 if result == cups.IPP_OK: 2026 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 2027 e = EVENT_PRINTER_QUEUE_ACCEPTING_JOBS 2028 else: 2029 e = EVENT_FAX_QUEUE_ACCEPTING_JOBS 2030 2031 if result == cups.IPP_OK: 2032 self.updatePrintController() 2033 self.cur_device.sendEvent(e, self.cur_printer) 2034 else: 2035 FailureUI(self, self.__tr("<b>Accept/Reject printer queue operation fails.</b><p>Error : %s"%result_str)) 2036 cups.releaseCupsInstance() 2037 2038 finally: 2039 endWaitCursor() 2040 2041 2042 2043 def SetDefaultButton_clicked(self): 2044 beginWaitCursor() 2045 try: 2046 result, result_str = cups.cups_operation(cups.setDefaultPrinter, GUI_MODE, 'qt4', self, self.cur_printer.encode('utf8')) 2047 if result != cups.IPP_OK: 2048 FailureUI(self, self.__tr("<b>Set printer queue as default operation fails. </b><p>Error : %s"%result_str)) 2049 cups.releaseCupsInstance() 2050 else: 2051 self.updatePrintController() 2052 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 2053 e = EVENT_PRINTER_QUEUE_SET_AS_DEFAULT 2054 else: 2055 e = EVENT_FAX_QUEUE_SET_AS_DEFAULT 2056 2057 self.cur_device.sendEvent(e, self.cur_printer) 2058 2059 finally: 2060 endWaitCursor() 2061 2062 2063 2064 def cancelCheckedJobs(self): 2065 beginWaitCursor() 2066 try: 2067 item = self.JobTable.firstChild() 2068 while item is not None: 2069 if item.isOn(): 2070 self.cur_device.cancelJob(item.job_id) 2071 2072 item = item.nextSibling() 2073 2074 finally: 2075 endWaitCursor() 2076 2077 2078 self.updatePrintControlTab() 2079 2080 2081 2082 2083 # *********************************************************************************** 2084 # 2085 # EXIT/CHILD CLEANUP 2086 # 2087 # *********************************************************************************** 2088 2089 def closeEvent(self, event): 2090 self.cleanup() 2091 event.accept() 2092 2093 2094 def cleanup(self): 2095 self.cleanupChildren() 2096 2097 2098 def cleanupChildren(self): 2099 log.debug("Cleaning up child processes.") 2100 try: 2101 os.waitpid(-1, os.WNOHANG) 2102 except OSError: 2103 pass 2104 2105 2106 def quit(self): 2107 self.cleanupChildren() 2108 cups.releaseCupsInstance() 2109 self.close() 2110 2111 2112 # *********************************************************************************** 2113 # 2114 # DEVICE SETTINGS PLUGIN 2115 # 2116 # *********************************************************************************** 2117 2118 2119 # *********************************************************************************** 2120 # 2121 # SETTINGS DIALOG 2122 # 2123 # *********************************************************************************** 2124 2125 def PreferencesAction_activated(self, tab_to_show=0): 2126 dlg = SettingsDialog(self) 2127 dlg.TabWidget.setCurrentIndex(tab_to_show) 2128 2129 if dlg.exec_() == QDialog.Accepted: 2130 self.user_settings.load() 2131 2132 if self.cur_device is not None: 2133 self.cur_device.sendEvent(EVENT_USER_CONFIGURATION_CHANGED, self.cur_printer) 2134 2135 2136 # *********************************************************************************** 2137 # 2138 # SETUP/REMOVE 2139 # 2140 # *********************************************************************************** 2141 2142 def SetupDeviceAction_activated(self): 2143 if utils.which('hp-setup'): 2144 cmd = 'hp-setup --gui' 2145 else: 2146 cmd = 'python ./setup.py --gui' 2147 2148 log.debug(cmd) 2149 utils.run(cmd) 2150 self.rescanDevices() 2151 self.updatePrinterCombos() 2152 2153 2154 def RemoveDeviceAction_activated(self): 2155 if utils.which('hp-setup'): 2156 cmd = 'hp-setup --gui --remove' 2157 else: 2158 cmd = 'python ./setup.py --gui --remove' 2159 2160 if self.cur_device_uri is not None: 2161 cmd += ' --device=%s' % self.cur_device_uri 2162 2163 log.debug(cmd) 2164 utils.run(cmd) 2165 self.rescanDevices() 2166 self.updatePrinterCombos() 2167 2168 2169 def DiagnoseQueueAction_activated(self): 2170 if utils.which('hp-diagnose_queues'): 2171 cmd= 'hp-diagnose_queues --gui' 2172 else: 2173 cmd= 'python ./diagnose_queues.py --gui' 2174 log.debug(cmd) 2175# ok, output = utils.run(cmd) 2176 os_utils.execute(cmd) 2177 2178 2179 def DiagnoseHPLIP_activated(self): 2180 if utils.which('hp-doctor'): 2181 cmd = 'hp-doctor -i -w' 2182 else: 2183 cmd = 'python ./doctor.py -i -w' 2184 2185 terminal_cmd = utils.get_terminal() 2186 if terminal_cmd: 2187 cmd = terminal_cmd + " '%s'"%cmd 2188 os_utils.execute(cmd) 2189 2190 2191 2192 # *********************************************************************************** 2193 # 2194 # MISC 2195 # 2196 # *********************************************************************************** 2197 2198 def runExternalCommand(self, cmd, macro_char='%'): 2199 beginWaitCursor() 2200 2201 try: 2202 if len(cmd) == 0: 2203 FailureUI(self,self.__tr("<p><b>Unable to run command. No command specified.</b><p>Use <pre>Configure...</pre> to specify a command to run.")) 2204 log.error("No command specified. Use settings to configure commands.") 2205 else: 2206 log.debug("Run: %s %s (%s) %s" % ("*"*20, cmd, self.cur_device_uri, "*"*20)) 2207 log.debug(cmd) 2208 2209 try: 2210 cmd = ''.join([self.cur_device.device_vars.get(x, x) \ 2211 for x in cmd.split(macro_char)]) 2212 except AttributeError: 2213 pass 2214 2215 log.debug(cmd) 2216 2217 path = cmd.split()[0] 2218 args = cmd.split() 2219 2220 log.debug(path) 2221 log.debug(args) 2222 2223 self.cleanupChildren() 2224 os.spawnvp(os.P_NOWAIT, path, args) 2225 qApp.processEvents() 2226 2227 finally: 2228 endWaitCursor() 2229 2230 2231 def helpContents(self): 2232 utils.openURL(self.docs) 2233 2234 2235 def helpAbout(self): 2236 dlg = AboutDialog(self, prop.version, self.toolbox_version + " (Qt4)") 2237 dlg.exec_() 2238 2239 2240 def __tr(self,s,c = None): 2241 return qApp.translate("DevMgr5",s,c) 2242 2243 2244# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2245 2246class PasswordDialog(QDialog): 2247 def __init__(self, prompt, parent=None, name=None, modal=0, fl=0): 2248 QDialog.__init__(self, parent) 2249 self.prompt = prompt 2250 2251 Layout= QGridLayout(self) 2252 Layout.setMargin(11) 2253 Layout.setSpacing(6) 2254 2255 self.PromptTextLabel = QLabel(self) 2256 Layout.addWidget(self.PromptTextLabel,0,0,1,3) 2257 2258 self.UsernameTextLabel = QLabel(self) 2259 Layout.addWidget(self.UsernameTextLabel,1,0) 2260 2261 self.UsernameLineEdit = QLineEdit(self) 2262 self.UsernameLineEdit.setEchoMode(QLineEdit.Normal) 2263 Layout.addWidget(self.UsernameLineEdit,1,1,1,2) 2264 2265 self.PasswordTextLabel = QLabel(self) 2266 Layout.addWidget(self.PasswordTextLabel,2,0) 2267 2268 self.PasswordLineEdit = QLineEdit(self) 2269 self.PasswordLineEdit.setEchoMode(QLineEdit.Password) 2270 Layout.addWidget(self.PasswordLineEdit,2,1,1,2) 2271 2272 self.OkPushButton = QPushButton(self) 2273 Layout.addWidget(self.OkPushButton,3,2) 2274 2275 self.languageChange() 2276 2277 self.resize(QSize(420,163).expandedTo(self.minimumSizeHint())) 2278 2279 self.OkPushButton.clicked.connect(self.accept) 2280 self.PasswordLineEdit.returnPressed.connect(self.accept) 2281 2282 2283 def getUsername(self): 2284 return to_unicode(self.UsernameLineEdit.text()) 2285 2286 2287 def getPassword(self): 2288 return to_unicode(self.PasswordLineEdit.text()) 2289 2290 2291 def languageChange(self): 2292 self.setWindowTitle(self.__tr("HP Device Manager - Enter Username/Password")) 2293 self.PromptTextLabel.setText(self.__tr(self.prompt)) 2294 self.UsernameTextLabel.setText(self.__tr("Username:")) 2295 self.PasswordTextLabel.setText(self.__tr("Password:")) 2296 self.OkPushButton.setText(self.__tr("OK")) 2297 2298 2299 def __tr(self,s,c = None): 2300 return qApp.translate("DevMgr5",s,c) 2301 2302# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2303 2304def showPasswordUI(prompt): 2305 try: 2306 dlg = PasswordDialog(prompt, None) 2307 2308 if dlg.exec_() == QDialog.Accepted: 2309 return (dlg.getUsername(), dlg.getPassword()) 2310 2311 finally: 2312 pass 2313 2314 return ("", "") 2315 2316 2317def openEWS(host, zc): 2318 if zc: 2319 status, ip = hpmudext.get_zc_ip_address(zc) 2320 if status != hpmudext.HPMUD_R_OK: 2321 ip = "hplipopensource.com" 2322 else: 2323 ip = host 2324 return "http://%s" % ip 2325