mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
226 lines
7.7 KiB
Python
226 lines
7.7 KiB
Python
#!/usr/bin/env python
|
|
# vim:fileencoding=utf-8
|
|
from __future__ import (unicode_literals, division, absolute_import,
|
|
print_function)
|
|
|
|
__license__ = 'GPL v3'
|
|
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
|
|
|
from PyQt4.Qt import (
|
|
QDialog, QDialogButtonBox, QGridLayout, QLabel, QLineEdit, QVBoxLayout,
|
|
QFormLayout, QHBoxLayout, QToolButton, QIcon, QApplication, Qt)
|
|
|
|
from calibre.gui2 import error_dialog, choose_files, choose_save_file
|
|
from calibre.gui2.tweak_book import tprefs
|
|
|
|
class Dialog(QDialog):
|
|
|
|
def __init__(self, title, name, parent=None):
|
|
QDialog.__init__(self, parent)
|
|
self.setWindowTitle(title)
|
|
self.name = name
|
|
self.bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
|
self.bb.accepted.connect(self.accept)
|
|
self.bb.rejected.connect(self.reject)
|
|
|
|
self.setup_ui()
|
|
|
|
self.resize(self.sizeHint())
|
|
geom = tprefs.get(name + '-geometry', None)
|
|
if geom is not None:
|
|
self.restoreGeometry(geom)
|
|
if hasattr(self, 'splitter'):
|
|
state = tprefs.get(name + '-splitter-state', None)
|
|
if state is not None:
|
|
self.splitter.restoreState(state)
|
|
|
|
def accept(self):
|
|
tprefs.set(self.name + '-geometry', bytearray(self.saveGeometry()))
|
|
if hasattr(self, 'splitter'):
|
|
tprefs.set(self.name + '-splitter-state', bytearray(self.splitter.saveState()))
|
|
QDialog.accept(self)
|
|
|
|
def reject(self):
|
|
tprefs.set(self.name + '-geometry', bytearray(self.saveGeometry()))
|
|
if hasattr(self, 'splitter'):
|
|
tprefs.set(self.name + '-splitter-state', bytearray(self.splitter.saveState()))
|
|
QDialog.reject(self)
|
|
|
|
def setup_ui(self):
|
|
raise NotImplementedError('You must implement this method in Dialog subclasses')
|
|
|
|
class RationalizeFolders(Dialog): # {{{
|
|
|
|
TYPE_MAP = (
|
|
('text', _('Text (HTML) files')),
|
|
('style', _('Style (CSS) files')),
|
|
('image', _('Images')),
|
|
('font', _('Fonts')),
|
|
('audio', _('Audio')),
|
|
('video', _('Video')),
|
|
('opf', _('OPF file (metadata)')),
|
|
('toc', _('Table of contents file (NCX)')),
|
|
)
|
|
|
|
def __init__(self, parent=None):
|
|
Dialog.__init__(self, _('Arrange in folders'), 'rationalize-folders', parent=parent)
|
|
|
|
def setup_ui(self):
|
|
self.l = l = QGridLayout()
|
|
self.setLayout(l)
|
|
|
|
self.la = la = QLabel(_(
|
|
'Arrange the files in this book into sub-folders based on their types.'
|
|
' If you leave a folder blank, the files will be placed in the root.'))
|
|
la.setWordWrap(True)
|
|
l.addWidget(la, 0, 0, 1, -1)
|
|
|
|
folders = tprefs['folders_for_types']
|
|
for i, (typ, text) in enumerate(self.TYPE_MAP):
|
|
la = QLabel('&' + text)
|
|
setattr(self, '%s_label' % typ, la)
|
|
le = QLineEdit(self)
|
|
setattr(self, '%s_folder' % typ, le)
|
|
val = folders.get(typ, '')
|
|
if val and not val.endswith('/'):
|
|
val += '/'
|
|
le.setText(val)
|
|
la.setBuddy(le)
|
|
l.addWidget(la, i + 1, 0)
|
|
l.addWidget(le, i + 1, 1)
|
|
self.la2 = la = QLabel(_(
|
|
'Note that this will only arrange files inside the book,'
|
|
' it will not affect how they are displayed in the Files Browser'))
|
|
la.setWordWrap(True)
|
|
l.addWidget(la, i + 2, 0, 1, -1)
|
|
l.addWidget(self.bb, i + 3, 0, 1, -1)
|
|
|
|
@property
|
|
def folder_map(self):
|
|
ans = {}
|
|
for typ, x in self.TYPE_MAP:
|
|
val = unicode(getattr(self, '%s_folder' % typ).text()).strip().strip('/')
|
|
ans[typ] = val
|
|
return ans
|
|
|
|
def accept(self):
|
|
tprefs['folders_for_types'] = self.folder_map
|
|
return Dialog.accept(self)
|
|
# }}}
|
|
|
|
class MultiSplit(Dialog): # {{{
|
|
|
|
def __init__(self, parent=None):
|
|
Dialog.__init__(self, _('Specify locations to split at'), 'multisplit-xpath', parent=parent)
|
|
|
|
def setup_ui(self):
|
|
from calibre.gui2.convert.xpath_wizard import XPathEdit
|
|
self.l = l = QVBoxLayout(self)
|
|
self.setLayout(l)
|
|
|
|
self.la = la = QLabel(_(
|
|
'Specify the locations to split at, using an XPath expression (click'
|
|
' the wizard button for help with generating XPath expressions).'))
|
|
la.setWordWrap(True)
|
|
l.addWidget(la)
|
|
|
|
self._xpath = xp = XPathEdit(self)
|
|
xp.set_msg(_('&XPath expression:'))
|
|
xp.setObjectName('editor-multisplit-xpath-edit')
|
|
l.addWidget(xp)
|
|
l.addWidget(self.bb)
|
|
|
|
def accept(self):
|
|
if not self._xpath.check():
|
|
return error_dialog(self, _('Invalid XPath expression'), _(
|
|
'The XPath expression %s is invalid.') % self.xpath)
|
|
return Dialog.accept(self)
|
|
|
|
@property
|
|
def xpath(self):
|
|
return self._xpath.xpath
|
|
|
|
# }}}
|
|
|
|
class ImportForeign(Dialog): # {{{
|
|
|
|
def __init__(self, parent=None):
|
|
Dialog.__init__(self, _('Choose file to import'), 'import-foreign')
|
|
|
|
def sizeHint(self):
|
|
ans = Dialog.sizeHint(self)
|
|
ans.setWidth(ans.width() + 200)
|
|
return ans
|
|
|
|
def setup_ui(self):
|
|
self.l = l = QFormLayout(self)
|
|
self.setLayout(l)
|
|
|
|
la = self.la = QLabel(_(
|
|
'You can import an HTML or DOCX file directly as an EPUB and edit it. The EPUB'
|
|
' will be generated with minimal changes from the source, unlike doing a full'
|
|
' conversion in calibre.'))
|
|
la.setWordWrap(True)
|
|
l.addRow(la)
|
|
|
|
self.h1 = h1 = QHBoxLayout()
|
|
self.src = src = QLineEdit(self)
|
|
src.setPlaceholderText(_('Choose the file to import'))
|
|
h1.addWidget(src)
|
|
self.b1 = b = QToolButton(self)
|
|
b.setIcon(QIcon(I('document_open.png')))
|
|
b.setText(_('Choose file'))
|
|
h1.addWidget(b)
|
|
l.addRow(_('Source file'), h1)
|
|
b.clicked.connect(self.choose_source)
|
|
b.setFocus(Qt.OtherFocusReason)
|
|
|
|
self.h2 = h1 = QHBoxLayout()
|
|
self.dest = src = QLineEdit(self)
|
|
src.setPlaceholderText(_('Choose the location for the newly created EPUB'))
|
|
h1.addWidget(src)
|
|
self.b2 = b = QToolButton(self)
|
|
b.setIcon(QIcon(I('document_open.png')))
|
|
b.setText(_('Choose file'))
|
|
h1.addWidget(b)
|
|
l.addRow(_('Destination file'), h1)
|
|
b.clicked.connect(self.choose_destination)
|
|
|
|
l.addRow(self.bb)
|
|
|
|
def choose_source(self):
|
|
path = choose_files(self, 'edit-book-choose-file-to-import', _('Choose file'), filters=[
|
|
(_('HTML or DOCX files'), ['htm', 'html', 'xhtml', 'xhtm', 'docx'])], select_only_single_file=True)
|
|
if path:
|
|
self.src.setText(path[0])
|
|
self.dest.setText(self.data[1])
|
|
|
|
def choose_destination(self):
|
|
path = choose_save_file(self, 'edit-book-destination-for-generated-epub', _('Choose destination'), filters=[
|
|
(_('EPUB files'), ['epub'])], all_files=False)
|
|
if path:
|
|
if not path.lower().endswith('.epub'):
|
|
path += '.epub'
|
|
self.dest.setText(path)
|
|
|
|
def accept(self):
|
|
if not unicode(self.src.text()):
|
|
return error_dialog(self, _('Need document'), _(
|
|
'You must specify the source file that will be imported.'), show=True)
|
|
Dialog.accept(self)
|
|
|
|
@property
|
|
def data(self):
|
|
src = unicode(self.src.text()).strip()
|
|
dest = unicode(self.dest.text()).strip()
|
|
if not dest:
|
|
dest = src.rpartition('.')[0] + '.epub'
|
|
return src, dest
|
|
# }}}
|
|
|
|
if __name__ == '__main__':
|
|
app = QApplication([])
|
|
d = ImportForeign()
|
|
d.exec_()
|
|
print (d.data)
|