コード例 #1
0
    def create_controls(self):
        table = QTableView(self)
        self.model = PluginsModel(self.plugin_manager)
        table.setModel(self.model)
        h = table.horizontalHeader()
        h.setSectionResizeMode(QHeaderView.ResizeToContents)
        table.setHorizontalHeader(h)
        h = table.verticalHeader()
        h.setSectionResizeMode(QHeaderView.ResizeToContents)
        table.setVerticalHeader(h)
        self.table = table
        width = 80
        for i in range(3):
            width += table.columnWidth(i)

        btns = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel,
                                Qt.Horizontal)
        self.edit_btn = QPushButton("Edit")
        btns.addButton(self.edit_btn, QDialogButtonBox.ActionRole)
        self.edit_btn.clicked.connect(self.edit_plugin)
        btns.accepted.connect(self.accept)
        btns.rejected.connect(self.reject)

        vbox = QVBoxLayout()
        vbox.addWidget(table)
        vbox.addWidget(btns)
        self.setLayout(vbox)
        s = self.size()
        s.setHeight(table.rowHeight(0) * 10)
        s.setWidth(width)
        self.resize(s)
コード例 #2
0
ファイル: close.py プロジェクト: Discalced51/conda-manager
class ClosePackageManagerDialog(QDialog):
    """
    """
    def __init__(self, *args, **kwargs):
        super(ClosePackageManagerDialog, self).__init__(*args, **kwargs)
        self.label_icon = QLabel()
        self.label_about = QLabel('Conda is still busy.\n\n'
                                  'Do you want to cancel the process?')
        self.button_ok = QPushButton('Yes')
        self.button_cancel = QPushButton('No')
        self.buttonbox = QDialogButtonBox(Qt.Horizontal)

        # Widget setup
        self.buttonbox.addButton(self.button_ok, QDialogButtonBox.ActionRole)
        self.buttonbox.addButton(self.button_cancel,
                                 QDialogButtonBox.ActionRole)
#        self.label_icon.setPixmap(QPixmap(images.ANACONDA_ICON_64_PATH))
        self.setWindowTitle("Cancel Process")

        # Layouts
        h_layout = QHBoxLayout()
        h_layout.addWidget(self.label_icon, 0, Qt.AlignTop)
        h_layout.addSpacing(10)
        h_layout.addWidget(self.label_about)

        main_layout = QVBoxLayout()
        main_layout.addLayout(h_layout)
        main_layout.addSpacing(20)
        main_layout.addWidget(self.buttonbox)
        self.setLayout(main_layout)

        # Signals
        self.button_ok.clicked.connect(self.accept)
        self.button_cancel.clicked.connect(self.reject)
コード例 #3
0
    def _init_layout(self):
        self.setMinimumWidth(600)
        self.setMinimumHeight(400)

        dialog_buttons = QDialogButtonBox(QDialogButtonBox.Ok)
        dialog_buttons.accepted.connect(self.accept)

        self._copy_all_button = dialog_buttons.addButton(
            "Copy All", QDialogButtonBox.ActionRole)
        self._copy_all_button.clicked.connect(self._copy_all)

        self._follow_button = dialog_buttons.addButton(
            "Follow", QDialogButtonBox.ActionRole)
        self._follow_button.setCheckable(True)
        self._follow_button.toggled.connect(self._enable_follow_mode)
        self._enable_follow_mode(self._follow_mode)

        layout = QVBoxLayout(self)
        layout.addWidget(self._view)
        layout.addWidget(dialog_buttons)
コード例 #4
0
 def add_button_box(self, stdbtns):
     """Create dialog button box and add it to the dialog layout"""
     bbox = QDialogButtonBox(stdbtns)
     run_btn = bbox.addButton(_("Run"), QDialogButtonBox.AcceptRole)
     run_btn.clicked.connect(self.run_btn_clicked)
     bbox.accepted.connect(self.accept)
     bbox.rejected.connect(self.reject)
     btnlayout = QHBoxLayout()
     btnlayout.addStretch(1)
     btnlayout.addWidget(bbox)
     self.layout().addLayout(btnlayout)
コード例 #5
0
ファイル: runconfig.py プロジェクト: burrbull/spyder
 def add_button_box(self, stdbtns):
     """Create dialog button box and add it to the dialog layout"""
     bbox = QDialogButtonBox(stdbtns)
     run_btn = bbox.addButton(_("Run"), QDialogButtonBox.AcceptRole)
     run_btn.clicked.connect(self.run_btn_clicked)
     bbox.accepted.connect(self.accept)
     bbox.rejected.connect(self.reject)
     btnlayout = QHBoxLayout()
     btnlayout.addStretch(1)
     btnlayout.addWidget(bbox)
     self.layout().addLayout(btnlayout)
コード例 #6
0
ファイル: historydialog.py プロジェクト: ECGKit/mnelab
 def __init__(self, parent, history):
     super().__init__(parent=parent)
     self.setWindowTitle("History")
     layout = QVBoxLayout()
     text = QPlainTextEdit()
     font = QFont()
     font.setFamily("monospace")
     font.setStyleHint(QFont.Monospace)
     text.setFont(font)
     highlighter = PythonHighlighter(text.document())  # noqa: F841
     text.setReadOnly(True)
     text.setPlainText(history)
     layout.addWidget(text)
     buttonbox = QDialogButtonBox(QDialogButtonBox.Ok)
     clipboardbutton = QPushButton("Copy to clipboard")
     buttonbox.addButton(clipboardbutton, QDialogButtonBox.ActionRole)
     clipboard = QGuiApplication.clipboard()
     clipboardbutton.clicked.connect(
         lambda: clipboard.setText(history + "\n"))
     layout.addWidget(buttonbox)
     self.setLayout(layout)
     buttonbox.accepted.connect(self.accept)
     self.resize(700, 500)
コード例 #7
0
class ProjectDialog(QDialog):
    """Project creation dialog."""

    sig_project_creation_requested = Signal(str, str, object)
    """
    This signal is emitted to request the Projects plugin the creation of a
    project.

    Parameters
    ----------
    project_path: str
        Location of project.
    project_type: str	
        Type of project as defined by project types.	
    project_packages: object	
        Package to install. Currently not in use.	
    """

    def __init__(self, parent, project_types):
        """Project creation dialog."""
        super(ProjectDialog, self).__init__(parent=parent)
        self.plugin = parent
        self._project_types = project_types
        self.project_data = {}

        # Variables
        current_python_version = '.'.join([to_text_string(sys.version_info[0]),
                                           to_text_string(sys.version_info[1])])
        python_versions = ['2.7', '3.4', '3.5']
        if current_python_version not in python_versions:
            python_versions.append(current_python_version)
            python_versions = sorted(python_versions)

        self.project_name = None
        self.location = get_home_dir()

        # Widgets
        self.groupbox = QGroupBox()
        self.radio_new_dir = QRadioButton(_("New directory"))
        self.radio_from_dir = QRadioButton(_("Existing directory"))

        self.label_project_name = QLabel(_('Project name'))
        self.label_location = QLabel(_('Location'))
        self.label_project_type = QLabel(_('Project type'))
        self.label_python_version = QLabel(_('Python version'))

        self.text_project_name = QLineEdit()
        self.text_location = QLineEdit(get_home_dir())
        self.combo_project_type = QComboBox()
        self.combo_python_version = QComboBox()

        self.label_information = QLabel("")

        self.button_select_location = QToolButton()
        self.button_cancel = QPushButton(_('Cancel'))
        self.button_create = QPushButton(_('Create'))

        self.bbox = QDialogButtonBox(Qt.Horizontal)
        self.bbox.addButton(self.button_cancel, QDialogButtonBox.ActionRole)
        self.bbox.addButton(self.button_create, QDialogButtonBox.ActionRole)

        # Widget setup
        self.combo_python_version.addItems(python_versions)
        self.radio_new_dir.setChecked(True)
        self.text_location.setEnabled(True)
        self.text_location.setReadOnly(True)
        self.button_select_location.setIcon(get_std_icon('DirOpenIcon'))
        self.button_cancel.setDefault(True)
        self.button_cancel.setAutoDefault(True)
        self.button_create.setEnabled(False)
        for (id_, name) in [(pt_id, pt.get_name()) for pt_id, pt
                            in project_types.items()]:
            self.combo_project_type.addItem(name, id_)

        self.combo_python_version.setCurrentIndex(
            python_versions.index(current_python_version))
        self.setWindowTitle(_('Create new project'))
        self.setFixedWidth(500)
        self.label_python_version.setVisible(False)
        self.combo_python_version.setVisible(False)

        # Layouts
        layout_top = QHBoxLayout()
        layout_top.addWidget(self.radio_new_dir)
        layout_top.addWidget(self.radio_from_dir)
        layout_top.addStretch(1)
        self.groupbox.setLayout(layout_top)

        layout_grid = QGridLayout()
        layout_grid.addWidget(self.label_project_name, 0, 0)
        layout_grid.addWidget(self.text_project_name, 0, 1, 1, 2)
        layout_grid.addWidget(self.label_location, 1, 0)
        layout_grid.addWidget(self.text_location, 1, 1)
        layout_grid.addWidget(self.button_select_location, 1, 2)
        layout_grid.addWidget(self.label_project_type, 2, 0)
        layout_grid.addWidget(self.combo_project_type, 2, 1, 1, 2)
        layout_grid.addWidget(self.label_python_version, 3, 0)
        layout_grid.addWidget(self.combo_python_version, 3, 1, 1, 2)
        layout_grid.addWidget(self.label_information, 4, 0, 1, 3)

        layout = QVBoxLayout()
        layout.addWidget(self.groupbox)
        layout.addSpacing(10)
        layout.addLayout(layout_grid)
        layout.addStretch()
        layout.addSpacing(20)
        layout.addWidget(self.bbox)

        self.setLayout(layout)

        # Signals and slots
        self.button_select_location.clicked.connect(self.select_location)
        self.button_create.clicked.connect(self.create_project)
        self.button_cancel.clicked.connect(self.close)
        self.radio_from_dir.clicked.connect(self.update_location)
        self.radio_new_dir.clicked.connect(self.update_location)
        self.text_project_name.textChanged.connect(self.update_location)

    def select_location(self):
        """Select directory."""
        location = osp.normpath(
            getexistingdirectory(
                self,
                _("Select directory"),
                self.location,
            )
        )

        if location:
            if is_writable(location):
                self.location = location
                self.update_location()

    def update_location(self, text=''):
        """Update text of location."""
        self.text_project_name.setEnabled(self.radio_new_dir.isChecked())
        name = self.text_project_name.text().strip()

        if name and self.radio_new_dir.isChecked():
            path = osp.join(self.location, name)
            self.button_create.setDisabled(os.path.isdir(path))
        elif self.radio_from_dir.isChecked():
            self.button_create.setEnabled(True)
            path = self.location
        else:
            self.button_create.setEnabled(False)
            path = self.location

        self.text_location.setText(path)

        # Validate name with the method from the currently selected project
        project_type_id = self.combo_project_type.currentData()
        validate_func = self._project_types[project_type_id].validate_name
        validated, msg = validate_func(path, name)
        msg = "" if validated else msg
        self.label_information.setText(msg)
        self.button_create.setEnabled(validated)

    def create_project(self):
        """Create project."""
        self.project_data = {
            "root_path": self.text_location.text(),
            "project_type": self.combo_project_type.currentData(),
        }
        self.sig_project_creation_requested.emit(
            self.text_location.text(),
            self.combo_project_type.currentData(),
            [],
        )
        self.accept()
コード例 #8
0
class FormulaPane(BaseCodePane):

    def __init__(self, parent, title='', code='', editor_type=MxCodeEditor):
        super().__init__(parent, title, code, editor_type)

        self.buttonBox = QDialogButtonBox(self)
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.saveButton = QPushButton(_("Save"))
        self.discardButton = QPushButton(_("Discard"))
        self.buttonBox.addButton(self.saveButton, QDialogButtonBox.AcceptRole)
        self.buttonBox.addButton(
            self.discardButton, QDialogButtonBox.RejectRole)

        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        self.bottomLayout = QHBoxLayout()
        self.bottomLayout.setContentsMargins(5, 0, 5, 5)
        self.status = QLabel()
        self.bottomLayout.addWidget(self.status)
        self.bottomLayout.addWidget(self.buttonBox)
        self.layout.addLayout(self.bottomLayout)
        self.clearCode()

    def setCode(self, source, reconnect=True):
        self.editor.set_text(source)
        self.resetModification()
        if reconnect:
            self.editor.modificationChanged.connect(self.activateActions)
        self.editor.setReadOnly(False)

    def clearCode(self):
        self.editor.set_text("")
        try:
            self.editor.modificationChanged.disconnect(self.activateActions)
        except TypeError:
            pass
        self.editor.setReadOnly(True)
        self.resetModification()

    def resetModification(self):
        self.editor.document().setModified(False)
        self.updateStatus()
        self.saveButton.setEnabled(False)
        self.discardButton.setEnabled(False)

    def updateStatus(self):
        modified = self.editor.document().isModified()
        if modified:
            self.status.setText("Modified")
        else:
            self.status.setText("")

    @Slot(bool)
    def activateActions(self, status):
        if status:
            self.saveButton.setEnabled(True)
            self.discardButton.setEnabled(True)
            self.updateStatus()

    def accept(self):
        self.parent().formula_updated()

    def reject(self):
        self.parent().shell.reload_mxproperty()
コード例 #9
0
ファイル: projectdialog.py プロジェクト: rlugojr/spyder-1
class ProjectDialog(QDialog):
    """Project creation dialog."""

    # path, type, packages
    sig_project_creation_requested = Signal(object, object, object)

    def __init__(self, parent):
        """Project creation dialog."""
        super(ProjectDialog, self).__init__(parent=parent)

        # Variables
        current_python_version = '.'.join([
            to_text_string(sys.version_info[0]),
            to_text_string(sys.version_info[1])
        ])
        python_versions = ['2.7', '3.4', '3.5']
        if current_python_version not in python_versions:
            python_versions.append(current_python_version)
            python_versions = sorted(python_versions)

        self.project_name = None
        self.location = get_home_dir()

        # Widgets
        self.groupbox = QGroupBox()
        self.radio_new_dir = QRadioButton(_("New directory"))
        self.radio_from_dir = QRadioButton(_("Existing directory"))

        self.label_project_name = QLabel(_('Project name'))
        self.label_location = QLabel(_('Location'))
        self.label_project_type = QLabel(_('Project type'))
        self.label_python_version = QLabel(_('Python version'))

        self.text_project_name = QLineEdit()
        self.text_location = QLineEdit(get_home_dir())
        self.combo_project_type = QComboBox()
        self.combo_python_version = QComboBox()

        self.button_select_location = QToolButton()
        self.button_cancel = QPushButton(_('Cancel'))
        self.button_create = QPushButton(_('Create'))

        self.bbox = QDialogButtonBox(Qt.Horizontal)
        self.bbox.addButton(self.button_cancel, QDialogButtonBox.ActionRole)
        self.bbox.addButton(self.button_create, QDialogButtonBox.ActionRole)

        # Widget setup
        self.combo_python_version.addItems(python_versions)
        self.radio_new_dir.setChecked(True)
        self.text_location.setEnabled(True)
        self.text_location.setReadOnly(True)
        self.button_select_location.setIcon(get_std_icon('DirOpenIcon'))
        self.button_cancel.setDefault(True)
        self.button_cancel.setAutoDefault(True)
        self.button_create.setEnabled(False)
        self.combo_project_type.addItems(self._get_project_types())
        self.combo_python_version.setCurrentIndex(
            python_versions.index(current_python_version))
        self.setWindowTitle(_('Create new project'))
        self.setFixedWidth(500)
        self.label_python_version.setVisible(False)
        self.combo_python_version.setVisible(False)

        # Layouts
        layout_top = QHBoxLayout()
        layout_top.addWidget(self.radio_new_dir)
        layout_top.addWidget(self.radio_from_dir)
        layout_top.addStretch(1)
        self.groupbox.setLayout(layout_top)

        layout_grid = QGridLayout()
        layout_grid.addWidget(self.label_project_name, 0, 0)
        layout_grid.addWidget(self.text_project_name, 0, 1, 1, 2)
        layout_grid.addWidget(self.label_location, 1, 0)
        layout_grid.addWidget(self.text_location, 1, 1)
        layout_grid.addWidget(self.button_select_location, 1, 2)
        layout_grid.addWidget(self.label_project_type, 2, 0)
        layout_grid.addWidget(self.combo_project_type, 2, 1, 1, 2)
        layout_grid.addWidget(self.label_python_version, 3, 0)
        layout_grid.addWidget(self.combo_python_version, 3, 1, 1, 2)

        layout = QVBoxLayout()
        layout.addWidget(self.groupbox)
        layout.addSpacing(10)
        layout.addLayout(layout_grid)
        layout.addStretch()
        layout.addSpacing(20)
        layout.addWidget(self.bbox)

        self.setLayout(layout)

        # Signals and slots
        self.button_select_location.clicked.connect(self.select_location)
        self.button_create.clicked.connect(self.create_project)
        self.button_cancel.clicked.connect(self.close)
        self.radio_from_dir.clicked.connect(self.update_location)
        self.radio_new_dir.clicked.connect(self.update_location)
        self.text_project_name.textChanged.connect(self.update_location)

    def _get_project_types(self):
        """Get all available project types."""
        project_types = get_available_project_types()
        projects = []

        for project in project_types:
            projects.append(project.PROJECT_TYPE_NAME)

        return projects

    def select_location(self):
        """Select directory."""
        location = getexistingdirectory(self, _("Select directory"),
                                        self.location)
        if location:
            if is_writable(location):
                self.location = location
                self.update_location()

    def update_location(self, text=''):
        """Update text of location."""
        self.text_project_name.setEnabled(self.radio_new_dir.isChecked())
        name = self.text_project_name.text().strip()

        if name and self.radio_new_dir.isChecked():
            path = osp.join(self.location, name)
            self.button_create.setDisabled(os.path.isdir(path))
        elif self.radio_from_dir.isChecked():
            self.button_create.setEnabled(True)
            path = self.location
        else:
            self.button_create.setEnabled(False)
            path = self.location

        self.text_location.setText(path)

    def create_project(self):
        """Create project."""
        packages = [
            'python={0}'.format(self.combo_python_version.currentText())
        ]
        self.sig_project_creation_requested.emit(
            self.text_location.text(), self.combo_project_type.currentText(),
            packages)
        self.accept()
コード例 #10
0
class CondaPackagesWidget(QWidget):
    """
    Conda Packages Widget.
    """

    # Location of updated repo.json files from continuum/binstar
    CONDA_CONF_PATH = get_conf_path('repo')

    # Location of continuum/anaconda default repos shipped with conda-manager
    DATA_PATH = get_module_data_path()

    # file inside DATA_PATH with metadata for conda packages
    DATABASE_FILE = 'packages.ini'

    sig_worker_ready = Signal()
    sig_packages_ready = Signal()
    sig_environment_created = Signal(object, object)
    sig_environment_removed = Signal(object, object)
    sig_environment_cloned = Signal(object, object)
    sig_channels_updated = Signal(tuple, tuple)  # channels, active_channels
    sig_process_cancelled = Signal()
    sig_next_focus = Signal()
    sig_packages_busy = Signal()

    def __init__(self,
                 parent,
                 name=None,
                 prefix=None,
                 channels=(),
                 active_channels=(),
                 conda_url='https://conda.anaconda.org',
                 conda_api_url='https://api.anaconda.org',
                 setup=True,
                 data_directory=None,
                 extra_metadata={}):

        super(CondaPackagesWidget, self).__init__(parent)

        # Check arguments: active channels, must be witbhin channels
        for ch in active_channels:
            if ch not in channels:
                raise Exception("'active_channels' must be also within "
                                "'channels'")

        if data_directory is None:
            data_directory = self.CONDA_CONF_PATH

        self._parent = parent
        self._current_action_name = ''
        self._hide_widgets = False
        self._metadata = extra_metadata  # From repo.continuum
        self._metadata_links = {}  # Bundled metadata
        self.api = ManagerAPI()
        self.busy = False
        self.data_directory = data_directory
        self.conda_url = conda_url
        self.conda_api_url = conda_api_url
        self.name = name
        self.package_blacklist = []
        self.prefix = prefix
        self.root_prefix = self.api.ROOT_PREFIX
        self.style_sheet = None
        self.message = ''
        self.apply_actions_dialog = None
        self.conda_errors = []
        self.message_box_error = None
        self.token = None

        if channels:
            self._channels = channels
            self._active_channels = active_channels
        else:
            self._channels = self.api.conda_get_condarc_channels()
            self._active_channels = self._channels[:]

        # Widgets
        self.cancel_dialog = ClosePackageManagerDialog
        self.bbox = QDialogButtonBox(Qt.Horizontal)
        self.button_cancel = ButtonPackageCancel('Cancel')
        self.button_channels = ButtonPackageChannels(_('Channels'))
        self.button_ok = ButtonPackageOk(_('Ok'))
        self.button_update = ButtonPackageUpdate(_('Update package index...'))
        self.button_apply = ButtonPackageApply(_('Apply'))
        self.button_clear = ButtonPackageClear(_('Clear'))
        self.combobox_filter = DropdownPackageFilter(self)
        self.frame_top = FramePackageTop()
        self.frame_bottom = FramePackageTop()
        self.progress_bar = ProgressBarPackage(self)
        self.status_bar = LabelPackageStatus(self)
        self.table = TableCondaPackages(self)
        self.textbox_search = LineEditSearch(self)
        self.widgets = [
            self.button_update, self.button_channels, self.combobox_filter,
            self.textbox_search, self.table, self.button_ok, self.button_apply,
            self.button_clear
        ]
        self.table_first_row = FirstRowWidget(
            widget_before=self.textbox_search)
        self.table_last_row = LastRowWidget(widgets_after=[
            self.button_apply, self.button_clear, self.button_cancel,
            self.combobox_filter
        ])

        # Widgets setup
        for button in [
                self.button_cancel, self.button_apply, self.button_clear,
                self.button_ok, self.button_update, self.button_channels
        ]:
            button.setDefault(True)
        max_height = self.status_bar.fontMetrics().height()
        max_width = self.textbox_search.fontMetrics().width('M' * 23)
        self.bbox.addButton(self.button_ok, QDialogButtonBox.ActionRole)
        self.button_ok.setAutoDefault(True)
        self.button_ok.setDefault(True)
        self.button_ok.setMaximumSize(QSize(0, 0))
        self.button_ok.setVisible(False)
        self.button_channels.setCheckable(True)
        self.combobox_filter.addItems([k for k in C.COMBOBOX_VALUES_ORDERED])
        self.combobox_filter.setMinimumWidth(120)
        self.progress_bar.setMaximumHeight(max_height * 1.2)
        self.progress_bar.setMaximumWidth(max_height * 12)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.setVisible(False)
        self.setMinimumSize(QSize(480, 300))
        self.setWindowTitle(_("Conda Package Manager"))
        self.status_bar.setFixedHeight(max_height * 1.5)
        self.textbox_search.setMaximumWidth(max_width)
        self.textbox_search.setPlaceholderText('Search Packages')
        self.table_first_row.setMaximumHeight(0)
        self.table_last_row.setMaximumHeight(0)
        self.table_last_row.setVisible(False)
        self.table_first_row.setVisible(False)

        # Layout
        top_layout = QHBoxLayout()
        top_layout.addWidget(self.combobox_filter)
        top_layout.addWidget(self.button_channels)
        top_layout.addWidget(self.button_update)
        top_layout.addWidget(self.textbox_search)
        top_layout.addStretch()
        top_layout.setContentsMargins(0, 0, 0, 0)
        self.frame_top.setLayout(top_layout)

        middle_layout = QVBoxLayout()
        middle_layout.addWidget(self.table_first_row)
        middle_layout.addWidget(self.table)
        middle_layout.addWidget(self.table_last_row)

        bottom_layout = QHBoxLayout()
        bottom_layout.addWidget(self.status_bar)
        bottom_layout.addStretch()
        bottom_layout.addWidget(self.progress_bar)
        bottom_layout.addWidget(self.button_cancel)
        bottom_layout.addWidget(self.button_apply)
        bottom_layout.addWidget(self.button_clear)
        bottom_layout.setContentsMargins(0, 0, 0, 0)
        self.frame_bottom.setLayout(bottom_layout)

        layout = QVBoxLayout(self)
        layout.addWidget(self.frame_top)
        layout.addLayout(middle_layout)
        layout.addWidget(self.frame_bottom)
        self.setLayout(layout)

        self.setTabOrder(self.combobox_filter, self.button_channels)
        self.setTabOrder(self.button_channels, self.button_update)
        self.setTabOrder(self.button_update, self.textbox_search)
        self.setTabOrder(self.textbox_search, self.table_first_row)
        self.setTabOrder(self.table, self.table_last_row)
        self.setTabOrder(self.table_last_row, self.button_apply)
        self.setTabOrder(self.button_apply, self.button_clear)
        self.setTabOrder(self.button_clear, self.button_cancel)

        # Signals and slots
        self.api.sig_repodata_updated.connect(self._repodata_updated)
        self.combobox_filter.currentIndexChanged.connect(self.filter_package)
        self.button_apply.clicked.connect(self.apply_multiple_actions)
        self.button_clear.clicked.connect(self.clear_actions)
        self.button_cancel.clicked.connect(self.cancel_process)
        self.button_channels.clicked.connect(self.show_channels_dialog)
        self.button_update.clicked.connect(self.update_package_index)
        self.textbox_search.textChanged.connect(self.search_package)
        self.table.sig_conda_action_requested.connect(self._run_conda_action)
        self.table.sig_actions_updated.connect(self.update_actions)
        self.table.sig_pip_action_requested.connect(self._run_pip_action)
        self.table.sig_status_updated.connect(self.update_status)
        self.table.sig_next_focus.connect(self.table_last_row.handle_tab)
        self.table.sig_previous_focus.connect(
            lambda: self.table_first_row.widget_before.setFocus())
        self.table_first_row.sig_enter_first.connect(self._handle_tab_focus)
        self.table_last_row.sig_enter_last.connect(self._handle_backtab_focus)

        # Setup
        self.api.client_set_domain(conda_api_url)
        self.api.set_data_directory(self.data_directory)
        self._load_bundled_metadata()
        self.update_actions(0)

        if setup:
            self.set_environment(name=name, prefix=prefix)
            self.setup()

    # --- Helpers
    # -------------------------------------------------------------------------
    def _handle_tab_focus(self):
        self.table.setFocus()
        if self.table.proxy_model:
            index = self.table.proxy_model.index(0, 0)
            self.table.setCurrentIndex(index)

    def _handle_backtab_focus(self):
        self.table.setFocus()
        if self.table.proxy_model:
            row = self.table.proxy_model.rowCount() - 1
            index = self.table.proxy_model.index(row, 0)
            self.table.setCurrentIndex(index)

    # --- Callbacks
    # -------------------------------------------------------------------------
    def _load_bundled_metadata(self):
        """
        """
        logger.debug('')

        parser = cp.ConfigParser()
        db_file = CondaPackagesWidget.DATABASE_FILE
        with open(osp.join(self.DATA_PATH, db_file)) as f:
            parser.readfp(f)

        for name in parser.sections():
            metadata = {}
            for key, data in parser.items(name):
                metadata[key] = data
            self._metadata_links[name] = metadata

    def _setup_packages(self, worker, data, error):
        """
        """
        if error:
            logger.error(error)
        else:
            logger.debug('')

        combobox_index = self.combobox_filter.currentIndex()
        status = C.PACKAGE_STATUS[combobox_index]

        packages = worker.packages

        # Remove blacklisted packages
        for package in self.package_blacklist:
            if package in packages:
                packages.pop(package)
            for i, row in enumerate(data):
                if package == data[i][C.COL_NAME]:
                    data.pop(i)

        self.table.setup_model(packages, data, self._metadata_links)
        self.combobox_filter.setCurrentIndex(combobox_index)
        self.filter_package(status)

        if self._current_model_index:
            self.table.setCurrentIndex(self._current_model_index)
            self.table.verticalScrollBar().setValue(self._current_table_scroll)

        if error:
            self.update_status(error, False)
        self.sig_packages_ready.emit()
        self.table.setFocus()

    def get_logged_user_list_channels(self):
        channels = []
        for ch in self._active_channels:
            if self.conda_url in ch and 'repo.continuum' not in ch:
                channel = ch.split('/')[-1]
                channels.append(channel)
        return channels

    def _prepare_model_data(self, worker=None, output=None, error=None):
        """
        """
        if error:
            logger.error(error)
        else:
            logger.debug('')

        packages, apps = output
        #        worker = self.api.pip_list(prefix=self.prefix)
        #        worker.sig_finished.connect(self._pip_list_ready)
        logins = self.get_logged_user_list_channels()
        worker = self.api.client_multi_packages(logins=logins,
                                                access='private')
        worker.sig_finished.connect(self._user_private_packages_ready)
        worker.packages = packages
        worker.apps = apps

    def _user_private_packages_ready(self, worker, output, error):
        if error:
            logger.error(error)
        else:
            logger.debug('')

        packages = worker.packages
        apps = worker.apps
        worker = self.api.pip_list(prefix=self.prefix)
        worker.sig_finished.connect(self._pip_list_ready)
        worker.packages = packages
        worker.apps = apps

        #        private_packages = {}
        #        if output:
        #            all_private_packages = output
        #            for item in all_private_packages:
        #                name = item.get('name', '')
        #                public = item.get('public', True)
        #                package_types = item.get('package_types', [])
        #                latest_version = item.get('latest_version', '')
        #                if name and not public and 'conda' in package_types:
        #                    private_packages[name] = {'versions': item.get('versions', []),
        #                                              'app_entry': {},
        #                                              'type': {},
        #                                              'size': {},
        #                                              'latest_version': latest_version,
        #                                              }
        worker.private_packages = output

    def _pip_list_ready(self, worker, pip_packages, error):
        """
        """
        if error:
            logger.error(error)
        else:
            logger.debug('')

        packages = worker.packages
        private_packages = worker.private_packages
        linked_packages = self.api.conda_linked(prefix=self.prefix)
        data = self.api.client_prepare_packages_data(packages, linked_packages,
                                                     pip_packages,
                                                     private_packages)

        combobox_index = self.combobox_filter.currentIndex()
        status = C.PACKAGE_STATUS[combobox_index]

        # Remove blacklisted packages
        for package in self.package_blacklist:
            if package in packages:
                packages.pop(package)

            for i, row in enumerate(data):
                if package == data[i][C.COL_NAME]:
                    data.pop(i)

        self.table.setup_model(packages, data, self._metadata_links)
        self.combobox_filter.setCurrentIndex(combobox_index)
        self.filter_package(status)

        if self._current_model_index:
            self.table.setCurrentIndex(self._current_model_index)
            self.table.verticalScrollBar().setValue(self._current_table_scroll)

        if error:
            self.update_status(str(error), False)
        self.sig_packages_ready.emit()
        self.table.setFocus()

    def _repodata_updated(self, paths):
        """
        """
        worker = self.api.client_load_repodata(paths,
                                               extra_data={},
                                               metadata=self._metadata)
        worker.paths = paths
        worker.sig_finished.connect(self._prepare_model_data)

    def _metadata_updated(self, worker, path, error):
        """
        """
        if error:
            logger.error(error)
        else:
            logger.debug('')

        if path and osp.isfile(path):
            with open(path, 'r') as f:
                data = f.read()
            try:
                self._metadata = json.loads(data)
            except Exception:
                self._metadata = {}
        else:
            self._metadata = {}
        self.api.update_repodata(self._channels)

    # ---
    # -------------------------------------------------------------------------
    def _run_multiple_actions(self, worker=None, output=None, error=None):
        """
        """
        logger.error(str(error))

        if output and isinstance(output, dict):
            conda_error_type = output.get('error_type', None)
            conda_error = output.get('error', None)

            if conda_error_type or conda_error:
                self.conda_errors.append((conda_error_type, conda_error))
                logger.error((conda_error_type, conda_error))

        if self._multiple_process:
            status, func = self._multiple_process.popleft()
            self.update_status(status)
            worker = func()
            worker.sig_finished.connect(self._run_multiple_actions)
            worker.sig_partial.connect(self._partial_output_ready)
        else:
            if self.conda_errors and self.message_box_error:
                text = "The following errors occured:"
                error = ''
                for conda_error in self.conda_errors:
                    error += str(conda_error[0]) + ':\n'
                    error += str(conda_error[1]) + '\n\n'
                dlg = self.message_box_error(text=text,
                                             error=error,
                                             title='Conda process error')
                dlg.setMinimumWidth(400)
                dlg.exec_()

            self.update_status('', hide=False)
            self.setup()

    def _pip_process_ready(self, worker, output, error):
        """
        """
        if error is not None:
            status = _('there was an error')
            self.update_status(hide=False, message=status)
        else:
            self.update_status(hide=True)

        self.setup()

    def _conda_process_ready(self, worker, output, error):
        """
        """
        if error is not None:
            status = _('there was an error')
            self.update_status(hide=False, message=status)
        else:
            self.update_status(hide=True)

        conda_error = None
        conda_error_type = None
        if output and isinstance(output, dict):
            conda_error_type = output.get('error_type')
            conda_error = output.get('error')

            if conda_error_type or conda_error:
                logger.error((conda_error_type, conda_error))

        dic = self._temporal_action_dic

        if dic['action'] == C.ACTION_CREATE:
            self.sig_environment_created.emit(conda_error, conda_error_type)
        elif dic['action'] == C.ACTION_CLONE:
            self.sig_environment_cloned.emit(conda_error, conda_error_type)
        elif dic['action'] == C.ACTION_REMOVE_ENV:
            self.sig_environment_removed.emit(conda_error, conda_error_type)

        self.setup()

    def _partial_output_ready(self, worker, output, error):
        """
        """
        message = None
        progress = (0, 0)

        if isinstance(output, dict):
            progress = (output.get('progress',
                                   None), output.get('maxval', None))
            name = output.get('name', None)
            fetch = output.get('fetch', None)

            if fetch:
                message = "Downloading <b>{0}</b>...".format(fetch)

            if name:
                self._current_action_name = name
                message = "Linking <b>{0}</b>...".format(name)

        logger.debug(message)
        self.update_status(message, progress=progress)

    def _run_pip_action(self, package_name, action):
        """
        DEPRECATED
        """
        prefix = self.prefix

        if prefix == self.root_prefix:
            name = 'root'
        elif self.api.conda_environment_exists(prefix=prefix):
            name = osp.basename(prefix)
        else:
            name = prefix

        if action == C.ACTION_REMOVE:
            msgbox = QMessageBox.question(
                self, "Remove pip package: "
                "{0}".format(package_name), "Do you want to proceed?",
                QMessageBox.Yes | QMessageBox.No)
            if msgbox == QMessageBox.Yes:
                self.update_status()
                worker = self.api.pip_remove(prefix=self.prefix,
                                             pkgs=[package_name])
                worker.sig_finished.connect(self._pip_process_ready)
                status = (_('Removing pip package <b>') + package_name +
                          '</b>' + _(' from <i>') + name + '</i>')
                self.update_status(hide=True, message=status, progress=[0, 0])

    def _run_conda_action(self, package_name, action, version, versions,
                          packages_sizes):
        """
        DEPRECATED
        """
        prefix = self.prefix
        dlg = CondaPackageActionDialog(self, prefix, package_name, action,
                                       version, versions, packages_sizes,
                                       self._active_channels)

        if dlg.exec_():
            dic = {}

            self.status = 'Processing'
            self.update_status(hide=True)
            self.repaint()

            ver1 = dlg.label_version.text()
            ver2 = dlg.combobox_version.currentText()
            pkg = u'{0}={1}{2}'.format(package_name, ver1, ver2)
            dep = dlg.checkbox.checkState()
            state = dlg.checkbox.isEnabled()
            dlg.close()

            dic['pkg'] = pkg
            dic['dep'] = not (dep == 0 and state)
            dic['action'] = None
            self._run_conda_process(action, dic)

    def _run_conda_process(self, action, dic):
        """
        DEPRECTAED
        """
        self._temporal_action_dic = dic
        #        prefix = self.prefix
        #
        #        if prefix == self.root_prefix:
        #            name = 'root'
        #        elif self.api.conda_environment_exists(prefix=prefix):
        #            name = osp.basename(prefix)
        #        else:
        #            name = prefix

        if 'pkgs' in dic and 'dep' in dic:
            dep = dic['dep']
            pkgs = dic['pkgs']
            if not isinstance(pkgs, list):
                pkgs = [pkgs]

#        if (action == C.ACTION_INSTALL or action == C.ACTION_UPGRADE or
#           action == C.ACTION_DOWNGRADE):
#            status = _('Installing <b>') + dic['pkg'] + '</b>'
#            status = status + _(' into <i>') + name + '</i>'
#            worker = self.api.conda_install(prefix=prefix, pkgs=pkgs, dep=dep,
#                                            channels=self._active_channels)
#        elif action == C.ACTION_REMOVE:
#            status = (_('Removing <b>') + dic['pkg'] + '</b>' +
#                      _(' from <i>') + name + '</i>')
#            worker = self.api.conda_remove(pkgs[0], prefix=prefix)

# --- Environment management actions
        name = dic['name']
        if action == C.ACTION_CREATE:
            status = _('Creating environment <b>') + name + '</b>'
            worker = self.api.conda_create(name=name,
                                           pkgs=pkgs,
                                           channels=self._active_channels)
        elif action == C.ACTION_CLONE:
            clone = dic['clone']
            status = (_('Cloning ') + '<i>' + clone + _('</i> into <b>') +
                      name + '</b>')
            worker = self.api.conda_clone(clone, name=name)
        elif action == C.ACTION_REMOVE_ENV:
            status = _('Removing environment <b>') + name + '</b>'
            worker = self.api.conda_remove(name=name, all_=True)

        worker.sig_finished.connect(self._conda_process_ready)
        worker.sig_partial.connect(self._partial_output_ready)
        self.update_status(hide=True, message=status, progress=None)
        self._temporal_action_dic = dic
        return worker

    # Public API
    # -------------------------------------------------------------------------
    def prepare_model_data(self, packages, apps):
        """
        """
        logger.debug('')
        self._prepare_model_data(output=(packages, apps))

    # These should be private methods....
    def enable_widgets(self):
        """ """
        self.table.hide_columns()

    def disable_widgets(self):
        """ """
        self.table.hide_action_columns()

    def accept_channels_dialog(self):
        self.button_channels.setFocus()
        self.button_channels.toggle()

    def update_actions(self, number_of_actions):
        """
        """
        self.button_apply.setVisible(bool(number_of_actions))
        self.button_clear.setVisible(bool(number_of_actions))

    # --- Non UI API
    # -------------------------------------------------------------------------
    def setup(self, check_updates=False, blacklist=[], metadata={}):
        """
        Setup packages.

        Main triger method to download repodata, load repodata, prepare and
        updating the data model.

        Parameters
        ----------
        check_updates : bool
            If `True`, checks that the latest repodata is available on the
            listed channels. If `False`, the data will be loaded from the
            downloaded files without checking for newer versions.
        blacklist: list of str
            List of conda package names to be excluded from the actual package
            manager view.
        """
        self.sig_packages_busy.emit()

        if self.busy:
            logger.debug('Busy...')
            return
        else:
            logger.debug('')

        if blacklist:
            self.package_blacklist = [p.lower() for p in blacklist]

        if metadata:
            self._metadata = metadata

        self._current_model_index = self.table.currentIndex()
        self._current_table_scroll = self.table.verticalScrollBar().value()
        self.update_status('Updating package index', True)

        if check_updates:
            worker = self.api.update_metadata()
            worker.sig_finished.connect(self._metadata_updated)
        else:
            paths = self.api.repodata_files(channels=self._active_channels)
            self._repodata_updated(paths)

    def update_domains(self, anaconda_api_url=None, conda_url=None):
        """
        """
        logger.debug(str((anaconda_api_url, conda_url)))
        update = False

        if anaconda_api_url:
            if self.conda_api_url != anaconda_api_url:
                update = True

            self.conda_api_url = anaconda_api_url
            self.api.client_set_domain(anaconda_api_url)

        if conda_url:
            if self.conda_url != conda_url:
                update = True
            self.conda_url = conda_url

        if update:
            pass

    def set_environment(self, name=None, prefix=None):
        """
        This does not update the package manager!
        """
        logger.debug(str((name, prefix)))

        if prefix and self.api.conda_environment_exists(prefix=prefix):
            self.prefix = prefix
        elif name and self.api.conda_environment_exists(name=name):
            self.prefix = self.get_prefix_envname(name)
        else:
            self.prefix = self.root_prefix

    def set_token(self, token):
        self.token = token

    def update_channels(self, channels, active_channels):
        """
        """
        logger.debug(str((channels, active_channels)))

        if sorted(self._active_channels) != sorted(active_channels) or \
                sorted(self._channels) != sorted(channels):
            self._channels = channels
            self._active_channels = active_channels
            self.sig_channels_updated.emit(tuple(channels),
                                           tuple(active_channels))
            self.setup(check_updates=True)

    def update_style_sheet(self,
                           style_sheet=None,
                           extra_dialogs={},
                           palette={}):
        if style_sheet:
            self.style_sheet = style_sheet
            self.table.update_style_palette(palette=palette)
            self.textbox_search.update_style_sheet(style_sheet)
            self.setStyleSheet(style_sheet)

        if extra_dialogs:
            cancel_dialog = extra_dialogs.get('cancel_dialog', None)
            apply_actions_dialog = extra_dialogs.get('apply_actions_dialog',
                                                     None)
            message_box_error = extra_dialogs.get('message_box_error', None)
            if cancel_dialog:
                self.cancel_dialog = cancel_dialog
            if apply_actions_dialog:
                self.apply_actions_dialog = apply_actions_dialog
            if message_box_error:
                self.message_box_error = message_box_error

    # --- UI API
    # -------------------------------------------------------------------------
    def filter_package(self, value):
        """ """
        self.table.filter_status_changed(value)

    def show_channels_dialog(self):
        """
        Show the channels dialog.
        """
        button_channels = self.button_channels
        self.dlg = DialogChannels(self,
                                  channels=self._channels,
                                  active_channels=self._active_channels,
                                  conda_url=self.conda_url)
        self.dlg.update_style_sheet(style_sheet=self.style_sheet)
        button_channels.setDisabled(True)
        self.dlg.sig_channels_updated.connect(self.update_channels)
        self.dlg.rejected.connect(lambda: button_channels.setEnabled(True))
        self.dlg.rejected.connect(button_channels.toggle)
        self.dlg.rejected.connect(button_channels.setFocus)
        self.dlg.accepted.connect(self.accept_channels_dialog)

        geo_tl = button_channels.geometry().topLeft()
        tl = button_channels.parentWidget().mapToGlobal(geo_tl)
        x = tl.x() + 2
        y = tl.y() + button_channels.height()
        self.dlg.move(x, y)
        self.dlg.show()
        self.dlg.button_add.setFocus()

    def update_package_index(self):
        """ """
        self.setup(check_updates=True)

    def search_package(self, text):
        """ """
        self.table.search_string_changed(text)

    def apply_multiple_actions(self):
        """
        """
        logger.debug('')

        self.conda_errors = []

        prefix = self.prefix

        if prefix == self.root_prefix:
            name = 'root'
        elif self.api.conda_environment_exists(prefix=prefix):
            name = osp.basename(prefix)
        else:
            name = prefix

        actions = self.table.get_actions()

        if actions is None:
            return

        self._multiple_process = deque()

        pip_actions = actions[C.PIP_PACKAGE]
        conda_actions = actions[C.CONDA_PACKAGE]

        pip_remove = pip_actions.get(C.ACTION_REMOVE, [])
        conda_remove = conda_actions.get(C.ACTION_REMOVE, [])
        conda_install = conda_actions.get(C.ACTION_INSTALL, [])
        conda_upgrade = conda_actions.get(C.ACTION_UPGRADE, [])
        conda_downgrade = conda_actions.get(C.ACTION_DOWNGRADE, [])

        message = ''
        template_1 = '<li><b>{0}={1}</b></li>'
        template_2 = '<li><b>{0}: {1} -> {2}</b></li>'

        if pip_remove:
            temp = [
                template_1.format(i['name'], i['version_to'])
                for i in pip_remove
            ]
            message += ('The following pip packages will be removed: '
                        '<ul>' + ''.join(temp) + '</ul>')
        if conda_remove:
            temp = [
                template_1.format(i['name'], i['version_to'])
                for i in conda_remove
            ]
            message += ('<br>The following conda packages will be removed: '
                        '<ul>' + ''.join(temp) + '</ul>')
        if conda_install:
            temp = [
                template_1.format(i['name'], i['version_to'])
                for i in conda_install
            ]
            message += ('<br>The following conda packages will be installed: '
                        '<ul>' + ''.join(temp) + '</ul>')
        if conda_downgrade:
            temp = [
                template_2.format(i['name'], i['version_from'],
                                  i['version_to']) for i in conda_downgrade
            ]
            message += ('<br>The following conda packages will be downgraded: '
                        '<ul>' + ''.join(temp) + '</ul>')
        if conda_upgrade:
            temp = [
                template_2.format(i['name'], i['version_from'],
                                  i['version_to']) for i in conda_upgrade
            ]
            message += ('<br>The following conda packages will be upgraded: '
                        '<ul>' + ''.join(temp) + '</ul>')
        message += '<br>'

        if self.apply_actions_dialog:
            dlg = self.apply_actions_dialog(message, parent=self)
            dlg.update_style_sheet(style_sheet=self.style_sheet)
            reply = dlg.exec_()
        else:
            reply = QMessageBox.question(self,
                                         'Proceed with the following actions?',
                                         message,
                                         buttons=QMessageBox.Ok
                                         | QMessageBox.Cancel)

        if reply:
            # Pip remove
            for pkg in pip_remove:
                status = (_('Removing pip package <b>') + pkg['name'] +
                          '</b>' + _(' from <i>') + name + '</i>')
                pkgs = [pkg['name']]

                def trigger(prefix=prefix, pkgs=pkgs):
                    return lambda: self.api.pip_remove(prefix=prefix,
                                                       pkgs=pkgs)

                self._multiple_process.append([status, trigger()])

            # Process conda actions
            if conda_remove:
                status = (_('Removing conda packages <b>') + '</b>' +
                          _(' from <i>') + name + '</i>')
                pkgs = [i['name'] for i in conda_remove]

                def trigger(prefix=prefix, pkgs=pkgs):
                    return lambda: self.api.conda_remove(pkgs=pkgs,
                                                         prefix=prefix)

                self._multiple_process.append([status, trigger()])

            if conda_install:
                pkgs = [
                    '{0}={1}'.format(i['name'], i['version_to'])
                    for i in conda_install
                ]

                status = (_('Installing conda packages <b>') + '</b>' +
                          _(' on <i>') + name + '</i>')

                def trigger(prefix=prefix, pkgs=pkgs):
                    return lambda: self.api.conda_install(prefix=prefix,
                                                          pkgs=pkgs,
                                                          channels=self.
                                                          _active_channels,
                                                          token=self.token)

                self._multiple_process.append([status, trigger()])

            # Conda downgrade
            if conda_downgrade:
                status = (_('Downgrading conda packages <b>') + '</b>' +
                          _(' on <i>') + name + '</i>')

                pkgs = [
                    '{0}={1}'.format(i['name'], i['version_to'])
                    for i in conda_downgrade
                ]

                def trigger(prefix=prefix, pkgs=pkgs):
                    return lambda: self.api.conda_install(prefix=prefix,
                                                          pkgs=pkgs,
                                                          channels=self.
                                                          _active_channels,
                                                          token=self.token)

                self._multiple_process.append([status, trigger()])

            # Conda update
            if conda_upgrade:
                status = (_('Upgrading conda packages <b>') + '</b>' +
                          _(' on <i>') + name + '</i>')

                pkgs = [
                    '{0}={1}'.format(i['name'], i['version_to'])
                    for i in conda_upgrade
                ]

                def trigger(prefix=prefix, pkgs=pkgs):
                    return lambda: self.api.conda_install(prefix=prefix,
                                                          pkgs=pkgs,
                                                          channels=self.
                                                          _active_channels,
                                                          token=self.token)

                self._multiple_process.append([status, trigger()])

            self._run_multiple_actions()

    def clear_actions(self):
        """
        """
        self.table.clear_actions()

    def cancel_process(self):
        """
        Allow user to cancel an ongoing process.
        """
        logger.debug(str('process canceled by user.'))
        if self.busy:
            dlg = self.cancel_dialog()
            reply = dlg.exec_()
            if reply:
                self.update_status(hide=False, message='Process cancelled')
                self.api.conda_terminate()
                self.api.download_requests_terminate()
                self.api.conda_clear_lock()
                self.table.clear_actions()
                self.sig_process_cancelled.emit()
        else:
            QDialog.reject(self)

    def update_status(self, message=None, hide=True, progress=None, env=False):
        """
        Update status bar, progress bar display and widget visibility

        message : str
            Message to display in status bar.
        hide : bool
            Enable/Disable widgets.
        progress : [int, int]
            Show status bar progress. [0, 0] means spinning statusbar.
        """
        self.busy = hide
        for widget in self.widgets:
            widget.setDisabled(hide)
        self.table.verticalScrollBar().setValue(self._current_table_scroll)

        self.button_apply.setVisible(False)
        self.button_clear.setVisible(False)

        self.progress_bar.setVisible(hide)
        self.button_cancel.setVisible(hide)

        if message is not None:
            self.message = message

        if self.prefix == self.root_prefix:
            short_env = 'root'


#        elif self.api.environment_exists(prefix=self.prefix):
#            short_env = osp.basename(self.prefix)
        else:
            short_env = self.prefix

        if env:
            self.message = '{0} (<b>{1}</b>)'.format(
                self.message,
                short_env,
            )
        self.status_bar.setText(self.message)

        if progress is not None:
            current_progress, max_progress = 0, 0

            if progress[1]:
                max_progress = progress[1]

            if progress[0]:
                current_progress = progress[0]

            self.progress_bar.setMinimum(0)
            self.progress_bar.setMaximum(max_progress)
            self.progress_bar.setValue(current_progress)
        else:
            self.progress_bar.setMinimum(0)
            self.progress_bar.setMaximum(0)

    # --- Conda helpers
    # -------------------------------------------------------------------------
    def get_environment_prefix(self):
        """
        Returns the active environment prefix.
        """
        return self._prefix

    def get_environment_name(self):
        """
        Returns the active environment name if it is located in the default
        conda environments directory, otherwise it returns the prefix.
        """
        name = osp.basename(self._prefix)

        if not (name and self.api.environment_exists(name=name)):
            name = self._prefix

        return name

    def get_environments(self):
        """
        Get a list of conda environments located in the default conda
        environments directory.
        """
        return self.api.conda_get_envs()

    def get_prefix_envname(self, name):
        """
        Returns the prefix for a given environment by name.
        """
        return self.api.conda_get_prefix_envname(name)

    def get_package_versions(self, name):
        """ """
        return self.table.source_model.get_package_versions(name)

    # --- Conda actions
    # -------------------------------------------------------------------------
    def create_environment(self, name=None, prefix=None, packages=['python']):
        """ """
        # If environment exists already? GUI should take care of this
        # BUT the api call should simply set that env as the env
        dic = {}
        dic['name'] = name
        dic['prefix'] = prefix
        dic['pkgs'] = packages
        dic['dep'] = True  # Not really needed but for the moment!
        dic['action'] = C.ACTION_CREATE
        return self._run_conda_process(dic['action'], dic)

    def clone_environment(self, name=None, prefix=None, clone=None):
        dic = {}
        dic['name'] = name
        dic['prefix'] = prefix
        dic['clone'] = clone
        dic['pkgs'] = None
        dic['dep'] = True  # Not really needed but for the moment!
        dic['action'] = C.ACTION_CLONE
        return self._run_conda_process(dic['action'], dic)

    def remove_environment(self, name=None, prefix=None):
        dic = {}
        dic['name'] = name
        dic['pkgs'] = None
        dic['dep'] = True  # Not really needed but for the moment!
        dic['action'] = C.ACTION_REMOVE_ENV
        return self._run_conda_process(dic['action'], dic)
コード例 #11
0
class MetadataDialog(QDialog):
    """Dialog for calibrating images.

    User can select from a list of catalogs (pulled from the active ensemble),
    preview, and calibrate the image data.
    """

    default_parameters_dict = [{
        'name': 'Sample Name',
        'label': 'sample_name',
        'type': 'str',
        'renamable': False,
        'removable': False,
    }]

    _default_parameter_state = ScalableGroup(children=default_parameters_dict,
                                             name='blah',
                                             type='group').saveState()

    _qsettings_key = 'xicam.Acquire.metadata'
    _parameter_state = QSettings().value(_qsettings_key,
                                         defaultValue=_default_parameter_state)
    parameter = ScalableGroup(name='blah')
    parameter.restoreState(_parameter_state)

    def __init__(self,
                 reserved: Iterable[str] = None,
                 parent=None,
                 window_flags=Qt.WindowFlags()):
        super(MetadataDialog, self).__init__(parent, window_flags)

        self.reserved = set(reserved or [])

        self.parameter_tree = pt.ParameterTree(showHeader=False)
        self.parameter_tree.setParameters(self.parameter, showTop=False)

        calibrate_button = QPushButton("&Acquire")

        self.buttons = QDialogButtonBox(Qt.Horizontal)
        # Add calibration button that accepts the dialog (closes with 1 status)
        self.buttons.addButton(calibrate_button, QDialogButtonBox.AcceptRole)
        # Add a cancel button that will reject the dialog (closes with 0 status)
        self.buttons.addButton(QDialogButtonBox.Cancel)

        self.buttons.rejected.connect(self.reject)
        self.buttons.accepted.connect(self.accept)

        outer_layout = QVBoxLayout()
        outer_layout.addWidget(self.parameter_tree)
        outer_layout.addWidget(self.buttons)
        outer_layout.setSpacing(0)
        outer_layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(outer_layout)

    def get_metadata(self):
        return self.parameter.saveState('user')['children']

    def accept(self):
        intersection = set(self.get_metadata().keys()).intersection(
            self.reserved)

        if intersection:
            msg.notifyMessage(
                f'The field name "{list(intersection)[0]}" is reserved and cannot be used.'
            )
        else:
            super(MetadataDialog, self).accept()
            QSettings().setValue(self._qsettings_key,
                                 self.parameter.saveState())
コード例 #12
0
ファイル: login.py プロジェクト: fisher2017/Anaconda
class AuthenticationDialog(DialogBase):
    FORGOT_USERNAME_URL = 'https://anaconda.org/account/forgot_username'
    FORGOT_PASWORD_URL = 'https://anaconda.org/account/forgot_password'
    REGISTER_URL = 'https://anaconda.org'

    def __init__(self, api, parent=None):
        super(AuthenticationDialog, self).__init__(parent)

        self.api = api
        self._parent = parent
        self.token = None
        self.error = None
        self.tracker = GATracker()

        # Widgets
        self.label_username = QLabel('Username:'******'Password:'******'You can register ')
        self.label_signin_text = QLabel('<hr><br><b>Already a member? '
                                        'Sign in!</b><br>')
        # For styling purposes the label next to a ButtonLink is also a button
        # so they align adequately
        self.button_register_text = ButtonLabel('You can register by '
                                                'visiting the')
        self.button_register = ButtonLink('Anaconda Cloud')
        self.button_register_after_text = ButtonLabel('website.')
        self.label_information = QLabel('''
            <strong>Anaconda Cloud</strong> is where packages, notebooks,
            and <br> environments are shared. It provides powerful <br>
            collaboration and package management for open <br>
            source and private projects.<br>
            ''')
        self.label_message = QLabel('')
        self.button_forgot_username = ButtonLink('I forgot my username')
        self.button_forgot_password = ButtonLink('I forgot my password')
        self.button_login = QPushButton('Login')
        self.button_cancel = ButtonCancel('Cancel')
        self.bbox = QDialogButtonBox(Qt.Horizontal)

        # Widgets setup
        self.bbox.addButton(self.button_cancel, QDialogButtonBox.RejectRole)
        self.bbox.addButton(self.button_login, QDialogButtonBox.AcceptRole)
        self.text_username.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.text_password.setAttribute(Qt.WA_MacShowFocusRect, False)

        self.setMinimumWidth(260)
        self.setWindowTitle('Sign in')

        # This allows to completely style the dialog with css using the frame
        self.text_password.setEchoMode(QLineEdit.Password)
        self.label_message.setVisible(False)

        # Layout
        grid_layout = QGridLayout()
        grid_layout.addWidget(self.label_username, 0, 0)
        grid_layout.addWidget(self.text_username, 0, 1)
        grid_layout.addWidget(self.label_password, 1, 0)
        grid_layout.addWidget(self.text_password, 1, 1)

        main_layout = QVBoxLayout()
        main_layout.addWidget(self.label_information)

        register_layout = QHBoxLayout()
        register_layout.addWidget(self.button_register_text, 0)
        register_layout.addWidget(self.button_register, 0, Qt.AlignLeft)
        register_layout.addWidget(self.button_register_after_text, 0,
                                  Qt.AlignLeft)
        register_layout.addStretch()
        register_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.addLayout(register_layout)
        main_layout.addWidget(self.label_signin_text)
        main_layout.addLayout(grid_layout)
        main_layout.addSpacing(5)
        main_layout.addWidget(self.label_message)
        main_layout.addWidget(self.button_forgot_username, 0, Qt.AlignRight)
        main_layout.addWidget(self.button_forgot_password, 0, Qt.AlignRight)

        main_layout.addSpacing(15)
        main_layout.addWidget(self.bbox)

        self.setLayout(main_layout)

        # Signals
        self.button_forgot_username.clicked.connect(
            lambda: self.open_url(self.FORGOT_USERNAME_URL))
        self.button_forgot_password.clicked.connect(
            lambda: self.open_url(self.FORGOT_PASWORD_URL))
        self.button_register.clicked.connect(
            lambda: self.open_url(self.REGISTER_URL))
        self.text_username.textEdited.connect(self.check_text)
        self.text_password.textEdited.connect(self.check_text)
        self.button_login.clicked.connect(self.login)
        self.button_cancel.clicked.connect(self.reject)

        # Setup
        self.check_text()
        self.update_style_sheet()
        self.text_username.setFocus()

    @property
    def username(self):
        return self.text_username.text()

    def update_style_sheet(self, style_sheet=None):
        if style_sheet is None:
            style_sheet = load_style_sheet()
        self.setStyleSheet(style_sheet)

    def check_text(self):
        """
        Check that `username` and `password` are not empty and disabel/enable
        buttons accordingly.
        """
        username = self.text_username.text()
        password = self.text_password.text()

        if len(username) == 0 or len(password) == 0:
            self.button_login.setDisabled(True)
        else:
            self.button_login.setDisabled(False)

    def login(self):
        self.button_login.setEnabled(False)
        QApplication.setOverrideCursor(Qt.WaitCursor)
        self.label_message.setText('')
        worker = self.api.client_login(self.text_username.text(),
                                       self.text_password.text(),
                                       'Anaconda Navigator',
                                       '')
        worker.sig_finished.connect(self._finished)

    def _finished(self, worker, output, error):
        """
        Method called when the anaconda-client Api has finished a process
        that runs in a separate worker thread.
        """
        token = output

        if token:
            self.token = token
            self.accept()
        elif error:
            username = self.text_username.text()
            bold_username = '******'.format(username)

            # The error might come in (error_message, http_error) format
            try:
                error_message = eval(str(error))[0]
            except Exception:
                error_message = str(error)

            error_message = error_message.lower().capitalize()
            error_message = error_message.split(', ')[0]
            error_text = '<i>{0}</i>'.format(error_message)
            error_text = error_text.replace(username, bold_username)
            self.label_message.setText(error_text)
            self.label_message.setVisible(True)

            if error_message:
                domain = self.api.client_domain()
                label = '{0}/{1}: {2}'.format(domain, username,
                                              error_message.lower())
                self.tracker.track_event('authenticate', 'login failed',
                                         label=label)
                self.text_password.setFocus()
                self.text_password.selectAll()

        self.button_login.setDisabled(False)
        self.check_text()
        QApplication.restoreOverrideCursor()

    def open_url(self, url):
        self.tracker.track_event('content', 'click', url)
        QDesktopServices.openUrl(QUrl(url))
コード例 #13
0
ファイル: editor.py プロジェクト: slaclab/nalms
class AlarmTreeEditorDisplay(Display):
    def __init__(self, parent=None):
        super(AlarmTreeEditorDisplay, self).__init__(parent=parent)

        self.app = QApplication.instance()

        # set up the ui
        self.setup_ui()

        # allow add and remove row
        self.add_button.clicked.connect(self.insertChild)
        self.remove_button.clicked.connect(self.removeItem)
        self.remove_button.setEnabled(True)

        # connect save changes
        self.button_box.accepted.connect(self.save_property_changes)

        # upon tree view selection, change the item view
        self.tree_view.selectionModel().selectionChanged.connect(
            self.handle_selection)
        self.tree_view.tree_model.dataChanged.connect(self.item_change)

        self.file_dialog = QFileDialog()
        self.open_config_action = QAction("Open", self)
        self.open_config_action.triggered.connect(self.open_file)
        self.toolbar.addAction(self.open_config_action)

        self.save_config_action = QAction("Save", self)
        self.save_config_action.triggered.connect(self.save_configuration)
        self.toolbar.addAction(self.save_config_action)

        # update configuration name
        self.tree_label.editingFinished.connect(self._update_config_name)

        # default open size
        self.resize(800, 600)

        self.config_tool = PhoebusConfigTool()

    def setup_ui(self):
        self.main_layout = QGridLayout()
        self.setLayout(self.main_layout)

        # add toolbar
        self.toolbar = QToolBar()
        self.main_layout.setMenuBar(self.toolbar)

        # create the tree view layout and add/remove buttons
        self.tree_view_layout = QVBoxLayout()
        self.tree_view = PyDMAlarmTree(self,
                                       config_name="UNITITLED",
                                       edit_mode=True)
        self.tree_view.setEditTriggers(QAbstractItemView.DoubleClicked)
        self.tree_view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.tree_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tree_view.setHeaderHidden(True)

        # Drag/drop
        self.tree_view.setDragDropMode(QAbstractItemView.InternalMove)
        self.tree_view.setDragEnabled(True)
        self.tree_view.setAcceptDrops(True)

        # view sizing
        self.tree_view.setColumnWidth(0, 160)
        self.tree_view.setColumnWidth(1, 160)
        self.tree_view.setColumnWidth(2, 160)

        # lable for tree view
        configuration_indicator = QLabel("Configuration:")
        self.tree_label = QLineEdit("Untitled")

        self.tree_label_layout = QHBoxLayout()
        self.tree_label_layout.addWidget(configuration_indicator)
        self.tree_label_layout.addWidget(self.tree_label)

        self.tree_view_layout.addLayout(self.tree_label_layout)
        self.tree_view_layout.addWidget(self.tree_view)

        # add/ remove buttons
        self.add_remove_layout = QHBoxLayout()
        spacer = QSpacerItem(40, 20, QSizePolicy.Expanding,
                             QSizePolicy.Minimum)
        self.add_remove_layout.addItem(spacer)
        self.add_button = QPushButton("New", self)
        self.add_remove_layout.addWidget(self.add_button)
        self.remove_button = QPushButton("Remove", self)
        self.add_remove_layout.addWidget(self.remove_button)
        self.tree_view_layout.addLayout(self.add_remove_layout)

        # add the tree view to the window
        self.main_layout.addLayout(self.tree_view_layout, 0, 0)

        self.property_layout = QVBoxLayout()
        self.property_layout.addWidget(QLabel("Alarm Properties"))

        # crate property view
        self.property_data_layout = QStackedLayout()
        self.property_layout.addLayout(self.property_data_layout)

        self.property_widget_config = QWidget()
        self.property_widget_config.setWindowTitle("config")

        # create group widget
        self.property_widget_group = QWidget()
        self.property_widget_group.setWindowTitle("group")

        self.property_view_layout_group = QGridLayout()

        # add label
        self.label_edit_group = QLineEdit()
        self.label_label_group = QLabel("NAME")

        # add guidance
        self.guidance_edit_group = QLineEdit()
        self.guidance_label_group = QLabel("GUIDANCE")

        self.property_view_layout_group.addWidget(self.label_label_group, 1, 0)
        self.property_view_layout_group.addWidget(self.label_edit_group, 1, 1)

        self.property_view_layout_group.addWidget(self.guidance_label_group, 2,
                                                  0)
        self.property_view_layout_group.addWidget(self.guidance_edit_group, 2,
                                                  1)

        spacer = QSpacerItem(40, 200, QSizePolicy.Expanding,
                             QSizePolicy.Minimum)

        self.property_view_layout_group.addItem(spacer, 3, 0)
        self.property_view_layout_group.addItem(spacer, 4, 0)
        self.property_view_layout_group.addItem(spacer, 5, 0)
        self.property_view_layout_group.addItem(spacer, 6, 0)
        self.property_view_layout_group.addItem(spacer, 7, 0)
        self.property_view_layout_group.addItem(spacer, 8, 0)

        # create pv widget
        self.property_widget_pv = QWidget()
        self.property_widget_pv.setWindowTitle("pv")

        self.property_view_layout_pv = QGridLayout()

        # add label
        self.label_edit_pv = QLineEdit()
        self.label_label_pv = QLabel("NAME")

        # add guidance
        self.guidance_edit_pv = QLineEdit()
        self.guidance_label_pv = QLabel("GUIDANCE")

        self.property_view_layout_pv.addWidget(self.label_label_pv, 1, 0)
        self.property_view_layout_pv.addWidget(self.label_edit_pv, 1, 1, 1, 3)

        self.property_view_layout_pv.addWidget(self.guidance_label_pv, 2, 0)
        self.property_view_layout_pv.addWidget(self.guidance_edit_pv, 2, 1, 1,
                                               3)

        # add description
        self.description_edit = QLineEdit()
        self.description_label = QLabel("DESCRIPTION")
        self.property_view_layout_pv.addWidget(self.description_label, 3, 0)
        self.property_view_layout_pv.addWidget(self.description_edit, 3, 1, 1,
                                               3)

        # add delay
        self.delay_edit = QLineEdit()
        self.delay_label = QLabel("DELAY")
        self.property_view_layout_pv.addWidget(self.delay_label, 4, 0)
        self.property_view_layout_pv.addWidget(self.delay_edit, 4, 1, 1, 3)
        self.delay_edit.setValidator(QIntValidator())

        # add count
        self.count_edit = QLineEdit()
        self.count_label = QLabel("COUNT")
        self.property_view_layout_pv.addWidget(self.count_label, 5, 0)
        self.property_view_layout_pv.addWidget(self.count_edit, 5, 1, 1, 3)
        self.count_edit.setValidator(QIntValidator())

        # add filter/force pv
        self.filter_edit = QLineEdit()
        self.filter_label = QLabel("ENABLING FILTER")
        self.property_view_layout_pv.addWidget(self.filter_label, 6, 0)
        self.property_view_layout_pv.addWidget(self.filter_edit, 6, 1, 1, 3)

        # enabled, latching, annunciating
        self.enabled_check = QCheckBox("ENABLED")
        self.annunciating_check = QCheckBox("ANNUNCIATING")
        self.latching_check = QCheckBox("LATCHING")
        self.property_view_layout_pv.addWidget(self.enabled_check, 7, 0)
        self.property_view_layout_pv.addWidget(self.annunciating_check, 7, 1)
        self.property_view_layout_pv.addWidget(self.latching_check, 7, 2)

        self.property_view_layout_pv.addItem(spacer, 8, 0)

        # create save button
        self.button_box = QDialogButtonBox(self)
        self.button_box.setOrientation(Qt.Horizontal)
        self.button_box.addButton("Save Properties",
                                  QDialogButtonBox.AcceptRole)

        self.property_layout.addWidget(self.button_box)
        # self.property_layout.addLayout(self.property_view_layout)

        self.property_widget_pv.setLayout(self.property_view_layout_pv)
        self.property_widget_group.setLayout(self.property_view_layout_group)

        self.property_data_layout.addWidget(self.property_widget_config)
        self.property_data_layout.addWidget(self.property_widget_pv)
        self.property_data_layout.addWidget(self.property_widget_group)

        self.main_layout.addLayout(self.property_layout, 0, 1)

        self.setWindowTitle("Alarm Tree Editor")
        self.tree_view.expandAll()

    def minimumSizeHint(self):
        # This is the default recommended size
        # for this screen
        return QSize(400, 200)

    def insertChild(self):
        index = self.tree_view.selectionModel().currentIndex()
        model = self.tree_view.model()

        if model.columnCount(index) == 0:
            if not model.insertColumn(0, index):
                return

        if not model.insertRow(0, index):
            return

        for column in range(model.columnCount(index)):
            child = model.index(0, column, index)
            model.set_data(child, label="NEW_ITEM", role=Qt.EditRole)

    def removeItem(self):
        index = self.tree_view.selectionModel().currentIndex()
        self.tree_view.model().removeRow(index.row(), index.parent())

    @Slot()
    def save_property_changes(self):
        index = self.tree_view.selectionModel().currentIndex()
        item = self.tree_view.model().getItem(index)
        if item.is_group:
            guidance = self.guidance_edit_group.text()
            label = self.label_edit_group.text()
        else:
            guidance = self.guidance_edit_pv.text()
            label = self.label_edit_pv.text()

        self.tree_view.model().set_data(
            index,
            label=label,
            description=self.description_edit.text(),
            delay=self.delay_edit.text(),
            count=self.count_edit.text(),
            enabled=self.enabled_check.isChecked(),
            annunciating=self.annunciating_check.isChecked(),
            latching=self.latching_check.isChecked(),
            alarm_filter=self.filter_edit.text(),
            guidance=guidance,
            role=Qt.EditRole,
        )

    @Slot()
    def handle_selection(self):
        self.remove_button.setEnabled(
            self.tree_view.selectionModel().hasSelection())

        index = self.tree_view.selectionModel().currentIndex()
        item = self.tree_view.model().getItem(index)

        if item.is_group:
            self.guidance_edit_group.setText(item.guidance)
            self.label_edit_group.setText(item.label)
        else:
            self.guidance_edit_pv.setText(item.guidance)
            self.label_edit_pv.setText(item.label)

        if item.is_group:
            # black for configuration screen
            if not item.parent:
                self.property_data_layout.setCurrentWidget(
                    self.property_widget_config)
            # otherwise show group screen and set all disables
            else:
                self.property_data_layout.setCurrentWidget(
                    self.property_widget_group)
                self.description_edit.setEnabled(False)
                self.description_edit.setVisible(False)
                self.description_label.setVisible(False)

                self.count_edit.setEnabled(False)
                self.count_edit.setVisible(False)
                self.count_label.setVisible(False)

                self.delay_edit.setEnabled(False)
                self.delay_edit.setVisible(False)
                self.delay_label.setVisible(False)

                self.latching_check.setEnabled(False)
                self.latching_check.setVisible(False)

                self.annunciating_check.setEnabled(False)
                self.annunciating_check.setVisible(False)

                self.filter_edit.setEnabled(False)
                self.filter_edit.setVisible(False)
                self.filter_label.setVisible(False)

        # set pv enabled
        else:
            self.property_data_layout.setCurrentWidget(self.property_widget_pv)
            self.description_edit.setEnabled(True)
            self.description_edit.setVisible(True)
            self.description_label.setVisible(True)

            self.count_edit.setEnabled(True)
            self.count_edit.setVisible(True)
            self.count_label.setVisible(True)

            self.delay_edit.setEnabled(True)
            self.delay_edit.setVisible(True)
            self.delay_label.setVisible(True)

            self.latching_check.setEnabled(True)
            self.latching_check.setVisible(True)

            self.annunciating_check.setEnabled(True)
            self.annunciating_check.setVisible(True)

            self.filter_edit.setEnabled(True)
            self.filter_edit.setVisible(True)
            self.filter_label.setVisible(True)

            if item.enabled:
                self.enabled_check.setChecked(True)
            else:
                self.enabled_check.setChecked(False)

            if item.latching:
                self.latching_check.setChecked(True)
            else:
                self.latching_check.setChecked(False)

            if item.annunciating:
                self.annunciating_check.setChecked(True)
            else:
                self.annunciating_check.setChecked(False)

    @Slot()
    def item_change(self):
        index = self.tree_view.selectionModel().currentIndex()
        item = self.tree_view.model().getItem(index)

        if item.is_group:
            self.guidance_edit_group.setText(item.guidance)
            self.label_edit_group.setText(item.label)
        else:
            self.guidance_edit_pv.setText(item.guidance)
            self.label_edit_pv.setText(item.label)

        if item.is_group:
            if not item.parent():
                self.property_data_layout.setCurrentWidget(
                    self.property_widget_config)

            else:
                self.property_data_layout.setCurrentWidget(
                    self.property_widget_group)

            self.description_edit.setEnabled(False)
            self.description_edit.setVisible(False)
            self.description_label.setVisible(False)

            self.count_edit.setEnabled(False)
            self.count_edit.setVisible(False)
            self.count_label.setVisible(False)

            self.delay_edit.setEnabled(False)
            self.delay_edit.setVisible(False)
            self.delay_label.setVisible(False)

            self.latching_check.setEnabled(False)
            self.latching_check.setVisible(False)

            self.annunciating_check.setEnabled(False)
            self.annunciating_check.setVisible(False)

            self.filter_edit.setEnabled(False)
            self.filter_edit.setVisible(False)
            self.filter_label.setVisible(False)

        else:
            self.delay_edit.setText(item.delay)
            self.count_edit.setText(item.count)

            if item.enabled:
                self.enabled_check.setChecked(True)
            else:
                self.enabled_check.setChecked(False)

            self.property_data_layout.setCurrentWidget(self.property_widget_pv)
            self.description_edit.setEnabled(True)
            self.description_edit.setVisible(True)
            self.description_label.setVisible(True)

            self.count_edit.setEnabled(True)
            self.count_edit.setVisible(True)
            self.count_label.setVisible(True)

            self.delay_edit.setEnabled(True)
            self.delay_edit.setVisible(True)
            self.delay_label.setVisible(True)

            self.latching_check.setEnabled(True)
            self.latching_check.setVisible(True)

            self.annunciating_check.setEnabled(True)
            self.annunciating_check.setVisible(True)

            self.filter_edit.setEnabled(True)
            self.filter_edit.setVisible(True)
            self.filter_label.setVisible(True)

            if item.latching:
                self.latching_check.setChecked(True)
            else:
                self.latching_check.setChecked(False)

            if item.annunciating:
                self.annunciating_check.setChecked(True)
            else:
                self.annunciating_check.setChecked(False)

    def ui_filepath(self):
        # No UI file is being used
        return None

    @Slot(bool)
    def open_file(self, checked):
        modifiers = QApplication.keyboardModifiers()
        try:
            curr_file = self.current_file()
            folder = os.path.dirname(curr_file)
        except Exception:
            folder = os.getcwd()

        filename = QFileDialog.getOpenFileName(
            self, "Open File...", folder,
            "XML (*.xml);; ALH Config (*.alhConfig)")
        filename = filename[0] if isinstance(filename,
                                             (list, tuple)) else filename

        if filename:
            filename = str(filename)

            # if alh file selected, open conversion prompt
            if filename[-9:] == "alhConfig":
                self.legacy_window = LegacyWindow(filename)
                self.legacy_window.exec_()

                if self.legacy_window.converted_filename:
                    self.import_configuration(
                        self.legacy_window.converted_filename)

            else:
                self.import_configuration(filename)

    def import_configuration(self, filename):
        nodes = self.config_tool.parse_config(filename)
        self.tree_view.model().import_hierarchy(nodes)
        self.tree_label.setText(self.tree_view.model()._nodes[0].label)

    @Slot()
    def save_configuration(self):
        modifiers = QApplication.keyboardModifiers()
        try:
            curr_file = self.current_file()
            folder = os.path.dirname(curr_file)
        except Exception:
            folder = os.getcwd()

        filename = QFileDialog.getSaveFileName(self, "Save File...", folder,
                                               "Configration files (*.xml)")
        filename = filename[0] if isinstance(filename,
                                             (list, tuple)) else filename

        self.config_tool.save_configuration(self.tree_view.model()._root_item,
                                            filename)

    def _update_config_name(self):
        name = self.tree_label.text()
        self.tree_view.model()._nodes[0].label = name

    def _import_legacy_file(self):
        convert_alh_to_phoebus()
コード例 #14
0
class ServerInfoDialog(BaseDialog):
    """Dialog window showing information about notebook servers."""
    def __init__(self, server_info, parent=None):
        """
        Construct a RecoveryDialog.

        Parameters
        ----------
        servers : list of ServerProcess
            Information to be displayed. This parameter is read only.
        parent : QWidget, optional
            Parent of the dialog window. The default is None.
        """
        super().__init__(parent)
        self.servers = server_info

        self.setWindowTitle(_('Notebook server info'))

        self.layout = QVBoxLayout(self)
        self.formlayout = QFormLayout()
        self.layout.addLayout(self.formlayout)

        self.process_combo = QComboBox(self)
        self.process_combo.currentIndexChanged.connect(self.select_process)
        self.formlayout.addRow(_('Process ID:'), self.process_combo)

        self.dir_lineedit = QLineEdit(self)
        self.dir_lineedit.setReadOnly(True)
        self.formlayout.addRow(_('Notebook dir:'), self.dir_lineedit)

        self.interpreter_lineedit = QLineEdit(self)
        self.interpreter_lineedit.setReadOnly(True)
        self.formlayout.addRow(_('Python interpreter:'),
                               self.interpreter_lineedit)

        self.state_lineedit = QLineEdit(self)
        self.state_lineedit.setReadOnly(True)
        self.formlayout.addRow(_('State:'), self.state_lineedit)

        self.log_textedit = QTextEdit(self)
        self.log_textedit.setReadOnly(True)
        self.layout.addWidget(self.log_textedit)

        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok, self)
        self.buttonbox.accepted.connect(self.accept)
        self.refresh_button = QPushButton(_('Refresh'), self)
        self.refresh_button.clicked.connect(self.refresh_data)
        self.buttonbox.addButton(self.refresh_button,
                                 QDialogButtonBox.ActionRole)
        self.layout.addWidget(self.buttonbox)

        self.refresh_data()

    def refresh_data(self):
        self.process_combo.clear()
        for server in self.servers:
            self.process_combo.addItem(str(server.process.processId()))
        self.select_process(0)

    def select_process(self, index):
        self.dir_lineedit.setText(self.servers[index].notebook_dir)
        self.interpreter_lineedit.setText(self.servers[index].interpreter)
        self.state_lineedit.setText(
            SERVER_STATE_DESCRIPTIONS[self.servers[index].state])
        self.log_textedit.setPlainText(self.servers[index].output)
コード例 #15
0
class BasePlotCurveEditorDialog(QDialog):
    """QDialog that is used in Qt Designer to edit the properties of the
    curves in a waveform plot.  This dialog is shown when you double-click
    the plot, or when you right click it and choose 'edit curves'.

    This thing is mostly just a wrapper for a table view, with a couple
    buttons to add and remove curves, and a button to save the changes."""
    TABLE_MODEL_CLASS = BasePlotCurvesModel

    def __init__(self, plot, parent=None):
        super(BasePlotCurveEditorDialog, self).__init__(parent)
        self.plot = plot
        self.setup_ui()
        self.table_model = self.TABLE_MODEL_CLASS(self.plot)
        self.table_view.setModel(self.table_model)
        self.table_model.plot = plot
        # self.table_view.resizeColumnsToContents()
        self.add_button.clicked.connect(self.addCurve)
        self.remove_button.clicked.connect(self.removeSelectedCurve)
        self.remove_button.setEnabled(False)
        self.table_view.selectionModel().selectionChanged.connect(
            self.handleSelectionChange)
        self.table_view.doubleClicked.connect(self.handleDoubleClick)
        self.resize(800, 300)

    def setup_ui(self):
        self.vertical_layout = QVBoxLayout(self)
        self.table_view = QTableView(self)
        self.table_view.setEditTriggers(QAbstractItemView.DoubleClicked)
        self.table_view.setProperty("showDropIndicator", False)
        self.table_view.setDragDropOverwriteMode(False)
        self.table_view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table_view.setSortingEnabled(False)
        self.table_view.horizontalHeader().setStretchLastSection(True)
        self.table_view.verticalHeader().setVisible(False)
        self.table_view.setColumnWidth(0, 160)
        self.table_view.setColumnWidth(1, 160)
        self.table_view.setColumnWidth(2, 160)
        self.vertical_layout.addWidget(self.table_view)
        self.add_remove_layout = QHBoxLayout()
        spacer = QSpacerItem(40, 20, QSizePolicy.Expanding,
                             QSizePolicy.Minimum)
        self.add_remove_layout.addItem(spacer)
        self.add_button = QPushButton("Add Curve", self)
        self.add_remove_layout.addWidget(self.add_button)
        self.remove_button = QPushButton("Remove Curve", self)
        self.add_remove_layout.addWidget(self.remove_button)
        self.vertical_layout.addLayout(self.add_remove_layout)
        self.button_box = QDialogButtonBox(self)
        self.button_box.setOrientation(Qt.Horizontal)
        self.button_box.addButton("Done", QDialogButtonBox.AcceptRole)
        self.vertical_layout.addWidget(self.button_box)
        self.button_box.accepted.connect(self.saveChanges)
        self.button_box.rejected.connect(self.reject)
        self.setWindowTitle("Waveform Curve Editor")

    def setup_delegate_columns(self, index=2):
        symbol_delegate = SymbolColumnDelegate(self)
        self.table_view.setItemDelegateForColumn(index + 3, symbol_delegate)
        line_delegate = LineColumnDelegate(self)
        self.table_view.setItemDelegateForColumn(index + 1, line_delegate)
        color_delegate = ColorColumnDelegate(self)
        self.table_view.setItemDelegateForColumn(index, color_delegate)

    @Slot()
    def addCurve(self):
        self.table_model.append()

    @Slot()
    def removeSelectedCurve(self):
        self.table_model.removeAtIndex(self.table_view.currentIndex())

    @Slot(QItemSelection, QItemSelection)
    def handleSelectionChange(self, selected, deselected):
        self.remove_button.setEnabled(
            self.table_view.selectionModel().hasSelection())

    @Slot(QModelIndex)
    def handleDoubleClick(self, index):
        if self.table_model.needsColorDialog(index):
            # The table model returns a QBrush for BackgroundRole, not a QColor
            init_color = self.table_model.data(index,
                                               Qt.BackgroundRole).color()
            color = QColorDialog.getColor(init_color, self)
            if color.isValid():
                self.table_model.setData(index, color, role=Qt.EditRole)

    @Slot()
    def saveChanges(self):
        formWindow = QDesignerFormWindowInterface.findFormWindow(self.plot)
        if formWindow:
            formWindow.cursor().setProperty("curves", self.plot.curves)
        self.accept()
コード例 #16
0
class FirstSplash(DialogBase):
    """
    Startup splash to display the first time that Navigator runs.
    """
    def __init__(self, parent=None, analytics=True):
        super(FirstSplash, self).__init__()

        text = """
        Thanks for installing Anaconda!

        Anaconda Navigator helps you easily start important Python applications
        and manage the packages in your local Anaconda installation. It also
        connects you to online resources for learning and engaging with the
        Python, SciPy, and PyData community.

        To help us improve Anaconda Navigator, fix bugs, and make it even easier
        for everyone to use Python, we gather anonymized usage information,
        just like most web browsers and mobile apps.

        To opt out of this, please uncheck below (You can always change this
        setting in the Preferences menu).
        """

        # Widgets
        self.button_ok = QPushButton('Ok')
        self.button_ok_dont_show = QPushButton("Ok, and don't show again")
        self.buttonbox = QDialogButtonBox(Qt.Horizontal)
        self.checkbox_track = QCheckBox("Yes, I'd like to help improve "
                                        "Anaconda.")
        self.label_about = QLabel(text)
        self.label_icon = QLabel()

        # Widget setup
        self.buttonbox.addButton(self.button_ok, QDialogButtonBox.ActionRole)
        self.buttonbox.addButton(self.button_ok_dont_show,
                                 QDialogButtonBox.ActionRole)
        self.checkbox_track.setChecked(analytics)
        self.checkbox_track.setChecked(
            CONF.get('main', 'provide_analytics', True))
        self.frame_title_bar.hide()
        self.label_icon.setPixmap(QPixmap(ANACONDA_NAVIGATOR_LOGO))

        # Layouts
        layout = QVBoxLayout()
        layout.addWidget(self.label_icon, 0, Qt.AlignCenter)
        layout.addWidget(self.label_about)
        layout.addWidget(self.checkbox_track, 0, Qt.AlignCenter)
        layout.addSpacing(20)
        layout.addWidget(self.buttonbox)
        self.setLayout(layout)

        # Signals
        self.button_ok.clicked.connect(lambda: self.accept(show_startup=True))
        self.button_ok_dont_show.clicked.connect(
            lambda: self.accept(show_startup=False))

    def accept(self, show_startup):
        """
        Qt override.
        """
        CONF.set('main', 'provide_analytics',
                 self.checkbox_track.checkState() == Qt.Checked)
        CONF.set('main', 'show_startup', show_startup)
        DialogBase.accept(self)

    def reject(self):
        """
        Qt override.

        Force user to select one of the two options bellow and disalow
        canceling the dialog (pressing escape)
        """
        pass
コード例 #17
0
ファイル: packages.py プロジェクト: Discalced51/conda-manager
class CondaPackagesWidget(QWidget):
    """
    Conda Packages Widget.
    """

    # Location of updated repo.json files from continuum/binstar
    CONDA_CONF_PATH = get_conf_path('repo')

    # Location of continuum/anaconda default repos shipped with conda-manager
    DATA_PATH = get_module_data_path()

    # file inside DATA_PATH with metadata for conda packages
    DATABASE_FILE = 'packages.ini'

    sig_worker_ready = Signal()
    sig_packages_ready = Signal()
    sig_environment_created = Signal(object, object)
    sig_environment_removed = Signal(object, object)
    sig_environment_cloned = Signal(object, object)
    sig_channels_updated = Signal(tuple, tuple)  # channels, active_channels
    sig_process_cancelled = Signal()
    sig_next_focus = Signal()
    sig_packages_busy = Signal()

    def __init__(self,
                 parent,
                 name=None,
                 prefix=None,
                 channels=(),
                 active_channels=(),
                 conda_url='https://conda.anaconda.org',
                 conda_api_url='https://api.anaconda.org',
                 setup=True,
                 data_directory=None,
                 extra_metadata={}):

        super(CondaPackagesWidget, self).__init__(parent)

        # Check arguments: active channels, must be witbhin channels
        for ch in active_channels:
            if ch not in channels:
                raise Exception("'active_channels' must be also within "
                                "'channels'")

        if data_directory is None:
            data_directory = self.CONDA_CONF_PATH

        self._parent = parent
        self._current_action_name = ''
        self._hide_widgets = False
        self._metadata = extra_metadata  # From repo.continuum
        self._metadata_links = {}        # Bundled metadata
        self.api = ManagerAPI()
        self.busy = False
        self.data_directory = data_directory
        self.conda_url = conda_url
        self.conda_api_url = conda_api_url
        self.name = name
        self.package_blacklist = []
        self.prefix = prefix
        self.root_prefix = self.api.ROOT_PREFIX
        self.style_sheet = None
        self.message = ''
        self.apply_actions_dialog = None
        self.conda_errors = []
        self.message_box_error = None
        self.token = None

        if channels:
            self._channels = channels
            self._active_channels = active_channels
        else:
            self._channels = self.api.conda_get_condarc_channels()
            self._active_channels = self._channels[:]

        # Widgets
        self.cancel_dialog = ClosePackageManagerDialog
        self.bbox = QDialogButtonBox(Qt.Horizontal)
        self.button_cancel = ButtonPackageCancel('Cancel')
        self.button_channels = ButtonPackageChannels(_('Channels'))
        self.button_ok = ButtonPackageOk(_('Ok'))
        self.button_update = ButtonPackageUpdate(_('Update package index...'))
        self.button_apply = ButtonPackageApply(_('Apply'))
        self.button_clear = ButtonPackageClear(_('Clear'))
        self.combobox_filter = DropdownPackageFilter(self)
        self.frame_top = FramePackageTop()
        self.frame_bottom = FramePackageTop()
        self.progress_bar = ProgressBarPackage(self)
        self.status_bar = LabelPackageStatus(self)
        self.table = TableCondaPackages(self)
        self.textbox_search = LineEditSearch(self)
        self.widgets = [self.button_update, self.button_channels,
                        self.combobox_filter, self.textbox_search, self.table,
                        self.button_ok, self.button_apply, self.button_clear]
        self.table_first_row = FirstRowWidget(
            widget_before=self.textbox_search)
        self.table_last_row = LastRowWidget(
            widgets_after=[self.button_apply, self.button_clear,
                           self.button_cancel, self.combobox_filter])

        # Widgets setup
        for button in [self.button_cancel, self.button_apply,
                       self.button_clear, self.button_ok, self.button_update,
                       self.button_channels]:
            button.setDefault(True)
        max_height = self.status_bar.fontMetrics().height()
        max_width = self.textbox_search.fontMetrics().width('M'*23)
        self.bbox.addButton(self.button_ok, QDialogButtonBox.ActionRole)
        self.button_ok.setAutoDefault(True)
        self.button_ok.setDefault(True)
        self.button_ok.setMaximumSize(QSize(0, 0))
        self.button_ok.setVisible(False)
        self.button_channels.setCheckable(True)
        self.combobox_filter.addItems([k for k in C.COMBOBOX_VALUES_ORDERED])
        self.combobox_filter.setMinimumWidth(120)
        self.progress_bar.setMaximumHeight(max_height*1.2)
        self.progress_bar.setMaximumWidth(max_height*12)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.setVisible(False)
        self.setMinimumSize(QSize(480, 300))
        self.setWindowTitle(_("Conda Package Manager"))
        self.status_bar.setFixedHeight(max_height*1.5)
        self.textbox_search.setMaximumWidth(max_width)
        self.textbox_search.setPlaceholderText('Search Packages')
        self.table_first_row.setMaximumHeight(0)
        self.table_last_row.setMaximumHeight(0)
        self.table_last_row.setVisible(False)
        self.table_first_row.setVisible(False)

        # Layout
        top_layout = QHBoxLayout()
        top_layout.addWidget(self.combobox_filter)
        top_layout.addWidget(self.button_channels)
        top_layout.addWidget(self.button_update)
        top_layout.addWidget(self.textbox_search)
        top_layout.addStretch()
        top_layout.setContentsMargins(0, 0, 0, 0)
        self.frame_top.setLayout(top_layout)

        middle_layout = QVBoxLayout()
        middle_layout.addWidget(self.table_first_row)
        middle_layout.addWidget(self.table)
        middle_layout.addWidget(self.table_last_row)

        bottom_layout = QHBoxLayout()
        bottom_layout.addWidget(self.status_bar)
        bottom_layout.addStretch()
        bottom_layout.addWidget(self.progress_bar)
        bottom_layout.addWidget(self.button_cancel)
        bottom_layout.addWidget(self.button_apply)
        bottom_layout.addWidget(self.button_clear)
        bottom_layout.setContentsMargins(0, 0, 0, 0)
        self.frame_bottom.setLayout(bottom_layout)

        layout = QVBoxLayout(self)
        layout.addWidget(self.frame_top)
        layout.addLayout(middle_layout)
        layout.addWidget(self.frame_bottom)
        self.setLayout(layout)

        self.setTabOrder(self.combobox_filter, self.button_channels)
        self.setTabOrder(self.button_channels, self.button_update)
        self.setTabOrder(self.button_update, self.textbox_search)
        self.setTabOrder(self.textbox_search, self.table_first_row)
        self.setTabOrder(self.table, self.table_last_row)
        self.setTabOrder(self.table_last_row, self.button_apply)
        self.setTabOrder(self.button_apply, self.button_clear)
        self.setTabOrder(self.button_clear, self.button_cancel)

        # Signals and slots
        self.api.sig_repodata_updated.connect(self._repodata_updated)
        self.combobox_filter.currentIndexChanged.connect(self.filter_package)
        self.button_apply.clicked.connect(self.apply_multiple_actions)
        self.button_clear.clicked.connect(self.clear_actions)
        self.button_cancel.clicked.connect(self.cancel_process)
        self.button_channels.clicked.connect(self.show_channels_dialog)
        self.button_update.clicked.connect(self.update_package_index)
        self.textbox_search.textChanged.connect(self.search_package)
        self.table.sig_conda_action_requested.connect(self._run_conda_action)
        self.table.sig_actions_updated.connect(self.update_actions)
        self.table.sig_pip_action_requested.connect(self._run_pip_action)
        self.table.sig_status_updated.connect(self.update_status)
        self.table.sig_next_focus.connect(self.table_last_row.handle_tab)
        self.table.sig_previous_focus.connect(
            lambda: self.table_first_row.widget_before.setFocus())
        self.table_first_row.sig_enter_first.connect(self._handle_tab_focus)
        self.table_last_row.sig_enter_last.connect(self._handle_backtab_focus)

        # Setup
        self.api.client_set_domain(conda_api_url)
        self.api.set_data_directory(self.data_directory)
        self._load_bundled_metadata()
        self.update_actions(0)

        if setup:
            self.set_environment(name=name, prefix=prefix)
            self.setup()

    # --- Helpers
    # -------------------------------------------------------------------------
    def _handle_tab_focus(self):
        self.table.setFocus()
        if self.table.proxy_model:
            index = self.table.proxy_model.index(0, 0)
            self.table.setCurrentIndex(index)

    def _handle_backtab_focus(self):
        self.table.setFocus()
        if self.table.proxy_model:
            row = self.table.proxy_model.rowCount() - 1
            index = self.table.proxy_model.index(row, 0)
            self.table.setCurrentIndex(index)

    # --- Callbacks
    # -------------------------------------------------------------------------
    def _load_bundled_metadata(self):
        """
        """
        logger.debug('')

        parser = cp.ConfigParser()
        db_file = CondaPackagesWidget.DATABASE_FILE
        with open(osp.join(self.DATA_PATH, db_file)) as f:
            parser.readfp(f)

        for name in parser.sections():
            metadata = {}
            for key, data in parser.items(name):
                metadata[key] = data
            self._metadata_links[name] = metadata

    def _setup_packages(self, worker, data, error):
        """
        """
        if error:
            logger.error(error)
        else:
            logger.debug('')

        combobox_index = self.combobox_filter.currentIndex()
        status = C.PACKAGE_STATUS[combobox_index]

        packages = worker.packages

        # Remove blacklisted packages
        for package in self.package_blacklist:
            if package in packages:
                packages.pop(package)
            for i, row in enumerate(data):
                if package == data[i][C.COL_NAME]:
                    data.pop(i)

        self.table.setup_model(packages, data, self._metadata_links)
        self.combobox_filter.setCurrentIndex(combobox_index)
        self.filter_package(status)

        if self._current_model_index:
            self.table.setCurrentIndex(self._current_model_index)
            self.table.verticalScrollBar().setValue(self._current_table_scroll)

        if error:
            self.update_status(error, False)
        self.sig_packages_ready.emit()
        self.table.setFocus()

    def get_logged_user_list_channels(self):
        channels = []
        for ch in self._active_channels:
            if self.conda_url in ch and 'repo.continuum' not in ch:
                channel = ch.split('/')[-1]
                channels.append(channel)
        return channels

    def _prepare_model_data(self, worker=None, output=None, error=None):
        """
        """
        if error:
            logger.error(error)
        else:
            logger.debug('')

        packages, apps = output
#        worker = self.api.pip_list(prefix=self.prefix)
#        worker.sig_finished.connect(self._pip_list_ready)
        logins = self.get_logged_user_list_channels()
        worker = self.api.client_multi_packages(logins=logins,
                                                access='private')
        worker.sig_finished.connect(self._user_private_packages_ready)
        worker.packages = packages
        worker.apps = apps

    def _user_private_packages_ready(self, worker, output, error):
        if error:
            logger.error(error)
        else:
            logger.debug('')

        packages = worker.packages
        apps = worker.apps
        worker = self.api.pip_list(prefix=self.prefix)
        worker.sig_finished.connect(self._pip_list_ready)
        worker.packages = packages
        worker.apps = apps

#        private_packages = {}
#        if output:
#            all_private_packages = output
#            for item in all_private_packages:
#                name = item.get('name', '')
#                public = item.get('public', True)
#                package_types = item.get('package_types', [])
#                latest_version = item.get('latest_version', '')
#                if name and not public and 'conda' in package_types:
#                    private_packages[name] = {'versions': item.get('versions', []),
#                                              'app_entry': {},
#                                              'type': {},
#                                              'size': {},
#                                              'latest_version': latest_version,
#                                              }
        worker.private_packages = output

    def _pip_list_ready(self, worker, pip_packages, error):
        """
        """
        if error:
            logger.error(error)
        else:
            logger.debug('')

        packages = worker.packages
        private_packages = worker.private_packages
        linked_packages = self.api.conda_linked(prefix=self.prefix)
        data = self.api.client_prepare_packages_data(packages,
                                                     linked_packages,
                                                     pip_packages,
                                                     private_packages)

        combobox_index = self.combobox_filter.currentIndex()
        status = C.PACKAGE_STATUS[combobox_index]

        # Remove blacklisted packages
        for package in self.package_blacklist:
            if package in packages:
                packages.pop(package)

            for i, row in enumerate(data):
                if package == data[i][C.COL_NAME]:
                    data.pop(i)

        self.table.setup_model(packages, data, self._metadata_links)
        self.combobox_filter.setCurrentIndex(combobox_index)
        self.filter_package(status)

        if self._current_model_index:
            self.table.setCurrentIndex(self._current_model_index)
            self.table.verticalScrollBar().setValue(self._current_table_scroll)

        if error:
            self.update_status(str(error), False)
        self.sig_packages_ready.emit()
        self.table.setFocus()

    def _repodata_updated(self, paths):
        """
        """
        worker = self.api.client_load_repodata(paths, extra_data={},
                                               metadata=self._metadata)
        worker.paths = paths
        worker.sig_finished.connect(self._prepare_model_data)

    def _metadata_updated(self, worker, path, error):
        """
        """
        if error:
            logger.error(error)
        else:
            logger.debug('')

        if path and osp.isfile(path):
            with open(path, 'r') as f:
                data = f.read()
            try:
                self._metadata = json.loads(data)
            except Exception:
                self._metadata = {}
        else:
            self._metadata = {}
        self.api.update_repodata(self._channels)

    # ---
    # -------------------------------------------------------------------------
    def _run_multiple_actions(self, worker=None, output=None, error=None):
        """
        """
        logger.error(str(error))

        if output and isinstance(output, dict):
            conda_error_type = output.get('error_type', None)
            conda_error = output.get('error', None)

            if conda_error_type or conda_error:
                self.conda_errors.append((conda_error_type, conda_error))
                logger.error((conda_error_type, conda_error))

        if self._multiple_process:
            status, func = self._multiple_process.popleft()
            self.update_status(status)
            worker = func()
            worker.sig_finished.connect(self._run_multiple_actions)
            worker.sig_partial.connect(self._partial_output_ready)
        else:
            if self.conda_errors and self.message_box_error:
                text = "The following errors occured:"
                error = ''
                for conda_error in self.conda_errors:
                    error += str(conda_error[0]) + ':\n'
                    error += str(conda_error[1]) + '\n\n'
                dlg = self.message_box_error(text=text, error=error,
                                             title='Conda process error')
                dlg.setMinimumWidth(400)
                dlg.exec_()

            self.update_status('', hide=False)
            self.setup()

    def _pip_process_ready(self, worker, output, error):
        """
        """
        if error is not None:
            status = _('there was an error')
            self.update_status(hide=False, message=status)
        else:
            self.update_status(hide=True)

        self.setup()

    def _conda_process_ready(self, worker, output, error):
        """
        """
        if error is not None:
            status = _('there was an error')
            self.update_status(hide=False, message=status)
        else:
            self.update_status(hide=True)

        conda_error = None
        conda_error_type = None
        if output and isinstance(output, dict):
            conda_error_type = output.get('error_type')
            conda_error = output.get('error')

            if conda_error_type or conda_error:
                logger.error((conda_error_type, conda_error))

        dic = self._temporal_action_dic

        if dic['action'] == C.ACTION_CREATE:
            self.sig_environment_created.emit(conda_error, conda_error_type)
        elif dic['action'] == C.ACTION_CLONE:
            self.sig_environment_cloned.emit(conda_error, conda_error_type)
        elif dic['action'] == C.ACTION_REMOVE_ENV:
            self.sig_environment_removed.emit(conda_error, conda_error_type)

        self.setup()

    def _partial_output_ready(self, worker, output, error):
        """
        """
        message = None
        progress = (0, 0)

        if isinstance(output, dict):
            progress = (output.get('progress', None),
                        output.get('maxval', None))
            name = output.get('name', None)
            fetch = output.get('fetch', None)

            if fetch:
                message = "Downloading <b>{0}</b>...".format(fetch)

            if name:
                self._current_action_name = name
                message = "Linking <b>{0}</b>...".format(name)

        logger.debug(message)
        self.update_status(message, progress=progress)

    def _run_pip_action(self, package_name, action):
        """
        DEPRECATED
        """
        prefix = self.prefix

        if prefix == self.root_prefix:
            name = 'root'
        elif self.api.conda_environment_exists(prefix=prefix):
            name = osp.basename(prefix)
        else:
            name = prefix

        if action == C.ACTION_REMOVE:
            msgbox = QMessageBox.question(self,
                                          "Remove pip package: "
                                          "{0}".format(package_name),
                                          "Do you want to proceed?",
                                          QMessageBox.Yes | QMessageBox.No)
            if msgbox == QMessageBox.Yes:
                self.update_status()
                worker = self.api.pip_remove(prefix=self.prefix,
                                             pkgs=[package_name])
                worker.sig_finished.connect(self._pip_process_ready)
                status = (_('Removing pip package <b>') + package_name +
                          '</b>' + _(' from <i>') + name + '</i>')
                self.update_status(hide=True, message=status,
                                   progress=[0, 0])

    def _run_conda_action(self, package_name, action, version, versions,
                          packages_sizes):
        """
        DEPRECATED
        """
        prefix = self.prefix
        dlg = CondaPackageActionDialog(self, prefix, package_name, action,
                                       version, versions, packages_sizes,
                                       self._active_channels)

        if dlg.exec_():
            dic = {}

            self.status = 'Processing'
            self.update_status(hide=True)
            self.repaint()

            ver1 = dlg.label_version.text()
            ver2 = dlg.combobox_version.currentText()
            pkg = u'{0}={1}{2}'.format(package_name, ver1, ver2)
            dep = dlg.checkbox.checkState()
            state = dlg.checkbox.isEnabled()
            dlg.close()

            dic['pkg'] = pkg
            dic['dep'] = not (dep == 0 and state)
            dic['action'] = None
            self._run_conda_process(action, dic)

    def _run_conda_process(self, action, dic):
        """
        DEPRECTAED
        """
        self._temporal_action_dic = dic
#        prefix = self.prefix
#
#        if prefix == self.root_prefix:
#            name = 'root'
#        elif self.api.conda_environment_exists(prefix=prefix):
#            name = osp.basename(prefix)
#        else:
#            name = prefix

        if 'pkgs' in dic and 'dep' in dic:
            dep = dic['dep']
            pkgs = dic['pkgs']
            if not isinstance(pkgs, list):
                pkgs = [pkgs]

#        if (action == C.ACTION_INSTALL or action == C.ACTION_UPGRADE or
#           action == C.ACTION_DOWNGRADE):
#            status = _('Installing <b>') + dic['pkg'] + '</b>'
#            status = status + _(' into <i>') + name + '</i>'
#            worker = self.api.conda_install(prefix=prefix, pkgs=pkgs, dep=dep,
#                                            channels=self._active_channels)
#        elif action == C.ACTION_REMOVE:
#            status = (_('Removing <b>') + dic['pkg'] + '</b>' +
#                      _(' from <i>') + name + '</i>')
#            worker = self.api.conda_remove(pkgs[0], prefix=prefix)

        # --- Environment management actions
        name = dic['name']
        if action == C.ACTION_CREATE:
            status = _('Creating environment <b>') + name + '</b>'
            worker = self.api.conda_create(name=name, pkgs=pkgs,
                                           channels=self._active_channels)
        elif action == C.ACTION_CLONE:
            clone = dic['clone']
            status = (_('Cloning ') + '<i>' + clone +
                      _('</i> into <b>') + name + '</b>')
            worker = self.api.conda_clone(clone, name=name)
        elif action == C.ACTION_REMOVE_ENV:
            status = _('Removing environment <b>') + name + '</b>'
            worker = self.api.conda_remove(name=name, all_=True)

        worker.sig_finished.connect(self._conda_process_ready)
        worker.sig_partial.connect(self._partial_output_ready)
        self.update_status(hide=True, message=status, progress=None)
        self._temporal_action_dic = dic
        return worker

    # Public API
    # -------------------------------------------------------------------------
    def prepare_model_data(self, packages, apps):
        """
        """
        logger.debug('')
        self._prepare_model_data(output=(packages, apps))

    # These should be private methods....
    def enable_widgets(self):
        """ """
        self.table.hide_columns()

    def disable_widgets(self):
        """ """
        self.table.hide_action_columns()

    def accept_channels_dialog(self):
        self.button_channels.setFocus()
        self.button_channels.toggle()

    def update_actions(self, number_of_actions):
        """
        """
        self.button_apply.setVisible(bool(number_of_actions))
        self.button_clear.setVisible(bool(number_of_actions))

    # --- Non UI API
    # -------------------------------------------------------------------------
    def setup(self, check_updates=False, blacklist=[], metadata={}):
        """
        Setup packages.

        Main triger method to download repodata, load repodata, prepare and
        updating the data model.

        Parameters
        ----------
        check_updates : bool
            If `True`, checks that the latest repodata is available on the
            listed channels. If `False`, the data will be loaded from the
            downloaded files without checking for newer versions.
        blacklist: list of str
            List of conda package names to be excluded from the actual package
            manager view.
        """
        self.sig_packages_busy.emit()

        if self.busy:
            logger.debug('Busy...')
            return
        else:
            logger.debug('')

        if blacklist:
            self.package_blacklist = [p.lower() for p in blacklist]

        if metadata:
            self._metadata = metadata

        self._current_model_index = self.table.currentIndex()
        self._current_table_scroll = self.table.verticalScrollBar().value()
        self.update_status('Updating package index', True)

        if check_updates:
            worker = self.api.update_metadata()
            worker.sig_finished.connect(self._metadata_updated)
        else:
            paths = self.api.repodata_files(channels=self._active_channels)
            self._repodata_updated(paths)

    def update_domains(self, anaconda_api_url=None, conda_url=None):
        """
        """
        logger.debug(str((anaconda_api_url, conda_url)))
        update = False

        if anaconda_api_url:
            if self.conda_api_url != anaconda_api_url:
                update = True

            self.conda_api_url = anaconda_api_url
            self.api.client_set_domain(anaconda_api_url)

        if conda_url:
            if self.conda_url != conda_url:
                update = True
            self.conda_url = conda_url

        if update:
            pass

    def set_environment(self, name=None, prefix=None):
        """
        This does not update the package manager!
        """
        logger.debug(str((name, prefix)))

        if prefix and self.api.conda_environment_exists(prefix=prefix):
            self.prefix = prefix
        elif name and self.api.conda_environment_exists(name=name):
            self.prefix = self.get_prefix_envname(name)
        else:
            self.prefix = self.root_prefix

    def set_token(self, token):
        self.token = token

    def update_channels(self, channels, active_channels):
        """
        """
        logger.debug(str((channels, active_channels)))

        if sorted(self._active_channels) != sorted(active_channels) or \
                sorted(self._channels) != sorted(channels):
            self._channels = channels
            self._active_channels = active_channels
            self.sig_channels_updated.emit(tuple(channels),
                                           tuple(active_channels))
            self.setup(check_updates=True)

    def update_style_sheet(self, style_sheet=None, extra_dialogs={},
                           palette={}):
        if style_sheet:
            self.style_sheet = style_sheet
            self.table.update_style_palette(palette=palette)
            self.textbox_search.update_style_sheet(style_sheet)
            self.setStyleSheet(style_sheet)

        if extra_dialogs:
            cancel_dialog = extra_dialogs.get('cancel_dialog', None)
            apply_actions_dialog = extra_dialogs.get('apply_actions_dialog',
                                                     None)
            message_box_error = extra_dialogs.get('message_box_error',
                                                  None)
            if cancel_dialog:
                self.cancel_dialog = cancel_dialog
            if apply_actions_dialog:
                self.apply_actions_dialog = apply_actions_dialog
            if message_box_error:
                self.message_box_error = message_box_error

    # --- UI API
    # -------------------------------------------------------------------------
    def filter_package(self, value):
        """ """
        self.table.filter_status_changed(value)

    def show_channels_dialog(self):
        """
        Show the channels dialog.
        """
        button_channels = self.button_channels
        self.dlg = DialogChannels(self,
                                  channels=self._channels,
                                  active_channels=self._active_channels,
                                  conda_url=self.conda_url)
        self.dlg.update_style_sheet(style_sheet=self.style_sheet)
        button_channels.setDisabled(True)
        self.dlg.sig_channels_updated.connect(self.update_channels)
        self.dlg.rejected.connect(lambda: button_channels.setEnabled(True))
        self.dlg.rejected.connect(button_channels.toggle)
        self.dlg.rejected.connect(button_channels.setFocus)
        self.dlg.accepted.connect(self.accept_channels_dialog)

        geo_tl = button_channels.geometry().topLeft()
        tl = button_channels.parentWidget().mapToGlobal(geo_tl)
        x = tl.x() + 2
        y = tl.y() + button_channels.height()
        self.dlg.move(x, y)
        self.dlg.show()
        self.dlg.button_add.setFocus()

    def update_package_index(self):
        """ """
        self.setup(check_updates=True)

    def search_package(self, text):
        """ """
        self.table.search_string_changed(text)

    def apply_multiple_actions(self):
        """
        """
        logger.debug('')

        self.conda_errors = []

        prefix = self.prefix

        if prefix == self.root_prefix:
            name = 'root'
        elif self.api.conda_environment_exists(prefix=prefix):
            name = osp.basename(prefix)
        else:
            name = prefix

        actions = self.table.get_actions()

        if actions is None:
            return

        self._multiple_process = deque()

        pip_actions = actions[C.PIP_PACKAGE]
        conda_actions = actions[C.CONDA_PACKAGE]

        pip_remove = pip_actions.get(C.ACTION_REMOVE, [])
        conda_remove = conda_actions.get(C.ACTION_REMOVE, [])
        conda_install = conda_actions.get(C.ACTION_INSTALL, [])
        conda_upgrade = conda_actions.get(C.ACTION_UPGRADE, [])
        conda_downgrade = conda_actions.get(C.ACTION_DOWNGRADE, [])

        message = ''
        template_1 = '<li><b>{0}={1}</b></li>'
        template_2 = '<li><b>{0}: {1} -> {2}</b></li>'

        if pip_remove:
            temp = [template_1.format(i['name'], i['version_to']) for i in
                    pip_remove]
            message += ('The following pip packages will be removed: '
                        '<ul>' + ''.join(temp) + '</ul>')
        if conda_remove:
            temp = [template_1.format(i['name'], i['version_to']) for i in
                    conda_remove]
            message += ('<br>The following conda packages will be removed: '
                        '<ul>' + ''.join(temp) + '</ul>')
        if conda_install:
            temp = [template_1.format(i['name'], i['version_to']) for i in
                    conda_install]
            message += ('<br>The following conda packages will be installed: '
                        '<ul>' + ''.join(temp) + '</ul>')
        if conda_downgrade:
            temp = [template_2.format(
                    i['name'], i['version_from'], i['version_to']) for i in
                    conda_downgrade]
            message += ('<br>The following conda packages will be downgraded: '
                        '<ul>' + ''.join(temp) + '</ul>')
        if conda_upgrade:
            temp = [template_2.format(
                    i['name'], i['version_from'], i['version_to']) for i in
                    conda_upgrade]
            message += ('<br>The following conda packages will be upgraded: '
                        '<ul>' + ''.join(temp) + '</ul>')
        message += '<br>'

        if self.apply_actions_dialog:
            dlg = self.apply_actions_dialog(message, parent=self)
            dlg.update_style_sheet(style_sheet=self.style_sheet)
            reply = dlg.exec_()
        else:
            reply = QMessageBox.question(self,
                                         'Proceed with the following actions?',
                                         message,
                                         buttons=QMessageBox.Ok |
                                         QMessageBox.Cancel)

        if reply:
            # Pip remove
            for pkg in pip_remove:
                status = (_('Removing pip package <b>') + pkg['name'] +
                          '</b>' + _(' from <i>') + name + '</i>')
                pkgs = [pkg['name']]

                def trigger(prefix=prefix, pkgs=pkgs):
                    return lambda: self.api.pip_remove(prefix=prefix,
                                                       pkgs=pkgs)

                self._multiple_process.append([status, trigger()])

            # Process conda actions
            if conda_remove:
                status = (_('Removing conda packages <b>') +
                          '</b>' + _(' from <i>') + name + '</i>')
                pkgs = [i['name'] for i in conda_remove]

                def trigger(prefix=prefix, pkgs=pkgs):
                    return lambda: self.api.conda_remove(pkgs=pkgs,
                                                         prefix=prefix)
                self._multiple_process.append([status, trigger()])

            if conda_install:
                pkgs = ['{0}={1}'.format(i['name'], i['version_to']) for i in
                        conda_install]

                status = (_('Installing conda packages <b>') +
                          '</b>' + _(' on <i>') + name + '</i>')

                def trigger(prefix=prefix, pkgs=pkgs):
                    return lambda: self.api.conda_install(
                        prefix=prefix,
                        pkgs=pkgs,
                        channels=self._active_channels,
                        token=self.token)
                self._multiple_process.append([status, trigger()])

            # Conda downgrade
            if conda_downgrade:
                status = (_('Downgrading conda packages <b>') +
                          '</b>' + _(' on <i>') + name + '</i>')

                pkgs = ['{0}={1}'.format(i['name'], i['version_to']) for i in
                        conda_downgrade]

                def trigger(prefix=prefix, pkgs=pkgs):
                    return lambda: self.api.conda_install(
                        prefix=prefix,
                        pkgs=pkgs,
                        channels=self._active_channels,
                        token=self.token)

                self._multiple_process.append([status, trigger()])

            # Conda update
            if conda_upgrade:
                status = (_('Upgrading conda packages <b>') +
                          '</b>' + _(' on <i>') + name + '</i>')

                pkgs = ['{0}={1}'.format(i['name'], i['version_to']) for i in
                        conda_upgrade]

                def trigger(prefix=prefix, pkgs=pkgs):
                    return lambda: self.api.conda_install(
                        prefix=prefix,
                        pkgs=pkgs,
                        channels=self._active_channels,
                        token=self.token)

                self._multiple_process.append([status, trigger()])

            self._run_multiple_actions()

    def clear_actions(self):
        """
        """
        self.table.clear_actions()

    def cancel_process(self):
        """
        Allow user to cancel an ongoing process.
        """
        logger.debug(str('process canceled by user.'))
        if self.busy:
            dlg = self.cancel_dialog()
            reply = dlg.exec_()
            if reply:
                self.update_status(hide=False, message='Process cancelled')
                self.api.conda_terminate()
                self.api.download_requests_terminate()
                self.api.conda_clear_lock()
                self.table.clear_actions()
                self.sig_process_cancelled.emit()
        else:
            QDialog.reject(self)

    def update_status(self, message=None, hide=True, progress=None,
                      env=False):
        """
        Update status bar, progress bar display and widget visibility

        message : str
            Message to display in status bar.
        hide : bool
            Enable/Disable widgets.
        progress : [int, int]
            Show status bar progress. [0, 0] means spinning statusbar.
        """
        self.busy = hide
        for widget in self.widgets:
            widget.setDisabled(hide)
        self.table.verticalScrollBar().setValue(self._current_table_scroll)

        self.button_apply.setVisible(False)
        self.button_clear.setVisible(False)

        self.progress_bar.setVisible(hide)
        self.button_cancel.setVisible(hide)

        if message is not None:
            self.message = message

        if self.prefix == self.root_prefix:
            short_env = 'root'
#        elif self.api.environment_exists(prefix=self.prefix):
#            short_env = osp.basename(self.prefix)
        else:
            short_env = self.prefix

        if env:
            self.message = '{0} (<b>{1}</b>)'.format(
                self.message, short_env,
                )
        self.status_bar.setText(self.message)

        if progress is not None:
            current_progress, max_progress = 0, 0

            if progress[1]:
                max_progress = progress[1]

            if progress[0]:
                current_progress = progress[0]

            self.progress_bar.setMinimum(0)
            self.progress_bar.setMaximum(max_progress)
            self.progress_bar.setValue(current_progress)
        else:
            self.progress_bar.setMinimum(0)
            self.progress_bar.setMaximum(0)

    # --- Conda helpers
    # -------------------------------------------------------------------------
    def get_environment_prefix(self):
        """
        Returns the active environment prefix.
        """
        return self._prefix

    def get_environment_name(self):
        """
        Returns the active environment name if it is located in the default
        conda environments directory, otherwise it returns the prefix.
        """
        name = osp.basename(self._prefix)

        if not (name and self.api.environment_exists(name=name)):
            name = self._prefix

        return name

    def get_environments(self):
        """
        Get a list of conda environments located in the default conda
        environments directory.
        """
        return self.api.conda_get_envs()

    def get_prefix_envname(self, name):
        """
        Returns the prefix for a given environment by name.
        """
        return self.api.conda_get_prefix_envname(name)

    def get_package_versions(self, name):
        """ """
        return self.table.source_model.get_package_versions(name)

    # --- Conda actions
    # -------------------------------------------------------------------------
    def create_environment(self, name=None, prefix=None, packages=['python']):
        """ """
        # If environment exists already? GUI should take care of this
        # BUT the api call should simply set that env as the env
        dic = {}
        dic['name'] = name
        dic['prefix'] = prefix
        dic['pkgs'] = packages
        dic['dep'] = True  # Not really needed but for the moment!
        dic['action'] = C.ACTION_CREATE
        return self._run_conda_process(dic['action'], dic)

    def clone_environment(self, name=None, prefix=None, clone=None):
        dic = {}
        dic['name'] = name
        dic['prefix'] = prefix
        dic['clone'] = clone
        dic['pkgs'] = None
        dic['dep'] = True  # Not really needed but for the moment!
        dic['action'] = C.ACTION_CLONE
        return self._run_conda_process(dic['action'], dic)

    def remove_environment(self, name=None, prefix=None):
        dic = {}
        dic['name'] = name
        dic['pkgs'] = None
        dic['dep'] = True  # Not really needed but for the moment!
        dic['action'] = C.ACTION_REMOVE_ENV
        return self._run_conda_process(dic['action'], dic)
コード例 #18
0
ファイル: dlg_find_elements.py プロジェクト: mrakitin/PyXRF
    def __init__(self, parent=None):

        super().__init__(parent)

        self._dialog_data = {}

        self.setWindowTitle("Find Elements in Sample")

        # Check this flag after the dialog is exited with 'True' value
        #   If this flag is True, then run element search, if False,
        #   then simply save the changed parameter values.
        self.find_elements_requested = False

        self.validator = QDoubleValidator()

        self.le_e_calib_a0 = LineEditExtended()
        self.le_e_calib_a0.setValidator(self.validator)
        self.pb_e_calib_a0_default = QPushButton("Default")
        self.pb_e_calib_a0_default.setAutoDefault(False)

        self.le_e_calib_a1 = LineEditExtended()
        self.le_e_calib_a1.setValidator(self.validator)
        self.pb_e_calib_a1_default = QPushButton("Default")
        self.pb_e_calib_a1_default.setAutoDefault(False)

        self.le_e_calib_a2 = LineEditExtended()
        self.le_e_calib_a2.setValidator(self.validator)
        self.pb_e_calib_a2_default = QPushButton("Default")
        self.pb_e_calib_a2_default.setAutoDefault(False)

        self.group_energy_axis_calib = QGroupBox(
            "Polynomial Approximation of Energy Axis")
        set_tooltip(
            self.group_energy_axis_calib,
            "Parameters of polynomial approximation of <b>energy axis</b>. "
            "The values of the bins for photon energies are approximated "
            "using 2nd degree polynomial <b>E(n) = a0 + a1 * n + a2 * n^2</b>, "
            "where <b>n</b> is bin number (typically in the range 0..4096).",
        )
        grid = QGridLayout()
        grid.addWidget(QLabel("Bias (a0):"), 0, 0)
        grid.addWidget(self.le_e_calib_a0, 0, 1)
        grid.addWidget(self.pb_e_calib_a0_default, 0, 2)
        grid.addWidget(QLabel("Linear (a1):"), 1, 0)
        grid.addWidget(self.le_e_calib_a1, 1, 1)
        grid.addWidget(self.pb_e_calib_a1_default, 1, 2)
        grid.addWidget(QLabel("Quadratic (a2):"), 2, 0)
        grid.addWidget(self.le_e_calib_a2, 2, 1)
        grid.addWidget(self.pb_e_calib_a2_default, 2, 2)
        self.group_energy_axis_calib.setLayout(grid)

        self.le_fwhm_b1 = LineEditExtended()
        self.le_fwhm_b1.setValidator(self.validator)
        self.pb_fwhm_b1_default = QPushButton("Default")
        self.pb_fwhm_b1_default.setAutoDefault(False)

        self.le_fwhm_b2 = LineEditExtended()
        self.le_fwhm_b2.setValidator(self.validator)
        self.pb_fwhm_b2_default = QPushButton("Default")
        self.pb_fwhm_b2_default.setAutoDefault(False)

        self.group_fwhm = QGroupBox("Peak FWHM Settings")
        set_tooltip(
            self.group_fwhm,
            "Parameters used to estimate <b>FWHM</b> of peaks based on energy: "
            "<b>b1</b> - 'offset', <b>b2</b> - 'fanoprime'",
        )
        grid = QGridLayout()
        grid.addWidget(QLabel("Coefficient b1:"), 0, 0)
        grid.addWidget(self.le_fwhm_b1, 0, 1)
        grid.addWidget(self.pb_fwhm_b1_default, 0, 2)
        grid.addWidget(QLabel("Coefficient b2:"), 1, 0)
        grid.addWidget(self.le_fwhm_b2, 1, 1)
        grid.addWidget(self.pb_fwhm_b2_default, 1, 2)
        self.group_fwhm.setLayout(grid)

        self.le_incident_energy = LineEditExtended()
        self.le_incident_energy.setValidator(self.validator)
        set_tooltip(self.le_incident_energy, "<b>Incident energy</b> in keV.")
        self.pb_incident_energy_default = QPushButton("Default")
        self.pb_incident_energy_default.setAutoDefault(False)
        self.le_range_low = LineEditExtended()
        self.le_range_low.setValidator(self.validator)
        set_tooltip(self.le_range_low,
                    "<b>Lower boundary</b> of the selected range in keV.")
        self.pb_range_low_default = QPushButton("Default")
        self.pb_range_low_default.setAutoDefault(False)
        self.le_range_high = LineEditExtended()
        self.le_range_high.setValidator(self.validator)
        set_tooltip(self.le_range_high,
                    "<b>Upper boundary</b> of the selected range in keV.")
        self.pb_range_high_default = QPushButton("Default")
        self.pb_range_high_default.setAutoDefault(False)
        self.group_energy_range = QGroupBox(
            "Incident Energy and Selected Range")
        grid = QGridLayout()
        grid.addWidget(QLabel("Incident energy, keV"), 0, 0)
        grid.addWidget(self.le_incident_energy, 0, 1)
        grid.addWidget(self.pb_incident_energy_default, 0, 2)
        grid.addWidget(QLabel("Range (low), keV"), 1, 0)
        grid.addWidget(self.le_range_low, 1, 1)
        grid.addWidget(self.pb_range_low_default, 1, 2)
        grid.addWidget(QLabel("Range (high), keV"), 2, 0)
        grid.addWidget(self.le_range_high, 2, 1)
        grid.addWidget(self.pb_range_high_default, 2, 2)
        self.group_energy_range.setLayout(grid)

        self.pb_find_elements = QPushButton("Find &Elements")
        self.pb_find_elements.clicked.connect(self.pb_find_elements_clicked)
        self.pb_apply_settings = QPushButton("&Apply Settings")

        # 'Close' button box
        button_box = QDialogButtonBox(QDialogButtonBox.Cancel)
        button_box.addButton(self.pb_find_elements, QDialogButtonBox.YesRole)
        button_box.addButton(self.pb_apply_settings,
                             QDialogButtonBox.AcceptRole)
        button_box.button(QDialogButtonBox.Cancel).setDefault(True)
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)

        self.pb_cancel = button_box.button(QDialogButtonBox.Cancel)
        self.pb_cancel.setAutoDefault(False)
        self.pb_apply_settings.setAutoDefault(True)

        vbox = QVBoxLayout()
        vbox.addWidget(self.group_energy_axis_calib)
        vbox.addWidget(self.group_fwhm)
        vbox.addWidget(self.group_energy_range)
        vbox.addWidget(button_box)

        self.setLayout(vbox)

        self.le_e_calib_a0.editingFinished.connect(
            self.le_e_calib_a0_editing_finished)
        self.le_e_calib_a1.editingFinished.connect(
            self.le_e_calib_a1_editing_finished)
        self.le_e_calib_a2.editingFinished.connect(
            self.le_e_calib_a2_editing_finished)
        self.le_fwhm_b1.editingFinished.connect(
            self.le_fwhm_b1_editing_finished)
        self.le_fwhm_b2.editingFinished.connect(
            self.le_fwhm_b2_editing_finished)
        self.le_incident_energy.editingFinished.connect(
            self.le_incident_energy_editing_finished)
        self.le_range_low.editingFinished.connect(
            self.le_range_low_editing_finished)
        self.le_range_high.editingFinished.connect(
            self.le_range_high_editing_finished)

        self.le_e_calib_a0.focusOut.connect(self.le_e_calib_a0_focus_out)
        self.le_e_calib_a1.focusOut.connect(self.le_e_calib_a1_focus_out)
        self.le_e_calib_a2.focusOut.connect(self.le_e_calib_a2_focus_out)
        self.le_fwhm_b1.focusOut.connect(self.le_fwhm_b1_focus_out)
        self.le_fwhm_b2.focusOut.connect(self.le_fwhm_b2_focus_out)
        self.le_incident_energy.focusOut.connect(
            self.le_incident_energy_focus_out)
        self.le_range_low.focusOut.connect(self.le_range_low_focus_out)
        self.le_range_high.focusOut.connect(self.le_range_high_focus_out)

        self.le_e_calib_a0.textChanged.connect(self.le_e_calib_a0_text_changed)
        self.le_e_calib_a1.textChanged.connect(self.le_e_calib_a1_text_changed)
        self.le_e_calib_a2.textChanged.connect(self.le_e_calib_a2_text_changed)
        self.le_fwhm_b1.textChanged.connect(self.le_fwhm_b1_text_changed)
        self.le_fwhm_b2.textChanged.connect(self.le_fwhm_b2_text_changed)
        self.le_incident_energy.textChanged.connect(
            self.le_incident_energy_text_changed)
        self.le_range_low.textChanged.connect(self.le_range_low_text_changed)
        self.le_range_high.textChanged.connect(self.le_range_high_text_changed)

        self.pb_e_calib_a0_default.clicked.connect(
            self.pb_e_calib_a0_default_clicked)
        self.pb_e_calib_a1_default.clicked.connect(
            self.pb_e_calib_a1_default_clicked)
        self.pb_e_calib_a2_default.clicked.connect(
            self.pb_e_calib_a2_default_clicked)
        self.pb_fwhm_b1_default.clicked.connect(
            self.pb_fwhm_b1_default_clicked)
        self.pb_fwhm_b2_default.clicked.connect(
            self.pb_fwhm_b2_default_clicked)
        self.pb_incident_energy_default.clicked.connect(
            self.pb_incident_energy_default_clicked)
        self.pb_range_low_default.clicked.connect(
            self.pb_range_low_default_clicked)
        self.pb_range_high_default.clicked.connect(
            self.pb_range_high_default_clicked)
コード例 #19
0
class SelectFromListDialog(QDialog):
    """Dialog box for selecting multiple items.

    The original order of items are preserved in the candidate list.
    """

    def __init__(self, parent=None, allItems=(), selectedItems=()):
        QDialog.__init__(
            self, parent, flags=Qt.WindowSystemMenuHint | Qt.WindowTitleHint)

        self.allItems = allItems

        self.fromKeys = list(range(len(allItems)))
        self.selectedKeys = []
        for item in selectedItems:
            key = allItems.index(item)
            self.fromKeys.remove(key)
            self.selectedKeys.append(key)

        self.setAttribute(Qt.WA_DeleteOnClose)

        fromLabel = QLabel(_("Select from"))
        self.fromList = QListWidget(self)
        self.fromList.addItems(allItems[key] for key in self.fromKeys)

        selectedLabel = QLabel(_("Selected"))
        self.selectedList = QListWidget(self)
        self.selectedList.addItems(allItems[key] for key in self.selectedKeys)

        self.selectButton = QPushButton(_("Select"))
        self.deselectButton = QPushButton(_("Deselect"))
        self.selectBox = QDialogButtonBox(Qt.Vertical)
        self.selectBox.addButton(self.selectButton, QDialogButtonBox.ActionRole)
        self.selectBox.addButton(self.deselectButton, QDialogButtonBox.ActionRole)
        self.selectButton.clicked.connect(self.on_select)
        self.deselectButton.clicked.connect(self.on_deselect)

        self.buttonBox = QDialogButtonBox(self)
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(
            QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        mainLayout = QGridLayout(self)
        mainLayout.addWidget(fromLabel, 0, 0)
        mainLayout.addWidget(selectedLabel, 0, 2)
        mainLayout.addWidget(self.fromList, 1, 0)
        mainLayout.addWidget(self.selectBox, 1, 1)
        mainLayout.addWidget(self.selectedList, 1, 2)
        mainLayout.addWidget(self.buttonBox, 2, 0, 1, 3)
        mainLayout.setAlignment(self.selectBox, Qt.AlignCenter)
        self.setLayout(mainLayout)

    def on_select(self):
        if len(self.fromList.selectedItems()):
            idx = self.fromList.currentRow()
            key = self.fromKeys.pop(idx)
            self.selectedKeys.append(key)
            item = self.fromList.takeItem(idx)
            self.selectedList.addItem(item)

    def on_deselect(self):
        if len(self.selectedList.selectedItems()):
            idx = self.selectedList.currentRow()
            item = self.selectedList.takeItem(idx)
            key = self.selectedKeys.pop(idx)
            idx = next((i for i, v in enumerate(self.fromKeys) if v > key),
                       len(self.fromKeys))
            self.fromKeys.insert(idx, key)
            self.fromList.insertItem(idx, item)
コード例 #20
0
ファイル: projectdialog.py プロジェクト: burrbull/spyder
class ProjectDialog(QDialog):
    """Project creation dialog."""

    # path, type, packages
    sig_project_creation_requested = Signal(object, object, object)

    def __init__(self, parent):
        """Project creation dialog."""
        super(ProjectDialog, self).__init__(parent=parent)

        # Variables
        current_python_version = '.'.join([to_text_string(sys.version_info[0]),
                                           to_text_string(sys.version_info[1])])
        python_versions = ['2.7', '3.4', '3.5']
        if current_python_version not in python_versions:
            python_versions.append(current_python_version)
            python_versions = sorted(python_versions)

        self.project_name = None
        self.location = get_home_dir()

        # Widgets
        self.groupbox = QGroupBox()
        self.radio_new_dir = QRadioButton(_("New directory"))
        self.radio_from_dir = QRadioButton(_("Existing directory"))

        self.label_project_name = QLabel(_('Project name'))
        self.label_location = QLabel(_('Location'))
        self.label_project_type = QLabel(_('Project type'))
        self.label_python_version = QLabel(_('Python version'))

        self.text_project_name = QLineEdit()
        self.text_location = QLineEdit(get_home_dir())
        self.combo_project_type = QComboBox()
        self.combo_python_version = QComboBox()

        self.button_select_location = QToolButton()
        self.button_cancel = QPushButton(_('Cancel'))
        self.button_create = QPushButton(_('Create'))

        self.bbox = QDialogButtonBox(Qt.Horizontal)
        self.bbox.addButton(self.button_cancel, QDialogButtonBox.ActionRole)
        self.bbox.addButton(self.button_create, QDialogButtonBox.ActionRole)

        # Widget setup
        self.combo_python_version.addItems(python_versions)
        self.radio_new_dir.setChecked(True)
        self.text_location.setEnabled(True)
        self.text_location.setReadOnly(True)
        self.button_select_location.setIcon(get_std_icon('DirOpenIcon'))
        self.button_cancel.setDefault(True)
        self.button_cancel.setAutoDefault(True)
        self.button_create.setEnabled(False)
        self.combo_project_type.addItems(self._get_project_types())
        self.combo_python_version.setCurrentIndex(
            python_versions.index(current_python_version))
        self.setWindowTitle(_('Create new project'))
        self.setFixedWidth(500)
        self.label_python_version.setVisible(False)
        self.combo_python_version.setVisible(False)

        # Layouts        
        layout_top = QHBoxLayout()
        layout_top.addWidget(self.radio_new_dir)
        layout_top.addWidget(self.radio_from_dir)
        layout_top.addStretch(1)
        self.groupbox.setLayout(layout_top)

        layout_grid = QGridLayout()
        layout_grid.addWidget(self.label_project_name, 0, 0)
        layout_grid.addWidget(self.text_project_name, 0, 1, 1, 2)
        layout_grid.addWidget(self.label_location, 1, 0)
        layout_grid.addWidget(self.text_location, 1, 1)
        layout_grid.addWidget(self.button_select_location, 1, 2)
        layout_grid.addWidget(self.label_project_type, 2, 0)
        layout_grid.addWidget(self.combo_project_type, 2, 1, 1, 2)
        layout_grid.addWidget(self.label_python_version, 3, 0)
        layout_grid.addWidget(self.combo_python_version, 3, 1, 1, 2)

        layout = QVBoxLayout()
        layout.addWidget(self.groupbox)
        layout.addSpacing(10)
        layout.addLayout(layout_grid)
        layout.addStretch()
        layout.addSpacing(20)
        layout.addWidget(self.bbox)

        self.setLayout(layout)

        # Signals and slots
        self.button_select_location.clicked.connect(self.select_location)
        self.button_create.clicked.connect(self.create_project)
        self.button_cancel.clicked.connect(self.close)
        self.radio_from_dir.clicked.connect(self.update_location)
        self.radio_new_dir.clicked.connect(self.update_location)
        self.text_project_name.textChanged.connect(self.update_location)

    def _get_project_types(self):
        """Get all available project types."""
        project_types = get_available_project_types()
        projects = []

        for project in project_types:
            projects.append(project.PROJECT_TYPE_NAME)

        return projects

    def select_location(self):
        """Select directory."""
        location = osp.normpath(getexistingdirectory(self,
                                                     _("Select directory"),
                                                     self.location))

        if location:
            if is_writable(location):
                self.location = location
                self.update_location()

    def update_location(self, text=''):
        """Update text of location."""
        self.text_project_name.setEnabled(self.radio_new_dir.isChecked())
        name = self.text_project_name.text().strip()

        if name and self.radio_new_dir.isChecked():
            path = osp.join(self.location, name)
            self.button_create.setDisabled(os.path.isdir(path))
        elif self.radio_from_dir.isChecked():
            self.button_create.setEnabled(True)
            path = self.location
        else:
            self.button_create.setEnabled(False)
            path = self.location
        
        self.text_location.setText(path)
        
    def create_project(self):
        """Create project."""
        packages = ['python={0}'.format(self.combo_python_version.currentText())]
        self.sig_project_creation_requested.emit(
            self.text_location.text(),
            self.combo_project_type.currentText(),
            packages)
        self.accept()
コード例 #21
0
class ProjectDialog(QDialog):
    """Project creation dialog."""

    sig_project_creation_requested = Signal(str, str, object)
    """
    This signal is emitted to request the Projects plugin the creation of a
    project.

    Parameters
    ----------
    project_path: str
        Location of project.
    project_type: str
        Type of project as defined by project types.
    project_packages: object
        Package to install. Currently not in use.
    """
    def __init__(self, parent, project_types):
        """Project creation dialog."""
        super(ProjectDialog, self).__init__(parent=parent)
        self.plugin = parent
        self._project_types = project_types
        self.project_data = {}

        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)

        self.project_name = None
        self.location = get_home_dir()

        # Widgets
        projects_url = "http://docs.spyder-ide.org/current/panes/projects.html"
        self.description_label = QLabel(
            _("Select a new or existing directory to create a new Spyder "
              "project in it. To learn more about projects, take a look at "
              "our <a href=\"{0}\">documentation</a>.").format(projects_url))
        self.description_label.setOpenExternalLinks(True)
        self.description_label.setWordWrap(True)

        self.groupbox = QGroupBox()
        self.radio_new_dir = QRadioButton(_("New directory"))
        self.radio_from_dir = QRadioButton(_("Existing directory"))

        self.label_project_name = QLabel(_('Project name'))
        self.label_location = QLabel(_('Location'))
        self.label_project_type = QLabel(_('Project type'))

        self.text_project_name = QLineEdit()
        self.text_location = QLineEdit(get_home_dir())
        self.combo_project_type = QComboBox()

        self.label_information = QLabel("")
        self.label_information.hide()

        self.button_select_location = create_toolbutton(
            self,
            triggered=self.select_location,
            icon=ima.icon('DirOpenIcon'),
            tip=_("Select directory"))
        self.button_cancel = QPushButton(_('Cancel'))
        self.button_create = QPushButton(_('Create'))

        self.bbox = QDialogButtonBox(Qt.Horizontal)
        self.bbox.addButton(self.button_cancel, QDialogButtonBox.ActionRole)
        self.bbox.addButton(self.button_create, QDialogButtonBox.ActionRole)

        # Widget setup
        self.radio_new_dir.setChecked(True)
        self.text_location.setEnabled(True)
        self.text_location.setReadOnly(True)
        self.button_cancel.setDefault(True)
        self.button_cancel.setAutoDefault(True)
        self.button_create.setEnabled(False)
        for (id_, name) in [(pt_id, pt.get_name())
                            for pt_id, pt in project_types.items()]:
            self.combo_project_type.addItem(name, id_)

        self.setWindowTitle(_('Create new project'))

        # Layouts
        layout_top = QHBoxLayout()
        layout_top.addWidget(self.radio_new_dir)
        layout_top.addSpacing(15)
        layout_top.addWidget(self.radio_from_dir)
        layout_top.addSpacing(200)
        self.groupbox.setLayout(layout_top)

        layout_grid = QGridLayout()
        layout_grid.addWidget(self.label_project_name, 0, 0)
        layout_grid.addWidget(self.text_project_name, 0, 1, 1, 2)
        layout_grid.addWidget(self.label_location, 1, 0)
        layout_grid.addWidget(self.text_location, 1, 1)
        layout_grid.addWidget(self.button_select_location, 1, 2)
        layout_grid.addWidget(self.label_project_type, 2, 0)
        layout_grid.addWidget(self.combo_project_type, 2, 1, 1, 2)
        layout_grid.addWidget(self.label_information, 3, 0, 1, 3)

        layout = QVBoxLayout()
        layout.addWidget(self.description_label)
        layout.addSpacing(3)
        layout.addWidget(self.groupbox)
        layout.addSpacing(8)
        layout.addLayout(layout_grid)
        layout.addSpacing(8)
        layout.addWidget(self.bbox)
        layout.setSizeConstraint(layout.SetFixedSize)

        self.setLayout(layout)

        # Signals and slots
        self.button_create.clicked.connect(self.create_project)
        self.button_cancel.clicked.connect(self.close)
        self.radio_from_dir.clicked.connect(self.update_location)
        self.radio_new_dir.clicked.connect(self.update_location)
        self.text_project_name.textChanged.connect(self.update_location)

    def select_location(self):
        """Select directory."""
        location = osp.normpath(
            getexistingdirectory(
                self,
                _("Select directory"),
                self.location,
            ))

        if location and location != '.':
            if is_writable(location):
                self.location = location
                self.text_project_name.setText(osp.basename(location))
                self.update_location()

    def update_location(self, text=''):
        """Update text of location and validate it."""
        msg = ''
        path_validation = False
        path = self.location
        name = self.text_project_name.text().strip()

        # Setup
        self.text_project_name.setEnabled(self.radio_new_dir.isChecked())
        self.label_information.setText('')
        self.label_information.hide()

        if name and self.radio_new_dir.isChecked():
            # Allow to create projects only on new directories.
            path = osp.join(self.location, name)
            path_validation = not osp.isdir(path)
            if not path_validation:
                msg = _("This directory already exists!")
        elif self.radio_from_dir.isChecked():
            # Allow to create projects in current directories that are not
            # Spyder projects.
            path = self.location
            path_validation = not osp.isdir(osp.join(path, '.spyproject'))
            if not path_validation:
                msg = _("This directory is already a Spyder project!")

        # Set path in text_location
        self.text_location.setText(path)

        # Validate project name with the method from the currently selected
        # project.
        project_type_id = self.combo_project_type.currentData()
        validate_func = self._project_types[project_type_id].validate_name
        project_name_validation, project_msg = validate_func(path, name)
        if not project_name_validation:
            if msg:
                msg = msg + '\n\n' + project_msg
            else:
                msg = project_msg

        # Set message
        if msg:
            self.label_information.show()
            self.label_information.setText('\n' + msg)

        # Allow to create project if validation was successful
        validated = path_validation and project_name_validation
        self.button_create.setEnabled(validated)

        # Set default state of buttons according to validation
        # Fixes spyder-ide/spyder#16745
        if validated:
            self.button_create.setDefault(True)
            self.button_create.setAutoDefault(True)
        else:
            self.button_cancel.setDefault(True)
            self.button_cancel.setAutoDefault(True)

    def create_project(self):
        """Create project."""
        self.project_data = {
            "root_path": self.text_location.text(),
            "project_type": self.combo_project_type.currentData(),
        }
        self.sig_project_creation_requested.emit(
            self.text_location.text(),
            self.combo_project_type.currentData(),
            [],
        )
        self.accept()
コード例 #22
0
ファイル: packages.py プロジェクト: locolucco209/MongoScraper
class CondaPackagesWidget(QWidget):
    """Conda Packages Widget."""

    sig_ready = Signal()
    sig_next_focus = Signal()

    # conda_packages_action_dict, pip_packages_action_dict
    sig_packages_action_requested = Signal(object, object)

    # button_widget, sender
    sig_channels_requested = Signal(object, object)

    # sender
    sig_update_index_requested = Signal(object)
    sig_cancel_requested = Signal(object)

    def __init__(self, parent, config=CONF):
        """Conda Packages Widget."""
        super(CondaPackagesWidget, self).__init__(parent)

        self._parent = parent
        self._current_model_index = None
        self._current_action_name = ''
        self._current_table_scroll = None
        self._hide_widgets = False

        self.api = AnacondaAPI()
        self.prefix = None

        self.style_sheet = None
        self.message = ''
        self.config = config

        # Widgets
        self.bbox = QDialogButtonBox(Qt.Horizontal)
        self.button_cancel = ButtonPackageCancel('Cancel')
        self.button_channels = ButtonPackageChannels(_('Channels'))
        self.button_ok = ButtonPackageOk(_('Ok'))
        self.button_update = ButtonPackageUpdate(_('Update index...'))
        self.button_apply = ButtonPackageApply(_('Apply'))
        self.button_clear = ButtonPackageClear(_('Clear'))
        self.combobox_filter = ComboBoxPackageFilter(self)
        self.frame_top = FrameTabHeader()
        self.frame_bottom = FrameTabFooter()
        self.progress_bar = ProgressBarPackage(self)
        self.label_status = LabelPackageStatus(self)
        self.label_status_action = LabelPackageStatusAction(self)
        self.table = TableCondaPackages(self)
        self.textbox_search = LineEditSearch(self)
        self.widgets = [
            self.button_update, self.button_channels, self.combobox_filter,
            self.textbox_search, self.table, self.button_ok, self.button_apply,
            self.button_clear
        ]
        self.table_first_row = FirstRowWidget(
            widget_before=self.textbox_search)
        self.table_last_row = LastRowWidget(widgets_after=[
            self.button_apply,
            self.button_clear,
            self.button_cancel,
        ])

        # Widgets setup
        max_height = self.label_status.fontMetrics().height()
        max_width = self.textbox_search.fontMetrics().width('M' * 23)
        self.bbox.addButton(self.button_ok, QDialogButtonBox.ActionRole)
        self.button_ok.setMaximumSize(QSize(0, 0))
        self.button_ok.setVisible(False)
        self.button_channels.setCheckable(True)
        combo_items = [k for k in C.COMBOBOX_VALUES_ORDERED]
        self.combobox_filter.addItems(combo_items)
        self.combobox_filter.setMinimumWidth(120)
        self.progress_bar.setMaximumHeight(max_height * 1.2)
        self.progress_bar.setMaximumWidth(max_height * 12)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.setVisible(False)
        self.setMinimumSize(QSize(480, 300))
        self.setWindowTitle(_("Conda Package Manager"))
        self.label_status.setFixedHeight(max_height * 1.5)
        self.textbox_search.setMaximumWidth(max_width)
        self.textbox_search.setPlaceholderText('Search Packages')
        self.table_first_row.setMaximumHeight(0)
        self.table_last_row.setMaximumHeight(0)
        self.table_last_row.setVisible(False)
        self.table_first_row.setVisible(False)

        # Layout
        top_layout = QHBoxLayout()
        top_layout.addWidget(self.combobox_filter, 0, Qt.AlignCenter)
        top_layout.addWidget(SpacerHorizontal())
        top_layout.addWidget(self.button_channels, 0, Qt.AlignCenter)
        top_layout.addWidget(SpacerHorizontal())
        top_layout.addWidget(self.button_update, 0, Qt.AlignCenter)
        top_layout.addWidget(SpacerHorizontal())
        top_layout.addWidget(self.textbox_search, 0, Qt.AlignCenter)
        top_layout.addStretch()
        self.frame_top.setLayout(top_layout)

        middle_layout = QVBoxLayout()
        middle_layout.addWidget(self.table_first_row)
        middle_layout.addWidget(self.table)
        middle_layout.addWidget(self.table_last_row)

        bottom_layout = QHBoxLayout()
        bottom_layout.addWidget(self.label_status_action)
        bottom_layout.addWidget(SpacerHorizontal())
        bottom_layout.addWidget(self.label_status)
        bottom_layout.addStretch()
        bottom_layout.addWidget(self.progress_bar)
        bottom_layout.addWidget(SpacerHorizontal())
        bottom_layout.addWidget(self.button_cancel)
        bottom_layout.addWidget(SpacerHorizontal())
        bottom_layout.addWidget(self.button_apply)
        bottom_layout.addWidget(SpacerHorizontal())
        bottom_layout.addWidget(self.button_clear)
        self.frame_bottom.setLayout(bottom_layout)

        layout = QVBoxLayout(self)
        layout.addWidget(self.frame_top)
        layout.addLayout(middle_layout)
        layout.addWidget(self.frame_bottom)
        self.setLayout(layout)

        # Signals and slots
        self.button_cancel.clicked.connect(
            lambda: self.sig_cancel_requested.emit(C.TAB_ENVIRONMENT))
        self.combobox_filter.currentTextChanged.connect(self.filter_package)
        self.button_apply.clicked.connect(self.apply_multiple_actions)
        self.button_clear.clicked.connect(self.clear_actions)
        self.button_channels.clicked.connect(self.show_channels)
        self.button_update.clicked.connect(self.update_package_index)
        self.textbox_search.textChanged.connect(self.search_package)
        self.table.sig_actions_updated.connect(self.update_actions)
        self.table.sig_status_updated.connect(self.update_status)

        self.table.sig_next_focus.connect(self.table_last_row.handle_tab)
        self.table.sig_previous_focus.connect(
            lambda: self.table_first_row.widget_before.setFocus())
        self.table_first_row.sig_enter_first.connect(self._handle_tab_focus)
        self.table_last_row.sig_enter_last.connect(self._handle_backtab_focus)

        self.button_cancel.setVisible(False)

    # --- Helpers
    # -------------------------------------------------------------------------
    def _handle_tab_focus(self):
        self.table.setFocus()
        if self.table.proxy_model:
            index = self.table.proxy_model.index(0, 0)
            self.table.setCurrentIndex(index)

    def _handle_backtab_focus(self):
        self.table.setFocus()
        if self.table.proxy_model:
            row = self.table.proxy_model.rowCount() - 1
            index = self.table.proxy_model.index(row, 0)
            self.table.setCurrentIndex(index)

    # --- Setup
    # -------------------------------------------------------------------------
    def setup(self, packages=None, model_data=None, prefix=None):
        """
        Setup packages.

        Populate the table with `packages` information.

        Parameters
        ----------
        packages: dict
            Grouped package information by package name.
        blacklist: list of str
            List of conda package names to be excluded from the actual package
            manager view.
        """
        self.table.setup_model(packages, model_data)
        combobox_text = self.combobox_filter.currentText()
        self.combobox_filter.setCurrentText(combobox_text)
        self.filter_package(combobox_text)
        self.table.setFocus()
        self.sig_ready.emit()

    # --- Other methods
    # -------------------------------------------------------------------------
    def apply_multiple_actions(self):
        """Apply multiple actions on packages."""
        logger.debug('')

        actions = self.table.get_actions()
        pip_actions = actions[C.PIP_PACKAGE]
        conda_actions = actions[C.CONDA_PACKAGE]

        self.sig_packages_action_requested.emit(conda_actions, pip_actions)

    def clear_actions(self):
        """Clear the table actions."""
        self.table.clear_actions()

    def filter_package(self, value):
        """Filter packages by type."""
        self.table.filter_status_changed(value)

    def search_package(self, text):
        """Search and filter packages by text."""
        self.table.search_string_changed(text)

    def show_channels(self):
        """Show channel dialog."""
        self.sig_channels_requested.emit(
            self.button_channels,
            C.TAB_ENVIRONMENT,
        )

    def update_actions(self, number_of_actions):
        """Update visibility of buttons based on actions."""
        self.button_apply.setVisible(bool(number_of_actions))
        self.button_clear.setVisible(bool(number_of_actions))

    def update_package_index(self):
        """Update pacakge index."""
        self.sig_update_index_requested.emit(C.ENVIRONMENT_PACKAGE_MANAGER)

    # --- Common methods
    # -------------------------------------------------------------------------
    def ordered_widgets(self):
        pass

    def set_widgets_enabled(self, value):
        """Set the enabled status of widgets and subwidgets."""
        self.table.setEnabled(value)
        self.button_clear.setEnabled(value)
        self.button_apply.setEnabled(value)
        self.button_cancel.setEnabled(not value)
        self.button_cancel.setVisible(not value)

    def update_status(self, action='', message='', value=None, max_value=None):
        """
        Update status of package widget.

        - progress == None and max_value == None -> Not Visible
        - progress == 0 and max_value == 0 -> Busy
        - progress == n and max_value == m -> Progress values
        """
        self.label_status_action.setText(action)
        self.label_status.setText(message)

        if max_value is None and value is None:
            self.progress_bar.setVisible(False)
        else:
            self.progress_bar.setVisible(True)
            self.progress_bar.setMaximum(max_value)
            self.progress_bar.setValue(value)

    def update_style_sheet(self, style_sheet=None):
        """Update custom CSS style sheet."""
        if style_sheet is None:
            self.style_sheet = load_style_sheet()
        else:
            self.style_sheet = style_sheet
        self.setStyleSheet(self.style_sheet)
コード例 #23
0
ファイル: baseplot_curve_editor.py プロジェクト: slaclab/pydm
class BasePlotCurveEditorDialog(QDialog):
    """QDialog that is used in Qt Designer to edit the properties of the
    curves in a waveform plot.  This dialog is shown when you double-click
    the plot, or when you right click it and choose 'edit curves'.

    This thing is mostly just a wrapper for a table view, with a couple
    buttons to add and remove curves, and a button to save the changes."""
    TABLE_MODEL_CLASS = BasePlotCurvesModel

    def __init__(self, plot, parent=None):
        super(BasePlotCurveEditorDialog, self).__init__(parent)
        self.plot = plot
        self.setup_ui()
        self.table_model = self.TABLE_MODEL_CLASS(self.plot)
        self.table_view.setModel(self.table_model)
        self.table_model.plot = plot
        # self.table_view.resizeColumnsToContents()
        self.add_button.clicked.connect(self.addCurve)
        self.remove_button.clicked.connect(self.removeSelectedCurve)
        self.remove_button.setEnabled(False)
        self.table_view.selectionModel().selectionChanged.connect(
            self.handleSelectionChange)
        self.table_view.doubleClicked.connect(self.handleDoubleClick)
        self.resize(800, 300)

    def setup_ui(self):
        self.vertical_layout = QVBoxLayout(self)
        self.table_view = QTableView(self)
        self.table_view.setEditTriggers(QAbstractItemView.DoubleClicked)
        self.table_view.setProperty("showDropIndicator", False)
        self.table_view.setDragDropOverwriteMode(False)
        self.table_view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table_view.setSortingEnabled(False)
        self.table_view.horizontalHeader().setStretchLastSection(True)
        self.table_view.verticalHeader().setVisible(False)
        self.table_view.setColumnWidth(0, 160)
        self.table_view.setColumnWidth(1, 160)
        self.table_view.setColumnWidth(2, 160)
        self.vertical_layout.addWidget(self.table_view)
        self.add_remove_layout = QHBoxLayout()
        spacer = QSpacerItem(40, 20, QSizePolicy.Expanding,
                             QSizePolicy.Minimum)
        self.add_remove_layout.addItem(spacer)
        self.add_button = QPushButton("Add Curve", self)
        self.add_remove_layout.addWidget(self.add_button)
        self.remove_button = QPushButton("Remove Curve", self)
        self.add_remove_layout.addWidget(self.remove_button)
        self.vertical_layout.addLayout(self.add_remove_layout)
        self.button_box = QDialogButtonBox(self)
        self.button_box.setOrientation(Qt.Horizontal)
        self.button_box.addButton("Done", QDialogButtonBox.AcceptRole)
        self.vertical_layout.addWidget(self.button_box)
        self.button_box.accepted.connect(self.saveChanges)
        self.button_box.rejected.connect(self.reject)
        self.setWindowTitle("Waveform Curve Editor")

    def setup_delegate_columns(self, index=2):
        symbol_delegate = SymbolColumnDelegate(self)
        self.table_view.setItemDelegateForColumn(index+3, symbol_delegate)
        line_delegate = LineColumnDelegate(self)
        self.table_view.setItemDelegateForColumn(index+1, line_delegate)
        color_delegate = ColorColumnDelegate(self)
        self.table_view.setItemDelegateForColumn(index, color_delegate)

    @Slot()
    def addCurve(self):
        self.table_model.append()

    @Slot()
    def removeSelectedCurve(self):
        self.table_model.removeAtIndex(self.table_view.currentIndex())

    @Slot(QItemSelection, QItemSelection)
    def handleSelectionChange(self, selected, deselected):
        self.remove_button.setEnabled(
            self.table_view.selectionModel().hasSelection())

    @Slot(QModelIndex)
    def handleDoubleClick(self, index):
        if self.table_model.needsColorDialog(index):
            # The table model returns a QBrush for BackgroundRole, not a QColor
            init_color = self.table_model.data(index,
                                               Qt.BackgroundRole).color()
            color = QColorDialog.getColor(init_color, self)
            if color.isValid():
                self.table_model.setData(index, color, role=Qt.EditRole)

    @Slot()
    def saveChanges(self):
        formWindow = QDesignerFormWindowInterface.findFormWindow(self.plot)
        if formWindow:
            formWindow.cursor().setProperty("curves", self.plot.curves)
        self.accept()