Example #1
0
    def __init__(self, process, command_string, parent=None):
        config_key = "layout/window/process"
        super(ProcessDialog, self).__init__(parent)
        StoreSizeMixin.__init__(self, app.config, config_key)
        self.setWindowTitle("Running: %s" % command_string)

        self.proc = process
        self.ended = False
        self.output_ended = False
        self.capture_output = True
        self.buffer = []

        self.bar = QtGui.QProgressBar()
        self.bar.setRange(0, 0)
        self.edit = StreamableTextEdit()
        close_btn = QtGui.QPushButton("Close")
        btn_pane = create_pane([None, close_btn], True)
        create_pane([self.bar, self.edit, btn_pane], False, parent_widget=self)

        self.lock = Lock()
        self.stdout_thread = Thread(target=self._read_output,
                                    args=(self.proc.stdout, ))
        self.stderr_thread = Thread(target=self._read_output,
                                    args=(self.proc.stderr, ))

        self.timer = QtCore.QTimer()
        self.timer.setInterval(100)
        self.timer.timeout.connect(self._update)
        self.timer.start()

        self.stdout_thread.start()
        self.stderr_thread.start()

        close_btn.clicked.connect(self.close)
Example #2
0
class Writer(QtCore.QObject):
    graph_written = QtCore.Signal(str, str)

    def __init__(self, graph_str, filepath, prune_to=None):
        super(Writer, self).__init__()
        self.graph_str = graph_str
        self.filepath = filepath
        self.prune_to = prune_to
        self.process = None

    def cancel(self):
        if self.process:
            self.process.terminate()

    def write_graph(self):
        filepath = ""
        error_msg = ""
        try:
            self.process = Process(target=_save_graph,
                                   args=(self.graph_str, self.filepath,
                                         self.prune_to))

            self.process.start()
            self.process.join()
            if self.process.exitcode == 0:
                filepath = self.filepath
        except Exception as e:
            error_msg = str(e)

        self.graph_written.emit(filepath, error_msg)
Example #3
0
class Writer(QtCore.QObject):
    graph_written = QtCore.Signal(str, str)

    def __init__(self, graph_str, filepath, prune_to=None):
        super(Writer, self).__init__()
        self.graph_str = graph_str
        self.filepath = filepath
        self.prune_to = prune_to
        self.process = None

    def cancel(self):
        if self.process:
            self.process.terminate()

    def write_graph(self):
        if self.prune_to:
            graph_str = prune_graph(self.graph_str, self.prune_to)
        else:
            graph_str = self.graph_str

        error_msg = ''
        try:
            save_graph(graph_str, self.filepath)
        except Exception as e:
            error_msg = str(e)

        self.graph_written.emit(self.filepath, error_msg)
Example #4
0
    def _start_resolve(self):
        max_fails = self._get_max_fails()
        if max_fails is None:
            return

        self.setWindowTitle("Resolving...")
        self.resolve_btn.hide()
        self.cancel_btn.show()
        self._set_progress(None)
        self.started = True

        verbosity = 0
        show_package_loads = True
        timestamp = None
        if self.advanced:
            verbosity = app.config.get("resolve/verbosity")
            show_package_loads = app.config.get("resolve/show_package_loads")
            timestamp = self.timestamp_widget.datetime()
            if timestamp is not None:
                timestamp = timestamp.toTime_t()

        self.resolver = ResolveThread(self.context_model,
                                      verbosity=verbosity,
                                      max_fails=max_fails,
                                      timestamp=timestamp,
                                      show_package_loads=show_package_loads,
                                      buf=self.edit)

        self.resolver.finished.connect(self._resolve_finished)

        self.thread = QtCore.QThread()
        self.resolver.moveToThread(self.thread)
        self.thread.started.connect(self.resolver.run)
        self.thread.start()
Example #5
0
class BrowsePackageWidget(QtGui.QWidget, ContextViewMixin):
    """A widget for browsing rez packages.
    """
    packageSelected = QtCore.Signal()

    def __init__(self, context_model=None, parent=None, lock_package=False,
                 package_selectable_callback=None):
        super(BrowsePackageWidget, self).__init__(parent)
        ContextViewMixin.__init__(self, context_model)

        self.edit = PackageLineEdit(context_model, family_only=True)
        if lock_package:
            self.edit.hide()

        self.versions_table = PackageVersionsTable(context_model,
                                                   callback=package_selectable_callback)
        self.package_tab = PackageTabWidget(versions_tab=False)

        splitter = ConfiguredSplitter(app.config, "layout/splitter/browse_package")
        splitter.setOrientation(QtCore.Qt.Vertical)
        splitter.addWidget(self.versions_table)
        splitter.addWidget(self.package_tab)
        if not splitter.apply_saved_layout():
            splitter.setStretchFactor(0, 2)
            splitter.setStretchFactor(1, 1)

        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.edit)
        layout.addWidget(splitter)
        self.setLayout(layout)

        self.edit.focusOutViaKeyPress.connect(self._set_package_name)
        self.versions_table.itemSelectionChanged.connect(self._set_package)

    def set_package_text(self, txt):
        try:
            req = Requirement(str(txt))
            package_name = req.name
            version_range = req.range
        except:
            package_name = str(txt)
            version_range = None

        self.edit.setText(package_name)
        self._set_package_name(package_name)

        if version_range is not None:
            self.versions_table.select_version(version_range)

    def current_package(self):
        return self.versions_table.current_package()

    def _set_package_name(self, package_name):
        self.versions_table.set_package_name(package_name)
        self.versions_table.setFocus()

    def _set_package(self):
        package = self.versions_table.current_package()
        self.package_tab.set_package(package)
        self.packageSelected.emit()
Example #6
0
    def __init__(self, pivot_widget, width=240, height=160, parent=None):
        super(TimeSelecterPopup, self).__init__(parent)
        self.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised)
        self.setWindowFlags(QtCore.Qt.Popup)
        self.seconds = None

        self.label = QtGui.QLabel("")

        canvas_frame = QtGui.QFrame()
        canvas_frame.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken)
        canvas = Canvas(width, height)
        layout = QtGui.QVBoxLayout()
        layout.setSpacing(2)
        layout.setContentsMargins(2, 2, 2, 2)
        layout.addWidget(canvas)
        canvas_frame.setLayout(layout)

        create_pane([self.label, canvas_frame],
                    False,
                    compact=True,
                    parent_widget=self)
        self.adjustSize()

        pt = pivot_widget.rect().topLeft()
        global_pt = pivot_widget.mapToGlobal(pt)
        self.move(global_pt - QtCore.QPoint(0, self.height()))

        canvas.secondsHover.connect(self._secondsHover)
        canvas.secondsClicked.connect(self._secondsClicked)
Example #7
0
    def __init__(self, context_model=None, parent=None):
        super(ContextResolveTimeLabel, self).__init__(parent)
        ContextViewMixin.__init__(self, context_model)

        self.timer = QtCore.QTimer(self)
        self.timer.setInterval(60 * 1000)
        self.timer.timeout.connect(self.refresh)
        self.refresh()
Example #8
0
class LoadPackagesThread(QtCore.QObject):
    """Load packages in a separate thread.

    Packages are loaded in decreasing version order.
    """
    progress = QtCore.Signal(int, int)
    finished = QtCore.Signal(object)

    def __init__(self,
                 package_paths,
                 package_name,
                 range_=None,
                 package_attributes=None,
                 callback=None):
        super(LoadPackagesThread, self).__init__()
        self.stopped = False
        self.package_paths = package_paths
        self.package_name = package_name
        self.range_ = range_
        self.package_attributes = package_attributes
        self.callback = callback

    def stop(self):
        self.stopped = True

    def run(self):
        it = iter_packages(name=self.package_name,
                           paths=self.package_paths,
                           range_=self.range_)
        packages = sorted(it, key=lambda x: x.version, reverse=True)
        num_packages = len(packages)
        self.progress.emit(0, num_packages)

        for i, package in enumerate(packages):
            if self.stopped:
                return
            if self.callback and not self.callback(package):
                break

            for attr in self.package_attributes:
                getattr(package, attr)  # cause load and/or data validation
            self.progress.emit(i + 1, num_packages)

        if not self.stopped:
            self.finished.emit(packages)
Example #9
0
    def __init__(self, parent=None):
        super(ProcessTrackerThread, self).__init__(parent)
        self.processes = {}
        self.proc_list = []
        self.pending_procs = []
        self.lock = Lock()

        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self._update)
Example #10
0
class ResolveThread(QtCore.QObject):

    finished = QtCore.Signal()

    def __init__(self,
                 context_model,
                 verbosity=0,
                 max_fails=-1,
                 timestamp=None,
                 show_package_loads=True,
                 buf=None):
        super(ResolveThread, self).__init__()
        self.context_model = context_model
        self.context = None
        self.verbosity = verbosity
        self.max_fails = max_fails
        self.timestamp = timestamp
        self.show_package_loads = show_package_loads
        self.buf = buf
        self.context = None
        self.stopped = False
        self.abort_reason = None
        self.error_message = None

    def run(self):
        package_load_callback = (self._package_load_callback
                                 if self.show_package_loads else None)
        try:
            self.context = self.context_model.resolve_context(
                verbosity=self.verbosity,
                max_fails=self.max_fails,
                timestamp=self.timestamp,
                buf=self.buf,
                callback=self._callback,
                package_load_callback=package_load_callback)
        except RezError as e:
            self.error_message = str(e)

        if not self.stopped:
            self.finished.emit()

    def stop(self):
        self.stopped = True
        self.abort_reason = "Cancelled by user."

    def success(self):
        return bool(self.context and self.context.success)

    def _callback(self, solver_state):
        if self.buf and self.verbosity == 0:
            print >> self.buf, "solve step %d..." % solver_state.num_solves
        return (not self.stopped), self.abort_reason

    def _package_load_callback(self, package):
        if self.buf:
            print >> self.buf, "loading %s..." % str(package)
Example #11
0
class FindPopup(QtGui.QFrame):

    find = QtCore.Signal(str)

    def __init__(self,
                 pivot_widget,
                 pivot_position=None,
                 words=None,
                 initial_word=None,
                 close_on_find=True,
                 parent=None):
        super(FindPopup, self).__init__(parent)
        self.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised)
        self.setWindowFlags(QtCore.Qt.Popup)
        self.close_on_find = close_on_find

        self.edit = QtGui.QLineEdit()
        self.btn = QtGui.QPushButton("Find")
        create_pane([self.edit, self.btn],
                    True,
                    compact=True,
                    compact_spacing=0,
                    parent_widget=self)
        self.edit.setFocus()

        if initial_word:
            self.edit.setText(initial_word)
            self.edit.selectAll()

        self.completer = None
        if words:
            self.completer = QtGui.QCompleter(self)
            self.completer.setCompletionMode(QtGui.QCompleter.PopupCompletion)
            self.completions = QtGui.QStringListModel(words, self.completer)
            self.completer.setModel(self.completions)
            self.edit.setCompleter(self.completer)

        pt = getattr(pivot_widget.rect(), pivot_position)()
        global_pt = pivot_widget.mapToGlobal(pt)
        self.move(global_pt)

        self.btn.clicked.connect(self._find)
        self.edit.returnPressed.connect(self._find)

        find_shortcut = QtGui.QShortcut(QtGui.QKeySequence("Ctrl+F"), self)
        find_shortcut.activated.connect(self._find_again)

    def _find(self):
        word = self.edit.text()
        self.find.emit(word)
        if self.close_on_find:
            self.close()

    def _find_again(self):
        self.edit.selectAll()
Example #12
0
    def load_packages(self,
                      package_paths,
                      package_name,
                      range_=None,
                      package_attributes=None,
                      callback=None):
        self.stop_loading_packages()
        self.bar.setRange(0, 0)

        self.worker = LoadPackagesThread(package_paths=package_paths,
                                         package_name=package_name,
                                         range_=range_,
                                         package_attributes=package_attributes,
                                         callback=callback)
        id_ = id(self.worker)
        self.worker.progress.connect(partial(self._progress, id_))
        self.worker.finished.connect(partial(self._packagesLoaded, id_))

        thread = QtCore.QThread()
        self.worker.moveToThread(thread)
        thread.started.connect(self.worker.run)

        threads = [(thread, self.worker)]
        for th, worker in self.threads:
            if th.isRunning():
                threads.append((th, worker))
        self.threads = threads

        if self.swap_delay == 0:
            self.loading_widget.show()
            if self.main_widget is not None:
                self.main_widget.hide()
        else:
            self.timer = QtCore.QTimer()
            self.timer.setSingleShot(True)
            self.timer.setInterval(self.swap_delay)
            fn = partial(self._swap_to_loader, id_)
            self.timer.timeout.connect(fn)
            self.timer.start()

        thread.start()
Example #13
0
class IconButton(QtGui.QLabel):

    clicked = QtCore.Signal(int)

    def __init__(self, icon_name, tooltip=None, parent=None):
        super(IconButton, self).__init__(parent)
        icon = get_icon(icon_name)
        self.setPixmap(icon)
        self.setCursor(QtCore.Qt.PointingHandCursor)
        if tooltip:
            self.setToolTip(tooltip)

    def mousePressEvent(self, event):
        self.clicked.emit(event.button())
Example #14
0
class _TreeNode(QtGui.QLabel):

    clicked = QtCore.Signal()

    def __init__(self, item, txt, parent=None):
        super(_TreeNode, self).__init__(txt, parent)
        self.item = item
        self.setCursor(QtCore.Qt.PointingHandCursor)

    def mouseReleaseEvent(self, event):
        super(_TreeNode, self).mouseReleaseEvent(event)
        self.clicked.emit()
        if event.button() == QtCore.Qt.LeftButton:
            self.item.setExpanded(not self.item.isExpanded())
Example #15
0
class StreamableTextEdit(SearchableTextEdit):
    """A QTextEdit that also acts like a write-only file object.

    The object is threadsafe and can be written to from any thread.
    """
    written = QtCore.Signal()

    def __init__(self, parent=None):
        super(StreamableTextEdit, self).__init__(parent)
        self.setReadOnly(True)
        self.buffer = []
        self.lock = threading.Lock()

        self.written.connect(self._consume)

    # -- file-like methods

    def isatty(self):
        return False

    def write(self, txt):
        emit = False
        try:
            self.lock.acquire()
            emit = not bool(self.buffer)
            self.buffer.append(str(txt))
        finally:
            self.lock.release()
        if emit:
            self.written.emit()

    def _consume(self):
        try:
            self.lock.acquire()
            buffer_ = self.buffer
            self.buffer = []
        finally:
            self.lock.release()

        if buffer_:
            txt = ''.join(buffer_)
            self._write(txt)

    def _write(self, txt):
        self.moveCursor(QtGui.QTextCursor.End)
        self.insertPlainText(txt)
        self.moveCursor(QtGui.QTextCursor.End)
Example #16
0
    def _currentCellChanged(self, currentRow, currentColumn, previousRow,
                            previousColumn):
        widget = self.cellWidget(currentRow, currentColumn)
        if self._widget_is_selectable(widget):
            self._current_variant = widget.variant
        else:
            self._current_variant = None
            self.setCurrentIndex(QtCore.QModelIndex())

        # update other variants, this causes them to show/hide the depends icon
        if previousColumn != currentColumn:
            for _, widget in self._iter_column_widgets(previousColumn,
                                                       VariantCellWidget):
                widget.set_reference_sibling(None)
        for _, widget in self._iter_column_widgets(currentColumn,
                                                   VariantCellWidget):
            widget.set_reference_sibling(self._current_variant)

        # new selection is failing to cause a paint update sometimes?? This
        # seems to help but does not 100% fix the problem.
        self.update(self.model().index(previousRow, previousColumn))
        self.update(self.model().index(currentRow, currentColumn))

        self.variantSelected.emit(self._current_variant)
Example #17
0
class HelpEntryWidget(QtGui.QWidget):

    clicked = QtCore.Signal()

    def __init__(self, help_, index, parent=None):
        super(HelpEntryWidget, self).__init__(parent)
        self.help_ = help_
        self.index = index

        icon = get_icon_widget("help")
        label = self.help_.sections[self.index][0]
        label_widget = QtGui.QLabel(label)
        self.setCursor(QtCore.Qt.PointingHandCursor)

        create_pane([icon, label_widget, None],
                    True,
                    compact=True,
                    parent_widget=self)

    def mouseReleaseEvent(self, event):
        super(HelpEntryWidget, self).mouseReleaseEvent(event)
        self.clicked.emit()
        if event.button() == QtCore.Qt.LeftButton:
            self.help_.open(self.index)
Example #18
0
class ContextTableWidget(QtGui.QTableWidget, ContextViewMixin):

    default_row_count = 10
    double_arrow = u"\u27FA"
    short_double_arrow = u"\u21D4"
    variantSelected = QtCore.Signal(object)

    def __init__(self, context_model=None, parent=None):
        """Create a context table."""
        super(ContextTableWidget, self).__init__(self.default_row_count, 2,
                                                 parent)
        ContextViewMixin.__init__(self, context_model)

        self.diff_mode = False
        self.diff_context_model = None
        self.diff_from_source = False
        self._show_effective_request = False
        self._current_variant = None

        self.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)

        hh = self.horizontalHeader()
        hh.setDefaultSectionSize(12 * self.fontMetrics().height())

        vh = self.verticalHeader()
        vh.setResizeMode(QtGui.QHeaderView.ResizeToContents)
        vh.setVisible(False)

        self.delegate = CellDelegate(self)
        self.setItemDelegate(self.delegate)
        self.setShowGrid(False)

        self.currentCellChanged.connect(self._currentCellChanged)
        self.itemSelectionChanged.connect(self._itemSelectionChanged)
        self.refresh()

    def selectionCommand(self, index, event=None):
        row = index.row()
        column = index.column()

        widget = self.cellWidget(row, column)
        if self._widget_is_selectable(widget):
            return QtGui.QItemSelectionModel.ClearAndSelect
        else:
            return QtGui.QItemSelectionModel.Clear

    def current_variant(self):
        """Returns the currently selected variant, if any."""
        return self._current_variant

    def show_effective_request(self, b):
        if b != self._show_effective_request:
            self._show_effective_request = b
            self._update_request_column(0, self.context_model)
            if self.diff_mode:
                self._update_request_column(4, self.diff_context_model)

    def get_request(self):
        """Get the current request list.

        Returns:
            List of strings.
        """
        return self._get_request(0)

    def enter_diff_mode(self, context_model=None):
        """Enter diff mode.

        Args:
            context_model (`ContextModel`): Context to diff against. If None, a
            copy of the current context is used.
        """
        assert not self.diff_mode
        self.diff_mode = True

        if context_model is None:
            self.diff_from_source = True
            self.diff_context_model = self.context_model.copy()
        else:
            self.diff_from_source = False
            self.diff_context_model = context_model

        self.clear()
        self.setColumnCount(5)
        self.refresh()

    def leave_diff_mode(self):
        """Leave diff mode."""
        assert self.diff_mode
        self.diff_mode = False
        self.diff_context_model = None
        self.diff_from_source = False
        self.setColumnCount(2)
        self.refresh()

    def revert_to_diff(self):
        assert self.diff_mode
        source_context = self.diff_context_model.context()
        self.context_model.set_context(source_context)

    def revert_to_disk(self):
        filepath = self.context_model.filepath()
        assert filepath
        disk_context = app.load_context(filepath)
        self.context_model.set_context(disk_context)

    def get_title(self):
        """Returns a string suitable for titling a window containing this table."""
        def _title(context_model):
            context = context_model.context()
            if context is None:
                return "new context*"
            title = os.path.basename(context.load_path) if context.load_path \
                else "new context"
            if context_model.is_modified():
                title += '*'
            return title

        if self.diff_mode:
            diff_title = _title(self.diff_context_model)
            if self.diff_from_source:
                diff_title += "'"
            return "%s  %s  %s" % (_title(
                self.context_model), self.short_double_arrow, diff_title)
        else:
            return _title(self.context_model)

    # Stops focus loss when a widget inside the table is selected. In an MDI app
    # this can cause the current subwindow to lose focus.
    def clear(self):
        self.setFocus()
        super(ContextTableWidget, self).clear()

    def select_variant(self, name):
        for row, widget in self._iter_column_widgets(1, VariantCellWidget):
            if widget.variant.name == str(name):
                self.setCurrentIndex(self.model().index(row, 1))
                return

    def refresh(self):
        self._contextChanged(ContextModel.CONTEXT_CHANGED)

    def _contextChanged(self, flags=0):
        update_request_columns = {}

        # apply request and variant widgets to columns
        if flags & ContextModel.CONTEXT_CHANGED:
            self.clear()

            if self.diff_mode:
                hh = self.horizontalHeader()
                hh.setResizeMode(2, QtGui.QHeaderView.Fixed)
                self.setColumnWidth(2, 50)

            if self.context():
                if self.diff_mode:
                    self._apply_request(self.diff_context_model, 4)
                    self._apply_resolve(self.diff_context_model,
                                        3,
                                        4,
                                        hide_locks=True,
                                        read_only=True)
                    self._apply_request(self.context_model, 0)
                    self._apply_resolve(self.context_model,
                                        1,
                                        3,
                                        reference_column_is_variants=True)
                    self._update_comparison_column(2)
                    update_request_columns[4] = self.diff_context_model
                else:
                    self._apply_request(self.context_model, 0)
                    self._apply_resolve(self.context_model, 1, 0)
            else:
                self._set_package_cell(0, 0)
            update_request_columns[0] = self.context_model

        if flags & ContextModel.LOCKS_CHANGED and self._show_effective_request:
            update_request_columns[0] = self.context_model

        for column, context_model in update_request_columns.iteritems():
            self._update_request_column(column, context_model)

        # set column headers
        if self.diff_mode:
            headers = [["current request", False], ["current resolve", False],
                       [self.double_arrow, False], ["reference resolve", True],
                       ["reference request", True]]
        else:
            headers = [["request", False], ["resolve", False]]
        if self.context_model.is_stale():
            headers[0][0] += '*'
            headers[1][0] += " (stale)"
            headers[1][1] = True

        for column, (label, italic) in enumerate(headers):
            item = QtGui.QTableWidgetItem(label)
            update_font(item, italic=italic)
            self.setHorizontalHeaderItem(column, item)

        self.update()

    def _update_request_column(self, column, context_model):
        # remove effective request cells
        for row, widget in self._iter_column_widgets(
                column, EffectivePackageCellWidget):
            self.removeCellWidget(row, column)

        # update effective request cells
        if self._show_effective_request:
            # get row following package select widgets
            last_row = -1
            for row, widget in self._iter_column_widgets(
                    column, PackageSelectWidget):
                last_row = row

            row = last_row + 1
            for request_str in context_model.implicit_packages:
                self._set_effective_package_cell(row, column, request_str,
                                                 "implicit")
                row += 1

            d = context_model.get_lock_requests()
            for lock, requests in d.iteritems():
                for request in requests:
                    request_str = str(request)
                    self._set_effective_package_cell(row, column, request_str,
                                                     lock.name)
                    row += 1

        self._trim_trailing_rows()

    def _widget_is_selectable(self, widget):
        return (widget and widget.isEnabled()
                and isinstance(widget, VariantCellWidget)
                and not widget.read_only)

    def _currentCellChanged(self, currentRow, currentColumn, previousRow,
                            previousColumn):
        widget = self.cellWidget(currentRow, currentColumn)
        if self._widget_is_selectable(widget):
            self._current_variant = widget.variant
        else:
            self._current_variant = None
            self.setCurrentIndex(QtCore.QModelIndex())

        # update other variants, this causes them to show/hide the depends icon
        if previousColumn != currentColumn:
            for _, widget in self._iter_column_widgets(previousColumn,
                                                       VariantCellWidget):
                widget.set_reference_sibling(None)
        for _, widget in self._iter_column_widgets(currentColumn,
                                                   VariantCellWidget):
            widget.set_reference_sibling(self._current_variant)

        # new selection is failing to cause a paint update sometimes?? This
        # seems to help but does not 100% fix the problem.
        self.update(self.model().index(previousRow, previousColumn))
        self.update(self.model().index(currentRow, currentColumn))

        self.variantSelected.emit(self._current_variant)

    # this is only here to clear the current index, which leaves an annoying
    # visual cue even though the cell is not selected
    def _itemSelectionChanged(self):
        if not self.selectedIndexes():
            self.setCurrentIndex(QtCore.QModelIndex())

    def _iter_column_widgets(self, column, types=None):
        types = types or QtGui.QWidget
        for row in range(self.rowCount()):
            widget = self.cellWidget(row, column)
            if widget and isinstance(widget, types):
                yield row, widget

    def _get_request(self, column):
        request_strs = []
        for _, edit in self._iter_column_widgets(column, PackageSelectWidget):
            txt = str(edit.text()).strip()
            if txt:
                request_strs.append(txt)
        return request_strs

    def _apply_request(self, context_model, column):
        context = context_model.context()
        requests = context.requested_packages()
        num_requests = len(requests)
        for i, request in enumerate(requests):
            self._set_package_cell(i, column, request)
        self._set_package_cell(num_requests, column)

    def _apply_resolve(self,
                       context_model,
                       column,
                       reference_column,
                       hide_locks=False,
                       read_only=False,
                       reference_column_is_variants=False):
        context = context_model.context()
        resolved = context.resolved_packages[:]
        consumed_rows = set()

        # match variants up with matching request/variant in source column
        for row, widget in self._iter_column_widgets(
                reference_column, (PackageSelectWidget, VariantCellWidget)):
            request_str = str(widget.text())
            if not request_str:
                continue

            package_name = Requirement(request_str).name
            matches = [x for x in resolved if x.name == package_name]
            if matches:
                variant = matches[0]
                resolved = [x for x in resolved if x.name != package_name]
                reference_variant = None
                if reference_column_is_variants and isinstance(
                        widget, VariantCellWidget):
                    reference_variant = widget.variant
                self._set_variant_cell(row,
                                       column,
                                       context_model,
                                       variant,
                                       reference_variant=reference_variant,
                                       hide_locks=hide_locks,
                                       read_only=read_only)
            consumed_rows.add(row)

        # append variants that don't match reference requests/variants
        if reference_column_is_variants:
            hide_locks = True
        row = 0

        while resolved:
            variant = resolved[0]
            resolved = resolved[1:]
            while row in consumed_rows:
                row += 1
            self._set_variant_cell(row,
                                   column,
                                   context_model,
                                   variant,
                                   hide_locks=hide_locks,
                                   read_only=read_only)
            row += 1

    def _update_comparison_column(self, column):
        #no_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base)

        for row in range(self.rowCount()):
            left = self.cellWidget(row, column - 1)
            right = self.cellWidget(row, column + 1)
            left_variant = left.variant if left else None
            right_variant = right.variant if right else None
            if left_variant or right_variant:
                widget = CompareCell(self.context_model, left_variant,
                                     right_variant)
                self.setCellWidget(row, column, widget)

    def _set_package_cell(self, row, column, request=None):
        if row >= self.rowCount():
            self.setRowCount(row + 1)

        if request is None:
            # don't overwrite existing package request
            widget = self.cellWidget(row, column)
            if widget and isinstance(widget, PackageSelectWidget):
                return None

        txt = str(request) if request else ""
        read_only = (column != 0)

        edit = PackageSelectWidget(self.context_model, read_only=read_only)
        edit.setText(txt)
        self.setCellWidget(row, column, edit)
        edit.textChanged.connect(partial(self._packageTextChanged, row,
                                         column))
        edit.focusOut.connect(partial(self._packageFocusOut, row, column))
        edit.focusOutViaKeyPress.connect(
            partial(self._packageFocusOutViaKeyPress, row, column))
        return edit

    def _set_effective_package_cell(self, row, column, request, lock_type):
        if row >= self.rowCount():
            self.setRowCount(row + 1)
        cell = EffectivePackageCellWidget(request, lock_type)
        self.setCellWidget(row, column, cell)

    def _set_variant_cell(self,
                          row,
                          column,
                          context_model,
                          variant,
                          reference_variant=None,
                          hide_locks=False,
                          read_only=False):
        if row >= self.rowCount():
            self.setRowCount(row + 1)

        widget = VariantCellWidget(context_model,
                                   variant,
                                   reference_variant=reference_variant,
                                   hide_locks=hide_locks,
                                   read_only=read_only)
        self.setCellWidget(row, column, widget)
        widget._set_stale(column != 1)

    def _set_cell_text(self, row, column, txt):
        if row >= self.rowCount():
            self.setRowCount(row + 1)

        if self.cellWidget(row, column):
            self.removeCellWidget(row, column)
        item = QtGui.QTableWidgetItem(txt)
        self.setItem(row, column, item)

    def _packageTextChanged(self, row, column, txt):
        if txt:
            if self._set_package_cell(row + 1, column):
                self._update_request_column(column, self.context_model)

    def _packageFocusOutViaKeyPress(self, row, column, txt):
        if txt:
            self._set_current_cell(row + 1, column)
        else:
            widget = self.cellWidget(row + 1, column)
            if widget and isinstance(widget, PackageSelectWidget):
                self._delete_cell(row, column)

            new_request = self.get_request()
            self.context_model.set_request(new_request)
            self._update_request_column(column, self.context_model)

    def _packageFocusOut(self, row, column, txt):
        if txt:
            self._set_package_cell(row + 1, column)
        else:
            widget = self.cellWidget(row + 1, column)
            if widget and isinstance(widget, PackageSelectWidget):
                self._delete_cell(row, column)

        new_request = self.get_request()
        self.context_model.set_request(new_request)
        self._update_request_column(column, self.context_model)

    def _delete_cell(self, row, column):
        for i in range(row, self.rowCount()):
            edit = self.cellWidget(i, column)
            if edit and isinstance(edit, PackageSelectWidget):
                next_edit = self.cellWidget(i + 1, column)
                if next_edit and isinstance(next_edit, PackageSelectWidget):
                    next_edit.clone_into(edit)
                else:
                    self.removeCellWidget(i, column)

    def _trim_trailing_rows(self):
        n = 0
        for i in reversed(range(self.default_row_count, self.rowCount())):
            row_clear = not any(
                self.cellWidget(i, x) for x in range(self.columnCount()))
            if row_clear:
                n += 1
            else:
                break
        if n:
            row, column = self.currentRow(), self.currentColumn()
            self.setRowCount(self.rowCount() - n)
            self._set_current_cell(row, column)

    def _set_current_cell(self, row, column):
        self.setCurrentCell(row, column)
        edit = self.cellWidget(row, column)
        if edit:
            edit.setFocus()
Example #19
0
    def paint(self, painter, option, index):
        row = index.row()
        column = index.column()
        table = self.parent()
        cmp_widget = table.cellWidget(row, 2)
        stale = table.context_model.is_stale()
        rect = option.rect
        oldbrush = painter.brush()
        oldpen = painter.pen()
        pal = table.palette()

        def _setpen(to_stale):
            pen = self.stale_pen if stale and to_stale else self.pen
            painter.setPen(pen)

        # determine cell bg color and paint it
        selected_cells = set(
            (x.row(), x.column()) for x in table.selectedIndexes())
        bg_color = None
        if (row, column) in selected_cells:
            bg_color = self.highlight_brush
        elif cmp_widget and \
                ((cmp_widget.left() and column == 1)
                 or (cmp_widget.right() and column == 3)):
            bg_color = cmp_widget.color
        else:
            bg_color = pal.color(QtGui.QPalette.Base)

        painter.fillRect(rect, bg_color)

        # draw grid lines
        r = (rect.topRight(), rect.bottomRight())
        b = (rect.bottomLeft(), rect.bottomRight() - QtCore.QPoint(1, 0))
        _setpen(column < 2)

        if column == 0:
            painter.drawLine(*r)
            _setpen(False)
            painter.drawLine(*b)
        elif column == 1:
            if not cmp_widget or not cmp_widget.left():
                painter.drawLine(*r)
            if row == table.rowCount() - 1:
                painter.drawLine(*b)
            else:
                if stale and row == 0:
                    painter.drawLine(rect.topLeft(), rect.topRight())
                _setpen(False)
                painter.drawLine(*b)
        elif column == 2:
            # draw the curvy bits in the comparison column
            draw_right_edge = True

            def _draw_path():
                painter.setRenderHints(QtGui.QPainter.Antialiasing, True)
                painter.drawPath(self.path)
                painter.resetTransform()
                painter.setRenderHints(QtGui.QPainter.Antialiasing, False)

            if cmp_widget:
                if cmp_widget.left():
                    painter.translate(rect.topLeft() - QtCore.QPoint(1, 0.5))
                    painter.scale(rect.width() / 2.5, rect.height())
                    _setpen(True)
                    if stale:
                        pen = QtGui.QPen(self.stale_color)
                        pen.setCosmetic(True)
                        pen.setWidthF(1.5)
                        painter.setPen(pen)
                    if (row, 1) in selected_cells:
                        painter.setBrush(self.highlight_brush)
                    elif cmp_widget.color:
                        painter.setBrush(QtGui.QBrush(cmp_widget.color))
                    _draw_path()
                    _setpen(False)
                if cmp_widget.right():
                    painter.translate(rect.topRight() - QtCore.QPoint(-1, 0.5))
                    painter.scale(-rect.width() / 2.5, rect.height())
                    if (row, 3) in selected_cells:
                        painter.setBrush(self.highlight_brush)
                    elif cmp_widget.color:
                        painter.setBrush(QtGui.QBrush(cmp_widget.color))
                    _draw_path()
                    draw_right_edge = False

            if draw_right_edge:
                painter.drawLine(*r)
        else:
            painter.drawLine(*r)
            painter.drawLine(*b)

        painter.setPen(oldpen)
        painter.setBrush(oldbrush)

        if cmp_widget and column in (1, 3):
            index = table.model().index(row, 2)
            table.update(index)
Example #20
0
class PackageLineEdit(QtGui.QLineEdit, ContextViewMixin):

    focusOutViaKeyPress = QtCore.Signal(str)
    focusOut = QtCore.Signal(str)
    focusIn = QtCore.Signal()

    def __init__(self,
                 context_model=None,
                 parent=None,
                 family_only=False,
                 read_only=False):
        super(PackageLineEdit, self).__init__(parent)
        ContextViewMixin.__init__(self, context_model)
        self.read_only = read_only
        self.family_only = family_only
        self.default_style = None

        pal = self.palette()
        self.normal_font = self.font()
        self.placeholder_font = self.font()
        self.placeholder_font.setItalic(True)
        self.normal_text_color = pal.color(QtGui.QPalette.Text)
        self.placeholder_text_color = pal.color(QtGui.QPalette.Disabled,
                                                QtGui.QPalette.Text)
        if not self.read_only:
            self.setPlaceholderText("enter package")
            self._update_font()

        self.completer = QtGui.QCompleter(self)
        self.completer.setCompletionMode(QtGui.QCompleter.PopupCompletion)
        self.completions = QtGui.QStringListModel(self.completer)
        self.completer.setModel(self.completions)
        self.setCompleter(self.completer)

        self.textEdited.connect(self._textEdited)
        self.textChanged.connect(self._textChanged)

    def mouseReleaseEvent(self, event):
        if not self.hasSelectedText():
            self.completer.complete()

    def event(self, event):
        # keyPressEvent does not capture tab
        if event.type() == QtCore.QEvent.KeyPress \
                and event.key() in (QtCore.Qt.Key_Tab,
                                    QtCore.Qt.Key_Enter,
                                    QtCore.Qt.Key_Return):
            self._update_status()
            self.focusOutViaKeyPress.emit(self.text())
            return True
        return super(PackageLineEdit, self).event(event)

    def focusInEvent(self, event):
        self._update_font()
        self.focusIn.emit()
        return super(PackageLineEdit, self).focusInEvent(event)

    def focusOutEvent(self, event):
        self._update_status()
        self._update_font()
        self.focusOut.emit(self.text())
        return super(PackageLineEdit, self).focusOutEvent(event)

    def clone_into(self, other):
        other.family_only = self.family_only
        other.default_style = self.default_style
        other.setText(self.text())
        other.setStyleSheet(self.styleSheet())
        completions = self.completions.stringList()
        other.completions.setStringList(completions)
        other.completer.setCompletionPrefix(self.text())

    def _textChanged(self, txt):
        self._update_font()

    def _update_font(self):
        if self.read_only:
            return
        elif self.text():
            font = self.normal_font
            color = self.normal_text_color
        else:
            font = self.placeholder_font
            color = self.placeholder_text_color

        self.setFont(font)
        pal = self.palette()
        pal.setColor(QtGui.QPalette.Active, QtGui.QPalette.Text, color)
        pal.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Text, color)
        self.setPalette(pal)

    def _contextChanged(self, flags=0):
        if flags & ContextModel.PACKAGES_PATH_CHANGED:
            self._update_status()

    @property
    def _paths(self):
        return self.context_model.packages_path

    def _textEdited(self, txt):
        words = get_completions(str(txt),
                                paths=self._paths,
                                family_only=self.family_only)
        self.completions.setStringList(list(reversed(list(words))))

    def _set_style(self, style=None):
        if style is None:
            if self.default_style is not None:
                self.setStyleSheet(self.default_style)
        else:
            if self.default_style is None:
                self.default_style = self.styleSheet()
            self.setStyleSheet(style)

    def _update_status(self):
        def _ok():
            self._set_style()
            self.setToolTip("")

        def _err(msg, color="red"):
            self._set_style("QLineEdit { border : 2px solid %s;}" % color)
            self.setToolTip(msg)

        txt = str(self.text())
        if not txt:
            _ok()
            return

        try:
            req = Requirement(str(txt))
        except Exception as e:
            _err(str(e))
            return

        _ok()
        if not req.conflict:
            try:
                it = iter_packages(name=req.name,
                                   range_=req.range,
                                   paths=self._paths)
                pkg = sorted(it, key=lambda x: x.version)[-1]
            except Exception:
                _err("cannot find package: %r" % txt, "orange")
                return

            if pkg.description:
                self.setToolTip(pkg.description)
Example #21
0
class VariantVersionsWidget(PackageLoadingWidget, ContextViewMixin):

    closeWindow = QtCore.Signal()

    def __init__(self,
                 context_model=None,
                 reference_variant=None,
                 in_window=False,
                 parent=None):
        """
        Args:
            reference_variant (`Variant`): Used to show the difference between
                two variants.
            in_window (bool): If True, the 'view changelogs' option turns
                into a checkbox, dropping the 'View in window' option.
        """
        super(VariantVersionsWidget, self).__init__(parent)
        ContextViewMixin.__init__(self, context_model)

        self.in_window = in_window
        self.variant = None
        self.reference_variant = reference_variant
        self.pending_changelog_packages = None

        self.label = QtGui.QLabel()
        self.changelog_edit = ChangelogEdit()
        self.table = VariantVersionsTable(self.context_model,
                                          reference_variant=reference_variant)

        self.tab = QtGui.QTabWidget()
        self.tab.addTab(self.table, "list view")
        self.tab.addTab(self.changelog_edit, "changelogs")
        self.tab.currentChanged.connect(self._tabIndexChanged)

        buttons = [None]
        if self.in_window:
            close_btn = QtGui.QPushButton("Close")
            buttons.append(close_btn)
            close_btn.clicked.connect(self._close_window)
        else:
            browse_versions_btn = QtGui.QPushButton("Browse Versions...")
            browse_versions_btn.clicked.connect(self._browseVersions)
            buttons.append(browse_versions_btn)

            window_btn = QtGui.QPushButton("View In Window...")
            window_btn.clicked.connect(self._view_changelogs_window)
            buttons.append(window_btn)

        btn_pane = create_pane(buttons, True, compact=not self.in_window)
        pane = create_pane([self.label, self.tab, btn_pane],
                           False,
                           compact=True)

        self.set_main_widget(pane)
        self.set_loader_swap_delay(300)
        self.clear()

    def clear(self):
        self.label.setText("no package selected")
        self.table.clear()
        self.pending_changelog_packages = None
        self.setEnabled(False)

    def refresh(self):
        variant = self.variant
        self.variant = None
        self.set_variant(variant)

    def set_variant(self, variant):
        self.tab.setCurrentIndex(0)
        self.stop_loading_packages()
        self.clear()

        self.variant = variant
        if self.variant is None:
            return

        package_paths = self.context_model.packages_path
        if self.variant.wrapped.location not in package_paths:
            txt = "not on the package search path"
            self.label.setText(txt)
            return

        self.setEnabled(True)

        range_ = None
        if self.reference_variant and self.reference_variant.name == variant.name:
            versions = sorted(
                [variant.version, self.reference_variant.version])
            range_ = VersionRange.as_span(*versions)

        self.load_packages(package_paths=package_paths,
                           package_name=variant.name,
                           range_=range_,
                           package_attributes=("timestamp", ))

    def set_packages(self, packages):
        self.table._set_variant(self.variant, packages)
        self._update_label()
        self._update_changelogs(packages)
        self.setEnabled(True)

    def _update_label(self):
        diff_num = self.table.get_reference_difference()
        if diff_num is None:
            # normal mode
            if self.table.version_index == 0:
                if self.table.num_versions == 1:
                    txt = "the only package"
                else:
                    txt = "the latest package"
            else:
                nth = positional_number_string(self.table.version_index + 1)
                txt = "the %s latest package" % nth
            if self.table.num_versions > 1:
                txt += " of %d packages" % self.table.num_versions
            txt = "%s is %s" % (self.variant.qualified_package_name, txt)
        else:
            # reference mode - showing difference between two versions
            adj = "ahead" if diff_num > 0 else "behind"
            diff_num = abs(diff_num)
            unit = "version" if diff_num == 1 else "versions"
            txt = "Package is %d %s %s" % (diff_num, unit, adj)

        self.label.setText(txt)

    def _update_changelogs(self, packages):
        # don't actually update until tab is selected - changelogs may get big,
        # we don't want to block up the gui thread unless necessary
        self.pending_changelog_packages = packages
        if self.tab.currentIndex() == 1:
            self._apply_changelogs()

    def _tabIndexChanged(self, index):
        if index == 1:
            self._apply_changelogs()

    def _apply_changelogs(self):
        if self.pending_changelog_packages:
            self.changelog_edit.set_packages(self.pending_changelog_packages)
            self.pending_changelog_packages = None

    def _changelogStateChanged(self, state):
        self._view_changelogs(state == QtCore.Qt.Checked)
        self.refresh()

    def _view_or_hide_changelogs(self):
        enable = (not self.table.view_changelog)
        self._view_changelogs(enable)
        self.refresh()

    def _view_changelogs_window(self):
        from rezgui.dialogs.VariantVersionsDialog import VariantVersionsDialog
        dlg = VariantVersionsDialog(self.context_model,
                                    self.variant,
                                    parent=self)
        dlg.exec_()

    def _browseVersions(self):
        from rezgui.dialogs.BrowsePackageDialog import BrowsePackageDialog
        dlg = BrowsePackageDialog(
            context_model=self.context_model,
            package_text=self.variant.qualified_package_name,
            close_only=True,
            lock_package=True,
            parent=self.parentWidget())

        dlg.setWindowTitle("Versions - %s" % self.variant.name)
        dlg.exec_()

    def _close_window(self):
        self.closeWindow.emit()
Example #22
0
 def sizeHint(self):
     width = self.config.get(self.config_key + "/width")
     height = self.config.get(self.config_key + "/height")
     return QtCore.QSize(width, height)
Example #23
0
class ToolWidget(QtGui.QWidget):

    clicked = QtCore.Signal()

    def __init__(self, context, tool_name, process_tracker=None, parent=None):
        super(ToolWidget, self).__init__(parent)
        self.context = context
        self.tool_name = tool_name
        self.process_tracker = process_tracker

        tool_icon = get_icon_widget("spanner")
        self.label = QtGui.QLabel(tool_name)
        self.instances_label = QtGui.QLabel("")
        self.instances_label.setEnabled(False)
        update_font(self.instances_label, italic=True)

        if self.context:
            self.setCursor(QtCore.Qt.PointingHandCursor)
            if self.process_tracker:
                entries = self.get_processes()
                self.set_instance_count(len(entries))

        layout = QtGui.QHBoxLayout()
        layout.setSpacing(2)
        layout.setContentsMargins(2, 2, 2, 2)
        layout.addWidget(tool_icon)
        layout.addWidget(self.label, 1)
        layout.addWidget(self.instances_label)
        self.setLayout(layout)

    def get_processes(self):
        if not self.process_tracker:
            return []

        return self.process_tracker.running_instances(self.context,
                                                      self.tool_name)

    def mouseReleaseEvent(self, event):
        super(ToolWidget, self).mouseReleaseEvent(event)
        if not self.context:
            return

        menu = QtGui.QMenu(self)
        add_menu_action(menu, "Run", self._launch_tool)
        fn = partial(self._launch_tool, terminal=True)
        add_menu_action(menu, "Run In Terminal", fn)
        fn = partial(self._launch_tool, moniter=True)
        add_menu_action(menu, "Run And Moniter", fn)

        entries = self.get_processes()
        if entries:
            menu.addSeparator()
            add_menu_action(menu, "Running Processes...", self._list_processes)

        menu.addSeparator()
        add_menu_action(menu, "Cancel")

        menu.exec_(self.mapToGlobal(event.pos()))
        self.clicked.emit()

    def _launch_tool(self, terminal=False, moniter=False):
        buf = subprocess.PIPE if moniter else None
        proc = app.execute_shell(context=self.context,
                                 command=self.tool_name,
                                 terminal=terminal,
                                 stdout=buf,
                                 stderr=buf)

        if self.process_tracker:
            self.process_tracker.add_instance(self.context, self.tool_name,
                                              proc)
        if moniter:
            dlg = ProcessDialog(proc, self.tool_name)
            dlg.exec_()

    def _list_processes(self):
        entries = self.get_processes()
        now = int(time.time())
        items = []
        for proc, start_time in entries:
            age = now - start_time
            items.append((age, proc.pid))

        if items:
            items = sorted(items)
            lines = []
            for age, pid in items:
                t_str = readable_time_duration(age)
                line = "Process #%d has been running for %s" % (pid, t_str)
                lines.append(line)
            txt = "\n".join(lines)
        else:
            txt = "There are no running processes."

        QtGui.QMessageBox.information(self, "Processes", txt)

    def set_instance_count(self, nprocs):
        if nprocs:
            txt = "%d instances running..." % nprocs
        else:
            txt = ""
        self.instances_label.setText(txt)
Example #24
0
class ProcessTrackerThread(QtCore.QThread):

    instanceCountChanged = QtCore.Signal(int, str, int)

    def __init__(self, parent=None):
        super(ProcessTrackerThread, self).__init__(parent)
        self.processes = {}
        self.proc_list = []
        self.pending_procs = []
        self.lock = Lock()

        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self._update)

    def run(self):
        self.timer.start()
        self.exec_()

    def running_instances(self, context, process_name):
        """Get a list of running instances.

        Args:
            context (`ResolvedContext`): Context the process is running in.
            process_name (str): Name of the process.

        Returns:
            List of (`subprocess.Popen`, start-time) 2-tuples, where start_time
            is the epoch time the process was added.
        """
        handle = (id(context), process_name)
        it = self.processes.get(handle, {}).itervalues()
        entries = [x for x in it if x[0].poll() is None]
        return entries

    def add_instance(self, context, process_name, process):
        try:
            self.lock.acquire()
            entry = (id(context), process_name, process, int(time.time()))
            self.pending_procs.append(entry)
        finally:
            self.lock.release()

    def _update(self):
        # add pending instances
        if self.pending_procs:
            try:
                self.lock.acquire()
                pending_procs = self.pending_procs
                self.pending_procs = []
            finally:
                self.lock.release()

            for (context_id, process_name, process,
                 start_time) in pending_procs:
                handle = (context_id, process_name)
                procs = self.processes.get(handle)
                value = (process, start_time)

                if procs is None:
                    self.processes[handle] = {process.pid: value}
                    nprocs = 1
                else:
                    if process.pid not in procs:
                        procs[process.pid] = value
                    nprocs = len(procs)
                self.instanceCountChanged.emit(context_id, process_name,
                                               nprocs)

        # rebuild proc list to iterate over
        if self.processes and not self.proc_list:
            for (context_id, process_name), d in self.processes.iteritems():
                for proc, _ in d.itervalues():
                    entry = (context_id, process_name, proc)
                    self.proc_list.append(entry)

        # poll a proc
        if self.proc_list:
            context_id, process_name, proc = self.proc_list.pop()
            if proc.poll() is not None:
                nprocs = self._remove_proc(context_id, process_name, proc.pid)
                self.instanceCountChanged.emit(context_id, process_name,
                                               nprocs)

    def _remove_proc(self, context_id, process_name, pid):
        handle = (context_id, process_name)
        procs = self.processes.get(handle)
        if procs is None:
            return 0

        if pid in procs:
            del procs[pid]
        nprocs = len(procs)
        if not procs:
            del self.processes[handle]
        return nprocs
Example #25
0
    def __init__(self, context_model, parent=None, advanced=False):
        config_key = ("layout/window/advanced_resolve" if advanced
                      else "layout/window/resolve")
        super(ResolveDialog, self).__init__(parent)
        StoreSizeMixin.__init__(self, app.config, config_key)

        self.setWindowTitle("Resolve")
        self.setContentsMargins(0, 0, 0, 0)

        self.context_model = context_model
        self.advanced = advanced
        self.resolver = None
        self.thread = None
        self.started = False
        self._finished = False

        self.busy_cursor = QtGui.QCursor(QtCore.Qt.WaitCursor)

        self.edit = StreamableTextEdit()
        self.edit.setStyleSheet("font: 9pt 'Courier'")

        self.bar = QtGui.QProgressBar()
        self.bar.setRange(0, 10)

        self.save_context_btn = QtGui.QPushButton("Save Context As...")
        self.graph_btn = QtGui.QPushButton("View Graph...")
        self.ok_btn = QtGui.QPushButton("Ok")
        self.start_again_btn = QtGui.QPushButton("Start Again")
        self.cancel_btn = QtGui.QPushButton("Cancel")
        self.resolve_btn = QtGui.QPushButton("Resolve")
        self.ok_btn.hide()
        self.graph_btn.hide()
        self.start_again_btn.hide()
        self.save_context_btn.hide()

        btn_pane = create_pane([None,
                               self.save_context_btn,
                               self.graph_btn,
                               self.start_again_btn,
                               self.ok_btn,
                               self.cancel_btn,
                               self.resolve_btn],
                               not self.advanced)

        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.bar)
        layout.addWidget(self.edit, 1)

        self.resolve_group = None
        self.max_fails_combo = None
        self.verbosity_combo = None
        self.show_package_loads_checkbox = None

        # this is solely to execute _start_resolve() as soon as the dialog opens
        self.timer = QtCore.QTimer()
        self.timer.setInterval(1)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self._on_dialog_open)

        if self.advanced:
            self.resolve_group = QtGui.QGroupBox("resolve settings")

            label = QtGui.QLabel("maximum fails:")
            self.max_fails_combo = QtGui.QComboBox()
            self.max_fails_combo.setEditable(True)
            self.max_fails_combo.addItem("-")
            self.max_fails_combo.addItem("1")
            self.max_fails_combo.addItem("2")
            self.max_fails_combo.addItem("3")
            app.config.attach(self.max_fails_combo, "resolve/max_fails")
            max_fails_pane = create_pane([None, label, self.max_fails_combo], True)

            label = QtGui.QLabel("verbosity:")
            self.verbosity_combo = QtGui.QComboBox()
            self.verbosity_combo.addItem("0")
            self.verbosity_combo.addItem("1")
            self.verbosity_combo.addItem("2")
            app.config.attach(self.verbosity_combo, "resolve/verbosity")
            verbosity_pane = create_pane([None, label, self.verbosity_combo], True)

            self.show_package_loads_checkbox = QtGui.QCheckBox("show package loads")
            self.show_package_loads_checkbox.setLayoutDirection(QtCore.Qt.RightToLeft)
            app.config.attach(self.show_package_loads_checkbox, "resolve/show_package_loads")
            show_loads_pane = create_pane([None, self.show_package_loads_checkbox], True)

            self.timestamp_widget = TimestampWidget(self.context_model)
            context = self.context_model.context()
            if context and context.requested_timestamp:
                self.timestamp_widget.set_time(context.requested_timestamp)

            left_pane = create_pane([self.timestamp_widget, None], False,
                                    compact=True)

            right_pane = create_pane([max_fails_pane,
                                      verbosity_pane,
                                      show_loads_pane,
                                      None],
                                     False, compact=True)

            create_pane([left_pane, right_pane], True,
                        parent_widget=self.resolve_group)

            pane = create_pane([self.resolve_group, None, btn_pane], True)
            self.cancel_btn.hide()
            layout.addWidget(pane)
        else:
            self.resolve_btn.hide()
            layout.addWidget(btn_pane)

        self.setLayout(layout)

        self.cancel_btn.clicked.connect(self._cancel_resolve)
        self.resolve_btn.clicked.connect(self._start_resolve)
        self.graph_btn.clicked.connect(self._view_graph)
        self.save_context_btn.clicked.connect(self._save_context)
        self.start_again_btn.clicked.connect(self._reset)
        self.ok_btn.clicked.connect(self.close)
Example #26
0
 def _itemSelectionChanged(self):
     if not self.selectedIndexes():
         self.setCurrentIndex(QtCore.QModelIndex())
Example #27
0
class ContextModel(QtCore.QObject):
    """A model of a `ResolvedContext` object.

    Note that this is NOT a QAbstractItemModel subclass! A context does not lend
    itself to this data structure unfortunately.

    This model not only represents a context, but also contains the settings
    needed to create a new context, or re-resolve an existing context.
    """
    dataChanged = QtCore.Signal(int)

    # dataChanged flags
    REQUEST_CHANGED = 1
    PACKAGES_PATH_CHANGED = 2
    LOCKS_CHANGED = 4
    CONTEXT_CHANGED = 8
    LOADPATH_CHANGED = 16
    PACKAGE_FILTER_CHANGED = 32

    def __init__(self, context=None, parent=None):
        super(ContextModel, self).__init__(parent)

        self._context = None
        self._stale = True
        self._modified = True
        self._dependency_graph = None
        self._dependency_lookup = None

        self.request = []
        self.packages_path = config.packages_path
        self.implicit_packages = config.implicit_packages
        self.package_filter = config.package_filter
        self.default_patch_lock = PatchLock.no_lock
        self.patch_locks = {}

        if context:
            self._set_context(context)
            self._modified = False

    def copy(self):
        """Returns a copy of the context."""
        other = ContextModel(self._context, self.parent())
        other._stale = self._stale
        other._modified = self._modified
        other.request = self.request[:]
        other.packages_path = self.packages_path
        other.implicit_packages = self.implicit_packages
        other.package_filter = self.package_filter
        other.default_patch_lock = self.default_patch_lock
        other.patch_locks = copy.deepcopy(self.patch_locks)
        return other

    def is_stale(self):
        """Returns True if the context is stale.

        If the context is stale, this means there are pending changes. To update
        the model, you should call resolve_context().
        """
        return self._stale

    def is_modified(self):
        """Returns True if the context has been changed since save/load, False
        otherwise.

        If the context has never been saved, True is always returned.
        """
        return self._modified

    def package_depends_on(self, name_a, name_b):
        """Returns dependency information about two packages:

            0: A does not depend, directly or indirectly, on B;
            1: A depends indirectly on B;
            2: A depends directly on B.
        """
        assert self._context
        if self._dependency_lookup is None:
            self._dependency_graph = self._context.get_dependency_graph()
            self._dependency_lookup = accessibility(self._dependency_graph)

        downstream = self._dependency_lookup.get(name_a, [])
        accessible = (name_b in downstream)
        if accessible:
            neighbours = self._dependency_graph.neighbors(name_a)
            return 2 if name_b in neighbours else 1
        else:
            return 0

    def context(self):
        """Return the current context, if any."""
        return self._context

    def filepath(self):
        """Return the path the current context was saved/loaded to, if any."""
        return self._context.load_path if self._context else None

    def get_patch_lock(self, package_name):
        """Return the patch lock associated with the package, or None."""
        return self.patch_locks.get(package_name)

    def get_lock_requests(self):
        """Take the current context, and the current patch locks, and determine
        the effective requests that will be added to the main request.

        Returns:
            A dict of (PatchLock, [Requirement]) tuples. Each requirement will be
            a weak package reference. If there is no current context, an empty
            dict will be returned.
        """
        d = defaultdict(list)
        if self._context:
            for variant in self._context.resolved_packages:
                name = variant.name
                version = variant.version
                lock = self.patch_locks.get(name)
                if lock is None:
                    lock = self.default_patch_lock

                request = get_lock_request(name, version, lock)
                if request is not None:
                    d[lock].append(request)
        return d

    def set_request(self, request_strings):
        self._attr_changed("request", request_strings, self.REQUEST_CHANGED)

    def set_packages_path(self, packages_path):
        self._attr_changed("packages_path", packages_path, self.PACKAGES_PATH_CHANGED)

    def set_package_filter(self, package_filter):
        self._attr_changed("package_filter", package_filter, self.PACKAGE_FILTER_CHANGED)

    def save(self, filepath):
        assert self._context
        assert not self._stale
        self._context.save(filepath)
        self._context.set_load_path(filepath)
        self._modified = False
        self.dataChanged.emit(self.LOADPATH_CHANGED)

    def set_default_patch_lock(self, lock):
        self._attr_changed("default_patch_lock", lock, self.LOCKS_CHANGED)

    def set_patch_lock(self, package_name, lock):
        existing_lock = self.patch_locks.get(package_name)
        if lock != existing_lock:
            self.patch_locks[package_name] = lock
            self._changed(self.LOCKS_CHANGED)

    def remove_patch_lock(self, package_name):
        if package_name in self.patch_locks:
            del self.patch_locks[package_name]
            self._changed(self.LOCKS_CHANGED)

    def remove_all_patch_locks(self):
        if self.patch_locks:
            self.patch_locks = {}
            self._changed(self.LOCKS_CHANGED)

    def resolve_context(self, verbosity=0, max_fails=-1, timestamp=None,
                        callback=None, buf=None, package_load_callback=None):
        """Update the current context by performing a re-resolve.

        The newly resolved context is only applied if it is a successful solve.

        Returns:
            `ResolvedContext` object, which may be a successful or failed solve.
        """
        package_filter = PackageFilterList.from_pod(self.package_filter)

        context = ResolvedContext(
            self.request,
            package_paths=self.packages_path,
            package_filter=package_filter,
            verbosity=verbosity,
            max_fails=max_fails,
            timestamp=timestamp,
            buf=buf,
            callback=callback,
            package_load_callback=package_load_callback)

        if context.success:
            if self._context and self._context.load_path:
                context.set_load_path(self._context.load_path)
            self._set_context(context)
            self._modified = True
        return context

    def can_revert(self):
        """Return True if the model is revertable, False otherwise."""
        return bool(self._stale and self._context)

    def revert(self):
        """Discard any pending changes."""
        if self.can_revert():
            self._set_context(self._context)

    def set_context(self, context):
        """Replace the current context with another."""
        self._set_context(context, emit=False)
        self._modified = (not context.load_path)
        self.dataChanged.emit(self.CONTEXT_CHANGED |
                              self.REQUEST_CHANGED |
                              self.PACKAGES_PATH_CHANGED |
                              self.LOCKS_CHANGED |
                              self.LOADPATH_CHANGED |
                              self.PACKAGE_FILTER_CHANGED)

    def _set_context(self, context, emit=True):
        self._context = context
        self._stale = False
        self._dependency_lookup = None

        self.request = [str(x) for x in context.requested_packages()]
        self.packages_path = context.package_paths
        self.implicit_packages = context.implicit_packages[:]
        self.package_filter = context.package_filter.to_pod()
        self.default_patch_lock = context.default_patch_lock
        self.patch_locks = copy.deepcopy(context.patch_locks)
        if emit:
            self.dataChanged.emit(self.CONTEXT_CHANGED |
                                  self.REQUEST_CHANGED |
                                  self.PACKAGES_PATH_CHANGED |
                                  self.LOCKS_CHANGED)

    def _changed(self, flags):
        self._stale = True
        self._modified = True
        self.dataChanged.emit(flags)

    def _attr_changed(self, attr, value, flags):
        if getattr(self, attr) == value:
            return
        setattr(self, attr, value)
        self._changed(flags)
Example #28
0
class ContextManagerWidget(QtGui.QWidget, ContextViewMixin):

    diffModeChanged = QtCore.Signal()

    def __init__(self, context_model=None, parent=None):
        super(ContextManagerWidget, self).__init__(parent)
        ContextViewMixin.__init__(self, context_model)

        # widgets
        self.popup = None
        self.context_table = ContextTableWidget(self.context_model)
        self.show_effective_request_checkbox = QtGui.QCheckBox(
            "show effective request")

        resolve_time_label = ContextResolveTimeLabel(self.context_model)

        self.time_lock_tbtn = QtGui.QToolButton()
        icon = get_icon("time_lock", as_qicon=True)
        self.time_lock_tbtn.setIcon(icon)

        self.find_tbtn = QtGui.QToolButton()
        self.find_tbtn.setToolTip("find resolved package")
        icon = get_icon("find", as_qicon=True)
        self.find_tbtn.setIcon(icon)

        self.shell_tbtn = QtGui.QToolButton()
        self.shell_tbtn.setToolTip("open shell")
        icon = get_icon("terminal", as_qicon=True)
        self.shell_tbtn.setIcon(icon)

        self.diff_tbtn = QtGui.QToolButton()
        self.diff_tbtn.setToolTip("enter diff mode")
        self.diff_tbtn.setPopupMode(QtGui.QToolButton.MenuButtonPopup)
        self.diff_menu = QtGui.QMenu()
        self.diff_action = add_menu_action(self.diff_menu,
                                           "Diff Against Current",
                                           self._diff_with_last_resolve,
                                           "diff")
        self.diff_to_disk_action = add_menu_action(self.diff_menu,
                                                   "Diff Against Disk",
                                                   self._diff_with_disk,
                                                   "diff_to_disk")
        self.diff_to_other_action = add_menu_action(self.diff_menu,
                                                    "Diff Against Other...",
                                                    self._diff_with_other,
                                                    "diff_to_other")
        self.diff_tbtn.setMenu(self.diff_menu)
        self.diff_tbtn.setDefaultAction(self.diff_action)

        self.undiff_tbtn = QtGui.QToolButton()
        self.undiff_tbtn.setToolTip("leave diff mode")
        icon = get_icon("diff", as_qicon=True)
        self.undiff_tbtn.setIcon(icon)
        self.undiff_tbtn.setCheckable(True)

        self.lock_tbtn = QtGui.QToolButton()
        self.lock_tbtn.setToolTip("locking")
        icon = get_icon("no_lock", as_qicon=True)
        self.lock_tbtn.setIcon(icon)
        self.lock_tbtn.setPopupMode(QtGui.QToolButton.InstantPopup)
        menu = QtGui.QMenu()
        for lock_type in PatchLock:
            fn = partial(self._set_lock_type, lock_type)
            add_menu_action(menu, lock_type.description, fn, lock_type.name)
        menu.addSeparator()
        add_menu_action(menu, "Remove Explicit Locks",
                        self._removeExplicitLocks)
        self.lock_tbtn.setMenu(menu)

        self.revert_tbtn = QtGui.QToolButton()
        self.revert_tbtn.setToolTip("revert")
        icon = get_icon("revert", as_qicon=True)
        self.revert_tbtn.setIcon(icon)
        self.revert_tbtn.setPopupMode(QtGui.QToolButton.InstantPopup)

        self.revert_menu = QtGui.QMenu()
        self.revert_action = add_menu_action(self.revert_menu,
                                             "Revert To Last Resolve...",
                                             self._revert_to_last_resolve,
                                             "revert")
        self.revert_diff_action = add_menu_action(self.revert_menu,
                                                  "Revert To Reference...",
                                                  self._revert_to_diff,
                                                  "revert_to_diff")
        self.revert_disk_action = add_menu_action(self.revert_menu,
                                                  "Revert To Disk...",
                                                  self._revert_to_disk,
                                                  "revert_to_disk")
        self.revert_tbtn.setMenu(self.revert_menu)

        resolve_tbtn = QtGui.QToolButton()
        resolve_tbtn.setPopupMode(QtGui.QToolButton.MenuButtonPopup)
        menu = QtGui.QMenu()
        default_resolve_action = add_menu_action(menu, "Resolve",
                                                 self._resolve, "resolve")
        add_menu_action(menu, "Advanced Resolve...",
                        partial(self._resolve, advanced=True),
                        "advanced_resolve")
        resolve_tbtn.setDefaultAction(default_resolve_action)
        resolve_tbtn.setMenu(menu)

        toolbar = QtGui.QToolBar()
        toolbar.addWidget(resolve_time_label)
        self.time_lock_tbtn_action = toolbar.addWidget(self.time_lock_tbtn)
        toolbar.addSeparator()
        toolbar.addWidget(self.find_tbtn)
        toolbar.addWidget(self.shell_tbtn)
        self.diff_tbtn_action = toolbar.addWidget(self.diff_tbtn)
        self.undiff_tbtn_action = toolbar.addWidget(self.undiff_tbtn)
        toolbar.addWidget(self.lock_tbtn)
        toolbar.addWidget(self.revert_tbtn)
        toolbar.addWidget(resolve_tbtn)
        self.time_lock_tbtn_action.setVisible(False)
        self.undiff_tbtn_action.setVisible(False)

        self.time_lock_tbtn.setCursor(QtCore.Qt.PointingHandCursor)
        self.find_tbtn.setCursor(QtCore.Qt.PointingHandCursor)
        self.shell_tbtn.setCursor(QtCore.Qt.PointingHandCursor)
        self.diff_tbtn.setCursor(QtCore.Qt.PointingHandCursor)
        self.lock_tbtn.setCursor(QtCore.Qt.PointingHandCursor)
        self.revert_tbtn.setCursor(QtCore.Qt.PointingHandCursor)
        resolve_tbtn.setCursor(QtCore.Qt.PointingHandCursor)

        btn_pane = create_pane(
            [self.show_effective_request_checkbox, None, toolbar],
            True,
            compact=True,
            compact_spacing=0)

        context_pane = create_pane([btn_pane, self.context_table],
                                   False,
                                   compact=True,
                                   compact_spacing=0)

        self.package_tab = PackageTabWidget(self.context_model,
                                            versions_tab=True)

        context_splitter = ConfiguredSplitter(app.config,
                                              "layout/splitter/main")
        context_splitter.setOrientation(QtCore.Qt.Vertical)
        context_splitter.addWidget(context_pane)
        context_splitter.addWidget(self.package_tab)
        if not context_splitter.apply_saved_layout():
            context_splitter.setStretchFactor(0, 2)
            context_splitter.setStretchFactor(1, 1)

        self.settings = ContextSettingsWidget(self.context_model)
        self.tools_list = ContextToolsWidget(self.context_model)
        self.resolve_details = ContextDetailsWidget(self.context_model)

        self.tab = QtGui.QTabWidget()
        icon = get_icon("context", as_qicon=True)
        self.tab.addTab(context_splitter, icon, "context")
        icon = get_icon("context_settings", as_qicon=True)
        self.tab.addTab(self.settings, icon, "settings")
        icon = get_icon("tools", as_qicon=True)
        self.tab.addTab(self.tools_list, icon, "tools")
        icon = get_icon("info", as_qicon=True)
        self.tab.addTab(self.resolve_details, icon, "resolve details")
        self.tab.setTabEnabled(2, False)
        self.tab.setTabEnabled(3, False)

        # layout
        layout = QtGui.QVBoxLayout()
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.tab)
        self.setLayout(layout)

        # shortcuts
        find_shortcut = QtGui.QShortcut(QtGui.QKeySequence("Ctrl+F"), self)
        find_shortcut.activated.connect(self._search)

        # widget signals
        self.context_table.variantSelected.connect(self._variantSelected)
        self.find_tbtn.clicked.connect(self._search_variant)
        self.shell_tbtn.clicked.connect(self._open_shell)
        self.undiff_tbtn.clicked.connect(self._leave_diff_mode)
        self.time_lock_tbtn.clicked.connect(self._timelockClicked)
        self.tools_list.toolsChanged.connect(self._updateToolsCount)
        self.diff_menu.aboutToShow.connect(self._aboutToShowDiffMenu)
        self.revert_menu.aboutToShow.connect(self._aboutToShowRevertMenu)
        self.show_effective_request_checkbox.stateChanged.connect(
            self._effectiveRequestStateChanged)

        self.refresh()
        self._updateToolsCount()

    def sizeHint(self):
        return QtCore.QSize(800, 500)

    def get_title(self):
        """Returns a string suitable for titling a window containing this widget."""
        return self.context_table.get_title()

    def refresh(self):
        self._contextChanged(ContextModel.CONTEXT_CHANGED)

    def _resolve(self, advanced=False):
        dlg = ResolveDialog(self.context_model, parent=self, advanced=advanced)
        dlg.resolve()  # this updates the model on successful solve

    def _changes_prompt(self):
        ret = QtGui.QMessageBox.warning(
            self, "The context has been modified.",
            "Your changes will be lost. Are you sure?", QtGui.QMessageBox.Ok,
            QtGui.QMessageBox.Cancel)
        return (ret == QtGui.QMessageBox.Ok)

    def _revert_to_last_resolve(self):
        assert self.context_model.can_revert()
        if self._changes_prompt():
            self.context_model.revert()

    def _revert_to_diff(self):
        if self._changes_prompt():
            self.context_table.revert_to_diff()

    def _revert_to_disk(self):
        if self._changes_prompt():
            self.context_table.revert_to_disk()

    def _open_shell(self):
        assert self.context()
        app.execute_shell(context=self.context(), terminal=True)

    def _leave_diff_mode(self):
        self.context_table.leave_diff_mode()
        self._change_diff_mode(False)

    def _diff_with_last_resolve(self):
        self.context_table.enter_diff_mode()
        self._change_diff_mode(True)

    def _diff_with_disk(self):
        filepath = self.context_model.filepath()
        self._diff_with_file(filepath)

    def _diff_with_other(self):
        filepath = QtGui.QFileDialog.getOpenFileName(
            self, "Open Context", filter="Context files (*.rxt)")
        if filepath:
            self._diff_with_file(str(filepath))

    def _diff_with_file(self, filepath):
        assert filepath
        disk_context = app.load_context(filepath)
        model = ContextModel(disk_context)
        self.context_table.enter_diff_mode(model)
        self._change_diff_mode(True)

    def _change_diff_mode(self, enabled):
        self.undiff_tbtn.setChecked(enabled)
        self.diff_tbtn_action.setVisible(not enabled)
        self.undiff_tbtn_action.setVisible(enabled)
        self.diffModeChanged.emit()

    def _aboutToShowDiffMenu(self):
        stale = self.context_model.is_stale()
        self.diff_action.setEnabled(not stale)
        self.diff_to_other_action.setEnabled(not stale)
        self.diff_to_disk_action.setEnabled(
            bool(self.context_model.filepath()) and not stale)

    def _aboutToShowRevertMenu(self):
        model = self.context_model
        self.revert_action.setEnabled(model.can_revert())
        self.revert_disk_action.setEnabled(
            bool(model.filepath()) and model.is_modified())
        self.revert_diff_action.setEnabled(
            self.context_table.diff_mode
            and self.context_table.diff_from_source and not model.is_stale())

    def _contextChanged(self, flags=0):
        stale = self.context_model.is_stale()
        context = self.context()
        is_context = bool(context)

        self.diff_action.setEnabled(not stale)
        self.diff_tbtn.setEnabled(not stale)
        self.undiff_tbtn.setEnabled(not stale)
        self.shell_tbtn.setEnabled(not stale)
        self.lock_tbtn.setEnabled(is_context)
        self.find_tbtn.setEnabled(is_context)

        self.tab.setTabEnabled(2, is_context)
        self.tab.setTabEnabled(3, is_context)
        tab_text = "context*" if stale else "context"
        self.tab.setTabText(0, tab_text)

        context_changed = (flags & ContextModel.CONTEXT_CHANGED)

        if context_changed:
            if is_context and context.requested_timestamp:
                t = time.localtime(context.requested_timestamp)
                t_str = time.strftime("%a %b %d %H:%M:%S %Y", t)
                txt = "packages released after %s were ignored" % t_str
                self.time_lock_tbtn.setToolTip(txt)
                self.time_lock_tbtn_action.setVisible(True)
            else:
                self.time_lock_tbtn_action.setVisible(False)

        settings_modified = ((flags & ContextModel.PACKAGES_PATH_CHANGED)
                             and not context_changed)
        label = "settings*" if settings_modified else "settings"
        self.tab.setTabText(1, label)

        if flags & (ContextModel.LOCKS_CHANGED | ContextModel.CONTEXT_CHANGED):
            lock_type = self.context_model.default_patch_lock
            icon = get_icon(lock_type.name, as_qicon=True)
            self.lock_tbtn.setIcon(icon)

    def _variantSelected(self, variant):
        self.package_tab.set_variant(variant)

    def _effectiveRequestStateChanged(self, state):
        self.context_table.show_effective_request(state == QtCore.Qt.Checked)

    def _timelockClicked(self):
        title = "The resolve is timelocked"
        body = str(self.time_lock_tbtn.toolTip()).capitalize()
        secs = int(time.time()) - self.context().requested_timestamp
        t_str = readable_time_duration(secs)
        body += "\n(%s ago)" % t_str
        QtGui.QMessageBox.information(self, title, body)

    def _set_lock_type(self, lock_type):
        self.context_model.set_default_patch_lock(lock_type)

    def _updateToolsCount(self):
        label = "tools (%d)" % self.tools_list.num_tools()
        self.tab.setTabText(2, label)

    def _removeExplicitLocks(self):
        self.context_model.remove_all_patch_locks()

    def _search(self):
        tab_index = self.tab.currentIndex()
        if tab_index == 0:
            self._search_variant()
        elif tab_index == 3:
            self.resolve_details.search()

    def _search_variant(self):
        context = self.context()
        if not context:
            return

        words = [x.name for x in context.resolved_packages]
        self.popup = FindPopup(self.find_tbtn,
                               "bottomLeft",
                               words,
                               parent=self)
        self.popup.find.connect(self.context_table.select_variant)
        self.popup.show()
Example #29
0
 def _clear_selection(self):
     self.clearSelection()
     self.setCurrentIndex(QtCore.QModelIndex())
Example #30
0
 def sizeHint(self):
     return QtCore.QSize(800, 500)