def create(self, window: QtGui.QMainWindow, parent_menu: QtGui.QMenu): if self.disabled: return if callable(self.method_name): method = self.method_name else: method = getattr(window, self.method_name) if self.sep: parent_menu.addSeparator() if self.submenu: menu = QtGui.QMenu(self.verbose_name, p(parent_menu)) if self.icon: action = parent_menu.addMenu(get_icon(self.icon), menu) else: action = parent_menu.addMenu(menu) action.hovered.connect(functools.partial(self.fill_submenu, window, menu, method)) else: if self.icon: action = QtGui.QAction(get_icon(self.icon), self.verbose_name, p(parent_menu)) else: action = QtGui.QAction(self.verbose_name, p(parent_menu)) # noinspection PyUnresolvedReferences action.triggered.connect(method) parent_menu.addAction(action) if self.shortcut: action.setShortcut(self.shortcut) if self.help_text: action.setStatusTip(self.help_text)
def _fill_grid_layout(self, layout: QtGui.QGridLayout): """ Fill a QGridLayout with all MultiForms and Field, in the right order :param layout: :return: """ all_components = [] for multiform in self._multiforms.values(): all_components.append(multiform) for field in self._fields.values(): all_components.append(field) all_components.sort(key=self._sort_components) row_offset = layout.rowCount() for row_index, obj in enumerate(all_components): if isinstance(obj, MultiForm): # a MultiForm already is a QWidget layout.addWidget(obj, row_offset + row_index, 0, 1, 2) elif isinstance(obj, SubForm): widget = QtGui.QGroupBox(str(obj.verbose_name), p(self)) sub_layout = QtGui.QGridLayout(p(widget)) obj._fill_grid_layout(sub_layout) widget.setLayout(sub_layout) layout.addWidget(widget, row_offset + row_index, 0, 1, 2) else: widget = obj.get_widget(self, self) self._widgets[obj.name] = widget obj.set_widget_value(widget, self._values[obj.name]) if obj.label: label = QtGui.QLabel(obj.label, p(self)) label.setDisabled(obj.disabled) layout.addWidget(label, row_offset + row_index, 0) layout.addWidget(widget, row_offset + row_index, 1)
def _fill_form_layout(self, layout: QtGui.QFormLayout): """ Fill a QGridLayout with all MultiForms and Field, in the right order :param layout: :return: """ all_components = [] for multiform in self._multiforms.values(): all_components.append(multiform) for field in self._fields.values(): all_components.append(field) all_components.sort(key=self._sort_components) for row_index, obj in enumerate(all_components): if isinstance(obj, MultiForm): # a MultiForm already is a QWidget layout.addRow(obj) elif isinstance(obj, SubForm): widget = QtGui.QGroupBox(str(obj.verbose_name), p(self)) sub_layout = QtGui.QFormLayout(p(widget)) obj._fill_form_layout(sub_layout) widget.setLayout(sub_layout) layout.addRow(widget) else: widget = obj.get_widget(self, self) self._widgets[obj.name] = widget obj.set_widget_value(widget, self._values[obj.name]) layout.addRow(obj.label or '', widget)
def get_widget(self, field_group, parent=None): if self.verbose_name: editor = QtGui.QCheckBox(self.verbose_name, p(parent)) else: editor = QtGui.QCheckBox(p(parent)) if self.help_text: editor.setToolTip(self.help_text) editor.setDisabled(self.disabled) return editor
def __init__(self, initial=None, parent=None): QtGui.QGroupBox.__init__(self, p(parent)) self._stacked_names = QtGui.QComboBox(p(self)) # noinspection PyUnresolvedReferences self._stacked_names.currentIndexChanged.connect(self._change_widget) self._stacked_widget = QtGui.QStackedWidget(p(self)) MultiForm.__init__(self, initial=initial) self.setTitle(str(self.verbose_name)) self.setLayout(v_layout(self, self._stacked_names, self._stacked_widget))
def __init__(self, initial=None, parent=None): BaseForm.__init__(self, initial=initial) BaseDock.__init__(self, parent=p(parent)) # widget creation widgets = [] if self.description: widgets.append(QtGui.QLabel(self.description, p(self))) sub_layout = QtGui.QGridLayout(p(self)) self._fill_grid_layout(layout=sub_layout) widgets.append(sub_layout) sub_widget = QtGui.QWidget(p(self)) sub_widget.setLayout(v_layout(self, *widgets)) self.setWidget(sub_widget)
def __init__(self, message, parent=None): super().__init__(p(parent)) widgets = [] if application.splashscreen_icon: pixmap = get_pixmap(application.splashscreen_icon) label = QtGui.QLabel(p(self)) label.setPixmap(pixmap) widgets.append(label) edit = QtGui.QTextEdit(message, self) edit.setReadOnly(True) widgets.append(edit) widgets.append(create_button(_('Close'), min_size=True, parent=self, connect=self.close)) self.setLayout(v_layout(self, *widgets))
def get_widget(self, field_group, parent=None): regexp = None if self.base_type == int: regexp = r'\d+(,\d+)*' elif self.base_type == float: regexp = r'(\?.\d+|\d+\.\d*)(,\?.\d+|,\d+\.\d)*' editor = QtGui.QLineEdit(p(parent)) editor.setDisabled(self.disabled) if self.help_text is not None: editor.setToolTip(self.help_text) if regexp is not None: editor.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(regexp), p(parent))) return editor
def get_widget(self, field_group, parent=None): editor = QtGui.QLineEdit(p(parent)) if self.help_text is not None: editor.setToolTip(self.help_text) editor.setValidator(self.widget_validator) editor.setDisabled(self.disabled) return editor
def __generic_layout(parent, layout, extra_args, args): for arg in args: if isinstance(arg, QtGui.QLayout): sub_widget = QtGui.QWidget(p(parent)) sub_widget.setLayout(arg) layout.addWidget(sub_widget, *extra_args) elif isinstance(arg, QtGui.QWidget): layout.addWidget(arg, *extra_args) return layout
def create(self, window: QtGui.QMainWindow, parent: QtGui.QToolBar): if self.disabled: return if callable(self.method_name): method = self.method_name else: method = getattr(window, self.method_name) if self.sep: parent.addSeparator() if self.icon: action = QtGui.QAction(get_icon(self.icon), self.verbose_name, p(window)) else: action = QtGui.QAction(self.verbose_name, p(window)) # noinspection PyUnresolvedReferences action.triggered.connect(method) parent.addAction(action) if self.shortcut: action.setShortcut(self.shortcut) if self.help_text: action.setStatusTip(self.help_text)
def __init__(self, filename: str = None, selection_filter: str = None, parent: QtGui.QWidget = None): self.selection_filter = selection_filter self.filename = None super().__init__(parent) self.select_button = create_button( _("Choose a file…"), min_size=True, connect=self.select_file, icon="edit-find" ) self.line_editor = QtGui.QLineEdit(p(self)) self.set_value(filename) layout = h_layout(self, self.select_button, self.line_editor) self.setLayout(layout) self.adjustSize()
def select_file(self): try: from qthelpers.application import application dirname = application.GlobalInfos.last_open_folder except AttributeError: dirname = os.path.expanduser("~") # noinspection PyTypeChecker filename, selected_filter = QtGui.QFileDialog.getOpenFileName( p(self), _("Select a file"), dirname, self.selection_filter, "", 0 ) if filename: self.set_value(filename)
def create_button(legend: str='', icon: str=None, min_size: bool=False, connect=None, help_text: str=None, flat: bool=False, parent=None, default=False): if isinstance(icon, str): button = QtGui.QPushButton(get_icon(icon), legend, p(parent)) elif icon: button = QtGui.QPushButton(icon, legend, p(parent)) else: button = QtGui.QPushButton(legend, p(parent)) if min_size: size = button.minimumSizeHint() if not legend: size.setWidth(button.iconSize().width() + 4) button.setFixedSize(size) if help_text: button.setToolTip(help_text) if default: button.setDefault(True) button.setFlat(flat) if connect is not None: # noinspection PyUnresolvedReferences button.clicked.connect(connect) return button
def __init__(self, initial=None, parent=None): QtGui.QDialog.__init__(self, p(parent)) BaseForm.__init__(self, initial=initial) ThreadedCalls.__init__(self) # widget creation widgets = [] if self.description: widgets.append(QtGui.QLabel(self.description, p(self))) sub_layout = QtGui.QFormLayout(self) self._fill_form_layout(layout=sub_layout) widgets.append(sub_layout) self._buttons = [] if self.text_confirm: self._buttons.append(create_button(self.text_confirm, connect=self.accept, min_size=True)) if self.text_cancel: self._buttons.append(create_button(self.text_cancel, connect=self.reject, min_size=True)) if self._buttons: widgets.append(h_layout(self, *self._buttons, direction=QtGui.QBoxLayout.RightToLeft)) self.setLayout(v_layout(self, *widgets)) if self.verbose_name: self.setWindowTitle(str(self.verbose_name)) self.raise_()
def get_item(title: str, label: str, choices: list, initial: object=None) -> object: from qthelpers.fields import ChoiceField from qthelpers.forms import FormDialog class Dialog(FormDialog): verbose_name = title text_confirm = _('Select') value = ChoiceField(verbose_name=label, choices=choices, default=initial) values = Dialog.process(initial={'value': initial}, parent=p(None)) if values is None: return None return values['value']
def __init__(self, color: str = None, parent: QtGui.QWidget = None): self.color = None super().__init__(parent) self.select_button = create_button( _("Choose a color…"), min_size=True, connect=self.select_color, icon="preferences-color" ) self.line_editor = QtGui.QLineEdit(p(self)) self.line_editor.setValidator(self.validator) if not color or not COLOR_RE.match(color): color = None self.set_value(color) layout = h_layout(self, self.select_button, self.line_editor) self.setLayout(layout) self.adjustSize()
def base_set_sb_indicator(self, key, icon_name=None, message=None): if key not in self._indicators: label = QtGui.QLabel(p(self)) statusbar = self.statusBar() """:type: QtGui.QStatusBar""" statusbar.insertPermanentWidget(len(self._indicators), label, 0) self._indicators[key] = label else: label = self._indicators[key] """:type: QtGui.Label""" if icon_name is not None: label.setPixmap(get_pixmap(icon_name)) if message is not None: label.setText(message)
def __init__(self, initial: list=None, parent=None): """ :param initial: initial values, as a dictionnary {field_name: field_value} """ QtGui.QTreeWidget.__init__(self, p(parent)) if initial is None: initial = [] self._fields = {} item_count = len(initial) if self.min_number is not None: item_count = max(self.min_number, item_count) if self.max_number is not None: item_count = min(self.max_number, item_count) # noinspection PyUnusedLocal self._values = [{} for i in range(item_count)] fields = [] for cls in self.__class__.__mro__: for field_name, field in cls.__dict__.items(): if not isinstance(field, Field) or field_name in self._fields: continue self._fields[field_name] = field field.name = field_name for index in range(item_count): # get initial values if index < len(initial): self._values[index][field_name] = initial[index].get(field_name, field.default) else: self._values[index][field_name] = field.default fields.append((field.group_field_order, field_name)) fields.sort() self._field_order = [f[1] for f in fields] headers = [self._fields[field_name].verbose_name for field_name in self._field_order] if self.show_remove_button: key = '1__' self._field_order.insert(0, key) headers.insert(0, '') self._fields[key] = ButtonField(connect=self.remove_item, legend='', icon='list-remove', verbose_name='', help_text=self.remove_help_text, default=None) if self.show_add_button: key = '0__' self._field_order.insert(0, key) headers.insert(0, '') self._fields[key] = ButtonField(connect=self.add_item, legend='', icon='list-add', verbose_name='', help_text=self.add_help_text, default=None) self.setIndentation(0) self.setHeaderLabels(headers) if not self.show_headers: self.header().close() for values in self._values: self.insert_item(values, index=None)
def base_save_document_as(self): # noinspection PyCallByClass (filename, selected_filter) = QtGui.QFileDialog.getSaveFileName(p(self), _('Please choose a name'), application.GlobalInfos.last_save_folder, filter=self.document_known_extensions) if not filename: return False application.GlobalInfos.last_save_folder = os.path.dirname(filename) self.current_document_filename = filename if self.save_document(): self.current_document_is_modified = False self.base_window_title() self.base_add_recent_filename() return True return False
def base_open_document(self, filename=None): if self._base_check_is_modified(): return False if not filename: # noinspection PyCallByClass (filename, selected_filter) = QtGui.QFileDialog.getOpenFileName(p(self), _('Please select a file'), application.GlobalInfos.last_open_folder, self.document_known_extensions) if not filename: return False application.GlobalInfos.last_open_folder = os.path.dirname(filename) if not self.is_valid_document(filename): warning(_('Invalid document'), _('Unable to open document %(filename)s.') % {'filename': os.path.basename(filename)}, only_ok=True) return False self.unload_document() self.current_document_filename = filename self.current_document_is_modified = False self.base_window_title() self.base_add_recent_filename() self.load_document() return True
def __init__(self, parent=None): QtGui.QMainWindow.__init__(self, p(parent)) ThreadedCalls.__init__(self) self._window_id = next(BaseMainWindow._window_counter) self._docks = {} application.windows[self._window_id] = self # retrieve menus and associated actions from the whole class hierarchy menubar = self.menuBar() defined_qmenus = {} created_action_keys = set() supernames = [x.__name__.rpartition('.')[2] for x in self.__class__.__mro__] supernames.reverse() for menu_name in self.menus: defined_qmenus[menu_name] = menubar.addMenu(menu_name) for cls_name in supernames: for menu_name in registered_menus.get(cls_name, []): # create all top-level menus if menu_name not in defined_qmenus: defined_qmenus[menu_name] = menubar.addMenu(menu_name) supernames.reverse() for cls_name in supernames: for menu_action in registered_menu_actions.get(cls_name, []): if menu_action.uid in created_action_keys: # skip overriden actions (there are already created) continue created_action_keys.add(menu_action.uid) menu_action.create(self, defined_qmenus[menu_action.menu]) # retrieve toolbar actions from the whole class hierarchy self.setUnifiedTitleAndToolBarOnMac(True) defined_qtoolbars = {} created_action_keys = set() for superclass in self.__class__.__mro__: cls_name = superclass.__name__.rpartition('.')[2] if cls_name not in registered_toolbars: continue for toolbar_name in registered_toolbars[cls_name]: # create all top-level menus if toolbar_name not in defined_qtoolbars: if toolbar_name is not None: defined_qtoolbars[toolbar_name] = BaseToolBar(toolbar_name, p(self)) else: defined_qtoolbars[toolbar_name] = BaseToolBar(_('Toolbar'), p(self)) self.addToolBar(defined_qtoolbars[toolbar_name]) for toolbar_action in registered_toolbar_actions[cls_name]: if toolbar_action.uid in created_action_keys: # skip overriden actions (there are already created) continue created_action_keys.add(toolbar_action.uid) toolbar_action.create(self, defined_qtoolbars[toolbar_action.toolbar]) # create all dock widgets for dock_cls in self.docks: """:type dock_cls: type""" if not isinstance(dock_cls, type) or not issubclass(dock_cls, BaseDock): continue dock = dock_cls(parent=self) """:type dock: BaseDock""" self._docks[dock_cls] = dock self.addDockWidget(dock.default_position, dock) menu_name = dock.menu if menu_name is not None: if menu_name not in defined_qmenus: defined_qmenus[menu_name] = menubar.addMenu(menu_name) connect = functools.partial(self._base_swap_dock_display, dock_cls) action = MenuAction(connect, verbose_name=dock.verbose_name, menu=menu_name, shortcut=dock.shortcut) action.create(self, defined_qmenus[menu_name]) # some extra stuff self.setWindowTitle(self.verbose_name) if self.description_icon: self.setWindowIcon(get_icon(self.description_icon)) self.setCentralWidget(self.central_widget()) # restore state and geometry # noinspection PyBroadException self.adjustSize() try: cls_name = self.__class__.__name__ if cls_name in application['GlobalInfos/main_window_geometries']: geometry_str = application['GlobalInfos/main_window_geometries'][cls_name].encode('utf-8') geometry = base64.b64decode(geometry_str) self.restoreGeometry(geometry) if cls_name in application['GlobalInfos/main_window_states']: state_str = application['GlobalInfos/main_window_states'][cls_name].encode('utf-8') state = base64.b64decode(state_str) self.restoreState(state) except ValueError: pass self.raise_()
def __init__(self, parent=None): QtGui.QDockWidget.__init__(self, str(self.verbose_name), p(parent)) ThreadedCalls.__init__(self) self.parent_window = weakref.ref(parent) self.setObjectName(self.__class__.__name__)
def get_widget(self, field_group, parent=None): value = field_group connect = functools.partial(self.connect, value) return create_button(self.legend, icon=self.icon, min_size=True, flat=True, help_text=self.help_text, connect=connect, parent=p(parent))
def __init__(self, initial=None, parent=None): BaseForm.__init__(self, initial=initial) QtGui.QWidget.__init__(self, p(parent)) layout = QtGui.QGridLayout(p(parent)) self._fill_grid_layout(layout) self.setLayout(layout)
def get_widget(self, field_group, parent=None): widget = QtGui.QComboBox(p(parent)) for value, text_value in self.choices: widget.addItem(text_value, value) widget.setDisabled(self.disabled) return widget
def __init__(self, initial=None, parent=None): QtGui.QTabWidget.__init__(self, p(parent)) MultiForm.__init__(self, initial=initial)
def __init__(self, initial=None, parent=None): QtGui.QToolBox.__init__(self, p(parent)) MultiForm.__init__(self, initial=initial)
def get_widget(self, field_group, parent=None): button = Button(p(parent), self.connect, icon=self.icon, legend=self.legend, min_size=True, flat=True, tooltip=self.help_text) button.args = [field_group] return button
def get_widget(self, field_group, parent=None): editor = QtGui.QLabel(p(parent)) if self.help_text is not None: editor.setToolTip(self.help_text) return editor