~ubuntu-branches/debian/sid/calibre/sid

« back to all changes in this revision

Viewing changes to src/calibre/gui2/dialogs/user_profiles.py

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2014-05-14 18:17:50 UTC
  • mto: This revision was merged to the branch mainline in revision 75.
  • Revision ID: package-import@ubuntu.com-20140514181750-efj1wymey2vb4cao
Tags: upstream-1.36.0+dfsg
ImportĀ upstreamĀ versionĀ 1.36.0+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
 
4
4
import time, os
5
5
 
6
 
from PyQt4.Qt import SIGNAL, QUrl, QAbstractListModel, Qt, \
7
 
        QVariant, QFont
 
6
from PyQt4.Qt import (QUrl, QAbstractListModel, Qt, QVariant, QFont)
8
7
 
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)
61
61
            self.reset()
62
62
 
 
63
    def replace_many_by_title(self, scriptmap):
 
64
        script_urn_map = {}
 
65
        for title, script in scriptmap.iteritems():
 
66
            urn = None
 
67
            for x in self.recipe_model.custom_recipe_collection:
 
68
                if x.get('title', False) == title:
 
69
                    urn = x.get('id')
 
70
            if urn is not None:
 
71
                script_urn_map.update({urn: (title, script)})
 
72
 
 
73
        if script_urn_map:
 
74
            self.recipe_model.update_custom_recipes(script_urn_map)
 
75
            self.reset()
 
76
 
63
77
    def add(self, title, script):
64
78
        self.recipe_model.add_custom_recipe(title, script)
65
79
        self.reset()
66
80
 
 
81
    def add_many(self, scriptmap):
 
82
        self.recipe_model.add_custom_recipes(scriptmap)
 
83
        self.reset()
 
84
 
67
85
    def remove(self, rows):
68
86
        urns = []
69
87
        for r in rows:
87
105
        f.setStyleHint(f.Monospace)
88
106
        self.source_code.setFont(f)
89
107
 
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)'),
95
 
                     self.add_feed)
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)'),
103
 
                     self.add_profile)
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)
107
122
        self.clear()
108
123
 
109
124
    def show_recipe_files(self, *args):
156
171
        url.addQueryItem('attachment', pt.name)
157
172
        open_url(url)
158
173
 
159
 
 
160
174
    def current_changed(self, current, previous):
161
 
        if not current.isValid(): return
 
175
        if not current.isValid():
 
176
            return
162
177
        src = self._model.script(current)
163
178
        if src is None:
164
179
            return
186
201
                self.source_code.setPlainText(src.replace('BasicUserRecipe', 'AdvancedUserRecipe'))
187
202
                self.highlighter = PythonHighlighter(self.source_code.document())
188
203
 
189
 
 
190
204
    def add_feed(self, *args):
191
205
        title = unicode(self.feed_title.text()).strip()
192
206
        if not title:
207
221
        self.feed_title.setText('')
208
222
        self.feed_url.setText('')
209
223
 
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()
213
228
        if not title:
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()])
219
235
 
220
236
        src = '''\
221
237
class %(classname)s(%(base_class)s):
231
247
                 base_class='AutomaticNewsRecipe')
232
248
        return src, title
233
249
 
234
 
 
235
250
    def populate_source_code(self):
236
251
        src = self.options_to_profile().replace('BasicUserRecipe', 'AdvancedUserRecipe')
237
252
        self.source_code.setPlainText(src)
328
343
 
329
344
        self.clear()
330
345
 
331
 
 
332
346
    def load(self):
333
347
        files = choose_files(self, 'recipe loader dialog',
334
348
            _('Choose a recipe file'),
354
368
                self.model.add(title, profile)
355
369
            self.clear()
356
370
 
 
371
    def opml_import(self):
 
372
        from calibre.gui2.dialogs.opml import ImportOPML
 
373
        d = ImportOPML(parent=self)
 
374
        if d.exec_() != d.Accepted:
 
375
            return
 
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 = {}, {}, {}
 
378
 
 
379
        for group in d.recipes:
 
380
            title = base_title = group.title or _('Unknown')
 
381
            if not replace_existing:
 
382
                c = 0
 
383
                while self._model.has_title(title):
 
384
                    c += 1
 
385
                    title = u'%s %d' % (base_title, c)
 
386
            src, title = self.options_to_profile(**{
 
387
                    'title':title,
 
388
                    'feeds':group.feeds,
 
389
                    'oldest_article':oldest_article,
 
390
                    'max_articles':max_articles_per_feed,
 
391
                })
 
392
            try:
 
393
                compile_recipe(src)
 
394
            except Exception:
 
395
                import traceback
 
396
                failed_recipes[title] = traceback.format_exc()
 
397
                continue
 
398
 
 
399
            if replace_existing and self._model.has_title(title):
 
400
                replace_recipes[title] = src
 
401
            else:
 
402
                add_recipes[title] = src
 
403
 
 
404
        if add_recipes:
 
405
            self.model.add_many(add_recipes)
 
406
        if replace_recipes:
 
407
            self.model.replace_many_by_title(replace_recipes)
 
408
        if failed_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,
 
412
                         det_msg=det_msg)
 
413
        self.clear()
 
414
 
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)
365
423
        self.feed_title.setText('')
366
424
        self.feed_url.setText('')
367
425
 
368
 
 
369
426
    def clear(self):
370
427
        self.populate_options(AutomaticNewsRecipe)
371
428
        self.source_code.setText('')