Example #1
0
class DistributionSelector(QWidget):
    """Python distribution selector widget"""
    TITLE = 'Select a Python distribution path'

    # Signals after PyQt4 old SIGNAL removal
    selected_distribution = Signal(str)

    def __init__(self, parent):
        super(DistributionSelector, self).__init__(parent)
        self.browse_btn = None
        self.label = None
        self.line_edit = None
        self.setup_widget()

    def set_distribution(self, path):
        """Set distribution directory"""
        self.line_edit.setText(path)

    def setup_widget(self):
        """Setup workspace selector widget"""
        self.label = QLabel()
        self.line_edit = QLineEdit()
        self.line_edit.setAlignment(Qt.AlignRight)
        self.line_edit.setReadOnly(True)
        # self.line_edit.setDisabled(True)
        self.browse_btn = QPushButton(get_std_icon('DirOpenIcon'), "", self)
        self.browse_btn.setToolTip(self.TITLE)
        # PyQt4 old SIGNAL:self.connect(self.browse_btn, SIGNAL("clicked()"),
        # PyQt4 old SIGNAL:             self.select_directory)
        self.browse_btn.clicked.connect(self.select_directory)
        layout = QHBoxLayout()
        layout.addWidget(self.label)
        layout.addWidget(self.line_edit)
        layout.addWidget(self.browse_btn)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

    def select_directory(self):
        """Select directory"""
        basedir = to_text_string(self.line_edit.text())
        if not osp.isdir(basedir):
            basedir = getcwd()
        while True:
            directory = getexistingdirectory(self, self.TITLE, basedir)
            if not directory:
                break
            if not utils.is_python_distribution(directory):
                QMessageBox.warning(
                    self, self.TITLE,
                    "The following directory is not a Python distribution.",
                    QMessageBox.Ok)
                basedir = directory
                continue
            directory = osp.abspath(osp.normpath(directory))
            self.set_distribution(directory)
            # PyQt4 old SIGNAL: self.emit(SIGNAL('selected_distribution(QString)'), directory)
            self.selected_distribution.emit(directory)
            break
Example #2
0
class MacApplication(QApplication):
    """Subclass to be able to open external files with our Mac app"""
    open_external_file = Signal(str)

    def __init__(self, *args):
        QApplication.__init__(self, *args)

    def event(self, event):
        if event.type() == QEvent.FileOpen:
            fname = str(event.file())
            # PyQt4 old SIGNAL: self.emit(SIGNAL('open_external_file(QString)'), fname)
            self.open_external_file.emit(fname)
        return QApplication.event(self, event)
Example #3
0
class PackagesModel(QAbstractTableModel):
    # Signals after PyQt4 old SIGNAL removal
    dataChanged = Signal(QModelIndex, QModelIndex)

    def __init__(self):
        QAbstractTableModel.__init__(self)
        self.packages = []
        self.checked = set()
        self.actions = {}

    def sortByName(self):
        self.packages = sorted(self.packages, key=lambda x: x.name)
        self.reset()

    def flags(self, index):
        if not index.isValid():
            return Qt.ItemIsEnabled
        column = index.column()
        if column in (NAME, VERSION, ACTION, DESCRIPTION):
            return Qt.ItemFlags(QAbstractTableModel.flags(self, index))
        else:
            return Qt.ItemFlags(
                QAbstractTableModel.flags(self, index) | Qt.ItemIsUserCheckable
                | Qt.ItemIsEditable)

    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid() or not (0 <= index.row() < len(self.packages)):
            return to_qvariant()
        package = self.packages[index.row()]
        column = index.column()
        if role == Qt.CheckStateRole and column == CHECK:
            return to_qvariant(package in self.checked)
        elif role == Qt.DisplayRole:
            if column == NAME:
                return to_qvariant(package.name)
            elif column == VERSION:
                return to_qvariant(package.version)
            elif column == ACTION:
                action = self.actions.get(package)
                if action is not None:
                    return to_qvariant(action)
            elif column == DESCRIPTION:
                return to_qvariant(package.description)
        elif role == Qt.TextAlignmentRole:
            if column == ACTION:
                return to_qvariant(int(Qt.AlignRight | Qt.AlignVCenter))
            else:
                return to_qvariant(int(Qt.AlignLeft | Qt.AlignVCenter))
        elif role == Qt.BackgroundColorRole:
            if package in self.checked:
                color = QColor(Qt.darkGreen)
                color.setAlphaF(.1)
                return to_qvariant(color)
            else:
                color = QColor(Qt.lightGray)
                color.setAlphaF(.3)
                return to_qvariant(color)
        return to_qvariant()

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if role == Qt.TextAlignmentRole:
            if orientation == Qt.Horizontal:
                return to_qvariant(int(Qt.AlignHCenter | Qt.AlignVCenter))
            return to_qvariant(int(Qt.AlignRight | Qt.AlignVCenter))
        if role != Qt.DisplayRole:
            return to_qvariant()
        if orientation == Qt.Horizontal:
            if section == NAME:
                return to_qvariant("Name")
            elif section == VERSION:
                return to_qvariant("Version")
            elif section == ACTION:
                return to_qvariant("Action")
            elif section == DESCRIPTION:
                return to_qvariant("Description")
        return to_qvariant()

    def rowCount(self, index=QModelIndex()):
        return len(self.packages)

    def columnCount(self, index=QModelIndex()):
        return len(COLUMNS)

    def setData(self, index, value, role=Qt.EditRole):
        if index.isValid() and 0 <= index.row() < len(self.packages)\
           and role == Qt.CheckStateRole:
            package = self.packages[index.row()]
            if package in self.checked:
                self.checked.remove(package)
            else:
                self.checked.add(package)
            # PyQt4 old SIGNAL: self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"),
            # PyQt4 old SIGNAL:           index, index)
            self.dataChanged.emit(index, index)
            return True
        return False
Example #4
0
class PackagesTable(QTableView):
    # Signals after PyQt4 old SIGNAL removal, to be emitted after package_added event
    package_added = Signal()

    def __init__(self, parent, process, winname):
        QTableView.__init__(self, parent)
        assert process in ('install', 'uninstall')
        self.process = process
        self.model = PackagesModel()
        self.setModel(self.model)
        self.winname = winname
        self.repair = False
        self.resizeColumnToContents(0)
        self.setAcceptDrops(process == 'install')
        if process == 'uninstall':
            self.hideColumn(0)
        self.distribution = None

        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.verticalHeader().hide()
        self.setShowGrid(False)

    def reset_model(self):
        # self.model.reset() is deprecated in Qt5
        self.model.beginResetModel()
        self.model.endResetModel()
        self.horizontalHeader().setStretchLastSection(True)
        for colnb in (ACTION, CHECK, NAME, VERSION):
            self.resizeColumnToContents(colnb)

    def get_selected_packages(self):
        """Return selected packages"""
        return [
            pack for pack in self.model.packages if pack in self.model.checked
        ]

    def add_packages(self, fnames):
        """Add packages"""
        notsupported = []
        notcompatible = []
        dist = self.distribution
        for fname in fnames:
            bname = osp.basename(fname)
            try:
                package = wppm.Package(fname)
                if package.is_compatible_with(dist):
                    self.add_package(package)
                else:
                    notcompatible.append(bname)
            except NotImplementedError:
                notsupported.append(bname)
        # PyQt4 old SIGNAL: self.emit(SIGNAL('package_added()'))
        self.package_added.emit()
        if notsupported:
            QMessageBox.warning(
                self, "Warning",
                "The following packages filenaming are <b>not "
                "recognized</b> by %s:\n\n%s" %
                (self.winname, "<br>".join(notsupported)), QMessageBox.Ok)
        if notcompatible:
            QMessageBox.warning(
                self, "Warning", "The following packages "
                "are <b>not compatible</b> with "
                "Python <u>%s %dbit</u>:\n\n%s" %
                (dist.version, dist.architecture, "<br>".join(notcompatible)),
                QMessageBox.Ok)

    def add_package(self, package):
        for pack in self.model.packages:
            if pack.name == package.name:
                return
        self.model.packages.append(package)
        self.model.packages.sort(key=lambda x: x.name)
        self.model.checked.add(package)
        self.reset_model()

    def remove_package(self, package):
        self.model.packages = [
            pack for pack in self.model.packages if pack.fname != package.fname
        ]
        if package in self.model.checked:
            self.model.checked.remove(package)
        if package in self.model.actions:
            self.model.actions.pop(package)
        self.reset_model()

    def refresh_distribution(self, dist):
        self.distribution = dist
        if self.process == 'install':
            for package in self.model.packages:
                pack = dist.find_package(package.name)
                if pack is None:
                    action = INSTALL_ACTION
                elif pack.version == package.version:
                    if self.repair:
                        action = REPAIR_ACTION
                    else:
                        action = NO_REPAIR_ACTION
                else:
                    action = UPGRADE_ACTION + pack.version
                self.model.actions[package] = action
        else:
            self.model.packages = self.distribution.get_installed_packages()
            for package in self.model.packages:
                self.model.actions[package] = NONE_ACTION
        self.reset_model()

    def select_all(self):
        allpk = set(self.model.packages)
        if self.model.checked == allpk:
            self.model.checked = set()
        else:
            self.model.checked = allpk
        self.model.reset()

    def dragMoveEvent(self, event):
        """Reimplement Qt method, just to avoid default drag'n drop
        implementation of QTableView to handle events"""
        event.acceptProposedAction()

    def dragEnterEvent(self, event):
        """Reimplement Qt method
        Inform Qt about the types of data that the widget accepts"""
        source = event.mimeData()
        if source.hasUrls() and mimedata2url(source):
            event.acceptProposedAction()

    def dropEvent(self, event):
        """Reimplement Qt method
        Unpack dropped data and handle it"""
        source = event.mimeData()
        fnames = [path for path in mimedata2url(source) if osp.isfile(path)]
        self.add_packages(fnames)
        event.acceptProposedAction()