def __init__(self, parent=None, **kwargs): super(ProgressCricle, self).__init__(parent) self._infinite = False self._timer = QtCore.QTimer(self) self._timer.timeout.connect(self._on_increase_value) self._main_layout = QtWidgets.QHBoxLayout() self._default_label = QtWidgets.QLabel() self._default_label.setAlignment(QtCore.Qt.AlignCenter) self._main_layout.addWidget(self._default_label) self.setLayout(self._main_layout) self._color = QtGui.QColor(221, 235, 230) self._width = kwargs.get('width', 140) self.setTextDirection(self.Direction.BottomToTop) self._start_angle = 90 * 16 self._max_delta_angle = 360 * 16 self._height_factor = 1.0 self._width_factor = 1.0 self.setFixedSize( QtCore.QSize(self._width * self._width_factor, self._width * self._height_factor))
def setup_ui(self): super(ProgressSplashDialog, self).setup_ui() self._stack = stack.SlidingOpacityStackedWidget(parent=self) self._splash_layout.addStretch() self._splash_layout.addWidget(self._stack) progress_widget = QtWidgets.QWidget(parent=self) progress_layout = QtWidgets.QVBoxLayout() progress_widget.setLayout(progress_layout) self._progress = ProgressCricle() progress_lyt = QtWidgets.QHBoxLayout() progress_lyt.addStretch() progress_lyt.addWidget(self._progress) progress_lyt.addStretch() self._progress_text = QtWidgets.QLabel('Wait please ...') progress_txt_lyt = QtWidgets.QHBoxLayout() progress_txt_lyt.addStretch() progress_txt_lyt.addWidget(self._progress_text) progress_txt_lyt.addStretch() progress_layout.addStretch() progress_layout.addLayout(progress_lyt) progress_layout.addLayout(progress_txt_lyt) self._stack.addWidget(progress_widget)
def setup_ui(self): super(InfoSplashDialog, self).setup_ui() self._progress_text = QtWidgets.QLabel('Wait please ...') progress_text_layout = QtWidgets.QHBoxLayout() progress_text_layout.addStretch() progress_text_layout.addWidget(self._progress_text) progress_text_layout.addStretch() self._splash_layout.addLayout(progress_text_layout)
def _fill_data(self): current_plugin_version = dccplugin.DccPlugin().get_version() or 'Undefined' self._artella_dcc_plugin_version_label.setText(current_plugin_version) added_packages = dict() # Retrieve Artella plugins versions all_plugins = plugins.plugins() for plugin_id, plugin_data in all_plugins.items(): plugin_package = plugin_data.get('package', 'Not Defined') package_item = added_packages.get(plugin_package, None) if not package_item: package_item = QtWidgets.QTreeWidgetItem([plugin_package]) self._plugins_tree.addTopLevelItem(package_item) added_packages[plugin_package] = package_item plugin_name = plugin_data['name'] plugin_version = plugin_data.get('version', 'Undefined') plugin_item = QtWidgets.QTreeWidgetItem([plugin_name, plugin_version, plugin_id]) package_item.addChild(plugin_item) package_item = added_packages.get('Artella', None) if not package_item: package_item = QtWidgets.QTreeWidgetItem(['Artella']) self._plugins_tree.addTopLevelItem(package_item) # Retrieve DCC plugin version dcc_version = None dcc_module_name = core_dcc.CURRENT_DCC_MODULE if dcc_module_name: try: dcc_module_version = '{}.__version__'.format(dcc_module_name) dcc_version_mod = utils.import_module(dcc_module_version) dcc_version = dcc_version_mod.get_version() except Exception as exc: logger.warning('Impossible to retrieve {} Artella plugin version: {}'.format(dcc.name(), exc)) dcc_version = dcc_version or 'Undefined' dcc_version_item = QtWidgets.QTreeWidgetItem([dcc.nice_name(), dcc_version, dcc_module_name.replace('.', '- ')]) package_item.insertChild(0, dcc_version_item) # Retrieve Artella core version core_version = None core_version_path = 'artella.__version__' try: core_version_mod = utils.import_module(core_version_path) core_version = core_version_mod.get_version() except Exception as exc: logger.warning('Impossible to retrieve Artella Core version: {}'.format(exc)) core_version = core_version or 'Undefined' core_version_item = QtWidgets.QTreeWidgetItem(['Core', core_version, 'artella-plugins-core']) package_item.insertChild(0, core_version_item) self._plugins_tree.expandAll() self._plugins_tree.resizeColumnToContents(0) self._plugins_tree.resizeColumnToContents(1) self._plugins_tree.resizeColumnToContents(2)
def _add_package_tab(self, package_name): package_widget = QtWidgets.QWidget() package_layout = QtWidgets.QVBoxLayout() package_layout.setContentsMargins(2, 2, 2, 2) package_layout.setSpacing(2) package_widget.setLayout(package_layout) package_scroll = QtWidgets.QScrollArea() package_scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) package_scroll.setWidgetResizable(True) package_scroll.setWidget(package_widget) self._package_tabs.addTab(package_widget, package_name) return package_layout
def show_comment_input_dialog(title, label, text='', parent=None): """ Shows a text string input dialog that users can use to input text. :param str title: text that is displayed in the title bar of the dialog :param str label: text which is shown to the user telling them what kind of text they need to input :param str text: default text which is placed in the comment section :param QWidget parent: optional parent widget for the input text dialog. If not given, current DCC main parent window will be used. :return: Tuple containing as the first element the text typed by the user and as the second argument a boolean that will be True if the user clicked on the Ok button or False if the user cancelled the operation :rtype: tuple(str, bool) """ if not QT_AVAILABLE: return '', False from artella import dcc parent = parent if parent else dcc.get_main_window() comment_dialog = QtWidgets.QInputDialog() flags = comment_dialog.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint | QtCore.Qt.WindowStaysOnTopHint if hasattr(QtWidgets.QInputDialog, 'getMultiLineText'): comment, res = comment_dialog.getMultiLineText(parent, title, label, text=text, flags=flags) else: comment, res = comment_dialog.getText(parent, title, label, text, text=text, flags=flags) return comment, res
def show_error_message_box(title, text, parent=None): """ Shows an error message box that can be used to show critical text to users. :param str title: text that is displayed in the title bar of the dialog :param str text: default text which is placed n the plain text edit :param QWidget parent: optional parent widget for the input text dialog. If not given, current DCC main parent window will be used. """ if not QT_AVAILABLE: return from artella import dcc from artella.core import resource parent = parent if parent else dcc.get_main_window() window_icon = resource.icon('artella') message_box = QtWidgets.QMessageBox(parent) message_box.setWindowTitle(title) message_box.setWindowIcon(window_icon) message_box.setIcon(message_box.Icon.Critical) flags = message_box.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint | QtCore.Qt.WindowStaysOnTopHint if text: message_box.setText(text) message_box.setStandardButtons(QtWidgets.QMessageBox.Ok) message_box.setWindowFlags(flags) message_box.exec_()
def __init__(self, file_path, parent=None): super(DownloadItemWidget, self).__init__(parent) download_layout = QtWidgets.QHBoxLayout() self.setLayout(download_layout) self._path_label = QtWidgets.QLabel(os.path.basename(file_path)) self._progress_text = QtWidgets.QLabel('Waiting ...') self._progress = ProgressCricle(width=qtutils.dpi_scale(35)) # self._progress.setTextVisible(False) download_layout.addWidget(self._progress) download_layout.addWidget(self._path_label) download_layout.addStretch() download_layout.addWidget(self._progress_text) download_layout.addStretch() self._progress_text.setVisible(False)
def setup_ui(self): self.main_layout = self.get_main_layout() self.setLayout(self.main_layout) if self._use_artella_header: artella_frame = QtWidgets.QFrame() artella_frame.setObjectName('artellaFrame') artella_frame_layout = QtWidgets.QHBoxLayout() artella_frame.setLayout(artella_frame_layout) artella_header = QtWidgets.QLabel() artella_header_pixmap = resource.pixmap('artella_header') artella_header.setPixmap(artella_header_pixmap) artella_frame_layout.addStretch() artella_frame_layout.addWidget(artella_header) artella_frame_layout.addStretch() self.main_layout.addWidget(artella_frame)
def setup_ui(self): super(SplashDialog, self).setup_ui() self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint | QtCore.Qt.WA_DeleteOnClose) self.setAttribute(QtCore.Qt.WA_TranslucentBackground) splash_pixmap = resource.pixmap('artella_splash') splash = SplashScreen(splash_pixmap) splash.setMask(splash_pixmap.mask()) self._splash_layout = QtWidgets.QVBoxLayout() self._splash_layout.setAlignment(QtCore.Qt.AlignBottom) splash.setLayout(self._splash_layout) self.main_layout.addWidget(splash) size_width = splash_pixmap.size().width() + 20 size_height = splash_pixmap.size().height() + 20 self.setFixedSize(QtCore.QSize(size_width, size_height)) shadow_effect = QtWidgets.QGraphicsDropShadowEffect(self) shadow_effect.setBlurRadius(qtutils.dpi_scale(15)) shadow_effect.setColor(QtGui.QColor(0, 0, 0, 150)) shadow_effect.setOffset(qtutils.dpi_scale(0)) self.setGraphicsEffect(shadow_effect)
def show_question_message_box(title, text, cancel=True, parent=None): """ Shows a question message box that can be used to show question text to users. :param str title: text that is displayed in the title bar of the dialog :param str text: default text which is placed n the plain text edit :param bool cancel: Whether or not cancel button should appear in question message box :param QWidget parent: optional parent widget for the input text dialog. If not given, current DCC main parent window will be used. :return: True if the user presses the Ok button; False if the user presses the No button; None if the user preses the Cancel button :rtype: bool or None """ if not QT_AVAILABLE: return None from artella import dcc parent = parent if parent else dcc.get_main_window() message_box = QtWidgets.QMessageBox(parent) message_box.setWindowTitle(title) flags = message_box.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint | QtCore.Qt.WindowStaysOnTopHint if text: message_box.setText(text) if cancel: message_box.setStandardButtons( QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel) else: message_box.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) message_box.setWindowFlags(flags) result = message_box.exec_() if result == QtWidgets.QMessageBox.Yes: return True elif result == QtWidgets.QMessageBox.No: return False elif result == QtWidgets.QMessageBox.Cancel: return None
def setup_ui(self): super(DownloadSplashDialog, self).setup_ui() main_widget = QtWidgets.QWidget() main_layout = QtWidgets.QVBoxLayout() main_widget.setLayout(main_layout) self._stack.addWidget(main_widget) download_widget = QtWidgets.QWidget() download_layout = QtWidgets.QVBoxLayout() download_widget.setLayout(download_layout) content_area = QtWidgets.QScrollArea(parent=self) content_area.setMinimumHeight(qtutils.dpi_scale(150)) content_area.setWidgetResizable(True) content_area.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) # content_area.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) content_area.setWidget(download_widget) content_area.setStyleSheet( 'background-color: transparent; border: none;') self._download_layout = QtWidgets.QVBoxLayout() download_layout.addLayout(self._download_layout) main_layout.addStretch() main_layout.addWidget(content_area)
def setup_ui(self): super(AboutDialog, self).setup_ui() version_layout = QtWidgets.QHBoxLayout() version_layout.setContentsMargins(2, 2, 2, 2) version_layout.setSpacing(2) version_label = QtWidgets.QLabel('Version: '.format(dcc.nice_name())) self._artella_dcc_plugin_version_label = QtWidgets.QLabel() version_layout.addStretch() version_layout.addWidget(version_label) version_layout.addWidget(self._artella_dcc_plugin_version_label) version_layout.addStretch() button_layout = QtWidgets.QHBoxLayout() button_layout.setContentsMargins(2, 2, 2, 2) button_layout.setSpacing(2) self._show_plugins_btn = QtWidgets.QPushButton('Show Plugins') button_layout.addStretch() button_layout.addWidget(self._show_plugins_btn) button_layout.addStretch() self._plugins_tree = QtWidgets.QTreeWidget() self._plugins_tree.setHeaderLabels(['Name', 'Version', 'ID']) self._plugins_tree.setColumnCount(3) self._plugins_tree.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self._plugins_tree.setVisible(False) self.main_layout.addStretch() self.main_layout.addLayout(version_layout) self.main_layout.addLayout(button_layout) self.main_layout.addStretch() self.main_layout.addLayout(button_layout) self.main_layout.addStretch() self.main_layout.addWidget(self._plugins_tree) self._show_plugins_btn.clicked.connect(self._on_toggle_plugins_visibility)
def get_main_layout(self): main_layout = QtWidgets.QVBoxLayout() main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) return main_layout
def setup_ui(self): super(VersionInfoDialog, self).setup_ui() versions_layout = QtWidgets.QHBoxLayout() versions_layout.setSpacing(2) versions_layout.setContentsMargins(0, 0, 0, 0) current_version_label = QtWidgets.QLabel('Current Version: ') self._current_version_label = QtWidgets.QLabel() latest_version_label = QtWidgets.QLabel('Latest Version: ') self._latest_version_label = QtWidgets.QLabel() versions_layout.addStretch() versions_layout.addWidget(current_version_label) versions_layout.addWidget(self._current_version_label) versions_layout.addStretch() versions_layout.addWidget(latest_version_label) versions_layout.addWidget(self._latest_version_label) versions_layout.addStretch() version_message_frame = QtWidgets.QFrame() version_message_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) version_message_frame.setFrameShadow(QtWidgets.QFrame.Sunken) version_message_layout = QtWidgets.QHBoxLayout() version_message_layout.setSpacing(2) version_message_layout.setContentsMargins(0, 0, 0, 0) version_message_frame.setLayout(version_message_layout) self._version_icon = QtWidgets.QLabel() self._version_message_label = QtWidgets.QLabel() version_message_layout.addStretch() version_message_layout.addWidget(self._version_icon) version_message_layout.addWidget(self._version_message_label) version_message_layout.addStretch() buttons_layout = QtWidgets.QHBoxLayout() buttons_layout.setSpacing(2) buttons_layout.setContentsMargins(0, 0, 0, 0) self._go_to_download_web_btn = QtWidgets.QPushButton( 'Go to Artella Plugins website') buttons_layout.addWidget(self._go_to_download_web_btn) self.main_layout.addLayout(versions_layout) self.main_layout.addWidget(version_message_frame) self.main_layout.addLayout(buttons_layout) self._go_to_download_web_btn.clicked.connect( self._on_open_artella_plugins_webiste)
def __init__(self, id, name, package, version, author, email, summary, latest_version, upload_date, size, url, icon_pixmap=None, parent=None): super(PluginVersionWidget, self).__init__(parent) self._id = id self._name = name self._package = package self._version = version self._author = author self._email = email self._summary = summary self._latest_version = latest_version self._upload_date = upload_date self._size = size self._url = url icon_pixmap = (icon_pixmap or resource.pixmap('artella') or QtGui.QPixmap()).scaled( QtCore.QSize(30, 30), QtCore.Qt.KeepAspectRatio, transformMode=QtCore.Qt.SmoothTransformation) self.setFrameShape(QtWidgets.QFrame.StyledPanel) self.setFrameShadow(QtWidgets.QFrame.Raised) self.setMinimumHeight(130) main_layout = QtWidgets.QHBoxLayout() main_layout.setContentsMargins(2, 2, 2, 2) main_layout.setSpacing(2) self.setLayout(main_layout) main_info_layout = QtWidgets.QVBoxLayout() main_info_layout.setContentsMargins(2, 2, 2, 2) main_info_layout.setSpacing(2) top_layout = QtWidgets.QHBoxLayout() top_layout.setContentsMargins(2, 2, 2, 2) top_layout.setSpacing(5) self._icon_label = QtWidgets.QLabel() self._icon_label.setPixmap(icon_pixmap) self._icon_label.setAlignment(QtCore.Qt.AlignTop) self._plugin_name_label = QtWidgets.QLabel(name) self._plugin_version_label = QtWidgets.QLabel( '({})'.format(version)) plugin_name_info_layout = QtWidgets.QVBoxLayout() plugin_name_info_layout.setContentsMargins(2, 2, 2, 2) plugin_name_info_layout.setSpacing(5) plugin_name_layout = QtWidgets.QHBoxLayout() plugin_name_layout.setContentsMargins(2, 2, 2, 2) plugin_name_layout.setSpacing(2) plugin_info_layout = QtWidgets.QHBoxLayout() plugin_info_layout.setContentsMargins(2, 2, 2, 2) plugin_info_layout.setSpacing(5) plugin_name_layout.addWidget(self._plugin_name_label) plugin_name_layout.addWidget(self._plugin_version_label) plugin_name_layout.addStretch() plugin_name_info_layout.addLayout(plugin_name_layout) plugin_name_info_layout.addLayout(plugin_info_layout) plugin_name_info_layout.addStretch() self._plugin_date_label = QtWidgets.QLabel(upload_date) self._plugin_size_label = QtWidgets.QLabel(size) separator_widget = QtWidgets.QWidget() separator_layout = QtWidgets.QVBoxLayout() separator_layout.setAlignment(QtCore.Qt.AlignLeft) separator_layout.setContentsMargins(0, 0, 0, 0) separator_layout.setSpacing(0) separator_widget.setLayout(separator_layout) separator_frame = QtWidgets.QFrame() separator_frame.setMaximumHeight(15) separator_frame.setFrameShape(QtWidgets.QFrame.VLine) separator_frame.setFrameShadow(QtWidgets.QFrame.Sunken) separator_layout.addWidget(separator_frame) plugin_info_layout.addWidget(self._plugin_date_label) plugin_info_layout.addWidget(separator_widget) plugin_info_layout.addWidget(self._plugin_size_label) plugin_info_layout.addStretch() top_layout.addWidget(self._icon_label) top_layout.addLayout(plugin_name_info_layout) bottom_layout = QtWidgets.QHBoxLayout() bottom_layout.setContentsMargins(2, 2, 2, 2) bottom_layout.setSpacing(5) self._summary_text = QtWidgets.QPlainTextEdit(summary) self._summary_text.setReadOnly(True) self._summary_text.setMinimumHeight(60) self._summary_text.setFocusPolicy(QtCore.Qt.NoFocus) bottom_layout.addWidget(self._summary_text) download_layout = QtWidgets.QVBoxLayout() download_layout.setContentsMargins(2, 2, 2, 2) download_layout.setSpacing(2) self._progress = splash.ProgressCricle(width=80) self._progress_text = QtWidgets.QLabel('Wait please ...') self._ok_label = QtWidgets.QLabel() self._ok_label.setPixmap(resource.pixmap('success')) self._update_button = QtWidgets.QPushButton() self._progress.setVisible(False) self._progress_text.setVisible(False) self._ok_label.setVisible(False) progress_layout = QtWidgets.QHBoxLayout() progress_layout.addStretch() progress_layout.addWidget(self._progress) progress_layout.addStretch() progress_text_layout = QtWidgets.QHBoxLayout() progress_text_layout.addStretch() progress_text_layout.addWidget(self._progress_text) progress_text_layout.addStretch() ok_layout = QtWidgets.QHBoxLayout() ok_layout.addStretch() ok_layout.addWidget(self._ok_label) ok_layout.addStretch() download_layout.addStretch() download_layout.addLayout(progress_layout) download_layout.addLayout(progress_text_layout) download_layout.addLayout(ok_layout) download_layout.addWidget(self._update_button) download_layout.addStretch() main_info_layout.addLayout(top_layout) main_info_layout.addStretch() main_info_layout.addLayout(bottom_layout) main_info_layout.addStretch() main_info_layout.addStretch() main_layout.addLayout(main_info_layout) separator_widget = QtWidgets.QWidget() separator_layout = QtWidgets.QVBoxLayout() separator_layout.setAlignment(QtCore.Qt.AlignLeft) separator_layout.setContentsMargins(0, 0, 0, 0) separator_layout.setSpacing(0) separator_widget.setLayout(separator_layout) separator_frame = QtWidgets.QFrame() separator_frame.setFrameShape(QtWidgets.QFrame.VLine) separator_frame.setFrameShadow(QtWidgets.QFrame.Sunken) separator_layout.addWidget(separator_frame) main_layout.addWidget(separator_widget) main_layout.addLayout(download_layout) main_info_layout.addStretch() self._update_plugin_thread = QtCore.QThread(self) self._update_plugin_worker = utils.UpdatePluginWorker() self._update_plugin_worker.moveToThread(self._update_plugin_thread) self._update_plugin_worker.updateStart.connect( self._on_start_update) self._update_plugin_worker.updateFinish.connect( self._on_finish_update) self._update_plugin_thread.start() self._timer = QtCore.QTimer(self) self.updatePlugin.connect(self._update_plugin_worker.run) self._update_button.clicked.connect(self._on_update) self._timer.timeout.connect(self._on_advance_progress) self.refresh()
try: import shiboken except ImportError: try: from Shiboken import shiboken except ImportError: try: from PySide import shiboken except ImportError: pass # If QApplication does not exists we force its creation try: app = QtWidgets.QApplication.instance() if not app: QtWidgets.QApplication([]) except TypeError: QT_AVAILABLE = False DEFAULT_DPI = 96 if utils.is_python3(): long = int logger = logging.getLogger('artella') class StyleTemplate(string.Template): delimiter = '@' idpattern = r'[_a-z][_a-z0-9]*'
def __init__(self, text='', title='', duration=None, artella_type=None, closable=False, parent=None): if parent is None: parent = dcc.get_main_window() current_type = artella_type or SnackBarTypes.ARTELLA super(SnackBarMessage, self).__init__(parent) self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Dialog | QtCore.Qt.WA_DeleteOnClose) self.setAttribute(QtCore.Qt.WA_StyledBackground) self.setAttribute(QtCore.Qt.WA_TranslucentBackground) main_layout = QtWidgets.QVBoxLayout() main_layout.setContentsMargins(2, 2, 2, 2) main_layout.setSpacing(2) self.setLayout(main_layout) main_frame = QtWidgets.QFrame() main_frame.setObjectName('mainFrame') frame_layout = QtWidgets.QVBoxLayout() frame_layout.setContentsMargins(5, 5, 5, 5) frame_layout.setSpacing(5) main_frame.setLayout(frame_layout) main_layout.addWidget(main_frame) info_layout = QtWidgets.QHBoxLayout() artella_label_layout = QtWidgets.QHBoxLayout() artella_label = image.ArtellaImage.small() artella_label.set_artella_image(resource.pixmap('artella_white')) self._close_btn = button.ArtellaToolButton( parent=self).image('close').tiny().icon_only() self._close_btn.setVisible(closable or False) self._close_btn.clicked.connect(self.close) if closable: artella_label_layout.addSpacing(20) artella_label_layout.addStretch() artella_label_layout.addWidget(artella_label) artella_label_layout.addStretch() artella_label_layout.addWidget(self._close_btn) title_layout = QtWidgets.QHBoxLayout() self._title_label = label.ArtellaLabel(parent=self).strong() self._title_label.setText(title) self._title_label.setVisible(bool(text)) title_layout.addStretch() title_layout.addWidget(self._title_label) title_layout.addStretch() self._icon_label = image.ArtellaImage.small() self._icon_label.set_artella_image( resource.pixmap('{}'.format(current_type), color=vars(theme.theme()).get(current_type + '_color'))) self._content_label = label.ArtellaLabel(parent=self) self._content_label.setText(text) info_layout.addStretch() info_layout.addWidget(self._icon_label) info_layout.addWidget(self._content_label) info_layout.addStretch() frame_layout.addLayout(artella_label_layout) frame_layout.addWidget(divider.ArtellaDivider()) frame_layout.addLayout(title_layout) frame_layout.addLayout(info_layout) self._setup_timers(duration) self._on_fade_in()
def setup_ui(self): super(UpdaterWindow, self).setup_ui() self._package_tabs = QtWidgets.QTabWidget() self.main_layout.addWidget(self._package_tabs)