1
# -*- coding: utf-8 -*-
3
# (c) Copyright 2001-2009 Hewlett-Packard Development Company, L.P.
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.
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.
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
30
from base.codes import *
31
from base import utils
35
from PyQt4.QtCore import *
36
from PyQt4.QtGui import *
38
pat_html_remove = re.compile("(?is)<.*?>", re.I)
40
# databaseChanged signal values (for FABWindow)
41
FAB_NAME_ADD = 0 # s1 - new name
42
FAB_NAME_RENAME = 1 # s1 - old name, s2 - new name
43
FAB_NAME_REMOVE = 2 # s1 - removed name
44
FAB_NAME_DETAILS_CHANGED = 3 # s1 - name
45
FAB_GROUP_ADD = 4 # s1 - new group
46
FAB_GROUP_RENAME = 5 # s1 - old group, s2 - new group
47
FAB_GROUP_REMOVE = 6 # s1 - removed group
48
FAB_GROUP_MEMBERSHIP_CHANGED = 7 # s1 - group
52
return QApplication.translate("ui_utils", t, None, QApplication.UnicodeUTF8)
55
def beginWaitCursor():
56
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
60
QApplication.restoreOverrideCursor()
64
def load_pixmap(name, subdir=None, resize_to=None):
65
name = ''.join([os.path.splitext(name)[0], '.png'])
69
ldir = os.path.join(os.getcwd(), 'data', 'images')
71
dir = os.path.join(prop.image_dir, subdir)
72
ldir = os.path.join(os.getcwd(), 'data', 'images', subdir)
75
f = os.path.join(d, name)
77
if resize_to is not None:
80
return QPixmap.fromImage(img.scaled(x, y, Qt.IgnoreAspectRatio, Qt.SmoothTransformation))
84
for w in utils.walkFiles(dir, recurse=True, abs_paths=True, return_folders=False, pattern=name):
85
if resize_to is not None:
88
return QPixmap.fromImage(img.scaled(x, y, Qt.IgnoreAspectRatio, Qt.SmoothTransformation))
92
log.error("Pixmap '%s' not found!" % name)
95
loadPixmap = load_pixmap
98
def getPynotifyIcon(name, subdir='32x32'):
99
name = ''.join([os.path.splitext(name)[0], '.png'])
100
return "file://" + os.path.join(prop.image_dir, subdir, name)
104
class UserSettings(QSettings):
106
if prop.user_dir is None:
107
QSettings.__init__(self)
109
QSettings.__init__(self, os.path.join(prop.user_dir, 'hplip.conf'), QSettings.IniFormat)
111
self.systray_visible = SYSTRAY_VISIBLE_SHOW_ALWAYS
112
self.systray_messages = SYSTRAY_MESSAGES_SHOW_ALL
113
self.last_used_device_uri = ''
114
self.last_used_printer = ''
117
self.auto_refresh = False
118
self.auto_refresh_rate = 30
119
self.auto_refresh_type = 1
120
self.polling_interval = 5
122
self.device_list = []
123
self.working_dir = '.'
124
self.voice_phone = ''
125
self.email_address = ''
126
self.upgrade_notify=True
127
self.upgrade_last_update_time=0
128
self.upgrade_pending_update_time=0
129
self.latest_available_version=""
133
def __setup(self, cmds):
135
basename = c.split()[0]
136
path = utils.which(basename)
138
return ' '.join([os.path.join(path, basename), ' '.join(c.split()[1:])])
143
def loadDefaults(self):
144
self.cmd_scan = self.__setup(['xsane -V %SANE_URI%', 'kooka', 'xscanimage'])
145
self.cmd_fab = self.__setup(['hp-fab'])
149
log.debug("Loading user settings...")
152
self.beginGroup("settings")
153
i, ok = self.value("systray_visible").toInt()
155
self.systray_visible = i
157
i, ok = self.value("systray_messages").toInt()
159
self.systray_messages = i
163
self.beginGroup("last_used")
164
self.last_used_device_uri = unicode(self.value("device_uri").toString()) or self.last_used_device_uri
165
self.last_used_printer = unicode(self.value("printer_name").toString()) or self.last_used_printer
166
self.working_dir = unicode(self.value("working_dir").toString()) or self.working_dir
169
self.beginGroup("commands")
170
self.cmd_scan = unicode(self.value("scan").toString()) or self.cmd_scan
173
self.beginGroup("refresh")
174
self.auto_refresh_rate = int(self.value("rate").toString() or self.auto_refresh_rate)
175
self.auto_refresh = bool(self.value("enable").toBool())
176
self.auto_refresh_type = int(self.value("type").toString() or self.auto_refresh_type)
179
self.beginGroup("installation")
180
self.version = unicode(self.value("version").toString())
181
self.date_time = unicode(self.value("date_time").toString())
184
self.beginGroup("polling")
185
self.polling = bool(self.value("enable").toBool())
186
self.polling_interval = int(self.value("interval").toString() or self.polling_interval)
187
self.polling_device_list = unicode(self.value("device_list").toString() or '').split(u',')
190
self.beginGroup("fax")
191
self.voice_phone = unicode(self.value("voice_phone").toString())
192
self.email_address = unicode(self.value("email_address").toString())
195
self.beginGroup("upgrade")
196
self.upgrade_notify= bool(self.value("notify_upgrade").toBool())
197
self.latest_available_version=str(self.value("latest_available_version").toString())
199
i, Ok = self.value("last_upgraded_time").toInt()
201
self.upgrade_last_update_time =i
203
self.upgrade_last_update_time = 0
205
i, Ok = self.value("pending_upgrade_time").toInt()
207
self.upgrade_pending_update_time = i
209
self.upgrade_pending_update_time = 0
215
log.debug("Saving user settings...")
217
self.beginGroup("settings")
218
self.setValue("systray_visible", QVariant(self.systray_visible))
219
self.setValue("systray_messages", QVariant(self.systray_messages))
222
self.beginGroup("last_used")
223
self.setValue("device_uri", QVariant(self.last_used_device_uri))
224
self.setValue("printer_name", QVariant(self.last_used_printer))
225
self.setValue("working_dir", QVariant(self.working_dir))
228
self.beginGroup("commands")
229
self.setValue("scan", QVariant(self.cmd_scan))
232
self.beginGroup("refresh")
233
self.setValue("rate", QVariant(self.auto_refresh_rate))
234
self.setValue("enable", QVariant(self.auto_refresh))
235
self.setValue("type", QVariant(self.auto_refresh_type))
238
self.beginGroup("polling")
239
self.setValue("enable", QVariant(self.polling))
240
self.setValue("interval", QVariant(self.polling_interval))
241
self.setValue("device_list", QVariant(u','.join(self.polling_device_list)))
244
self.beginGroup("fax")
245
self.setValue("voice_phone", QVariant(self.voice_phone))
246
self.setValue("email_address", QVariant(self.email_address))
249
self.beginGroup("upgrade")
250
self.setValue("notify_upgrade", QVariant(self.upgrade_notify))
251
if self.upgrade_last_update_time <1:
252
self.upgrade_last_update_time = time.time() # <---Need to verify code once
254
self.setValue("last_upgraded_time", QVariant(self.upgrade_last_update_time))
255
self.setValue("pending_upgrade_time", QVariant(self.upgrade_pending_update_time))
263
log.debug("FAB command: %s" % self.cmd_fab)
264
log.debug("Scan command: %s" % self.cmd_scan)
265
log.debug("Auto refresh: %s" % self.auto_refresh)
266
log.debug("Auto refresh rate: %s" % self.auto_refresh_rate)
267
log.debug("Auto refresh type: %s" % self.auto_refresh_type)
268
log.debug("Systray visible: %d" % self.systray_visible)
269
log.debug("Systray messages: %d" % self.systray_messages)
270
log.debug("Last used device URI: %s" % self.last_used_device_uri)
271
log.debug("Last used printer: %s" % self.last_used_printer)
272
log.debug("Working directory: %s" % self.working_dir)
275
DEFAULT_TITLE = __translate("HP Device Manager")
278
def FailureUI(parent, error_text, title_text=None):
279
log.error(pat_html_remove.sub(' ', unicode(error_text)))
281
if title_text is None:
282
if parent is not None:
283
title_text = parent.windowTitle()
285
title_text = DEFAULT_TITLE
287
QMessageBox.critical(parent,
291
QMessageBox.NoButton,
292
QMessageBox.NoButton)
294
showFailureUi = FailureUI
297
def WarningUI(parent, warn_text, title_text=None):
298
log.warn(pat_html_remove.sub(' ', unicode(warn_text)))
300
if title_text is None:
301
if parent is not None:
302
title_text = parent.windowTitle()
304
title_text = DEFAULT_TITLE
307
QMessageBox.warning(parent,
311
QMessageBox.NoButton,
312
QMessageBox.NoButton)
314
showWarningUi = WarningUI
317
def SuccessUI(parent, text, title_text=None):
318
log.info(pat_html_remove.sub(' ', unicode(text)))
320
if title_text is None:
321
if parent is not None:
322
title_text = parent.windowTitle()
324
title_text = DEFAULT_TITLE
327
QMessageBox.information(parent,
331
QMessageBox.NoButton,
332
QMessageBox.NoButton)
334
showSuccessUi = SuccessUI
337
def CheckDeviceUI(parent, title_text=None):
338
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>")
339
return FailureUI(parent, text, title_text)
341
checkDeviceUi = CheckDeviceUI
344
class PrinterNameValidator(QValidator):
345
def __init__(self, parent=None):
346
QValidator.__init__(self, parent)
348
def validate(self, input, pos):
349
input = unicode(input)
352
return QValidator.Acceptable, pos
354
if input[pos-1] in cups.INVALID_PRINTER_NAME_CHARS:
355
return QValidator.Invalid, pos
357
# TODO: How to determine if unicode char is "printable" and acceptable
359
#elif input != utils.printable(input):
360
# return QValidator.Invalid, pos
362
return QValidator.Acceptable, pos
366
class PhoneNumValidator(QValidator):
367
def __init__(self, parent=None):
368
QValidator.__init__(self, parent)
370
def validate(self, input, pos):
371
input = unicode(input)
374
return QValidator.Acceptable, pos
376
if input[pos-1] not in u'0123456789-(+).,#* ':
377
return QValidator.Invalid, pos
379
return QValidator.Acceptable, pos
382
class AddressBookNameValidator(QValidator):
383
def __init__(self, db, parent=None):
384
QValidator.__init__(self, parent)
387
def validate(self, input, pos):
388
input = unicode(input)
391
return QValidator.Acceptable, pos
393
if input in self.db.get_all_names():
394
return QValidator.Invalid, pos
396
if input[pos-1] in u'''|\\/"''': # | is the drag 'n drop separator
397
return QValidator.Invalid, pos
399
return QValidator.Acceptable, pos
405
"application/pdf" : (__translate("PDF Document"), '.pdf'),
406
"application/postscript" : (__translate("Postscript Document"), '.ps'),
407
"application/vnd.hp-HPGL" : (__translate("HP Graphics Language File"), '.hgl, .hpg, .plt, .prn'),
408
"application/x-cshell" : (__translate("C Shell Script"), '.csh, .sh'),
409
"application/x-csource" : (__translate("C Source Code"), '.c'),
410
"text/cpp": (__translate("C/C++ Source Code"), '.c, .cpp, .cxx'),
411
"application/x-perl" : (__translate("Perl Script"), '.pl'),
412
"application/x-python" : (__translate("Python Program"), '.py'),
413
"application/x-shell" : (__translate("Shell Script"), '.sh'),
414
"application/x-sh" : (__translate("Shell Script"), '.sh'),
415
"text/plain" : (__translate("Plain Text"), '.txt, .log'),
416
"text/html" : (__translate("HTML Dcoument"), '.htm, .html'),
417
"image/gif" : (__translate("GIF Image"), '.gif'),
418
"image/png" : (__translate("PNG Image"), '.png'),
419
"image/jpeg" : (__translate("JPEG Image"), '.jpg, .jpeg'),
420
"image/tiff" : (__translate("TIFF Image"), '.tif, .tiff'),
421
"image/x-bitmap" : (__translate("Bitmap (BMP) Image"), '.bmp'),
422
"image/x-bmp" : (__translate("Bitmap (BMP) Image"), '.bmp'),
423
"image/x-photocd" : (__translate("Photo CD Image"), '.pcd'),
424
"image/x-portable-anymap" : (__translate("Portable Image (PNM)"), '.pnm'),
425
"image/x-portable-bitmap" : (__translate("Portable B&W Image (PBM)"), '.pbm'),
426
"image/x-portable-graymap" : (__translate("Portable Grayscale Image (PGM)"), '.pgm'),
427
"image/x-portable-pixmap" : (__translate("Portable Color Image (PPM)"), '.ppm'),
428
"image/x-sgi-rgb" : (__translate("SGI RGB"), '.rgb'),
429
"image/x-xbitmap" : (__translate("X11 Bitmap (XBM)"), '.xbm'),
430
"image/x-xpixmap" : (__translate("X11 Pixmap (XPM)"), '.xpm'),
431
"image/x-sun-raster" : (__translate("Sun Raster Format"), '.ras'),
432
"application/hplip-fax" : (__translate("HPLIP Fax File"), '.g3, .g4'),
435
# pixmaps for status list(s) (inkjet, laserjet)
438
def getStatusListIcon(error_state):
440
if status_icons is None:
442
ERROR_STATE_CLEAR : (load_pixmap('idle', '16x16'), load_pixmap('idle', '16x16')),
443
ERROR_STATE_BUSY : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')),
444
ERROR_STATE_ERROR : (load_pixmap('error', '16x16'), load_pixmap('error', '16x16')),
445
ERROR_STATE_LOW_SUPPLIES : (load_pixmap('inkdrop', '16x16'), load_pixmap('toner', '16x16')),
446
ERROR_STATE_OK : (load_pixmap('ok', '16x16'), load_pixmap('ok', '16x16')),
447
ERROR_STATE_WARNING : (load_pixmap('warning', '16x16'), load_pixmap('warning', '16x16')),
448
ERROR_STATE_LOW_PAPER: (load_pixmap('paper', '16x16'), load_pixmap('paper', '16x16')),
449
ERROR_STATE_PRINTING : (load_pixmap("print", '16x16'), load_pixmap("print", '16x16')),
450
ERROR_STATE_SCANNING : (load_pixmap("scan", '16x16'), load_pixmap("scan", '16x16')),
451
ERROR_STATE_PHOTOCARD : (load_pixmap("pcard", '16x16'), load_pixmap("pcard", '16x16')),
452
ERROR_STATE_FAXING : (load_pixmap("fax", '16x16'), load_pixmap("fax", '16x16')),
453
ERROR_STATE_COPYING : (load_pixmap("makecopies", '16x16'), load_pixmap("makecopies", '16x16')),
456
return status_icons.get(error_state, status_icons[ERROR_STATE_CLEAR])
458
# pixmaps for device icons (inkjet, laserjet)
461
def getStatusOverlayIcon(error_state):
463
if overlay_icons is None:
465
ERROR_STATE_CLEAR : (None, None),
466
ERROR_STATE_BUSY : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')),
467
ERROR_STATE_ERROR : (load_pixmap('error', '16x16'), load_pixmap('error', '16x16')),
468
ERROR_STATE_LOW_SUPPLIES : (load_pixmap('inkdrop', '16x16'), load_pixmap('toner', '16x16')),
469
ERROR_STATE_OK : (load_pixmap('ok', '16x16'), load_pixmap('ok', '16x16')),
470
ERROR_STATE_WARNING : (load_pixmap('warning', '16x16'), load_pixmap('warning', '16x16')),
471
ERROR_STATE_LOW_PAPER: (load_pixmap('paper', '16x16'), load_pixmap('paper', '16x16')),
472
ERROR_STATE_PRINTING : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')),
473
ERROR_STATE_SCANNING : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')),
474
ERROR_STATE_PHOTOCARD : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')),
475
ERROR_STATE_FAXING : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')),
476
ERROR_STATE_COPYING : (load_pixmap('busy', '16x16'), load_pixmap('busy', '16x16')),
477
ERROR_STATE_REFRESHING : (load_pixmap('refresh1', '16x16'), load_pixmap('refresh1', '16x16')),
480
return overlay_icons.get(error_state, overlay_icons[ERROR_STATE_CLEAR])
484
1 : __translate("one"),
485
2 : __translate("two"),
486
3 : __translate("three"),
487
4 : __translate("four"),
488
5 : __translate("five"),
489
6 : __translate("six"),
490
7 : __translate("seven"),
491
8 : __translate("eight"),
492
9 : __translate("nine"),
493
10 : __translate("ten"),
494
11 : __translate("eleven"),
495
12 : __translate("twelve")
499
"year" : (__translate("year"), __translate("years")),
500
"month" : (__translate("month"), __translate("months")),
501
"week" : (__translate("week"), __translate("weeks")),
502
"day" : (__translate("day"), __translate("days")),
503
"hour" : (__translate("hour"), __translate("hours")),
504
"minute" : (__translate("minute"), __translate("minutes")),
505
"second" : (__translate("second"), __translate("seconds")),
509
def getTimeDeltaDesc(past):
511
t1.setTime_t(int(past))
512
t2 = QDateTime.currentDateTime()
513
delta = t1.secsTo(t2)
514
return __translate("(%1 ago)").arg(stringify(delta))
517
# "Nicely readable timedelta"
518
# Credit: Bjorn Lindqvist
519
# ASPN Python Recipe 498062
520
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/498062
521
# Note: Modified from recipe
522
def getSecondsInUnits(seconds):
523
unit_limits = [("year", 31536000),
530
for unit_name, limit in unit_limits:
532
amount = int(round(float(seconds) / limit))
533
return amount, unit_name
535
return seconds, "second"
538
def stringify(seconds):
539
amount, unit_name = getSecondsInUnits(seconds)
542
i18n_amount = NUM_REPRS[amount]
544
i18n_amount = unicode(amount)
547
i18n_unit = UNIT_NAMES[unit_name][0]
549
i18n_unit = UNIT_NAMES[unit_name][1]
551
return QString("%1 %2").arg(i18n_amount).arg(i18n_unit)