6
from PyQt4.Qt import SIGNAL, QUrl, QAbstractListModel, Qt, \
6
from PyQt4.Qt import (QUrl, QAbstractListModel, Qt, QVariant, QFont)
9
8
from calibre.web.feeds.recipes import compile_recipe, custom_recipes
10
9
from calibre.web.feeds.news import AutomaticNewsRecipe
11
10
from calibre.gui2.dialogs.user_profiles_ui import Ui_Dialog
12
from calibre.gui2 import error_dialog, question_dialog, open_url, \
13
choose_files, ResizableDialog, NONE, open_local_file
11
from calibre.gui2 import (
12
error_dialog, question_dialog, open_url, choose_files, ResizableDialog,
13
NONE, open_local_file)
14
14
from calibre.gui2.widgets import PythonHighlighter
15
15
from calibre.ptempfile import PersistentTemporaryFile
16
16
from calibre.utils.icu import sort_key
60
60
self.recipe_model.update_custom_recipe(urn, title, script)
63
def replace_many_by_title(self, scriptmap):
65
for title, script in scriptmap.iteritems():
67
for x in self.recipe_model.custom_recipe_collection:
68
if x.get('title', False) == title:
71
script_urn_map.update({urn: (title, script)})
74
self.recipe_model.update_custom_recipes(script_urn_map)
63
77
def add(self, title, script):
64
78
self.recipe_model.add_custom_recipe(title, script)
81
def add_many(self, scriptmap):
82
self.recipe_model.add_custom_recipes(scriptmap)
67
85
def remove(self, rows):
87
105
f.setStyleHint(f.Monospace)
88
106
self.source_code.setFont(f)
90
self.connect(self.remove_feed_button, SIGNAL('clicked(bool)'),
91
self.added_feeds.remove_selected_items)
92
self.connect(self.remove_profile_button, SIGNAL('clicked(bool)'),
93
self.remove_selected_items)
94
self.connect(self.add_feed_button, SIGNAL('clicked(bool)'),
96
self.connect(self.load_button, SIGNAL('clicked()'), self.load)
97
self.connect(self.builtin_recipe_button, SIGNAL('clicked()'), self.add_builtin_recipe)
98
self.connect(self.share_button, SIGNAL('clicked()'), self.share)
108
self.remove_feed_button.clicked[(bool)].connect(self.added_feeds.remove_selected_items)
109
self.remove_profile_button.clicked[(bool)].connect(self.remove_selected_items)
110
self.add_feed_button.clicked[(bool)].connect(self.add_feed)
111
self.load_button.clicked[()].connect(self.load)
112
self.opml_button.clicked[()].connect(self.opml_import)
113
self.builtin_recipe_button.clicked[()].connect(self.add_builtin_recipe)
114
self.share_button.clicked[()].connect(self.share)
99
115
self.show_recipe_files_button.clicked.connect(self.show_recipe_files)
100
self.connect(self.down_button, SIGNAL('clicked()'), self.down)
101
self.connect(self.up_button, SIGNAL('clicked()'), self.up)
102
self.connect(self.add_profile_button, SIGNAL('clicked(bool)'),
104
self.connect(self.feed_url, SIGNAL('returnPressed()'), self.add_feed)
105
self.connect(self.feed_title, SIGNAL('returnPressed()'), self.add_feed)
106
self.connect(self.toggle_mode_button, SIGNAL('clicked(bool)'), self.toggle_mode)
116
self.down_button.clicked[()].connect(self.down)
117
self.up_button.clicked[()].connect(self.up)
118
self.add_profile_button.clicked[(bool)].connect(self.add_profile)
119
self.feed_url.returnPressed[()].connect(self.add_feed)
120
self.feed_title.returnPressed[()].connect(self.add_feed)
121
self.toggle_mode_button.clicked[(bool)].connect(self.toggle_mode)
109
124
def show_recipe_files(self, *args):
156
171
url.addQueryItem('attachment', pt.name)
160
174
def current_changed(self, current, previous):
161
if not current.isValid(): return
175
if not current.isValid():
162
177
src = self._model.script(current)
207
221
self.feed_title.setText('')
208
222
self.feed_url.setText('')
210
def options_to_profile(self):
224
def options_to_profile(self, **kw):
211
225
classname = 'BasicUserRecipe'+str(int(time.time()))
212
title = unicode(self.profile_title.text()).strip()
226
title = kw.get('title', self.profile_title.text())
227
title = unicode(title).strip()
214
229
title = classname
215
230
self.profile_title.setText(title)
216
oldest_article = self.oldest_article.value()
217
max_articles = self.max_articles.value()
218
feeds = [i.user_data for i in self.added_feeds.items()]
231
oldest_article = kw.get('oldest_article', self.oldest_article.value())
232
max_articles = kw.get('max_articles', self.max_articles.value())
233
feeds = kw.get('feeds',
234
[i.user_data for i in self.added_feeds.items()])
221
237
class %(classname)s(%(base_class)s):
354
368
self.model.add(title, profile)
371
def opml_import(self):
372
from calibre.gui2.dialogs.opml import ImportOPML
373
d = ImportOPML(parent=self)
374
if d.exec_() != d.Accepted:
376
oldest_article, max_articles_per_feed, replace_existing = d.oldest_article, d.articles_per_feed, d.replace_existing
377
failed_recipes, replace_recipes, add_recipes = {}, {}, {}
379
for group in d.recipes:
380
title = base_title = group.title or _('Unknown')
381
if not replace_existing:
383
while self._model.has_title(title):
385
title = u'%s %d' % (base_title, c)
386
src, title = self.options_to_profile(**{
389
'oldest_article':oldest_article,
390
'max_articles':max_articles_per_feed,
396
failed_recipes[title] = traceback.format_exc()
399
if replace_existing and self._model.has_title(title):
400
replace_recipes[title] = src
402
add_recipes[title] = src
405
self.model.add_many(add_recipes)
407
self.model.replace_many_by_title(replace_recipes)
409
det_msg = '\n'.join('%s\n%s\n' % (title, tb) for title, tb in failed_recipes.iteritems())
410
error_dialog(self, _('Failed to create recipes'), _(
411
'Failed to create some recipes, click "Show details" for details'), show=True,
357
415
def populate_options(self, profile):
358
416
self.oldest_article.setValue(profile.oldest_article)
359
417
self.max_articles.setValue(profile.max_articles_per_feed)