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