mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
[Sync] Sync with trunk. Revision 7367.
This commit is contained in:
commit
0ba1752d55
@ -4,6 +4,11 @@ License: GPL-3
|
|||||||
The full text of the GPL is distributed as in
|
The full text of the GPL is distributed as in
|
||||||
/usr/share/common-licenses/GPL-3 on Debian systems.
|
/usr/share/common-licenses/GPL-3 on Debian systems.
|
||||||
|
|
||||||
|
Files: src/calibre/ebooks/pdf/*.h,*.cpp
|
||||||
|
License: GPL-2 or later
|
||||||
|
The full text of the GPL is distributed as in
|
||||||
|
/usr/share/common-licenses/GPL-2 on Debian systems.
|
||||||
|
|
||||||
Files: src/calibre/ebooks/BeautifulSoup.py
|
Files: src/calibre/ebooks/BeautifulSoup.py
|
||||||
Copyright: Copyright (c) 2004-2007, Leonard Richardson
|
Copyright: Copyright (c) 2004-2007, Leonard Richardson
|
||||||
License: BSD
|
License: BSD
|
||||||
|
@ -4,6 +4,101 @@
|
|||||||
# for important features/bug fixes.
|
# for important features/bug fixes.
|
||||||
# Also, each release can have new and improved recipes.
|
# Also, each release can have new and improved recipes.
|
||||||
|
|
||||||
|
- version: 0.7.35
|
||||||
|
date: 2010-12-23
|
||||||
|
|
||||||
|
new features:
|
||||||
|
- title: "Add a simple to use Rich text editor for comments to the edit metadata dialog."
|
||||||
|
description: >
|
||||||
|
"You can now easily add formatting like bold/italic/lists/headings/colors/etc. to book comments via the
|
||||||
|
edit metadata dialog"
|
||||||
|
type: major
|
||||||
|
|
||||||
|
- title: "E-book viewer: Add a right click menu item 'Inspect' that allows you to inspect the underlying HTML/CSS source of the currently displayed content"
|
||||||
|
type: major
|
||||||
|
|
||||||
|
- title: "When deleting books from the library if a device is connected and the books are also present on the device ask the user if the books should be deleted from the device, the library, or both."
|
||||||
|
|
||||||
|
- title: "Add device drivers for Trekstore eBook Player 7, Sanda Bambook, ALuratek Color, Samsung Galaxy, LG Optimus, Motorola Droid 2 and Sunstech EB700"
|
||||||
|
tickets: [8021, 7966, 7973, 7956]
|
||||||
|
|
||||||
|
- title: "Add an entry to the menu of the calibre library button to select a random book from your calibre library"
|
||||||
|
tickets: [8010]
|
||||||
|
|
||||||
|
- title: "SONY driver: Add a couple of special extra collections for all books by author and all books by title, to workaround the broken sorting on newer SONY models. To enable these collections, go to Preferences->Plugins->Device Interface plugins and customize the SONY plugin."
|
||||||
|
|
||||||
|
- title: "Edit metadata dialog: When downloading metadata, make the table of matching books sortable"
|
||||||
|
tickets: [7951]
|
||||||
|
|
||||||
|
- title: "Add a success message after a database integrity check completes successfully"
|
||||||
|
|
||||||
|
- title: "Search and replace: When using regular expression mode, add a special input field '{template}' that allows use the templating language to create complex input fields. Also allow setting of series_index by search and replace using the same syntax as in the book list, namely, Series Name [series number]"
|
||||||
|
|
||||||
|
- title: "Bulk metadata edit: Add option to automatically set cover from the cover present in the actual ebook files"
|
||||||
|
tickets: [7947]
|
||||||
|
|
||||||
|
- title: "E-book viewer: Show format of current book in the title bar."
|
||||||
|
tickets: [7974]
|
||||||
|
|
||||||
|
- title: "Add a tweak to control how author names are displayed in the Tag Browser and Content Server"
|
||||||
|
|
||||||
|
- title: "FB2 Output: Restore sectionizing functionality"
|
||||||
|
|
||||||
|
bug fixes:
|
||||||
|
- title: "When in narrow layout, reserve 40% of available width in the book details panel for series/formats/etc and use the rest for comments"
|
||||||
|
tickets: [8028]
|
||||||
|
|
||||||
|
- title: "PDB Input: Fix failure to block-indent PML \t sections"
|
||||||
|
tickets: [8019]
|
||||||
|
|
||||||
|
- title: "Tag browser: When renaming items dont reset the library view and try not to scroll the Tag Browser itself"
|
||||||
|
|
||||||
|
- title: "Conversion pipeline: Fix broken link rewriting for inline CSS embedded in HTML"
|
||||||
|
|
||||||
|
- title: "Fix regression in 0.7.34 that broke recipes using extra_css to link to SONY device fonts"
|
||||||
|
tickets: [7995]
|
||||||
|
|
||||||
|
- title: "SONY driver: Don't upload thumbnails as they slow down post disconnect processing on older models"
|
||||||
|
|
||||||
|
- title: "Content server: Fix a bug that allowed remote users to read arbitrary png/gif/js/css/html files"
|
||||||
|
tickets: [7980]
|
||||||
|
|
||||||
|
- title: "On X11 initialize fontconfig in the GUI thread as Qt also uses fontconfig internally and fontconfig is not thread safe. Fixes a few random crashes on calibre strartup"
|
||||||
|
|
||||||
|
- title: "When using the remove specific format actions, only show available formats in the selected books"
|
||||||
|
tickets: [7967]
|
||||||
|
|
||||||
|
- title: "Linux binary build: If setting system default locale fails, try setting locale to en_US.UTF-8 instead"
|
||||||
|
|
||||||
|
- title: "Have the title sort tweak respected everywhere"
|
||||||
|
|
||||||
|
- title: "PocketBook 701 driver: Swap the main memory and card drives on windows"
|
||||||
|
|
||||||
|
- title: "Fix regression in templating that caused series_index to be shown even when book had no series"
|
||||||
|
tickets: [7949]
|
||||||
|
|
||||||
|
- title: "Content server: Fix regressiont hat broke browsing by rating"
|
||||||
|
|
||||||
|
- title: "Content server OPDS feeds: Fix parsing of author names as XML"
|
||||||
|
tickets: [7938]
|
||||||
|
|
||||||
|
improved recipes:
|
||||||
|
- Business Week Magazine
|
||||||
|
- Gazet van Antwerpen
|
||||||
|
- La Nacion
|
||||||
|
- New England Journal of Medicine
|
||||||
|
- Journal of Hospital Medicine
|
||||||
|
|
||||||
|
new recipes:
|
||||||
|
- title: "NRC Handelsblad (EPUB version)"
|
||||||
|
author: "veezh"
|
||||||
|
|
||||||
|
- title: "CND and wenxuecity - znjy"
|
||||||
|
author: "Derek Liang"
|
||||||
|
|
||||||
|
- title: "Mish's Global Economic Trend Analysis"
|
||||||
|
author: "Darko Miletic"
|
||||||
|
|
||||||
- version: 0.7.34
|
- version: 0.7.34
|
||||||
date: 2010-12-17
|
date: 2010-12-17
|
||||||
|
|
||||||
|
@ -135,32 +135,53 @@ auto_connect_to_folder = ''
|
|||||||
# metadata management is set to automatic. Collections on Sonys are named
|
# metadata management is set to automatic. Collections on Sonys are named
|
||||||
# depending upon whether the field is standard or custom. A collection derived
|
# depending upon whether the field is standard or custom. A collection derived
|
||||||
# from a standard field is named for the value in that field. For example, if
|
# from a standard field is named for the value in that field. For example, if
|
||||||
# the standard 'series' column contains the name 'Darkover', then the series
|
# the standard 'series' column contains the value 'Darkover', then the
|
||||||
# will be named 'Darkover'. A collection derived from a custom field will have
|
# collection name is 'Darkover'. A collection derived from a custom field will
|
||||||
# the name of the field added to the value. For example, if a custom series
|
# have the name of the field added to the value. For example, if a custom series
|
||||||
# column named 'My Series' contains the name 'Darkover', then the collection
|
# column named 'My Series' contains the name 'Darkover', then the collection
|
||||||
# will be named 'Darkover (My Series)'. If two books have fields that generate
|
# will by default be named 'Darkover (My Series)'. For purposes of this
|
||||||
# the same collection name, then both books will be in that collection. This
|
# documentation, 'Darkover' is called the value and 'My Series' is called the
|
||||||
# tweak lets you specify for a standard or custom field the value to be put
|
# category. If two books have fields that generate the same collection name,
|
||||||
# inside the parentheses. You can use it to add a parenthetical description to a
|
# then both books will be in that collection.
|
||||||
|
# This set of tweaks lets you specify for a standard or custom field how
|
||||||
|
# the collections are to be named. You can use it to add a description to a
|
||||||
# standard field, for example 'Foo (Tag)' instead of the 'Foo'. You can also use
|
# standard field, for example 'Foo (Tag)' instead of the 'Foo'. You can also use
|
||||||
# it to force multiple fields to end up in the same collection. For example, you
|
# it to force multiple fields to end up in the same collection. For example, you
|
||||||
# could force the values in 'series', '#my_series_1', and '#my_series_2' to
|
# could force the values in 'series', '#my_series_1', and '#my_series_2' to
|
||||||
# appear in collections named 'some_value (Series)', thereby merging all of the
|
# appear in collections named 'some_value (Series)', thereby merging all of the
|
||||||
# fields into one set of collections. The syntax of this tweak is
|
# fields into one set of collections.
|
||||||
# {'field_lookup_name':'name_to_use', 'lookup_name':'name', ...}
|
# There are two related tweaks. The first determines the category name to use
|
||||||
# Example 1: I want three series columns to be merged into one set of
|
# for a metadata field. The second is a template, used to determines how the
|
||||||
# collections. If the column lookup names are 'series', '#series_1' and
|
# value and category are combined to create the collection name.
|
||||||
# '#series_2', and if I want nothing in the parenthesis, then the value to use
|
# The syntax of the first tweak, sony_collection_renaming_rules, is:
|
||||||
# in the tweak value would be:
|
# {'field_lookup_name':'category_name_to_use', 'lookup_name':'name', ...}
|
||||||
# sony_collection_renaming_rules={'series':'', '#series_1':'', '#series_2':''}
|
# The second tweak, sony_collection_name_template, is a template. It uses the
|
||||||
# Example 2: I want the word '(Series)' to appear on collections made from
|
# same template language as plugboards and save templates. This tweak controls
|
||||||
# series, and the word '(Tag)' to appear on collections made from tags. Use:
|
# how the value and category are combined together to make the collection name.
|
||||||
# sony_collection_renaming_rules={'series':'Series', 'tags':'Tag'}
|
# The only two fields available are {category} and {value}. The {value} field is
|
||||||
# Example 3: I want 'series' and '#myseries' to be merged, and for the
|
# never empty. The {category} field can be empty. The default is to put the
|
||||||
# collection name to have '(Series)' appended. The renaming rule is:
|
# value first, then the category enclosed in parentheses, it is isn't empty:
|
||||||
# sony_collection_renaming_rules={'series':'Series', '#myseries':'Series'}
|
# '{value} {category:|(|)}'
|
||||||
|
# Examples: The first three examples assume that the second tweak
|
||||||
|
# has not been changed.
|
||||||
|
# 1: I want three series columns to be merged into one set of collections. The
|
||||||
|
# column lookup names are 'series', '#series_1' and '#series_2'. I want nothing
|
||||||
|
# in the parenthesis. The value to use in the tweak value would be:
|
||||||
|
# sony_collection_renaming_rules={'series':'', '#series_1':'', '#series_2':''}
|
||||||
|
# 2: I want the word '(Series)' to appear on collections made from series, and
|
||||||
|
# the word '(Tag)' to appear on collections made from tags. Use:
|
||||||
|
# sony_collection_renaming_rules={'series':'Series', 'tags':'Tag'}
|
||||||
|
# 3: I want 'series' and '#myseries' to be merged, and for the collection name
|
||||||
|
# to have '(Series)' appended. The renaming rule is:
|
||||||
|
# sony_collection_renaming_rules={'series':'Series', '#myseries':'Series'}
|
||||||
|
# 4: Same as example 2, but instead of having the category name in parentheses
|
||||||
|
# and appended to the value, I want it prepended and separated by a colon, such
|
||||||
|
# as in Series: Darkover. I must change the template used to format the category name
|
||||||
|
# The resulting two tweaks are:
|
||||||
|
# sony_collection_renaming_rules={'series':'Series', 'tags':'Tag'}
|
||||||
|
# sony_collection_name_template='{category:||: }{value}'
|
||||||
sony_collection_renaming_rules={}
|
sony_collection_renaming_rules={}
|
||||||
|
sony_collection_name_template='{value}{category:| (|)}'
|
||||||
|
|
||||||
|
|
||||||
# Specify how sony collections are sorted. This tweak is only applicable if
|
# Specify how sony collections are sorted. This tweak is only applicable if
|
||||||
@ -244,8 +265,10 @@ generate_cover_title_font = None
|
|||||||
generate_cover_foot_font = None
|
generate_cover_foot_font = None
|
||||||
|
|
||||||
|
|
||||||
# Behavior of doubleclick on the books list. Choices:
|
# Behavior of doubleclick on the books list. Choices: open_viewer, do_nothing,
|
||||||
# open_viewer, do_nothing, edit_cell. Default: open_viewer.
|
# edit_cell, edit_metadata. Selecting edit_metadata has the side effect of
|
||||||
|
# disabling editing a field using a single click.
|
||||||
|
# Default: open_viewer.
|
||||||
# Example: doubleclick_on_library_view = 'do_nothing'
|
# Example: doubleclick_on_library_view = 'do_nothing'
|
||||||
doubleclick_on_library_view = 'open_viewer'
|
doubleclick_on_library_view = 'open_viewer'
|
||||||
|
|
||||||
@ -265,4 +288,4 @@ locale_for_sorting = ''
|
|||||||
# Set whether to use one or two columns for custom metadata when editing
|
# Set whether to use one or two columns for custom metadata when editing
|
||||||
# metadata one book at a time. If True, then the fields are laid out using two
|
# metadata one book at a time. If True, then the fields are laid out using two
|
||||||
# columns. If False, one column is used.
|
# columns. If False, one column is used.
|
||||||
metadata_single_use_2_cols_for_custom_fields = True
|
metadata_single_use_2_cols_for_custom_fields = True
|
||||||
|
BIN
resources/images/edit-clear.png
Normal file
BIN
resources/images/edit-clear.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
109
resources/recipes/el_periodico.recipe
Normal file
109
resources/recipes/el_periodico.recipe
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '04 December 2010, desUBIKado'
|
||||||
|
__author__ = 'desUBIKado'
|
||||||
|
__description__ = 'Daily newspaper from Aragon'
|
||||||
|
__version__ = 'v0.05'
|
||||||
|
__date__ = '07, December 2010'
|
||||||
|
'''
|
||||||
|
elperiodicodearagon.com
|
||||||
|
'''
|
||||||
|
import re
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
|
||||||
|
class elperiodicodearagon(BasicNewsRecipe):
|
||||||
|
title = u'El Periodico de Aragon'
|
||||||
|
__author__ = u'desUBIKado'
|
||||||
|
description = u'Noticias desde Aragon'
|
||||||
|
publisher = u'elperiodicodearagon.com'
|
||||||
|
category = u'news, politics, Spain, Aragon'
|
||||||
|
oldest_article = 2
|
||||||
|
delay = 0
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = False
|
||||||
|
language = 'es'
|
||||||
|
encoding = 'utf8'
|
||||||
|
remove_empty_feeds = True
|
||||||
|
remove_javascript = True
|
||||||
|
|
||||||
|
|
||||||
|
conversion_options = {
|
||||||
|
'comments' : description
|
||||||
|
,'tags' : category
|
||||||
|
,'language' : language
|
||||||
|
,'publisher' : publisher
|
||||||
|
}
|
||||||
|
|
||||||
|
feeds = [(u'Arag\xf3n', u'http://elperiodicodearagon.com/RSS/2.xml'),
|
||||||
|
(u'Internacional', u'http://elperiodicodearagon.com/RSS/4.xml'),
|
||||||
|
(u'Espa\xf1a', u'http://elperiodicodearagon.com/RSS/3.xml'),
|
||||||
|
(u'Econom\xeda', u'http://elperiodicodearagon.com/RSS/5.xml'),
|
||||||
|
(u'Deportes', u'http://elperiodicodearagon.com/RSS/7.xml'),
|
||||||
|
(u'Real Zaragoza', u'http://elperiodicodearagon.com/RSS/10.xml'),
|
||||||
|
(u'Opini\xf3n', u'http://elperiodicodearagon.com/RSS/103.xml'),
|
||||||
|
(u'Escenarios', u'http://elperiodicodearagon.com/RSS/105.xml'),
|
||||||
|
(u'Sociedad', u'http://elperiodicodearagon.com/RSS/104.xml'),
|
||||||
|
(u'Gente', u'http://elperiodicodearagon.com/RSS/330.xml')]
|
||||||
|
|
||||||
|
|
||||||
|
extra_css = '''
|
||||||
|
h3{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:xx-large;}
|
||||||
|
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
|
||||||
|
dd{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
|
||||||
|
'''
|
||||||
|
|
||||||
|
remove_attributes = ['height','width']
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'id':'contenidos'})]
|
||||||
|
|
||||||
|
|
||||||
|
# Quitar toda la morralla
|
||||||
|
|
||||||
|
remove_tags = [dict(name='ul', attrs={'class':'herramientasDeNoticia'}),
|
||||||
|
dict(name='span', attrs={'class':'MasInformacion '}),
|
||||||
|
dict(name='span', attrs={'class':'MasInformacion'}),
|
||||||
|
dict(name='div', attrs={'class':'Middle'}),
|
||||||
|
dict(name='div', attrs={'class':'MenuCabeceraRZaragoza'}),
|
||||||
|
dict(name='div', attrs={'id':'MenuCabeceraRZaragoza'}),
|
||||||
|
dict(name='div', attrs={'class':'MenuEquipo'}),
|
||||||
|
dict(name='div', attrs={'class':'TemasRelacionados'}),
|
||||||
|
dict(name='div', attrs={'class':'GaleriaEnNoticia'}),
|
||||||
|
dict(name='div', attrs={'class':'Recorte'}),
|
||||||
|
dict(name='div', attrs={'id':'NoticiasenRecursos'}),
|
||||||
|
dict(name='div', attrs={'id':'NoticiaEnPapel'}),
|
||||||
|
dict(name='p', attrs={'class':'RecorteEnNoticias'}),
|
||||||
|
dict(name='div', attrs={'id':'Comparte'}),
|
||||||
|
dict(name='div', attrs={'id':'CajaComparte'}),
|
||||||
|
dict(name='a', attrs={'class':'EscribirComentario'}),
|
||||||
|
dict(name='a', attrs={'class':'AvisoComentario'}),
|
||||||
|
dict(name='div', attrs={'class':'CajaAvisoComentario'}),
|
||||||
|
dict(name='div', attrs={'class':'navegaNoticias'}),
|
||||||
|
dict(name='div', attrs={'id':'PaginadorDiCom'}),
|
||||||
|
dict(name='div', attrs={'id':'CajaAccesoCuentaUsuario'}),
|
||||||
|
dict(name='div', attrs={'id':'CintilloComentario'}),
|
||||||
|
dict(name='div', attrs={'id':'EscribeComentario'}),
|
||||||
|
dict(name='div', attrs={'id':'FormularioComentario'}),
|
||||||
|
dict(name='div', attrs={'id':'FormularioNormas'})]
|
||||||
|
|
||||||
|
# Recuperamos la portada de papel (la imagen format=1 tiene mayor resolucion)
|
||||||
|
|
||||||
|
def get_cover_url(self):
|
||||||
|
index = 'http://pdf.elperiodicodearagon.com/'
|
||||||
|
soup = self.index_to_soup(index)
|
||||||
|
for image in soup.findAll('img',src=True):
|
||||||
|
if image['src'].startswith('http://pdf.elperiodicodearagon.com/funciones/portada-preview.php?eid='):
|
||||||
|
return image['src'].rstrip('format=2') + 'format=1'
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Para quitar espacios entre la noticia y los comentarios (lineas 1 y 2)
|
||||||
|
# El indice no apuntaba correctamente al empiece de la noticia (linea 3)
|
||||||
|
|
||||||
|
preprocess_regexps = [
|
||||||
|
(re.compile(r'<p> </p>', re.DOTALL|re.IGNORECASE), lambda match: ''),
|
||||||
|
(re.compile(r'<p> </p>', re.DOTALL|re.IGNORECASE), lambda match: ''),
|
||||||
|
(re.compile(r'<p id="">', re.DOTALL|re.IGNORECASE), lambda match: '<p>')
|
||||||
|
]
|
@ -1,50 +1,65 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__author__ = 'Lorenzo Vigentini'
|
__copyright__ = '04 December 2010, desUBIKado'
|
||||||
__copyright__ = '2009, Lorenzo Vigentini <l.vigentini at gmail.com>'
|
__author__ = 'desUBIKado'
|
||||||
__description__ = 'Daily newspaper from Aragon'
|
__description__ = 'Daily newspaper from Aragon'
|
||||||
__version__ = 'v1.01'
|
__version__ = 'v0.03'
|
||||||
__date__ = '30, January 2010'
|
__date__ = '11, December 2010'
|
||||||
|
|
||||||
'''
|
'''
|
||||||
http://www.heraldo.es/
|
[url]http://www.heraldo.es/[/url]
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
import time
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class heraldo(BasicNewsRecipe):
|
class heraldo(BasicNewsRecipe):
|
||||||
author = 'Lorenzo Vigentini'
|
__author__ = 'desUBIKado'
|
||||||
description = 'Daily newspaper from Aragon'
|
description = 'Daily newspaper from Aragon'
|
||||||
|
|
||||||
cover_url = 'http://www.heraldo.es/MODULOS/global/publico/interfaces/img/logo.gif'
|
|
||||||
title = u'Heraldo de Aragon'
|
title = u'Heraldo de Aragon'
|
||||||
publisher = 'OJD Nielsen'
|
publisher = 'OJD Nielsen'
|
||||||
category = 'News, politics, culture, economy, general interest'
|
category = 'News, politics, culture, economy, general interest'
|
||||||
|
|
||||||
language = 'es'
|
language = 'es'
|
||||||
timefmt = '[%a, %d %b, %Y]'
|
timefmt = '[%a, %d %b, %Y]'
|
||||||
|
|
||||||
oldest_article = 1
|
oldest_article = 1
|
||||||
max_articles_per_feed = 25
|
max_articles_per_feed = 100
|
||||||
|
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
recursion = 10
|
|
||||||
|
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
|
recursion = 10
|
||||||
keep_only_tags = [
|
|
||||||
dict(name='div', attrs={'class':['titularNoticiaNN','textoGrisVerdanaContenidos']})
|
|
||||||
]
|
|
||||||
|
|
||||||
feeds = [
|
feeds = [
|
||||||
(u'Portadas ', u'http://www.heraldo.es/index.php/mod.portadas/mem.rss')
|
(u'Portadas', u'http://www.heraldo.es/index.php/mod.portadas/mem.rss')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'id':['dts','com']})]
|
||||||
|
|
||||||
|
remove_tags = [dict(name='a', attrs={'class':['com flo-r','enl-if','enl-df']}),
|
||||||
|
dict(name='div', attrs={'class':['brb-b-s con marg-btt','cnt-rel con']}),
|
||||||
|
dict(name='form', attrs={'class':'form'})]
|
||||||
|
|
||||||
|
remove_tags_before = dict(name='div' , attrs={'id':'dts'})
|
||||||
|
remove_tags_after = dict(name='div' , attrs={'id':'com'})
|
||||||
|
|
||||||
|
def get_cover_url(self):
|
||||||
|
cover = None
|
||||||
|
st = time.localtime()
|
||||||
|
year = str(st.tm_year)
|
||||||
|
month = "%.2d" % st.tm_mon
|
||||||
|
day = "%.2d" % st.tm_mday
|
||||||
|
#[url]http://oldorigin-www.heraldo.es/20101211/primeras/portada_aragon.pdf[/url]
|
||||||
|
cover='http://oldorigin-www.heraldo.es/'+ year + month + day +'/primeras/portada_aragon.pdf'
|
||||||
|
br = BasicNewsRecipe.get_browser()
|
||||||
|
try:
|
||||||
|
br.open(cover)
|
||||||
|
except:
|
||||||
|
self.log("\nPortada no disponible")
|
||||||
|
cover ='http://www.heraldo.es/MODULOS/global/publico/interfaces/img/logo-Heraldo.png'
|
||||||
|
return cover
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extra_css = '''
|
extra_css = '''
|
||||||
.articledate {color: gray;font-family: monospace;}
|
h2{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:xx-large;}
|
||||||
.articledescription {display: block;font-family: sans;font-size: 0.7em; text-indent: 0;}
|
'''
|
||||||
.firma {color: #666;display: block;font-family: verdana, arial, helvetica;font-size: 1em;margin-bottom: 8px;}
|
|
||||||
.textoGrisVerdanaContenidos {color: #56595c;display: block;font-family: Verdana;font-size: 1.28571em;padding-bottom: 10px}
|
|
||||||
.titularNoticiaNN {display: block;padding-bottom: 10px;padding-left: 0;padding-right: 0;padding-top: 4px}
|
|
||||||
.titulo {color: #003066;font-family: Tahoma;font-size: 1.92857em;font-weight: bold;line-height: 1.2em}
|
|
||||||
'''
|
|
||||||
|
47
resources/recipes/red_aragon.recipe
Normal file
47
resources/recipes/red_aragon.recipe
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '11 December 2010, desUBIKado'
|
||||||
|
__author__ = 'desUBIKado'
|
||||||
|
__description__ = 'Entertainment guide from Aragon'
|
||||||
|
__version__ = 'v0.01'
|
||||||
|
__date__ = '11, December 2010'
|
||||||
|
'''
|
||||||
|
[url]http://www.redaragon.es/[/url]
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class heraldo(BasicNewsRecipe):
|
||||||
|
__author__ = 'desUBIKado'
|
||||||
|
description = u'Guia de ocio desde Aragon'
|
||||||
|
title = u'RedAragon'
|
||||||
|
publisher = 'Grupo Z'
|
||||||
|
category = 'Concerts, Movies, Entertainment news'
|
||||||
|
cover_url = 'http://www.redaragon.com/2008_img/logotipo.gif'
|
||||||
|
language = 'es'
|
||||||
|
timefmt = '[%a, %d %b, %Y]'
|
||||||
|
oldest_article = 15
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
encoding = 'iso-8859-1'
|
||||||
|
use_embedded_content = False
|
||||||
|
remove_javascript = True
|
||||||
|
no_stylesheets = True
|
||||||
|
|
||||||
|
feeds = [(u'Conciertos', u'http://redaragon.com/rss/agenda.asp?tid=1'),
|
||||||
|
(u'Exposiciones', u'http://redaragon.com/rss/agenda.asp?tid=5'),
|
||||||
|
(u'Teatro', u'http://redaragon.com/rss/agenda.asp?tid=10'),
|
||||||
|
(u'Conferencias', u'http://redaragon.com/rss/agenda.asp?tid=2'),
|
||||||
|
(u'Ferias', u'http://redaragon.com/rss/agenda.asp?tid=6'),
|
||||||
|
(u'Filmotecas/Cineclubs', u'http://redaragon.com/rss/agenda.asp?tid=7'),
|
||||||
|
(u'Presentaciones', u'http://redaragon.com/rss/agenda.asp?tid=9'),
|
||||||
|
(u'Fiestas', u'http://redaragon.com/rss/agenda.asp?tid=11'),
|
||||||
|
(u'Infantil', u'http://redaragon.com/rss/agenda.asp?tid=13'),
|
||||||
|
(u'Otros', u'http://redaragon.com/rss/agenda.asp?tid=8')]
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'id':'FichaEventoAgenda'})]
|
||||||
|
|
||||||
|
remove_tags = [dict(name='div', attrs={'class':['Comparte','CajaAgenda','Caja','Cintillo']})]
|
||||||
|
|
||||||
|
remove_tags_before = dict(name='div' , attrs={'id':'FichaEventoAgenda'})
|
||||||
|
|
||||||
|
remove_tags_after = dict(name='div' , attrs={'class':'Cintillo'})
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
__appname__ = 'calibre'
|
__appname__ = 'calibre'
|
||||||
__version__ = '0.7.34'
|
__version__ = '0.7.35'
|
||||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
@ -477,7 +477,8 @@ from calibre.devices.teclast.driver import TECLAST_K3, NEWSMY, IPAPYRUS, \
|
|||||||
SOVOS, PICO, SUNSTECH_EB700
|
SOVOS, PICO, SUNSTECH_EB700
|
||||||
from calibre.devices.sne.driver import SNE
|
from calibre.devices.sne.driver import SNE
|
||||||
from calibre.devices.misc import PALMPRE, AVANT, SWEEX, PDNOVEL, KOGAN, \
|
from calibre.devices.misc import PALMPRE, AVANT, SWEEX, PDNOVEL, KOGAN, \
|
||||||
GEMEI, VELOCITYMICRO, PDNOVEL_KOBO, Q600, LUMIREAD, ALURATEK_COLOR
|
GEMEI, VELOCITYMICRO, PDNOVEL_KOBO, Q600, LUMIREAD, ALURATEK_COLOR, \
|
||||||
|
TREKSTOR, EEEREADER
|
||||||
from calibre.devices.folder_device.driver import FOLDER_DEVICE_FOR_CONFIG
|
from calibre.devices.folder_device.driver import FOLDER_DEVICE_FOR_CONFIG
|
||||||
from calibre.devices.kobo.driver import KOBO
|
from calibre.devices.kobo.driver import KOBO
|
||||||
from calibre.devices.bambook.driver import BAMBOOK
|
from calibre.devices.bambook.driver import BAMBOOK
|
||||||
@ -603,6 +604,8 @@ plugins += [
|
|||||||
LUMIREAD,
|
LUMIREAD,
|
||||||
ALURATEK_COLOR,
|
ALURATEK_COLOR,
|
||||||
BAMBOOK,
|
BAMBOOK,
|
||||||
|
TREKSTOR,
|
||||||
|
EEEREADER,
|
||||||
ITUNES,
|
ITUNES,
|
||||||
]
|
]
|
||||||
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
||||||
|
@ -224,3 +224,43 @@ class ALURATEK_COLOR(USBMS):
|
|||||||
VENDOR_NAME = 'USB_2.0'
|
VENDOR_NAME = 'USB_2.0'
|
||||||
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = 'USB_FLASH_DRIVER'
|
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = 'USB_FLASH_DRIVER'
|
||||||
|
|
||||||
|
class TREKSTOR(USBMS):
|
||||||
|
|
||||||
|
name = 'Trekstor E-book player device interface'
|
||||||
|
gui_name = 'Trekstor'
|
||||||
|
description = _('Communicate with the Trekstor')
|
||||||
|
author = 'Kovid Goyal'
|
||||||
|
supported_platforms = ['windows', 'osx', 'linux']
|
||||||
|
|
||||||
|
# Ordered list of supported formats
|
||||||
|
FORMATS = ['epub', 'txt', 'pdf']
|
||||||
|
|
||||||
|
VENDOR_ID = [0x1e68]
|
||||||
|
PRODUCT_ID = [0x0041]
|
||||||
|
BCD = [0x0002]
|
||||||
|
|
||||||
|
EBOOK_DIR_MAIN = 'Ebooks'
|
||||||
|
|
||||||
|
VENDOR_NAME = 'TREKSTOR'
|
||||||
|
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = 'EBOOK_PLAYER_7'
|
||||||
|
|
||||||
|
class EEEREADER(USBMS):
|
||||||
|
|
||||||
|
name = 'Asus EEE Reader device interface'
|
||||||
|
gui_name = 'EEE Reader'
|
||||||
|
description = _('Communicate with the EEE Reader')
|
||||||
|
author = 'Kovid Goyal'
|
||||||
|
supported_platforms = ['windows', 'osx', 'linux']
|
||||||
|
|
||||||
|
# Ordered list of supported formats
|
||||||
|
FORMATS = ['epub', 'fb2', 'txt', 'pdf']
|
||||||
|
|
||||||
|
VENDOR_ID = [0x0b05]
|
||||||
|
PRODUCT_ID = [0x178f]
|
||||||
|
BCD = [0x0319]
|
||||||
|
|
||||||
|
EBOOK_DIR_MAIN = 'Books'
|
||||||
|
|
||||||
|
VENDOR_NAME = 'LINUX'
|
||||||
|
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = 'FILE-STOR_GADGET'
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ from calibre.constants import preferred_encoding
|
|||||||
from calibre import isbytestring, force_unicode
|
from calibre import isbytestring, force_unicode
|
||||||
from calibre.utils.config import prefs, tweaks
|
from calibre.utils.config import prefs, tweaks
|
||||||
from calibre.utils.icu import strcmp
|
from calibre.utils.icu import strcmp
|
||||||
|
from calibre.utils.formatter import eval_formatter
|
||||||
|
|
||||||
class Book(Metadata):
|
class Book(Metadata):
|
||||||
def __init__(self, prefix, lpath, size=None, other=None):
|
def __init__(self, prefix, lpath, size=None, other=None):
|
||||||
@ -107,23 +108,25 @@ class CollectionsBookList(BookList):
|
|||||||
return sortattr
|
return sortattr
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def compute_category_name(self, attr, category, field_meta):
|
def compute_category_name(self, field_key, field_value, field_meta):
|
||||||
renames = tweaks['sony_collection_renaming_rules']
|
renames = tweaks['sony_collection_renaming_rules']
|
||||||
attr_name = renames.get(attr, None)
|
field_name = renames.get(field_key, None)
|
||||||
if attr_name is None:
|
if field_name is None:
|
||||||
if field_meta['is_custom']:
|
if field_meta['is_custom']:
|
||||||
attr_name = '(%s)'%field_meta['name']
|
field_name = field_meta['name']
|
||||||
else:
|
else:
|
||||||
attr_name = ''
|
field_name = ''
|
||||||
elif attr_name != '':
|
cat_name = eval_formatter.safe_format(
|
||||||
attr_name = '(%s)'%attr_name
|
fmt=tweaks['sony_collection_name_template'],
|
||||||
cat_name = '%s %s'%(category, attr_name)
|
kwargs={'category':field_name, 'value':field_value},
|
||||||
|
error_value='GET_CATEGORY', book=None)
|
||||||
return cat_name.strip()
|
return cat_name.strip()
|
||||||
|
|
||||||
def get_collections(self, collection_attributes):
|
def get_collections(self, collection_attributes):
|
||||||
from calibre.devices.usbms.driver import debug_print
|
from calibre.devices.usbms.driver import debug_print
|
||||||
debug_print('Starting get_collections:', prefs['manage_device_metadata'])
|
debug_print('Starting get_collections:', prefs['manage_device_metadata'])
|
||||||
debug_print('Renaming rules:', tweaks['sony_collection_renaming_rules'])
|
debug_print('Renaming rules:', tweaks['sony_collection_renaming_rules'])
|
||||||
|
debug_print('Formatting template:', tweaks['sony_collection_name_template'])
|
||||||
debug_print('Sorting rules:', tweaks['sony_collection_sorting_rules'])
|
debug_print('Sorting rules:', tweaks['sony_collection_sorting_rules'])
|
||||||
|
|
||||||
# Complexity: we can use renaming rules only when using automatic
|
# Complexity: we can use renaming rules only when using automatic
|
||||||
|
@ -468,8 +468,9 @@ class MobiMLizer(object):
|
|||||||
vtag.append(child)
|
vtag.append(child)
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
for child in vbstate.para:
|
if vbstate.para is not None:
|
||||||
vtag.append(child)
|
for child in vbstate.para:
|
||||||
|
vtag.append(child)
|
||||||
return
|
return
|
||||||
|
|
||||||
if text or tag in CONTENT_TAGS or tag in NESTABLE_TAGS:
|
if text or tag in CONTENT_TAGS or tag in NESTABLE_TAGS:
|
||||||
|
56
src/calibre/ebooks/oeb/transforms/margins.py
Normal file
56
src/calibre/ebooks/oeb/transforms/margins.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveFakeMargins(object):
|
||||||
|
'''
|
||||||
|
Try to detect and remove fake margins inserted by asinine ebook creation
|
||||||
|
software on each paragraph/wrapper div. Can be used only after CSS
|
||||||
|
flattening.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __call__(self, oeb, opts, log):
|
||||||
|
self.oeb, self.opts, self.log = oeb, opts, log
|
||||||
|
|
||||||
|
from calibre.ebooks.oeb.base import XPath, OEB_STYLES
|
||||||
|
|
||||||
|
stylesheet = None
|
||||||
|
for item in self.oeb.manifest:
|
||||||
|
if item.media_type.lower() in OEB_STYLES:
|
||||||
|
stylesheet = item.data
|
||||||
|
break
|
||||||
|
|
||||||
|
if stylesheet is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
top_level_elements = {}
|
||||||
|
second_level_elements = {}
|
||||||
|
|
||||||
|
for x in self.oeb.spine:
|
||||||
|
root = x.data
|
||||||
|
body = XPath('//h:body')(root)
|
||||||
|
if body:
|
||||||
|
body = body[0]
|
||||||
|
|
||||||
|
if not hasattr(body, 'xpath'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check for margins on top level elements
|
||||||
|
for lb in XPath('./h:div|./h:p|./*/h:div|./*/h:p')(body):
|
||||||
|
cls = lb.get('class', '')
|
||||||
|
level = top_level_elements if lb.getparent() is body else \
|
||||||
|
second_level_elements
|
||||||
|
if cls not in level:
|
||||||
|
level[cls] = []
|
||||||
|
top_level_elements[cls] = []
|
||||||
|
level[cls].append(lb)
|
||||||
|
|
||||||
|
|
||||||
|
def get_margins(self, stylesheet, cls):
|
||||||
|
pass
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
* License: GNU GPL v3
|
* License: GNU GPL v2+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
* License: GNU GPL v3
|
* License: GNU GPL v2+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
|
* License: GNU GPL v2+
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
|
* License: GNU GPL v2+
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
* License: GNU GPL v3
|
* License: GNU GPL v2+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
* License: GNU GPL v3
|
* License: GNU GPL v2+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
|
* License: GNU GPL v2+
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef PDF2XML
|
#ifndef PDF2XML
|
||||||
#define UNICODE
|
#define UNICODE
|
||||||
#define PY_SSIZE_T_CLEAN
|
#define PY_SSIZE_T_CLEAN
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
* License: GNU GPL v3
|
* License: GNU GPL v2+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Outline.h>
|
#include <Outline.h>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
* License: GNU GPL v3
|
* License: GNU GPL v2+
|
||||||
* Based on pdftohtml from the poppler project.
|
* Based on pdftohtml from the poppler project.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
* Copyright 2009 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
* License: GNU GPL v3
|
* License: GNU GPL v2+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +44,10 @@ def render_rows(data):
|
|||||||
key = key.decode(preferred_encoding, 'replace')
|
key = key.decode(preferred_encoding, 'replace')
|
||||||
if isinstance(txt, str):
|
if isinstance(txt, str):
|
||||||
txt = txt.decode(preferred_encoding, 'replace')
|
txt = txt.decode(preferred_encoding, 'replace')
|
||||||
if '</font>' not in txt:
|
if key.endswith(u':html'):
|
||||||
|
key = key[:-5]
|
||||||
|
txt = comments_to_html(txt)
|
||||||
|
elif '</font>' not in txt:
|
||||||
txt = prepare_string_for_xml(txt)
|
txt = prepare_string_for_xml(txt)
|
||||||
if 'id' in data:
|
if 'id' in data:
|
||||||
if key == _('Path'):
|
if key == _('Path'):
|
||||||
@ -249,7 +252,7 @@ class BookInfo(QWebView):
|
|||||||
left_pane = u'<table>%s</table>'%rows
|
left_pane = u'<table>%s</table>'%rows
|
||||||
right_pane = u'<div>%s</div>'%comments
|
right_pane = u'<div>%s</div>'%comments
|
||||||
self.setHtml(templ%(u'<table><tr><td valign="top" '
|
self.setHtml(templ%(u'<table><tr><td valign="top" '
|
||||||
'style="padding-right:2em">%s</td><td valign="top">%s</td></tr></table>'
|
'style="padding-right:2em; width:40%%">%s</td><td valign="top">%s</td></tr></table>'
|
||||||
% (left_pane, right_pane)))
|
% (left_pane, right_pane)))
|
||||||
|
|
||||||
def mouseDoubleClickEvent(self, ev):
|
def mouseDoubleClickEvent(self, ev):
|
||||||
|
@ -62,6 +62,8 @@ class EditorWidget(QWebView): # {{{
|
|||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QWebView.__init__(self, parent)
|
QWebView.__init__(self, parent)
|
||||||
|
|
||||||
|
self.comments_pat = re.compile(r'<!--.*?-->', re.DOTALL)
|
||||||
|
|
||||||
for wac, name, icon, text, checkable in [
|
for wac, name, icon, text, checkable in [
|
||||||
('ToggleBold', 'bold', 'format-text-bold', _('Bold'), True),
|
('ToggleBold', 'bold', 'format-text-bold', _('Bold'), True),
|
||||||
('ToggleItalic', 'italic', 'format-text-italic', _('Italic'),
|
('ToggleItalic', 'italic', 'format-text-italic', _('Italic'),
|
||||||
@ -137,10 +139,19 @@ class EditorWidget(QWebView): # {{{
|
|||||||
self.action_insert_link = QAction(QIcon(I('insert-link.png')),
|
self.action_insert_link = QAction(QIcon(I('insert-link.png')),
|
||||||
_('Insert link'), self)
|
_('Insert link'), self)
|
||||||
self.action_insert_link.triggered.connect(self.insert_link)
|
self.action_insert_link.triggered.connect(self.insert_link)
|
||||||
|
self.action_clear = QAction(QIcon(I('edit-clear')), _('Clear'), self)
|
||||||
|
self.action_clear.triggered.connect(self.clear_text)
|
||||||
|
|
||||||
self.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
|
self.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
|
||||||
self.page().linkClicked.connect(self.link_clicked)
|
self.page().linkClicked.connect(self.link_clicked)
|
||||||
|
|
||||||
|
self.setHtml('')
|
||||||
|
self.page().setContentEditable(True)
|
||||||
|
|
||||||
|
def clear_text(self, *args):
|
||||||
|
self.action_select_all.trigger()
|
||||||
|
self.action_cut.trigger()
|
||||||
|
|
||||||
def link_clicked(self, url):
|
def link_clicked(self, url):
|
||||||
open_url(url)
|
open_url(url)
|
||||||
|
|
||||||
@ -210,6 +221,7 @@ class EditorWidget(QWebView): # {{{
|
|||||||
raw = unicode(self.page().mainFrame().toHtml())
|
raw = unicode(self.page().mainFrame().toHtml())
|
||||||
raw = xml_to_unicode(raw, strip_encoding_pats=True,
|
raw = xml_to_unicode(raw, strip_encoding_pats=True,
|
||||||
resolve_entities=True)[0]
|
resolve_entities=True)[0]
|
||||||
|
raw = self.comments_pat.sub('', raw)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
root = html.fromstring(raw)
|
root = html.fromstring(raw)
|
||||||
@ -218,12 +230,17 @@ class EditorWidget(QWebView): # {{{
|
|||||||
|
|
||||||
elems = []
|
elems = []
|
||||||
for body in root.xpath('//body'):
|
for body in root.xpath('//body'):
|
||||||
|
if body.text:
|
||||||
|
elems.append(body.text)
|
||||||
elems += [html.tostring(x, encoding=unicode) for x in body if
|
elems += [html.tostring(x, encoding=unicode) for x in body if
|
||||||
x.tag != 'script']
|
x.tag not in ('script', 'style')]
|
||||||
|
|
||||||
if len(elems) > 1:
|
if len(elems) > 1:
|
||||||
ans = u'<div>%s</div>'%(u''.join(elems))
|
ans = u'<div>%s</div>'%(u''.join(elems))
|
||||||
else:
|
else:
|
||||||
ans = u''.join(elems)
|
ans = u''.join(elems)
|
||||||
|
if not ans.startswith('<'):
|
||||||
|
ans = '<p>%s</p>'%ans
|
||||||
ans = xml_replace_entities(ans)
|
ans = xml_replace_entities(ans)
|
||||||
except:
|
except:
|
||||||
import traceback
|
import traceback
|
||||||
@ -462,6 +479,7 @@ class Editor(QWidget): # {{{
|
|||||||
QWidget.__init__(self, parent)
|
QWidget.__init__(self, parent)
|
||||||
self.toolbar1 = QToolBar(self)
|
self.toolbar1 = QToolBar(self)
|
||||||
self.toolbar2 = QToolBar(self)
|
self.toolbar2 = QToolBar(self)
|
||||||
|
self.toolbar3 = QToolBar(self)
|
||||||
self.editor = EditorWidget(self)
|
self.editor = EditorWidget(self)
|
||||||
self.tabs = QTabWidget(self)
|
self.tabs = QTabWidget(self)
|
||||||
self.tabs.setTabPosition(self.tabs.South)
|
self.tabs.setTabPosition(self.tabs.South)
|
||||||
@ -476,6 +494,7 @@ class Editor(QWidget): # {{{
|
|||||||
l.setContentsMargins(0, 0, 0, 0)
|
l.setContentsMargins(0, 0, 0, 0)
|
||||||
l.addWidget(self.toolbar1)
|
l.addWidget(self.toolbar1)
|
||||||
l.addWidget(self.toolbar2)
|
l.addWidget(self.toolbar2)
|
||||||
|
l.addWidget(self.toolbar3)
|
||||||
l.addWidget(self.editor)
|
l.addWidget(self.editor)
|
||||||
self._layout.addWidget(self.tabs)
|
self._layout.addWidget(self.tabs)
|
||||||
self.tabs.addTab(self.wyswyg, _('Normal view'))
|
self.tabs.addTab(self.wyswyg, _('Normal view'))
|
||||||
@ -483,43 +502,50 @@ class Editor(QWidget): # {{{
|
|||||||
self.tabs.currentChanged[int].connect(self.change_tab)
|
self.tabs.currentChanged[int].connect(self.change_tab)
|
||||||
self.highlighter = Highlighter(self.code_edit.document())
|
self.highlighter = Highlighter(self.code_edit.document())
|
||||||
|
|
||||||
for x in ('bold', 'italic', 'underline', 'strikethrough',
|
# toolbar1 {{{
|
||||||
'superscript', 'subscript', 'indent', 'outdent'):
|
|
||||||
ac = getattr(self.editor, 'action_'+x)
|
|
||||||
if x in ('superscript', 'indent'):
|
|
||||||
self.toolbar2.addSeparator()
|
|
||||||
self.toolbar2.addAction(ac)
|
|
||||||
self.toolbar2.addSeparator()
|
|
||||||
|
|
||||||
for x in ('left', 'center', 'right', 'justified'):
|
|
||||||
ac = getattr(self.editor, 'action_align_'+x)
|
|
||||||
self.toolbar2.addAction(ac)
|
|
||||||
self.toolbar2.addSeparator()
|
|
||||||
|
|
||||||
self.toolbar1.addAction(self.editor.action_undo)
|
self.toolbar1.addAction(self.editor.action_undo)
|
||||||
self.toolbar1.addAction(self.editor.action_redo)
|
self.toolbar1.addAction(self.editor.action_redo)
|
||||||
self.toolbar1.addAction(self.editor.action_select_all)
|
self.toolbar1.addAction(self.editor.action_select_all)
|
||||||
self.toolbar1.addAction(self.editor.action_remove_format)
|
self.toolbar1.addAction(self.editor.action_remove_format)
|
||||||
|
self.toolbar1.addAction(self.editor.action_clear)
|
||||||
self.toolbar1.addSeparator()
|
self.toolbar1.addSeparator()
|
||||||
|
|
||||||
for x in ('copy', 'cut', 'paste'):
|
for x in ('copy', 'cut', 'paste'):
|
||||||
ac = getattr(self.editor, 'action_'+x)
|
ac = getattr(self.editor, 'action_'+x)
|
||||||
self.toolbar1.addAction(ac)
|
self.toolbar1.addAction(ac)
|
||||||
self.toolbar1.addSeparator()
|
|
||||||
|
|
||||||
|
self.toolbar1.addSeparator()
|
||||||
|
self.toolbar1.addAction(self.editor.action_background)
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# toolbar2 {{{
|
||||||
for x in ('', 'un'):
|
for x in ('', 'un'):
|
||||||
ac = getattr(self.editor, 'action_%sordered_list'%x)
|
ac = getattr(self.editor, 'action_%sordered_list'%x)
|
||||||
self.toolbar1.addAction(ac)
|
self.toolbar2.addAction(ac)
|
||||||
self.toolbar1.addSeparator()
|
self.toolbar2.addSeparator()
|
||||||
|
for x in ('superscript', 'subscript', 'indent', 'outdent'):
|
||||||
|
self.toolbar2.addAction(getattr(self.editor, 'action_' + x))
|
||||||
|
if x in ('subscript', 'outdent'):
|
||||||
|
self.toolbar2.addSeparator()
|
||||||
|
|
||||||
self.toolbar1.addAction(self.editor.action_color)
|
self.toolbar2.addAction(self.editor.action_block_style)
|
||||||
self.toolbar1.addAction(self.editor.action_background)
|
w = self.toolbar2.widgetForAction(self.editor.action_block_style)
|
||||||
self.toolbar1.addSeparator()
|
|
||||||
|
|
||||||
self.toolbar1.addAction(self.editor.action_block_style)
|
|
||||||
w = self.toolbar1.widgetForAction(self.editor.action_block_style)
|
|
||||||
w.setPopupMode(w.InstantPopup)
|
w.setPopupMode(w.InstantPopup)
|
||||||
self.toolbar1.addAction(self.editor.action_insert_link)
|
self.toolbar2.addAction(self.editor.action_insert_link)
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# toolbar3 {{{
|
||||||
|
for x in ('bold', 'italic', 'underline', 'strikethrough'):
|
||||||
|
ac = getattr(self.editor, 'action_'+x)
|
||||||
|
self.toolbar3.addAction(ac)
|
||||||
|
self.toolbar3.addSeparator()
|
||||||
|
|
||||||
|
for x in ('left', 'center', 'right', 'justified'):
|
||||||
|
ac = getattr(self.editor, 'action_align_'+x)
|
||||||
|
self.toolbar3.addAction(ac)
|
||||||
|
self.toolbar3.addSeparator()
|
||||||
|
self.toolbar3.addAction(self.editor.action_color)
|
||||||
|
# }}}
|
||||||
|
|
||||||
self.code_edit.textChanged.connect(self.code_dirtied)
|
self.code_edit.textChanged.connect(self.code_dirtied)
|
||||||
self.editor.page().contentsChanged.connect(self.wyswyg_dirtied)
|
self.editor.page().contentsChanged.connect(self.wyswyg_dirtied)
|
||||||
|
@ -9,15 +9,17 @@ import sys
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \
|
from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \
|
||||||
QDate, QGroupBox, QVBoxLayout, QPlainTextEdit, QSizePolicy, \
|
QDate, QGroupBox, QVBoxLayout, QSizePolicy, \
|
||||||
QSpacerItem, QIcon, QCheckBox, QWidget, QHBoxLayout, SIGNAL, \
|
QSpacerItem, QIcon, QCheckBox, QWidget, QHBoxLayout, SIGNAL, \
|
||||||
QPushButton
|
QPushButton
|
||||||
|
|
||||||
from calibre.utils.date import qt_to_dt, now
|
from calibre.utils.date import qt_to_dt, now
|
||||||
from calibre.gui2.widgets import TagsLineEdit, EnComboBox
|
from calibre.gui2.widgets import TagsLineEdit, EnComboBox
|
||||||
|
from calibre.gui2.comments_editor import Editor as CommentsEditor
|
||||||
from calibre.gui2 import UNDEFINED_QDATE, error_dialog
|
from calibre.gui2 import UNDEFINED_QDATE, error_dialog
|
||||||
from calibre.utils.config import tweaks
|
from calibre.utils.config import tweaks
|
||||||
from calibre.utils.icu import sort_key
|
from calibre.utils.icu import sort_key
|
||||||
|
from calibre.library.comments import comments_to_html
|
||||||
|
|
||||||
class Base(object):
|
class Base(object):
|
||||||
|
|
||||||
@ -186,9 +188,9 @@ class Comments(Base):
|
|||||||
self._box = QGroupBox(parent)
|
self._box = QGroupBox(parent)
|
||||||
self._box.setTitle('&'+self.col_metadata['name'])
|
self._box.setTitle('&'+self.col_metadata['name'])
|
||||||
self._layout = QVBoxLayout()
|
self._layout = QVBoxLayout()
|
||||||
self._tb = QPlainTextEdit(self._box)
|
self._tb = CommentsEditor(self._box)
|
||||||
self._tb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
self._tb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||||
self._tb.setTabChangesFocus(True)
|
#self._tb.setTabChangesFocus(True)
|
||||||
self._layout.addWidget(self._tb)
|
self._layout.addWidget(self._tb)
|
||||||
self._box.setLayout(self._layout)
|
self._box.setLayout(self._layout)
|
||||||
self.widgets = [self._box]
|
self.widgets = [self._box]
|
||||||
@ -196,10 +198,10 @@ class Comments(Base):
|
|||||||
def setter(self, val):
|
def setter(self, val):
|
||||||
if val is None:
|
if val is None:
|
||||||
val = ''
|
val = ''
|
||||||
self._tb.setPlainText(val)
|
self._tb.html = comments_to_html(val)
|
||||||
|
|
||||||
def getter(self):
|
def getter(self):
|
||||||
val = unicode(self._tb.toPlainText()).strip()
|
val = unicode(self._tb.html).strip()
|
||||||
if not val:
|
if not val:
|
||||||
val = None
|
val = None
|
||||||
return val
|
return val
|
||||||
|
@ -12,6 +12,7 @@ from calibre.gui2.dialogs.book_info_ui import Ui_BookInfo
|
|||||||
from calibre.gui2 import dynamic, open_local_file
|
from calibre.gui2 import dynamic, open_local_file
|
||||||
from calibre import fit_image
|
from calibre import fit_image
|
||||||
from calibre.library.comments import comments_to_html
|
from calibre.library.comments import comments_to_html
|
||||||
|
from calibre.utils.icu import sort_key
|
||||||
|
|
||||||
class BookInfo(QDialog, Ui_BookInfo):
|
class BookInfo(QDialog, Ui_BookInfo):
|
||||||
|
|
||||||
@ -130,9 +131,12 @@ class BookInfo(QDialog, Ui_BookInfo):
|
|||||||
for f in formats:
|
for f in formats:
|
||||||
f = f.strip()
|
f = f.strip()
|
||||||
info[_('Formats')] += '<a href="%s">%s</a>, '%(f,f)
|
info[_('Formats')] += '<a href="%s">%s</a>, '%(f,f)
|
||||||
for key in info.keys():
|
for key in sorted(info.keys(), key=sort_key):
|
||||||
if key == 'id': continue
|
if key == 'id': continue
|
||||||
txt = info[key]
|
txt = info[key]
|
||||||
|
if key.endswith(':html'):
|
||||||
|
key = key[:-5]
|
||||||
|
txt = comments_to_html(txt)
|
||||||
if key != _('Path'):
|
if key != _('Path'):
|
||||||
txt = u'<br />\n'.join(textwrap.wrap(txt, 120))
|
txt = u'<br />\n'.join(textwrap.wrap(txt, 120))
|
||||||
rows += u'<tr><td><b>%s:</b></td><td>%s</td></tr>'%(key, txt)
|
rows += u'<tr><td><b>%s:</b></td><td>%s</td></tr>'%(key, txt)
|
||||||
|
@ -5,6 +5,7 @@ __license__ = 'GPL v3'
|
|||||||
|
|
||||||
from PyQt4.Qt import Qt, QDialog, QDialogButtonBox
|
from PyQt4.Qt import Qt, QDialog, QDialogButtonBox
|
||||||
from calibre.gui2.dialogs.comments_dialog_ui import Ui_CommentsDialog
|
from calibre.gui2.dialogs.comments_dialog_ui import Ui_CommentsDialog
|
||||||
|
from calibre.library.comments import comments_to_html
|
||||||
|
|
||||||
class CommentsDialog(QDialog, Ui_CommentsDialog):
|
class CommentsDialog(QDialog, Ui_CommentsDialog):
|
||||||
|
|
||||||
@ -18,8 +19,8 @@ class CommentsDialog(QDialog, Ui_CommentsDialog):
|
|||||||
self.setWindowIcon(icon)
|
self.setWindowIcon(icon)
|
||||||
|
|
||||||
if text is not None:
|
if text is not None:
|
||||||
self.textbox.setPlainText(text)
|
self.textbox.html = comments_to_html(text)
|
||||||
self.textbox.setTabChangesFocus(True)
|
# self.textbox.setTabChangesFocus(True)
|
||||||
self.buttonBox.button(QDialogButtonBox.Ok).setText(_('&OK'))
|
self.buttonBox.button(QDialogButtonBox.Ok).setText(_('&OK'))
|
||||||
self.buttonBox.button(QDialogButtonBox.Cancel).setText(_('&Cancel'))
|
self.buttonBox.button(QDialogButtonBox.Cancel).setText(_('&Cancel'))
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>336</width>
|
<width>400</width>
|
||||||
<height>235</height>
|
<height>400</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -19,22 +19,29 @@
|
|||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Edit Comments</string>
|
<string>Edit Comments</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPlainTextEdit" name="textbox"/>
|
<widget class="Editor" name="textbox" native="true"/>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="standardButtons">
|
<property name="standardButtons">
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>Editor</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>calibre/gui2/comments_editor.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
|
@ -414,6 +414,11 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
self.s_r_template.completer().setCaseSensitivity(Qt.CaseSensitive)
|
self.s_r_template.completer().setCaseSensitivity(Qt.CaseSensitive)
|
||||||
|
|
||||||
self.s_r_search_mode_changed(self.search_mode.currentIndex())
|
self.s_r_search_mode_changed(self.search_mode.currentIndex())
|
||||||
|
self.multiple_separator.setFixedWidth(30)
|
||||||
|
self.multiple_separator.setText(' ::: ')
|
||||||
|
self.multiple_separator.textChanged.connect(self.s_r_separator_changed)
|
||||||
|
self.results_count.valueChanged[int].connect(self.s_r_display_bounds_changed)
|
||||||
|
self.starting_from.valueChanged[int].connect(self.s_r_display_bounds_changed)
|
||||||
|
|
||||||
def s_r_get_field(self, mi, field):
|
def s_r_get_field(self, mi, field):
|
||||||
if field:
|
if field:
|
||||||
@ -436,6 +441,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
val = []
|
val = []
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
def s_r_display_bounds_changed(self, i):
|
||||||
|
self.s_r_search_field_changed(self.search_field.currentIndex())
|
||||||
|
|
||||||
def s_r_template_changed(self):
|
def s_r_template_changed(self):
|
||||||
self.s_r_search_field_changed(self.search_field.currentIndex())
|
self.s_r_search_field_changed(self.search_field.currentIndex())
|
||||||
|
|
||||||
@ -451,21 +459,23 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
mi = self.db.get_metadata(self.ids[i], index_is_id=True)
|
mi = self.db.get_metadata(self.ids[i], index_is_id=True)
|
||||||
src = unicode(self.search_field.currentText())
|
src = unicode(self.search_field.currentText())
|
||||||
t = self.s_r_get_field(mi, src)
|
t = self.s_r_get_field(mi, src)
|
||||||
w.setText(''.join(t[0:1]))
|
if len(t) > 1:
|
||||||
|
t = t[self.starting_from.value()-1:
|
||||||
|
self.starting_from.value()-1 + self.results_count.value()]
|
||||||
|
w.setText(unicode(self.multiple_separator.text()).join(t))
|
||||||
|
|
||||||
if self.search_mode.currentIndex() == 0:
|
if self.search_mode.currentIndex() == 0:
|
||||||
self.destination_field.setCurrentIndex(idx)
|
self.destination_field.setCurrentIndex(idx)
|
||||||
else:
|
else:
|
||||||
|
self.s_r_destination_field_changed(self.destination_field.currentText())
|
||||||
self.s_r_paint_results(None)
|
self.s_r_paint_results(None)
|
||||||
|
|
||||||
def s_r_destination_field_changed(self, txt):
|
def s_r_destination_field_changed(self, txt):
|
||||||
txt = unicode(txt)
|
txt = unicode(txt)
|
||||||
self.comma_separated.setEnabled(True)
|
if not txt:
|
||||||
if txt:
|
txt = unicode(self.search_field.currentText())
|
||||||
fm = self.db.metadata_for_field(txt)
|
if txt and txt in self.writable_fields:
|
||||||
if fm['is_multiple']:
|
self.destination_field_fm = self.db.metadata_for_field(txt)
|
||||||
self.comma_separated.setEnabled(False)
|
|
||||||
self.comma_separated.setChecked(True)
|
|
||||||
self.s_r_paint_results(None)
|
self.s_r_paint_results(None)
|
||||||
|
|
||||||
def s_r_search_mode_changed(self, val):
|
def s_r_search_mode_changed(self, val):
|
||||||
@ -493,6 +503,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
self.s_r_heading.setText('<p>'+self.main_heading + self.regexp_heading)
|
self.s_r_heading.setText('<p>'+self.main_heading + self.regexp_heading)
|
||||||
self.s_r_paint_results(None)
|
self.s_r_paint_results(None)
|
||||||
|
|
||||||
|
def s_r_separator_changed(self, txt):
|
||||||
|
self.s_r_search_field_changed(self.search_field.currentIndex())
|
||||||
|
|
||||||
def s_r_set_colors(self):
|
def s_r_set_colors(self):
|
||||||
if self.s_r_error is not None:
|
if self.s_r_error is not None:
|
||||||
col = 'rgb(255, 0, 0, 20%)'
|
col = 'rgb(255, 0, 0, 20%)'
|
||||||
@ -533,6 +546,22 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
dest = src
|
dest = src
|
||||||
dest_mode = self.replace_mode.currentIndex()
|
dest_mode = self.replace_mode.currentIndex()
|
||||||
|
|
||||||
|
if self.destination_field_fm['is_multiple']:
|
||||||
|
if self.comma_separated.isChecked():
|
||||||
|
if dest == 'authors':
|
||||||
|
splitter = ' & '
|
||||||
|
else:
|
||||||
|
splitter = ','
|
||||||
|
|
||||||
|
res = []
|
||||||
|
for v in val:
|
||||||
|
for x in v.split(splitter):
|
||||||
|
if x.strip():
|
||||||
|
res.append(x.strip())
|
||||||
|
val = res
|
||||||
|
else:
|
||||||
|
val = [v.replace(',', '') for v in val]
|
||||||
|
|
||||||
if dest_mode != 0:
|
if dest_mode != 0:
|
||||||
dest_val = mi.get(dest, '')
|
dest_val = mi.get(dest, '')
|
||||||
if dest_val is None:
|
if dest_val is None:
|
||||||
@ -592,8 +621,13 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
wr = getattr(self, 'book_%d_result'%(i+1))
|
wr = getattr(self, 'book_%d_result'%(i+1))
|
||||||
try:
|
try:
|
||||||
result = self.s_r_do_regexp(mi)
|
result = self.s_r_do_regexp(mi)
|
||||||
t = self.s_r_do_destination(mi, result[0:1])
|
t = self.s_r_do_destination(mi, result)
|
||||||
t = self.s_r_replace_mode_separator().join(t)
|
if len(t) > 1 and self.destination_field_fm['is_multiple']:
|
||||||
|
t = t[self.starting_from.value()-1:
|
||||||
|
self.starting_from.value()-1 + self.results_count.value()]
|
||||||
|
t = unicode(self.multiple_separator.text()).join(t)
|
||||||
|
else:
|
||||||
|
t = self.s_r_replace_mode_separator().join(t)
|
||||||
wr.setText(t)
|
wr.setText(t)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.s_r_error = e
|
self.s_r_error = e
|
||||||
|
@ -478,7 +478,7 @@ Future conversion of these books will use the default settings.</string>
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="xlabel_24">
|
<widget class="QLabel" name="xlabel_24">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Search mode:</string>
|
<string>Search &mode:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy">
|
||||||
<cstring>search_mode</cstring>
|
<cstring>search_mode</cstring>
|
||||||
@ -559,7 +559,7 @@ Future conversion of these books will use the default settings.</string>
|
|||||||
<string>Check this box if the search string must match exactly upper and lower case. Uncheck it if case is to be ignored</string>
|
<string>Check this box if the search string must match exactly upper and lower case. Uncheck it if case is to be ignored</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Case sensitive</string>
|
<string>Cas&e sensitive</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="checked">
|
<property name="checked">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@ -588,7 +588,7 @@ Future conversion of these books will use the default settings.</string>
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_41">
|
<widget class="QLabel" name="label_41">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Apply function after replace:</string>
|
<string>&Apply function after replace:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy">
|
||||||
<cstring>replace_func</cstring>
|
<cstring>replace_func</cstring>
|
||||||
@ -641,7 +641,7 @@ If blank, the source field is used if the field is modifiable</string>
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="replace_mode_label">
|
<widget class="QLabel" name="replace_mode_label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Mode:</string>
|
<string>M&ode:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy">
|
||||||
<cstring>replace_mode</cstring>
|
<cstring>replace_mode</cstring>
|
||||||
@ -658,11 +658,12 @@ If blank, the source field is used if the field is modifiable</string>
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="comma_separated">
|
<widget class="QCheckBox" name="comma_separated">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>If the replace mode is prepend or append, then this box indicates whether a comma or
|
<string>Specifies whether result items should be split into multiple values or
|
||||||
nothing should be put between the original text and the inserted text</string>
|
left as single values. This option has the most effect when the source field is
|
||||||
|
not multiple and the destination field is multiple</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>use comma</string>
|
<string>Split &result</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="checked">
|
<property name="checked">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@ -684,25 +685,91 @@ nothing should be put between the original text and the inserted text</string>
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="1">
|
<item row="8" column="1" colspan="2">
|
||||||
<widget class="QLabel" name="xlabel_3">
|
<layout class="QHBoxLayout" name="horizontalLayout_21">
|
||||||
<property name="text">
|
<item>
|
||||||
<string>Test &text</string>
|
<spacer name="HSpacer_347">
|
||||||
</property>
|
<property name="orientation">
|
||||||
<property name="buddy">
|
<enum>Qt::Horizontal</enum>
|
||||||
<cstring>test_text</cstring>
|
</property>
|
||||||
</property>
|
<property name="sizeHint" stdset="0">
|
||||||
</widget>
|
<size>
|
||||||
</item>
|
<width>20</width>
|
||||||
<item row="8" column="2">
|
<height>0</height>
|
||||||
<widget class="QLabel" name="label_51">
|
</size>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>Test re&sult</string>
|
</spacer>
|
||||||
</property>
|
</item>
|
||||||
<property name="buddy">
|
<item>
|
||||||
<cstring>test_result</cstring>
|
<widget class="QLabel" name="xlabel_412">
|
||||||
</property>
|
<property name="text">
|
||||||
</widget>
|
<string>For multiple-valued fields, sho&w</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>results_count</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="results_count">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>999</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>999</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="xlabel_412">
|
||||||
|
<property name="text">
|
||||||
|
<string>values starting a&t</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>starting_from</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="starting_from">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>999</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="xlabel_41">
|
||||||
|
<property name="text">
|
||||||
|
<string>with values separated b&y</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>multiple_separator</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="multiple_separator">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Used when displaying test results to separate values in multiple-valued fields</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="0" colspan="4">
|
<item row="9" column="0" colspan="4">
|
||||||
<widget class="QScrollArea" name="scrollArea11">
|
<widget class="QScrollArea" name="scrollArea11">
|
||||||
@ -722,6 +789,20 @@ nothing should be put between the original text and the inserted text</string>
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="testgrid">
|
<layout class="QGridLayout" name="testgrid">
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="QLabel" name="xlabel_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Test text</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="2">
|
||||||
|
<widget class="QLabel" name="xlabel_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Test result</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="8" column="0">
|
<item row="8" column="0">
|
||||||
<widget class="QLabel" name="label_31">
|
<widget class="QLabel" name="label_31">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -823,7 +904,9 @@ nothing should be put between the original text and the inserted text</string>
|
|||||||
<tabstop>destination_field</tabstop>
|
<tabstop>destination_field</tabstop>
|
||||||
<tabstop>replace_mode</tabstop>
|
<tabstop>replace_mode</tabstop>
|
||||||
<tabstop>comma_separated</tabstop>
|
<tabstop>comma_separated</tabstop>
|
||||||
<tabstop>scrollArea11</tabstop>
|
<tabstop>results_count</tabstop>
|
||||||
|
<tabstop>starting_from</tabstop>
|
||||||
|
<tabstop>multiple_separator</tabstop>
|
||||||
<tabstop>test_text</tabstop>
|
<tabstop>test_text</tabstop>
|
||||||
<tabstop>test_result</tabstop>
|
<tabstop>test_result</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
|
25
src/calibre/gui2/dialogs/template_dialog.py
Normal file
25
src/calibre/gui2/dialogs/template_dialog.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
|
||||||
|
from PyQt4.Qt import Qt, QDialog, QDialogButtonBox
|
||||||
|
from calibre.gui2.dialogs.template_dialog_ui import Ui_TemplateDialog
|
||||||
|
|
||||||
|
class TemplateDialog(QDialog, Ui_TemplateDialog):
|
||||||
|
|
||||||
|
def __init__(self, parent, text):
|
||||||
|
QDialog.__init__(self, parent)
|
||||||
|
Ui_TemplateDialog.__init__(self)
|
||||||
|
self.setupUi(self)
|
||||||
|
# Remove help icon on title bar
|
||||||
|
icon = self.windowIcon()
|
||||||
|
self.setWindowFlags(self.windowFlags()&(~Qt.WindowContextHelpButtonHint))
|
||||||
|
self.setWindowIcon(icon)
|
||||||
|
|
||||||
|
if text is not None:
|
||||||
|
self.textbox.setPlainText(text)
|
||||||
|
self.textbox.setTabChangesFocus(True)
|
||||||
|
self.buttonBox.button(QDialogButtonBox.Ok).setText(_('&OK'))
|
||||||
|
self.buttonBox.button(QDialogButtonBox.Cancel).setText(_('&Cancel'))
|
||||||
|
|
73
src/calibre/gui2/dialogs/template_dialog.ui
Normal file
73
src/calibre/gui2/dialogs/template_dialog.ui
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>TemplateDialog</class>
|
||||||
|
<widget class="QDialog" name="TemplateDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>336</width>
|
||||||
|
<height>235</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Edit Comments</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPlainTextEdit" name="textbox"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>TemplateDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>229</x>
|
||||||
|
<y>211</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>234</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>TemplateDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>297</x>
|
||||||
|
<y>217</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>234</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -13,7 +13,7 @@ from PyQt4.Qt import QColor, Qt, QModelIndex, QSize, \
|
|||||||
QPen, QStyle, QPainter, QStyleOptionViewItemV4, \
|
QPen, QStyle, QPainter, QStyleOptionViewItemV4, \
|
||||||
QIcon, QDoubleSpinBox, QVariant, QSpinBox, \
|
QIcon, QDoubleSpinBox, QVariant, QSpinBox, \
|
||||||
QStyledItemDelegate, QCompleter, \
|
QStyledItemDelegate, QCompleter, \
|
||||||
QComboBox
|
QComboBox, QTextDocument
|
||||||
|
|
||||||
from calibre.gui2 import UNDEFINED_QDATE, error_dialog
|
from calibre.gui2 import UNDEFINED_QDATE, error_dialog
|
||||||
from calibre.gui2.widgets import EnLineEdit, TagsLineEdit
|
from calibre.gui2.widgets import EnLineEdit, TagsLineEdit
|
||||||
@ -22,6 +22,8 @@ from calibre.utils.config import tweaks
|
|||||||
from calibre.utils.formatter import validation_formatter
|
from calibre.utils.formatter import validation_formatter
|
||||||
from calibre.utils.icu import sort_key
|
from calibre.utils.icu import sort_key
|
||||||
from calibre.gui2.dialogs.comments_dialog import CommentsDialog
|
from calibre.gui2.dialogs.comments_dialog import CommentsDialog
|
||||||
|
from calibre.gui2.dialogs.template_dialog import TemplateDialog
|
||||||
|
|
||||||
|
|
||||||
class RatingDelegate(QStyledItemDelegate): # {{{
|
class RatingDelegate(QStyledItemDelegate): # {{{
|
||||||
COLOR = QColor("blue")
|
COLOR = QColor("blue")
|
||||||
@ -294,6 +296,24 @@ class CcCommentsDelegate(QStyledItemDelegate): # {{{
|
|||||||
Delegate for comments data.
|
Delegate for comments data.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
QStyledItemDelegate.__init__(self, parent)
|
||||||
|
self.document = QTextDocument()
|
||||||
|
|
||||||
|
def paint(self, painter, option, index):
|
||||||
|
style = self.parent().style()
|
||||||
|
self.document.setHtml(index.data(Qt.DisplayRole).toString())
|
||||||
|
painter.save()
|
||||||
|
if hasattr(QStyle, 'CE_ItemViewItem'):
|
||||||
|
style.drawControl(QStyle.CE_ItemViewItem, option,
|
||||||
|
painter, self.parent())
|
||||||
|
elif option.state & QStyle.State_Selected:
|
||||||
|
painter.fillRect(option.rect, option.palette.highlight())
|
||||||
|
painter.setClipRect(option.rect)
|
||||||
|
painter.translate(option.rect.topLeft())
|
||||||
|
self.document.drawContents(painter)
|
||||||
|
painter.restore()
|
||||||
|
|
||||||
def createEditor(self, parent, option, index):
|
def createEditor(self, parent, option, index):
|
||||||
m = index.model()
|
m = index.model()
|
||||||
col = m.column_map[index.column()]
|
col = m.column_map[index.column()]
|
||||||
@ -301,11 +321,11 @@ class CcCommentsDelegate(QStyledItemDelegate): # {{{
|
|||||||
editor = CommentsDialog(parent, text)
|
editor = CommentsDialog(parent, text)
|
||||||
d = editor.exec_()
|
d = editor.exec_()
|
||||||
if d:
|
if d:
|
||||||
m.setData(index, QVariant(editor.textbox.toPlainText()), Qt.EditRole)
|
m.setData(index, QVariant(editor.textbox.html), Qt.EditRole)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def setModelData(self, editor, model, index):
|
def setModelData(self, editor, model, index):
|
||||||
model.setData(index, QVariant(editor.textbox.toPlainText()), Qt.EditRole)
|
model.setData(index, QVariant(editor.textbox.html), Qt.EditRole)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class CcBoolDelegate(QStyledItemDelegate): # {{{
|
class CcBoolDelegate(QStyledItemDelegate): # {{{
|
||||||
@ -351,7 +371,7 @@ class CcTemplateDelegate(QStyledItemDelegate): # {{{
|
|||||||
def createEditor(self, parent, option, index):
|
def createEditor(self, parent, option, index):
|
||||||
m = index.model()
|
m = index.model()
|
||||||
text = m.custom_columns[m.column_map[index.column()]]['display']['composite_template']
|
text = m.custom_columns[m.column_map[index.column()]]['display']['composite_template']
|
||||||
editor = CommentsDialog(parent, text)
|
editor = TemplateDialog(parent, text)
|
||||||
editor.setWindowTitle(_("Edit template"))
|
editor.setWindowTitle(_("Edit template"))
|
||||||
editor.textbox.setTabChangesFocus(False)
|
editor.textbox.setTabChangesFocus(False)
|
||||||
editor.textbox.setTabStopWidth(20)
|
editor.textbox.setTabStopWidth(20)
|
||||||
|
@ -334,6 +334,8 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
if key not in cf_to_display:
|
if key not in cf_to_display:
|
||||||
continue
|
continue
|
||||||
name, val = mi.format_field(key)
|
name, val = mi.format_field(key)
|
||||||
|
if mi.metadata_for_field(key)['datatype'] == 'comments':
|
||||||
|
name += ':html'
|
||||||
if val:
|
if val:
|
||||||
data[name] = val
|
data[name] = val
|
||||||
return data
|
return data
|
||||||
|
@ -57,6 +57,11 @@ class BooksView(QTableView): # {{{
|
|||||||
elif tweaks['doubleclick_on_library_view'] == 'open_viewer':
|
elif tweaks['doubleclick_on_library_view'] == 'open_viewer':
|
||||||
self.setEditTriggers(self.SelectedClicked|self.editTriggers())
|
self.setEditTriggers(self.SelectedClicked|self.editTriggers())
|
||||||
self.doubleClicked.connect(parent.iactions['View'].view_triggered)
|
self.doubleClicked.connect(parent.iactions['View'].view_triggered)
|
||||||
|
elif tweaks['doubleclick_on_library_view'] == 'edit_metadata':
|
||||||
|
# Must not enable single-click to edit, or the field will remain
|
||||||
|
# open in edit mode underneath the edit metadata dialog
|
||||||
|
self.doubleClicked.connect(
|
||||||
|
partial(parent.iactions['Edit Metadata'].edit_metadata, checked=False))
|
||||||
|
|
||||||
self.drag_allowed = True
|
self.drag_allowed = True
|
||||||
self.setDragEnabled(True)
|
self.setDragEnabled(True)
|
||||||
|
@ -103,7 +103,7 @@ class PluginModel(QAbstractItemModel): # {{{
|
|||||||
plugin = self.index_to_plugin(index)
|
plugin = self.index_to_plugin(index)
|
||||||
if role == Qt.DisplayRole:
|
if role == Qt.DisplayRole:
|
||||||
ver = '.'.join(map(str, plugin.version))
|
ver = '.'.join(map(str, plugin.version))
|
||||||
desc = '\n'.join(textwrap.wrap(plugin.description, 50))
|
desc = '\n'.join(textwrap.wrap(plugin.description, 100))
|
||||||
ans='%s (%s) %s %s\n%s'%(plugin.name, ver, _('by'), plugin.author, desc)
|
ans='%s (%s) %s %s\n%s'%(plugin.name, ver, _('by'), plugin.author, desc)
|
||||||
c = plugin_customization(plugin)
|
c = plugin_customization(plugin)
|
||||||
if c:
|
if c:
|
||||||
|
@ -769,7 +769,7 @@ class DocumentView(QWebView): # {{{
|
|||||||
self.to_bottom = True
|
self.to_bottom = True
|
||||||
if epf:
|
if epf:
|
||||||
self.flipper.initialize(self.current_page_image(), False)
|
self.flipper.initialize(self.current_page_image(), False)
|
||||||
self.manager.previous_document()
|
self.manager.previous_document()
|
||||||
else:
|
else:
|
||||||
opos = self.document.ypos
|
opos = self.document.ypos
|
||||||
upper_limit = opos - delta_y
|
upper_limit = opos - delta_y
|
||||||
@ -783,8 +783,8 @@ class DocumentView(QWebView): # {{{
|
|||||||
if epf:
|
if epf:
|
||||||
self.flipper(self.current_page_image(),
|
self.flipper(self.current_page_image(),
|
||||||
duration=self.document.page_flip_duration)
|
duration=self.document.page_flip_duration)
|
||||||
if self.manager is not None:
|
if self.manager is not None:
|
||||||
self.manager.scrolled(self.scroll_fraction)
|
self.manager.scrolled(self.scroll_fraction)
|
||||||
|
|
||||||
def next_page(self):
|
def next_page(self):
|
||||||
if self.flipper.running and not self.is_auto_repeat_event:
|
if self.flipper.running and not self.is_auto_repeat_event:
|
||||||
|
@ -51,6 +51,10 @@ def comments_to_html(comments):
|
|||||||
if not isinstance(comments, unicode):
|
if not isinstance(comments, unicode):
|
||||||
comments = comments.decode(preferred_encoding, 'replace')
|
comments = comments.decode(preferred_encoding, 'replace')
|
||||||
|
|
||||||
|
if comments.lstrip().startswith('<'):
|
||||||
|
# Comment is already HTML do not mess with it
|
||||||
|
return comments
|
||||||
|
|
||||||
if '<' not in comments:
|
if '<' not in comments:
|
||||||
comments = prepare_string_for_xml(comments)
|
comments = prepare_string_for_xml(comments)
|
||||||
parts = [u'<p class="description">%s</p>'%x.replace(u'\n', u'<br />')
|
parts = [u'<p class="description">%s</p>'%x.replace(u'\n', u'<br />')
|
||||||
|
@ -556,18 +556,19 @@ class BrowseServer(object):
|
|||||||
ids = self.search_cache('search:"%s"'%which)
|
ids = self.search_cache('search:"%s"'%which)
|
||||||
except:
|
except:
|
||||||
raise cherrypy.HTTPError(404, 'Search: %r not understood'%which)
|
raise cherrypy.HTTPError(404, 'Search: %r not understood'%which)
|
||||||
all_ids = self.search_cache('')
|
|
||||||
if category == 'newest':
|
|
||||||
ids = all_ids
|
|
||||||
hide_sort = 'true'
|
|
||||||
elif category == 'allbooks':
|
|
||||||
ids = all_ids
|
|
||||||
else:
|
else:
|
||||||
q = category
|
all_ids = self.search_cache('')
|
||||||
if q == 'news':
|
if category == 'newest':
|
||||||
q = 'tags'
|
ids = all_ids
|
||||||
ids = self.db.get_books_for_category(q, cid)
|
hide_sort = 'true'
|
||||||
ids = [x for x in ids if x in all_ids]
|
elif category == 'allbooks':
|
||||||
|
ids = all_ids
|
||||||
|
else:
|
||||||
|
q = category
|
||||||
|
if q == 'news':
|
||||||
|
q = 'tags'
|
||||||
|
ids = self.db.get_books_for_category(q, cid)
|
||||||
|
ids = [x for x in ids if x in all_ids]
|
||||||
|
|
||||||
items = [self.db.data._data[x] for x in ids]
|
items = [self.db.data._data[x] for x in ids]
|
||||||
if category == 'newest':
|
if category == 'newest':
|
||||||
|
@ -173,6 +173,8 @@ def ACQUISITION_ENTRY(item, version, db, updated, CFM, CKEYS, prefix):
|
|||||||
extra.append('%s: %s<br />'%(xml(name), xml(format_tag_string(val, ',',
|
extra.append('%s: %s<br />'%(xml(name), xml(format_tag_string(val, ',',
|
||||||
ignore_max=True,
|
ignore_max=True,
|
||||||
no_tag_count=True))))
|
no_tag_count=True))))
|
||||||
|
elif datatype == 'comments':
|
||||||
|
extra.append('%s: %s<br />'%(xml(name), comments_to_html(unicode(val))))
|
||||||
else:
|
else:
|
||||||
extra.append('%s: %s<br />'%(xml(name), xml(unicode(val))))
|
extra.append('%s: %s<br />'%(xml(name), xml(unicode(val))))
|
||||||
comments = item[FM['comments']]
|
comments = item[FM['comments']]
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user