home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_1285 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  13.8 KB  |  332 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __license__ = 'GPL v3'
  5. __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
  6. import time
  7. import os
  8. from PyQt4.Qt import SIGNAL, QUrl, QAbstractListModel, Qt, QVariant, QInputDialog
  9. from calibre.web.feeds.recipes import compile_recipe
  10. from calibre.web.feeds.news import AutomaticNewsRecipe
  11. from calibre.gui2.dialogs.user_profiles_ui import Ui_Dialog
  12. from calibre.gui2 import error_dialog, question_dialog, open_url, choose_files, ResizableDialog, NONE
  13. from calibre.gui2.widgets import PythonHighlighter
  14. from calibre.ptempfile import PersistentTemporaryFile
  15.  
  16. class CustomRecipeModel(QAbstractListModel):
  17.     
  18.     def __init__(self, recipe_model):
  19.         QAbstractListModel.__init__(self)
  20.         self.recipe_model = recipe_model
  21.  
  22.     
  23.     def title(self, index):
  24.         row = index.row()
  25.         if row > -1 and row < self.rowCount():
  26.             return self.recipe_model.custom_recipe_collection[row].get('title', '')
  27.  
  28.     
  29.     def script(self, index):
  30.         row = index.row()
  31.         if row > -1 and row < self.rowCount():
  32.             urn = self.recipe_model.custom_recipe_collection[row].get('id')
  33.             return self.recipe_model.get_recipe(urn)
  34.  
  35.     
  36.     def has_title(self, title):
  37.         for x in self.recipe_model.custom_recipe_collection:
  38.             if x.get('title', False) == title:
  39.                 return True
  40.         
  41.         return False
  42.  
  43.     
  44.     def rowCount(self, *args):
  45.         return len(self.recipe_model.custom_recipe_collection)
  46.  
  47.     
  48.     def data(self, index, role):
  49.         if role == Qt.DisplayRole:
  50.             ans = self.title(index)
  51.             if ans is not None:
  52.                 return QVariant(ans)
  53.         
  54.         return NONE
  55.  
  56.     
  57.     def replace_by_title(self, title, script):
  58.         urn = None
  59.         for x in self.recipe_model.custom_recipe_collection:
  60.             if x.get('title', False) == title:
  61.                 urn = x.get('id')
  62.                 continue
  63.         
  64.         if urn is not None:
  65.             self.recipe_model.update_custom_recipe(urn, title, script)
  66.             self.reset()
  67.         
  68.  
  69.     
  70.     def add(self, title, script):
  71.         self.recipe_model.add_custom_recipe(title, script)
  72.         self.reset()
  73.  
  74.     
  75.     def remove(self, rows):
  76.         urns = []
  77.         for r in rows:
  78.             
  79.             try:
  80.                 urn = self.recipe_model.custom_recipe_collection[r].get('id')
  81.                 urns.append(urn)
  82.             continue
  83.             continue
  84.  
  85.         
  86.         self.recipe_model.remove_custom_recipes(urns)
  87.         self.reset()
  88.  
  89.  
  90.  
  91. class UserProfiles(ResizableDialog, Ui_Dialog):
  92.     
  93.     def __init__(self, parent, recipe_model):
  94.         ResizableDialog.__init__(self, parent)
  95.         self._model = self.model = CustomRecipeModel(recipe_model)
  96.         self.available_profiles.setModel(self._model)
  97.         self.available_profiles.currentChanged = self.current_changed
  98.         self.connect(self.remove_feed_button, SIGNAL('clicked(bool)'), self.added_feeds.remove_selected_items)
  99.         self.connect(self.remove_profile_button, SIGNAL('clicked(bool)'), self.remove_selected_items)
  100.         self.connect(self.add_feed_button, SIGNAL('clicked(bool)'), self.add_feed)
  101.         self.connect(self.load_button, SIGNAL('clicked()'), self.load)
  102.         self.connect(self.builtin_recipe_button, SIGNAL('clicked()'), self.add_builtin_recipe)
  103.         self.connect(self.share_button, SIGNAL('clicked()'), self.share)
  104.         self.connect(self.down_button, SIGNAL('clicked()'), self.down)
  105.         self.connect(self.up_button, SIGNAL('clicked()'), self.up)
  106.         self.connect(self.add_profile_button, SIGNAL('clicked(bool)'), self.add_profile)
  107.         self.connect(self.feed_url, SIGNAL('returnPressed()'), self.add_feed)
  108.         self.connect(self.feed_title, SIGNAL('returnPressed()'), self.add_feed)
  109.         self.connect(self.toggle_mode_button, SIGNAL('clicked(bool)'), self.toggle_mode)
  110.         self.clear()
  111.  
  112.     
  113.     def break_cycles(self):
  114.         self.recipe_model = None
  115.         self._model.recipe_model = None
  116.  
  117.     
  118.     def remove_selected_items(self):
  119.         indices = self.available_profiles.selectionModel().selectedRows()
  120.         []([ i.row() for i in indices ])
  121.         self.clear()
  122.  
  123.     
  124.     def up(self):
  125.         row = self.added_feeds.currentRow()
  126.         item = self.added_feeds.takeItem(row)
  127.         if item is not None:
  128.             self.added_feeds.insertItem(max(row - 1, 0), item)
  129.             self.added_feeds.setCurrentItem(item)
  130.         
  131.  
  132.     
  133.     def down(self):
  134.         row = self.added_feeds.currentRow()
  135.         item = self.added_feeds.takeItem(row)
  136.         if item is not None:
  137.             self.added_feeds.insertItem(row + 1, item)
  138.             self.added_feeds.setCurrentItem(item)
  139.         
  140.  
  141.     
  142.     def share(self):
  143.         index = self.available_profiles.currentIndex()
  144.         title = self._model.title(index)
  145.         src = self._model.script(index)
  146.         if not title or not src:
  147.             error_dialog(self, _('No recipe selected'), _('No recipe selected')).exec_()
  148.             return None
  149.         pt = PersistentTemporaryFile(suffix = '.recipe')
  150.         pt.write(src.encode('utf-8'))
  151.         pt.close()
  152.         body = _('The attached file: %s is a recipe to download %s.') % (os.path.basename(pt.name), title)
  153.         subject = _('Recipe for ') + title
  154.         url = QUrl('mailto:')
  155.         url.addQueryItem('subject', subject)
  156.         url.addQueryItem('body', body)
  157.         url.addQueryItem('attachment', pt.name)
  158.         open_url(url)
  159.  
  160.     
  161.     def current_changed(self, current, previous):
  162.         if not current.isValid():
  163.             return None
  164.         src = self._model.script(current)
  165.         if src is None:
  166.             return None
  167.  
  168.     
  169.     def toggle_mode(self, *args):
  170.         if self.stacks.currentIndex() == 1:
  171.             self.stacks.setCurrentIndex(0)
  172.             self.toggle_mode_button.setText(_('Switch to Advanced mode'))
  173.         else:
  174.             self.stacks.setCurrentIndex(1)
  175.             self.toggle_mode_button.setText(_('Switch to Basic mode'))
  176.             if not unicode(self.source_code.toPlainText()).strip():
  177.                 src = self.options_to_profile()[0].replace('AutomaticNewsRecipe', 'BasicNewsRecipe')
  178.                 self.source_code.setPlainText(src.replace('BasicUserRecipe', 'AdvancedUserRecipe'))
  179.                 self.highlighter = PythonHighlighter(self.source_code.document())
  180.             
  181.  
  182.     
  183.     def add_feed(self, *args):
  184.         title = unicode(self.feed_title.text()).strip()
  185.         if not title:
  186.             error_dialog(self, _('Feed must have a title'), _('The feed must have a title')).exec_()
  187.             return None
  188.         url = unicode(self.feed_url.text()).strip()
  189.         if not url:
  190.             error_dialog(self, _('Feed must have a URL'), _('The feed %s must have a URL') % title).exec_()
  191.             return None
  192.         
  193.         try:
  194.             self.added_feeds.add_item(title + ' - ' + url, (title, url))
  195.         except ValueError:
  196.             url
  197.             url
  198.             title
  199.             error_dialog(self, _('Already exists'), _('This feed has already been added to the recipe')).exec_()
  200.             return None
  201.  
  202.         self.feed_title.setText('')
  203.         self.feed_url.setText('')
  204.  
  205.     
  206.     def options_to_profile(self):
  207.         classname = 'BasicUserRecipe' + str(int(time.time()))
  208.         title = unicode(self.profile_title.text()).strip()
  209.         if not title:
  210.             title = classname
  211.         
  212.         self.profile_title.setText(title)
  213.         oldest_article = self.oldest_article.value()
  214.         max_articles = self.max_articles.value()
  215.         feeds = [ i.user_data for i in self.added_feeds.items() ]
  216.         src = 'class %(classname)s(%(base_class)s):\n    title          = %(title)s\n    oldest_article = %(oldest_article)d\n    max_articles_per_feed = %(max_articles)d\n\n    feeds          = %(feeds)s\n' % dict(classname = classname, title = repr(title), feeds = repr(feeds), oldest_article = oldest_article, max_articles = max_articles, base_class = 'AutomaticNewsRecipe')
  217.         return (src, title)
  218.  
  219.     
  220.     def populate_source_code(self):
  221.         src = self.options_to_profile().replace('BasicUserRecipe', 'AdvancedUserRecipe')
  222.         self.source_code.setPlainText(src)
  223.         self.highlighter = PythonHighlighter(self.source_code.document())
  224.  
  225.     
  226.     def add_profile(self, clicked):
  227.         if self.stacks.currentIndex() == 0:
  228.             (src, title) = self.options_to_profile()
  229.             
  230.             try:
  231.                 compile_recipe(src)
  232.             except Exception:
  233.                 err = None
  234.                 error_dialog(self, _('Invalid input'), _('<p>Could not create recipe. Error:<br>%s') % str(err)).exec_()
  235.                 return None
  236.  
  237.             profile = src
  238.         else:
  239.             src = unicode(self.source_code.toPlainText())
  240.             
  241.             try:
  242.                 title = compile_recipe(src).title
  243.             except Exception:
  244.                 err = None
  245.                 error_dialog(self, _('Invalid input'), _('<p>Could not create recipe. Error:<br>%s') % str(err)).exec_()
  246.                 return None
  247.  
  248.             profile = src.replace('BasicUserRecipe', 'AdvancedUserRecipe')
  249.         if self._model.has_title(title):
  250.             if question_dialog(self, _('Replace recipe?'), _('A custom recipe named %s already exists. Do you want to replace it?') % title):
  251.                 self._model.replace_by_title(title, profile)
  252.             else:
  253.                 return None
  254.         question_dialog(self, _('Replace recipe?'), _('A custom recipe named %s already exists. Do you want to replace it?') % title)
  255.         self.model.add(title, profile)
  256.         self.clear()
  257.  
  258.     
  259.     def add_builtin_recipe(self):
  260.         get_builtin_recipe_by_title = get_builtin_recipe_by_title
  261.         get_builtin_recipe_titles = get_builtin_recipe_titles
  262.         import calibre.web.feeds.recipes.collection
  263.         items = sorted(get_builtin_recipe_titles())
  264.         (title, ok) = QInputDialog.getItem(self, _('Pick recipe'), _('Pick the recipe to customize'), items, 0, False)
  265.         if ok:
  266.             title = unicode(title)
  267.             profile = get_builtin_recipe_by_title(title)
  268.             if self._model.has_title(title):
  269.                 if question_dialog(self, _('Replace recipe?'), _('A custom recipe named %s already exists. Do you want to replace it?') % title):
  270.                     self._model.replace_by_title(title, profile)
  271.                 else:
  272.                     return None
  273.             question_dialog(self, _('Replace recipe?'), _('A custom recipe named %s already exists. Do you want to replace it?') % title)
  274.             self.model.add(title, profile)
  275.         
  276.         self.clear()
  277.  
  278.     
  279.     def load(self):
  280.         files = choose_files(self, 'recipe loader dialog', _('Choose a recipe file'), filters = [
  281.             (_('Recipes'), [
  282.                 '.py',
  283.                 '.recipe'])], all_files = False, select_only_single_file = True)
  284.         if files:
  285.             file = files[0]
  286.             
  287.             try:
  288.                 profile = open(file, 'rb').read().decode('utf-8')
  289.                 title = compile_recipe(profile).title
  290.             except Exception:
  291.                 err = None
  292.                 error_dialog(self, _('Invalid input'), _('<p>Could not create recipe. Error:<br>%s') % str(err)).exec_()
  293.                 return None
  294.  
  295.             if self._model.has_title(title):
  296.                 if question_dialog(self, _('Replace recipe?'), _('A custom recipe named %s already exists. Do you want to replace it?') % title):
  297.                     self._model.replace_by_title(title, profile)
  298.                 else:
  299.                     return None
  300.             question_dialog(self, _('Replace recipe?'), _('A custom recipe named %s already exists. Do you want to replace it?') % title)
  301.             self.model.add(title, profile)
  302.             self.clear()
  303.         
  304.  
  305.     
  306.     def populate_options(self, profile):
  307.         self.oldest_article.setValue(profile.oldest_article)
  308.         self.max_articles.setValue(profile.max_articles_per_feed)
  309.         self.profile_title.setText(profile.title)
  310.         self.added_feeds.clear()
  311.         feeds = None if profile.feeds is None else profile.feeds
  312.         for title, url in feeds:
  313.             self.added_feeds.add_item(title + ' - ' + url, (title, url))
  314.         
  315.         self.feed_title.setText('')
  316.         self.feed_url.setText('')
  317.  
  318.     
  319.     def clear(self):
  320.         self.populate_options(AutomaticNewsRecipe)
  321.         self.source_code.setText('')
  322.  
  323.  
  324. if __name__ == '__main__':
  325.     from calibre.gui2 import is_ok_to_use_qt
  326.     is_ok_to_use_qt()
  327.     from calibre.library.database2 import LibraryDatabase2
  328.     from calibre.web.feeds.recipes.model import RecipeModel
  329.     d = UserProfiles(None, RecipeModel(LibraryDatabase2('/home/kovid/documents/library')))
  330.     d.exec_()
  331.  
  332.