From 1a42f0aae76b553395eb4d9b1cf9abf00bcb07e2 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sat, 15 May 2010 20:08:18 +0100 Subject: [PATCH] First iteration of folder_device. --- src/calibre/devices/folder_device/__init__.py | 10 +++ src/calibre/devices/folder_device/driver.py | 74 +++++++++++++++++++ src/calibre/devices/htc_td2/driver.py | 3 +- src/calibre/gui2/device.py | 35 +++++++++ src/calibre/gui2/ui.py | 14 ++++ 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 src/calibre/devices/folder_device/__init__.py create mode 100644 src/calibre/devices/folder_device/driver.py diff --git a/src/calibre/devices/folder_device/__init__.py b/src/calibre/devices/folder_device/__init__.py new file mode 100644 index 0000000000..3d1a86922e --- /dev/null +++ b/src/calibre/devices/folder_device/__init__.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai +from __future__ import with_statement + +__license__ = 'GPL v3' +__copyright__ = '2009, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + + + diff --git a/src/calibre/devices/folder_device/driver.py b/src/calibre/devices/folder_device/driver.py new file mode 100644 index 0000000000..700b7f3eec --- /dev/null +++ b/src/calibre/devices/folder_device/driver.py @@ -0,0 +1,74 @@ +''' +Created on 15 May 2010 + +@author: charles +''' +import os +import time + +from calibre.customize.ui import available_output_formats +from calibre.devices.usbms.driver import USBMS, BookList +from calibre.devices.interface import DevicePlugin +from calibre.devices.usbms.deviceconfig import DeviceConfig +from calibre.utils.filenames import ascii_filename as sanitize, shorten_components_to + +class FOLDER_DEVICE(USBMS): + type = _('Device Interface') + + # Ordered list of supported formats + FORMATS = ['epub', 'fb2', 'mobi', 'lrf', 'tcr', 'pmlz', 'lit', 'rtf', 'rb', 'pdf', 'oeb', 'txt', 'pdb'] + + THUMBNAIL_HEIGHT = 68 # Height for thumbnails on device + # Whether the metadata on books can be set via the GUI. + CAN_SET_METADATA = True + SUPPORTS_SUB_DIRS = True + DELETE_EXTS = [] + #: Path separator for paths to books on device + path_sep = os.sep + #: Icon for this device + icon = I('reader.svg') + METADATA_CACHE = '.metadata.calibre' + + _main_prefix = None + _card_a_prefix = None + _card_b_prefix = None + + def __init__(self, path): + self._main_prefix = path + self.booklist_class = BookList + self.is_connected = True + + @classmethod + def get_gui_name(cls): + if hasattr(cls, 'gui_name'): + return cls.gui_name + if hasattr(cls, '__name__'): + return cls.__name__ + return cls.name + + def disconnect_from_folder(self): + self.is_connected = False + + def is_usb_connected(self, devices_on_system, debug=False, + only_presence=False): + return self.is_connected, self + + def open(self): + if self._main_prefix is None: + raise NotImplementedError() + return True + + def set_progress_reporter(self, report_progress): + self.report_progress = report_progress + + def card_prefix(self, end_session=True): + return (None, None) + + def total_space(self, end_session=True): + return (1024*1024*1024, 0, 0) + + def free_space(self, end_session=True): + return (1024*1024*1024, 0, 0) + + def get_main_ebook_dir(self): + return '' diff --git a/src/calibre/devices/htc_td2/driver.py b/src/calibre/devices/htc_td2/driver.py index 9a83e32961..41eccfa0b2 100644 --- a/src/calibre/devices/htc_td2/driver.py +++ b/src/calibre/devices/htc_td2/driver.py @@ -19,7 +19,8 @@ class HTC_TD2(USBMS): VENDOR_ID = { # HTC - 0x0bb4 : { 0x0c30 : [0x000]}, +# 0x0bb4 : { 0x0c30 : [0x000]}, + 0xFbb4 : { 0x0c30 : [0x000]}, } EBOOK_DIR_MAIN = ['EBooks'] EXTRA_CUSTOMIZATION_MESSAGE = _('Comma separated list of directories to ' diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index af314c5468..048e5b0ccb 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -25,6 +25,7 @@ from calibre.utils.filenames import ascii_filename from calibre.devices.errors import FreeSpaceError from calibre.utils.smtp import compose_mail, sendmail, extract_email_address, \ config as email_config +from calibre.devices.folder_device.driver import FOLDER_DEVICE class DeviceJob(BaseJob): @@ -207,6 +208,27 @@ class DeviceManager(Thread): return self.create_job(self._get_device_information, done, description=_('Get device information')) + def connect_to_folder(self, path): + dev = FOLDER_DEVICE(path) + try: + dev.open() + except: + print 'Unable to open device', dev + traceback.print_exc() + return False + self.connected_device = dev + self.connected_slot(True) + return True + + def disconnect_folder(self): + if self.connected_device is not None: + if hasattr(self.connected_device, 'disconnect_from_folder'): + self.connected_device.disconnect_from_folder() + +# def connect_to_folder(self, path): +# return self.create_job(self._connect_to_folder, None, +# description=_('Connect to folder')) + def _books(self): '''Get metadata from device''' mainlist = self.device.books(oncard=None, end_session=False) @@ -309,6 +331,8 @@ class DeviceAction(QAction): class DeviceMenu(QMenu): fetch_annotations = pyqtSignal() + connect_to_folder = pyqtSignal() + disconnect_from_folder = pyqtSignal() def __init__(self, parent=None): QMenu.__init__(self, parent) @@ -410,6 +434,17 @@ class DeviceMenu(QMenu): annot.triggered.connect(lambda x : self.fetch_annotations.emit()) self.annotation_action = annot + + mitem = self.addAction(_('Connect to folder (experimental)')) + mitem.setEnabled(True) + mitem.triggered.connect(lambda x : self.connect_to_folder.emit()) + self.connect_to_folder_action = mitem + + mitem = self.addAction(_('Disconnect from folder (experimental)')) + mitem.setEnabled(False) + mitem.triggered.connect(lambda x : self.disconnect_from_folder.emit()) + self.disconnect_from_folder_action = mitem + self.enable_device_actions(False) def change_default_action(self, action): diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index ba6bac76e4..8cd89bd397 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -666,6 +666,18 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): MainWindow.resizeEvent(self, ev) self.search.setMaximumWidth(self.width()-150) + def connect_to_folder(self): + dir = choose_dir(self, 'Select Device Folder', 'Select folder to open') + if dir is not None: + print dir + self.device_manager.connect_to_folder(dir) + self._sync_menu.connect_to_folder_action.setEnabled(False) + self._sync_menu.disconnect_from_folder_action.setEnabled(True) + + def disconnect_from_folder(self): + self.device_manager.disconnect_folder() + self._sync_menu.connect_to_folder_action.setEnabled(True) + self._sync_menu.disconnect_from_folder_action.setEnabled(False) def create_device_menu(self): self._sync_menu = DeviceMenu(self) @@ -676,6 +688,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.connect(self.action_sync, SIGNAL('triggered(bool)'), self._sync_menu.trigger_default) self._sync_menu.fetch_annotations.connect(self.fetch_annotations) + self._sync_menu.connect_to_folder.connect(self.connect_to_folder) + self._sync_menu.disconnect_from_folder.connect(self.disconnect_from_folder) def add_spare_server(self, *args): self.spare_servers.append(Server(limit=int(config['worker_limit']/2.0)))