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, Pete Parks, Naga Samrat Chowdary Narla, 20# 21 22 23 24# Std Lib 25import sys 26import time 27import os 28import gzip 29import select 30import struct 31import threading 32import signal 33 34# Local 35from base.sixext.moves import queue 36from base.g import * 37from base import device, utils, pml, maint, pkit, os_utils 38from base.sixext import to_unicode 39from prnt import cups 40from base.codes import * 41from .ui_utils import load_pixmap 42from installer.core_install import * 43 44# Qt 45from qt import * 46 47# Main form 48from .devmgr4_base import DevMgr4_base 49 50# Scrollviews 51from .scrollview import ScrollView 52from .scrollprintsettings import ScrollPrintSettingsView 53 54# Alignment and ColorCal forms 55from .alignform import AlignForm 56from .aligntype6form1 import AlignType6Form1 57from .aligntype6form2 import AlignType6Form2 58from .paperedgealignform import PaperEdgeAlignForm 59from .colorcalform import ColorCalForm # Type 1 color cal 60from .coloradjform import ColorAdjForm # Type 5 and 6 color adj 61from .colorcalform2 import ColorCalForm2 # Type 2 color cal 62from .colorcal4form import ColorCal4Form # Type 4 color cal 63from .align10form import Align10Form # Type 10 and 11 alignment 64from .align13form import Align13Form # Type 13 alignment 65 66# Misc forms 67from .loadpaperform import LoadPaperForm 68from .settingsdialog import SettingsDialog 69from .aboutdlg import AboutDlg 70from .cleaningform import CleaningForm 71from .cleaningform2 import CleaningForm2 72from .waitform import WaitForm 73from .faxsettingsform import FaxSettingsForm 74from .nodevicesform import NoDevicesForm 75from .settingsdialog import SettingsDialog 76from .firmwaredialog import FirmwareDialog 77 78# all in seconds 79MIN_AUTO_REFRESH_RATE = 5 80MAX_AUTO_REFRESH_RATE = 60 81DEF_AUTO_REFRESH_RATE = 30 82 83 84devices = {} # { Device_URI : device.Device(), ... } 85devices_lock = threading.RLock() 86 87RESPONSE_START = 1 88RESPONSE_DONE = 2 89 90# *********************************************************************************** 91# 92# LISTVIEW/UTILITY UI CLASSES 93# 94# *********************************************************************************** 95 96class IconViewToolTip(QToolTip): 97 def __init__(self, parent, tooltip_text): 98 QToolTip.__init__(self, parent.viewport()) 99 self.parent = parent 100 101 102 def maybeTip(self, pos): 103 abs_coords = QPoint(pos.x() + self.parent.contentsX(), 104 pos.y() + self.parent.contentsY()) 105 106 item = self.parent.findItem(abs_coords) 107 108 if item is not None and item.tooltip_text: 109 rel_coords = QRect() 110 rel_coords.setX(pos.x()) 111 rel_coords.setY(pos.y()) 112 i = item.rect() 113 rel_coords.setWidth(i.width()) 114 rel_coords.setHeight(i.height()) 115 self.tip(rel_coords, item.tooltip_text) 116 117 118 119class FuncViewItem(QIconViewItem): 120 def __init__(self, parent, text, pixmap, tooltip_text, cmd): 121 QIconViewItem.__init__(self, parent, text, pixmap) 122 self.tooltip_text = tooltip_text 123 self.cmd = cmd 124 125 self.tooltip = IconViewToolTip(parent, tooltip_text) 126 127 128 129class DeviceViewItem(QIconViewItem): 130 def __init__(self, parent, text, pixmap, device_uri, is_avail=True): 131 QIconViewItem.__init__(self, parent, text, pixmap) 132 self.device_uri = device_uri 133 self.is_avail = is_avail 134 135 136 137class SuppliesListViewItem(QListViewItem): 138 def __init__(self, parent, pixmap, desc, part_no, level_pixmap, status): 139 QListViewItem.__init__(self, parent, '', desc, part_no, '', status) 140 if pixmap is not None: 141 self.setPixmap(0, pixmap) 142 if level_pixmap is not None: 143 self.setPixmap(3, level_pixmap) 144 145 def paintCell(self, p, cg, c, w, a): 146 color = QColorGroup(cg) 147 pos = self.listView().itemPos(self) 148 h = self.totalHeight() 149 150 if (pos/h) % 2: 151 color.setColor(QColorGroup.Base, QColor(220, 228, 249)) 152 153 QListViewItem.paintCell(self, p, color, c, w, a) 154 155 156 157class PasswordDialog(QDialog): 158 def __init__(self,prompt, parent=None, name=None, modal=0, fl=0): 159 QDialog.__init__(self,parent,name,modal,fl) 160 self.prompt = prompt 161 162 if not name: 163 self.setName("PasswordDialog") 164 165 passwordDlg_baseLayout = QGridLayout(self,1,1,11,6,"passwordDlg_baseLayout") 166 167 self.promptTextLabel = QLabel(self,"promptTextLabel") 168 passwordDlg_baseLayout.addMultiCellWidget(self.promptTextLabel,0,0,0,1) 169 170 self.usernameTextLabel = QLabel(self,"usernameTextLabel") 171 passwordDlg_baseLayout.addMultiCellWidget(self.usernameTextLabel,1,1,0,1) 172 173 self.usernameLineEdit = QLineEdit(self,"usernameLineEdit") 174 self.usernameLineEdit.setEchoMode(QLineEdit.Normal) 175 passwordDlg_baseLayout.addMultiCellWidget(self.usernameLineEdit,1,1,1,2) 176 177 self.passwordTextLabel = QLabel(self,"passwordTextLabel") 178 passwordDlg_baseLayout.addMultiCellWidget(self.passwordTextLabel,2,2,0,1) 179 180 self.passwordLineEdit = QLineEdit(self,"passwordLineEdit") 181 self.passwordLineEdit.setEchoMode(QLineEdit.Password) 182 passwordDlg_baseLayout.addMultiCellWidget(self.passwordLineEdit,2,2,1,2) 183 184 self.okPushButton = QPushButton(self,"okPushButton") 185 passwordDlg_baseLayout.addWidget(self.okPushButton,3,2) 186 187 self.languageChange() 188 189 self.resize(QSize(420,163).expandedTo(self.minimumSizeHint())) 190 self.clearWState(Qt.WState_Polished) 191 192 self.connect(self.okPushButton,SIGNAL("clicked()"),self.accept) 193 self.connect(self.passwordLineEdit,SIGNAL("returnPressed()"),self.accept) 194 def getUsername(self): 195 return to_unicode(self.usernameLineEdit.text()) 196 197 def getPassword(self): 198 return to_unicode(self.passwordLineEdit.text()) 199 200 def languageChange(self): 201 self.setCaption(self.__tr("HP Device Manager - Enter Username/Password")) 202 self.promptTextLabel.setText(self.__tr(self.prompt)) 203 self.usernameTextLabel.setText(self.__tr("Username")) 204 self.passwordTextLabel.setText(self.__tr("Password")) 205 self.okPushButton.setText(self.__tr("OK")) 206 207 def __tr(self,s,c = None): 208 return qApp.translate("PasswordDialog",s,c) 209 210 211 212class ScrollDialog(QDialog): 213 def __init__(self, scrollview_cls, cur_device, cur_printer, service, 214 parent = None, name=None, modal=0, fl=0): 215 216 QDialog.__init__(self,parent,name,modal,fl) 217 218 if not name: 219 self.setName("ScrollDialog") 220 221 self.setSizeGripEnabled(1) 222 ScrollDialogLayout = QGridLayout(self,1,1,11,6,"ScrollDialogLayout") 223 Layout1 = QHBoxLayout(None,0,6,"Layout1") 224 Horizontal_Spacing2 = QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum) 225 Layout1.addItem(Horizontal_Spacing2) 226 self.buttonOk = QPushButton(self,"buttonOk") 227 self.buttonOk.setAutoDefault(1) 228 self.buttonOk.setDefault(1) 229 Layout1.addWidget(self.buttonOk) 230 ScrollDialogLayout.addLayout(Layout1,1,0) 231 232 self.scrollview = scrollview_cls(service, self) 233 ScrollDialogLayout.addWidget(self.scrollview,0,0) 234 235 self.scrollview.onDeviceChange(cur_device) 236 self.scrollview.onPrinterChange(cur_printer) 237 self.languageChange() 238 239 self.resize(QSize(520,457).expandedTo(self.minimumSizeHint())) 240 self.clearWState(Qt.WState_Polished) 241 self.connect(self.buttonOk,SIGNAL("clicked()"),self.accept) 242 243 244 def languageChange(self): 245 self.setCaption(self.__tr("HP Device Manager")) 246 self.buttonOk.setText(self.__tr("Close")) 247 self.buttonOk.setAccel(QKeySequence(QString.null)) 248 249 def __tr(self,s,c = None): 250 return qApp.translate("ScrollDialog",s,c) 251 252 253def showPasswordUI(prompt): 254 try: 255 dlg = PasswordDialog(prompt, None) 256 257 if dlg.exec_loop() == QDialog.Accepted: 258 return (dlg.getUsername(), dlg.getPassword()) 259 260 finally: 261 pass 262 263 return ("", "") 264 265 266class StatusListViewItem(QListViewItem): 267 def __init__(self, parent, pixmap, ess, tt, event_code, job_id, username): 268 QListViewItem.__init__(self, parent, '', ess, tt, event_code, job_id, username) 269 self.setPixmap(0, pixmap) 270 271 def paintCell(self, p, cg, c, w, a): 272 color = QColorGroup(cg) 273 pos = self.listView().itemPos(self) 274 h = self.totalHeight() 275 row = pos/2 276 277 if row % 2: 278 color.setColor(QColorGroup.Base, QColor(220, 228, 249)) 279 280 QListViewItem.paintCell(self, p, color, c, w, a) 281 282 283 284class JobListViewItem(QCheckListItem): 285 def __init__(self, parent, pixmap, desc, status, job_id): 286 QCheckListItem.__init__(self, parent, '', QCheckListItem.CheckBox) 287 self.job_id = job_id 288 self.setPixmap(1, pixmap) 289 self.setText(2, desc) 290 self.setText(3, status) 291 self.setText(4, job_id) 292 293 def paintCell(self, p, cg, c, w, a): 294 color = QColorGroup(cg) 295 pos = self.listView().itemPos(self) 296 h = self.totalHeight() 297 298 if (pos/h) % 2: 299 color.setColor(QColorGroup.Base, QColor(220, 228, 249)) 300 301 QCheckListItem.paintCell(self, p, color, c, w, a) 302 303 304 305class JobInfoDialog(QDialog): 306 def __init__(self, text, parent=None, name=None, modal=0, fl=0): 307 QDialog.__init__(self, parent, name, modal, fl) 308 309 if not name: 310 self.setName("JobInfoDialog") 311 312 Form1Layout = QGridLayout(self,1,1,11,6,"Form1Layout") 313 spacer6 = QSpacerItem(371,20,QSizePolicy.Expanding,QSizePolicy.Minimum) 314 Form1Layout.addItem(spacer6,1,0) 315 self.pushButton4 = QPushButton(self,"pushButton4") 316 Form1Layout.addWidget(self.pushButton4,1,1) 317 self.textEdit = QTextEdit(self,"textEdit") 318 Form1Layout.addMultiCellWidget(self.textEdit,0,0,0,1) 319 320 self.languageChange() 321 322 self.resize(QSize(571,542).expandedTo(self.minimumSizeHint())) 323 self.clearWState(Qt.WState_Polished) 324 325 self.connect(self.pushButton4,SIGNAL("clicked()"),self.close) 326 327 self.textEdit.setText(text) 328 329 330 def languageChange(self): 331 self.setCaption(self.__tr("HP Device Manager - Job Log")) 332 self.pushButton4.setText(self.__tr("Close")) 333 334 335 def __tr(self,s,c = None): 336 return qApp.translate("JobInfoDialog",s,c) 337 338 339# *********************************************************************************** 340# 341# DEVICE UPDATE THREAD 342# 343# *********************************************************************************** 344 345 346class UpdateThread(QThread): 347 def __init__(self, response_queue=None, request_queue=None): 348 self.response_queue = response_queue # update queue -> main window 349 self.request_queue = request_queue # main window -> update queue 350 351 QThread.__init__(self) 352 353 def run(self): 354 while True: 355 dev = self.request_queue.get(True) 356 357 if dev is None: 358 log.debug("Update thread: exit") 359 break 360 361 log.debug("Update thread start: %s" % dev.device_uri) 362 363 try: 364 #print "THREAD LOCK ACQUIRE" 365 devices_lock.acquire() 366 #print "THREAD LOCK ACQUIRE - OK" 367 self.response_queue.put((RESPONSE_START, dev.device_uri)) 368 log.debug(log.bold("Update: %s %s %s" % ("*"*20, dev.device_uri, "*"*20))) 369 370 if dev.supported: 371 try: 372 dev.open() 373 except Error as e: 374 log.warn(e.msg) 375 376 time.sleep(0.1) 377 378 if dev.device_state == DEVICE_STATE_NOT_FOUND: 379 dev.error_state = ERROR_STATE_ERROR 380 else: 381 try: 382 dev.queryDevice() 383 384 except Error as e: 385 log.error("Query device error (%s)." % e.msg) 386 dev.error_state = ERROR_STATE_ERROR 387 388 finally: 389 dev.close() 390 #print "THREAD LOCK RELEASE" 391 cups.releaseCupsInstance() 392 devices_lock.release() 393 394 log.debug("Device state = %d" % dev.device_state) 395 log.debug("Status code = %d" % dev.status_code) 396 log.debug("Error state = %d" % dev.error_state) 397 398 log.debug("Update thread end: %s" % dev.device_uri) 399 400 self.response_queue.put((RESPONSE_DONE, dev.device_uri)) 401 402 403# *********************************************************************************** 404# 405# MAINWINDOW 406# 407# *********************************************************************************** 408 409class DevMgr4(DevMgr4_base): 410 def __init__(self, read_pipe=None, toolbox_version='0.0', 411 initial_device_uri=None, disable_dbus=False, 412 parent=None, name=None, fl = 0): 413 414 415 # Distro insformation 416 core = CoreInstall(MODE_CHECK) 417# core.init() 418 self.Is_autoInstaller_distro = core.is_auto_installer_support() 419 self.Latest_ver= user_conf.get('upgrade', 'latest_available_version') 420 installed_version=sys_conf.get('hplip','version') 421 if utils.Is_HPLIP_older_version(installed_version, self.Latest_ver): 422 DevMgr4_base.__init__(self, parent, name, fl,self.Latest_ver,self.Is_autoInstaller_distro) 423 else: 424 self.Latest_ver = "" 425 DevMgr4_base.__init__(self, parent, name, fl,self.Latest_ver,self.Is_autoInstaller_distro) 426 log.debug("Initializing toolbox UI (Qt3)...") 427 log.debug("HPLIP Version: %s" % prop.installed_version) 428 429 self.disable_dbus = disable_dbus 430 self.toolbox_version = toolbox_version 431 self.cur_device_uri = user_conf.get('last_used', 'device_uri') 432 self.device_vars = {} 433 self.num_devices = 0 434 self.cur_device = None 435 self.rescanning = False 436 self.initial_device_uri = initial_device_uri 437 438 # dbus setup 439 if not self.disable_dbus: 440 self.dbus_avail, self.service, session_bus = device.init_dbus() 441 442 if not self.dbus_avail: 443 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.") 444 else: 445 log.debug("dbus enabled") 446 447 else: 448 log.debug("dbus disabled") 449 self.dbus_avail, self.service = False, None 450 451 452 # Update thread setup 453 self.request_queue = queue.Queue() 454 self.response_queue = queue.Queue() 455 self.update_thread = UpdateThread(self.response_queue, self.request_queue) 456 self.update_thread.start() 457 458 # Pipe from toolbox/dbus setup 459 self.fmt = "80s80sI32sI80sf" 460 self.fmt_size = struct.calcsize(self.fmt) 461 462 if read_pipe is not None and not disable_dbus: 463 log.debug("Setting up read_pipe") 464 self.notifier = QSocketNotifier(read_pipe, QSocketNotifier.Read) 465 QObject.connect(self.notifier, SIGNAL("activated(int)"), self.notifier_activated) 466 467 # Application icon 468 self.setIcon(load_pixmap('hp_logo', '128x128')) 469 470 # User settings 471 self.user_settings = utils.UserSettings() 472 self.cmd_fab = self.user_settings.cmd_fab 473 log.debug("FAB command: %s" % self.cmd_fab) 474 475 if not self.user_settings.auto_refresh: 476 self.autoRefresh.toggle() 477 478 # Other initialization 479 self.InitPixmaps() 480 self.InitMisc() 481 self.InitUI() 482 483 cups.setPasswordCallback(showPasswordUI) 484 485 if not prop.doc_build: 486 self.helpContentsAction.setEnabled(False) 487 488 self.allow_auto_refresh = True 489 QTimer.singleShot(0, self.InitialUpdate) 490 491 492 # *********************************************************************************** 493 # 494 # INIT 495 # 496 # *********************************************************************************** 497 498 def InitPixmaps(self): 499 self.func_icons_cached = False 500 self.func_icons = {} 501 self.device_icons = {} 502 503 # TODO: Use Qt pixmap cache for all pixmaps? 504 505 # Device icon list overlays 506 self.warning_pix = load_pixmap('warning', '16x16') 507 self.error_pix = load_pixmap('error', '16x16') 508 self.ok_pix = load_pixmap('ok', '16x16') 509 self.lowink_pix = load_pixmap('inkdrop', '16x16') 510 self.lowtoner_pix = load_pixmap('toner', '16x16') 511 self.busy_pix = load_pixmap('busy', '16x16') 512 self.lowpaper_pix = load_pixmap('paper', '16x16') 513 self.refresh_pix = load_pixmap('refresh', '16x16') 514 self.refresh1_pix = load_pixmap('refresh1', '16x16') 515 self.fax_icon = load_pixmap('fax2', 'other') 516 self.idle_pix = load_pixmap('idle', '16x16') 517 self.scan_pix = load_pixmap("scan", '16x16') 518 self.print_pix = load_pixmap("print", '16x16') 519 self.sendfax_pix =load_pixmap("fax", '16x16') 520 self.pcard_pix = load_pixmap("pcard", '16x16') 521 self.makecopies_pix = load_pixmap("makecopies", '16x16') 522 self.help_pix = load_pixmap("help", '16x16') 523 524 525 # pixmaps: (inkjet, laserjet) 526 self.SMALL_ICONS = { ERROR_STATE_CLEAR : (None, None), 527 ERROR_STATE_BUSY : (self.busy_pix, self.busy_pix), 528 ERROR_STATE_ERROR : (self.error_pix, self.error_pix), 529 ERROR_STATE_LOW_SUPPLIES : (self.lowink_pix, self.lowtoner_pix), 530 ERROR_STATE_OK : (self.ok_pix, self.ok_pix), 531 ERROR_STATE_WARNING : (self.warning_pix, self.warning_pix), 532 ERROR_STATE_LOW_PAPER: (self.lowpaper_pix, self.lowpaper_pix), 533 ERROR_STATE_PRINTING : (self.busy_pix, self.busy_pix), 534 ERROR_STATE_SCANNING : (self.busy_pix, self.busy_pix), 535 ERROR_STATE_PHOTOCARD : (self.busy_pix, self.busy_pix), 536 ERROR_STATE_FAXING : (self.busy_pix, self.busy_pix), 537 ERROR_STATE_COPYING : (self.busy_pix, self.busy_pix), 538 ERROR_STATE_REFRESHING : (self.refresh1_pix, self.refresh1_pix), 539 } 540 541 self.STATUS_ICONS = { ERROR_STATE_CLEAR : (self.idle_pix, self.idle_pix), 542 ERROR_STATE_BUSY : (self.busy_pix, self.busy_pix), 543 ERROR_STATE_ERROR : (self.error_pix, self.error_pix), 544 ERROR_STATE_LOW_SUPPLIES : (self.lowink_pix, self.lowtoner_pix), 545 ERROR_STATE_OK : (self.ok_pix, self.ok_pix), 546 ERROR_STATE_WARNING : (self.warning_pix, self.warning_pix), 547 ERROR_STATE_LOW_PAPER: (self.lowpaper_pix, self.lowpaper_pix), 548 ERROR_STATE_PRINTING : (self.print_pix, self.print_pix), 549 ERROR_STATE_SCANNING : (self.scan_pix, self.scan_pix), 550 ERROR_STATE_PHOTOCARD : (self.pcard_pix, self.print_pix), 551 ERROR_STATE_FAXING : (self.sendfax_pix, self.sendfax_pix), 552 ERROR_STATE_COPYING : (self.makecopies_pix, self.makecopies_pix), 553 } 554 555 556 557 def InitUI(self): 558 # Setup device icon list 559 self.DeviceList.setAutoArrange(True) 560 self.DeviceList.setSorting(True) 561 562 # Setup main menu 563 self.deviceRescanAction.setIconSet(QIconSet(self.refresh1_pix)) 564 self.deviceRefreshAll.setIconSet(QIconSet(self.refresh_pix)) 565 self.deviceInstallAction.setIconSet(QIconSet(load_pixmap('list_add', '16x16'))) 566 self.deviceRemoveAction.setIconSet(QIconSet(load_pixmap('list_remove', '16x16'))) 567 self.settingsConfigure.setIconSet(QIconSet(load_pixmap('settings', '16x16'))) 568 self.helpContentsAction.setIconSet(QIconSet(self.help_pix)) 569 570 # Setup toolbar 571 self.deviceRescanAction.addTo(self.Toolbar) 572 self.deviceRefreshAll.addTo(self.Toolbar) 573 self.Toolbar.addSeparator() 574 self.deviceInstallAction.addTo(self.Toolbar) 575 self.deviceRemoveAction.addTo(self.Toolbar) 576 self.Toolbar.addSeparator() 577 self.settingsConfigure.addTo(self.Toolbar) 578 self.helpContentsAction.addTo(self.Toolbar) 579 580 # Init tabs/controls 581 self.InitFuncsTab() 582 self.InitStatusTab() 583 self.InitSuppliesTab() 584 self.InitPrintSettingsTab() 585 self.InitPrintControlTab() 586 587 # Resize the splitter so that the device list starts as a single column 588 self.splitter2.setSizes([120, 700]) 589 signal.signal(signal.SIGINT, signal.SIG_IGN) 590 591 592 def InitMisc(self): 593 self.unit_names = { "year" : (self.__tr("year"), self.__tr("years")), 594 "month" : (self.__tr("month"), self.__tr("months")), 595 "week" : (self.__tr("week"), self.__tr("weeks")), 596 "day" : (self.__tr("day"), self.__tr("days")), 597 "hour" : (self.__tr("hour"), self.__tr("hours")), 598 "minute" : (self.__tr("minute"), self.__tr("minutes")), 599 "second" : (self.__tr("second"), self.__tr("seconds")), 600 } 601 602 self.num_repr = { 1 : self.__tr("one"), 603 2 : self.__tr("two"), 604 3 : self.__tr("three"), 605 4 : self.__tr("four"), 606 5 : self.__tr("five"), 607 6 : self.__tr("six"), 608 7 : self.__tr("seven"), 609 8 : self.__tr("eight"), 610 9 : self.__tr("nine"), 611 10 : self.__tr("ten"), 612 11 : self.__tr("eleven"), 613 12 : self.__tr("twelve") 614 } 615 616 if self.Latest_ver is "": 617 self.TabIndex = { self.FunctionsTab: self.UpdateFuncsTab, 618 self.StatusTab: self.UpdateStatusTab, 619 self.SuppliesTab: self.UpdateSuppliesTab, 620 self.PrintSettingsTab: self.UpdatePrintSettingsTab, 621 self.PrintJobsTab: self.UpdatePrintControlTab, 622 } 623 else: 624 self.TabIndex = { self.FunctionsTab: self.UpdateFuncsTab, 625 self.StatusTab: self.UpdateStatusTab, 626 self.SuppliesTab: self.UpdateSuppliesTab, 627 self.PrintSettingsTab: self.UpdatePrintSettingsTab, 628 self.PrintJobsTab: self.UpdatePrintControlTab, 629 self.UpgradeTab:self.UpdateUpgradeTab, 630 } 631 632 633 634 def InitialUpdate(self): 635 self.RescanDevices() 636 637 cont = True 638 if self.initial_device_uri is not None: 639 if not self.ActivateDevice(self.initial_device_uri): 640 log.error("Device %s not found" % self.initial_device_uri) 641 cont = False 642 643 self.refresh_timer = QTimer(self, "RefreshTimer") 644 self.connect(self.refresh_timer, SIGNAL('timeout()'), self.TimedRefresh) 645 646 if MIN_AUTO_REFRESH_RATE <= self.user_settings.auto_refresh_rate <= MAX_AUTO_REFRESH_RATE: 647 self.refresh_timer.start(self.user_settings.auto_refresh_rate * 1000) 648 649 self.update_timer = QTimer(self) 650 self.connect(self.update_timer, SIGNAL("timeout()"), self.ThreadUpdate) 651 self.update_timer.start(500) 652 653 654 def ActivateDevice(self, device_uri): 655 log.debug(log.bold("Activate: %s %s %s" % ("*"*20, device_uri, "*"*20))) 656 d = self.DeviceList.firstItem() 657 found = False 658 659 while d is not None: 660 if d.device_uri == device_uri: 661 found = True 662 self.DeviceList.setSelected(d, True) 663 self.DeviceList.setCurrentItem(d) 664 break 665 666 d = d.nextItem() 667 668 return found 669 670 671 672 # *********************************************************************************** 673 # 674 # UPDATES/NOTIFICATIONS 675 # 676 # *********************************************************************************** 677 678 def notifier_activated(self, sock): # dbus message has arrived 679 m = '' 680 while True: 681 ready = select.select([sock], [], [], 0.1) 682 683 if ready[0]: 684 m = ''.join([m, os.read(sock, self.fmt_size)]) 685 if len(m) == self.fmt_size: 686 if self.cur_device is None or self.rescanning: 687 return 688 689 event = device.Event(*struct.unpack(self.fmt, m)) 690 desc = device.queryString(event.event_code) 691 error_state = STATUS_TO_ERROR_STATE_MAP.get(event.event_code, ERROR_STATE_CLEAR) 692 log.debug("Status event: %s (%d)" % (event.device_uri, event.event_code)) 693 694 if event.event_code > EVENT_MAX_USER_EVENT: 695 696 if event.event_code == EVENT_HISTORY_UPDATE: # 9003 697 log.debug("History update: %s" % event.device_uri) 698 699 if not self.rescanning: 700 dev = self.findDeviceByURI(event.device_uri) 701 702 self.UpdateHistory(dev) 703 self.UpdateDevice(dev) 704 705 elif event.event_code == EVENT_CUPS_QUEUES_REMOVED or event.event_code == EVENT_CUPS_QUEUES_ADDED: 706 pass 707 708 elif event.event_code == EVENT_RAISE_DEVICE_MANAGER: # 9001 709 log.debug("Raise requested") 710 self.showNormal() 711 self.setActiveWindow() 712 self.raiseW() 713 714 else: 715 log.debug("Ignored") 716 717 else: 718 break 719 720 721 def TimedRefresh(self): 722 if not self.rescanning and self.user_settings.auto_refresh and self.allow_auto_refresh: 723 log.debug("Refresh timer...") 724 self.CleanupChildren() 725 726 if self.user_settings.auto_refresh_type == 0: 727 self.RequestDeviceUpdate() 728 else: 729 self.RescanDevices() 730 731 732 def ThreadUpdate(self): # periodically check for updates from update thread 733 if not self.response_queue.empty(): 734 response_code, device_uri = self.response_queue.get() 735 736 if response_code == RESPONSE_START: 737 self.statusBar().message(self.__tr("Updating %1...").arg(device_uri)) 738 qApp.processEvents() 739 740 elif response_code == RESPONSE_DONE: 741 self.statusBar().message(QString("%1 (%2)").arg(self.cur_device_uri).\ 742 arg(', '.join(self.cur_device.cups_printers))) 743 744 dev = self.findDeviceByURI(device_uri) 745 746 if dev is not None: 747 self.UpdateHistory(dev) 748 self.UpdateDevice(dev) 749 750 qApp.processEvents() 751 752 if self.response_queue.empty() and self.request_queue.empty(): 753 self.UpdateTitle() 754 # Disable thread timer until more items placed in request queue? 755 756 757 # *********************************************************************************** 758 # 759 # TAB/DEVICE CHANGE SLOTS 760 # 761 # *********************************************************************************** 762 763 def Tabs_currentChanged(self, tab=None): 764 """ Called when the active tab changes. 765 Update newly displayed tab. 766 """ 767 768 if tab is None: 769 tab = self.Tabs.currentPage() 770 771 try: 772 self.TabIndex[tab]() 773 except AttributeError: 774 pass 775 776 def Tabs_deviceChanged(self, tab=None): 777 """ Called when the device changes. 778 Update the currently displayed tab. 779 """ 780 if tab is None: 781 tab = self.Tabs.currentPage() 782 783 self.TabIndex[tab]() 784 785 786 # *********************************************************************************** 787 # 788 # DEVICE ICON LIST/DEVICE UPDATE(S) 789 # 790 # *********************************************************************************** 791 792 def DeviceList_onItem(self, a0): 793 pass 794 795 796 def deviceRescanAction_activated(self): 797 self.deviceRescanAction.setEnabled(False) 798 self.RequestDeviceUpdate() 799 self.deviceRescanAction.setEnabled(True) 800 801 802 def deviceRefreshAll_activated(self): 803 self.RescanDevices() 804 805 806 def DeviceList_clicked(self,a0): 807 pass 808 809 810 def CreatePixmap(self, dev=None): 811 if dev is None: 812 dev = self.cur_device 813 814 try: 815 dev.icon 816 except AttributeError: 817 dev.icon = "default_printer" 818 819 try: 820 self.device_icons[dev.icon] 821 except: 822 self.device_icons[dev.icon] = load_pixmap(dev.icon, 'devices') 823 824 pix = self.device_icons[dev.icon] 825 826 w, h = pix.width(), pix.height() 827 error_state = dev.error_state 828 icon = QPixmap(w, h) 829 p = QPainter(icon) 830 p.eraseRect(0, 0, icon.width(), icon.height()) 831 p.drawPixmap(0, 0, pix) 832 833 try: 834 tech_type = dev.tech_type 835 except AttributeError: 836 tech_type = TECH_TYPE_NONE 837 838 if dev.device_type == DEVICE_TYPE_FAX: 839 p.drawPixmap(w - self.fax_icon.width(), 0, self.fax_icon) 840 841 if error_state != ERROR_STATE_CLEAR: 842 if tech_type in (TECH_TYPE_COLOR_INK, TECH_TYPE_MONO_INK): 843 status_icon = self.SMALL_ICONS[error_state][0] # ink 844 else: 845 status_icon = self.SMALL_ICONS[error_state][1] # laser 846 847 if status_icon is not None: 848 p.drawPixmap(0, 0, status_icon) 849 850 p.end() 851 852 return icon 853 854 855 def DeviceListRefresh(self): 856 global devices 857 log.debug("Rescanning device list...") 858 859 if not self.rescanning: 860 self.setCaption(self.__tr("Refreshing Device List - HP Device Manager")) 861 self.statusBar().message(self.__tr("Refreshing device list...")) 862 863 self.rescanning = True 864 self.cups_devices = device.getSupportedCUPSDevices(['hp', 'hpfax']) 865 866 devices_lock.acquire() 867 868 try: 869 adds = [] 870 for d in self.cups_devices: 871 if d not in devices: 872 adds.append(d) 873 874 log.debug("Adds: %s" % ','.join(adds)) 875 876 removals = [] 877 for d in devices: 878 if d not in self.cups_devices: 879 removals.append(d) 880 881 log.debug("Removals (1): %s" % ','.join(removals)) 882 883 updates = [] 884 for d in devices: 885 if d not in adds and d not in removals: 886 updates.append(d) 887 888 log.debug("Updates: %s" % ','.join(updates)) 889 890 891 for d in adds: 892 log.debug("adding: %s" % d) 893 try: 894 dev = device.Device(d, service=self.service, callback=self.callback, 895 disable_dbus=self.disable_dbus) 896 except Error: 897 log.error("Unexpected error in Device class.") 898 log.exception() 899 900 if not dev.supported: 901 log.debug("Unsupported model - removing device.") 902 removals.append(d) 903 continue 904 905 self.CheckForDeviceSettingsUI(dev) 906 icon = self.CreatePixmap(dev) 907 908 if dev.device_type == DEVICE_TYPE_FAX: 909 DeviceViewItem(self.DeviceList, self.__tr("%1 (Fax)").arg(dev.model_ui), 910 icon, d) 911 else: 912 if dev.fax_type: 913 DeviceViewItem(self.DeviceList, self.__tr("%1 (Printer)").arg(dev.model_ui), 914 icon, d) 915 else: 916 DeviceViewItem(self.DeviceList, dev.model_ui, 917 icon, d) 918 919 devices[d] = dev 920 921 log.debug("Removals (2): %s" % ','.join(removals)) 922 removed_device=None 923 for d in removals: 924 removed_device = d 925 item = self.DeviceList.firstItem() 926 log.debug("removing: %s" % d) 927 928 try: 929 del devices[d] 930 except KeyError: 931 pass 932 933 934 while item is not None: 935 if item.device_uri == d: 936 self.DeviceList.takeItem(item) 937 break 938 939 item = item.nextItem() 940 941 qApp.processEvents() 942 943 self.DeviceList.adjustItems() 944 self.DeviceList.updateGeometry() 945 qApp.processEvents() 946 # sending Event to remove this device from hp-systray 947 if removed_device: 948 utils.sendEvent(EVENT_CUPS_QUEUES_REMOVED,removed_device, "") 949 950 if len(devices): 951 for tab in self.TabIndex: 952 self.Tabs.setTabEnabled(tab, True) 953 954 if self.cur_device_uri: 955 item = first_item = self.DeviceList.firstItem() 956 957 while item is not None: 958 qApp.processEvents() 959 if item.device_uri == self.cur_device_uri: 960 self.DeviceList.setCurrentItem(item) 961 self.DeviceList.setSelected(item, True) 962 self.statusBar().message(self.cur_device_uri) 963 break 964 965 item = item.nextItem() 966 967 else: 968 self.cur_device = None 969 self.cur_device_uri = '' 970 971 if self.cur_device is None: 972 self.cur_device_uri = self.DeviceList.firstItem().device_uri 973 self.cur_device = devices[self.cur_device_uri] 974 self.DeviceList.setCurrentItem(self.DeviceList.firstItem()) 975 976 self.Tabs.setTabEnabled(self.SuppliesTab, self.cur_device.device_type == DEVICE_TYPE_PRINTER and 977 self.cur_device.error_state != ERROR_STATE_ERROR) 978 979 self.UpdatePrinterCombos() 980 981 user_conf.set('last_used', 'device_uri', self.cur_device_uri) 982 983 for d in updates + adds: 984 if d not in removals: 985 self.RequestDeviceUpdate(devices[d]) 986 987 else: 988 self.cur_device = None 989 self.deviceRescanAction.setEnabled(False) 990 self.deviceRemoveAction.setEnabled(False) 991 self.rescanning = False 992 self.statusBar().message(self.__tr("Press F6 to refresh.")) 993 994 for tab in self.TabIndex: 995 self.Tabs.setTabEnabled(tab, False) 996 997 dlg = NoDevicesForm(self, "", True) 998 dlg.show() 999 1000 finally: 1001 self.rescanning = False 1002 devices_lock.release() 1003 1004 self.deviceRescanAction.setEnabled(True) 1005 self.deviceRemoveAction.setEnabled(True) 1006 1007 1008 1009 def UpdateTitle(self): 1010 if self.cur_device.device_type == DEVICE_TYPE_FAX: 1011 self.setCaption(self.__tr("HP Device Manager - %1 (Fax)").arg(self.cur_device.model_ui)) 1012 else: 1013 if self.cur_device.fax_type: 1014 self.setCaption(self.__tr("HP Device Manager - %1 (Printer)").arg(self.cur_device.model_ui)) 1015 else: 1016 self.setCaption(self.__tr("HP Device Manager - %1").arg(self.cur_device.model_ui)) 1017 1018 1019 def UpdateDeviceByURI(self, device_uri): 1020 return self.UpdateDevice(self.findDeviceByURI(device_uri)) 1021 1022 1023 def UpdateDevice(self, dev=None, update_tab=True): 1024 """ Update the device icon and currently displayed tab. 1025 """ 1026 if dev is None: 1027 dev = self.cur_device 1028 1029 log.debug("UpdateDevice(%s)" % dev.device_uri) 1030 1031 item = self.findItem(dev) 1032 1033 if item is not None: 1034 item.setPixmap(self.CreatePixmap(dev)) 1035 1036 if dev is self.cur_device and dev.error_state == ERROR_STATE_ERROR: 1037 self.Tabs.setCurrentPage(1) 1038 1039 if dev is self.cur_device and update_tab: 1040 self.UpdatePrinterCombos() 1041 self.TabIndex[self.Tabs.currentPage()]() 1042 1043 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 1044 self.Tabs.changeTab(self.PrintSettingsTab,self.__tr("Print Settings")) 1045 self.Tabs.changeTab(self.PrintJobsTab,self.__tr("Print Control")) 1046 else: 1047 self.Tabs.changeTab(self.PrintSettingsTab,self.__tr("Fax Settings")) 1048 self.Tabs.changeTab(self.PrintJobsTab,self.__tr("Fax Control")) 1049 qApp.processEvents() 1050 1051 1052 def DeviceList_currentChanged(self, i): 1053 if i is not None: # and not self.rescanning: 1054 self.cur_device_uri = self.DeviceList.currentItem().device_uri 1055 self.cur_device = devices[self.cur_device_uri] 1056 user_conf.set('last_used', 'device_uri', self.cur_device_uri) 1057 1058 self.Tabs.setTabEnabled(self.SuppliesTab, self.cur_device.device_type == DEVICE_TYPE_PRINTER and 1059 self.cur_device.error_state != ERROR_STATE_ERROR) 1060 1061 self.UpdateDevice() 1062 self.UpdateTitle() 1063 1064 1065 def findItem(self, dev): 1066 if dev is None: 1067 dev = self.cur_device 1068 1069 return self.findItemByURI(dev.device_uri) 1070 1071 1072 def findItemByURI(self, device_uri): 1073 item = self.DeviceList.firstItem() 1074 1075 while item is not None: 1076 if item.device_uri == device_uri: 1077 return item 1078 item = item.nextItem() 1079 1080 1081 def findDeviceByURI(self, device_uri): 1082 try: 1083 return devices[device_uri] 1084 except: 1085 return None 1086 1087 1088 def RequestDeviceUpdate(self, dev=None, item=None): 1089 """ Submit device update request to update thread. """ 1090 1091 if dev is None: 1092 dev = self.cur_device 1093 1094 if dev is not None: 1095 #log.debug("RequestDeviceUpdate(%s)" % dev.device_uri) 1096 dev.error_state = ERROR_STATE_REFRESHING 1097 self.UpdateDevice(dev, update_tab=False) 1098 qApp.processEvents() 1099 1100 self.request_queue.put(dev) 1101 1102 1103 def RescanDevices(self): 1104 #log.debug("RescanDevices()") 1105 if not self.rescanning: 1106 self.deviceRefreshAll.setEnabled(False) 1107 try: 1108 self.DeviceListRefresh() 1109 finally: 1110 self.deviceRefreshAll.setEnabled(True) 1111 1112 1113 def callback(self): 1114 qApp.processEvents() 1115 1116 1117 # *********************************************************************************** 1118 # 1119 # DEVICE LIST RIGHT CLICK 1120 # 1121 # *********************************************************************************** 1122 1123 def DeviceList_rightButtonClicked(self, item, pos): 1124 popup = QPopupMenu(self) 1125 1126 if item is not None and item is self.DeviceList.currentItem(): 1127 if self.cur_device.error_state != ERROR_STATE_ERROR: 1128 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 1129 popup.insertItem(self.__tr("Print..."), self.PrintButton_clicked) 1130 1131 if self.cur_device.scan_type: 1132 popup.insertItem(self.__tr("Scan..."), self.ScanButton_clicked) 1133 1134 if self.cur_device.pcard_type: 1135 popup.insertItem(self.__tr("Access Photo Cards..."), self.PCardButton_clicked) 1136 1137 if self.cur_device.copy_type: 1138 popup.insertItem(self.__tr("Make Copies..."), self.MakeCopiesButton_clicked) 1139 1140 elif self.cur_device.device_type == DEVICE_TYPE_FAX: 1141 if self.cur_device.fax_type: 1142 popup.insertItem(self.__tr("Send Fax..."), self.SendFaxButton_clicked) 1143 1144 popup.insertSeparator() 1145 1146 if self.cur_device.device_settings_ui is not None: 1147 popup.insertItem(self.__tr("Device Settings..."), self.deviceSettingsButton_clicked) 1148 1149 if not self.rescanning: 1150 popup.insertItem(self.__tr("Refresh Device"), self.deviceRescanAction_activated) 1151 1152 if not self.rescanning: 1153 popup.insertItem(self.__tr("Refresh All"), self.deviceRefreshAll_activated) 1154 1155 popup.popup(pos) 1156 1157 1158 # *********************************************************************************** 1159 # 1160 # PRINTER NAME COMBOS 1161 # 1162 # *********************************************************************************** 1163 1164 def updatePrinterList(self): 1165 if self.cur_device is not None and \ 1166 self.cur_device.supported: 1167 1168 printers = cups.getPrinters() 1169 self.cur_device.cups_printers = [] 1170 1171 for p in printers: 1172 if p.device_uri == self.cur_device_uri: 1173 self.cur_device.cups_printers.append(p.name) 1174 1175 1176 def UpdatePrinterCombos(self): 1177 self.PrintSettingsPrinterCombo.clear() 1178 self.PrintJobPrinterCombo.clear() 1179 1180 if self.cur_device is not None and \ 1181 self.cur_device.supported: 1182 1183 for c in self.cur_device.cups_printers: 1184 self.PrintSettingsPrinterCombo.insertItem(c.decode("utf-8")) 1185 self.PrintJobPrinterCombo.insertItem(c.decode("utf-8")) 1186 1187 self.cur_printer = to_unicode(self.PrintSettingsPrinterCombo.currentText()) 1188 1189 def PrintSettingsPrinterCombo_activated(self, s): 1190 self.cur_printer = to_unicode(s) 1191 self.PrintJobPrinterCombo.setCurrentText(self.cur_printer.encode("latin1")) # TODO: ? 1192 return self.PrinterCombo_activated(self.cur_printer) 1193 1194 def PrintJobPrinterCombo_activated(self, s): 1195 self.cur_printer = to_unicode(s) 1196 self.PrintSettingsPrinterCombo.setCurrentText(self.cur_printer.encode("latin1")) # TODO: ? 1197 return self.PrinterCombo_activated(self.cur_printer) 1198 1199 def PrinterCombo_activated(self, printer): 1200 self.TabIndex[self.Tabs.currentPage()]() 1201 self.UpdatePrintSettingsTabPrinter() 1202 1203 1204 1205 # *********************************************************************************** 1206 # 1207 # FUNCTIONS/ACTION TAB 1208 # 1209 # *********************************************************************************** 1210 1211 def InitFuncsTab(self): 1212 self.click_lock = None 1213 1214 def UpdateFuncsTab(self): 1215 self.iconList.clear() 1216 1217 d = self.cur_device 1218 1219 if d is not None: 1220 1221 avail = d.device_state != DEVICE_STATE_NOT_FOUND and d.supported 1222 fax = d.fax_type and prop.fax_build and d.device_type == DEVICE_TYPE_FAX and \ 1223 sys.hexversion >= 0x020300f0 and avail 1224 printer = d.device_type == DEVICE_TYPE_PRINTER and avail 1225 req_plugin = d.plugin == PLUGIN_REQUIRED 1226 opt_plugin = d.plugin == PLUGIN_OPTIONAL 1227 1228 hplip_conf = ConfigParser.ConfigParser() 1229 fp = open("/usr/local/etc/hp/hplip.conf", "r") 1230 hplip_conf.readfp(fp) 1231 fp.close() 1232 1233 try: 1234 plugin_installed = utils.to_bool(hplip_conf.get("hplip", "plugin")) 1235 except ConfigParser.NoOptionError: 1236 plugin_installed = False 1237 1238 if d.plugin: 1239 if req_plugin and plugin_installed: 1240 x = self.__tr("Download and install<br>required plugin (already installed).") 1241 1242 elif req_plugin and not plugin_installed: 1243 x = self.__tr("Download and install<br>required plugin (needs installation).") 1244 1245 elif opt_plugin and plugin_installed: 1246 x = self.__tr("Download and install<br>optional plugin (already installed).") 1247 1248 elif opt_plugin and not plugin_installed: 1249 x = self.__tr("Download and install<br>optional plugin (needs installation).") 1250 1251 else: 1252 x = '' 1253 1254 1255 self.ICONS = [ 1256 1257 # PRINTER 1258 1259 (lambda : printer, # filter func 1260 self.__tr("Print"), # Text 1261 "print", # Icon 1262 self.__tr("Print documents or files."), # Tooltip 1263 self.user_settings.cmd_print), # command/action 1264 1265 (lambda : d.scan_type and prop.scan_build and \ 1266 d.device_type == DEVICE_TYPE_PRINTER and avail, 1267 self.__tr("Scan"), 1268 "scan", 1269 self.__tr("Scan a document, image, or photograph.<br>"), 1270 self.user_settings.cmd_scan), 1271 1272 (lambda : d.copy_type and d.device_type == DEVICE_TYPE_PRINTER and avail, 1273 self.__tr("Make Copies"), 1274 "makecopies", 1275 self.__tr("Make copies on the device controlled by the PC.<br>"), 1276 self.user_settings.cmd_copy), 1277 1278 (lambda : d.pcard_type and d.device_type == DEVICE_TYPE_PRINTER and avail, 1279 self.__tr("Unload Photo Card"), 1280 "makecopies", 1281 self.__tr("Copy images from the device's photo card to the PC."), 1282 self.PCardButton_clicked), 1283 1284 # FAX 1285 1286 (lambda: fax, 1287 self.__tr("Send Fax"), 1288 "fax", 1289 self.__tr("Send a fax from the PC."), 1290 self.user_settings.cmd_fax), 1291 1292 (lambda: fax, 1293 self.__tr("Fax Setup"), 1294 "fax_setup", 1295 self.__tr("Fax support must be setup before you can send faxes."), 1296 self.faxSettingsButton_clicked), 1297 1298 (lambda: fax, 1299 self.__tr("Fax Address Book"), 1300 "fab", 1301 self.__tr("Setup fax phone numbers to use when sending faxes from the PC."), 1302 self.cmd_fab), 1303 1304 # SETTINGS/TOOLS 1305 1306 (lambda : self.cur_device.device_settings_ui is not None and avail, 1307 self.__tr("Device Settings"), 1308 "settings", 1309 self.__tr("Your device has special device settings.<br>You may alter these settings here."), 1310 self.deviceSettingsButton_clicked), 1311 1312 (lambda : printer, 1313 self.__tr("Print Test Page"), 1314 "testpage", 1315 self.__tr("Print a test page to test the setup of your printer."), 1316 self.PrintTestPageButton_clicked), 1317 1318 (lambda : True, 1319 self.__tr("View Printer (Queue) Information"), 1320 "cups", 1321 self.__tr("View the printers (queues) installed in CUPS."), 1322 self.viewPrinterInformation), 1323 1324 (lambda : True, 1325 self.__tr("View Device Information"), 1326 "info", 1327 self.__tr("This information is primarily useful for <br>debugging and troubleshooting (advanced)."), 1328 self.viewInformation), 1329 1330 (lambda: printer and d.align_type, 1331 self.__tr("Align Cartridges (Print Heads)"), 1332 "align", 1333 self.__tr("This will improve the quality of output when a new cartridge is installed."), 1334 self.AlignPensButton_clicked), 1335 1336 (lambda: printer and d.clean_type, 1337 self.__tr("Clean Printheads"), 1338 "clean", 1339 self.__tr("You only need to perform this action if you are<br>having problems with poor printout quality due to clogged ink nozzles."), 1340 self.CleanPensButton_clicked), 1341 1342 (lambda: printer and d.color_cal_type and d.color_cal_type == COLOR_CAL_TYPE_TYPHOON, 1343 self.__tr("Color Calibration"), 1344 "colorcal", 1345 self.__tr("Use this procedure to optimimize your printer's color output<br>(requires glossy photo paper)."), 1346 self.ColorCalibrationButton_clicked), 1347 1348 (lambda: printer and d.color_cal_type and d.color_cal_type != COLOR_CAL_TYPE_TYPHOON, 1349 self.__tr("Color Calibration"), 1350 "colorcal", 1351 self.__tr("Use this procedure to optimimize your printer's color output."), 1352 self.ColorCalibrationButton_clicked), 1353 1354 (lambda: printer and d.linefeed_cal_type, 1355 self.__tr("Line Feed Calibration"), 1356 "linefeed_cal", 1357 self.__tr("Use line feed calibration to optimize print quality<br>(to remove gaps in the printed output)."), 1358 self.linefeedCalibration), 1359 1360 (lambda: printer and d.pq_diag_type, 1361 self.__tr("Print Diagnostic Page"), 1362 "pq_diag", 1363 self.__tr("Your printer can print a test page <br>to help diagnose print quality problems."), 1364 self.pqDiag), 1365 1366 # FIRMWARE 1367 1368 (lambda : printer and d.fw_download, 1369 self.__tr("Download Firmware"), 1370 "firmware", 1371 self.__tr("Download firmware to your printer <br>(required on some devices after each power-up)."), 1372 self.ShowFirmwareDlg), 1373 1374 # PLUGIN 1375 1376 (lambda : req_plugin, 1377 self.__tr("Install Required Plugin"), 1378 "plugin", 1379 x, #self.__tr("Download and install the HPLIP plugin."), 1380 self.downloadPlugin), 1381 1382 (lambda : opt_plugin, 1383 self.__tr("Install Optional Plugin"), 1384 "plugin", 1385 x, #self.__tr("Download and install the HPLIP plugin."), 1386 self.downloadPlugin), 1387 1388 # HELP/WEBSITE 1389 1390 (lambda : True, 1391 self.__tr("Visit HPLIP Website"), 1392 "hp_logo", 1393 self.__tr("Visit HPLIP website."), 1394 self.viewSupport), 1395 1396 (lambda : True, 1397 self.__tr("Help"), 1398 "help", 1399 self.__tr("View HPLIP help."), 1400 self.viewHelp), 1401 ] 1402 1403 if not self.func_icons_cached: 1404 for filter, text, icon, tooltip, cmd in self.ICONS: 1405 self.func_icons[icon] = load_pixmap(icon, '32x32') 1406 self.func_icons_cached = True 1407 1408 for filter, text, icon, tooltip, cmd in self.ICONS: 1409 if filter is not None: 1410 if not list(filter()): 1411 continue 1412 1413 FuncViewItem(self.iconList, text, 1414 self.func_icons[icon], 1415 tooltip, 1416 cmd) 1417 1418 1419 def downloadPlugin(self): 1420 ok, sudo_ok = pkit.run_plugin_command(self.cur_device.plugin == PLUGIN_REQUIRED, self.cur_device.mq['plugin-reason']) 1421 if not sudo_ok: 1422 QMessageBox.critical(self, 1423 self.caption(), 1424 self.__tr("<b>Unable to find an appropriate su/sudo utility to run hp-plugin.</b><p>Install kdesu, gnomesu, or gksu.</p>"), 1425 QMessageBox.Ok, 1426 QMessageBox.NoButton, 1427 QMessageBox.NoButton) 1428 else: 1429 self.UpdateFuncsTab() 1430 1431 1432 def iconList_clicked(self, item): 1433 return self.RunFuncCmd(item) 1434 1435 1436 def RunFuncCmd(self, item): 1437 if item is not None and self.click_lock is not item: 1438 try: 1439 item.cmd() 1440 except TypeError: 1441 self.RunCommand(item.cmd) 1442 1443 self.click_lock = item 1444 QTimer.singleShot(1000, self.UnlockClick) 1445 1446 1447 def UnlockClick(self): 1448 self.click_lock = None 1449 1450 1451 def RunFuncCmdContext(self): 1452 return self.RunFuncCmd(self.iconList.currentItem()) 1453 1454 1455 def iconList_contextMenuRequested(self, item, pos): 1456 if item is not None and item is self.iconList.currentItem(): 1457 popup = QPopupMenu(self) 1458 popup.insertItem(self.__tr("Open..."), self.RunFuncCmdContext) 1459 popup.popup(pos) 1460 1461 1462 def iconList_returnPressed(self, item): 1463 return self.RunFuncCmd(item) 1464 1465 1466 def deviceSettingsButton_clicked(self): 1467 try: 1468 self.cur_device.open() 1469 self.cur_device.device_settings_ui(self.cur_device, self) 1470 finally: 1471 self.cur_device.close() 1472 1473 1474 def setupDevice_activated(self): 1475 try: 1476 self.cur_device.open() 1477 self.cur_device.device_settings_ui(self.cur_device, self) 1478 finally: 1479 self.cur_device.close() 1480 1481 1482 def PrintButton_clicked(self): 1483 self.RunCommand(self.user_settings.cmd_print) 1484 1485 1486 def ScanButton_clicked(self): 1487 self.RunCommand(self.user_settings.cmd_scan) 1488 1489 1490 def PCardButton_clicked(self): 1491 if self.cur_device.pcard_type == PCARD_TYPE_MLC: 1492 self.RunCommand(self.user_settings.cmd_pcard) 1493 1494 elif self.cur_device.pcard_type == PCARD_TYPE_USB_MASS_STORAGE: 1495 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.")) 1496 1497 1498 def SendFaxButton_clicked(self): 1499 self.RunCommand(self.user_settings.cmd_fax) 1500 1501 1502 def MakeCopiesButton_clicked(self): 1503 self.RunCommand(self.user_settings.cmd_copy) 1504 1505 1506 def ConfigureFeaturesButton_clicked(self): 1507 self.settingsConfigure_activated(2) 1508 1509 1510 def viewInformation(self): 1511 dlg = ScrollDialog(ScrollDeviceInfoView, self.cur_device, self.cur_printer, self.service, self) 1512 dlg.exec_loop() 1513 1514 1515 def viewPrinterInformation(self): 1516 dlg = ScrollDialog(ScrollPrinterInfoView, self.cur_device, self.cur_printer, self.service, self) 1517 dlg.exec_loop() 1518 1519 1520 def viewHelp(self): 1521 f = "http://hplip.sf.net" 1522 1523 if prop.doc_build: 1524 g = os.path.join(sys_conf.get('dirs', 'doc'), 'index.html') 1525 if os.path.exists(g): 1526 f = "file://%s" % g 1527 1528 log.debug(f) 1529 utils.openURL(f) 1530 1531 1532 def viewSupport(self): 1533 f = "http://hplip.sf.net" 1534 log.debug(f) 1535 utils.openURL(f) 1536 1537 1538 def pqDiag(self): 1539 d = self.cur_device 1540 pq_diag = d.pq_diag_type 1541 1542 try: 1543 QApplication.setOverrideCursor(QApplication.waitCursor) 1544 1545 try: 1546 d.open() 1547 except Error: 1548 self.CheckDeviceUI() 1549 else: 1550 if d.isIdleAndNoError(): 1551 QApplication.restoreOverrideCursor() 1552 1553 if pq_diag == 1: 1554 maint.printQualityDiagType1(d, self.LoadPaperUI) 1555 1556 elif pq_diag == 2: 1557 maint.printQualityDiagType2(d, self.LoadPaperUI) 1558 1559 else: 1560 self.CheckDeviceUI() 1561 1562 finally: 1563 d.close() 1564 QApplication.restoreOverrideCursor() 1565 1566 1567 def linefeedCalibration(self): 1568 d = self.cur_device 1569 linefeed_type = d.linefeed_cal_type 1570 1571 try: 1572 QApplication.setOverrideCursor(QApplication.waitCursor) 1573 1574 try: 1575 d.open() 1576 except Error: 1577 self.CheckDeviceUI() 1578 else: 1579 if d.isIdleAndNoError(): 1580 QApplication.restoreOverrideCursor() 1581 1582 if linefeed_type == 1: 1583 maint.linefeedCalType1(d, self.LoadPaperUI) 1584 1585 elif linefeed_type == 2: 1586 maint.linefeedCalType2(d, self.LoadPaperUI) 1587 1588 else: 1589 self.CheckDeviceUI() 1590 1591 finally: 1592 d.close() 1593 QApplication.restoreOverrideCursor() 1594 1595 1596 def downloadFirmware(self): 1597 d = self.cur_device 1598 ok = False 1599 1600 try: 1601 QApplication.setOverrideCursor(QApplication.waitCursor) 1602 d.open() 1603 1604 if d.isIdleAndNoError(): 1605 ok = d.downloadFirmware() 1606 1607 finally: 1608 d.close() 1609 QApplication.restoreOverrideCursor() 1610 1611 if not ok: 1612 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.")) 1613 1614 1615 def CheckDeviceUI(self): 1616 self.FailureUI(self.__tr("<b>Device is busy or in an error state.</b><p>Please check device and try again.")) 1617 1618 1619 def LoadPaperUI(self, msg="", title=""): 1620 LPFObj = LoadPaperForm(self) 1621 if title: 1622 LPFObj.setCaption(title) 1623 if msg: 1624 LPFObj.textLabel7.setText(msg) 1625 1626 if LPFObj.exec_loop() == QDialog.Accepted: 1627 return True 1628 return False 1629 1630 1631 def AlignmentNumberUI(self, letter, hortvert, colors, line_count, choice_count): 1632 dlg = AlignForm(self, letter, hortvert, colors, line_count, choice_count) 1633 if dlg.exec_loop() == QDialog.Accepted: 1634 return True, dlg.value 1635 else: 1636 return False, 0 1637 1638 1639 def PaperEdgeUI(self, maximum): 1640 dlg = PaperEdgeAlignForm(self) 1641 if dlg.exec_loop() == QDialog.Accepted: 1642 return True, dlg.value 1643 else: 1644 return False, 0 1645 1646 1647 def BothPensRequiredUI(self): 1648 self.WarningUI(self.__tr("<p><b>Both cartridges are required for alignment.</b><p>Please install both cartridges and try again.")) 1649 1650 1651 def InvalidPenUI(self): 1652 self.WarningUI(self.__tr("<p><b>One or more cartiridges are missing from the printer.</b><p>Please install cartridge(s) and try again.")) 1653 1654 1655 def PhotoPenRequiredUI(self): 1656 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.")) 1657 1658 1659 def PhotoPenRequiredUI2(self): 1660 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.")) 1661 1662 1663 def NotPhotoOnlyRequired(self): # Type 11 1664 self.WarningUI(self.__tr("<p><b>Cannot align with only the photo cartridge installed.</b><p>Please install other cartridges and try again.")) 1665 1666 1667 def AioUI1(self): 1668 dlg = AlignType6Form1(self) 1669 return dlg.exec_loop() == QDialog.Accepted 1670 1671 1672 def AioUI2(self): 1673 AlignType6Form2(self).exec_loop() 1674 1675 1676 def Align10and11UI(self, pattern, align_type): 1677 dlg = Align10Form(pattern, align_type, self) 1678 dlg.exec_loop() 1679 return dlg.getValues() 1680 1681 1682 def Align13UI(self): 1683 dlg = Align13Form(self) 1684 dlg.exec_loop() 1685 return True 1686 1687 1688 def AlignPensButton_clicked(self): 1689 d = self.cur_device 1690 align_type = d.align_type 1691 1692 log.debug("Align: %s %s (type=%d) %s" % ("*"*20, self.cur_device.device_uri, align_type, "*"*20)) 1693 1694 try: 1695 QApplication.setOverrideCursor(QApplication.waitCursor) 1696 1697 try: 1698 d.open() 1699 except Error: 1700 self.CheckDeviceUI() 1701 else: 1702 if d.isIdleAndNoError(): 1703 QApplication.restoreOverrideCursor() 1704 1705 if align_type == ALIGN_TYPE_AUTO: 1706 maint.AlignType1(d, self.LoadPaperUI) 1707 1708 elif align_type == ALIGN_TYPE_8XX: 1709 maint.AlignType2(d, self.LoadPaperUI, self.AlignmentNumberUI, 1710 self.BothPensRequiredUI) 1711 1712 elif align_type in (ALIGN_TYPE_9XX,ALIGN_TYPE_9XX_NO_EDGE_ALIGN): 1713 maint.AlignType3(d, self.LoadPaperUI, self.AlignmentNumberUI, 1714 self.PaperEdgeUI, align_type) 1715 1716 elif align_type in (ALIGN_TYPE_LIDIL_0_3_8, ALIGN_TYPE_LIDIL_0_4_3, ALIGN_TYPE_LIDIL_VIP): 1717 maint.AlignxBow(d, align_type, self.LoadPaperUI, self.AlignmentNumberUI, 1718 self.PaperEdgeUI, self.InvalidPenUI, self.ColorAdjUI) 1719 1720 elif align_type == ALIGN_TYPE_LIDIL_AIO: 1721 maint.AlignType6(d, self.AioUI1, self.AioUI2, self.LoadPaperUI) 1722 1723 elif align_type == ALIGN_TYPE_DESKJET_450: 1724 maint.AlignType8(d, self.LoadPaperUI, self.AlignmentNumberUI) 1725 1726 elif align_type == ALIGN_TYPE_LBOW: 1727 maint.AlignType10(d, self.LoadPaperUI, self.Align10and11UI) 1728 1729 elif align_type == ALIGN_TYPE_LIDIL_0_5_4: 1730 maint.AlignType11(d, self.LoadPaperUI, self.Align10and11UI, self.NotPhotoOnlyRequired) 1731 1732 elif align_type == ALIGN_TYPE_OJ_PRO: 1733 maint.AlignType12(d, self.LoadPaperUI) 1734 1735 elif align_type == ALIGN_TYPE_AIO: 1736 maint.AlignType13(d, self.LoadPaperUI, self.Align13UI) 1737 1738 elif align_type == ALIGN_TYPE_LEDM: 1739 maint.AlignType15(d, self.LoadPaperUI, self.Align13UI) 1740 1741 elif align_type == ALIGN_TYPE_LEDM_MANUAL: 1742 maint.AlignType16(d, self.LoadPaperUI, self.AlignmentNumberUI) 1743 1744 elif align_type == ALIGN_TYPE_LEDM_FF_CC_0: 1745 maint.AlignType17(d, self.LoadPaperUI, self.Align13UI) 1746 1747 elif align_type == ALIGN_TYPE_UNSUPPORTED: 1748 self.WarningUI(self.__tr("<p><b>Alignment through HPLIP not supported for this printer. Please use the printer's front panel to perform cartridge alignment.</b>")) 1749 1750 else: 1751 self.CheckDeviceUI() 1752 1753 finally: 1754 d.close() 1755 QApplication.restoreOverrideCursor() 1756 1757 1758 def ColorAdjUI(self, line, maximum=0): 1759 dlg = ColorAdjForm(self, line) 1760 if dlg.exec_loop() == QDialog.Accepted: 1761 return True, dlg.value 1762 else: 1763 return False, 0 1764 1765 1766 def ColorCalUI(self): 1767 dlg = ColorCalForm(self) 1768 if dlg.exec_loop() == QDialog.Accepted: 1769 return True, dlg.value 1770 else: 1771 return False, 0 1772 1773 1774 def ColorCalUI2(self): 1775 dlg = ColorCalForm2(self) 1776 if dlg.exec_loop() == QDialog.Accepted: 1777 return True, dlg.value 1778 else: 1779 return False, 0 1780 1781 1782 def ColorCalUI4(self): 1783 dlg = ColorCal4Form(self) 1784 if dlg.exec_loop() == QDialog.Accepted: 1785 return True, dlg.values 1786 else: 1787 return False, None 1788 1789 1790 def ColorCalibrationButton_clicked(self): 1791 d = self.cur_device 1792 color_cal_type = d.color_cal_type 1793 log.debug("Color-cal: %s %s (type=%d) %s" % ("*"*20, self.cur_device.device_uri, color_cal_type, "*"*20)) 1794 1795 if color_cal_type == COLOR_CAL_TYPE_TYPHOON: 1796 dlg = ScrollDialog(ScrollColorCalView, self.cur_device, self.cur_printer, self.service, self) 1797 dlg.exec_loop() 1798 else: 1799 try: 1800 QApplication.setOverrideCursor(QApplication.waitCursor) 1801 1802 try: 1803 d.open() 1804 except Error: 1805 self.CheckDeviceUI() 1806 else: 1807 if d.isIdleAndNoError(): 1808 QApplication.restoreOverrideCursor() 1809 1810 if color_cal_type == COLOR_CAL_TYPE_DESKJET_450: 1811 maint.colorCalType1(d, self.LoadPaperUI, self.ColorCalUI, 1812 self.PhotoPenRequiredUI) 1813 1814 elif color_cal_type == COLOR_CAL_TYPE_MALIBU_CRICK: 1815 maint.colorCalType2(d, self.LoadPaperUI, self.ColorCalUI2, 1816 self.InvalidPenUI) 1817 1818 elif color_cal_type == COLOR_CAL_TYPE_STRINGRAY_LONGBOW_TORNADO: 1819 maint.colorCalType3(d, self.LoadPaperUI, self.ColorAdjUI, 1820 self.PhotoPenRequiredUI2) 1821 1822 elif color_cal_type == COLOR_CAL_TYPE_CONNERY: 1823 maint.colorCalType4(d, self.LoadPaperUI, self.ColorCalUI4, 1824 self.WaitUI) 1825 1826 elif color_cal_type == COLOR_CAL_TYPE_COUSTEAU: 1827 maint.colorCalType5(d, self.LoadPaperUI) 1828 1829 elif color_cal_type == COLOR_CAL_TYPE_CARRIER: 1830 maint.colorCalType6(d, self.LoadPaperUI) 1831 1832 else: 1833 self.CheckDeviceUI() 1834 1835 finally: 1836 d.close() 1837 QApplication.restoreOverrideCursor() 1838 1839 1840 def PrintTestPageButton_clicked(self): 1841 dlg = ScrollDialog(ScrollTestpageView, self.cur_device, self.cur_printer, self.service, self) 1842 dlg.exec_loop() 1843 1844 1845 def CleanUI1(self, msg=""): 1846 CFObj = CleaningForm(self, self.cur_device, 1) 1847 if msg: 1848 CFObj.CleaningText.setText(msg) 1849 return CFObj.exec_loop() == QDialog.Accepted 1850 1851 1852 def CleanUI2(self, msg=""): 1853 CFObj = CleaningForm(self, self.cur_device, 2) 1854 if msg: 1855 CFObj.CleaningText.setText(msg) 1856 return CFObj.exec_loop() == QDialog.Accepted 1857 1858 1859 def CleanUI3(self, msg=""): 1860 CleaningForm2(self).exec_loop() 1861 return True 1862 1863 1864 def WaitUI(self, seconds): 1865 WaitForm(seconds, None, self).exec_loop() 1866 1867 1868 def CleanPensButton_clicked(self): 1869 d = self.cur_device 1870 clean_type = d.clean_type 1871 log.debug("Clean: %s %s (type=%d) %s" % ("*"*20, self.cur_device.device_uri, clean_type, "*"*20)) 1872 1873 try: 1874 QApplication.setOverrideCursor(QApplication.waitCursor) 1875 1876 try: 1877 d.open() 1878 except Error: 1879 self.CheckDeviceUI() 1880 else: 1881 if d.isIdleAndNoError(): 1882 QApplication.restoreOverrideCursor() 1883 1884 if clean_type == CLEAN_TYPE_PCL: 1885 maint.cleaning(d, clean_type, maint.cleanType1, maint.primeType1, 1886 maint.wipeAndSpitType1, self.LoadPaperUI, 1887 self.CleanUI1, self.CleanUI2, self.CleanUI3, 1888 self.WaitUI) 1889 1890 elif clean_type == CLEAN_TYPE_LIDIL: 1891 maint.cleaning(d, clean_type, maint.cleanType2, maint.primeType2, 1892 maint.wipeAndSpitType2, self.LoadPaperUI, 1893 self.CleanUI1, self.CleanUI2, self.CleanUI3, 1894 self.WaitUI) 1895 1896 elif clean_type == CLEAN_TYPE_PCL_WITH_PRINTOUT: 1897 maint.cleaning(d, clean_type, maint.cleanType1, maint.primeType1, 1898 maint.wipeAndSpitType1, self.LoadPaperUI, 1899 self.CleanUI1, self.CleanUI2, self.CleanUI3, 1900 self.WaitUI) 1901 1902 elif clean_type == CLEAN_TYPE_LEDM: 1903 maint.cleaning(d, clean_type, maint.cleanTypeLedm, maint.cleanTypeLedm1, 1904 maint.cleanTypeLedm2, self.LoadPaperUI, 1905 self.CleanUI1, self.CleanUI2, self.CleanUI3, 1906 self.WaitUI, maint.isCleanTypeLedmWithPrint) 1907 1908 elif clean_type == CLEAN_TYPE_UNSUPPORTED: 1909 self.WarningUI(self.__tr("<p><b>Cleaning through HPLIP not supported for this printer. Please use the printer's front panel to perform cartridge cleaning.</b>")) 1910 1911 else: 1912 self.CheckDeviceUI() 1913 1914 finally: 1915 d.close() 1916 QApplication.restoreOverrideCursor() 1917 1918 1919 def OpenEmbeddedBrowserButton_clicked(self): 1920 utils.openURL("http://%s" % self.cur_device.host) 1921 1922 1923 def faxAddressBookButton_clicked(self): 1924 self.RunCommand(self.cmd_fab) 1925 1926 1927 def faxSettingsButton_clicked(self): 1928 try: 1929 try: 1930 self.cur_device.open() 1931 except Error: 1932 self.CheckDeviceUI() 1933 else: 1934 try: 1935 result_code, fax_num = self.cur_device.getPML(pml.OID_FAX_LOCAL_PHONE_NUM) 1936 except Error: 1937 log.error("PML failure.") 1938 self.FailureUI(self.__tr("<p><b>Operation failed. Device busy.</b>")) 1939 return 1940 1941 fax_num = str(fax_num) 1942 1943 try: 1944 result_code, name = self.cur_device.getPML(pml.OID_FAX_STATION_NAME) 1945 except Error: 1946 log.error("PML failure.") 1947 self.FailureUI(self.__tr("<p><b>Operation failed. Device busy.</b>")) 1948 return 1949 1950 name = str(name) 1951 1952 dlg = FaxSettingsForm(self.cur_device, fax_num, name, self) 1953 dlg.exec_loop() 1954 1955 finally: 1956 self.cur_device.close() 1957 1958 1959 def addressBookButton_clicked(self): 1960 self.RunCommand(self.cmd_fab) 1961 1962 1963 def ShowFirmwareDlg(self): 1964 dlg = FirmwareDialog(self, self.cur_device_uri) 1965 dlg.show() 1966 return dlg.exec_loop() == QDialog.Accepted 1967 1968 # *********************************************************************************** 1969 # 1970 # STATUS TAB 1971 # 1972 # *********************************************************************************** 1973 1974 def InitStatusTab(self): 1975 self.statusListView.setSorting(-1) 1976 self.statusListView.setColumnText(0, QString("")) 1977 #self.statusListView.setColumnWidthMode(0, QListView.Manual) 1978 self.statusListView.setColumnWidth(0, 16) 1979 1980 1981 def UpdateStatusTab(self): 1982 #log.debug("UpdateStatusTab()") 1983 self.UpdateHistory() 1984 self.UpdatePanel() 1985 self.UpdateStatusList() 1986 1987 1988 def UpdatePanel(self): 1989 if self.cur_device is not None and \ 1990 self.cur_device.hist and \ 1991 self.cur_device.supported: 1992 1993 dq = self.cur_device.dq 1994 1995 if dq.get('panel', 0) == 1: 1996 line1 = dq.get('panel-line1', '') 1997 line2 = dq.get('panel-line2', '') 1998 else: 1999 try: 2000 line1 = device.queryString(self.cur_device.hist[0].event_code) 2001 except (AttributeError, TypeError): 2002 line1 = '' 2003 2004 line2 = '' 2005 2006 pm = load_pixmap('panel_lcd', 'other') 2007 2008 p = QPainter() 2009 p.begin(pm) 2010 p.setPen(QColor(0, 0, 0)) 2011 p.setFont(self.font()) 2012 2013 x, y_line1, y_line2 = 10, 17, 33 2014 2015 # TODO: Scroll long lines 2016 p.drawText(x, y_line1, line1) 2017 p.drawText(x, y_line2, line2) 2018 p.end() 2019 2020 self.panel.setPixmap(pm) 2021 2022 else: 2023 self.panel.setPixmap(load_pixmap('panel_lcd', 'other')) 2024 2025 2026 def UpdateHistory(self, dev=None): 2027 if self.dbus_avail: 2028 if dev is None: 2029 dev = self.cur_device 2030 2031 return dev.queryHistory() 2032 2033 self.cur_device.hist = [self.cur_device.last_event] 2034 2035 2036 2037 def UpdateStatusList(self): 2038 self.statusListView.clear() 2039 row = 0 2040 hist = self.cur_device.hist[:] 2041 2042 if hist: 2043 hist.reverse() 2044 row = len(hist)-1 2045 2046 for e in hist: 2047 if e is None: 2048 continue 2049 2050 ess = device.queryString(e.event_code, 0) 2051 esl = device.queryString(e.event_code, 1) 2052 2053 if row == 0: 2054 desc = self.__tr("(most recent)") 2055 2056 else: 2057 desc = self.getTimeDeltaDesc(e.timedate) 2058 2059 dt = QDateTime() 2060 dt.setTime_t(int(e.timedate), Qt.LocalTime) 2061 2062 # TODO: In Qt4.x, use QLocale.toString(date, format) 2063 tt = QString("%1 %2").arg(dt.toString()).arg(desc) 2064 2065 if e.job_id: 2066 job_id = to_unicode(e.job_id) 2067 else: 2068 job_id = '' 2069 2070 error_state = STATUS_TO_ERROR_STATE_MAP.get(e.event_code, ERROR_STATE_CLEAR) 2071 tech_type = self.cur_device.tech_type 2072 2073 try: 2074 if tech_type in (TECH_TYPE_COLOR_INK, TECH_TYPE_MONO_INK): 2075 status_pix = self.STATUS_ICONS[error_state][0] # ink 2076 else: 2077 status_pix = self.STATUS_ICONS[error_state][1] # laser 2078 except KeyError: 2079 status_pix = self.STATUS_ICONS[ERROR_STATE_CLEAR][0] 2080 2081 StatusListViewItem(self.statusListView, status_pix, ess, tt, to_unicode(e.event_code), 2082 job_id, to_unicode(e.username)) 2083 2084 row -= 1 2085 2086 i = self.statusListView.firstChild() 2087 if i is not None: 2088 self.statusListView.setCurrentItem(i) 2089 2090 2091 def getTimeDeltaDesc(self, past): 2092 t1 = QDateTime() 2093 t1.setTime_t(int(past)) 2094 t2 = QDateTime.currentDateTime() 2095 delta = t1.secsTo(t2) 2096 return self.__tr("(about %1 ago)").arg(self.stringify(delta)) 2097 2098 2099 # "Nicely readable timedelta" 2100 # Credit: Bjorn Lindqvist 2101 # ASPN Python Recipe 498062 2102 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/498062 2103 # Note: Modified from recipe 2104 def seconds_in_units(self, seconds): 2105 unit_limits = [("year", 31536000), 2106 ("month", 2592000), 2107 ("week", 604800), 2108 ("day", 86400), 2109 ("hour", 3600), 2110 ("minute", 60)] 2111 2112 for unit_name, limit in unit_limits: 2113 if seconds >= limit: 2114 amount = int(round(float(seconds) / limit)) 2115 return amount, unit_name 2116 2117 return seconds, "second" 2118 2119 2120 def stringify(self, seconds): 2121 amount, unit_name = self.seconds_in_units(seconds) 2122 2123 try: 2124 i18n_amount = self.num_repr[amount] 2125 except KeyError: 2126 i18n_amount = to_unicode(amount) 2127 2128 if amount == 1: 2129 i18n_unit = self.unit_names[unit_name][0] 2130 else: 2131 i18n_unit = self.unit_names[unit_name][1] 2132 2133 return QString("%1 %2").arg(i18n_amount).arg(i18n_unit) 2134 2135 2136 2137 2138 # *********************************************************************************** 2139 # 2140 # SUPPLIES TAB 2141 # 2142 # *********************************************************************************** 2143 2144 def InitSuppliesTab(self): 2145 self.pix_battery = load_pixmap('battery', '16x16') 2146 2147 yellow = "#ffff00" 2148 light_yellow = "#ffffcc" 2149 cyan = "#00ffff" 2150 light_cyan = "#ccffff" 2151 magenta = "#ff00ff" 2152 light_magenta = "#ffccff" 2153 black = "#000000" 2154 blue = "#0000ff" 2155 gray = "#808080" 2156 dark_gray = "#a9a9a9" 2157 light_gray = "#c0c0c0" 2158 red = "#ff0000" 2159 2160 self.TYPE_TO_PIX_MAP = { 2161 AGENT_TYPE_UNSPECIFIED : [black], 2162 AGENT_TYPE_BLACK: [black], 2163 AGENT_TYPE_MATTE_BLACK : [black], 2164 AGENT_TYPE_PHOTO_BLACK : [dark_gray], 2165 AGENT_TYPE_BLACK_B8800: [black], 2166 AGENT_TYPE_CMY: [cyan, magenta, yellow], 2167 AGENT_TYPE_KCM: [light_cyan, light_magenta, light_yellow], 2168 AGENT_TYPE_GGK: [dark_gray], 2169 AGENT_TYPE_YELLOW: [yellow], 2170 AGENT_TYPE_MAGENTA: [magenta], 2171 AGENT_TYPE_CYAN : [cyan], 2172 AGENT_TYPE_CYAN_LOW: [light_cyan], 2173 AGENT_TYPE_YELLOW_LOW: [light_yellow], 2174 AGENT_TYPE_MAGENTA_LOW: [light_magenta], 2175 AGENT_TYPE_BLUE: [blue], 2176 AGENT_TYPE_KCMY_CM: [yellow, cyan, magenta], 2177 AGENT_TYPE_LC_LM: [light_cyan, light_magenta], 2178 #AGENT_TYPE_Y_M: [yellow, magenta], 2179 #AGENT_TYPE_C_K: [black, cyan], 2180 AGENT_TYPE_LG_PK: [light_gray, dark_gray], 2181 AGENT_TYPE_LG: [light_gray], 2182 AGENT_TYPE_G: [gray], 2183 AGENT_TYPE_DG: [dark_gray], 2184 AGENT_TYPE_PG: [light_gray], 2185 AGENT_TYPE_C_M: [cyan, magenta], 2186 AGENT_TYPE_K_Y: [black, yellow], 2187 AGENT_TYPE_LC: [light_cyan], 2188 AGENT_TYPE_RED : [red], 2189 } 2190 2191 self.suppliesList.setSorting(-1) 2192 self.suppliesList.setColumnText(0, QString("")) 2193 #self.suppliesList.setColumnWidthMode(0, QListView.Manual) 2194 self.suppliesList.setColumnWidth(0, 16) 2195 self.suppliesList.setColumnWidth(3, 100) 2196 2197 2198 def UpdateSuppliesTab(self): 2199 #log.debug("UpdateSuppliesTab()") 2200 2201 self.suppliesList.clear() 2202 2203 if self.cur_device is not None and \ 2204 self.cur_device.supported and \ 2205 self.cur_device.status_type != STATUS_TYPE_NONE and \ 2206 self.cur_device.device_state != DEVICE_STATE_NOT_FOUND: 2207 2208 try: 2209 self.cur_device.sorted_supplies 2210 except AttributeError: 2211 self.cur_device.sorted_supplies = [] 2212 2213 if not self.cur_device.sorted_supplies: 2214 a = 1 2215 while True: 2216 try: 2217 agent_type = int(self.cur_device.dq['agent%d-type' % a]) 2218 agent_kind = int(self.cur_device.dq['agent%d-kind' % a]) 2219 agent_sku = self.cur_device.dq['agent%d-sku' % a] 2220 except KeyError: 2221 break 2222 else: 2223 self.cur_device.sorted_supplies.append((a, agent_kind, agent_type, agent_sku)) 2224 2225 a += 1 2226 2227 self.cur_device.sorted_supplies.sort(lambda x, y: cmp(x[1], y[1]) or cmp(x[3], y[3]), reverse=True) 2228 2229 2230 for x in self.cur_device.sorted_supplies: 2231 a, agent_kind, agent_type, agent_sku = x 2232 agent_level = int(self.cur_device.dq['agent%d-level' % a]) 2233 agent_desc = self.cur_device.dq['agent%d-desc' % a] 2234 agent_health_desc = self.cur_device.dq['agent%d-health-desc' % a] 2235 2236 # Bar graph level 2237 level_pixmap = None 2238 if agent_kind in (AGENT_KIND_SUPPLY, 2239 AGENT_KIND_HEAD, 2240 AGENT_KIND_HEAD_AND_SUPPLY, 2241 AGENT_KIND_TONER_CARTRIDGE, 2242 AGENT_KIND_MAINT_KIT, 2243 AGENT_KIND_ADF_KIT, 2244 AGENT_KIND_INT_BATTERY, 2245 AGENT_KIND_DRUM_KIT, 2246 ): 2247 2248 level_pixmap = self.createBarGraph(agent_level, agent_type) 2249 2250 # Color icon 2251 pixmap = None 2252 if agent_kind in (AGENT_KIND_SUPPLY, 2253 AGENT_KIND_HEAD, 2254 AGENT_KIND_HEAD_AND_SUPPLY, 2255 AGENT_KIND_TONER_CARTRIDGE, 2256 #AGENT_KIND_MAINT_KIT, 2257 #AGENT_KIND_ADF_KIT, 2258 AGENT_KIND_INT_BATTERY, 2259 #AGENT_KIND_DRUM_KIT, 2260 ): 2261 2262 pixmap = self.getIcon(agent_kind, agent_type) 2263 2264 2265 SuppliesListViewItem(self.suppliesList, pixmap, agent_desc, 2266 agent_sku, level_pixmap, agent_health_desc) 2267 2268 i = self.suppliesList.firstChild() 2269 if i is not None: 2270 self.suppliesList.setCurrentItem(i) 2271 2272 2273 2274 2275 def getIcon(self, agent_kind, agent_type): 2276 if agent_kind in (AGENT_KIND_SUPPLY, 2277 AGENT_KIND_HEAD, 2278 AGENT_KIND_HEAD_AND_SUPPLY, 2279 AGENT_KIND_TONER_CARTRIDGE): 2280 2281 map = self.TYPE_TO_PIX_MAP[agent_type] 2282 2283 if isinstance(map, list): 2284 map_len = len(map) 2285 pix = QPixmap(16, 16) #, -1, QPixmap.DefaultOptim) 2286 pix.fill(qApp.palette().color(QPalette.Active, QColorGroup.Background)) 2287 p = QPainter() 2288 p.begin(pix) 2289 p.setBackgroundMode(Qt.OpaqueMode) 2290 2291 if map_len == 1: 2292 p.setPen(QColor(map[0])) 2293 p.setBrush(QBrush(QColor(map[0]), Qt.SolidPattern)) 2294 p.drawPie(2, 2, 10, 10, 0, 5760) 2295 2296 elif map_len == 2: 2297 p.setPen(QColor(map[0])) 2298 p.setBrush(QBrush(QColor(map[0]), Qt.SolidPattern)) 2299 p.drawPie(2, 4, 8, 8, 0, 5760) 2300 2301 p.setPen(QColor(map[1])) 2302 p.setBrush(QBrush(QColor(map[1]), Qt.SolidPattern)) 2303 p.drawPie(6, 4, 8, 8, 0, 5760) 2304 2305 elif map_len == 3: 2306 p.setPen(QColor(map[2])) 2307 p.setBrush(QBrush(QColor(map[2]), Qt.SolidPattern)) 2308 p.drawPie(6, 6, 8, 8, 0, 5760) 2309 2310 p.setPen(QColor(map[1])) 2311 p.setBrush(QBrush(QColor(map[1]), Qt.SolidPattern)) 2312 p.drawPie(2, 6, 8, 8, 0, 5760) 2313 2314 p.setPen(QColor(map[0])) 2315 p.setBrush(QBrush(QColor(map[0]), Qt.SolidPattern)) 2316 p.drawPie(4, 2, 8, 8, 0, 5760) 2317 2318 p.end() 2319 return pix 2320 2321 else: 2322 return map 2323 2324 elif agent_kind == AGENT_KIND_INT_BATTERY: 2325 return self.pix_battery 2326 2327 2328 def createBarGraph(self, percent, agent_type, w=100, h=18): 2329 fw = w/100*percent 2330 px = QPixmap(w, h) 2331 px.fill(qApp.palette().color(QPalette.Active, QColorGroup.Background)) 2332 2333 pp = QPainter(px) 2334 pp.setPen(Qt.black) 2335 pp.setBackgroundColor(qApp.palette().color(QPalette.Active, QColorGroup.Base)) 2336 2337 map = self.TYPE_TO_PIX_MAP[agent_type] 2338 map_len = len(map) 2339 2340 if map_len == 1 or map_len > 3: 2341 pp.fillRect(0, 0, fw, h, QBrush(QColor(map[0]))) 2342 2343 elif map_len == 2: 2344 h2 = h / 2 2345 pp.fillRect(0, 0, fw, h2, QBrush(QColor(map[0]))) 2346 pp.fillRect(0, h2, fw, h, QBrush(QColor(map[1]))) 2347 2348 elif map_len == 3: 2349 h3 = h / 3 2350 h23 = 2 * h3 2351 pp.fillRect(0, 0, fw, h3, QBrush(QColor(map[0]))) 2352 pp.fillRect(0, h3, fw, h23, QBrush(QColor(map[1]))) 2353 pp.fillRect(0, h23, fw, h, QBrush(QColor(map[2]))) 2354 2355 # draw black frame 2356 pp.drawRect(0, 0, w, h) 2357 2358 if percent > 75 and agent_type in \ 2359 (AGENT_TYPE_BLACK, AGENT_TYPE_UNSPECIFIED, AGENT_TYPE_BLUE): 2360 pp.setPen(Qt.white) 2361 2362 # 75% ticks 2363 w1 = 3 * w / 4 2364 h6 = h / 6 2365 pp.drawLine(w1, 0, w1, h6) 2366 pp.drawLine(w1, h, w1, h-h6) 2367 2368 if percent > 50 and agent_type in \ 2369 (AGENT_TYPE_BLACK, AGENT_TYPE_UNSPECIFIED, AGENT_TYPE_BLUE): 2370 pp.setPen(Qt.white) 2371 2372 # 50% ticks 2373 w2 = w / 2 2374 h4 = h / 4 2375 pp.drawLine(w2, 0, w2, h4) 2376 pp.drawLine(w2, h, w2, h-h4) 2377 2378 if percent > 25 and agent_type in \ 2379 (AGENT_TYPE_BLACK, AGENT_TYPE_UNSPECIFIED, AGENT_TYPE_BLUE): 2380 pp.setPen(Qt.white) 2381 2382 # 25% ticks 2383 w4 = w / 4 2384 pp.drawLine(w4, 0, w4, h6) 2385 pp.drawLine(w4, h, w4, h-h6) 2386 2387 return px 2388 2389 2390 2391 # *********************************************************************************** 2392 # 2393 # PRINTER SETTINGS TAB 2394 # 2395 # *********************************************************************************** 2396 2397 def InitPrintSettingsTab(self): # Add Scrolling Print Settings 2398 PrintJobsTabLayout = QGridLayout(self.PrintSettingsTab,1,1,11,6,"PrintJobsTabLayout") 2399 2400 self.PrintSettingsList = ScrollPrintSettingsView(self.service, self.PrintSettingsTab, "PrintSettingsView") 2401 PrintJobsTabLayout.addMultiCellWidget(self.PrintSettingsList,1,1,0,3) 2402 2403 self.PrintSettingsPrinterCombo = QComboBox(0,self.PrintSettingsTab,"comboBox5") 2404 2405 self.PrintSettingsPrinterCombo.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed,0,0, 2406 self.PrintSettingsPrinterCombo.sizePolicy().hasHeightForWidth())) 2407 2408 PrintJobsTabLayout.addWidget(self.PrintSettingsPrinterCombo, 0, 2) 2409 2410 self.settingTextLabel = QLabel(self.PrintSettingsTab,"self.settingTextLabel") 2411 PrintJobsTabLayout.addWidget(self.settingTextLabel,0,1) 2412 2413 self.settingTextLabel.setText(self.__tr("Printer Name:")) 2414 2415 spacer34 = QSpacerItem(20,20,QSizePolicy.Preferred, QSizePolicy.Minimum) 2416 PrintJobsTabLayout.addItem(spacer34,0,3) 2417 2418 spacer35 = QSpacerItem(20,20,QSizePolicy.Preferred, QSizePolicy.Minimum) 2419 PrintJobsTabLayout.addItem(spacer35,0,0) 2420 2421 self.connect(self.PrintSettingsPrinterCombo, SIGNAL("activated(const QString&)"), 2422 self.PrintSettingsPrinterCombo_activated) 2423 2424 2425 def UpdatePrintSettingsTab(self): 2426 #log.debug("UpdatePrintSettingsTab()") 2427 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 2428 self.settingTextLabel.setText(self.__tr("Printer Name:")) 2429 else: 2430 self.settingTextLabel.setText(self.__tr("Fax Name:")) 2431 2432 self.PrintSettingsList.onDeviceChange(self.cur_device) 2433 2434 2435 def UpdatePrintSettingsTabPrinter(self): 2436 self.PrintSettingsList.onPrinterChange(self.cur_printer) 2437 2438 2439 # *********************************************************************************** 2440 # 2441 # PRINTER CONTROL TAB 2442 # 2443 # *********************************************************************************** 2444 2445 def InitPrintControlTab(self): 2446 self.JOB_STATES = { cups.IPP_JOB_PENDING : self.__tr("Pending"), 2447 cups.IPP_JOB_HELD : self.__tr("On hold"), 2448 cups.IPP_JOB_PROCESSING : self.__tr("Printing"), 2449 cups.IPP_JOB_STOPPED : self.__tr("Stopped"), 2450 cups.IPP_JOB_CANCELLED : self.__tr("Canceled"), 2451 cups.IPP_JOB_ABORTED : self.__tr("Aborted"), 2452 cups.IPP_JOB_COMPLETED : self.__tr("Completed"), 2453 } 2454 2455 self.cancelToolButton.setIconSet(QIconSet(load_pixmap('cancel', '16x16'))) 2456 self.infoToolButton.setIconSet(QIconSet(load_pixmap('info', '16x16'))) 2457 2458 self.JOB_STATE_ICONS = { cups.IPP_JOB_PENDING: self.busy_pix, 2459 cups.IPP_JOB_HELD : self.busy_pix, 2460 cups.IPP_JOB_PROCESSING : self.print_pix, 2461 cups.IPP_JOB_STOPPED : self.warning_pix, 2462 cups.IPP_JOB_CANCELLED : self.warning_pix, 2463 cups.IPP_JOB_ABORTED : self.error_pix, 2464 cups.IPP_JOB_COMPLETED : self.ok_pix, 2465 } 2466 2467 self.jobList.setSorting(-1) 2468 self.jobList.setColumnText(0, QString("")) 2469 #self.jobList.setColumnWidthMode(0, QListView.Manual) 2470 self.jobList.setColumnWidth(0, 16) 2471 self.jobList.setColumnText(1, QString("")) 2472 #self.jobList.setColumnWidthMode(1, QListView.Manual) 2473 self.jobList.setColumnWidth(1, 16) 2474 self.jobList.setColumnWidth(2, 300) 2475 self.cancelToolButton.setEnabled(False) 2476 self.infoToolButton.setEnabled(False) 2477 2478 self.printer_state = cups.IPP_PRINTER_STATE_IDLE 2479 2480 # TODO: Check queues at startup and send events if stopped or rejecting 2481 2482 2483 def UpdatePrintControlTab(self): 2484 #log.debug("UpdatePrintControlTab()") 2485 2486 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 2487 self.printerTextLabel.setText(self.__tr("Printer Name:")) 2488 self.groupBox1.setTitle(self.__tr("Printer Queue Control")) 2489 2490 else: 2491 self.printerTextLabel.setText(self.__tr("Fax Name:")) 2492 self.groupBox1.setTitle(self.__tr("Fax Queue Control")) 2493 2494 self.jobList.clear() 2495 self.UpdatePrintController() 2496 2497 jobs = cups.getJobs() 2498 num_jobs = 0 2499 for j in jobs: 2500 if j.dest.decode('utf-8') == to_unicode(self.cur_printer): 2501 num_jobs += 1 2502 2503 for j in jobs: 2504 if j.dest == self.cur_printer: 2505 JobListViewItem(self.jobList, self.JOB_STATE_ICONS[j.state], 2506 j.title, self.JOB_STATES[j.state], to_unicode(j.id)) 2507 2508 i = self.jobList.firstChild() 2509 if i is not None: 2510 self.jobList.setCurrentItem(i) 2511 2512 2513 def jobList_clicked(self, i): 2514 num = 0 2515 item = self.jobList.firstChild() 2516 while item is not None: 2517 if item.isOn(): 2518 num += 1 2519 2520 item = item.nextSibling() 2521 2522 self.cancelToolButton.setEnabled(num) 2523 self.infoToolButton.setEnabled(num == 1) 2524 2525 2526 def infoToolButton_clicked(self): 2527 item = self.jobList.firstChild() 2528 while item is not None: 2529 if item.isOn(): 2530 return self.showJobInfoDialog(item) 2531 2532 item = item.nextSibling() 2533 2534 2535 def cancelToolButton_clicked(self): 2536 self.cancelCheckedJobs() 2537 2538 2539 def jobList_contextMenuRequested(self, item, pos, a2): 2540 if item is not None and item is self.jobList.currentItem(): 2541 popup = QPopupMenu(self) 2542 2543 popup.insertItem(self.__tr("Cancel Job"), self.cancelJob) 2544 popup.insertSeparator() 2545 popup.insertItem(self.__tr("View Job Log (advanced)..."), self.getJobInfo) 2546 2547 popup.popup(pos) 2548 2549 2550 def cancelJob(self): 2551 item = self.jobList.currentItem() 2552 2553 if item is not None: 2554 self.cur_device.cancelJob(int(item.job_id)) 2555 2556 2557 def getJobInfo(self): 2558 return self.showJobInfoDialog(self.jobList.currentItem()) 2559 2560 2561 def showJobInfoDialog(self, item): 2562 if item is not None: 2563 text = cups.getPrintJobErrorLog(int(item.job_id)) 2564 2565 if text: 2566 dlg = JobInfoDialog(text, self) 2567 dlg.setCaption(self.__tr("HP Device Manager - Job Log - %1 - Job %2").\ 2568 arg(self.cur_printer).arg(to_unicode(item.job_id))) 2569 2570 dlg.exec_loop() 2571 2572 else: 2573 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'.")) 2574 2575 2576 def UpdatePrintController(self): 2577 # default printer 2578 self.defaultPushButton.setText(self.__tr("Set as Default")) 2579 2580 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 2581 device_string = "Printer" 2582 else: 2583 device_string = "Fax" 2584 2585 2586 default_printer = cups.getDefaultPrinter() 2587 if default_printer is not None: 2588 default_printer = default_printer.decode('utf8') 2589 2590 if default_printer == self.cur_printer: 2591 s = self.__tr("SET AS DEFAULT") 2592 self.defaultPushButton.setEnabled(False) 2593 2594 else: 2595 s = self.__tr("NOT SET AS DEFAULT") 2596 self.defaultPushButton.setEnabled(True) 2597 2598 QToolTip.add(self.defaultPushButton, self.__tr("The %2 is currently: %1").arg(s,device_string)) 2599 2600 2601 self.printer_state = cups.IPP_PRINTER_STATE_IDLE 2602 2603 cups_printers = cups.getPrinters() 2604 2605 for p in cups_printers: 2606 if p.name.decode('utf-8') == self.cur_printer: 2607 self.printer_state = p.state 2608 self.printer_accepting = p.accepting 2609 break 2610 2611 # start/stop 2612 if self.printer_state == cups.IPP_PRINTER_STATE_IDLE: 2613 s = self.__tr("IDLE") 2614 self.stopstartPushButton.setText(self.__tr("Stop %s"%device_string)) 2615 2616 elif self.printer_state == cups.IPP_PRINTER_STATE_PROCESSING: 2617 s = self.__tr("PROCESSING") 2618 self.stopstartPushButton.setText(self.__tr("Stop %s"%device_string)) 2619 2620 else: 2621 s = self.__tr("STOPPED") 2622 self.stopstartPushButton.setText(self.__tr("Start %s"%device_string)) 2623 2624 QToolTip.add(self.stopstartPushButton, self.__tr("The %2 is currently: %1").arg(s,device_string)) 2625 2626 # reject/accept 2627 if self.printer_accepting: 2628 s = self.__tr("ACCEPTING JOBS") 2629 self.rejectacceptPushButton.setText(self.__tr("Reject Jobs")) 2630 2631 else: 2632 s = self.__tr("REJECTING JOBS") 2633 self.rejectacceptPushButton.setText(self.__tr("Accept Jobs")) 2634 2635 QToolTip.add(self.rejectacceptPushButton, self.__tr("The %2 is currently: %1").arg(s,device_string)) 2636 2637 2638 2639 def stopstartPushButton_clicked(self): 2640 QApplication.setOverrideCursor(QApplication.waitCursor) 2641 try: 2642 if self.printer_state in (cups.IPP_PRINTER_STATE_IDLE, cups.IPP_PRINTER_STATE_PROCESSING): 2643 2644 result, result_str = cups.cups_operation(cups.stop, GUI_MODE, 'qt3', self, self.cur_printer) 2645 if result == cups.IPP_OK: 2646 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 2647 e = EVENT_PRINTER_QUEUE_STOPPED 2648 else: 2649 e = EVENT_FAX_QUEUE_STOPPED 2650 2651 else: 2652 result, result_str = cups.cups_operation(cups.start, GUI_MODE, 'qt3', self, self.cur_printer) 2653 if result == cups.IPP_OK: 2654 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 2655 e = EVENT_PRINTER_QUEUE_STARTED 2656 else: 2657 e = EVENT_FAX_QUEUE_STARTED 2658 2659 if result == cups.IPP_OK: 2660 self.UpdatePrintController() 2661 self.cur_device.sendEvent(e, self.cur_printer) 2662 else: 2663 log.error("Start/Stop printer operation failed") 2664 self.FailureUI(self.__tr("<b>Start/Stop printer operation failed.</b><p> Error : %s"%result_str)) 2665 cups.releaseCupsInstance() 2666 2667 finally: 2668 QApplication.restoreOverrideCursor() 2669 2670 2671 def rejectacceptPushButton_clicked(self): 2672 QApplication.setOverrideCursor(QApplication.waitCursor) 2673 try: 2674 if self.printer_accepting: 2675 result ,result_str = cups.cups_operation(cups.reject, GUI_MODE, 'qt3', self, self.cur_printer) 2676 if result == cups.IPP_OK: 2677 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 2678 e = EVENT_PRINTER_QUEUE_REJECTING_JOBS 2679 else: 2680 e = EVENT_FAX_QUEUE_REJECTING_JOBS 2681 2682 else: 2683 result ,result_str = cups.cups_operation(cups.accept, GUI_MODE, 'qt3', self, self.cur_printer) 2684 if result == cups.IPP_OK: 2685 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 2686 e = EVENT_PRINTER_QUEUE_ACCEPTING_JOBS 2687 else: 2688 e = EVENT_FAX_QUEUE_ACCEPTING_JOBS 2689 2690 if result == cups.IPP_OK: 2691 self.UpdatePrintController() 2692 self.cur_device.sendEvent(e, self.cur_printer) 2693 else: 2694 log.error("Reject/Accept jobs operation failed") 2695 self.FailureUI(self.__tr("<b>Accept/Reject printer operation failed.</b><p>Error : %s"%result_str)) 2696 cups.releaseCupsInstance() 2697 2698 finally: 2699 QApplication.restoreOverrideCursor() 2700 2701 2702 def defaultPushButton_clicked(self): 2703 QApplication.setOverrideCursor(QApplication.waitCursor) 2704 try: 2705 result, result_str = cups.cups_operation(cups.setDefaultPrinter.encode('utf8'), GUI_MODE, 'qt3', self, self.cur_printer.encode('utf8')) 2706 2707 if result != cups.IPP_OK: 2708 log.error("Set default printer failed.") 2709 self.FailureUI(self.__tr("<b>Set default printer operation failed.</b><p>Error : %s"%result_str)) 2710 cups.releaseCupsInstance() 2711 else: 2712 self.UpdatePrintController() 2713 if self.cur_device.device_type == DEVICE_TYPE_PRINTER: 2714 e = EVENT_PRINTER_QUEUE_SET_AS_DEFAULT 2715 else: 2716 e = EVENT_FAX_QUEUE_SET_AS_DEFAULT 2717 2718 self.cur_device.sendEvent(e, self.cur_printer) 2719 2720 finally: 2721 QApplication.restoreOverrideCursor() 2722 2723 2724 def cancelCheckedJobs(self): 2725 QApplication.setOverrideCursor(QApplication.waitCursor) 2726 try: 2727 item = self.jobList.firstChild() 2728 while item is not None: 2729 if item.isOn(): 2730 self.cur_device.cancelJob(int(item.job_id)) 2731 2732 item = item.nextSibling() 2733 2734 finally: 2735 QApplication.restoreOverrideCursor() 2736 2737 self.UpdatePrintControlTab() 2738 2739 def UpdateUpgradeTab(self): 2740 log.debug("Upgrade Tab is pressed") 2741 self.InstallPushButton_lock = False 2742 2743 def InstallPushButton_clicked(self): 2744 if self.InstallPushButton_lock is True: 2745 return 2746 2747 if self.Is_autoInstaller_distro: 2748 self.InstallPushButton.setEnabled(False) 2749 terminal_cmd = utils.get_terminal() 2750 if terminal_cmd is not None and utils.which("hp-upgrade"): 2751 cmd = terminal_cmd + " 'hp-upgrade -w'" 2752 os_utils.execute(cmd) 2753 else: 2754 log.error("Failed to run hp-upgrade command from terminal =%s "%terminal_cmd) 2755 self.InstallPushButton.setEnabled(True) 2756 else: 2757 self.InstallPushButton_lock = True 2758 utils.openURL("http://hplipopensource.com/hplip-web/install/manual/index.html") 2759 QTimer.singleShot(1000, self.InstallPushButton_unlock) 2760 2761 def InstallPushButton_unlock(self): 2762 self.InstallPushButton_lock = False 2763 2764 # *********************************************************************************** 2765 # 2766 # EXIT/CHILD CLEANUP 2767 # 2768 # *********************************************************************************** 2769 2770 def closeEvent(self, event): 2771 self.Cleanup() 2772 self.request_queue.put(None) 2773 event.accept() 2774 2775 2776 def Cleanup(self): 2777 self.request_queue.put(None) 2778 self.CleanupChildren() 2779 if not self.update_thread.wait(5000): 2780 self.update_thread.terminate() 2781 2782 2783 def CleanupChildren(self): 2784 log.debug("Cleaning up child processes.") 2785 try: 2786 os.waitpid(-1, os.WNOHANG) 2787 except OSError: 2788 pass 2789 2790 2791 # *********************************************************************************** 2792 # 2793 # DEVICE SETTINGS PLUGIN 2794 # 2795 # *********************************************************************************** 2796 2797 def CheckForDeviceSettingsUI(self, dev): 2798 dev.device_settings_ui = None 2799 name = '.'.join(['plugins', dev.model]) 2800 log.debug("Attempting to load plugin: %s" % name) 2801 try: 2802 mod = __import__(name, globals(), locals(), []) 2803 except ImportError: 2804 log.debug("No plugin found.") 2805 return 2806 else: 2807 components = name.split('.') 2808 for c in components[1:]: 2809 mod = getattr(mod, c) 2810 log.debug("Loaded: %s" % repr(mod)) 2811 dev.device_settings_ui = mod.settingsUI 2812 2813 2814 # *********************************************************************************** 2815 # 2816 # SETTINGS DIALOG 2817 # 2818 # *********************************************************************************** 2819 2820 def settingsConfigure_activated(self, tab_to_show=0): 2821 dlg = SettingsDialog(self) 2822 dlg.TabWidget.setCurrentPage(tab_to_show) 2823 2824 if dlg.exec_loop() == QDialog.Accepted: 2825 old_auto_refresh = self.user_settings.auto_refresh_rate 2826 self.user_settings.load() 2827 2828 if self.user_settings.auto_refresh and old_auto_refresh != self.user_settings.auto_refresh_rate: 2829 self.refresh_timer.changeInterval(self.user_settings.auto_refresh_rate * 1000) 2830 2831 if old_auto_refresh != self.user_settings.auto_refresh: 2832 self.autoRefresh.toggle() 2833 2834 2835 # *********************************************************************************** 2836 # 2837 # SETUP/REMOVE 2838 # 2839 # *********************************************************************************** 2840 2841 def deviceInstallAction_activated(self): 2842 if utils.which('hp-setup'): 2843 cmd = 'hp-setup -u' 2844 else: 2845 cmd = 'python ./setup.py --gui' 2846 2847 log.debug(cmd) 2848 utils.run(cmd) 2849 self.RescanDevices() 2850 2851 2852 def deviceRemoveAction_activated(self): 2853 if self.cur_device is not None: 2854 x = QMessageBox.critical(self, 2855 self.caption(), 2856 self.__tr("<b>Annoying Confirmation: Are you sure you want to remove this device?</b>"), 2857 QMessageBox.Yes, 2858 QMessageBox.No | QMessageBox.Default, 2859 QMessageBox.NoButton) 2860 if x == QMessageBox.Yes: 2861 QApplication.setOverrideCursor(QApplication.waitCursor) 2862 print_uri = self.cur_device.device_uri 2863 fax_uri = print_uri.replace('hp:', 'hpfax:') 2864 2865 log.debug(print_uri) 2866 log.debug(fax_uri) 2867 2868 self.cups_devices = device.getSupportedCUPSDevices(['hp', 'hpfax']) 2869 2870 for d in self.cups_devices: 2871 if d in (print_uri, fax_uri): 2872 for p in self.cups_devices[d]: 2873 log.debug("Removing %s" % p) 2874 r, result_str = cups.cups_operation(cups.delPrinter, GUI_MODE, 'qt3', self, p) 2875 2876 if r != cups.IPP_OK: 2877 self.FailureUI(self.__tr("<p><b>Delete printer queue fails.</b><p>Error : %s"%result_str)) 2878 print_uri ="" # Ignoring further devices delete operation, as authentication is failed or cancelled. 2879 fax_uri = "" 2880 2881 self.cur_device = None 2882 self.cur_device_uri = '' 2883 user_conf.set('last_used', 'device_uri', '') 2884 QApplication.restoreOverrideCursor() 2885 2886 self.RescanDevices() 2887 2888 2889 # *********************************************************************************** 2890 # 2891 # MISC 2892 # 2893 # *********************************************************************************** 2894 2895 2896 def RunCommand(self, cmd, macro_char='%'): 2897 QApplication.setOverrideCursor(QApplication.waitCursor) 2898 2899 try: 2900 if len(cmd) == 0: 2901 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.")) 2902 log.error("No command specified. Use settings to configure commands.") 2903 else: 2904 log.debug("Run: %s %s (%s) %s" % ("*"*20, cmd, self.cur_device_uri, "*"*20)) 2905 log.debug(cmd) 2906 2907 try: 2908 cmd = ''.join([self.cur_device.device_vars.get(x, x) \ 2909 for x in cmd.split(macro_char)]) 2910 except AttributeError: 2911 pass 2912 2913 log.debug(cmd) 2914 2915 path = cmd.split()[0] 2916 args = cmd.split() 2917 2918 log.debug(path) 2919 log.debug(args) 2920 2921 self.CleanupChildren() 2922 os.spawnvp(os.P_NOWAIT, path, args) 2923 qApp.processEvents() 2924 2925 finally: 2926 QApplication.restoreOverrideCursor() 2927 2928 2929 def helpContents(self): 2930 f = "http://hplip.sf.net" 2931 2932 if prop.doc_build: 2933 g = os.path.join(sys_conf.get('dirs', 'doc'), 'index.html') 2934 if os.path.exists(g): 2935 f = "file://%s" % g 2936 2937 log.debug(f) 2938 utils.openURL(f) 2939 2940 2941 def helpAbout(self): 2942 dlg = AboutDlg(self) 2943 dlg.VersionText.setText(prop.version) 2944 dlg.ToolboxVersionText.setText(self.toolbox_version + " (Qt3)") 2945 dlg.exec_loop() 2946 2947 2948 def FailureUI(self, error_text): 2949 QMessageBox.critical(self, 2950 self.caption(), 2951 error_text, 2952 QMessageBox.Ok, 2953 QMessageBox.NoButton, 2954 QMessageBox.NoButton) 2955 2956 2957 def WarningUI(self, msg): 2958 QMessageBox.warning(self, 2959 self.caption(), 2960 msg, 2961 QMessageBox.Ok, 2962 QMessageBox.NoButton, 2963 QMessageBox.NoButton) 2964 2965 2966 def __tr(self,s,c = None): 2967 return qApp.translate("DevMgr4",s,c) 2968 2969 2970 2971# *********************************************************************************** 2972# 2973# ScrollDeviceInfoView (View Device Information) 2974# 2975# *********************************************************************************** 2976 2977class ScrollDeviceInfoView(ScrollView): 2978 def __init__(self, service, parent=None, form=None, name=None, fl=0): 2979 ScrollView.__init__(self, service, parent, name, fl) 2980 2981 2982 def fillControls(self): 2983 ScrollView.fillControls(self) 2984 self.addDeviceInfo() 2985 self.maximizeControl() 2986 2987 2988 def addDeviceInfo(self): 2989 self.addGroupHeading("info_title", self.__tr("Device Information")) 2990 2991 widget = self.getWidget() 2992 2993 layout37 = QGridLayout(widget,1,1,5,10,"layout37") 2994 2995 self.infoListView = QListView(widget,"fileListView") 2996 self.infoListView.addColumn(self.__tr("Static/Dynamic")) 2997 self.infoListView.addColumn(self.__tr("Key")) 2998 self.infoListView.addColumn(self.__tr("Value")) 2999 self.infoListView.setAllColumnsShowFocus(1) 3000 self.infoListView.setShowSortIndicator(1) 3001 self.infoListView.setColumnWidth(0, 50) 3002 self.infoListView.setColumnWidth(1, 150) 3003 self.infoListView.setColumnWidth(2, 300) 3004 self.infoListView.setItemMargin(2) 3005 self.infoListView.setSorting(-1) 3006 3007 layout37.addMultiCellWidget(self.infoListView,1,1,0,3) 3008 3009 mq_keys = list(self.cur_device.mq.keys()) 3010 mq_keys.sort() 3011 mq_keys.reverse() 3012 for key,i in zip(mq_keys, list(range(len(mq_keys)))): 3013 QListViewItem(self.infoListView, self.__tr("Static"), key, str(self.cur_device.mq[key])) 3014 3015 dq_keys = list(self.cur_device.dq.keys()) 3016 dq_keys.sort() 3017 dq_keys.reverse() 3018 for key,i in zip(dq_keys, list(range(len(dq_keys)))): 3019 QListViewItem(self.infoListView, self.__tr("Dynamic"), key, str(self.cur_device.dq[key])) 3020 3021 self.addWidget(widget, "file_list", maximize=True) 3022 3023 3024 def __tr(self,s,c = None): 3025 return qApp.translate("ScrollDeviceInfoView",s,c) 3026 3027 3028 3029# *********************************************************************************** 3030# 3031# ScrollTestpageView (Print Test Page) 3032# 3033# *********************************************************************************** 3034 3035class ScrollTestpageView(ScrollView): 3036 def __init__(self, service, parent=None, form=None, name=None, fl=0): 3037 ScrollView.__init__(self, service, parent, name, fl) 3038 self.dialog = parent 3039 3040 3041 def fillControls(self): 3042 ScrollView.fillControls(self) 3043 3044 if self.addPrinterFaxList(): 3045 self.addTestpageType() 3046 3047 self.addLoadPaper() 3048 3049 self.printButton = self.addActionButton("bottom_nav", self.__tr("Print Test Page"), 3050 self.printButton_clicked, 'print.png', None) 3051 3052 3053 def addTestpageType(self): 3054 self.addGroupHeading("testpage_type", self.__tr("Test Page Type")) 3055 widget = self.getWidget() 3056 3057 Form4Layout = QGridLayout(widget,1,1,5,10,"Form4Layout") 3058 3059 self.buttonGroup3 = QButtonGroup(widget,"buttonGroup3") 3060 self.buttonGroup3.setLineWidth(0) 3061 self.buttonGroup3.setColumnLayout(0,Qt.Vertical) 3062 self.buttonGroup3.layout().setSpacing(5) 3063 self.buttonGroup3.layout().setMargin(10) 3064 3065 buttonGroup3Layout = QGridLayout(self.buttonGroup3.layout()) 3066 buttonGroup3Layout.setAlignment(Qt.AlignTop) 3067 3068 self.radioButton6 = QRadioButton(self.buttonGroup3,"radioButton6") 3069 self.radioButton6.setEnabled(False) 3070 buttonGroup3Layout.addWidget(self.radioButton6,1,0) 3071 3072 self.radioButton5 = QRadioButton(self.buttonGroup3,"radioButton5") 3073 self.radioButton5.setChecked(1) 3074 buttonGroup3Layout.addWidget(self.radioButton5,0,0) 3075 3076 Form4Layout.addWidget(self.buttonGroup3,0,0) 3077 3078 self.radioButton6.setText(self.__tr("Printer diagnostic page (does not test print driver)")) 3079 self.radioButton5.setText(self.__tr("HPLIP test page (tests print driver)")) 3080 3081 self.addWidget(widget, "page_type") 3082 3083 3084 def printButton_clicked(self): 3085 d = self.cur_device 3086 printer_name = self.cur_printer 3087 printed = False 3088 3089 try: 3090 QApplication.setOverrideCursor(QApplication.waitCursor) 3091 3092 try: 3093 d.open() 3094 except Error: 3095 self.CheckDeviceUI() 3096 else: 3097 try: 3098 if d.isIdleAndNoError(): 3099 QApplication.restoreOverrideCursor() 3100 d.close() 3101 3102 d.printTestPage(printer_name) 3103 printed = True 3104 3105 else: 3106 d.close() 3107 self.CheckDeviceUI() 3108 except Error: 3109 self.CheckDeviceUI() 3110 3111 finally: 3112 QApplication.restoreOverrideCursor() 3113 3114 if printed: 3115 QMessageBox.information(self, 3116 self.caption(), 3117 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."), 3118 QMessageBox.Ok, 3119 QMessageBox.NoButton, 3120 QMessageBox.NoButton) 3121 3122 self.dialog.accept() 3123 3124 3125 def CheckDeviceUI(self): 3126 self.FailureUI(self.__tr("<b>Device is busy or in an error state.</b><p>Please check device and try again.")) 3127 3128 3129 def FailureUI(self, error_text): 3130 QMessageBox.critical(self, 3131 self.caption(), 3132 error_text, 3133 QMessageBox.Ok, 3134 QMessageBox.NoButton, 3135 QMessageBox.NoButton) 3136 3137 3138 def __tr(self,s,c = None): 3139 return qApp.translate("ScrollTestpageView",s,c) 3140 3141# *********************************************************************************** 3142# 3143# ScrollPrinterInfoView (View Device Information) 3144# 3145# *********************************************************************************** 3146 3147class ScrollPrinterInfoView(ScrollView): 3148 def __init__(self, service, parent = None, form=None, name = None,fl = 0): 3149 ScrollView.__init__(self, service, parent, name, fl) 3150 3151 3152 def fillControls(self): 3153 ScrollView.fillControls(self) 3154 3155 printers = [] 3156 for p in self.printers: 3157 if p.device_uri == self.cur_device.device_uri: 3158 printers.append(p) 3159 3160 if not printers: 3161 self.addGroupHeading("error_title", self.__tr("No printers found for this device.")) 3162 else: 3163 for p in printers: 3164 self.addPrinterInfo(p) 3165 3166 self.maximizeControl() 3167 3168 3169 def addPrinterInfo(self, p): 3170 self.addGroupHeading(p.name, p.name) 3171 widget = self.getWidget() 3172 3173 layout1 = QVBoxLayout(widget,5,10,"layout1") 3174 3175 textLabel2 = QLabel(widget,"textLabel2") 3176 3177 if p.device_uri.startswith("hpfax:"): 3178 s = self.__tr("Fax") 3179 else: 3180 s = self.__tr("Printer") 3181 3182 textLabel2.setText(self.__tr("Type: %1").arg(s)) 3183 layout1.addWidget(textLabel2) 3184 3185 textLabel3 = QLabel(widget,"textLabel3") 3186 textLabel3.setText(self.__tr("Location: %1").arg(p.location)) 3187 layout1.addWidget(textLabel3) 3188 3189 textLabel4 = QLabel(widget,"textLabel4") 3190 textLabel4.setText(self.__tr("Description/Info: %1").arg(p.info)) 3191 layout1.addWidget(textLabel4) 3192 3193 textLabel5 = QLabel(widget,"textLabel5") 3194 3195 if p.state == cups.IPP_PRINTER_STATE_IDLE: 3196 s = self.__tr("Idle") 3197 elif p.state == cups.IPP_PRINTER_STATE_PROCESSING: 3198 s = self.__tr("Processing") 3199 elif p.state == cups.IPP_PRINTER_STATE_STOPPED: 3200 s = self.__tr("Stopped") 3201 else: 3202 s = self.__tr("Unknown") 3203 3204 textLabel5.setText(self.__tr("State: %1").arg(s)) 3205 layout1.addWidget(textLabel5) 3206 3207 textLabel6 = QLabel(widget,"textLabel6") 3208 textLabel6.setText(self.__tr("PPD/Driver: %1").arg(p.makemodel)) 3209 layout1.addWidget(textLabel6) 3210 3211 textLabel7 = QLabel(widget,"textLabel7") 3212 textLabel7.setText(self.__tr("CUPS/IPP Printer URI: %1").arg(p.printer_uri)) 3213 layout1.addWidget(textLabel7) 3214 3215 self.addWidget(widget, p.name) 3216 3217 3218 def __tr(self,s,c = None): 3219 return qApp.translate("ScrollPrinterInfoView",s,c) 3220 3221 3222 3223 3224# *********************************************************************************** 3225# 3226# Color cal type 7 3227# 3228# *********************************************************************************** 3229 3230class ScrollColorCalView(ScrollView): 3231 def __init__(self, service, parent = None, form=None, name = None,fl = 0): 3232 ScrollView.__init__(self, service, parent, name, fl) 3233 self.dialog = parent 3234 3235 3236 def fillControls(self): 3237 ScrollView.fillControls(self) 3238 self.addLoadPaper(PAPER_TYPE_HP_ADV_PHOTO) 3239 3240 self.printButton = self.addActionButton("bottom_nav", self.__tr("Perform Color Calibration"), 3241 self.colorcalButton_clicked, 'print.png', None) 3242 3243 3244 def colorcalButton_clicked(self): 3245 d = self.cur_device 3246 printer_name = self.cur_printer 3247 printed = False 3248 3249 try: 3250 QApplication.setOverrideCursor(QApplication.waitCursor) 3251 3252 try: 3253 d.open() 3254 except Error: 3255 self.CheckDeviceUI() 3256 else: 3257 if d.isIdleAndNoError(): 3258 QApplication.restoreOverrideCursor() 3259 d.close() 3260 3261 d.setPML(pml.OID_PRINT_INTERNAL_PAGE, pml.PRINT_INTERNAL_PAGE_AUTOMATIC_COLOR_CALIBRATION) 3262 printed = True 3263 3264 else: 3265 d.close() 3266 self.CheckDeviceUI() 3267 3268 finally: 3269 QApplication.restoreOverrideCursor() 3270 3271 if printed: 3272 QMessageBox.information(self, 3273 self.caption(), 3274 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."), 3275 QMessageBox.Ok, 3276 QMessageBox.NoButton, 3277 QMessageBox.NoButton) 3278 3279 self.dialog.accept() 3280 3281 3282 def CheckDeviceUI(self): 3283 self.FailureUI(self.__tr("<b>Device is busy or in an error state.</b><p>Please check device and try again.")) 3284 3285 3286 def FailureUI(self, error_text): 3287 QMessageBox.critical(self, 3288 self.caption(), 3289 error_text, 3290 QMessageBox.Ok, 3291 QMessageBox.NoButton, 3292 QMessageBox.NoButton) 3293 3294 3295 def __tr(self,s,c = None): 3296 return qApp.translate("ScrollColorCalView",s,c) 3297