From bcd1d79352d584b33c4d09cb755712aadd3f1139 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 11 Oct 2010 10:42:29 +0100 Subject: [PATCH 1/3] Fix #7124, collections becoming unsorted when using manual management --- src/calibre/devices/usbms/books.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/calibre/devices/usbms/books.py b/src/calibre/devices/usbms/books.py index a267d18584..30d25781cf 100644 --- a/src/calibre/devices/usbms/books.py +++ b/src/calibre/devices/usbms/books.py @@ -124,7 +124,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) @@ -198,20 +197,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 From 4e8115a753b70430ebd850f83ea7277e4ed2057b Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 11 Oct 2010 11:23:39 +0100 Subject: [PATCH 2/3] Code for #7131 - implementing SUPPORTS_BACKLOADING --- src/calibre/devices/interface.py | 4 ++++ src/calibre/devices/usbms/device.py | 3 +++ src/calibre/gui2/actions/add_to_library.py | 7 ++++++- 3 files changed, 13 insertions(+), 1 deletion(-) 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/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): From 00fd77ffe895fd39bf7d1f2eb2f151d7f16122e9 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 11 Oct 2010 12:08:54 +0100 Subject: [PATCH 3/3] More fix for #7131 - disable drag & drop --- src/calibre/gui2/device.py | 9 ++++++--- src/calibre/gui2/library/views.py | 9 ++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) 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 + # }}}