Beispiel #1
0
def drag_with_pixmap(list_widget: QListWidget) -> QDrag:
    """Create a QDrag object with a pixmap of the currently select list item.

    This method is useful when you have a QListWidget that displays custom
    widgets for each QListWidgetItem instance in the list (usually by calling
    ``QListWidget.setItemWidget(item, widget)``).  When used in a
    ``QListWidget.startDrag`` method, this function creates a QDrag object that
    shows an image of the item being dragged (rather than an empty rectangle).

    Parameters
    ----------
    list_widget : QListWidget
        The QListWidget for which to create a QDrag object.

    Returns
    -------
    QDrag
        A QDrag instance with a pixmap of the currently selected item.

    Examples
    --------
    >>> class QListWidget:
    ...     def startDrag(self, supportedActions):
    ...         drag = drag_with_pixmap(self)
    ...         drag.exec_(supportedActions, Qt.MoveAction)

    """
    drag = QDrag(list_widget)
    drag.setMimeData(list_widget.mimeData(list_widget.selectedItems()))
    size = list_widget.viewport().visibleRegion().boundingRect().size()
    pixmap = QPixmap(size)
    pixmap.fill(Qt.transparent)
    painter = QPainter(pixmap)
    for index in list_widget.selectedIndexes():
        rect = list_widget.visualRect(index)
        painter.drawPixmap(rect, list_widget.viewport().grab(rect))
    painter.end()
    drag.setPixmap(pixmap)
    drag.setHotSpot(list_widget.viewport().mapFromGlobal(QCursor.pos()))
    return drag
Beispiel #2
0
class RemoveLasersWindow(QWidget):
    def __init__(self, main_window):
        super().__init__()

        self.main_window = main_window
        lasers = self.main_window.lasers
        self.setWindowTitle("Remove laser")

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.laser_list = QListWidget()
        self.laser_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        layout.addWidget(self.laser_list)

        names = []
        for laser in lasers:
            settings = laser.get_settings()
            names.append(settings['name'])
        print(names)
        self.laser_list.addItems(names)

        self.removeButton = QPushButton("Remove")
        layout.addWidget(self.removeButton)

        self._createActions()
        self._connectActions()

    def _createActions(self):
        self.removeAction = QAction(self)
        self.removeAction.setText("Remove")

    def _connectActions(self):
        self.removeButton.clicked.connect(self.removeAction.trigger)
        self.removeAction.triggered.connect(self.remove_lasers)

    def remove_lasers(self):
        selected_rows = [x.row() for x in self.laser_list.selectedIndexes()]
        print(selected_rows)
        self.main_window.remove_lasers(selected_rows)
Beispiel #3
0
class RemoveRPWindow(QWidget):
    def __init__(self, main_window):
        super().__init__()

        self.main_window = main_window
        rps = self.main_window.rps
        self.setWindowTitle("Remove RedPitaya")

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.laser_list = QListWidget()
        self.laser_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        layout.addWidget(self.laser_list)

        names = []
        self.laser_list.addItems(rps)

        self.removeButton = QPushButton("Remove")
        layout.addWidget(self.removeButton)

        self._createActions()
        self._connectActions()

    def _createActions(self):
        self.removeAction = QAction(self)
        self.removeAction.setText("Remove")

    def _connectActions(self):
        self.removeButton.clicked.connect(self.removeAction.trigger)
        self.removeAction.triggered.connect(self.remove_lasers)

    def remove_lasers(self):
        selected_rows = [x.row() for x in self.laser_list.selectedIndexes()]
        print(selected_rows)
        self.main_window.remove_rps(selected_rows)
Beispiel #4
0
class HeaderEditDialog(QDialog):

    # name of the current preset; whether to set this preset as default; list of Columns
    header_changed = Signal(str, bool, list)

    def __init__(self, parent, table_header):
        super().__init__(parent)

        self.table_header = table_header
        self.default_preset_name = None
        self.preset_name = table_header.preset_name
        self.columns = deepcopy(table_header.columns)
        self.setupUi()
        self.update_output()

    def setupUi(self):
        self.resize(240, 400)
        self.vbox = QVBoxLayout(self)
        self.presetLabel = QLabel(self)
        self.columnList = QListWidget(self)
        self.setAsDefaultCheckbox = QCheckBox("Set as default preset", self)
        self.vbox.addWidget(self.presetLabel)
        self.vbox.addWidget(self.columnList)
        self.vbox.addWidget(self.setAsDefaultCheckbox)

        self.columnList.setDragDropMode(QListWidget.InternalMove)
        self.columnList.setDefaultDropAction(Qt.MoveAction)
        self.columnList.setSelectionMode(QListWidget.ExtendedSelection)
        self.columnList.setAlternatingRowColors(True)
        self.columnList.installEventFilter(self)
        self.columnList.setContextMenuPolicy(Qt.CustomContextMenu)
        self.columnList.customContextMenuRequested.connect(self.open_menu)
        self.columnList.model().rowsMoved.connect(self.read_columns_from_list)

        # for a dumb qss hack to make selected checkboxes not white on a light theme
        self.columnList.setObjectName("ColumnList")

        buttons = QDialogButtonBox.Reset | QDialogButtonBox.Save | QDialogButtonBox.Cancel
        self.buttonBox = QDialogButtonBox(buttons, self)
        self.vbox.addWidget(self.buttonBox)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)
        self.resetButton = self.buttonBox.button(QDialogButtonBox.Reset)
        self.resetButton.clicked.connect(self.reset_to_stock)

    def eventFilter(self, object, event):
        if event.type() == QEvent.KeyPress:
            if event.key() == Qt.Key_Space or event.key() == Qt.Key_Return:
                self.toggle_selected_columns()
                return True
            if event.key() == Qt.Key_Delete:
                self.delete_selected()
                return True
        return False

    def update_output(self):
        self.presetLabel.setText("Preset: {}".format(self.preset_name))
        self.setAsDefaultCheckbox.setChecked(
            CONFIG['default_header_preset'] == self.preset_name)
        self.columnList.clear()
        for column in self.columns:
            ColumnListItem(self.columnList, column)

    def accept(self):
        self.read_columns_from_list()
        self.header_changed.emit(self.preset_name,
                                 self.setAsDefaultCheckbox.isChecked(),
                                 self.columns)
        self.done(0)

    def reject(self):
        self.done(0)

    def reset_to_stock(self):
        self.columns = deepcopy(DEFAULT_COLUMNS)
        self.update_output()

    def read_columns_from_list(self):
        new_columns = []
        for i in range(self.columnList.count()):
            item = self.columnList.item(i)
            new_columns.append(item.column)
        self.columns = new_columns

    def toggle_selected_columns(self):
        selected = self.columnList.selectedItems()
        for item in selected:
            value_now = item.data(Qt.CheckStateRole)
            item.setData(Qt.CheckStateRole, not value_now)
        self.columnList.reset(
        )  # @Improvement: is there a better way to update QListWidget?

    def open_menu(self, position):
        menu = QMenu(self)

        preset_menu = menu.addMenu('Presets')
        preset_menu.addAction('New preset', self.new_preset_dialog)
        preset_menu.addSeparator()

        preset_names = CONFIG.get_header_presets()

        if len(preset_names) == 0:
            action = preset_menu.addAction('No presets')
            action.setEnabled(False)
        else:
            delete_menu = menu.addMenu('Delete preset')
            for name in preset_names:
                preset_menu.addAction(name, partial(self.load_preset, name))
                delete_menu.addAction(name, partial(self.delete_preset, name))

        menu.addSeparator()
        menu.addAction('New column...', self.create_new_column_dialog)

        if len(self.columnList.selectedIndexes()) > 0:
            menu.addAction('Delete selected', self.delete_selected)

        menu.popup(self.columnList.viewport().mapToGlobal(position))

    def load_preset(self, name):
        new_columns = CONFIG.load_header_preset(name)
        if not new_columns:
            return

        self.columns = new_columns
        self.preset_name = name
        self.update_output()

    def new_preset_dialog(self):
        d = QInputDialog(self)
        d.setLabelText('Enter the new name for the new preset:')
        d.setWindowTitle('Create new preset')
        d.textValueSelected.connect(self.create_new_preset)
        d.open()

    def create_new_preset(self, name):
        if name in CONFIG.get_header_presets():
            show_warning_dialog(
                self, "Preset creation error",
                'Preset named "{}" already exists.'.format(name))
            return
        if len(name.strip()) == 0:
            show_warning_dialog(
                self, "Preset creation error",
                'This preset name is not allowed.'.format(name))
            return

        self.preset_name = name
        self.update_output()
        CONFIG.save_header_preset(name, self.columns)

    def delete_preset(self, name):
        CONFIG.delete_header_preset(name)
        if name == self.preset_name:
            self.columns = deepcopy(DEFAULT_COLUMNS)
            self.update_output()

    def create_new_column_dialog(self):
        d = CreateNewColumnDialog(self)
        d.add_new_column.connect(self.add_new_column)
        d.setWindowTitle('Create new column')
        d.open()

    def add_new_column(self, name, title):
        new_column = Column(name, title)
        # if the last column is message, insert this column before it (I think that makes sense?)
        if len(self.columns) == 0:
            self.columns.append(new_column)
        elif self.columns[-1].name in ('message', 'msg'):
            self.columns.insert(-1, new_column)
        else:
            self.columns.append(new_column)
        self.update_output()

    def delete_selected(self):
        selected = self.columnList.selectedItems()
        for item in selected:
            self.columnList.takeItem(self.columnList.row(item))
        self.read_columns_from_list()
        self.update_output()
class RemoteKernelSetupDialog(QDialog):
    """Dialog to connect to existing kernels (either local or remote)."""

    def __init__(self, parent=None):
        super(RemoteKernelSetupDialog, self).__init__(parent)
        self.setWindowTitle(_('Setup remote kernel'))

        self.TEXT_FETCH_REMOTE_CONN_FILES_BTN = 'Fetch remote connection files'
        self.DEFAULT_CMD_FOR_JUPYTER_RUNTIME = 'jupyter --runtime-dir'

        # Name of the connection
        cfg_name_label = QLabel(_('Configuration name:'))
        self.cfg_name_line_edit = QLineEdit()

        # SSH connection
        hostname_label = QLabel(_('Hostname:'))
        self.hostname_lineedit = QLineEdit()
        port_label = QLabel(_('Port:'))
        self.port_lineeidt = QLineEdit()
        self.port_lineeidt.setMaximumWidth(75)

        username_label = QLabel(_('Username:'******'Password:'******'SSH keyfile:'))

        self.pw = QLineEdit()
        self.pw.setEchoMode(QLineEdit.Password)
        self.pw_radio.toggled.connect(self.pw.setEnabled)
        self.keyfile_radio.toggled.connect(self.pw.setDisabled)

        self.keyfile_path_lineedit = QLineEdit()
        keyfile_browse_btn = QPushButton(_('Browse'))
        keyfile_browse_btn.clicked.connect(self.select_ssh_key)
        keyfile_layout = QHBoxLayout()
        keyfile_layout.addWidget(self.keyfile_path_lineedit)
        keyfile_layout.addWidget(keyfile_browse_btn)

        passphrase_label = QLabel(_('Passphrase:'))
        self.passphrase_lineedit = QLineEdit()
        self.passphrase_lineedit.setPlaceholderText(_('Optional'))
        self.passphrase_lineedit.setEchoMode(QLineEdit.Password)

        self.keyfile_radio.toggled.connect(self.keyfile_path_lineedit.setEnabled)
        self.keyfile_radio.toggled.connect(self.passphrase_lineedit.setEnabled)
        self.keyfile_radio.toggled.connect(keyfile_browse_btn.setEnabled)
        self.keyfile_radio.toggled.connect(passphrase_label.setEnabled)
        self.pw_radio.toggled.connect(self.keyfile_path_lineedit.setDisabled)
        self.pw_radio.toggled.connect(self.passphrase_lineedit.setDisabled)
        self.pw_radio.toggled.connect(keyfile_browse_btn.setDisabled)
        self.pw_radio.toggled.connect(passphrase_label.setDisabled)

        # Button to fetch JSON files listing
        # self.kf_fetch_conn_files_btn = QPushButton(_(self.TEXT_FETCH_REMOTE_CONN_FILES_BTN))
        # self.kf_fetch_conn_files_btn.clicked.connect(self.fill_combobox_with_fetched_remote_connection_files)
        # self.cb_remote_conn_files = QComboBox()
        # self.cb_remote_conn_files.currentIndexChanged.connect(self._take_over_selected_remote_configuration_file)

        # Remote kernel groupbox
        self.start_remote_kernel_group = QGroupBox(_("Start remote kernel"))

        # Advanced settings to get remote connection files
        jupyter_runtime_location_cmd_label = QLabel(_('Command to get Jupyter runtime:'))
        self.jupyter_runtime_location_cmd_lineedit = QLineEdit()
        self.jupyter_runtime_location_cmd_lineedit.setPlaceholderText(_(self.DEFAULT_CMD_FOR_JUPYTER_RUNTIME))

        # SSH layout
        ssh_layout = QGridLayout()
        ssh_layout.addWidget(cfg_name_label, 0, 0)
        ssh_layout.addWidget(self.cfg_name_line_edit, 0, 2)

        ssh_layout.addWidget(hostname_label, 1, 0, 1, 2)
        ssh_layout.addWidget(self.hostname_lineedit, 1, 2)
        ssh_layout.addWidget(port_label, 1, 3)
        ssh_layout.addWidget(self.port_lineeidt, 1, 4)
        ssh_layout.addWidget(username_label, 2, 0, 1, 2)
        ssh_layout.addWidget(self.username_lineedit, 2, 2, 1, 3)

        # SSH authentication layout
        auth_layout = QGridLayout()
        auth_layout.addWidget(self.pw_radio, 1, 0)
        auth_layout.addWidget(pw_label, 1, 1)
        auth_layout.addWidget(self.pw, 1, 2)
        auth_layout.addWidget(self.keyfile_radio, 2, 0)
        auth_layout.addWidget(keyfile_label, 2, 1)
        auth_layout.addLayout(keyfile_layout, 2, 2)
        auth_layout.addWidget(passphrase_label, 3, 1)
        auth_layout.addWidget(self.passphrase_lineedit, 3, 2)

        auth_layout.addWidget(jupyter_runtime_location_cmd_label, 4, 1)
        auth_layout.addWidget(self.jupyter_runtime_location_cmd_lineedit, 4, 2)
        # auth_layout.addWidget(self.kf_fetch_conn_files_btn, 5, 1)
        # auth_layout.addWidget(self.cb_remote_conn_files, 5, 2)

        auth_group.setLayout(auth_layout)

        # Remote kernel layout
        self.rm_group = QGroupBox(_("Setup up of a remote connection"))
        self.rm_group.setEnabled(False)
        rm_layout = QVBoxLayout()
        rm_layout.addLayout(ssh_layout)
        rm_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8)))
        rm_layout.addWidget(auth_group)
        self.rm_group.setLayout(rm_layout)
        self.rm_group.setCheckable(False)

        # Ok and Cancel buttons
        self.accept_btns = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel,
            Qt.Horizontal, self)

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

        btns_layout = QHBoxLayout()
        btns_layout.addWidget(self.accept_btns)

        # Dialog layout
        layout = QVBoxLayout()
        layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8)))
        # layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 12)))
        layout.addWidget(self.rm_group)
        layout.addLayout(btns_layout)

        # Main layout
        hbox_layout = QHBoxLayout(self)

        # Left side with the list of all remote connection configurations
        items_label = QLabel(text="Configured remote locations")
        self.items_list = QListWidget()
        self.items_list.clicked.connect(self._on_items_list_click)

        items_layout = QVBoxLayout()
        items_layout.addWidget(items_label)
        items_layout.addWidget(self.items_list)
        edit_delete_new_buttons_layout = QHBoxLayout()
        edit_btn = QPushButton(text="Edit")
        add_btn = QPushButton(text="Add")
        delete_btn = QPushButton(text="Delete")

        add_btn.clicked.connect(self._on_add_btn_click)
        edit_btn.clicked.connect(self._on_edit_btn_click)
        delete_btn.clicked.connect(self._on_delete_btn_click)

        edit_delete_new_buttons_layout.addWidget(add_btn)
        edit_delete_new_buttons_layout.addWidget(edit_btn)
        edit_delete_new_buttons_layout.addWidget(delete_btn)

        items_layout.addLayout(edit_delete_new_buttons_layout)

        hbox_layout.addSpacerItem(QSpacerItem(10, 0))
        hbox_layout.addLayout(items_layout)
        hbox_layout.addLayout(layout)

        self.lst_with_connecion_configs = []

    def _on_items_list_click(self):
        from .kernelconnectmaindialog import LocalConnectionSettings, RemoteConnectionSettings
        idx_of_config = self.items_list.selectedIndexes()[0].row()
        cfg = self.lst_with_connecion_configs[idx_of_config]
        if isinstance(cfg, RemoteConnectionSettings):
            self._update_remote_connection_input_fields(cfg)
        else:
            show_info_dialog("Information", "This functionality is still not available")

    def _clear_remote_connection_input_fields(self):
        self.keyfile_path_lineedit.setText("")
        self.passphrase_lineedit.setText("")
        self.hostname_lineedit.setText("")
        self.username_lineedit.setText("")
        self.port_lineeidt.setText("")
        self.cfg_name_line_edit.setText("")
        self.jupyter_runtime_location_cmd_lineedit.setText("")

        self.keyfile_radio.setChecked(False)
        self.pw_radio.setChecked(False)

    def _update_remote_connection_input_fields(self, remote_conn_settings):
        self.keyfile_path_lineedit.setText(remote_conn_settings.keyfile_path)
        self.passphrase_lineedit.setText(remote_conn_settings.password)
        self.hostname_lineedit.setText(remote_conn_settings.hostname)
        self.username_lineedit.setText(remote_conn_settings.username)
        self.port_lineeidt.setText(str(remote_conn_settings.port))
        self.cfg_name_line_edit.setText(remote_conn_settings.connection_name)
        self.jupyter_runtime_location_cmd_lineedit.setText(remote_conn_settings.cmd_for_jupyter_runtime_location)

        self.keyfile_radio.setChecked(remote_conn_settings.keyfile_path is not None)
        self.pw_radio.setChecked(remote_conn_settings.password is not None)

    def _on_add_btn_click(self):
        from .kernelconnectmaindialog import LocalConnectionSettings, RemoteConnectionSettings

        username = self.username_lineedit.text()
        passphrase = self.passphrase_lineedit.text()
        hostname = self.hostname_lineedit.text()
        keyfile_path = self.keyfile_path_lineedit.text()
        port = int(self.port_lineeidt.text()) if self.port_lineeidt.text() != "" else 22
        jup_runtime_cmd = self.jupyter_runtime_location_cmd_lineedit.text()
        cfg_name = self.cfg_name_line_edit.text()

        cfg = RemoteConnectionSettings(
            username=username,
            hostname=hostname,
            keyfile_path=keyfile_path,
            port=port,
            connection_name=cfg_name,
            cmd_for_jupyter_runtime_location=jup_runtime_cmd,
            password=passphrase
        )

        self.lst_with_connecion_configs.append(cfg)
        self._update_list_with_configs()
        self.rm_group.setEnabled(False)

    def _on_edit_btn_click(self):
        from .kernelconnectmaindialog import LocalConnectionSettings, RemoteConnectionSettings
        self.rm_group.setEnabled(True)
        idx_of_config = self.items_list.selectedIndexes()[0].row()
        cfg = self.lst_with_connecion_configs[idx_of_config]
        if isinstance(cfg, RemoteConnectionSettings):
            self._update_remote_connection_input_fields(cfg)
        else:
            show_info_dialog("Information", "This functionality is still not available")

    def _on_delete_btn_click(self):
        idx_of_config = self.items_list.selectedIndexes()[0].row()
        self.lst_with_connecion_configs.pop(idx_of_config)
        self._update_list_with_configs()

    def select_ssh_key(self):
        kf = getopenfilename(self, _('Select SSH keyfile'),
                             get_home_dir(), '*.pem;;*')[0]
        self.keyfile_path_lineedit.setText(kf)

    def _take_over_selected_remote_configuration_file(self, chosen_idx_of_combobox_with_remote_conn_files):
        remote_path_filename = self.remote_conn_file_paths[chosen_idx_of_combobox_with_remote_conn_files]
        self.cf.setText(remote_path_filename)

    def set_connection_configs(self, lst_with_connecion_configs):
        self.lst_with_connecion_configs = lst_with_connecion_configs
        self._update_list_with_configs()

    def _update_list_with_configs(self):
        from .kernelconnectmaindialog import LocalConnectionSettings, RemoteConnectionSettings
        # now, fill the list
        self.items_list.clear()
        for cfg in self.lst_with_connecion_configs:
            if isinstance(cfg, LocalConnectionSettings):
                self.items_list.addItem(f"Local: {cfg.connection_name}")
            elif isinstance(cfg, RemoteConnectionSettings):
                self.items_list.addItem(f"Remote: {cfg.connection_name}")

    def get_connection_settings(self):
        return self.lst_with_connecion_configs