Changed GUI to only show devices. No subsets.

Added a warning about PyQt4 too setup script
Added initial code for Dropping on reader (not tested)
This commit is contained in:
Kovid Goyal 2006-12-09 05:55:36 +00:00
parent 8e4010e0f3
commit 876f994a4a
13 changed files with 4665 additions and 628 deletions

View File

@ -32,7 +32,7 @@ the following rule in C{/etc/udev/rules.d/90-local.rules} ::
BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", MODE="660", GROUP="plugdev"
You may have to adjust the GROUP and the location of the rules file to suit your distribution.
"""
__version__ = "0.2.1"
__version__ = "0.3.0"
__docformat__ = "epytext"
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
TEMPORARY_FILENAME_TEMPLATE = "libprs500_"+__version__+"_temp"

View File

@ -16,16 +16,24 @@
from xml.dom.ext import PrettyPrint as PrettyPrint
import xml.dom.minidom as dom
from base64 import b64decode as decode
from base64 import b64encode as encode
import time
MIME_MAP = { "lrf":"application/x-sony-bbeb", "rtf":"application/rtf", "pdf":"application/pdf", "txt":"text/plain" }
class book_metadata_field(object):
def __init__(self, attr, formatter=None):
def __init__(self, attr, formatter=None, setter=None):
self.attr = attr
self.formatter = formatter
def __get__(self, obj, typ=None):
""" Return a string. String may be empty if self.attr is absent """
return self.formatter(obj.elem.getAttribute(self.attr)) if self.formatter else obj.elem.getAttribute(self.attr).strip()
def __set__(self, obj, val):
val = self.setter(val) if self.setter else val
obj.elem.setAttribute(self.attr, str(val))
class Book(object):
title = book_metadata_field("title")
author = book_metadata_field("author", formatter=lambda x: x if x.strip() else "Unknown")
@ -33,7 +41,7 @@ class Book(object):
rpath = book_metadata_field("path")
id = book_metadata_field("id", formatter=int)
size = book_metadata_field("size", formatter=int)
datetime = book_metadata_field("date", formatter=lambda x: time.strptime(x, "%a, %d %b %Y %H:%M:%S %Z"))
datetime = book_metadata_field("date", formatter=lambda x: time.strptime(x, "%a, %d %b %Y %H:%M:%S %Z"), setter=lambda x: time.strftime("%a, %d %b %Y %H:%M:%S %Z", x))
@apply
def thumbnail():
@ -78,4 +86,23 @@ class BookList(list):
file.seek(0)
self.document = dom.parse(file)
for book in self.document.getElementsByTagName(self.prefix + "text"): self.append(Book(book, root=root, prefix=prefix))
self._file = file
def add_book(self, info, name):
root = self.document.documentElement
node = self.document.createElement(self.prefix + "text")
mime = MIME_MAP[name[name.rfind(".")+1:]]
id = 0
for book in self:
if book.id > id:
id = book.id
break
attrs = { "title":info["title"], "author":info["authors"], "page":"0", "part":"0", "scale":"0", "sourceid":"1", "id":str(id), "date":"", "mime":mime, "path":name, "size":str(size)}
for attr in attrs.keys():
node.setAttributeNode(self.document.createAttribute(attr))
node.setAttribute(attr, attrs[attr])
book = Book(node, root=self.root, prefix=self.prefix)
book.datetime = time.gmtime()
self.append(book)

View File

@ -134,6 +134,7 @@ class PRS500Device(object):
PRS500_BULK_OUT_EP = 0x02 #: Endpoint for Bulk writes
MEDIA_XML = "/Data/database/cache/media.xml" #: Location of media.xml file on device
CACHE_XML = "/Sony Reader/database/cache.xml" #: Location of cache.xml on storage card in device
FORMATS = ["lrf", "rtf", "pdf", "txt"] #: Ordered list of supported formats
device_descriptor = DeviceDescriptor(SONY_VENDOR_ID, PRS500_PRODUCT_ID, PRS500_INTERFACE_ID)
@ -572,7 +573,14 @@ class PRS500Device(object):
raise ProtocolError("Failed to delete directory " + path + ". Response code: " + hex(res.code))
@safe
def books(self, oncard=False):
def card(self, end_session=True):
card = None
if self._exists("a:/")[0]: card = "a:"
if self._exists("b:/")[0]: card = "b:"
return card
@safe
def books(self, oncard=False, end_session=True):
"""
Return a list of ebooks on the device.
@param oncard: If True return a list of ebookson the storage card, otherwise return list of ebooks in main memory of device
@ -595,3 +603,32 @@ class PRS500Device(object):
if file.tell() == 0: file = None
else: self.get_file(self.MEDIA_XML, file, end_session=False)
return BookList(prefix=prefix, root=root, file=file)
@safe
def add_book(self, infile, name, info, booklists, oncard=False, end_session=True):
"""
Add a book to the device. If oncard is True then the book is copied to the card rather than main memory.
@param infile: The source file, should be opened in "rb" mode
@param name: The name of the book file when uploaded to the device. The extension of name must be one of the supported formats for this device.
@param info: A dictionary that must have the keys "title", "authors", "cover". C{info["cover"]} should be the data from a 60x80 image file or None. If it is something else, results are undefined.
@param booklists: A tuple containing the result of calls to (L{books}(oncard=False), L{books}(oncard=True)).
@todo: Implement syncing the booklists to the device. This would mean juggling with the nextId attribute in media.xml and renumbering ids in cache.xml?
"""
infile.seek(0,2)
size = infile.tell()
infile.seek(0)
card = self.card(end_session=False)
space = self.available_space(end_session=False)
mspace = space[0][1]
cspace = space[1][1] if space[1][1] >= space[2][1] else space[2][1]
if oncard and size > cspace - 1024*1024: raise FreeSpaceError("There is insufficient free space on the storage card")
if not oncard and size > mspace - 1024*1024: raise FreeSpaceError("There is insufficient free space in main memory")
prefix = "/Data/media/"
if oncard: prefix = card + "/"
else: name = "books/"+name
path = prefix + name
self.put_file(infile, path, end_session=False)
if oncard: booklists[1].add_book(info, name, size)
else: booklists[0].add_book(info, name, size)

View File

@ -37,6 +37,9 @@ class DeviceError(ProtocolError):
class PacketError(ProtocolError):
""" Errors with creating/interpreting packets """
class FreeSpaceError(ProtocolError):
""" Errors caused when trying to put files onto an overcrowded device """
class ArgumentError(ProtocolError):
""" Errors caused by invalid arguments to a public interface function """

View File

@ -15,11 +15,35 @@
__docformat__ = "epytext"
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
import pkg_resources, sys, os, StringIO
import pkg_resources, sys, os, re, StringIO, traceback
from PyQt4 import QtCore, QtGui # Needed for classes imported with import_ui
from libprs500.gui.widgets import LibraryBooksView, DeviceBooksView, CoverDisplay, DeviceView # Needed for import_ui
from PyQt4.uic.Compiler import compiler
error_dialog = None
def extension(path):
return os.path.splitext(path)[1][1:].lower()
def installErrorHandler(dialog):
global error_dialog
error_dialog = dialog
error_dialog.resize(600, 400)
error_dialog.setWindowTitle("SONY Reader - Error")
error_dialog.setModal(True)
def Warning(msg, e):
print >> sys.stderr, msg
traceback.print_exc(e)
def Error(msg, e):
if error_dialog:
if e: msg += "<br>" + traceback.format_exc(e)
msg = re.sub("Traceback", "<b>Traceback</b>", msg)
msg = re.sub(r"\n", "<br>", msg)
error_dialog.showMessage(msg)
error_dialog.show()
def import_ui(name):
uifile = pkg_resources.resource_stream(__name__, name)
code_string = StringIO.StringIO()
@ -27,3 +51,5 @@ def import_ui(name):
ui = pkg_resources.resource_filename(__name__, name)
exec code_string.getvalue()
return locals()[winfo["uiclass"]]
from libprs500.gui.widgets import LibraryBooksView, DeviceBooksView, CoverDisplay, DeviceView # Needed for import_ui

View File

@ -1,7 +1,8 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="icon">images/library.png</file>
<file alias="default_cover">images/cherubs.jpg</file>
<file alias="library">images/mycomputer.png</file>
<file alias="library">images/library.png</file>
<file alias="reader">images/reader.png</file>
<file alias="card">images/memory_stick_unmount.png</file>
<file>images/clear.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

File diff suppressed because it is too large Load Diff

View File

@ -12,22 +12,24 @@
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, QSettings, QVariant, QSize, QEventLoop
from PyQt4.QtGui import QPixmap, QAbstractItemView, QErrorMessage, QMessageBox, QFileDialog
from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, QSettings, QVariant, QSize, QEventLoop, QString
from PyQt4.QtGui import QPixmap, QAbstractItemView, QErrorMessage, QMessageBox, QFileDialog, QIcon
from PyQt4.Qt import qInstallMsgHandler, qDebug, qFatal, qWarning, qCritical
from PyQt4 import uic
from libprs500.communicate import PRS500Device as device
from libprs500.errors import *
from libprs500.lrf.meta import LRFMetaFile, LRFException
from libprs500.gui import import_ui
from libprs500.gui.widgets import LibraryBooksModel, DeviceBooksModel, DeviceModel, human_readable
from libprs500.gui import import_ui, installErrorHandler, Error, Warning, extension
from libprs500.gui.widgets import LibraryBooksModel, DeviceBooksModel, DeviceModel, TableView
from database import LibraryDatabase
from editbook import EditBookDialog
import sys, re, os, traceback
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>")
DEVICE_BOOK_TEMPLATE = QString("<table><tr><td><b>Title: </b>%1</td><td><b>&nbsp;Size:</b> %2</td></tr><tr><td><b>Author: </b>%3</td><td><b>&nbsp;Type: </b>%4</td></tr></table>")
Ui_MainWindow = import_ui("main.ui")
class MainWindow(QObject, Ui_MainWindow):
@ -49,18 +51,19 @@ class MainWindow(QObject, Ui_MainWindow):
def tree_clicked(self, index):
if index.isValid():
text = (index.data(Qt.DisplayRole).toString())
if "Books" in text: text = str(index.parent().data(Qt.DisplayRole).toString())
if "Library" in text:
self.show_device(False)
elif "SONY Reader" in text:
self.search.clear()
show_dev = True
model = self.device_tree.model()
if model.is_library(index):
show_dev = False
elif model.is_reader(index):
self.device_view.setModel(self.reader_model)
QObject.connect(self.device_view.selectionModel(), SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.show_book)
self.show_device(True)
elif "Storage Card" in text:
elif model.is_card(index):
self.device_view.setModel(self.card_model)
QObject.connect(self.device_view.selectionModel(), SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.show_book)
self.show_device(True)
self.show_device(show_dev)
def model_modified(self):
if self.library_view.isVisible(): view = self.library_view
@ -78,14 +81,18 @@ class MainWindow(QObject, Ui_MainWindow):
view.resizeColumnToContents(c)
def show_book(self, current, previous):
title, author, size, mime, thumbnail = current.model().info(current.row())
self.book_info.setText(self.BOOK_TEMPLATE.arg(title).arg(size).arg(author).arg(mime))
if not thumbnail: thumbnail = DEFAULT_BOOK_COVER
self.book_cover.setPixmap(thumbnail)
try:
name = os.path.abspath(current.model().image_file.name)
self.book_cover.setToolTip('<img src="'+name+'">')
except Exception, e: self.book_cover.setToolTip('<img src=":/default_cover">')
if self.library_view.isVisible():
formats, tags, comments, cover = current.model().info(current.row())
data = LIBRARY_BOOK_TEMPLATE.arg(formats).arg(tags).arg(comments)
tooltip = "To save the cover, drag it to the desktop.<br>To change the cover drag the new cover onto this picture"
else:
title, author, size, mime, cover = current.model().info(current.row())
data = DEVICE_BOOK_TEMPLATE.arg(title).arg(size).arg(author).arg(mime)
tooltip = "To save the cover, drag it to the desktop."
self.book_info.setText(data)
self.book_cover.setToolTip(tooltip)
if not cover: cover = DEFAULT_BOOK_COVER
self.book_cover.setPixmap(cover)
self.book_cover.show()
self.book_info.show()
@ -95,7 +102,7 @@ class MainWindow(QObject, Ui_MainWindow):
def delete(self, action):
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(" items?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
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)
if ret != QMessageBox.Yes: return
self.window.setCursor(Qt.WaitCursor)
if self.library_view.isVisible():
@ -168,14 +175,17 @@ class MainWindow(QObject, Ui_MainWindow):
self.add_books(files)
def add_books(self, files):
self.window.setCursor(Qt.WaitCursor)
for file in files:
file = os.path.abspath(file)
self.library_view.model().add_book(file)
self.search.clear()
if self.library_view.isVisible(): self.search.clear()
else: self.library_model.search("")
hv = self.library_view.horizontalHeader()
col = hv.sortIndicatorSection()
order = hv.sortIndicatorOrder()
self.library_view.model().sort(col, order)
self.window.setCursor(Qt.ArrowCursor)
def edit(self, action):
@ -189,15 +199,69 @@ class MainWindow(QObject, Ui_MainWindow):
self.library_model.refresh_row(row.row())
def show_error(self, e, msg):
QErrorMessage(self.window).showMessage(msg+"<br><b>Error: </b>"+str(e)+"<br><br>"+re.sub("\n","<br>", traceback.format_exc(e)))
def update_cover(self, pix):
if not pix.isNull():
try:
self.library_view.model().update_cover(self.library_view.currentIndex(), pix)
self.book_cover.setPixmap(pix)
except Exception, e: self.show_error(e, "Unable to change cover")
except Exception, e: Error("Unable to change cover", e)
def upload_books(self, to, files, ids):
def update_models():
hv = self.device_view.horizontalHeader()
col = hv.sortIndicatorSection()
order = hv.sortIndicatorOrder()
model = self.card_model if oncard else self.reader_model
model.sort(col, order)
if self.device_view.isVisible() and self.device_view.model() == model: self.search.clear()
else: model.search("")
self.window.setCursor(Qt.WaitCursor)
oncard = False if to == "reader" else True
ename = "file"
booklists = (self.reader_model._orig_data, self.card_model._orig_data)
try:
if ids:
for id in ids:
formats = []
info = self.library_view.model().book_info(id, ["title", "authors", "cover"])
ename = info["title"]
for f in files:
if re.match("......_"+str(id)+"_", f):
formats.append(f)
file = None
try:
for format in self.dev.FORMATS:
for f in formats:
if extension(format) == format:
file = f
raise StopIteration()
except StopIteration: pass
if not file:
Error("The library does not have any compatible formats for " + ename)
continue
f = open(file, "rb")
self.status("Sending "+info["title"]+" to device")
try:
self.dev.add_book(f, "libprs500_"+str(id)+"."+extension(file), info, booklists, oncard=oncard)
update_models()
finally: f.close()
else:
for file in files:
ename = file
if extension(file) not in self.dev.FORMATS:
Error(ename + " is not in a supported format")
continue
info = { "title":file, "authors":"Unknown", cover:None }
f = open(file, "rb")
self.status("Sending "+info["title"]+" to device")
try:
self.dev.add_book(f, os.path.basename(file), info, booklists, oncard=oncard)
update_models()
finally: f.close()
except Exception, e:
Error("Unable to send "+ename+" to device", e)
finally: self.window.setCursor(Qt.WaitCursor)
def __init__(self, window, log_packets):
QObject.__init__(self)
@ -228,15 +292,12 @@ class MainWindow(QObject, Ui_MainWindow):
self.library_view.resizeColumnsToContents()
# Create Device tree
model = DeviceModel(self.device_tree)
QObject.connect(self.device_tree, SIGNAL("activated(QModelIndex)"), self.tree_clicked)
QObject.connect(self.device_tree, SIGNAL("clicked(QModelIndex)"), self.tree_clicked)
model = DeviceModel(self.device_tree)
QObject.connect(model, SIGNAL('books_dropped'), self.add_books)
QObject.connect(model, SIGNAL('upload_books'), self.upload_books)
self.device_tree.setModel(model)
self.device_tree.expand(model.indexFromItem(model.library))
self.device_tree.expand(model.indexFromItem(model.reader))
self.device_tree.expand(model.indexFromItem(model.card))
self.device_tree.hide_reader(True)
self.device_tree.hide_card(True)
# Create Device Book list
self.reader_model = DeviceBooksModel(window)
@ -252,8 +313,6 @@ class MainWindow(QObject, Ui_MainWindow):
QObject.connect(model, SIGNAL("dataChanged(QModelIndex, QModelIndex)"), self.resize_columns)
# Setup book display
self.BOOK_TEMPLATE = self.book_info.text()
self.BOOK_IMAGE = DEFAULT_BOOK_COVER
self.book_cover.hide()
self.book_info.hide()
@ -266,9 +325,10 @@ class MainWindow(QObject, Ui_MainWindow):
QObject.connect(self.book_cover, SIGNAL("cover_received(QPixmap)"), self.update_cover)
self.device_detector = self.startTimer(1000)
self.splitter.setStretchFactor(1,100)
self.search.setFocus(Qt.OtherFocusReason)
self.show_device(False)
self.df_template = self.df.text()
self.df.setText(self.df_template.arg("").arg("").arg(""))
window.show()
def timerEvent(self, e):
@ -307,26 +367,27 @@ class MainWindow(QObject, Ui_MainWindow):
self.window.setCursor(Qt.WaitCursor)
self.status("Connecting to device")
try:
space = self.dev.available_space()
info = self.dev.get_device_information(end_session=False)
except DeviceError:
self.dev.reconnect()
return
except ProtocolError, e:
traceback.print_exc(e)
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]))
space = self.dev.available_space(end_session=False)
sc = space[1][1] if space[1][1] else space[2][1]
self.df.setText("SONY Reader: " + human_readable(space[0][1]) + "<br><br>Storage card: " + human_readable(sc))
self.device_tree.model().update_free_space(space[0][1], sc)
self.is_connected = True
if space[1][2] > 0: card = "a:"
elif space[2][2] > 0: card = "b:"
else: card = None
if card: self.device_tree.hide_card(False)
if space[1][2] > 0: self.card = "a:"
elif space[2][2] > 0: self.card = "b:"
else: self.card = None
if self.card: self.device_tree.hide_card(False)
else: self.device_tree.hide_card(True)
self.device_tree.hide_reader(False)
self.status("Loading media list from SONY Reader")
self.reader_model.set_data(self.dev.books())
if card: self.status("Loading media list from Storage Card")
self.reader_model.set_data(self.dev.books(end_session=False))
if self.card: self.status("Loading media list from Storage Card")
self.card_model.set_data(self.dev.books(oncard=True))
self.progress(100)
self.window.setCursor(Qt.ArrowCursor)
@ -344,6 +405,8 @@ def main():
global DEFAULT_BOOK_COVER
DEFAULT_BOOK_COVER = QPixmap(":/default_cover")
window = QMainWindow()
window.setWindowIcon(QIcon(":/icon"))
installErrorHandler(QErrorMessage(window))
QCoreApplication.setOrganizationName("KovidsBrain")
QCoreApplication.setApplicationName("SONY Reader")
gui = MainWindow(window, options.log_packets)

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>878</width>
<height>759</height>
<width>728</width>
<height>711</height>
</rect>
</property>
<property name="sizePolicy" >
@ -22,14 +22,245 @@
<string>SONY Reader</string>
</property>
<widget class="QWidget" name="centralwidget" >
<layout class="QGridLayout" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="1" column="0" >
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="DeviceView" name="device_tree" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize" >
<size>
<width>10000</width>
<height>95</height>
</size>
</property>
<property name="verticalScrollBarPolicy" >
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy" >
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="dragDropMode" >
<enum>QAbstractItemView::DropOnly</enum>
</property>
<property name="flow" >
<enum>QListView::TopToBottom</enum>
</property>
<property name="spacing" >
<number>20</number>
</property>
<property name="viewMode" >
<enum>QListView::IconMode</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="df" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>&lt;b>libprs500&lt;/b> was created by &lt;b>Kovid Goyal&lt;/b> &amp;copy; 2006&lt;br>&lt;br>%1 %2 %3</string>
</property>
<property name="textFormat" >
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="0" column="0" >
<widget class="DeviceBooksView" name="device_view" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="dragEnabled" >
<bool>true</bool>
</property>
<property name="dragDropOverwriteMode" >
<bool>false</bool>
</property>
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="selectionBehavior" >
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid" >
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="LibraryBooksView" name="library_view" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>10</verstretch>
</sizepolicy>
</property>
<property name="acceptDrops" >
<bool>true</bool>
</property>
<property name="dragEnabled" >
<bool>true</bool>
</property>
<property name="dragDropOverwriteMode" >
<bool>false</bool>
</property>
<property name="dragDropMode" >
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="selectionBehavior" >
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label" >
<property name="text" >
<string>&amp;Search:</string>
</property>
<property name="buddy" >
<cstring>search</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="search" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="acceptDrops" >
<bool>false</bool>
</property>
<property name="toolTip" >
<string>Search the list of books by title or author&lt;br>&lt;br>Words separated by spaces are ANDed</string>
</property>
<property name="whatsThis" >
<string>Search the list of books by title or author&lt;br>&lt;br>Words separated by spaces are ANDed</string>
</property>
<property name="autoFillBackground" >
<bool>false</bool>
</property>
<property name="text" >
<string/>
</property>
<property name="frame" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="clear_button" >
<property name="toolTip" >
<string>Reset Quick Search</string>
</property>
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="images.qrc" >:/images/clear.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="CoverDisplay" name="book_cover" >
<property name="maximumSize" >
<size>
<width>60</width>
<height>80</height>
</size>
</property>
<property name="acceptDrops" >
<bool>true</bool>
</property>
<property name="pixmap" >
<pixmap resource="images.qrc" >:/images/cherubs.jpg</pixmap>
</property>
<property name="scaledContents" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="book_info" >
<property name="text" >
<string>&lt;table>&lt;tr>&lt;td>&lt;b>Title: &lt;/b>%1&lt;/td>&lt;td>&lt;b>&amp;nbsp;Size:&lt;/b> %2&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;b>Author: &lt;/b>%3&lt;/td>&lt;td>&lt;b>&amp;nbsp;Type: &lt;/b>%4&lt;/td>&lt;/tr>&lt;/table></string>
</property>
<property name="textFormat" >
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QProgressBar" name="progress_bar" >
<property name="value" >
<number>100</number>
@ -39,246 +270,6 @@
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QSplitter" name="splitter" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="layoutWidget" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="DeviceView" name="device_tree" >
<property name="acceptDrops" >
<bool>true</bool>
</property>
<property name="dragDropMode" >
<enum>QAbstractItemView::DropOnly</enum>
</property>
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="rootIsDecorated" >
<bool>false</bool>
</property>
<property name="animated" >
<bool>true</bool>
</property>
<property name="allColumnsShowFocus" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="df" >
<property name="autoFillBackground" >
<bool>false</bool>
</property>
<property name="text" >
<string>Main Memory:&lt;br>&lt;br>Storage card:</string>
</property>
<property name="textFormat" >
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label" >
<property name="text" >
<string>&amp;Search:</string>
</property>
<property name="buddy" >
<cstring>search</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="search" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="acceptDrops" >
<bool>false</bool>
</property>
<property name="toolTip" >
<string>Search the list of books by title or author&lt;br>&lt;br>Words separated by spaces are ANDed</string>
</property>
<property name="whatsThis" >
<string>Search the list of books by title or author&lt;br>&lt;br>Words separated by spaces are ANDed</string>
</property>
<property name="autoFillBackground" >
<bool>false</bool>
</property>
<property name="text" >
<string/>
</property>
<property name="frame" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="clear_button" >
<property name="toolTip" >
<string>Reset Quick Search</string>
</property>
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="images.qrc" >:/images/clear.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="DeviceBooksView" name="device_view" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>13</hsizetype>
<vsizetype>13</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="dragEnabled" >
<bool>true</bool>
</property>
<property name="dragDropOverwriteMode" >
<bool>false</bool>
</property>
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="selectionBehavior" >
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid" >
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="LibraryBooksView" name="library_view" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>13</hsizetype>
<vsizetype>13</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="acceptDrops" >
<bool>true</bool>
</property>
<property name="dragEnabled" >
<bool>true</bool>
</property>
<property name="dragDropOverwriteMode" >
<bool>false</bool>
</property>
<property name="dragDropMode" >
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="selectionBehavior" >
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="CoverDisplay" name="book_cover" >
<property name="maximumSize" >
<size>
<width>60</width>
<height>80</height>
</size>
</property>
<property name="acceptDrops" >
<bool>true</bool>
</property>
<property name="text" >
<string/>
</property>
<property name="pixmap" >
<pixmap resource="images.qrc" >:/images/cherubs.jpg</pixmap>
</property>
<property name="scaledContents" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="book_info" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>10</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>&lt;table>&lt;tr>&lt;td>&lt;b>Title: &lt;/b>%1&lt;/td>&lt;td>&lt;b>&amp;nbsp;Size:&lt;/b> %2&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;b>Author: &lt;/b>%3&lt;/td>&lt;td>&lt;b>&amp;nbsp;Type: &lt;/b>%4&lt;/td>&lt;/tr></string>
</property>
<property name="textFormat" >
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QToolBar" name="tool_bar" >
@ -348,23 +339,23 @@
</action>
</widget>
<customwidgets>
<customwidget>
<class>DeviceBooksView</class>
<extends>QTableView</extends>
<header>widgets.h</header>
</customwidget>
<customwidget>
<class>CoverDisplay</class>
<extends>QLabel</extends>
<header>widgets.h</header>
</customwidget>
<customwidget>
<class>LibraryBooksView</class>
<extends>QTableView</extends>
<header>widgets.h</header>
</customwidget>
<customwidget>
<class>DeviceView</class>
<extends>QTreeView</extends>
<extends>QListView</extends>
<header>widgets.h</header>
</customwidget>
<customwidget>
<class>DeviceBooksView</class>
<class>LibraryBooksView</class>
<extends>QTableView</extends>
<header>widgets.h</header>
</customwidget>

View File

@ -15,7 +15,7 @@
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import Qt, SIGNAL
from PyQt4.Qt import QApplication, QString, QFont, QStandardItemModel, QStandardItem, QVariant, QAbstractTableModel, QTableView, QTreeView, QLabel,\
from PyQt4.Qt import QApplication, QString, QFont, QAbstractListModel, QVariant, QAbstractTableModel, QTableView, QListView, QLabel,\
QAbstractItemView, QPixmap, QIcon, QSize, QMessageBox, QSettings, QFileDialog, QErrorMessage, QDialog, QSpinBox, QPoint, QTemporaryFile, QDir, QFile, QIODevice,\
QPainterPath, QItemDelegate, QPainter, QPen, QColor, QLinearGradient, QBrush, QStyle,\
QStringList, QByteArray, QBuffer, QMimeData, QTextStream, QIODevice, QDrag, QRect
@ -28,25 +28,12 @@ from urllib import quote, unquote
from math import sin, cos, pi
from libprs500 import TEMPORARY_FILENAME_TEMPLATE as TFT
from libprs500.lrf.meta import LRFMetaFile
from libprs500.gui import Error, Warning
NONE = QVariant()
TIME_WRITE_FMT = "%d %b %Y"
COVER_HEIGHT = 80
def human_readable(size):
""" Convert a size in bytes into a human readable form """
if size < 1024: divisor, suffix = 1, "B"
elif size < 1024*1024: divisor, suffix = 1024., "KB"
elif size < 1024*1024*1024: divisor, suffix = 1024*1024, "MB"
elif size < 1024*1024*1024*1024: divisor, suffix = 1024*1024, "GB"
size = str(size/divisor)
if size.find(".") > -1: size = size[:size.find(".")+2]
return size + " " + suffix
def wrap(s, width=20):
return textwrap.fill(str(s), width)
class FileDragAndDrop(object):
@ -67,11 +54,11 @@ class FileDragAndDrop(object):
for url in candidates:
o = urlparse(url)
if o.scheme and o.scheme != 'file':
print >>sys.stderr, o.scheme, " not supported in drop events"
Warning(o.scheme + " not supported in drop events")
continue
path = unquote(o.path)
if not os.access(path, os.R_OK):
print >>sys.stderr, "You do not have read permission for: " + path
Warning("You do not have read permission for: " + path)
continue
if os.path.isdir(path):
root, dirs, files2 = os.walk(path)
@ -81,20 +68,23 @@ class FileDragAndDrop(object):
else: files.append(path)
return files
def __init__(self, QtBaseClass):
def __init__(self, QtBaseClass, enable_drag=True):
self.QtBaseClass = QtBaseClass
self.enable_drag = enable_drag
def mousePressEvent(self, event):
self.QtBaseClass.mousePressEvent(self, event)
if event.button == Qt.LeftButton:
self._drag_start_position = event.pos()
if self.enable_drag:
if event.button == Qt.LeftButton:
self._drag_start_position = event.pos()
def mouseMoveEvent(self, event):
self.QtBaseClass.mousePressEvent(self, event)
if event.buttons() & Qt.LeftButton != Qt.LeftButton: return
if (event.pos() - self._drag_start_position).manhattanLength() < QApplication.startDragDistance(): return
self.start_drag(self._drag_start_position)
if self.enable_drag:
if event.buttons() & Qt.LeftButton != Qt.LeftButton: return
if (event.pos() - self._drag_start_position).manhattanLength() < QApplication.startDragDistance(): return
self.start_drag(self._drag_start_position)
def start_drag(self, pos): pass
@ -108,9 +98,14 @@ class FileDragAndDrop(object):
def dropEvent(self, event):
files = self._get_r_ok_files(event)
if files:
if self.files_dropped(files, event): event.acceptProposedAction()
try:
if self.files_dropped(files, event): event.acceptProposedAction()
except Exception, e:
Error("There was an error processing the dropped files.", e)
raise e
def files_dropped(self, files): return False
def files_dropped(self, files, event): return False
def drag_object_from_files(self, files):
if files:
@ -138,8 +133,26 @@ class FileDragAndDrop(object):
return self.drag_object_from_files(files), self._dragged_files
class TableView(QTableView):
def renderToPixmap(self, indices):
class TableView(FileDragAndDrop, QTableView):
def __init__(self, parent):
FileDragAndDrop.__init__(self, QTableView)
QTableView.__init__(self, parent)
@classmethod
def wrap(cls, s, width=20): return textwrap.fill(str(s), width)
@classmethod
def human_readable(cls, size):
""" Convert a size in bytes into a human readable form """
if size < 1024: divisor, suffix = 1, "B"
elif size < 1024*1024: divisor, suffix = 1024., "KB"
elif size < 1024*1024*1024: divisor, suffix = 1024*1024, "MB"
elif size < 1024*1024*1024*1024: divisor, suffix = 1024*1024, "GB"
size = str(size/divisor)
if size.find(".") > -1: size = size[:size.find(".")+2]
return size + " " + suffix
def render_to_pixmap(self, indices):
rect = self.visualRect(indices[0])
rects = []
for i in range(len(indices)):
@ -157,8 +170,15 @@ class TableView(QTableView):
painter.end()
return pixmap
def drag_object_from_files(self, files):
drag = FileDragAndDrop.drag_object_from_files(self, files)
drag.setPixmap(self.render_to_pixmap(self.selectedIndexes()))
return drag
class TemporaryFile(QTemporaryFile):
_file_name = ""
def __del__(self):
if os.access(self.name, os.F_OK): os.remove(self.name)
def __init__(self, ext=""):
if ext: ext = "." + ext
path = QDir.tempPath() + "/" + TFT + "_XXXXXX"+ext
@ -202,31 +222,38 @@ class CoverDisplay(FileDragAndDrop, QLabel):
file.close()
drag.start(Qt.MoveAction)
class DeviceView(QTreeView):
class DeviceView(FileDragAndDrop, QListView):
def __init__(self, parent):
QTreeView.__init__(self, parent)
self.header().hide()
self.setIconSize(QSize(32,32))
FileDragAndDrop.__init__(self, QListView, enable_drag=False)
QListView.__init__(self, parent)
def hide_reader(self, x):
self.setRowHidden(2, self.model().indexFromItem(self.model().invisibleRootItem()), x)
self.model().update_devices(reader=not x)
def hide_card(self, x):
self.setRowHidden(4, self.model().indexFromItem(self.model().invisibleRootItem()), x)
self.model().update_devices(card=not x)
def files_dropped(self, files, event):
ids = []
md = event.mimeData()
if md.hasFormat("application/x-libprs500-id"):
ids = [ int(id) for id in FileDragAndDrop._bytes_to_string(md.data("application/x-libprs500-id")).split()]
index = self.indexAt(event.pos())
if index.isValid():
return self.model().files_dropped(files, index, ids)
class DeviceBooksView(TableView):
def __init__(self, parent):
QTableView.__init__(self, parent)
TableView.__init__(self, parent)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSortingEnabled(True)
class LibraryBooksView(FileDragAndDrop, TableView):
class LibraryBooksView(TableView):
def __init__(self, parent):
FileDragAndDrop.__init__(self, QTableView)
QTableView.__init__(self, parent)
TableView.__init__(self, parent)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSortingEnabled(True)
self.setItemDelegate(LibraryDelegate(self))
self.setItemDelegate(LibraryDelegate(self, rating_column=4))
def dragEnterEvent(self, event):
if not event.mimeData().hasFormat("application/x-libprs500-id"):
@ -242,7 +269,6 @@ class LibraryBooksView(FileDragAndDrop, TableView):
if drag:
ids = [ str(self.model().id_from_index(index)) for index in indexes ]
drag.mimeData().setData("application/x-libprs500-id", QByteArray("\n".join(ids)))
drag.setPixmap(self.renderToPixmap(indexes))
drag.start()
@ -261,8 +287,9 @@ class LibraryDelegate(QItemDelegate):
SIZE = 16
PEN = QPen(COLOR, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
def __init__(self, parent):
QItemDelegate.__init__(self, parent)
def __init__(self, parent, rating_column=-1):
QItemDelegate.__init__(self, parent )
self.rating_column = rating_column
self.star_path = QPainterPath()
self.star_path.moveTo(90, 50)
for i in range(1, 5):
@ -277,13 +304,13 @@ class LibraryDelegate(QItemDelegate):
def sizeHint(self, option, index):
if index.column() != 4:
if index.column() != self.rating_column:
return QItemDelegate.sizeHint(self, option, index)
num = index.model().data(index, Qt.DisplayRole).toInt()[0]
return QSize(num*(self.SIZE), self.SIZE+4)
def paint(self, painter, option, index):
if index.column() != 4:
if index.column() != self.rating_column:
return QItemDelegate.paint(self, painter, option, index)
num = index.model().data(index, Qt.DisplayRole).toInt()[0]
def draw_star():
@ -343,14 +370,13 @@ class LibraryDelegate(QItemDelegate):
class LibraryBooksModel(QAbstractTableModel):
FIELDS = ["id", "title", "authors", "size", "date", "rating", "publisher", "tags"]
FIELDS = ["id", "title", "authors", "size", "date", "rating", "publisher", "tags", "comments"]
TIME_READ_FMT = "%Y-%m-%d %H:%M:%S"
def __init__(self, parent):
QAbstractTableModel.__init__(self, parent)
self.db = None
self._data = None
self._orig_data = None
self.image_file = None
def extract_formats(self, indices):
files, rows = [], []
@ -359,7 +385,8 @@ class LibraryBooksModel(QAbstractTableModel):
if row in rows: continue
else: rows.append(row)
id = self.id_from_index(index)
basename = re.sub("\n", "", self._data[row]["title"]+" by "+ self._data[row]["authors"])
au = self._data[row]["authors"] if self._data[row]["authors"] else "Unknown"
basename = re.sub("\n", "", "_"+str(id)+"_"+self._data[row]["title"]+" by "+ au)
exts = self.db.get_extensions(id)
for ext in exts:
fmt = self.db.get_format(id, ext)
@ -393,7 +420,7 @@ class LibraryBooksModel(QAbstractTableModel):
self.emit(SIGNAL('formats_added'), index)
def rowCount(self, parent): return len(self._data)
def columnCount(self, parent): return len(self.FIELDS)-2
def columnCount(self, parent): return len(self.FIELDS)-3
def setData(self, index, value, role):
done = False
@ -457,9 +484,11 @@ class LibraryBooksModel(QAbstractTableModel):
pix = QPixmap()
pix.loadFromData(cover, "", Qt.AutoColor)
cover = None if pix.isNull() else pix
au = row["authors"]
if not au: au = "Unknown"
return row["title"], au, human_readable(int(row["size"])), exts, cover
tags = row["tags"]
if not tags: tags = ""
comments = row["comments"]
if not comments: comments = ""
return exts, tags, comments, cover
def id_from_index(self, index): return self._data[index.row()]["id"]
@ -471,6 +500,9 @@ class LibraryBooksModel(QAbstractTableModel):
break
self.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), self.index(row, 0), self.index(row, self.columnCount(0)-1))
def book_info(self, id, cols=["title", "authors", "cover"]):
return self.db.get_row_by_id(id, cols)
def data(self, index, role):
if role == Qt.DisplayRole or role == Qt.EditRole:
row, col = index.row(), index.column()
@ -481,15 +513,15 @@ class LibraryBooksModel(QAbstractTableModel):
if r < 0: r= 0
if r > 5: r=5
return QVariant(r)
if col == 0: text = wrap(row["title"], width=25)
if col == 0: text = TableView.wrap(row["title"], width=25)
elif col == 1:
au = row["authors"]
if au : text = wrap(re.sub("&", "\n", au), width=25)
elif col == 2: text = human_readable(row["size"])
if au : text = TableView.wrap(re.sub("&", "\n", au), width=25)
elif col == 2: text = TableView.human_readable(row["size"])
elif col == 3: text = time.strftime(TIME_WRITE_FMT, time.strptime(row["date"], self.TIME_READ_FMT))
elif col == 5:
pub = row["publisher"]
if pub: text = wrap(pub, 20)
if pub: text = TableView.wrap(pub, 20)
if text == None: text = "Unknown"
return QVariant(text)
elif role == Qt.TextAlignmentRole and index.column() in [2,3,4]:
@ -582,9 +614,9 @@ class DeviceBooksModel(QAbstractTableModel):
if role == Qt.DisplayRole:
row, col = index.row(), index.column()
book = self._data[row]
if col == 0: text = wrap(book.title, width=40)
if col == 0: text = TableView.wrap(book.title, width=40)
elif col == 1: text = re.sub("&\s*","\n", book.author)
elif col == 2: text = human_readable(book.size)
elif col == 2: text = TableView.human_readable(book.size)
elif col == 3: text = time.strftime(TIME_WRITE_FMT, book.datetime)
return QVariant(text)
elif role == Qt.TextAlignmentRole and index.column() in [2,3]:
@ -602,7 +634,7 @@ class DeviceBooksModel(QAbstractTableModel):
except:
traceback.print_exc()
au = row.author if row.author else "Unknown"
return row.title, au, human_readable(row.size), row.mime, cover
return row.title, au, TableView.human_readable(row.size), row.mime, cover
def sort(self, col, order):
def getter(key, func): return lambda x : func(attrgetter(key)(x))
@ -653,30 +685,61 @@ class DeviceBooksModel(QAbstractTableModel):
class DeviceModel(QStandardItemModel):
def __init__(self, parent):
QStandardItemModel.__init__(self, parent)
root = self.invisibleRootItem()
font = QFont()
font.setBold(True)
self.library = QStandardItem(QIcon(":/library"), QString("Library"))
self.reader = QStandardItem(QIcon(":/reader"), "SONY Reader")
self.card = QStandardItem(QIcon(":/card"), "Storage Card")
self.library.setFont(font)
self.reader.setFont(font)
self.card.setFont(font)
self.blank = QStandardItem("")
self.blank.setFlags(Qt.ItemFlags())
root.appendRow(self.library)
root.appendRow(self.blank)
root.appendRow(self.reader)
root.appendRow(self.blank.clone())
root.appendRow(self.card)
self.library.appendRow(QStandardItem("Books"))
self.reader.appendRow(QStandardItem("Books"))
self.card.appendRow(QStandardItem("Books"))
class DeviceModel(QAbstractListModel):
memory_free = 0
card_free = 0
show_reader = False
show_card = False
def update_devices(self, reader=None, card=None):
if reader != None: self.show_reader = reader
if card != None: self.show_card = card
self.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), self.index(1), self.index(2))
def rowCount(self, parent): return 3
def update_free_space(self, reader, card):
self.memory_free = reader
self.card_free = card
self.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), self.index(1), self.index(2))
def data(self, index, role):
row = index.row()
data = NONE
if role == Qt.DisplayRole:
text = None
if row == 0: text = "Library"
if row == 1 and self.show_reader:
text = "Reader\n" + TableView.human_readable(self.memory_free) + " available"
elif row == 2 and self.show_card:
text = "Card\n" + TableView.human_readable(self.card_free) + " available"
if text: data = QVariant(text)
elif role == Qt.DecorationRole:
icon = None
if row == 0: icon = QIcon(":/library")
elif row == 1 and self.show_reader: icon = QIcon(":/reader")
elif self.show_card: icon = QIcon(":/card")
if icon: data = QVariant(icon)
elif role == Qt.SizeHintRole:
if row == 1: return QVariant(QSize(150, 70))
elif role == Qt.FontRole:
font = QFont()
font.setBold(True)
data = QVariant(font)
return data
def is_library(self, index): return index.row() == 0
def is_reader(self, index): return index.row() == 1
def is_card(self, index): return index.row() == 2
def files_dropped(self, files, index, ids):
ret = False
if self.is_library(index) and not ids:
self.emit(SIGNAL("books_dropped"), files)
ret = True
elif self.is_reader(index):
self.emit(SIGNAL("upload_books"), "reader", files, ids)
elif self.is_card(index):
self.emit(SIGNAL("upload_books"), "card", files, ids)
return ret