Sync to trunk

This commit is contained in:
John Schember 2009-01-25 12:05:00 -05:00
commit 381b5a0607
17 changed files with 2586 additions and 2614 deletions

View File

@ -22,7 +22,7 @@ def string_to_authors(raw):
def authors_to_string(authors): def authors_to_string(authors):
if authors is not None: if authors is not None:
return ' & '.join([a.replace('&', '&&') for a in authors]) return ' & '.join([a.replace('&', '&&') for a in authors if a])
else: else:
return '' return ''

View File

@ -78,7 +78,7 @@ def get_metadata(stream, stream_type='lrf', use_libprs_metadata=False):
# The regex is meant to match the standard format filenames are written # The regex is meant to match the standard format filenames are written
# in: title_-_author_number.extension # in: title_-_author_number.extension
base.smart_update(metadata_from_filename(name, re.compile( base.smart_update(metadata_from_filename(name, re.compile(
'^(?P<title>[^\s]+?)_-_(?P<author>[^\s]+?)_+\d+'))) r'^(?P<title>\S+?)_-_(?P<author>\S+?)_+\d+')))
if base.title: if base.title:
base.title = base.title.replace('_', ' ') base.title = base.title.replace('_', ' ')
if base.authors: if base.authors:

View File

@ -23,7 +23,6 @@ from calibre import LoggingInterface
from calibre.translations.dynamic import translate from calibre.translations.dynamic import translate
from calibre.startup import get_lang from calibre.startup import get_lang
XML_PARSER = etree.XMLParser(recover=True)
XML_NS = 'http://www.w3.org/XML/1998/namespace' XML_NS = 'http://www.w3.org/XML/1998/namespace'
XHTML_NS = 'http://www.w3.org/1999/xhtml' XHTML_NS = 'http://www.w3.org/1999/xhtml'
OPF1_NS = 'http://openebook.org/namespaces/oeb-package/1.0/' OPF1_NS = 'http://openebook.org/namespaces/oeb-package/1.0/'
@ -140,8 +139,7 @@ class Logger(LoggingInterface, object):
class AbstractContainer(object): class AbstractContainer(object):
def read_xml(self, path): def read_xml(self, path):
return etree.fromstring( return etree.fromstring(
self.read(path), parser=XML_PARSER, self.read(path), base_url=os.path.dirname(path))
base_url=os.path.dirname(path))
class DirContainer(AbstractContainer): class DirContainer(AbstractContainer):
def __init__(self, rootdir): def __init__(self, rootdir):
@ -334,15 +332,15 @@ class Manifest(object):
if self.oeb.encoding is not None: if self.oeb.encoding is not None:
data = data.decode(self.oeb.encoding, 'replace') data = data.decode(self.oeb.encoding, 'replace')
try: try:
data = etree.fromstring(data, parser=XML_PARSER) data = etree.fromstring(data)
except etree.XMLSyntaxError: except etree.XMLSyntaxError:
data = html.fromstring(data) data = html.fromstring(data)
data = etree.tostring(data, encoding=unicode) data = etree.tostring(data, encoding=unicode)
data = etree.fromstring(data, parser=XML_PARSER) data = etree.fromstring(data)
if namespace(data.tag) != XHTML_NS: if namespace(data.tag) != XHTML_NS:
data.attrib['xmlns'] = XHTML_NS data.attrib['xmlns'] = XHTML_NS
data = etree.tostring(data, encoding=unicode) data = etree.tostring(data, encoding=unicode)
data = etree.fromstring(data, parser=XML_PARSER) data = etree.fromstring(data)
for meta in self.META_XP(data): for meta in self.META_XP(data):
meta.getparent().remove(meta) meta.getparent().remove(meta)
return data return data
@ -355,7 +353,7 @@ class Manifest(object):
if self.media_type in OEB_DOCS: if self.media_type in OEB_DOCS:
data = self._force_xhtml(data) data = self._force_xhtml(data)
elif self.media_type[-4:] in ('+xml', '/xml'): elif self.media_type[-4:] in ('+xml', '/xml'):
data = etree.fromstring(data, parser=XML_PARSER) data = etree.fromstring(data)
self._data = data self._data = data
return data return data
def fset(self, value): def fset(self, value):
@ -788,7 +786,7 @@ class OEBBook(object):
for tag in ('manifest', 'spine', 'tours', 'guide'): for tag in ('manifest', 'spine', 'tours', 'guide'):
for element in opf.xpath(tag): for element in opf.xpath(tag):
nroot.append(element) nroot.append(element)
return etree.fromstring(etree.tostring(nroot), parser=XML_PARSER) return etree.fromstring(etree.tostring(nroot))
def _read_opf(self, opfpath): def _read_opf(self, opfpath):
opf = self.container.read_xml(opfpath) opf = self.container.read_xml(opfpath)

View File

@ -277,7 +277,10 @@ class Style(object):
def _apply_style_attr(self): def _apply_style_attr(self):
attrib = self._element.attrib attrib = self._element.attrib
if 'style' in attrib: if 'style' in attrib:
style = CSSStyleDeclaration(attrib['style']) css = attrib['style'].strip()
if css.startswith(';'):
css = css[1:]
style = CSSStyleDeclaration(css)
self._style.update(self._stylizer.flatten_style(style)) self._style.update(self._stylizer.flatten_style(style))
def _has_parent(self): def _has_parent(self):

View File

@ -6,7 +6,7 @@ from PyQt4.QtCore import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, QSiz
QByteArray, QLocale, QUrl, QTranslator, QCoreApplication, \ QByteArray, QLocale, QUrl, QTranslator, QCoreApplication, \
QModelIndex QModelIndex
from PyQt4.QtGui import QFileDialog, QMessageBox, QPixmap, QFileIconProvider, \ from PyQt4.QtGui import QFileDialog, QMessageBox, QPixmap, QFileIconProvider, \
QIcon, QTableView, QDialogButtonBox, QApplication QIcon, QTableView, QDialogButtonBox, QApplication, QDialog
ORG_NAME = 'KovidsBrain' ORG_NAME = 'KovidsBrain'
APP_UID = 'libprs500' APP_UID = 'libprs500'
@ -394,7 +394,20 @@ def pixmap_to_data(pixmap, format='JPEG'):
pixmap.save(buf, format) pixmap.save(buf, format)
return str(ba.data()) return str(ba.data())
class ResizableDialog(QDialog):
def __init__(self, *args, **kwargs):
QDialog.__init__(self, *args)
self.setupUi(self)
nh, nw = min_available_height()-25, available_width()-10
if nh < 0:
nh = 800
if nw < 0:
nw = 600
nh = min(self.height(), nh)
nw = min(self.width(), nw)
self.resize(nw, nh)
try: try:
from calibre.utils.single_qt_application import SingleApplication from calibre.utils.single_qt_application import SingleApplication
except: except:

View File

@ -14,7 +14,7 @@ from lxml.etree import XPath
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
from calibre.gui2.dialogs.epub_ui import Ui_Dialog from calibre.gui2.dialogs.epub_ui import Ui_Dialog
from calibre.gui2 import error_dialog, choose_images, pixmap_to_data from calibre.gui2 import error_dialog, choose_images, pixmap_to_data, ResizableDialog
from calibre.ebooks.epub.from_any import SOURCE_FORMATS, config as epubconfig from calibre.ebooks.epub.from_any import SOURCE_FORMATS, config as epubconfig
from calibre.ebooks.metadata import MetaInformation from calibre.ebooks.metadata import MetaInformation
from calibre.ptempfile import PersistentTemporaryFile from calibre.ptempfile import PersistentTemporaryFile
@ -22,13 +22,12 @@ from calibre.ebooks.metadata.opf import OPFCreator
from calibre.ebooks.metadata import authors_to_string, string_to_authors from calibre.ebooks.metadata import authors_to_string, string_to_authors
class Config(QDialog, Ui_Dialog): class Config(ResizableDialog, Ui_Dialog):
OUTPUT = 'EPUB' OUTPUT = 'EPUB'
def __init__(self, parent, db, row=None, config=epubconfig): def __init__(self, parent, db, row=None, config=epubconfig):
QDialog.__init__(self, parent) ResizableDialog.__init__(self, parent)
self.setupUi(self)
self.hide_controls() self.hide_controls()
self.connect(self.category_list, SIGNAL('itemEntered(QListWidgetItem *)'), self.connect(self.category_list, SIGNAL('itemEntered(QListWidgetItem *)'),
self.show_category_help) self.show_category_help)
@ -68,11 +67,11 @@ class Config(QDialog, Ui_Dialog):
self.__w.append(QIcon(':/images/dialog_information.svg')) self.__w.append(QIcon(':/images/dialog_information.svg'))
self.item1 = QListWidgetItem(self.__w[-1], _('Metadata'), self.category_list) self.item1 = QListWidgetItem(self.__w[-1], _('Metadata'), self.category_list)
self.__w.append(QIcon(':/images/lookfeel.svg')) self.__w.append(QIcon(':/images/lookfeel.svg'))
self.item2 = QListWidgetItem(self.__w[-1], _('Look & Feel'), self.category_list) self.item2 = QListWidgetItem(self.__w[-1], _('Look & Feel').replace(' ','\n'), self.category_list)
self.__w.append(QIcon(':/images/page.svg')) self.__w.append(QIcon(':/images/page.svg'))
self.item3 = QListWidgetItem(self.__w[-1], _('Page Setup'), self.category_list) self.item3 = QListWidgetItem(self.__w[-1], _('Page Setup').replace(' ','\n'), self.category_list)
self.__w.append(QIcon(':/images/chapters.svg')) self.__w.append(QIcon(':/images/chapters.svg'))
self.item4 = QListWidgetItem(self.__w[-1], _('Chapter Detection'), self.category_list) self.item4 = QListWidgetItem(self.__w[-1], _('Chapter Detection').replace(' ','\n'), self.category_list)
self.setup_tooltips() self.setup_tooltips()
self.initialize_options() self.initialize_options()
@ -98,7 +97,7 @@ class Config(QDialog, Ui_Dialog):
_('Page Setup') : _('Specify the page layout settings like margins.'), _('Page Setup') : _('Specify the page layout settings like margins.'),
_('Chapter Detection') : _('Fine tune the detection of chapter and section headings.'), _('Chapter Detection') : _('Fine tune the detection of chapter and section headings.'),
} }
self.set_help(help[text]) self.set_help(help[text.replace('\n', ' ')])
def select_cover(self): def select_cover(self):
files = choose_images(self, 'change cover dialog', files = choose_images(self, 'change cover dialog',

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ from PyQt4.QtGui import QPixmap, QListWidgetItem, QErrorMessage, QDialog, QCompl
from calibre.gui2 import qstring_to_unicode, error_dialog, file_icon_provider, \ from calibre.gui2 import qstring_to_unicode, error_dialog, file_icon_provider, \
choose_files, pixmap_to_data, choose_images choose_files, pixmap_to_data, choose_images, ResizableDialog
from calibre.gui2.dialogs.metadata_single_ui import Ui_MetadataSingleDialog from calibre.gui2.dialogs.metadata_single_ui import Ui_MetadataSingleDialog
from calibre.gui2.dialogs.fetch_metadata import FetchMetadata from calibre.gui2.dialogs.fetch_metadata import FetchMetadata
from calibre.gui2.dialogs.tag_editor import TagEditor from calibre.gui2.dialogs.tag_editor import TagEditor
@ -40,7 +40,7 @@ class AuthorCompleter(QCompleter):
all_authors.sort(cmp=lambda x, y : cmp(x[1], y[1])) all_authors.sort(cmp=lambda x, y : cmp(x[1], y[1]))
QCompleter.__init__(self, [x[1] for x in all_authors]) QCompleter.__init__(self, [x[1] for x in all_authors])
class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog): class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
def do_reset_cover(self, *args): def do_reset_cover(self, *args):
pix = QPixmap(':/images/book.svg') pix = QPixmap(':/images/book.svg')
@ -164,9 +164,7 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
self.db.remove_format(self.row, ext, notify=False) self.db.remove_format(self.row, ext, notify=False)
def __init__(self, window, row, db, accepted_callback=None): def __init__(self, window, row, db, accepted_callback=None):
QDialog.__init__(self, window) ResizableDialog.__init__(self, window)
Ui_MetadataSingleDialog.__init__(self)
self.setupUi(self)
self.bc_box.layout().setAlignment(self.cover, Qt.AlignCenter|Qt.AlignHCenter) self.bc_box.layout().setAlignment(self.cover, Qt.AlignCenter|Qt.AlignHCenter)
self.splitter.setStretchFactor(100, 1) self.splitter.setStretchFactor(100, 1)
self.db = db self.db = db

File diff suppressed because it is too large Load Diff

View File

@ -3,21 +3,20 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import time, os import time, os
from PyQt4.QtCore import SIGNAL, QUrl from PyQt4.QtCore import SIGNAL, QUrl
from PyQt4.QtGui import QDialog, QMessageBox, QDesktopServices from PyQt4.QtGui import QMessageBox, QDesktopServices
from calibre.web.feeds.recipes import compile_recipe from calibre.web.feeds.recipes import compile_recipe
from calibre.web.feeds.news import AutomaticNewsRecipe from calibre.web.feeds.news import AutomaticNewsRecipe
from calibre.gui2.dialogs.user_profiles_ui import Ui_Dialog from calibre.gui2.dialogs.user_profiles_ui import Ui_Dialog
from calibre.gui2 import qstring_to_unicode, error_dialog, question_dialog, choose_files from calibre.gui2 import qstring_to_unicode, error_dialog, question_dialog, \
choose_files, ResizableDialog
from calibre.gui2.widgets import PythonHighlighter from calibre.gui2.widgets import PythonHighlighter
from calibre.ptempfile import PersistentTemporaryFile from calibre.ptempfile import PersistentTemporaryFile
class UserProfiles(QDialog, Ui_Dialog): class UserProfiles(ResizableDialog, Ui_Dialog):
def __init__(self, parent, feeds): def __init__(self, parent, feeds):
QDialog.__init__(self, parent) ResizableDialog.__init__(self, parent)
Ui_Dialog.__init__(self)
self.setupUi(self)
self.connect(self.remove_feed_button, SIGNAL('clicked(bool)'), self.connect(self.remove_feed_button, SIGNAL('clicked(bool)'),
self.added_feeds.remove_selected_items) self.added_feeds.remove_selected_items)

View File

@ -5,8 +5,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>744</width> <width>719</width>
<height>633</height> <height>612</height>
</rect> </rect>
</property> </property>
<property name="windowTitle" > <property name="windowTitle" >
@ -16,8 +16,420 @@
<iconset resource="../images.qrc" > <iconset resource="../images.qrc" >
<normaloff>:/images/user_profile.svg</normaloff>:/images/user_profile.svg</iconset> <normaloff>:/images/user_profile.svg</normaloff>:/images/user_profile.svg</iconset>
</property> </property>
<layout class="QGridLayout" > <layout class="QVBoxLayout" name="verticalLayout_4" >
<item row="1" column="0" > <item>
<widget class="QScrollArea" name="scrollArea" >
<property name="frameShape" >
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth" >
<number>0</number>
</property>
<property name="widgetResizable" >
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>711</width>
<height>572</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3" >
<property name="margin" >
<number>0</number>
</property>
<item>
<widget class="QWidget" native="1" name="central_widget" >
<property name="minimumSize" >
<size>
<width>680</width>
<height>550</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" >
<property name="margin" >
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title" >
<string>Available user recipes</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" >
<item>
<widget class="BasicList" name="available_profiles" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Minimum" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="add_profile_button" >
<property name="text" >
<string>Add/Update &amp;recipe</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/plus.svg</normaloff>:/images/plus.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="remove_profile_button" >
<property name="text" >
<string>&amp;Remove recipe</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/list_remove.svg</normaloff>:/images/list_remove.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="share_button" >
<property name="text" >
<string>&amp;Share recipe</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/forward.svg</normaloff>:/images/forward.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="builtin_recipe_button" >
<property name="text" >
<string>Customize &amp;builtin recipe</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/news.svg</normaloff>:/images/news.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="load_button" >
<property name="text" >
<string>&amp;Load recipe from file</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/chapters.svg</normaloff>:/images/chapters.svg</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame" >
<property name="frameShape" >
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<widget class="QPushButton" name="toggle_mode_button" >
<property name="text" >
<string>Switch to Advanced mode</string>
</property>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="stacks" >
<property name="currentIndex" >
<number>0</number>
</property>
<widget class="QWidget" name="page" >
<layout class="QVBoxLayout" name="verticalLayout_5" >
<item>
<widget class="QLabel" name="label" >
<property name="text" >
<string>&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
p, li { white-space: pre-wrap; }
&lt;/style>&lt;/head>&lt;body style=" font-family:'DejaVu Sans'; font-size:10pt; font-weight:400; font-style:normal;">
&lt;p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Create a basic news recipe, by adding RSS feeds to it. &lt;br />For most feeds, you will have to use the "Advanced mode" to further customize the fetch process.&lt;/p>&lt;/body>&lt;/html></string>
</property>
<property name="textFormat" >
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Recipe &amp;title:</string>
</property>
<property name="buddy" >
<cstring>profile_title</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2" >
<widget class="QLineEdit" name="profile_title" >
<property name="font" >
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_6" >
<property name="text" >
<string>&amp;Oldest article:</string>
</property>
<property name="buddy" >
<cstring>oldest_article</cstring>
</property>
</widget>
</item>
<item row="2" column="2" >
<widget class="QSpinBox" name="oldest_article" >
<property name="toolTip" >
<string>The oldest article to download</string>
</property>
<property name="suffix" >
<string> days</string>
</property>
<property name="minimum" >
<number>1</number>
</property>
<property name="maximum" >
<number>365</number>
</property>
<property name="value" >
<number>7</number>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_7" >
<property name="text" >
<string>&amp;Max. number of articles per feed:</string>
</property>
<property name="buddy" >
<cstring>max_articles</cstring>
</property>
</widget>
</item>
<item row="3" column="2" >
<widget class="QSpinBox" name="max_articles" >
<property name="toolTip" >
<string>Maximum number of articles to download per feed.</string>
</property>
<property name="minimum" >
<number>5</number>
</property>
<property name="maximum" >
<number>100</number>
</property>
<property name="value" >
<number>10</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
<horstretch>100</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title" >
<string>Feeds in recipe</string>
</property>
<layout class="QHBoxLayout" >
<item>
<widget class="BasicList" name="added_feeds" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>100</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="selectionMode" >
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" >
<item>
<widget class="QToolButton" name="up_button" >
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/arrow-up.svg</normaloff>:/images/arrow-up.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="remove_feed_button" >
<property name="toolTip" >
<string>Remove feed from recipe</string>
</property>
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/list_remove.svg</normaloff>:/images/list_remove.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="down_button" >
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/arrow-down.svg</normaloff>:/images/arrow-down.svg</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3" >
<property name="title" >
<string>Add feed to recipe</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>&amp;Feed title:</string>
</property>
<property name="buddy" >
<cstring>feed_title</cstring>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLineEdit" name="feed_title" />
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<string>Feed &amp;URL:</string>
</property>
<property name="buddy" >
<cstring>feed_url</cstring>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLineEdit" name="feed_url" />
</item>
<item row="2" column="0" colspan="2" >
<widget class="QPushButton" name="add_feed_button" >
<property name="toolTip" >
<string>Add feed to recipe</string>
</property>
<property name="text" >
<string>&amp;Add feed</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/plus.svg</normaloff>:/images/plus.svg</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2" >
<layout class="QVBoxLayout" >
<item>
<widget class="QLabel" name="label_8" >
<property name="text" >
<string>For help with writing advanced news recipes, please visit &lt;a href="http://__appname__.kovidgoyal.net/user_manual/news.html">User Recipes&lt;/a></string>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
<property name="openExternalLinks" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4" >
<property name="title" >
<string>Recipe source code (python)</string>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="QTextEdit" name="source_code" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>100</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font" >
<font>
<family>DejaVu Sans Mono</family>
</font>
</property>
<property name="lineWrapMode" >
<enum>QTextEdit::NoWrap</enum>
</property>
<property name="acceptRichText" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</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>
@ -27,360 +439,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0" >
<widget class="QSplitter" name="splitter" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<widget class="QGroupBox" name="groupBox" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize" >
<size>
<width>215</width>
<height>16777215</height>
</size>
</property>
<property name="title" >
<string>Available user recipes</string>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="BasicList" name="available_profiles" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Minimum" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="add_profile_button" >
<property name="text" >
<string>Add/Update &amp;recipe</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/plus.svg</normaloff>:/images/plus.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="remove_profile_button" >
<property name="text" >
<string>&amp;Remove recipe</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/list_remove.svg</normaloff>:/images/list_remove.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="share_button" >
<property name="text" >
<string>&amp;Share recipe</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/forward.svg</normaloff>:/images/forward.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="builtin_recipe_button" >
<property name="text" >
<string>Customize &amp;builtin recipe</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/news.svg</normaloff>:/images/news.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="load_button" >
<property name="text" >
<string>&amp;Load recipe from file</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/chapters.svg</normaloff>:/images/chapters.svg</iconset>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget" >
<layout class="QVBoxLayout" >
<item>
<widget class="QPushButton" name="toggle_mode_button" >
<property name="text" >
<string>Switch to Advanced mode</string>
</property>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="stacks" >
<property name="currentIndex" >
<number>0</number>
</property>
<widget class="QWidget" name="page" >
<layout class="QVBoxLayout" >
<item>
<widget class="QLabel" name="label" >
<property name="text" >
<string>&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
p, li { white-space: pre-wrap; }
&lt;/style>&lt;/head>&lt;body style=" font-family:'DejaVu Sans'; font-size:10pt; font-weight:400; font-style:normal;">
&lt;p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Create a basic news recipe, by adding RSS feeds to it. &lt;br />For most feeds, you will have to use the "Advanced mode" to further customize the fetch process.&lt;/p>&lt;/body>&lt;/html></string>
</property>
<property name="textFormat" >
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Recipe &amp;title:</string>
</property>
<property name="buddy" >
<cstring>profile_title</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2" >
<widget class="QLineEdit" name="profile_title" >
<property name="font" >
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_6" >
<property name="text" >
<string>&amp;Oldest article:</string>
</property>
<property name="buddy" >
<cstring>oldest_article</cstring>
</property>
</widget>
</item>
<item row="2" column="2" >
<widget class="QSpinBox" name="oldest_article" >
<property name="toolTip" >
<string>The oldest article to download</string>
</property>
<property name="suffix" >
<string> days</string>
</property>
<property name="minimum" >
<number>1</number>
</property>
<property name="maximum" >
<number>365</number>
</property>
<property name="value" >
<number>7</number>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_7" >
<property name="text" >
<string>&amp;Max. number of articles per feed:</string>
</property>
<property name="buddy" >
<cstring>max_articles</cstring>
</property>
</widget>
</item>
<item row="3" column="2" >
<widget class="QSpinBox" name="max_articles" >
<property name="toolTip" >
<string>Maximum number of articles to download per feed.</string>
</property>
<property name="minimum" >
<number>5</number>
</property>
<property name="maximum" >
<number>100</number>
</property>
<property name="value" >
<number>10</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<string>Feeds in recipe</string>
</property>
<layout class="QHBoxLayout" >
<item>
<widget class="BasicList" name="added_feeds" >
<property name="selectionMode" >
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" >
<item>
<widget class="QToolButton" name="up_button" >
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/arrow-up.svg</normaloff>:/images/arrow-up.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="remove_feed_button" >
<property name="toolTip" >
<string>Remove feed from recipe</string>
</property>
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/list_remove.svg</normaloff>:/images/list_remove.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="down_button" >
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/arrow-down.svg</normaloff>:/images/arrow-down.svg</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3" >
<property name="title" >
<string>Add feed to recipe</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>&amp;Feed title:</string>
</property>
<property name="buddy" >
<cstring>feed_title</cstring>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLineEdit" name="feed_title" />
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<string>Feed &amp;URL:</string>
</property>
<property name="buddy" >
<cstring>feed_url</cstring>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLineEdit" name="feed_url" />
</item>
<item row="2" column="0" colspan="2" >
<widget class="QPushButton" name="add_feed_button" >
<property name="toolTip" >
<string>Add feed to recipe</string>
</property>
<property name="text" >
<string>&amp;Add feed</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/plus.svg</normaloff>:/images/plus.svg</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2" >
<layout class="QVBoxLayout" >
<item>
<widget class="QLabel" name="label_8" >
<property name="text" >
<string>For help with writing advanced news recipes, please visit &lt;a href="http://__appname__.kovidgoyal.net/user_manual/news.html">User Recipes&lt;/a></string>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
<property name="openExternalLinks" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4" >
<property name="title" >
<string>Recipe source code (python)</string>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="QTextEdit" name="source_code" >
<property name="font" >
<font>
<family>DejaVu Sans Mono</family>
</font>
</property>
<property name="lineWrapMode" >
<enum>QTextEdit::NoWrap</enum>
</property>
<property name="acceptRichText" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>

View File

@ -134,16 +134,8 @@ class Main(MainWindow, Ui_MainWindow):
for f in self.output_formats: for f in self.output_formats:
self.output_format.addItem(f) self.output_format.addItem(f)
self.output_format.setCurrentIndex(self.output_formats.index(prefs['output_format'])) self.output_format.setCurrentIndex(self.output_formats.index(prefs['output_format']))
def change_output_format(x):
of = unicode(x).strip()
if of != prefs['output_format']:
if of not in ('LRF',):
warning_dialog(self, 'Warning',
'<p>%s support is still in beta. If you find bugs, please report them by opening a <a href="http://calibre.kovidgoyal.net">ticket</a>.'%of).exec_()
prefs.set('output_format', of)
self.connect(self.output_format, SIGNAL('currentIndexChanged(QString)'), self.connect(self.output_format, SIGNAL('currentIndexChanged(QString)'),
change_output_format) self.change_output_format, Qt.QueuedConnection)
####################### Vanity ######################## ####################### Vanity ########################
self.vanity_template = _('<p>For help visit <a href="http://%s.kovidgoyal.net/user_manual">%s.kovidgoyal.net</a><br>')%(__appname__, __appname__) self.vanity_template = _('<p>For help visit <a href="http://%s.kovidgoyal.net/user_manual">%s.kovidgoyal.net</a><br>')%(__appname__, __appname__)
@ -376,6 +368,15 @@ class Main(MainWindow, Ui_MainWindow):
self.action_news.setMenu(self.scheduler.news_menu) self.action_news.setMenu(self.scheduler.news_menu)
self.connect(self.action_news, SIGNAL('triggered(bool)'), self.scheduler.show_dialog) self.connect(self.action_news, SIGNAL('triggered(bool)'), self.scheduler.show_dialog)
self.location_view.setCurrentIndex(self.location_view.model().index(0)) self.location_view.setCurrentIndex(self.location_view.model().index(0))
def change_output_format(self, x):
of = unicode(x).strip()
if of != prefs['output_format']:
if of not in ('LRF',):
warning_dialog(self, 'Warning',
'<p>%s support is still in beta. If you find bugs, please report them by opening a <a href="http://calibre.kovidgoyal.net">ticket</a>.'%of).exec_()
prefs.set('output_format', of)
def test_server(self, *args): def test_server(self, *args):
if self.content_server.exception is not None: if self.content_server.exception is not None:

View File

@ -11,7 +11,7 @@ class FazNet(BasicNewsRecipe):
title = 'FAZ NET' title = 'FAZ NET'
__author__ = 'Kovid Goyal' __author__ = 'Kovid Goyal'
description = 'News from Germany' description = '"Frankfurter Allgemeine Zeitung'
use_embedded_content = False use_embedded_content = False
max_articles_per_feed = 30 max_articles_per_feed = 30

View File

@ -13,7 +13,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
class SpeigelOnline(BasicNewsRecipe): class SpeigelOnline(BasicNewsRecipe):
title = 'Spiegel Online' title = 'Spiegel Online'
description = 'News from Germany' description = 'Nachrichten des Magazins Der Spiegel'
__author__ = 'Kovid Goyal' __author__ = 'Kovid Goyal'
use_embedded_content = False use_embedded_content = False
timefmt = ' [ %Y-%m-%d %a]' timefmt = ' [ %Y-%m-%d %a]'

View File

@ -11,7 +11,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
class ZeitDe(BasicNewsRecipe): class ZeitDe(BasicNewsRecipe):
title = 'Die Zeit Nachrichten' title = 'Die Zeit Nachrichten'
description = 'News from Germany' description = 'Die Zeit - Online Nachrichten'
__author__ = 'Kovid Goyal' __author__ = 'Kovid Goyal'
use_embedded_content = False use_embedded_content = False
timefmt = ' [%d %b %Y]' timefmt = ' [%d %b %Y]'

View File

@ -407,6 +407,7 @@ class RecursiveFetcher(object, LoggingInterface):
if not isinstance(_fname, unicode): if not isinstance(_fname, unicode):
_fname.decode('latin1', 'replace') _fname.decode('latin1', 'replace')
_fname = _fname.encode('ascii', 'replace').replace('%', '').replace(os.sep, '') _fname = _fname.encode('ascii', 'replace').replace('%', '').replace(os.sep, '')
_fname = sanitize_file_name(_fname)
res = os.path.join(linkdiskpath, _fname) res = os.path.join(linkdiskpath, _fname)
self.downloaded_paths.append(res) self.downloaded_paths.append(res)
self.filemap[nurl] = res self.filemap[nurl] = res