diff options
Diffstat (limited to 'scan.py')
-rw-r--r-- | scan.py | 120 |
1 files changed, 80 insertions, 40 deletions
@@ -64,7 +64,7 @@ class SettingsToolbar(gtk.ToolPalette): def set_scanner(self, scanner): self._scanner = scanner self._clear() - if self._scanner: + if self._scanner is not None: self._add_options() def _clear(self): @@ -286,9 +286,9 @@ class SettingsToolbar(gtk.ToolPalette): class ScanThread(threading.Thread): - def __init__(self, devs, temp_dir, callback=None): + def __init__(self, temp_dir, callback=None): threading.Thread.__init__(self) - self._devs = devs + self._device = None self._temp_dir = temp_dir self._callback = callback self._cond = threading.Condition() @@ -298,6 +298,10 @@ class ScanThread(threading.Thread): self._ready = False self._dpi = None + def set_device(self, device): + with self._cond: + self._device = device + def run(self): while True: with self._cond: @@ -323,6 +327,9 @@ class ScanThread(threading.Thread): @trace() def start_scan(self): with self._cond: + if self._device is None: + raise ValueError('No device set') + logging.debug('start_scan(): got lock') self._action = 'start' self._cond.notify() @@ -358,8 +365,8 @@ class ScanThread(threading.Thread): self._images = None self._error = None - source = getattr(self._devs[0], 'source', 'Auto') - if getattr(self._devs[0], 'batch_scan', False): + source = getattr(self._device, 'source', 'Auto') + if getattr(self._device, 'batch_scan', False): scan_multi = source in ['Auto', 'ADF'] else: scan_multi = source == 'ADF' @@ -369,8 +376,8 @@ class ScanThread(threading.Thread): self._scan_multi() else: logging.debug('starting single scan') - self._dpi = self._devs[0].resolution - self._images = [self._process_image(self._devs[0].scan())] + self._dpi = self._device.resolution + self._images = [self._process_image(self._device.scan())] except sane.error, exc: # Ouch. sane.error doesn't derive from Exception :-/ @@ -391,18 +398,18 @@ class ScanThread(threading.Thread): @trace() def _scan_multi(self): logging.debug('_scan: calling multi_scan()') - scan_iter = self._devs[0].multi_scan() + scan_iter = self._device.multi_scan() logging.debug('_scan: acquiring images') images = [] try: - self._dpi = self._devs[0].resolution + self._dpi = self._device.resolution for image in scan_iter: images.append(self._process_image(image)) if self._check_action(['stop', 'quit']): break - self._dpi = self._devs[0].resolution + self._dpi = self._device.resolution self._images = images @@ -480,8 +487,10 @@ class ScanActivity(activity.Activity): def __init__(self, handle): activity.Activity.__init__(self, handle) self.max_participants = 1 - self._scanner_name = None - self._scanners = [] + # content: (device_name, vendor, model, description) + self._scanner_infos = [] + self._current_scanner = None + self._current_scanner_name = None self._scanner_options = {'source': 'ADF'} self._status = 'init' self._msg_box_buf = None @@ -489,10 +498,12 @@ class ScanActivity(activity.Activity): self._scan_button = None self._settings_toolbar = None temp_dir = os.path.join(self.get_activity_root(), 'tmp') - self._scan_thread = ScanThread(self._scanners, temp_dir, + self._scan_thread = ScanThread(temp_dir, callback=self._scan_finished_cb) self._scan_thread.start() self._setup_widgets() + # TODO: delay opening scanner device if we're resuming a + # previous session self._init_scanner() @trace() @@ -504,47 +515,62 @@ class ScanActivity(activity.Activity): activity.Activity.destroy(self) def read_file(self, file_path): - if not self._scanners: + if not self._scanner_infos: + # no scanners available, nothing to do for now (see TODO + # item in write_file()) return globals_dict = {'__builtins__': None} settings = eval(file(file_path).read(), globals_dict) + logging.debug('old settings: %r', settings) + scanner_name = settings.pop('_scanner_name', None) + if not scanner_name: + # Saved by a previous version, just pick the first + # available scanner like the previous version did. + scanner_name = self._scanner_infos[0][0] + + if scanner_name not in [info[0] for info in self._scanner_infos]: + # The previous scanner is not available right now, pick + # another one and apply as much of the previous settings + # as we can. + scanner_name = self._scanner_infos[0][0] + + self._open_scanner(scanner_name) self._set_settings(settings) - # TODO: don't call set_scanner() twice when resuming (once in - # _init_scanner() and once here) - self._settings_toolbar.set_scanner(self._scanners[0]) + # HACK: cause the toolbar to re-read the settings after + # changing them + self._settings_toolbar.set_scanner(self._current_scanner) def write_file(self, file_path): + # TODO: retain settings for all scanners, not just the current one self.metadata['mime_type'] = 'text/plain' with file(file_path, 'w') as f: f.write(repr(self._get_settings())) @trace() def _get_settings(self): - if not self._scanners: + if self._current_scanner is None: return {} - settings = {} - scanner = self._scanners[0] - for py_name in scanner.optlist: + settings = {'_scanner_name': self._current_scanner_name} + for py_name in self._current_scanner.optlist: logging.debug('getting value for setting %r', py_name) - option = scanner[py_name] + option = self._current_scanner[py_name] if option.type in [sane.TYPE_BOOL, sane.TYPE_INT, sane.TYPE_FIXED, sane.TYPE_STRING] and option.is_active(): - settings[py_name] = getattr(scanner, py_name) + settings[py_name] = getattr(self._current_scanner, py_name) return settings @trace() def _set_settings(self, settings): - if not self._scanners: + if self._current_scanner is None: return - scanner = self._scanners[0] for name, value in settings.items(): try: - setattr(scanner, name, value) + setattr(self._current_scanner, name, value) except AttributeError: logging.info('Saved setting %r=%r not support by current' @@ -557,41 +583,55 @@ class ScanActivity(activity.Activity): @trace() def _init_scanner(self): sane.init() - scanner_devs = sane.get_devices() - if not scanner_devs: + self._scanner_infos = sane.get_devices() + if not self._scanner_infos: self._set_status('no-dev') return - self._scanner_name = scanner_devs[0][0] - self._reopen_scanner() + self._open_scanner(self._scanner_infos[0][0]) + + def _open_scanner(self, name): + """Open the current scanner device - def _reopen_scanner(self): - """Reopen scanner device to work around lower layer bugs.""" - if self._scanners: + Close the previous device if there is one, but ignore errors + while closing. Open the device identified by name. + + Can be used to open the scanner device on start-up, change the + current scanner or reopen the scanner device to work around + lower layer bugs. + """ + if self._current_scanner: + old_scanner, self._current_scanner = self._current_scanner, None try: - old_scanner = self._scanners.pop() old_scanner.close() del old_scanner except sane.error, exc: logging.exception('Error closing scanner') - if not self._scanner_name: + if not name: self._set_status('no-dev') + self._set_scanner(None, None) return try: - self._scanners.append(sane.open(self._scanner_name)) + scanner = sane.open(name) except sane.error, exc: - logging.exception('Error opening scanner %r', self._scanner_name) + logging.exception('Error opening scanner %r', name) self._show_error(exc) return - self._settings_toolbar.set_scanner(self._scanners[0]) - + self._set_scanner(scanner, name) self._set_status('ready') + @trace() + def _set_scanner(self, device, name): + self._current_scanner = device + self._current_scanner_name = name + self._scan_thread.set_device(device) + self._settings_toolbar.set_scanner(device) + def _setup_widgets(self): self._setup_toolbar() self._setup_canvas() @@ -755,7 +795,7 @@ class ScanActivity(activity.Activity): if not exc: self._set_status('ready') else: - self._reopen_scanner() + self._open_scanner(self._current_scanner_name) def _add_images(self, image_infos): for info in image_infos: |