diff --git a/src/calibre/devices/interface.py b/src/calibre/devices/interface.py index aee35649d2..9c10de7d6c 100644 --- a/src/calibre/devices/interface.py +++ b/src/calibre/devices/interface.py @@ -39,6 +39,10 @@ class DevicePlugin(Plugin): #: Whether the metadata on books can be set via the GUI. CAN_SET_METADATA = ['title', 'authors', 'collections'] + # Set this to True if the books on the device are files that the GUI can + # access in order to add the books from the device to the library + SUPPORTS_BACKLOADING = False + #: Path separator for paths to books on device path_sep = os.sep diff --git a/src/calibre/devices/usbms/books.py b/src/calibre/devices/usbms/books.py index c8b2638690..462d78b233 100644 --- a/src/calibre/devices/usbms/books.py +++ b/src/calibre/devices/usbms/books.py @@ -125,7 +125,6 @@ class CollectionsBookList(BookList): collections = {} # This map of sets is used to avoid linear searches when testing for # book equality - collections_lpaths = {} for book in self: # Make sure we can identify this book via the lpath lpath = getattr(book, 'lpath', None) @@ -199,20 +198,22 @@ class CollectionsBookList(BookList): cat_name = category if cat_name not in collections: - collections[cat_name] = [] - collections_lpaths[cat_name] = set() - if lpath in collections_lpaths[cat_name]: - continue - collections_lpaths[cat_name].add(lpath) + collections[cat_name] = {} if is_series: - collections[cat_name].append( - (book, book.get(attr+'_index', sys.maxint))) + if doing_dc: + collections[cat_name][lpath] = \ + (book, book.get('series_index', sys.maxint)) + else: + collections[cat_name][lpath] = \ + (book, book.get(attr+'_index', sys.maxint)) else: - collections[cat_name].append( - (book, book.get('title_sort', 'zzzz'))) + if lpath not in collections[cat_name]: + collections[cat_name][lpath] = \ + (book, book.get('title_sort', 'zzzz')) # Sort collections result = {} - for category, books in collections.items(): + for category, lpaths in collections.items(): + books = lpaths.values() books.sort(cmp=lambda x,y:cmp(x[1], y[1])) result[category] = [x[0] for x in books] return result diff --git a/src/calibre/devices/usbms/device.py b/src/calibre/devices/usbms/device.py index 78d4606e85..cb26f6a50c 100644 --- a/src/calibre/devices/usbms/device.py +++ b/src/calibre/devices/usbms/device.py @@ -94,6 +94,9 @@ class Device(DeviceConfig, DevicePlugin): EBOOK_DIR_CARD_B = '' DELETE_EXTS = [] + # USB disk-based devices can see the book files on the device, so can + # copy these back to the library + SUPPORTS_BACKLOADING = True def reset(self, key='-1', log_packets=False, report_progress=None, detected_device=None): diff --git a/src/calibre/gui2/actions/add_to_library.py b/src/calibre/gui2/actions/add_to_library.py index 05aea8f1dd..efdf645acb 100644 --- a/src/calibre/gui2/actions/add_to_library.py +++ b/src/calibre/gui2/actions/add_to_library.py @@ -19,7 +19,12 @@ class AddToLibraryAction(InterfaceAction): self.qaction.triggered.connect(self.add_books_to_library) def location_selected(self, loc): - enabled = loc != 'library' + enabled = False + if loc != 'library': + if self.gui.device_manager.is_device_connected: + device = self.gui.device_manager.connected_device + if device is not None: + enabled = getattr(device, 'SUPPORTS_BACKLOADING', False) self.qaction.setEnabled(enabled) def add_books_to_library(self, *args): diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index bc9f5cf671..49bc5c0016 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -793,11 +793,14 @@ class DeviceMixin(object): # {{{ self.set_books_in_library(job.result, reset=True) mainlist, cardalist, cardblist = job.result self.memory_view.set_database(mainlist) - self.memory_view.set_editable(self.device_manager.device.CAN_SET_METADATA) + self.memory_view.set_editable(self.device_manager.device.CAN_SET_METADATA, + self.device_manager.device.SUPPORTS_BACKLOADING) self.card_a_view.set_database(cardalist) - self.card_a_view.set_editable(self.device_manager.device.CAN_SET_METADATA) + self.card_a_view.set_editable(self.device_manager.device.CAN_SET_METADATA, + self.device_manager.device.SUPPORTS_BACKLOADING) self.card_b_view.set_database(cardblist) - self.card_b_view.set_editable(self.device_manager.device.CAN_SET_METADATA) + self.card_b_view.set_editable(self.device_manager.device.CAN_SET_METADATA, + self.device_manager.device.SUPPORTS_BACKLOADING) self.sync_news() self.sync_catalogs() self.refresh_ondevice() diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 57ea04fb75..8f86bf43b8 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -30,6 +30,7 @@ class BooksView(QTableView): # {{{ def __init__(self, parent, modelcls=BooksModel): QTableView.__init__(self, parent) + self.drag_allowed = True self.setDragEnabled(True) self.setDragDropOverwriteMode(False) self.setDragDropMode(self.DragDrop) @@ -505,6 +506,8 @@ class BooksView(QTableView): # {{{ return QTableView.mousePressEvent(self, event) def mouseMoveEvent(self, event): + if not self.drag_allowed: + return if self.drag_start_pos is None: return QTableView.mouseMoveEvent(self, event) @@ -613,7 +616,7 @@ class BooksView(QTableView): # {{{ def close(self): self._model.close() - def set_editable(self, editable): + def set_editable(self, editable, supports_backloading): self._model.set_editable(editable) def connect_to_search_box(self, sb, search_done): @@ -700,5 +703,9 @@ class DeviceBooksView(BooksView): # {{{ error_dialog(self, _('Not allowed'), _('Dropping onto a device is not supported. First add the book to the calibre library.')).exec_() + def set_editable(self, editable, supports_backloading): + self._model.set_editable(editable) + self.drag_allowed = supports_backloading + # }}}