mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-30 21:41:57 -04:00
Pull from trunk
This commit is contained in:
commit
74837333f3
BIN
resources/images/news/la_razon_bo.png
Normal file
BIN
resources/images/news/la_razon_bo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 356 B |
BIN
resources/images/news/los_tiempos_bo.png
Normal file
BIN
resources/images/news/los_tiempos_bo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 464 B |
64
resources/recipes/la_razon_bo.recipe
Normal file
64
resources/recipes/la_razon_bo.recipe
Normal file
@ -0,0 +1,64 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
www.la-razon.com
|
||||
'''
|
||||
|
||||
from calibre import strftime
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class LaRazon_Bol(BasicNewsRecipe):
|
||||
title = 'La Razón - Bolivia'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'El diario nacional de Bolivia'
|
||||
publisher = 'Praxsis S.R.L.'
|
||||
category = 'news, politics, Bolivia'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 200
|
||||
no_stylesheets = True
|
||||
encoding = 'cp1252'
|
||||
use_embedded_content = False
|
||||
language = 'es'
|
||||
publication_type = 'newspaper'
|
||||
delay = 1
|
||||
remove_empty_feeds = True
|
||||
cover_url = strftime('http://www.la-razon.com/portadas/%Y%m%d_LaRazon.jpg')
|
||||
masthead_url = 'http://www.la-razon.com/imagenes/logo.jpg'
|
||||
extra_css = """ body{font-family: Arial,Helvetica,sans-serif }
|
||||
img{margin-bottom: 0.4em}
|
||||
.noticia-titulo{font-family: Georgia,"Times New Roman",Times,serif}
|
||||
.lead{font-weight: bold; font-size: 0.8em}
|
||||
"""
|
||||
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher' : publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'class':['noticia-titulo','noticia-desarrollo']})]
|
||||
remove_tags = [dict(name=['meta','link','form','iframe','embed','object'])]
|
||||
remove_attributes = ['width','height']
|
||||
|
||||
feeds = [
|
||||
(u'Editorial' , u'http://www.la-razon.com/rss_editorial.php' )
|
||||
,(u'Opinión' , u'http://www.la-razon.com/rss_opinion.php' )
|
||||
,(u'Nacional' , u'http://www.la-razon.com/rss_nacional.php' )
|
||||
,(u'Economia' , u'http://www.la-razon.com/rss_economia.php' )
|
||||
,(u'Ciudades' , u'http://www.la-razon.com/rss_ciudades.php' )
|
||||
,(u'Sociedad' , u'http://www.la-razon.com/rss_sociedad.php' )
|
||||
,(u'Mundo' , u'http://www.la-razon.com/rss_sociedad.php' )
|
||||
,(u'La Revista' , u'http://www.la-razon.com/rss_larevista.php' )
|
||||
,(u'Sociales' , u'http://www.la-razon.com/rss_sociales.php' )
|
||||
,(u'Mia' , u'http://www.la-razon.com/rss_mia.php' )
|
||||
,(u'Marcas' , u'http://www.la-razon.com/rss_marcas.php' )
|
||||
,(u'Escape' , u'http://www.la-razon.com/rss_escape.php' )
|
||||
,(u'El Financiero' , u'http://www.la-razon.com/rss_financiero.php')
|
||||
,(u'Tendencias' , u'http://www.la-razon.com/rss_tendencias.php')
|
||||
]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
return soup
|
63
resources/recipes/los_tiempos_bo.recipe
Normal file
63
resources/recipes/los_tiempos_bo.recipe
Normal file
@ -0,0 +1,63 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
www.lostiempos.com
|
||||
'''
|
||||
|
||||
from calibre import strftime
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class LosTiempos_Bol(BasicNewsRecipe):
|
||||
title = 'Los Tiempos - Bolivia'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'El periódico de mayor circulación en la ciudad de Cochabamba, Bolivia'
|
||||
publisher = 'Los Tiempos'
|
||||
category = 'news, politics, Bolivia'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 200
|
||||
no_stylesheets = True
|
||||
encoding = 'cp1252'
|
||||
use_embedded_content = False
|
||||
language = 'es'
|
||||
publication_type = 'newspaper'
|
||||
delay = 1
|
||||
remove_empty_feeds = True
|
||||
cover_url = strftime('http://www.lostiempos.com/media_recortes/%Y/%m/%d/portada_md_1.jpg')
|
||||
masthead_url = 'http://www.lostiempos.com/img_stat/logo_tiempos_sin_beta.jpg'
|
||||
extra_css = """ body{font-family: Arial,Helvetica,sans-serif }
|
||||
img{margin-bottom: 0.4em}
|
||||
h1,.hora,.breadcum,.pie_foto{font-family: Georgia,"Times New Roman",Times,serif}
|
||||
.hora,.breadcum,.pie_foto{font-size: small}
|
||||
.en_gris,.pie_foto{color: #666666}
|
||||
"""
|
||||
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher' : publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'articulo'})]
|
||||
remove_tags = [
|
||||
dict(name=['meta','link','form','iframe','embed','object','hr'])
|
||||
,dict(attrs={'class':['caja_fonts sin_border_bot','pub']})
|
||||
]
|
||||
remove_attributes = ['width','height']
|
||||
|
||||
feeds = [
|
||||
(u'Nacional' , u'http://www.lostiempos.com/rss/lostiempos-nacional.xml' )
|
||||
,(u'Local' , u'http://www.lostiempos.com/rss/lostiempos-local.xml' )
|
||||
,(u'Deportes' , u'http://www.lostiempos.com/rss/lostiempos-deportes.xml' )
|
||||
,(u'Economía' , u'http://www.lostiempos.com/rss/lostiempos-economia.xml' )
|
||||
,(u'Internacional' , u'http://www.lostiempos.com/rss/lostiempos-internacional.xml' )
|
||||
,(u'Vida y Futuro' , u'http://www.lostiempos.com/rss/lostiempos-vida-y-futuro.xml' )
|
||||
,(u'Tragaluz' , u'http://www.lostiempos.com/rss/lostiempos-tragaluz.xml' )
|
||||
,(u'Opiniones' , u'http://www.lostiempos.com/rss/lostiempos-opiniones.xml' )
|
||||
]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
return soup
|
||||
|
34
resources/recipes/yahoo_news.recipe
Normal file
34
resources/recipes/yahoo_news.recipe
Normal file
@ -0,0 +1,34 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
import re
|
||||
|
||||
class YahooNews(BasicNewsRecipe):
|
||||
title = 'Yahoo News'
|
||||
__author__ = 'Starson17'
|
||||
description = 'Yahoo-Science'
|
||||
language = 'en'
|
||||
use_embedded_content= False
|
||||
no_stylesheets = True
|
||||
linearize_tables = True
|
||||
oldest_article = 24
|
||||
remove_javascript = True
|
||||
remove_empty_feeds = True
|
||||
max_articles_per_feed = 10
|
||||
|
||||
feeds = [#There are dozens of other feeds at http://news.yahoo.com/rss
|
||||
(u'Top Stories', u'http://rss.news.yahoo.com/rss/topstories'),
|
||||
(u'Science', u'http://rss.news.yahoo.com/rss/science')
|
||||
]
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'yn-story'})]
|
||||
|
||||
remove_tags = [dict(name='div', attrs={'class':['hd', 'ft', 'yn-share-social']}),
|
||||
dict(name='div', attrs={'id':['yn-story-minor-media']})]
|
||||
|
||||
preprocess_regexps = [(re.compile(r'<span>Play Video</span>', re.DOTALL),lambda match: '<span></span>')]
|
||||
|
||||
extra_css = '''
|
||||
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
|
||||
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
|
||||
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
|
||||
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
|
||||
'''
|
@ -19,8 +19,8 @@ class ANDROID(USBMS):
|
||||
|
||||
VENDOR_ID = {
|
||||
# HTC
|
||||
0x0bb4 : { 0x0c02 : [0x100, 0x227], 0x0c01 : [0x100, 0x227], 0x0ff9
|
||||
: [0x0100, 0x227]},
|
||||
0x0bb4 : { 0x0c02 : [0x100, 0x0227], 0x0c01 : [0x100, 0x0227], 0x0ff9
|
||||
: [0x0100, 0x0227, 0x0226]},
|
||||
|
||||
# Motorola
|
||||
0x22b8 : { 0x41d9 : [0x216], 0x2d67 : [0x100], 0x41db : [0x216],
|
||||
|
@ -931,7 +931,7 @@ class SaveToDiskAction(object): # {{{
|
||||
lpath = self.library_view.model().db.library_path.replace('/', os.sep)
|
||||
if dpath.startswith(lpath):
|
||||
return error_dialog(self, _('Not allowed'),
|
||||
_('You are tying to save files into the calibre '
|
||||
_('You are trying to save files into the calibre '
|
||||
'library. This can cause corruption of your '
|
||||
'library. Save to disk is meant to export '
|
||||
'files from your calibre library elsewhere.'), show=True)
|
||||
|
@ -18,7 +18,7 @@ from calibre.gui2 import error_dialog, config, gprefs, \
|
||||
open_url, open_local_file, \
|
||||
ALL_COLUMNS, NONE, info_dialog, choose_files, \
|
||||
warning_dialog, ResizableDialog, question_dialog
|
||||
from calibre.utils.config import prefs
|
||||
from calibre.utils.config import prefs, read_raw_tweaks, write_tweaks
|
||||
from calibre.ebooks import BOOK_EXTENSIONS
|
||||
from calibre.ebooks.oeb.iterator import is_supported
|
||||
from calibre.library.server import server_config
|
||||
@ -514,8 +514,18 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
||||
self.opt_toolbar_text.setCurrentIndex(idx)
|
||||
self.reset_confirmation_button.clicked.connect(self.reset_confirmation)
|
||||
|
||||
deft, curt = read_raw_tweaks()
|
||||
self.current_tweaks.setPlainText(curt)
|
||||
self.default_tweaks.setPlainText(deft)
|
||||
self.restore_tweaks_to_default_button.clicked.connect(self.restore_tweaks_to_default)
|
||||
|
||||
self.category_view.setCurrentIndex(self.category_view.model().index_for_name(initial_category))
|
||||
|
||||
def restore_tweaks_to_default(self, *args):
|
||||
deft, curt = read_raw_tweaks()
|
||||
self.current_tweaks.setPlainText(deft)
|
||||
|
||||
|
||||
def reset_confirmation(self):
|
||||
from calibre.gui2 import dynamic
|
||||
for key in dynamic.keys():
|
||||
@ -687,6 +697,22 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
||||
self.input_order.insertItem(idx-1, self.input_order.takeItem(idx))
|
||||
self.input_order.setCurrentRow(idx-1)
|
||||
|
||||
def set_tweaks(self):
|
||||
raw = unicode(self.current_tweaks.toPlainText())
|
||||
raw = re.sub(r'(?m)^#.*fileencoding.*', '# ', raw)
|
||||
try:
|
||||
exec raw
|
||||
except:
|
||||
import traceback
|
||||
error_dialog(self, _('Invalid tweaks'),
|
||||
_('The tweaks you entered are invalid, try resetting the'
|
||||
' tweaks to default and changing them one by one until'
|
||||
' you find the invalid setting.'),
|
||||
det_msg=traceback.format_exc(), show=True)
|
||||
return False
|
||||
write_tweaks(raw)
|
||||
return True
|
||||
|
||||
def down_input(self):
|
||||
idx = self.input_order.currentRow()
|
||||
if idx < self.input_order.count()-1:
|
||||
@ -852,6 +878,8 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
||||
return
|
||||
if not self.add_save.save_settings():
|
||||
return
|
||||
if not self.set_tweaks():
|
||||
return
|
||||
wl = self.opt_worker_limit.value()
|
||||
if wl%2 != 0:
|
||||
wl += 1
|
||||
|
@ -719,61 +719,192 @@
|
||||
<widget class="QWidget" name="page_2">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>&Maximum number of waiting worker processes (needs restart):</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_worker_limit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="opt_worker_limit">
|
||||
<property name="minimum">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="compact_button">
|
||||
<property name="text">
|
||||
<string>&Check database integrity</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="button_osx_symlinks">
|
||||
<property name="text">
|
||||
<string>&Install command line tools</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="button_open_config_dir">
|
||||
<property name="text">
|
||||
<string>Open calibre &configuration directory</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="opt_enforce_cpu_limit">
|
||||
<property name="text">
|
||||
<string>Limit the max. simultaneous jobs to the available CPU &cores</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="device_detection_button">
|
||||
<property name="text">
|
||||
<string>Debug &device detection</string>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>&Miscellaneous</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_9">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>&Maximum number of waiting worker processes (needs restart):</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_worker_limit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="opt_worker_limit">
|
||||
<property name="minimum">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="opt_enforce_cpu_limit">
|
||||
<property name="text">
|
||||
<string>Limit the max. simultaneous jobs to the available CPU &cores</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>79</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="device_detection_button">
|
||||
<property name="text">
|
||||
<string>Debug &device detection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="compact_button">
|
||||
<property name="text">
|
||||
<string>&Check database integrity</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<spacer name="verticalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>79</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="button_open_config_dir">
|
||||
<property name="text">
|
||||
<string>Open calibre &configuration directory</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<spacer name="verticalSpacer_8">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="9" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="button_osx_symlinks">
|
||||
<property name="text">
|
||||
<string>&Install command line tools</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<spacer name="verticalSpacer_9">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>79</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>&Tweaks</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Values for the tweaks are shown below. Edit them to change the behavior of calibre</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="title">
|
||||
<string>All available tweaks</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_11">
|
||||
<item row="0" column="0">
|
||||
<widget class="QPlainTextEdit" name="default_tweaks">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_7">
|
||||
<property name="title">
|
||||
<string>&Current tweaks</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_10">
|
||||
<item row="0" column="0">
|
||||
<widget class="QPlainTextEdit" name="current_tweaks"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="restore_tweaks_to_default_button">
|
||||
<property name="text">
|
||||
<string>&Restore to defaults</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -48,17 +48,42 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
||||
select_item = sort
|
||||
self.table.resizeColumnsToContents()
|
||||
|
||||
# set up the signal after the table is filled
|
||||
# set up the cellChanged signal only after the table is filled
|
||||
self.table.cellChanged.connect(self.cell_changed)
|
||||
|
||||
self.table.setSortingEnabled(True)
|
||||
# set up sort buttons
|
||||
self.sort_by_author.setCheckable(True)
|
||||
self.sort_by_author.setChecked(False)
|
||||
self.sort_by_author.clicked.connect(self.do_sort_by_author)
|
||||
self.author_order = 1
|
||||
|
||||
self.table.sortByColumn(1, Qt.AscendingOrder)
|
||||
self.sort_by_author_sort.clicked.connect(self.do_sort_by_author_sort)
|
||||
self.sort_by_author_sort.setCheckable(True)
|
||||
self.sort_by_author_sort.setChecked(True)
|
||||
self.author_sort_order = 1
|
||||
|
||||
# set up author sort calc button
|
||||
self.recalc_author_sort.clicked.connect(self.do_recalc_author_sort)
|
||||
|
||||
if select_item is not None:
|
||||
self.table.setCurrentItem(select_item)
|
||||
self.table.editItem(select_item)
|
||||
else:
|
||||
self.table.setCurrentCell(0, 0)
|
||||
|
||||
def do_sort_by_author(self):
|
||||
self.author_order = 1 if self.author_order == 0 else 0
|
||||
self.table.sortByColumn(0, self.author_order)
|
||||
self.sort_by_author.setChecked(True)
|
||||
self.sort_by_author_sort.setChecked(False)
|
||||
|
||||
def do_sort_by_author_sort(self):
|
||||
self.author_sort_order = 1 if self.author_sort_order == 0 else 0
|
||||
self.table.sortByColumn(1, self.author_sort_order)
|
||||
self.sort_by_author.setChecked(False)
|
||||
self.sort_by_author_sort.setChecked(True)
|
||||
|
||||
def accepted(self):
|
||||
self.result = []
|
||||
for row in range(0,self.table.rowCount()):
|
||||
@ -69,6 +94,17 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
||||
if orig_aut != aut or orig_sort != sort:
|
||||
self.result.append((id, orig_aut, aut, sort))
|
||||
|
||||
def do_recalc_author_sort(self):
|
||||
self.table.cellChanged.disconnect()
|
||||
for row in range(0,self.table.rowCount()):
|
||||
item = self.table.item(row, 0)
|
||||
aut = unicode(item.text()).strip()
|
||||
c = self.table.item(row, 1)
|
||||
# Sometimes trailing commas are left by changing between copy algs
|
||||
c.setText(author_to_author_sort(aut).rstrip(','))
|
||||
self.table.setFocus(Qt.OtherFocusReason)
|
||||
self.table.cellChanged.connect(self.cell_changed)
|
||||
|
||||
def cell_changed(self, row, col):
|
||||
if col == 0:
|
||||
item = self.table.item(row, 0)
|
||||
@ -79,8 +115,4 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
||||
else:
|
||||
item = self.table.item(row, 1)
|
||||
self.table.setCurrentItem(item)
|
||||
# disable and reenable sorting to force the sort now, so we can scroll
|
||||
# to the item after it moves
|
||||
self.table.setSortingEnabled(False)
|
||||
self.table.setSortingEnabled(True)
|
||||
self.table.scrollToItem(item)
|
||||
|
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>730</width>
|
||||
<width>768</width>
|
||||
<height>342</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -34,17 +34,64 @@
|
||||
</widget>
|
||||
</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>
|
||||
<property name="centerButtons">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="sort_by_author">
|
||||
<property name="text">
|
||||
<string>Sort by author</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="sort_by_author_sort">
|
||||
<property name="text">
|
||||
<string>Sort by author sort</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="recalc_author_sort">
|
||||
<property name="toolTip">
|
||||
<string>Reset all the author sort values to a value automatically generated from the author. Exactly how this value is automatically generated can be controlled via Preferences->Advanced->Tweaks</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Recalculate all author sort values</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
<property name="centerButtons">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@ -675,9 +675,7 @@ class Wizard(QWizard):
|
||||
self.connect(self.library_page, SIGNAL('retranslate()'),
|
||||
self.retranslate)
|
||||
self.finish_page = FinishPage()
|
||||
bt = unicode(self.buttonText(self.FinishButton)).replace('&', '')
|
||||
t = unicode(self.finish_page.finish_text.text())
|
||||
self.finish_page.finish_text.setText(t%bt)
|
||||
self.set_finish_text()
|
||||
self.kindle_page = KindlePage()
|
||||
self.stanza_page = StanzaPage()
|
||||
self.word_player_page = WordPlayerPage()
|
||||
@ -702,6 +700,7 @@ class Wizard(QWizard):
|
||||
for pid in self.pageIds():
|
||||
page = self.page(pid)
|
||||
page.retranslateUi(page)
|
||||
self.set_finish_text()
|
||||
|
||||
def accept(self):
|
||||
pages = map(self.page, self.visitedPages())
|
||||
@ -715,6 +714,13 @@ class Wizard(QWizard):
|
||||
def completed(self, newloc):
|
||||
return QWizard.accept(self)
|
||||
|
||||
def set_finish_text(self, *args):
|
||||
bt = unicode(self.buttonText(self.FinishButton)).replace('&', '')
|
||||
t = unicode(self.finish_page.finish_text.text())
|
||||
if '%s' in t:
|
||||
self.finish_page.finish_text.setText(t%bt)
|
||||
|
||||
|
||||
def wizard(parent=None):
|
||||
w = Wizard(parent)
|
||||
return w
|
||||
|
@ -15,6 +15,7 @@ from calibre import prepare_string_for_xml
|
||||
# Hackish - ignoring sentences ending or beginning in numbers to avoid
|
||||
# confusion with decimal points.
|
||||
lost_cr_pat = re.compile('([a-z])([\.\?!])([A-Z])')
|
||||
lost_cr_exception_pat = re.compile(r'(Ph\.D)|(D\.Phil)|((Dr|Mr|Mrs|Ms)\.[A-Z])')
|
||||
|
||||
def comments_to_html(comments):
|
||||
'''
|
||||
@ -51,6 +52,8 @@ def comments_to_html(comments):
|
||||
return '\n'.join(parts)
|
||||
|
||||
# Explode lost CRs to \n\n
|
||||
comments = lost_cr_exception_pat.sub(lambda m: m.group().replace('.',
|
||||
'.\r'), comments)
|
||||
for lost_cr in lost_cr_pat.finditer(comments):
|
||||
comments = comments.replace(lost_cr.group(),
|
||||
'%s%s\n\n%s' % (lost_cr.group(1),
|
||||
|
@ -317,6 +317,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
'title', 'timestamp', 'uuid', 'pubdate'):
|
||||
setattr(self, prop, functools.partial(get_property,
|
||||
loc=self.FIELD_MAP['comments' if prop == 'comment' else prop]))
|
||||
setattr(self, 'title_sort', functools.partial(get_property,
|
||||
loc=self.FIELD_MAP['sort']))
|
||||
|
||||
def initialize_database(self):
|
||||
metadata_sqlite = open(P('metadata_sqlite.sql'), 'rb').read()
|
||||
@ -494,6 +496,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
mi.timestamp = self.timestamp(idx, index_is_id=index_is_id)
|
||||
mi.pubdate = self.pubdate(idx, index_is_id=index_is_id)
|
||||
mi.uuid = self.uuid(idx, index_is_id=index_is_id)
|
||||
mi.title_sort = self.title_sort(idx, index_is_id=index_is_id)
|
||||
tags = self.tags(idx, index_is_id=index_is_id)
|
||||
if tags:
|
||||
mi.tags = [i.strip() for i in tags.split(',')]
|
||||
|
@ -177,7 +177,7 @@ def extract(path, dir):
|
||||
try:
|
||||
if open_archive_data.OpenResult != 0:
|
||||
raise UnRARException(_interpret_open_error(open_archive_data.OpenResult, path))
|
||||
prints('Archive:', path)
|
||||
#prints('Archive:', path)
|
||||
#print get_archive_info(open_archive_data.Flags)
|
||||
header_data = RARHeaderDataEx(CmtBuf=None)
|
||||
#_libunrar.RARSetCallback(arc_data, callback_func, mode)
|
||||
|
@ -277,7 +277,8 @@ In |app|, you would instead use tags to mark genre and read status and then just
|
||||
|
||||
Why doesn't |app| have a column for foo?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|app| is designed to have columns for the most frequently and widely used fields. If it does not have a coulmn for your favorite field, you can always add a tag to the book for that piece of information. |app| also supports a general purpose "comments" fields for longer items.
|
||||
|app| is designed to have columns for the most frequently and widely used fields. In addition, you can add any columns you like. Columns can be added via Preferences->Interface.
|
||||
Watch the tutorial `UI Power tips <http://calibre-ebook.com/demo#tutorials>`_ to learn how to create your own columns.
|
||||
|
||||
How do I move my |app| library from one computer to another?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -703,16 +703,21 @@ if prefs['installation_uuid'] is None:
|
||||
prefs['installation_uuid'] = str(uuid.uuid4())
|
||||
|
||||
# Read tweaks
|
||||
def read_tweaks():
|
||||
def read_raw_tweaks():
|
||||
make_config_dir()
|
||||
default_tweaks = P('default_tweaks.py', data=True)
|
||||
tweaks_file = os.path.join(config_dir, 'tweaks.py')
|
||||
if not os.path.exists(tweaks_file):
|
||||
with open(tweaks_file, 'wb') as f:
|
||||
f.write(default_tweaks)
|
||||
with open(tweaks_file, 'rb') as f:
|
||||
return default_tweaks, f.read()
|
||||
|
||||
def read_tweaks():
|
||||
default_tweaks, tweaks = read_raw_tweaks()
|
||||
l, g = {}, {}
|
||||
try:
|
||||
exec open(tweaks_file, 'rb') in g, l
|
||||
exec tweaks in g, l
|
||||
except:
|
||||
print 'Failed to load custom tweaks file'
|
||||
traceback.print_exc()
|
||||
@ -721,6 +726,13 @@ def read_tweaks():
|
||||
dl.update(l)
|
||||
return dl
|
||||
|
||||
def write_tweaks(raw):
|
||||
make_config_dir()
|
||||
tweaks_file = os.path.join(config_dir, 'tweaks.py')
|
||||
with open(tweaks_file, 'wb') as f:
|
||||
f.write(raw)
|
||||
|
||||
|
||||
tweaks = read_tweaks()
|
||||
|
||||
def migrate():
|
||||
|
@ -194,7 +194,7 @@ class Image(_magick.Image): # {{{
|
||||
|
||||
# }}}
|
||||
|
||||
def create_canvas(width, height, bgcolor):
|
||||
def create_canvas(width, height, bgcolor='white'):
|
||||
canvas = Image()
|
||||
canvas.create_canvas(int(width), int(height), str(bgcolor))
|
||||
return canvas
|
||||
|
Loading…
x
Reference in New Issue
Block a user