mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
Merge from trunk
This commit is contained in:
commit
cda3451390
@ -1,17 +1,18 @@
|
|||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class AdvancedUserRecipe1293122276(BasicNewsRecipe):
|
class AdvancedUserRecipe1293122276(BasicNewsRecipe):
|
||||||
title = u'Smarter Planet | Tumblr for eReaders'
|
title = u'Smarter Planet | Tumblr'
|
||||||
__author__ = 'Jack Mason'
|
__author__ = 'Jack Mason'
|
||||||
author = 'IBM Global Business Services'
|
author = 'IBM Global Business Services'
|
||||||
publisher = 'IBM'
|
publisher = 'IBM'
|
||||||
language = 'en'
|
language = 'en'
|
||||||
category = 'news, technology, IT, internet of things, analytics'
|
category = 'news, technology, IT, internet of things, analytics'
|
||||||
oldest_article = 7
|
oldest_article = 14
|
||||||
max_articles_per_feed = 30
|
max_articles_per_feed = 30
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
masthead_url = 'http://30.media.tumblr.com/tumblr_l70dow9UmU1qzs4rbo1_r3_250.jpg'
|
masthead_url = 'http://www.hellercd.com/wp-content/uploads/2010/09/hero.jpg'
|
||||||
remove_tags_before = dict(id='item')
|
remove_tags_before = dict(id='item')
|
||||||
remove_tags_after = dict(id='item')
|
remove_tags_after = dict(id='item')
|
||||||
remove_tags = [dict(attrs={'class':['sidebar', 'about', 'footer', 'description,' 'disqus', 'nav', 'notes', 'disqus_thread']}),
|
remove_tags = [dict(attrs={'class':['sidebar', 'about', 'footer', 'description,' 'disqus', 'nav', 'notes', 'disqus_thread']}),
|
||||||
@ -21,4 +22,3 @@ class AdvancedUserRecipe1293122276(BasicNewsRecipe):
|
|||||||
|
|
||||||
|
|
||||||
feeds = [(u'Smarter Planet Tumblr', u'http://smarterplanet.tumblr.com/mobile/rss')]
|
feeds = [(u'Smarter Planet Tumblr', u'http://smarterplanet.tumblr.com/mobile/rss')]
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ class N516(USBMS):
|
|||||||
supported_platforms = ['windows', 'osx', 'linux']
|
supported_platforms = ['windows', 'osx', 'linux']
|
||||||
|
|
||||||
# Ordered list of supported formats
|
# Ordered list of supported formats
|
||||||
FORMATS = ['epub', 'prc', 'html', 'pdf', 'txt']
|
FORMATS = ['epub', 'prc', 'mobi', 'html', 'pdf', 'txt']
|
||||||
|
|
||||||
VENDOR_ID = [0x0525]
|
VENDOR_ID = [0x0525]
|
||||||
PRODUCT_ID = [0xa4a5]
|
PRODUCT_ID = [0xa4a5]
|
||||||
|
@ -576,10 +576,12 @@ OptionRecommendation(name='sr3_replace',
|
|||||||
if not input_fmt:
|
if not input_fmt:
|
||||||
raise ValueError('Input file must have an extension')
|
raise ValueError('Input file must have an extension')
|
||||||
input_fmt = input_fmt[1:].lower()
|
input_fmt = input_fmt[1:].lower()
|
||||||
|
self.archive_input_tdir = None
|
||||||
if input_fmt in ('zip', 'rar', 'oebzip'):
|
if input_fmt in ('zip', 'rar', 'oebzip'):
|
||||||
self.log('Processing archive...')
|
self.log('Processing archive...')
|
||||||
tdir = PersistentTemporaryDirectory('_plumber')
|
tdir = PersistentTemporaryDirectory('_plumber_archive')
|
||||||
self.input, input_fmt = self.unarchive(self.input, tdir)
|
self.input, input_fmt = self.unarchive(self.input, tdir)
|
||||||
|
self.archive_input_tdir = tdir
|
||||||
if os.access(self.input, os.R_OK):
|
if os.access(self.input, os.R_OK):
|
||||||
nfp = run_plugins_on_preprocess(self.input, input_fmt)
|
nfp = run_plugins_on_preprocess(self.input, input_fmt)
|
||||||
if nfp != self.input:
|
if nfp != self.input:
|
||||||
|
@ -121,6 +121,7 @@ class LibraryThingCovers(CoverDownload): # {{{
|
|||||||
LIBRARYTHING = 'http://www.librarything.com/isbn/'
|
LIBRARYTHING = 'http://www.librarything.com/isbn/'
|
||||||
|
|
||||||
def get_cover_url(self, isbn, br, timeout=5.):
|
def get_cover_url(self, isbn, br, timeout=5.):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
src = br.open_novisit('http://www.librarything.com/isbn/'+isbn,
|
src = br.open_novisit('http://www.librarything.com/isbn/'+isbn,
|
||||||
timeout=timeout).read().decode('utf-8', 'replace')
|
timeout=timeout).read().decode('utf-8', 'replace')
|
||||||
@ -129,6 +130,8 @@ class LibraryThingCovers(CoverDownload): # {{{
|
|||||||
err = Exception(_('LibraryThing.com timed out. Try again later.'))
|
err = Exception(_('LibraryThing.com timed out. Try again later.'))
|
||||||
raise err
|
raise err
|
||||||
else:
|
else:
|
||||||
|
if '/wiki/index.php/HelpThing:Verify' in src:
|
||||||
|
raise Exception('LibraryThing is blocking calibre.')
|
||||||
s = BeautifulSoup(src)
|
s = BeautifulSoup(src)
|
||||||
url = s.find('td', attrs={'class':'left'})
|
url = s.find('td', attrs={'class':'left'})
|
||||||
if url is None:
|
if url is None:
|
||||||
@ -142,9 +145,12 @@ class LibraryThingCovers(CoverDownload): # {{{
|
|||||||
return url
|
return url
|
||||||
|
|
||||||
def has_cover(self, mi, ans, timeout=5.):
|
def has_cover(self, mi, ans, timeout=5.):
|
||||||
if not mi.isbn:
|
if not mi.isbn or not self.site_customization:
|
||||||
return False
|
return False
|
||||||
br = browser()
|
from calibre.ebooks.metadata.library_thing import get_browser, login
|
||||||
|
br = get_browser()
|
||||||
|
un, _, pw = self.site_customization.partition(':')
|
||||||
|
login(br, un, pw)
|
||||||
try:
|
try:
|
||||||
self.get_cover_url(mi.isbn, br, timeout=timeout)
|
self.get_cover_url(mi.isbn, br, timeout=timeout)
|
||||||
self.debug('cover for', mi.isbn, 'found')
|
self.debug('cover for', mi.isbn, 'found')
|
||||||
@ -153,9 +159,12 @@ class LibraryThingCovers(CoverDownload): # {{{
|
|||||||
self.debug(e)
|
self.debug(e)
|
||||||
|
|
||||||
def get_covers(self, mi, result_queue, abort, timeout=5.):
|
def get_covers(self, mi, result_queue, abort, timeout=5.):
|
||||||
if not mi.isbn:
|
if not mi.isbn or not self.site_customization:
|
||||||
return
|
return
|
||||||
br = browser()
|
from calibre.ebooks.metadata.library_thing import get_browser, login
|
||||||
|
br = get_browser()
|
||||||
|
un, _, pw = self.site_customization.partition(':')
|
||||||
|
login(br, un, pw)
|
||||||
try:
|
try:
|
||||||
url = self.get_cover_url(mi.isbn, br, timeout=timeout)
|
url = self.get_cover_url(mi.isbn, br, timeout=timeout)
|
||||||
cover_data = br.open_novisit(url).read()
|
cover_data = br.open_novisit(url).read()
|
||||||
@ -164,6 +173,11 @@ class LibraryThingCovers(CoverDownload): # {{{
|
|||||||
result_queue.put((False, self.exception_to_string(e),
|
result_queue.put((False, self.exception_to_string(e),
|
||||||
traceback.format_exc(), self.name))
|
traceback.format_exc(), self.name))
|
||||||
|
|
||||||
|
def customization_help(self, gui=False):
|
||||||
|
ans = _('To use librarything.com you must sign up for a %sfree account%s '
|
||||||
|
'and enter your username and password separated by a : below.')
|
||||||
|
return '<p>'+ans%('<a href="http://www.librarything.com">', '</a>')
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
def check_for_cover(mi, timeout=5.): # {{{
|
def check_for_cover(mi, timeout=5.): # {{{
|
||||||
|
@ -251,19 +251,26 @@ class LibraryThing(MetadataSource): # {{{
|
|||||||
|
|
||||||
name = 'LibraryThing'
|
name = 'LibraryThing'
|
||||||
metadata_type = 'social'
|
metadata_type = 'social'
|
||||||
description = _('Downloads series/tags/rating information from librarything.com')
|
description = _('Downloads series/covers/rating information from librarything.com')
|
||||||
|
|
||||||
def fetch(self):
|
def fetch(self):
|
||||||
if not self.isbn:
|
if not self.isbn or not self.site_customization:
|
||||||
return
|
return
|
||||||
from calibre.ebooks.metadata.library_thing import get_social_metadata
|
from calibre.ebooks.metadata.library_thing import get_social_metadata
|
||||||
|
un, _, pw = self.site_customization.partition(':')
|
||||||
try:
|
try:
|
||||||
self.results = get_social_metadata(self.title, self.book_author,
|
self.results = get_social_metadata(self.title, self.book_author,
|
||||||
self.publisher, self.isbn)
|
self.publisher, self.isbn, username=un, password=pw)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.exception = e
|
self.exception = e
|
||||||
self.tb = traceback.format_exc()
|
self.tb = traceback.format_exc()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def string_customization_help(self):
|
||||||
|
ans = _('To use librarything.com you must sign up for a %sfree account%s '
|
||||||
|
'and enter your username and password separated by a : below.')
|
||||||
|
return '<p>'+ans%('<a href="http://www.librarything.com">', '</a>')
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,14 +4,13 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
Fetch cover from LibraryThing.com based on ISBN number.
|
Fetch cover from LibraryThing.com based on ISBN number.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import sys, socket, os, re, random
|
import sys, re, random
|
||||||
|
|
||||||
from lxml import html
|
from lxml import html
|
||||||
import mechanize
|
import mechanize
|
||||||
|
|
||||||
from calibre import browser, prints
|
from calibre import browser, prints
|
||||||
from calibre.utils.config import OptionParser
|
from calibre.utils.config import OptionParser
|
||||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
|
||||||
from calibre.ebooks.chardet import strip_encoding_declarations
|
from calibre.ebooks.chardet import strip_encoding_declarations
|
||||||
|
|
||||||
OPENLIBRARY = 'http://covers.openlibrary.org/b/isbn/%s-L.jpg?default=false'
|
OPENLIBRARY = 'http://covers.openlibrary.org/b/isbn/%s-L.jpg?default=false'
|
||||||
@ -28,6 +27,12 @@ def get_ua():
|
|||||||
]
|
]
|
||||||
return choices[random.randint(0, len(choices)-1)]
|
return choices[random.randint(0, len(choices)-1)]
|
||||||
|
|
||||||
|
_lt_br = None
|
||||||
|
def get_browser():
|
||||||
|
global _lt_br
|
||||||
|
if _lt_br is None:
|
||||||
|
_lt_br = browser(user_agent=get_ua())
|
||||||
|
return _lt_br.clone_browser()
|
||||||
|
|
||||||
class HeadRequest(mechanize.Request):
|
class HeadRequest(mechanize.Request):
|
||||||
|
|
||||||
@ -35,7 +40,7 @@ class HeadRequest(mechanize.Request):
|
|||||||
return 'HEAD'
|
return 'HEAD'
|
||||||
|
|
||||||
def check_for_cover(isbn, timeout=5.):
|
def check_for_cover(isbn, timeout=5.):
|
||||||
br = browser(user_agent=get_ua())
|
br = get_browser()
|
||||||
br.set_handle_redirect(False)
|
br.set_handle_redirect(False)
|
||||||
try:
|
try:
|
||||||
br.open_novisit(HeadRequest(OPENLIBRARY%isbn), timeout=timeout)
|
br.open_novisit(HeadRequest(OPENLIBRARY%isbn), timeout=timeout)
|
||||||
@ -54,46 +59,16 @@ class ISBNNotFound(LibraryThingError):
|
|||||||
class ServerBusy(LibraryThingError):
|
class ServerBusy(LibraryThingError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def login(br, username, password, force=True):
|
def login(br, username, password):
|
||||||
br.open('http://www.librarything.com')
|
raw = br.open('http://www.librarything.com').read()
|
||||||
|
if '>Sign out' in raw:
|
||||||
|
return
|
||||||
br.select_form('signup')
|
br.select_form('signup')
|
||||||
br['formusername'] = username
|
br['formusername'] = username
|
||||||
br['formpassword'] = password
|
br['formpassword'] = password
|
||||||
br.submit()
|
raw = br.submit().read()
|
||||||
|
if '>Sign out' not in raw:
|
||||||
|
raise ValueError('Failed to login as %r:%r'%(username, password))
|
||||||
def cover_from_isbn(isbn, timeout=5., username=None, password=None):
|
|
||||||
src = None
|
|
||||||
br = browser(user_agent=get_ua())
|
|
||||||
try:
|
|
||||||
return br.open(OPENLIBRARY%isbn, timeout=timeout).read(), 'jpg'
|
|
||||||
except:
|
|
||||||
pass # Cover not found
|
|
||||||
if username and password:
|
|
||||||
try:
|
|
||||||
login(br, username, password, force=False)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
src = br.open_novisit('http://www.librarything.com/isbn/'+isbn,
|
|
||||||
timeout=timeout).read().decode('utf-8', 'replace')
|
|
||||||
except Exception, err:
|
|
||||||
if isinstance(getattr(err, 'args', [None])[0], socket.timeout):
|
|
||||||
err = LibraryThingError(_('LibraryThing.com timed out. Try again later.'))
|
|
||||||
raise err
|
|
||||||
else:
|
|
||||||
s = BeautifulSoup(src)
|
|
||||||
url = s.find('td', attrs={'class':'left'})
|
|
||||||
if url is None:
|
|
||||||
if s.find('div', attrs={'class':'highloadwarning'}) is not None:
|
|
||||||
raise ServerBusy(_('Could not fetch cover as server is experiencing high load. Please try again later.'))
|
|
||||||
raise ISBNNotFound('ISBN: '+isbn+_(' not found.'))
|
|
||||||
url = url.find('img')
|
|
||||||
if url is None:
|
|
||||||
raise LibraryThingError(_('LibraryThing.com server error. Try again later.'))
|
|
||||||
url = re.sub(r'_S[XY]\d+', '', url['src'])
|
|
||||||
cover_data = br.open_novisit(url).read()
|
|
||||||
return cover_data, url.rpartition('.')[-1]
|
|
||||||
|
|
||||||
def option_parser():
|
def option_parser():
|
||||||
parser = OptionParser(usage=\
|
parser = OptionParser(usage=\
|
||||||
@ -113,15 +88,16 @@ def get_social_metadata(title, authors, publisher, isbn, username=None,
|
|||||||
from calibre.ebooks.metadata import MetaInformation
|
from calibre.ebooks.metadata import MetaInformation
|
||||||
mi = MetaInformation(title, authors)
|
mi = MetaInformation(title, authors)
|
||||||
if isbn:
|
if isbn:
|
||||||
br = browser(user_agent=get_ua())
|
br = get_browser()
|
||||||
if username and password:
|
try:
|
||||||
try:
|
login(br, username, password)
|
||||||
login(br, username, password, force=False)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
raw = br.open_novisit('http://www.librarything.com/isbn/'
|
raw = br.open_novisit('http://www.librarything.com/isbn/'
|
||||||
+isbn).read()
|
+isbn).read()
|
||||||
|
except:
|
||||||
|
return mi
|
||||||
|
if '/wiki/index.php/HelpThing:Verify' in raw:
|
||||||
|
raise Exception('LibraryThing is blocking calibre.')
|
||||||
if not raw:
|
if not raw:
|
||||||
return mi
|
return mi
|
||||||
raw = raw.decode('utf-8', 'replace')
|
raw = raw.decode('utf-8', 'replace')
|
||||||
@ -172,15 +148,46 @@ def main(args=sys.argv):
|
|||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 1
|
return 1
|
||||||
isbn = args[1]
|
isbn = args[1]
|
||||||
mi = get_social_metadata('', [], '', isbn)
|
from calibre.customize.ui import metadata_sources, cover_sources
|
||||||
|
lt = None
|
||||||
|
for x in metadata_sources('social'):
|
||||||
|
if x.name == 'LibraryThing':
|
||||||
|
lt = x
|
||||||
|
break
|
||||||
|
lt('', '', '', isbn, True)
|
||||||
|
lt.join()
|
||||||
|
if lt.exception:
|
||||||
|
print lt.tb
|
||||||
|
return 1
|
||||||
|
mi = lt.results
|
||||||
prints(mi)
|
prints(mi)
|
||||||
cover_data, ext = cover_from_isbn(isbn, username=opts.username,
|
mi.isbn = isbn
|
||||||
password=opts.password)
|
|
||||||
if not ext:
|
lt = None
|
||||||
ext = 'jpg'
|
for x in cover_sources():
|
||||||
oname = os.path.abspath(isbn+'.'+ext)
|
if x.name == 'librarything.com covers':
|
||||||
open(oname, 'w').write(cover_data)
|
lt = x
|
||||||
print 'Cover saved to file', oname
|
break
|
||||||
|
|
||||||
|
from threading import Event
|
||||||
|
from Queue import Queue
|
||||||
|
ev = Event()
|
||||||
|
lt.has_cover(mi, ev)
|
||||||
|
hc = ev.is_set()
|
||||||
|
print 'Has cover:', hc
|
||||||
|
if hc:
|
||||||
|
abort = Event()
|
||||||
|
temp = Queue()
|
||||||
|
lt.get_covers(mi, temp, abort)
|
||||||
|
|
||||||
|
cover = temp.get_nowait()
|
||||||
|
if cover[0]:
|
||||||
|
open(isbn + '.jpg', 'wb').write(cover[1])
|
||||||
|
print 'Cover saved to:', isbn+'.jpg'
|
||||||
|
else:
|
||||||
|
print 'Cover download failed'
|
||||||
|
print cover[2]
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -8,12 +8,12 @@ from urllib import unquote
|
|||||||
from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, \
|
from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, \
|
||||||
QByteArray, QTranslator, QCoreApplication, QThread, \
|
QByteArray, QTranslator, QCoreApplication, QThread, \
|
||||||
QEvent, QTimer, pyqtSignal, QDate, QDesktopServices, \
|
QEvent, QTimer, pyqtSignal, QDate, QDesktopServices, \
|
||||||
QFileDialog, QMessageBox, QPixmap, QFileIconProvider, \
|
QFileDialog, QFileIconProvider, \
|
||||||
QIcon, QApplication, QDialog, QPushButton, QUrl, QFont
|
QIcon, QApplication, QDialog, QUrl, QFont
|
||||||
|
|
||||||
ORG_NAME = 'KovidsBrain'
|
ORG_NAME = 'KovidsBrain'
|
||||||
APP_UID = 'libprs500'
|
APP_UID = 'libprs500'
|
||||||
from calibre.constants import islinux, iswindows, isosx, isfreebsd, isfrozen
|
from calibre.constants import islinux, iswindows, isfreebsd, isfrozen
|
||||||
from calibre.utils.config import Config, ConfigProxy, dynamic, JSONConfig
|
from calibre.utils.config import Config, ConfigProxy, dynamic, JSONConfig
|
||||||
from calibre.utils.localization import set_qt_translator
|
from calibre.utils.localization import set_qt_translator
|
||||||
from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats
|
from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats
|
||||||
@ -178,104 +178,40 @@ def is_widescreen():
|
|||||||
def extension(path):
|
def extension(path):
|
||||||
return os.path.splitext(path)[1][1:].lower()
|
return os.path.splitext(path)[1][1:].lower()
|
||||||
|
|
||||||
class CopyButton(QPushButton):
|
|
||||||
|
|
||||||
ACTION_KEYS = [Qt.Key_Enter, Qt.Key_Return, Qt.Key_Space]
|
|
||||||
|
|
||||||
def copied(self):
|
|
||||||
self.emit(SIGNAL('copy()'))
|
|
||||||
self.setDisabled(True)
|
|
||||||
self.setText(_('Copied'))
|
|
||||||
|
|
||||||
|
|
||||||
def keyPressEvent(self, ev):
|
|
||||||
try:
|
|
||||||
if ev.key() in self.ACTION_KEYS:
|
|
||||||
self.copied()
|
|
||||||
return
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
QPushButton.keyPressEvent(self, ev)
|
|
||||||
|
|
||||||
|
|
||||||
def keyReleaseEvent(self, ev):
|
|
||||||
try:
|
|
||||||
if ev.key() in self.ACTION_KEYS:
|
|
||||||
return
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
QPushButton.keyReleaseEvent(self, ev)
|
|
||||||
|
|
||||||
def mouseReleaseEvent(self, ev):
|
|
||||||
ev.accept()
|
|
||||||
self.copied()
|
|
||||||
|
|
||||||
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)
|
|
||||||
# Cannot set keyboard shortcut as the event is not easy to filter
|
|
||||||
self.cb = CopyButton(_('Copy') if isosx else _('Copy to Clipboard'))
|
|
||||||
self.connect(self.cb, SIGNAL('copy()'), self.copy_to_clipboard)
|
|
||||||
self.addButton(self.cb, QMessageBox.ActionRole)
|
|
||||||
default_button = self.button(self.Ok)
|
|
||||||
if default_button is None:
|
|
||||||
default_button = self.button(self.Yes)
|
|
||||||
if default_button is not None:
|
|
||||||
self.setDefaultButton(default_button)
|
|
||||||
|
|
||||||
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,
|
def warning_dialog(parent, title, msg, det_msg='', show=False,
|
||||||
show_copy_button=True):
|
show_copy_button=True):
|
||||||
d = MessageBox(QMessageBox.Warning, 'WARNING: '+title, msg, QMessageBox.Ok,
|
from calibre.gui2.dialogs.message_box import MessageBox
|
||||||
parent, det_msg)
|
d = MessageBox(MessageBox.WARNING, 'WARNING: '+title, msg, det_msg, parent=parent,
|
||||||
d.setEscapeButton(QMessageBox.Ok)
|
show_copy_button=show_copy_button)
|
||||||
d.setIconPixmap(QPixmap(I('dialog_warning.png')))
|
|
||||||
if not show_copy_button:
|
|
||||||
d.cb.setVisible(False)
|
|
||||||
if show:
|
if show:
|
||||||
return d.exec_()
|
return d.exec_()
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def error_dialog(parent, title, msg, det_msg='', show=False,
|
def error_dialog(parent, title, msg, det_msg='', show=False,
|
||||||
show_copy_button=True):
|
show_copy_button=True):
|
||||||
d = MessageBox(QMessageBox.Critical, 'ERROR: '+title, msg, QMessageBox.Ok,
|
from calibre.gui2.dialogs.message_box import MessageBox
|
||||||
parent, det_msg)
|
d = MessageBox(MessageBox.ERROR, 'ERROR: '+title, msg, det_msg, parent=parent,
|
||||||
d.setIconPixmap(QPixmap(I('dialog_error.png')))
|
show_copy_button=show_copy_button)
|
||||||
d.setEscapeButton(QMessageBox.Ok)
|
|
||||||
if not show_copy_button:
|
|
||||||
d.cb.setVisible(False)
|
|
||||||
if show:
|
if show:
|
||||||
return d.exec_()
|
return d.exec_()
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def question_dialog(parent, title, msg, det_msg='', show_copy_button=True,
|
def question_dialog(parent, title, msg, det_msg='', show_copy_button=False,
|
||||||
buttons=QMessageBox.Yes|QMessageBox.No, yes_button=QMessageBox.Yes):
|
buttons=None, yes_button=None):
|
||||||
d = MessageBox(QMessageBox.Question, title, msg, buttons,
|
from calibre.gui2.dialogs.message_box import MessageBox
|
||||||
parent, det_msg)
|
d = MessageBox(MessageBox.QUESTION, title, msg, det_msg, parent=parent,
|
||||||
d.setIconPixmap(QPixmap(I('dialog_question.png')))
|
show_copy_button=show_copy_button)
|
||||||
d.setEscapeButton(QMessageBox.No)
|
if buttons is not None:
|
||||||
if not show_copy_button:
|
d.bb.setStandardButtons(buttons)
|
||||||
d.cb.setVisible(False)
|
|
||||||
|
|
||||||
return d.exec_() == yes_button
|
return d.exec_() == d.Accepted
|
||||||
|
|
||||||
def info_dialog(parent, title, msg, det_msg='', show=False,
|
def info_dialog(parent, title, msg, det_msg='', show=False,
|
||||||
show_copy_button=True):
|
show_copy_button=True):
|
||||||
d = MessageBox(QMessageBox.Information, title, msg, QMessageBox.Ok,
|
from calibre.gui2.dialogs.message_box import MessageBox
|
||||||
parent, det_msg)
|
d = MessageBox(MessageBox.INFO, title, msg, det_msg, parent=parent,
|
||||||
d.setIconPixmap(QPixmap(I('dialog_information.png')))
|
show_copy_button=show_copy_button)
|
||||||
if not show_copy_button:
|
|
||||||
d.cb.setVisible(False)
|
|
||||||
|
|
||||||
if show:
|
if show:
|
||||||
return d.exec_()
|
return d.exec_()
|
||||||
|
@ -4,6 +4,8 @@ __license__ = 'GPL 3'
|
|||||||
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
|
||||||
from PyQt4.Qt import QString, SIGNAL
|
from PyQt4.Qt import QString, SIGNAL
|
||||||
|
|
||||||
from calibre.gui2.convert.single import Config, sort_formats_by_preference, \
|
from calibre.gui2.convert.single import Config, sort_formats_by_preference, \
|
||||||
@ -108,6 +110,11 @@ class BulkConfig(Config):
|
|||||||
idx = oidx if -1 < oidx < self._groups_model.rowCount() else 0
|
idx = oidx if -1 < oidx < self._groups_model.rowCount() else 0
|
||||||
self.groups.setCurrentIndex(self._groups_model.index(idx))
|
self.groups.setCurrentIndex(self._groups_model.index(idx))
|
||||||
self.stack.setCurrentIndex(idx)
|
self.stack.setCurrentIndex(idx)
|
||||||
|
try:
|
||||||
|
shutil.rmtree(self.plumber.archive_input_tdir, ignore_errors=True)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def setup_output_formats(self, db, preferred_output_format):
|
def setup_output_formats(self, db, preferred_output_format):
|
||||||
if preferred_output_format:
|
if preferred_output_format:
|
||||||
|
@ -6,7 +6,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import sys, cPickle
|
import sys, cPickle, shutil
|
||||||
|
|
||||||
from PyQt4.Qt import QString, SIGNAL, QAbstractListModel, Qt, QVariant, QFont
|
from PyQt4.Qt import QString, SIGNAL, QAbstractListModel, Qt, QVariant, QFont
|
||||||
|
|
||||||
@ -224,6 +224,10 @@ class Config(ResizableDialog, Ui_Dialog):
|
|||||||
idx = oidx if -1 < oidx < self._groups_model.rowCount() else 0
|
idx = oidx if -1 < oidx < self._groups_model.rowCount() else 0
|
||||||
self.groups.setCurrentIndex(self._groups_model.index(idx))
|
self.groups.setCurrentIndex(self._groups_model.index(idx))
|
||||||
self.stack.setCurrentIndex(idx)
|
self.stack.setCurrentIndex(idx)
|
||||||
|
try:
|
||||||
|
shutil.rmtree(self.plumber.archive_input_tdir, ignore_errors=True)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def setup_input_output_formats(self, db, book_id, preferred_input_format,
|
def setup_input_output_formats(self, db, book_id, preferred_input_format,
|
||||||
|
104
src/calibre/gui2/dialogs/message_box.py
Normal file
104
src/calibre/gui2/dialogs/message_box.py
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt4.Qt import QDialog, QIcon, QApplication, QSize, QKeySequence, \
|
||||||
|
QAction, Qt
|
||||||
|
|
||||||
|
from calibre.constants import __version__
|
||||||
|
from calibre.gui2.dialogs.message_box_ui import Ui_Dialog
|
||||||
|
|
||||||
|
class MessageBox(QDialog, Ui_Dialog):
|
||||||
|
|
||||||
|
ERROR = 0
|
||||||
|
WARNING = 1
|
||||||
|
INFO = 2
|
||||||
|
QUESTION = 3
|
||||||
|
|
||||||
|
def __init__(self, type_, title, msg, det_msg='', show_copy_button=True,
|
||||||
|
parent=None):
|
||||||
|
QDialog.__init__(self, parent)
|
||||||
|
icon = {
|
||||||
|
self.ERROR : 'error',
|
||||||
|
self.WARNING: 'warning',
|
||||||
|
self.INFO: 'information',
|
||||||
|
self.QUESTION: 'question',
|
||||||
|
}[type_]
|
||||||
|
icon = 'dialog_%s.png'%icon
|
||||||
|
self.icon = QIcon(I(icon))
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
self.setWindowTitle(title)
|
||||||
|
self.setWindowIcon(self.icon)
|
||||||
|
self.icon_label.setPixmap(self.icon.pixmap(128, 128))
|
||||||
|
self.msg.setText(msg)
|
||||||
|
self.det_msg.setPlainText(det_msg)
|
||||||
|
self.det_msg.setVisible(False)
|
||||||
|
|
||||||
|
if det_msg:
|
||||||
|
self.show_det_msg = _('Show &details')
|
||||||
|
self.hide_det_msg = _('Hide &details')
|
||||||
|
self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole)
|
||||||
|
self.det_msg_toggle.clicked.connect(self.toggle_det_msg)
|
||||||
|
self.det_msg_toggle.setToolTip(
|
||||||
|
_('Show detailed information about this error'))
|
||||||
|
|
||||||
|
if show_copy_button:
|
||||||
|
self.ctc_button = self.bb.addButton(_('&Copy to clipboard'),
|
||||||
|
self.bb.ActionRole)
|
||||||
|
self.ctc_button.clicked.connect(self.copy_to_clipboard)
|
||||||
|
|
||||||
|
|
||||||
|
self.copy_action = QAction(self)
|
||||||
|
self.addAction(self.copy_action)
|
||||||
|
self.copy_action.setShortcuts(QKeySequence.Copy)
|
||||||
|
self.copy_action.triggered.connect(self.copy_to_clipboard)
|
||||||
|
|
||||||
|
self.is_question = type_ == self.QUESTION
|
||||||
|
if self.is_question:
|
||||||
|
self.bb.setStandardButtons(self.bb.Yes|self.bb.No)
|
||||||
|
self.bb.button(self.bb.Yes).setDefault(True)
|
||||||
|
else:
|
||||||
|
self.bb.button(self.bb.Ok).setDefault(True)
|
||||||
|
|
||||||
|
self.do_resize()
|
||||||
|
|
||||||
|
def toggle_det_msg(self, *args):
|
||||||
|
vis = self.det_msg.isVisible()
|
||||||
|
self.det_msg_toggle.setText(self.show_det_msg if vis else
|
||||||
|
self.hide_det_msg)
|
||||||
|
self.det_msg.setVisible(not vis)
|
||||||
|
self.do_resize()
|
||||||
|
|
||||||
|
def do_resize(self):
|
||||||
|
sz = self.sizeHint() + QSize(100, 0)
|
||||||
|
sz.setWidth(min(500, sz.width()))
|
||||||
|
sz.setHeight(min(500, sz.height()))
|
||||||
|
self.resize(sz)
|
||||||
|
|
||||||
|
def copy_to_clipboard(self, *args):
|
||||||
|
QApplication.clipboard().setText(
|
||||||
|
'calibre, version %s\n%s: %s\n\n%s' %
|
||||||
|
(__version__, unicode(self.windowTitle()),
|
||||||
|
unicode(self.msg.text()),
|
||||||
|
unicode(self.det_msg.toPlainText())))
|
||||||
|
self.ctc_button.setText(_('Copied'))
|
||||||
|
|
||||||
|
def showEvent(self, ev):
|
||||||
|
ret = QDialog.showEvent(self, ev)
|
||||||
|
if self.is_question:
|
||||||
|
self.bb.button(self.bb.Yes).setFocus(Qt.OtherFocusReason)
|
||||||
|
else:
|
||||||
|
self.bb.button(self.bb.Ok).setFocus(Qt.OtherFocusReason)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app = QApplication([])
|
||||||
|
from calibre.gui2 import question_dialog
|
||||||
|
print question_dialog(None, 'title', 'msg <a href="http://google.com">goog</a> ',
|
||||||
|
det_msg='det '*1000,
|
||||||
|
show_copy_button=True)
|
105
src/calibre/gui2/dialogs/message_box.ui
Normal file
105
src/calibre/gui2/dialogs/message_box.ui
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Dialog</class>
|
||||||
|
<widget class="QDialog" name="Dialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>497</width>
|
||||||
|
<height>235</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="icon_label">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>68</width>
|
||||||
|
<height>68</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="../../../../resources/images.qrc">:/images/dialog_warning.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="msg">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QPlainTextEdit" name="det_msg">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="bb">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../../resources/images.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>bb</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>bb</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>
|
Loading…
x
Reference in New Issue
Block a user