mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Created conversion dialog.
This commit is contained in:
parent
653cd41d50
commit
22e3f9aaf9
@ -18,7 +18,7 @@ __docformat__ = "epytext"
|
||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
__appname__ = 'libprs500'
|
||||
|
||||
import sys, os, logging
|
||||
import sys, os, logging, mechanize
|
||||
iswindows = 'win32' in sys.platform.lower()
|
||||
isosx = 'darwin' in sys.platform.lower()
|
||||
|
||||
@ -75,3 +75,12 @@ def extract(path, dir):
|
||||
if not extractor:
|
||||
raise Exception('Unknown archive type')
|
||||
extractor(path, dir)
|
||||
|
||||
def browser():
|
||||
opener = mechanize.Browser()
|
||||
opener.set_handle_refresh(True)
|
||||
opener.set_handle_robots(False)
|
||||
opener.addheaders = [('User-agent', 'Mozilla/5.0 (X11; U; i686 Linux; en_US; rv:1.8.0.4) Gecko/20060508 Firefox/1.5.0.4')]
|
||||
return opener
|
||||
|
||||
|
@ -72,14 +72,10 @@ def option_parser(usage):
|
||||
parser = OptionParser(usage=usage, version=__appname__+' '+__version__,
|
||||
epilog='Created by '+__author__)
|
||||
metadata = parser.add_option_group('METADATA OPTIONS')
|
||||
metadata.add_option('--header', action='store_true', default=False, dest='header',
|
||||
help='Add a header to all the pages with title and author.')
|
||||
metadata.add_option('--headerformat', default="%t by %a", dest='headerformat', type='string',
|
||||
help='Set the format of the header. %a is replaced by the author and %t by the title. Default is %default')
|
||||
metadata.add_option("-t", "--title", action="store", type="string", default=None,\
|
||||
dest="title", help="Set the title. Default: filename.")
|
||||
metadata.add_option("-a", "--author", action="store", type="string", \
|
||||
dest="author", help="Set the author. Default: %default", default='Unknown')
|
||||
dest="author", help="Set the author(s). Multiple authors should be set as a comma separated list. Default: %default", default='Unknown')
|
||||
metadata.add_option("--comment", action="store", type="string", \
|
||||
dest="freetext", help="Set the comment.", default=' ')
|
||||
metadata.add_option("--category", action="store", type="string", \
|
||||
@ -90,14 +86,14 @@ def option_parser(usage):
|
||||
help='Sort key for the author')
|
||||
metadata.add_option('--publisher', action='store', default='Unknown', dest='publisher',
|
||||
help='Publisher')
|
||||
metadata.add_option('--cover', action='store', dest='cover', default=None, \
|
||||
help='Path to file containing image to be used as cover')
|
||||
profiles=['prs500']
|
||||
parser.add_option('-o', '--output', action='store', default=None, \
|
||||
help='Output file name. Default is derived from input filename')
|
||||
parser.add_option('--ignore-tables', action='store_true', default=False, dest='ignore_tables',
|
||||
help='Render HTML tables as blocks of text instead of actual tables. This is neccessary if the HTML contains very large or complex tables.')
|
||||
laf = parser.add_option_group('LOOK AND FEEL')
|
||||
laf.add_option('--cover', action='store', dest='cover', default=None, \
|
||||
help='Path to file containing image to be used as cover')
|
||||
laf.add_option('--font-delta', action='store', type='float', default=0., \
|
||||
help="""Increase the font size by 2 * FONT_DELTA pts and """
|
||||
'''the line spacing by FONT_DELTA pts. FONT_DELTA can be a fraction.'''
|
||||
@ -109,12 +105,19 @@ def option_parser(usage):
|
||||
help='Set the space between words in pts. Default is %default')
|
||||
laf.add_option('--blank-after-para', action='store_true', default=False,
|
||||
dest='blank_after_para', help='Separate paragraphs by blank lines.')
|
||||
laf.add_option('--header', action='store_true', default=False, dest='header',
|
||||
help='Add a header to all the pages with title and author.')
|
||||
laf.add_option('--headerformat', default="%t by %a", dest='headerformat', type='string',
|
||||
help='Set the format of the header. %a is replaced by the author and %t by the title. Default is %default')
|
||||
|
||||
page = parser.add_option_group('PAGE OPTIONS')
|
||||
page.add_option('-p', '--profile', default=PRS500_PROFILE, dest='profile', type='choice',
|
||||
choices=profiles, action='callback', callback=profile_from_string,
|
||||
help='''Profile of the target device for which this LRF is '''
|
||||
'''being generated. Default: ''' + profiles[0] + \
|
||||
''' Supported profiles: '''+', '.join(profiles))
|
||||
'''being generated. The profile determines things like the '''
|
||||
'''resolution and screen size of the target device. '''
|
||||
'''Default: ''' + profiles[0] + ''' Supported profiles: '''+\
|
||||
', '.join(profiles))
|
||||
page.add_option('--left-margin', default=20, dest='left_margin', type='int',
|
||||
help='''Left margin of page. Default is %default px.''')
|
||||
page.add_option('--right-margin', default=20, dest='right_margin', type='int',
|
||||
@ -134,14 +137,14 @@ def option_parser(usage):
|
||||
'''matches will be ignored. Defaults to %default''')
|
||||
chapter = parser.add_option_group('CHAPTER OPTIONS')
|
||||
chapter.add_option('--disable-chapter-detection', action='store_false',
|
||||
default=True, dest='chapter_detection',
|
||||
default=False, dest='disable_chapter_detection',
|
||||
help='''Prevent html2lrf from automatically inserting page breaks'''
|
||||
''' before what it thinks are chapters.''')
|
||||
chapter.add_option('--chapter-regex', dest='chapter_regex',
|
||||
default='chapter|book|appendix',
|
||||
help='''The regular expression used to detect chapter titles.'''
|
||||
''' It is searched for in heading tags. Defaults to %default''')
|
||||
chapter.add_option('--page-break-before', dest='page_break', default='h[12]',
|
||||
chapter.add_option('--page-break-before-tag', dest='page_break', default='h[12]',
|
||||
help='''If html2lrf does not find any page breaks in the '''
|
||||
'''html file and cannot detect chapter headings, it will '''
|
||||
'''automatically insert page-breaks before the tags whose '''
|
||||
@ -151,8 +154,8 @@ def option_parser(usage):
|
||||
'''there are no really long pages as this degrades the page '''
|
||||
'''turn performance of the LRF. Thus this option is ignored '''
|
||||
'''if the current page has only a few elements.''')
|
||||
chapter.add_option('--force-page-break-before', dest='force_page_break',
|
||||
default='$', help='Like --page-break-before, but page breaks are forced.')
|
||||
chapter.add_option('--force-page-break-before-tag', dest='force_page_break',
|
||||
default='$', help='Force a page break before tags whoose names match this regular expression.')
|
||||
chapter.add_option('--force-page-break-before-attr', dest='force_page_break_attr',
|
||||
default='$,,$', help='Force a page break before an element having the specified attribute. The format for this option is tagname regexp,attribute name,attribute value regexp. For example to match all heading tags that have the attribute class="chapter" you would use "h\d,class,chapter". Default is %default''')
|
||||
prepro = parser.add_option_group('PREPROCESSING OPTIONS')
|
||||
|
@ -1,4 +1,6 @@
|
||||
UI = main_ui.py dialogs/metadata_single_ui.py dialogs/metadata_bulk_ui.py dialogs/jobs_ui.py dialogs/conversion_error_ui.py
|
||||
UI = main_ui.py dialogs/metadata_single_ui.py dialogs/metadata_bulk_ui.py dialogs/jobs_ui.py \
|
||||
dialogs/conversion_error_ui.py dialogs/lrf_single_ui.py dialogs/choose_format_ui.py \
|
||||
dialogs/password_ui.py
|
||||
RC = images_rc.pyc
|
||||
|
||||
%_ui.py : %.ui
|
||||
|
@ -41,7 +41,7 @@ def error_dialog(parent, title, msg):
|
||||
return d
|
||||
|
||||
def qstring_to_unicode(q):
|
||||
return unicode(q.toUtf8(), 'utf8')
|
||||
return unicode(q)
|
||||
|
||||
def human_readable(size):
|
||||
""" Convert a size in bytes into a human readable form """
|
||||
|
@ -102,6 +102,7 @@ class DeviceManager(QObject):
|
||||
'''Upload books to device'''
|
||||
def upload_books(updater, files, names, on_card=False):
|
||||
'''Upload books to device: '''
|
||||
self.device.set_progress_reporter(updater)
|
||||
return self.device.upload_books(files, names, on_card, end_session=False)
|
||||
return upload_books
|
||||
|
||||
|
@ -13,20 +13,3 @@
|
||||
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
'''Various dialogs used in the GUI'''
|
||||
|
||||
from PyQt4.QtCore import QObject
|
||||
from PyQt4.QtGui import QDialog
|
||||
|
||||
class Dialog(QObject):
|
||||
def __init__(self, window):
|
||||
QObject.__init__(self, window)
|
||||
self.dialog = QDialog(window)
|
||||
self.accept = self.dialog.accept
|
||||
self.reject = self.dialog.reject
|
||||
self._close_event = self.dialog.closeEvent
|
||||
self.dialog.closeEvent = self.close_event
|
||||
self.window = window
|
||||
self.isVisible = self.dialog.isVisible
|
||||
|
||||
def close_event(self, e):
|
||||
e.accept()
|
||||
|
38
src/libprs500/gui2/dialogs/choose_format.py
Normal file
38
src/libprs500/gui2/dialogs/choose_format.py
Normal file
@ -0,0 +1,38 @@
|
||||
## Copyright (C) 2007 Kovid Goyal kovid@kovidgoyal.net
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 2 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## 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.QtGui import QDialog, QListWidgetItem
|
||||
|
||||
from libprs500.gui2 import file_icon_provider
|
||||
from libprs500.gui2.dialogs.choose_format_ui import Ui_ChooseFormatDialog
|
||||
|
||||
class ChooseFormatDialog(QDialog, Ui_ChooseFormatDialog):
|
||||
|
||||
def __init__(self, window, msg, formats):
|
||||
QDialog.__init__(self, window)
|
||||
Ui_ChooseFormatDialog.__init__(self)
|
||||
self.setupUi(self)
|
||||
|
||||
self.msg.setText(msg)
|
||||
for format in formats:
|
||||
self.formats.addItem(QListWidgetItem(file_icon_provider().icon_from_ext(format.lower()),
|
||||
format.upper()))
|
||||
self._formats = formats
|
||||
self.formats.setCurrentRow(0)
|
||||
|
||||
def format(self):
|
||||
self._formats[self.formats.currentRow()]
|
||||
|
||||
|
85
src/libprs500/gui2/dialogs/choose_format.ui
Normal file
85
src/libprs500/gui2/dialogs/choose_format.ui
Normal file
@ -0,0 +1,85 @@
|
||||
<ui version="4.0" >
|
||||
<class>ChooseFormatDialog</class>
|
||||
<widget class="QDialog" name="ChooseFormatDialog" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>507</width>
|
||||
<height>377</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Choose Format</string>
|
||||
</property>
|
||||
<property name="windowIcon" >
|
||||
<iconset resource="../images.qrc" >:/images/mimetypes/unknown.svg</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="msg" >
|
||||
<property name="text" >
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="formats" >
|
||||
<property name="iconSize" >
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../images.qrc" />
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ChooseFormatDialog</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>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ChooseFormatDialog</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>
|
@ -14,16 +14,21 @@
|
||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
''''''
|
||||
|
||||
from libprs500.gui2.dialogs import Dialog
|
||||
from PyQt4.QtGui import QDialog
|
||||
|
||||
from libprs500.gui2.dialogs.conversion_error_ui import Ui_ConversionErrorDialog
|
||||
|
||||
class ConversionErrorDialog(Dialog, Ui_ConversionErrorDialog):
|
||||
class ConversionErrorDialog(QDialog, Ui_ConversionErrorDialog):
|
||||
|
||||
def __init__(self, window, title, html):
|
||||
def __init__(self, window, title, html, show=False):
|
||||
QDialog.__init__(self, window)
|
||||
Ui_ConversionErrorDialog.__init__(self)
|
||||
Dialog.__init__(self, window)
|
||||
self.setupUi(self.dialog)
|
||||
html = '<html><body>' + html + '</body></html>'
|
||||
self.dialog.setWindowTitle(title)
|
||||
self.text.setHtml(html)
|
||||
self.dialog.show()
|
||||
self.setupUi(self)
|
||||
self.setWindowTitle(title)
|
||||
self.set_message(html)
|
||||
if show:
|
||||
self.show()
|
||||
|
||||
def set_message(self, html):
|
||||
self.text.setHtml('<html><body>%s</body></html'%(html,))
|
||||
|
@ -15,30 +15,23 @@
|
||||
'''Display active jobs'''
|
||||
|
||||
from PyQt4.QtCore import Qt, QObject, SIGNAL
|
||||
from PyQt4.QtGui import QDialog
|
||||
|
||||
from libprs500.gui2.dialogs import Dialog
|
||||
from libprs500.gui2.dialogs.jobs_ui import Ui_JobsDialog
|
||||
from libprs500 import __appname__
|
||||
|
||||
class JobsDialog(Ui_JobsDialog, Dialog):
|
||||
class JobsDialog(QDialog, Ui_JobsDialog):
|
||||
def __init__(self, window, model):
|
||||
QDialog.__init__(self, window)
|
||||
Ui_JobsDialog.__init__(self)
|
||||
Dialog.__init__(self, window)
|
||||
self.setupUi(self.dialog)
|
||||
self.setupUi(self)
|
||||
self.jobs_view.setModel(model)
|
||||
self.model = model
|
||||
self.dialog.setWindowModality(Qt.NonModal)
|
||||
self.dialog.setWindowTitle(__appname__ + ' - Active Jobs')
|
||||
self.setWindowModality(Qt.NonModal)
|
||||
self.setWindowTitle(__appname__ + ' - Active Jobs')
|
||||
QObject.connect(self.jobs_view.model(), SIGNAL('modelReset()'),
|
||||
self.jobs_view.resizeColumnsToContents)
|
||||
|
||||
def show(self):
|
||||
self.dialog.show()
|
||||
self.jobs_view.resizeColumnsToContents()
|
||||
|
||||
def hide(self):
|
||||
self.dialog.hide()
|
||||
|
||||
def close_event(self, e):
|
||||
def closeEvent(self, e):
|
||||
self.jobs_view.write_settings()
|
||||
e.accept()
|
||||
|
277
src/libprs500/gui2/dialogs/lrf_single.py
Normal file
277
src/libprs500/gui2/dialogs/lrf_single.py
Normal file
@ -0,0 +1,277 @@
|
||||
## Copyright (C) 2007 Kovid Goyal kovid@kovidgoyal.net
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 2 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## 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.
|
||||
import os
|
||||
|
||||
from PyQt4.QtCore import QObject, SIGNAL, Qt
|
||||
from PyQt4.QtGui import QAbstractSpinBox, QLineEdit, QCheckBox, QDialog, QPixmap
|
||||
|
||||
from libprs500.gui2.dialogs.lrf_single_ui import Ui_LRFSingleDialog
|
||||
from libprs500.gui2.dialogs.choose_format import ChooseFormatDialog
|
||||
from libprs500.gui2 import qstring_to_unicode, error_dialog, \
|
||||
pixmap_to_data, choose_images
|
||||
from libprs500.ebooks.lrf import option_parser
|
||||
|
||||
class LRFSingleDialog(QDialog, Ui_LRFSingleDialog):
|
||||
|
||||
PARSER = option_parser('')
|
||||
PREPROCESS_OPTIONS = [ o for o in PARSER.option_groups if o.title == 'PREPROCESSING OPTIONS'][0].option_list
|
||||
|
||||
@classmethod
|
||||
def options(cls):
|
||||
options = cls.PARSER.option_list
|
||||
for g in cls.PARSER.option_groups:
|
||||
options.extend(g.option_list)
|
||||
for opt in options:
|
||||
yield opt
|
||||
|
||||
@classmethod
|
||||
def option_to_name(cls, opt):
|
||||
src = opt.get_opt_string()
|
||||
return 'gui_' + src[2:].replace('-', '_')
|
||||
|
||||
def __init__(self, window, db, row):
|
||||
QDialog.__init__(self, window)
|
||||
Ui_LRFSingleDialog.__init__(self)
|
||||
self.setupUi(self)
|
||||
self.categoryList.setCurrentRow(0)
|
||||
QObject.connect(self.categoryList, SIGNAL('itemEntered(QListWidgetItem *)'),
|
||||
self.show_category_help)
|
||||
QObject.connect(self.cover_button, SIGNAL("clicked(bool)"), self.select_cover)
|
||||
self.categoryList.leaveEvent = self.reset_help
|
||||
self.reset_help()
|
||||
self.setup_tooltips()
|
||||
self.initialize_options()
|
||||
self.db = db
|
||||
self.row = row.row()
|
||||
self.id = self.db.id(self.row)
|
||||
self.cover_changed = False
|
||||
self.cpixmap = None
|
||||
self.changed = False
|
||||
self.read_saved_options()
|
||||
self.initialize_metadata()
|
||||
formats = self.db.formats(self.row)
|
||||
if not formats:
|
||||
d = error_dialog(self, 'No availabla formats', 'Cannot convert as this book has not available formats')
|
||||
d.exec_()
|
||||
formats = [i.upper() for i in formats.split(',')]
|
||||
self.selected_format = None
|
||||
try:
|
||||
formats.remove('LRF')
|
||||
except ValueError:
|
||||
pass
|
||||
if len(formats) > 1:
|
||||
d = ChooseFormatDialog(self, 'Choose the format to convert into LRF', formats)
|
||||
d.exec_()
|
||||
if d.result() == QDialog.Accepted:
|
||||
self.selected_format = d.format()
|
||||
else:
|
||||
self.selected_format = formats[0]
|
||||
if self.selected_format:
|
||||
self.setWindowTitle('Convert %s to LRF'%(self.selected_format,))
|
||||
|
||||
|
||||
def read_saved_options(self):
|
||||
cmdline = self.db.conversion_options(self.id, 'lrf')
|
||||
print 1, cmdline
|
||||
if cmdline:
|
||||
for opt in self.options():
|
||||
try:
|
||||
i = cmdline.index(opt.get_opt_string())
|
||||
except ValueError:
|
||||
continue
|
||||
guiname = self.option_to_name(opt)
|
||||
try:
|
||||
obj = getattr(self, guiname)
|
||||
except AttributeError:
|
||||
continue
|
||||
if isinstance(obj, QCheckBox):
|
||||
obj.setCheckState(Qt.Checked)
|
||||
elif isinstance(obj, QAbstractSpinBox):
|
||||
obj.setValue(cmdline[i+1])
|
||||
elif isinstance(obj, QLineEdit):
|
||||
obj.setText(cmdline[i+1])
|
||||
profile = cmdline[cmdline.index('--profile')+1]
|
||||
self.gui_profile.setCurrentIndex(self.gui_profile.findText(profile))
|
||||
for prepro in self.PREPROCESS_OPTIONS:
|
||||
ops = prepro.get_opt_string()
|
||||
if ops in cmdline:
|
||||
self.preprocess.setCurrentIndex(self.preprocess.findText(ops[2:]))
|
||||
break
|
||||
|
||||
|
||||
def select_cover(self, checked):
|
||||
files = choose_images(self, 'change cover dialog',
|
||||
u'Choose cover for ' + qstring_to_unicode(self.title.text()))
|
||||
if not files:
|
||||
return
|
||||
_file = files[0]
|
||||
if _file:
|
||||
_file = os.path.abspath(_file)
|
||||
if not os.access(_file, os.R_OK):
|
||||
d = error_dialog(self.window, 'Cannot read',
|
||||
'You do not have permission to read the file: ' + _file)
|
||||
d.exec_()
|
||||
return
|
||||
cf, cover = None, None
|
||||
try:
|
||||
cf = open(_file, "rb")
|
||||
cover = cf.read()
|
||||
except IOError, e:
|
||||
d = error_dialog(self.window, 'Error reading file',
|
||||
"<p>There was an error reading from file: <br /><b>" + _file + "</b></p><br />"+str(e))
|
||||
d.exec_()
|
||||
if cover:
|
||||
pix = QPixmap()
|
||||
pix.loadFromData(cover)
|
||||
if pix.isNull():
|
||||
d = error_dialog(self.window, _file + " is not a valid picture")
|
||||
d.exec_()
|
||||
else:
|
||||
self.cover_path.setText(_file)
|
||||
self.cover.setPixmap(pix)
|
||||
self.cover_changed = True
|
||||
self.cpixmap = pix
|
||||
|
||||
def initialize_metadata(self):
|
||||
db, row = self.db, self.row
|
||||
self.id = self.db.id(row)
|
||||
self.gui_title.setText(db.title(row))
|
||||
au = self.db.authors(row)
|
||||
self.gui_author.setText(au if au else '')
|
||||
aus = self.db.author_sort(row)
|
||||
self.gui_author_sort.setText(aus if aus else '')
|
||||
pub = self.db.publisher(row)
|
||||
self.gui_publisher.setText(pub if pub else '')
|
||||
tags = self.db.tags(row)
|
||||
self.tags.setText(tags if tags else '')
|
||||
comments = self.db.comments(row)
|
||||
self.gui_comment.setPlainText(comments if comments else '')
|
||||
cover = self.db.cover(row)
|
||||
if cover:
|
||||
pm = QPixmap()
|
||||
pm.loadFromData(cover)
|
||||
if not pm.isNull():
|
||||
self.cover.setPixmap(pm)
|
||||
|
||||
def initialize_options(self):
|
||||
'''Initialize non metadata options from the defaults.'''
|
||||
for name in self.option_map.keys():
|
||||
default = self.option_map[name].default
|
||||
obj = getattr(self, name)
|
||||
if isinstance(obj, QAbstractSpinBox):
|
||||
obj.setValue(default)
|
||||
elif isinstance(obj, QLineEdit) and default:
|
||||
obj.setText(default)
|
||||
elif isinstance(obj, QCheckBox):
|
||||
state = Qt.Checked if default else Qt.Unchecked
|
||||
obj.setCheckState(state)
|
||||
self.gui_headerformat.setDisabled(True)
|
||||
self.preprocess.addItem('No preprocessing')
|
||||
for opt in self.PREPROCESS_OPTIONS:
|
||||
self.preprocess.addItem(opt.get_opt_string()[2:])
|
||||
ph = 'Preprocess the file before converting to LRF. This is useful if you know that the file is from a specific source. Known sources:'
|
||||
ph += '<ol><li><b>baen</b> - Books from BAEN Publishers</li>'
|
||||
ph += '<li><b>pdftohtml</b> - HTML files that are the output of the program pdftohtml</li>'
|
||||
self.preprocess.setToolTip(ph)
|
||||
self.preprocess.setWhatsThis(ph)
|
||||
for profile in self.PARSER.get_option('--profile').choices:
|
||||
if self.gui_profile.findText(profile) < 0:
|
||||
self.gui_profile.addItem(profile)
|
||||
|
||||
def setup_tooltips(self):
|
||||
def show_item_help(obj, event):
|
||||
self.set_help(obj.toolTip())
|
||||
|
||||
self.option_map = {}
|
||||
for opt in self.options():
|
||||
try:
|
||||
help = opt.help.replace('%default', str(opt.default))
|
||||
except (ValueError, TypeError):
|
||||
help = opt.help
|
||||
|
||||
guiname = self.option_to_name(opt)
|
||||
if hasattr(self, guiname):
|
||||
obj = getattr(self, guiname)
|
||||
obj.setToolTip(help)
|
||||
obj.setWhatsThis(help)
|
||||
self.option_map[guiname] = opt
|
||||
obj.__class__.enterEvent = show_item_help
|
||||
obj.leaveEvent = self.reset_help
|
||||
self.preprocess.__class__.enterEvent = show_item_help
|
||||
self.preprocess.leaveEvent = self.reset_help
|
||||
|
||||
|
||||
def show_category_help(self, item):
|
||||
text = qstring_to_unicode(item.text())
|
||||
help = {
|
||||
u'Metadata' : 'Specify metadata such as title and author for the book.<p>Metadata will be updated in the database as well as the generated LRF file.',
|
||||
u'Look & Feel' : 'Adjust the look of the generated LRF file by specifying things like font sizes and the spacing between words.',
|
||||
u'Page Setup' : 'Specify the page settings like margins and the screen size of the target device.',
|
||||
u'Chapter Detection' : 'Fine tune the detection of chapter and section headings.',
|
||||
}
|
||||
self.set_help(help[text])
|
||||
|
||||
def set_help(self, msg):
|
||||
self.help_view.setHtml('<html><body>%s</body></html>'%(msg,))
|
||||
|
||||
def reset_help(self, *args):
|
||||
self.set_help('<font color="gray">No help available</font>')
|
||||
if args:
|
||||
args[0].accept()
|
||||
|
||||
def build_commandline(self):
|
||||
cmd = []
|
||||
for name in self.option_map.keys():
|
||||
opt = self.option_map[name].get_opt_string()
|
||||
obj = getattr(self, name)
|
||||
if isinstance(obj, QAbstractSpinBox):
|
||||
cmd.extend([opt, obj.value()])
|
||||
elif isinstance(obj, QLineEdit):
|
||||
val = qstring_to_unicode(obj.text())
|
||||
if val:
|
||||
cmd.extend([opt, val])
|
||||
elif isinstance(obj, QCheckBox):
|
||||
if obj.checkState() == Qt.Checked:
|
||||
cmd.append(opt)
|
||||
|
||||
text = qstring_to_unicode(self.preprocess.currentText())
|
||||
if text != 'No preprocessing':
|
||||
cmd.append('--'+text)
|
||||
cmd.extend(['--profile', qstring_to_unicode(self.gui_profile.currentText())])
|
||||
return cmd
|
||||
|
||||
def write_metadata(self):
|
||||
title = qstring_to_unicode(self.gui_title.text())
|
||||
self.db.set_title(self.id, title)
|
||||
au = qstring_to_unicode(self.gui_author.text()).split(',')
|
||||
if au: self.db.set_authors(self.id, au)
|
||||
aus = qstring_to_unicode(self.gui_author_sort.text())
|
||||
if aus: self.db.set_author_sort(self.id, aus)
|
||||
print self.db.author_sort(self.row)
|
||||
self.db.set_publisher(self.id, qstring_to_unicode(self.gui_publisher.text()))
|
||||
self.db.set_tags(self.id, qstring_to_unicode(self.tags.text()).split(','))
|
||||
self.db.set_series(self.id, qstring_to_unicode(self.series.currentText()))
|
||||
self.db.set_series_index(self.id, self.series_index.value())
|
||||
if self.cover_changed:
|
||||
self.db.set_cover(self.id, pixmap_to_data(self.cover.pixmap()))
|
||||
|
||||
|
||||
def accept(self):
|
||||
cmdline = self.build_commandline()
|
||||
# TODO: put cover into tempfile
|
||||
self.write_metadata()
|
||||
self.db.set_conversion_options(self.id, 'lrf', cmdline)
|
||||
QDialog.accept(self)
|
||||
|
948
src/libprs500/gui2/dialogs/lrf_single.ui
Normal file
948
src/libprs500/gui2/dialogs/lrf_single.ui
Normal file
@ -0,0 +1,948 @@
|
||||
<ui version="4.0" >
|
||||
<class>LRFSingleDialog</class>
|
||||
<widget class="QDialog" name="LRFSingleDialog" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>850</width>
|
||||
<height>671</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Convert to LRF</string>
|
||||
</property>
|
||||
<property name="windowIcon" >
|
||||
<iconset resource="../images.qrc" >:/images/convert.svg</iconset>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item rowspan="2" row="0" column="0" >
|
||||
<widget class="QGroupBox" name="category" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title" >
|
||||
<string>Category</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QListWidget" name="categoryList" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Expanding" hsizetype="Minimum" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font" >
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="mouseTracking" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="showDropIndicator" stdset="0" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="selectionBehavior" >
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="iconSize" >
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="textElideMode" >
|
||||
<enum>Qt::ElideLeft</enum>
|
||||
</property>
|
||||
<property name="movement" >
|
||||
<enum>QListView::Snap</enum>
|
||||
</property>
|
||||
<property name="flow" >
|
||||
<enum>QListView::TopToBottom</enum>
|
||||
</property>
|
||||
<property name="isWrapping" stdset="0" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>40</number>
|
||||
</property>
|
||||
<property name="viewMode" >
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
<property name="uniformItemSizes" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Metadata</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="../images.qrc" >:/images/metadata.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Look & Feel</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="../images.qrc" >:/images/lookfeel.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Page Setup</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="../images.qrc" >:/images/page.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Chapter Detection</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="../images.qrc" >:/images/chapters.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QGroupBox" name="groupBox_3" >
|
||||
<property name="title" >
|
||||
<string>Options</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QStackedWidget" name="stack" >
|
||||
<property name="currentIndex" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="metadata_page" >
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<string>&Title: </string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_title</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="4" >
|
||||
<widget class="QLineEdit" name="gui_title" >
|
||||
<property name="toolTip" >
|
||||
<string>Change the title of this book</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<string>&Author(s): </string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_author</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2" >
|
||||
<widget class="QLineEdit" name="gui_author" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip" >
|
||||
<string>Change the author(s) of this book. Multiple authors should be separated by a comma</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3" >
|
||||
<widget class="QLabel" name="label_6" >
|
||||
<property name="text" >
|
||||
<string>So&rt:</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_author_sort</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4" >
|
||||
<widget class="QLineEdit" name="gui_author_sort" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip" >
|
||||
<string>Change the author(s) of this book. Multiple authors should be separated by a comma</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QLabel" name="label_3" >
|
||||
<property name="text" >
|
||||
<string>&Publisher: </string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_publisher</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="4" >
|
||||
<widget class="QLineEdit" name="gui_publisher" >
|
||||
<property name="toolTip" >
|
||||
<string>Change the publisher of this book</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" >
|
||||
<widget class="QLabel" name="label_4" >
|
||||
<property name="text" >
|
||||
<string>Ta&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="3" column="1" colspan="4" >
|
||||
<widget class="QLineEdit" name="tags" >
|
||||
<property name="toolTip" >
|
||||
<string>Tags categorize the book. This is particularly useful while searching. <br><br>They can be any words or phrases, separated by commas.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" >
|
||||
<widget class="QLabel" name="label_7" >
|
||||
<property name="text" >
|
||||
<string>&Series:</string>
|
||||
</property>
|
||||
<property name="textFormat" >
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>series</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" >
|
||||
<widget class="QComboBox" name="series" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
|
||||
<horstretch>2</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip" >
|
||||
<string>List of known series. You can add new series.</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string>List of known series. You can add new series.</string>
|
||||
</property>
|
||||
<property name="editable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="insertPolicy" >
|
||||
<enum>QComboBox::InsertAlphabetically</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy" >
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2" colspan="3" >
|
||||
<widget class="QSpinBox" name="series_index" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip" >
|
||||
<string>Series index.</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string>Series index.</string>
|
||||
</property>
|
||||
<property name="prefix" >
|
||||
<string>Book </string>
|
||||
</property>
|
||||
<property name="minimum" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2" >
|
||||
<widget class="QGroupBox" name="groupBox_2" >
|
||||
<property name="title" >
|
||||
<string>Comments</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QTextEdit" name="gui_comment" />
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2" colspan="3" >
|
||||
<widget class="QGroupBox" name="groupBox_4" >
|
||||
<property name="title" >
|
||||
<string>Book Cover</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>81</width>
|
||||
<height>181</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="cover" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>180</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap resource="../images.qrc" >:/images/book.svg</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>71</width>
|
||||
<height>181</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5" >
|
||||
<property name="text" >
|
||||
<string>Change &cover image:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>cover_path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="cover_path" >
|
||||
<property name="readOnly" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</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/document_open.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="lookandfeel_page" >
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" colspan="3" >
|
||||
<widget class="QLabel" name="label_8" >
|
||||
<property name="text" >
|
||||
<string>&Font delta:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_font_delta</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QDoubleSpinBox" name="gui_font_delta" >
|
||||
<property name="buttonSymbols" >
|
||||
<enum>QAbstractSpinBox::PlusMinus</enum>
|
||||
</property>
|
||||
<property name="suffix" >
|
||||
<string> pts</string>
|
||||
</property>
|
||||
<property name="decimals" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="minimum" >
|
||||
<double>-5.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep" >
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3" >
|
||||
<widget class="QLabel" name="label_9" >
|
||||
<property name="text" >
|
||||
<string>&Word spacing:</string>
|
||||
</property>
|
||||
<property name="textFormat" >
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_wordspace</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3" >
|
||||
<widget class="QDoubleSpinBox" name="gui_wordspace" >
|
||||
<property name="buttonSymbols" >
|
||||
<enum>QAbstractSpinBox::PlusMinus</enum>
|
||||
</property>
|
||||
<property name="suffix" >
|
||||
<string> pts</string>
|
||||
</property>
|
||||
<property name="decimals" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="minimum" >
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep" >
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<double>2.500000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QLabel" name="label_16" >
|
||||
<property name="text" >
|
||||
<string>&Preprocess:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>preprocess</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2" colspan="2" >
|
||||
<widget class="QComboBox" name="preprocess" />
|
||||
</item>
|
||||
<item row="3" column="0" colspan="4" >
|
||||
<widget class="QGroupBox" name="groupBox_5" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Minimum" hsizetype="Preferred" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title" >
|
||||
<string>Header</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QCheckBox" name="gui_header" >
|
||||
<property name="text" >
|
||||
<string>&Show header</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_10" >
|
||||
<property name="text" >
|
||||
<string>&Header format:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_headerformat</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLineEdit" name="gui_headerformat" />
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="3" >
|
||||
<widget class="QCheckBox" name="gui_disable_autorotation" >
|
||||
<property name="text" >
|
||||
<string>Disable auto &rotation of images</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="3" >
|
||||
<widget class="QCheckBox" name="gui_blank_after_para" >
|
||||
<property name="text" >
|
||||
<string>Insert &blank lines between paragraphs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="3" >
|
||||
<widget class="QCheckBox" name="gui_ignore_tables" >
|
||||
<property name="text" >
|
||||
<string>Ignore &tables</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>41</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="pagesetup_page" >
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label_11" >
|
||||
<property name="text" >
|
||||
<string>&Profile:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_profile</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QComboBox" name="gui_profile" >
|
||||
<property name="currentIndex" >
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="minimumContentsLength" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_12" >
|
||||
<property name="text" >
|
||||
<string>&Left Margin:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_left_margin</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QSpinBox" name="gui_left_margin" >
|
||||
<property name="suffix" >
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QLabel" name="label_13" >
|
||||
<property name="text" >
|
||||
<string>&Right Margin:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_right_margin</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" >
|
||||
<widget class="QSpinBox" name="gui_right_margin" >
|
||||
<property name="suffix" >
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" >
|
||||
<widget class="QLabel" name="label_14" >
|
||||
<property name="text" >
|
||||
<string>&Top Margin:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_top_margin</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" >
|
||||
<widget class="QSpinBox" name="gui_top_margin" >
|
||||
<property name="suffix" >
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" >
|
||||
<widget class="QLabel" name="label_15" >
|
||||
<property name="text" >
|
||||
<string>&Bottom Margin:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_bottom_margin</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" >
|
||||
<widget class="QSpinBox" name="gui_bottom_margin" >
|
||||
<property name="suffix" >
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="chapterdetection_page" >
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_6" >
|
||||
<property name="title" >
|
||||
<string>Title based detection</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QCheckBox" name="gui_disable_chapter_detection" >
|
||||
<property name="text" >
|
||||
<string>&Disable chapter detection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_17" >
|
||||
<property name="text" >
|
||||
<string>&Regular expression:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_chapter_regex</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLineEdit" name="gui_chapter_regex" />
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_7" >
|
||||
<property name="title" >
|
||||
<string>Tag based detection</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label_18" >
|
||||
<property name="text" >
|
||||
<string>&Page break before tag:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_page_break_before_tag</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLineEdit" name="gui_page_break_before_tag" />
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_19" >
|
||||
<property name="text" >
|
||||
<string>&Force page break before tag:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_force_page_break_before_tag</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLineEdit" name="gui_force_page_break_before_tag" />
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QLabel" name="label_20" >
|
||||
<property name="text" >
|
||||
<string>Force page break before &attribute:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_force_page_break_before_attr</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" >
|
||||
<widget class="QLineEdit" name="gui_force_page_break_before_attr" />
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_5" />
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QGroupBox" name="groupBox" >
|
||||
<property name="title" >
|
||||
<string>Help on item</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QTextBrowser" name="help_view" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>170</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="html" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" >
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
<property name="centerButtons" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../images.qrc" />
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>LRFSingleDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>516</x>
|
||||
<y>655</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>LRFSingleDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>584</x>
|
||||
<y>661</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>categoryList</sender>
|
||||
<signal>currentRowChanged(int)</signal>
|
||||
<receiver>stack</receiver>
|
||||
<slot>setCurrentIndex(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>245</x>
|
||||
<y>199</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>368</x>
|
||||
<y>185</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>gui_disable_chapter_detection</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>gui_chapter_regex</receiver>
|
||||
<slot>setDisabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>439</x>
|
||||
<y>97</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>539</x>
|
||||
<y>149</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>gui_header</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>gui_headerformat</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>398</x>
|
||||
<y>177</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>476</x>
|
||||
<y>211</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -16,15 +16,15 @@
|
||||
'''Dialog to edit metadata in bulk'''
|
||||
|
||||
from PyQt4.QtCore import SIGNAL, QObject
|
||||
from PyQt4.QtGui import QDialog
|
||||
|
||||
from libprs500.gui2 import qstring_to_unicode
|
||||
from libprs500.gui2.dialogs import Dialog
|
||||
from libprs500.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog
|
||||
|
||||
class MetadataBulkDialog(Ui_MetadataBulkDialog, Dialog):
|
||||
class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
||||
def __init__(self, window, rows, db):
|
||||
QDialog.__init__(self, window)
|
||||
Ui_MetadataBulkDialog.__init__(self)
|
||||
Dialog.__init__(self, window)
|
||||
self.setupUi(self.dialog)
|
||||
self.db = db
|
||||
self.ids = [ db.id(r) for r in rows]
|
||||
|
@ -18,13 +18,12 @@ add/remove formats
|
||||
'''
|
||||
import os
|
||||
|
||||
from PyQt4.QtCore import SIGNAL
|
||||
from PyQt4.Qt import QObject, QPixmap, QListWidgetItem, QErrorMessage
|
||||
from PyQt4.QtCore import SIGNAL, QObject
|
||||
from PyQt4.QtGui import QPixmap, QListWidgetItem, QErrorMessage, QDialog
|
||||
|
||||
|
||||
from libprs500.gui2 import qstring_to_unicode, error_dialog, file_icon_provider, \
|
||||
choose_files, pixmap_to_data, BOOK_EXTENSIONS, choose_images
|
||||
from libprs500.gui2.dialogs import Dialog
|
||||
from libprs500.gui2.dialogs.metadata_single_ui import Ui_MetadataSingleDialog
|
||||
|
||||
class Format(QListWidgetItem):
|
||||
@ -34,10 +33,10 @@ class Format(QListWidgetItem):
|
||||
QListWidgetItem.__init__(self, file_icon_provider().icon_from_ext(ext),
|
||||
ext.upper(), parent, QListWidgetItem.UserType)
|
||||
|
||||
class MetadataSingleDialog(Ui_MetadataSingleDialog, Dialog):
|
||||
class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
|
||||
|
||||
def select_cover(self, checked):
|
||||
files = choose_images(self.window, 'change cover dialog',
|
||||
files = choose_images(self, 'change cover dialog',
|
||||
u'Choose cover for ' + qstring_to_unicode(self.title.text()))
|
||||
if not files:
|
||||
return
|
||||
@ -71,7 +70,7 @@ class MetadataSingleDialog(Ui_MetadataSingleDialog, Dialog):
|
||||
|
||||
|
||||
def add_format(self, x):
|
||||
files = choose_files(self.window, 'add formats dialog',
|
||||
files = choose_files(self, 'add formats dialog',
|
||||
"Choose formats for " + str(self.title.text()),
|
||||
[('Books', BOOK_EXTENSIONS)])
|
||||
if not files:
|
||||
@ -120,9 +119,9 @@ class MetadataSingleDialog(Ui_MetadataSingleDialog, Dialog):
|
||||
self.db.remove_format(self.row, ext)
|
||||
|
||||
def __init__(self, window, row, db):
|
||||
Ui_MetadataSingleDialog.__init__(self)
|
||||
Dialog.__init__(self, window)
|
||||
self.setupUi(self.dialog)
|
||||
QDialog.__init__(self, window)
|
||||
Ui_MetadataSingleDialog.__init__(self)
|
||||
self.setupUi(self)
|
||||
self.splitter.setStretchFactor(100, 1)
|
||||
self.db = db
|
||||
self.id = db.id(row)
|
||||
@ -138,8 +137,6 @@ class MetadataSingleDialog(Ui_MetadataSingleDialog, Dialog):
|
||||
self.add_format)
|
||||
QObject.connect(self.remove_format_button, SIGNAL("clicked(bool)"), \
|
||||
self.remove_format)
|
||||
QObject.connect(self.button_box, SIGNAL("accepted()"), \
|
||||
self.sync)
|
||||
|
||||
self.title.setText(db.title(row))
|
||||
au = self.db.authors(row)
|
||||
@ -190,18 +187,18 @@ class MetadataSingleDialog(Ui_MetadataSingleDialog, Dialog):
|
||||
QObject.connect(self.series, SIGNAL('editTextChanged(QString)'), self.enable_series_index)
|
||||
|
||||
|
||||
self.dialog.exec_()
|
||||
self.exec_()
|
||||
|
||||
def enable_series_index(self, *args):
|
||||
self.series_index.setEnabled(True)
|
||||
|
||||
def sync(self):
|
||||
def accept(self):
|
||||
if self.formats_changed:
|
||||
self.sync_formats()
|
||||
title = qstring_to_unicode(self.title.text())
|
||||
self.db.set_title(self.id, title)
|
||||
au = qstring_to_unicode(self.authors.text()).split(',')
|
||||
self.db.set_authors(self.id, au)
|
||||
if au: self.db.set_authors(self.id, au)
|
||||
self.db.set_rating(self.id, 2*self.rating.value())
|
||||
self.db.set_publisher(self.id, qstring_to_unicode(self.publisher.text()))
|
||||
self.db.set_tags(self.id, qstring_to_unicode(self.tags.text()).split(','))
|
||||
@ -211,6 +208,5 @@ class MetadataSingleDialog(Ui_MetadataSingleDialog, Dialog):
|
||||
if self.cover_changed:
|
||||
self.db.set_cover(self.id, pixmap_to_data(self.cover.pixmap()))
|
||||
self.changed = True
|
||||
|
||||
def reject(self):
|
||||
self.rejected = True
|
||||
QDialog.accept(self)
|
||||
|
47
src/libprs500/gui2/dialogs/password.py
Normal file
47
src/libprs500/gui2/dialogs/password.py
Normal file
@ -0,0 +1,47 @@
|
||||
## Copyright (C) 2007 Kovid Goyal kovid@kovidgoyal.net
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 2 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## 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.QtGui import QDialog
|
||||
from PyQt4.QtCore import QSettings, QVariant
|
||||
|
||||
from libprs500.gui2.dialogs.password_ui import Ui_Dialog
|
||||
from libprs500.gui2 import qstring_to_unicode
|
||||
|
||||
class PasswordDialog(QDialog, Ui_Dialog):
|
||||
|
||||
def __init__(self, window, name, msg):
|
||||
QDialog.__init__(self, window)
|
||||
Ui_Dialog.__init__(self)
|
||||
self.setupUi(self)
|
||||
|
||||
settings = QSettings()
|
||||
un = settings.value(name+': un', QVariant('')).toString()
|
||||
pw = settings.value(name+': pw', QVariant('')).toString()
|
||||
self.gui_username.setText(un)
|
||||
self.gui_username.setText(pw)
|
||||
self.sname = name
|
||||
self.msg.setText(msg)
|
||||
|
||||
def username(self):
|
||||
return qstring_to_unicode(self.gui_username.text())
|
||||
|
||||
def password(self):
|
||||
return qstring_to_unicode(self.gui_password.text())
|
||||
|
||||
def accept(self):
|
||||
settings = QSettings()
|
||||
settings.setValue(self.sname+': un', QVariant(self.gui_username.text()))
|
||||
settings.setValue(self.sname+': pw', QVariant(self.gui_password.text()))
|
||||
QDialog.accept(self)
|
108
src/libprs500/gui2/dialogs/password.ui
Normal file
108
src/libprs500/gui2/dialogs/password.ui
Normal file
@ -0,0 +1,108 @@
|
||||
<ui version="4.0" >
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>350</width>
|
||||
<height>209</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Password needed</string>
|
||||
</property>
|
||||
<property name="windowIcon" >
|
||||
<iconset resource="../images.qrc" >:/images/mimetypes/unknown.svg</iconset>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLabel" name="msg" >
|
||||
<property name="text" >
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="openExternalLinks" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<string>&Username:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_username</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLineEdit" name="gui_username" />
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<string>&Password:</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>gui_password</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" >
|
||||
<widget class="QLineEdit" name="gui_password" >
|
||||
<property name="echoMode" >
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" >
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<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>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Dialog</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>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Dialog</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>
|
@ -1,4 +1,21 @@
|
||||
from libprs500.gui2 import TableView
|
||||
## Copyright (C) 2007 Kovid Goyal kovid@kovidgoyal.net
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 2 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## 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.QtGui import QStackedWidget
|
||||
|
||||
from libprs500.gui2 import TableView, qstring_to_unicode
|
||||
|
||||
class JobsView(TableView):
|
||||
pass
|
||||
pass
|
||||
|
@ -1,8 +1,10 @@
|
||||
<RCC>
|
||||
<qresource prefix="/" >
|
||||
<file>images/book.svg</file>
|
||||
<file>images/news.svg</file>
|
||||
<file>images/chapters.svg</file>
|
||||
<file>images/clear_left.svg</file>
|
||||
<file>images/config.svg</file>
|
||||
<file>images/convert.svg</file>
|
||||
<file>images/dialog_error.svg</file>
|
||||
<file>images/dialog_warning.svg</file>
|
||||
<file>images/document_open.svg</file>
|
||||
@ -11,6 +13,8 @@
|
||||
<file>images/jobs.svg</file>
|
||||
<file alias="library" >images/library.png</file>
|
||||
<file>images/list_remove.svg</file>
|
||||
<file>images/lookfeel.svg</file>
|
||||
<file>images/metadata.svg</file>
|
||||
<file>images/mimetypes/bmp.svg</file>
|
||||
<file>images/mimetypes/dir.svg</file>
|
||||
<file>images/mimetypes/gif.svg</file>
|
||||
@ -28,14 +32,16 @@
|
||||
<file>images/mimetypes/unknown.svg</file>
|
||||
<file>images/mimetypes/zero.svg</file>
|
||||
<file>images/mimetypes/zip.svg</file>
|
||||
<file>images/news.svg</file>
|
||||
<file>images/news/bbc.png</file>
|
||||
<file>images/news/newsweek.png</file>
|
||||
<file>images/news/nytimes.png</file>
|
||||
<file>images/page.svg</file>
|
||||
<file>images/plus.svg</file>
|
||||
<file>images/reader.svg</file>
|
||||
<file>images/save.svg</file>
|
||||
<file>images/sd.svg</file>
|
||||
<file>images/sync.svg</file>
|
||||
<file>images/trash.svg</file>
|
||||
<file>images/news/bbc.png</file>
|
||||
<file>images/news/newsweek.png</file>
|
||||
<file>images/news/nytimes.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -362,7 +362,7 @@ class BooksView(TableView):
|
||||
|
||||
|
||||
def migrate_database(self):
|
||||
if self._model.database_needs_migration():
|
||||
if self.model().database_needs_migration():
|
||||
print 'Migrating database from pre 0.4.0 version'
|
||||
path = os.path.abspath(os.path.expanduser('~/library.db'))
|
||||
progress = QProgressDialog('Upgrading database from pre 0.4.0 version.<br>'+\
|
||||
@ -554,7 +554,7 @@ class DeviceBooksModel(BooksModel):
|
||||
text = self.db[self.map[row]].title
|
||||
if not text:
|
||||
text = self.unknown
|
||||
return QVariant(BooksView.wrap(text, width=35))
|
||||
return QVariant(text)
|
||||
elif col == 1:
|
||||
au = self.db[self.map[row]].authors
|
||||
if not au:
|
||||
@ -565,7 +565,7 @@ class DeviceBooksModel(BooksModel):
|
||||
authors = []
|
||||
for i in au:
|
||||
authors += i.strip().split('&')
|
||||
jau = [ BooksView.wrap(a.strip(), width=30).strip() for a in authors ]
|
||||
jau = [ a.strip() for a in authors ]
|
||||
return QVariant("\n".join(jau))
|
||||
elif col == 2:
|
||||
size = self.db[self.map[row]].size
|
||||
|
@ -12,12 +12,13 @@
|
||||
## 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.Warning
|
||||
from libprs500.gui2.dialogs.password import PasswordDialog
|
||||
import os, sys, traceback, StringIO, textwrap
|
||||
|
||||
from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, \
|
||||
QSettings, QVariant, QSize, QThread
|
||||
from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox, \
|
||||
QToolButton
|
||||
QToolButton, QDialog
|
||||
from PyQt4.QtSvg import QSvgRenderer
|
||||
|
||||
from libprs500 import __version__, __appname__
|
||||
@ -37,6 +38,7 @@ from libprs500.gui2.dialogs.metadata_single import MetadataSingleDialog
|
||||
from libprs500.gui2.dialogs.metadata_bulk import MetadataBulkDialog
|
||||
from libprs500.gui2.dialogs.jobs import JobsDialog
|
||||
from libprs500.gui2.dialogs.conversion_error import ConversionErrorDialog
|
||||
from libprs500.gui2.dialogs.lrf_single import LRFSingleDialog
|
||||
|
||||
|
||||
class Main(QObject, Ui_MainWindow):
|
||||
@ -64,7 +66,7 @@ class Main(QObject, Ui_MainWindow):
|
||||
self.conversion_jobs = {}
|
||||
self.persistent_files = []
|
||||
self.default_thumbnail = None
|
||||
self.device_error_dialog = error_dialog(self.window, 'Error communicating with device', ' ')
|
||||
self.device_error_dialog = ConversionErrorDialog(self.window, 'Error communicating with device', ' ')
|
||||
self.device_error_dialog.setModal(Qt.NonModal)
|
||||
self.tb_wrapper = textwrap.TextWrapper(width=40)
|
||||
self.device_connected = False
|
||||
@ -113,9 +115,18 @@ class Main(QObject, Ui_MainWindow):
|
||||
QObject.connect(nm.actions()[2], SIGNAL('triggered(bool)'), self.fetch_news_nytimes)
|
||||
self.news_menu = nm
|
||||
self.action_news.setMenu(nm)
|
||||
cm = QMenu()
|
||||
cm.addAction('Convert individually')
|
||||
cm.addAction('Bulk convert')
|
||||
self.action_convert.setMenu(cm)
|
||||
QObject.connect(cm.actions()[0], SIGNAL('triggered(bool)'), self.convert_single)
|
||||
QObject.connect(cm.actions()[1], SIGNAL('triggered(bool)'), self.convert_bulk)
|
||||
QObject.connect(self.action_convert, SIGNAL('triggered(bool)'), self.convert_single)
|
||||
self.convert_menu = cm
|
||||
self.tool_bar.widgetForAction(self.action_news).setPopupMode(QToolButton.InstantPopup)
|
||||
self.tool_bar.widgetForAction(self.action_edit).setPopupMode(QToolButton.MenuButtonPopup)
|
||||
self.tool_bar.widgetForAction(self.action_sync).setPopupMode(QToolButton.MenuButtonPopup)
|
||||
self.tool_bar.widgetForAction(self.action_convert).setPopupMode(QToolButton.MenuButtonPopup)
|
||||
self.tool_bar.setContextMenuPolicy(Qt.PreventContextMenu)
|
||||
####################### Library view ########################
|
||||
self.library_view.set_database(self.database_path)
|
||||
@ -470,10 +481,14 @@ class Main(QObject, Ui_MainWindow):
|
||||
|
||||
############################### Fetch news #################################
|
||||
|
||||
def fetch_news(self, profile, pretty):
|
||||
def fetch_news(self, profile, pretty, username=None, password=None):
|
||||
pt = PersistentTemporaryFile(suffix='.lrf')
|
||||
pt.close()
|
||||
args = ['web2lrf', '-o', pt.name, profile]
|
||||
if username:
|
||||
args.extend(['--username', username])
|
||||
if password:
|
||||
args.extend(['--password', password])
|
||||
id = self.job_manager.run_conversion_job(self.news_fetched, web2lrf, args=args,
|
||||
job_description='Fetch news from '+pretty)
|
||||
self.conversion_jobs[id] = (pt, 'lrf')
|
||||
@ -497,7 +512,29 @@ class Main(QObject, Ui_MainWindow):
|
||||
self.fetch_news('newsweek', 'Newsweek')
|
||||
|
||||
def fetch_news_nytimes(self, checked):
|
||||
self.fetch_news('nytimes', 'New York Times')
|
||||
d = PasswordDialog(self.window, 'nytimes info dialog',
|
||||
'<p>Please enter your username and password for nytimes.com<br>If you do not have, you can <a href="http://www.nytimes.com/gst/regi.html">register</a> for free.<br>Without a registration, some articles will not be downloaded correctly. Click OK to proceed.')
|
||||
d.exec_()
|
||||
if d.result() == QDialog.Accepted:
|
||||
un, pw = d.username(), d.password()
|
||||
self.fetch_news('nytimes', 'New York Times', username=un, password=pw)
|
||||
|
||||
############################################################################
|
||||
|
||||
############################### Convert ####################################
|
||||
def convert_bulk(self, checked):
|
||||
pass
|
||||
|
||||
def convert_single(self, checked):
|
||||
rows = self.library_view.selectionModel().selectedRows()
|
||||
if not rows or len(rows) == 0:
|
||||
d = error_dialog(self.window, 'Cannot convert', 'No books selected')
|
||||
d.exec_()
|
||||
|
||||
for row in rows:
|
||||
d = LRFSingleDialog(self.window, self.library_view.model().db, row)
|
||||
if d.selected_format:
|
||||
d.exec_()
|
||||
|
||||
############################################################################
|
||||
def location_selected(self, location):
|
||||
@ -519,16 +556,12 @@ class Main(QObject, Ui_MainWindow):
|
||||
if self.device_connected:
|
||||
self.action_sync.setEnabled(True)
|
||||
self.action_edit.setEnabled(True)
|
||||
self.action_convert.setEnabled(True)
|
||||
else:
|
||||
self.action_sync.setEnabled(False)
|
||||
self.action_edit.setEnabled(False)
|
||||
self.action_convert.setEnabled(False)
|
||||
|
||||
|
||||
def wrap_traceback(self, tb):
|
||||
tb = unicode(tb, 'utf8', 'replace')
|
||||
tb = '\n'.join(self.tb_wrapper.wrap(tb))
|
||||
return tb
|
||||
|
||||
def device_job_exception(self, id, description, exception, formatted_traceback):
|
||||
'''
|
||||
Handle exceptions in threaded jobs.
|
||||
@ -541,8 +574,8 @@ class Main(QObject, Ui_MainWindow):
|
||||
msg += u'<p>Failed to perform <b>job</b>: '+description
|
||||
msg += u'<p>Further device related error messages will not be shown while this message is visible.'
|
||||
msg += u'<p>Detailed <b>traceback</b>:<pre>'
|
||||
msg += self.wrap_traceback(formatted_traceback)
|
||||
self.device_error_dialog.setText(msg)
|
||||
msg += formatted_traceback
|
||||
self.device_error_dialog.set_message(msg)
|
||||
self.device_error_dialog.show()
|
||||
|
||||
def conversion_job_exception(self, id, description, exception, formatted_traceback, log):
|
||||
@ -556,7 +589,7 @@ class Main(QObject, Ui_MainWindow):
|
||||
msg += formatted_traceback + '</pre>'
|
||||
msg += '<p><b>Log:</b></p><pre>'
|
||||
msg += log
|
||||
ConversionErrorDialog(self.window, 'Conversion Error', msg)
|
||||
ConversionErrorDialog(self.window, 'Conversion Error', msg, show=True)
|
||||
|
||||
|
||||
def read_settings(self):
|
||||
@ -604,8 +637,8 @@ class Main(QObject, Ui_MainWindow):
|
||||
self.window.close()
|
||||
self.window.thread().exit(0)
|
||||
msg = '<p><b>' + unicode(str(value), 'utf8', 'replace') + '</b></p>'
|
||||
msg += '<p>Detailed <b>traceback</b>:<pre>'+self.wrap_traceback(fe)+'</pre>'
|
||||
d = error_dialog(self.window, 'ERROR: Unhandled exception', msg)
|
||||
msg += '<p>Detailed <b>traceback</b>:<pre>'+fe+'</pre>'
|
||||
d = ConversionErrorDialog(self.window, 'ERROR: Unhandled exception', msg)
|
||||
d.exec_()
|
||||
|
||||
def main():
|
||||
|
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>777</width>
|
||||
<width>787</width>
|
||||
<height>822</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -44,7 +44,7 @@
|
||||
<item>
|
||||
<widget class="LocationView" name="location_view" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
|
||||
<sizepolicy vsizetype="Minimum" hsizetype="Preferred" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
@ -61,11 +61,20 @@
|
||||
<property name="horizontalScrollBarPolicy" >
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="dragDropMode" >
|
||||
<enum>QAbstractItemView::DragDrop</enum>
|
||||
<property name="iconSize" >
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="movement" >
|
||||
<enum>QListView::Static</enum>
|
||||
</property>
|
||||
<property name="flow" >
|
||||
<enum>QListView::TopToBottom</enum>
|
||||
<enum>QListView::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="isWrapping" stdset="0" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>20</number>
|
||||
@ -73,6 +82,9 @@
|
||||
<property name="viewMode" >
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
<property name="uniformItemSizes" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@ -325,6 +337,7 @@
|
||||
<addaction name="action_save" />
|
||||
<addaction name="separator" />
|
||||
<addaction name="action_news" />
|
||||
<addaction name="action_convert" />
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar" >
|
||||
<property name="mouseTracking" >
|
||||
@ -400,6 +413,14 @@
|
||||
<string>Fetch news</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_convert" >
|
||||
<property name="icon" >
|
||||
<iconset resource="images.qrc" >:/images/convert.svg</iconset>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Convert E-books</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
@ -13,11 +13,11 @@
|
||||
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
from libprs500 import __appname__
|
||||
"""
|
||||
'''
|
||||
Backend that implements storage of ebooks in an sqlite database.
|
||||
"""
|
||||
'''
|
||||
import sqlite3 as sqlite
|
||||
import datetime, re, os
|
||||
import datetime, re, os, cPickle
|
||||
from zlib import compress, decompress
|
||||
|
||||
class Concatenate(object):
|
||||
@ -88,12 +88,12 @@ class LibraryDatabase(object):
|
||||
def import_old_database(path, conn, progress=None):
|
||||
count = 0
|
||||
for book, cover, formats in LibraryDatabase.books_in_old_database(path):
|
||||
obj = conn.execute('INSERT INTO books(title, timestamp) VALUES (?,?)',
|
||||
(book['title'], book['timestamp']))
|
||||
id = obj.lastrowid
|
||||
authors = book['authors']
|
||||
if not authors:
|
||||
authors = 'Unknown'
|
||||
obj = conn.execute('INSERT INTO books(title, timestamp, author_sort) VALUES (?,?,?)',
|
||||
(book['title'], book['timestamp'], authors))
|
||||
id = obj.lastrowid
|
||||
authors = authors.split('&')
|
||||
for a in authors:
|
||||
author = conn.execute('SELECT id from authors WHERE name=?', (a,)).fetchone()
|
||||
@ -559,16 +559,83 @@ class LibraryDatabase(object):
|
||||
)
|
||||
conn.execute('pragma user_version=1')
|
||||
conn.commit()
|
||||
|
||||
@staticmethod
|
||||
def upgrade_version1(conn):
|
||||
conn.executescript(
|
||||
'''
|
||||
/***** authors_sort table *****/
|
||||
ALTER TABLE books ADD COLUMN author_sort TEXT COLLATE NOCASE;
|
||||
UPDATE books SET author_sort=(SELECT name FROM authors WHERE id=(SELECT author FROM books_authors_link WHERE book=books.id)) WHERE id IN (SELECT id FROM books ORDER BY id);
|
||||
DROP INDEX authors_idx;
|
||||
DROP TRIGGER authors_insert_trg;
|
||||
DROP TRIGGER authors_update_trg;
|
||||
CREATE INDEX authors_idx ON books (author_sort COLLATE NOCASE);
|
||||
|
||||
CREATE TABLE conversion_options ( id INTEGER PRIMARY KEY,
|
||||
format TEXT NOT NULL COLLATE NOCASE,
|
||||
book INTEGER,
|
||||
data BLOB NOT NULL,
|
||||
UNIQUE(format,book)
|
||||
);
|
||||
CREATE INDEX conversion_options_idx_a ON conversion_options (format COLLATE NOCASE);
|
||||
CREATE INDEX conversion_options_idx_b ON conversion_options (book);
|
||||
|
||||
DROP TRIGGER books_delete_trg;
|
||||
CREATE TRIGGER books_delete_trg
|
||||
AFTER DELETE ON books
|
||||
BEGIN
|
||||
DELETE FROM books_authors_link WHERE book=OLD.id;
|
||||
DELETE FROM books_publishers_link WHERE book=OLD.id;
|
||||
DELETE FROM books_ratings_link WHERE book=OLD.id;
|
||||
DELETE FROM books_series_link WHERE book=OLD.id;
|
||||
DELETE FROM books_tags_link WHERE book=OLD.id;
|
||||
DELETE FROM data WHERE book=OLD.id;
|
||||
DELETE FROM covers WHERE book=OLD.id;
|
||||
DELETE FROM comments WHERE book=OLD.id;
|
||||
DELETE FROM conversion_options WHERE book=OLD.id;
|
||||
END;
|
||||
|
||||
DROP VIEW meta;
|
||||
CREATE VIEW meta AS
|
||||
SELECT id, title,
|
||||
(SELECT concat(name) FROM authors WHERE authors.id IN (SELECT author from books_authors_link WHERE book=books.id)) authors,
|
||||
(SELECT name FROM publishers WHERE publishers.id IN (SELECT publisher from books_publishers_link WHERE book=books.id)) publisher,
|
||||
(SELECT rating FROM ratings WHERE ratings.id IN (SELECT rating from books_ratings_link WHERE book=books.id)) rating,
|
||||
timestamp,
|
||||
(SELECT MAX(uncompressed_size) FROM data WHERE book=books.id) size,
|
||||
(SELECT concat(name) FROM tags WHERE tags.id IN (SELECT tag from books_tags_link WHERE book=books.id)) tags,
|
||||
(SELECT text FROM comments WHERE book=books.id) comments,
|
||||
(SELECT name FROM series WHERE series.id IN (SELECT series FROM books_series_link WHERE book=books.id)) series,
|
||||
sort,
|
||||
author_sort
|
||||
FROM books;
|
||||
|
||||
DROP INDEX publishers_idx;
|
||||
CREATE INDEX publishers_idx ON publishers (name COLLATE NOCASE);
|
||||
DROP TRIGGER publishers_insert_trg;
|
||||
DROP TRIGGER publishers_update_trg;
|
||||
'''
|
||||
)
|
||||
conn.execute('pragma user_version=2')
|
||||
conn.commit()
|
||||
|
||||
def __init__(self, dbpath):
|
||||
self.dbpath = dbpath
|
||||
self.conn = _connect(dbpath)
|
||||
self.user_version = self.conn.execute('pragma user_version;').next()[0]
|
||||
self.cache = []
|
||||
self.data = []
|
||||
if self.user_version == 0:
|
||||
if self.user_version == 0: # No tables have been created
|
||||
LibraryDatabase.create_version1(self.conn)
|
||||
if self.user_version == 1: # Upgrade to 2
|
||||
LibraryDatabase.upgrade_version1(self.conn)
|
||||
|
||||
@apply
|
||||
def user_version():
|
||||
doc = 'The user version of this database'
|
||||
def fget(self):
|
||||
return self.conn.execute('pragma user_version;').next()[0]
|
||||
return property(doc=doc, fget=fget)
|
||||
|
||||
def is_empty(self):
|
||||
return not self.conn.execute('SELECT id FROM books LIMIT 1').fetchone()
|
||||
@ -578,7 +645,7 @@ class LibraryDatabase(object):
|
||||
Rebuild self.data and self.cache. Filter results are lost.
|
||||
'''
|
||||
FIELDS = {'title' : 'sort',
|
||||
'authors': 'authors_sort',
|
||||
'authors': 'author_sort',
|
||||
'publisher': 'publisher_sort',
|
||||
'size': 'size',
|
||||
'date': 'timestamp',
|
||||
@ -631,6 +698,10 @@ class LibraryDatabase(object):
|
||||
''' Authors as a comman separated list or None'''
|
||||
return self.data[index][2]
|
||||
|
||||
def author_sort(self, index):
|
||||
id = self.id(index)
|
||||
return self.conn.execute('SELECT author_sort FROM books WHERE id=?', (id,)).fetchone()[0]
|
||||
|
||||
def publisher(self, index):
|
||||
return self.data[index][3]
|
||||
|
||||
@ -699,6 +770,13 @@ class LibraryDatabase(object):
|
||||
return [ (i[0], i[1]) for i in \
|
||||
self.conn.execute('SELECT id, name FROM series').fetchall()]
|
||||
|
||||
def conversion_options(self, id, format):
|
||||
data = self.conn.execute('SELECT data FROM conversion_options WHERE book=? AND format=?', (id, format.upper())).fetchone()
|
||||
if data:
|
||||
return cPickle.loads(str(data[0]))
|
||||
return None
|
||||
|
||||
|
||||
def add_format(self, index, ext, stream):
|
||||
'''
|
||||
Add the format specified by ext. If it already exists it is replaced.
|
||||
@ -749,6 +827,16 @@ class LibraryDatabase(object):
|
||||
elif column == 'rating':
|
||||
self.set_rating(id, val)
|
||||
|
||||
def set_conversion_options(self, id, format, options):
|
||||
data = sqlite.Binary(cPickle.dumps(options))
|
||||
oid = self.conn.execute('SELECT id FROM conversion_options WHERE book=? AND format=?', (id, format.upper())).fetchone()
|
||||
if oid:
|
||||
self.conn.execute('UPDATE conversion_options SET data=? WHERE id=?', (data, oid[0]))
|
||||
else:
|
||||
self.conn.execute('INSERT INTO conversion_options(book,format,data) VALUES (?,?,?)', (id,format.upper(),data))
|
||||
self.conn.commit()
|
||||
|
||||
|
||||
def set_authors(self, id, authors):
|
||||
'''
|
||||
@param authors: A list of authors.
|
||||
@ -766,6 +854,10 @@ class LibraryDatabase(object):
|
||||
self.conn.execute('INSERT INTO books_authors_link(book, author) VALUES (?,?)', (id, aid))
|
||||
self.conn.commit()
|
||||
|
||||
def set_author_sort(self, id, sort):
|
||||
self.conn.execute('UPDATE books SET author_sort=? WHERE id=?', (sort, id))
|
||||
self.conn.commit()
|
||||
|
||||
def set_title(self, id, title):
|
||||
if not title:
|
||||
return
|
||||
@ -925,5 +1017,4 @@ class LibraryDatabase(object):
|
||||
|
||||
if __name__ == '__main__':
|
||||
db = LibraryDatabase('/home/kovid/library1.db')
|
||||
db.refresh('title', True)
|
||||
db.export_to_dir('/tmp/test', range(1, 10))
|
||||
|
Loading…
x
Reference in New Issue
Block a user