61
75
utils.format_text(USAGE, typ, __title__, 'hp-unload', __version__)
65
return qApp.translate("Unload",s,c)
69
if not utils.checkPyQtImport():
70
log.error("PyQt/Qt initialization error. Please check install of PyQt/Qt and try again.")
74
from ui import unloadform
79
## Console class (from ASPN Python Cookbook)
80
## Author: James Thiele
81
## Date: 27 April 2004
83
## Location: http://www.eskimo.com/~jet/python/examples/cmd/
84
## Copyright (c) 2004, James Thiele
86
class Console(cmd.Cmd):
88
def __init__(self, pc):
89
cmd.Cmd.__init__(self)
90
self.intro = "Type 'help' for a list of commands. Type 'exit' to quit."
92
disk_info = self.pc.info()
93
pc.write_protect = disk_info[8]
95
log.warning("Photo card is write protected.")
96
self.prompt = utils.bold("pcard: %s > " % self.pc.pwd())
98
## Command definitions ##
99
def do_hist(self, args):
100
"""Print a list of commands that have been entered"""
103
def do_exit(self, args):
104
"""Exits from the console"""
107
def do_quit(self, args):
108
"""Exits from the console"""
111
## Command definitions to support Cmd object functionality ##
112
def do_EOF(self, args):
113
"""Exit on system end of file character"""
114
return self.do_exit(args)
116
def do_help(self, args):
117
"""Get help on commands
118
'help' or '?' with no arguments prints a list of commands for which help is available
119
'help <command>' or '? <command>' gives help on <command>
121
## The only reason to define this method is for the help text in the doc string
122
cmd.Cmd.do_help(self, args)
124
## Override methods in Cmd object ##
126
"""Initialization before prompting user for commands.
127
Despite the claims in the Cmd documentaion, Cmd.preloop() is not a stub.
129
cmd.Cmd.preloop(self) ## sets up command completion
130
self._hist = [] ## No history yet
131
self._locals = {} ## Initialize execution namespace for user
135
"""Take care of any unfinished business.
136
Despite the claims in the Cmd documentaion, Cmd.postloop() is not a stub.
138
cmd.Cmd.postloop(self) ## Clean up command completion
141
def precmd(self, line):
142
""" This method is called after the line has been input but before
143
it has been interpreted. If you want to modifdy the input line
144
before execution (for example, variable substitution) do it here.
146
self._hist += [line.strip()]
149
def postcmd(self, stop, line):
150
"""If you want to stop the console, return something that evaluates to true.
151
If you want to do some post command processing, do it here.
156
"""Do nothing on empty input line"""
159
def default(self, line):
160
print utils.bold("ERROR: Unrecognized command. Use 'help' to list commands.")
162
def do_ldir(self, args):
163
""" List local directory contents."""
166
def do_lls(self, args):
167
""" List local directory contents."""
170
def do_dir(self, args):
171
"""Synonym for the ls command."""
172
return self.do_ls(args)
174
def do_ls(self, args):
175
"""List photo card directory contents."""
176
args = args.strip().lower()
177
files = self.pc.ls(True, args)
180
formatter = utils.TextFormatter(
182
{'width': 14, 'margin' : 2},
183
{'width': 12, 'margin' : 2, 'alignment' : utils.TextFormatter.RIGHT},
184
{'width': 30, 'margin' : 2},
189
print utils.bold(formatter.compose(("Name", "Size", "Type")))
192
for d in self.pc.current_directories():
193
if d[0] in ('.', '..'):
194
print formatter.compose((d[0], "", "directory"))
196
print formatter.compose((d[0] + "/", "", "directory"))
198
for f in self.pc.current_files():
199
print formatter.compose((f[0], utils.format_bytes(f[2]), self.pc.classify_file(f[0])))
203
print utils.bold("% d files, %s" % (num_files, utils.format_bytes(total_size, True)))
206
def do_df(self, args):
207
"""Display free space on photo card.
209
-h\tDisplay in human readable format
211
freespace = self.pc.df()
213
if args.strip().lower() == '-h':
214
fs = utils.format_bytes(freespace)
216
fs = utils.commafy(freespace)
218
print "Freespace = %s Bytes" % fs
221
def do_cp(self, args, remove_after_copy=False):
222
"""Copy files from photo card to current local directory.
224
\tcp FILENAME(S)|GLOB PATTERN(S)
226
\tCopy all JPEG and GIF files and a file named thumbs.db from photo card to local directory:
227
\tcp *.jpg *.gif thumbs.db
229
args = args.strip().lower()
231
matched_files = self.pc.match_files(args)
233
if len(matched_files) == 0:
234
print "ERROR: File(s) not found."
236
total, delta = self.pc.cp_multiple(matched_files, remove_after_copy, self.cp_status_callback, self.rm_status_callback)
238
print utils.bold("\n%s transfered in %d sec (%d KB/sec)" % (utils.format_bytes(total), delta, (total/1024)/(delta)))
240
def do_unload(self, args):
241
"""Unload all image files from photocard to current local directory.
243
\tSubdirectories on photo card are not preserved
245
-x\tDon't remove files after copy
246
-p\tPrint unload list but do not copy or remove files"""
247
args = args.lower().strip().split()
250
if self.pc.write_protect:
251
log.error("Photo card is write protected. -x not allowed.")
257
unload_list = self.pc.get_unload_list()
260
if len(unload_list) > 0:
264
for u in unload_list:
265
max_len = max(max_len, len(u[0]))
267
formatter = utils.TextFormatter(
269
{'width': max_len+2, 'margin' : 2},
270
{'width': 12, 'margin' : 2, 'alignment' : utils.TextFormatter.RIGHT},
271
{'width': 12, 'margin' : 2},
276
print utils.bold(formatter.compose(("Name", "Size", "Type")))
279
for u in unload_list:
280
print formatter.compose(('%s' % u[0], utils.format_bytes(u[1]), '%s/%s' % (u[2], u[3])))
284
print utils.bold("Found %d files to unload, %s" % (len(unload_list), utils.format_bytes(total, True)))
286
print utils.bold("Unloading %d files..." % len(unload_list))
287
total, delta, was_cancelled = self.pc.unload(unload_list, self.cp_status_callback, self.rm_status_callback, dont_remove)
288
print utils.bold("\n%s unloaded in %d sec (%d KB/sec)" % (utils.format_bytes(total), delta, (total/1024)/delta))
291
print "No image, audio, or video files found."
294
def cp_status_callback(self, src, trg, size):
297
print utils.bold("Copying %s..." % src)
299
print "\nCopied %s to %s (%s)..." % (src, trg, utils.format_bytes(size))
301
def rm_status_callback(self, src):
302
print "Removing %s..." % src
306
def do_rm(self, args):
307
"""Remove files from photo card."""
308
if self.pc.write_protect:
309
log.error("Photo card is write protected. rm not allowed.")
312
args = args.strip().lower()
314
matched_files = self.pc.match_files(args)
316
if len(matched_files) == 0:
317
print "ERROR: File(s) not found."
319
for f in matched_files:
324
def do_mv(self, args):
325
"""Move files off photocard"""
326
if self.pc.write_protect:
327
log.error("Photo card is write protected. mv not allowed.")
329
self.do_cp(args, True)
331
def do_lpwd(self, args):
332
"""Print name of local current/working directory."""
335
def do_lcd(self, args):
336
"""Change current local working directory."""
338
os.chdir(args.strip())
340
print utils.bold("ERROR: Directory not found.")
343
def do_pwd(self, args):
344
"""Print name of photo card current/working directory
349
def do_cd(self, args):
350
"""Change current working directory on photo card.
352
\tYou may only specify one directory level at a time.
356
args = args.lower().strip()
359
if self.pc.pwd() != '/':
369
matched_dirs = self.pc.match_dirs(args)
371
if len(matched_dirs) == 0:
372
print "Directory not found"
374
elif len(matched_dirs) > 1:
375
print "Pattern matches more than one directory"
378
self.pc.cd(matched_dirs[0])
380
self.prompt = utils.bold("pcard: %s > " % self.pc.pwd())
382
def do_cdup(self, args):
383
"""Change to parent directory."""
386
#def complete_cd( self, text, line, begidx, endidx ):
387
# print text, line, begidx, endidx
390
def do_cache(self, args):
391
"""Display current cache entries, or turn cache on/off.
395
\tTurn off: cache off
397
args = args.strip().lower()
400
self.pc.cache_control(True)
403
self.pc.cache_control(False)
406
if self.pc.cache_state():
407
cache_info = self.pc.cache_info()
409
t = cache_info.keys()
413
print "sector %d (%d hits)" % (s, cache_info[s])
415
print utils.bold("Total cache usage: %s (%s maximum)" % (utils.format_bytes(len(t)*512), utils.format_bytes(photocard.MAX_CACHE * 512)))
416
print utils.bold("Total cache sectors: %s of %s" % (utils.commafy(len(t)), utils.commafy(photocard.MAX_CACHE)))
418
print "Cache is off."
420
def do_sector(self, args):
421
"""Display sector data.
423
\tsector <sector num>
425
args = args.strip().lower()
430
print "Sector must be specified as a number"
433
if self.pc.cache_check(sector) > 0:
434
print "Cached sector"
436
print repr(self.pc.sector(sector))
439
def do_tree(self, args):
440
"""Display photo card directory tree."""
441
tree = self.pc.tree()
443
self.print_tree(tree)
445
def print_tree(self, tree, level=0):
447
if type(tree[d]) == type({}):
448
print ''.join([' '*level*4, d, '/'])
449
self.print_tree(tree[d], level+1)
452
def do_reset(self, args):
453
"""Reset the cache."""
454
self.pc.cache_reset()
457
def do_card(self, args):
458
"""Print info about photocard."""
460
print "Device URI = %s" % self.pc.device.device_uri
461
print "Model = %s" % self.pc.device.model_ui
462
print "Working dir = %s" % self.pc.pwd()
463
disk_info = self.pc.info()
464
print "OEM ID = %s" % disk_info[0]
465
print "Bytes/sector = %d" % disk_info[1]
466
print "Sectors/cluster = %d" % disk_info[2]
467
print "Reserved sectors = %d" % disk_info[3]
468
print "Root entries = %d" % disk_info[4]
469
print "Sectors/FAT = %d" % disk_info[5]
470
print "Volume label = %s" % disk_info[6]
471
print "System ID = %s" % disk_info[7]
472
print "Write protected = %d" % disk_info[8]
473
print "Cached sectors = %s" % utils.commafy(len(self.pc.cache_info()))
476
def do_display(self, args):
477
"""Display an image with ImageMagick.
479
\tdisplay <filename>"""
480
args = args.strip().lower()
481
matched_files = self.pc.match_files(args)
483
if len(matched_files) == 1:
485
typ = self.pc.classify_file(args).split('/')[0]
488
fd, temp_name = utils.make_temp_file()
489
self.pc.cp(args, temp_name)
490
os.system('display %s' % temp_name)
494
print "File is not an image."
496
elif len(matched_files) == 0:
497
print "File not found."
500
print "Only one file at a time may be specified for display."
502
def do_show(self, args):
503
"""Synonym for the display command."""
504
self.do_display(args)
506
def do_thumbnail(self, args):
507
"""Display an embedded thumbnail image with ImageMagick.
509
\tOnly works with JPEG/JFIF images with embedded JPEG/TIFF thumbnails
511
\tthumbnail <filename>"""
512
args = args.strip().lower()
513
matched_files = self.pc.match_files(args)
515
if len(matched_files) == 1:
516
typ, subtyp = self.pc.classify_file(args).split('/')
517
#print "'%s' '%s'" % (typ, subtyp)
519
if typ == 'image' and subtyp in ('jpeg', 'tiff'):
520
exif_info = self.pc.get_exif(args)
522
dir_name, file_name=os.path.split(args)
523
photo_name, photo_ext=os.path.splitext(args)
525
if 'JPEGThumbnail' in exif_info:
526
#print "JPEG thumbnail found."
527
temp_file_fd, temp_file_name = utils.make_temp_file()
528
#thumb_name = os.path.join( os.getcwd(), photo_name ) + '_thumb.jpg'
529
open(temp_file_name, 'wb').write(exif_info['JPEGThumbnail'])
530
os.system('display %s' % temp_file_name)
531
os.remove(temp_file_name)
533
elif 'TIFFThumbnail' in exif_info:
534
#print "TIFF thumbnail found."
535
#thumb_name = os.path.join( os.getcwd(), photo_name ) + '_thumb.tif'
536
temp_file_fd, temp_file_name = utils.make_temp_file()
537
open(temp_file_name, 'wb').write(exif_info['TIFFThumbnail'])
538
os.system('display %s' % temp_file_name)
539
os.remove(temp_file_name)
542
print "No thumbnail found."
545
print "Incorrect file type for thumbnail."
547
elif len(matched_files) == 0:
548
print "File not found."
550
print "Only one file at a time may be specified for thumbnail display."
552
def do_thumb(self, args):
553
"""Synonym for the thumbnail command."""
554
self.do_thumbnail(args)
556
def do_exif(self, args):
557
"""Display EXIF info for file.
560
args = args.strip().lower()
561
matched_files = self.pc.match_files(args)
563
if len(matched_files) == 1:
564
typ, subtyp = self.pc.classify_file(args).split('/')
565
#print "'%s' '%s'" % (typ, subtyp)
567
if typ == 'image' and subtyp in ('jpeg', 'tiff'):
568
exif_info = self.pc.get_exif(args)
570
formatter = utils.TextFormatter(
572
{'width': 40, 'margin' : 2},
573
{'width': 40, 'margin' : 2},
578
print utils.bold(formatter.compose(("Tag", "Value")))
580
ee = exif_info.keys()
583
if e not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename'):
584
#if e != 'EXIF MakerNote':
585
print formatter.compose((e, '%s' % exif_info[e]))
587
# print formatter.compose( ( e, ''.join( [ chr(x) for x in exif_info[e].values if chr(x) in string.printable ] ) ) )
589
print "Incorrect file type for thumbnail."
591
elif len(matched_files) == 0:
592
print "File not found."
594
print "Only one file at a time may be specified for thumbnail display."
596
def do_info(self, args):
597
"""Synonym for the exif command."""
600
def do_about(self, args):
601
utils.log_title(__title__, __version__)
604
def status_callback(src, trg, size):
607
print utils.bold("Copying %s..." % src)
609
print "\nCopied %s to %s (%s)..." % (src, trg, utils.format_bytes(size))
77
opts, args = getopt.getopt(sys.argv[1:],
81
'help', 'help-rest', 'help-man',
614
opts, args = getopt.getopt(sys.argv[1:], 'p:d:hb:l:giuno:',
615
['printer=', 'device=', 'help', 'help-rest', 'help-man',
616
'bus=', 'logging=', 'interactive', 'gui', 'non-interactive',
86
618
except getopt.GetoptError:
89
if os.getenv("HPLIP_DEBUG"):
90
log.set_level('debug')
92
621
printer_name = None
94
623
bus = device.DEFAULT_PROBE_BUS
95
624
log_level = logger.DEFAULT_LOG_LEVEL
626
mode_specified = False
627
output_dir = os.getcwd()
629
if os.getenv("HPLIP_DEBUG"):
630
log.set_level('debug')
100
633
if o in ('-h', '--help'):
103
636
elif o == '--help-rest':
106
639
elif o == '--help-man':
109
642
elif o in ('-p', '--printer'):
110
if a.startswith('*'):
111
printer_name = cups.getDefault()
115
645
elif o in ('-d', '--device'):
129
659
log.set_level('debug')
661
elif o in ('-i', '--interactive'):
663
log.error("You may only specify a single mode as a parameter (-i, -n or -u).")
666
mode = INTERACTIVE_MODE
667
mode_specified = True
669
elif o in ('-u', '--gui'):
671
log.error("You may only specify a single mode as a parameter (-i, -n or -u).")
675
mode_specified = True
677
elif o in ('-n', '--non-interactive'):
679
log.error("You may only specify a single mode as a parameter (-i, -n or -u).")
682
mode = NON_INTERACTIVE_MODE
683
mode_specified = True
685
elif o in ('-o', '--output'):
132
689
utils.log_title(__title__, __version__)
692
if not os.getenv('DISPLAY'):
693
mode = INTERACTIVE_MODE
694
elif not utils.checkPyQtImport():
695
mode = INTERACTIVE_MODE
697
if mode in (INTERACTIVE_MODE, NON_INTERACTIVE_MODE):
698
if device_uri and printer_name:
699
log.error("You may not specify both a printer (-p) and a device (-d).")
704
printer_list = cups.getPrinters()
706
for p in printer_list:
707
if p.name == printer_name:
711
log.error("Unknown printer name: %s" % printer_name)
715
if not device_uri and not printer_name:
717
device_uri = device.getInteractiveDeviceURI(bus, 'pcard')
718
if device_uri is None:
721
log.error("Error occured during interactive mode. Exiting.")
725
pc = photocard.PhotoCard( None, device_uri, printer_name )
727
log.error("Unable to start photocard session: %s" % e.msg)
730
pc.set_callback(update_spinner)
732
if pc.device.device_uri is None and printer_name:
733
log.error("Printer '%s' not found." % printer_name)
736
if pc.device.device_uri is None and device_uri:
737
log.error("Malformed/invalid device-uri: %s" % device_uri)
740
pc.device.sendEvent(EVENT_START_PCARD_JOB)
745
log.error("Unable to mount photo card on device. Check that device is powered on and photo card is correctly inserted.")
747
pc.device.sendEvent(EVENT_PCARD_UNABLE_TO_MOUNT, typ='error')
750
log.info(utils.bold("\nPhotocard on device %s mounted" % pc.device.device_uri))
751
log.info(utils.bold("DO NOT REMOVE PHOTO CARD UNTIL YOU EXIT THIS PROGRAM"))
753
output_dir = os.path.realpath(os.path.normpath(os.path.expanduser(output_dir)))
758
print utils.bold("ERROR: Output directory %s not found." % output_dir)
763
if mode == INTERACTIVE_MODE: # INTERACTIVE_MODE
765
console = Console(pc)
769
except KeyboardInterrupt:
770
log.error("Aborted.")
772
log.error("An error occured: %s" % e)
776
pc.device.sendEvent(EVENT_END_PCARD_JOB)
779
else: # NON_INTERACTIVE_MODE
780
print "Output directory is %s" % os.getcwd()
783
unload_list = pc.get_unload_list()
786
if len(unload_list) > 0:
789
for u in unload_list:
790
max_len = max(max_len, len(u[0]))
792
formatter = utils.TextFormatter(
794
{'width': max_len+2, 'margin' : 2},
795
{'width': 12, 'margin' : 2, 'alignment' : utils.TextFormatter.RIGHT},
796
{'width': 12, 'margin' : 2},
801
print utils.bold(formatter.compose(("Name", "Size", "Type")))
804
for u in unload_list:
805
print formatter.compose(('%s' % u[0], utils.format_bytes(u[1]), '%s/%s' % (u[2], u[3])))
809
print utils.bold("Found %d files to unload, %s\n" % (len(unload_list), utils.format_bytes(total, True)))
810
print utils.bold("Unloading files...\n")
811
total, delta, was_cancelled = pc.unload(unload_list, status_callback, None, True)
812
print utils.bold("\n%s unloaded in %d sec (%d KB/sec)" % (utils.format_bytes(total), delta, (total/1024)/delta))
814
except KeyboardInterrupt:
815
log.error("Aborted.")
825
from ui import unloadform
137
827
a = QApplication(sys.argv)
138
828
QObject.connect(a,SIGNAL("lastWindowClosed()"),a,SLOT("quit()"))
140
if use_qt_splashscreen:
141
pixmap = QPixmap(os.path.join(prop.image_dir, "hp-tux-printer.png"))
142
splash = QSplashScreen(pixmap)
143
splash.message(__tr("Loading..."), Qt.AlignBottom)
147
831
w = unloadform.UnloadForm(bus, device_uri, printer_name)