def create_scedit(self, text, option, default=NoDefault, tip=None, without_layout=False): label = QLabel(text) clayout = ColorLayout(QColor(Qt.black), self) clayout.lineedit.setMaximumWidth(80) if tip is not None: clayout.setToolTip(tip) cb_bold = QCheckBox() cb_bold.setIcon(ima.icon('bold')) cb_bold.setToolTip(_("Bold")) cb_italic = QCheckBox() cb_italic.setIcon(ima.icon('italic')) cb_italic.setToolTip(_("Italic")) self.scedits[(clayout, cb_bold, cb_italic)] = (option, default) if without_layout: return label, clayout, cb_bold, cb_italic layout = QHBoxLayout() layout.addWidget(label) layout.addLayout(clayout) layout.addSpacing(10) layout.addWidget(cb_bold) layout.addWidget(cb_italic) layout.addStretch(1) layout.setContentsMargins(0, 0, 0, 0) widget = QWidget(self) widget.setLayout(layout) return widget
def __init__(self, value, parent=None): QGridLayout.__init__(self) font = tuple_to_qfont(value) assert font is not None # Font family self.family = QFontComboBox(parent) self.family.setCurrentFont(font) self.addWidget(self.family, 0, 0, 1, -1) # Font size self.size = QComboBox(parent) self.size.setEditable(True) sizelist = list(range(6, 12)) + list(range(12, 30, 2)) + [36, 48, 72] size = font.pointSize() if size not in sizelist: sizelist.append(size) sizelist.sort() self.size.addItems([str(s) for s in sizelist]) self.size.setCurrentIndex(sizelist.index(size)) self.addWidget(self.size, 1, 0) # Italic or not self.italic = QCheckBox(_("Italic"), parent) self.italic.setChecked(font.italic()) self.addWidget(self.italic, 1, 1) # Bold or not self.bold = QCheckBox(_("Bold"), parent) self.bold.setChecked(font.bold()) self.addWidget(self.bold, 1, 2)
def dialog(title, text, icon, setting=None, default=None): if not getattr(settings, setting.upper()): return True check = QCheckBox() check.setText('Dont show this message again (can be reset via the preferences)') info = QMessageBox() info.setIcon(icon) info.setText(title) info.setInformativeText(text) info.setCheckBox(check) info.setStandardButtons(info.Cancel | info.Ok) if default == 'Cancel': info.setDefaultButton(info.Cancel) result = info.exec_() if result == info.Cancel: return False if check.isChecked(): setattr(settings, setting.upper(), False) save_settings() return True
def create_controls(self): """ Create UI controls. """ vbox = QVBoxLayout() form = QFormLayout() self.num_angle = QDoubleSpinBox() self.num_angle.setValue(0.0) self.num_angle.setMinimum(-360) self.num_angle.setMaximum(360) form.addRow(tr("Angle:"), self.num_angle) vbox.addLayout(form) self.gbo_preview = QGroupBox(tr("Preview")) self.gbo_preview.setCheckable(True) self.gbo_preview.setChecked(False) gbo_vbox = QVBoxLayout() self.chk_grid = QCheckBox(tr("Grid")) self.chk_grid.setChecked(False) self.num_grid = QSpinBox() self.num_grid.setValue(4) self.num_grid.setMinimum(1) self.num_grid.setEnabled(False) self.chk_grid.toggled[bool].connect(self.num_grid.setEnabled) gbo_vbox.addWidget(self.chk_grid) gbo_vbox.addWidget(self.num_grid) self.gbo_preview.setLayout(gbo_vbox) vbox.addWidget(self.gbo_preview) self.gbo_preview.toggled[bool].connect(self.set_preview) self.gbo_output = QGroupBox(tr("Output")) self.opt_new = QRadioButton(tr("New signal")) self.opt_replace = QRadioButton(tr("In place")) self.opt_new.setChecked(True) gbo_vbox2 = QVBoxLayout() gbo_vbox2.addWidget(self.opt_new) gbo_vbox2.addWidget(self.opt_replace) self.gbo_output.setLayout(gbo_vbox2) vbox.addWidget(self.gbo_output) self.chk_reshape = QCheckBox(tr("Resize to fit")) self.chk_reshape.setChecked(False) vbox.addWidget(self.chk_reshape) self.btn_ok = QPushButton(tr("&OK")) self.btn_ok.setDefault(True) self.btn_ok.clicked.connect(self.accept) self.btn_cancel = QPushButton(tr("&Cancel")) self.btn_cancel.clicked.connect(self.reject) hbox = QHBoxLayout() hbox.addWidget(self.btn_ok) hbox.addWidget(self.btn_cancel) vbox.addLayout(hbox) vbox.addStretch(1) self.setLayout(vbox)
class MovieArgsPrompt(QtWidgets.QWidget): def __init__(self, parent=None): super(MovieArgsPrompt, self).__init__(parent) self.create_controls() def create_controls(self): self.num_fps = QtWidgets.QDoubleSpinBox() self.num_fps.setValue(15.0) self.num_fps.setMinimum(0.001) self.edt_fname = QLineEdit() self.btn_browse = QtWidgets.QPushButton("...") self.num_dpi = QtWidgets.QSpinBox() self.num_dpi.setValue(72) self.num_dpi.setMinimum(1) self.num_dpi.setMaximum(10000) self.chk_axes = QCheckBox("Axes") self.chk_colorbar = QCheckBox("Colorbar") # codec = mpl.rcParams['animation.codec'] codec = 'h264' self.edt_codec = QLineEdit(codec) self.edt_extra = QLineEdit("-preset veryslow -crf 0") # TODO: Use QCompleter or QComboBox for codecs # TODO: Use QCompleter for 'extra' history # TODO: Bitrate and/or quality slider self.chk_verbose = QCheckBox("Verbose") try: sys.stdout.fileno() except: self.chk_verbose.setEnabled(False) self.chk_verbose.setToolTip("Verbose output does not work with " + "internal console.") frm = QtWidgets.QFormLayout() frm.addRow(tr("FPS:"), self.num_fps) frm.addRow(tr("DPI:"), self.num_dpi) frm.addRow(tr("Codec:"), self.edt_codec) frm.addRow(tr("Extra args:"), self.edt_extra) frm.addRow(self.chk_axes, self.chk_colorbar) hbox = QtWidgets.QHBoxLayout() hbox.addWidget(self.edt_fname) hbox.addWidget(self.btn_browse) frm.addRow(tr("File:"), hbox) frm.addRow("", self.chk_verbose) self.setLayout(frm)
def __init__(self, parent): QFileDialog.__init__(self, parent) self.setFileMode(QFileDialog.AnyFile) self.setAcceptMode(QFileDialog.AcceptSave) # Widgets self._chk_tight = QCheckBox('Tight layout') self._txt_dpi = QSpinBox() self._txt_dpi.setRange(1, 10000) self._txt_dpi.setSingleStep(50) self._txt_dpi.setSuffix('dpi') self._txt_dpi.setValue(100) # Layouts layout = self.layout() lyt_extras = QHBoxLayout() lyt_extras.addWidget(QLabel('Extra options')) lyt_extras.addWidget(self._chk_tight) lyt_extras.addWidget(QLabel('Resolution')) lyt_extras.addWidget(self._txt_dpi) layout.addLayout(lyt_extras, layout.rowCount(), 0, 1, layout.columnCount()) self.setLayout(layout)
def create_checkbox(self, text, option, default=NoDefault, tip=None, msg_warning=None, msg_info=None, msg_if_enabled=False): checkbox = QCheckBox(text) if tip is not None: checkbox.setToolTip(tip) self.checkboxes[checkbox] = (option, default) if msg_warning is not None or msg_info is not None: def show_message(is_checked=False): if is_checked or not msg_if_enabled: if msg_warning is not None: QMessageBox.warning(self, self.get_name(), msg_warning, QMessageBox.Ok) if msg_info is not None: QMessageBox.information(self, self.get_name(), msg_info, QMessageBox.Ok) checkbox.clicked.connect(show_message) return checkbox
class MessageCheckBox(QMessageBox): """ A QMessageBox derived widget that includes a QCheckBox aligned to the right under the message and on top of the buttons. """ def __init__(self, *args, **kwargs): super(MessageCheckBox, self).__init__(*args, **kwargs) self._checkbox = QCheckBox() # Set layout to include checkbox size = 9 check_layout = QVBoxLayout() check_layout.addItem(QSpacerItem(size, size)) check_layout.addWidget(self._checkbox, 0, Qt.AlignRight) check_layout.addItem(QSpacerItem(size, size)) # Access the Layout of the MessageBox to add the Checkbox layout = self.layout() if PYQT5: layout.addLayout(check_layout, 1, 2) else: layout.addLayout(check_layout, 1, 1) # --- Public API # Methods to access the checkbox def is_checked(self): return self._checkbox.isChecked() def set_checked(self, value): return self._checkbox.setChecked(value) def set_check_visible(self, value): self._checkbox.setVisible(value) def is_check_visible(self): self._checkbox.isVisible() def checkbox_text(self): self._checkbox.text() def set_checkbox_text(self, text): self._checkbox.setText(text)
def setup_and_check(self, data, title=''): """ Setup DataFrameEditor: return False if data is not supported, True otherwise """ self.layout = QGridLayout() self.setLayout(self.layout) self.setWindowIcon(ima.icon('arredit')) if title: title = to_text_string(title) + " - %s" % data.__class__.__name__ else: title = _("%s editor") % data.__class__.__name__ if isinstance(data, Series): self.is_series = True data = data.to_frame() self.setWindowTitle(title) self.resize(600, 500) self.dataModel = DataFrameModel(data, parent=self) self.dataTable = DataFrameView(self, self.dataModel) self.layout.addWidget(self.dataTable) self.setLayout(self.layout) self.setMinimumSize(400, 300) # Make the dialog act as a window self.setWindowFlags(Qt.Window) btn_layout = QHBoxLayout() btn = QPushButton(_("Format")) # disable format button for int type btn_layout.addWidget(btn) btn.clicked.connect(self.change_format) btn = QPushButton(_('Resize')) btn_layout.addWidget(btn) btn.clicked.connect(self.resize_to_contents) bgcolor = QCheckBox(_('Background color')) bgcolor.setChecked(self.dataModel.bgcolor_enabled) bgcolor.setEnabled(self.dataModel.bgcolor_enabled) bgcolor.stateChanged.connect(self.change_bgcolor_enable) btn_layout.addWidget(bgcolor) self.bgcolor_global = QCheckBox(_('Column min/max')) self.bgcolor_global.setChecked(self.dataModel.colum_avg_enabled) self.bgcolor_global.setEnabled(not self.is_series and self.dataModel.bgcolor_enabled) self.bgcolor_global.stateChanged.connect(self.dataModel.colum_avg) btn_layout.addWidget(self.bgcolor_global) btn_layout.addStretch() bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) btn_layout.addWidget(bbox) self.layout.addLayout(btn_layout, 2, 0) return True
def create_controls(self): self.txt_name = QLineEdit() self.chk_menu = QCheckBox(tr("Menu entry")) self.chk_menu.setChecked(True) self.chk_toolbar = QCheckBox(tr("Toolbar button")) self.chk_toolbar.setChecked(True) self.txt_category = QLineEdit() self.chk_icon = QCheckBox() self.chk_toolbar.setChecked(False) self.txt_iconpath = QLineEdit() self.btn_browse_icon = QPushButton("...") self.txt_iconpath.setEnabled(False) self.btn_browse_icon.setEnabled(False) btns = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, QtCore.Qt.Horizontal) self.chk_menu.toggled.connect(self.checks_changed) self.chk_toolbar.toggled.connect(self.checks_changed) self.chk_icon.toggled.connect(self.checks_changed) self.btn_browse_icon.clicked.connect(self.browse_icon) btns.accepted.connect(self.accept) btns.rejected.connect(self.reject) hbox = QHBoxLayout() for w in [self.chk_icon, self.txt_iconpath, self.btn_browse_icon]: hbox.addWidget(w) form = QFormLayout() form.addRow(tr("Name"), self.txt_name) form.addRow(self.chk_menu, self.chk_toolbar) form.addRow(tr("Category"), self.txt_category) form.addRow(tr("Icon"), hbox) vbox = QVBoxLayout(self) vbox.addLayout(form) vbox.addWidget(btns) self.setLayout(vbox)
def __init__(self, parent, data, readonly=False, xlabels=None, ylabels=None): QWidget.__init__(self, parent) self.data = data self.old_data_shape = None if len(self.data.shape) == 1: self.old_data_shape = self.data.shape self.data.shape = (self.data.shape[0], 1) elif len(self.data.shape) == 0: self.old_data_shape = self.data.shape self.data.shape = (1, 1) format = SUPPORTED_FORMATS.get(data.dtype.name, '%s') self.model = ArrayModel(self.data, format=format, xlabels=xlabels, ylabels=ylabels, readonly=readonly, parent=self) self.view = ArrayView(self, self.model, data.dtype, data.shape) btn_layout = QHBoxLayout() btn_layout.setAlignment(Qt.AlignLeft) btn = QPushButton(_( "Format")) # disable format button for int type btn.setEnabled(is_float(data.dtype)) btn_layout.addWidget(btn) btn.clicked.connect(self.change_format) btn = QPushButton(_( "Resize")) btn_layout.addWidget(btn) btn.clicked.connect(self.view.resize_to_contents) bgcolor = QCheckBox(_( 'Background color')) bgcolor.setChecked(self.model.bgcolor_enabled) bgcolor.setEnabled(self.model.bgcolor_enabled) bgcolor.stateChanged.connect(self.model.bgcolor) btn_layout.addWidget(bgcolor) layout = QVBoxLayout() layout.addWidget(self.view) layout.addLayout(btn_layout) self.setLayout(layout)
def set_check_box(self, row, col, state): """ function to add a new select checkbox to a cell in a table row won't add a new checkbox if one already exists """ # Check input assert isinstance(state, bool) # Check if cellWidget exists if self.cellWidget(row, col): # existing: just set the value self.cellWidget(row, col).setChecked(state) else: # case to add checkbox checkbox = QCheckBox() checkbox.setText('') checkbox.setChecked(state) # Adding a widget which will be inserted into the table cell # then centering the checkbox within this widget which in turn, # centers it within the table column :-) self.setCellWidget(row, col, checkbox) # END-IF-ELSE return
def __init__(self, *args, **kwargs): super(MessageCheckBox, self).__init__(*args, **kwargs) self._checkbox = QCheckBox() # Set layout to include checkbox size = 9 check_layout = QVBoxLayout() check_layout.addItem(QSpacerItem(size, size)) check_layout.addWidget(self._checkbox, 0, Qt.AlignRight) check_layout.addItem(QSpacerItem(size, size)) # Access the Layout of the MessageBox to add the Checkbox layout = self.layout() layout.addLayout(check_layout, 1, 1)
def __init__(self, presenter, parent = None, name = '', isMD=False, noExp = 0): super(SampleLogsView, self).__init__(parent) self.presenter = presenter self.setWindowTitle("{} sample logs".format(name)) self.setWindowFlags(Qt.Window) # Create sample log table self.table = QTableView() self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.clicked.connect(self.presenter.clicked) self.table.doubleClicked.connect(self.presenter.doubleClicked) self.table.contextMenuEvent = self.tableMenu self.addWidget(self.table) frame_right = QFrame() layout_right = QVBoxLayout() #Add full_time and experimentinfo options layout_options = QHBoxLayout() if isMD: layout_options.addWidget(QLabel("Experiment Info #")) self.experimentInfo = QSpinBox() self.experimentInfo.setMaximum(noExp-1) self.experimentInfo.valueChanged.connect(self.presenter.changeExpInfo) layout_options.addWidget(self.experimentInfo) self.full_time = QCheckBox("Relative Time") self.full_time.setChecked(True) self.full_time.stateChanged.connect(self.presenter.plot_logs) layout_options.addWidget(self.full_time) layout_right.addLayout(layout_options) # Sample log plot self.fig = Figure() self.canvas = FigureCanvas(self.fig) self.canvas.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding) self.canvas.mpl_connect('button_press_event', self.presenter.plot_clicked) self.ax = self.fig.add_subplot(111, projection='mantid') layout_right.addWidget(self.canvas) # Sample stats self.create_stats_widgets() layout_stats = QFormLayout() layout_stats.addRow('', QLabel("Log Statistics")) layout_stats.addRow('Min:', self.stats_widgets["minimum"]) layout_stats.addRow('Max:', self.stats_widgets["maximum"]) layout_stats.addRow('Mean:', self.stats_widgets["mean"]) layout_stats.addRow('Median:', self.stats_widgets["median"]) layout_stats.addRow('Std Dev:', self.stats_widgets["standard_deviation"]) layout_stats.addRow('Time Avg:', self.stats_widgets["time_mean"]) layout_stats.addRow('Time Std Dev:', self.stats_widgets["time_standard_deviation"]) layout_stats.addRow('Duration:', self.stats_widgets["duration"]) layout_right.addLayout(layout_stats) frame_right.setLayout(layout_right) self.addWidget(frame_right) self.setStretchFactor(0,1) self.resize(1200,800) self.show()
def __init__(self, parent, env, name, action, version, versions): super(CondaPackageActionDialog, self).__init__(parent) self._parent = parent self._env = env self._version_text = None self._name = name self._dependencies_dic = {} self._conda_process = \ conda_api_q.CondaProcess(self, self._on_process_finished) # widgets self.label = QLabel(self) self.combobox_version = QComboBox() self.label_version = QLabel(self) self.widget_version = None self.table_dependencies = None self.checkbox = QCheckBox(_('Install dependencies (recommended)')) self.bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.button_ok = self.bbox.button(QDialogButtonBox.Ok) self.button_cancel = self.bbox.button(QDialogButtonBox.Cancel) self.button_cancel.setDefault(True) self.button_cancel.setAutoDefault(True) dialog_size = QSize(300, 90) # helper variable values action_title = {const.UPGRADE: _("Upgrade package"), const.DOWNGRADE: _("Downgrade package"), const.REMOVE: _("Remove package"), const.INSTALL: _("Install package")} # Versions might have duplicates from different builds versions = sort_versions(list(set(versions)), reverse=True) # FIXME: There is a bug, a package installed by anaconda has version # astropy 0.4 and the linked list 0.4 but the available versions # in the json file do not include 0.4 but 0.4rc1... so... # temporal fix is to check if inside list otherwise show full list if action == const.UPGRADE: if version in versions: index = versions.index(version) versions = versions[:index] else: versions = versions elif action == const.DOWNGRADE: if version in versions: index = versions.index(version) versions = versions[index+1:] else: versions = versions elif action == const.REMOVE: versions = [version] self.combobox_version.setEnabled(False) if len(versions) == 1: if action == const.REMOVE: labeltext = _('Package version to remove:') else: labeltext = _('Package version available:') self.label_version.setText(versions[0]) self.widget_version = self.label_version else: labeltext = _("Select package version:") self.combobox_version.addItems(versions) self.widget_version = self.combobox_version self.label.setText(labeltext) self.label_version.setAlignment(Qt.AlignLeft) self.table_dependencies = QWidget(self) self._layout = QGridLayout() self._layout.addWidget(self.label, 0, 0, Qt.AlignVCenter | Qt.AlignLeft) self._layout.addWidget(self.widget_version, 0, 1, Qt.AlignVCenter | Qt.AlignRight) self.widgets = [self.checkbox, self.button_ok, self.widget_version, self.table_dependencies] row_index = 1 # Create a Table if action in [const.INSTALL, const.UPGRADE, const.DOWNGRADE]: table = QTableView(self) dialog_size = QSize(dialog_size.width() + 40, 300) self.table_dependencies = table row_index = 1 self._layout.addItem(QSpacerItem(10, 5), row_index, 0) self._layout.addWidget(self.checkbox, row_index + 1, 0, 1, 2) self.checkbox.setChecked(True) self._changed_version(versions[0]) table.setSelectionBehavior(QAbstractItemView.SelectRows) table.verticalHeader().hide() table.horizontalHeader().hide() table.setAlternatingRowColors(True) table.setShowGrid(False) table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) table.horizontalHeader().setStretchLastSection(True) self._layout.addWidget(self.table_dependencies, row_index + 2, 0, 1, 2, Qt.AlignHCenter) self._layout.addItem(QSpacerItem(10, 5), row_index + 3, 0) self._layout.addWidget(self.bbox, row_index + 6, 0, 1, 2, Qt.AlignHCenter) title = "{0}: {1}".format(action_title[action], name) self.setLayout(self._layout) self.setMinimumSize(dialog_size) self.setFixedSize(dialog_size) self.setWindowTitle(title) self.setModal(True) # signals and slots self.bbox.accepted.connect(self.accept) self.bbox.rejected.connect(self.close) self.combobox_version.currentIndexChanged.connect( self._changed_version) self.checkbox.stateChanged.connect(self._changed_checkbox)
class NameCategoryPrompt(ExToolWindow): def __init__(self, main_window, parent=None): super(NameCategoryPrompt, self).__init__(parent) self.setWindowTitle(tr("Plugin properties")) self.ui = main_window self.create_controls() def checks_changed(self): menu = self.chk_menu.isChecked() toolbar = self.chk_toolbar.isChecked() icon = self.chk_icon.isChecked() if menu or toolbar: self.txt_category.setEnabled(True) else: self.txt_category.setEnabled(False) self.txt_iconpath.setEnabled(icon) self.btn_browse_icon.setEnabled(icon) def browse_icon(self): formats = QtGui.QImageReader.supportedImageFormats() formats = [str(f, encoding='ascii') for f in formats] # Add one filter that takes all supported: type_filter = tr("Supported formats") type_filter += ' (*.{0})'.format(' *.'.join(formats)) # Add all as individual options type_filter += ';;' + tr("All files") + \ ' (*.*) ;;*.' + ';;*.'.join(formats) path = QtWidgets.QFileDialog.getOpenFileName(self, tr("Pick icon"), os.path.dirname(self.ui.cur_dir), type_filter) if isinstance(path, tuple): # Pyside returns tuple, PyQt not path = path[0] if path is None: return self.txt_iconpath.setText(path) def create_controls(self): self.txt_name = QLineEdit() self.chk_menu = QCheckBox(tr("Menu entry")) self.chk_menu.setChecked(True) self.chk_toolbar = QCheckBox(tr("Toolbar button")) self.chk_toolbar.setChecked(True) self.txt_category = QLineEdit() self.chk_icon = QCheckBox() self.chk_toolbar.setChecked(False) self.txt_iconpath = QLineEdit() self.btn_browse_icon = QPushButton("...") self.txt_iconpath.setEnabled(False) self.btn_browse_icon.setEnabled(False) btns = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, QtCore.Qt.Horizontal) self.chk_menu.toggled.connect(self.checks_changed) self.chk_toolbar.toggled.connect(self.checks_changed) self.chk_icon.toggled.connect(self.checks_changed) self.btn_browse_icon.clicked.connect(self.browse_icon) btns.accepted.connect(self.accept) btns.rejected.connect(self.reject) hbox = QHBoxLayout() for w in [self.chk_icon, self.txt_iconpath, self.btn_browse_icon]: hbox.addWidget(w) form = QFormLayout() form.addRow(tr("Name"), self.txt_name) form.addRow(self.chk_menu, self.chk_toolbar) form.addRow(tr("Category"), self.txt_category) form.addRow(tr("Icon"), hbox) vbox = QVBoxLayout(self) vbox.addLayout(form) vbox.addWidget(btns) self.setLayout(vbox)
class QtTracksControls(QtLayerControls): """Qt view and controls for the Tracks layer. Parameters ---------- layer : napari.layers.Tracks An instance of a Tracks layer. Attributes ---------- grid_layout : qtpy.QtWidgets.QGridLayout Layout of Qt widget controls for the layer. layer : layers.Tracks An instance of a Tracks layer. """ def __init__(self, layer): super().__init__(layer) # NOTE(arl): there are no events fired for changing checkboxes self.layer.events.tail_width.connect(self._on_tail_width_change) self.layer.events.tail_length.connect(self._on_tail_length_change) self.layer.events.properties.connect(self._on_properties_change) self.layer.events.colormap.connect(self._on_colormap_change) self.layer.events.color_by.connect(self._on_color_by_change) # combo box for track coloring, we can get these from the properties # keys self.color_by_combobox = QComboBox() self.color_by_combobox.addItems(self.layer.properties_to_color_by) self.colormap_combobox = QComboBox() self.colormap_combobox.addItems(list(AVAILABLE_COLORMAPS.keys())) # slider for track tail length self.tail_length_slider = QSlider(Qt.Horizontal) self.tail_length_slider.setFocusPolicy(Qt.NoFocus) self.tail_length_slider.setMinimum(1) self.tail_length_slider.setMaximum(MAX_TAIL_LENGTH) self.tail_length_slider.setSingleStep(1) # slider for track edge width self.tail_width_slider = QSlider(Qt.Horizontal) self.tail_width_slider.setFocusPolicy(Qt.NoFocus) self.tail_width_slider.setMinimum(1) self.tail_width_slider.setMaximum(MAX_TAIL_WIDTH) self.tail_width_slider.setSingleStep(1) # checkboxes for display self.id_checkbox = QCheckBox() self.tail_checkbox = QCheckBox() self.tail_checkbox.setChecked(True) self.graph_checkbox = QCheckBox() self.graph_checkbox.setChecked(True) self.tail_width_slider.valueChanged.connect(self.change_tail_width) self.tail_length_slider.valueChanged.connect(self.change_tail_length) self.tail_checkbox.stateChanged.connect(self.change_display_tail) self.id_checkbox.stateChanged.connect(self.change_display_id) self.graph_checkbox.stateChanged.connect(self.change_display_graph) self.color_by_combobox.currentTextChanged.connect(self.change_color_by) self.colormap_combobox.currentTextChanged.connect(self.change_colormap) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addWidget(QLabel(trans._('color by:')), 0, 0) self.grid_layout.addWidget(self.color_by_combobox, 0, 1) self.grid_layout.addWidget(QLabel(trans._('colormap:')), 1, 0) self.grid_layout.addWidget(self.colormap_combobox, 1, 1) self.grid_layout.addWidget(QLabel(trans._('blending:')), 2, 0) self.grid_layout.addWidget(self.blendComboBox, 2, 1) self.grid_layout.addWidget(QLabel(trans._('opacity:')), 3, 0) self.grid_layout.addWidget(self.opacitySlider, 3, 1) self.grid_layout.addWidget(QLabel(trans._('tail width:')), 4, 0) self.grid_layout.addWidget(self.tail_width_slider, 4, 1) self.grid_layout.addWidget(QLabel(trans._('tail length:')), 5, 0) self.grid_layout.addWidget(self.tail_length_slider, 5, 1) self.grid_layout.addWidget(QLabel(trans._('tail:')), 6, 0) self.grid_layout.addWidget(self.tail_checkbox, 6, 1) self.grid_layout.addWidget(QLabel(trans._('show ID:')), 7, 0) self.grid_layout.addWidget(self.id_checkbox, 7, 1) self.grid_layout.addWidget(QLabel(trans._('graph:')), 8, 0) self.grid_layout.addWidget(self.graph_checkbox, 8, 1) self.grid_layout.setRowStretch(9, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) self._on_tail_length_change() self._on_tail_width_change() self._on_colormap_change() self._on_color_by_change() def _on_tail_width_change(self, event=None): """Receive layer model track line width change event and update slider. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context, by default None. """ with self.layer.events.tail_width.blocker(): value = self.layer.tail_width value = np.clip(int(2 * value), 1, MAX_TAIL_WIDTH) self.tail_width_slider.setValue(value) def _on_tail_length_change(self, event=None): """Receive layer model track line width change event and update slider. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context, by default None. """ with self.layer.events.tail_length.blocker(): value = self.layer.tail_length value = np.clip(value, 1, MAX_TAIL_LENGTH) self.tail_length_slider.setValue(value) def _on_properties_change(self, event=None): """Change the properties that can be used to color the tracks.""" with self.layer.events.properties.blocker(): self.color_by_combobox.clear() self.color_by_combobox.addItems(self.layer.properties_to_color_by) def _on_colormap_change(self, event=None): """Receive layer model colormap change event and update combobox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context, by default None. """ with self.layer.events.colormap.blocker(): colormap = self.layer.colormap idx = self.colormap_combobox.findText( colormap, Qt.MatchFixedString ) self.colormap_combobox.setCurrentIndex(idx) def _on_color_by_change(self, event=None): """Receive layer model color_by change event and update combobox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context, by default None. """ with self.layer.events.color_by.blocker(): color_by = self.layer.color_by idx = self.color_by_combobox.findText( color_by, Qt.MatchFixedString ) self.color_by_combobox.setCurrentIndex(idx) def change_tail_width(self, value): """Change track line width of shapes on the layer model. Parameters ---------- value : float Line width of track tails. """ self.layer.tail_width = float(value) / 2.0 def change_tail_length(self, value): """Change edge line width of shapes on the layer model. Parameters ---------- value : int Line length of track tails. """ self.layer.tail_length = value def change_display_tail(self, state): self.layer.display_tail = self.tail_checkbox.isChecked() def change_display_id(self, state): self.layer.display_id = self.id_checkbox.isChecked() def change_display_graph(self, state): self.layer.display_graph = self.graph_checkbox.isChecked() def change_color_by(self, value: str): self.layer.color_by = value def change_colormap(self, colormap: str): self.layer.colormap = colormap
class ImplementationListItem(QFrame): """A Widget to render each hook implementation item in a ListWidget. Parameters ---------- item : QListWidgetItem An item instance from a QListWidget. This will most likely come from :meth:`QtHookImplementationListWidget.add_hook_implementation_to_list`. parent : QWidget, optional The parent widget, by default None Attributes ---------- plugin_name_label : QLabel The name of the plugin providing the hook implementation. enabled_checkbox : QCheckBox Checkbox to set the ``enabled`` status of the corresponding hook implementation. opacity : QGraphicsOpacityEffect The opacity of the whole widget. When self.enabled_checkbox is unchecked, the opacity of the item is decreased. """ on_changed = Signal() # when user changes whether plugin is enabled. def __init__(self, item: QListWidgetItem, parent: QWidget = None): super().__init__(parent) self.item = item self.opacity = QGraphicsOpacityEffect(self) self.setGraphicsEffect(self.opacity) layout = QHBoxLayout() self.setLayout(layout) self.position_label = QLabel() self.update_position_label() self.setToolTip(trans._("Click and drag to change call order")) self.plugin_name_label = ElidingLabel(parent=self) self.plugin_name_label.setObjectName('small_text') self.plugin_name_label.setText(item.hook_implementation.plugin_name) plugin_name_size_policy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred) plugin_name_size_policy.setHorizontalStretch(2) self.plugin_name_label.setSizePolicy(plugin_name_size_policy) self.function_name_label = QLabel( item.hook_implementation.function.__name__) self.enabled_checkbox = QCheckBox(self) self.enabled_checkbox.setToolTip( trans._("Uncheck to disable this plugin")) self.enabled_checkbox.stateChanged.connect(self._set_enabled) self.enabled_checkbox.setChecked( getattr(item.hook_implementation, 'enabled', True)) layout.addWidget(self.position_label) layout.addWidget(self.enabled_checkbox) layout.addWidget(self.function_name_label) layout.addWidget(self.plugin_name_label) layout.setStretch(2, 1) layout.setContentsMargins(0, 0, 0, 0) def _set_enabled(self, state: Union[bool, int]): """Set the enabled state of this hook implementation to ``state``.""" self.item.hook_implementation.enabled = bool(state) self.opacity.setOpacity(1 if state else 0.5) self.on_changed.emit() def update_position_label(self, order=None): """Update the label showing the position of this item in the list. Parameters ---------- order : list, optional A HookOrderType list ... unused by this function, but here for ease of signal connection, by default None. """ position = self.item.listWidget().indexFromItem(self.item).row() + 1 self.position_label.setText(str(position))
def __init__(self, parent, language=None, cmd='', host='127.0.0.1', port=2084, args='', external=False, stdio=False, configurations={}, **kwargs): super(LSPServerEditor, self).__init__(parent) description = _( "To create a new server configuration, you need to select a " "programming language, set the command to start its associated " "server and enter any arguments that should be passed to it on " "startup. Additionally, you can set the server's hostname and " "port if connecting to an external server, " "or to a local one using TCP instead of stdio pipes." "<br><br>" "<i>Note</i>: You can use the placeholders <tt>{host}</tt> and " "<tt>{port}</tt> in the server arguments field to automatically " "fill in the respective values.<br>") self.parent = parent self.external = external # Widgets self.server_settings_description = QLabel(description) self.lang_cb = QComboBox(self) self.external_cb = QCheckBox(_('External server'), self) self.host_label = QLabel(_('Host:')) self.host_input = QLineEdit(self) self.port_label = QLabel(_('Port:')) self.port_spinner = QSpinBox(self) self.cmd_label = QLabel(_('Command:')) self.cmd_input = QLineEdit(self) self.args_label = QLabel(_('Arguments:')) self.args_input = QLineEdit(self) self.json_label = QLabel(self.JSON_VALID, self) self.conf_label = QLabel(_('<b>Server Configuration:</b>')) self.conf_input = CodeEditor(None) self.bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = self.bbox.button(QDialogButtonBox.Ok) self.button_cancel = self.bbox.button(QDialogButtonBox.Cancel) # Widget setup self.setMinimumSize(self.MIN_SIZE) self.setWindowTitle(_('LSP server editor')) self.server_settings_description.setWordWrap(True) self.lang_cb.setToolTip( _('Programming language provided by the LSP server')) self.lang_cb.addItem(_('Select a language')) self.lang_cb.addItems(LSP_LANGUAGES) self.button_ok.setEnabled(False) if language is not None: idx = LSP_LANGUAGES.index(language) self.lang_cb.setCurrentIndex(idx + 1) self.button_ok.setEnabled(True) self.host_input.setPlaceholderText('127.0.0.1') self.host_input.setText(host) self.host_input.textChanged.connect(lambda x: self.validate()) self.port_spinner.setToolTip(_('TCP port number of the server')) self.port_spinner.setMinimum(1) self.port_spinner.setMaximum(60000) self.port_spinner.setValue(port) self.cmd_input.setText(cmd) self.cmd_input.setPlaceholderText('/absolute/path/to/command') self.args_input.setToolTip( _('Additional arguments required to start the server')) self.args_input.setText(args) self.args_input.setPlaceholderText(r'--host {host} --port {port}') self.conf_input.setup_editor(language='json', color_scheme=CONF.get( 'appearance', 'selected'), wrap=False, edge_line=True, highlight_current_line=True, highlight_current_cell=True, occurrence_highlighting=True, auto_unindent=True, font=get_font(), filename='config.json', folding=False) self.conf_input.set_language('json', 'config.json') self.conf_input.setToolTip( _('Additional LSP server configuration ' 'set at runtime. JSON required')) try: conf_text = json.dumps(configurations, indent=4, sort_keys=True) except Exception: conf_text = '{}' self.conf_input.set_text(conf_text) self.external_cb.setToolTip( _('Check if the server runs on a remote location')) self.external_cb.setChecked(external) self.stdio_cb = QCheckBox(_('Use stdio pipes for communication'), self) self.stdio_cb.setToolTip( _('Check if the server communicates ' 'using stdin/out pipes')) self.stdio_cb.setChecked(stdio) # Layout setup hlayout = QHBoxLayout() general_vlayout = QVBoxLayout() general_vlayout.addWidget(self.server_settings_description) vlayout = QVBoxLayout() lang_group = QGroupBox(_('Language')) lang_layout = QVBoxLayout() lang_layout.addWidget(self.lang_cb) lang_group.setLayout(lang_layout) vlayout.addWidget(lang_group) server_group = QGroupBox(_('Language server')) server_layout = QGridLayout() server_layout.addWidget(self.cmd_label, 0, 0) server_layout.addWidget(self.cmd_input, 0, 1) server_layout.addWidget(self.args_label, 1, 0) server_layout.addWidget(self.args_input, 1, 1) server_group.setLayout(server_layout) vlayout.addWidget(server_group) address_group = QGroupBox(_('Server address')) host_layout = QVBoxLayout() host_layout.addWidget(self.host_label) host_layout.addWidget(self.host_input) port_layout = QVBoxLayout() port_layout.addWidget(self.port_label) port_layout.addWidget(self.port_spinner) conn_info_layout = QHBoxLayout() conn_info_layout.addLayout(host_layout) conn_info_layout.addLayout(port_layout) address_group.setLayout(conn_info_layout) vlayout.addWidget(address_group) advanced_group = QGroupBox(_('Advanced')) advanced_layout = QVBoxLayout() advanced_layout.addWidget(self.external_cb) advanced_layout.addWidget(self.stdio_cb) advanced_group.setLayout(advanced_layout) vlayout.addWidget(advanced_group) conf_layout = QVBoxLayout() conf_layout.addWidget(self.conf_label) conf_layout.addWidget(self.conf_input) conf_layout.addWidget(self.json_label) vlayout.addStretch() hlayout.addLayout(vlayout, 2) hlayout.addLayout(conf_layout, 3) general_vlayout.addLayout(hlayout) general_vlayout.addWidget(self.bbox) self.setLayout(general_vlayout) self.form_status(False) # Signals if not external: self.cmd_input.textChanged.connect(lambda x: self.validate()) self.external_cb.stateChanged.connect(self.set_local_options) self.stdio_cb.stateChanged.connect(self.set_stdio_options) self.lang_cb.currentIndexChanged.connect(self.lang_selection_changed) self.conf_input.textChanged.connect(self.validate) self.bbox.accepted.connect(self.accept) self.bbox.rejected.connect(self.reject) # Final setup if language is not None: self.form_status(True) self.validate() if stdio: self.set_stdio_options(True) if external: self.set_local_options(True)
class ArrayEditor(BaseDialog): """Array Editor Dialog""" def __init__(self, parent=None): super().__init__(parent) # Destroying the C++ object right after closing the dialog box, # otherwise it may be garbage-collected in another QThread # (e.g. the editor's analysis thread in Spyder), thus leading to # a segmentation fault on UNIX or an application crash on Windows self.setAttribute(Qt.WA_DeleteOnClose) self.data = None self.arraywidget = None self.stack = None self.layout = None self.btn_save_and_close = None self.btn_close = None # Values for 3d array editor self.dim_indexes = [{}, {}, {}] self.last_dim = 0 # Adjust this for changing the startup dimension def setup_and_check(self, data, title='', readonly=False, xlabels=None, ylabels=None): """ Setup ArrayEditor: return False if data is not supported, True otherwise """ self.data = data readonly = readonly or not self.data.flags.writeable is_record_array = data.dtype.names is not None is_masked_array = isinstance(data, np.ma.MaskedArray) if data.ndim > 3: self.error( _("Arrays with more than 3 dimensions are not " "supported")) return False if xlabels is not None and len(xlabels) != self.data.shape[1]: self.error( _("The 'xlabels' argument length do no match array " "column number")) return False if ylabels is not None and len(ylabels) != self.data.shape[0]: self.error( _("The 'ylabels' argument length do no match array row " "number")) return False if not is_record_array: dtn = data.dtype.name if dtn == 'object': # If the array doesn't have shape, we can't display it if data.shape == (): self.error( _("Object arrays without shape are not " "supported")) return False # We don't know what's inside these arrays, so we can't handle # edits self.readonly = readonly = True elif (dtn not in SUPPORTED_FORMATS and not dtn.startswith('str') and not dtn.startswith('unicode')): arr = _("%s arrays") % data.dtype.name self.error(_("%s are currently not supported") % arr) return False self.layout = QGridLayout() self.setLayout(self.layout) if title: title = to_text_string(title) + " - " + _("NumPy object array") else: title = _("Array editor") if readonly: title += ' (' + _('read only') + ')' self.setWindowTitle(title) # ---- Stack widget self.stack = QStackedWidget(self) if is_record_array: for name in data.dtype.names: self.stack.addWidget( ArrayEditorWidget(self, data[name], readonly, xlabels, ylabels)) elif is_masked_array: self.stack.addWidget( ArrayEditorWidget(self, data, readonly, xlabels, ylabels)) self.stack.addWidget( ArrayEditorWidget(self, data.data, readonly, xlabels, ylabels)) self.stack.addWidget( ArrayEditorWidget(self, data.mask, readonly, xlabels, ylabels)) elif data.ndim == 3: # We create here the necessary widgets for current_dim_changed to # work. The rest are created below. # QSpinBox self.index_spin = QSpinBox(self, keyboardTracking=False) self.index_spin.valueChanged.connect(self.change_active_widget) # Labels self.shape_label = QLabel() self.slicing_label = QLabel() # Set the widget to display when launched self.current_dim_changed(self.last_dim) else: self.stack.addWidget( ArrayEditorWidget(self, data, readonly, xlabels, ylabels)) self.arraywidget = self.stack.currentWidget() self.arraywidget.model.dataChanged.connect(self.save_and_close_enable) self.stack.currentChanged.connect(self.current_widget_changed) self.layout.addWidget(self.stack, 1, 0) # ---- Top row of buttons btn_layout_top = None if is_record_array or is_masked_array or data.ndim == 3: btn_layout_top = QHBoxLayout() if is_record_array: btn_layout_top.addWidget(QLabel(_("Record array fields:"))) names = [] for name in data.dtype.names: field = data.dtype.fields[name] text = name if len(field) >= 3: title = field[2] if not is_text_string(title): title = repr(title) text += ' - ' + title names.append(text) else: names = [_('Masked data'), _('Data'), _('Mask')] if data.ndim == 3: # QComboBox names = [str(i) for i in range(3)] ra_combo = QComboBox(self) ra_combo.addItems(names) ra_combo.currentIndexChanged.connect(self.current_dim_changed) # Adding the widgets to layout label = QLabel(_("Axis:")) btn_layout_top.addWidget(label) btn_layout_top.addWidget(ra_combo) btn_layout_top.addWidget(self.shape_label) label = QLabel(_("Index:")) btn_layout_top.addWidget(label) btn_layout_top.addWidget(self.index_spin) btn_layout_top.addWidget(self.slicing_label) else: ra_combo = QComboBox(self) ra_combo.currentIndexChanged.connect( self.stack.setCurrentIndex) ra_combo.addItems(names) btn_layout_top.addWidget(ra_combo) if is_masked_array: label = QLabel( _("<u>Warning</u>: Changes are applied separately")) label.setToolTip( _("For performance reasons, changes applied " "to masked arrays won't be reflected in " "array's data (and vice-versa).")) btn_layout_top.addWidget(label) btn_layout_top.addStretch() # ---- Bottom row of buttons btn_layout_bottom = QHBoxLayout() btn_format = QPushButton(_("Format")) # disable format button for int type btn_format.setEnabled(is_float(self.arraywidget.data.dtype)) btn_layout_bottom.addWidget(btn_format) btn_format.clicked.connect(lambda: self.arraywidget.change_format()) btn_resize = QPushButton(_("Resize")) btn_layout_bottom.addWidget(btn_resize) btn_resize.clicked.connect( lambda: self.arraywidget.view.resize_to_contents()) self.bgcolor = QCheckBox(_('Background color')) self.bgcolor.setEnabled(self.arraywidget.model.bgcolor_enabled) self.bgcolor.setChecked(self.arraywidget.model.bgcolor_enabled) self.bgcolor.stateChanged.connect( lambda state: self.arraywidget.model.bgcolor(state)) btn_layout_bottom.addWidget(self.bgcolor) btn_layout_bottom.addStretch() if not readonly: self.btn_save_and_close = QPushButton(_('Save and Close')) self.btn_save_and_close.setDisabled(True) self.btn_save_and_close.clicked.connect(self.accept) btn_layout_bottom.addWidget(self.btn_save_and_close) self.btn_close = QPushButton(_('Close')) self.btn_close.setAutoDefault(True) self.btn_close.setDefault(True) self.btn_close.clicked.connect(self.reject) btn_layout_bottom.addWidget(self.btn_close) # ---- Final layout btn_layout_bottom.setContentsMargins(4, 4, 4, 4) if btn_layout_top is not None: btn_layout_top.setContentsMargins(4, 4, 4, 4) self.layout.addLayout(btn_layout_top, 2, 0) self.layout.addLayout(btn_layout_bottom, 3, 0) else: self.layout.addLayout(btn_layout_bottom, 2, 0) # Set minimum size self.setMinimumSize(500, 300) # Make the dialog act as a window self.setWindowFlags(Qt.Window) return True @Slot(QModelIndex, QModelIndex) def save_and_close_enable(self, left_top, bottom_right): """Handle the data change event to enable the save and close button.""" if self.btn_save_and_close: self.btn_save_and_close.setEnabled(True) self.btn_save_and_close.setAutoDefault(True) self.btn_save_and_close.setDefault(True) def current_widget_changed(self, index): self.arraywidget = self.stack.widget(index) self.arraywidget.model.dataChanged.connect(self.save_and_close_enable) self.bgcolor.setChecked(self.arraywidget.model.bgcolor_enabled) def change_active_widget(self, index): """ This is implemented for handling negative values in index for 3d arrays, to give the same behavior as slicing """ string_index = [':'] * 3 string_index[self.last_dim] = '<font color=red>%i</font>' self.slicing_label.setText( (r"Slicing: [" + ", ".join(string_index) + "]") % index) if index < 0: data_index = self.data.shape[self.last_dim] + index else: data_index = index slice_index = [slice(None)] * 3 slice_index[self.last_dim] = data_index stack_index = self.dim_indexes[self.last_dim].get(data_index) if stack_index is None: stack_index = self.stack.count() try: self.stack.addWidget( ArrayEditorWidget(self, self.data[tuple(slice_index)])) except IndexError: # Handle arrays of size 0 in one axis self.stack.addWidget(ArrayEditorWidget(self, self.data)) self.dim_indexes[self.last_dim][data_index] = stack_index self.stack.update() self.stack.setCurrentIndex(stack_index) def current_dim_changed(self, index): """ This change the active axis the array editor is plotting over in 3D """ self.last_dim = index string_size = ['%i'] * 3 string_size[index] = '<font color=red>%i</font>' self.shape_label.setText( ('Shape: (' + ', '.join(string_size) + ') ') % self.data.shape) if self.index_spin.value() != 0: self.index_spin.setValue(0) else: # this is done since if the value is currently 0 it does not emit # currentIndexChanged(int) self.change_active_widget(0) self.index_spin.setRange(-self.data.shape[index], self.data.shape[index] - 1) @Slot() def accept(self): """Reimplement Qt method.""" try: for index in range(self.stack.count()): self.stack.widget(index).accept_changes() QDialog.accept(self) except RuntimeError: # Sometimes under CI testing the object the following error appears # RuntimeError: wrapped C/C++ object has been deleted pass def get_value(self): """Return modified array -- this is *not* a copy""" # It is important to avoid accessing Qt C++ object as it has probably # already been destroyed, due to the Qt.WA_DeleteOnClose attribute return self.data def error(self, message): """An error occurred, closing the dialog box""" QMessageBox.critical(self, _("Array editor"), message) self.setAttribute(Qt.WA_DeleteOnClose) self.reject() @Slot() def reject(self): """Reimplement Qt method""" if self.arraywidget is not None: for index in range(self.stack.count()): self.stack.widget(index).reject_changes() QDialog.reject(self)
def setup_and_check(self, data, title='', readonly=False, xlabels=None, ylabels=None): """ Setup ArrayEditor: return False if data is not supported, True otherwise """ self.data = data readonly = readonly or not self.data.flags.writeable is_record_array = data.dtype.names is not None is_masked_array = isinstance(data, np.ma.MaskedArray) if data.ndim > 3: self.error( _("Arrays with more than 3 dimensions are not " "supported")) return False if xlabels is not None and len(xlabels) != self.data.shape[1]: self.error( _("The 'xlabels' argument length do no match array " "column number")) return False if ylabels is not None and len(ylabels) != self.data.shape[0]: self.error( _("The 'ylabels' argument length do no match array row " "number")) return False if not is_record_array: dtn = data.dtype.name if dtn == 'object': # If the array doesn't have shape, we can't display it if data.shape == (): self.error( _("Object arrays without shape are not " "supported")) return False # We don't know what's inside these arrays, so we can't handle # edits self.readonly = readonly = True elif (dtn not in SUPPORTED_FORMATS and not dtn.startswith('str') and not dtn.startswith('unicode')): arr = _("%s arrays") % data.dtype.name self.error(_("%s are currently not supported") % arr) return False self.layout = QGridLayout() self.setLayout(self.layout) if title: title = to_text_string(title) + " - " + _("NumPy object array") else: title = _("Array editor") if readonly: title += ' (' + _('read only') + ')' self.setWindowTitle(title) # ---- Stack widget self.stack = QStackedWidget(self) if is_record_array: for name in data.dtype.names: self.stack.addWidget( ArrayEditorWidget(self, data[name], readonly, xlabels, ylabels)) elif is_masked_array: self.stack.addWidget( ArrayEditorWidget(self, data, readonly, xlabels, ylabels)) self.stack.addWidget( ArrayEditorWidget(self, data.data, readonly, xlabels, ylabels)) self.stack.addWidget( ArrayEditorWidget(self, data.mask, readonly, xlabels, ylabels)) elif data.ndim == 3: # We create here the necessary widgets for current_dim_changed to # work. The rest are created below. # QSpinBox self.index_spin = QSpinBox(self, keyboardTracking=False) self.index_spin.valueChanged.connect(self.change_active_widget) # Labels self.shape_label = QLabel() self.slicing_label = QLabel() # Set the widget to display when launched self.current_dim_changed(self.last_dim) else: self.stack.addWidget( ArrayEditorWidget(self, data, readonly, xlabels, ylabels)) self.arraywidget = self.stack.currentWidget() self.arraywidget.model.dataChanged.connect(self.save_and_close_enable) self.stack.currentChanged.connect(self.current_widget_changed) self.layout.addWidget(self.stack, 1, 0) # ---- Top row of buttons btn_layout_top = None if is_record_array or is_masked_array or data.ndim == 3: btn_layout_top = QHBoxLayout() if is_record_array: btn_layout_top.addWidget(QLabel(_("Record array fields:"))) names = [] for name in data.dtype.names: field = data.dtype.fields[name] text = name if len(field) >= 3: title = field[2] if not is_text_string(title): title = repr(title) text += ' - ' + title names.append(text) else: names = [_('Masked data'), _('Data'), _('Mask')] if data.ndim == 3: # QComboBox names = [str(i) for i in range(3)] ra_combo = QComboBox(self) ra_combo.addItems(names) ra_combo.currentIndexChanged.connect(self.current_dim_changed) # Adding the widgets to layout label = QLabel(_("Axis:")) btn_layout_top.addWidget(label) btn_layout_top.addWidget(ra_combo) btn_layout_top.addWidget(self.shape_label) label = QLabel(_("Index:")) btn_layout_top.addWidget(label) btn_layout_top.addWidget(self.index_spin) btn_layout_top.addWidget(self.slicing_label) else: ra_combo = QComboBox(self) ra_combo.currentIndexChanged.connect( self.stack.setCurrentIndex) ra_combo.addItems(names) btn_layout_top.addWidget(ra_combo) if is_masked_array: label = QLabel( _("<u>Warning</u>: Changes are applied separately")) label.setToolTip( _("For performance reasons, changes applied " "to masked arrays won't be reflected in " "array's data (and vice-versa).")) btn_layout_top.addWidget(label) btn_layout_top.addStretch() # ---- Bottom row of buttons btn_layout_bottom = QHBoxLayout() btn_format = QPushButton(_("Format")) # disable format button for int type btn_format.setEnabled(is_float(self.arraywidget.data.dtype)) btn_layout_bottom.addWidget(btn_format) btn_format.clicked.connect(lambda: self.arraywidget.change_format()) btn_resize = QPushButton(_("Resize")) btn_layout_bottom.addWidget(btn_resize) btn_resize.clicked.connect( lambda: self.arraywidget.view.resize_to_contents()) self.bgcolor = QCheckBox(_('Background color')) self.bgcolor.setEnabled(self.arraywidget.model.bgcolor_enabled) self.bgcolor.setChecked(self.arraywidget.model.bgcolor_enabled) self.bgcolor.stateChanged.connect( lambda state: self.arraywidget.model.bgcolor(state)) btn_layout_bottom.addWidget(self.bgcolor) btn_layout_bottom.addStretch() if not readonly: self.btn_save_and_close = QPushButton(_('Save and Close')) self.btn_save_and_close.setDisabled(True) self.btn_save_and_close.clicked.connect(self.accept) btn_layout_bottom.addWidget(self.btn_save_and_close) self.btn_close = QPushButton(_('Close')) self.btn_close.setAutoDefault(True) self.btn_close.setDefault(True) self.btn_close.clicked.connect(self.reject) btn_layout_bottom.addWidget(self.btn_close) # ---- Final layout btn_layout_bottom.setContentsMargins(4, 4, 4, 4) if btn_layout_top is not None: btn_layout_top.setContentsMargins(4, 4, 4, 4) self.layout.addLayout(btn_layout_top, 2, 0) self.layout.addLayout(btn_layout_bottom, 3, 0) else: self.layout.addLayout(btn_layout_bottom, 2, 0) # Set minimum size self.setMinimumSize(500, 300) # Make the dialog act as a window self.setWindowFlags(Qt.Window) return True
def setup(self): for label, value in self.data: if DEBUG_FORMLAYOUT: print("value:", value) if label is None and value is None: # Separator: (None, None) self.formlayout.addRow(QLabel(" "), QLabel(" ")) self.widgets.append(None) continue elif label is None: # Comment self.formlayout.addRow(QLabel(value)) self.widgets.append(None) continue elif tuple_to_qfont(value) is not None: field = FontLayout(value, self) elif text_to_qcolor(value).isValid(): field = ColorLayout(QColor(value), self) elif is_text_string(value): if '\n' in value: for linesep in (os.linesep, '\n'): if linesep in value: value = value.replace(linesep, u"\u2029") field = QTextEdit(value, self) else: field = QLineEdit(value, self) elif isinstance(value, (list, tuple)): value = list(value) # in case this is a tuple selindex = value.pop(0) field = QComboBox(self) if isinstance(value[0], (list, tuple)): keys = [key for key, _val in value] value = [val for _key, val in value] else: keys = value field.addItems(value) if selindex in value: selindex = value.index(selindex) elif selindex in keys: selindex = keys.index(selindex) elif not isinstance(selindex, int): print("Warning: '%s' index is invalid (label: "\ "%s, value: %s)" % (selindex, label, value), file=STDERR) selindex = 0 field.setCurrentIndex(selindex) elif isinstance(value, bool): field = QCheckBox(self) field.setCheckState(Qt.Checked if value else Qt.Unchecked) elif isinstance(value, float): field = QLineEdit(repr(value), self) field.setValidator(QDoubleValidator(field)) dialog = self.get_dialog() dialog.register_float_field(field) field.textChanged.connect(lambda text: dialog.update_buttons()) elif isinstance(value, int): field = QSpinBox(self) field.setRange(-1e9, 1e9) field.setValue(value) elif isinstance(value, datetime.datetime): field = QDateTimeEdit(self) field.setDateTime(value) elif isinstance(value, datetime.date): field = QDateEdit(self) field.setDate(value) else: field = QLineEdit(repr(value), self) self.formlayout.addRow(label, field) self.widgets.append(field)
def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.selected_label.connect( self._on_selected_label_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contiguous_change) self.layer.events.n_edit_dimensions.connect( self._on_n_edit_dimensions_change) self.layer.events.contour.connect(self._on_contour_change) self.layer.events.editable.connect(self._on_editable_change) self.layer.events.preserve_labels.connect( self._on_preserve_labels_change) self.layer.events.color_mode.connect(self._on_color_mode_change) # selection spinbox self.selectionSpinBox = QtLargeIntSpinBox() layer_dtype = get_dtype(layer) self.selectionSpinBox.set_dtype(layer_dtype) self.selectionSpinBox.setKeyboardTracking(False) self.selectionSpinBox.valueChanged.connect(self.changeSelection) self.selectionSpinBox.setAlignment(Qt.AlignCenter) self._on_selected_label_change() sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(1) sld.setMaximum(40) sld.setSingleStep(1) sld.valueChanged.connect(self.changeSize) self.brushSizeSlider = sld self._on_brush_size_change() contig_cb = QCheckBox() contig_cb.setToolTip(trans._('contiguous editing')) contig_cb.stateChanged.connect(self.change_contig) self.contigCheckBox = contig_cb self._on_contiguous_change() ndim_sb = QSpinBox() self.ndimSpinBox = ndim_sb ndim_sb.setToolTip(trans._('number of dimensions for label editing')) ndim_sb.valueChanged.connect(self.change_n_edit_dim) ndim_sb.setMinimum(2) ndim_sb.setMaximum(self.layer.ndim) ndim_sb.setSingleStep(1) ndim_sb.setAlignment(Qt.AlignCenter) self._on_n_edit_dimensions_change() self.contourSpinBox = QtLargeIntSpinBox() self.contourSpinBox.set_dtype(layer_dtype) self.contourSpinBox.setToolTip(trans._('display contours of labels')) self.contourSpinBox.valueChanged.connect(self.change_contour) self.contourSpinBox.setKeyboardTracking(False) self.contourSpinBox.setAlignment(Qt.AlignCenter) self._on_contour_change() preserve_labels_cb = QCheckBox() preserve_labels_cb.setToolTip( trans._('preserve existing labels while painting')) preserve_labels_cb.stateChanged.connect(self.change_preserve_labels) self.preserveLabelsCheckBox = preserve_labels_cb self._on_preserve_labels_change() selectedColorCheckbox = QCheckBox() selectedColorCheckbox.setToolTip( trans._("Display only selected label")) selectedColorCheckbox.stateChanged.connect(self.toggle_selected_mode) self.selectedColorCheckbox = selectedColorCheckbox # shuffle colormap button self.colormapUpdate = QtModePushButton( None, 'shuffle', slot=self.changeColor, tooltip=trans._('shuffle colors'), ) self.panzoom_button = QtModeRadioButton( layer, 'zoom', Mode.PAN_ZOOM, tooltip=trans._('Pan/zoom mode (Space)'), checked=True, ) self.pick_button = QtModeRadioButton(layer, 'picker', Mode.PICK, tooltip=trans._('Pick mode (L)')) self.paint_button = QtModeRadioButton( layer, 'paint', Mode.PAINT, tooltip=trans._('Paint mode (P)')) self.fill_button = QtModeRadioButton( layer, 'fill', Mode.FILL, tooltip=trans._( "Fill mode (F) \nToggle with {shortcut}", shortcut=Shortcut("Control"), ), ) self.erase_button = QtModeRadioButton( layer, 'erase', Mode.ERASE, tooltip=trans._( "Erase mode (E) \nToggle with {shortcut}", shortcut=Shortcut("Alt"), ), ) self.button_group = QButtonGroup(self) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.paint_button) self.button_group.addButton(self.pick_button) self.button_group.addButton(self.fill_button) self.button_group.addButton(self.erase_button) self._on_editable_change() button_row = QHBoxLayout() button_row.addStretch(1) button_row.addWidget(self.colormapUpdate) button_row.addWidget(self.erase_button) button_row.addWidget(self.fill_button) button_row.addWidget(self.paint_button) button_row.addWidget(self.pick_button) button_row.addWidget(self.panzoom_button) button_row.setSpacing(4) button_row.setContentsMargins(0, 0, 0, 5) color_mode_comboBox = QComboBox(self) for index, (data, text) in enumerate(LABEL_COLOR_MODE_TRANSLATIONS.items()): data = data.value color_mode_comboBox.addItem(text, data) if self.layer.color_mode == data: color_mode_comboBox.setCurrentIndex(index) color_mode_comboBox.activated[str].connect(self.change_color_mode) self.colorModeComboBox = color_mode_comboBox self._on_color_mode_change() color_layout = QHBoxLayout() self.colorBox = QtColorBox(layer) color_layout.addWidget(self.colorBox) color_layout.addWidget(self.selectionSpinBox) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_row, 0, 0, 1, 4) self.grid_layout.addWidget(QLabel(trans._('label:')), 1, 0, 1, 1) self.grid_layout.addLayout(color_layout, 1, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('opacity:')), 2, 0, 1, 1) self.grid_layout.addWidget(self.opacitySlider, 2, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('brush size:')), 3, 0, 1, 1) self.grid_layout.addWidget(self.brushSizeSlider, 3, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('blending:')), 5, 0, 1, 1) self.grid_layout.addWidget(self.blendComboBox, 5, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('color mode:')), 6, 0, 1, 1) self.grid_layout.addWidget(self.colorModeComboBox, 6, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('contour:')), 7, 0, 1, 1) self.grid_layout.addWidget(self.contourSpinBox, 7, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('n edit dim:')), 8, 0, 1, 1) self.grid_layout.addWidget(self.ndimSpinBox, 8, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('contiguous:')), 9, 0, 1, 1) self.grid_layout.addWidget(self.contigCheckBox, 9, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('preserve labels:')), 10, 0, 1, 2) self.grid_layout.addWidget(self.preserveLabelsCheckBox, 10, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('show selected:')), 10, 2, 1, 1) self.grid_layout.addWidget(self.selectedColorCheckbox, 10, 3, 1, 1) self.grid_layout.setRowStretch(10, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4)
class AutosaveErrorDialog(QDialog): """ Dialog window notifying user of autosave-related errors. The window also includes a check box which allows the user to hide any future autosave-related errors. Class attribute: show_errors (bool): whether to show errors or not """ show_errors = True def __init__(self, action, error): """ Constructor. Args: action (str): what Spyder was trying to do when error occured error (Exception): the error that occured """ logger.error(action, exc_info=error) QDialog.__init__(self) self.setWindowTitle(_('Autosave error')) self.setModal(True) layout = QVBoxLayout() header = _('Error message:') txt = '<br>{}<br><br>{}<br>{!s}'.format(action, header, error) layout.addWidget(QLabel(txt)) layout.addSpacing(15) txt = _("Hide all future autosave-related errors during this session") self.dismiss_box = QCheckBox(txt) layout.addWidget(self.dismiss_box) layout.addSpacing(15) button_box = QDialogButtonBox(QDialogButtonBox.Ok) button_box.accepted.connect(self.accept) layout.addWidget(button_box) self.setLayout(layout) def exec_if_enabled(self): """ Execute dialog box unless disabled by the user. The dialog box is disabled once the user clicks the 'Hide all future errors' check box on one dialog box. """ if AutosaveErrorDialog.show_errors: return self.exec_() def accept(self): """ Update `show_errors` and hide dialog box. Overrides method of `QDialogBox`. """ AutosaveErrorDialog.show_errors = not self.dismiss_box.isChecked() return QDialog.accept(self)
def _setupUi(self): self._text = 'It is all ok!' self._plot = None if isinstance(self._desired, type(self._current)): if isinstance(self._desired, (_np.ndarray, tuple, list)): if len(self._desired) != len(self._current): self._text = \ 'Implemented and desired values have different\n'\ 'lenghts: {} and {}, respectively!'.format( len(self._current), len(self._desired)) else: self._text = 'Difference: ' self._plot = PyDMWaveformPlot() self._plot.autoRangeX = True self._plot.autoRangeY = True self._plot.plotItem.showButtons() self._plot.setBackgroundColor(QColor(255, 255, 255)) self._plot.addChannel(y_channel='DES', color='blue') self._plot.addChannel(y_channel='CURR', color='black') self._plot.addChannel(y_channel='DIFF', color='magenta') self._desired_curve = self._plot.curveAtIndex(0) self._desired_curve.receiveYWaveform(self._desired) self._desired_curve.redrawCurve() self._current_curve = self._plot.curveAtIndex(1) self._current_curve.receiveYWaveform(self._current) self._current_curve.redrawCurve() self._diff_curve = self._plot.curveAtIndex(2) diff = self._current - self._desired self._diff_curve.receiveYWaveform(diff) self._diff_curve.redrawCurve() elif isinstance(self._desired, (int, float, str)): self._text = 'Implemented: {}\nDesired: {}'.format( self._current, self._desired) elif self._current == 'UNDEF': self._text = 'PV is disconnected!' elif isinstance(self._desired, (tuple, list)): self._text = 'Implemented value ({}) is not within\n' \ 'desired interval ({})!'.format( self._current, self._desired) else: self._text = 'Implemented value (of type {}) has type\n' \ 'different from desired ({})!'.format( type(self._current), type(self._desired)) lay = QGridLayout(self) self._label = QLabel(self._text, self, alignment=Qt.AlignCenter) self._label.setStyleSheet("min-width: 20em;") lay.addWidget(self._label, 0, 0, 1, 3) if self._plot: lay.addWidget(self._plot, 1, 0, 1, 3) self.show_des = QCheckBox('Desired') self.show_des.setChecked(True) self.show_des.setStyleSheet('color: blue;') self.show_des.stateChanged.connect(self._desired_curve.setVisible) lay.addWidget(self.show_des, 2, 0) self.show_cur = QCheckBox('Implemented') self.show_cur.setChecked(True) self.show_cur.setStyleSheet('color: black;') self.show_cur.stateChanged.connect(self._current_curve.setVisible) lay.addWidget(self.show_cur, 2, 1) self.show_dif = QCheckBox('Diff') self.show_dif.setChecked(True) self.show_dif.setStyleSheet('color: magenta;') self.show_dif.stateChanged.connect(self._diff_curve.setVisible) lay.addWidget(self.show_dif, 2, 2) self._ok_bt = QPushButton('Ok', self) self._ok_bt.clicked.connect(self.close) lay.addWidget(self._ok_bt, 3, 1)
def __init__(self, presenter, parent=None, window_flags=Qt.Window, name='', isMD=False, noExp=0): super(SampleLogsView, self).__init__(parent) self.presenter = presenter self.setWindowTitle("{} sample logs".format(name)) self.setWindowFlags(window_flags) self.setAttribute(Qt.WA_DeleteOnClose, True) # left hand side self.frame_left = QFrame() layout_left = QVBoxLayout() # add a spin box for MD workspaces if isMD: layout_mult_expt_info = QHBoxLayout() layout_mult_expt_info.addWidget(QLabel("Experiment Info #")) self.experimentInfo = QSpinBox() self.experimentInfo.setMaximum(noExp - 1) self.experimentInfo.valueChanged.connect( self.presenter.changeExpInfo) layout_mult_expt_info.addWidget(self.experimentInfo) layout_mult_expt_info.addSpacerItem( QSpacerItem(10, 10, QSizePolicy.Expanding)) layout_left.addLayout(layout_mult_expt_info) # create a line edit to allow for filtering keys self.line_edit = QLineEdit() self.line_edit.setClearButtonEnabled(True) self.line_edit.setToolTip("Type here to filter the logs") self.line_edit.setPlaceholderText("Search the logs") self.line_edit.textEdited.connect(self.presenter.search_key_changed) layout_left.addWidget(self.line_edit) # Create sample log table self.table = QTableView() self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.doubleClicked.connect(self.presenter.doubleClicked) self.table.contextMenuEvent = self.tableMenu layout_left.addWidget(self.table) self.frame_left.setLayout(layout_left) self.addWidget(self.frame_left) #right hand side self.frame_right = QFrame() layout_right = QVBoxLayout() #Add full_time and experimentinfo options layout_options = QHBoxLayout() if isMD: layout_options.addWidget(QLabel("Experiment Info #")) self.experimentInfo = QSpinBox() self.experimentInfo.setMaximum(noExp - 1) self.experimentInfo.valueChanged.connect( self.presenter.changeExpInfo) layout_options.addWidget(self.experimentInfo) #check boxes self.full_time = QCheckBox("Relative Time") self.full_time.setToolTip( "Shows relative time in seconds from the start of the run.") self.full_time.setChecked(True) self.full_time.stateChanged.connect(self.presenter.plot_logs) layout_options.addWidget(self.full_time) self.show_filtered = QCheckBox("Filtered Data") self.show_filtered.setToolTip( "Filtered data only shows data while running and in this period.\nInvalid values are also filtered." ) self.show_filtered.setChecked(True) self.show_filtered.stateChanged.connect( self.presenter.filtered_changed) layout_options.addWidget(self.show_filtered) self.spaceItem = QSpacerItem(10, 10, QSizePolicy.Expanding) layout_options.addSpacerItem(self.spaceItem) layout_right.addLayout(layout_options) # Sample log plot self.fig = Figure() self.canvas = FigureCanvas(self.fig) self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.canvas.mpl_connect('button_press_event', self.presenter.plot_clicked) self.ax = self.fig.add_subplot(111, projection='mantid') layout_right.addWidget(self.canvas) # Sample stats self.create_stats_widgets() layout_stats = QFormLayout() layout_stats.addRow('', QLabel("Log Statistics")) layout_stats.addRow('Min:', self.stats_widgets["minimum"]) layout_stats.addRow('Max:', self.stats_widgets["maximum"]) layout_stats.addRow('Time Avg:', self.stats_widgets["time_mean"]) layout_stats.addRow('Time Std Dev:', self.stats_widgets["time_standard_deviation"]) layout_stats.addRow('Mean (unweighted):', self.stats_widgets["mean"]) layout_stats.addRow('Median (unweighted):', self.stats_widgets["median"]) layout_stats.addRow('Std Dev:', self.stats_widgets["standard_deviation"]) layout_stats.addRow('Duration:', self.stats_widgets["duration"]) layout_right.addLayout(layout_stats) self.frame_right.setLayout(layout_right) self.addWidget(self.frame_right) self.setStretchFactor(0, 1) self.resize(1200, 800) self.show()
class LSPServerEditor(QDialog): DEFAULT_HOST = '127.0.0.1' DEFAULT_PORT = 2084 DEFAULT_CMD = '' DEFAULT_ARGS = '' DEFAULT_CONFIGURATION = '{}' DEFAULT_EXTERNAL = False HOST_REGEX = re.compile(r'^\w+([.]\w+)*$') NON_EMPTY_REGEX = re.compile(r'^\S+$') JSON_VALID = _('JSON valid') JSON_INVALID = _('JSON invalid') def __init__(self, parent, language=None, cmd='', host='127.0.0.1', port=2084, args='', external=False, configurations={}, **kwargs): super(LSPServerEditor, self).__init__(parent) self.parent = parent self.external = external bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = bbox.button(QDialogButtonBox.Ok) self.button_cancel = bbox.button(QDialogButtonBox.Cancel) self.button_ok.setEnabled(False) description = _('To create a new configuration, ' 'you need to select a programming ' 'language, along with a executable ' 'name for the server to execute ' '(If the instance is local), ' 'and the host and port. Finally, ' 'you need to provide the ' 'arguments that the server accepts. ' 'The placeholders <tt>%(host)s</tt> and ' '<tt>%(port)s</tt> refer to the host ' 'and the port, respectively.') server_settings_description = QLabel(description) server_settings_description.setWordWrap(True) lang_label = QLabel(_('Language:')) self.lang_cb = QComboBox(self) self.lang_cb.setToolTip(_('Programming language provided ' 'by the LSP server')) self.lang_cb.addItem(_('Select a language')) self.lang_cb.addItems(LSP_LANGUAGES) if language is not None: idx = LSP_LANGUAGES.index(language) self.lang_cb.setCurrentIndex(idx + 1) self.button_ok.setEnabled(True) host_label = QLabel(_('Host:')) self.host_input = QLineEdit(self) self.host_input.setToolTip(_('Name of the host that will provide ' 'access to the server')) self.host_input.setText(host) self.host_input.textChanged.connect(lambda x: self.validate()) port_label = QLabel(_('Port:')) self.port_spinner = QSpinBox(self) self.port_spinner.setToolTip(_('TCP port number of the server')) self.port_spinner.setMinimum(1) self.port_spinner.setMaximum(60000) self.port_spinner.setValue(port) cmd_label = QLabel(_('Command to execute:')) self.cmd_input = QLineEdit(self) self.cmd_input.setToolTip(_('Command used to start the ' 'LSP server locally')) self.cmd_input.setText(cmd) if not external: self.cmd_input.textChanged.connect(lambda x: self.validate()) args_label = QLabel(_('Server arguments:')) self.args_input = QLineEdit(self) self.args_input.setToolTip(_('Additional arguments required to ' 'start the server')) self.args_input.setText(args) conf_label = QLabel(_('LSP Server Configurations:')) self.conf_input = CodeEditor(None) self.conf_input.textChanged.connect(self.validate) color_scheme = CONF.get('appearance', 'selected') self.conf_input.setup_editor( language='JSON', color_scheme=color_scheme, wrap=False, edge_line=True, highlight_current_line=True, highlight_current_cell=True, occurrence_highlighting=True, auto_unindent=True, font=get_font(), filename='config.json') self.conf_input.setToolTip(_('Additional LSP server configurations ' 'set at runtime. JSON required')) conf_text = '{}' try: conf_text = json.dumps(configurations, indent=4, sort_keys=True) except Exception: pass self.conf_input.set_text(conf_text) self.json_label = QLabel(self.JSON_VALID, self) self.external_cb = QCheckBox(_('External server'), self) self.external_cb.setToolTip(_('Check if the server runs ' 'on a remote location')) self.external_cb.setChecked(external) self.external_cb.stateChanged.connect(self.set_local_options) hlayout = QHBoxLayout() general_vlayout = QVBoxLayout() general_vlayout.addWidget(server_settings_description) vlayout = QVBoxLayout() lang_layout = QVBoxLayout() lang_layout.addWidget(lang_label) lang_layout.addWidget(self.lang_cb) # layout2 = QHBoxLayout() # layout2.addLayout(lang_layout) lang_layout.addWidget(self.external_cb) vlayout.addLayout(lang_layout) host_layout = QVBoxLayout() host_layout.addWidget(host_label) host_layout.addWidget(self.host_input) port_layout = QVBoxLayout() port_layout.addWidget(port_label) port_layout.addWidget(self.port_spinner) conn_info_layout = QHBoxLayout() conn_info_layout.addLayout(host_layout) conn_info_layout.addLayout(port_layout) vlayout.addLayout(conn_info_layout) cmd_layout = QVBoxLayout() cmd_layout.addWidget(cmd_label) cmd_layout.addWidget(self.cmd_input) vlayout.addLayout(cmd_layout) args_layout = QVBoxLayout() args_layout.addWidget(args_label) args_layout.addWidget(self.args_input) vlayout.addLayout(args_layout) conf_layout = QVBoxLayout() conf_layout.addWidget(conf_label) conf_layout.addWidget(self.conf_input) conf_layout.addWidget(self.json_label) hlayout.addLayout(vlayout) hlayout.addLayout(conf_layout) general_vlayout.addLayout(hlayout) general_vlayout.addWidget(bbox) self.setLayout(general_vlayout) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) self.lang_cb.currentIndexChanged.connect( self.lang_selection_changed) self.form_status(False) if language is not None: self.form_status(True) self.validate() @Slot() def validate(self): host_text = self.host_input.text() cmd_text = self.cmd_input.text() if not self.HOST_REGEX.match(host_text): self.button_ok.setEnabled(False) self.host_input.setStyleSheet("QLineEdit{border: 1px solid red;}") self.host_input.setToolTip('Hostname must be valid') return else: self.host_input.setStyleSheet( "QLineEdit{border: 1px solid green;}") self.host_input.setToolTip('Hostname is valid') self.button_ok.setEnabled(True) if not self.external: if not self.NON_EMPTY_REGEX.match(cmd_text): self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid red;}") self.cmd_input.setToolTip('Command must be non empty') return if find_program(cmd_text) is None: self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid red;}") self.cmd_input.setToolTip('Program was not found ' 'on your system') return else: self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid green;}") self.cmd_input.setToolTip('Program was found on your system') self.button_ok.setEnabled(True) try: json.loads(self.conf_input.toPlainText()) try: self.json_label.setText(self.JSON_VALID) except: pass except (ValueError, json.decoder.JSONDecodeError): try: self.json_label.setText(self.JSON_INVALID) self.button_ok.setEnabled(False) except: pass def form_status(self, status): self.host_input.setEnabled(status) self.port_spinner.setEnabled(status) self.external_cb.setEnabled(status) self.cmd_input.setEnabled(status) self.args_input.setEnabled(status) self.conf_input.setEnabled(status) self.json_label.setVisible(status) @Slot() def lang_selection_changed(self): idx = self.lang_cb.currentIndex() if idx == 0: self.set_defaults() self.form_status(False) self.button_ok.setEnabled(False) else: server = self.parent.get_server_by_lang(LSP_LANGUAGES[idx - 1]) self.form_status(True) if server is not None: self.host_input.setText(server.host) self.port_spinner.setValue(server.port) self.external_cb.setChecked(server.external) self.cmd_input.setText(server.cmd) self.args_input.setText(server.args) self.conf_input.set_text(json.dumps(server.configurations)) self.json_label.setText(self.JSON_VALID) self.button_ok.setEnabled(True) else: self.set_defaults() def set_defaults(self): self.cmd_input.setStyleSheet('') self.host_input.setStyleSheet('') self.host_input.setText(self.DEFAULT_HOST) self.port_spinner.setValue(self.DEFAULT_PORT) self.external_cb.setChecked(self.DEFAULT_EXTERNAL) self.cmd_input.setText(self.DEFAULT_CMD) self.args_input.setText(self.DEFAULT_ARGS) self.conf_input.set_text(self.DEFAULT_CONFIGURATION) self.json_label.setText(self.JSON_VALID) @Slot(bool) @Slot(int) def set_local_options(self, enabled): self.external = enabled self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) if enabled: self.cmd_input.setEnabled(False) self.cmd_input.setStyleSheet('') self.args_input.setEnabled(False) try: self.validate() except: pass def get_options(self): language_idx = self.lang_cb.currentIndex() language = LSP_LANGUAGES[language_idx - 1] host = self.host_input.text() port = int(self.port_spinner.value()) external = self.external_cb.isChecked() args = self.args_input.text() cmd = self.cmd_input.text() configurations = json.loads(self.conf_input.toPlainText()) server = LSPServer(language=language.lower(), cmd=cmd, args=args, host=host, port=port, external=external, configurations=configurations) return server
class RunConfigOptions(QWidget): """Run configuration options""" def __init__(self, parent=None): QWidget.__init__(self, parent) self.dir = None self.runconf = RunConfiguration() firstrun_o = CONF.get('run', ALWAYS_OPEN_FIRST_RUN_OPTION, False) # --- Interpreter --- interpreter_group = QGroupBox(_("Console")) interpreter_layout = QVBoxLayout() interpreter_group.setLayout(interpreter_layout) self.current_radio = QRadioButton(CURRENT_INTERPRETER) interpreter_layout.addWidget(self.current_radio) self.dedicated_radio = QRadioButton(DEDICATED_INTERPRETER) interpreter_layout.addWidget(self.dedicated_radio) self.systerm_radio = QRadioButton(SYSTERM_INTERPRETER) interpreter_layout.addWidget(self.systerm_radio) # --- General settings ---- common_group = QGroupBox(_("General settings")) common_layout = QGridLayout() common_group.setLayout(common_layout) self.clear_var_cb = QCheckBox(CLEAR_ALL_VARIABLES) common_layout.addWidget(self.clear_var_cb, 0, 0) self.post_mortem_cb = QCheckBox(POST_MORTEM) common_layout.addWidget(self.post_mortem_cb, 1, 0) self.clo_cb = QCheckBox(_("Command line options:")) common_layout.addWidget(self.clo_cb, 2, 0) self.clo_edit = QLineEdit() self.clo_cb.toggled.connect(self.clo_edit.setEnabled) self.clo_edit.setEnabled(False) common_layout.addWidget(self.clo_edit, 2, 1) # --- Working directory --- wdir_group = QGroupBox(_("Working Directory settings")) wdir_layout = QVBoxLayout() wdir_group.setLayout(wdir_layout) self.file_dir_radio = QRadioButton(FILE_DIR) wdir_layout.addWidget(self.file_dir_radio) self.cwd_radio = QRadioButton(CW_DIR) wdir_layout.addWidget(self.cwd_radio) fixed_dir_layout = QHBoxLayout() self.fixed_dir_radio = QRadioButton(FIXED_DIR) fixed_dir_layout.addWidget(self.fixed_dir_radio) self.wd_edit = QLineEdit() self.fixed_dir_radio.toggled.connect(self.wd_edit.setEnabled) self.wd_edit.setEnabled(False) fixed_dir_layout.addWidget(self.wd_edit) browse_btn = QPushButton(ima.icon('DirOpenIcon'), '', self) browse_btn.setToolTip(_("Select directory")) browse_btn.clicked.connect(self.select_directory) fixed_dir_layout.addWidget(browse_btn) wdir_layout.addLayout(fixed_dir_layout) # --- System terminal --- external_group = QGroupBox(_("External system terminal")) external_group.setDisabled(True) self.systerm_radio.toggled.connect(external_group.setEnabled) external_layout = QGridLayout() external_group.setLayout(external_layout) self.interact_cb = QCheckBox(INTERACT) external_layout.addWidget(self.interact_cb, 1, 0, 1, -1) self.pclo_cb = QCheckBox(_("Command line options:")) external_layout.addWidget(self.pclo_cb, 3, 0) self.pclo_edit = QLineEdit() self.pclo_cb.toggled.connect(self.pclo_edit.setEnabled) self.pclo_edit.setEnabled(False) self.pclo_edit.setToolTip( _("<b>-u</b> is added to the " "other options you set here")) external_layout.addWidget(self.pclo_edit, 3, 1) # Checkbox to preserve the old behavior, i.e. always open the dialog # on first run hline = QFrame() hline.setFrameShape(QFrame.HLine) hline.setFrameShadow(QFrame.Sunken) self.firstrun_cb = QCheckBox(ALWAYS_OPEN_FIRST_RUN % _("this dialog")) self.firstrun_cb.clicked.connect(self.set_firstrun_o) self.firstrun_cb.setChecked(firstrun_o) layout = QVBoxLayout() layout.addWidget(interpreter_group) layout.addWidget(common_group) layout.addWidget(wdir_group) layout.addWidget(external_group) layout.addWidget(hline) layout.addWidget(self.firstrun_cb) self.setLayout(layout) def select_directory(self): """Select directory""" basedir = to_text_string(self.wd_edit.text()) if not osp.isdir(basedir): basedir = getcwd_or_home() directory = getexistingdirectory(self, _("Select directory"), basedir) if directory: self.wd_edit.setText(directory) self.dir = directory def set(self, options): self.runconf.set(options) self.clo_cb.setChecked(self.runconf.args_enabled) self.clo_edit.setText(self.runconf.args) if self.runconf.current: self.current_radio.setChecked(True) elif self.runconf.systerm: self.systerm_radio.setChecked(True) else: self.dedicated_radio.setChecked(True) self.interact_cb.setChecked(self.runconf.interact) self.post_mortem_cb.setChecked(self.runconf.post_mortem) self.pclo_cb.setChecked(self.runconf.python_args_enabled) self.pclo_edit.setText(self.runconf.python_args) self.clear_var_cb.setChecked(self.runconf.clear_namespace) self.file_dir_radio.setChecked(self.runconf.file_dir) self.cwd_radio.setChecked(self.runconf.cw_dir) self.fixed_dir_radio.setChecked(self.runconf.fixed_dir) self.dir = self.runconf.dir self.wd_edit.setText(self.dir) def get(self): self.runconf.args_enabled = self.clo_cb.isChecked() self.runconf.args = to_text_string(self.clo_edit.text()) self.runconf.current = self.current_radio.isChecked() self.runconf.systerm = self.systerm_radio.isChecked() self.runconf.interact = self.interact_cb.isChecked() self.runconf.post_mortem = self.post_mortem_cb.isChecked() self.runconf.python_args_enabled = self.pclo_cb.isChecked() self.runconf.python_args = to_text_string(self.pclo_edit.text()) self.runconf.clear_namespace = self.clear_var_cb.isChecked() self.runconf.file_dir = self.file_dir_radio.isChecked() self.runconf.cw_dir = self.cwd_radio.isChecked() self.runconf.fixed_dir = self.fixed_dir_radio.isChecked() self.runconf.dir = self.wd_edit.text() return self.runconf.get() def is_valid(self): wdir = to_text_string(self.wd_edit.text()) if not self.fixed_dir_radio.isChecked() or osp.isdir(wdir): return True else: QMessageBox.critical( self, _("Run configuration"), _("The following working directory is " "not valid:<br><b>%s</b>") % wdir) return False def set_firstrun_o(self): CONF.set('run', ALWAYS_OPEN_FIRST_RUN_OPTION, self.firstrun_cb.isChecked())
class FindReplace(QWidget): """Find widget""" STYLE = {False: "background-color:rgb(255, 175, 90);", True: ""} visibility_changed = Signal(bool) def __init__(self, parent, enable_replace=False): QWidget.__init__(self, parent) self.enable_replace = enable_replace self.editor = None self.is_code_editor = None glayout = QGridLayout() glayout.setContentsMargins(0, 0, 0, 0) self.setLayout(glayout) self.close_button = create_toolbutton(self, triggered=self.hide, icon=ima.icon('DialogCloseButton')) glayout.addWidget(self.close_button, 0, 0) # Find layout self.search_text = PatternComboBox(self, tip=_("Search string"), adjust_to_minimum=False) self.search_text.valid.connect( lambda state: self.find(changed=False, forward=True, rehighlight=False)) self.search_text.lineEdit().textEdited.connect( self.text_has_been_edited) self.previous_button = create_toolbutton(self, triggered=self.find_previous, icon=ima.icon('ArrowUp')) self.next_button = create_toolbutton(self, triggered=self.find_next, icon=ima.icon('ArrowDown')) self.next_button.clicked.connect(self.update_search_combo) self.previous_button.clicked.connect(self.update_search_combo) self.re_button = create_toolbutton(self, icon=ima.icon('advanced'), tip=_("Regular expression")) self.re_button.setCheckable(True) self.re_button.toggled.connect(lambda state: self.find()) self.case_button = create_toolbutton(self, icon=get_icon("upper_lower.png"), tip=_("Case Sensitive")) self.case_button.setCheckable(True) self.case_button.toggled.connect(lambda state: self.find()) self.words_button = create_toolbutton(self, icon=get_icon("whole_words.png"), tip=_("Whole words")) self.words_button.setCheckable(True) self.words_button.toggled.connect(lambda state: self.find()) self.highlight_button = create_toolbutton(self, icon=get_icon("highlight.png"), tip=_("Highlight matches")) self.highlight_button.setCheckable(True) self.highlight_button.toggled.connect(self.toggle_highlighting) hlayout = QHBoxLayout() self.widgets = [self.close_button, self.search_text, self.previous_button, self.next_button, self.re_button, self.case_button, self.words_button, self.highlight_button] for widget in self.widgets[1:]: hlayout.addWidget(widget) glayout.addLayout(hlayout, 0, 1) # Replace layout replace_with = QLabel(_("Replace with:")) self.replace_text = PatternComboBox(self, adjust_to_minimum=False, tip=_('Replace string')) self.replace_button = create_toolbutton(self, text=_('Replace/find'), icon=ima.icon('DialogApplyButton'), triggered=self.replace_find, text_beside_icon=True) self.replace_button.clicked.connect(self.update_replace_combo) self.replace_button.clicked.connect(self.update_search_combo) self.all_check = QCheckBox(_("Replace all")) self.replace_layout = QHBoxLayout() widgets = [replace_with, self.replace_text, self.replace_button, self.all_check] for widget in widgets: self.replace_layout.addWidget(widget) glayout.addLayout(self.replace_layout, 1, 1) self.widgets.extend(widgets) self.replace_widgets = widgets self.hide_replace() self.search_text.setTabOrder(self.search_text, self.replace_text) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.shortcuts = self.create_shortcuts(parent) self.highlight_timer = QTimer(self) self.highlight_timer.setSingleShot(True) self.highlight_timer.setInterval(1000) self.highlight_timer.timeout.connect(self.highlight_matches) def create_shortcuts(self, parent): """Create shortcuts for this widget""" # Configurable findnext = config_shortcut(self.find_next, context='_', name='Find next', parent=parent) findprev = config_shortcut(self.find_previous, context='_', name='Find previous', parent=parent) togglefind = config_shortcut(self.show, context='_', name='Find text', parent=parent) togglereplace = config_shortcut(self.toggle_replace_widgets, context='_', name='Replace text', parent=parent) # Fixed fixed_shortcut("Escape", self, self.hide) return [findnext, findprev, togglefind, togglereplace] def get_shortcut_data(self): """ Returns shortcut data, a list of tuples (shortcut, text, default) shortcut (QShortcut or QAction instance) text (string): action/shortcut description default (string): default key sequence """ return [sc.data for sc in self.shortcuts] def update_search_combo(self): self.search_text.lineEdit().returnPressed.emit() def update_replace_combo(self): self.replace_text.lineEdit().returnPressed.emit() def toggle_replace_widgets(self): if self.enable_replace: # Toggle replace widgets if self.replace_widgets[0].isVisible(): self.hide_replace() self.hide() else: self.show_replace() self.replace_text.setFocus() @Slot(bool) def toggle_highlighting(self, state): """Toggle the 'highlight all results' feature""" if self.editor is not None: if state: self.highlight_matches() else: self.clear_matches() def show(self): """Overrides Qt Method""" QWidget.show(self) self.visibility_changed.emit(True) if self.editor is not None: text = self.editor.get_selected_text() # If no text is highlighted for search, use whatever word is under the cursor if not text: cursor = self.editor.textCursor() cursor.select(QTextCursor.WordUnderCursor) text = to_text_string(cursor.selectedText()) # Now that text value is sorted out, use it for the search if text: self.search_text.setEditText(text) self.search_text.lineEdit().selectAll() self.refresh() else: self.search_text.lineEdit().selectAll() self.search_text.setFocus() @Slot() def hide(self): """Overrides Qt Method""" for widget in self.replace_widgets: widget.hide() QWidget.hide(self) self.visibility_changed.emit(False) if self.editor is not None: self.editor.setFocus() self.clear_matches() def show_replace(self): """Show replace widgets""" self.show() for widget in self.replace_widgets: widget.show() def hide_replace(self): """Hide replace widgets""" for widget in self.replace_widgets: widget.hide() def refresh(self): """Refresh widget""" if self.isHidden(): if self.editor is not None: self.clear_matches() return state = self.editor is not None for widget in self.widgets: widget.setEnabled(state) if state: self.find() def set_editor(self, editor, refresh=True): """ Set associated editor/web page: codeeditor.base.TextEditBaseWidget browser.WebView """ self.editor = editor # Note: This is necessary to test widgets/editor.py # in Qt builds that don't have web widgets try: from qtpy.QtWebEngineWidgets import QWebEngineView except ImportError: QWebEngineView = type(None) self.words_button.setVisible(not isinstance(editor, QWebEngineView)) self.re_button.setVisible(not isinstance(editor, QWebEngineView)) from spyderlib.widgets.sourcecode.codeeditor import CodeEditor self.is_code_editor = isinstance(editor, CodeEditor) self.highlight_button.setVisible(self.is_code_editor) if refresh: self.refresh() if self.isHidden() and editor is not None: self.clear_matches() @Slot() def find_next(self): """Find next occurrence""" state = self.find(changed=False, forward=True, rehighlight=False) self.editor.setFocus() self.search_text.add_current_text() return state @Slot() def find_previous(self): """Find previous occurrence""" state = self.find(changed=False, forward=False, rehighlight=False) self.editor.setFocus() return state def text_has_been_edited(self, text): """Find text has been edited (this slot won't be triggered when setting the search pattern combo box text programmatically""" self.find(changed=True, forward=True, start_highlight_timer=True) def highlight_matches(self): """Highlight found results""" if self.is_code_editor and self.highlight_button.isChecked(): text = self.search_text.currentText() words = self.words_button.isChecked() regexp = self.re_button.isChecked() self.editor.highlight_found_results(text, words=words, regexp=regexp) def clear_matches(self): """Clear all highlighted matches""" if self.is_code_editor: self.editor.clear_found_results() def find(self, changed=True, forward=True, rehighlight=True, start_highlight_timer=False): """Call the find function""" text = self.search_text.currentText() if len(text) == 0: self.search_text.lineEdit().setStyleSheet("") return None else: case = self.case_button.isChecked() words = self.words_button.isChecked() regexp = self.re_button.isChecked() found = self.editor.find_text(text, changed, forward, case=case, words=words, regexp=regexp) self.search_text.lineEdit().setStyleSheet(self.STYLE[found]) if self.is_code_editor and found: if rehighlight or not self.editor.found_results: self.highlight_timer.stop() if start_highlight_timer: self.highlight_timer.start() else: self.highlight_matches() else: self.clear_matches() return found @Slot() def replace_find(self): """Replace and find""" if (self.editor is not None): replace_text = to_text_string(self.replace_text.currentText()) search_text = to_text_string(self.search_text.currentText()) pattern = search_text if self.re_button.isChecked() else None case = self.case_button.isChecked() first = True cursor = None while True: if first: # First found seltxt = to_text_string(self.editor.get_selected_text()) cmptxt1 = search_text if case else search_text.lower() cmptxt2 = seltxt if case else seltxt.lower() if self.editor.has_selected_text() and cmptxt1 == cmptxt2: # Text was already found, do nothing pass else: if not self.find(changed=False, forward=True, rehighlight=False): break first = False wrapped = False position = self.editor.get_position('cursor') position0 = position cursor = self.editor.textCursor() cursor.beginEditBlock() else: position1 = self.editor.get_position('cursor') if is_position_inf(position1, position0 + len(replace_text) - len(search_text) + 1): # Identify wrapping even when the replace string # includes part of the search string wrapped = True if wrapped: if position1 == position or \ is_position_sup(position1, position): # Avoid infinite loop: replace string includes # part of the search string break if position1 == position0: # Avoid infinite loop: single found occurrence break position0 = position1 if pattern is None: cursor.removeSelectedText() cursor.insertText(replace_text) else: seltxt = to_text_string(cursor.selectedText()) cursor.removeSelectedText() cursor.insertText(re.sub(pattern, replace_text, seltxt)) if self.find_next(): found_cursor = self.editor.textCursor() cursor.setPosition(found_cursor.selectionStart(), QTextCursor.MoveAnchor) cursor.setPosition(found_cursor.selectionEnd(), QTextCursor.KeepAnchor) else: break if not self.all_check.isChecked(): break self.all_check.setCheckState(Qt.Unchecked) if cursor is not None: cursor.endEditBlock()
def __init__(self, parent=None): QWidget.__init__(self, parent) self.dir = None self.runconf = RunConfiguration() firstrun_o = CONF.get('run', ALWAYS_OPEN_FIRST_RUN_OPTION, False) # --- Interpreter --- interpreter_group = QGroupBox(_("Console")) interpreter_layout = QVBoxLayout() interpreter_group.setLayout(interpreter_layout) self.current_radio = QRadioButton(CURRENT_INTERPRETER) interpreter_layout.addWidget(self.current_radio) self.dedicated_radio = QRadioButton(DEDICATED_INTERPRETER) interpreter_layout.addWidget(self.dedicated_radio) self.systerm_radio = QRadioButton(SYSTERM_INTERPRETER) interpreter_layout.addWidget(self.systerm_radio) # --- General settings ---- common_group = QGroupBox(_("General settings")) common_layout = QGridLayout() common_group.setLayout(common_layout) self.clear_var_cb = QCheckBox(CLEAR_ALL_VARIABLES) common_layout.addWidget(self.clear_var_cb, 0, 0) self.post_mortem_cb = QCheckBox(POST_MORTEM) common_layout.addWidget(self.post_mortem_cb, 1, 0) self.clo_cb = QCheckBox(_("Command line options:")) common_layout.addWidget(self.clo_cb, 2, 0) self.clo_edit = QLineEdit() self.clo_cb.toggled.connect(self.clo_edit.setEnabled) self.clo_edit.setEnabled(False) common_layout.addWidget(self.clo_edit, 2, 1) # --- Working directory --- wdir_group = QGroupBox(_("Working Directory settings")) wdir_layout = QVBoxLayout() wdir_group.setLayout(wdir_layout) self.file_dir_radio = QRadioButton(FILE_DIR) wdir_layout.addWidget(self.file_dir_radio) self.cwd_radio = QRadioButton(CW_DIR) wdir_layout.addWidget(self.cwd_radio) fixed_dir_layout = QHBoxLayout() self.fixed_dir_radio = QRadioButton(FIXED_DIR) fixed_dir_layout.addWidget(self.fixed_dir_radio) self.wd_edit = QLineEdit() self.fixed_dir_radio.toggled.connect(self.wd_edit.setEnabled) self.wd_edit.setEnabled(False) fixed_dir_layout.addWidget(self.wd_edit) browse_btn = QPushButton(ima.icon('DirOpenIcon'), '', self) browse_btn.setToolTip(_("Select directory")) browse_btn.clicked.connect(self.select_directory) fixed_dir_layout.addWidget(browse_btn) wdir_layout.addLayout(fixed_dir_layout) # --- System terminal --- external_group = QGroupBox(_("External system terminal")) external_group.setDisabled(True) self.systerm_radio.toggled.connect(external_group.setEnabled) external_layout = QGridLayout() external_group.setLayout(external_layout) self.interact_cb = QCheckBox(INTERACT) external_layout.addWidget(self.interact_cb, 1, 0, 1, -1) self.pclo_cb = QCheckBox(_("Command line options:")) external_layout.addWidget(self.pclo_cb, 3, 0) self.pclo_edit = QLineEdit() self.pclo_cb.toggled.connect(self.pclo_edit.setEnabled) self.pclo_edit.setEnabled(False) self.pclo_edit.setToolTip( _("<b>-u</b> is added to the " "other options you set here")) external_layout.addWidget(self.pclo_edit, 3, 1) # Checkbox to preserve the old behavior, i.e. always open the dialog # on first run hline = QFrame() hline.setFrameShape(QFrame.HLine) hline.setFrameShadow(QFrame.Sunken) self.firstrun_cb = QCheckBox(ALWAYS_OPEN_FIRST_RUN % _("this dialog")) self.firstrun_cb.clicked.connect(self.set_firstrun_o) self.firstrun_cb.setChecked(firstrun_o) layout = QVBoxLayout() layout.addWidget(interpreter_group) layout.addWidget(common_group) layout.addWidget(wdir_group) layout.addWidget(external_group) layout.addWidget(hline) layout.addWidget(self.firstrun_cb) self.setLayout(layout)
def __init__(self, parent=None): QWidget.__init__(self, parent) self.dir = None self.runconf = RunConfiguration() firstrun_o = CONF.get('run', ALWAYS_OPEN_FIRST_RUN_OPTION, False) # --- Interpreter --- interpreter_group = QGroupBox(_("Console")) interpreter_layout = QVBoxLayout() interpreter_group.setLayout(interpreter_layout) self.current_radio = QRadioButton(CURRENT_INTERPRETER) interpreter_layout.addWidget(self.current_radio) self.dedicated_radio = QRadioButton(DEDICATED_INTERPRETER) interpreter_layout.addWidget(self.dedicated_radio) self.systerm_radio = QRadioButton(SYSTERM_INTERPRETER) interpreter_layout.addWidget(self.systerm_radio) # --- General settings ---- common_group = QGroupBox(_("General settings")) common_layout = QGridLayout() common_group.setLayout(common_layout) self.clear_var_cb = QCheckBox(CLEAR_ALL_VARIABLES) common_layout.addWidget(self.clear_var_cb, 0, 0) self.post_mortem_cb = QCheckBox(POST_MORTEM) common_layout.addWidget(self.post_mortem_cb, 1, 0) self.clo_cb = QCheckBox(_("Command line options:")) common_layout.addWidget(self.clo_cb, 2, 0) self.clo_edit = QLineEdit() self.clo_cb.toggled.connect(self.clo_edit.setEnabled) self.clo_edit.setEnabled(False) common_layout.addWidget(self.clo_edit, 2, 1) # --- Working directory --- wdir_group = QGroupBox(_("Working Directory settings")) wdir_layout = QVBoxLayout() wdir_group.setLayout(wdir_layout) self.file_dir_radio = QRadioButton(FILE_DIR) wdir_layout.addWidget(self.file_dir_radio) self.cwd_radio = QRadioButton(CW_DIR) wdir_layout.addWidget(self.cwd_radio) fixed_dir_layout = QHBoxLayout() self.fixed_dir_radio = QRadioButton(FIXED_DIR) fixed_dir_layout.addWidget(self.fixed_dir_radio) self.wd_edit = QLineEdit() self.fixed_dir_radio.toggled.connect(self.wd_edit.setEnabled) self.wd_edit.setEnabled(False) fixed_dir_layout.addWidget(self.wd_edit) browse_btn = QPushButton(ima.icon('DirOpenIcon'), '', self) browse_btn.setToolTip(_("Select directory")) browse_btn.clicked.connect(self.select_directory) fixed_dir_layout.addWidget(browse_btn) wdir_layout.addLayout(fixed_dir_layout) # --- System terminal --- external_group = QGroupBox(_("External system terminal")) external_group.setDisabled(True) self.systerm_radio.toggled.connect(external_group.setEnabled) external_layout = QGridLayout() external_group.setLayout(external_layout) self.interact_cb = QCheckBox(INTERACT) external_layout.addWidget(self.interact_cb, 1, 0, 1, -1) self.pclo_cb = QCheckBox(_("Command line options:")) external_layout.addWidget(self.pclo_cb, 3, 0) self.pclo_edit = QLineEdit() self.pclo_cb.toggled.connect(self.pclo_edit.setEnabled) self.pclo_edit.setEnabled(False) self.pclo_edit.setToolTip(_("<b>-u</b> is added to the " "other options you set here")) external_layout.addWidget(self.pclo_edit, 3, 1) # Checkbox to preserve the old behavior, i.e. always open the dialog # on first run hline = QFrame() hline.setFrameShape(QFrame.HLine) hline.setFrameShadow(QFrame.Sunken) self.firstrun_cb = QCheckBox(ALWAYS_OPEN_FIRST_RUN % _("this dialog")) self.firstrun_cb.clicked.connect(self.set_firstrun_o) self.firstrun_cb.setChecked(firstrun_o) layout = QVBoxLayout() layout.addWidget(interpreter_group) layout.addWidget(common_group) layout.addWidget(wdir_group) layout.addWidget(external_group) layout.addWidget(hline) layout.addWidget(self.firstrun_cb) self.setLayout(layout)
def create_scedit(self, text, option, default=NoDefault, tip=None, without_layout=False, section=None): if section is not None and section != self.CONF_SECTION: self.cross_section_options[option] = section label = QLabel(text) clayout = ColorLayout(QColor(Qt.black), self) clayout.lineedit.setMaximumWidth(80) if tip is not None: clayout.setToolTip(tip) cb_bold = QCheckBox() cb_bold.setIcon(ima.icon('bold')) cb_bold.setToolTip(_("Bold")) cb_italic = QCheckBox() cb_italic.setIcon(ima.icon('italic')) cb_italic.setToolTip(_("Italic")) self.scedits[(clayout, cb_bold, cb_italic)] = (section, option, default) if without_layout: return label, clayout, cb_bold, cb_italic layout = QHBoxLayout() layout.addWidget(label) layout.addLayout(clayout) layout.addSpacing(10) layout.addWidget(cb_bold) layout.addWidget(cb_italic) layout.addStretch(1) layout.setContentsMargins(0, 0, 0, 0) widget = QWidget(self) widget.setLayout(layout) return widget
class SampleLogsView(QSplitter): """Sample Logs View This contains a table of the logs, a plot of the currently selected logs, and the statistics of the selected log. """ def __init__(self, presenter, parent=None, window_flags=Qt.Window, name='', isMD=False, noExp=0): super(SampleLogsView, self).__init__(parent) self.presenter = presenter self.setWindowTitle("{} sample logs".format(name)) self.setWindowFlags(window_flags) self.setAttribute(Qt.WA_DeleteOnClose, True) # left hand side self.frame_left = QFrame() layout_left = QVBoxLayout() # add a spin box for MD workspaces if isMD: layout_mult_expt_info = QHBoxLayout() layout_mult_expt_info.addWidget(QLabel("Experiment Info #")) self.experimentInfo = QSpinBox() self.experimentInfo.setMaximum(noExp - 1) self.experimentInfo.valueChanged.connect( self.presenter.changeExpInfo) layout_mult_expt_info.addWidget(self.experimentInfo) layout_mult_expt_info.addSpacerItem( QSpacerItem(10, 10, QSizePolicy.Expanding)) layout_left.addLayout(layout_mult_expt_info) # create a line edit to allow for filtering keys self.line_edit = QLineEdit() self.line_edit.setClearButtonEnabled(True) self.line_edit.setToolTip("Type here to filter the logs") self.line_edit.setPlaceholderText("Search the logs") self.line_edit.textEdited.connect(self.presenter.search_key_changed) layout_left.addWidget(self.line_edit) # Create sample log table self.table = QTableView() self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.doubleClicked.connect(self.presenter.doubleClicked) self.table.contextMenuEvent = self.tableMenu layout_left.addWidget(self.table) self.frame_left.setLayout(layout_left) self.addWidget(self.frame_left) #right hand side self.frame_right = QFrame() layout_right = QVBoxLayout() #Add full_time and experimentinfo options layout_options = QHBoxLayout() if isMD: layout_options.addWidget(QLabel("Experiment Info #")) self.experimentInfo = QSpinBox() self.experimentInfo.setMaximum(noExp - 1) self.experimentInfo.valueChanged.connect( self.presenter.changeExpInfo) layout_options.addWidget(self.experimentInfo) #check boxes self.full_time = QCheckBox("Relative Time") self.full_time.setToolTip( "Shows relative time in seconds from the start of the run.") self.full_time.setChecked(True) self.full_time.stateChanged.connect(self.presenter.plot_logs) layout_options.addWidget(self.full_time) self.show_filtered = QCheckBox("Filtered Data") self.show_filtered.setToolTip( "Filtered data only shows data while running and in this period.\nInvalid values are also filtered." ) self.show_filtered.setChecked(True) self.show_filtered.stateChanged.connect( self.presenter.filtered_changed) layout_options.addWidget(self.show_filtered) self.spaceItem = QSpacerItem(10, 10, QSizePolicy.Expanding) layout_options.addSpacerItem(self.spaceItem) layout_right.addLayout(layout_options) # Sample log plot self.fig = Figure() self.canvas = FigureCanvas(self.fig) self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.canvas.mpl_connect('button_press_event', self.presenter.plot_clicked) self.ax = self.fig.add_subplot(111, projection='mantid') layout_right.addWidget(self.canvas) # Sample stats self.create_stats_widgets() layout_stats = QFormLayout() layout_stats.addRow('', QLabel("Log Statistics")) layout_stats.addRow('Min:', self.stats_widgets["minimum"]) layout_stats.addRow('Max:', self.stats_widgets["maximum"]) layout_stats.addRow('Time Avg:', self.stats_widgets["time_mean"]) layout_stats.addRow('Time Std Dev:', self.stats_widgets["time_standard_deviation"]) layout_stats.addRow('Mean (unweighted):', self.stats_widgets["mean"]) layout_stats.addRow('Median (unweighted):', self.stats_widgets["median"]) layout_stats.addRow('Std Dev:', self.stats_widgets["standard_deviation"]) layout_stats.addRow('Duration:', self.stats_widgets["duration"]) layout_right.addLayout(layout_stats) self.frame_right.setLayout(layout_right) self.addWidget(self.frame_right) self.setStretchFactor(0, 1) self.resize(1200, 800) self.show() def closeEvent(self, event): self.deleteLater() super(SampleLogsView, self).closeEvent(event) def tableMenu(self, event): """Right click menu for table, can plot or print selected logs""" menu = QMenu(self) plotAction = menu.addAction("Plot selected") plotAction.triggered.connect(self.presenter.new_plot_logs) plotAction = menu.addAction("Print selected") plotAction.triggered.connect(self.presenter.print_selected_logs) menu.exec_(event.globalPos()) def set_model(self, model): """Set the model onto the table""" self.model = model self.table.setModel(self.model) self.table.resizeColumnsToContents() self.table.horizontalHeader().setSectionResizeMode( 2, QHeaderView.Stretch) self.table.selectionModel().selectionChanged.connect( self.presenter.update) def show_plot_and_stats(self, show_plot_and_stats): """sets wether the plot and stats section should be visible""" if self.frame_right.isVisible() != show_plot_and_stats: # the desired state is nor the current state self.setUpdatesEnabled(False) current_width = self.frame_right.width() if current_width: self.last_width = current_width else: current_width = self.last_width if show_plot_and_stats: self.resize(self.width() + current_width, self.height()) else: self.resize(self.width() - current_width, self.height()) self.frame_right.setVisible(show_plot_and_stats) self.setUpdatesEnabled(True) def plot_selected_logs(self, ws, exp, rows): """Update the plot with the selected rows""" if self.frame_right.isVisible(): self.ax.clear() self.create_ax_by_rows(self.ax, ws, exp, rows) try: self.fig.canvas.draw() except ValueError as ve: #this can throw an error if the plot has recently been hidden, but the error does not matter if not str(ve).startswith("Image size of"): raise def new_plot_selected_logs(self, ws, exp, rows): """Create a new plot, in a separate window for selected rows""" fig, ax = plt.subplots(subplot_kw={'projection': 'mantid'}) self.create_ax_by_rows(ax, ws, exp, rows) fig.show() def create_ax_by_rows(self, ax, ws, exp, rows): """Creates the plots for given rows onto axis ax""" for row in rows: log_text = self.get_row_log_name(row) ax.plot(ws, LogName=log_text, label=log_text, FullTime=not self.full_time.isChecked(), Filtered=self.show_filtered.isChecked(), ExperimentInfo=exp) ax.set_ylabel('') if ax.get_legend_handles_labels()[0]: ax.legend() def set_log_controls(self, are_logs_filtered): """Sets log specific settings based on the log clicked on""" self.show_filtered.setEnabled(are_logs_filtered) def get_row_log_name(self, i): """Returns the log name of particular row""" return str(self.model.item(i, 0).text()) def get_exp(self): """Get set experiment info number""" return self.experimentInfo.value() def get_selected_row_indexes(self): """Return a list of selected row from table""" return [ row.row() for row in self.table.selectionModel().selectedRows() ] def set_selected_rows(self, rows): """Set seleceted rows in table""" mode = QItemSelectionModel.Select | QItemSelectionModel.Rows for row in rows: self.table.selectionModel().select(self.model.index(row, 0), mode) def create_stats_widgets(self): """Creates the statistics widgets""" self.stats_widgets = { "minimum": QLineEdit(), "maximum": QLineEdit(), "mean": QLineEdit(), "median": QLineEdit(), "standard_deviation": QLineEdit(), "time_mean": QLineEdit(), "time_standard_deviation": QLineEdit(), "duration": QLineEdit() } for widget in self.stats_widgets.values(): widget.setReadOnly(True) def set_statistics(self, stats): """Updates the statistics widgets from stats dictionary""" for param in self.stats_widgets.keys(): self.stats_widgets[param].setText('{:.6}'.format( getattr(stats, param))) def clear_statistics(self): """Clears the values in statistics widgets""" for widget in self.stats_widgets.values(): widget.clear()
def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.edge_width.connect(self._on_edge_width_change) self.layer.events.current_edge_color.connect( self._on_current_edge_color_change) self.layer.events.current_face_color.connect( self._on_current_face_color_change) self.layer.events.editable.connect(self._on_editable_change) self.layer.text.events.visible.connect(self._on_text_visibility_change) sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(40) sld.setSingleStep(1) value = self.layer.current_edge_width if isinstance(value, Iterable): if isinstance(value, list): value = np.asarray(value) value = value.mean() sld.setValue(int(value)) sld.valueChanged.connect(self.changeWidth) self.widthSlider = sld def _radio_button( parent, btn_name, mode, action_name, extra_tooltip_text='', **kwargs, ): """ Convenience local function to create a RadioButton and bind it to an action at the same time. Parameters ---------- parent : Any Parent of the generated QtModeRadioButton btn_name : str name fo the button mode : Enum Value Associated to current button action_name : str Action triggered when button pressed extra_tooltip_text : str Text you want added after the automatic tooltip set by the action manager **kwargs: Passed to QtModeRadioButton Returns ------- button: QtModeRadioButton button bound (or that will be bound to) to action `action_name` Notes ----- When shortcuts are modifed/added/removed via the action manager, the tooltip will be updated to reflect the new shortcut. """ action_name = 'napari:' + action_name btn = QtModeRadioButton(parent, btn_name, mode, **kwargs) action_manager.bind_button( action_name, btn, extra_tooltip_text='', ) return btn self.select_button = _radio_button(layer, 'select', Mode.SELECT, "activate_select_mode") self.direct_button = _radio_button(layer, 'direct', Mode.DIRECT, "activate_direct_mode") self.panzoom_button = _radio_button( layer, 'zoom', Mode.PAN_ZOOM, "activate_shape_pan_zoom_mode", extra_tooltip_text=trans._('(or hold Space)'), checked=True, ) self.rectangle_button = _radio_button( layer, 'rectangle', Mode.ADD_RECTANGLE, "activate_add_rectangle_mode", ) self.ellipse_button = _radio_button( layer, 'ellipse', Mode.ADD_ELLIPSE, "activate_add_ellipse_mode", ) self.line_button = _radio_button(layer, 'line', Mode.ADD_LINE, "activate_add_line_mode") self.path_button = _radio_button(layer, 'path', Mode.ADD_PATH, "activate_add_path_mode") self.polygon_button = _radio_button( layer, 'polygon', Mode.ADD_POLYGON, "activate_add_polygon_mode", ) self.vertex_insert_button = _radio_button( layer, 'vertex_insert', Mode.VERTEX_INSERT, "activate_vertex_insert_mode", ) self.vertex_remove_button = _radio_button( layer, 'vertex_remove', Mode.VERTEX_REMOVE, "activate_vertex_remove_mode", ) self.move_front_button = QtModePushButton( layer, 'move_front', slot=self.layer.move_to_front, tooltip=trans._('Move to front'), ) action_manager.bind_button('napari:move_shapes_selection_to_front', self.move_front_button) self.move_back_button = QtModePushButton( layer, 'move_back', slot=self.layer.move_to_back, tooltip=trans._('Move to back'), ) action_manager.bind_button('napari:move_shapes_selection_to_back', self.move_back_button) self.delete_button = QtModePushButton( layer, 'delete_shape', slot=self.layer.remove_selected, tooltip=trans._( "Delete selected shapes ({shortcut})", shortcut=Shortcut('Backspace').platform, ), ) self.button_group = QButtonGroup(self) self.button_group.addButton(self.select_button) self.button_group.addButton(self.direct_button) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.rectangle_button) self.button_group.addButton(self.ellipse_button) self.button_group.addButton(self.line_button) self.button_group.addButton(self.path_button) self.button_group.addButton(self.polygon_button) self.button_group.addButton(self.vertex_insert_button) self.button_group.addButton(self.vertex_remove_button) button_grid = QGridLayout() button_grid.addWidget(self.vertex_remove_button, 0, 2) button_grid.addWidget(self.vertex_insert_button, 0, 3) button_grid.addWidget(self.delete_button, 0, 4) button_grid.addWidget(self.direct_button, 0, 5) button_grid.addWidget(self.select_button, 0, 6) button_grid.addWidget(self.panzoom_button, 0, 7) button_grid.addWidget(self.move_back_button, 1, 1) button_grid.addWidget(self.move_front_button, 1, 2) button_grid.addWidget(self.ellipse_button, 1, 3) button_grid.addWidget(self.rectangle_button, 1, 4) button_grid.addWidget(self.polygon_button, 1, 5) button_grid.addWidget(self.line_button, 1, 6) button_grid.addWidget(self.path_button, 1, 7) button_grid.setContentsMargins(5, 0, 0, 5) button_grid.setColumnStretch(0, 1) button_grid.setSpacing(4) self.faceColorEdit = QColorSwatchEdit( initial_color=self.layer.current_face_color, tooltip=trans._('click to set current face color'), ) self._on_current_face_color_change() self.edgeColorEdit = QColorSwatchEdit( initial_color=self.layer.current_edge_color, tooltip=trans._('click to set current edge color'), ) self._on_current_edge_color_change() self.faceColorEdit.color_changed.connect(self.changeFaceColor) self.edgeColorEdit.color_changed.connect(self.changeEdgeColor) text_disp_cb = QCheckBox() text_disp_cb.setToolTip(trans._('toggle text visibility')) text_disp_cb.setChecked(self.layer.text.visible) text_disp_cb.stateChanged.connect(self.change_text_visibility) self.textDispCheckBox = text_disp_cb # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_grid, 0, 0, 1, 2) self.grid_layout.addWidget(QLabel(trans._('opacity:')), 1, 0) self.grid_layout.addWidget(self.opacitySlider, 1, 1) self.grid_layout.addWidget(QLabel(trans._('edge width:')), 2, 0) self.grid_layout.addWidget(self.widthSlider, 2, 1) self.grid_layout.addWidget(QLabel(trans._('blending:')), 3, 0) self.grid_layout.addWidget(self.blendComboBox, 3, 1) self.grid_layout.addWidget(QLabel(trans._('face color:')), 4, 0) self.grid_layout.addWidget(self.faceColorEdit, 4, 1) self.grid_layout.addWidget(QLabel(trans._('edge color:')), 5, 0) self.grid_layout.addWidget(self.edgeColorEdit, 5, 1) self.grid_layout.addWidget(QLabel(trans._('display text:')), 6, 0) self.grid_layout.addWidget(self.textDispCheckBox, 6, 1) self.grid_layout.setRowStretch(7, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4)
def __init__(self, layer): super().__init__(layer) # NOTE(arl): there are no events fired for changing checkboxes self.layer.events.tail_width.connect(self._on_tail_width_change) self.layer.events.tail_length.connect(self._on_tail_length_change) self.layer.events.properties.connect(self._on_properties_change) self.layer.events.colormap.connect(self._on_colormap_change) self.layer.events.color_by.connect(self._on_color_by_change) # combo box for track coloring, we can get these from the properties # keys self.color_by_combobox = QComboBox() self.color_by_combobox.addItems(self.layer.properties_to_color_by) self.colormap_combobox = QComboBox() self.colormap_combobox.addItems(list(AVAILABLE_COLORMAPS.keys())) # slider for track tail length self.tail_length_slider = QSlider(Qt.Horizontal) self.tail_length_slider.setFocusPolicy(Qt.NoFocus) self.tail_length_slider.setMinimum(1) self.tail_length_slider.setMaximum(MAX_TAIL_LENGTH) self.tail_length_slider.setSingleStep(1) # slider for track edge width self.tail_width_slider = QSlider(Qt.Horizontal) self.tail_width_slider.setFocusPolicy(Qt.NoFocus) self.tail_width_slider.setMinimum(1) self.tail_width_slider.setMaximum(MAX_TAIL_WIDTH) self.tail_width_slider.setSingleStep(1) # checkboxes for display self.id_checkbox = QCheckBox() self.tail_checkbox = QCheckBox() self.tail_checkbox.setChecked(True) self.graph_checkbox = QCheckBox() self.graph_checkbox.setChecked(True) self.tail_width_slider.valueChanged.connect(self.change_tail_width) self.tail_length_slider.valueChanged.connect(self.change_tail_length) self.tail_checkbox.stateChanged.connect(self.change_display_tail) self.id_checkbox.stateChanged.connect(self.change_display_id) self.graph_checkbox.stateChanged.connect(self.change_display_graph) self.color_by_combobox.currentTextChanged.connect(self.change_color_by) self.colormap_combobox.currentTextChanged.connect(self.change_colormap) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addWidget(QLabel(trans._('color by:')), 0, 0) self.grid_layout.addWidget(self.color_by_combobox, 0, 1) self.grid_layout.addWidget(QLabel(trans._('colormap:')), 1, 0) self.grid_layout.addWidget(self.colormap_combobox, 1, 1) self.grid_layout.addWidget(QLabel(trans._('blending:')), 2, 0) self.grid_layout.addWidget(self.blendComboBox, 2, 1) self.grid_layout.addWidget(QLabel(trans._('opacity:')), 3, 0) self.grid_layout.addWidget(self.opacitySlider, 3, 1) self.grid_layout.addWidget(QLabel(trans._('tail width:')), 4, 0) self.grid_layout.addWidget(self.tail_width_slider, 4, 1) self.grid_layout.addWidget(QLabel(trans._('tail length:')), 5, 0) self.grid_layout.addWidget(self.tail_length_slider, 5, 1) self.grid_layout.addWidget(QLabel(trans._('tail:')), 6, 0) self.grid_layout.addWidget(self.tail_checkbox, 6, 1) self.grid_layout.addWidget(QLabel(trans._('show ID:')), 7, 0) self.grid_layout.addWidget(self.id_checkbox, 7, 1) self.grid_layout.addWidget(QLabel(trans._('graph:')), 8, 0) self.grid_layout.addWidget(self.graph_checkbox, 8, 1) self.grid_layout.setRowStretch(9, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) self._on_tail_length_change() self._on_tail_width_change() self._on_colormap_change() self._on_color_by_change()
def __init__(self, parent, data=None, readonly=False, bg_value=None, bg_gradient='blue-red', minvalue=None, maxvalue=None, digits=None): QWidget.__init__(self, parent) assert bg_gradient in gradient_map if data is not None and np.isscalar(data): readonly = True self.readonly = readonly # prepare internal views and models self.model_axes = AxesArrayModel(parent=self, readonly=readonly) self.view_axes = AxesView(parent=self, model=self.model_axes) self.model_hlabels = LabelsArrayModel(parent=self, readonly=readonly) self.view_hlabels = LabelsView(parent=self, model=self.model_hlabels, hpos=RIGHT, vpos=TOP) self.model_vlabels = LabelsArrayModel(parent=self, readonly=readonly) self.view_vlabels = LabelsView(parent=self, model=self.model_vlabels, hpos=LEFT, vpos=BOTTOM) self.model_data = DataArrayModel(parent=self, readonly=readonly, minvalue=minvalue, maxvalue=maxvalue) self.view_data = DataView(parent=self, model=self.model_data) # in case data is None self.data_adapter = None # Create vertical and horizontal scrollbars self.vscrollbar = ScrollBar(self, self.view_data.verticalScrollBar()) self.hscrollbar = ScrollBar(self, self.view_data.horizontalScrollBar()) # Synchronize resizing self.view_axes.horizontalHeader().sectionResized.connect( self.view_vlabels.updateSectionWidth) self.view_axes.verticalHeader().sectionResized.connect( self.view_hlabels.updateSectionHeight) self.view_hlabels.horizontalHeader().sectionResized.connect( self.view_data.updateSectionWidth) self.view_vlabels.verticalHeader().sectionResized.connect( self.view_data.updateSectionHeight) # Synchronize auto-resizing self.view_axes.horizontalHeader().sectionHandleDoubleClicked.connect( self.resize_axes_column_to_contents) self.view_hlabels.horizontalHeader( ).sectionHandleDoubleClicked.connect( self.resize_hlabels_column_to_contents) self.view_axes.verticalHeader().sectionHandleDoubleClicked.connect( self.resize_axes_row_to_contents) self.view_vlabels.verticalHeader().sectionHandleDoubleClicked.connect( self.resize_vlabels_row_to_contents) # synchronize specific methods self.view_axes.allSelected.connect(self.view_data.selectAll) self.view_data.signal_copy.connect(self.copy) self.view_data.signal_excel.connect(self.to_excel) self.view_data.signal_paste.connect(self.paste) self.view_data.signal_plot.connect(self.plot) # propagate changes (add new items in the QUndoStack attribute of MappingEditor) self.model_data.newChanges.connect(self.data_changed) # Synchronize scrolling # data <--> hlabels self.view_data.horizontalScrollBar().valueChanged.connect( self.view_hlabels.horizontalScrollBar().setValue) self.view_hlabels.horizontalScrollBar().valueChanged.connect( self.view_data.horizontalScrollBar().setValue) # data <--> vlabels self.view_data.verticalScrollBar().valueChanged.connect( self.view_vlabels.verticalScrollBar().setValue) self.view_vlabels.verticalScrollBar().valueChanged.connect( self.view_data.verticalScrollBar().setValue) # Synchronize selecting columns(rows) via hor.(vert.) header of x(y)labels view self.view_hlabels.horizontalHeader().sectionPressed.connect( self.view_data.selectColumn) self.view_hlabels.horizontalHeader().sectionEntered.connect( self.view_data.selectNewColumn) self.view_vlabels.verticalHeader().sectionPressed.connect( self.view_data.selectRow) self.view_vlabels.verticalHeader().sectionEntered.connect( self.view_data.selectNewRow) # following lines are required to keep usual selection color # when selecting rows/columns via headers of label views. # Otherwise, selected rows/columns appear in grey. self.view_data.setStyleSheet("""QTableView { selection-background-color: palette(highlight); selection-color: white; }""") # set external borders array_frame = QFrame(self) array_frame.setFrameStyle(QFrame.StyledPanel) # remove borders of internal tables self.view_axes.setFrameStyle(QFrame.NoFrame) self.view_hlabels.setFrameStyle(QFrame.NoFrame) self.view_vlabels.setFrameStyle(QFrame.NoFrame) self.view_data.setFrameStyle(QFrame.NoFrame) # Set layout of table views: # [ axes ][hlabels]|V| # [vlabels][ data ]|s| # | H. scrollbar | array_layout = QGridLayout() array_layout.addWidget(self.view_axes, 0, 0) array_layout.addWidget(self.view_hlabels, 0, 1) array_layout.addWidget(self.view_vlabels, 1, 0) self.view_data.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) array_layout.addWidget(self.view_data, 1, 1) array_layout.addWidget(self.vscrollbar, 0, 2, 2, 1) array_layout.addWidget(self.hscrollbar, 2, 0, 1, 2) array_layout.setSpacing(0) array_layout.setContentsMargins(0, 0, 0, 0) array_frame.setLayout(array_layout) # Set filters and buttons layout self.filters_layout = QHBoxLayout() self.btn_layout = QHBoxLayout() self.btn_layout.setAlignment(Qt.AlignLeft) label = QLabel("Digits") self.btn_layout.addWidget(label) spin = QSpinBox(self) spin.valueChanged.connect(self.digits_changed) self.digits_spinbox = spin self.btn_layout.addWidget(spin) self.digits = 0 scientific = QCheckBox(_('Scientific')) scientific.stateChanged.connect(self.scientific_changed) self.scientific_checkbox = scientific self.btn_layout.addWidget(scientific) self.use_scientific = False gradient_chooser = QComboBox() gradient_chooser.setMaximumSize(120, 20) gradient_chooser.setIconSize(QSize(100, 20)) pixmap = QPixmap(100, 15) pixmap.fill(Qt.white) gradient_chooser.addItem(QIcon(pixmap), " ") pixmap.fill(Qt.transparent) painter = QPainter(pixmap) for name, gradient in available_gradients[1:]: qgradient = gradient.as_qgradient() # * fill with white because gradient can be transparent and if we do not "start from whilte", it skews the # colors. # * 1 and 13 instead of 0 and 15 to have a transparent border around/between the gradients painter.fillRect(0, 1, 100, 13, Qt.white) painter.fillRect(0, 1, 100, 13, qgradient) gradient_chooser.addItem(QIcon(pixmap), name, gradient) # without this, we can crash python :) del painter, pixmap # select default gradient # requires Qt5+ # gradient_chooser.setCurrentText(bg_gradient) gradient_chooser.setCurrentIndex( gradient_chooser.findText(bg_gradient)) gradient_chooser.currentIndexChanged.connect(self.gradient_changed) self.btn_layout.addWidget(gradient_chooser) self.gradient_chooser = gradient_chooser # Set widget layout layout = QVBoxLayout() layout.addLayout(self.filters_layout) layout.addWidget(array_frame) layout.addLayout(self.btn_layout) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # set gradient self.model_data.set_bg_gradient(gradient_map[bg_gradient]) # set data if data is not None: self.set_data(data, bg_value=bg_value, digits=digits) # See http://doc.qt.io/qt-4.8/qt-draganddrop-fridgemagnets-dragwidget-cpp.html for an example self.setAcceptDrops(True)
def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.selected_label.connect(self._on_selection_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contig_change) self.layer.events.n_dimensional.connect(self._on_n_dim_change) self.layer.events.editable.connect(self._on_editable_change) # shuffle colormap button self.colormapUpdate = QPushButton('shuffle colors') self.colormapUpdate.setObjectName('shuffleButton') self.colormapUpdate.clicked.connect(self.changeColor) # selection spinbox self.selectionSpinBox = QSpinBox() self.selectionSpinBox.setKeyboardTracking(False) self.selectionSpinBox.setSingleStep(1) self.selectionSpinBox.setMinimum(0) self.selectionSpinBox.setMaximum(2147483647) self.selectionSpinBox.valueChanged.connect(self.changeSelection) self.selectionSpinBox.setAlignment(Qt.AlignCenter) self._on_selection_change() sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(1) sld.setMaximum(40) sld.setSingleStep(1) sld.valueChanged.connect(self.changeSize) self.brushSizeSlider = sld self._on_brush_size_change() contig_cb = QCheckBox() contig_cb.setToolTip('contiguous editing') contig_cb.stateChanged.connect(self.change_contig) self.contigCheckBox = contig_cb self._on_contig_change() ndim_cb = QCheckBox() ndim_cb.setToolTip('n-dimensional editing') ndim_cb.stateChanged.connect(self.change_ndim) self.ndimCheckBox = ndim_cb self._on_n_dim_change() self.panzoom_button = QtModeRadioButton(layer, 'zoom', Mode.PAN_ZOOM, tooltip='Pan/zoom mode', checked=True) self.pick_button = QtModeRadioButton(layer, 'picker', Mode.PICKER, tooltip='Pick mode') self.paint_button = QtModeRadioButton(layer, 'paint', Mode.PAINT, tooltip='Paint mode') self.fill_button = QtModeRadioButton(layer, 'fill', Mode.FILL, tooltip='Fill mode') self.button_group = QButtonGroup(self) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.paint_button) self.button_group.addButton(self.pick_button) self.button_group.addButton(self.fill_button) self._on_editable_change() button_row = QHBoxLayout() button_row.addStretch(1) button_row.addWidget(self.pick_button) button_row.addWidget(self.fill_button) button_row.addWidget(self.paint_button) button_row.addWidget(self.panzoom_button) button_row.setSpacing(4) button_row.setContentsMargins(0, 0, 0, 5) color_layout = QHBoxLayout() color_layout.addWidget(QtColorBox(layer)) color_layout.addWidget(self.selectionSpinBox) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_row, 0, 1) self.grid_layout.addWidget(self.colormapUpdate, 0, 0) self.grid_layout.addWidget(QLabel('label:'), 1, 0) self.grid_layout.addLayout(color_layout, 1, 1) self.grid_layout.addWidget(QLabel('opacity:'), 2, 0) self.grid_layout.addWidget(self.opacitySlider, 2, 1) self.grid_layout.addWidget(QLabel('brush size:'), 3, 0) self.grid_layout.addWidget(self.brushSizeSlider, 3, 1) self.grid_layout.addWidget(QLabel('blending:'), 4, 0) self.grid_layout.addWidget(self.blendComboBox, 4, 1) self.grid_layout.addWidget(QLabel('contiguous:'), 5, 0) self.grid_layout.addWidget(self.contigCheckBox, 5, 1) self.grid_layout.addWidget(QLabel('n-dim:'), 6, 0) self.grid_layout.addWidget(self.ndimCheckBox, 6, 1) self.grid_layout.setRowStretch(7, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4)
def __init__(self, parent, text): QWidget.__init__(self, parent) self.text_editor = QTextEdit(self) self.text_editor.setText(text) self.text_editor.setReadOnly(True) # Type frame type_layout = QHBoxLayout() type_label = QLabel(_("Import as")) type_layout.addWidget(type_label) data_btn = QRadioButton(_("data")) data_btn.setChecked(True) self._as_data= True type_layout.addWidget(data_btn) code_btn = QRadioButton(_("code")) self._as_code = False type_layout.addWidget(code_btn) txt_btn = QRadioButton(_("text")) type_layout.addWidget(txt_btn) h_spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) type_layout.addItem(h_spacer) type_frame = QFrame() type_frame.setLayout(type_layout) # Opts frame grid_layout = QGridLayout() grid_layout.setSpacing(0) col_label = QLabel(_("Column separator:")) grid_layout.addWidget(col_label, 0, 0) col_w = QWidget() col_btn_layout = QHBoxLayout() self.tab_btn = QRadioButton(_("Tab")) self.tab_btn.setChecked(False) col_btn_layout.addWidget(self.tab_btn) self.ws_btn = QRadioButton(_("Whitespace")) self.ws_btn.setChecked(False) col_btn_layout.addWidget(self.ws_btn) other_btn_col = QRadioButton(_("other")) other_btn_col.setChecked(True) col_btn_layout.addWidget(other_btn_col) col_w.setLayout(col_btn_layout) grid_layout.addWidget(col_w, 0, 1) self.line_edt = QLineEdit(",") self.line_edt.setMaximumWidth(30) self.line_edt.setEnabled(True) other_btn_col.toggled.connect(self.line_edt.setEnabled) grid_layout.addWidget(self.line_edt, 0, 2) row_label = QLabel(_("Row separator:")) grid_layout.addWidget(row_label, 1, 0) row_w = QWidget() row_btn_layout = QHBoxLayout() self.eol_btn = QRadioButton(_("EOL")) self.eol_btn.setChecked(True) row_btn_layout.addWidget(self.eol_btn) other_btn_row = QRadioButton(_("other")) row_btn_layout.addWidget(other_btn_row) row_w.setLayout(row_btn_layout) grid_layout.addWidget(row_w, 1, 1) self.line_edt_row = QLineEdit(";") self.line_edt_row.setMaximumWidth(30) self.line_edt_row.setEnabled(False) other_btn_row.toggled.connect(self.line_edt_row.setEnabled) grid_layout.addWidget(self.line_edt_row, 1, 2) grid_layout.setRowMinimumHeight(2, 15) other_group = QGroupBox(_("Additional options")) other_layout = QGridLayout() other_group.setLayout(other_layout) skiprows_label = QLabel(_("Skip rows:")) other_layout.addWidget(skiprows_label, 0, 0) self.skiprows_edt = QLineEdit('0') self.skiprows_edt.setMaximumWidth(30) intvalid = QIntValidator(0, len(to_text_string(text).splitlines()), self.skiprows_edt) self.skiprows_edt.setValidator(intvalid) other_layout.addWidget(self.skiprows_edt, 0, 1) other_layout.setColumnMinimumWidth(2, 5) comments_label = QLabel(_("Comments:")) other_layout.addWidget(comments_label, 0, 3) self.comments_edt = QLineEdit('#') self.comments_edt.setMaximumWidth(30) other_layout.addWidget(self.comments_edt, 0, 4) self.trnsp_box = QCheckBox(_("Transpose")) #self.trnsp_box.setEnabled(False) other_layout.addWidget(self.trnsp_box, 1, 0, 2, 0) grid_layout.addWidget(other_group, 3, 0, 2, 0) opts_frame = QFrame() opts_frame.setLayout(grid_layout) data_btn.toggled.connect(opts_frame.setEnabled) data_btn.toggled.connect(self.set_as_data) code_btn.toggled.connect(self.set_as_code) # self.connect(txt_btn, SIGNAL("toggled(bool)"), # self, SLOT("is_text(bool)")) # Final layout layout = QVBoxLayout() layout.addWidget(type_frame) layout.addWidget(self.text_editor) layout.addWidget(opts_frame) self.setLayout(layout)
def __init__(self, parent=None): super(KernelConnectionDialog, self).__init__(parent) self.setWindowTitle(_('Connect to an existing kernel')) main_label = QLabel(_( "<p>Please select the JSON connection file (<i>e.g.</i> " "<tt>kernel-1234.json</tt>) of the existing kernel, and enter " "the SSH information if connecting to a remote machine. " "To learn more about starting external kernels and connecting " "to them, see <a href=\"https://docs.spyder-ide.org/" "ipythonconsole.html#connect-to-an-external-kernel\">" "our documentation</a>.</p>")) main_label.setWordWrap(True) main_label.setAlignment(Qt.AlignJustify) main_label.setOpenExternalLinks(True) # Connection file cf_label = QLabel(_('Connection file:')) self.cf = QLineEdit() self.cf.setPlaceholderText(_('Kernel connection file path')) self.cf.setMinimumWidth(350) cf_open_btn = QPushButton(_('Browse')) cf_open_btn.clicked.connect(self.select_connection_file) cf_layout = QHBoxLayout() cf_layout.addWidget(cf_label) cf_layout.addWidget(self.cf) cf_layout.addWidget(cf_open_btn) # Remote kernel groupbox self.rm_group = QGroupBox(_("This is a remote kernel (via SSH)")) # SSH connection hn_label = QLabel(_('Hostname:')) self.hn = QLineEdit() pn_label = QLabel(_('Port:')) self.pn = QLineEdit() self.pn.setMaximumWidth(75) un_label = QLabel(_('Username:'******'Password:'******'SSH keyfile:')) self.pw = QLineEdit() self.pw.setEchoMode(QLineEdit.Password) self.pw_radio.toggled.connect(self.pw.setEnabled) self.kf_radio.toggled.connect(self.pw.setDisabled) self.kf = QLineEdit() kf_open_btn = QPushButton(_('Browse')) kf_open_btn.clicked.connect(self.select_ssh_key) kf_layout = QHBoxLayout() kf_layout.addWidget(self.kf) kf_layout.addWidget(kf_open_btn) kfp_label = QLabel(_('Passphase:')) self.kfp = QLineEdit() self.kfp.setPlaceholderText(_('Optional')) self.kfp.setEchoMode(QLineEdit.Password) self.kf_radio.toggled.connect(self.kf.setEnabled) self.kf_radio.toggled.connect(self.kfp.setEnabled) self.kf_radio.toggled.connect(kf_open_btn.setEnabled) self.kf_radio.toggled.connect(kfp_label.setEnabled) self.pw_radio.toggled.connect(self.kf.setDisabled) self.pw_radio.toggled.connect(self.kfp.setDisabled) self.pw_radio.toggled.connect(kf_open_btn.setDisabled) self.pw_radio.toggled.connect(kfp_label.setDisabled) # SSH layout ssh_layout = QGridLayout() ssh_layout.addWidget(hn_label, 0, 0, 1, 2) ssh_layout.addWidget(self.hn, 0, 2) ssh_layout.addWidget(pn_label, 0, 3) ssh_layout.addWidget(self.pn, 0, 4) ssh_layout.addWidget(un_label, 1, 0, 1, 2) ssh_layout.addWidget(self.un, 1, 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.kf_radio, 2, 0) auth_layout.addWidget(kf_label, 2, 1) auth_layout.addLayout(kf_layout, 2, 2) auth_layout.addWidget(kfp_label, 3, 1) auth_layout.addWidget(self.kfp, 3, 2) auth_group.setLayout(auth_layout) # Remote kernel layout 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(True) self.rm_group.toggled.connect(self.pw_radio.setChecked) # Ok and Cancel buttons self.accept_btns = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.accept_btns.accepted.connect(self.save_connection_settings) self.accept_btns.accepted.connect(self.accept) self.accept_btns.rejected.connect(self.reject) # Save connection settings checkbox self.save_layout = QCheckBox(self) self.save_layout.setText(_("Save connection settings")) btns_layout = QHBoxLayout() btns_layout.addWidget(self.save_layout) btns_layout.addWidget(self.accept_btns) # Dialog layout layout = QVBoxLayout(self) layout.addWidget(main_label) layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) layout.addLayout(cf_layout) layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 12))) layout.addWidget(self.rm_group) layout.addLayout(btns_layout) self.load_connection_settings()
class SpyderErrorDialog(QDialog): """Custom error dialog for error reporting.""" def __init__(self, parent=None): QDialog.__init__(self, parent) self.setWindowTitle(_("Spyder internal error")) self.setModal(True) # To save the traceback sent to the internal console self.error_traceback = "" # Dialog main label self.main_label = QLabel( _("""<b>Spyder has encountered an internal problem</b><hr> Please enter below a step-by-step description of your problem (in English). Issue reports without a clear way to reproduce them will be closed. <br><br> <b>Note</b>: You need a Github account for this. """)) self.main_label.setWordWrap(True) self.main_label.setAlignment(Qt.AlignJustify) # Field to input the description of the problem self.input_description = DescriptionWidget(self) # Only allow to submit to Github if we have a long enough description self.input_description.textChanged.connect(self._description_changed) # Widget to show errors self.details = ShowErrorWidget(self) self.details.set_pythonshell_font(get_font()) self.details.hide() # Label to show missing chars self.initial_chars = len(self.input_description.toPlainText()) self.chars_label = QLabel(_("Enter at least {} " "characters".format(MIN_CHARS))) # Checkbox to dismiss future errors self.dismiss_box = QCheckBox() self.dismiss_box.setText(_("Don't show again during this session")) # Labels layout labels_layout = QHBoxLayout() labels_layout.addWidget(self.chars_label) labels_layout.addWidget(self.dismiss_box, 0, Qt.AlignRight) # Dialog buttons self.submit_btn = QPushButton(_('Submit to Github')) self.submit_btn.setEnabled(False) self.submit_btn.clicked.connect(self._submit_to_github) self.details_btn = QPushButton(_('Show details')) self.details_btn.clicked.connect(self._show_details) self.close_btn = QPushButton(_('Close')) # Buttons layout buttons_layout = QHBoxLayout() buttons_layout.addWidget(self.submit_btn) buttons_layout.addWidget(self.details_btn) buttons_layout.addWidget(self.close_btn) # Main layout vlayout = QVBoxLayout() vlayout.addWidget(self.main_label) vlayout.addWidget(self.input_description) vlayout.addWidget(self.details) vlayout.addLayout(labels_layout) vlayout.addLayout(buttons_layout) self.setLayout(vlayout) self.resize(600, 420) self.input_description.setFocus() def _submit_to_github(self): """Action to take when pressing the submit button.""" main = self.parent().main # Getting description and traceback description = self.input_description.toPlainText() traceback = self.error_traceback[:-1] # Remove last eol # Render issue issue_text = main.render_issue(description=description, traceback=traceback) # Copy issue to clipboard QApplication.clipboard().setText(issue_text) # Submit issue to Github issue_body=("<!--- " "Please paste the contents of your clipboard " "below to complete reporting your problem. " "--->\n\n") main.report_issue(body=issue_body, title="Automatic error report") def append_traceback(self, text): """Append text to the traceback, to be displayed in details.""" self.error_traceback += text def _show_details(self): """Show traceback on its own dialog""" if self.details.isVisible(): self.details.hide() self.details_btn.setText(_('Show details')) else: self.resize(600, 550) self.details.document().setPlainText('') self.details.append_text_to_shell(self.error_traceback, error=True, prompt=False) self.details.show() self.details_btn.setText(_('Hide details')) def _description_changed(self): """Activate submit_btn if we have a long enough description.""" chars = len(self.input_description.toPlainText()) - self.initial_chars if chars < MIN_CHARS: self.chars_label.setText( u"{} {}".format(MIN_CHARS - chars, _("more characters to go..."))) else: self.chars_label.setText(_("Ready to submit! Thanks!")) self.submit_btn.setEnabled(chars >= MIN_CHARS)
class SampleLogsView(QSplitter): """Sample Logs View This contains a table of the logs, a plot of the currently selected logs, and the statistics of the selected log. """ def __init__(self, presenter, parent = None, name = '', isMD=False, noExp = 0): super(SampleLogsView, self).__init__(parent) self.presenter = presenter self.setWindowTitle("{} sample logs".format(name)) self.setWindowFlags(Qt.Window) # Create sample log table self.table = QTableView() self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.clicked.connect(self.presenter.clicked) self.table.doubleClicked.connect(self.presenter.doubleClicked) self.table.contextMenuEvent = self.tableMenu self.addWidget(self.table) frame_right = QFrame() layout_right = QVBoxLayout() #Add full_time and experimentinfo options layout_options = QHBoxLayout() if isMD: layout_options.addWidget(QLabel("Experiment Info #")) self.experimentInfo = QSpinBox() self.experimentInfo.setMaximum(noExp-1) self.experimentInfo.valueChanged.connect(self.presenter.changeExpInfo) layout_options.addWidget(self.experimentInfo) self.full_time = QCheckBox("Relative Time") self.full_time.setChecked(True) self.full_time.stateChanged.connect(self.presenter.plot_logs) layout_options.addWidget(self.full_time) layout_right.addLayout(layout_options) # Sample log plot self.fig = Figure() self.canvas = FigureCanvas(self.fig) self.canvas.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding) self.canvas.mpl_connect('button_press_event', self.presenter.plot_clicked) self.ax = self.fig.add_subplot(111, projection='mantid') layout_right.addWidget(self.canvas) # Sample stats self.create_stats_widgets() layout_stats = QFormLayout() layout_stats.addRow('', QLabel("Log Statistics")) layout_stats.addRow('Min:', self.stats_widgets["minimum"]) layout_stats.addRow('Max:', self.stats_widgets["maximum"]) layout_stats.addRow('Mean:', self.stats_widgets["mean"]) layout_stats.addRow('Median:', self.stats_widgets["median"]) layout_stats.addRow('Std Dev:', self.stats_widgets["standard_deviation"]) layout_stats.addRow('Time Avg:', self.stats_widgets["time_mean"]) layout_stats.addRow('Time Std Dev:', self.stats_widgets["time_standard_deviation"]) layout_stats.addRow('Duration:', self.stats_widgets["duration"]) layout_right.addLayout(layout_stats) frame_right.setLayout(layout_right) self.addWidget(frame_right) self.setStretchFactor(0,1) self.resize(1200,800) self.show() def tableMenu(self, event): """Right click menu for table, can plot or print selected logs""" menu = QMenu(self) plotAction = menu.addAction("Plot selected") plotAction.triggered.connect(self.presenter.new_plot_logs) plotAction = menu.addAction("Print selected") plotAction.triggered.connect(self.presenter.print_selected_logs) menu.exec_(event.globalPos()) def set_model(self, model): """Set the model onto the table""" self.model = model self.table.setModel(self.model) self.table.resizeColumnsToContents() self.table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) def plot_selected_logs(self, ws, exp, rows): """Update the plot with the selected rows""" self.ax.clear() self.create_ax_by_rows(self.ax, ws, exp, rows) self.fig.canvas.draw() def new_plot_selected_logs(self, ws, exp, rows): """Create a new plot, in a separate window for selected rows""" fig, ax = plt.subplots(subplot_kw={'projection': 'mantid'}) self.create_ax_by_rows(ax, ws, exp, rows) fig.show() def create_ax_by_rows(self, ax, ws, exp, rows): """Creates the plots for given rows onto axis ax""" for row in rows: log_text = self.get_row_log_name(row) ax.plot(ws, LogName=log_text, label=log_text, marker='.', FullTime=not self.full_time.isChecked(), ExperimentInfo=exp) ax.set_ylabel('') if ax.get_legend_handles_labels()[0]: ax.legend() def get_row_log_name(self, i): """Returns the log name of particular row""" return str(self.model.item(i, 0).text()) def get_exp(self): """Get set experiment info number""" return self.experimentInfo.value() def get_selected_row_indexes(self): """Return a list of selected row from table""" return [row.row() for row in self.table.selectionModel().selectedRows()] def set_selected_rows(self, rows): """Set seleceted rows in table""" mode = QItemSelectionModel.Select | QItemSelectionModel.Rows for row in rows: self.table.selectionModel().select(self.model.index(row, 0), mode) def create_stats_widgets(self): """Creates the statistics widgets""" self.stats_widgets = {"minimum": QLineEdit(), "maximum": QLineEdit(), "mean": QLineEdit(), "median": QLineEdit(), "standard_deviation": QLineEdit(), "time_mean": QLineEdit(), "time_standard_deviation": QLineEdit(), "duration": QLineEdit()} for widget in self.stats_widgets.values(): widget.setReadOnly(True) def set_statistics(self, stats): """Updates the statistics widgets from stats dictionary""" for param in self.stats_widgets.keys(): self.stats_widgets[param].setText('{:.6}'.format(getattr(stats, param))) def clear_statistics(self): """Clears the values in statistics widgets""" for widget in self.stats_widgets.values(): widget.clear()
class ColorbarWidget(QWidget): colorbarChanged = Signal() # The parent should simply redraw their canvas def __init__(self, parent=None): super(ColorbarWidget, self).__init__(parent) self.setWindowTitle("Colorbar") self.setMaximumWidth(200) self.dval = QDoubleValidator() self.cmin = QLineEdit() self.cmin_value = 0 self.cmin.setMaximumWidth(100) self.cmin.editingFinished.connect(self.clim_changed) self.cmin_layout = QHBoxLayout() self.cmin_layout.addStretch() self.cmin_layout.addWidget(self.cmin) self.cmin_layout.addStretch() self.cmax = QLineEdit() self.cmax_value = 1 self.cmax.setMaximumWidth(100) self.cmax.editingFinished.connect(self.clim_changed) self.cmin.setValidator(self.dval) self.cmax.setValidator(self.dval) self.cmax_layout = QHBoxLayout() self.cmax_layout.addStretch() self.cmax_layout.addWidget(self.cmax) self.cmax_layout.addStretch() self.norm_layout = QHBoxLayout() self.norm = QComboBox() self.norm.addItems(NORM_OPTS) self.norm.currentIndexChanged.connect(self.norm_changed) self.powerscale = QLineEdit() self.powerscale_value = 2 self.powerscale.setText("2") self.powerscale.setValidator(QDoubleValidator(0.001,100,3)) self.powerscale.setMaximumWidth(50) self.powerscale.editingFinished.connect(self.norm_changed) self.powerscale.hide() self.powerscale_label = QLabel("n=") self.powerscale_label.hide() self.norm_layout.addStretch() self.norm_layout.addWidget(self.norm) self.norm_layout.addStretch() self.norm_layout.addWidget(self.powerscale_label) self.norm_layout.addWidget(self.powerscale) self.autoscale = QCheckBox("Autoscaling") self.autoscale.setChecked(True) self.autoscale.stateChanged.connect(self.update_clim) self.canvas = FigureCanvas(Figure()) if parent: # Set facecolor to match parent self.canvas.figure.set_facecolor(parent.palette().window().color().getRgbF()) self.ax = self.canvas.figure.add_axes([0.4,0.05,0.2,0.9]) # layout self.layout = QVBoxLayout(self) self.layout.addLayout(self.cmax_layout) self.layout.addWidget(self.canvas, stretch=1) self.layout.addLayout(self.cmin_layout) self.layout.addLayout(self.norm_layout) self.layout.addWidget(self.autoscale) def set_mappable(self, mappable): """ When a new plot is created this method should be called with the new mappable """ self.ax.clear() self.colorbar = Colorbar(ax=self.ax, mappable=mappable) self.cmin_value, self.cmax_value = self.colorbar.get_clim() self.update_clim_text() self.redraw() def norm_changed(self): """ Called when a different normalization is selected """ idx = self.norm.currentIndex() if NORM_OPTS[idx] == 'Power': self.powerscale.show() self.powerscale_label.show() else: self.powerscale.hide() self.powerscale_label.hide() self.colorbar.mappable.set_norm(self.get_norm()) self.colorbarChanged.emit() def get_norm(self): """ This will create a matplotlib.colors.Normalize from selected idx, limits and powerscale """ idx = self.norm.currentIndex() if self.autoscale.isChecked(): cmin = cmax = None else: cmin = self.cmin_value cmax = self.cmax_value if NORM_OPTS[idx] == 'Power': if self.powerscale.hasAcceptableInput(): self.powerscale_value = float(self.powerscale.text()) return PowerNorm(gamma=self.powerscale_value, vmin=cmin, vmax=cmax) elif NORM_OPTS[idx] == "SymmetricLog10": return SymLogNorm(1e-8 if cmin is None else max(1e-8, abs(cmin)*1e-3), vmin=cmin, vmax=cmax) else: return Normalize(vmin=cmin, vmax=cmax) def clim_changed(self): """ Called when either the min or max is changed. Will unset the autoscale. """ self.autoscale.blockSignals(True) self.autoscale.setChecked(False) self.autoscale.blockSignals(False) self.update_clim() def update_clim(self): """ This will update the clim of the plot based on min, max, and autoscale """ if self.autoscale.isChecked(): data = self.colorbar.mappable.get_array() try: try: self.cmin_value = data[~data.mask].min() self.cmax_value = data[~data.mask].max() except AttributeError: self.cmin_value = np.nanmin(data) self.cmax_value = np.nanmax(data) except (ValueError, RuntimeWarning): # all values mask pass self.update_clim_text() else: if self.cmin.hasAcceptableInput(): self.cmin_value = float(self.cmin.text()) if self.cmax.hasAcceptableInput(): self.cmax_value = float(self.cmax.text()) self.colorbar.set_clim(self.cmin_value, self.cmax_value) self.redraw() def update_clim_text(self): """ Update displayed limit values based on stored ones """ self.cmin.setText("{:.4}".format(self.cmin_value)) self.cmax.setText("{:.4}".format(self.cmax_value)) def redraw(self): """ Redraws the colobar and emits signal to cause the parent to redraw """ self.colorbar.update_ticks() self.colorbar.draw_all() self.canvas.draw_idle() self.colorbarChanged.emit()
class KernelConnectionDialog(QDialog): """Dialog to connect to existing kernels (either local or remote).""" def __init__(self, parent=None): super(KernelConnectionDialog, self).__init__(parent) self.setWindowTitle(_('Connect to an existing kernel')) main_label = QLabel(_( "<p>Please select the JSON connection file (<i>e.g.</i> " "<tt>kernel-1234.json</tt>) of the existing kernel, and enter " "the SSH information if connecting to a remote machine. " "To learn more about starting external kernels and connecting " "to them, see <a href=\"https://docs.spyder-ide.org/" "ipythonconsole.html#connect-to-an-external-kernel\">" "our documentation</a>.</p>")) main_label.setWordWrap(True) main_label.setAlignment(Qt.AlignJustify) main_label.setOpenExternalLinks(True) # Connection file cf_label = QLabel(_('Connection file:')) self.cf = QLineEdit() self.cf.setPlaceholderText(_('Kernel connection file path')) self.cf.setMinimumWidth(350) cf_open_btn = QPushButton(_('Browse')) cf_open_btn.clicked.connect(self.select_connection_file) cf_layout = QHBoxLayout() cf_layout.addWidget(cf_label) cf_layout.addWidget(self.cf) cf_layout.addWidget(cf_open_btn) # Remote kernel groupbox self.rm_group = QGroupBox(_("This is a remote kernel (via SSH)")) # SSH connection hn_label = QLabel(_('Hostname:')) self.hn = QLineEdit() pn_label = QLabel(_('Port:')) self.pn = QLineEdit() self.pn.setMaximumWidth(75) un_label = QLabel(_('Username:'******'Password:'******'SSH keyfile:')) self.pw = QLineEdit() self.pw.setEchoMode(QLineEdit.Password) self.pw_radio.toggled.connect(self.pw.setEnabled) self.kf_radio.toggled.connect(self.pw.setDisabled) self.kf = QLineEdit() kf_open_btn = QPushButton(_('Browse')) kf_open_btn.clicked.connect(self.select_ssh_key) kf_layout = QHBoxLayout() kf_layout.addWidget(self.kf) kf_layout.addWidget(kf_open_btn) kfp_label = QLabel(_('Passphase:')) self.kfp = QLineEdit() self.kfp.setPlaceholderText(_('Optional')) self.kfp.setEchoMode(QLineEdit.Password) self.kf_radio.toggled.connect(self.kf.setEnabled) self.kf_radio.toggled.connect(self.kfp.setEnabled) self.kf_radio.toggled.connect(kf_open_btn.setEnabled) self.kf_radio.toggled.connect(kfp_label.setEnabled) self.pw_radio.toggled.connect(self.kf.setDisabled) self.pw_radio.toggled.connect(self.kfp.setDisabled) self.pw_radio.toggled.connect(kf_open_btn.setDisabled) self.pw_radio.toggled.connect(kfp_label.setDisabled) # SSH layout ssh_layout = QGridLayout() ssh_layout.addWidget(hn_label, 0, 0, 1, 2) ssh_layout.addWidget(self.hn, 0, 2) ssh_layout.addWidget(pn_label, 0, 3) ssh_layout.addWidget(self.pn, 0, 4) ssh_layout.addWidget(un_label, 1, 0, 1, 2) ssh_layout.addWidget(self.un, 1, 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.kf_radio, 2, 0) auth_layout.addWidget(kf_label, 2, 1) auth_layout.addLayout(kf_layout, 2, 2) auth_layout.addWidget(kfp_label, 3, 1) auth_layout.addWidget(self.kfp, 3, 2) auth_group.setLayout(auth_layout) # Remote kernel layout 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(True) self.rm_group.toggled.connect(self.pw_radio.setChecked) # Ok and Cancel buttons self.accept_btns = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.accept_btns.accepted.connect(self.save_connection_settings) self.accept_btns.accepted.connect(self.accept) self.accept_btns.rejected.connect(self.reject) # Save connection settings checkbox self.save_layout = QCheckBox(self) self.save_layout.setText(_("Save connection settings")) btns_layout = QHBoxLayout() btns_layout.addWidget(self.save_layout) btns_layout.addWidget(self.accept_btns) # Dialog layout layout = QVBoxLayout(self) layout.addWidget(main_label) layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) layout.addLayout(cf_layout) layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 12))) layout.addWidget(self.rm_group) layout.addLayout(btns_layout) self.load_connection_settings() def load_connection_settings(self): """Load the user's previously-saved kernel connection settings.""" existing_kernel = CONF.get("existing-kernel", "settings", {}) connection_file_path = existing_kernel.get("json_file_path", "") is_remote = existing_kernel.get("is_remote", False) username = existing_kernel.get("username", "") hostname = existing_kernel.get("hostname", "") port = str(existing_kernel.get("port", 22)) is_ssh_kf = existing_kernel.get("is_ssh_keyfile", False) ssh_kf = existing_kernel.get("ssh_key_file_path", "") if connection_file_path != "": self.cf.setText(connection_file_path) if username != "": self.un.setText(username) if hostname != "": self.hn.setText(hostname) if ssh_kf != "": self.kf.setText(ssh_kf) self.rm_group.setChecked(is_remote) self.pn.setText(port) self.kf_radio.setChecked(is_ssh_kf) self.pw_radio.setChecked(not is_ssh_kf) try: import keyring ssh_passphrase = keyring.get_password("spyder_remote_kernel", "ssh_key_passphrase") ssh_password = keyring.get_password("spyder_remote_kernel", "ssh_password") if ssh_passphrase: self.kfp.setText(ssh_passphrase) if ssh_password: self.pw.setText(ssh_password) except Exception: pass def save_connection_settings(self): """Save user's kernel connection settings.""" if not self.save_layout.isChecked(): return is_ssh_key = bool(self.kf_radio.isChecked()) connection_settings = { "json_file_path": self.cf.text(), "is_remote": self.rm_group.isChecked(), "username": self.un.text(), "hostname": self.hn.text(), "port": self.pn.text(), "is_ssh_keyfile": is_ssh_key, "ssh_key_file_path": self.kf.text() } CONF.set("existing-kernel", "settings", connection_settings) try: import keyring if is_ssh_key: keyring.set_password("spyder_remote_kernel", "ssh_key_passphrase", self.kfp.text()) else: keyring.set_password("spyder_remote_kernel", "ssh_password", self.pw.text()) except Exception: pass def select_connection_file(self): cf = getopenfilename(self, _('Select kernel connection file'), jupyter_runtime_dir(), '*.json;;*.*')[0] self.cf.setText(cf) def select_ssh_key(self): kf = getopenfilename(self, _('Select SSH keyfile'), get_home_dir(), '*.pem;;*')[0] self.kf.setText(kf) @staticmethod def get_connection_parameters(parent=None, dialog=None): if not dialog: dialog = KernelConnectionDialog(parent) result = dialog.exec_() is_remote = bool(dialog.rm_group.isChecked()) accepted = result == QDialog.Accepted if is_remote: def falsy_to_none(arg): return arg if arg else None if dialog.hn.text() and dialog.un.text(): port = dialog.pn.text() if dialog.pn.text() else '22' hostname = "{0}@{1}:{2}".format(dialog.un.text(), dialog.hn.text(), port) else: hostname = None if dialog.pw_radio.isChecked(): password = falsy_to_none(dialog.pw.text()) keyfile = None elif dialog.kf_radio.isChecked(): keyfile = falsy_to_none(dialog.kf.text()) password = falsy_to_none(dialog.kfp.text()) else: # imposible? keyfile = None password = None return (dialog.cf.text(), hostname, keyfile, password, accepted) else: path = dialog.cf.text() _dir, filename = osp.dirname(path), osp.basename(path) if _dir == '' and not filename.endswith('.json'): path = osp.join(jupyter_runtime_dir(), 'kernel-'+path+'.json') return (path, None, None, None, accepted)
class DlgGitHubLogin(QDialog): """Dialog to submit error reports to Github.""" def __init__(self, parent, username, password, token, remember=False, remember_token=False): QDialog.__init__(self, parent) title = _("Sign in to Github") self.resize(415, 375) self.setWindowTitle(title) self.setWindowFlags( self.windowFlags() & ~Qt.WindowContextHelpButtonHint) # Header html = ('<html><head/><body><p align="center">' '{title}</p></body></html>') lbl_html = QLabel(html.format(title=title)) lbl_html.setStyleSheet('font-size: 16px;') # Tabs self.tabs = QTabWidget() # Basic form layout basic_form_layout = QFormLayout() basic_form_layout.setContentsMargins(-1, 0, -1, -1) basic_lbl_msg = QLabel(_("For regular users, i.e. users <b>without</b>" " two-factor authentication enabled")) basic_lbl_msg.setWordWrap(True) basic_lbl_msg.setAlignment(Qt.AlignJustify) lbl_user = QLabel(_("Username:"******"", QWidget()) lbl_password = QLabel(_("Password: "******"Remember me")) self.cb_remember.setToolTip(_("Spyder will save your credentials " "safely")) self.cb_remember.setChecked(remember) basic_form_layout.setWidget(4, QFormLayout.FieldRole, self.cb_remember) # Basic auth tab basic_auth = QWidget() basic_layout = QVBoxLayout() basic_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) basic_layout.addWidget(basic_lbl_msg) basic_layout.addSpacerItem( QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding))) basic_layout.addLayout(basic_form_layout) basic_layout.addSpacerItem( QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding))) basic_auth.setLayout(basic_layout) self.tabs.addTab(basic_auth, _("Password Only")) # Token form layout token_form_layout = QFormLayout() token_form_layout.setContentsMargins(-1, 0, -1, -1) token_lbl_msg = QLabel(_("For users <b>with</b> two-factor " "authentication enabled, or who prefer a " "per-app token authentication.<br><br>" "You can go <b><a href=\"{}\">here</a></b> " "and click \"Generate token\" at the bottom " "to create a new token to use for this, with " "the appropriate permissions.").format( TOKEN_URL)) token_lbl_msg.setOpenExternalLinks(True) token_lbl_msg.setWordWrap(True) token_lbl_msg.setAlignment(Qt.AlignJustify) lbl_token = QLabel("Token: ") token_form_layout.setWidget(1, QFormLayout.LabelRole, lbl_token) self.le_token = QLineEdit() self.le_token.setEchoMode(QLineEdit.Password) self.le_token.textChanged.connect(self.update_btn_state) token_form_layout.setWidget(1, QFormLayout.FieldRole, self.le_token) self.cb_remember_token = None # Same validation as with cb_remember if self.is_keyring_available() and valid_py_os: self.cb_remember_token = QCheckBox(_("Remember token")) self.cb_remember_token.setToolTip(_("Spyder will save your " "token safely")) self.cb_remember_token.setChecked(remember_token) token_form_layout.setWidget(3, QFormLayout.FieldRole, self.cb_remember_token) # Token auth tab token_auth = QWidget() token_layout = QVBoxLayout() token_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) token_layout.addWidget(token_lbl_msg) token_layout.addSpacerItem( QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding))) token_layout.addLayout(token_form_layout) token_layout.addSpacerItem( QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding))) token_auth.setLayout(token_layout) self.tabs.addTab(token_auth, _("Access Token")) # Sign in button self.bt_sign_in = QPushButton(_("Sign in")) self.bt_sign_in.clicked.connect(self.accept) self.bt_sign_in.setDisabled(True) # Main layout layout = QVBoxLayout() layout.addWidget(lbl_html) layout.addWidget(self.tabs) layout.addWidget(self.bt_sign_in) self.setLayout(layout) # Final adjustments if username and password: self.le_user.setText(username) self.le_password.setText(password) self.bt_sign_in.setFocus() elif username: self.le_user.setText(username) self.le_password.setFocus() elif token: self.le_token.setText(token) else: self.le_user.setFocus() self.setFixedSize(self.width(), self.height()) self.le_password.installEventFilter(self) self.le_user.installEventFilter(self) self.tabs.currentChanged.connect(self.update_btn_state) def eventFilter(self, obj, event): interesting_objects = [self.le_password, self.le_user] if obj in interesting_objects and event.type() == QEvent.KeyPress: if (event.key() == Qt.Key_Return and event.modifiers() & Qt.ControlModifier and self.bt_sign_in.isEnabled()): self.accept() return True return False def update_btn_state(self): user = to_text_string(self.le_user.text()).strip() != '' password = to_text_string(self.le_password.text()).strip() != '' token = to_text_string(self.le_token.text()).strip() != '' enable = ((user and password and self.tabs.currentIndex() == 0) or (token and self.tabs.currentIndex() == 1)) self.bt_sign_in.setEnabled(enable) def is_keyring_available(self): """Check if keyring is available for password storage.""" try: import keyring # analysis:ignore return True except Exception: return False @classmethod def login(cls, parent, username, password, token, remember, remember_token): dlg = DlgGitHubLogin(parent, username, password, token, remember, remember_token) if dlg.exec_() == dlg.Accepted: user = dlg.le_user.text() password = dlg.le_password.text() token = dlg.le_token.text() if dlg.cb_remember: remember = dlg.cb_remember.isChecked() else: remember = False if dlg.cb_remember_token: remember_token = dlg.cb_remember_token.isChecked() else: remember_token = False credentials = dict(username=user, password=password, token=token, remember=remember, remember_token=remember_token) return credentials return dict(username=None, password=None, token=None, remember=False, remember_token=False)
def __init__(self, parent, language=None, cmd='', host='127.0.0.1', port=2084, args='', external=False, configurations={}, **kwargs): super(LSPServerEditor, self).__init__(parent) self.parent = parent self.external = external bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = bbox.button(QDialogButtonBox.Ok) self.button_cancel = bbox.button(QDialogButtonBox.Cancel) self.button_ok.setEnabled(False) description = _('To create a new configuration, ' 'you need to select a programming ' 'language, along with a executable ' 'name for the server to execute ' '(If the instance is local), ' 'and the host and port. Finally, ' 'you need to provide the ' 'arguments that the server accepts. ' 'The placeholders <tt>%(host)s</tt> and ' '<tt>%(port)s</tt> refer to the host ' 'and the port, respectively.') server_settings_description = QLabel(description) server_settings_description.setWordWrap(True) lang_label = QLabel(_('Language:')) self.lang_cb = QComboBox(self) self.lang_cb.setToolTip(_('Programming language provided ' 'by the LSP server')) self.lang_cb.addItem(_('Select a language')) self.lang_cb.addItems(LSP_LANGUAGES) if language is not None: idx = LSP_LANGUAGES.index(language) self.lang_cb.setCurrentIndex(idx + 1) self.button_ok.setEnabled(True) host_label = QLabel(_('Host:')) self.host_input = QLineEdit(self) self.host_input.setToolTip(_('Name of the host that will provide ' 'access to the server')) self.host_input.setText(host) self.host_input.textChanged.connect(lambda x: self.validate()) port_label = QLabel(_('Port:')) self.port_spinner = QSpinBox(self) self.port_spinner.setToolTip(_('TCP port number of the server')) self.port_spinner.setMinimum(1) self.port_spinner.setMaximum(60000) self.port_spinner.setValue(port) cmd_label = QLabel(_('Command to execute:')) self.cmd_input = QLineEdit(self) self.cmd_input.setToolTip(_('Command used to start the ' 'LSP server locally')) self.cmd_input.setText(cmd) if not external: self.cmd_input.textChanged.connect(lambda x: self.validate()) args_label = QLabel(_('Server arguments:')) self.args_input = QLineEdit(self) self.args_input.setToolTip(_('Additional arguments required to ' 'start the server')) self.args_input.setText(args) conf_label = QLabel(_('LSP Server Configurations:')) self.conf_input = CodeEditor(None) self.conf_input.textChanged.connect(self.validate) color_scheme = CONF.get('appearance', 'selected') self.conf_input.setup_editor( language='JSON', color_scheme=color_scheme, wrap=False, edge_line=True, highlight_current_line=True, highlight_current_cell=True, occurrence_highlighting=True, auto_unindent=True, font=get_font(), filename='config.json') self.conf_input.setToolTip(_('Additional LSP server configurations ' 'set at runtime. JSON required')) conf_text = '{}' try: conf_text = json.dumps(configurations, indent=4, sort_keys=True) except Exception: pass self.conf_input.set_text(conf_text) self.json_label = QLabel(self.JSON_VALID, self) self.external_cb = QCheckBox(_('External server'), self) self.external_cb.setToolTip(_('Check if the server runs ' 'on a remote location')) self.external_cb.setChecked(external) self.external_cb.stateChanged.connect(self.set_local_options) hlayout = QHBoxLayout() general_vlayout = QVBoxLayout() general_vlayout.addWidget(server_settings_description) vlayout = QVBoxLayout() lang_layout = QVBoxLayout() lang_layout.addWidget(lang_label) lang_layout.addWidget(self.lang_cb) # layout2 = QHBoxLayout() # layout2.addLayout(lang_layout) lang_layout.addWidget(self.external_cb) vlayout.addLayout(lang_layout) host_layout = QVBoxLayout() host_layout.addWidget(host_label) host_layout.addWidget(self.host_input) port_layout = QVBoxLayout() port_layout.addWidget(port_label) port_layout.addWidget(self.port_spinner) conn_info_layout = QHBoxLayout() conn_info_layout.addLayout(host_layout) conn_info_layout.addLayout(port_layout) vlayout.addLayout(conn_info_layout) cmd_layout = QVBoxLayout() cmd_layout.addWidget(cmd_label) cmd_layout.addWidget(self.cmd_input) vlayout.addLayout(cmd_layout) args_layout = QVBoxLayout() args_layout.addWidget(args_label) args_layout.addWidget(self.args_input) vlayout.addLayout(args_layout) conf_layout = QVBoxLayout() conf_layout.addWidget(conf_label) conf_layout.addWidget(self.conf_input) conf_layout.addWidget(self.json_label) hlayout.addLayout(vlayout) hlayout.addLayout(conf_layout) general_vlayout.addLayout(hlayout) general_vlayout.addWidget(bbox) self.setLayout(general_vlayout) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) self.lang_cb.currentIndexChanged.connect( self.lang_selection_changed) self.form_status(False) if language is not None: self.form_status(True) self.validate()
class LSPServerEditor(QDialog): DEFAULT_HOST = '127.0.0.1' DEFAULT_PORT = 2084 DEFAULT_CMD = '' DEFAULT_ARGS = '' DEFAULT_CONFIGURATION = '{}' DEFAULT_EXTERNAL = False DEFAULT_STDIO = False HOST_REGEX = re.compile(r'^\w+([.]\w+)*$') NON_EMPTY_REGEX = re.compile(r'^\S+$') JSON_VALID = _('Valid JSON') JSON_INVALID = _('Invalid JSON') MIN_SIZE = QSize(850, 600) INVALID_CSS = "QLineEdit {border: 1px solid red;}" VALID_CSS = "QLineEdit {border: 1px solid green;}" def __init__(self, parent, language=None, cmd='', host='127.0.0.1', port=2084, args='', external=False, stdio=False, configurations={}, **kwargs): super(LSPServerEditor, self).__init__(parent) description = _( "To create a new server configuration, you need to select a " "programming language, set the command to start its associated " "server and enter any arguments that should be passed to it on " "startup. Additionally, you can set the server's hostname and " "port if connecting to an external server, " "or to a local one using TCP instead of stdio pipes." "<br><br>" "<i>Note</i>: You can use the placeholders <tt>{host}</tt> and " "<tt>{port}</tt> in the server arguments field to automatically " "fill in the respective values.<br>") self.parent = parent self.external = external # Widgets self.server_settings_description = QLabel(description) self.lang_cb = QComboBox(self) self.external_cb = QCheckBox(_('External server'), self) self.host_label = QLabel(_('Host:')) self.host_input = QLineEdit(self) self.port_label = QLabel(_('Port:')) self.port_spinner = QSpinBox(self) self.cmd_label = QLabel(_('Command:')) self.cmd_input = QLineEdit(self) self.args_label = QLabel(_('Arguments:')) self.args_input = QLineEdit(self) self.json_label = QLabel(self.JSON_VALID, self) self.conf_label = QLabel(_('<b>Server Configuration:</b>')) self.conf_input = CodeEditor(None) self.bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = self.bbox.button(QDialogButtonBox.Ok) self.button_cancel = self.bbox.button(QDialogButtonBox.Cancel) # Widget setup self.setMinimumSize(self.MIN_SIZE) self.setWindowTitle(_('LSP server editor')) self.server_settings_description.setWordWrap(True) self.lang_cb.setToolTip( _('Programming language provided by the LSP server')) self.lang_cb.addItem(_('Select a language')) self.lang_cb.addItems(LSP_LANGUAGES) self.button_ok.setEnabled(False) if language is not None: idx = LSP_LANGUAGES.index(language) self.lang_cb.setCurrentIndex(idx + 1) self.button_ok.setEnabled(True) self.host_input.setPlaceholderText('127.0.0.1') self.host_input.setText(host) self.host_input.textChanged.connect(lambda x: self.validate()) self.port_spinner.setToolTip(_('TCP port number of the server')) self.port_spinner.setMinimum(1) self.port_spinner.setMaximum(60000) self.port_spinner.setValue(port) self.cmd_input.setText(cmd) self.cmd_input.setPlaceholderText('/absolute/path/to/command') self.args_input.setToolTip( _('Additional arguments required to start the server')) self.args_input.setText(args) self.args_input.setPlaceholderText(r'--host {host} --port {port}') self.conf_input.setup_editor(language='json', color_scheme=CONF.get( 'appearance', 'selected'), wrap=False, edge_line=True, highlight_current_line=True, highlight_current_cell=True, occurrence_highlighting=True, auto_unindent=True, font=get_font(), filename='config.json', folding=False) self.conf_input.set_language('json', 'config.json') self.conf_input.setToolTip( _('Additional LSP server configuration ' 'set at runtime. JSON required')) try: conf_text = json.dumps(configurations, indent=4, sort_keys=True) except Exception: conf_text = '{}' self.conf_input.set_text(conf_text) self.external_cb.setToolTip( _('Check if the server runs on a remote location')) self.external_cb.setChecked(external) self.stdio_cb = QCheckBox(_('Use stdio pipes for communication'), self) self.stdio_cb.setToolTip( _('Check if the server communicates ' 'using stdin/out pipes')) self.stdio_cb.setChecked(stdio) # Layout setup hlayout = QHBoxLayout() general_vlayout = QVBoxLayout() general_vlayout.addWidget(self.server_settings_description) vlayout = QVBoxLayout() lang_group = QGroupBox(_('Language')) lang_layout = QVBoxLayout() lang_layout.addWidget(self.lang_cb) lang_group.setLayout(lang_layout) vlayout.addWidget(lang_group) server_group = QGroupBox(_('Language server')) server_layout = QGridLayout() server_layout.addWidget(self.cmd_label, 0, 0) server_layout.addWidget(self.cmd_input, 0, 1) server_layout.addWidget(self.args_label, 1, 0) server_layout.addWidget(self.args_input, 1, 1) server_group.setLayout(server_layout) vlayout.addWidget(server_group) address_group = QGroupBox(_('Server address')) host_layout = QVBoxLayout() host_layout.addWidget(self.host_label) host_layout.addWidget(self.host_input) port_layout = QVBoxLayout() port_layout.addWidget(self.port_label) port_layout.addWidget(self.port_spinner) conn_info_layout = QHBoxLayout() conn_info_layout.addLayout(host_layout) conn_info_layout.addLayout(port_layout) address_group.setLayout(conn_info_layout) vlayout.addWidget(address_group) advanced_group = QGroupBox(_('Advanced')) advanced_layout = QVBoxLayout() advanced_layout.addWidget(self.external_cb) advanced_layout.addWidget(self.stdio_cb) advanced_group.setLayout(advanced_layout) vlayout.addWidget(advanced_group) conf_layout = QVBoxLayout() conf_layout.addWidget(self.conf_label) conf_layout.addWidget(self.conf_input) conf_layout.addWidget(self.json_label) vlayout.addStretch() hlayout.addLayout(vlayout, 2) hlayout.addLayout(conf_layout, 3) general_vlayout.addLayout(hlayout) general_vlayout.addWidget(self.bbox) self.setLayout(general_vlayout) self.form_status(False) # Signals if not external: self.cmd_input.textChanged.connect(lambda x: self.validate()) self.external_cb.stateChanged.connect(self.set_local_options) self.stdio_cb.stateChanged.connect(self.set_stdio_options) self.lang_cb.currentIndexChanged.connect(self.lang_selection_changed) self.conf_input.textChanged.connect(self.validate) self.bbox.accepted.connect(self.accept) self.bbox.rejected.connect(self.reject) # Final setup if language is not None: self.form_status(True) self.validate() if stdio: self.set_stdio_options(True) if external: self.set_local_options(True) @Slot() def validate(self): host_text = self.host_input.text() cmd_text = self.cmd_input.text() if not self.HOST_REGEX.match(host_text): self.button_ok.setEnabled(False) self.host_input.setStyleSheet(self.INVALID_CSS) if bool(host_text): self.host_input.setToolTip(_('Hostname must be valid')) else: self.host_input.setToolTip( _('Hostname or IP address of the host on which the server ' 'is running. Must be non empty.')) else: self.host_input.setStyleSheet(self.VALID_CSS) self.host_input.setToolTip(_('Hostname is valid')) self.button_ok.setEnabled(True) if not self.external: if not self.NON_EMPTY_REGEX.match(cmd_text): self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet(self.INVALID_CSS) self.cmd_input.setToolTip( _('Command used to start the LSP server locally. Must be ' 'non empty')) return if find_program(cmd_text) is None: self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet(self.INVALID_CSS) self.cmd_input.setToolTip( _('Program was not found ' 'on your system')) else: self.cmd_input.setStyleSheet(self.VALID_CSS) self.cmd_input.setToolTip( _('Program was found on your ' 'system')) self.button_ok.setEnabled(True) try: json.loads(self.conf_input.toPlainText()) try: self.json_label.setText(self.JSON_VALID) except Exception: pass except ValueError: try: self.json_label.setText(self.JSON_INVALID) self.button_ok.setEnabled(False) except Exception: pass def form_status(self, status): self.host_input.setEnabled(status) self.port_spinner.setEnabled(status) self.external_cb.setEnabled(status) self.stdio_cb.setEnabled(status) self.cmd_input.setEnabled(status) self.args_input.setEnabled(status) self.conf_input.setEnabled(status) self.json_label.setVisible(status) @Slot() def lang_selection_changed(self): idx = self.lang_cb.currentIndex() if idx == 0: self.set_defaults() self.form_status(False) self.button_ok.setEnabled(False) else: server = self.parent.get_server_by_lang(LSP_LANGUAGES[idx - 1]) self.form_status(True) if server is not None: self.host_input.setText(server.host) self.port_spinner.setValue(server.port) self.external_cb.setChecked(server.external) self.stdio_cb.setChecked(server.stdio) self.cmd_input.setText(server.cmd) self.args_input.setText(server.args) self.conf_input.set_text(json.dumps(server.configurations)) self.json_label.setText(self.JSON_VALID) self.button_ok.setEnabled(True) else: self.set_defaults() def set_defaults(self): self.cmd_input.setStyleSheet('') self.host_input.setStyleSheet('') self.host_input.setText(self.DEFAULT_HOST) self.port_spinner.setValue(self.DEFAULT_PORT) self.external_cb.setChecked(self.DEFAULT_EXTERNAL) self.stdio_cb.setChecked(self.DEFAULT_STDIO) self.cmd_input.setText(self.DEFAULT_CMD) self.args_input.setText(self.DEFAULT_ARGS) self.conf_input.set_text(self.DEFAULT_CONFIGURATION) self.json_label.setText(self.JSON_VALID) @Slot(bool) @Slot(int) def set_local_options(self, enabled): self.external = enabled self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) if enabled: self.cmd_input.setEnabled(False) self.cmd_input.setStyleSheet('') self.args_input.setEnabled(False) self.stdio_cb.stateChanged.disconnect() self.stdio_cb.setChecked(False) self.stdio_cb.setEnabled(False) else: self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) self.stdio_cb.setEnabled(True) self.stdio_cb.setChecked(False) self.stdio_cb.stateChanged.connect(self.set_stdio_options) try: self.validate() except Exception: pass @Slot(bool) @Slot(int) def set_stdio_options(self, enabled): self.stdio = enabled if enabled: self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) self.external_cb.stateChanged.disconnect() self.external_cb.setChecked(False) self.external_cb.setEnabled(False) self.host_input.setStyleSheet('') self.host_input.setEnabled(False) self.port_spinner.setEnabled(False) else: self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) self.external_cb.setChecked(False) self.external_cb.setEnabled(True) self.external_cb.stateChanged.connect(self.set_local_options) self.host_input.setEnabled(True) self.port_spinner.setEnabled(True) try: self.validate() except Exception: pass def get_options(self): language_idx = self.lang_cb.currentIndex() language = LSP_LANGUAGES[language_idx - 1] host = self.host_input.text() port = int(self.port_spinner.value()) external = self.external_cb.isChecked() stdio = self.stdio_cb.isChecked() args = self.args_input.text() cmd = self.cmd_input.text() configurations = json.loads(self.conf_input.toPlainText()) server = LSPServer(language=language.lower(), cmd=cmd, args=args, host=host, port=port, external=external, stdio=stdio, configurations=configurations) return server
def __init__(self, parent, enable_replace=False): QWidget.__init__(self, parent) self.enable_replace = enable_replace self.editor = None self.is_code_editor = None glayout = QGridLayout() glayout.setContentsMargins(0, 0, 0, 0) self.setLayout(glayout) self.close_button = create_toolbutton(self, triggered=self.hide, icon=ima.icon('DialogCloseButton')) glayout.addWidget(self.close_button, 0, 0) # Find layout self.search_text = PatternComboBox(self, tip=_("Search string"), adjust_to_minimum=False) self.search_text.valid.connect( lambda state: self.find(changed=False, forward=True, rehighlight=False)) self.search_text.lineEdit().textEdited.connect( self.text_has_been_edited) self.previous_button = create_toolbutton(self, triggered=self.find_previous, icon=ima.icon('ArrowUp')) self.next_button = create_toolbutton(self, triggered=self.find_next, icon=ima.icon('ArrowDown')) self.next_button.clicked.connect(self.update_search_combo) self.previous_button.clicked.connect(self.update_search_combo) self.re_button = create_toolbutton(self, icon=ima.icon('advanced'), tip=_("Regular expression")) self.re_button.setCheckable(True) self.re_button.toggled.connect(lambda state: self.find()) self.case_button = create_toolbutton(self, icon=get_icon("upper_lower.png"), tip=_("Case Sensitive")) self.case_button.setCheckable(True) self.case_button.toggled.connect(lambda state: self.find()) self.words_button = create_toolbutton(self, icon=get_icon("whole_words.png"), tip=_("Whole words")) self.words_button.setCheckable(True) self.words_button.toggled.connect(lambda state: self.find()) self.highlight_button = create_toolbutton(self, icon=get_icon("highlight.png"), tip=_("Highlight matches")) self.highlight_button.setCheckable(True) self.highlight_button.toggled.connect(self.toggle_highlighting) hlayout = QHBoxLayout() self.widgets = [self.close_button, self.search_text, self.previous_button, self.next_button, self.re_button, self.case_button, self.words_button, self.highlight_button] for widget in self.widgets[1:]: hlayout.addWidget(widget) glayout.addLayout(hlayout, 0, 1) # Replace layout replace_with = QLabel(_("Replace with:")) self.replace_text = PatternComboBox(self, adjust_to_minimum=False, tip=_('Replace string')) self.replace_button = create_toolbutton(self, text=_('Replace/find'), icon=ima.icon('DialogApplyButton'), triggered=self.replace_find, text_beside_icon=True) self.replace_button.clicked.connect(self.update_replace_combo) self.replace_button.clicked.connect(self.update_search_combo) self.all_check = QCheckBox(_("Replace all")) self.replace_layout = QHBoxLayout() widgets = [replace_with, self.replace_text, self.replace_button, self.all_check] for widget in widgets: self.replace_layout.addWidget(widget) glayout.addLayout(self.replace_layout, 1, 1) self.widgets.extend(widgets) self.replace_widgets = widgets self.hide_replace() self.search_text.setTabOrder(self.search_text, self.replace_text) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.shortcuts = self.create_shortcuts(parent) self.highlight_timer = QTimer(self) self.highlight_timer.setSingleShot(True) self.highlight_timer.setInterval(1000) self.highlight_timer.timeout.connect(self.highlight_matches)
class WndComputeRoiMaps(SecondaryWindow): # Signal that is sent (to main window) to update global state of the program update_global_state = Signal() computations_complete = Signal(object) signal_roi_computation_complete = Signal() signal_activate_tab_xrf_maps = Signal() def __init__(self, *, gpc, gui_vars): super().__init__() # Global processing classes self.gpc = gpc # Global GUI variables (used for control of GUI state) self.gui_vars = gui_vars # Reference to the main window. The main window will hold # references to all non-modal windows that could be opened # from multiple places in the program. self.ref_main_window = self.gui_vars["ref_main_window"] self.update_global_state.connect( self.ref_main_window.update_widget_state) self.initialize() def initialize(self): self.setWindowTitle("PyXRF: Compute XRF Maps Based on ROIs") self.setMinimumWidth(600) self.setMinimumHeight(300) self.resize(600, 600) header_vbox = self._setup_header() self._setup_table() footer_hbox = self._setup_footer() vbox = QVBoxLayout() vbox.addLayout(header_vbox) vbox.addWidget(self.table) vbox.addLayout(footer_hbox) self.setLayout(vbox) self._set_tooltips() def _setup_header(self): self.pb_clear = QPushButton("Clear") self.pb_clear.clicked.connect(self.pb_clear_clicked) self.pb_use_lines_for_fitting = QPushButton( "Use Lines Selected For Fitting") self.pb_use_lines_for_fitting.clicked.connect( self.pb_use_lines_for_fitting_clicked) self.le_sel_emission_lines = LineEditExtended() self.le_sel_emission_lines.textChanged.connect( self.le_sel_emission_lines_text_changed) self.le_sel_emission_lines.editingFinished.connect( self.le_sel_emission_lines_editing_finished) sample_elements = "" self.le_sel_emission_lines.setText(sample_elements) vbox = QVBoxLayout() hbox = QHBoxLayout() hbox.addWidget(QLabel("Enter emission lines, e.g. Fe_K, Gd_L ")) hbox.addStretch(1) hbox.addWidget(self.pb_clear) hbox.addWidget(self.pb_use_lines_for_fitting) vbox.addLayout(hbox) vbox.addWidget(self.le_sel_emission_lines) return vbox def _setup_table(self): # Labels for horizontal header self.tbl_labels = ["Line", "E, keV", "ROI, keV", "Show", "Reset"] # The list of columns that stretch with the table self.tbl_cols_stretch = ("E, keV", "ROI, keV") # Table item representation if different from default self.tbl_format = {"E, keV": ".3f"} # Editable items (highlighted with lighter background) self.tbl_cols_editable = {"ROI, keV"} # Columns that contain Range Manager self.tbl_cols_range_manager = ("ROI, keV", ) self.table = QTableWidget() self.table.setColumnCount(len(self.tbl_labels)) self.table.setHorizontalHeaderLabels(self.tbl_labels) self.table.verticalHeader().hide() self.table.setSelectionMode(QTableWidget.NoSelection) self.table.setStyleSheet("QTableWidget::item{color: black;}") header = self.table.horizontalHeader() for n, lbl in enumerate(self.tbl_labels): # Set stretching for the columns if lbl in self.tbl_cols_stretch: header.setSectionResizeMode(n, QHeaderView.Stretch) else: header.setSectionResizeMode(n, QHeaderView.ResizeToContents) self._table_contents = [] self.cb_list = [] self.range_manager_list = [] self.pb_default_list = [] self.fill_table(self._table_contents) def fill_table(self, table_contents): self.table.clearContents() self._table_contents = table_contents # Save new table contents for item in self.range_manager_list: item.selection_changed.disconnect( self.range_manager_selection_changed) self.range_manager_list = [] for cb in self.cb_list: cb.stateChanged.disconnect(self.cb_state_changed) self.cb_list = [] for pb in self.pb_default_list: pb.clicked.connect(self.pb_default_clicked) self.pb_default_list = [] self.table.setRowCount(len(table_contents)) for nr, row in enumerate(table_contents): eline_name = row["eline"] + "a1" energy = row["energy_center"] energy_left = row["energy_left"] energy_right = row["energy_right"] range_displayed = row["range_displayed"] table_row = [eline_name, energy, (energy_left, energy_right)] for nc, entry in enumerate(table_row): label = self.tbl_labels[nc] # Set alternating background colors for the table rows # Make background for editable items a little brighter brightness = 240 if label in self.tbl_cols_editable else 220 if nr % 2: rgb_bckg = (255, brightness, brightness) else: rgb_bckg = (brightness, 255, brightness) if self.tbl_labels[nc] not in self.tbl_cols_range_manager: if self.tbl_labels[nc] in self.tbl_format: fmt = self.tbl_format[self.tbl_labels[nc]] s = ("{:" + fmt + "}").format(entry) else: s = f"{entry}" item = QTableWidgetItem(s) if nc > 0: item.setTextAlignment(Qt.AlignCenter) else: item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) # Set all columns not editable (unless needed) item.setFlags(item.flags() & ~Qt.ItemIsEditable) # Note, that there is no way to set style sheet for QTableWidgetItem item.setBackground(QBrush(QColor(*rgb_bckg))) self.table.setItem(nr, nc, item) else: spin_name = f"{nr}" item = RangeManager(name=spin_name, add_sliders=False, selection_to_range_min=0.0001) item.set_range( 0.0, 100.0) # The range is greater than needed (in keV) item.set_selection(value_low=entry[0], value_high=entry[1]) item.setTextColor((0, 0, 0)) # In case of dark theme item.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.range_manager_list.append(item) item.selection_changed.connect( self.range_manager_selection_changed) color = (rgb_bckg[0], rgb_bckg[1], rgb_bckg[2]) item.setBackground(color) self.table.setCellWidget(nr, nc, item) brightness = 220 if nr % 2: rgb_bckg = (255, brightness, brightness) else: rgb_bckg = (brightness, 255, brightness) item = QWidget() cb = CheckBoxNamed(name=f"{nr}") cb.setChecked(Qt.Checked if range_displayed else Qt.Unchecked) self.cb_list.append(cb) cb.stateChanged.connect(self.cb_state_changed) item_hbox = QHBoxLayout(item) item_hbox.addWidget(cb) item_hbox.setAlignment(Qt.AlignCenter) item_hbox.setContentsMargins(0, 0, 0, 0) color_css = f"rgb({rgb_bckg[0]}, {rgb_bckg[1]}, {rgb_bckg[2]})" item.setStyleSheet( f"QWidget {{ background-color: {color_css}; }} " f"QCheckBox {{ color: black; background-color: white }}") self.table.setCellWidget(nr, nc + 1, item) item = PushButtonNamed("Reset", name=f"{nr}") item.clicked.connect(self.pb_default_clicked) self.pb_default_list.append(item) rgb_bckg = [_ - 35 if (_ < 255) else _ for _ in rgb_bckg] color_css = f"rgb({rgb_bckg[0]}, {rgb_bckg[1]}, {rgb_bckg[2]})" item.setStyleSheet( f"QPushButton {{ color: black; background-color: {color_css}; }}" ) self.table.setCellWidget(nr, nc + 2, item) def _setup_footer(self): self.cb_subtract_baseline = QCheckBox("Subtract baseline") self.cb_subtract_baseline.setChecked( Qt.Checked if self.gpc.get_roi_subtract_background( ) else Qt.Unchecked) self.cb_subtract_baseline.toggled.connect( self.cb_subtract_baseline_toggled) self.pb_compute_roi = QPushButton("Compute ROIs") self.pb_compute_roi.clicked.connect(self.pb_compute_roi_clicked) hbox = QHBoxLayout() hbox.addWidget(self.cb_subtract_baseline) hbox.addStretch(1) hbox.addWidget(self.pb_compute_roi) return hbox def _set_tooltips(self): set_tooltip(self.pb_clear, "<b>Clear</b> the list") set_tooltip( self.pb_use_lines_for_fitting, "Copy the contents of <b>the list of emission lines selected for fitting</b> to the list of ROIs", ) set_tooltip( self.le_sel_emission_lines, "The list of <b>emission lines</b> selected for ROI computation.") set_tooltip(self.table, "The list of ROIs") set_tooltip( self.cb_subtract_baseline, "<b>Subtract baseline</b> from the pixel spectra before computing ROIs. " "Subtracting baseline slows down computations and usually have no benefit. " "In most cases it should remain <b>unchecked</b>.", ) set_tooltip( self.pb_compute_roi, "<b>Run</b> computations of the ROIs. The resulting <b>ROI</b> dataset " "may be viewed in <b>XRF Maps</b> tab.", ) def update_widget_state(self, condition=None): # Update the state of the menu bar state = not self.gui_vars["gui_state"]["running_computations"] self.setEnabled(state) # Hide the window if required by the program state state_file_loaded = self.gui_vars["gui_state"]["state_file_loaded"] state_model_exist = self.gui_vars["gui_state"]["state_model_exists"] if not state_file_loaded or not state_model_exist: self.hide() if condition == "tooltips": self._set_tooltips() def pb_clear_clicked(self): self.gpc.clear_roi_element_list() self._update_displayed_element_list() self._validate_element_list() def pb_use_lines_for_fitting_clicked(self): self.gpc.load_roi_element_list_from_selected() self._update_displayed_element_list() self._validate_element_list() def le_sel_emission_lines_text_changed(self, text): self._validate_element_list(text) def le_sel_emission_lines_editing_finished(self): text = self.le_sel_emission_lines.text() if self._validate_element_list(text): self.gpc.set_roi_selected_element_list(text) self._update_table() else: element_list = self.gpc.get_roi_selected_element_list() self.le_sel_emission_lines.setText(element_list) def cb_subtract_baseline_toggled(self, state): self.gpc.set_roi_subtract_background(bool(state)) def cb_state_changed(self, name, state): try: nr = int(name) # Row number checked = state == Qt.Checked eline = self._table_contents[nr]["eline"] self._table_contents[nr]["range_displayed"] = checked self.gpc.show_roi(eline, checked) except Exception as ex: logger.error( f"Failed to process selection change. Exception occurred: {ex}." ) def _find_spin_box(self, name): for item in self.spin_list: if item.getName() == name: return item return None def spin_value_changed(self, name, value): try: nr, side = name.split(",") nr = int(nr) keys = {"left": "energy_left", "right": "energy_right"} side = keys[side] eline = self._table_contents[nr]["eline"] if self._table_contents[nr][side] == value: return if side == "energy_left": # Left boundary if value < self._table_contents[nr]["energy_right"]: self._table_contents[nr][side] = value else: # Right boundary if value > self._table_contents[nr]["energy_left"]: self._table_contents[nr][side] = value # Update plot left, right = self._table_contents[nr][ "energy_left"], self._table_contents[nr]["energy_right"] self.gpc.change_roi(eline, left, right) except Exception as ex: logger.error( f"Failed to change the ROI. Exception occurred: {ex}.") def range_manager_selection_changed(self, left, right, name): try: nr = int(name) eline = self._table_contents[nr]["eline"] self.gpc.change_roi(eline, left, right) except Exception as ex: logger.error( f"Failed to change the ROI. Exception occurred: {ex}.") def pb_default_clicked(self, name): try: nr = int(name) eline = self._table_contents[nr]["eline"] left = self._table_contents[nr]["energy_left_default"] right = self._table_contents[nr]["energy_right_default"] self.range_manager_list[nr].set_selection(value_low=left, value_high=right) self.gpc.change_roi(eline, left, right) except Exception as ex: logger.error( f"Failed to change the ROI. Exception occurred: {ex}.") def pb_compute_roi_clicked(self): def cb(): try: self.gpc.compute_rois() success, msg = True, "" except Exception as ex: success, msg = False, str(ex) return {"success": success, "msg": msg} self._compute_in_background(cb, self.slot_compute_roi_clicked) @Slot(object) def slot_compute_roi_clicked(self, result): self._recover_after_compute(self.slot_compute_roi_clicked) success = result["success"] if success: self.gui_vars["gui_state"]["state_xrf_map_exists"] = True else: msg = result["msg"] msgbox = QMessageBox(QMessageBox.Critical, "Failed to Compute ROIs", msg, QMessageBox.Ok, parent=self) msgbox.exec() self.signal_roi_computation_complete.emit() self.update_global_state.emit() if success: self.signal_activate_tab_xrf_maps.emit() def _update_displayed_element_list(self): element_list = self.gpc.get_roi_selected_element_list() self.le_sel_emission_lines.setText(element_list) self._validate_element_list() self._update_table() def _update_table(self): table_contents = self.gpc.get_roi_settings() self.fill_table(table_contents) def _validate_element_list(self, text=None): if text is None: text = self.le_sel_emission_lines.text() el_list = text.split(",") el_list = [_.strip() for _ in el_list] if el_list == [""]: el_list = [] valid = bool(len(el_list)) for eline in el_list: if self.gpc.get_eline_name_category(eline) != "eline": valid = False self.le_sel_emission_lines.setValid(valid) self.pb_compute_roi.setEnabled(valid) return valid def _compute_in_background(self, func, slot, *args, **kwargs): """ Run function `func` in a background thread. Send the signal `self.computations_complete` once computation is finished. Parameters ---------- func: function Reference to a function that is supposed to be executed at the background. The function return value is passed as a signal parameter once computation is complete. slot: qtpy.QtCore.Slot or None Reference to a slot. If not None, then the signal `self.computation_complete` is connected to this slot. args, kwargs arguments of the function `func`. """ signal_complete = self.computations_complete def func_to_run(func, *args, **kwargs): class LoadFile(QRunnable): def run(self): result_dict = func(*args, **kwargs) signal_complete.emit(result_dict) return LoadFile() if slot is not None: self.computations_complete.connect(slot) self.gui_vars["gui_state"]["running_computations"] = True self.update_global_state.emit() QThreadPool.globalInstance().start(func_to_run(func, *args, **kwargs)) def _recover_after_compute(self, slot): """ The function should be called after the signal `self.computations_complete` is received. The slot should be the same as the one used when calling `self.compute_in_background`. """ if slot is not None: self.computations_complete.disconnect(slot) self.gui_vars["gui_state"]["running_computations"] = False self.update_global_state.emit()
class RunConfigOptions(QWidget): """Run configuration options""" def __init__(self, parent=None): QWidget.__init__(self, parent) self.dir = None self.runconf = RunConfiguration() firstrun_o = CONF.get('run', ALWAYS_OPEN_FIRST_RUN_OPTION, False) # --- Interpreter --- interpreter_group = QGroupBox(_("Console")) interpreter_layout = QVBoxLayout() interpreter_group.setLayout(interpreter_layout) self.current_radio = QRadioButton(CURRENT_INTERPRETER) interpreter_layout.addWidget(self.current_radio) self.dedicated_radio = QRadioButton(DEDICATED_INTERPRETER) interpreter_layout.addWidget(self.dedicated_radio) self.systerm_radio = QRadioButton(SYSTERM_INTERPRETER) interpreter_layout.addWidget(self.systerm_radio) # --- General settings ---- common_group = QGroupBox(_("General settings")) common_layout = QGridLayout() common_group.setLayout(common_layout) self.clear_var_cb = QCheckBox(CLEAR_ALL_VARIABLES) common_layout.addWidget(self.clear_var_cb, 0, 0) self.post_mortem_cb = QCheckBox(POST_MORTEM) common_layout.addWidget(self.post_mortem_cb, 1, 0) self.clo_cb = QCheckBox(_("Command line options:")) common_layout.addWidget(self.clo_cb, 2, 0) self.clo_edit = QLineEdit() self.clo_cb.toggled.connect(self.clo_edit.setEnabled) self.clo_edit.setEnabled(False) common_layout.addWidget(self.clo_edit, 2, 1) # --- Working directory --- wdir_group = QGroupBox(_("Working Directory settings")) wdir_layout = QVBoxLayout() wdir_group.setLayout(wdir_layout) self.file_dir_radio = QRadioButton(FILE_DIR) wdir_layout.addWidget(self.file_dir_radio) self.cwd_radio = QRadioButton(CW_DIR) wdir_layout.addWidget(self.cwd_radio) fixed_dir_layout = QHBoxLayout() self.fixed_dir_radio = QRadioButton(FIXED_DIR) fixed_dir_layout.addWidget(self.fixed_dir_radio) self.wd_edit = QLineEdit() self.fixed_dir_radio.toggled.connect(self.wd_edit.setEnabled) self.wd_edit.setEnabled(False) fixed_dir_layout.addWidget(self.wd_edit) browse_btn = QPushButton(ima.icon('DirOpenIcon'), '', self) browse_btn.setToolTip(_("Select directory")) browse_btn.clicked.connect(self.select_directory) fixed_dir_layout.addWidget(browse_btn) wdir_layout.addLayout(fixed_dir_layout) # --- System terminal --- external_group = QGroupBox(_("External system terminal")) external_group.setDisabled(True) self.systerm_radio.toggled.connect(external_group.setEnabled) external_layout = QGridLayout() external_group.setLayout(external_layout) self.interact_cb = QCheckBox(INTERACT) external_layout.addWidget(self.interact_cb, 1, 0, 1, -1) self.pclo_cb = QCheckBox(_("Command line options:")) external_layout.addWidget(self.pclo_cb, 3, 0) self.pclo_edit = QLineEdit() self.pclo_cb.toggled.connect(self.pclo_edit.setEnabled) self.pclo_edit.setEnabled(False) self.pclo_edit.setToolTip(_("<b>-u</b> is added to the " "other options you set here")) external_layout.addWidget(self.pclo_edit, 3, 1) # Checkbox to preserve the old behavior, i.e. always open the dialog # on first run hline = QFrame() hline.setFrameShape(QFrame.HLine) hline.setFrameShadow(QFrame.Sunken) self.firstrun_cb = QCheckBox(ALWAYS_OPEN_FIRST_RUN % _("this dialog")) self.firstrun_cb.clicked.connect(self.set_firstrun_o) self.firstrun_cb.setChecked(firstrun_o) layout = QVBoxLayout() layout.addWidget(interpreter_group) layout.addWidget(common_group) layout.addWidget(wdir_group) layout.addWidget(external_group) layout.addWidget(hline) layout.addWidget(self.firstrun_cb) self.setLayout(layout) def select_directory(self): """Select directory""" basedir = to_text_string(self.wd_edit.text()) if not osp.isdir(basedir): basedir = getcwd_or_home() directory = getexistingdirectory(self, _("Select directory"), basedir) if directory: self.wd_edit.setText(directory) self.dir = directory def set(self, options): self.runconf.set(options) self.clo_cb.setChecked(self.runconf.args_enabled) self.clo_edit.setText(self.runconf.args) if self.runconf.current: self.current_radio.setChecked(True) elif self.runconf.systerm: self.systerm_radio.setChecked(True) else: self.dedicated_radio.setChecked(True) self.interact_cb.setChecked(self.runconf.interact) self.post_mortem_cb.setChecked(self.runconf.post_mortem) self.pclo_cb.setChecked(self.runconf.python_args_enabled) self.pclo_edit.setText(self.runconf.python_args) self.clear_var_cb.setChecked(self.runconf.clear_namespace) self.file_dir_radio.setChecked(self.runconf.file_dir) self.cwd_radio.setChecked(self.runconf.cw_dir) self.fixed_dir_radio.setChecked(self.runconf.fixed_dir) self.dir = self.runconf.dir self.wd_edit.setText(self.dir) def get(self): self.runconf.args_enabled = self.clo_cb.isChecked() self.runconf.args = to_text_string(self.clo_edit.text()) self.runconf.current = self.current_radio.isChecked() self.runconf.systerm = self.systerm_radio.isChecked() self.runconf.interact = self.interact_cb.isChecked() self.runconf.post_mortem = self.post_mortem_cb.isChecked() self.runconf.python_args_enabled = self.pclo_cb.isChecked() self.runconf.python_args = to_text_string(self.pclo_edit.text()) self.runconf.clear_namespace = self.clear_var_cb.isChecked() self.runconf.file_dir = self.file_dir_radio.isChecked() self.runconf.cw_dir = self.cwd_radio.isChecked() self.runconf.fixed_dir = self.fixed_dir_radio.isChecked() self.runconf.dir = self.wd_edit.text() return self.runconf.get() def is_valid(self): wdir = to_text_string(self.wd_edit.text()) if not self.fixed_dir_radio.isChecked() or osp.isdir(wdir): return True else: QMessageBox.critical(self, _("Run configuration"), _("The following working directory is " "not valid:<br><b>%s</b>") % wdir) return False def set_firstrun_o(self): CONF.set('run', ALWAYS_OPEN_FIRST_RUN_OPTION, self.firstrun_cb.isChecked())
def __init__(self, parent, language=None, cmd='', host='127.0.0.1', port=2084, args='', external=False, configurations={}, **kwargs): super(LSPServerEditor, self).__init__(parent) self.parent = parent self.external = external bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = bbox.button(QDialogButtonBox.Ok) self.button_cancel = bbox.button(QDialogButtonBox.Cancel) self.button_ok.setEnabled(False) description = _('To create a new configuration, ' 'you need to select a programming ' 'language, along with a executable ' 'name for the server to execute ' '(If the instance is local), ' 'and the host and port. Finally, ' 'you need to provide the ' 'arguments that the server accepts. ' 'The placeholders <tt>%(host)s</tt> and ' '<tt>%(port)s</tt> refer to the host ' 'and the port, respectively.') server_settings_description = QLabel(description) server_settings_description.setWordWrap(True) lang_label = QLabel(_('Language:')) self.lang_cb = QComboBox(self) self.lang_cb.setToolTip( _('Programming language provided ' 'by the LSP server')) self.lang_cb.addItem(_('Select a language')) self.lang_cb.addItems(LSP_LANGUAGES) if language is not None: idx = LSP_LANGUAGES.index(language) self.lang_cb.setCurrentIndex(idx + 1) self.button_ok.setEnabled(True) host_label = QLabel(_('Host:')) self.host_input = QLineEdit(self) self.host_input.setToolTip( _('Name of the host that will provide ' 'access to the server')) self.host_input.setText(host) self.host_input.textChanged.connect(lambda x: self.validate()) port_label = QLabel(_('Port:')) self.port_spinner = QSpinBox(self) self.port_spinner.setToolTip(_('TCP port number of the server')) self.port_spinner.setMinimum(1) self.port_spinner.setMaximum(60000) self.port_spinner.setValue(port) cmd_label = QLabel(_('Command to execute:')) self.cmd_input = QLineEdit(self) self.cmd_input.setToolTip( _('Command used to start the ' 'LSP server locally')) self.cmd_input.setText(cmd) if not external: self.cmd_input.textChanged.connect(lambda x: self.validate()) args_label = QLabel(_('Server arguments:')) self.args_input = QLineEdit(self) self.args_input.setToolTip( _('Additional arguments required to ' 'start the server')) self.args_input.setText(args) conf_label = QLabel(_('LSP Server Configurations:')) self.conf_input = CodeEditor(None) self.conf_input.textChanged.connect(self.validate) color_scheme = CONF.get('appearance', 'selected') self.conf_input.setup_editor(language='JSON', color_scheme=color_scheme, wrap=False, edge_line=True, highlight_current_line=True, highlight_current_cell=True, occurrence_highlighting=True, auto_unindent=True, font=get_font(), filename='config.json') self.conf_input.setToolTip( _('Additional LSP server configurations ' 'set at runtime. JSON required')) conf_text = '{}' try: conf_text = json.dumps(configurations, indent=4, sort_keys=True) except Exception: pass self.conf_input.set_text(conf_text) self.json_label = QLabel(self.JSON_VALID, self) self.external_cb = QCheckBox(_('External server'), self) self.external_cb.setToolTip( _('Check if the server runs ' 'on a remote location')) self.external_cb.setChecked(external) self.external_cb.stateChanged.connect(self.set_local_options) hlayout = QHBoxLayout() general_vlayout = QVBoxLayout() general_vlayout.addWidget(server_settings_description) vlayout = QVBoxLayout() lang_layout = QVBoxLayout() lang_layout.addWidget(lang_label) lang_layout.addWidget(self.lang_cb) # layout2 = QHBoxLayout() # layout2.addLayout(lang_layout) lang_layout.addWidget(self.external_cb) vlayout.addLayout(lang_layout) host_layout = QVBoxLayout() host_layout.addWidget(host_label) host_layout.addWidget(self.host_input) port_layout = QVBoxLayout() port_layout.addWidget(port_label) port_layout.addWidget(self.port_spinner) conn_info_layout = QHBoxLayout() conn_info_layout.addLayout(host_layout) conn_info_layout.addLayout(port_layout) vlayout.addLayout(conn_info_layout) cmd_layout = QVBoxLayout() cmd_layout.addWidget(cmd_label) cmd_layout.addWidget(self.cmd_input) vlayout.addLayout(cmd_layout) args_layout = QVBoxLayout() args_layout.addWidget(args_label) args_layout.addWidget(self.args_input) vlayout.addLayout(args_layout) conf_layout = QVBoxLayout() conf_layout.addWidget(conf_label) conf_layout.addWidget(self.conf_input) conf_layout.addWidget(self.json_label) hlayout.addLayout(vlayout) hlayout.addLayout(conf_layout) general_vlayout.addLayout(hlayout) general_vlayout.addWidget(bbox) self.setLayout(general_vlayout) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) self.lang_cb.currentIndexChanged.connect(self.lang_selection_changed) self.form_status(False) if language is not None: self.form_status(True) self.validate()
def add_new_row(self, _metadata, row=0): self.main_window.postprocessing_ui.table.insertRow(row) _layout = QHBoxLayout() _widget = QCheckBox() _widget.setEnabled(True) _layout.addWidget(_widget) _layout.addStretch() _new_widget = QWidget() _new_widget.setLayout(_layout) _widget.stateChanged.connect(lambda state=0, row=row: self.parent.table_select_state_changed(state, row)) self.main_window_postprocessing_ui.table.setCellWidget(row, 0, _new_widget) _item = QTableWidgetItem(_metadata['name']) self.main_window_postprocessing_ui.table.setItem(row, 1, _item) _item = QTableWidgetItem(_metadata['runs']) self.main_window_postprocessing_ui.table.setItem(row, 2, _item) if not _metadata['sample_formula']: _item = QTableWidgetItem(_metadata['sample_formula']) self.main_window_postprocessing_ui.table.setItem(row, 3, _item) if not _metadata['mass_density']: _item = QTableWidgetItem(_metadata['mass_density']) self.main_window_postprocessing_ui.table.setItem(row, 4, _item) if not _metadata['radius']: _item = QTableWidgetItem(_metadata['radius']) self.main_window_postprocessing_ui.table.setItem(row, 5, _item) if not _metadata['packing_fraction']: _item = QTableWidgetItem(_metadata['packing_fraction']) self.main_window_postprocessing_ui.table.setItem(row, 6, _item) _widget = QComboBox() _widget.addItem("cylindrical") _widget.addItem("spherical") if _metadata['sample_shape'] == 'spherical': _widget.setCurrentIndex(1) self.main_window_postprocessing_ui.table.setCellWidget(row, 7, _widget) _layout = QHBoxLayout() _widget = QCheckBox() if _metadata['do_abs_correction'] == 'go': _widget.setCheckState(Qt.Checked) _widget.setStyleSheet("border: 2px; solid-black") _widget.setEnabled(True) _layout.addStretch() _layout.addWidget(_widget) _layout.addStretch() _new_widget = QWidget() _new_widget.setLayout(_layout) self.main_window_postprocessing_ui.table.setCellWidget(row, 8, _new_widget)
class LSPServerEditor(QDialog): DEFAULT_HOST = '127.0.0.1' DEFAULT_PORT = 2084 DEFAULT_CMD = '' DEFAULT_ARGS = '' DEFAULT_CONFIGURATION = '{}' DEFAULT_EXTERNAL = False HOST_REGEX = re.compile(r'^\w+([.]\w+)*$') NON_EMPTY_REGEX = re.compile(r'^\S+$') JSON_VALID = _('JSON valid') JSON_INVALID = _('JSON invalid') def __init__(self, parent, language=None, cmd='', host='127.0.0.1', port=2084, args='', external=False, configurations={}, **kwargs): super(LSPServerEditor, self).__init__(parent) self.parent = parent self.external = external bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = bbox.button(QDialogButtonBox.Ok) self.button_cancel = bbox.button(QDialogButtonBox.Cancel) self.button_ok.setEnabled(False) description = _('To create a new configuration, ' 'you need to select a programming ' 'language, along with a executable ' 'name for the server to execute ' '(If the instance is local), ' 'and the host and port. Finally, ' 'you need to provide the ' 'arguments that the server accepts. ' 'The placeholders <tt>%(host)s</tt> and ' '<tt>%(port)s</tt> refer to the host ' 'and the port, respectively.') server_settings_description = QLabel(description) server_settings_description.setWordWrap(True) lang_label = QLabel(_('Language:')) self.lang_cb = QComboBox(self) self.lang_cb.setToolTip( _('Programming language provided ' 'by the LSP server')) self.lang_cb.addItem(_('Select a language')) self.lang_cb.addItems(LSP_LANGUAGES) if language is not None: idx = LSP_LANGUAGES.index(language) self.lang_cb.setCurrentIndex(idx + 1) self.button_ok.setEnabled(True) host_label = QLabel(_('Host:')) self.host_input = QLineEdit(self) self.host_input.setToolTip( _('Name of the host that will provide ' 'access to the server')) self.host_input.setText(host) self.host_input.textChanged.connect(lambda x: self.validate()) port_label = QLabel(_('Port:')) self.port_spinner = QSpinBox(self) self.port_spinner.setToolTip(_('TCP port number of the server')) self.port_spinner.setMinimum(1) self.port_spinner.setMaximum(60000) self.port_spinner.setValue(port) cmd_label = QLabel(_('Command to execute:')) self.cmd_input = QLineEdit(self) self.cmd_input.setToolTip( _('Command used to start the ' 'LSP server locally')) self.cmd_input.setText(cmd) if not external: self.cmd_input.textChanged.connect(lambda x: self.validate()) args_label = QLabel(_('Server arguments:')) self.args_input = QLineEdit(self) self.args_input.setToolTip( _('Additional arguments required to ' 'start the server')) self.args_input.setText(args) conf_label = QLabel(_('LSP Server Configurations:')) self.conf_input = CodeEditor(None) self.conf_input.textChanged.connect(self.validate) color_scheme = CONF.get('appearance', 'selected') self.conf_input.setup_editor(language='JSON', color_scheme=color_scheme, wrap=False, edge_line=True, highlight_current_line=True, highlight_current_cell=True, occurrence_highlighting=True, auto_unindent=True, font=get_font(), filename='config.json') self.conf_input.setToolTip( _('Additional LSP server configurations ' 'set at runtime. JSON required')) conf_text = '{}' try: conf_text = json.dumps(configurations, indent=4, sort_keys=True) except Exception: pass self.conf_input.set_text(conf_text) self.json_label = QLabel(self.JSON_VALID, self) self.external_cb = QCheckBox(_('External server'), self) self.external_cb.setToolTip( _('Check if the server runs ' 'on a remote location')) self.external_cb.setChecked(external) self.external_cb.stateChanged.connect(self.set_local_options) hlayout = QHBoxLayout() general_vlayout = QVBoxLayout() general_vlayout.addWidget(server_settings_description) vlayout = QVBoxLayout() lang_layout = QVBoxLayout() lang_layout.addWidget(lang_label) lang_layout.addWidget(self.lang_cb) # layout2 = QHBoxLayout() # layout2.addLayout(lang_layout) lang_layout.addWidget(self.external_cb) vlayout.addLayout(lang_layout) host_layout = QVBoxLayout() host_layout.addWidget(host_label) host_layout.addWidget(self.host_input) port_layout = QVBoxLayout() port_layout.addWidget(port_label) port_layout.addWidget(self.port_spinner) conn_info_layout = QHBoxLayout() conn_info_layout.addLayout(host_layout) conn_info_layout.addLayout(port_layout) vlayout.addLayout(conn_info_layout) cmd_layout = QVBoxLayout() cmd_layout.addWidget(cmd_label) cmd_layout.addWidget(self.cmd_input) vlayout.addLayout(cmd_layout) args_layout = QVBoxLayout() args_layout.addWidget(args_label) args_layout.addWidget(self.args_input) vlayout.addLayout(args_layout) conf_layout = QVBoxLayout() conf_layout.addWidget(conf_label) conf_layout.addWidget(self.conf_input) conf_layout.addWidget(self.json_label) hlayout.addLayout(vlayout) hlayout.addLayout(conf_layout) general_vlayout.addLayout(hlayout) general_vlayout.addWidget(bbox) self.setLayout(general_vlayout) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) self.lang_cb.currentIndexChanged.connect(self.lang_selection_changed) self.form_status(False) if language is not None: self.form_status(True) self.validate() @Slot() def validate(self): host_text = self.host_input.text() cmd_text = self.cmd_input.text() if not self.HOST_REGEX.match(host_text): self.button_ok.setEnabled(False) self.host_input.setStyleSheet("QLineEdit{border: 1px solid red;}") self.host_input.setToolTip('Hostname must be valid') return else: self.host_input.setStyleSheet( "QLineEdit{border: 1px solid green;}") self.host_input.setToolTip('Hostname is valid') self.button_ok.setEnabled(True) if not self.external: if not self.NON_EMPTY_REGEX.match(cmd_text): self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid red;}") self.cmd_input.setToolTip('Command must be non empty') return if find_program(cmd_text) is None: self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid red;}") self.cmd_input.setToolTip('Program was not found ' 'on your system') return else: self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid green;}") self.cmd_input.setToolTip('Program was found on your system') self.button_ok.setEnabled(True) try: json.loads(self.conf_input.toPlainText()) try: self.json_label.setText(self.JSON_VALID) except: pass except (ValueError, json.decoder.JSONDecodeError): try: self.json_label.setText(self.JSON_INVALID) self.button_ok.setEnabled(False) except: pass def form_status(self, status): self.host_input.setEnabled(status) self.port_spinner.setEnabled(status) self.external_cb.setEnabled(status) self.cmd_input.setEnabled(status) self.args_input.setEnabled(status) self.conf_input.setEnabled(status) self.json_label.setVisible(status) @Slot() def lang_selection_changed(self): idx = self.lang_cb.currentIndex() if idx == 0: self.set_defaults() self.form_status(False) self.button_ok.setEnabled(False) else: server = self.parent.get_server_by_lang(LSP_LANGUAGES[idx - 1]) self.form_status(True) if server is not None: self.host_input.setText(server.host) self.port_spinner.setValue(server.port) self.external_cb.setChecked(server.external) self.cmd_input.setText(server.cmd) self.args_input.setText(server.args) self.conf_input.set_text(json.dumps(server.configurations)) self.json_label.setText(self.JSON_VALID) self.button_ok.setEnabled(True) else: self.set_defaults() def set_defaults(self): self.cmd_input.setStyleSheet('') self.host_input.setStyleSheet('') self.host_input.setText(self.DEFAULT_HOST) self.port_spinner.setValue(self.DEFAULT_PORT) self.external_cb.setChecked(self.DEFAULT_EXTERNAL) self.cmd_input.setText(self.DEFAULT_CMD) self.args_input.setText(self.DEFAULT_ARGS) self.conf_input.set_text(self.DEFAULT_CONFIGURATION) self.json_label.setText(self.JSON_VALID) @Slot(bool) @Slot(int) def set_local_options(self, enabled): self.external = enabled self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) if enabled: self.cmd_input.setEnabled(False) self.cmd_input.setStyleSheet('') self.args_input.setEnabled(False) try: self.validate() except: pass def get_options(self): language_idx = self.lang_cb.currentIndex() language = LSP_LANGUAGES[language_idx - 1] host = self.host_input.text() port = int(self.port_spinner.value()) external = self.external_cb.isChecked() args = self.args_input.text() cmd = self.cmd_input.text() configurations = json.loads(self.conf_input.toPlainText()) server = LSPServer(language=language.lower(), cmd=cmd, args=args, host=host, port=port, external=external, configurations=configurations) return server
class EditNodeProperties(QDialog): def __init__(self, data, win_parent=None): """ +-----------------+ | Edit Node Props | +-----------------+------+ | LEwingTip | | Node2 | | Node3 | | Node4 | | | | All Nodes: | | Color red | | PointSize 3 | | Opacity 0.3 | | Show/Hide | | | | Name LEwingTip | | Location X Y Z | | Coord 0 | | CoordType R, C, S | | | | Previous Next | | | | Close | +------------------------+ """ QDialog.__init__(self, win_parent) self.setWindowTitle('Edit Node Properties') #default self.win_parent = win_parent self.out_data = data point_properties = data['point_properties'] print(point_properties) #name = point_properties.name point_size = point_properties.point_size opacity = point_properties.opacity color = point_properties.color show = point_properties.is_visible self.points = data['points'] self.keys = sorted(self.points.keys()) keys = self.keys #nrows = len(keys) active_point = data['active_point'] #self.active_key = keys[0] self.active_key = active_point name = self.active_key description = self.points[self.active_key][0] self._use_old_table = False items = ['Node %i' % val for val in keys] header_labels = ['Nodes'] table_model = Model(items, header_labels, self) view = SingleChoiceQTableView(self) #Call your custom QTableView here view.setModel(table_model) if qt_version in [4, 'pyside']: view.horizontalHeader().setResizeMode(QHeaderView.Stretch) else: view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.table = view #self.representation = actor_obj.representation #print('rep =', self.representation) table = self.table #headers = [QtCore.QString('Groups')] header = table.horizontalHeader() header.setStretchLastSection(True) #---------------------------------------------- #self._default_is_apply = False self.color = QLabel("Color:") self.color_edit = QPushButton() #self.color_edit.setFlat(True) color = self.out_data['point_properties'].color opacity = self.out_data['point_properties'].opacity show = self.out_data['point_properties'].is_visible #color = self.out_data[self.active_key].color qcolor = QColor() qcolor.setRgb(*color) #print('color =%s' % str(color)) palette = QPalette( self.color_edit.palette()) # make a copy of the palette #palette.setColor(QPalette.Active, QPalette.Base, \ #qcolor) palette.setColor(QPalette.Background, QColor('blue')) # ButtonText self.color_edit.setPalette(palette) self.color_edit.setStyleSheet("QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(color) + #"border:1px solid rgb(255, 170, 255); " "}") self.all_nodes_header = QLabel("All Nodes:") self.point_size = QLabel("Point Size:") self.point_size_edit = QSpinBox(self) self.point_size_edit.setRange(1, 10) self.point_size_edit.setSingleStep(1) self.point_size_edit.setValue(point_size) self.opacity = QLabel("Opacity:") self.opacity_edit = QDoubleSpinBox(self) self.opacity_edit.setRange(0.1, 1.0) self.opacity_edit.setDecimals(1) self.opacity_edit.setSingleStep(0.1) self.opacity_edit.setValue(opacity) # show/hide self.checkbox_show = QCheckBox("Show") self.checkbox_hide = QCheckBox("Hide") self.checkbox_show.setChecked(show) self.checkbox_hide.setChecked(not show) #---------------------------------------------- self.nodes_header = QLabel("Single Node:") self.name = QLabel("ID:") self.name_edit = QLineEdit('Node %i' % name) self.name_edit.setDisabled(True) self.description = QLabel("Description:") self.description_edit = QLineEdit(str(description)) #self.description_edit.setDisabled(True) location_x = 0.1 location_y = 0.1 location_z = 0.1 self.location = QLabel("Location:") self.location_x_edit = QDoubleSpinBox(self) self.location_y_edit = QDoubleSpinBox(self) self.location_z_edit = QDoubleSpinBox(self) #self.location_x_edit.setDecimals(1) delta_x = abs(location_x) / 100. if location_x != 0.0 else 0.1 delta_y = abs(location_y) / 100. if location_y != 0.0 else 0.1 delta_z = abs(location_z) / 100. if location_z != 0.0 else 0.1 self.location_x_edit.setSingleStep(delta_x) self.location_y_edit.setSingleStep(delta_y) self.location_z_edit.setSingleStep(delta_z) self.location_x_edit.setValue(location_x) self.location_y_edit.setValue(location_y) self.location_z_edit.setValue(location_z) self.coord = QLabel("Coord:") self.coord_edit = QSpinBox(self) self.coord_edit.setRange(0, 99999999) #self.coord_edit.setSingleStep(1) self.coord_edit.setValue(0) self.coord_type = QLabel("Coord Type:") #---------------------------------------------- # closing #if self._default_is_apply: #self.apply_button.setDisabled(True) self.close_button = QPushButton("Close") self.create_layout() self.set_connections() def update_active_key(self, index): name = self.active_key old_obj = self.out_data['points'][name] #self.active_key #self.points[self.active_key] old_obj[0] = str(self.description_edit.text()) #old_obj.coord = self.description_edit.value() #old_obj.description = self.description_edit.value() #old_obj.description = self.description_edit.value() str_name = str(index.data().toString()) name = int(str_name[5:]) #i = self.keys.index(self.active_key) self.active_key = name point = self.points[self.active_key] #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], self.name_edit.setText(str(self.active_key)) self.description_edit.setText(point[0]) self.coord_edit.setValue(point[1]) if point[2] == 'R': self.radio_rectangular.setChecked(True) elif point[2] == 'C': self.radio_cylindrical.setChecked(True) elif point[2] == 'S': self.radio_spherical.setChecked(True) self.location_x_edit.setValue(point[3]) self.location_y_edit.setValue(point[4]) self.location_z_edit.setValue(point[5]) #obj = self.out_data[name] #point_size = obj.point_size #opacity = obj.opacity #representation = obj.representation #is_visible = obj.is_visible #self.opacity_edit.setValue(opacity) #self.checkbox_show.setChecked(is_visible) #self.checkbox_hide.setChecked(not is_visible) #def on_name_select(self): #print('on_name_select') #return def create_layout(self): cancel_box = QHBoxLayout() cancel_box.addWidget(self.close_button) grid1 = QGridLayout() grid2 = QGridLayout() #----------------------------------------- # setup self.radio_rectangular = QRadioButton('Rectangular') self.radio_cylindrical = QRadioButton('Cylindrical') self.radio_spherical = QRadioButton('Spherical') coord_type_layout = QHBoxLayout() coord_type_layout.addWidget(self.radio_rectangular) coord_type_layout.addWidget(self.radio_cylindrical) coord_type_layout.addWidget(self.radio_spherical) location_layout = QHBoxLayout() location_layout.addWidget(self.location_x_edit) location_layout.addWidget(self.location_y_edit) location_layout.addWidget(self.location_z_edit) checkboxs = QButtonGroup(self) checkboxs.addButton(self.checkbox_show) checkboxs.addButton(self.checkbox_hide) vbox1 = QVBoxLayout() vbox1.addWidget(self.checkbox_show) vbox1.addWidget(self.checkbox_hide) #vbox1.addLayout(checkboxs) #----------------------------------------- irow = 0 grid1.addWidget(self.all_nodes_header, irow, 0) irow += 1 grid1.addWidget(self.color, irow, 0) grid1.addWidget(self.color_edit, irow, 1) irow += 1 grid1.addWidget(self.opacity, irow, 0) grid1.addWidget(self.opacity_edit, irow, 1) irow += 1 grid1.addWidget(self.point_size, irow, 0) grid1.addWidget(self.point_size_edit, irow, 1) irow += 1 #----------------------------------------- irow = 0 grid2.addWidget(self.nodes_header, irow, 0) irow += 1 grid2.addWidget(self.name, irow, 0) grid2.addWidget(self.name_edit, irow, 1) irow += 1 grid2.addWidget(self.description, irow, 0) grid2.addWidget(self.description_edit, irow, 1) irow += 1 #| All Nodes: | #| Color red | #| PointSize 3 | #| Opacity 0.3 | #| Show/Hide | #| | #| Name LEwingTip | #| Location X Y Z | #| Coord 0 | #| CoordType R, C, S | #| | #| Previous Next | grid2.addWidget(self.coord, irow, 0) grid2.addWidget(self.coord_edit, irow, 1) irow += 1 grid2.addWidget(self.coord_type, irow, 0) grid2.addLayout(coord_type_layout, irow, 1) irow += 1 grid2.addWidget(self.location, irow, 0) grid2.addLayout(location_layout, irow, 1) irow += 1 #------------------------------------ vbox = QVBoxLayout() vbox.addLayout(grid1) vbox.addLayout(vbox1) vbox.addStretch() vbox.addWidget(self.table) vbox.addLayout(grid2) vbox.addStretch() #vbox.addWidget(self.check_apply) vbox.addLayout(cancel_box) self.setLayout(vbox) def set_connections(self): if qt_version == 4: self.connect(self.opacity_edit, QtCore.SIGNAL('clicked()'), self.on_opacity) self.connect(self.point_size, QtCore.SIGNAL('clicked()'), self.on_point_size) self.connect(self.color_edit, QtCore.SIGNAL('clicked()'), self.on_color) self.connect(self.checkbox_show, QtCore.SIGNAL('clicked()'), self.on_show) self.connect(self.checkbox_hide, QtCore.SIGNAL('clicked()'), self.on_hide) self.connect(self.description_edit, QtCore.SIGNAL("valueChanged(int)"), self.on_description) self.connect(self.coord_edit, QtCore.SIGNAL("valueChanged(int)"), self.on_coord) self.connect(self.radio_rectangular, QtCore.SIGNAL('clicked()'), self.on_coord_type) self.connect(self.radio_cylindrical, QtCore.SIGNAL('clicked()'), self.on_coord_type) self.connect(self.radio_spherical, QtCore.SIGNAL('clicked()'), self.on_coord_type) self.connect(self.location_x_edit, QtCore.SIGNAL('clicked()'), self.on_location_x) self.connect(self.location_y_edit, QtCore.SIGNAL('clicked()'), self.on_location_y) self.connect(self.location_z_edit, QtCore.SIGNAL('clicked()'), self.on_location_z) self.connect(self.close_button, QtCore.SIGNAL('clicked()'), self.on_close) #self.connect(self.check_apply, QtCore.SIGNAL('clicked()'), self.on_check_apply) #self.connect(self.apply_button, QtCore.SIGNAL('clicked()'), self.on_apply) #self.connect(self.ok_button, QtCore.SIGNAL('clicked()'), self.on_ok) #self.connect(self.close_button, QtCore.SIGNAL('clicked()'), self.on_close) else: #self.opacity_edit.clicked.connect(self.on_opacity) #self.point_size.clicked.connect(self.on_point_size) #self.color_edit.clicked.connect(self.on_color) #self.checkbox_show.clicked.connect(self.on_show) #self.checkbox_hide.clicked.connect(self.on_hide) #self.description_edit.valueChanged.connect(self.on_description) #self.coord_edit.valueChanged.connect(self.on_coord) #self.radio_rectangular.clicked.connect(self.on_coord_type) #self.radio_cylindrical.clicked.connect(self.on_coord_type) #self.radio_spherical.clicked.connect(self.on_coord_type) #self.location_x_edit.clicked.connect(self.on_location_x) #self.location_y_edit.clicked.connect(self.on_location_y) #self.location_z_edit.clicked.connect(self.on_location_z) self.close_button.clicked.connect(self.on_close) def on_color(self): obj = self.out_data['point_properties'] rgb_color_ints = obj.color msg = 'Points' col = QColorDialog.getColor(QColor(*rgb_color_ints), self, "Choose a %s color" % msg) if col.isValid(): color = col.getRgbF()[:3] obj.color = color #print('new_color =', color) self.color_edit.setStyleSheet( "QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(obj.color) + #"border:1px solid rgb(255, 170, 255); " "}") def on_show(self): is_checked = self.checkbox_show.isChecked() self.out_data['point_properties'].is_visible = is_checked def on_hide(self): is_checked = self.checkbox_hide.isChecked() self.out_data['point_properties'].is_visible = not is_checked def on_point_size(self): point_size = self.point_size_edit.value() self.out_data['point_properties'].point_size = point_size def on_opacity(self): opacity = self.opacity_edit.value() self.out_data['point_properties'].opacity = opacity def on_description(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key description = self.description_edit.value() self.out_data['points'][name][0] = description def on_coord(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key coord_id = self.coord_edit.value() self.out_data['points'][name][1] = coord_id def on_coord_type(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key if self.radio_rectangular.isChecked(): coord_type = 'R' elif self.radio_cylindrical.isChecked(): coord_type = 'C' elif self.radio_spherical.isChecked(): coord_type = 'S' else: raise NotImplementedError() self.out_data['points'][name][2] = coord_type def on_location_x(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key value = self.coord_edit.value() self.out_data['points'][name][3] = value def on_location_y(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key value = self.coord_edit.value() self.out_data['points'][name][4] = value def on_location_z(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key value = self.coord_edit.value() self.out_data['points'][name][5] = value def closeEvent(self, event): event.accept() #def on_default_name(self): #self.name_edit.setText(str(self._default_name)) #self.name_edit.setStyleSheet("QLineEdit{background: white;}") #def check_float(self, cell): #text = cell.text() #try: #value = eval_float_from_string(text) #cell.setStyleSheet("QLineEdit{background: white;}") #return value, True #except ValueError: #cell.setStyleSheet("QLineEdit{background: red;}") #return None, False #def check_name(self, cell): #text = str(cell.text()).strip() #if len(text): #cell.setStyleSheet("QLineEdit{background: white;}") #return text, True #else: #cell.setStyleSheet("QLineEdit{background: red;}") #return None, False def on_validate(self): self.out_data['clicked_ok'] = True self.out_data['clicked_cancel'] = False old_obj = self.out_data[self.active_key] old_obj.point_size = self.point_size_edit.value() old_obj.opacity = self.opacity_edit.value() old_obj.is_visible = self.checkbox_show.isChecked() return True #name_value, flag0 = self.check_name(self.name_edit) #ox_value, flag1 = self.check_float(self.transparency_edit) #if flag0 and flag1: #self.out_data['clicked_ok'] = True #return True #return False def on_apply(self): passed = self.on_validate() if passed: self.win_parent.on_update_gui_nodes(self.out_data) return passed def on_ok(self): passed = self.on_apply() if passed: self.close() #self.destroy() def on_close(self): self.out_data['clicked_close'] = True self.close()
def setup_page(self): if ERR_MSG: label = QLabel(_("Could not load plugin:\n{0}".format(ERR_MSG))) layout = QVBoxLayout() layout.addWidget(label) self.setLayout(layout) return # Layout parameter indent = QCheckBox().sizeHint().width() # General options options_group = QGroupBox(_("Options")) # Hack : the spinbox widget will be added to self.spinboxes spinboxes_before = set(self.spinboxes) passes_spin = self.create_spinbox(_("Number of pep8 passes: "), "", 'passes', default=0, min_=0, max_=1000000, step=1) spinbox = set(self.spinboxes) - spinboxes_before spinbox = spinbox.pop() spinbox.setSpecialValueText(_("Infinite")) aggressive1_checkbox = self.create_checkbox("Aggressivity level 1", "aggressive1", default=False) aggressive1_label = QLabel( _("Allow possibly unsafe fixes (E711 and W6), shorten lines" " and remove trailing whitespace more aggressively (in" " docstrings and multiline strings).")) aggressive1_label.setWordWrap(True) aggressive1_label.setIndent(indent) font_description = aggressive1_label.font() font_description.setPointSizeF(font_description.pointSize() * 0.9) aggressive1_label.setFont(font_description) aggressive2_checkbox = self.create_checkbox("Aggressivity level 2", "aggressive2", default=False) aggressive2_label = QLabel( _("Allow more possibly unsafe fixes (E712) and shorten lines.")) aggressive2_label.setWordWrap(True) aggressive2_label.setIndent(indent) aggressive2_label.setFont(font_description) aggressive1_checkbox.toggled.connect(aggressive2_checkbox.setEnabled) aggressive1_checkbox.toggled.connect(aggressive2_label.setEnabled) aggressive2_checkbox.setEnabled(aggressive1_checkbox.isChecked()) aggressive2_label.setEnabled(aggressive1_checkbox.isChecked()) # Enable/disable error codes fix_layout = QVBoxLayout() last_group = "" FIX_LIST.sort(key=lambda item: item[0][1]) for code, description in FIX_LIST: # Create a new group if necessary if code[1] != last_group: last_group = code[1] group = QGroupBox(_(self.GROUPS.get(code[1], ""))) fix_layout.addWidget(group) group_layout = QVBoxLayout(group) # Checkbox for the option text = code default = True if code in DEFAULT_IGNORE: text += _(" (UNSAFE)") default = False option = self.create_checkbox(text, code, default=default) # Label for description if code in self.CODES: label = QLabel("{autopep8} ({pep8}).".format( autopep8=_(description).rstrip("."), pep8=self.CODES[code])) else: label = QLabel(_(description)) label.setWordWrap(True) label.setIndent(indent) label.setFont(font_description) # Add widgets to layout option_layout = QVBoxLayout() option_layout.setSpacing(0) option_layout.addWidget(option) option_layout.addWidget(label) group_layout.addLayout(option_layout) # Special cases if code in ("E711", "W6"): aggressive1_checkbox.toggled.connect(option.setEnabled) aggressive1_checkbox.toggled.connect(label.setEnabled) option.setEnabled(aggressive1_checkbox.isChecked()) label.setEnabled(aggressive1_checkbox.isChecked()) if code == "E712": def e712_enabled(): enabled = (aggressive1_checkbox.isChecked() and aggressive2_checkbox.isChecked()) option.setEnabled(enabled) label.setEnabled(enabled) aggressive1_checkbox.toggled.connect(e712_enabled) aggressive2_checkbox.toggled.connect(e712_enabled) e712_enabled() # General layout aggressive2_layout = QVBoxLayout() margins = aggressive2_layout.contentsMargins() margins.setLeft(indent) aggressive2_layout.setContentsMargins(margins) aggressive2_layout.addWidget(aggressive2_checkbox) aggressive2_layout.addWidget(aggressive2_label) options_layout = QVBoxLayout() options_layout.addWidget(passes_spin) options_layout.addWidget(aggressive1_checkbox) options_layout.addWidget(aggressive1_label) options_layout.addLayout(aggressive2_layout) options_group.setLayout(options_layout) widget_scroll = QWidget() widget_scroll.setLayout(fix_layout) fix_scroll = QScrollArea() fix_scroll.setWidget(widget_scroll) fix_scroll.setWidgetResizable(True) fig_out_layout = QVBoxLayout() fig_out_layout.addWidget(fix_scroll, 1) fix_group = QGroupBox(_("Errors/warnings to fix")) fix_group.setLayout(fig_out_layout) vlayout = QVBoxLayout() vlayout.addWidget(options_group) vlayout.addWidget(fix_group, 1) self.setLayout(vlayout)
def __init__(self, parent=None): QDialog.__init__(self, parent) self.setWindowTitle(_("Spyder internal error")) self.setModal(True) # To save the traceback sent to the internal console self.error_traceback = "" # Dialog main label self.main_label = QLabel( _("""<b>Spyder has encountered an internal problem</b><hr> Please enter below a step-by-step description of your problem (in English). Issue reports without a clear way to reproduce them will be closed. <br><br> <b>Note</b>: You need a Github account for this. """)) self.main_label.setWordWrap(True) self.main_label.setAlignment(Qt.AlignJustify) # Field to input the description of the problem self.input_description = DescriptionWidget(self) # Only allow to submit to Github if we have a long enough description self.input_description.textChanged.connect(self._description_changed) # Widget to show errors self.details = ShowErrorWidget(self) self.details.set_pythonshell_font(get_font()) self.details.hide() # Label to show missing chars self.initial_chars = len(self.input_description.toPlainText()) self.chars_label = QLabel(_("Enter at least {} " "characters".format(MIN_CHARS))) # Checkbox to dismiss future errors self.dismiss_box = QCheckBox() self.dismiss_box.setText(_("Don't show again during this session")) # Labels layout labels_layout = QHBoxLayout() labels_layout.addWidget(self.chars_label) labels_layout.addWidget(self.dismiss_box, 0, Qt.AlignRight) # Dialog buttons self.submit_btn = QPushButton(_('Submit to Github')) self.submit_btn.setEnabled(False) self.submit_btn.clicked.connect(self._submit_to_github) self.details_btn = QPushButton(_('Show details')) self.details_btn.clicked.connect(self._show_details) self.close_btn = QPushButton(_('Close')) # Buttons layout buttons_layout = QHBoxLayout() buttons_layout.addWidget(self.submit_btn) buttons_layout.addWidget(self.details_btn) buttons_layout.addWidget(self.close_btn) # Main layout vlayout = QVBoxLayout() vlayout.addWidget(self.main_label) vlayout.addWidget(self.input_description) vlayout.addWidget(self.details) vlayout.addLayout(labels_layout) vlayout.addLayout(buttons_layout) self.setLayout(vlayout) self.resize(600, 420) self.input_description.setFocus()
def __init__(self, data, win_parent=None): """ +-----------------+ | Edit Node Props | +-----------------+------+ | LEwingTip | | Node2 | | Node3 | | Node4 | | | | All Nodes: | | Color red | | PointSize 3 | | Opacity 0.3 | | Show/Hide | | | | Name LEwingTip | | Location X Y Z | | Coord 0 | | CoordType R, C, S | | | | Previous Next | | | | Close | +------------------------+ """ QDialog.__init__(self, win_parent) self.setWindowTitle('Edit Node Properties') #default self.win_parent = win_parent self.out_data = data point_properties = data['point_properties'] print(point_properties) #name = point_properties.name point_size = point_properties.point_size opacity = point_properties.opacity color = point_properties.color show = point_properties.is_visible self.points = data['points'] self.keys = sorted(self.points.keys()) keys = self.keys #nrows = len(keys) active_point = data['active_point'] #self.active_key = keys[0] self.active_key = active_point name = self.active_key description = self.points[self.active_key][0] self._use_old_table = False items = ['Node %i' % val for val in keys] header_labels = ['Nodes'] table_model = Model(items, header_labels, self) view = SingleChoiceQTableView(self) #Call your custom QTableView here view.setModel(table_model) if qt_version in [4, 'pyside']: view.horizontalHeader().setResizeMode(QHeaderView.Stretch) else: view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.table = view #self.representation = actor_obj.representation #print('rep =', self.representation) table = self.table #headers = [QtCore.QString('Groups')] header = table.horizontalHeader() header.setStretchLastSection(True) #---------------------------------------------- #self._default_is_apply = False self.color = QLabel("Color:") self.color_edit = QPushButton() #self.color_edit.setFlat(True) color = self.out_data['point_properties'].color opacity = self.out_data['point_properties'].opacity show = self.out_data['point_properties'].is_visible #color = self.out_data[self.active_key].color qcolor = QColor() qcolor.setRgb(*color) #print('color =%s' % str(color)) palette = QPalette( self.color_edit.palette()) # make a copy of the palette #palette.setColor(QPalette.Active, QPalette.Base, \ #qcolor) palette.setColor(QPalette.Background, QColor('blue')) # ButtonText self.color_edit.setPalette(palette) self.color_edit.setStyleSheet("QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(color) + #"border:1px solid rgb(255, 170, 255); " "}") self.all_nodes_header = QLabel("All Nodes:") self.point_size = QLabel("Point Size:") self.point_size_edit = QSpinBox(self) self.point_size_edit.setRange(1, 10) self.point_size_edit.setSingleStep(1) self.point_size_edit.setValue(point_size) self.opacity = QLabel("Opacity:") self.opacity_edit = QDoubleSpinBox(self) self.opacity_edit.setRange(0.1, 1.0) self.opacity_edit.setDecimals(1) self.opacity_edit.setSingleStep(0.1) self.opacity_edit.setValue(opacity) # show/hide self.checkbox_show = QCheckBox("Show") self.checkbox_hide = QCheckBox("Hide") self.checkbox_show.setChecked(show) self.checkbox_hide.setChecked(not show) #---------------------------------------------- self.nodes_header = QLabel("Single Node:") self.name = QLabel("ID:") self.name_edit = QLineEdit('Node %i' % name) self.name_edit.setDisabled(True) self.description = QLabel("Description:") self.description_edit = QLineEdit(str(description)) #self.description_edit.setDisabled(True) location_x = 0.1 location_y = 0.1 location_z = 0.1 self.location = QLabel("Location:") self.location_x_edit = QDoubleSpinBox(self) self.location_y_edit = QDoubleSpinBox(self) self.location_z_edit = QDoubleSpinBox(self) #self.location_x_edit.setDecimals(1) delta_x = abs(location_x) / 100. if location_x != 0.0 else 0.1 delta_y = abs(location_y) / 100. if location_y != 0.0 else 0.1 delta_z = abs(location_z) / 100. if location_z != 0.0 else 0.1 self.location_x_edit.setSingleStep(delta_x) self.location_y_edit.setSingleStep(delta_y) self.location_z_edit.setSingleStep(delta_z) self.location_x_edit.setValue(location_x) self.location_y_edit.setValue(location_y) self.location_z_edit.setValue(location_z) self.coord = QLabel("Coord:") self.coord_edit = QSpinBox(self) self.coord_edit.setRange(0, 99999999) #self.coord_edit.setSingleStep(1) self.coord_edit.setValue(0) self.coord_type = QLabel("Coord Type:") #---------------------------------------------- # closing #if self._default_is_apply: #self.apply_button.setDisabled(True) self.close_button = QPushButton("Close") self.create_layout() self.set_connections()
def __init__(self, parent=None): super(ColorbarWidget, self).__init__(parent) self.setWindowTitle("Colorbar") self.setMaximumWidth(200) self.dval = QDoubleValidator() self.cmin = QLineEdit() self.cmin_value = 0 self.cmin.setMaximumWidth(100) self.cmin.editingFinished.connect(self.clim_changed) self.cmin_layout = QHBoxLayout() self.cmin_layout.addStretch() self.cmin_layout.addWidget(self.cmin) self.cmin_layout.addStretch() self.cmax = QLineEdit() self.cmax_value = 1 self.cmax.setMaximumWidth(100) self.cmax.editingFinished.connect(self.clim_changed) self.cmin.setValidator(self.dval) self.cmax.setValidator(self.dval) self.cmax_layout = QHBoxLayout() self.cmax_layout.addStretch() self.cmax_layout.addWidget(self.cmax) self.cmax_layout.addStretch() self.norm_layout = QHBoxLayout() self.norm = QComboBox() self.norm.addItems(NORM_OPTS) self.norm.currentIndexChanged.connect(self.norm_changed) self.powerscale = QLineEdit() self.powerscale_value = 2 self.powerscale.setText("2") self.powerscale.setValidator(QDoubleValidator(0.001,100,3)) self.powerscale.setMaximumWidth(50) self.powerscale.editingFinished.connect(self.norm_changed) self.powerscale.hide() self.powerscale_label = QLabel("n=") self.powerscale_label.hide() self.norm_layout.addStretch() self.norm_layout.addWidget(self.norm) self.norm_layout.addStretch() self.norm_layout.addWidget(self.powerscale_label) self.norm_layout.addWidget(self.powerscale) self.autoscale = QCheckBox("Autoscaling") self.autoscale.setChecked(True) self.autoscale.stateChanged.connect(self.update_clim) self.canvas = FigureCanvas(Figure()) if parent: # Set facecolor to match parent self.canvas.figure.set_facecolor(parent.palette().window().color().getRgbF()) self.ax = self.canvas.figure.add_axes([0.4,0.05,0.2,0.9]) # layout self.layout = QVBoxLayout(self) self.layout.addLayout(self.cmax_layout) self.layout.addWidget(self.canvas, stretch=1) self.layout.addLayout(self.cmin_layout) self.layout.addLayout(self.norm_layout) self.layout.addWidget(self.autoscale)
def __init__(self, parent): super(FindReplaceDialog, self).__init__(parent) self.parent = parent self.setWindowTitle("Find Replace") self.setFixedSize(400, 200) main_layout = QVBoxLayout() find_layout = QHBoxLayout() replace_layout = QHBoxLayout() options_layout = QHBoxLayout() buttons_layout = QHBoxLayout() find_label = QLabel() find_label.setText("Find:") self.find_input = QLineEdit() find_layout.addWidget(find_label) find_layout.addWidget(self.find_input) replace_label = QLabel() replace_label.setText("Replace:") self.replace_input = QLineEdit() replace_layout.addWidget(replace_label) replace_layout.addWidget(self.replace_input) self.close_button = QPushButton() self.close_button.setText("Close") self.find_button = QPushButton() self.find_button.setText("Find") self.replace_button = QPushButton() self.replace_button.setText("Replace") self.all_button = QPushButton() self.all_button.setText("Replace All") buttons_layout.addWidget(self.close_button) buttons_layout.addWidget(self.find_button) buttons_layout.addWidget(self.replace_button) buttons_layout.addWidget(self.all_button) self.highlight_result = QCheckBox() self.highlight_result.setText("highlight results") options_layout.addWidget(self.highlight_result) main_layout.addLayout(find_layout) main_layout.addLayout(replace_layout) main_layout.addLayout(options_layout) main_layout.addLayout(buttons_layout) self.setLayout(main_layout) self.find_button.clicked.connect(self.find_text) self.replace_button.clicked.connect(self.replace_text) self.all_button.clicked.connect(self.replace_all_text) self.close_button.clicked.connect(self.hide_dialog)
def __init__(self, parent, username, password, token, remember=False, remember_token=False): QDialog.__init__(self, parent) title = _("Sign in to Github") self.resize(415, 375) self.setWindowTitle(title) self.setWindowFlags( self.windowFlags() & ~Qt.WindowContextHelpButtonHint) # Header html = ('<html><head/><body><p align="center">' '{title}</p></body></html>') lbl_html = QLabel(html.format(title=title)) lbl_html.setStyleSheet('font-size: 16px;') # Tabs self.tabs = QTabWidget() # Basic form layout basic_form_layout = QFormLayout() basic_form_layout.setContentsMargins(-1, 0, -1, -1) basic_lbl_msg = QLabel(_("For regular users, i.e. users <b>without</b>" " two-factor authentication enabled")) basic_lbl_msg.setWordWrap(True) basic_lbl_msg.setAlignment(Qt.AlignJustify) lbl_user = QLabel(_("Username:"******"", QWidget()) lbl_password = QLabel(_("Password: "******"Remember me")) self.cb_remember.setToolTip(_("Spyder will save your credentials " "safely")) self.cb_remember.setChecked(remember) basic_form_layout.setWidget(4, QFormLayout.FieldRole, self.cb_remember) # Basic auth tab basic_auth = QWidget() basic_layout = QVBoxLayout() basic_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) basic_layout.addWidget(basic_lbl_msg) basic_layout.addSpacerItem( QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding))) basic_layout.addLayout(basic_form_layout) basic_layout.addSpacerItem( QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding))) basic_auth.setLayout(basic_layout) self.tabs.addTab(basic_auth, _("Password Only")) # Token form layout token_form_layout = QFormLayout() token_form_layout.setContentsMargins(-1, 0, -1, -1) token_lbl_msg = QLabel(_("For users <b>with</b> two-factor " "authentication enabled, or who prefer a " "per-app token authentication.<br><br>" "You can go <b><a href=\"{}\">here</a></b> " "and click \"Generate token\" at the bottom " "to create a new token to use for this, with " "the appropriate permissions.").format( TOKEN_URL)) token_lbl_msg.setOpenExternalLinks(True) token_lbl_msg.setWordWrap(True) token_lbl_msg.setAlignment(Qt.AlignJustify) lbl_token = QLabel("Token: ") token_form_layout.setWidget(1, QFormLayout.LabelRole, lbl_token) self.le_token = QLineEdit() self.le_token.setEchoMode(QLineEdit.Password) self.le_token.textChanged.connect(self.update_btn_state) token_form_layout.setWidget(1, QFormLayout.FieldRole, self.le_token) self.cb_remember_token = None # Same validation as with cb_remember if self.is_keyring_available() and valid_py_os: self.cb_remember_token = QCheckBox(_("Remember token")) self.cb_remember_token.setToolTip(_("Spyder will save your " "token safely")) self.cb_remember_token.setChecked(remember_token) token_form_layout.setWidget(3, QFormLayout.FieldRole, self.cb_remember_token) # Token auth tab token_auth = QWidget() token_layout = QVBoxLayout() token_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) token_layout.addWidget(token_lbl_msg) token_layout.addSpacerItem( QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding))) token_layout.addLayout(token_form_layout) token_layout.addSpacerItem( QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding))) token_auth.setLayout(token_layout) self.tabs.addTab(token_auth, _("Access Token")) # Sign in button self.bt_sign_in = QPushButton(_("Sign in")) self.bt_sign_in.clicked.connect(self.accept) self.bt_sign_in.setDisabled(True) # Main layout layout = QVBoxLayout() layout.addWidget(lbl_html) layout.addWidget(self.tabs) layout.addWidget(self.bt_sign_in) self.setLayout(layout) # Final adjustments if username and password: self.le_user.setText(username) self.le_password.setText(password) self.bt_sign_in.setFocus() elif username: self.le_user.setText(username) self.le_password.setFocus() elif token: self.le_token.setText(token) else: self.le_user.setFocus() self.setFixedSize(self.width(), self.height()) self.le_password.installEventFilter(self) self.le_user.installEventFilter(self) self.tabs.currentChanged.connect(self.update_btn_state)
def __init__(self, layer): super().__init__(layer) self.layer.events.edge_width.connect(self._on_edge_width_change) self.layer.events.length.connect(self._on_length_change) self.layer.events.out_of_slice_display.connect( self._on_out_of_slice_display_change ) self.layer.events.edge_color_mode.connect( self._on_edge_color_mode_change ) self.layer.events.edge_color.connect(self._on_edge_color_change) # dropdown to select the property for mapping edge_color color_properties = self._get_property_values() color_prop_box = QComboBox(self) color_prop_box.activated[str].connect(self.change_edge_color_property) color_prop_box.addItems(color_properties) self.color_prop_box = color_prop_box self.edge_prop_label = QLabel(trans._('edge property:')) # vector direct color mode adjustment and widget self.edgeColorEdit = QColorSwatchEdit( initial_color=self.layer.edge_color, tooltip=trans._( 'click to set current edge color', ), ) self.edgeColorEdit.color_changed.connect(self.change_edge_color_direct) self.edge_color_label = QLabel(trans._('edge color:')) self._on_edge_color_change() # dropdown to select the edge color mode colorModeComboBox = QComboBox(self) color_modes = [e.value for e in ColorMode] colorModeComboBox.addItems(color_modes) colorModeComboBox.activated[str].connect(self.change_edge_color_mode) self.color_mode_comboBox = colorModeComboBox self._on_edge_color_mode_change() # line width in pixels self.widthSpinBox = QDoubleSpinBox() self.widthSpinBox.setKeyboardTracking(False) self.widthSpinBox.setSingleStep(0.1) self.widthSpinBox.setMinimum(0.1) self.widthSpinBox.setMaximum(np.inf) self.widthSpinBox.setValue(self.layer.edge_width) self.widthSpinBox.valueChanged.connect(self.change_width) # line length self.lengthSpinBox = QDoubleSpinBox() self.lengthSpinBox.setKeyboardTracking(False) self.lengthSpinBox.setSingleStep(0.1) self.lengthSpinBox.setValue(self.layer.length) self.lengthSpinBox.setMinimum(0.1) self.lengthSpinBox.setMaximum(np.inf) self.lengthSpinBox.valueChanged.connect(self.change_length) out_of_slice_cb = QCheckBox() out_of_slice_cb.setToolTip(trans._('Out of slice display')) out_of_slice_cb.setChecked(self.layer.out_of_slice_display) out_of_slice_cb.stateChanged.connect(self.change_out_of_slice) self.outOfSliceCheckBox = out_of_slice_cb self.layout().addRow(trans._('opacity:'), self.opacitySlider) self.layout().addRow(trans._('width:'), self.widthSpinBox) self.layout().addRow(trans._('length:'), self.lengthSpinBox) self.layout().addRow(trans._('blending:'), self.blendComboBox) self.layout().addRow( trans._('edge color mode:'), self.color_mode_comboBox ) self.layout().addRow(self.edge_color_label, self.edgeColorEdit) self.layout().addRow(self.edge_prop_label, self.color_prop_box) self.layout().addRow(trans._('out of slice:'), self.outOfSliceCheckBox)