home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 January / maximum-cd-2011-01.iso / DiscContents / calibre-0.7.26.msi / file_1290 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-10-31  |  14.7 KB  |  379 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. from __future__ import with_statement
  5. __license__ = 'GPL v3'
  6. __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
  7. __docformat__ = 'restructuredtext en'
  8. from datetime import timedelta
  9. from PyQt4.Qt import QDialog, SIGNAL, Qt, QTime, QObject, QMenu, QAction, QIcon, QMutex, QTimer, pyqtSignal
  10. from calibre.gui2.dialogs.scheduler_ui import Ui_Dialog
  11. from calibre.gui2.search_box import SearchBox2
  12. from calibre.gui2 import config as gconf, error_dialog
  13. from calibre.web.feeds.recipes.model import RecipeModel
  14. from calibre.ptempfile import PersistentTemporaryFile
  15. from calibre.utils.date import utcnow
  16. from calibre.utils.network import internet_connected
  17.  
  18. class SchedulerDialog(QDialog, Ui_Dialog):
  19.     
  20.     def __init__(self, recipe_model, parent = None):
  21.         QDialog.__init__(self, parent)
  22.         self.setupUi(self)
  23.         self.recipe_model = recipe_model
  24.         self.recipe_model.do_refresh()
  25.         self.search = SearchBox2(self)
  26.         self.search.setMinimumContentsLength(25)
  27.         self.search.initialize('scheduler_search_history')
  28.         self.recipe_box.layout().insertWidget(0, self.search)
  29.         self.search.search.connect(self.recipe_model.search)
  30.         self.connect(self.recipe_model, SIGNAL('searched(PyQt_PyObject)'), self.search.search_done)
  31.         self.connect(self.recipe_model, SIGNAL('searched(PyQt_PyObject)'), self.search_done)
  32.         self.search.setFocus(Qt.OtherFocusReason)
  33.         self.commit_on_change = True
  34.         self.recipes.setModel(self.recipe_model)
  35.         self.detail_box.setVisible(False)
  36.         self.download_button.setVisible(False)
  37.         self.recipes.currentChanged = self.current_changed
  38.         self.interval_button.setChecked(True)
  39.         self.connect(self.schedule, SIGNAL('stateChanged(int)'), self.toggle_schedule_info)
  40.         self.connect(self.show_password, (SIGNAL('stateChanged(int)'),), (lambda state: None(self.password.setEchoMode if state == Qt.Checked else self.password.Password)))
  41.         self.connect(self.download_button, SIGNAL('clicked()'), self.download_clicked)
  42.         self.connect(self.download_all_button, SIGNAL('clicked()'), self.download_all_clicked)
  43.         self.old_news.setValue(gconf['oldest_news'])
  44.  
  45.     
  46.     def keyPressEvent(self, ev):
  47.         if ev.key() not in (Qt.Key_Enter, Qt.Key_Return):
  48.             return QDialog.keyPressEvent(self, ev)
  49.  
  50.     
  51.     def break_cycles(self):
  52.         self.disconnect(self.recipe_model, SIGNAL('searched(PyQt_PyObject)'), self.search_done)
  53.         self.disconnect(self.recipe_model, SIGNAL('searched(PyQt_PyObject)'), self.search.search_done)
  54.         self.search.search.disconnect()
  55.         self.recipe_model = None
  56.  
  57.     
  58.     def search_done(self, *args):
  59.         if self.recipe_model.showing_count < 10:
  60.             self.recipes.expandAll()
  61.         
  62.  
  63.     
  64.     def toggle_schedule_info(self, *args):
  65.         enabled = self.schedule.isChecked()
  66.         for x in ('daily_button', 'day', 'time', 'interval_button', 'interval'):
  67.             getattr(self, x).setEnabled(enabled)
  68.         
  69.         self.last_downloaded.setVisible(enabled)
  70.  
  71.     
  72.     def current_changed(self, current, previous):
  73.         if self.commit_on_change:
  74.             if previous.isValid():
  75.                 if not self.commit(urn = getattr(previous.internalPointer(), 'urn', None)):
  76.                     self.commit_on_change = False
  77.                     self.recipes.setCurrentIndex(previous)
  78.                 
  79.             
  80.         else:
  81.             self.commit_on_change = True
  82.         urn = self.current_urn
  83.         if urn is not None:
  84.             self.initialize_detail_box(urn)
  85.         
  86.  
  87.     
  88.     def accept(self):
  89.         if not self.commit():
  90.             return False
  91.         return QDialog.accept(self)
  92.  
  93.     
  94.     def download_clicked(self):
  95.         self.commit()
  96.         if self.commit() and self.current_urn:
  97.             self.emit(SIGNAL('download(PyQt_PyObject)'), self.current_urn)
  98.         
  99.  
  100.     
  101.     def download_all_clicked(self):
  102.         if self.commit() and self.commit():
  103.             self.emit(SIGNAL('download(PyQt_PyObject)'), None)
  104.         
  105.  
  106.     
  107.     def current_urn(self):
  108.         current = self.recipes.currentIndex()
  109.         if current.isValid():
  110.             return getattr(current.internalPointer(), 'urn', None)
  111.  
  112.     current_urn = property(current_urn)
  113.     
  114.     def commit(self, urn = None):
  115.         urn = None if urn is None else urn
  116.         if not self.detail_box.isVisible() or urn is None:
  117.             return True
  118.         if self.account.isVisible():
  119.             (un, pw) = map(unicode, (self.username.text(), self.password.text()))
  120.             un = un.strip()
  121.             pw = pw.strip()
  122.             if un or pw:
  123.                 self.recipe_model.set_account_info(urn, un, pw)
  124.             
  125.         
  126.         if self.schedule.isChecked():
  127.             schedule_type = None if self.interval_button.isChecked() else 'day/time'
  128.             if schedule_type == 'interval':
  129.                 schedule = self.interval.value()
  130.                 if schedule < 0.1:
  131.                     schedule = 1 / 24
  132.                 
  133.             else:
  134.                 day_of_week = self.day.currentIndex() - 1
  135.                 t = self.time.time()
  136.                 hour = t.hour()
  137.                 minute = t.minute()
  138.                 schedule = (day_of_week, hour, minute)
  139.             self.recipe_model.schedule_recipe(urn, schedule_type, schedule)
  140.         else:
  141.             self.recipe_model.un_schedule_recipe(urn)
  142.         add_title_tag = self.add_title_tag.isChecked()
  143.         custom_tags = unicode(self.custom_tags.text()).strip()
  144.         custom_tags = [ x.strip() for x in custom_tags.split(',') ]
  145.         self.recipe_model.customize_recipe(urn, add_title_tag, custom_tags)
  146.         return True
  147.  
  148.     
  149.     def initialize_detail_box(self, urn):
  150.         self.detail_box.setVisible(True)
  151.         self.download_button.setVisible(True)
  152.         self.detail_box.setCurrentIndex(0)
  153.         recipe = self.recipe_model.recipe_from_urn(urn)
  154.         schedule_info = self.recipe_model.schedule_info_from_urn(urn)
  155.         account_info = self.recipe_model.account_info_from_urn(urn)
  156.         customize_info = self.recipe_model.get_customize_info(urn)
  157.         ns = recipe.get('needs_subscription', '')
  158.         self.account.setVisible(ns in ('yes', 'optional'))
  159.         self.subscription_optional = ns == 'optional'
  160.         act = _('Account')
  161.         act2 = None if self.subscription_optional else _('(required)')
  162.         self.account.setTitle(act + ' ' + act2)
  163.         un = pw = ''
  164.         if account_info is not None:
  165.             (un, pw) = account_info[:2]
  166.             if not un:
  167.                 un = ''
  168.             
  169.             if not pw:
  170.                 pw = ''
  171.             
  172.         
  173.         self.username.setText(un)
  174.         self.password.setText(pw)
  175.         self.show_password.setChecked(False)
  176.         self.blurb.setText('\n        <p>\n        <b>%(title)s</b><br>\n        %(cb)s %(author)s<br/>\n        %(description)s\n        </p>\n        ' % dict(title = recipe.get('title'), cb = _('Created by: '), author = recipe.get('author', _('Unknown')), description = recipe.get('description', '')))
  177.         scheduled = schedule_info is not None
  178.         self.schedule.setChecked(scheduled)
  179.         self.toggle_schedule_info()
  180.         self.last_downloaded.setText(_('Last downloaded: never'))
  181.         if scheduled:
  182.             (typ, sch, last_downloaded) = schedule_info
  183.             if typ == 'interval':
  184.                 self.interval_button.setChecked(True)
  185.                 self.interval.setValue(sch)
  186.             elif typ == 'day/time':
  187.                 self.daily_button.setChecked(True)
  188.                 (day, hour, minute) = sch
  189.                 self.day.setCurrentIndex(day + 1)
  190.                 self.time.setTime(QTime(hour, minute))
  191.             
  192.             d = utcnow() - last_downloaded
  193.             
  194.             def hm(x):
  195.                 return ((x - x % 3600) // 3600, (x % 3600 - x % 3600 % 60) // 60)
  196.  
  197.             (hours, minutes) = hm(d.seconds)
  198.             tm = _('%d days, %d hours and %d minutes ago') % (d.days, hours, minutes)
  199.             if d < timedelta(days = 366):
  200.                 self.last_downloaded.setText(_('Last downloaded') + ': ' + tm)
  201.             
  202.         
  203.         (add_title_tag, custom_tags) = customize_info
  204.         self.add_title_tag.setChecked(add_title_tag)
  205.         self.custom_tags.setText(u', '.join(custom_tags))
  206.  
  207.  
  208.  
  209. class Scheduler(QObject):
  210.     INTERVAL = 1
  211.     delete_old_news = pyqtSignal(object)
  212.     start_recipe_fetch = pyqtSignal(object)
  213.     
  214.     def __init__(self, parent, db):
  215.         QObject.__init__(self, parent)
  216.         self.internet_connection_failed = False
  217.         self._parent = parent
  218.         self.recipe_model = RecipeModel(db)
  219.         self.lock = QMutex(QMutex.Recursive)
  220.         self.download_queue = set([])
  221.         self.news_menu = QMenu()
  222.         self.news_icon = QIcon(I('news.png'))
  223.         self.scheduler_action = QAction(QIcon(I('scheduler.png')), _('Schedule news download'), self)
  224.         self.news_menu.addAction(self.scheduler_action)
  225.         self.connect(self.scheduler_action, SIGNAL('triggered(bool)'), self.show_dialog)
  226.         self.cac = QAction(QIcon(I('user_profile.png')), _('Add a custom news source'), self)
  227.         self.connect(self.cac, SIGNAL('triggered(bool)'), self.customize_feeds)
  228.         self.news_menu.addAction(self.cac)
  229.         self.news_menu.addSeparator()
  230.         self.all_action = self.news_menu.addAction(_('Download all scheduled new sources'), self.download_all_scheduled)
  231.         self.timer = QTimer(self)
  232.         self.timer.start(int(self.INTERVAL * 60 * 1000))
  233.         self.oldest_timer = QTimer()
  234.         self.connect(self.oldest_timer, SIGNAL('timeout()'), self.oldest_check)
  235.         self.connect(self.timer, SIGNAL('timeout()'), self.check)
  236.         self.oldest = gconf['oldest_news']
  237.         self.oldest_timer.start(int(3600000))
  238.         QTimer.singleShot(5000, self.oldest_check)
  239.         self.database_changed = self.recipe_model.database_changed
  240.  
  241.     
  242.     def oldest_check(self):
  243.         if self.oldest > 0:
  244.             delta = timedelta(days = self.oldest)
  245.             ids = self.recipe_model.db.tags_older_than(_('News'), delta)
  246.             if ids:
  247.                 ids = list(ids)
  248.                 if ids:
  249.                     self.delete_old_news.emit(ids)
  250.                 
  251.             
  252.         
  253.  
  254.     
  255.     def show_dialog(self, *args):
  256.         self.lock.lock()
  257.         
  258.         try:
  259.             d = SchedulerDialog(self.recipe_model)
  260.             self.connect(d, SIGNAL('download(PyQt_PyObject)'), self.download_clicked)
  261.             d.exec_()
  262.             gconf['oldest_news'] = self.oldest = d.old_news.value()
  263.             d.break_cycles()
  264.         finally:
  265.             self.lock.unlock()
  266.  
  267.  
  268.     
  269.     def customize_feeds(self, *args):
  270.         UserProfiles = UserProfiles
  271.         import calibre.gui2.dialogs.user_profiles
  272.         d = UserProfiles(self._parent, self.recipe_model)
  273.         d.exec_()
  274.         d.break_cycles()
  275.  
  276.     
  277.     def do_download(self, urn):
  278.         self.lock.lock()
  279.         
  280.         try:
  281.             account_info = self.recipe_model.get_account_info(urn)
  282.             customize_info = self.recipe_model.get_customize_info(urn)
  283.             recipe = self.recipe_model.recipe_from_urn(urn)
  284.             un = None
  285.             pw = None
  286.             if account_info is not None:
  287.                 (un, pw) = account_info
  288.             
  289.             (add_title_tag, custom_tags) = customize_info
  290.             script = self.recipe_model.get_recipe(urn)
  291.             pt = PersistentTemporaryFile('_builtin.recipe')
  292.             pt.write(script)
  293.             pt.close()
  294.             arg = {
  295.                 'username': un,
  296.                 'password': pw,
  297.                 'add_title_tag': add_title_tag,
  298.                 'custom_tags': custom_tags,
  299.                 'recipe': pt.name,
  300.                 'title': recipe.get('title', ''),
  301.                 'urn': urn }
  302.             self.download_queue.add(urn)
  303.             self.start_recipe_fetch.emit(arg)
  304.         finally:
  305.             self.lock.unlock()
  306.  
  307.  
  308.     
  309.     def recipe_downloaded(self, arg):
  310.         self.lock.lock()
  311.         
  312.         try:
  313.             self.recipe_model.update_last_downloaded(arg['urn'])
  314.             self.download_queue.remove(arg['urn'])
  315.         finally:
  316.             self.lock.unlock()
  317.  
  318.  
  319.     
  320.     def recipe_download_failed(self, arg):
  321.         self.lock.lock()
  322.         
  323.         try:
  324.             self.recipe_model.update_last_downloaded(arg['urn'])
  325.             self.download_queue.remove(arg['urn'])
  326.         finally:
  327.             self.lock.unlock()
  328.  
  329.  
  330.     
  331.     def download_clicked(self, urn):
  332.         if urn is not None:
  333.             return self.download(urn)
  334.         for urn in self.recipe_model.scheduled_urns():
  335.             if not self.download(urn):
  336.                 break
  337.                 continue
  338.             urn is not None
  339.         
  340.  
  341.     
  342.     def download_all_scheduled(self):
  343.         self.download_clicked(None)
  344.  
  345.     
  346.     def download(self, urn):
  347.         self.lock.lock()
  348.         if not internet_connected():
  349.             if not self.internet_connection_failed:
  350.                 self.internet_connection_failed = True
  351.                 d = error_dialog(self._parent, _('No internet connection'), _('Cannot download news as no internet connection is active'))
  352.                 d.setModal(False)
  353.                 d.show()
  354.             
  355.             return False
  356.         self.internet_connection_failed = False
  357.         doit = urn not in self.download_queue
  358.         self.lock.unlock()
  359.         if doit:
  360.             self.do_download(urn)
  361.         
  362.         return True
  363.  
  364.     
  365.     def check(self):
  366.         recipes = self.recipe_model.get_to_be_downloaded_recipes()
  367.         for urn in recipes:
  368.             self.download(urn)
  369.         
  370.  
  371.  
  372. if __name__ == '__main__':
  373.     from calibre.gui2 import is_ok_to_use_qt
  374.     is_ok_to_use_qt()
  375.     from calibre.library.database2 import LibraryDatabase2
  376.     d = SchedulerDialog(RecipeModel(LibraryDatabase2('/home/kovid/documents/library')))
  377.     d.exec_()
  378.  
  379.