~ubuntu-branches/ubuntu/saucy/hplip/saucy-proposed

« back to all changes in this revision

Viewing changes to .pc/simple-scan-as-default.dpatch/ui4/ui_utils.py

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2012-05-26 11:20:39 UTC
  • mfrom: (1.5.6) (31.1.3 precise)
  • Revision ID: package-import@ubuntu.com-20120526112039-bevxczegxnbyr5m7
Tags: 3.12.4-1
* New upstream release
* Switch to source/format 3.0 (quilt) - drop dpatch
* Refreshed debian/patches
* dh_autoreconf debian/autogen.sh & set local-options single-debian-patch
* Update to debian/compat -> 9
* Fix "hardened build flags" patch from Moritz - thanks (Closes: #667828)
* Fix "duplex descriptor uninitialized" patch from Matej (Closes: #583273)
* Fix "please migrate to kde-runtime" patch from Pino (Closes: #666544)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
#
 
3
# (c) Copyright 2001-2009 Hewlett-Packard 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
# Author: Don Welch
 
20
#
 
21
 
 
22
# Std Lib
 
23
import os.path
 
24
import re
 
25
import os
 
26
import time
 
27
 
 
28
# Local
 
29
from base.g import *
 
30
from base.codes import *
 
31
from base import utils
 
32
from prnt import cups
 
33
 
 
34
# Qt
 
35
from PyQt4.QtCore import *
 
36
from PyQt4.QtGui import *
 
37
 
 
38
pat_html_remove = re.compile("(?is)<.*?>", re.I)
 
39
 
 
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
 
49
 
 
50
 
 
51
def __translate(t):
 
52
    return QApplication.translate("ui_utils", t, None, QApplication.UnicodeUTF8)
 
53
 
 
54
 
 
55
def beginWaitCursor():
 
56
    QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
 
57
 
 
58
 
 
59
def endWaitCursor():
 
60
    QApplication.restoreOverrideCursor()
 
61
 
 
62
 
 
63
# TODO: Cache pixmaps
 
64
def load_pixmap(name, subdir=None, resize_to=None):
 
65
    name = ''.join([os.path.splitext(name)[0], '.png'])
 
66
 
 
67
    if subdir is None:
 
68
        dir = prop.image_dir
 
69
        ldir = os.path.join(os.getcwd(), 'data', 'images')
 
70
    else:
 
71
        dir = os.path.join(prop.image_dir, subdir)
 
72
        ldir = os.path.join(os.getcwd(), 'data', 'images', subdir)
 
73
 
 
74
    for d in [dir, ldir]:
 
75
        f = os.path.join(d, name)
 
76
        if os.path.exists(f):
 
77
            if resize_to is not None:
 
78
                img = QImage(f)
 
79
                x, y = resize_to
 
80
                return QPixmap.fromImage(img.scaled(x, y, Qt.IgnoreAspectRatio, Qt.SmoothTransformation))
 
81
            else:
 
82
                return QPixmap(f)
 
83
 
 
84
        for w in utils.walkFiles(dir, recurse=True, abs_paths=True, return_folders=False, pattern=name):
 
85
            if resize_to is not None:
 
86
                img = QImage(w)
 
87
                x, y = resize_to
 
88
                return QPixmap.fromImage(img.scaled(x, y, Qt.IgnoreAspectRatio, Qt.SmoothTransformation))
 
89
            else:
 
90
                return QPixmap(w)
 
91
 
 
92
    log.error("Pixmap '%s' not found!" % name)
 
93
    return QPixmap()
 
94
 
 
95
loadPixmap = load_pixmap
 
96
 
 
97
 
 
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)
 
101
 
 
102
 
 
103
 
 
104
class UserSettings(QSettings):
 
105
    def __init__(self):
 
106
        if prop.user_dir is None:
 
107
            QSettings.__init__(self)
 
108
        else:
 
109
            QSettings.__init__(self, os.path.join(prop.user_dir,  'hplip.conf'),  QSettings.IniFormat)
 
110
 
 
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 = ''
 
115
        self.version = ''
 
116
        self.date_time = ''
 
117
        self.auto_refresh = False
 
118
        self.auto_refresh_rate = 30
 
119
        self.auto_refresh_type = 1
 
120
        self.polling_interval = 5
 
121
        self.polling = True
 
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=""
 
130
        self.loadDefaults()
 
131
 
 
132
 
 
133
    def __setup(self,  cmds):
 
134
        for c in cmds:
 
135
            basename = c.split()[0]
 
136
            path = utils.which(basename)
 
137
            if path:
 
138
                return ' '.join([os.path.join(path, basename), ' '.join(c.split()[1:])])
 
139
 
 
140
        return ''
 
141
 
 
142
 
 
143
    def loadDefaults(self):
 
144
        self.cmd_scan = self.__setup(['xsane -V %SANE_URI%', 'kooka', 'xscanimage'])
 
145
        self.cmd_fab = self.__setup(['hp-fab'])
 
146
 
 
147
 
 
148
    def load(self):
 
149
        log.debug("Loading user settings...")
 
150
        self.sync()
 
151
 
 
152
        self.beginGroup("settings")
 
153
        i, ok = self.value("systray_visible").toInt()
 
154
        if ok:
 
155
            self.systray_visible = i
 
156
 
 
157
        i, ok = self.value("systray_messages").toInt()
 
158
        if ok:
 
159
            self.systray_messages = i
 
160
 
 
161
        self.endGroup()
 
162
 
 
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
 
167
        self.endGroup()
 
168
 
 
169
        self.beginGroup("commands")
 
170
        self.cmd_scan = unicode(self.value("scan").toString()) or self.cmd_scan
 
171
        self.endGroup()
 
172
 
 
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)
 
177
        self.endGroup()
 
178
 
 
179
        self.beginGroup("installation")
 
180
        self.version = unicode(self.value("version").toString())
 
181
        self.date_time = unicode(self.value("date_time").toString())
 
182
        self.endGroup()
 
183
 
 
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',')
 
188
        self.endGroup()
 
189
 
 
190
        self.beginGroup("fax")
 
191
        self.voice_phone = unicode(self.value("voice_phone").toString())
 
192
        self.email_address = unicode(self.value("email_address").toString())
 
193
        self.endGroup()
 
194
        
 
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())
 
198
            
 
199
        i, Ok = self.value("last_upgraded_time").toInt()
 
200
        if Ok and i >0:
 
201
            self.upgrade_last_update_time =i
 
202
        else:
 
203
            self.upgrade_last_update_time = 0
 
204
            
 
205
        i, Ok = self.value("pending_upgrade_time").toInt()
 
206
        if Ok and i >0 :
 
207
            self.upgrade_pending_update_time = i
 
208
        else:
 
209
            self.upgrade_pending_update_time = 0
 
210
            
 
211
        self.endGroup()
 
212
 
 
213
 
 
214
    def save(self):
 
215
        log.debug("Saving user settings...")
 
216
 
 
217
        self.beginGroup("settings")
 
218
        self.setValue("systray_visible", QVariant(self.systray_visible))
 
219
        self.setValue("systray_messages", QVariant(self.systray_messages))
 
220
        self.endGroup()
 
221
 
 
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))
 
226
        self.endGroup()
 
227
 
 
228
        self.beginGroup("commands")
 
229
        self.setValue("scan",  QVariant(self.cmd_scan))
 
230
        self.endGroup()
 
231
 
 
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))
 
236
        self.endGroup()
 
237
 
 
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)))
 
242
        self.endGroup()
 
243
 
 
244
        self.beginGroup("fax")
 
245
        self.setValue("voice_phone", QVariant(self.voice_phone))
 
246
        self.setValue("email_address", QVariant(self.email_address))
 
247
        self.endGroup()
 
248
        
 
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
 
253
            
 
254
        self.setValue("last_upgraded_time", QVariant(self.upgrade_last_update_time))
 
255
        self.setValue("pending_upgrade_time", QVariant(self.upgrade_pending_update_time))
 
256
        self.endGroup()
 
257
 
 
258
 
 
259
        self.sync()
 
260
 
 
261
 
 
262
    def debug(self):
 
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)
 
273
 
 
274
 
 
275
DEFAULT_TITLE =  __translate("HP Device Manager")
 
276
 
 
277
 
 
278
def FailureUI(parent, error_text, title_text=None):
 
279
    log.error(pat_html_remove.sub(' ', unicode(error_text)))
 
280
 
 
281
    if title_text is None:
 
282
        if parent is not None:
 
283
            title_text = parent.windowTitle()
 
284
        else:
 
285
            title_text = DEFAULT_TITLE
 
286
 
 
287
    QMessageBox.critical(parent,
 
288
        title_text,
 
289
        error_text,
 
290
        QMessageBox.Ok,
 
291
        QMessageBox.NoButton,
 
292
        QMessageBox.NoButton)
 
293
 
 
294
showFailureUi = FailureUI
 
295
 
 
296
 
 
297
def WarningUI(parent,  warn_text, title_text=None):
 
298
    log.warn(pat_html_remove.sub(' ', unicode(warn_text)))
 
299
 
 
300
    if title_text is None:
 
301
        if parent is not None:
 
302
            title_text = parent.windowTitle()
 
303
        else:
 
304
            title_text = DEFAULT_TITLE
 
305
 
 
306
 
 
307
    QMessageBox.warning(parent,
 
308
        title_text,
 
309
        warn_text,
 
310
        QMessageBox.Ok,
 
311
        QMessageBox.NoButton,
 
312
        QMessageBox.NoButton)
 
313
 
 
314
showWarningUi = WarningUI
 
315
 
 
316
 
 
317
def SuccessUI(parent, text, title_text=None):
 
318
    log.info(pat_html_remove.sub(' ', unicode(text)))
 
319
 
 
320
    if title_text is None:
 
321
        if parent is not None:
 
322
            title_text = parent.windowTitle()
 
323
        else:
 
324
            title_text = DEFAULT_TITLE
 
325
 
 
326
 
 
327
    QMessageBox.information(parent,
 
328
        title_text,
 
329
        text,
 
330
        QMessageBox.Ok,
 
331
        QMessageBox.NoButton,
 
332
        QMessageBox.NoButton)
 
333
 
 
334
showSuccessUi = SuccessUI
 
335
 
 
336
 
 
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)
 
340
 
 
341
checkDeviceUi = CheckDeviceUI
 
342
 
 
343
 
 
344
class PrinterNameValidator(QValidator):
 
345
    def __init__(self, parent=None):
 
346
        QValidator.__init__(self, parent)
 
347
 
 
348
    def validate(self, input, pos):
 
349
        input = unicode(input)
 
350
 
 
351
        if not input:
 
352
            return QValidator.Acceptable, pos
 
353
 
 
354
        if input[pos-1] in cups.INVALID_PRINTER_NAME_CHARS:
 
355
            return QValidator.Invalid, pos
 
356
 
 
357
        # TODO: How to determine if unicode char is "printable" and acceptable
 
358
        # to CUPS?
 
359
        #elif input != utils.printable(input):
 
360
        #    return QValidator.Invalid, pos
 
361
 
 
362
        return QValidator.Acceptable, pos
 
363
 
 
364
 
 
365
 
 
366
class PhoneNumValidator(QValidator):
 
367
    def __init__(self, parent=None):
 
368
        QValidator.__init__(self, parent)
 
369
 
 
370
    def validate(self, input, pos):
 
371
        input = unicode(input)
 
372
 
 
373
        if not input:
 
374
            return QValidator.Acceptable, pos
 
375
 
 
376
        if input[pos-1] not in u'0123456789-(+).,#* ':
 
377
            return QValidator.Invalid, pos
 
378
 
 
379
        return QValidator.Acceptable, pos
 
380
 
 
381
 
 
382
class AddressBookNameValidator(QValidator):
 
383
    def __init__(self, db, parent=None):
 
384
        QValidator.__init__(self, parent)
 
385
        self.db = db
 
386
 
 
387
    def validate(self, input, pos):
 
388
        input = unicode(input)
 
389
 
 
390
        if not input:
 
391
            return QValidator.Acceptable, pos
 
392
 
 
393
        if input in self.db.get_all_names():
 
394
            return QValidator.Invalid, pos
 
395
 
 
396
        if input[pos-1] in u'''|\\/"''': # | is the drag 'n drop separator
 
397
            return QValidator.Invalid, pos
 
398
 
 
399
        return QValidator.Acceptable, pos
 
400
 
 
401
 
 
402
 
 
403
MIME_TYPES_DESC = \
 
404
{
 
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'),
 
433
}
 
434
 
 
435
# pixmaps for status list(s) (inkjet, laserjet)
 
436
status_icons = None
 
437
 
 
438
def getStatusListIcon(error_state):
 
439
    global status_icons
 
440
    if status_icons is None:
 
441
        status_icons = {
 
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')),
 
454
        }
 
455
 
 
456
    return status_icons.get(error_state, status_icons[ERROR_STATE_CLEAR])
 
457
 
 
458
# pixmaps for device icons (inkjet, laserjet)
 
459
overlay_icons = None
 
460
 
 
461
def getStatusOverlayIcon(error_state):
 
462
    global overlay_icons
 
463
    if overlay_icons is None:
 
464
        overlay_icons = {
 
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')),
 
478
        }
 
479
 
 
480
    return overlay_icons.get(error_state, overlay_icons[ERROR_STATE_CLEAR])
 
481
 
 
482
 
 
483
NUM_REPRS = {
 
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")
 
496
}
 
497
 
 
498
UNIT_NAMES = {
 
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")),
 
506
}
 
507
 
 
508
 
 
509
def getTimeDeltaDesc(past):
 
510
    t1 = QDateTime()
 
511
    t1.setTime_t(int(past))
 
512
    t2 = QDateTime.currentDateTime()
 
513
    delta = t1.secsTo(t2)
 
514
    return __translate("(%1 ago)").arg(stringify(delta))
 
515
 
 
516
 
 
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),
 
524
                   ("month", 2592000),
 
525
                   ("week", 604800),
 
526
                   ("day", 86400),
 
527
                   ("hour", 3600),
 
528
                   ("minute", 60)]
 
529
 
 
530
    for unit_name, limit in unit_limits:
 
531
        if seconds >= limit:
 
532
            amount = int(round(float(seconds) / limit))
 
533
            return amount, unit_name
 
534
 
 
535
    return seconds, "second"
 
536
 
 
537
 
 
538
def stringify(seconds):
 
539
    amount, unit_name = getSecondsInUnits(seconds)
 
540
 
 
541
    try:
 
542
        i18n_amount = NUM_REPRS[amount]
 
543
    except KeyError:
 
544
        i18n_amount = unicode(amount)
 
545
 
 
546
    if amount == 1:
 
547
        i18n_unit = UNIT_NAMES[unit_name][0]
 
548
    else:
 
549
        i18n_unit = UNIT_NAMES[unit_name][1]
 
550
 
 
551
    return QString("%1 %2").arg(i18n_amount).arg(i18n_unit)
 
552
 
 
553