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

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __license__ = 'GPL v3'
  5. __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
  6. __docformat__ = 'restructuredtext en'
  7. import re
  8. from Queue import Empty, Queue
  9. from PyQt4.Qt import QAbstractTableModel, QVariant, QModelIndex, Qt, QTimer, pyqtSignal, QIcon, QDialog, QAbstractItemDelegate, QApplication, QSize, QStyleOptionProgressBarV2, QString, QStyle, QToolTip, QFrame, QHBoxLayout, QVBoxLayout, QSizePolicy, QLabel, QCoreApplication, QAction, QByteArray
  10. from calibre.utils.ipc.server import Server
  11. from calibre.utils.ipc.job import ParallelJob
  12. from calibre.gui2 import Dispatcher, error_dialog, NONE, config, gprefs
  13. from calibre.gui2.device import DeviceJob
  14. from calibre.gui2.dialogs.jobs_ui import Ui_JobsDialog
  15. from calibre import __appname__
  16. from calibre.gui2.dialogs.job_view_ui import Ui_Dialog
  17. from calibre.gui2.progress_indicator import ProgressIndicator
  18.  
  19. class JobManager(QAbstractTableModel):
  20.     job_added = pyqtSignal(int)
  21.     job_done = pyqtSignal(int)
  22.     
  23.     def __init__(self):
  24.         QAbstractTableModel.__init__(self)
  25.         self.wait_icon = QVariant(QIcon(I('jobs.png')))
  26.         self.running_icon = QVariant(QIcon(I('exec.png')))
  27.         self.error_icon = QVariant(QIcon(I('dialog_error.png')))
  28.         self.done_icon = QVariant(QIcon(I('ok.png')))
  29.         self.jobs = []
  30.         self.add_job = Dispatcher(self._add_job)
  31.         self.server = Server(limit = int(config['worker_limit'] / 2), enforce_cpu_limit = config['enforce_cpu_limit'])
  32.         self.changed_queue = Queue()
  33.         self.timer = QTimer(self)
  34.         self.timer.timeout.connect(self.update, type = Qt.QueuedConnection)
  35.         self.timer.start(1000)
  36.  
  37.     
  38.     def columnCount(self, parent = QModelIndex()):
  39.         return 4
  40.  
  41.     
  42.     def rowCount(self, parent = QModelIndex()):
  43.         return len(self.jobs)
  44.  
  45.     
  46.     def headerData(self, section, orientation, role):
  47.         if role != Qt.DisplayRole:
  48.             return NONE
  49.         if orientation == Qt.Horizontal:
  50.             if section == 0:
  51.                 text = _('Job')
  52.             elif section == 1:
  53.                 text = _('Status')
  54.             elif section == 2:
  55.                 text = _('Progress')
  56.             elif section == 3:
  57.                 text = _('Running time')
  58.             
  59.             return QVariant(text)
  60.         return QVariant(section + 1)
  61.  
  62.     
  63.     def show_tooltip(self, arg):
  64.         (widget, pos) = arg
  65.         QToolTip.showText(pos, self.get_tooltip())
  66.  
  67.     
  68.     def get_tooltip(self):
  69.         running_jobs = _[1]
  70.         waiting_jobs = _[2]
  71.         lines = [
  72.             _('There are %d running jobs:') % len(running_jobs)]
  73.         for job in running_jobs:
  74.             desc = job.description
  75.             p = [] if not desc else [] if job.is_finished else job.percent
  76.             lines.append('%s:  %.0f%% done' % (desc, p))
  77.         
  78.         lines.extend([
  79.             '',
  80.             _('There are %d waiting jobs:') % len(waiting_jobs)])
  81.         for job in waiting_jobs:
  82.             desc = job.description
  83.             if not desc:
  84.                 desc = _('Unknown job')
  85.             
  86.             lines.append(desc)
  87.         
  88.         return '\n'.join([
  89.             'calibre',
  90.             ''] + lines)
  91.  
  92.     
  93.     def data(self, index, role):
  94.         
  95.         try:
  96.             if role not in (Qt.DisplayRole, Qt.DecorationRole):
  97.                 return NONE
  98.             row = index.row()
  99.             col = index.column()
  100.             job = self.jobs[row]
  101.             if role == Qt.DecorationRole and col == 0:
  102.                 state = job.run_state
  103.                 if state == job.WAITING:
  104.                     return self.wait_icon
  105.                 if state == job.RUNNING:
  106.                     return self.running_icon
  107.                 if job.killed or job.failed:
  108.                     return self.error_icon
  109.                 return self.done_icon
  110.         except:
  111.             import traceback
  112.             traceback.print_exc()
  113.  
  114.         return NONE
  115.  
  116.     
  117.     def update(self):
  118.         
  119.         try:
  120.             self._update()
  121.         except BaseException:
  122.             import traceback
  123.             traceback.print_exc()
  124.  
  125.  
  126.     
  127.     def _update(self):
  128.         for i, j in enumerate(self.jobs):
  129.             if j.run_state == j.RUNNING:
  130.                 idx = self.index(i, 3)
  131.                 self.dataChanged.emit(idx, idx)
  132.                 continue
  133.         
  134.         jobs = set([])
  135.         while True:
  136.             
  137.             try:
  138.                 jobs.add(self.server.changed_jobs_queue.get_nowait())
  139.             continue
  140.             except Empty:
  141.                 break
  142.                 continue
  143.             
  144.  
  145.             None<EXCEPTION MATCH>Empty
  146.         while True:
  147.             
  148.             try:
  149.                 jobs.add(self.changed_queue.get_nowait())
  150.             continue
  151.             except Empty:
  152.                 break
  153.                 continue
  154.             
  155.  
  156.             None<EXCEPTION MATCH>Empty
  157.         if jobs:
  158.             needs_reset = False
  159.             for job in jobs:
  160.                 orig_state = job.run_state
  161.                 job.update()
  162.                 if orig_state != job.run_state:
  163.                     needs_reset = True
  164.                     continue
  165.             
  166.             if needs_reset:
  167.                 self.jobs.sort()
  168.                 self.reset()
  169.                 if job.is_finished:
  170.                     self.job_done.emit(len(self.unfinished_jobs()))
  171.                 
  172.             else:
  173.                 for job in jobs:
  174.                     idx = self.jobs.index(job)
  175.                     self.dataChanged.emit(self.index(idx, 0), self.index(idx, 3))
  176.                 
  177.         
  178.  
  179.     
  180.     def _add_job(self, job):
  181.         self.layoutAboutToBeChanged.emit()
  182.         self.jobs.append(job)
  183.         self.jobs.sort()
  184.         self.job_added.emit(len(self.unfinished_jobs()))
  185.         self.layoutChanged.emit()
  186.  
  187.     
  188.     def done_jobs(self):
  189.         return _[1]
  190.  
  191.     
  192.     def unfinished_jobs(self):
  193.         return _[1]
  194.  
  195.     
  196.     def row_to_job(self, row):
  197.         return self.jobs[row]
  198.  
  199.     
  200.     def has_device_jobs(self):
  201.         for job in self.jobs:
  202.             if job.is_running and isinstance(job, DeviceJob):
  203.                 return True
  204.         
  205.         return False
  206.  
  207.     
  208.     def has_jobs(self):
  209.         for job in self.jobs:
  210.             if job.is_running:
  211.                 return True
  212.         
  213.         return False
  214.  
  215.     
  216.     def run_job(self, done, name, args = [], kwargs = { }, description = '', core_usage = 1):
  217.         job = ParallelJob(name, description, done, args = args, kwargs = kwargs)
  218.         job.core_usage = core_usage
  219.         self.add_job(job)
  220.         self.server.add_job(job)
  221.         return job
  222.  
  223.     
  224.     def launch_gui_app(self, name, args = [], kwargs = { }, description = ''):
  225.         job = ParallelJob(name, description, (lambda x: x), args = args, kwargs = kwargs)
  226.         self.server.run_job(job, gui = True, redirect_output = False)
  227.  
  228.     
  229.     def kill_job(self, row, view):
  230.         job = self.jobs[row]
  231.         if isinstance(job, DeviceJob):
  232.             return error_dialog(view, _('Cannot kill job'), _('Cannot kill jobs that communicate with the device')).exec_()
  233.         if job.duration is not None:
  234.             return error_dialog(view, _('Cannot kill job'), _('Job has already run')).exec_()
  235.         self.server.kill_job(job)
  236.  
  237.     
  238.     def kill_all_jobs(self):
  239.         for job in self.jobs:
  240.             if isinstance(job, DeviceJob) or job.duration is not None:
  241.                 continue
  242.             
  243.             self.server.kill_job(job)
  244.         
  245.  
  246.     
  247.     def terminate_all_jobs(self):
  248.         self.server.killall()
  249.  
  250.  
  251.  
  252. class ProgressBarDelegate(QAbstractItemDelegate):
  253.     
  254.     def sizeHint(self, option, index):
  255.         return QSize(120, 30)
  256.  
  257.     
  258.     def paint(self, painter, option, index):
  259.         opts = QStyleOptionProgressBarV2()
  260.         opts.rect = option.rect
  261.         opts.minimum = 1
  262.         opts.maximum = 100
  263.         opts.textVisible = True
  264.         (percent, ok) = index.model().data(index, Qt.DisplayRole).toInt()
  265.         if not ok:
  266.             percent = 0
  267.         
  268.         opts.progress = percent
  269.         opts.text = None(QString if percent == 0 else '%d%%' % percent)
  270.         QApplication.style().drawControl(QStyle.CE_ProgressBar, opts, painter)
  271.  
  272.  
  273.  
  274. class DetailView(QDialog, Ui_Dialog):
  275.     
  276.     def __init__(self, parent, job):
  277.         QDialog.__init__(self, parent)
  278.         self.setupUi(self)
  279.         self.setWindowTitle(job.description)
  280.         self.job = job
  281.         self.next_pos = 0
  282.         self.update()
  283.         self.timer = QTimer(self)
  284.         self.timer.timeout.connect(self.update)
  285.         self.timer.start(1000)
  286.  
  287.     
  288.     def update(self):
  289.         f = self.job.log_file
  290.         f.seek(self.next_pos)
  291.         more = f.read()
  292.         self.next_pos = f.tell()
  293.         if more:
  294.             self.log.appendPlainText(more.decode('utf-8', 'replace'))
  295.         
  296.  
  297.  
  298.  
  299. class JobsButton(QFrame):
  300.     
  301.     def __init__(self, horizontal = False, size = 48, parent = None):
  302.         QFrame.__init__(self, parent)
  303.         if horizontal:
  304.             size = 24
  305.         
  306.         self.pi = ProgressIndicator(self, size)
  307.         self._jobs = QLabel('<b>' + _('Jobs:') + ' 0')
  308.         self._jobs.mouseReleaseEvent = self.mouseReleaseEvent
  309.         self.shortcut = _('Shift+Alt+J')
  310.         if horizontal:
  311.             self.setLayout(QHBoxLayout())
  312.             self.layout().setDirection(self.layout().RightToLeft)
  313.         else:
  314.             self.setLayout(QVBoxLayout())
  315.             self._jobs.setAlignment(Qt.AlignHCenter | Qt.AlignBottom)
  316.         self.layout().addWidget(self.pi)
  317.         self.layout().addWidget(self._jobs)
  318.         if not horizontal:
  319.             self.layout().setAlignment(self._jobs, Qt.AlignHCenter)
  320.         
  321.         self._jobs.setMargin(0)
  322.         self.layout().setMargin(0)
  323.         self._jobs.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
  324.         self.setCursor(Qt.PointingHandCursor)
  325.         b = _('Click to see list of jobs')
  326.         self.setToolTip(b + u' (%s)' % self.shortcut)
  327.         self.action_toggle = QAction(b, parent)
  328.         parent.addAction(self.action_toggle)
  329.         self.action_toggle.setShortcut(self.shortcut)
  330.         self.action_toggle.triggered.connect(self.toggle)
  331.  
  332.     
  333.     def initialize(self, jobs_dialog, job_manager):
  334.         self.jobs_dialog = jobs_dialog
  335.         job_manager.job_added.connect(self.job_added)
  336.         job_manager.job_done.connect(self.job_done)
  337.         self.jobs_dialog.addAction(self.action_toggle)
  338.  
  339.     
  340.     def mouseReleaseEvent(self, event):
  341.         self.toggle()
  342.  
  343.     
  344.     def toggle(self, *args):
  345.         if self.jobs_dialog.isVisible():
  346.             self.jobs_dialog.hide()
  347.         else:
  348.             self.jobs_dialog.show()
  349.  
  350.     
  351.     def is_running(self):
  352.         return self.pi.isAnimated()
  353.  
  354.     is_running = property(is_running)
  355.     
  356.     def start(self):
  357.         self.pi.startAnimation()
  358.  
  359.     
  360.     def stop(self):
  361.         self.pi.stopAnimation()
  362.  
  363.     
  364.     def jobs(self):
  365.         src = unicode(self._jobs.text())
  366.         return int(re.search('\\d+', src).group())
  367.  
  368.     
  369.     def job_added(self, nnum):
  370.         jobs = self._jobs
  371.         src = unicode(jobs.text())
  372.         num = self.jobs()
  373.         text = src.replace(str(num), str(nnum))
  374.         jobs.setText(text)
  375.         self.start()
  376.  
  377.     
  378.     def job_done(self, nnum):
  379.         jobs = self._jobs
  380.         src = unicode(jobs.text())
  381.         num = self.jobs()
  382.         text = src.replace(str(num), str(nnum))
  383.         jobs.setText(text)
  384.         if nnum == 0:
  385.             self.no_more_jobs()
  386.         
  387.  
  388.     
  389.     def no_more_jobs(self):
  390.         if self.is_running:
  391.             self.stop()
  392.             QCoreApplication.instance().alert(self, 5000)
  393.         
  394.  
  395.  
  396.  
  397. class JobsDialog(QDialog, Ui_JobsDialog):
  398.     
  399.     def __init__(self, window, model):
  400.         QDialog.__init__(self, window)
  401.         Ui_JobsDialog.__init__(self)
  402.         self.setupUi(self)
  403.         self.jobs_view.setModel(model)
  404.         self.model = model
  405.         self.setWindowModality(Qt.NonModal)
  406.         self.setWindowTitle(__appname__ + _(' - Jobs'))
  407.         self.kill_button.clicked.connect(self.kill_job)
  408.         self.details_button.clicked.connect(self.show_details)
  409.         self.stop_all_jobs_button.clicked.connect(self.kill_all_jobs)
  410.         self.pb_delegate = ProgressBarDelegate(self)
  411.         self.jobs_view.setItemDelegateForColumn(2, self.pb_delegate)
  412.         self.jobs_view.doubleClicked.connect(self.show_job_details)
  413.         self.jobs_view.horizontalHeader().setMovable(True)
  414.         self.restore_state()
  415.  
  416.     
  417.     def restore_state(self):
  418.         
  419.         try:
  420.             geom = gprefs.get('jobs_dialog_geometry', bytearray(''))
  421.             self.restoreGeometry(QByteArray(geom))
  422.             state = gprefs.get('jobs view column layout', bytearray(''))
  423.             self.jobs_view.horizontalHeader().restoreState(QByteArray(state))
  424.         except:
  425.             pass
  426.  
  427.  
  428.     
  429.     def save_state(self):
  430.         
  431.         try:
  432.             state = bytearray(self.jobs_view.horizontalHeader().saveState())
  433.             gprefs['jobs view column layout'] = state
  434.             geom = bytearray(self.saveGeometry())
  435.             gprefs['jobs_dialog_geometry'] = geom
  436.         except:
  437.             pass
  438.  
  439.  
  440.     
  441.     def show_job_details(self, index):
  442.         row = index.row()
  443.         job = self.jobs_view.model().row_to_job(row)
  444.         d = DetailView(self, job)
  445.         d.exec_()
  446.         d.timer.stop()
  447.  
  448.     
  449.     def kill_job(self, *args):
  450.         for index in self.jobs_view.selectedIndexes():
  451.             row = index.row()
  452.             self.model.kill_job(row, self)
  453.             return None
  454.         
  455.  
  456.     
  457.     def show_details(self, *args):
  458.         for index in self.jobs_view.selectedIndexes():
  459.             self.show_job_details(index)
  460.             return None
  461.         
  462.  
  463.     
  464.     def kill_all_jobs(self, *args):
  465.         self.model.kill_all_jobs()
  466.  
  467.     
  468.     def closeEvent(self, e):
  469.         self.save_state()
  470.         return QDialog.closeEvent(self, e)
  471.  
  472.     
  473.     def show(self, *args):
  474.         self.restore_state()
  475.         return QDialog.show(self, *args)
  476.  
  477.     
  478.     def hide(self, *args):
  479.         self.save_state()
  480.         return QDialog.hide(self, *args)
  481.  
  482.  
  483.