mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Added detection of device busy condition
Added a lock file to ensure that only one instance of the GUI runs
This commit is contained in:
parent
876f994a4a
commit
9962f95b31
@ -221,8 +221,12 @@ class PRS500Device(object):
|
|||||||
self.device = self.device_descriptor.getDevice()
|
self.device = self.device_descriptor.getDevice()
|
||||||
if not self.device:
|
if not self.device:
|
||||||
raise DeviceError()
|
raise DeviceError()
|
||||||
|
try:
|
||||||
self.handle = self.device.open()
|
self.handle = self.device.open()
|
||||||
self.handle.claimInterface(self.device_descriptor.interface_id)
|
self.handle.claimInterface(self.device_descriptor.interface_id)
|
||||||
|
except usb.USBError, e:
|
||||||
|
print >>sys.stderr, e
|
||||||
|
raise DeviceBusy()
|
||||||
res = self._send_validated_command(GetUSBProtocolVersion(), timeout=20000) # Large timeout as device may still be initializing
|
res = self._send_validated_command(GetUSBProtocolVersion(), timeout=20000) # Large timeout as device may still be initializing
|
||||||
if res.code != 0: raise ProtocolError("Unable to get USB Protocol version.")
|
if res.code != 0: raise ProtocolError("Unable to get USB Protocol version.")
|
||||||
version = self._bulk_read(24, data_type=USBProtocolVersion)[0].version
|
version = self._bulk_read(24, data_type=USBProtocolVersion)[0].version
|
||||||
@ -236,8 +240,10 @@ class PRS500Device(object):
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
""" Release device interface """
|
""" Release device interface """
|
||||||
|
try:
|
||||||
self.handle.reset()
|
self.handle.reset()
|
||||||
self.handle.releaseInterface()
|
self.handle.releaseInterface()
|
||||||
|
except: pass
|
||||||
self.handle, self.device = None, None
|
self.handle, self.device = None, None
|
||||||
|
|
||||||
def _send_command(self, command, response_type=Response, timeout=1000):
|
def _send_command(self, command, response_type=Response, timeout=1000):
|
||||||
|
@ -34,6 +34,11 @@ class DeviceError(ProtocolError):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
ProtocolError.__init__(self, "Unable to find SONY Reader. Is it connected?")
|
ProtocolError.__init__(self, "Unable to find SONY Reader. Is it connected?")
|
||||||
|
|
||||||
|
class DeviceBusy(ProtocolError):
|
||||||
|
""" Raised when device is busy """
|
||||||
|
def __init__(self):
|
||||||
|
ProtocolError.__init__(self, "Device is in use by another application")
|
||||||
|
|
||||||
class PacketError(ProtocolError):
|
class PacketError(ProtocolError):
|
||||||
""" Errors with creating/interpreting packets """
|
""" Errors with creating/interpreting packets """
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
__docformat__ = "epytext"
|
__docformat__ = "epytext"
|
||||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||||
|
APP_TITLE = "libprs500"
|
||||||
|
|
||||||
import pkg_resources, sys, os, re, StringIO, traceback
|
import pkg_resources, sys, os, re, StringIO, traceback
|
||||||
from PyQt4 import QtCore, QtGui # Needed for classes imported with import_ui
|
from PyQt4 import QtCore, QtGui # Needed for classes imported with import_ui
|
||||||
@ -28,7 +29,7 @@ def installErrorHandler(dialog):
|
|||||||
global error_dialog
|
global error_dialog
|
||||||
error_dialog = dialog
|
error_dialog = dialog
|
||||||
error_dialog.resize(600, 400)
|
error_dialog.resize(600, 400)
|
||||||
error_dialog.setWindowTitle("SONY Reader - Error")
|
error_dialog.setWindowTitle(APP_TITLE + " - Error")
|
||||||
error_dialog.setModal(True)
|
error_dialog.setModal(True)
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,12 +20,12 @@ from PyQt4 import uic
|
|||||||
from libprs500.communicate import PRS500Device as device
|
from libprs500.communicate import PRS500Device as device
|
||||||
from libprs500.errors import *
|
from libprs500.errors import *
|
||||||
from libprs500.lrf.meta import LRFMetaFile, LRFException
|
from libprs500.lrf.meta import LRFMetaFile, LRFException
|
||||||
from libprs500.gui import import_ui, installErrorHandler, Error, Warning, extension
|
from libprs500.gui import import_ui, installErrorHandler, Error, Warning, extension, APP_TITLE
|
||||||
from libprs500.gui.widgets import LibraryBooksModel, DeviceBooksModel, DeviceModel, TableView
|
from libprs500.gui.widgets import LibraryBooksModel, DeviceBooksModel, DeviceModel, TableView
|
||||||
from database import LibraryDatabase
|
from database import LibraryDatabase
|
||||||
from editbook import EditBookDialog
|
from editbook import EditBookDialog
|
||||||
|
|
||||||
import sys, re, os, traceback
|
import sys, re, os, traceback, tempfile
|
||||||
|
|
||||||
DEFAULT_BOOK_COVER = None
|
DEFAULT_BOOK_COVER = None
|
||||||
LIBRARY_BOOK_TEMPLATE = QString("<table><tr><td><b>Formats:</b> %1 </td><td><b>Tags:</b> %2</td></tr><tr><td><b>Comments:</b>%3</td></tr></table>")
|
LIBRARY_BOOK_TEMPLATE = QString("<table><tr><td><b>Formats:</b> %1 </td><td><b>Tags:</b> %2</td></tr><tr><td><b>Comments:</b>%3</td></tr></table>")
|
||||||
@ -102,7 +102,7 @@ class MainWindow(QObject, Ui_MainWindow):
|
|||||||
|
|
||||||
def delete(self, action):
|
def delete(self, action):
|
||||||
count = str(len(self.current_view.selectionModel().selectedRows()))
|
count = str(len(self.current_view.selectionModel().selectedRows()))
|
||||||
ret = QMessageBox.question(self.window, self.trUtf8("SONY Reader - confirm"), self.trUtf8("Are you sure you want to <b>permanently delete</b> these ") +count+self.trUtf8(" item(s)?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
|
ret = QMessageBox.question(self.window, self.trUtf8(APP_TITLE + " - confirm"), self.trUtf8("Are you sure you want to <b>permanently delete</b> these ") +count+self.trUtf8(" item(s)?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
|
||||||
if ret != QMessageBox.Yes: return
|
if ret != QMessageBox.Yes: return
|
||||||
self.window.setCursor(Qt.WaitCursor)
|
self.window.setCursor(Qt.WaitCursor)
|
||||||
if self.library_view.isVisible():
|
if self.library_view.isVisible():
|
||||||
@ -342,7 +342,7 @@ class MainWindow(QObject, Ui_MainWindow):
|
|||||||
def device_removed(self, timeout=False):
|
def device_removed(self, timeout=False):
|
||||||
""" @todo: only reset stuff if library is not shown """
|
""" @todo: only reset stuff if library is not shown """
|
||||||
self.is_connected = False
|
self.is_connected = False
|
||||||
self.df.setText("SONY Reader: <br><br>Storage card:")
|
self.df.setText(self.df_template.arg("").arg("").arg(""))
|
||||||
self.device_tree.hide_reader(True)
|
self.device_tree.hide_reader(True)
|
||||||
self.device_tree.hide_card(True)
|
self.device_tree.hide_card(True)
|
||||||
self.book_cover.hide()
|
self.book_cover.hide()
|
||||||
@ -368,13 +368,15 @@ class MainWindow(QObject, Ui_MainWindow):
|
|||||||
self.status("Connecting to device")
|
self.status("Connecting to device")
|
||||||
try:
|
try:
|
||||||
info = self.dev.get_device_information(end_session=False)
|
info = self.dev.get_device_information(end_session=False)
|
||||||
|
except DeviceBusy, e:
|
||||||
|
qFatal(str(e))
|
||||||
except DeviceError:
|
except DeviceError:
|
||||||
self.dev.reconnect()
|
self.dev.reconnect()
|
||||||
return
|
return
|
||||||
except ProtocolError, e:
|
except ProtocolError, e:
|
||||||
traceback.print_exc(e)
|
traceback.print_exc(e)
|
||||||
qFatal("Unable to connect to device. Please try unplugging and reconnecting it")
|
qFatal("Unable to connect to device. Please try unplugging and reconnecting it")
|
||||||
self.df.setText(self.df_template.arg(info[0]).arg(info[1]).arg(info[2]))
|
self.df.setText(self.df_template.arg("Connected: "+info[0]).arg(info[1]).arg(info[2]))
|
||||||
space = self.dev.available_space(end_session=False)
|
space = self.dev.available_space(end_session=False)
|
||||||
sc = space[1][1] if space[1][1] else space[2][1]
|
sc = space[1][1] if space[1][1] else space[2][1]
|
||||||
self.device_tree.model().update_free_space(space[0][1], sc)
|
self.device_tree.model().update_free_space(space[0][1], sc)
|
||||||
@ -395,6 +397,11 @@ class MainWindow(QObject, Ui_MainWindow):
|
|||||||
def main():
|
def main():
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
from libprs500 import __version__ as VERSION
|
from libprs500 import __version__ as VERSION
|
||||||
|
lock = os.path.join(tempfile.gettempdir(),"libprs500_gui_lock")
|
||||||
|
if os.access(lock, os.F_OK):
|
||||||
|
print >>sys.stderr, "Another instance of", APP_TITLE, "is running"
|
||||||
|
print >>sys.stderr, "If you are sure this is not the case then manually delete the file", lock
|
||||||
|
sys.exit(1)
|
||||||
parser = OptionParser(usage="usage: %prog [options]", version=VERSION)
|
parser = OptionParser(usage="usage: %prog [options]", version=VERSION)
|
||||||
parser.add_option("--log-packets", help="print out packet stream to stdout. "+\
|
parser.add_option("--log-packets", help="print out packet stream to stdout. "+\
|
||||||
"The numbers in the left column are byte offsets that allow the packet size to be read off easily.", \
|
"The numbers in the left column are byte offsets that allow the packet size to be read off easily.", \
|
||||||
@ -405,12 +412,17 @@ def main():
|
|||||||
global DEFAULT_BOOK_COVER
|
global DEFAULT_BOOK_COVER
|
||||||
DEFAULT_BOOK_COVER = QPixmap(":/default_cover")
|
DEFAULT_BOOK_COVER = QPixmap(":/default_cover")
|
||||||
window = QMainWindow()
|
window = QMainWindow()
|
||||||
|
window.setWindowTitle(APP_TITLE)
|
||||||
window.setWindowIcon(QIcon(":/icon"))
|
window.setWindowIcon(QIcon(":/icon"))
|
||||||
installErrorHandler(QErrorMessage(window))
|
installErrorHandler(QErrorMessage(window))
|
||||||
QCoreApplication.setOrganizationName("KovidsBrain")
|
QCoreApplication.setOrganizationName("KovidsBrain")
|
||||||
QCoreApplication.setApplicationName("SONY Reader")
|
QCoreApplication.setApplicationName(APP_TITLE)
|
||||||
gui = MainWindow(window, options.log_packets)
|
gui = MainWindow(window, options.log_packets)
|
||||||
|
f = open(lock, "w")
|
||||||
|
f.close()
|
||||||
|
try:
|
||||||
ret = app.exec_()
|
ret = app.exec_()
|
||||||
|
finally: os.remove(lock)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
if __name__ == "__main__": main()
|
if __name__ == "__main__": main()
|
||||||
|
@ -19,7 +19,10 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle" >
|
<property name="windowTitle" >
|
||||||
<string>SONY Reader</string>
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon" >
|
||||||
|
<iconset resource="images.qrc" >:/images/library.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralwidget" >
|
<widget class="QWidget" name="centralwidget" >
|
||||||
<layout class="QVBoxLayout" >
|
<layout class="QVBoxLayout" >
|
||||||
@ -60,7 +63,7 @@
|
|||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="dragDropMode" >
|
<property name="dragDropMode" >
|
||||||
<enum>QAbstractItemView::DropOnly</enum>
|
<enum>QAbstractItemView::DragDrop</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="flow" >
|
<property name="flow" >
|
||||||
<enum>QListView::TopToBottom</enum>
|
<enum>QListView::TopToBottom</enum>
|
||||||
@ -84,11 +87,14 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string><b>libprs500</b> was created by <b>Kovid Goyal</b> &copy; 2006<br><br>%1 %2 %3</string>
|
<string>For help visit <a href="http://libprs500.kovidgoyal.net">http://libprs500.kovidgoyal.net</a><br><br><b>libprs500</b> was created by <b>Kovid Goyal</b> &copy; 2006<br>%1 %2 %3</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat" >
|
<property name="textFormat" >
|
||||||
<enum>Qt::RichText</enum>
|
<enum>Qt::RichText</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="openExternalLinks" >
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@ -275,8 +281,8 @@
|
|||||||
<widget class="QToolBar" name="tool_bar" >
|
<widget class="QToolBar" name="tool_bar" >
|
||||||
<property name="minimumSize" >
|
<property name="minimumSize" >
|
||||||
<size>
|
<size>
|
||||||
<width>49</width>
|
<width>163</width>
|
||||||
<height>37</height>
|
<height>58</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="movable" >
|
<property name="movable" >
|
||||||
@ -291,6 +297,9 @@
|
|||||||
<height>22</height>
|
<height>22</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolButtonStyle" >
|
||||||
|
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||||
|
</property>
|
||||||
<attribute name="toolBarArea" >
|
<attribute name="toolBarArea" >
|
||||||
<number>4</number>
|
<number>4</number>
|
||||||
</attribute>
|
</attribute>
|
||||||
@ -303,7 +312,7 @@
|
|||||||
<iconset resource="images.qrc" >:/images/plus.png</iconset>
|
<iconset resource="images.qrc" >:/images/plus.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string>Add files to Library</string>
|
<string>Add books to Library</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut" >
|
<property name="shortcut" >
|
||||||
<string>A</string>
|
<string>A</string>
|
||||||
@ -317,7 +326,7 @@
|
|||||||
<iconset resource="images.qrc" >:/images/minus.png</iconset>
|
<iconset resource="images.qrc" >:/images/minus.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string>Delete selected items</string>
|
<string>Delete books</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut" >
|
<property name="shortcut" >
|
||||||
<string>Del</string>
|
<string>Del</string>
|
||||||
@ -328,7 +337,7 @@
|
|||||||
<iconset resource="images.qrc" >:/images/edit.png</iconset>
|
<iconset resource="images.qrc" >:/images/edit.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string>Edit meta-information for the currently selected items</string>
|
<string>Edit meta-information</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut" >
|
<property name="shortcut" >
|
||||||
<string>E</string>
|
<string>E</string>
|
||||||
|
@ -116,9 +116,7 @@ class FileDragAndDrop(object):
|
|||||||
urls.append(urlunparse(('file', quote(gethostname()), quote(str(file.name)), '','','')))
|
urls.append(urlunparse(('file', quote(gethostname()), quote(str(file.name)), '','','')))
|
||||||
self._dragged_files.append(file)
|
self._dragged_files.append(file)
|
||||||
mime_data.setData("text/uri-list", QByteArray("\n".join(urls)))
|
mime_data.setData("text/uri-list", QByteArray("\n".join(urls)))
|
||||||
user = None
|
user = os.getenv['USER']
|
||||||
try: user = os.environ['USER']
|
|
||||||
except: pass
|
|
||||||
if user: mime_data.setData("text/x-xdnd-username", QByteArray(user))
|
if user: mime_data.setData("text/x-xdnd-username", QByteArray(user))
|
||||||
drag.setMimeData(mime_data)
|
drag.setMimeData(mime_data)
|
||||||
return drag
|
return drag
|
||||||
|
Loading…
x
Reference in New Issue
Block a user