%PDF- %PDF-
Direktori : /usr/share/hplip/ui5/ |
Current File : //usr/share/hplip/ui5/ui_utils.py |
# -*- coding: utf-8 -*- # # (c) Copyright 2001-2015 HP Development Company, L.P. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Author: Don Welch # # Std Lib import re import os import time # Local from base.g import * from base.codes import * from base import utils from prnt import cups from base.sixext import PY3, to_unicode from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * # End pat_html_remove = re.compile("(?is)<.*?>", re.I) # databaseChanged signal values (for FABWindow) FAB_NAME_ADD = 0 # s1 - new name FAB_NAME_RENAME = 1 # s1 - old name, s2 - new name FAB_NAME_REMOVE = 2 # s1 - removed name FAB_NAME_DETAILS_CHANGED = 3 # s1 - name FAB_GROUP_ADD = 4 # s1 - new group FAB_GROUP_RENAME = 5 # s1 - old group, s2 - new group FAB_GROUP_REMOVE = 6 # s1 - removed group FAB_GROUP_MEMBERSHIP_CHANGED = 7 # s1 - group def __translate(t): return QApplication.translate("ui_utils", t, None) def beginWaitCursor(): QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) def endWaitCursor(): QApplication.restoreOverrideCursor() # TODO: Cache pixmaps def load_pixmap(name, subdir=None, resize_to=None): name = ''.join([os.path.splitext(name)[0], '.png']) if subdir is None: image_dir = prop.image_dir ldir = os.path.join(os.getcwd(), 'data', 'images') else: image_dir = os.path.join(prop.image_dir, subdir) ldir = os.path.join(os.getcwd(), 'data', 'images', subdir) for d in [image_dir, ldir]: f = os.path.join(d, name) if os.path.exists(f): if resize_to is not None: img = QImage(f) x, y = resize_to return QPixmap.fromImage(img.scaled(x, y, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) else: return QPixmap(f) for w in utils.walkFiles(image_dir, recurse=True, abs_paths=True, return_folders=False, pattern=name): if resize_to is not None: img = QImage(w) x, y = resize_to return QPixmap.fromImage(img.scaled(x, y, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) else: return QPixmap(w) log.error("Pixmap '%s' not found!" % name) return QPixmap() loadPixmap = load_pixmap def getPynotifyIcon(name, subdir='32x32'): name = ''.join([os.path.splitext(name)[0], '.png']) return "file://" + os.path.join(prop.image_dir, subdir, name) def value_str(data): if data is None: return "" try: if not PY3: try: data = data.toString() except AttributeError as e: return data except(ValueError, TypeError) as e: log.warn("value_str() Failed to convert data: %s" % e) return data def value_int(data): i, ok = 0, False if data is None: return i, ok try: if PY3: i = int(data) ok = True else: try: i, ok = data.toInt() except AttributeError as e: i = int(data) ok = True except (ValueError,TypeError) as e: log.warn("value_int() Failed to convert data[%s]:%s "%(data,e)) return i, ok def value_bool( data ): b = False if data is None: return b try: if PY3: if type(data) == str and data.lower() in ['false', '0']: b = False elif data in [False, 0]: b = False else: b= True else: try: b = data.toBool() except AttributeError as e: if type(data) == str and data.lower() in ['false', '0']: b = False elif data in [False, 0]: b = False else: b= True except (ValueError,TypeError) as e: log.warn("value_bool() Failed to convert data :%s"%e) return b class UserSettings(QSettings): def __init__(self): if prop.user_dir is None: QSettings.__init__(self) else: QSettings.__init__(self, os.path.join(prop.user_dir, 'hplip.conf'), QSettings.IniFormat) self.systray_visible = SYSTRAY_VISIBLE_SHOW_ALWAYS self.systray_messages = SYSTRAY_MESSAGES_SHOW_ALL self.last_used_device_uri = '' self.last_used_printer = '' self.version = '' self.date_time = '' self.auto_refresh = False self.auto_refresh_rate = 30 self.auto_refresh_type = 1 self.polling_interval = 5 self.polling = True self.device_list = [] self.working_dir = '.' self.voice_phone = '' self.email_address = '' self.upgrade_notify=True self.upgrade_last_update_time=0 self.upgrade_pending_update_time=0 self.latest_available_version="" self.loadDefaults() def __setup(self, cmds): for c in cmds: basename = c.split()[0] path = utils.which(basename) if path: return ' '.join([os.path.join(path, basename), ' '.join(c.split()[1:])]) return '' def loadDefaults(self): self.cmd_scan = self.__setup(['simple-scan %SANE_URI%', 'xsane -V %SANE_URI%', 'kooka', 'xscanimage']) self.cmd_fab = self.__setup(['hp-fab']) def load(self): log.debug("Loading user settings...") self.sync() self.beginGroup("settings") self.systray_visible = value_int(self.value("systray_visible"))[0] self.systray_messages = value_int(self.value("systray_messages"))[0] self.endGroup() self.beginGroup("last_used") self.last_used_device_uri = value_str(self.value("device_uri")) or self.last_used_device_uri self.last_used_printer = value_str(self.value("printer_name")) or self.last_used_printer self.working_dir = value_str(self.value("working_dir")) or self.working_dir self.endGroup() self.beginGroup("commands") self.cmd_scan = value_str(self.value("scan")) or self.cmd_scan self.endGroup() self.beginGroup("refresh") self.auto_refresh_rate = value_int(self.value("rate"))[0] or int(self.auto_refresh_rate) self.auto_refresh = value_bool(self.value("enable")) self.auto_refresh_type = value_int(self.value("type"))[0] or int(self.auto_refresh_type) self.endGroup() self.beginGroup("installation") self.version = value_str(self.value("version")) self.date_time = value_str(self.value("date_time")) self.endGroup() self.beginGroup("polling") self.polling = value_bool(self.value("enable")) self.polling_interval = value_int(self.value("interval"))[0] or int(self.polling_interval) self.polling_device_list = to_unicode(value_str(self.value("device_list"))).split(to_unicode(',')) self.endGroup() self.beginGroup("fax") self.voice_phone = value_str(self.value("voice_phone")) self.email_address = to_unicode(value_str(self.value("email_address"))) self.endGroup() self.beginGroup("upgrade") self.upgrade_notify= value_bool(self.value("notify_upgrade")) self.latest_available_version=value_str(self.value("latest_available_version")) self.upgrade_last_update_time = value_int(self.value("last_upgraded_time"))[0] self.upgrade_pending_update_time = value_int(self.value("pending_upgrade_time"))[0] self.endGroup() def save(self): log.debug("Saving user settings...") self.beginGroup("settings") self.setValue("systray_visible", self.systray_visible) self.setValue("systray_messages", self.systray_messages) self.endGroup() self.beginGroup("last_used") self.setValue("device_uri", self.last_used_device_uri) self.setValue("printer_name", self.last_used_printer) self.setValue("working_dir", self.working_dir) self.endGroup() self.beginGroup("commands") self.setValue("scan", self.cmd_scan) self.endGroup() self.beginGroup("refresh") self.setValue("rate", self.auto_refresh_rate) self.setValue("enable", self.auto_refresh) self.setValue("type", self.auto_refresh_type) self.endGroup() self.beginGroup("polling") self.setValue("enable", self.polling) self.setValue("interval", self.polling_interval) self.setValue("device_list", (to_unicode(',').join(self.polling_device_list))) self.endGroup() self.beginGroup("fax") self.setValue("voice_phone", self.voice_phone) self.setValue("email_address", self.email_address) self.endGroup() self.beginGroup("upgrade") self.setValue("notify_upgrade", self.upgrade_notify) if self.upgrade_last_update_time <1: self.upgrade_last_update_time = int(time.time()) # <---Need to verify code once self.setValue("last_upgraded_time", self.upgrade_last_update_time) self.setValue("pending_upgrade_time", self.upgrade_pending_update_time) self.endGroup() self.sync() def debug(self): log.debug("FAB command: %s" % self.cmd_fab) log.debug("Scan command: %s" % self.cmd_scan) log.debug("Auto refresh: %s" % self.auto_refresh) log.debug("Auto refresh rate: %s" % self.auto_refresh_rate) log.debug("Auto refresh type: %s" % self.auto_refresh_type) log.debug("Systray visible: %d" % self.systray_visible) log.debug("Systray messages: %d" % self.systray_messages) log.debug("Last used device URI: %s" % self.last_used_device_uri) log.debug("Last used printer: %s" % self.last_used_printer) log.debug("Working directory: %s" % self.working_dir) DEFAULT_TITLE = __translate("HP Device Manager") def FailureUI(parent, error_text, title_text=None): log.error(pat_html_remove.sub(' ', to_unicode(error_text))) if title_text is None: if parent is not None: title_text = parent.windowTitle() else: title_text = DEFAULT_TITLE QMessageBox.critical(parent, title_text, error_text, QMessageBox.Ok|\ QMessageBox.NoButton, QMessageBox.NoButton) showFailureUi = FailureUI def WarningUI(parent, warn_text, title_text=None): log.warn(pat_html_remove.sub(' ', to_unicode(warn_text))) if title_text is None: if parent is not None: title_text = parent.windowTitle() else: title_text = DEFAULT_TITLE QMessageBox.warning(parent, title_text, warn_text, QMessageBox.Ok|\ QMessageBox.NoButton, QMessageBox.NoButton) showWarningUi = WarningUI def SuccessUI(parent, text, title_text=None): log.info(pat_html_remove.sub(' ', to_unicode(text))) if title_text is None: if parent is not None: title_text = parent.windowTitle() else: title_text = DEFAULT_TITLE QMessageBox.information(parent, title_text, text, QMessageBox.Ok|\ QMessageBox.NoButton, QMessageBox.NoButton) showSuccessUi = SuccessUI def CheckDeviceUI(parent, title_text=None): text = __translate("<b>Unable to communicate with device or device is in an error state.</b><p>Please check device setup and try again.</p>") return FailureUI(parent, text, title_text) checkDeviceUi = CheckDeviceUI class PrinterNameValidator(QValidator): def __init__(self, parent=None): QValidator.__init__(self, parent) def validate(self, input_data, pos): returnCode = QValidator.Invalid input_data = to_unicode(input_data) if not input_data: returnCode = QValidator.Acceptable elif input_data[pos-1] in cups.INVALID_PRINTER_NAME_CHARS: returnCode = QValidator.Invalid else: returnCode = QValidator.Acceptable # TODO: How to determine if unicode char is "printable" and acceptable # to CUPS? #elif input_data != utils.printable(input_data): # return QValidator.Invalid, pos return returnCode, input_data, pos class PhoneNumValidator(QValidator): def __init__(self, parent=None): QValidator.__init__(self, parent) def validate(self, input_data, pos): returnCode = QValidator.Invalid input_data = to_unicode(input_data) if not input_data: returnCode = QValidator.Acceptable elif input_data[pos-1] not in to_unicode('0123456789-(+).,#* '): returnCode = QValidator.Invalid else: returnCode = QValidator.Acceptable return returnCode, input_data, pos class AddressBookNameValidator(QValidator): def __init__(self, db, parent=None): QValidator.__init__(self, parent) self.db = db def validate(self, input_data, pos): returnCode = QValidator.Invalid input_data = to_unicode(input_data) if not input_data: returnCode = QValidator.Acceptable elif input_data in self.db.get_all_names(): returnCode = QValidator.Invalid elif input_data[pos-1] in to_unicode('''|\\/"'''): # | is the drag 'n drop separator returnCode = QValidator.Invalid else: returnCode = QValidator.Acceptable return returnCode, input_data, pos MIME_TYPES_DESC = \ { "application/pdf" : (__translate("PDF Document"), '.pdf'), "application/postscript" : (__translate("Postscript Document"), '.ps'), "application/vnd.hp-HPGL" : (__translate("HP Graphics Language File"), '.hgl, .hpg, .plt, .prn'), "application/x-cshell" : (__translate("C Shell Script"), '.csh, .sh'), "application/x-csource" : (__translate("C Source Code"), '.c'), "text/cpp": (__translate("C/C++ Source Code"), '.c, .cpp, .cxx'), "application/x-perl" : (__translate("Perl Script"), '.pl'), "application/x-python" : (__translate("Python Program"), '.py'), "application/x-shell" : (__translate("Shell Script"), '.sh'), "application/x-sh" : (__translate("Shell Script"), '.sh'), "text/plain" : (__translate("Plain Text"), '.txt, .log'), "text/html" : (__translate("HTML Dcoument"), '.htm, .html'), "image/gif" : (__translate("GIF Image"), '.gif'), "image/png" : (__translate("PNG Image"), '.png'), "image/jpeg" : (__translate("JPEG Image"), '.jpg, .jpeg'), "image/tiff" : (__translate("TIFF Image"), '.tif, .tiff'), "image/x-bitmap" : (__translate("Bitmap (BMP) Image"), '.bmp'), "image/x-bmp" : (__translate("Bitmap (BMP) Image"), '.bmp'), "image/x-photocd" : (__translate("Photo CD Image"), '.pcd'), "image/x-portable-anymap" : (__translate("Portable Image (PNM)"), '.pnm'), "image/x-portable-bitmap" : (__translate("Portable B&W Image (PBM)"), '.pbm'), "image/x-portable-graymap" : (__translate("Portable Grayscale Image (PGM)"), '.pgm'), "image/x-portable-pixmap" : (__translate("Portable Color Image (PPM)"), '.ppm'), "image/x-sgi-rgb" : (__translate("SGI RGB"), '.rgb'), "image/x-xbitmap" : (__translate("X11 Bitmap (XBM)"), '.xbm'), "image/x-xpixmap" : (__translate("X11 Pixmap (XPM)"), '.xpm'), "image/x-sun-raster" : (__translate("Sun Raster Format"), '.ras'), "application/hplip-fax" : (__translate("HPLIP Fax File"), '.g3, .g4'), } # pixmaps for status list(s) (inkjet, laserjet) status_icons = None def getStatusListIcon(error_state): global status_icons if status_icons is None: status_icons = { ERROR_STATE_CLEAR : (load_pixmap('idle', '16x16'), load_pixmap('idle', '16x16')), ERROR_STATE_BUSY : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')), ERROR_STATE_ERROR : (load_pixmap('error', '16x16'), load_pixmap('error', '16x16')), ERROR_STATE_LOW_SUPPLIES : (load_pixmap('inkdrop', '16x16'), load_pixmap('toner', '16x16')), ERROR_STATE_OK : (load_pixmap('ok', '16x16'), load_pixmap('ok', '16x16')), ERROR_STATE_WARNING : (load_pixmap('warning', '16x16'), load_pixmap('warning', '16x16')), ERROR_STATE_LOW_PAPER: (load_pixmap('paper', '16x16'), load_pixmap('paper', '16x16')), ERROR_STATE_PRINTING : (load_pixmap("print", '16x16'), load_pixmap("print", '16x16')), ERROR_STATE_SCANNING : (load_pixmap("scan", '16x16'), load_pixmap("scan", '16x16')), ERROR_STATE_PHOTOCARD : (load_pixmap("pcard", '16x16'), load_pixmap("pcard", '16x16')), ERROR_STATE_FAXING : (load_pixmap("fax", '16x16'), load_pixmap("fax", '16x16')), ERROR_STATE_COPYING : (load_pixmap("makecopies", '16x16'), load_pixmap("makecopies", '16x16')), } return status_icons.get(error_state, status_icons[ERROR_STATE_CLEAR]) # pixmaps for device icons (inkjet, laserjet) overlay_icons = None def getStatusOverlayIcon(error_state): global overlay_icons if overlay_icons is None: overlay_icons = { ERROR_STATE_CLEAR : (None, None), ERROR_STATE_BUSY : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')), ERROR_STATE_ERROR : (load_pixmap('error', '16x16'), load_pixmap('error', '16x16')), ERROR_STATE_LOW_SUPPLIES : (load_pixmap('inkdrop', '16x16'), load_pixmap('toner', '16x16')), ERROR_STATE_OK : (load_pixmap('ok', '16x16'), load_pixmap('ok', '16x16')), ERROR_STATE_WARNING : (load_pixmap('warning', '16x16'), load_pixmap('warning', '16x16')), ERROR_STATE_LOW_PAPER: (load_pixmap('paper', '16x16'), load_pixmap('paper', '16x16')), ERROR_STATE_PRINTING : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')), ERROR_STATE_SCANNING : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')), ERROR_STATE_PHOTOCARD : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')), ERROR_STATE_FAXING : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')), ERROR_STATE_COPYING : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')), ERROR_STATE_REFRESHING : (load_pixmap('refresh1', '16x16'), load_pixmap('refresh1', '16x16')), } return overlay_icons.get(error_state, overlay_icons[ERROR_STATE_CLEAR]) NUM_REPRS = { 1 : __translate("one"), 2 : __translate("two"), 3 : __translate("three"), 4 : __translate("four"), 5 : __translate("five"), 6 : __translate("six"), 7 : __translate("seven"), 8 : __translate("eight"), 9 : __translate("nine"), 10 : __translate("ten"), 11 : __translate("eleven"), 12 : __translate("twelve") } UNIT_NAMES = { "year" : (__translate("year"), __translate("years")), "month" : (__translate("month"), __translate("months")), "week" : (__translate("week"), __translate("weeks")), "day" : (__translate("day"), __translate("days")), "hour" : (__translate("hour"), __translate("hours")), "minute" : (__translate("minute"), __translate("minutes")), "second" : (__translate("second"), __translate("seconds")), } def getTimeDeltaDesc(past): t1 = QDateTime() t1.setTime_t(int(past)) t2 = QDateTime.currentDateTime() delta = t1.secsTo(t2) return __translate("(%s ago)"%stringify(delta)) # "Nicely readable timedelta" # Credit: Bjorn Lindqvist # ASPN Python Recipe 498062 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/498062 # Note: Modified from recipe def getSecondsInUnits(seconds): unit_limits = [("year", 31536000), ("month", 2592000), ("week", 604800), ("day", 86400), ("hour", 3600), ("minute", 60)] for unit_name, limit in unit_limits: if seconds >= limit: amount = int(round(float(seconds) / limit)) return amount, unit_name return seconds, "second" def stringify(seconds): amount, unit_name = getSecondsInUnits(seconds) try: i18n_amount = NUM_REPRS[amount] except KeyError: i18n_amount = to_unicode(amount) if amount == 1: i18n_unit = UNIT_NAMES[unit_name][0] else: i18n_unit = UNIT_NAMES[unit_name][1] return "%s %s"%(i18n_amount, i18n_unit)