home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_1290 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  16.6 KB  |  448 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
  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.svg')))
  26.         self.running_icon = QVariant(QIcon(I('exec.svg')))
  27.         self.error_icon = QVariant(QIcon(I('dialog_error.svg')))
  28.         self.done_icon = QVariant(QIcon(I('ok.svg')))
  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.  
  186.     
  187.     def done_jobs(self):
  188.         return _[1]
  189.  
  190.     
  191.     def unfinished_jobs(self):
  192.         return _[1]
  193.  
  194.     
  195.     def row_to_job(self, row):
  196.         return self.jobs[row]
  197.  
  198.     
  199.     def has_device_jobs(self):
  200.         for job in self.jobs:
  201.             if job.is_running and isinstance(job, DeviceJob):
  202.                 return True
  203.         
  204.         return False
  205.  
  206.     
  207.     def has_jobs(self):
  208.         for job in self.jobs:
  209.             if job.is_running:
  210.                 return True
  211.         
  212.         return False
  213.  
  214.     
  215.     def run_job(self, done, name, args = [], kwargs = { }, description = ''):
  216.         job = ParallelJob(name, description, done, args = args, kwargs = kwargs)
  217.         self.add_job(job)
  218.         self.server.add_job(job)
  219.         return job
  220.  
  221.     
  222.     def launch_gui_app(self, name, args = [], kwargs = { }, description = ''):
  223.         job = ParallelJob(name, description, (lambda x: x), args = args, kwargs = kwargs)
  224.         self.server.run_job(job, gui = True, redirect_output = False)
  225.  
  226.     
  227.     def kill_job(self, row, view):
  228.         job = self.jobs[row]
  229.         if isinstance(job, DeviceJob):
  230.             return error_dialog(view, _('Cannot kill job'), _('Cannot kill jobs that communicate with the device')).exec_()
  231.         if job.duration is not None:
  232.             return error_dialog(view, _('Cannot kill job'), _('Job has already run')).exec_()
  233.         self.server.kill_job(job)
  234.  
  235.     
  236.     def kill_all_jobs(self):
  237.         for job in self.jobs:
  238.             if isinstance(job, DeviceJob) or job.duration is not None:
  239.                 continue
  240.             
  241.             self.server.kill_job(job)
  242.         
  243.  
  244.     
  245.     def terminate_all_jobs(self):
  246.         self.server.killall()
  247.  
  248.  
  249.  
  250. class ProgressBarDelegate(QAbstractItemDelegate):
  251.     
  252.     def sizeHint(self, option, index):
  253.         return QSize(120, 30)
  254.  
  255.     
  256.     def paint(self, painter, option, index):
  257.         opts = QStyleOptionProgressBarV2()
  258.         opts.rect = option.rect
  259.         opts.minimum = 1
  260.         opts.maximum = 100
  261.         opts.textVisible = True
  262.         (percent, ok) = index.model().data(index, Qt.DisplayRole).toInt()
  263.         if not ok:
  264.             percent = 0
  265.         
  266.         opts.progress = percent
  267.         opts.text = None(QString if percent == 0 else '%d%%' % percent)
  268.         QApplication.style().drawControl(QStyle.CE_ProgressBar, opts, painter)
  269.  
  270.  
  271.  
  272. class DetailView(QDialog, Ui_Dialog):
  273.     
  274.     def __init__(self, parent, job):
  275.         QDialog.__init__(self, parent)
  276.         self.setupUi(self)
  277.         self.setWindowTitle(job.description)
  278.         self.job = job
  279.         self.next_pos = 0
  280.         self.update()
  281.         self.timer = QTimer(self)
  282.         self.timer.timeout.connect(self.update)
  283.         self.timer.start(1000)
  284.  
  285.     
  286.     def update(self):
  287.         f = self.job.log_file
  288.         f.seek(self.next_pos)
  289.         more = f.read()
  290.         self.next_pos = f.tell()
  291.         if more:
  292.             self.log.appendPlainText(more.decode('utf-8', 'replace'))
  293.         
  294.  
  295.  
  296.  
  297. class JobsButton(QFrame):
  298.     
  299.     def __init__(self, horizontal = False, size = 48, parent = None):
  300.         QFrame.__init__(self, parent)
  301.         if horizontal:
  302.             size = 24
  303.         
  304.         self.pi = ProgressIndicator(self, size)
  305.         self._jobs = QLabel('<b>' + _('Jobs:') + ' 0')
  306.         self._jobs.mouseReleaseEvent = self.mouseReleaseEvent
  307.         if horizontal:
  308.             self.setLayout(QHBoxLayout())
  309.             self.layout().setDirection(self.layout().RightToLeft)
  310.         else:
  311.             self.setLayout(QVBoxLayout())
  312.             self._jobs.setAlignment(Qt.AlignHCenter | Qt.AlignBottom)
  313.         self.layout().addWidget(self.pi)
  314.         self.layout().addWidget(self._jobs)
  315.         if not horizontal:
  316.             self.layout().setAlignment(self._jobs, Qt.AlignHCenter)
  317.         
  318.         self._jobs.setMargin(0)
  319.         self.layout().setMargin(0)
  320.         self._jobs.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
  321.         self.setCursor(Qt.PointingHandCursor)
  322.         self.setToolTip(_('Click to see list of active jobs.'))
  323.  
  324.     
  325.     def initialize(self, jobs_dialog, job_manager):
  326.         self.jobs_dialog = jobs_dialog
  327.         job_manager.job_added.connect(self.job_added)
  328.         job_manager.job_done.connect(self.job_done)
  329.  
  330.     
  331.     def mouseReleaseEvent(self, event):
  332.         if self.jobs_dialog.isVisible():
  333.             self.jobs_dialog.hide()
  334.         else:
  335.             self.jobs_dialog.show()
  336.  
  337.     
  338.     def is_running(self):
  339.         return self.pi.isAnimated()
  340.  
  341.     is_running = property(is_running)
  342.     
  343.     def start(self):
  344.         self.pi.startAnimation()
  345.  
  346.     
  347.     def stop(self):
  348.         self.pi.stopAnimation()
  349.  
  350.     
  351.     def jobs(self):
  352.         src = unicode(self._jobs.text())
  353.         return int(re.search('\\d+', src).group())
  354.  
  355.     
  356.     def job_added(self, nnum):
  357.         jobs = self._jobs
  358.         src = unicode(jobs.text())
  359.         num = self.jobs()
  360.         text = src.replace(str(num), str(nnum))
  361.         jobs.setText(text)
  362.         self.start()
  363.  
  364.     
  365.     def job_done(self, nnum):
  366.         jobs = self._jobs
  367.         src = unicode(jobs.text())
  368.         num = self.jobs()
  369.         text = src.replace(str(num), str(nnum))
  370.         jobs.setText(text)
  371.         if nnum == 0:
  372.             self.no_more_jobs()
  373.         
  374.  
  375.     
  376.     def no_more_jobs(self):
  377.         if self.is_running:
  378.             self.stop()
  379.             QCoreApplication.instance().alert(self, 5000)
  380.         
  381.  
  382.  
  383.  
  384. class JobsDialog(QDialog, Ui_JobsDialog):
  385.     
  386.     def __init__(self, window, model):
  387.         QDialog.__init__(self, window)
  388.         Ui_JobsDialog.__init__(self)
  389.         self.setupUi(self)
  390.         self.jobs_view.setModel(model)
  391.         self.model = model
  392.         self.setWindowModality(Qt.NonModal)
  393.         self.setWindowTitle(__appname__ + _(' - Jobs'))
  394.         self.kill_button.clicked.connect(self.kill_job)
  395.         self.details_button.clicked.connect(self.show_details)
  396.         self.stop_all_jobs_button.clicked.connect(self.kill_all_jobs)
  397.         self.pb_delegate = ProgressBarDelegate(self)
  398.         self.jobs_view.setItemDelegateForColumn(2, self.pb_delegate)
  399.         self.jobs_view.doubleClicked.connect(self.show_job_details)
  400.         self.jobs_view.horizontalHeader().setMovable(True)
  401.         state = gprefs.get('jobs view column layout', None)
  402.         if state is not None:
  403.             
  404.             try:
  405.                 self.jobs_view.horizontalHeader().restoreState(bytes(state))
  406.  
  407.         
  408.  
  409.     
  410.     def show_job_details(self, index):
  411.         row = index.row()
  412.         job = self.jobs_view.model().row_to_job(row)
  413.         d = DetailView(self, job)
  414.         d.exec_()
  415.         d.timer.stop()
  416.  
  417.     
  418.     def kill_job(self, *args):
  419.         for index in self.jobs_view.selectedIndexes():
  420.             row = index.row()
  421.             self.model.kill_job(row, self)
  422.             return None
  423.         
  424.  
  425.     
  426.     def show_details(self, *args):
  427.         for index in self.jobs_view.selectedIndexes():
  428.             self.show_job_details(index)
  429.             return None
  430.         
  431.  
  432.     
  433.     def kill_all_jobs(self, *args):
  434.         self.model.kill_all_jobs()
  435.  
  436.     
  437.     def closeEvent(self, e):
  438.         
  439.         try:
  440.             state = bytearray(self.jobs_view.horizontalHeader().saveState())
  441.             gprefs['jobs view column layout'] = state
  442.         except:
  443.             pass
  444.  
  445.         e.accept()
  446.  
  447.  
  448.