Merge from trunk

This commit is contained in:
Charles Haley 2011-04-28 18:46:34 +01:00
commit 2053ffb22c
8 changed files with 61 additions and 38 deletions

View File

@ -2,6 +2,11 @@ a {
text-decoration: none; text-decoration: none;
color: blue color: blue
} }
a:hover {
color: red
}
.comments { .comments {
margin-top: 0; margin-top: 0;
padding-top: 0; padding-top: 0;

View File

@ -156,17 +156,17 @@ class HeuristicProcessor(object):
] ]
ITALICIZE_STYLE_PATS = [ ITALICIZE_STYLE_PATS = [
r'(?msu)(?<=[\s>])_(?P<words>[^_]+)_', ur'(?msu)(?<=[\s>"\'])_(?P<words>[^_]+)_',
r'(?msu)(?<=[\s>])/(?P<words>[^/\*>]+)/', ur'(?msu)(?<=[\s>"\'])/(?P<words>[^/\*>]+)/',
r'(?msu)(?<=[\s>])~~(?P<words>[^~]+)~~', ur'(?msu)(?<=[\s>"\'])~~(?P<words>[^~]+)~~',
r'(?msu)(?<=[\s>])\*(?P<words>[^\*]+)\*', ur'(?msu)(?<=[\s>"\'])\*(?P<words>[^\*]+)\*',
r'(?msu)(?<=[\s>])~(?P<words>[^~]+)~', ur'(?msu)(?<=[\s>"\'])~(?P<words>[^~]+)~',
r'(?msu)(?<=[\s>])_/(?P<words>[^/_]+)/_', ur'(?msu)(?<=[\s>"\'])_/(?P<words>[^/_]+)/_',
r'(?msu)(?<=[\s>])_\*(?P<words>[^\*_]+)\*_', ur'(?msu)(?<=[\s>"\'])_\*(?P<words>[^\*_]+)\*_',
r'(?msu)(?<=[\s>])\*/(?P<words>[^/\*]+)/\*', ur'(?msu)(?<=[\s>"\'])\*/(?P<words>[^/\*]+)/\*',
r'(?msu)(?<=[\s>])_\*/(?P<words>[^\*_]+)/\*_', ur'(?msu)(?<=[\s>"\'])_\*/(?P<words>[^\*_]+)/\*_',
r'(?msu)(?<=[\s>])/:(?P<words>[^:/]+):/', ur'(?msu)(?<=[\s>"\'])/:(?P<words>[^:/]+):/',
r'(?msu)(?<=[\s>])\|:(?P<words>[^:\|]+):\|', ur'(?msu)(?<=[\s>"\'])\|:(?P<words>[^:\|]+):\|',
] ]
for word in ITALICIZE_WORDS: for word in ITALICIZE_WORDS:
@ -518,13 +518,13 @@ class HeuristicProcessor(object):
if re.findall('(<|>)', replacement_break): if re.findall('(<|>)', replacement_break):
if re.match('^<hr', replacement_break): if re.match('^<hr', replacement_break):
if replacement_break.find('width') != -1: if replacement_break.find('width') != -1:
width = int(re.sub('.*?width(:|=)(?P<wnum>\d+).*', '\g<wnum>', replacement_break)) width = int(re.sub('.*?width(:|=)(?P<wnum>\d+).*', '\g<wnum>', replacement_break))
replacement_break = re.sub('(?i)(width=\d+\%?|width:\s*\d+(\%|px|pt|em)?;?)', '', replacement_break) replacement_break = re.sub('(?i)(width=\d+\%?|width:\s*\d+(\%|px|pt|em)?;?)', '', replacement_break)
divpercent = (100 - width) / 2 divpercent = (100 - width) / 2
hr_open = re.sub('45', str(divpercent), hr_open) hr_open = re.sub('45', str(divpercent), hr_open)
scene_break = hr_open+replacement_break+'</div>' scene_break = hr_open+replacement_break+'</div>'
else: else:
scene_break = hr_open+'<hr style="height: 3px; background:#505050" /></div>' scene_break = hr_open+'<hr style="height: 3px; background:#505050" /></div>'
elif re.match('^<img', replacement_break): elif re.match('^<img', replacement_break):
scene_break = self.scene_break_open+replacement_break+'</p>' scene_break = self.scene_break_open+replacement_break+'</p>'
else: else:
@ -584,10 +584,10 @@ class HeuristicProcessor(object):
#print "styles for this line are: "+str(styles) #print "styles for this line are: "+str(styles)
split_styles = [] split_styles = []
for style in styles: for style in styles:
#print "style is: "+str(style) #print "style is: "+str(style)
newstyle = style.split(':') newstyle = style.split(':')
#print "newstyle is: "+str(newstyle) #print "newstyle is: "+str(newstyle)
split_styles.append(newstyle) split_styles.append(newstyle)
styles = split_styles styles = split_styles
for style, setting in styles: for style, setting in styles:
if style == 'text-align' and setting != 'left': if style == 'text-align' and setting != 'left':

View File

@ -563,10 +563,12 @@ class Metadata(object):
def format_tags(self): def format_tags(self):
return u', '.join([unicode(t) for t in sorted(self.tags, key=sort_key)]) return u', '.join([unicode(t) for t in sorted(self.tags, key=sort_key)])
def format_rating(self, v = None): def format_rating(self, v=None, divide_by=1.0):
if v is None: if v is None:
return unicode(self.rating/2) if self.rating is not None:
return unicode(v/2) return unicode(self.rating/divide_by)
return u'None'
return unicode(v/divide_by)
def format_field(self, key, series_with_index=True): def format_field(self, key, series_with_index=True):
''' '''

View File

@ -40,6 +40,11 @@ path_to_ebook to the database.
parser.add_option('--ignore-plugins', default=False, action='store_true', parser.add_option('--ignore-plugins', default=False, action='store_true',
help=_('Ignore custom plugins, useful if you installed a plugin' help=_('Ignore custom plugins, useful if you installed a plugin'
' that is preventing calibre from starting')) ' that is preventing calibre from starting'))
parser.add_option('-s', '--shutdown-running-calibre', default=False,
action='store_true',
help=_('Cause a running calibre instance, if any, to be'
' shutdown. Note that if there are running jobs, they '
'will be silently aborted, so use with care.'))
return parser return parser
def init_qt(args): def init_qt(args):
@ -339,7 +344,7 @@ def cant_start(msg=_('If you are sure it is not running')+', ',
raise SystemExit(1) raise SystemExit(1)
def communicate(args): def communicate(opts, args):
t = RC() t = RC()
t.start() t.start()
time.sleep(3) time.sleep(3)
@ -348,9 +353,12 @@ def communicate(args):
cant_start(what=_('try deleting the file')+': '+f) cant_start(what=_('try deleting the file')+': '+f)
raise SystemExit(1) raise SystemExit(1)
if len(args) > 1: if opts.shutdown_running_calibre:
args[1] = os.path.abspath(args[1]) t.conn.send('shutdown:')
t.conn.send('launched:'+repr(args)) else:
if len(args) > 1:
args[1] = os.path.abspath(args[1])
t.conn.send('launched:'+repr(args))
t.conn.close() t.conn.close()
raise SystemExit(0) raise SystemExit(0)
@ -365,6 +373,8 @@ def main(args=sys.argv):
from calibre.utils.lock import singleinstance from calibre.utils.lock import singleinstance
from multiprocessing.connection import Listener from multiprocessing.connection import Listener
si = singleinstance('calibre GUI') si = singleinstance('calibre GUI')
if si and opts.shutdown_running_calibre:
return 0
if si: if si:
try: try:
listener = Listener(address=ADDRESS) listener = Listener(address=ADDRESS)
@ -390,10 +400,10 @@ def main(args=sys.argv):
else: else:
# On windows only singleinstance can be trusted # On windows only singleinstance can be trusted
otherinstance = True if iswindows else False otherinstance = True if iswindows else False
if not otherinstance: if not otherinstance and not opts.shutdown_running_calibre:
return run_gui(opts, args, actions, listener, app, gui_debug=gui_debug) return run_gui(opts, args, actions, listener, app, gui_debug=gui_debug)
communicate(args) communicate(opts, args)
return 0 return 0

View File

@ -100,7 +100,8 @@ class ThreadedJob(BaseJob):
try: try:
self.consolidate_log() self.consolidate_log()
except: except:
self.log.exception('Log consolidation failed') if self.log is not None:
self.log.exception('Log consolidation failed')
# No need to keep references to these around anymore # No need to keep references to these around anymore
self.func = self.args = self.kwargs = self.notifications = None self.func = self.args = self.kwargs = self.notifications = None
@ -112,7 +113,7 @@ class ThreadedJob(BaseJob):
self.start_time = time.time() self.start_time = time.time()
self.duration = 0.0001 self.duration = 0.0001
else: else:
self.duration = time.time() - self.start_time() self.duration = time.time() - self.start_time
self.abort.set() self.abort.set()
self.log('Aborted job:', self.description) self.log('Aborted job:', self.description)

View File

@ -446,6 +446,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
self.library_view.model().refresh() self.library_view.model().refresh()
self.library_view.model().research() self.library_view.model().research()
self.tags_view.recount() self.tags_view.recount()
elif msg.startswith('shutdown:'):
self.quit(confirm_quit=False)
else: else:
print msg print msg
@ -599,8 +601,9 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
dynamic.set('sort_history', self.library_view.model().sort_history) dynamic.set('sort_history', self.library_view.model().sort_history)
self.save_layout_state() self.save_layout_state()
def quit(self, checked=True, restart=False, debug_on_restart=False): def quit(self, checked=True, restart=False, debug_on_restart=False,
if not self.confirm_quit(): confirm_quit=True):
if confirm_quit and not self.confirm_quit():
return return
try: try:
self.shutdown() self.shutdown()

View File

@ -189,7 +189,7 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250,
else: else:
template = re.sub(r'\{series_index[^}]*?\}', '', template) template = re.sub(r'\{series_index[^}]*?\}', '', template)
if mi.rating is not None: if mi.rating is not None:
format_args['rating'] = mi.format_rating() format_args['rating'] = mi.format_rating(divide_by=2.0)
if hasattr(mi.timestamp, 'timetuple'): if hasattr(mi.timestamp, 'timetuple'):
format_args['timestamp'] = strftime(timefmt, mi.timestamp.timetuple()) format_args['timestamp'] = strftime(timefmt, mi.timestamp.timetuple())
if hasattr(mi.pubdate, 'timetuple'): if hasattr(mi.pubdate, 'timetuple'):
@ -212,7 +212,8 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250,
elif cm['datatype'] == 'bool': elif cm['datatype'] == 'bool':
format_args[key] = _('yes') if format_args[key] else _('no') format_args[key] = _('yes') if format_args[key] else _('no')
elif cm['datatype'] == 'rating': elif cm['datatype'] == 'rating':
format_args[key] = mi.format_rating(format_args[key]) format_args[key] = mi.format_rating(format_args[key],
divide_by=2.0)
elif cm['datatype'] in ['int', 'float']: elif cm['datatype'] in ['int', 'float']:
if format_args[key] != 0: if format_args[key] != 0:
format_args[key] = unicode(format_args[key]) format_args[key] = unicode(format_args[key])

View File

@ -195,9 +195,10 @@ It can get tiresome to keep re-adding a plugin to calibre to test small changes.
Once you've located the zip file of your plugin you can then directly update it with your changes instead of re-adding it each time. To do so from the command line, in the directory that contains your plugin source code, use:: Once you've located the zip file of your plugin you can then directly update it with your changes instead of re-adding it each time. To do so from the command line, in the directory that contains your plugin source code, use::
zip -R /path/to/plugin/zip/file.zip * calibre -s; sleep 4s; zip -R /path/to/plugin/zip/file.zip *; calibre
This will update all changed files. It relies on the freely available zip command line tool. Note that you should quit calibre before running this command. This will shutdown a running calibre. Wait for the shutdown to complete, then update your plugin files and relaunch calibre.
It relies on the freely available zip command line tool.
More plugin examples More plugin examples
---------------------- ----------------------