mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Sync to trunk.
This commit is contained in:
commit
c5e5903eb8
@ -28,6 +28,7 @@ def freeze():
|
||||
|
||||
binary_includes = [
|
||||
'/usr/bin/pdftohtml',
|
||||
'/usr/bin/calibre-mount-helper',
|
||||
'/usr/lib/libunrar.so',
|
||||
'/usr/lib/libsqlite3.so.0',
|
||||
'/usr/lib/libsqlite3.so.0',
|
||||
|
28
setup.py
28
setup.py
@ -45,6 +45,24 @@ main_functions = {
|
||||
'gui' : [_ep_to_function(i) for i in entry_points['gui_scripts']],
|
||||
}
|
||||
|
||||
def setup_mount_helper():
|
||||
def warn():
|
||||
print 'WARNING: Failed to compile mount helper. Auto mounting of',
|
||||
print 'devices will not work'
|
||||
|
||||
if os.geteuid() != 0:
|
||||
return warn()
|
||||
import stat
|
||||
src = os.path.join('src', 'calibre', 'devices', 'linux_mount_helper.c')
|
||||
dest = '/usr/bin/calibre-mount-helper'
|
||||
p = subprocess.Popen(['gcc', '-Wall', src, '-o', dest])
|
||||
ret = p.wait()
|
||||
if ret != 0:
|
||||
return warn()
|
||||
os.chown(dest, 0, 0)
|
||||
os.chmod(dest,
|
||||
stat.S_ISUID|stat.S_ISGID|stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH)
|
||||
|
||||
if __name__ == '__main__':
|
||||
from setuptools import setup, find_packages
|
||||
from pyqtdistutils import PyQtExtension, build_ext, Extension
|
||||
@ -68,6 +86,10 @@ if __name__ == '__main__':
|
||||
qt_inc = qt_inc if qt_inc not in ('', '**Unknown**') and os.path.isdir(qt_inc) else None
|
||||
qt_lib = qmake_query('QT_INSTALL_LIBS').splitlines()[0]
|
||||
qt_lib = qt_lib if qt_lib not in ('', '**Unknown**') and os.path.isdir(qt_lib) else None
|
||||
if qt_lib is None or qt_inc is None:
|
||||
print 'WARNING: Could not find QT librariers and headers.',
|
||||
print 'Is qmake in your PATH?'
|
||||
|
||||
|
||||
if iswindows:
|
||||
optional.append(Extension('calibre.plugins.winutil',
|
||||
@ -90,7 +112,8 @@ if __name__ == '__main__':
|
||||
poppler_inc = '/Volumes/sw/build/poppler-0.10.7/qt4/src'
|
||||
poppler_lib = '/Users/kovid/poppler/lib'
|
||||
poppler_inc = os.environ.get('POPPLER_INC_DIR', poppler_inc)
|
||||
if os.path.exists(os.path.join(poppler_inc, 'poppler-qt4.h')):
|
||||
if os.path.exists(os.path.join(poppler_inc, 'poppler-qt4.h'))\
|
||||
and qt_lib is not None and qt_inc is not None:
|
||||
optional.append(Extension('calibre.plugins.calibre_poppler',
|
||||
sources=['src/calibre/utils/poppler/poppler.cpp'],
|
||||
libraries=(['poppler', 'poppler-qt4']+poppler_libs),
|
||||
@ -253,6 +276,7 @@ if __name__ == '__main__':
|
||||
|
||||
if 'develop' in ' '.join(sys.argv) and islinux:
|
||||
subprocess.check_call('calibre_postinstall --do-not-reload-udev-hal', shell=True)
|
||||
setup_mount_helper()
|
||||
if 'install' in sys.argv and islinux:
|
||||
subprocess.check_call('calibre_postinstall', shell=True)
|
||||
|
||||
setup_mount_helper()
|
||||
|
141
src/calibre/devices/linux_mount_helper.c
Normal file
141
src/calibre/devices/linux_mount_helper.c
Normal file
@ -0,0 +1,141 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define MARKER ".created_by_calibre_mount_helper"
|
||||
|
||||
int exists(char *path) {
|
||||
struct stat file_info;
|
||||
if (stat(path, &file_info) == 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_root() {
|
||||
int res;
|
||||
res = setreuid(0, 0);
|
||||
if (res != 0) return 1;
|
||||
if (setregid(0, 0) != 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_mount(char *dev, char *mp) {
|
||||
char options[1000];
|
||||
char marker[2000];
|
||||
if (exists(dev) == 0) {
|
||||
fprintf(stderr, "Specified device node does not exist\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (exists(mp) == 0) {
|
||||
if (mkdir(mp, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) {
|
||||
int errsv = errno;
|
||||
fprintf(stderr, "Failed to create mount point with error: %s\n", strerror(errsv));
|
||||
}
|
||||
}
|
||||
strncat(marker, mp, strlen(mp));
|
||||
strncat(marker, "/", 1);
|
||||
strncat(marker, MARKER, strlen(MARKER));
|
||||
if (exists(marker) == 0) {
|
||||
int fd = creat(marker, S_IRUSR|S_IWUSR);
|
||||
if (fd == -1) {
|
||||
int errsv = errno;
|
||||
fprintf(stderr, "Failed to create marker with error: %s\n", strerror(errsv));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
snprintf(options, 1000, "rw,noexec,nosuid,sync,nodev,quiet,shortname=mixed,uid=%d,gid=%d,umask=077,fmask=0177,dmask=0077,utf8,iocharset=iso8859-1", getuid(), getgid());
|
||||
if (get_root() != 0) {
|
||||
fprintf(stderr, "Failed to elevate to root privileges\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
execlp("mount", "mount", "-t", "vfat", "-o", options, dev, mp, NULL);
|
||||
int errsv = errno;
|
||||
fprintf(stderr, "Failed to mount with error: %s\n", strerror(errsv));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int do_eject(char *dev, char*mp) {
|
||||
char marker[2000];
|
||||
int status = EXIT_FAILURE, ret;
|
||||
if (get_root() != 0) {
|
||||
fprintf(stderr, "Failed to elevate to root privileges\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
int pid = fork();
|
||||
if (pid == -1) {
|
||||
fprintf(stderr, "Failed to fork\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (pid == 0) {
|
||||
if (get_root() != 0) {
|
||||
fprintf(stderr, "Failed to elevate to root privileges\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
execlp("eject", "eject", "-s", dev, NULL);
|
||||
int errsv = errno;
|
||||
fprintf(stderr, "Failed to eject with error: %s\n", strerror(errsv));
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
int i;
|
||||
for (i =0; i < 7; i++) {
|
||||
sleep(1);
|
||||
ret = waitpid(pid, &status, WNOHANG);
|
||||
if (ret == -1) return EXIT_FAILURE;
|
||||
if (ret > 0) break;
|
||||
}
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
|
||||
strncat(marker, mp, strlen(mp));
|
||||
strncat(marker, "/", 1);
|
||||
strncat(marker, MARKER, strlen(MARKER));
|
||||
if (exists(marker)) {
|
||||
int urt = unlink(marker);
|
||||
if (urt == -1) {
|
||||
fprintf(stderr, "Failed to unlink marker: %s\n", strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
int rmd = rmdir(mp);
|
||||
if (rmd == -1) {
|
||||
fprintf(stderr, "Failed to remove mount point: %s\n", strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
char *action, *dev, *mp;
|
||||
|
||||
/*printf("Real UID\t= %d\n", getuid());
|
||||
printf("Effective UID\t= %d\n", geteuid());
|
||||
printf("Real GID\t= %d\n", getgid());
|
||||
printf("Effective GID\t= %d\n", getegid());*/
|
||||
|
||||
if (argc != 4) {
|
||||
fprintf(stderr, "Needs 3 arguments: action, device node and mount point\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
action = argv[1]; dev = argv[2]; mp = argv[3];
|
||||
|
||||
if (strncmp(action, "mount", 5) == 0) {
|
||||
return do_mount(dev, mp);
|
||||
}
|
||||
else if (strncmp(action, "eject", 7) == 0) {
|
||||
return do_eject(dev, mp);
|
||||
} else {
|
||||
fprintf(stderr, "Unrecognized action: must be mount or eject\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -226,7 +226,6 @@ def main():
|
||||
|
||||
|
||||
try:
|
||||
dev.open()
|
||||
if command == "df":
|
||||
total = dev.total_space(end_session=False)
|
||||
free = dev.free_space()
|
||||
|
@ -17,7 +17,6 @@ import time
|
||||
import re
|
||||
import sys
|
||||
import glob
|
||||
import shutil
|
||||
from itertools import repeat
|
||||
from math import ceil
|
||||
|
||||
@ -489,7 +488,7 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
label = self.STORAGE_CARD_VOLUME_LABEL
|
||||
if type == 'cardb':
|
||||
label = self.STORAGE_CARD2_VOLUME_LABEL
|
||||
if label is None:
|
||||
if not label:
|
||||
label = self.STORAGE_CARD_VOLUME_LABEL + ' 2'
|
||||
extra = 0
|
||||
while True:
|
||||
@ -501,11 +500,15 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
label += ' (%d)'%extra
|
||||
|
||||
def do_mount(node, label):
|
||||
cmd = ['pmount', '-w', '-s']
|
||||
cmd = 'calibre-mount-helper'
|
||||
if getattr(sys, 'frozen_path', False):
|
||||
cmd = os.path.join(sys.frozen_path, cmd)
|
||||
cmd = [cmd, 'mount']
|
||||
try:
|
||||
p = subprocess.Popen(cmd + [node, label])
|
||||
p = subprocess.Popen(cmd + [node, '/media/'+label])
|
||||
except OSError:
|
||||
raise DeviceError(_('You must install the pmount package.'))
|
||||
raise DeviceError(
|
||||
_('Could not find mount helper: %s.')%cmd[0])
|
||||
while p.poll() is None:
|
||||
time.sleep(0.1)
|
||||
return p.returncode
|
||||
@ -520,11 +523,13 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
raise DeviceError(_('Unable to detect the %s disk drive.')
|
||||
%self.__class__.__name__)
|
||||
|
||||
self._linux_mount_map = {}
|
||||
mp, ret = mount(main, 'main')
|
||||
if mp is None:
|
||||
raise DeviceError(
|
||||
_('Unable to mount main memory (Error code: %d)')%ret)
|
||||
if not mp.endswith('/'): mp += '/'
|
||||
self._linux_mount_map[main] = mp
|
||||
self._main_prefix = mp
|
||||
cards = [(carda, '_card_a_prefix', 'carda'),
|
||||
(cardb, '_card_b_prefix', 'cardb')]
|
||||
@ -536,6 +541,7 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
else:
|
||||
if not mp.endswith('/'): mp += '/'
|
||||
setattr(self, prefix, mp)
|
||||
self._linux_mount_map[card] = mp
|
||||
|
||||
def open(self):
|
||||
time.sleep(5)
|
||||
@ -595,27 +601,16 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
success = False
|
||||
for drive in drives:
|
||||
if drive:
|
||||
cmd = ['pumount', '-l']
|
||||
cmd = 'calibre-mount-helper'
|
||||
if getattr(sys, 'frozen_path', False):
|
||||
cmd = os.path.join(sys.frozen_path, cmd)
|
||||
cmd = [cmd, 'eject']
|
||||
mp = getattr(self, "_linux_mount_map", {}).get(drive,
|
||||
'dummy/')[:-1]
|
||||
try:
|
||||
p = subprocess.Popen(cmd + [drive])
|
||||
subprocess.Popen(cmd + [drive, mp]).wait()
|
||||
except:
|
||||
pass
|
||||
while p.poll() is None:
|
||||
time.sleep(0.1)
|
||||
success = success or p.returncode == 0
|
||||
try:
|
||||
subprocess.Popen(['sudo', 'eject', drive])
|
||||
except:
|
||||
pass
|
||||
for x in ('_main_prefix', '_card_a_prefix', '_card_b_prefix'):
|
||||
x = getattr(self, x, None)
|
||||
if x is not None:
|
||||
if x.startswith('/media/') and os.path.exists(x) \
|
||||
and not os.listdir(x):
|
||||
try:
|
||||
shutil.rmtree(x)
|
||||
except:
|
||||
pass
|
||||
|
||||
def eject(self):
|
||||
if islinux:
|
||||
|
@ -19,6 +19,8 @@ def get_metadata(stream):
|
||||
author= [firstname+" "+lastname]
|
||||
title = soup.find("book-title").string
|
||||
comments = soup.find("annotation")
|
||||
tags = soup.findAll('genre')
|
||||
tags = [t.contents[0] for t in tags]
|
||||
cp = soup.find('coverpage')
|
||||
cdata = None
|
||||
if cp:
|
||||
@ -39,6 +41,8 @@ def get_metadata(stream):
|
||||
mi = MetaInformation(title, author)
|
||||
mi.comments = comments
|
||||
mi.author_sort = lastname+'; '+firstname
|
||||
if tags:
|
||||
mi.tags = tags
|
||||
if series:
|
||||
mi.series = series.get('name', None)
|
||||
try:
|
||||
|
@ -78,7 +78,10 @@ class EXTHHeader(object):
|
||||
if id == 100:
|
||||
if self.mi.authors == [_('Unknown')]:
|
||||
self.mi.authors = []
|
||||
self.mi.authors.append(content.decode(codec, 'ignore').strip())
|
||||
au = content.decode(codec, 'ignore').strip()
|
||||
self.mi.authors.append(au)
|
||||
if re.match(r'\S+?\s*,\s+\S+', au.strip()):
|
||||
self.mi.author_sort = au.strip()
|
||||
elif id == 101:
|
||||
self.mi.publisher = content.decode(codec, 'ignore').strip()
|
||||
elif id == 103:
|
||||
|
@ -795,14 +795,18 @@ class Manifest(object):
|
||||
def first_pass(data):
|
||||
try:
|
||||
data = etree.fromstring(data)
|
||||
except etree.XMLSyntaxError:
|
||||
except etree.XMLSyntaxError, err:
|
||||
repl = lambda m: ENTITYDEFS.get(m.group(1), m.group(0))
|
||||
data = ENTITY_RE.sub(repl, data)
|
||||
try:
|
||||
data = etree.fromstring(data)
|
||||
except etree.XMLSyntaxError:
|
||||
except etree.XMLSyntaxError, err:
|
||||
self.oeb.logger.warn('Parsing file %r as HTML' % self.href)
|
||||
data = html.fromstring(data)
|
||||
if err.args and err.args[0].startswith('Excessive depth'):
|
||||
from lxml.html import soupparser
|
||||
data = soupparser.fromstring(data)
|
||||
else:
|
||||
data = html.fromstring(data)
|
||||
data.attrib.pop('xmlns', None)
|
||||
for elem in data.iter(tag=etree.Comment):
|
||||
if elem.text:
|
||||
|
@ -183,7 +183,12 @@ class CSSFlattener(object):
|
||||
elif value <= slineh:
|
||||
cssdict[property] = "%0.5fem" % (dlineh / fsize)
|
||||
else:
|
||||
value = round(value / slineh) * dlineh
|
||||
try:
|
||||
value = round(value / slineh) * dlineh
|
||||
except:
|
||||
self.oeb.logger.warning(
|
||||
'Invalid length:', value)
|
||||
value = 0.0
|
||||
cssdict[property] = "%0.5fem" % (value / fsize)
|
||||
|
||||
def flatten_node(self, node, stylizer, names, styles, psize, left=0):
|
||||
|
@ -6,32 +6,60 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import cStringIO
|
||||
|
||||
from calibre import fit_image
|
||||
|
||||
class RescaleImages(object):
|
||||
'Rescale all images to fit inside given screen size'
|
||||
|
||||
def __call__(self, oeb, opts):
|
||||
from PyQt4.Qt import QApplication, QImage, Qt
|
||||
from calibre.gui2 import pixmap_to_data
|
||||
self.oeb, self.opts, self.log = oeb, opts, oeb.log
|
||||
page_width, page_height = opts.dest.width, opts.dest.height
|
||||
for item in oeb.manifest:
|
||||
from calibre.gui2 import is_ok_to_use_qt
|
||||
self.rescale(qt=is_ok_to_use_qt())
|
||||
|
||||
def rescale(self, qt=True):
|
||||
from PyQt4.Qt import QImage, Qt
|
||||
from calibre.gui2 import pixmap_to_data
|
||||
try:
|
||||
from PIL import Image as PILImage
|
||||
PILImage
|
||||
except ImportError:
|
||||
import Image as PILImage
|
||||
|
||||
|
||||
page_width, page_height = self.opts.dest.width, self.opts.dest.height
|
||||
for item in self.oeb.manifest:
|
||||
if item.media_type.startswith('image'):
|
||||
raw = item.data
|
||||
if not raw: continue
|
||||
if QApplication.instance() is None:
|
||||
QApplication([])
|
||||
if qt:
|
||||
img = QImage(10, 10, QImage.Format_ARGB32_Premultiplied)
|
||||
if not img.loadFromData(raw): continue
|
||||
width, height = img.width(), img.height()
|
||||
else:
|
||||
f = cStringIO.StringIO(raw)
|
||||
try:
|
||||
im = PILImage.open(f)
|
||||
except IOError:
|
||||
continue
|
||||
width, height = im.size
|
||||
|
||||
|
||||
|
||||
img = QImage(10, 10, QImage.Format_ARGB32_Premultiplied)
|
||||
if not img.loadFromData(raw): continue
|
||||
width, height = img.width(), img.height()
|
||||
scaled, new_width, new_height = fit_image(width, height,
|
||||
page_width, page_height)
|
||||
if scaled:
|
||||
self.log('Rescaling image', item.href)
|
||||
img = img.scaled(new_width, new_height,
|
||||
Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
|
||||
item.data = pixmap_to_data(img)
|
||||
if qt:
|
||||
img = img.scaled(new_width, new_height,
|
||||
Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
|
||||
item.data = pixmap_to_data(img)
|
||||
else:
|
||||
im = im.resize((int(new_width), int(new_height)), PILImage.ANTIALIAS)
|
||||
of = cStringIO.StringIO()
|
||||
im.convert('RGB').save(of, 'JPEG')
|
||||
item.data = of.getvalue()
|
||||
|
||||
|
||||
|
||||
|
@ -103,56 +103,50 @@ def available_width():
|
||||
def extension(path):
|
||||
return os.path.splitext(path)[1][1:].lower()
|
||||
|
||||
class MessageBox(QMessageBox):
|
||||
|
||||
def __init__(self, type_, title, msg, buttons, parent, det_msg=''):
|
||||
QMessageBox.__init__(self, type_, title, msg, buttons, parent)
|
||||
self.title = title
|
||||
self.msg = msg
|
||||
self.det_msg = det_msg
|
||||
self.setDetailedText(det_msg)
|
||||
self.cb = QPushButton(_('Copy to Clipboard'))
|
||||
self.layout().addWidget(self.cb)
|
||||
self.connect(self.cb, SIGNAL('clicked()'), self.copy_to_clipboard)
|
||||
|
||||
def copy_to_clipboard(self):
|
||||
QApplication.clipboard().setText('%s: %s\n\n%s' %
|
||||
(self.title, self.msg, self.det_msg))
|
||||
|
||||
|
||||
|
||||
def warning_dialog(parent, title, msg, det_msg='', show=False):
|
||||
d = QMessageBox(QMessageBox.Warning, 'WARNING: '+title, msg, QMessageBox.Ok,
|
||||
parent)
|
||||
d.setDetailedText(det_msg)
|
||||
d = MessageBox(QMessageBox.Warning, 'WARNING: '+title, msg, QMessageBox.Ok,
|
||||
parent, det_msg)
|
||||
d.setIconPixmap(QPixmap(':/images/dialog_warning.svg'))
|
||||
clipboard_button = QPushButton(_('Copy to Clipboard'))
|
||||
d.layout().addWidget(clipboard_button)
|
||||
def copy_to_clipboard():
|
||||
QApplication.clipboard().setText('%s - %s: %s' % (title, msg, det_msg))
|
||||
d.connect(clipboard_button, SIGNAL('clicked()'), copy_to_clipboard)
|
||||
if show:
|
||||
return d.exec_()
|
||||
return d
|
||||
|
||||
def error_dialog(parent, title, msg, det_msg='', show=False):
|
||||
d = QMessageBox(QMessageBox.Critical, 'ERROR: '+title, msg, QMessageBox.Ok,
|
||||
parent)
|
||||
d.setDetailedText(det_msg)
|
||||
d = MessageBox(QMessageBox.Critical, 'ERROR: '+title, msg, QMessageBox.Ok,
|
||||
parent, det_msg)
|
||||
d.setIconPixmap(QPixmap(':/images/dialog_error.svg'))
|
||||
clipboard_button = QPushButton(_('Copy to Clipboard'))
|
||||
d.layout().addWidget(clipboard_button)
|
||||
def copy_to_clipboard():
|
||||
QApplication.clipboard().setText('%s - %s: %s' % (title, msg, det_msg))
|
||||
d.connect(clipboard_button, SIGNAL('clicked()'), copy_to_clipboard)
|
||||
if show:
|
||||
return d.exec_()
|
||||
return d
|
||||
|
||||
def question_dialog(parent, title, msg, det_msg=''):
|
||||
d = QMessageBox(QMessageBox.Question, title, msg, QMessageBox.Yes|QMessageBox.No,
|
||||
parent)
|
||||
d.setDetailedText(det_msg)
|
||||
d = MessageBox(QMessageBox.Question, title, msg, QMessageBox.Yes|QMessageBox.No,
|
||||
parent, det_msg)
|
||||
d.setIconPixmap(QPixmap(':/images/dialog_information.svg'))
|
||||
clipboard_button = QPushButton(_('Copy to Clipboard'))
|
||||
d.layout().addWidget(clipboard_button)
|
||||
def copy_to_clipboard():
|
||||
QApplication.clipboard().setText('%s - %s: %s' % (title, msg, det_msg))
|
||||
d.connect(clipboard_button, SIGNAL('clicked()'), copy_to_clipboard)
|
||||
return d.exec_() == QMessageBox.Yes
|
||||
|
||||
def info_dialog(parent, title, msg, det_msg='', show=False):
|
||||
d = QMessageBox(QMessageBox.Information, title, msg, QMessageBox.NoButton,
|
||||
parent)
|
||||
d.setDetailedText(det_msg)
|
||||
d = MessageBox(QMessageBox.Information, title, msg, QMessageBox.NoButton,
|
||||
parent, det_msg)
|
||||
d.setIconPixmap(QPixmap(':/images/dialog_information.svg'))
|
||||
clipboard_button = QPushButton(_('Copy to Clipboard'))
|
||||
d.layout().addWidget(clipboard_button)
|
||||
def copy_to_clipboard():
|
||||
QApplication.clipboard().setText('%s - %s: %s' % (title, msg, det_msg))
|
||||
d.connect(clipboard_button, SIGNAL('clicked()'), copy_to_clipboard)
|
||||
if show:
|
||||
return d.exec_()
|
||||
return d
|
||||
@ -273,6 +267,7 @@ class FileIconProvider(QFileIconProvider):
|
||||
'azw' : 'mobi',
|
||||
'mobi' : 'mobi',
|
||||
'epub' : 'epub',
|
||||
'fb2' : 'fb2',
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
|
@ -129,7 +129,12 @@ class Adder(QObject):
|
||||
mi = MetaInformation('', [_('Unknown')])
|
||||
self.critical[name] = open(opf, 'rb').read().decode('utf-8', 'replace')
|
||||
else:
|
||||
mi = MetaInformation(OPF(opf))
|
||||
try:
|
||||
mi = MetaInformation(OPF(opf))
|
||||
except:
|
||||
import traceback
|
||||
mi = MetaInformation('', [_('Unknown')])
|
||||
self.critical[name] = traceback.format_exc()
|
||||
if not mi.title:
|
||||
mi.title = os.path.splitext(name)[0]
|
||||
mi.title = mi.title if isinstance(mi.title, unicode) else \
|
||||
|
26
src/calibre/gui2/images/mimetypes/fb2.svg
Normal file
26
src/calibre/gui2/images/mimetypes/fb2.svg
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="32px" height="32px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
|
||||
<image overflow="visible" width="32" height="32" xlink:href="data:image/gif;base64,R0lGODlhIAAgAOYAAP////X19eXl5ayws/n5+YCAgKCjpejo6PDw8KqtsJ6gov+UAKOmqJeZm6er
|
||||
rfz8/P+ZAaWoq5SWl5qdnpyeoIWFhubm5oyNjoaHh5aYmoGBgZibnoSEhIODg4mJio6PkI+Rkv+c
|
||||
CpKTlIKCgv/itf+sMP+6UouMjf/254eIiO3t7f/TkvHx8YqLi//FbsPDw//px/+0Rv/99f/x27u7
|
||||
u/+jG////fLy8v//+sXFxeDg4IGCgtLS0vPz8+fn57i4ucvLy52foe7u7vf4+ImKi8rKyYeIifr6
|
||||
+fX19svKy9DPz4WGh9TU1Ly8vKaqrNzc3NXW1YaGh46QkZ+io/T09NrZ2gAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5
|
||||
BAAAAAAALAAAAAAgACAAAAf/gAOCg4QJhg6IEREMDAaOCgAPkgSUBISXhgmJi4yPChSSD5UEAZeY
|
||||
h5udj5GTlaaDmamqCp+ho6WmsbKOBrQUE62UAbiFqIqcnp8TG6LCw8Q8Si8OL1VFiqq9n78bDZXP
|
||||
w4I+AEdIDgEAPsiev8sN3qTguDcAAEznAAKz2+4NGc7gEBjqAYCAIXQCePma0C8DgBkk5CEQSINK
|
||||
JB4JEACw8OKADgPc3mVwiKLEghXPJiLAV6+Uxgf1AKhoKAFAyQUQTgZQuRLKkEg0BqAD8AQmgm7+
|
||||
at4MUSPESZUqIjgRAiCAI3QHJhAAgCCpUpMuUACAYXIFAhVRGbCo2guhVq4Z/yR8xbnCRQwAJHKu
|
||||
QMuIXoBPCL1xlWvTJAQITkvgzXlShYEpfn8F3oqgJgAXOA9DcCEDRg2cC0LMMBCEYIBlCP9xFQEC
|
||||
AA4TmV3YWFEjRs4QJA7QWhugG0IJlEGA+ABABmzRNmCggIE49wEKFHj7QyiC8ocLF064jrEghonv
|
||||
JXAfGM+Qd1zqlLGfaOEBgA3Yh0M7H79hA2+5CEFQXu/BQwoMrsEn3ngHWPDOfSIg9AFl7P2HQQUc
|
||||
FGcCBPMVKIA/vImQoEzVceXfgxB2MEJxMxBooQBx8SbcUBpV9V8FIY6ggQYmWmCBADjiV9BwW21V
|
||||
jw4PctCBiBoUYOR4NuKIo2OGP7xAA3ZNvJBDDkAkAaOQMhZpZAEF3qikAKxJcV12RBiBQRRLhEik
|
||||
llsm+aUAw13H34dXirgDm1sW4OWbY/LnIIRYzphnnm8qGWd27NEZ452DGrnnl302iEGQgeJJaKEC
|
||||
BAIAOw==">
|
||||
</image>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
@ -153,7 +153,7 @@ def do_list(db, fields, sort_by, ascending, search_text, line_width, separator,
|
||||
break
|
||||
|
||||
widths = list(base_widths)
|
||||
titles = map(lambda x, y: '%-*s'%(x, y), widths, fields)
|
||||
titles = map(lambda x, y: '%-*s%s'%(x-len(separator), y, separator), widths, fields)
|
||||
print terminal_controller.GREEN + ''.join(titles)+terminal_controller.NORMAL
|
||||
|
||||
wrappers = map(lambda x: TextWrapper(x-1), widths)
|
||||
|
@ -1,6 +1,8 @@
|
||||
{% extends "!layout.html" %}
|
||||
{% block sidebarlogo %}
|
||||
{{ super() }}
|
||||
<p class="logo">
|
||||
<a href="http://calibre.kovidgoyal.net"><img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/></a>
|
||||
</p>
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
||||
<input type="hidden" name="cmd" value="_s-xclick" />
|
||||
<input type="hidden" name="hosted_button_id" value="3028915" />
|
||||
|
@ -21,7 +21,6 @@ DEPENDENCIES = [
|
||||
('dnspython', '1.6.0', 'dnspython', 'dnspython', 'dnspython', 'dnspython'),
|
||||
('poppler-qt4', '0.10.6', 'poppler-qt4', 'poppler-qt4', 'poppler-qt4', 'poppler-qt4'),
|
||||
('podofo', '0.7', 'podofo', 'podofo', 'podofo', 'podofo'),
|
||||
('pmount', '0.9.19', 'pmount', 'pmount', 'pmount', 'pmount'),
|
||||
]
|
||||
|
||||
|
||||
@ -385,6 +384,15 @@ else:
|
||||
|
||||
print 'Extracting files to %s ...'%destdir
|
||||
extract_tarball(f, destdir)
|
||||
mh = os.path.join(destdir, 'calibre-mount-helper')
|
||||
if os.geteuid() == 0:
|
||||
os.chown(mh, 0, 0)
|
||||
os.chmod(mh,
|
||||
stat.S_ISUID|stat.S_ISGID|stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH)
|
||||
else:
|
||||
print 'WARNING: Not running as root. Cannot install mount helper.',
|
||||
print 'Device automounting may not work.'
|
||||
|
||||
pi = os.path.join(destdir, 'calibre_postinstall')
|
||||
subprocess.call(pi, shell=True)
|
||||
return 0
|
||||
|
Loading…
x
Reference in New Issue
Block a user