mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-12-27 07:10:19 -05:00
Handle device removal
This commit is contained in:
parent
ef0df0e877
commit
6f8b824da9
@ -51,6 +51,9 @@ class DeviceManager(QObject):
|
||||
self.device_class = device_class
|
||||
self.device = device_class()
|
||||
|
||||
def device_removed(self):
|
||||
self.device = None
|
||||
|
||||
def info_func(self):
|
||||
''' Return callable that returns device information and free space on device'''
|
||||
def get_device_information(updater):
|
||||
|
||||
@ -289,7 +289,7 @@
|
||||
<item>
|
||||
<widget class="QToolButton" name="add_format_button" >
|
||||
<property name="toolTip" >
|
||||
<string>Add a new format for this book</string>
|
||||
<string>Add a new format for this book to the database</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>...</string>
|
||||
@ -297,6 +297,12 @@
|
||||
<property name="icon" >
|
||||
<iconset resource="../images.qrc" >:/images/plus.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize" >
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@ -324,7 +330,13 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="../images.qrc" >:/images/list_remove.svg</iconset>
|
||||
<iconset resource="../images.qrc" >:/images/trash.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize" >
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
import traceback, textwrap
|
||||
|
||||
from PyQt4.QtCore import QAbstractTableModel, QMutex, QObject, SIGNAL, Qt, \
|
||||
QVariant, QThread
|
||||
QVariant, QThread, QModelIndex
|
||||
from PyQt4.QtGui import QIcon
|
||||
|
||||
from libprs500.gui2 import NONE
|
||||
@ -55,8 +55,8 @@ class Job(QThread):
|
||||
finally:
|
||||
if self.mutex != None:
|
||||
self.mutex.unlock()
|
||||
self.emit(SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
||||
self.id, self.result, exception, last_traceback)
|
||||
self.emit(SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
||||
self.id, self.description, self.result, exception, last_traceback)
|
||||
|
||||
def progress_update(self, val):
|
||||
self.percent_done = val
|
||||
@ -87,6 +87,18 @@ class JobManager(QAbstractTableModel):
|
||||
self.job_icon = QVariant(QIcon(':/images/jobs.svg'))
|
||||
self.wrapper = textwrap.TextWrapper(width=40)
|
||||
|
||||
def terminate_device_jobs(self):
|
||||
changed = False
|
||||
for key in self.jobs.keys():
|
||||
if isinstance(self.jobs[key], DeviceJob):
|
||||
changed = True
|
||||
job = self.jobs.pop(key)
|
||||
job.terminate()
|
||||
job.mutex.unlock()
|
||||
self.emit(SIGNAL('job_done(int)'), job.id)
|
||||
if changed:
|
||||
self.reset()
|
||||
|
||||
def create_job(self, job_class, description, lock, *args, **kwargs):
|
||||
self.job_create_lock.lock()
|
||||
try:
|
||||
@ -94,9 +106,10 @@ class JobManager(QAbstractTableModel):
|
||||
job = job_class(self.next_id, description, lock, *args, **kwargs)
|
||||
QObject.connect(job, SIGNAL('finished()'), self.cleanup_jobs)
|
||||
QObject.connect(job, SIGNAL('status_update(int, int)'), self.status_update)
|
||||
self.beginInsertRows(QModelIndex(), len(self.jobs), len(self.jobs))
|
||||
self.jobs[self.next_id] = job
|
||||
self.endInsertRows()
|
||||
self.emit(SIGNAL('job_added(int)'), self.next_id)
|
||||
self.reset()
|
||||
return job
|
||||
finally:
|
||||
self.job_create_lock.unlock()
|
||||
@ -122,10 +135,10 @@ class JobManager(QAbstractTableModel):
|
||||
desc = callable.__doc__ if callable.__doc__ else ''
|
||||
desc += kwargs.pop('job_extra_description', '')
|
||||
job = self.create_job(DeviceJob, desc, self.device_lock, callable, *args, **kwargs)
|
||||
QObject.connect(job, SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
||||
QObject.connect(job, SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
||||
self.job_done)
|
||||
if slot:
|
||||
QObject.connect(job, SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
||||
QObject.connect(job, SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
||||
slot)
|
||||
job.start()
|
||||
return job.id
|
||||
@ -134,10 +147,16 @@ class JobManager(QAbstractTableModel):
|
||||
'''
|
||||
Slot that is called when a job is completed.
|
||||
'''
|
||||
keys = self.jobs.keys()
|
||||
if not id in keys: # Terminated job
|
||||
return
|
||||
self.job_remove_lock.lock()
|
||||
try:
|
||||
job = self.jobs.pop(id)
|
||||
self.reset()
|
||||
keys.sort()
|
||||
idx = keys.index(id)
|
||||
self.beginRemoveRows(QModelIndex(), idx, idx)
|
||||
job = self.jobs.pop(id)
|
||||
self.endRemoveRows()
|
||||
self.cleanup_lock.lock()
|
||||
self.cleanup[id] = job
|
||||
self.cleanup_lock.unlock()
|
||||
|
||||
@ -15,8 +15,9 @@
|
||||
import os, tempfile, sys
|
||||
|
||||
from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, \
|
||||
QSettings, QVariant, QSize, QThread
|
||||
from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox
|
||||
QSettings, QVariant, QSize, QThread, QModelIndex
|
||||
from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox, \
|
||||
QItemSelectionModel
|
||||
from PyQt4.QtSvg import QSvgRenderer
|
||||
|
||||
from libprs500 import __version__, __appname__
|
||||
@ -149,13 +150,23 @@ class Main(QObject, Ui_MainWindow):
|
||||
func = self.device_manager.info_func()
|
||||
self.job_manager.run_device_job(self.info_read, func)
|
||||
self.set_default_thumbnail(cls.THUMBNAIL_HEIGHT)
|
||||
self.status_bar.showMessage('Device: '+cls.__name__+' detected.', 3000)
|
||||
self.action_sync.setEnabled(True)
|
||||
else:
|
||||
self.job_manager.terminate_device_jobs()
|
||||
self.device_manager.device_removed()
|
||||
self.location_view.model().update_devices()
|
||||
self.action_sync.setEnabled(False)
|
||||
if self.current_view() != self.library_view:
|
||||
self.status_bar.reset_info()
|
||||
self.location_selected('library')
|
||||
|
||||
def info_read(self, id, result, exception, formatted_traceback):
|
||||
def info_read(self, id, description, result, exception, formatted_traceback):
|
||||
'''
|
||||
Called once device information has been read.
|
||||
'''
|
||||
if exception:
|
||||
self.job_exception(id, exception, formatted_traceback)
|
||||
self.job_exception(id, description, exception, formatted_traceback)
|
||||
return
|
||||
info, cp, fs = result
|
||||
self.location_view.model().update_devices(cp, fs)
|
||||
@ -163,12 +174,12 @@ class Main(QObject, Ui_MainWindow):
|
||||
func = self.device_manager.books_func()
|
||||
self.job_manager.run_device_job(self.metadata_downloaded, func)
|
||||
|
||||
def metadata_downloaded(self, id, result, exception, formatted_traceback):
|
||||
def metadata_downloaded(self, id, description, result, exception, formatted_traceback):
|
||||
'''
|
||||
Called once metadata has been read for all books on the device.
|
||||
'''
|
||||
if exception:
|
||||
self.job_exception(id, exception, formatted_traceback)
|
||||
self.job_exception(id, description, exception, formatted_traceback)
|
||||
return
|
||||
mainlist, cardlist = result
|
||||
self.memory_view.set_database(mainlist)
|
||||
@ -191,12 +202,12 @@ class Main(QObject, Ui_MainWindow):
|
||||
self.device_manager.sync_booklists_func(),
|
||||
self.booklists())
|
||||
|
||||
def metadata_synced(self, id, result, exception, formatted_traceback):
|
||||
def metadata_synced(self, id, description, result, exception, formatted_traceback):
|
||||
'''
|
||||
Called once metadata has been uploaded.
|
||||
'''
|
||||
if exception:
|
||||
self.job_exception(id, exception, formatted_traceback)
|
||||
self.job_exception(id, description, exception, formatted_traceback)
|
||||
return
|
||||
cp, fs = result
|
||||
self.location_view.model().update_devices(cp, fs)
|
||||
@ -249,7 +260,7 @@ class Main(QObject, Ui_MainWindow):
|
||||
)
|
||||
self.upload_memory[id] = metadata
|
||||
|
||||
def books_uploaded(self, id, result, exception, formatted_traceback):
|
||||
def books_uploaded(self, id, description, result, exception, formatted_traceback):
|
||||
'''
|
||||
Called once books have been uploaded.
|
||||
'''
|
||||
@ -263,7 +274,7 @@ class Main(QObject, Ui_MainWindow):
|
||||
'</p>\n<ul>%s</ul>'%(titles,))
|
||||
d.exec_()
|
||||
else:
|
||||
self.job_exception(id, exception, formatted_traceback)
|
||||
self.job_exception(id, description, exception, formatted_traceback)
|
||||
return
|
||||
|
||||
self.device_manager.add_books_to_metadata(result, metadata, self.booklists())
|
||||
@ -301,14 +312,14 @@ class Main(QObject, Ui_MainWindow):
|
||||
self.device_manager.delete_books_func(), paths)
|
||||
|
||||
|
||||
def books_deleted(self, id, result, exception, formatted_traceback):
|
||||
def books_deleted(self, id, description, result, exception, formatted_traceback):
|
||||
'''
|
||||
Called once deletion is done on the device
|
||||
'''
|
||||
for view in (self.memory_view, self.card_view):
|
||||
view.model().deletion_done(id, bool(exception))
|
||||
if exception:
|
||||
self.job_exception(id, exception, formatted_traceback)
|
||||
self.job_exception(id, description, exception, formatted_traceback)
|
||||
return
|
||||
|
||||
self.upload_booklists()
|
||||
@ -418,6 +429,10 @@ class Main(QObject, Ui_MainWindow):
|
||||
view.resizeRowsToContents()
|
||||
view.resizeColumnsToContents()
|
||||
view.resize_on_select = False
|
||||
self.status_bar.reset_info()
|
||||
self.current_view().clearSelection()
|
||||
self.current_view().setCurrentIndex(view.model().index(0, 0))
|
||||
|
||||
|
||||
def job_exception(self, id, exception, formatted_traceback):
|
||||
'''
|
||||
|
||||
@ -365,6 +365,9 @@
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_sync" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="images.qrc" >:/images/sync.svg</iconset>
|
||||
</property>
|
||||
|
||||
@ -120,6 +120,9 @@ class StatusBar(QStatusBar):
|
||||
self.book_info = BookInfoDisplay(self.clearMessage)
|
||||
self.addWidget(self.book_info)
|
||||
|
||||
def reset_info(self):
|
||||
self.book_info.show_data({})
|
||||
|
||||
def jobs(self):
|
||||
src = qstring_to_unicode(self.movie_button.jobs.text())
|
||||
return int(src.rpartition(':')[2].lstrip())
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user