diff options
Diffstat (limited to 'src/leap/gui/progress.py')
-rw-r--r-- | src/leap/gui/progress.py | 488 |
1 files changed, 0 insertions, 488 deletions
diff --git a/src/leap/gui/progress.py b/src/leap/gui/progress.py deleted file mode 100644 index ca4f6cc3..00000000 --- a/src/leap/gui/progress.py +++ /dev/null @@ -1,488 +0,0 @@ -""" -classes used in progress pages -from first run wizard -""" -try: - from collections import OrderedDict -except ImportError: # pragma: no cover - # We must be in 2.6 - from leap.util.dicts import OrderedDict - -import logging - -from PyQt4 import QtCore -from PyQt4 import QtGui - -from leap.gui.threads import FunThread - -from leap.gui import mainwindow_rc - -ICON_CHECKMARK = ":/images/Dialog-accept.png" -ICON_FAILED = ":/images/Dialog-error.png" -ICON_WAITING = ":/images/Emblem-question.png" - -logger = logging.getLogger(__name__) - - -class ImgWidget(QtGui.QWidget): - - # XXX move to widgets - - def __init__(self, parent=None, img=None): - super(ImgWidget, self).__init__(parent) - self.pic = QtGui.QPixmap(img) - - def paintEvent(self, event): - painter = QtGui.QPainter(self) - painter.drawPixmap(0, 0, self.pic) - - -class ProgressStep(object): - """ - Data model for sequential steps - to be used in a progress page in - connection wizard - """ - NAME = 0 - DONE = 1 - - def __init__(self, stepname, done, index=None): - """ - @param step: the name of the step - @type step: str - @param done: whether is completed or not - @type done: bool - """ - self.index = int(index) if index else 0 - self.name = unicode(stepname) - self.done = bool(done) - - @classmethod - def columns(self): - return ('name', 'done') - - -class ProgressStepContainer(object): - """ - a container for ProgressSteps objects - access data in the internal dict - """ - - def __init__(self): - self.dirty = False - self.steps = {} - - def step(self, identity): - return self.steps.get(identity, None) - - def addStep(self, step): - self.steps[step.index] = step - - def removeStep(self, step): - if step and self.steps.get(step.index, None): - del self.steps[step.index] - del step - self.dirty = True - - def removeAllSteps(self): - for item in iter(self): - self.removeStep(item) - - @property - def columns(self): - return ProgressStep.columns() - - def __len__(self): - return len(self.steps) - - def __iter__(self): - for step in self.steps.values(): - yield step - - -class StepsTableWidget(QtGui.QTableWidget): - """ - initializes a TableWidget - suitable for our display purposes, like removing - header info and grid display - """ - - def __init__(self, parent=None): - super(StepsTableWidget, self).__init__(parent=parent) - - # remove headers and all edit/select behavior - self.horizontalHeader().hide() - self.verticalHeader().hide() - self.setEditTriggers( - QtGui.QAbstractItemView.NoEditTriggers) - self.setSelectionMode( - QtGui.QAbstractItemView.NoSelection) - width = self.width() - - # WTF? Here init width is 100... - # but on populating is 456... :( - #logger.debug('init table. width=%s' % width) - - # XXX do we need this initial? - self.horizontalHeader().resizeSection(0, width * 0.7) - - # this disables the table grid. - # we should add alignment to the ImgWidget (it's top-left now) - self.setShowGrid(False) - self.setFocusPolicy(QtCore.Qt.NoFocus) - #self.setStyleSheet("QTableView{outline: 0;}") - - # XXX change image for done to rc - - # Note about the "done" status painting: - # - # XXX currently we are setting the CellWidget - # for the whole table on a per-row basis - # (on add_status_line method on ValidationPage). - # However, a more generic solution might be - # to implement a custom Delegate that overwrites - # the paint method (so it paints a checked tickmark if - # done is True and some other thing if checking or false). - # What we have now is quick and works because - # I'm supposing that on first fail we will - # go back to previous wizard page to signal the failure. - # A more generic solution could be used for - # some failing tests if they are not critical. - - -class WithStepsMixIn(object): - """ - This Class is a mixin that can be inherited - by InlineValidation pages (which will display - a progress steps widget in the same page as the form) - or by Validation Pages (which will only display - the progress steps in the page, below a progress bar widget) - """ - STEPS_TIMER_MS = 100 - - # - # methods related to worker threads - # launched for individual checks - # - - def setupStepsProcessingQueue(self): - """ - should be called from the init method - of the derived classes - """ - self.steps_queue = Queue.Queue() - self.stepscheck_timer = QtCore.QTimer() - self.stepscheck_timer.timeout.connect(self.processStepsQueue) - self.stepscheck_timer.start(self.STEPS_TIMER_MS) - # we need to keep a reference to child threads - self.threads = [] - - def do_checks(self): - """ - main entry point for checks. - it calls _do_checks in derived classes, - and it expects it to be a generator - yielding a tuple in the form (("message", progress_int), checkfunction) - """ - - # yo dawg, I heard you like checks - # so I put a __do_checks in your do_checks - # for calling others' _do_checks - - def __do_checks(fun=None, queue=None): - - for checkcase in fun(): # pragma: no cover - checkmsg, checkfun = checkcase - - queue.put(checkmsg) - if checkfun() is False: - queue.put("failed") - break - - t = FunThread(fun=partial( - __do_checks, - fun=self._do_checks, - queue=self.steps_queue)) - if hasattr(self, 'on_checks_validation_ready'): - t.finished.connect(self.on_checks_validation_ready) - t.begin() - self.threads.append(t) - - def processStepsQueue(self): - """ - consume steps queue - and pass messages - to the ui updater functions - """ - while self.steps_queue.qsize(): - try: - status = self.steps_queue.get(0) - if status == "failed": - self.set_failed_icon() - else: - self.onStepStatusChanged(*status) - except Queue.Empty: # pragma: no cover - pass - - def fail(self, err=None): - """ - return failed state - and send error notification as - a nice side effect. this function is called from - the _do_checks check functions returned in the - generator. - """ - wizard = self.wizard() - senderr = lambda err: wizard.set_validation_error( - self.current_page, err) - self.set_undone() - if err: - senderr(err) - return False - - @QtCore.pyqtSlot() - def launch_checks(self): - self.do_checks() - - # (gui) presentation stuff begins ##################### - - # slot - #@QtCore.pyqtSlot(str, int) - def onStepStatusChanged(self, status, progress=None): - status = unicode(status) - if status not in ("head_sentinel", "end_sentinel"): - self.add_status_line(status) - if status in ("end_sentinel"): - #self.checks_finished = True - self.set_checked_icon() - if progress and hasattr(self, 'progress'): - self.progress.setValue(progress) - self.progress.update() - - def setupSteps(self): - self.steps = ProgressStepContainer() - # steps table widget - if isinstance(self, QtCore.QObject): - parent = self - else: - parent = None - self.stepsTableWidget = StepsTableWidget(parent=parent) - zeros = (0, 0, 0, 0) - self.stepsTableWidget.setContentsMargins(*zeros) - self.errors = OrderedDict() - - def set_error(self, name, error): - self.errors[name] = error - - def pop_first_error(self): - errkey, errval = list(reversed(self.errors.items())).pop() - del self.errors[errkey] - return errkey, errval - - def clean_errors(self): - self.errors = OrderedDict() - - def clean_wizard_errors(self, pagename=None): - if pagename is None: # pragma: no cover - pagename = getattr(self, 'prev_page', None) - if pagename is None: # pragma: no cover - return - #logger.debug('cleaning wizard errors for %s' % pagename) - self.wizard().set_validation_error(pagename, None) - - def populateStepsTable(self): - # from examples, - # but I guess it's not needed to re-populate - # the whole table. - table = self.stepsTableWidget - table.setRowCount(len(self.steps)) - columns = self.steps.columns - table.setColumnCount(len(columns)) - - for row, step in enumerate(self.steps): - item = QtGui.QTableWidgetItem(step.name) - item.setData(QtCore.Qt.UserRole, - long(id(step))) - table.setItem(row, columns.index('name'), item) - table.setItem(row, columns.index('done'), - QtGui.QTableWidgetItem(step.done)) - self.resizeTable() - self.update() - - def clearTable(self): - # ??? -- not sure what's the difference - #self.stepsTableWidget.clear() - self.stepsTableWidget.clearContents() - - def resizeTable(self): - # resize first column to ~80% - table = self.stepsTableWidget - FIRST_COLUMN_PERCENT = 0.70 - width = table.width() - #logger.debug('populate table. width=%s' % width) - table.horizontalHeader().resizeSection(0, width * FIRST_COLUMN_PERCENT) - - def set_item_icon(self, img=ICON_CHECKMARK, current=True): - """ - mark the last item - as done - """ - # setting cell widget. - # see note on StepsTableWidget about plans to - # change this for a better solution. - if not hasattr(self, 'steps'): - return - index = len(self.steps) - table = self.stepsTableWidget - _index = index - 1 if current else index - 2 - table.setCellWidget( - _index, - ProgressStep.DONE, - ImgWidget(img=img)) - table.update() - - def set_failed_icon(self): - self.set_item_icon(img=ICON_FAILED, current=True) - - def set_checking_icon(self): - self.set_item_icon(img=ICON_WAITING, current=True) - - def set_checked_icon(self, current=True): - self.set_item_icon(current=current) - - def add_status_line(self, message): - """ - adds a new status line - and mark the next-to-last item - as done - """ - index = len(self.steps) - step = ProgressStep(message, False, index=index) - self.steps.addStep(step) - self.populateStepsTable() - self.set_checking_icon() - self.set_checked_icon(current=False) - - # Sets/unsets done flag - # for isComplete checks - - def set_done(self): - self.done = True - self.completeChanged.emit() - - def set_undone(self): - self.done = False - self.completeChanged.emit() - - def is_done(self): - return self.done - - # convenience for going back and forth - # in the wizard pages. - - def go_back(self): - self.wizard().back() - - def go_next(self): - self.wizard().next() - - -""" -We will use one base class for the intermediate pages -and another one for the in-page validations, both sharing the creation -of the tablewidgets. -The logic of this split comes from where I was trying to solve -the ui update using signals, but now that it's working well with -queues I could join them again. -""" - -import Queue -from functools import partial - - -class InlineValidationPage(QtGui.QWizardPage, WithStepsMixIn): - - def __init__(self, parent=None): - super(InlineValidationPage, self).__init__(parent) - self.setupStepsProcessingQueue() - self.done = False - - # slot - - @QtCore.pyqtSlot() - def showStepsFrame(self): - self.valFrame.show() - self.update() - - # progress frame - - def setupValidationFrame(self): - qframe = QtGui.QFrame - valFrame = qframe() - valFrame.setFrameStyle(qframe.NoFrame) - valframeLayout = QtGui.QVBoxLayout() - zeros = (0, 0, 0, 0) - valframeLayout.setContentsMargins(*zeros) - - valframeLayout.addWidget(self.stepsTableWidget) - valFrame.setLayout(valframeLayout) - self.valFrame = valFrame - - -class ValidationPage(QtGui.QWizardPage, WithStepsMixIn): - """ - class to be used as an intermediate - between two pages in a wizard. - shows feedback to the user and goes back if errors, - goes forward if ok. - initializePage triggers a one shot timer - that calls do_checks. - Derived classes should implement - _do_checks and - _do_validation - """ - - # signals - stepChanged = QtCore.pyqtSignal([str, int]) - - def __init__(self, parent=None): - super(ValidationPage, self).__init__(parent) - self.setupSteps() - #self.connect_step_status() - - layout = QtGui.QVBoxLayout() - self.progress = QtGui.QProgressBar(self) - layout.addWidget(self.progress) - layout.addWidget(self.stepsTableWidget) - - self.setLayout(layout) - self.layout = layout - - self.timer = QtCore.QTimer() - self.done = False - - self.setupStepsProcessingQueue() - - def isComplete(self): - return self.is_done() - - ######################## - - def show_progress(self): - self.progress.show() - self.stepsTableWidget.show() - - def hide_progress(self): - self.progress.hide() - self.stepsTableWidget.hide() - - # pagewizard methods. - # if overriden, child classes should call super. - - def initializePage(self): - self.clean_errors() - self.clean_wizard_errors() - self.steps.removeAllSteps() - self.clearTable() - self.resizeTable() - self.timer.singleShot(0, self.do_checks) |