From 6f8b824da9274a29c6e1237beeaee56cab172ce3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 5 Aug 2007 00:39:28 +0000 Subject: [PATCH] Handle device removal --- src/libprs500/gui2/device.py | 3 ++ src/libprs500/gui2/dialogs/metadata_single.ui | 16 +++++++- src/libprs500/gui2/jobs.py | 35 +++++++++++++---- src/libprs500/gui2/main.py | 39 +++++++++++++------ src/libprs500/gui2/main.ui | 3 ++ src/libprs500/gui2/status.py | 3 ++ 6 files changed, 77 insertions(+), 22 deletions(-) diff --git a/src/libprs500/gui2/device.py b/src/libprs500/gui2/device.py index a3965566be..3c91d6234b 100644 --- a/src/libprs500/gui2/device.py +++ b/src/libprs500/gui2/device.py @@ -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): diff --git a/src/libprs500/gui2/dialogs/metadata_single.ui b/src/libprs500/gui2/dialogs/metadata_single.ui index 13dbda62b8..6dde2bf049 100644 --- a/src/libprs500/gui2/dialogs/metadata_single.ui +++ b/src/libprs500/gui2/dialogs/metadata_single.ui @@ -289,7 +289,7 @@ - Add a new format for this book + Add a new format for this book to the database ... @@ -297,6 +297,12 @@ :/images/plus.svg + + + 32 + 32 + + @@ -324,7 +330,13 @@ ... - :/images/list_remove.svg + :/images/trash.svg + + + + 32 + 32 + diff --git a/src/libprs500/gui2/jobs.py b/src/libprs500/gui2/jobs.py index 79849e0a7b..66cbcc37f2 100644 --- a/src/libprs500/gui2/jobs.py +++ b/src/libprs500/gui2/jobs.py @@ -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() diff --git a/src/libprs500/gui2/main.py b/src/libprs500/gui2/main.py index b16bd9b0a2..608a0ef172 100644 --- a/src/libprs500/gui2/main.py +++ b/src/libprs500/gui2/main.py @@ -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): '

\n'%(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): ''' diff --git a/src/libprs500/gui2/main.ui b/src/libprs500/gui2/main.ui index b683153466..fe0b76bac2 100644 --- a/src/libprs500/gui2/main.ui +++ b/src/libprs500/gui2/main.ui @@ -365,6 +365,9 @@ + + false + :/images/sync.svg diff --git a/src/libprs500/gui2/status.py b/src/libprs500/gui2/status.py index 6b0e8e8580..db11975d37 100644 --- a/src/libprs500/gui2/status.py +++ b/src/libprs500/gui2/status.py @@ -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())