home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / hplip / ui / unloadform.py < prev    next >
Encoding:
Python Source  |  2006-08-30  |  18.1 KB  |  546 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. # (c) Copyright 2001-2006 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.  
  23. from base.g import *
  24. from base import utils, device, msg
  25. from prnt import cups
  26. from pcard import photocard
  27.  
  28. import sys
  29. import os, os.path
  30. import socket
  31.  
  32. from qt import *
  33.  
  34.  
  35. from unloadform_base import UnloadForm_base
  36. from imagepropertiesdlg import ImagePropertiesDlg
  37.  
  38. progress_dlg = None
  39.  
  40. class IconViewItem(QIconViewItem):
  41.     def __init__(self, parent, dirname, fname, path, pixmap, mime_type, mime_subtype, size, exif_info={}):
  42.         QIconViewItem.__init__(self, parent, fname, pixmap)
  43.         self.mime_type = mime_type
  44.         self.mime_subtype = mime_subtype
  45.         self.path = path
  46.         self.dirname = dirname
  47.         self.filename = fname
  48.         self.exif_info = exif_info
  49.         self.size = size
  50.         self.thumbnail_set = False
  51.  
  52.  
  53.  
  54. class UnloadForm(UnloadForm_base):
  55.     def __init__(self, bus='usb,par', device_uri=None, printer_name=None,
  56.                  parent=None, name=None, fl=0):
  57.  
  58.         UnloadForm_base.__init__(self,parent,name,fl)
  59.         self.pc = None
  60.         self.device_uri = device_uri
  61.         self.printer_name = printer_name
  62.         self.init_failed = False
  63.  
  64.         if self.device_uri and self.printer_name:
  65.             log.error("You may not specify both a printer (-p) and a device (-d).")
  66.             self.device_uri, self.printer_name = None, None
  67.  
  68.         if not self.device_uri and not self.printer_name:
  69.             probed_devices = device.probeDevices(bus=bus, filter='pcard')
  70.             cups_printers = cups.getPrinters()
  71.             log.debug(probed_devices)
  72.             log.debug(cups_printers)
  73.             max_deviceid_size, x, devices = 0, 0, {}
  74.  
  75.             for d in probed_devices:
  76.                 if d.startswith('hp:'):
  77.                     printers = []
  78.                     for p in cups_printers:
  79.                         if p.device_uri == d:
  80.                             printers.append(p.name)
  81.                     devices[x] = (d, printers)
  82.                     x += 1
  83.                     max_deviceid_size = max(len(d), max_deviceid_size)
  84.  
  85.             if x == 0:
  86.                 from nodevicesform import NoDevicesForm
  87.                 self.failure(self.__tr("<p><b>No devices found that support photo card access.</b><p>Please make sure your device is properly installed and try again."))
  88.                 self.init_failed = True
  89.  
  90.             elif x == 1:
  91.                 log.info(utils.bold("Using device: %s" % devices[0][0]))
  92.                 self.device_uri = devices[0][0]
  93.  
  94.             else:
  95.                 from choosedevicedlg import ChooseDeviceDlg
  96.                 dlg = ChooseDeviceDlg(devices)
  97.                 if dlg.exec_loop() == QDialog.Accepted:
  98.                     self.device_uri = dlg.device_uri
  99.                 else:
  100.                     self.init_failed = True
  101.  
  102.         QTimer.singleShot(0, self.initialUpdate)
  103.  
  104.  
  105.     def initialUpdate(self):
  106.         if self.init_failed:
  107.             self.cleanup(EVENT_PCARD_UNABLE_TO_MOUNT)
  108.             return
  109.  
  110.         QApplication.setOverrideCursor(QApplication.waitCursor)
  111.         
  112.         try:
  113.             self.pc = photocard.PhotoCard(None, self.device_uri, self.printer_name)
  114.         except Error, e:
  115.             log.error("An error occured: %s" % e[0])
  116.             self.failure(self.__tr("<p><b>Unable to mount photocard.</b><p>Could not connect to device."))
  117.             self.cleanup(EVENT_PCARD_UNABLE_TO_MOUNT)
  118.             return
  119.  
  120.         if self.pc.device.device_uri is None and self.printer_name:
  121.             log.error("Printer '%s' not found." % self.printer_name)
  122.             self.failure(self.__tr("<p><b>Unable to mount photocard.</b><p>Device not found."))
  123.             self.cleanup(EVENT_PCARD_JOB_FAIL)
  124.             return
  125.  
  126.         if self.pc.device.device_uri is None and self.device_uri:
  127.             log.error("Malformed/invalid device-uri: %s" % self.device_uri)
  128.             self.failure(self.__tr("<p><b>Unable to mount photocard.</b><p>Malformed/invalid device-uri."))
  129.             self.cleanup(EVENT_PCARD_JOB_FAIL)
  130.             return
  131.  
  132.         try:
  133.             self.pc.mount()
  134.         except Error:
  135.             log.error("Unable to mount photo card on device. Check that device is powered on and photo card is correctly inserted.")
  136.             self.failure(self.__tr("<p><b>Unable to mount photocard.</b><p>Check that device is powered on and photo card is correctly inserted."))
  137.             self.pc.umount()
  138.             self.cleanup(EVENT_PCARD_UNABLE_TO_MOUNT)
  139.             return
  140.  
  141.         self.pc.device.sendEvent(EVENT_START_PCARD_JOB)
  142.  
  143.         disk_info = self.pc.info()
  144.         self.pc.write_protect = disk_info[8]
  145.  
  146.         if self.pc.write_protect:
  147.             log.warning("Photo card is write protected.")
  148.  
  149.         log.info("Photocard on device %s mounted" % self.pc.device_uri)
  150.  
  151.         if not self.pc.write_protect:
  152.             log.info("DO NOT REMOVE PHOTO CARD UNTIL YOU EXIT THIS PROGRAM")
  153.  
  154.         self.unload_dir = os.path.normpath(os.path.expanduser('~'))
  155.         os.chdir(self.unload_dir)
  156.         self.UnloadDirectoryEdit.setText(self.unload_dir)
  157.  
  158.         self.unload_list = self.pc.get_unload_list()
  159.         self.DeviceText.setText(self.pc.device.device_uri)
  160.  
  161.         self.image_icon_map = {'tiff' : 'tif.png',
  162.                                 'bmp'  : 'bmp.png',
  163.                                 'jpeg' : 'jpg.png',
  164.                                 'gif'  : 'gif.png',
  165.                                 'unknown' : 'unknown.png',
  166.                                 }
  167.         self.video_icon_map = {'unknown' : 'movie.png',
  168.                                 'mpeg'    : 'mpg.png',
  169.                                 }
  170.  
  171.         self.total_number = 0
  172.         self.total_size = 0
  173.  
  174.         self.removal_option = 0
  175.  
  176.         self.UpdateStatusBar()
  177.  
  178.         if self.pc.write_protect:
  179.             self.FileRemovalGroup.setEnabled(False)
  180.             self.LeaveAllRadio.setEnabled(False)
  181.             self.RemoveSelectedRadio.setEnabled(False)
  182.             self.RemoveAllRadio.setEnabled(False)
  183.  
  184.         # Item map disambiguates between files of the same
  185.         # name that are on the pcard in more than one location
  186.         self.item_map = {}
  187.         
  188.         QApplication.restoreOverrideCursor()
  189.  
  190.         self.load_icon_view(first_load=True)
  191.  
  192.     def closeEvent(self, event):
  193.         if self.pc is not None:
  194.             self.pc.device.sendEvent(EVENT_END_PCARD_JOB)
  195.  
  196.         event.accept()
  197.  
  198.  
  199.     def CancelButton_clicked(self):
  200.         self.cleanup()
  201.  
  202.  
  203.     def cleanup(self, error=0):
  204.         if self.pc is not None:
  205.             if error > 0:
  206.                 self.pc.device.sendEvent(error, typ='error')
  207.  
  208.         self.close()
  209.  
  210.  
  211.     def success(self):
  212.         QMessageBox.information(self,
  213.                              self.caption(),
  214.                              self.__tr("<p><b>The operation completed successfully.</b>"),
  215.                               QMessageBox.Ok,
  216.                               QMessageBox.NoButton,
  217.                               QMessageBox.NoButton)
  218.  
  219.     def failure(self, error_text):
  220.         QMessageBox.critical(self,
  221.                              self.caption(),
  222.                              error_text,
  223.                               QMessageBox.Ok,
  224.                               QMessageBox.NoButton,
  225.                               QMessageBox.NoButton)
  226.  
  227.  
  228.     def load_icon_view(self, first_load):
  229.         QApplication.setOverrideCursor(QApplication.waitCursor)
  230.         self.first_load = first_load
  231.  
  232.         if first_load:
  233.             self.IconView.clear()
  234.  
  235.         self.num_items = len(self.unload_list)
  236.  
  237.         self.pb = QProgressBar()
  238.         self.pb.setTotalSteps(self.num_items)
  239.         self.statusBar().addWidget(self.pb)
  240.         self.pb.show()
  241.  
  242.         self.item_num = 0
  243.         
  244.         self.load_timer = QTimer(self, "ScanTimer")
  245.         self.connect(self.load_timer, SIGNAL('timeout()'), self.continue_load_icon_view)
  246.         self.load_timer.start(0)
  247.  
  248.     def continue_load_icon_view(self):
  249.  
  250.         if self.item_num == self.num_items:
  251.             self.load_timer.stop()
  252.             self.disconnect(self.load_timer, SIGNAL('timeout()'), self.continue_load_icon_view)
  253.             self.load_timer = None
  254.             del self.load_timer
  255.  
  256.             self.pb.hide()
  257.             self.statusBar().removeWidget(self.pb)
  258.  
  259.             self.IconView.adjustItems()
  260.             QApplication.restoreOverrideCursor()
  261.             return
  262.  
  263.         f = self.unload_list[self.item_num]
  264.  
  265.         self.item_num += 1
  266.         path, size = f[0], f[1]
  267.  
  268.         self.pb.setProgress(self.item_num)
  269.  
  270.         typ, subtyp = self.pc.classify_file(path).split('/')
  271.  
  272.         if not self.first_load and typ == 'image' and subtyp == 'jpeg':
  273.  
  274.             exif_info = self.pc.get_exif_path(path)
  275.  
  276.             if len(exif_info) > 0:
  277.  
  278.                 if 'JPEGThumbnail' in exif_info:
  279.                     pixmap = QPixmap()
  280.                     pixmap.loadFromData(exif_info['JPEGThumbnail'], "JPEG")
  281.  
  282.                     self.resizePixmap(pixmap)
  283.  
  284.                     del exif_info['JPEGThumbnail']
  285.                     dname, fname=os.path.split(path)
  286.                     x = self.item_map[fname]
  287.  
  288.                     if len(x) == 1:
  289.                         item = self.IconView.findItem(fname, 0)
  290.                     else:
  291.                         i = x.index(path)
  292.                         if i == 0:
  293.                             item = self.IconView.findItem(fname, 0)
  294.                         else:
  295.                             item = self.IconView.findItem(fname + " (%d)" % (i+1), 0)
  296.  
  297.                     if item is not None:
  298.                         item.setPixmap(pixmap)
  299.                         item.thumbnail_set = True
  300.  
  301.                     return
  302.  
  303.                 #elif 'TIFFThumbnail' in exif_info:
  304.                     # can't handle TIFF in Qt?
  305.                 #    del exif_info['TIFFThumbnail']
  306.                 #    if first_load:
  307.                 #        IconViewItem( self.IconView, filename,
  308.                 #                      QPixmap( os.path.join( prop.image_dir, 'tif.png' ) ),
  309.                 #                      typ, subtyp, size, exif_info )
  310.                 #    else:
  311.                 #        pass
  312.  
  313.                 #    continue
  314.  
  315.  
  316.         elif self.first_load:
  317.             if typ == 'image':
  318.                 f = os.path.join(prop.image_dir, self.image_icon_map.get(subtyp, 'unknown.png'))
  319.             elif typ == 'video':
  320.                 f = os.path.join(prop.image_dir, self.video_icon_map.get(subtyp, 'movie.png'))
  321.             elif typ == 'audio':
  322.                 f = os.path.join(prop.image_dir, 'sound.png')
  323.             else:
  324.                 f = os.path.join(prop.image_dir, 'unknown.png')
  325.  
  326.             dirname, fname=os.path.split(path)
  327.             num = 1
  328.             try:
  329.                 self.item_map[fname]
  330.             except:
  331.                 self.item_map[fname] = [path]
  332.             else:
  333.                 self.item_map[fname].append(path)
  334.                 num = len(self.item_map[fname])
  335.  
  336.             if num == 1:
  337.                 IconViewItem(self.IconView, dirname, fname, path, QPixmap(f),
  338.                               typ, subtyp, size)
  339.             else:
  340.                 IconViewItem(self.IconView, dirname, fname + " (%d)" % num,
  341.                               path, QPixmap(f), typ, subtyp, size)
  342.  
  343.  
  344.     def resizePixmap(self, pixmap):
  345.         w, h = pixmap.width(), pixmap.height()
  346.  
  347.         if h > 128 or w > 128:
  348.             ww, hh = w - 128, h - 128
  349.             if ww >= hh:
  350.                 pixmap.resize(128, int(float((w-ww))/w*h))
  351.             else:
  352.                 pixmap.resize(int(float((h-hh))/h*w), 128)
  353.  
  354.  
  355.  
  356.     def UpdateStatusBar(self):
  357.         if self.total_number == 0:
  358.             self.statusBar().message(self.__tr("No files selected"))
  359.         elif self.total_number == 1:
  360.             self.statusBar().message(self.__tr("1 file selected, %s" % utils.format_bytes(self.total_size, True)))
  361.         else:
  362.             self.statusBar().message(self.__tr("%d files selected, %s" % (self.total_number, utils.format_bytes(self.total_size, True))))
  363.  
  364.     def SelectAllButton_clicked(self):
  365.         self.IconView.selectAll(1)
  366.  
  367.     def SelectNoneButton_clicked(self):
  368.         self.IconView.selectAll(0)
  369.  
  370.     def IconView_doubleClicked(self, a0):
  371.         #self.Display( a0 )
  372.         pass
  373.  
  374.     def UnloadDirectoryBrowseButton_clicked(self):
  375.         old_dir = self.unload_dir
  376.         self.unload_dir = str(QFileDialog.getExistingDirectory(self.unload_dir, self))
  377.  
  378.         if not len(self.unload_dir):
  379.             return
  380.         elif not utils.is_path_writable(self.unload_dir):
  381.             self.failure(self.__tr("<p><b>The unload directory path you entered is not valid.</b><p>The directory must exist and you must have write permissions."))
  382.             self.unload_dir = old_dir
  383.         else:
  384.             self.UnloadDirectoryEdit.setText(self.unload_dir)
  385.             os.chdir(self.unload_dir)
  386.  
  387.     def UnloadButton_clicked(self):
  388.         was_cancelled = False
  389.         self.unload_dir = str(self.UnloadDirectoryEdit.text())
  390.         dir_error = False
  391.  
  392.         try:
  393.             os.chdir(self.unload_dir)
  394.         except OSError:
  395.             log.error("Directory not found: %s" % self.unload_dir)
  396.             dir_error = True
  397.  
  398.         if dir_error or not utils.is_path_writable(self.unload_dir):
  399.             self.failure(self.__tr("<p><b>The unload directory path is not valid.</b><p>Please enter a new path and try again."))
  400.             return
  401.  
  402.         unload_list = []
  403.         i = self.IconView.firstItem()
  404.         total_size = 0
  405.         while i is not None:
  406.  
  407.             if i.isSelected():
  408.                 unload_list.append((i.path, i.size, i.mime_type, i.mime_subtype))
  409.                 total_size += i.size
  410.             i = i.nextItem()
  411.  
  412.         if total_size == 0:
  413.             self.failure(self.__tr("<p><b>No files are selected to unload.</b><p>Please select one or more files to unload and try again."))
  414.             return
  415.  
  416.         global progress_dlg
  417.         progress_dlg = QProgressDialog(self.__tr("Unloading Files..."), self.__tr("Cancel"),
  418.                                        total_size, self, 'progress', True)
  419.         progress_dlg.setMinimumDuration(0)
  420.         progress_dlg.show()
  421.  
  422.         if self.removal_option == 0:
  423.             total_size, total_time, was_cancelled = \
  424.                 self.pc.unload(unload_list, self.UpdateUnloadProgressDlg, None, True)
  425.  
  426.         elif self.removal_option == 1: # remove selected
  427.             total_size, total_time, was_cancelled = \
  428.                 self.pc.unload(unload_list, self.UpdateUnloadProgressDlg, None, False)
  429.  
  430.         else: # remove all
  431.             total_size, total_time, was_cancelled = \
  432.                 self.pc.unload(unload_list, self.UpdateUnloadProgressDlg, None, False)
  433.             # TODO: Remove remainder of files
  434.  
  435.         progress_dlg.close()
  436.  
  437.         self.pc.device.sendEvent(EVENT_PCARD_FILES_TRANSFERED)
  438.  
  439.         if was_cancelled:
  440.             self.failure(self.__tr("<b>Unload cancelled at user request.</b>"))
  441.         else:
  442.             self.success()
  443.  
  444.  
  445.     def UpdateUnloadProgressDlg(self, src, trg, size):
  446.         global progress_dlg
  447.         progress_dlg.setProgress(progress_dlg.progress() + size)
  448.         progress_dlg.setLabelText(src)
  449.         qApp.processEvents()
  450.  
  451.         return progress_dlg.wasCancelled()
  452.  
  453.     def IconView_rightButtonClicked(self, item, pos):
  454.         popup = QPopupMenu(self)
  455.         popup.insertItem("Properties", self.PopupProperties)
  456.  
  457.         if item is not None and \
  458.             item.mime_type == 'image' and \
  459.             item.mime_subtype == 'jpeg' and \
  460.             not item.thumbnail_set:
  461.  
  462.             popup.insertItem("Show Thumbnail", self.showThumbNail)
  463.         popup.popup(pos)
  464.  
  465.  
  466.     def PopupDisplay(self):
  467.         self.Display(self.IconView.currentItem())
  468.  
  469.     def PopupProperties(self):
  470.         self.Properties(self.IconView.currentItem())
  471.  
  472.     def showThumbNail(self):
  473.         item = self.IconView.currentItem()
  474.         exif_info = self.pc.get_exif_path(item.path)
  475.  
  476.         if len(exif_info) > 0:
  477.             if 'JPEGThumbnail' in exif_info:
  478.                 pixmap = QPixmap()
  479.                 pixmap.loadFromData(exif_info['JPEGThumbnail'], "JPEG")
  480.                 self.resizePixmap(pixmap)
  481.                 del exif_info['JPEGThumbnail']
  482.                 item.setPixmap(pixmap)
  483.  
  484.                 self.IconView.adjustItems()
  485.  
  486.         else:
  487.             self.failure(self.__tr("<p><b>No thumbnail found in image.</b>"))
  488.  
  489.         item.thumbnail_set = True
  490.  
  491.     def Display(self, item):
  492.         pass
  493.         # cp over file (does this even make sense to do this at this point?)
  494.         # display with imagemagick?
  495.  
  496.     def Properties(self, item):
  497.         if item is not None:
  498.             if not item.exif_info:
  499.                 item.exif_info = self.pc.get_exif_path(item.path)
  500.  
  501.             ImagePropertiesDlg(item.filename, item.dirname,
  502.                                 '/'.join([item.mime_type, item.mime_subtype]),
  503.                                 utils.format_bytes(item.size, True),
  504.                                 item.exif_info, self).exec_loop()
  505.  
  506.  
  507.  
  508.     def IconView_selectionChanged(self):
  509.         self.total_number = 0
  510.         self.total_size = 0
  511.         i = self.IconView.firstItem()
  512.  
  513.         while i is not None:
  514.  
  515.             if i.isSelected():
  516.                 self.total_number += 1
  517.                 self.total_size += i.size
  518.  
  519.             i = i.nextItem()
  520.  
  521.         self.UpdateStatusBar()
  522.  
  523.  
  524.     def IconView_clicked(self,a0,a1):
  525.         pass
  526.  
  527.     def IconView_clicked(self,a0):
  528.         pass
  529.  
  530.     def IconView_currentChanged(self,a0):
  531.         pass
  532.  
  533.     def FileRemovalGroup_clicked(self, a0):
  534.         self.removal_option = a0
  535.  
  536.     def ShowThumbnailsButton_clicked(self):
  537.         self.ShowThumbnailsButton.setEnabled(False)
  538.         self.load_icon_view(first_load=False)
  539.  
  540.  
  541.     def __tr(self,s,c = None):
  542.         return qApp.translate("UnloadForm",s,c)
  543.  
  544.  
  545.  
  546.