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())