Show path information for books in the library and Implement #1013 (Add "Next" and "Previous" buttons in the detailed view)

This commit is contained in:
Kovid Goyal 2008-09-15 14:10:38 -07:00
parent 8c53abe905
commit 5e236b8edb
6 changed files with 142 additions and 54 deletions

View File

@ -5,24 +5,68 @@ __docformat__ = 'restructuredtext en'
'''
'''
import textwrap
import textwrap, os
from PyQt4.QtCore import QCoreApplication
from PyQt4.QtGui import QDialog, QPixmap, QGraphicsScene, QIcon
from PyQt4.QtCore import QCoreApplication, SIGNAL, QModelIndex, QUrl
from PyQt4.QtGui import QDialog, QPixmap, QGraphicsScene, QIcon, QDesktopServices
from calibre.gui2.dialogs.book_info_ui import Ui_BookInfo
class BookInfo(QDialog, Ui_BookInfo):
def __init__(self, parent, info):
def __init__(self, parent, view, row):
QDialog.__init__(self, parent)
Ui_BookInfo.__init__(self)
self.setupUi(self)
self.setWindowTitle(info[_('Title')])
desktop = QCoreApplication.instance().desktop()
screen_height = desktop.availableGeometry().height() - 100
self.resize(self.size().width(), screen_height)
self.view = view
self.current_row = None
self.refresh(row)
self.connect(self.view.selectionModel(), SIGNAL('currentChanged(QModelIndex,QModelIndex)'), self.slave)
self.connect(self.next_button, SIGNAL('clicked()'), self.next)
self.connect(self.previous_button, SIGNAL('clicked()'), self.previous)
self.connect(self.text, SIGNAL('linkActivated(QString)'), self.open_book_path)
def slave(self, current, previous):
row = current.row()
self.refresh(row)
def open_book_path(self, path):
if os.sep in unicode(path):
QDesktopServices.openUrl(QUrl('file:'+path))
else:
format = unicode(path)
path = self.view.model().db.format_abspath(self.current_row, format)
if path is not None:
QDesktopServices.openUrl(QUrl('file:'+path))
def next(self):
row = self.view.currentIndex().row()
ni = self.view.model().index(row+1, 0)
if ni.isValid():
self.view.setCurrentIndex(ni)
def previous(self):
row = self.view.currentIndex().row()
ni = self.view.model().index(row-1, 0)
if ni.isValid():
self.view.setCurrentIndex(ni)
def refresh(self, row):
if isinstance(row, QModelIndex):
row = row.row()
if row == self.current_row:
return
self.previous_button.setEnabled(False if row == 0 else True)
self.next_button.setEnabled(False if row == self.view.model().rowCount(QModelIndex())-1 else True)
self.current_row = row
info = self.view.model().get_book_info(row)
self.setWindowTitle(info[_('Title')])
self.title.setText('<b>'+info.pop(_('Title')))
self.comments.setText(info.pop(_('Comments'), ''))
@ -37,6 +81,15 @@ class BookInfo(QDialog, Ui_BookInfo):
rows = u''
self.text.setText('')
self.data = info
if _('Path') in info.keys():
p = info[_('Path')]
info[_('Path')] = '<a href="%s">%s</a>'%(p, p)
if _('Formats') in info.keys():
formats = info[_('Formats')].split(',')
info[_('Formats')] = ''
for f in formats:
f = f.strip()
info[_('Formats')] += '<a href="%s">%s</a>, '%(f,f)
for key in info.keys():
txt = info[key]
txt = u'<br />\n'.join(textwrap.wrap(txt, 120))

View File

@ -6,14 +6,14 @@
<x>0</x>
<y>0</y>
<width>917</width>
<height>780</height>
<height>783</height>
</rect>
</property>
<property name="windowTitle" >
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" >
<item>
<layout class="QGridLayout" name="gridLayout" >
<item row="0" column="0" colspan="2" >
<widget class="QLabel" name="title" >
<property name="text" >
<string>TextLabel</string>
@ -23,51 +23,68 @@
</property>
</widget>
</item>
<item>
<widget class="QSplitter" name="splitter" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<widget class="QGraphicsView" name="cover" />
<widget class="QWidget" name="" >
<layout class="QVBoxLayout" >
<item row="1" column="0" >
<widget class="QGraphicsView" name="cover" />
</item>
<item row="1" column="1" >
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<widget class="QLabel" name="text" >
<property name="text" >
<string>TextLabel</string>
</property>
<property name="alignment" >
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Comments</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QTextBrowser" name="comments" />
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" >
<item>
<widget class="QLabel" name="text" >
<widget class="QPushButton" name="previous_button" >
<property name="text" >
<string>TextLabel</string>
<string>&amp;Previous</string>
</property>
<property name="alignment" >
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap" >
<bool>true</bool>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/previous.svg</normaloff>:/images/previous.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Comments</string>
<widget class="QPushButton" name="next_button" >
<property name="text" >
<string>&amp;Next</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/next.svg</normaloff>:/images/next.svg</iconset>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QTextBrowser" name="comments" />
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<resources>
<include location="../images.qrc" />
</resources>
<connections/>
</ui>

View File

@ -230,6 +230,7 @@ class BooksModel(QAbstractTableModel):
else:
formats = _('None')
data[_('Formats')] = formats
data[_('Path')] = self.db.abspath(idx)
comments = self.db.comments(idx)
if not comments:
comments = _('None')
@ -265,6 +266,8 @@ class BooksModel(QAbstractTableModel):
return data
def get_book_info(self, index):
if isinstance(index, int):
index = self.index(index, 0)
data = self.current_changed(index, None, False)
row = index.row()
data[_('Title')] = self.db.title(row)

View File

@ -1185,8 +1185,7 @@ in which you want to store your books files. Any existing books will be automati
return
index = self.library_view.currentIndex()
if index.isValid():
info = self.library_view.model().get_book_info(index)
BookInfo(self, info).show()
BookInfo(self, self.library_view, index).show()
############################################################################

View File

@ -73,7 +73,7 @@ class BookInfoDisplay(QFrame):
rows = u''
self.book_data.setText('')
self.data = data
self.data = data.copy()
for key in data.keys():
txt = data[key]
#txt = '<br />\n'.join(textwrap.wrap(txt, 120))

View File

@ -418,10 +418,17 @@ class LibraryDatabase2(LibraryDatabase):
def path(self, index, index_is_id=False):
'Return the relative path to the directory containing this books files as a unicode string.'
id = index if index_is_id else self.id()
id = index if index_is_id else self.id(index)
path = self.conn.execute('SELECT path FROM books WHERE id=?', (id,)).fetchone()[0].replace('/', os.sep)
return path
def abspath(self, index, index_is_id=False):
'Return the absolute path to the directory containing this books files as a unicode string.'
path = os.path.join(self.library_path, self.path(index, index_is_id=index_is_id))
if not os.path.exists(path):
os.makedirs(path)
return path
def construct_path_name(self, id):
'''
@ -550,13 +557,8 @@ class LibraryDatabase2(LibraryDatabase):
return ','.join(ans)
def format(self, index, format, index_is_id=False, as_file=False, mode='r+b'):
'''
Return the ebook format as a bytestring or `None` if the format doesn't exist,
or we don't have permission to write to the ebook file.
`as_file`: If True the ebook format is returned as a file object opened in `mode`
'''
def format_abspath(self, index, format, index_is_id=False):
'Return absolute path to the ebook file of format `format`'
id = index if index_is_id else self.id(index)
path = os.path.join(self.library_path, self.path(id, index_is_id=True))
name = self.conn.execute('SELECT name FROM data WHERE book=? AND format=?', (id, format)).fetchone()[0]
@ -564,8 +566,19 @@ class LibraryDatabase2(LibraryDatabase):
format = ('.' + format.lower()) if format else ''
path = os.path.join(path, name+format)
if os.access(path, os.R_OK|os.W_OK):
f = open(path, mode)
return f if as_file else f.read()
return path
def format(self, index, format, index_is_id=False, as_file=False, mode='r+b'):
'''
Return the ebook format as a bytestring or `None` if the format doesn't exist,
or we don't have permission to write to the ebook file.
`as_file`: If True the ebook format is returned as a file object opened in `mode`
'''
path = self.format_abspath(index, format, index_is_id=index_is_id)
if path is not None:
f = open(path, mode)
return f if as_file else f.read()
self.remove_format(id, format, index_is_id=True)
def add_format(self, index, format, stream, index_is_id=False, path=None):
@ -578,6 +591,9 @@ class LibraryDatabase2(LibraryDatabase):
name = self.construct_file_name(id)
ext = ('.' + format.lower()) if format else ''
dest = os.path.join(path, name+ext)
pdir = os.path.dirname(dest)
if not os.path.exists(pdir):
os.makedirs(pdir)
with open(dest, 'wb') as f:
shutil.copyfileobj(stream, f)
stream.seek(0, 2)