def page(self, title, contents): """Format an HTML page.""" rich_text_font = get_font(option="rich_font").family() plain_text_font = get_font(option="font").family() if is_dark_interface(): css_path = "static/css/dark_pydoc.css" else: css_path = "static/css/light_pydoc.css" css_link = ('<link rel="stylesheet" type="text/css" href="%s">' % css_path) code_style = ('<style>code {font-family: "%s"}</style>' % plain_text_font) html_page = '''\ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html><head><title>Pydoc: %s</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> %s%s</head><body style="clear:both;font-family:'%s'"> %s<div style="clear:both;padding-top:.7em;">%s</div> </body></html>''' % (title, css_link, code_style, rich_text_font, html_navbar(), contents) return html_page
def update_preview(self, index=None, scheme_name=None): """ Update the color scheme of the preview editor and adds text. Note ---- 'index' is needed, because this is triggered by a signal that sends the selected index. """ text = ('"""A string"""\n\n' '# A comment\n\n' '# %% A cell\n\n' 'class Foo(object):\n' ' def __init__(self):\n' ' bar = 42\n' ' print(bar)\n' ) show_blanks = CONF.get('editor', 'blank_spaces') update_scrollbar = CONF.get('editor', 'scroll_past_end') if scheme_name is None: scheme_name = self.current_scheme self.preview_editor.setup_editor(linenumbers=True, markers=True, tab_mode=False, font=get_font(), show_blanks=show_blanks, color_scheme=scheme_name, scroll_past_end=update_scrollbar) self.preview_editor.set_text(text) self.preview_editor.set_language('Python')
def data(self, index, role=Qt.DisplayRole): """Cell content""" if not index.isValid(): return to_qvariant() if role == Qt.DisplayRole or role == Qt.EditRole: column = index.column() row = index.row() value = self.get_value(row, column) if value is None: return '' elif np.isnan(value): return '' elif isinstance(value, float): try: return to_qvariant(self._format % value) except (ValueError, TypeError): # may happen if format = '%d' and value = NaN; # see issue 4139 return to_qvariant(DEFAULT_FORMAT % value) elif is_type_text_string(value): # Don't perform any conversion on strings # because it leads to differences between # the data present in the dataframe and # what is shown by Spyder return value else: return to_qvariant(to_text_string(value)) # elif role == Qt.BackgroundColorRole: # return to_qvariant(self.get_bgcolor(index)) elif role == Qt.FontRole: return to_qvariant(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) return to_qvariant()
def __init__(self, parent=None): CodeEditor.__init__(self, parent) # Editor options self.setup_editor( language='md', color_scheme='Scintilla', linenumbers=False, scrollflagarea=False, wrap=True, edge_line=False, highlight_current_line=False, highlight_current_cell=False, occurrence_highlighting=False, auto_unindent=False) # Set font self.set_font(get_font()) # Header self.header = ( "### What steps will reproduce the problem?\n\n" "<!--- You can use Markdown here --->\n\n") self.set_text(self.header) self.move_cursor(len(self.header)) self.header_end_pos = self.get_position('eof')
def __init__(self, parent, text_color=None, max_results=1000): super().__init__(parent) self.search_text = None self.results = None self.max_results = max_results self.total_matches = None self.error_flag = None self.completed = None self.sorting = {} self.font = get_font() self.data = None self.files = None self.root_items = None self.text_color = text_color # Setup self.set_title('') self.set_sorting(OFF) self.setSortingEnabled(False) self.setItemDelegate(ItemDelegate(self)) self.setUniformRowHeights(True) # Needed for performance self.sortByColumn(0, Qt.AscendingOrder) # Only show the actions for collaps/expand all entries in the widget # For further information see spyder-ide/spyder#13178 self.common_actions = self.common_actions[:2] # Signals self.header().sectionClicked.connect(self.sort_section)
def data(self, index, role=Qt.DisplayRole): """Cell content""" if not index.isValid(): return to_qvariant() if role == Qt.DisplayRole or role == Qt.EditRole: column = index.column() row = index.row() if column == 0: return to_qvariant(to_text_string(self.df_index[row])) else: value = self.get_value(row, column - 1) if isinstance(value, float): try: return to_qvariant(self._format % value) except (ValueError, TypeError): # may happen if format = '%d' and value = NaN; # see issue 4139 return to_qvariant(DEFAULT_FORMAT % value) else: try: return to_qvariant(to_text_string(value)) except UnicodeDecodeError: return to_qvariant(encoding.to_unicode(value)) elif role == Qt.BackgroundColorRole: return to_qvariant(self.get_bgcolor(index)) elif role == Qt.FontRole: return to_qvariant(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) return to_qvariant()
def get_font(cls, rich_text=False): """ Return plain or rich text font used in Spyder. Parameters ---------- rich_text: bool Return rich text font (i.e. the one used in the Help pane) or plain text one (i.e. the one used in the Editor). Returns ------- QFont QFont object to be passed to other Qt widgets. Notes ----- All plugins in Spyder use the same, global font. This is a convenience method in case some plugins want to use a delta size based on the default one. That can be controlled by using FONT_SIZE_DELTA or RICH_FONT_SIZE_DELTA (declared in `SpyderPlugin`). """ if rich_text: option = 'rich_font' font_size_delta = cls.RICH_FONT_SIZE_DELTA else: option = 'font' font_size_delta = cls.FONT_SIZE_DELTA return get_font(option=option, font_size_delta=font_size_delta)
def update_preview(self, index=None, scheme_name=None): """ Update the color scheme of the preview editor and adds text. Note ---- 'index' is needed, because this is triggered by a signal that sends the selected index. """ text = ('"""A string"""\n\n' '# A comment\n\n' 'class Foo(object):\n' ' def __init__(self):\n' ' bar = 42\n' ' print(bar)\n' ) if scheme_name is None: scheme_name = self.current_scheme self.preview_editor.setup_editor( font=get_font(), color_scheme=scheme_name, show_blanks=False, scroll_past_end=False, ) self.preview_editor.set_language('Python') self.preview_editor.set_text(text)
def __init__(self, parent=None): CodeEditor.__init__(self, parent) # Editor options self.setup_editor( language='md', color_scheme='Scintilla', linenumbers=False, scrollflagarea=False, wrap=True, edge_line=False, highlight_current_line=False, highlight_current_cell=False, occurrence_highlighting=False, auto_unindent=False) # Set font self.set_font(get_font()) # Header self.header = ( "**What steps will reproduce your problem?**\n\n" "<!--- You can use Markdown here --->\n\n") self.set_text(self.header) self.move_cursor(len(self.header)) self.header_end_pos = self.get_position('eof')
def _update_details_for_item(self, tree_item): """Shows the object details in the editor given an tree_item.""" try: # obj = tree_item.obj button_id = self.button_group.checkedId() assert button_id >= 0, ("No radio button selected. " "Please report this bug.") attr_details = self._attr_details[button_id] data = attr_details.data_fn(tree_item) self.editor.setPlainText(data) self.editor.setWordWrapMode(attr_details.line_wrap) self.editor.setup_editor( font=get_font(font_size_delta=DEFAULT_SMALL_DELTA), show_blanks=False, color_scheme=CONF.get('appearance', 'selected'), scroll_past_end=False, ) self.editor.set_text(data) if attr_details.name == 'Source code': self.editor.set_language('Python') else: self.editor.set_language('Rst') except Exception as ex: self.editor.setStyleSheet("color: red;") stack_trace = traceback.format_exc() self.editor.setPlainText("{}\n\n{}".format(ex, stack_trace)) self.editor.setWordWrapMode( QTextOption.WrapAtWordBoundaryOrAnywhere)
def __init__(self, parent, text_color=None, max_results=1000): super().__init__(parent) self.search_text = None self.results = None self.max_results = max_results self.total_matches = None self.error_flag = None self.completed = None self.sorting = {} self.font = get_font() self.data = None self.files = None self.root_items = None self.text_color = text_color # Setup self.set_title('') self.set_sorting(OFF) self.setSortingEnabled(False) self.setItemDelegate(ItemDelegate(self)) self.setUniformRowHeights(True) # Needed for performance self.sortByColumn(0, Qt.AscendingOrder) # Signals self.header().sectionClicked.connect(self.sort_section)
def __init__(self, parent, color_scheme): super().__init__(parent) self.font = get_font() self.data = None self.threads = None self.color_scheme = color_scheme self.text_color = color_scheme['normal'][0] self.frames = None self.menu = None self.empty_ws_menu = None self.view_locals_action = None # Setup self.setItemsExpandable(True) self.setColumnCount(1) self.set_title('') self.setSortingEnabled(False) self.setItemDelegate(ItemDelegate(self)) self.setUniformRowHeights(True) # Needed for performance self.sortByColumn(0, Qt.AscendingOrder) # Signals self.header().sectionClicked.connect(self.sort_section) self.itemActivated.connect(self.activated) self.itemClicked.connect(self.activated)
def __repr__(self): match = to_text_string(self.match).rstrip() font = get_font() _str = to_text_string("<b>{1}</b> ({2}): " "<span style='font-family:{0};" "font-size:75%;'>{3}</span>") return _str.format(font.family(), self.lineno, self.colno, match)
def update_preview(self, index=None, scheme_name=None): """ Update the color scheme of the preview editor and adds text. Note ---- 'index' is needed, because this is triggered by a signal that sends the selected index. """ text = ('"""A string"""\n\n' '# A comment\n\n' '# %% A cell\n\n' 'class Foo(object):\n' ' def __init__(self):\n' ' bar = 42\n' ' print(bar)\n') show_blanks = CONF.get('editor', 'blank_spaces') update_scrollbar = CONF.get('editor', 'scroll_past_end') underline_errors = CONF.get('editor', 'underline_errors') if scheme_name is None: scheme_name = self.current_scheme self.preview_editor.setup_editor(linenumbers=True, markers=True, tab_mode=False, font=get_font(), show_blanks=show_blanks, underline_errors=underline_errors, color_scheme=scheme_name, scroll_past_end=update_scrollbar) self.preview_editor.set_text(text) self.preview_editor.set_language('Python')
def data(self, index, role=Qt.DisplayRole): """Cell content""" if not index.isValid(): return to_qvariant() value = self.get_value(index) if is_binary_string(value): try: value = to_text_string(value, 'utf8') except: pass if role == Qt.DisplayRole: if value is np.ma.masked: return '' else: try: return to_qvariant(self._format % value) except TypeError: self.readonly = True return repr(value) elif role == Qt.TextAlignmentRole: return to_qvariant(int(Qt.AlignCenter|Qt.AlignVCenter)) elif role == Qt.BackgroundColorRole and self.bgcolor_enabled \ and value is not np.ma.masked: try: hue = (self.hue0 + self.dhue * (float(self.vmax) - self.color_func(value)) / (float(self.vmax) - self.vmin)) hue = float(np.abs(hue)) color = QColor.fromHsvF(hue, self.sat, self.val, self.alp) return to_qvariant(color) except TypeError: return to_qvariant() elif role == Qt.FontRole: return to_qvariant(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) return to_qvariant()
def __repr__(self): match = to_text_string(self.match).rstrip() font = get_font() _str = to_text_string("<b>{1}</b> ({2}): " "<span style='font-family:{0};" "font-size:75%;'>{3}</span>") return _str.format(font.family(), self.lineno, self.colno, match)
def data(self, index, role=Qt.DisplayRole): """Cell content""" if not index.isValid(): return to_qvariant() value = self.get_value(index) if is_binary_string(value): try: value = to_text_string(value, 'utf8') except: pass if role == Qt.DisplayRole: if value is np.ma.masked: return '' else: try: return to_qvariant(self._format % value) except TypeError: self.readonly = True return repr(value) elif role == Qt.TextAlignmentRole: return to_qvariant(int(Qt.AlignCenter | Qt.AlignVCenter)) elif role == Qt.BackgroundColorRole and self.bgcolor_enabled \ and value is not np.ma.masked: try: hue = (self.hue0 + self.dhue * (float(self.vmax) - self.color_func(value)) / (float(self.vmax) - self.vmin)) hue = float(np.abs(hue)) color = QColor.fromHsvF(hue, self.sat, self.val, self.alp) return to_qvariant(color) except TypeError: return to_qvariant() elif role == Qt.FontRole: return to_qvariant(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) return to_qvariant()
def data(self, index, role=Qt.DisplayRole): """Cell content""" if not index.isValid(): return to_qvariant() if role == Qt.DisplayRole or role == Qt.EditRole: column = index.column() row = index.row() if column == 0: return to_qvariant(to_text_string(self.df_index[row])) else: value = self.get_value(row, column-1) if isinstance(value, float): try: return to_qvariant(self._format % value) except (ValueError, TypeError): # may happen if format = '%d' and value = NaN; # see issue 4139 return to_qvariant(DEFAULT_FORMAT % value) else: try: return to_qvariant(to_text_string(value)) except UnicodeDecodeError: return to_qvariant(encoding.to_unicode(value)) elif role == Qt.BackgroundColorRole: return to_qvariant(self.get_bgcolor(index)) elif role == Qt.FontRole: return to_qvariant(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) return to_qvariant()
def __init__(self, text, title='', font=None, parent=None, readonly=False, size=(400, 300)): QDialog.__init__(self, 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.text = None self.btn_save_and_close = None # Display text as unicode if it comes as bytes, so users see # its right representation if is_binary_string(text): self.is_binary = True text = to_text_string(text, 'utf8') else: self.is_binary = False self.layout = QVBoxLayout() self.setLayout(self.layout) # Text edit self.edit = QTextEdit(parent) self.edit.setReadOnly(readonly) self.edit.textChanged.connect(self.text_changed) self.edit.setPlainText(text) if font is None: font = get_font() self.edit.setFont(font) self.layout.addWidget(self.edit) # Buttons configuration btn_layout = QHBoxLayout() btn_layout.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.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.addWidget(self.btn_close) self.layout.addLayout(btn_layout) # Make the dialog act as a window self.setWindowFlags(Qt.Window) self.setWindowIcon(ima.icon('edit')) self.setWindowTitle(_("Text editor") + \ "%s" % (" - "+str(title) if str(title) else "")) self.resize(size[0], size[1])
def _get_font(self, rich_text=False): """Return plugin font.""" if rich_text: option = 'rich_font' font_size_delta = self.RICH_FONT_SIZE_DELTA else: option = 'font' font_size_delta = self.FONT_SIZE_DELTA return get_font(option=option, font_size_delta=font_size_delta)
def __init__(self, obj, obj_name='', attr_cols=None, parent=None, regular_font=None, special_attribute_font=None): """ Constructor :param obj: any Python object or variable :param obj_name: name of the object as it will appear in the root node If empty, no root node will be drawn. :param attr_cols: list of AttributeColumn definitions :param parent: the parent widget """ super(TreeModel, self).__init__(parent) self._attr_cols = attr_cols # Font for members (non-functions) self.regular_font = regular_font if regular_font else get_font() # Font for __special_attributes__ self.special_attribute_font = (special_attribute_font if special_attribute_font else get_font()) self.special_attribute_font.setItalic(False) self.regular_color = QBrush(QColor(ima.MAIN_FG_COLOR)) self.callable_color = QBrush( QColor(ima.MAIN_FG_COLOR)) # for functions, methods, etc. # The following members will be initialized by populateTree # The rootItem is always invisible. If the obj_name # is the empty string, the inspectedItem # will be the rootItem (and therefore be invisible). # If the obj_name is given, an # invisible root item will be added and the # inspectedItem will be its only child. # In that case the inspected item will be visible. self._inspected_node_is_visible = None self._inspected_item = None self._root_item = None self.populateTree(obj, obj_name=obj_name)
def __init__(self, text, title='', font=None, parent=None, readonly=False, size=(400, 300)): QDialog.__init__(self, 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.text = None # Display text as unicode if it comes as bytes, so users see # its right representation if is_binary_string(text): self.is_binary = True text = to_text_string(text, 'utf8') else: self.is_binary = False self.layout = QVBoxLayout() self.setLayout(self.layout) # Text edit self.edit = QTextEdit(parent) self.edit.textChanged.connect(self.text_changed) self.edit.setReadOnly(readonly) self.edit.setPlainText(text) if font is None: font = get_font() self.edit.setFont(font) self.layout.addWidget(self.edit) # Buttons configuration buttons = QDialogButtonBox.Ok if not readonly: buttons = buttons | QDialogButtonBox.Cancel bbox = QDialogButtonBox(buttons) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) self.layout.addWidget(bbox) # Make the dialog act as a window self.setWindowFlags(Qt.Window) self.setWindowIcon(ima.icon('edit')) self.setWindowTitle(_("Text editor") + \ "%s" % (" - "+str(title) if str(title) else "")) self.resize(size[0], size[1])
def clear_title(self, search_text): self.font = get_font() self.clear() self.setSortingEnabled(False) self.num_files = 0 self.data = {} self.files = {} self.set_sorting(OFF) self.search_text = search_text title = "'%s' - " % search_text text = _('String not found') self.set_title(title + text)
def __init__(self, parent, statusbar): QWidget.__init__(self, parent) self.label_font = font = get_font(option='rich_font') font.setPointSize(self.font().pointSize()) font.setBold(True) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) statusbar.addPermanentWidget(self)
def __init__(self, parent, statusbar): QWidget.__init__(self, parent) self.label_font = font = get_font(option='rich_font') font.setPointSize(self.font().pointSize()) font.setBold(True) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) statusbar.addPermanentWidget(self)
def __init__(self, parent, statusbar): """Status bar widget base.""" super(StatusBarWidget, self).__init__(parent) self.label_font = get_font(option='rich_font') self.label_font.setPointSize(self.font().pointSize()) self.label_font.setBold(True) # Layouts layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # Setup statusbar.addPermanentWidget(self)
def __init__(self, folder, parent=None): """Init.""" super().__init__(parent) font = get_font() self.folder = folder self.path_selected = "" self.path_list = [] self.results_old = {} self.setWindowTitle("Path Finder") self.setWindowFlags(Qt.Popup | Qt.FramelessWindowHint) self.setWindowOpacity(0.95) self.setFixedHeight(self._MAX_HEIGHT) self.setFont(font) # Set List widget self.list_viewer = QListView(self) self.list_viewer.setAttribute(Qt.WA_TransparentForMouseEvents) self.list_viewer.setFocusPolicy(Qt.NoFocus) self.list_viewer.setFixedWidth(self._MIN_WIDTH) self.list_viewer.setUniformItemSizes(True) self.list_model = QStringListModel() self.list_viewer.setModel(self.list_model) self.list_viewer.setFont(font) # Set edit self.edit = PathFinderEdit(self, textChanged=self.update_list) self.edit.setFont(font) self.edit.sig_esc_key_pressed.connect(self.close) self.edit.sig_enter_key_pressed.connect(self.enter) self.edit.sig_up_key_pressed.connect(lambda: self.prev_row(1)) self.edit.sig_pg_up_key_pressed.connect(self.pg_up) self.edit.sig_pg_half_up_key_pressed.connect(self.pg_half_up) self.edit.sig_down_key_pressed.connect(lambda: self.next_row(1)) self.edit.sig_pg_down_key_pressed.connect(self.pg_down) self.edit.sig_pg_half_down_key_pressed.connect(self.pg_half_down) layout = QVBoxLayout() layout.addWidget(self.edit) layout.addWidget(self.list_viewer) self.setLayout(layout) self.get_path_list() self.update_list() self.edit.setFocus()
def get_plugin_font(self, rich_text=False): """ Return plugin font option. All plugins in Spyder use a global font. This is a convenience method in case some plugins will have a delta size based on the default size. """ if rich_text: option = 'rich_font' font_size_delta = self.RICH_FONT_SIZE_DELTA else: option = 'font' font_size_delta = self.FONT_SIZE_DELTA return get_font(option=option, font_size_delta=font_size_delta)
def get_plugin_font(self, rich_text=False): """ Return plugin font option. All plugins in Spyder use a global font. This is a convenience method in case some plugins will have a delta size based on the default size. """ if rich_text: option = 'rich_font' font_size_delta = self.RICH_FONT_SIZE_DELTA else: option = 'font' font_size_delta = self.FONT_SIZE_DELTA return get_font(option=option, font_size_delta=font_size_delta)
def createEditor(self, parent, option, index): """Create editor widget""" model = index.model() value = model.get_value(index) if model._data.dtype.name == "bool": value = not value model.setData(index, to_qvariant(value)) return elif value is not np.ma.masked: editor = QLineEdit(parent) editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) editor.setAlignment(Qt.AlignCenter) if is_number(self.dtype): editor.setValidator(QDoubleValidator(editor)) editor.returnPressed.connect(self.commitAndCloseEditor) return editor
def createEditor(self, parent, option, index): """Create editor widget""" model = index.model() value = model.get_value(index) if model._data.dtype.name == "bool": value = not value model.setData(index, to_qvariant(value)) return elif value is not np.ma.masked: editor = QLineEdit(parent) editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) editor.setAlignment(Qt.AlignCenter) if is_number(self.dtype): editor.setValidator(QDoubleValidator(editor)) editor.returnPressed.connect(self.commitAndCloseEditor) return editor
def data(self, index, role=Qt.DisplayRole): """Cell content""" if not index.isValid(): return to_qvariant() if role == Qt.DisplayRole or role == Qt.EditRole: column = index.column() row = index.row() if column == 0: df_idx = self.df_index[row] if is_type_text_string(df_idx): # Don't perform any conversion on strings # because it leads to differences between # the data present in the dataframe and # what is shown by Spyder return df_idx else: return to_qvariant(to_text_string(df_idx)) else: value = self.get_value(row, column - 1) if isinstance(value, float): try: return to_qvariant(self._format % value) except (ValueError, TypeError): # may happen if format = '%d' and value = NaN; # see issue 4139 return to_qvariant(DEFAULT_FORMAT % value) elif is_type_text_string(value): # Don't perform any conversion on strings # because it leads to differences between # the data present in the dataframe and # what is shown by Spyder return value else: try: return to_qvariant(to_text_string(value)) except Exception: self.display_error_idxs.append(index) return u'Display Error!' elif role == Qt.BackgroundColorRole: return to_qvariant(self.get_bgcolor(index)) elif role == Qt.FontRole: return to_qvariant(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) elif role == Qt.ToolTipRole: if index in self.display_error_idxs: return _("It is not possible to display this value because\n" "an error ocurred while trying to do it") return to_qvariant()
def data(self, index, role=Qt.DisplayRole): """Cell content.""" if not index.isValid(): return to_qvariant() value = self.get_value(index) dtn = self._data.dtype.name # Tranform binary string to unicode so they are displayed # correctly if is_binary_string(value): try: value = to_text_string(value, 'utf8') except Exception: pass # Handle roles if role == Qt.DisplayRole: if value is np.ma.masked: return '' else: if dtn == 'object': # We don't know what's inside an object array, so # we can't trust value repr's here. return value_to_display(value) else: try: return to_qvariant(self._format % value) except TypeError: self.readonly = True return repr(value) elif role == Qt.TextAlignmentRole: return to_qvariant(int(Qt.AlignCenter | Qt.AlignVCenter)) elif (role == Qt.BackgroundColorRole and self.bgcolor_enabled and value is not np.ma.masked and not self.has_inf): try: hue = (self.hue0 + self.dhue * (float(self.vmax) - self.color_func(value)) / (float(self.vmax) - self.vmin)) hue = float(np.abs(hue)) color = QColor.fromHsvF(hue, self.sat, self.val, self.alp) return to_qvariant(color) except (TypeError, ValueError): return to_qvariant() elif role == Qt.FontRole: return to_qvariant(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) return to_qvariant()
def __init__(self, parent=None): super().__init__(parent) # Editor options self.setup_editor( language='md', font=get_font(), wrap=True, linenumbers=False, highlight_current_line=False, ) # Header self.header = ("### What steps will reproduce the problem?\n\n" "<!--- You can use Markdown here --->\n\n") self.set_text(self.header) self.move_cursor(len(self.header)) self.header_end_pos = self.get_position('eof')
def createEditor(self, parent, option, index): """Create editor widget""" model = index.model() value = model.get_value(index) if type(value) == np.ndarray or model.readonly: # The editor currently cannot properly handle this case return elif model._data.dtype.name == "bool": value = not value model.setData(index, to_qvariant(value)) return elif value is not np.ma.masked: editor = QLineEdit(parent) editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) editor.setAlignment(Qt.AlignCenter) if is_number(self.dtype): validator = QDoubleValidator(editor) validator.setLocale(QLocale('C')) editor.setValidator(validator) editor.returnPressed.connect(self.commitAndCloseEditor) return editor
def __init__(self, parent, statusbar, icon=None): """Status bar widget base.""" super(StatusBarWidget, self).__init__(parent) # Variables self.value = None # Widget self._status_bar = statusbar self._icon = None self._pixmap = None self._icon_size = QSize(16, 16) # Should this be adjustable? self.label_icon = QLabel() if icon is not None else None self.label_value = QLabel() # Widget setup self.set_icon(icon) # See spyder-ide/spyder#9044. self.text_font = QFont(get_font(option='font')) self.text_font.setPointSize(self.font().pointSize()) self.text_font.setBold(True) self.label_value.setAlignment(Qt.AlignRight) self.label_value.setFont(self.text_font) # Layout layout = QHBoxLayout() if icon is not None: layout.addWidget(self.label_icon) layout.addWidget(self.label_value) layout.addSpacing(20) # Layout setup layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # Setup statusbar.addPermanentWidget(self) self.set_value('') self.update_tooltip()
def __init__(self, parent, statusbar, icon=None): """Status bar widget base.""" super(StatusBarWidget, self).__init__(parent) # Variables self.value = None # Widget self._icon = icon self._pixmap = icon.pixmap(QSize(16, 16)) if icon is not None else None self.label_icon = QLabel() if icon is not None else None self.label_value = QLabel() # Widget setup if icon is not None: self.label_icon.setPixmap(self._pixmap) # See spyder-ide/spyder#9044. self.text_font = QFont(get_font(option='font')) self.text_font.setPointSize(self.font().pointSize()) self.text_font.setBold(True) self.label_value.setAlignment(Qt.AlignRight) self.label_value.setFont(self.text_font) if self.TIP: self.setToolTip(self.TIP) self.label_value.setToolTip(self.TIP) # Layout layout = QHBoxLayout() if icon is not None: layout.addWidget(self.label_icon) layout.addWidget(self.label_value) layout.addSpacing(20) # Layout setup layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # Setup statusbar.addPermanentWidget(self)
def __init__(self, parent, statusbar, icon=None): """Status bar widget base.""" super(StatusBarWidget, self).__init__(parent) # Variables self.value = None # Widget self._icon = icon self._pixmap = icon.pixmap(QSize(16, 16)) if icon is not None else None self.label_icon = QLabel() if icon is not None else None self.label_value = QLabel() # Widget setup if icon is not None: self.label_icon.setPixmap(self._pixmap) self.text_font = QFont(get_font(option='font')) # See Issue #9044 self.text_font.setPointSize(self.font().pointSize()) self.text_font.setBold(True) self.label_value.setAlignment(Qt.AlignRight) self.label_value.setFont(self.text_font) if self.TIP: self.setToolTip(self.TIP) self.label_value.setToolTip(self.TIP) # Layout layout = QHBoxLayout() if icon is not None: layout.addWidget(self.label_icon) layout.addWidget(self.label_value) layout.addSpacing(20) # Layout setup layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # Setup statusbar.addPermanentWidget(self)
def test(): from spyder.utils.qthelpers import qapplication app = qapplication() from spyder.plugins.variableexplorer import VariableExplorer settings = VariableExplorer.get_settings() shell = ExternalPythonShell(pythonexecutable=sys.executable, interact=True, stand_alone=settings, wdir=osp.dirname(__file__), mpl_backend=0, light_background=False) from spyder.config.gui import get_font font = get_font() shell.shell.set_font(font) shell.shell.toggle_wrap_mode(True) shell.start_shell(False) shell.show() sys.exit(app.exec_())
def test(): from spyder.utils.qthelpers import qapplication app = qapplication() from spyder.plugins.variableexplorer import VariableExplorer settings = VariableExplorer.get_settings() shell = ExternalPythonShell(pythonexecutable=sys.executable, interact=True, stand_alone=settings, wdir=osp.dirname(__file__), mpl_backend=0, light_background=False) from spyder.config.gui import get_font font = get_font() shell.shell.set_font(font) shell.shell.toggle_wrap_mode(True) shell.start_shell(False) shell.show() sys.exit(app.exec_())
def setup_completion(self): size = CONF.get('main', 'completion/size') font = get_font() self.completion_widget.setup_appearance(size, font)
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 get_font(self, option): """Return global font used in Spyder.""" return get_font(option=option)
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 set_infowidget_font(self): """Set font for infowidget""" font = get_font(option='rich_font') self.infowidget.set_font(font)
def createEditor(self, parent, option, index): """Overriding method createEditor""" if self.show_warning(index): answer = QMessageBox.warning( self.parent(), _("Warning"), _("Opening this variable can be slow\n\n" "Do you want to continue anyway?"), QMessageBox.Yes | QMessageBox.No) if answer == QMessageBox.No: return None try: value = self.get_value(index) try: self.old_obj = value.copy() except AttributeError: self.old_obj = copy.deepcopy(value) if value is None: return None except Exception as msg: QMessageBox.critical( self.parent(), _("Error"), _("Spyder was unable to retrieve the value of " "this variable from the console.<br><br>" "The error message was:<br>" "<i>%s</i>") % to_text_string(msg)) return self.current_index = index key = index.model().get_key(index).obj_name readonly = (isinstance(value, (tuple, set)) or self.parent().readonly or not is_known_type(value)) # CollectionsEditor for a list, tuple, dict, etc. if isinstance(value, (list, set, tuple, dict)): from spyder.widgets.collectionseditor import CollectionsEditor editor = CollectionsEditor(parent=parent) editor.setup(value, key, icon=self.parent().windowIcon(), readonly=readonly) self.create_dialog( editor, dict(model=index.model(), editor=editor, key=key, readonly=readonly)) return None # ArrayEditor for a Numpy array elif (isinstance(value, (ndarray, MaskedArray)) and ndarray is not FakeObject): editor = ArrayEditor(parent=parent) if not editor.setup_and_check(value, title=key, readonly=readonly): return self.create_dialog( editor, dict(model=index.model(), editor=editor, key=key, readonly=readonly)) return None # ArrayEditor for an images elif (isinstance(value, Image) and ndarray is not FakeObject and Image is not FakeObject): arr = array(value) editor = ArrayEditor(parent=parent) if not editor.setup_and_check(arr, title=key, readonly=readonly): return conv_func = lambda arr: Image.fromarray(arr, mode=value.mode) self.create_dialog( editor, dict(model=index.model(), editor=editor, key=key, readonly=readonly, conv=conv_func)) return None # DataFrameEditor for a pandas dataframe, series or index elif (isinstance(value, (DataFrame, Index, Series)) and DataFrame is not FakeObject): editor = DataFrameEditor(parent=parent) if not editor.setup_and_check(value, title=key): return editor.dataModel.set_format(index.model().dataframe_format) editor.sig_option_changed.connect(self.change_option) self.create_dialog( editor, dict(model=index.model(), editor=editor, key=key, readonly=readonly)) return None # QDateEdit and QDateTimeEdit for a dates or datetime respectively elif isinstance(value, datetime.date): if readonly: return None else: if isinstance(value, datetime.datetime): editor = QDateTimeEdit(value, parent=parent) else: editor = QDateEdit(value, parent=parent) editor.setCalendarPopup(True) editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) return editor # TextEditor for a long string elif is_text_string(value) and len(value) > 40: te = TextEditor(None, parent=parent) if te.setup_and_check(value): editor = TextEditor(value, key, readonly=readonly, parent=parent) self.create_dialog( editor, dict(model=index.model(), editor=editor, key=key, readonly=readonly)) return None # QLineEdit for an individual value (int, float, short string, etc) elif is_editable_type(value): if readonly: return None else: editor = QLineEdit(parent=parent) editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) editor.setAlignment(Qt.AlignLeft) # This is making Spyder crash because the QLineEdit that it's # been modified is removed and a new one is created after # evaluation. So the object on which this method is trying to # act doesn't exist anymore. # editor.returnPressed.connect(self.commitAndCloseEditor) return editor # An arbitrary Python object. # Since we are already in the Object Explorer no editor is needed else: return None
def createEditor(self, parent, option, index, object_explorer=False): """Overriding method createEditor""" val_type = index.sibling(index.row(), 1).data() self.sig_open_editor.emit() if index.column() < 3: return None if self.show_warning(index): answer = QMessageBox.warning( self.parent(), _("Warning"), _("Opening this variable can be slow\n\n" "Do you want to continue anyway?"), QMessageBox.Yes | QMessageBox.No) if answer == QMessageBox.No: return None try: value = self.get_value(index) if value is None: return None except ImportError as msg: self.sig_editor_shown.emit() module = str(msg).split("'")[1] if module in ['pandas', 'numpy']: if module == 'numpy': val_type = 'array' else: val_type = 'dataframe, series' QMessageBox.critical( self.parent(), _("Error"), _("Spyder is unable to show the {val_type} or object " "you're trying to view because <tt>{module}</tt> was " "not installed alongside Spyder. Please install " "this package in your Spyder environment." "<br>").format(val_type=val_type, module=module)) return else: QMessageBox.critical( self.parent(), _("Error"), _("Spyder is unable to show the variable you're " "trying to view because the module " "<tt>{module}</tt> was not found in your " "Spyder environment. Please install " "this package in your Spyder environment." "<br>").format(module=module)) return except Exception as msg: QMessageBox.critical( self.parent(), _("Error"), _("Spyder was unable to retrieve the value of " "this variable from the console.<br><br>" "The error message was:<br>" "%s") % to_text_string(msg)) return key = index.model().get_key(index) readonly = (isinstance(value, (tuple, set)) or self.parent().readonly or not is_known_type(value)) # CollectionsEditor for a list, tuple, dict, etc. if isinstance(value, (list, set, tuple, dict)) and not object_explorer: from spyder.widgets.collectionseditor import CollectionsEditor editor = CollectionsEditor(parent=parent) editor.setup(value, key, icon=self.parent().windowIcon(), readonly=readonly) self.create_dialog( editor, dict(model=index.model(), editor=editor, key=key, readonly=readonly)) return None # ArrayEditor for a Numpy array elif (isinstance(value, (ndarray, MaskedArray)) and ndarray is not FakeObject and not object_explorer): editor = ArrayEditor(parent=parent) if not editor.setup_and_check(value, title=key, readonly=readonly): return self.create_dialog( editor, dict(model=index.model(), editor=editor, key=key, readonly=readonly)) return None # ArrayEditor for an images elif (isinstance(value, Image) and ndarray is not FakeObject and Image is not FakeObject and not object_explorer): arr = array(value) editor = ArrayEditor(parent=parent) if not editor.setup_and_check(arr, title=key, readonly=readonly): return conv_func = lambda arr: Image.fromarray(arr, mode=value.mode) self.create_dialog( editor, dict(model=index.model(), editor=editor, key=key, readonly=readonly, conv=conv_func)) return None # DataFrameEditor for a pandas dataframe, series or index elif (isinstance(value, (DataFrame, Index, Series)) and DataFrame is not FakeObject and not object_explorer): editor = DataFrameEditor(parent=parent) if not editor.setup_and_check(value, title=key): return editor.dataModel.set_format(index.model().dataframe_format) editor.sig_option_changed.connect(self.change_option) self.create_dialog( editor, dict(model=index.model(), editor=editor, key=key, readonly=readonly)) return None # QDateEdit and QDateTimeEdit for a dates or datetime respectively elif isinstance(value, datetime.date) and not object_explorer: # Needed to handle NaT values # See spyder-ide/spyder#8329 try: value.time() except ValueError: self.sig_editor_shown.emit() return None if readonly: self.sig_editor_shown.emit() return None else: if isinstance(value, datetime.datetime): editor = QDateTimeEdit(value, parent=parent) else: editor = QDateEdit(value, parent=parent) editor.setCalendarPopup(True) editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) self.sig_editor_shown.emit() return editor # TextEditor for a long string elif is_text_string(value) and len(value) > 40 and not object_explorer: te = TextEditor(None, parent=parent) if te.setup_and_check(value): editor = TextEditor(value, key, readonly=readonly, parent=parent) self.create_dialog( editor, dict(model=index.model(), editor=editor, key=key, readonly=readonly)) return None # QLineEdit for an individual value (int, float, short string, etc) elif is_editable_type(value) and not object_explorer: if readonly: self.sig_editor_shown.emit() return None else: editor = QLineEdit(parent=parent) editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA)) editor.setAlignment(Qt.AlignLeft) # This is making Spyder crash because the QLineEdit that it's # been modified is removed and a new one is created after # evaluation. So the object on which this method is trying to # act doesn't exist anymore. # editor.returnPressed.connect(self.commitAndCloseEditor) self.sig_editor_shown.emit() return editor # ObjectExplorer for an arbitrary Python object else: show_callable_attributes = index.model().show_callable_attributes show_special_attributes = index.model().show_special_attributes dataframe_format = index.model().dataframe_format if show_callable_attributes is None: show_callable_attributes = False if show_special_attributes is None: show_special_attributes = False from spyder.plugins.variableexplorer.widgets.objectexplorer \ import ObjectExplorer editor = ObjectExplorer( value, name=key, parent=parent, show_callable_attributes=show_callable_attributes, show_special_attributes=show_special_attributes, dataframe_format=dataframe_format, readonly=readonly) editor.sig_option_changed.connect(self.change_option) self.create_dialog( editor, dict(model=index.model(), editor=editor, key=key, readonly=readonly)) return None
def __init__(self, parent=None, is_report=False): QDialog.__init__(self, parent) self.is_report = is_report self.setWindowTitle(_("Issue reporter")) self.setModal(True) # To save the traceback sent to the internal console self.error_traceback = "" # Dialog main label if self.is_report: title = _("Please fill the following information") else: title = _("Spyder has encountered an internal problem!") main_label = QLabel( _("<h3>{title}</h3>" "Before reporting this problem, <i>please</i> consult our " "comprehensive " "<b><a href=\"{trouble_url}\">Troubleshooting Guide</a></b> " "which should help solve most issues, and search for " "<b><a href=\"{project_url}\">known bugs</a></b> " "matching your error message or problem description for a " "quicker solution." ).format(title=title, trouble_url=__trouble_url__, project_url=__project_url__)) main_label.setOpenExternalLinks(True) main_label.setWordWrap(True) main_label.setAlignment(Qt.AlignJustify) main_label.setStyleSheet('font-size: 12px;') # Issue title self.title = QLineEdit() self.title.textChanged.connect(self._contents_changed) self.title_chars_label = QLabel(_("{} more characters " "to go...").format(TITLE_MIN_CHARS)) form_layout = QFormLayout() form_layout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow) red_asterisk = '<font color="Red">*</font>' title_label = QLabel(_("<b>Title</b>: {}").format(red_asterisk)) form_layout.setWidget(0, QFormLayout.LabelRole, title_label) form_layout.setWidget(0, QFormLayout.FieldRole, self.title) # Description steps_header = QLabel( _("<b>Steps to reproduce:</b> {}").format(red_asterisk)) steps_text = QLabel(_("Please enter a detailed step-by-step " "description (in English) of what led up to " "the problem below. Issue reports without a " "clear way to reproduce them will be closed.")) steps_text.setWordWrap(True) steps_text.setAlignment(Qt.AlignJustify) steps_text.setStyleSheet('font-size: 12px;') # 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._contents_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.desc_chars_label = QLabel(_("{} more characters " "to go...").format(DESC_MIN_CHARS)) # Checkbox to dismiss future errors self.dismiss_box = QCheckBox(_("Hide all future errors during this " "session")) if self.is_report: self.dismiss_box.hide() # Dialog buttons gh_icon = ima.icon('github') self.submit_btn = QPushButton(gh_icon, _('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) if self.is_report: self.details_btn.hide() self.close_btn = QPushButton(_('Close')) if self.is_report: self.close_btn.clicked.connect(self.reject) # 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 layout = QVBoxLayout() layout.addWidget(main_label) layout.addSpacing(20) layout.addLayout(form_layout) layout.addWidget(self.title_chars_label) layout.addSpacing(12) layout.addWidget(steps_header) layout.addSpacing(-1) layout.addWidget(steps_text) layout.addSpacing(1) layout.addWidget(self.input_description) layout.addWidget(self.details) layout.addWidget(self.desc_chars_label) layout.addSpacing(15) layout.addWidget(self.dismiss_box) layout.addSpacing(15) layout.addLayout(buttons_layout) layout.setContentsMargins(25, 20, 25, 10) self.setLayout(layout) self.resize(570, 600) self.title.setFocus() # Set Tab key focus order self.setTabOrder(self.title, self.input_description)