Created the form for editing book meta-info

Rejiggered the resource system so I can specify images from the resource file in QT Designer. This is a bit of a hack, and may not work when distributing via setp-tolls (especially with zip-safe)
This commit is contained in:
Kovid Goyal 2006-11-25 04:36:50 +00:00
parent c55638c6ec
commit 4cdf478efe
15 changed files with 2397 additions and 1618 deletions

389
libprs500/gui/editbook.ui Normal file
View File

@ -0,0 +1,389 @@
<ui version="4.0" >
<class>BookEditDialog</class>
<widget class="QDialog" name="BookEditDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>865</width>
<height>642</height>
</rect>
</property>
<property name="windowTitle" >
<string>Edit Meta Information</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="0" column="1" >
<widget class="QGroupBox" name="groupBox_3" >
<property name="title" >
<string>Available Formats</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="0" column="1" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="add_format" >
<property name="toolTip" >
<string>Add a new format for this book</string>
</property>
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="images.qrc" >:/images/plus.png</iconset>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>26</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="remove_format" >
<property name="toolTip" >
<string>Remove the selected formats for this book from the database.</string>
</property>
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="images.qrc" >:/images/minus.png</iconset>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="0" column="0" >
<widget class="QListWidget" name="formats" />
</item>
</layout>
</widget>
</item>
<item row="0" column="0" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Meta information</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="3" column="1" colspan="2" >
<widget class="QLineEdit" name="tags" >
<property name="toolTip" >
<string>Tags categorize the book. This is particularly useful while searching. &lt;br>&lt;br>They can be any words or phrases, separated by commas.</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2" >
<widget class="QLineEdit" name="publisher" >
<property name="toolTip" >
<string>Change the publisher of this book</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2" >
<widget class="QLineEdit" name="authors" >
<property name="toolTip" >
<string>Change the author(s) of this book. Multiple authors should be separated by the &amp; character</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2" >
<widget class="QLineEdit" name="title" >
<property name="toolTip" >
<string>Change the title of this book</string>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Ta&amp;gs: </string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy" >
<cstring>tags</cstring>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>&amp;Publisher: </string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy" >
<cstring>publisher</cstring>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>&amp;Author(s): </string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy" >
<cstring>authors</cstring>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>&amp;Title: </string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy" >
<cstring>title</cstring>
</property>
</widget>
</item>
<item row="5" column="2" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_5" >
<property name="text" >
<string>Change &amp;cover image:</string>
</property>
<property name="buddy" >
<cstring>cover_path</cstring>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLineEdit" name="cover_path" />
</item>
<item>
<widget class="QToolButton" name="cover_button" >
<property name="toolTip" >
<string>Browse for an image to use as the cover of this book.</string>
</property>
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="images.qrc" >:/images/fileopen.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="6" column="2" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="2" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>21</height>
</size>
</property>
</spacer>
</item>
<item rowspan="3" row="4" column="0" colspan="2" >
<widget class="QLabel" name="cover" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize" >
<size>
<width>100</width>
<height>120</height>
</size>
</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>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<string>Comments</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="0" column="0" >
<widget class="QTextEdit" name="comments" />
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="1" column="0" colspan="2" >
<widget class="QDialogButtonBox" name="button_box" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="images.qrc" />
</resources>
<connections>
<connection>
<sender>button_box</sender>
<signal>accepted()</signal>
<receiver>BookEditDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>button_box</sender>
<signal>rejected()</signal>
<receiver>BookEditDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

File diff suppressed because it is too large Load Diff

12
libprs500/gui/images.qrc Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="default_cover">images/cherubs.jpg</file>
<file alias="library">images/mycomputer.png</file>
<file alias="reader">images/reader.png</file>
<file>images/clear.png</file>
<file>images/minus.png</file>
<file>images/plus.png</file>
<file>images/edit.png</file>
<file>images/fileopen.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

1838
libprs500/gui/images_rc.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,6 @@ from libprs500.communicate import PRS500Device as device
from libprs500.errors import *
from libprs500.lrf.meta import LRFMetaFile, LRFException
from database import LibraryDatabase
import images
from PyQt4.QtCore import Qt, SIGNAL
from PyQt4.Qt import QObject, QThread, QCoreApplication, QEventLoop, QString, QStandardItem, QStandardItemModel, QStatusBar, QVariant, QAbstractTableModel, \
QAbstractItemView, QImage, QPixmap, QIcon, QSize, QMessageBox, QSettings, QFileDialog, QErrorMessage
@ -29,6 +28,7 @@ import xml.dom.minidom as dom
from xml.dom.ext import PrettyPrint as PrettyPrint
from operator import itemgetter
DEFAULT_BOOK_COVER = None
NONE = QVariant()
TIME_WRITE_FMT = "%d %b %Y"
COVER_HEIGHT = 80
@ -50,13 +50,12 @@ def wrap(s, width=20):
class LibraryBooksModel(QAbstractTableModel):
FIELDS = ["id", "title", "authors", "size", "date", "publisher", "tags"]
TIME_READ_FMT = "%Y-%m-%d %H:%M:%S"
def __init__(self, parent, db_path):
def __init__(self, parent):
QAbstractTableModel.__init__(self, parent)
self.db = LibraryDatabase(db_path)
self._data = self.db.get_table(self.FIELDS)
self._orig_data = self._data
self.db = None
self._data = None
self._orig_data = None
self.image_file = None
self.sort(0, Qt.DescendingOrder)
def rowCount(self, parent): return len(self._data)
def columnCount(self, parent): return len(self.FIELDS)-2
@ -86,7 +85,7 @@ class LibraryBooksModel(QAbstractTableModel):
cover = self.db.get_cover(row["id"])
exts = ",".join(self.db.get_extensions(row["id"]))
if not cover:
cover = QPixmap(":/images/book.png")
cover = DEFAULT_BOOK_COVER
self.image_file = None
else:
pix = QPixmap()
@ -206,7 +205,7 @@ class DeviceBooksModel(QAbstractTableModel):
cover = pix.scaledToHeight(COVER_HEIGHT, Qt.SmoothTransformation)
except Exception, e:
self.image_file = None
cover = QPixmap(":/images/book.png")
cover = DEFAULT_BOOK_COVER
return row["title"], row["author"], human_readable(int(row["size"])), row["mime"], cover
def sort(self, col, order):
@ -256,13 +255,26 @@ class DeviceBooksModel(QAbstractTableModel):
ui = pkg_resources.resource_stream(__name__, "main.ui")
sys.path.append(os.path.dirname(ui.name))
Ui_MainWindow, bclass = uic.loadUiType(pkg_resources.resource_stream(__name__, "main.ui"))
class MainWindow(QObject, Ui_MainWindow):
def show_device(self, yes):
""" If C{yes} show the items on the device otherwise show the items in the library """
self.device_view.clearSelection(), self.library_view.clearSelection()
self.book_cover.hide(), self.book_info.hide()
if yes:
self.device_view.show(), self.library_view.hide()
self.current_view = self.device_view
else:
self.device_view.hide(), self.library_view.show()
self.current_view = self.device_view
def tree_clicked(self, index):
def show_device(yes):
if yes: self.device_view.show(), self.library_view.hide()
else: self.device_view.hide(), self.library_view.show()
show_device = self.show_device
item = self.tree.itemFromIndex(index)
text = str(item.text())
if text == "Library":
@ -305,11 +317,10 @@ class MainWindow(QObject, Ui_MainWindow):
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=":/images/book.png">')
except Exception, e: self.book_cover.setToolTip('<img src=":/default_cover">')
self.book_cover.show()
self.book_info.show()
def clear(self, checked): self.search.setText("")
def list_context_event(self, event):
print "TODO:"
@ -399,6 +410,9 @@ class MainWindow(QObject, Ui_MainWindow):
except LRFException: pass
self.library_model.add(file, title, author, publisher, cover)
def edit(self, action):
pass
def show_error(self, e, msg):
QErrorMessage(self.window).showMessage(msg+"<br><b>Error: </b>"+str(e)+"<br><br>Traceback:<br>"+traceback.format_exc(e))
@ -414,8 +428,10 @@ class MainWindow(QObject, Ui_MainWindow):
self.read_settings()
# Setup Library Book list
self.library_model = LibraryBooksModel(window, str(self.database_path))
self.library_model = LibraryBooksModel(window)
self.library_model.set_data(LibraryDatabase(str(self.database_path)))
self.library_view.setModel(self.library_model)
self.current_view = self.library_view
self.library_view.setSelectionBehavior(QAbstractItemView.SelectRows)
self.library_view.setSortingEnabled(True)
self.library_view.contextMenuEvent = self.list_context_event
@ -431,7 +447,7 @@ class MainWindow(QObject, Ui_MainWindow):
# Create Device list
self.tree = QStandardItemModel()
library = QStandardItem(QString("Library"))
library.setIcon(QIcon(":/images/mycomputer.png"))
library.setIcon(QIcon(":/library"))
font = library.font()
font.setBold(True)
self.tree.appendRow(library)
@ -447,7 +463,7 @@ class MainWindow(QObject, Ui_MainWindow):
mc = QStandardItem(QString("Storage Card"))
mc.appendRow(QStandardItem(QString("Books")))
self.reader.appendRow(mc)
self.reader.setIcon(QIcon(":/images/reader.png"))
self.reader.setIcon(QIcon(":/reader"))
self.tree.appendRow(self.reader)
self.reader.setFont(font)
self.treeView.setModel(self.tree)
@ -472,24 +488,18 @@ class MainWindow(QObject, Ui_MainWindow):
QObject.connect(self.device_model, SIGNAL("sorted()"), self.model_modified)
QObject.connect(self.device_model, SIGNAL("searched()"), self.model_modified)
QObject.connect(self.device_model, SIGNAL("deleted()"), self.model_modified)
self.clearButton.setIcon(QIcon(":/images/clear.png"))
QObject.connect(self.clearButton, SIGNAL("clicked(bool)"), self.clear)
self.device_view.hide()
# Setup book display
self.BOOK_TEMPLATE = self.book_info.text()
self.BOOK_IMAGE = QPixmap(":/images/book.png")
self.BOOK_IMAGE = DEFAULT_BOOK_COVER
self.book_cover.hide()
self.book_info.hide()
# Populate toolbar
self.add_action = self.tool_bar.addAction(QIcon(":/images/fileopen.png"), "Add files to Library")
self.add_action.setShortcut(Qt.Key_A)
QObject.connect(self.add_action, SIGNAL("triggered(bool)"), self.add)
self.del_action = self.tool_bar.addAction(QIcon(":/images/delete.png"), "Delete selected items")
self.del_action.setShortcut(Qt.Key_Delete)
QObject.connect(self.del_action, SIGNAL("triggered(bool)"), self.delete)
# Connect actions
QObject.connect(self.action_add, SIGNAL("triggered(bool)"), self.add)
QObject.connect(self.action_del, SIGNAL("triggered(bool)"), self.delete)
QObject.connect(self.action_edit, SIGNAL("triggered(bool)"), self.edit)
self.device_detector = self.startTimer(1000)
self.splitter.setStretchFactor(0,0)
@ -573,7 +583,14 @@ class MainWindow(QObject, Ui_MainWindow):
def main():
from PyQt4.Qt import QApplication, QMainWindow
app = QApplication(sys.argv)
global DEFAULT_BOOK_COVER
DEFAULT_BOOK_COVER = QPixmap(":/default_cover")
window = QMainWindow()
def handle_exceptions(t, val, tb):
sys.__excepthook__(t, val, tb)
try: QErrorMessage(window).showMessage("There was an unexpected error: <br>"+"<br>".join(traceback.format_exception(t, val, tb)))
except: pass
sys.excepthook = handle_exceptions
QCoreApplication.setOrganizationName("KovidsBrain")
QCoreApplication.setApplicationName("prs500-gui")
gui = MainWindow(window)

View File

@ -44,7 +44,7 @@
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="" >
<widget class="QWidget" name="layoutWidget" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
@ -100,7 +100,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="" >
<widget class="QWidget" name="layoutWidget" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
@ -160,13 +160,16 @@
</widget>
</item>
<item>
<widget class="QToolButton" name="clearButton" >
<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>
@ -219,8 +222,20 @@
</property>
<item>
<widget class="QLabel" name="book_cover" >
<property name="maximumSize" >
<size>
<width>60</width>
<height>80</height>
</size>
</property>
<property name="text" >
<string>TextLabel</string>
<string/>
</property>
<property name="pixmap" >
<pixmap resource="images.qrc" >:/images/cherubs.jpg</pixmap>
</property>
<property name="scaledContents" >
<bool>true</bool>
</property>
</widget>
</item>
@ -251,6 +266,12 @@
</layout>
</widget>
<widget class="QToolBar" name="tool_bar" >
<property name="minimumSize" >
<size>
<width>49</width>
<height>37</height>
</size>
</property>
<property name="movable" >
<bool>false</bool>
</property>
@ -266,9 +287,69 @@
<attribute name="toolBarArea" >
<number>4</number>
</attribute>
<addaction name="action_add" />
<addaction name="action_del" />
<addaction name="action_edit" />
</widget>
<action name="action_add" >
<property name="icon" >
<iconset resource="images.qrc" >:/images/plus.png</iconset>
</property>
<property name="text" >
<string>Add files to Library</string>
</property>
<property name="shortcut" >
<string>a</string>
</property>
<property name="autoRepeat" >
<bool>false</bool>
</property>
</action>
<action name="action_del" >
<property name="icon" >
<iconset resource="images.qrc" >:/images/minus.png</iconset>
</property>
<property name="text" >
<string>Delete selected items</string>
</property>
<property name="shortcut" >
<string>Delete</string>
</property>
</action>
<action name="action_edit" >
<property name="icon" >
<iconset resource="images.qrc" >:/images/edit.png</iconset>
</property>
<property name="text" >
<string>Edit meta-information for the currently selected items</string>
</property>
<property name="shortcut" >
<string>e</string>
</property>
<property name="autoRepeat" >
<bool>false</bool>
</property>
</action>
</widget>
<includes/>
<resources/>
<connections/>
<resources>
<include location="images.qrc" />
</resources>
<connections>
<connection>
<sender>clear_button</sender>
<signal>clicked()</signal>
<receiver>search</receiver>
<slot>clear()</slot>
<hints>
<hint type="sourcelabel" >
<x>853</x>
<y>61</y>
</hint>
<hint type="destinationlabel" >
<x>784</x>
<y>58</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Project SYSTEM "Project-4.0.dtd">
<!-- eric4 project file for project prs-500 -->
<!-- Saved: 2006-11-20, 20:22:57 -->
<!-- Saved: 2006-11-24, 20:24:29 -->
<!-- Copyright (C) 2006 Kovid Goyal, kovid@kovidgoyal.net -->
<Project version="4.0">
<ProgLanguage mixed="0">Python</ProgLanguage>
@ -55,6 +55,21 @@
<Dir>gui</Dir>
<Name>__init__.py</Name>
</Source>
<Source>
<Dir>libprs500</Dir>
<Dir>lrf</Dir>
<Name>meta.py</Name>
</Source>
<Source>
<Dir>libprs500</Dir>
<Dir>lrf</Dir>
<Name>__init__.py</Name>
</Source>
<Source>
<Dir>libprs500</Dir>
<Dir>gui</Dir>
<Name>database.py</Name>
</Source>
</Sources>
<Forms>
<Form>
@ -62,6 +77,11 @@
<Dir>gui</Dir>
<Name>main.ui</Name>
</Form>
<Form>
<Dir>libprs500</Dir>
<Dir>gui</Dir>
<Name>editbook.ui</Name>
</Form>
</Forms>
<Translations>
</Translations>
@ -205,7 +225,7 @@
<FiletypeAssociation pattern="*.ui.h" type="FORMS" />
<FiletypeAssociation pattern="*.ui" type="FORMS" />
<FiletypeAssociation pattern="*.idl" type="INTERFACES" />
<FiletypeAssociation pattern="*.py" type="SOURCES" />
<FiletypeAssociation pattern="*.ptl" type="SOURCES" />
<FiletypeAssociation pattern="*.py" type="SOURCES" />
</FiletypeAssociations>
</Project>

View File

@ -34,7 +34,10 @@ setup(name='libprs500',
libprs500 is library to interface with the `SONY Portable Reader`_ over USB_.
It provides methods to list the contents of the file system on the device,
as well as copy files from and to the device.
It also provides a command line and a graphical user interface via the script prs500.py.
It also provides a command line and a graphical user interface via the commands prs500 and
prs500-gui.
In addition libprs500 has a utility to read/write the metadata from LRF files (unencrypted books in the SONY BBeB format). A command line
interface to this is provided via the command lrf-meta.
For SVN access: svn co https://kovidgoyal.net/svn/code/prs-500