def setCurrentIndex(self, index): """Change the current widget being displayed with an animation.""" old_widget = self.currentWidget() new_widget = self.widget(index) if old_widget != new_widget: self.fader_widget = ui_tools.FaderWidget(self.currentWidget(), self.widget(index)) QStackedWidget.setCurrentIndex(self, index)
class SettingsPanel(QDialog): def __init__(self, plugin_manager, settings_manager, parent=None): super().__init__(parent) self.settings_manager = settings_manager self.plugin_manager = plugin_manager self.contents_widget = QListWidget() self.contents_widget.setMovement(QListView.Static) self.contents_widget.setMaximumWidth(105) self.contents_widget.setSpacing(12) self.pages_widget = QStackedWidget() self.pages_widget.addWidget(EnvironmentPage(self.settings_manager)) self.pages_widget.addWidget( PluginsPage(self.settings_manager, self.plugin_manager)) close_button = QPushButton("Close") update_button = QPushButton("Update") self.__create_icons() self.contents_widget.setCurrentRow(0) close_button.clicked.connect(self.close) update_button.clicked.connect( lambda: self.pages_widget.currentWidget().update_settings()) horizontal_layout = QHBoxLayout() horizontal_layout.addWidget(self.contents_widget) horizontal_layout.addWidget(self.pages_widget, 1) buttons_layout = QHBoxLayout() buttons_layout.addStretch(1) buttons_layout.addWidget(update_button) buttons_layout.addWidget(close_button) main_layout = QVBoxLayout() main_layout.addLayout(horizontal_layout) main_layout.addStretch(1) main_layout.addSpacing(12) main_layout.addLayout(buttons_layout) self.setLayout(main_layout) self.setWindowTitle("Settings Panel") def change_page(self, current, previous): if not current: current = previous self.pages_widget.setCurrentIndex(self.contents_widget.row(current)) def __create_icons(self): environment_button = QListWidgetItem(self.contents_widget) environment_button.setText("Environment") environment_button.setTextAlignment(Qt.AlignHCenter) environment_button.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) plugins_button = QListWidgetItem(self.contents_widget) plugins_button.setText("Plugins") plugins_button.setTextAlignment(Qt.AlignCenter) plugins_button.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.contents_widget.currentItemChanged.connect(self.change_page)
def animationDoneSlot(self): """Animation end processing function""" # Since the setCurrentIndex method is rewritten, the method of the parent class itself is used here. # self.setCurrentIndex(self._next) QStackedWidget.setCurrentIndex(self, self._next) w = self.widget(self._now) w.hide() w.move(self._pnow) self._active = 0
class StackedExample(QWidget): def __init__(self): super(StackedExample, self).__init__() self.leftlist = QListWidget() self.leftlist.insertItem(0, 'Contact') self.leftlist.insertItem(1, 'Personal') self.leftlist.insertItem(2, 'Educational') self.stack1 = QWidget() self.stack2 = QWidget() self.stack3 = QWidget() self.stack1UI() self.stack2UI() self.stack3UI() self.Stack = QStackedWidget(self) self.Stack.addWidget(self.stack1) self.Stack.addWidget(self.stack2) self.Stack.addWidget(self.stack3) hbox = QHBoxLayout(self) hbox.addWidget(self.leftlist) hbox.addWidget(self.Stack) self.setLayout(hbox) self.leftlist.currentRowChanged.connect(self.display) self.setGeometry(300, 50, 10, 10) self.setWindowTitle('StackedWidget demo') self.show() def stack1UI(self): layout = QFormLayout() layout.addRow("Name", QLineEdit()) layout.addRow("Address", QLineEdit()) #self.setTabText(0,"Contact Details") self.stack1.setLayout(layout) def stack2UI(self): layout = QFormLayout() sex = QHBoxLayout() sex.addWidget(QRadioButton("Male")) sex.addWidget(QRadioButton("Female")) layout.addRow(QLabel("Sex"), sex) layout.addRow("Date of Birth", QLineEdit()) self.stack2.setLayout(layout) def stack3UI(self): layout = QHBoxLayout() layout.addWidget(QLabel("subjects")) layout.addWidget(QCheckBox("Physics")) layout.addWidget(QCheckBox("Maths")) self.stack3.setLayout(layout) def display(self, idx): self.Stack.setCurrentIndex(idx)
def animationDoneSlot(self): """动画结束处理函数""" # 由于重写了setCurrentIndex方法所以这里要用父类本身的方法 # self.setCurrentIndex(self._next) QStackedWidget.setCurrentIndex(self, self._next) w = self.widget(self._now) w.hide() w.move(self._pnow) self._active = 0
class CMainWindows(QWidget): def __init__(self): super(CMainWindows, self).__init__() self.InitView() def InitView(self): from trunk import entity self.setFixedSize(960, 800) self.SetCenter() self.setFixedSize(self.width(), self.height()) self.setWindowTitle("神武3工具箱") self.setWindowIcon(QIcon("trunk/images/title_red.png")) self.m_MainLayout = QHBoxLayout(self) # 新建一个水平布局作为本窗体的主布局 self.m_MainLayout.setSpacing(10) # 设置主布局内边距以及控件间距为10px self.m_ComBoxLayout = QVBoxLayout() # 新建垂直子布局用于放置按键 self.m_ComBoxLayout.setContentsMargins(10, 10, 10, 10) # 设置此子布局和内部控件的间距为10px oLabel = QLabel(self) oLabel.setText("当前操作:") oLabel.setFixedHeight(20) self.m_ComBoxLayout.addWidget(oLabel) self.m_ComBox = QComboBox(self) for oEntry in entity.get_all_eneity(): self.m_ComBox.addItem(oEntry.m_Name) self.m_ComBox.currentIndexChanged.connect(self.OnComBoxChange) self.m_ComBox.setFixedWidth(self.m_ComBox.width() + 10) self.m_ComBoxLayout.addWidget(self.m_ComBox) oSplitter = QSplitter(self) # 占位符 self.m_ComBoxLayout.addWidget(oSplitter) self.m_StackedWidget = QStackedWidget(self) for oEntry in entity.get_all_eneity(): self.m_StackedWidget.addWidget(oEntry) self.m_MainLayout.addLayout(self.m_ComBoxLayout) # 将子布局加入主布局 self.m_MainLayout.addWidget(self.m_StackedWidget) def OnComBoxChange(self): self.m_StackedWidget.setCurrentIndex(self.m_ComBox.currentIndex()) def SetSize(self, iHeight, iWidth): self.resize(iHeight, iWidth) def SetCenter(self): # 主窗口居中显示函数 screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)
class CentralWidget(QWidget): """ Making a class from the QWidget class, specify variables and behavior Variables: mainLayout <QVBoxLayout> nameAndDateLayout <QHBoxLayout> interactionLayout <QVBoxLayout> attributeInventoryLayout <QHBoxLayout> attributeLayout <QVBoxLayout> comboBoxesFormLayout <QFormLayout> nameLabel <QLabel> dateTimeLabel <QLabel> difficultyLabel <QLabel> strengthLabel <QLabel> dexterifyLabel <QLabel> constitutionLabel <QLabel> intellectLabel <QLabel> inventoryLabel <QLabel> nameLineEdit <QLineEdit> classSelectorComboBox <QComboBox> difficultyComboBox <QComboBox> finishPushButton <QPushButton> Methods: classChange difficultyChange finishChange nameChange """ def __init__(self): super().__init__() self.Stack = QStackedWidget(self) self.characterCreateWidget = CharacterCreateWidget() self.baseGraphicWorldTileWidget = BaseGraphicWorldTileWidget() self.characterCreateWidget.procGame.connect(self.change_index) self.characterCreateWidget.procCharLabel.connect( self.baseGraphicWorldTileWidget.set_player_image) self.characterCreateWidget.procRoomDescription.connect( self.baseGraphicWorldTileWidget.set_room_description) self.characterCreateWidget.procRoomAvailableAction.connect( self.baseGraphicWorldTileWidget.set_actions) self.baseGraphicWorldTileWidget.procGameChange.connect( self.characterCreateWidget.userInputChange) self.Stack.addWidget(self.characterCreateWidget) self.Stack.addWidget(self.baseGraphicWorldTileWidget) def change_index(self, index): self.Stack.setCurrentIndex(index)
class SettingsDialog(QWidget): """ Settings dialog opened from File -> Settings... """ def __init__(self, config, parent=None): super(SettingsDialog, self).__init__(parent) self.config = config # Widgets self.console = ConsoleSettings(self.config) # Settings self.widget_connections = { "Console": self.console } # Settings Tree self.settings_tree = QTreeWidget() self.settings_tree.setColumnCount(2) self.settings_tree.header().hideSection(1) self.settings_tree.header().close() # Settings Stacked Widget self.stack = QStackedWidget() self.populate = Populate(self, display=self.stack) self.populate.tree_widget( self.settings_tree.invisibleRootItem(), self.widget_connections ) # Layouts self.tree_layout = QVBoxLayout() self.tree_layout.addWidget(self.settings_tree) self.horizontal_layout = QHBoxLayout() self.horizontal_layout.addLayout(self.tree_layout) self.horizontal_layout.addWidget(self.stack) self.setLayout(self.horizontal_layout) # Slots self.settings_tree.currentItemChanged.connect(self.display) def display(self, current): """ Show the corresponding widget for the selected tree item. :param current: the current tree item """ try: item_connection = int(current.text(1)) self.stack.setCurrentIndex(item_connection) except ValueError as _: pass
class Editor(QDialog): """Basic scene editor.""" def __init__(self, parent: MainWindow, renderers: List[Renderer]) -> None: """Initialize the Editor.""" super().__init__(parent=parent) self.renderers = renderers self.tree_widget = QTreeWidget() self.tree_widget.setHeaderHidden(True) self.stacked_widget = QStackedWidget() self.layout = QHBoxLayout() self.layout.addWidget(self.tree_widget) self.layout.addWidget(self.stacked_widget) def _selection_callback() -> None: for item in self.tree_widget.selectedItems(): widget_idx = item.data(0, Qt.ItemDataRole.UserRole) self.stacked_widget.setCurrentIndex(widget_idx) self.tree_widget.itemSelectionChanged.connect(_selection_callback) self.setLayout(self.layout) self.setWindowTitle("Editor") self.setModal(True) self.update() def update(self) -> None: """Update the internal widget list.""" self.tree_widget.clear() for idx, renderer in enumerate(self.renderers): actors = renderer._actors # pylint: disable=protected-access widget_idx = self.stacked_widget.addWidget( _get_renderer_widget(renderer)) top_item = QTreeWidgetItem(self.tree_widget, ["Renderer {}".format(idx)]) top_item.setData(0, Qt.ItemDataRole.UserRole, widget_idx) self.tree_widget.addTopLevelItem(top_item) for name, actor in actors.items(): if actor is not None: widget_idx = self.stacked_widget.addWidget( _get_actor_widget(actor)) child_item = QTreeWidgetItem(top_item, [name]) child_item.setData(0, Qt.ItemDataRole.UserRole, widget_idx) top_item.addChild(child_item) self.tree_widget.expandAll() def toggle(self) -> None: """Toggle the editor visibility.""" self.update() if self.isVisible(): self.hide() else: self.show()
class MainApp(QMainWindow): def __init__(self): super(MainApp, self).__init__() # App metadata self.setWindowTitle('Alice Installer') self.setWindowIcon(QIcon(PATH + '/images/icon.png')) self.setWindowFlags(Qt.WindowCloseButtonHint) self.setFixedSize(800, 400) self.load_fonts() # Set central widget and init ui self.central_widget = QWidget(self) self.central_widget.resize(self.frameSize()) self.initUI() def initUI(self): self.stacked_widget = QStackedWidget(self.central_widget) self.stacked_widget.resize(self.frameSize()) self.stacked_widget.setAutoFillBackground(False) self.stacked_widget.setStyleSheet('background-color: #111118;') # Import activities and add to stack self.start_app = StartApp(self) self.install_window = InstallWindow(self) self.install_complete = InstallComplete(self) self.stacked_widget.addWidget(self.start_app) self.stacked_widget.addWidget(self.install_window) self.stacked_widget.addWidget(self.install_complete) # Activities Triggers self.start_app.install.clicked.connect(lambda: self.switch_layout(1)) def load_fonts(self, path=PATH + '/fonts/'): fonts = [f for f in listdir(path) if isfile(join(path, f))] self.font_db = {} # For each font finded in /fonts add to Application and create a directory of fonts for font in fonts: self.font_id = QFontDatabase.addApplicationFont(path + font) self.font_db[font.replace("-", " ")[:-4]] = self.font_id def set_font(self, font_name, font_size): selected_font = QFontDatabase.applicationFontFamilies( self.font_db[font_name]) font = QFont() font.setFamily(selected_font[0]) font.setPointSize(int(font_size)) return font def switch_layout(self, index): self.stacked_widget.setCurrentIndex(index)
class Window(QMainWindow): def __init__(self, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) self.Stack = QStackedWidget() self.menu_frm = menu.MenuWidget(self.prep_widgets) self.workspace = None self.settings = None self.Stack.addWidget(self.menu_frm) self.setCentralWidget(self.Stack) self.render() self.showMaximized() self.setStyleSheet(open('app.css').read()) def prep_widgets(self): self.workspace = workstation.App_Form() self.settings = settings.App_Form() self.Stack.addWidget(self.workspace) self.Stack.addWidget(self.settings) fn_pack = function_pack(self.render) self.workspace.set_fn_pack(fn_pack) self.settings.set_fn_pack(fn_pack) fn_pack.render_workspace() def render(self, i=0): self.Stack.setCurrentIndex(i) # if you switch to the workspace # refresh the workspace widget if i == 1: self.workspace.display() # if you switch back to the meny # refresh the menu widget if i == 0: # Except I don't know how to refresh the menu widget without taking it of the stack widget controller.TbWorkspace.log_off() # Need to refresh the workspaces, and settings if (self.workspace or self.settings): self.workspace.setParent(None) self.settings.setParent(None) def set_workspace(self, widget): self.workspace = widget def set_settings(self, widget): self.settings = widget
class Cherry(QMainWindow, Ui_MainWindow): """ Main window that holds the main layout """ def __init__(self, parent=None): super().__init__() self.setupUi(self) # Create sidebar self.sidebar = SidebarWidget(self.centralwidget) self.sidebar.actionChanged.connect(self.changeDisplay) self.stackedWidget = QStackedWidget() # Create separate widgets (views) for stacked widget self.configWidget = ConfigWidget(self.stackedWidget) self.configWidget.configCancelled.connect(self.changeDisplayToHome) self.configWidget.configChanged.connect(self.changeConfigInHome) self.homeWidget = HomeWidget(self.stackedWidget) self.homeWidget.setConfig(self.configWidget.getConfig()) self.progressWidget = ProgressWidget(self.stackedWidget) self.historyWidget = HistoryWidget(self.stackedWidget) self.stackedWidget.addWidget(self.homeWidget) self.stackedWidget.addWidget(self.progressWidget) self.stackedWidget.addWidget(self.historyWidget) self.stackedWidget.addWidget(self.configWidget) self.horizontalLayout.addWidget(self.sidebar) self.horizontalLayout.addWidget(self.stackedWidget) # Apparently not needed anymore #self.setMinimumWidth(self.stackedWidget.width() + self.sidebar.width() + 10) self.windowIcon = QIcon(":/icons/cherry.png") self.setWindowIcon(self.windowIcon) self.setWindowTitle("cherry-dl") @pyqtSlot(int) def changeDisplay(self, index): self.stackedWidget.setCurrentIndex(index) @pyqtSlot() def changeDisplayToHome(self): self.stackedWidget.setCurrentIndex(0) @pyqtSlot() def changeConfigInHome(self): self.homeWidget.setConfig(self.configWidget.getConfig()) def closeEvent(self, closeEvent): QCoreApplication.exit()
class TicTacToeWindow(QWidget): def __init__(self, boardlist, current_board, amplist): super(TicTacToeWindow, self).__init__() self.setWindowTitle("Quantum Tic Tac Toe") self.BoardPage = QVBoxLayout(self) self.data = QHBoxLayout(self) self.BoardPage.addLayout(self.data) self.stack = QStackedWidget(self) self.leftlist = QListWidget() self.data.addWidget(self.leftlist) self.data.addWidget(self.stack) for i in range(len(boardlist)): self.leftlist.insertItem(i, boardlist[i]) self.stackUI(boardlist[i], amplist[i]) buttonlayout = QHBoxLayout() button_play = QPushButton('Move') button_play.clicked.connect(self.move) buttonlayout.addWidget(button_play) self.BoardPage.addLayout(buttonlayout) self.setLayout(self.BoardPage) self.leftlist.currentRowChanged.connect(self.display) def stackUI(self, board, amp): s = QWidget() amplist = [ '0', '1', '-1', 'i', '-i', '1/np.sqrt(2)', '-1/np.sqrt(2)', 'i/np.sqrt(2)', '-i/np.sqrt(2)' ] vBox = QVBoxLayout(self) amplitude = QLabel(amp) Tictactoelayout = QGridLayout() for i in range(3): for j in range(3): index = (i * 3) + j if board[index] == '0': ampcb = QComboBox() ampcb.addItems(amplist) Tictactoelayout.addWidget(ampcb, i, j) else: Tictactoelayout.addWidget(QLabel(board[index]), i, j) vBox.addWidget(amplitude) vBox.addLayout(Tictactoelayout) s.setLayout(vBox) self.stack.addWidget(s) def move(self): print("move") def display(self, i): self.stack.setCurrentIndex(i)
class ConfigDialog(QDialog): def __init__(self, parent=None): super(ConfigDialog, self).__init__(parent) self.contentsWidget = QListWidget() self.contentsWidget.setViewMode(QListView.IconMode) self.contentsWidget.setIconSize(QSize(96, 84)) self.contentsWidget.setMovement(QListView.Static) self.contentsWidget.setMaximumWidth(128) self.contentsWidget.setSpacing(12) self.pagesWidget = QStackedWidget() self.pagesWidget.addWidget(ConfigurationPage()) self.pagesWidget.addWidget(UpdatePage()) self.pagesWidget.addWidget(QueryPage()) closeButton = QPushButton("Close") self.createIcons() self.contentsWidget.setCurrentRow(0) closeButton.clicked.connect(self.close) horizontalLayout = QHBoxLayout() horizontalLayout.addWidget(self.contentsWidget) horizontalLayout.addWidget(self.pagesWidget, 1) buttonsLayout = QHBoxLayout() buttonsLayout.addStretch(1) buttonsLayout.addWidget(closeButton) mainLayout = QVBoxLayout() mainLayout.addLayout(horizontalLayout) mainLayout.addStretch(1) mainLayout.addSpacing(12) mainLayout.addLayout(buttonsLayout) self.setLayout(mainLayout) self.setWindowTitle("Config Dialog") def changePage(self, current, previous): if not current: current = previous self.pagesWidget.setCurrentIndex(self.contentsWidget.row(current)) def createIcons(self): configButton = QListWidgetItem(self.contentsWidget) configButton.setIcon(QIcon(':/images/config.png')) configButton.setText("Configuration") configButton.setTextAlignment(Qt.AlignHCenter) configButton.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) updateButton = QListWidgetItem(self.contentsWidget) updateButton.setIcon(QIcon(':/images/update.png')) updateButton.setText("Update") updateButton.setTextAlignment(Qt.AlignHCenter) updateButton.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) queryButton = QListWidgetItem(self.contentsWidget) queryButton.setIcon(QIcon(':/images/query.png')) queryButton.setText("Query") queryButton.setTextAlignment(Qt.AlignHCenter) queryButton.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.contentsWidget.currentItemChanged.connect(self.changePage)
class MainWindow(QMainWindow): quit = pyqtSignal() def __init__( self, parent=None, flags=Qt.WindowFlags(), ): super().__init__(parent, flags) self.setWindowTitle("Photobooth") self.central_widget = QStackedWidget() self.setCentralWidget(self.central_widget) def set_widgets( self, idle_widget: IdleWidget, preview_widget: PreviewWidget, printing_widget: PrintingWidget, error_widget: ErrorWidget, ): self.central_widget.addWidget(idle_widget) self.central_widget.addWidget(preview_widget) self.central_widget.addWidget(printing_widget) self.central_widget.addWidget(error_widget) def select_idle(self): self._select_by_index(0) def select_preview(self): self._select_by_index(1) def select_printing(self): self._select_by_index(2) def select_error(self): self._select_by_index(3) def keyPressEvent(self, event: QEvent): key = event.key() logger.info("keyPressEvent: %s", key) if key in [Qt.Key_Q]: event.accept() self.quit.emit() else: event.ignore() def _select_by_index(self, index): self.central_widget.setCurrentIndex(index)
class TabLayout(QGridLayout): """The QT layout that displays tabs.""" def __init__(self, window: "OctogonWindow"): super().__init__() self.setContentsMargins(QMargins(0, 0, 0, 0)) self.setSpacing(0) self.btn_scoreboard = QPushButton("scoreboard", parent=window) self.btn_scoreboard.clicked.connect(lambda: self.set_tab(0)) self.btn_overlays = QPushButton("overlays", parent=window) self.btn_overlays.clicked.connect(lambda: self.set_tab(1)) # the pages self.widget_scoreboard = QWidget(window) self.widget_scoreboard.setLayout(ScoreboardLayout(window)) self.widget_overlays = QWidget(window) self.widget_overlays.setLayout(OverlaysLayout(window)) # the stackedlayout containing the pages self.widget_stack = QStackedWidget(window) self.widget_stack.addWidget(self.widget_scoreboard) self.widget_stack.addWidget(self.widget_overlays) self.addWidget(self.btn_scoreboard, 0, 0) self.addWidget(self.btn_overlays, 0, 1) self.addWidget(self.widget_stack, 1, 0, 1, 2) self.set_tab(0) def set_tab(self, n: int): # print("tab changed") IGNORE, EXPAND = QSizePolicy.Ignored, QSizePolicy.Expanding if n == 0: self.btn_scoreboard.setProperty("tab_selected", True) self.btn_overlays.setProperty("tab_selected", False) self.widget_scoreboard.setSizePolicy(EXPAND, EXPAND) self.widget_overlays.setSizePolicy(IGNORE, IGNORE) elif n == 1: self.btn_scoreboard.setProperty("tab_selected", False) self.btn_overlays.setProperty("tab_selected", True) self.widget_scoreboard.setSizePolicy(IGNORE, IGNORE) self.widget_overlays.setSizePolicy(EXPAND, EXPAND) self.widget_stack.setCurrentIndex(n) # update stylesheets self.btn_scoreboard.setStyle(self.btn_scoreboard.style()) self.btn_overlays.setStyle(self.btn_scoreboard.style())
class MainView(QMainWindow): def __init__(self): super(MainView, self).__init__() self.setWindowTitle('Jira Helper') self.window = QStackedWidget() # Create the main widget for the page main_window_widget = QWidget() main_window_layout = QGridLayout() main_window_widget.setLayout(main_window_layout) menu_widget = QWidget() menu_layout = QHBoxLayout() menu_widget.setLayout(menu_layout) main_window_layout.addWidget(menu_widget, 0, 0) main_window_layout.addWidget(self.window, 1, 0) self.setCentralWidget(main_window_widget) # Create a settings button self.settings_submit_button = QPushButton() self.settings_submit_button.setText("Settings") menu_layout.addWidget(self.settings_submit_button) # Create date time datetime_font = QFont("Times", 30) self.date = QLabel() self.date.setFont(datetime_font) self.time = QLabel() self.time.setFont(datetime_font) menu_layout.addWidget(self.date) menu_layout.addWidget(self.time) # Create a clean queue button self.clean_queue_button = QPushButton() self.clean_queue_button.setText("Clean Queue") self.clean_queue_button.setCheckable(True) menu_layout.addWidget(self.clean_queue_button) def update_datetime(self): '''Connected to a Qtimer to periodically update the date and time''' Qdate = QDate.currentDate() Qtime = QTime.currentTime() self.date.setText(Qdate.toString(Qt.DefaultLocaleLongDate)) self.time.setText(Qtime.toString(Qt.DefaultLocaleLongDate)) def transition_page(self): '''Connected to a Qtimer to periodically transition through the widgets stacked on self.window''' index_Id = self.window.currentIndex() if index_Id < self.window.count() - 1: self.window.setCurrentIndex(index_Id + 1) else: self.window.setCurrentIndex(0)
class receipt_view(QWidget, person_change_listener): __receipt_printouts = None __receipt_stack = None __person_list = None __model = None def __init__(self, model): super().__init__() self.__model = model self.__model.add_person_change_listeners(self) self.__receipt_printouts = list() # self.setWindowTitle("Receipt Tracker") self.__person_list = QComboBox() self.__person_list.adjustSize() self.__person_list.currentIndexChanged.connect(self.display) self.__receipt_stack = QStackedWidget() # for name in self.__model.get_names(): # printout = receipt_printout(name, self.__model) # self.__receipt_printouts.add(printout) # self.__receipt_stack.addWidget(printout) # self.__person_list.addItem(name) receipt_layout = QVBoxLayout() receipt_layout.addWidget(self.__person_list) receipt_layout.addWidget(self.__receipt_stack) self.setLayout(receipt_layout) self.show() def display(self, i): self.__receipt_stack.setCurrentIndex(i) def person_update(self, model): for printout in self.__receipt_printouts: self.__receipt_stack.removeWidget(printout) for name in model.get_names(): in_set = False for printout in self.__receipt_printouts: if name == printout.name: in_set = True if not in_set: self.__receipt_printouts.append(receipt_printout(name, model)) self.__person_list.addItem(name) for printout in self.__receipt_printouts: self.__receipt_stack.addWidget(printout)
class MapHolder(QWidget): def __init__(self, parent=None): super(MapHolder, self).__init__(parent=parent) self.map = IntervalMapClass(self) self.stack = QStackedWidget(self) self.stack.addWidget(self.map) self.stack.addWidget(QWidget(self)) layout = QVBoxLayout(self) layout.addWidget(self.stack) def show_map(self): self.stack.setCurrentIndex(0) def hide_map(self): self.stack.setCurrentIndex(1)
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle('CountDown') self.Stack = QStackedWidget() self.setCentralWidget(self.Stack) self.setWindowIcon(QIcon('CD_logo.png')) self.main_menu = MainMenu() self.Stack.addWidget(self.main_menu) self.problem_page = ProblemPage(0,30) self.Stack.addWidget(self.problem_page) self.Stack.setCurrentIndex(0) self.main_menu.next_page.clicked.connect(lambda: self.Stack.setCurrentIndex(1)) self.problem_page.back_button.clicked.connect(lambda: self.Stack.setCurrentIndex(0)) self.main_menu.next_page.clicked.connect(lambda: print(self.main_menu.selected_modes))
class SuttonKiosk(QScrollArea): def __init__(self, parent=None): super(SuttonKiosk, self).__init__(parent) self.widgetStack = QStackedWidget(self) #self.widgetStack.setGeometry(0,0, 320, 480) self.setGeometry(0, 0, 320, 480) classesWidgetWindow = ClassesWidgetWindow(self) #self.mainLayout.addWidget(self.widgetStack) #xself.setLayout(self.mainLayout) self.setWindowTitle("SuttonKiosk") self.setWidget(self.widgetStack) def setStackIndex(self, index): self.widgetStack.setCurrentIndex(index)
class Example(QWidget): def __init__(self): super().__init__() self.initUI() self.stacked_widget.currentChanged.connect(self.set_button_state) self.next_button.clicked.connect(self.next_page) self.prev_button.clicked.connect(self.prev_page) def initUI(self): self.next_button = QPushButton('Next') self.prev_button = QPushButton('Previous') self.next_button.setEnabled(False) self.prev_button.setEnabled(False) self.stacked_widget = QStackedWidget() hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(self.prev_button) hbox.addWidget(self.next_button) vbox = QVBoxLayout() vbox.addWidget(self.stacked_widget) vbox.addLayout(hbox) self.setLayout(vbox) def set_button_state(self, index): self.prev_button.setEnabled(index > 0) n_pages = len(self.stacked_widget) self.next_button.setEnabled( index % n_pages < n_pages - 1) def insert_page(self, widget, index=-1): self.stacked_widget.insertWidget(index, widget) self.set_button_state(self.stacked_widget.currentIndex()) def next_page(self): new_index = self.stacked_widget.currentIndex()+1 if new_index < len(self.stacked_widget): self.stacked_widget.setCurrentIndex(new_index) def prev_page(self): new_index = self.stacked_widget.currentIndex()-1 if new_index >= 0: self.stacked_widget.setCurrentIndex(new_index)
class Window(QWidget): def __init__(self): super().__init__() self.title = "Context Menu" self.left = 300 self.top = 100 self.width = 500 self.height = 500 self.IconName = "Icon/python.png" self.color = 'red' self.InitWindow() def InitWindow(self): self.setWindowIcon(QtGui.QIcon(self.IconName)) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) #self.setStyleSheet('background-color:green') self.StackedWidget() self.show() def StackedWidget(self): vbox = QVBoxLayout() self.stackedwidget = QStackedWidget() vbox.addWidget(self.stackedwidget) for x in range(0, 8): label = QLabel("Stacked Child " + str(x)) label.setFont(QtGui.QFont("Sanserif", 15)) label.setStyleSheet('color:red') self.stackedwidget.addWidget(label) self.button = QPushButton("Stack " + str(x)) self.button.setStyleSheet('background-color:green') self.button.page = x self.button.clicked.connect(self.btn_clicked) vbox.addWidget(self.button) self.setLayout(vbox) def btn_clicked(self): self.button = self.sender() self.stackedwidget.setCurrentIndex(self.button.page)
class StackWidget(QDialog): def __init__(self): super().__init__() self.title = "This is first thing" self.height = 700 self.width = 1100 self.top = 100 self.left = 200 self.iconName = "plioky.ico" self.setWindowIcon(QtGui.QIcon(self.iconName)) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.stacked() self.show() def stacked(self): vbox = QVBoxLayout() self.stacked_widget = QStackedWidget() vbox.addWidget(self.stacked_widget) for x in range(0, 8): label = QLabel("Stacked child" + str(x)) label.setFont(QtGui.QFont("Sanserif", 15)) label.setStyleSheet("color:red") self.stacked_widget.addWidget(label) self.button = QPushButton("Stack " + str(x)) self.button.setStyleSheet("background-color:orange") self.button.page = x self.button.clicked.connect(self.btn_clicked) vbox.addWidget(self.button) self.setLayout(vbox) def btn_clicked(self): self.button = self.sender() self.stacked_widget.setCurrentIndex(self.button.page)
class QStackedWidgetDemo(QWidget): def __init__(self): super(QStackedWidgetDemo, self).__init__() self.setWindowTitle("堆栈窗口控件") self.resize(500, 300) self.list_widget = QListWidget() self.stack1 = QWidget() self.stack2 = QWidget() # self.stack3 = QWidget() self.stack = QStackedWidget() self.list_widget.currentRowChanged.connect(self.display) self.set_ui() self.stack1_ui() self.stack2_ui() def set_ui(self): self.list_widget.insertItem(0, "个人信息") self.list_widget.insertItem(1, "账户信息") self.stack.addWidget(self.stack1) self.stack.addWidget(self.stack2) _layout = QHBoxLayout() _layout.addWidget(self.list_widget) _layout.addWidget(self.stack) self.setLayout(_layout) def stack1_ui(self): _layout = QFormLayout() _layout.addRow("昵称: ", QLineEdit("zy01")) _layout.addRow("等级: ", QLineEdit("80")) self.stack1.setLayout(_layout) def stack2_ui(self): _layout = QHBoxLayout() _table = QTableWidget() _table.setRowCount(5) _table.setColumnCount(3) _table.setHorizontalHeaderLabels(["昵称", "登录名", "等级"]) item1 = QTableWidgetItem("zy01") item2 = QTableWidgetItem("zy01") item3 = QTableWidgetItem("80") _table.setItem(0, 0, item1) _table.setItem(0, 1, item2) _table.setItem(0, 2, item3) _layout.addWidget(_table) self.stack2.setLayout(_layout) def display(self, _index): self.stack.setCurrentIndex(_index)
class Project_Clock(QWidget): def __init__(self): super().__init__() self.initUI() # Делаем макет для виджетов layer = QVBoxLayout(self) # Стакуем виджеты self.stack = QStackedWidget() self.stack.addWidget(TimesWidget()) self.stack.addWidget(AlarmWidget()) self.stack.addWidget(StopwatchWidget()) self.stack.addWidget(TimerWidget()) # Кнопка для показа виджета времени self.btn_times = QPushButton('Время', self) self.btn_times.move(0, 0) self.btn_times.resize(100, 25) self.btn_times.clicked.connect(self.times_on) # Кнопка для показа виджета будильника self.btn_alarm = QPushButton('Будильник', self) self.btn_alarm.move(100, 0) self.btn_alarm.resize(100, 25) self.btn_alarm.clicked.connect(self.alarm_on) # Кнопка для показа виджета секундомера self.btn_stopwatch = QPushButton('Секундомер', self) self.btn_stopwatch.move(200, 0) self.btn_stopwatch.resize(100, 25) self.btn_stopwatch.clicked.connect(self.stopwatch_on) # Кнопка для показа виджета таймера self.btn_timer = QPushButton('Таймер', self) self.btn_timer.move(300, 0) self.btn_timer.resize(100, 25) self.btn_timer.clicked.connect(self.timer_on) # Макет для кнопок btnLayout = QHBoxLayout() # Добавление кнопок в мает btnLayout.addWidget(self.btn_times) btnLayout.addWidget(self.btn_alarm) btnLayout.addWidget(self.btn_stopwatch) btnLayout.addWidget(self.btn_timer) # Добавление макета кнопок и стака с виджетами в основной макет layer.addWidget(self.stack) layer.addLayout(btnLayout) def initUI(self): self.setGeometry(100, 100, 500, 500) self.setWindowTitle('Часы') def times_on(self): self.stack.setCurrentIndex(0) def alarm_on(self): self.stack.setCurrentIndex(1) def stopwatch_on(self): self.stack.setCurrentIndex(2) def timer_on(self): self.stack.setCurrentIndex(3)
class ModelViewManager(QWidget): """ Qt widget to select the viewer object """ def __init__(self, lookup, spec): super().__init__() self._concrete_model = None self.results = None self.lookup = lookup # output viewers self.viewer = {'Tabular Viewer': 'TabularModelViewer'} if hasattr(spec, 'viewers'): self.viewer.update(spec.viewers) self.stacked_widget = QStackedWidget() for cl in self.viewer.values(): o = create_viewer(cl, lookup) self.stacked_widget.addWidget(o) # viewer combobox self.viewer_combobox = QComboBox() self.viewer_combobox.addItems(self.viewer.keys()) self.viewer_combobox.currentIndexChanged.connect(self.viewer_changed) # arrange widgets in grid self.grid_layout = QGridLayout() self.grid_layout.addWidget(self.viewer_combobox, 0, 0) self.grid_layout.addWidget(self.stacked_widget, 1, 0) self.setLayout(self.grid_layout) @property def concrete_model(self): return self._concrete_model @concrete_model.setter def concrete_model(self, model): logging.info('Concrete model changed in ModelViewManager') self._concrete_model = model # propagate model to viewers for view in self.stacked_widget.children(): view.concrete_model = model def viewer_changed(self, i): new_viewer_name = self.viewer_combobox.currentText() logging.info('Viewer changed to %s' % new_viewer_name) self.stacked_widget.setCurrentIndex(i)
def __init__(self, pluginsHelp: dict, parent=None, icon=None): QWidget.__init__(self, parent) CustomTitleBarWindowMixin.__init__(self, init=True, title=_("Help")) self.resize(800, 700) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.contentWidget.setLayout(layout) # self.setLayout(layout) itemList = QListWidget() itemList.setProperty("class", "helpList") tabs = QStackedWidget() layout.addWidget(itemList) layout.addWidget(tabs) layout.setStretch(0, 1) layout.setStretch(1, 4) for name, help in pluginsHelp.items(): tab = QWidget() tab.setProperty("class", "helpTab") tabLayout = QVBoxLayout() tab.setLayout(tabLayout) if type(help) == str: tabLabel = ScrollLabel(help) else: tabLabel = help tabLayout.addWidget(tabLabel) tabs.addWidget(tab) itemList.addItem(name) itemList.setCurrentRow(0) itemList.currentRowChanged.connect( lambda idx: tabs.setCurrentIndex(idx)) self.show()
class StackWidget(QDialog): def __init__(self): super().__init__() self.title = "PyQt5 Stacked Widget" self.top = 100 self.left = 100 self.width = 400 self.height = 300 self.stacked_widget() self.InitWindow() def InitWindow(self): self.setWindowIcon(QtGui.QIcon("home.png")) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.show() def stacked_widget(self): vbox = QVBoxLayout() self.stackedWidget = QStackedWidget() vbox.addWidget(self.stackedWidget) for x in range(0, 8): label = QLabel("Stacked Child" + str(x)) label.setFont(QtGui.QFont("Sanserif", 15)) label.setStyleSheet("color:red") self.stackedWidget.addWidget(label) self.button = QPushButton("Stack " + str(x)) self.button.setStyleSheet('background-color:green') self.button.page = x self.button.clicked.connect(self.btn_clicked) vbox.addWidget(self.button) self.setLayout(vbox) def btn_clicked(self): self.button = self.sender() self.stackedWidget.setCurrentIndex(self.button.page - 1)
class MainWidget(QFrame): def __init__(self): super().__init__() self.back_button = PushButton() self.back_button.setFixedWidth(55) self.back_button.setFixedHeight(30) self.back_button.setIcon(QIcon(resource_path("back_arrow.png"))) # so we can reference just this button in css self.back_button.setObjectName("backButton") self.back_button.clicked.connect(lambda: self.set_index(0)) # offset by a bit so we're not right against the window border margins = self.back_button.contentsMargins() margins.setLeft(10) margins.setTop(10) self.back_button.setContentsMargins(margins) self.stacked_widget = QStackedWidget() window_selector = WindowSelector() window_selector.visualize_button_clicked.connect( lambda: self.set_index(1)) window_selector.bulk_investigation_button_clicked.connect( lambda: self.set_index(2)) self.analysis_selection = AnalysisSelection() self.cg_classic = CircleguardClassic() self.stacked_widget.addWidget(window_selector) self.stacked_widget.addWidget(self.analysis_selection) self.stacked_widget.addWidget(self.cg_classic) index_map = {"selection": 0, "visualization": 1, "investigation": 2} index = index_map[get_setting("default_page")] self.set_index(index) layout = QVBoxLayout() layout.addWidget(self.back_button) layout.addWidget(self.stacked_widget) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.setLayout(layout) def set_index(self, index): # don't show the back button on the selection page itself self.back_button.hide() if index == 0 else self.back_button.show() self.stacked_widget.setCurrentIndex(index)
class Root(QMainWindow): task_list_index = 0 task_view_index = 1 def __init__(self): super().__init__() self.model = None self.task_view = None self.initUI() def initUI(self): # self.cal = QCalendarWidget(self) # self.cal.setVerticalHeaderFormat(QCalendarWidget.NoVerticalHeader) # self.cal.setGeometry(0, 0, 250, 250) self.model = TaskModel() self.central = QStackedWidget() task_list = TaskList(self.model) task_list.open.connect(self.task_open) self.central.insertWidget(Root.task_list_index, task_list) self.task_view = TaskView(self.model) self.task_view.close.connect(self.task_view_close) self.central.insertWidget(Root.task_view_index, self.task_view) self.central.setCurrentIndex(Root.task_list_index) self.setCentralWidget(self.central) # QDialog flags: # Qt.Dialog | # Qt.WindowTitleHint | # Qt.WindowSystemMenuHint | # Qt.WindowContextHelpButtonHint | # Qt.WindowCloseButtonHint self.setWindowFlags(Qt.Dialog | Qt.WindowStaysOnTopHint) self.setGeometry(700, 300, 250, 300) self.setWindowTitle('Calendar') @pyqtSlot(int) def task_open(self, index): self.task_view.set_task(index) self.central.setCurrentIndex(Root.task_view_index) @pyqtSlot() def task_view_close(self): self.central.setCurrentIndex(Root.task_list_index) def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.close()
class MainView(base, form): def __init__(self, pipeline, parent=None): super(base, self).__init__(parent) self.setupUi(self) self.pipeline = pipeline self.pip_widgets = [] self.default_pips = [] self.draw_ui() self.connect_ui() def register_observers(self): pass def connect_ui(self): """ This function connects the ui using signals from the ui elements and its method counterparts. """ self.input_btn.clicked.connect(self.set_input_url) self.output_btn.clicked.connect(self.set_output_url) self.save_btn.clicked.connect(self.save_pipeline) self.load_favorite_pipelines() self.fav_pips_combo_box.activated.connect(self.select_default_pip) self.run_btn.clicked.connect(self.run) self.delete_btn.clicked.connect(self.trash_pipeline) self.add_btn.clicked.connect(lambda: self.add_pipe_entry_new()) def draw_ui(self): """ This function draws all additional UI elements. If you want the application to display any additional things like a button you can either add it in the QtDesigner or declare it here. """ # *TODO* Create these ones with Qt Designer and put them into select_cat_alg_vbox_layout. I failed self.ComboxCategories = QComboBox() self.stackedWidgetComboxesAlgorithms = QStackedWidget() self.select_cat_alg_vbox_layout.addWidget(self.ComboxCategories) self.select_cat_alg_vbox_layout.addWidget(self.stackedWidgetComboxesAlgorithms) self.ComboxCategories.hide() """ This function is concerned with drawing all non static elements into the GUI. """ """self.set_pip_title("A. Junius2") self.set_preset(["A.Junius", "test", "test", "test"]) self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_cat_image("../assets/images/seg_fav.jpeg", "Preprocessing") self.add_cat_image("../assets/images/wing.jpeg", "Preprocessing") self.add_cat_image("../assets/images/wing.jpeg", "Preprocessing") self.add_cat_image("../assets/images/wing.jpeg", "Preprocessing") self.add_cat_image("../assets/images/wing.jpeg", "Preprocessing") self.add_cat_image("../assets/images/wing.jpeg", "Preprocessing") self.add_cat_image("../assets/images/wing.jpeg", "Preprocessing") self.main_image_label.setPixmap(QtGui.QPixmap("wing.jpeg")) category_combo_box = ComboBoxWidget("type") category_combo_box.add_item("Preprocessing", "../assets/images/P.png") category_combo_box.add_item("Segmentation", "../assets/images/S.png") category_combo_box.add_item("Graph Detection", "../assets/images/D.png") category_combo_box.add_item("Graph Filtering", "../assets/images/F.png") alg_combo_box = ComboBoxWidget("algorithm") alg_combo_box.add_item("Otsus") alg_combo_box.add_item("Guo Hall") alg_combo_box.add_item("Adaptive Treshold") slider_1 = SliderWidget("slider1das", 0, 10, 1, 4, True) slider_2 = SliderWidget("slider1", 0, 10, 2, 4, False) slider_3 = SliderWidget("sliderböadsad", 0, 10, 1, 4, True) slider_4 = SliderWidget("sliderböadsad", 0, 10, 1, 4, True) slider_5 = SliderWidget("sliderböadsad", 0, 10, 1, 4, True) checkbox_1 = CheckBoxWidget("checkbox1", True) self.setting_widget_vbox_layout.addWidget(category_combo_box) self.setting_widget_vbox_layout.addWidget(alg_combo_box) self.setting_widget_vbox_layout.addWidget(slider_1) self.setting_widget_vbox_layout.addWidget(slider_2) self.setting_widget_vbox_layout.addWidget(slider_3) self.setting_widget_vbox_layout.addWidget(slider_4) self.setting_widget_vbox_layout.addWidget(slider_5) self.setting_widget_vbox_layout.addWidget(checkbox_1) self.setting_widget_vbox_layout.setAlignment(Qt.AlignTop)""" def set_pip_title(self, title): """ Sets the title of the current selected pipeline in the ui. Args: | *title*: the title of the pipeline | *label_ref*: the reference to the label. """ self.current_pip_label.setText(title) def load_dark_theme(self, application): """ This function is called to load the white theme with all its icons for the buttons and the css file. Args: application: the cureent app instance """ # load buttons pixmap_icon = QtGui.QPixmap("./assets/images/add_white.png") q_icon = QtGui.QIcon(pixmap_icon) self.add_btn.setIcon(q_icon) pixmap_icon = QtGui.QPixmap("./assets/images/trash_white.png") q_icon = QtGui.QIcon(pixmap_icon) self.delete_btn.setIcon(q_icon) pixmap_icon = QtGui.QPixmap("./assets/images/diskette_white.png") q_icon = QtGui.QIcon(pixmap_icon) self.save_btn.setIcon(q_icon) pixmap_icon = QtGui.QPixmap("./assets/images/up-arrow_white.png") q_icon = QtGui.QIcon(pixmap_icon) self.input_btn.setIcon(q_icon) pixmap_icon = QtGui.QPixmap("./assets/images/folder_white.png") q_icon = QtGui.QIcon(pixmap_icon) self.output_btn.setIcon(q_icon) @pyqtSlot(int) def select_default_pip(self, index): """ This is the slot for the Pipeline combobox in the ui Args: index: index of the option currently selected """ # delete current pipeline self.trash_pipeline() # get url and name name, url = self.default_pips[index - 1] # parse the json in the model self.pipeline.load_pipeline_json(url) print("PARSER" + str(self.pipeline.executed_cats[0].active_algorithm)) print("PARSER" + str(self.pipeline.executed_cats[1].active_algorithm)) # set the title self.set_pip_title(name) # Create an entry in the pipeline widget for every step in the pipeline for i in range(0, len(self.pipeline.executed_cats)): self.add_pipe_entry_new(i) self.scroll_down_pip() """for widget in alg_widgets: self.setting_widget_vbox_layout.addWidget(widget)""" def trash_pipeline(self): """ This method clears the complete pipeline while users clicked the trash button. """ # remove all entries in the pipeline list while self.pip_widget_vbox_layout.count(): child = self.pip_widget_vbox_layout.takeAt(0) child.widget().deleteLater() while self.stackedWidget_Settings.currentWidget() is not None: self.stackedWidget_Settings.removeWidget(self.stackedWidget_Settings.currentWidget()) self.settings_collapsable.setTitle("") # remove the pipeline name self.set_pip_title("") # remove all entries int the executed_cats of the model pipeline del self.pipeline.executed_cats[:] # remove all widgets del self.pip_widgets[:] # remove category algorith dropdown self.remove_cat_alg_dropdown() # remove all entries from the pipeline model del self.pipeline.executed_cats[:] @pyqtSlot() def run(self): """ This method runs the the pipeline by calling the process methode in pipeline """ self.pipeline.process() @pyqtSlot() def set_input_url(self): """ This method sets the url for the input image in the pipeline. """ url = QtWidgets.QFileDialog.getOpenFileNames() if url[0]: print(url[0]) print(url[0][0]) self.lineEdit.setText(url[0][0]) self.pipeline.set_input(url[0][0]) @pyqtSlot() def set_output_url(self): """ This method sets the url for the output folder in the pipeline. Args: url: the url to the output folder a user selected in the ui """ url = QtWidgets.QFileDialog.getExistingDirectory() if url: print(url) print(url) self.custom_line_edit.setText(url) self.pipeline.set_output_dir(url) def load_favorite_pipelines(self): """ Scans the directory for default pipelines to display all available items """ self.fav_pips_combo_box.addItem("Please Select") # scan the directory for default pipelines for file in os.listdir("./_default_pipelines"): if file.endswith(".json"): name = file.split(".")[0] url = os.path.abspath("./_default_pipelines" + "/" + file) self.default_pips.append([name, url]) self.fav_pips_combo_box.addItem(name) @pyqtSlot() def save_pipeline(self): """ Saves the pipeline as a json at the users file system. """ url = str(QtWidgets.QFileDialog.getSaveFileName()[0]) split_list = url.split("/") name = split_list[len(split_list) - 1].split(".")[0] del split_list[len(split_list) - 1] url = url.replace(name, "") self.pipeline.save_pipeline_json(name, url) @pyqtSlot(int) def remove_pip_entry(self, pipe_entry_widget, settings_widget, cat=None): """ Removes the pip entry at the given position in the ui Args: pipeline_index (object): settings_widget: position: position at which the pip entry gets removed """ # remove pipeline entry widget from ui self.pip_widget_vbox_layout.removeWidget(pipe_entry_widget) pipe_entry_widget.deleteLater() # remove it settings widgets from ui if settings_widget is not None: if self.stackedWidget_Settings.currentWidget() == settings_widget: self.stackedWidget_Settings.hide() self.remove_cat_alg_dropdown() self.settings_collapsable.setTitle("Settings") self.stackedWidget_Settings.removeWidget(settings_widget) # remove in model if cat is not None: print("Remove entry at pos " + str(self.pipeline.get_index(cat)) + " " + str(cat)) self.pipeline.delete_category(self.pipeline.get_index(cat)) def change_pip_entry_alg(self, position, new_category, new_algorithm, pipe_entry_widget, settings_widget): """ Changes the selected algorithm of the pipeline entry at the position. Afterwards create all widgets for this algorithm instance Args: position: the position of the pipeline entry algorithm: the selected algorithm for this category """ print("Position to be changed:" + str(position)) print("Pipeline length: " + str(len(self.pipeline.executed_cats))) old_cat = self.pipeline.executed_cats[position] old_alg = old_cat.active_algorithm print("Old Cat found in pipeline: " + str(old_cat)) print("Old Alg: found in pipeline:" + str(old_alg)) print("New Category given:" + str(new_category)) print("New Algorithm given:" + str(new_algorithm)) # set in model self.pipeline.change_category(new_category, position) self.pipeline.change_algorithm(new_algorithm, position) new_cat = self.pipeline.executed_cats[position] new_alg = new_cat.active_algorithm # change settings widgets self.remove_pip_entry(pipe_entry_widget, settings_widget) (new_pipe_entry_widget, new_settings_widget) = self.add_pipe_entry_new(position) self.stackedWidget_Settings.show() self.stackedWidget_Settings.setCurrentIndex(position) self.settings_collapsable.setTitle(new_alg.get_name() + " Settings") self.remove_cat_alg_dropdown() self.create_cat_alg_dropdown(position, new_pipe_entry_widget, new_settings_widget) self.set_cat_alg_dropdown(new_cat, new_alg) print("New Cat found in pipeline: " + str(new_cat)) print("New Alg found in pipeline: " + str(new_alg)) def load_settings_widgets_from_pipeline_groupbox(self, position): """ Extracts all widgets from a single algorithm and returns a QBoxLayout Args: alg: the alg instance we extract from Returns: a QBoxLayout containing all widgets for this particular alg. """ alg = self.pipeline.executed_cats[position].active_algorithm print("alg " + str(alg)) print("cat " + str(self.pipeline.executed_cats[position])) empty_flag = True groupOfSliders = QGroupBox() sp = QSizePolicy() sp.setVerticalPolicy(QSizePolicy.Preferred) # groupOfSliders.setSizePolicy(sp) groupOfSliderssLayout = QBoxLayout(QBoxLayout.TopToBottom) groupOfSliderssLayout.setContentsMargins(0, -0, -0, 0) groupOfSliderssLayout.setAlignment(Qt.AlignTop) groupOfSliderssLayout.setSpacing(0) print("Build Slider @ "+ str(position)) # create integer sliders for slider in alg.integer_sliders: empty_flag = False print("slider.value " + str(slider.value)) print("slider " + str(slider)) #print(alg.get_name() + ": add slider (int).") groupOfSliderssLayout.addWidget( SliderWidget(slider.name, slider.lower, slider.upper, slider.step_size, slider.value, slider.set_value, False)) # create float sliders for slider in alg.float_sliders: empty_flag = False #print(alg.get_name() + ": add slider (float).") groupOfSliderssLayout.addWidget( SliderWidget(slider.name, slider.lower, slider.upper, slider.step_size, slider.value, slider.set_value, True), 0, Qt.AlignTop) # create checkboxes for checkbox in alg.checkboxes: empty_flag = False #print(alg.get_name() + ": add checkbox.") groupOfSliderssLayout.addWidget(CheckBoxWidget(checkbox.name, checkbox.value, checkbox.set_value), 0, Qt.AlignTop) # create dropdowns for combobox in alg.drop_downs: empty_flag = False #print(alg.get_name() + ": add combobox.") groupOfSliderssLayout.addWidget( ComboBoxWidget(combobox.name, combobox.options, combobox.set_value, combobox.value), 0, Qt.AlignTop) if empty_flag: label = QLabel() label.setText("This algorithm has no Settings.") groupOfSliderssLayout.addWidget(label, 0, Qt.AlignHCenter) groupOfSliders.setLayout(groupOfSliderssLayout) return groupOfSliders def create_cat_alg_dropdown(self, cat_position, pipe_entry_widget, settings_widget): """ Args: last_cat (object): """ layout = self.select_cat_alg_vbox_layout cat = self.pipeline.executed_cats[cat_position] last_cat = None # Show only allowed categories in dropdown if len(self.pipeline.executed_cats) > 1: last_cat = self.pipeline.executed_cats[cat_position - 1] # Combobox for selecting Category self.ComboxCategories.show() self.ComboxCategories.setFixedHeight(30) self.ComboxCategories.addItem("<Please Select Category>") self.stackedWidgetComboxesAlgorithms = QStackedWidget() self.stackedWidgetComboxesAlgorithms.setFixedHeight(30) self.stackedWidgetComboxesAlgorithms.hide() def setCurrentIndexCat(index): #print("Set Cat") if self.ComboxCategories.currentIndex() == 0: self.stackedWidgetComboxesAlgorithms.hide() else: self.stackedWidgetComboxesAlgorithms.show() self.stackedWidgetComboxesAlgorithms.setCurrentIndex(index - 1) for category_name in self.pipeline.report_available_cats(last_cat): # Add Category to combobox self.ComboxCategories.addItem(category_name) tmp1 = QComboBox() tmp1.addItem("<Please Select Algorithm>") tmp1.setFixedHeight(30) category = self.pipeline.get_category(category_name) #self.current_index = -1 def setCurrentIndexAlg(index): if self.ComboxCategories.currentIndex() == 0 or self.stackedWidgetComboxesAlgorithms.currentWidget().currentIndex() == 0: pass else: #self.current_index != index: self.change_pip_entry_alg(self.pipeline.get_index(cat), self.ComboxCategories.currentText(), self.stackedWidgetComboxesAlgorithms.currentWidget().currentText(), pipe_entry_widget, settings_widget) #self.current_index = index tmp1.activated.connect(setCurrentIndexAlg) for algorithm_name in self.pipeline.get_all_algorithm_list(category): tmp1.addItem(algorithm_name) self.stackedWidgetComboxesAlgorithms.addWidget(tmp1) layout.addWidget(self.ComboxCategories) layout.addWidget(self.stackedWidgetComboxesAlgorithms) self.ComboxCategories.activated.connect(setCurrentIndexCat) def set_cat_alg_dropdown(self, category, algorithm): indexC = self.ComboxCategories.findText(category.get_name()) #print("IndexC " + str(indexC)) self.ComboxCategories.setCurrentIndex(indexC) self.stackedWidgetComboxesAlgorithms.show() self.stackedWidgetComboxesAlgorithms.setCurrentIndex(indexC - 1) indexA = self.stackedWidgetComboxesAlgorithms.currentWidget().findText(algorithm.get_name()) #print("IndexA " + str(indexA)) self.stackedWidgetComboxesAlgorithms.currentWidget().setCurrentIndex(indexA) def remove_cat_alg_dropdown(self): """ Returns: object: """ self.ComboxCategories.clear() while self.stackedWidgetComboxesAlgorithms.currentWidget() is not None: self.stackedWidgetComboxesAlgorithms.removeWidget(self.stackedWidgetComboxesAlgorithms.currentWidget()) while self.select_cat_alg_vbox_layout.count(): child = self.select_cat_alg_vbox_layout.takeAt(0) child.widget().hide() def scroll_down_pip(self): self.pip_scroll.verticalScrollBar().setSliderPosition(self.pip_scroll.verticalScrollBar().maximum()) def add_pipe_entry_new(self, position=None): """ Creates a entry in the ui pipeline with a given position in pipeline. It also creates the corresponding settings widget. """ # create an widget that displays the pip entry in the ui and connect the remove button pip_main_widget = QWidget() pip_main_widget.setFixedHeight(70) pip_main_widget.setFixedWidth(300) pip_main_layout = QHBoxLayout() pip_main_widget.setLayout(pip_main_layout) new_marker = False if position is None: position = len(self.pipeline.executed_cats) cat = self.pipeline.new_category(position) label = "<Click to specify new step>" icon = None new_marker = True else: cat = self.pipeline.executed_cats[position] alg = cat.active_algorithm label = alg.get_name() icon = cat.get_icon() new_marker = False pixmap = QPixmap(icon) pixmap_scaled_keeping_aspec = pixmap.scaled(30, 30, QtCore.Qt.KeepAspectRatio) pixmap_label = QtWidgets.QLabel() pixmap_label.setPixmap(pixmap_scaled_keeping_aspec) pip_up_down = QWidget() pip_up_down.setFixedHeight(70) pip_up_down_layout = QVBoxLayout() pip_up_down.setLayout(pip_up_down_layout) up_btn = QToolButton() dw_btn = QToolButton() up_btn.setArrowType(Qt.UpArrow) up_btn.setFixedHeight(25) dw_btn.setArrowType(Qt.DownArrow) dw_btn.setFixedHeight(25) pip_up_down_layout.addWidget(up_btn) pip_up_down_layout.addWidget(dw_btn) string_label = QLabel() string_label.setText(label) string_label.setFixedWidth(210) btn = QtWidgets.QPushButton() btn.setFixedSize(20, 20) pixmap_icon = QtGui.QPixmap("./assets/images/delete_x_white.png") q_icon = QtGui.QIcon(pixmap_icon) btn.setIcon(q_icon) pip_main_layout.addWidget(pip_up_down, Qt.AlignVCenter) pip_main_layout.addWidget(pixmap_label, Qt.AlignVCenter) pip_main_layout.addWidget(string_label, Qt.AlignLeft) pip_main_layout.addWidget(btn, Qt.AlignVCenter) self.pip_widget_vbox_layout.insertWidget(position, pip_main_widget) # Create the corresponding settings widget and connect it self.settings_collapsable.setTitle("Settings") self.stackedWidget_Settings.hide() settings_main_widget = None if not new_marker: settings_main_widget = self.load_settings_widgets_from_pipeline_groupbox(position) self.stackedWidget_Settings.insertWidget(position, settings_main_widget) def show_settings(): # Set background color while widget is selected. Doesn't work because of theme? *TODO* p = pip_main_widget.palette() p.setColor(pip_main_widget.backgroundRole(), Qt.red) pip_main_widget.setPalette(p) if not new_marker: self.stackedWidget_Settings.show() self.stackedWidget_Settings.setCurrentIndex(self.pipeline.get_index(cat)) self.settings_collapsable.setTitle(alg.get_name() + " Settings") else: self.stackedWidget_Settings.hide() # Create drop down for cats and algs self.remove_cat_alg_dropdown() self.create_cat_alg_dropdown(self.pipeline.get_index(cat), pip_main_widget, settings_main_widget) if not new_marker: self.set_cat_alg_dropdown(cat, alg) # Connect Button to remove step from pipeline def delete_button_clicked(): self.remove_cat_alg_dropdown() self.remove_pip_entry(pip_main_widget, settings_main_widget, cat) self.clickable(pixmap_label).connect(show_settings) self.clickable(string_label).connect(show_settings) btn.clicked.connect(delete_button_clicked) return (pip_main_widget, settings_main_widget) def add_pip_entry_empty(self): """ Creates an blank entry in the ui pipeline since the user still needs to specify a type and an algorithm of the category. It also creates the corresponding settings widget. """ # create an widget that displays the pip entry in the ui and connect the remove button pip_main_widget = QWidget() pip_main_widget.setFixedHeight(70) pip_main_widget.setFixedWidth(300) pip_main_layout = QHBoxLayout() pip_main_widget.setLayout(pip_main_layout) label = "<Click to specify new step>" icon = None pixmap = QPixmap(icon) pixmap_scaled_keeping_aspec = pixmap.scaled(30, 30, QtCore.Qt.KeepAspectRatio) pixmap_label = QtWidgets.QLabel() pixmap_label.setPixmap(pixmap_scaled_keeping_aspec) pip_up_down = QWidget() pip_up_down.setFixedHeight(70) pip_up_down_layout = QVBoxLayout() pip_up_down.setLayout(pip_up_down_layout) up_btn = QToolButton() dw_btn = QToolButton() up_btn.setArrowType(Qt.UpArrow) up_btn.setFixedHeight(25) dw_btn.setArrowType(Qt.DownArrow) dw_btn.setFixedHeight(25) pip_up_down_layout.addWidget(up_btn) pip_up_down_layout.addWidget(dw_btn) string_label = QLabel() string_label.setText(label) string_label.setFixedWidth(210) btn = QtWidgets.QPushButton() btn.setFixedSize(20, 20) pixmap_icon = QtGui.QPixmap("./assets/images/delete_x_white.png") q_icon = QtGui.QIcon(pixmap_icon) btn.setIcon(q_icon) pip_main_layout.addWidget(pip_up_down, Qt.AlignVCenter) pip_main_layout.addWidget(pixmap_label, Qt.AlignVCenter) pip_main_layout.addWidget(string_label, Qt.AlignLeft) pip_main_layout.addWidget(btn, Qt.AlignVCenter) cat_position = len(self.pipeline.executed_cats) self.pip_widget_vbox_layout.insertWidget(cat_position, pip_main_widget) index = self.pip_widget_vbox_layout.indexOf(pip_main_widget) #print(index) # Create the corresponding empty settings widget and connect it # settings = self.load_widgets_from_cat_groupbox(cat_position) *TODO* EMPTY self.settings_collapsable.setTitle("Settings") self.stackedWidget_Settings.hide() # Add new step to pipeline new_category = self.pipeline.new_category(cat_position) print("Create new entry " + str(new_category)) print("Pipeline length: " + str(len(self.pipeline.executed_cats)) + ".") settings_main_widget = None # Connect pipeline entry with corresponding settings widget def show_settings(): #print("click") self.stackedWidget_Settings.show() self.remove_cat_alg_dropdown() # Create drop down for cats and algs self.create_cat_alg_dropdown(self.pipeline.get_index(new_category), pip_main_widget, settings_main_widget) self.stackedWidget_Settings.hide() # Connect Button to remove step from pipeline def delete_button_clicked(): self.remove_cat_alg_dropdown() self.remove_pip_entry(pip_main_widget, settings_main_widget, new_category) self.clickable(pixmap_label).connect(show_settings) self.clickable(string_label).connect(show_settings) btn.clicked.connect(delete_button_clicked) self.scroll_down_pip() def add_pip_entry(self, cat_position): """ Creates a entry in the ui pipeline with a given position in pipeline. It also creates the corresponding settings widget. """ # create an widget that displays the pip entry in the ui and connect the remove button pip_main_widget = QWidget() pip_main_widget.setFixedHeight(70) pip_main_widget.setFixedWidth(300) pip_main_layout = QHBoxLayout() pip_main_widget.setLayout(pip_main_layout) cat = self.pipeline.executed_cats[cat_position] alg = cat.active_algorithm label = alg.get_name() icon = cat.get_icon() pixmap = QPixmap(icon) pixmap_scaled_keeping_aspec = pixmap.scaled(30, 30, QtCore.Qt.KeepAspectRatio) pixmap_label = QtWidgets.QLabel() pixmap_label.setPixmap(pixmap_scaled_keeping_aspec) pip_up_down = QWidget() pip_up_down.setFixedHeight(70) pip_up_down_layout = QVBoxLayout() pip_up_down.setLayout(pip_up_down_layout) up_btn = QToolButton() dw_btn = QToolButton() up_btn.setArrowType(Qt.UpArrow) up_btn.setFixedHeight(25) dw_btn.setArrowType(Qt.DownArrow) dw_btn.setFixedHeight(25) pip_up_down_layout.addWidget(up_btn) pip_up_down_layout.addWidget(dw_btn) string_label = QLabel() string_label.setText(label) string_label.setFixedWidth(210) btn = QtWidgets.QPushButton() btn.setFixedSize(20, 20) pixmap_icon = QtGui.QPixmap("./assets/images/delete_x_white.png") q_icon = QtGui.QIcon(pixmap_icon) btn.setIcon(q_icon) pip_main_layout.addWidget(pip_up_down, Qt.AlignVCenter) pip_main_layout.addWidget(pixmap_label, Qt.AlignVCenter) pip_main_layout.addWidget(string_label, Qt.AlignLeft) pip_main_layout.addWidget(btn, Qt.AlignVCenter) self.pip_widget_vbox_layout.insertWidget(cat_position, pip_main_widget) index = self.pip_widget_vbox_layout.indexOf(pip_main_widget) #print(index) # Create the corresponding settings widget and connect it settings_main_widget = self.load_settings_widgets_from_pipeline_groupbox(cat_position) self.settings_collapsable.setTitle("Settings") self.stackedWidget_Settings.hide() self.stackedWidget_Settings.insertWidget(cat_position, settings_main_widget) #print("Read from pipeline entry " + str(cat)) #print("Pipeline length: " + str(len(self.pipeline.executed_cats)) + ".") def show_settings(): # Set background color while widget is selected. Doesn't work because of theme? *TODO* p = pip_main_widget.palette() p.setColor(pip_main_widget.backgroundRole(), Qt.red) pip_main_widget.setPalette(p) self.stackedWidget_Settings.show() self.stackedWidget_Settings.setCurrentIndex(self.pipeline.get_index(cat)) self.settings_collapsable.setTitle(alg.get_name() + " Settings") self.remove_cat_alg_dropdown() # Create drop down for cats and algs self.create_cat_alg_dropdown(self.pipeline.get_index(cat), pip_main_widget, settings_main_widget) #print(cat) #print(alg) self.set_cat_alg_dropdown(cat, alg) # Connect Button to remove step from pipeline def delete_button_clicked(): self.remove_pip_entry(pip_main_widget, settings_main_widget, cat) self.clickable(pixmap_label).connect(show_settings) self.clickable(string_label).connect(show_settings) btn.clicked.connect(delete_button_clicked) return (pip_main_widget, settings_main_widget) # https://wiki.python.org/moin/PyQt/Making%20non-clickable%20widgets%20clickable def clickable(self, widget): """ Convert any widget to a clickable widget. """ class Filter(QObject): clicked = pyqtSignal() def eventFilter(self, obj, event): if obj == widget: if event.type() == QEvent.MouseButtonPress: if obj.rect().contains(event.pos()): self.clicked.emit() # The developer can opt for .emit(obj) to get the object within the slot. return True return False filter = Filter(widget) widget.installEventFilter(filter) return filter.clicked
class E5SideBar(QWidget): """ Class implementing a sidebar with a widget area, that is hidden or shown, if the current tab is clicked again. """ Version = 1 North = 0 East = 1 South = 2 West = 3 def __init__(self, orientation=None, delay=200, parent=None): """ Constructor @param orientation orientation of the sidebar widget (North, East, South, West) @param delay value for the expand/shrink delay in milliseconds (integer) @param parent parent widget (QWidget) """ super(E5SideBar, self).__init__(parent) self.__tabBar = QTabBar() self.__tabBar.setDrawBase(True) self.__tabBar.setShape(QTabBar.RoundedNorth) self.__tabBar.setUsesScrollButtons(True) self.__tabBar.setDrawBase(False) self.__stackedWidget = QStackedWidget(self) self.__stackedWidget.setContentsMargins(0, 0, 0, 0) self.__autoHideButton = QToolButton() self.__autoHideButton.setCheckable(True) self.__autoHideButton.setIcon( UI.PixmapCache.getIcon("autoHideOff.png")) self.__autoHideButton.setChecked(True) self.__autoHideButton.setToolTip( self.tr("Deselect to activate automatic collapsing")) self.barLayout = QBoxLayout(QBoxLayout.LeftToRight) self.barLayout.setContentsMargins(0, 0, 0, 0) self.layout = QBoxLayout(QBoxLayout.TopToBottom) self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(0) self.barLayout.addWidget(self.__autoHideButton) self.barLayout.addWidget(self.__tabBar) self.layout.addLayout(self.barLayout) self.layout.addWidget(self.__stackedWidget) self.setLayout(self.layout) # initialize the delay timer self.__actionMethod = None self.__delayTimer = QTimer(self) self.__delayTimer.setSingleShot(True) self.__delayTimer.setInterval(delay) self.__delayTimer.timeout.connect(self.__delayedAction) self.__minimized = False self.__minSize = 0 self.__maxSize = 0 self.__bigSize = QSize() self.splitter = None self.splitterSizes = [] self.__hasFocus = False # flag storing if this widget or any child has the focus self.__autoHide = False self.__tabBar.installEventFilter(self) self.__orientation = E5SideBar.North if orientation is None: orientation = E5SideBar.North self.setOrientation(orientation) self.__tabBar.currentChanged[int].connect( self.__stackedWidget.setCurrentIndex) e5App().focusChanged[QWidget, QWidget].connect(self.__appFocusChanged) self.__autoHideButton.toggled[bool].connect(self.__autoHideToggled) def setSplitter(self, splitter): """ Public method to set the splitter managing the sidebar. @param splitter reference to the splitter (QSplitter) """ self.splitter = splitter self.splitter.splitterMoved.connect(self.__splitterMoved) self.splitter.setChildrenCollapsible(False) index = self.splitter.indexOf(self) self.splitter.setCollapsible(index, False) def __splitterMoved(self, pos, index): """ Private slot to react on splitter moves. @param pos new position of the splitter handle (integer) @param index index of the splitter handle (integer) """ if self.splitter: self.splitterSizes = self.splitter.sizes() def __delayedAction(self): """ Private slot to handle the firing of the delay timer. """ if self.__actionMethod is not None: self.__actionMethod() def setDelay(self, delay): """ Public method to set the delay value for the expand/shrink delay in milliseconds. @param delay value for the expand/shrink delay in milliseconds (integer) """ self.__delayTimer.setInterval(delay) def delay(self): """ Public method to get the delay value for the expand/shrink delay in milliseconds. @return value for the expand/shrink delay in milliseconds (integer) """ return self.__delayTimer.interval() def __cancelDelayTimer(self): """ Private method to cancel the current delay timer. """ self.__delayTimer.stop() self.__actionMethod = None def shrink(self): """ Public method to record a shrink request. """ self.__delayTimer.stop() self.__actionMethod = self.__shrinkIt self.__delayTimer.start() def __shrinkIt(self): """ Private method to shrink the sidebar. """ self.__minimized = True self.__bigSize = self.size() if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() self.__maxSize = self.maximumHeight() else: self.__minSize = self.minimumSizeHint().width() self.__maxSize = self.maximumWidth() if self.splitter: self.splitterSizes = self.splitter.sizes() self.__stackedWidget.hide() if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.setFixedHeight(self.__tabBar.minimumSizeHint().height()) else: self.setFixedWidth(self.__tabBar.minimumSizeHint().width()) self.__actionMethod = None def expand(self): """ Public method to record a expand request. """ self.__delayTimer.stop() self.__actionMethod = self.__expandIt self.__delayTimer.start() def __expandIt(self): """ Private method to expand the sidebar. """ self.__minimized = False self.__stackedWidget.show() self.resize(self.__bigSize) if self.__orientation in [E5SideBar.North, E5SideBar.South]: minSize = max(self.__minSize, self.minimumSizeHint().height()) self.setMinimumHeight(minSize) self.setMaximumHeight(self.__maxSize) else: minSize = max(self.__minSize, self.minimumSizeHint().width()) self.setMinimumWidth(minSize) self.setMaximumWidth(self.__maxSize) if self.splitter: self.splitter.setSizes(self.splitterSizes) self.__actionMethod = None def isMinimized(self): """ Public method to check the minimized state. @return flag indicating the minimized state (boolean) """ return self.__minimized def isAutoHiding(self): """ Public method to check, if the auto hide function is active. @return flag indicating the state of auto hiding (boolean) """ return self.__autoHide def eventFilter(self, obj, evt): """ Public method to handle some events for the tabbar. @param obj reference to the object (QObject) @param evt reference to the event object (QEvent) @return flag indicating, if the event was handled (boolean) """ if obj == self.__tabBar: if evt.type() == QEvent.MouseButtonPress: pos = evt.pos() for i in range(self.__tabBar.count()): if self.__tabBar.tabRect(i).contains(pos): break if i == self.__tabBar.currentIndex(): if self.isMinimized(): self.expand() else: self.shrink() return True elif self.isMinimized(): self.expand() elif evt.type() == QEvent.Wheel: if qVersion() >= "5.0.0": delta = evt.angleDelta().y() else: delta = evt.delta() if delta > 0: self.prevTab() else: self.nextTab() return True return QWidget.eventFilter(self, obj, evt) def addTab(self, widget, iconOrLabel, label=None): """ Public method to add a tab to the sidebar. @param widget reference to the widget to add (QWidget) @param iconOrLabel reference to the icon or the label text of the tab (QIcon, string) @param label the labeltext of the tab (string) (only to be used, if the second parameter is a QIcon) """ if label: index = self.__tabBar.addTab(iconOrLabel, label) self.__tabBar.setTabToolTip(index, label) else: index = self.__tabBar.addTab(iconOrLabel) self.__tabBar.setTabToolTip(index, iconOrLabel) self.__stackedWidget.addWidget(widget) if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() else: self.__minSize = self.minimumSizeHint().width() def insertTab(self, index, widget, iconOrLabel, label=None): """ Public method to insert a tab into the sidebar. @param index the index to insert the tab at (integer) @param widget reference to the widget to insert (QWidget) @param iconOrLabel reference to the icon or the labeltext of the tab (QIcon, string) @param label the labeltext of the tab (string) (only to be used, if the second parameter is a QIcon) """ if label: index = self.__tabBar.insertTab(index, iconOrLabel, label) self.__tabBar.setTabToolTip(index, label) else: index = self.__tabBar.insertTab(index, iconOrLabel) self.__tabBar.setTabToolTip(index, iconOrLabel) self.__stackedWidget.insertWidget(index, widget) if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() else: self.__minSize = self.minimumSizeHint().width() def removeTab(self, index): """ Public method to remove a tab. @param index the index of the tab to remove (integer) """ self.__stackedWidget.removeWidget(self.__stackedWidget.widget(index)) self.__tabBar.removeTab(index) if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() else: self.__minSize = self.minimumSizeHint().width() def clear(self): """ Public method to remove all tabs. """ while self.count() > 0: self.removeTab(0) def prevTab(self): """ Public slot used to show the previous tab. """ ind = self.currentIndex() - 1 if ind == -1: ind = self.count() - 1 self.setCurrentIndex(ind) self.currentWidget().setFocus() def nextTab(self): """ Public slot used to show the next tab. """ ind = self.currentIndex() + 1 if ind == self.count(): ind = 0 self.setCurrentIndex(ind) self.currentWidget().setFocus() def count(self): """ Public method to get the number of tabs. @return number of tabs in the sidebar (integer) """ return self.__tabBar.count() def currentIndex(self): """ Public method to get the index of the current tab. @return index of the current tab (integer) """ return self.__stackedWidget.currentIndex() def setCurrentIndex(self, index): """ Public slot to set the current index. @param index the index to set as the current index (integer) """ self.__tabBar.setCurrentIndex(index) self.__stackedWidget.setCurrentIndex(index) if self.isMinimized(): self.expand() def currentWidget(self): """ Public method to get a reference to the current widget. @return reference to the current widget (QWidget) """ return self.__stackedWidget.currentWidget() def setCurrentWidget(self, widget): """ Public slot to set the current widget. @param widget reference to the widget to become the current widget (QWidget) """ self.__stackedWidget.setCurrentWidget(widget) self.__tabBar.setCurrentIndex(self.__stackedWidget.currentIndex()) if self.isMinimized(): self.expand() def indexOf(self, widget): """ Public method to get the index of the given widget. @param widget reference to the widget to get the index of (QWidget) @return index of the given widget (integer) """ return self.__stackedWidget.indexOf(widget) def isTabEnabled(self, index): """ Public method to check, if a tab is enabled. @param index index of the tab to check (integer) @return flag indicating the enabled state (boolean) """ return self.__tabBar.isTabEnabled(index) def setTabEnabled(self, index, enabled): """ Public method to set the enabled state of a tab. @param index index of the tab to set (integer) @param enabled enabled state to set (boolean) """ self.__tabBar.setTabEnabled(index, enabled) def orientation(self): """ Public method to get the orientation of the sidebar. @return orientation of the sidebar (North, East, South, West) """ return self.__orientation def setOrientation(self, orient): """ Public method to set the orientation of the sidebar. @param orient orientation of the sidebar (North, East, South, West) """ if orient == E5SideBar.North: self.__tabBar.setShape(QTabBar.RoundedNorth) self.__tabBar.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred) self.barLayout.setDirection(QBoxLayout.LeftToRight) self.layout.setDirection(QBoxLayout.TopToBottom) self.layout.setAlignment(self.barLayout, Qt.AlignLeft) elif orient == E5SideBar.East: self.__tabBar.setShape(QTabBar.RoundedEast) self.__tabBar.setSizePolicy( QSizePolicy.Preferred, QSizePolicy.Expanding) self.barLayout.setDirection(QBoxLayout.TopToBottom) self.layout.setDirection(QBoxLayout.RightToLeft) self.layout.setAlignment(self.barLayout, Qt.AlignTop) elif orient == E5SideBar.South: self.__tabBar.setShape(QTabBar.RoundedSouth) self.__tabBar.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred) self.barLayout.setDirection(QBoxLayout.LeftToRight) self.layout.setDirection(QBoxLayout.BottomToTop) self.layout.setAlignment(self.barLayout, Qt.AlignLeft) elif orient == E5SideBar.West: self.__tabBar.setShape(QTabBar.RoundedWest) self.__tabBar.setSizePolicy( QSizePolicy.Preferred, QSizePolicy.Expanding) self.barLayout.setDirection(QBoxLayout.TopToBottom) self.layout.setDirection(QBoxLayout.LeftToRight) self.layout.setAlignment(self.barLayout, Qt.AlignTop) self.__orientation = orient def tabIcon(self, index): """ Public method to get the icon of a tab. @param index index of the tab (integer) @return icon of the tab (QIcon) """ return self.__tabBar.tabIcon(index) def setTabIcon(self, index, icon): """ Public method to set the icon of a tab. @param index index of the tab (integer) @param icon icon to be set (QIcon) """ self.__tabBar.setTabIcon(index, icon) def tabText(self, index): """ Public method to get the text of a tab. @param index index of the tab (integer) @return text of the tab (string) """ return self.__tabBar.tabText(index) def setTabText(self, index, text): """ Public method to set the text of a tab. @param index index of the tab (integer) @param text text to set (string) """ self.__tabBar.setTabText(index, text) def tabToolTip(self, index): """ Public method to get the tooltip text of a tab. @param index index of the tab (integer) @return tooltip text of the tab (string) """ return self.__tabBar.tabToolTip(index) def setTabToolTip(self, index, tip): """ Public method to set the tooltip text of a tab. @param index index of the tab (integer) @param tip tooltip text to set (string) """ self.__tabBar.setTabToolTip(index, tip) def tabWhatsThis(self, index): """ Public method to get the WhatsThis text of a tab. @param index index of the tab (integer) @return WhatsThis text of the tab (string) """ return self.__tabBar.tabWhatsThis(index) def setTabWhatsThis(self, index, text): """ Public method to set the WhatsThis text of a tab. @param index index of the tab (integer) @param text WhatsThis text to set (string) """ self.__tabBar.setTabWhatsThis(index, text) def widget(self, index): """ Public method to get a reference to the widget associated with a tab. @param index index of the tab (integer) @return reference to the widget (QWidget) """ return self.__stackedWidget.widget(index) def saveState(self): """ Public method to save the state of the sidebar. @return saved state as a byte array (QByteArray) """ if len(self.splitterSizes) == 0: if self.splitter: self.splitterSizes = self.splitter.sizes() self.__bigSize = self.size() if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() self.__maxSize = self.maximumHeight() else: self.__minSize = self.minimumSizeHint().width() self.__maxSize = self.maximumWidth() data = QByteArray() stream = QDataStream(data, QIODevice.WriteOnly) stream.setVersion(QDataStream.Qt_4_6) stream.writeUInt16(self.Version) stream.writeBool(self.__minimized) stream << self.__bigSize stream.writeUInt16(self.__minSize) stream.writeUInt16(self.__maxSize) stream.writeUInt16(len(self.splitterSizes)) for size in self.splitterSizes: stream.writeUInt16(size) stream.writeBool(self.__autoHide) return data def restoreState(self, state): """ Public method to restore the state of the sidebar. @param state byte array containing the saved state (QByteArray) @return flag indicating success (boolean) """ if state.isEmpty(): return False if self.__orientation in [E5SideBar.North, E5SideBar.South]: minSize = self.layout.minimumSize().height() maxSize = self.maximumHeight() else: minSize = self.layout.minimumSize().width() maxSize = self.maximumWidth() data = QByteArray(state) stream = QDataStream(data, QIODevice.ReadOnly) stream.setVersion(QDataStream.Qt_4_6) stream.readUInt16() # version minimized = stream.readBool() if minimized and not self.__minimized: self.shrink() stream >> self.__bigSize self.__minSize = max(stream.readUInt16(), minSize) self.__maxSize = max(stream.readUInt16(), maxSize) count = stream.readUInt16() self.splitterSizes = [] for i in range(count): self.splitterSizes.append(stream.readUInt16()) self.__autoHide = stream.readBool() self.__autoHideButton.setChecked(not self.__autoHide) if not minimized: self.expand() return True ####################################################################### ## methods below implement the autohide functionality ####################################################################### def __autoHideToggled(self, checked): """ Private slot to handle the toggling of the autohide button. @param checked flag indicating the checked state of the button (boolean) """ self.__autoHide = not checked if self.__autoHide: self.__autoHideButton.setIcon( UI.PixmapCache.getIcon("autoHideOn.png")) else: self.__autoHideButton.setIcon( UI.PixmapCache.getIcon("autoHideOff.png")) def __appFocusChanged(self, old, now): """ Private slot to handle a change of the focus. @param old reference to the widget, that lost focus (QWidget or None) @param now reference to the widget having the focus (QWidget or None) """ self.__hasFocus = self.isAncestorOf(now) if self.__autoHide and not self.__hasFocus and not self.isMinimized(): self.shrink() elif self.__autoHide and self.__hasFocus and self.isMinimized(): self.expand() def enterEvent(self, event): """ Protected method to handle the mouse entering this widget. @param event reference to the event (QEvent) """ if self.__autoHide and self.isMinimized(): self.expand() else: self.__cancelDelayTimer() def leaveEvent(self, event): """ Protected method to handle the mouse leaving this widget. @param event reference to the event (QEvent) """ if self.__autoHide and not self.__hasFocus and not self.isMinimized(): self.shrink() else: self.__cancelDelayTimer() def shutdown(self): """ Public method to shut down the object. This method does some preparations so the object can be deleted properly. It disconnects from the focusChanged signal in order to avoid trouble later on. """ e5App().focusChanged[QWidget, QWidget].disconnect( self.__appFocusChanged)
class Posttid(QMainWindow): """ The main application window and functions which apply to all windows. """ def __init__(self): super(Posttid, self).__init__() # Set up the main window ui including parameters such as window size and global font self.set_up_window() # Load in the saved email and requests self.data, self.email, self.requests = self.load() # Set up each individual window screen self.central_widget = QStackedWidget() self.settings_widget = SettingsWindow(self.email, self.requests, parent=self) self.status_widget = StatusWindow(parent=self) self.central_widget.addWidget(self.status_widget) self.central_widget.addWidget(self.settings_widget) self.setCentralWidget(self.central_widget) # Start a new background thread to run the requests self.worker = Worker() self.worker.set_values(self.email, self.requests) self.worker.missing_email_signal.connect(self.log.missing_email) self.worker.connect_signal.connect(self.log.connection) self.worker.reconnect_signal.connect(self.log.reconnect) self.worker.request_signal.connect(self.log.request_found) self.worker.connectionerror_signal.connect(self.log.no_connection) self.worker.subreddit_noexist_signal.connect(self.log.subreddit_noexists) self.worker.status_condition_signal.connect(self.status_widget.set_status) self.worker.timeout_signal.connect(self.log.timeout) self.worker.httperror_signal.connect(self.log.http) self.worker.test_inside_loop.connect(self.log.inside_loop) self.worker.test_query_requests.connect(self.log.query_requests) self.worker.start() # Stop the worker thread when accessing the settings window self.status_widget.settings.clicked.connect(self.worker.terminate) def set_up_window(self): """ Defines the features for the status window """ self.setWindowTitle("Posttid") font = QFont() font.setPointSize(10) self.setFont(font) self.resize(450, 300) self.move(QApplication.desktop().screen().rect().center() - self.rect().center()) def switch_layout_status(self): """ Switches from the settings window to the status window """ self.central_widget.setCurrentIndex(0) self.status_widget.status_disable_checkbox.setChecked(self.settings_widget.settings_disable_checkbox .isChecked()) def switch_layout_settings(self): """ Switches from the status window to the settings window """ self.central_widget.setCurrentIndex(1) self.settings_widget.settings_disable_checkbox.setChecked(self.status_widget.status_disable_checkbox .isChecked()) def link(self, link_string): QDesktopServices.openUrl(QUrl(link_string)) @staticmethod def load(): """ Load in saved email and requests on start. :return: dictionary containing saved data or null if no saved data """ try: with open(getcwd() + '/tkl.pkl', 'rb') as f: data = pickle.load(f) email = data["email"] requests = data["requests"] return data, email, requests except IOError: return {}, "", {}
class AppSettings(QDialog): SettingsWidgets = [] def __init__(self, conf, **kwargs): super().__init__(**kwargs) self.conf = conf self.setWindowTitle('LiSP preferences') self.setWindowModality(QtCore.Qt.ApplicationModal) self.setMaximumSize(635, 530) self.setMinimumSize(635, 530) self.resize(635, 530) self.listWidget = QListWidget(self) self.listWidget.setGeometry(QtCore.QRect(5, 10, 185, 470)) self.sections = QStackedWidget(self) self.sections.setGeometry(QtCore.QRect(200, 10, 430, 470)) for widget in self.SettingsWidgets: widget = widget(QtCore.QSize(430, 465), self) widget.set_configuration(self.conf) self.listWidget.addItem(widget.NAME) self.sections.addWidget(widget) if len(self.SettingsWidgets) > 0: self.listWidget.setCurrentRow(0) self.listWidget.currentItemChanged.connect(self._change_page) self.dialogButtons = QDialogButtonBox(self) self.dialogButtons.setGeometry(10, 495, 615, 30) self.dialogButtons.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.dialogButtons.rejected.connect(self.reject) self.dialogButtons.accepted.connect(self.accept) def get_configuraton(self): conf = {} for n in range(self.sections.count()): widget = self.sections.widget(n) newconf = widget.get_configuration() deep_update(conf, newconf) return conf @classmethod def register_settings_widget(cls, widget): if widget not in cls.SettingsWidgets: cls.SettingsWidgets.append(widget) @classmethod def unregister_settings_widget(cls, widget): if widget not in cls.SettingsWidgets: cls.SettingsWidgets.remove(widget) def _change_page(self, current, previous): if not current: current = previous self.sections.setCurrentIndex(self.listWidget.row(current))
class FilterDialog(QDialog): def __init__(self, parent=None): super(FilterDialog, self).__init__(parent) self.accepted.connect(self.createFilter) self.contentsWidget = QListWidget() self.contentsWidget.setViewMode(QListView.IconMode) self.contentsWidget.setIconSize(QSize(96, 84)) self.contentsWidget.setMovement(QListView.Static) self.contentsWidget.setMaximumWidth(128) self.contentsWidget.setSpacing(12) self.basicFilterPage = BasicFilterPage() self.timeFilterPage = DateTimeFilterPage() self.locationFilterPage = LocationFilterPage() self.pagesWidget = QStackedWidget() self.pagesWidget.addWidget(self.basicFilterPage) self.pagesWidget.addWidget(self.timeFilterPage) self.pagesWidget.addWidget(self.locationFilterPage) self.pagesWidget.setMinimumHeight(360) rejectButton = QPushButton("Storno") rejectButton.clicked.connect(self.reject) acceptButton = QPushButton("OK") acceptButton.clicked.connect(self.accept) self.createIcons() self.contentsWidget.setCurrentRow(0) horizontalLayout = QHBoxLayout() horizontalLayout.addWidget(self.contentsWidget) horizontalLayout.addWidget(self.pagesWidget, 1) buttonsLayout = QHBoxLayout() buttonsLayout.addStretch(1) buttonsLayout.addWidget(acceptButton) buttonsLayout.addWidget(rejectButton) layout = QVBoxLayout() layout.addLayout(horizontalLayout) layout.addStretch(1) layout.addSpacing(12) layout.addLayout(buttonsLayout) self.setLayout(layout) self.setMinimumWidth(450) self.setWindowTitle("Filtrování výsledků") def initControls(self, options, filter_): self.basicFilterPage.initControls(options, filter_) self.timeFilterPage.initControls(filter_) self.locationFilterPage.initControls(filter_) def changePage(self, current, previous): if not current: current = previous self.pagesWidget.setCurrentIndex(self.contentsWidget.row(current)) def createIcons(self): basicButton = QListWidgetItem(self.contentsWidget) basicButton.setIcon(QIcon('app/ui/images/settings.png')) basicButton.setText("Základní filtry") basicButton.setTextAlignment(Qt.AlignHCenter) basicButton.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) timeButton = QListWidgetItem(self.contentsWidget) timeButton.setIcon(QIcon('app/ui/images/time.png')) timeButton.setText("Datum a čas") timeButton.setTextAlignment(Qt.AlignHCenter) timeButton.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) locationButton = QListWidgetItem(self.contentsWidget) locationButton.setIcon(QIcon('app/ui/images/location.png')) locationButton.setText("Lokace") locationButton.setTextAlignment(Qt.AlignHCenter) locationButton.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.contentsWidget.currentItemChanged.connect(self.changePage) @pyqtSlot() def createFilter(self): self._filter = self.basicFilterPage.getFilter() self._filter.update(self.timeFilterPage.getFilter()) self._filter.update(self.locationFilterPage.getFilter()) def filter(self): return self._filter
class TableWidget(QSplitter): def __init__(self): super(TableWidget, self).__init__() # vbox = QVBoxLayout(self) # vbox.setContentsMargins(0, 0, 0, 0) self._tabs = QTabWidget() self._tabs.setAutoFillBackground(True) p = self._tabs.palette() p.setColor(p.Window, QColor("white")) self._tabs.setPalette(p) self._other_tab = QTabWidget() self._other_tab.setAutoFillBackground(True) self._other_tab.setPalette(p) self.addWidget(self._tabs) self.addWidget(self._other_tab) self.setSizes([1, 1]) self._other_tab.hide() self.relations = {} # Stack self.stacked = QStackedWidget() self._tabs.addTab(self.stacked, "Workspace") self.stacked_result = QStackedWidget() self._tabs.addTab(self.stacked_result, self.tr("Resultados")) btn_split = QToolButton() btn_split.setToolTip(self.tr("Click para dividir la pantalla")) btn_split.setAutoRaise(True) btn_split.setIcon(QIcon(":img/split")) self._tabs.setCornerWidget(btn_split) btn_split.clicked.connect(self._split) btn_split = QToolButton() btn_split.setToolTip(self.tr("Click para juntar las pantallas")) btn_split.setAutoRaise(True) btn_split.setIcon(QIcon(":img/split")) btn_split.clicked.connect(self._unsplit) self._other_tab.setCornerWidget(btn_split) # self.setContextMenuPolicy(Qt.CustomContextMenu) # self.customContextMenuRequested.connect(self._show_menu) lateral_widget = Pireal.get_service("lateral_widget") lateral_widget.resultClicked.connect(self._on_result_list_clicked) lateral_widget.resultSelectionChanged.connect( lambda index: self.stacked_result.setCurrentIndex(index)) # lateral_widget.newRowsRequested.connect(self._insert_rows) def insert_rows(self, tuplas): current_view = self.current_table() if current_view is not None: model = current_view.model() for tupla in tuplas: model.insertRow(model.rowCount(), tupla) current_view.adjust_columns() def _on_result_list_clicked(self, index): self.stacked_result.setCurrentIndex(index) if not self._other_tab.isVisible(): self._tabs.setCurrentIndex(1) def _unsplit(self): self._other_tab.hide() result_widget = self._other_tab.widget(0) self._tabs.addTab(result_widget, self.tr("Resultados")) self._tabs.cornerWidget().show() def _split(self): result_widget = self._tabs.widget(1) self._other_tab.addTab(result_widget, self.tr("Resultados")) self._other_tab.show() self.setSizes([1, 1]) self._tabs.cornerWidget().hide() self.setOrientation(Qt.Horizontal) def _show_menu(self, position): menu = QMenu(self) if self.count() > 0: add_tuple_action = menu.addAction(self.tr("Agregar Tupla")) add_col_action = menu.addAction(self.tr("Add Column")) add_tuple_action.triggered.connect(self.add_tuple) add_col_action.triggered.connect(self.add_column) menu.addSeparator() add_relation_action = menu.addAction(self.tr("Create new Relation")) add_relation_action.triggered.connect(self.__new_relation) menu.exec_(self.mapToGlobal(position)) def __new_relation(self): central_service = Pireal.get_service("central") central_service.create_new_relation() def count(self): return self.stacked.count() def remove_table(self, index): widget = self.stacked.widget(index) self.stacked.removeWidget(widget) del widget def current_table(self): return self.stacked.currentWidget() def remove_relation(self, name): del self.relations[name] def add_relation(self, name, rela): if self.relations.get(name, None) is None: self.relations[name] = rela return True return False def add_table(self, rela, name, table): """ Add new table from New Relation Dialog """ self.add_relation(name, rela) self.stacked.addWidget(table) def add_tuple(self): current_view = self.current_table() if current_view is not None: model = current_view.model() model.insertRow(model.rowCount()) def add_column(self): current_view = self.current_table() if current_view is not None: model = current_view.model() model.insertColumn(model.columnCount()) def delete_tuple(self): current_view = self.current_table() if current_view is not None: model = current_view.model() selection = current_view.selectionModel() if selection.hasSelection(): selection = selection.selection() rows = set([index.row() for index in selection.indexes()]) rows = sorted(list(rows)) previous = -1 i = len(rows) - 1 while i >= 0: current = rows[i] if current != previous: model.removeRow(current) i -= 1 def delete_column(self): """ Elimina la/las columnas seleccionadas """ current_view = self.current_table() if current_view is not None: model = current_view.model() selection = current_view.selectionModel() if selection.hasSelection(): selection = selection.selection() columns = set( [index.column() for index in selection.indexes()]) columns = sorted(list(columns)) previous = -1 i = len(columns) - 1 while i >= 0: current = columns[i] if current != previous: model.removeColumn(current) i -= 1 def create_table(self, rela, editable=True): """ Se crea la vista y el modelo """ _view = view.View() _model = model.Model(rela) if not editable: _model.editable = False _view.setModel(_model) _view.setItemDelegate(delegate.Delegate()) _view.setHorizontalHeader(view.Header()) return _view
class QChatTab(QWidget): def __init__(self, chat_window, nick=None, just_accepted=False): QWidget.__init__(self) self.chat_window = chat_window self.nick = nick self.just_accepted = just_accepted self.unread_count = 0 self.widget_stack = QStackedWidget(self) self.widget_stack.addWidget(QNickInputWidget('new_chat.png', 150, self.connectClicked, parent=self)) self.widget_stack.addWidget(QConnectingWidget(parent=self)) self.widget_stack.addWidget(QChatWidget(self.chat_window, nick=nick, parent=self)) if self.nick is not None: self.widget_stack.setCurrentIndex(2) else: self.widget_stack.setCurrentIndex(0) layout = QHBoxLayout() layout.addWidget(self.widget_stack) self.setLayout(layout) def connectClicked(self, nick): if self.chat_window.isNickInTabs(nick): QMessageBox.warning(self, TITLE_ALREADY_CONNECTED, ALREADY_CONNECTED % (nick)) return self.nick = nick self.widget_stack.widget(1).setConnectingToNick(self.nick) self.widget_stack.setCurrentIndex(1) self.chat_window.client.openSession(self.nick) self.widget_stack.widget(2).setRemoteNick(self.nick) def appendMessage(self, message, source): self.widget_stack.widget(2).appendMessage(message, source) def showNowChattingMessage(self): self.widget_stack.setCurrentIndex(2) self.widget_stack.widget(2).showNowChattingMessage(self.nick) def enable(self): self.widget_stack.setCurrentIndex(2) self.widget_stack.widget(2).enable() def resetOrDisable(self): cur_widget_index = self.widget_stack.currentIndex() if cur_widget_index == 1: self.widget_stack.setCurrentIndex(0) elif cur_widget_index == 2: self.widget_stack.widget(2).disable()
class CentralWidget(QWidget): # This signals is used by notificator databaseSaved = pyqtSignal('QString') querySaved = pyqtSignal('QString') def __init__(self): QWidget.__init__(self) box = QVBoxLayout(self) box.setContentsMargins(0, 0, 0, 0) box.setSpacing(0) self.stacked = QStackedWidget() box.addWidget(self.stacked) self.created = False self.__last_open_folder = None self.__recent_dbs = [] if PSetting.RECENT_DBS: self.__recent_dbs = PSetting.RECENT_DBS Pireal.load_service("central", self) @property def recent_databases(self): return self.__recent_dbs @recent_databases.setter def recent_databases(self, database_file): if database_file in PSetting.RECENT_DBS: PSetting.RECENT_DBS.remove(database_file) PSetting.RECENT_DBS.insert(0, database_file) self.__recent_dbs = PSetting.RECENT_DBS def create_database(self): """ Show a wizard widget to create a new database, only have one database open at time. """ if self.created: QMessageBox.information(self, self.tr("Information"), self.tr("You may only have one database" " open at time.")) DEBUG("Ya existe una base de datos abierta") return wizard = database_wizard.DatabaseWizard(self) wizard.wizardFinished.connect( self.__on_wizard_finished) # Hide menubar and toolbar pireal = Pireal.get_service("pireal") pireal.show_hide_menubar() pireal.show_hide_toolbar() # Add wizard widget to stacked self.add_widget(wizard) def __on_wizard_finished(self, data, wizard_widget): """ This slot execute when wizard to create a database is finished """ pireal = Pireal.get_service("pireal") if not data: # If it's canceled, remove wizard widget and return to Start Page self.remove_last_widget() else: # Create a new data base container db_container = database_container.DatabaseContainer() # Associate the file name with the PFile object pfile_object = pfile.File(data['filename']) # Associate PFile object with data base container # and add widget to stacked db_container.pfile = pfile_object self.add_widget(db_container) # Remove wizard self.stacked.removeWidget(wizard_widget) # Set window title pireal.change_title(file_manager.get_basename(data['filename'])) # Enable db actions pireal.set_enabled_db_actions(True) pireal.set_enabled_relation_actions(True) self.created = True DEBUG("Base de datos creada correctamente: '{}'".format( data['filename'])) # If data or not, show menubar and toolbar again pireal.show_hide_menubar() pireal.show_hide_toolbar() def open_database(self, filename=''): """ This function opens a database and set this on the UI """ # If not filename provide, then open dialog to select if self.created: QMessageBox.information(self, self.tr("Information"), self.tr("You may only have one database" " open at time.")) DEBUG("Ya existe una base de datos abierta") return if not filename: if self.__last_open_folder is None: directory = os.path.expanduser("~") else: directory = self.__last_open_folder filter_ = settings.SUPPORTED_FILES.split(';;')[0] filename, _ = QFileDialog.getOpenFileName(self, self.tr("Open Database"), directory, filter_) # If is canceled, return if not filename: return # Remember the folder self.__last_open_folder = file_manager.get_path(filename) DEBUG("Abriendo la base de datos: '{}'".format(filename)) # If filename provide try: # Read pdb file pfile_object = pfile.File(filename) db_data = pfile_object.read() # Create a dict to manipulate data more easy db_data = self.__sanitize_data(db_data) except Exception as reason: QMessageBox.information(self, self.tr("The file couldn't be open"), str(reason)) CRITICAL("Error al intentar abrir el archivo: {}".format(reason)) return # Create a database container widget db_container = database_container.DatabaseContainer() try: db_container.create_database(db_data) except Exception as reason: QMessageBox.information(self, self.tr("Error"), str(reason)) CRITICAL("Error al crear la base de datos: {}".format(reason)) return # Set the PFile object to the new database db_container.pfile = pfile_object # Add data base container to stacked self.add_widget(db_container) # Database name db_name = file_manager.get_basename(filename) # Update title with the new database name, and enable some actions pireal = Pireal.get_service("pireal") pireal.change_title(db_name) pireal.set_enabled_db_actions(True) pireal.set_enabled_relation_actions(True) # Add to recent databases self.recent_databases = filename self.created = True def open_query(self): filter_ = settings.SUPPORTED_FILES.split(';;')[1] filename, _ = QFileDialog.getOpenFileName(self, self.tr("Open Query"), os.path.expanduser("~"), filter_) if not filename: return # FIXME: mejorar éste y new_query self.new_query(filename) def save_query(self, editor=None): db = self.get_active_db() fname = db.save_query(editor) if fname: self.querySaved.emit(self.tr("Query saved: {}".format(fname))) def save_query_as(self): pass def __sanitize_data(self, data): """ This function converts the data into a dictionary for better handling then. The argument 'data' is the content of the database. """ # FIXME: controlar cuando al final de la línea hay una coma data_dict = {'tables': []} for line_count, line in enumerate(data.splitlines()): # Ignore blank lines if not line: continue if line.startswith('@'): # This line is a header tpoint = line.find(':') if tpoint == -1: raise Exception("Invalid syntax at line {}".format( line_count + 1)) table_name, line = line.split(':') table_name = table_name[1:].strip() table_dict = {} table_dict['name'] = table_name table_dict['header'] = line.split(',') table_dict['tuples'] = [] else: for l in csv.reader([line]): # Remove spaces l = list(map(str.strip, l)) # FIXME: this is necesary? if table_dict['name'] == table_name: table_dict['tuples'].append(l) if not table_dict['tuples']: data_dict['tables'].append(table_dict) return data_dict def remove_last_widget(self): """ Remove last widget from stacked """ widget = self.stacked.widget(self.stacked.count() - 1) self.stacked.removeWidget(widget) def close_database(self): """ Close the database and return to the main widget """ db = self.get_active_db() query_container = db.query_container if db.modified: msgbox = QMessageBox(self) msgbox.setIcon(QMessageBox.Question) msgbox.setWindowTitle(self.tr("Save Changes?")) msgbox.setText(self.tr("The <b>{}</b> database has ben" " modified.<br>Do you want save " "your changes?".format( db.dbname()))) cancel_btn = msgbox.addButton(self.tr("Cancel"), QMessageBox.RejectRole) msgbox.addButton(self.tr("No"), QMessageBox.NoRole) yes_btn = msgbox.addButton(self.tr("Yes"), QMessageBox.YesRole) msgbox.exec_() r = msgbox.clickedButton() if r == cancel_btn: return if r == yes_btn: self.save_database() # Check if editor is modified query_widget = query_container.currentWidget() if query_widget is not None: weditor = query_widget.get_editor() if weditor is not None: # TODO: duplicate code, see tab widget if weditor.modified: msgbox = QMessageBox(self) msgbox.setIcon(QMessageBox.Question) msgbox.setWindowTitle(self.tr("File modified")) msgbox.setText(self.tr("The file <b>{}</b> has unsaved " "changes. You want to keep " "them?".format( weditor.name))) cancel_btn = msgbox.addButton(self.tr("Cancel"), QMessageBox.RejectRole) msgbox.addButton(self.tr("No"), QMessageBox.NoRole) yes_btn = msgbox.addButton(self.tr("Yes"), QMessageBox.YesRole) msgbox.exec_() r = msgbox.clickedButton() if r == cancel_btn: return if r == yes_btn: self.save_query(weditor) self.stacked.removeWidget(db) pireal = Pireal.get_service("pireal") pireal.set_enabled_db_actions(False) pireal.set_enabled_relation_actions(False) pireal.set_enabled_query_actions(False) pireal.set_enabled_editor_actions(False) self.created = False DEBUG("Se cerró la base de datos: '{}'".format(db.dbname())) del db def new_query(self, filename=''): pireal = Pireal.get_service("pireal") db_container = self.get_active_db() db_container.new_query(filename) # Enable editor actions # FIXME: refactoring pireal.set_enabled_query_actions(True) zoom_in_action = Pireal.get_action("zoom_in") zoom_in_action.setEnabled(True) zoom_out_action = Pireal.get_action("zoom_out") zoom_out_action.setEnabled(True) paste_action = Pireal.get_action("paste_action") paste_action.setEnabled(True) comment_action = Pireal.get_action("comment") comment_action.setEnabled(True) uncomment_action = Pireal.get_action("uncomment") uncomment_action.setEnabled(True) def execute_queries(self): db_container = self.get_active_db() db_container.execute_queries() def execute_selection(self): db_container = self.get_active_db() db_container.execute_selection() def save_database(self): db = self.get_active_db() if not db.modified: return # Get relations dict relations = db.table_widget.relations # Generate content content = file_manager.generate_database(relations) db.pfile.save(content=content) filename = db.pfile.filename # Emit signal self.databaseSaved.emit( self.tr("Database saved: {}".format(filename))) db.modified = False def save_database_as(self): filter = settings.SUPPORTED_FILES.split(';;')[0] filename, _ = QFileDialog.getSaveFileName(self, self.tr("Save Database As"), settings.PIREAL_PROJECTS, filter) if not filename: return db = self.get_active_db() # Get relations relations = db.table_widget.relations # Content content = file_manager.generate_database(relations) db.pfile.save(content, filename) self.databaseSaved.emit( self.tr("Database saved: {}".format(db.pfile.filename))) db.modified = False def remove_relation(self): db = self.get_active_db() if db.delete_relation(): db.modified = True def create_new_relation(self): data = new_relation_dialog.create_relation() if data is not None: db = self.get_active_db() rela, rela_name = data # Add table db.table_widget.add_table(rela, rela_name) # Add item to lateral widget db.lateral_widget.add_item(rela_name, rela.count()) # Set modified db db.modified = True def edit_relation(self): db = self.get_active_db() lateral = db.lateral_widget selected_items = lateral.selectedItems() if selected_items: selected_relation = selected_items[0].text(0) relation_text = selected_relation.split()[0].strip() rela = db.table_widget.relations[relation_text] data = edit_relation_dialog.edit_relation(rela) if data is not None: # Update table db.table_widget.update_table(data) # Update relation db.table_widget.relations[relation_text] = data # Set modified db db.modified = True lateral.update_item(data.count()) def load_relation(self, filename=''): """ Load Relation file """ if not filename: if self.__last_open_folder is None: directory = os.path.expanduser("~") else: directory = self.__last_open_folder msg = self.tr("Open Relation File") filter_ = settings.SUPPORTED_FILES.split(';;')[-1] filenames = QFileDialog.getOpenFileNames(self, msg, directory, filter_)[0] if not filenames: return # Save folder self.__last_open_folder = file_manager.get_path(filenames[0]) db_container = self.get_active_db() if db_container.load_relation(filenames): db_container.modified = True def add_start_page(self): """ This function adds the Start Page to the stacked widget """ sp = start_page.StartPage() self.add_widget(sp) def show_settings(self): """ Show settings dialog on stacked """ preferences_dialog = preferences.Preferences(self) if isinstance(self.widget(1), preferences.Preferences): self.widget(1).close() else: self.stacked.insertWidget(1, preferences_dialog) self.stacked.setCurrentIndex(1) # Connect the closed signal preferences_dialog.settingsClosed.connect(self._settings_closed) def widget(self, index): """ Returns the widget at the given index """ return self.stacked.widget(index) def add_widget(self, widget): """ Appends and show the given widget to the Stacked """ index = self.stacked.addWidget(widget) self.stacked.setCurrentIndex(index) def _settings_closed(self): self.stacked.removeWidget(self.widget(1)) self.stacked.setCurrentWidget(self.stacked.currentWidget()) def get_active_db(self): """ Return an instance of DatabaseContainer widget if the stacked contains an DatabaseContainer in last index or None if it's not an instance of DatabaseContainer """ index = self.stacked.count() - 1 widget = self.widget(index) if isinstance(widget, database_container.DatabaseContainer): return widget return None def get_unsaved_queries(self): query_container = self.get_active_db().query_container return query_container.get_unsaved_queries() def undo_action(self): query_container = self.get_active_db().query_container query_container.undo() def redo_action(self): query_container = self.get_active_db().query_container query_container.redo() def cut_action(self): query_container = self.get_active_db().query_container query_container.cut() def copy_action(self): query_container = self.get_active_db().query_container query_container.copy() def paste_action(self): query_container = self.get_active_db().query_container query_container.paste() def zoom_in(self): query_container = self.get_active_db().query_container query_container.zoom_in() def zoom_out(self): query_container = self.get_active_db().query_container query_container.zoom_out() def comment(self): query_container = self.get_active_db().query_container query_container.comment() def uncomment(self): query_container = self.get_active_db().query_container query_container.uncomment()
class QueryWidget(QWidget): editorModified = pyqtSignal(bool) def __init__(self): super(QueryWidget, self).__init__() box = QVBoxLayout(self) box.setContentsMargins(0, 0, 0, 0) self._vsplitter = QSplitter(Qt.Vertical) self._hsplitter = QSplitter(Qt.Horizontal) self._result_list = lateral_widget.LateralWidget() self._result_list.header().hide() self._hsplitter.addWidget(self._result_list) self._stack_tables = QStackedWidget() self._hsplitter.addWidget(self._stack_tables) self.relations = {} self._query_editor = editor.Editor() # Editor connections self._query_editor.customContextMenuRequested.connect( self.__show_context_menu) self._query_editor.modificationChanged[bool].connect( self.__editor_modified) self._query_editor.undoAvailable[bool].connect( self.__on_undo_available) self._query_editor.redoAvailable[bool].connect( self.__on_redo_available) self._query_editor.copyAvailable[bool].connect( self.__on_copy_available) self._vsplitter.addWidget(self._query_editor) self._vsplitter.addWidget(self._hsplitter) box.addWidget(self._vsplitter) # Connections self._result_list.itemClicked.connect( lambda index: self._stack_tables.setCurrentIndex( self._result_list.row())) self._result_list.itemDoubleClicked.connect( self.show_relation) def __show_context_menu(self, point): popup_menu = self._query_editor.createStandardContextMenu() undock_editor = QAction(self.tr("Undock"), self) popup_menu.insertAction(popup_menu.actions()[0], undock_editor) popup_menu.insertSeparator(popup_menu.actions()[1]) undock_editor.triggered.connect(self.__undock_editor) popup_menu.exec_(self.mapToGlobal(point)) def __undock_editor(self): new_editor = editor.Editor() actual_doc = self._query_editor.document() new_editor.setDocument(actual_doc) new_editor.resize(900, 400) # Set text cursor tc = self._query_editor.textCursor() new_editor.setTextCursor(tc) # Set title db = Pireal.get_service("central").get_active_db() qc = db.query_container new_editor.setWindowTitle(qc.tab_text(qc.current_index())) new_editor.show() def __on_undo_available(self, value): """ Change state of undo action """ pireal = Pireal.get_service("pireal") action = pireal.get_action("undo_action") action.setEnabled(value) def __on_redo_available(self, value): """ Change state of redo action """ pireal = Pireal.get_service("pireal") action = pireal.get_action("redo_action") action.setEnabled(value) def __on_copy_available(self, value): """ Change states of cut and copy action """ cut_action = Pireal.get_action("cut_action") cut_action.setEnabled(value) copy_action = Pireal.get_action("copy_action") copy_action.setEnabled(value) def show_relation(self, item): central_widget = Pireal.get_service("central") table_widget = central_widget.get_active_db().table_widget rela = self.relations[item.name] dialog = QDialog(self) dialog.resize(700, 500) dialog.setWindowTitle(item.name) box = QVBoxLayout(dialog) box.setContentsMargins(5, 5, 5, 5) table = table_widget.create_table(rela) box.addWidget(table) hbox = QHBoxLayout() btn = QPushButton(self.tr("Ok")) btn.clicked.connect(dialog.close) hbox.addStretch() hbox.addWidget(btn) box.addLayout(hbox) dialog.show() def save_sizes(self): """ Save sizes of Splitters """ qsettings = QSettings(settings.SETTINGS_PATH, QSettings.IniFormat) qsettings.setValue('hsplitter_query_sizes', self._hsplitter.saveState()) qsettings.setValue('vsplitter_query_sizes', self._vsplitter.saveState()) def get_editor(self): return self._query_editor def __editor_modified(self, modified): self.editorModified.emit(modified) def showEvent(self, event): super(QueryWidget, self).showEvent(event) self._hsplitter.setSizes([1, self.width() / 3]) def clear_results(self): self._result_list.clear_items() i = self._stack_tables.count() while i >= 0: widget = self._stack_tables.widget(i) self._stack_tables.removeWidget(widget) if widget is not None: widget.deleteLater() i -= 1 def add_table(self, rela, rname): wtable = custom_table.Table() # Model model = QStandardItemModel() wtable.setModel(model) model.setHorizontalHeaderLabels(rela.header) for data in rela.content: nrow = model.rowCount() # wtable.insertRow(nrow) for col, text in enumerate(data): item = QStandardItem(text) item.setFlags(item.flags() & ~Qt.ItemIsEditable) model.setItem(nrow, col, item) index = self._stack_tables.addWidget(wtable) self._stack_tables.setCurrentIndex(index) self._result_list.add_item(rname, rela.count())
class EntryView(BaseTransactionView): def _setup(self): self._setupUi() self.etable = EntryTable(self.model.etable, view=self.tableView) self.efbar = EntryFilterBar(model=self.model.filter_bar, view=self.filterBar) self.bgraph = Chart(self.model.bargraph, view=self.barGraphView) self.lgraph = Chart(self.model.balgraph, view=self.lineGraphView) self._setupColumns() # Can only be done after the model has been connected self.reconciliationButton.clicked.connect(self.model.toggle_reconciliation_mode) def _setupUi(self): self.resize(483, 423) self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setSpacing(0) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setSpacing(0) self.filterBar = RadioBox(self) sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.filterBar.sizePolicy().hasHeightForWidth()) self.filterBar.setSizePolicy(sizePolicy) self.horizontalLayout.addWidget(self.filterBar) self.horizontalLayout.addItem(horizontalSpacer()) self.reconciliationButton = QPushButton(tr("Reconciliation")) self.reconciliationButton.setCheckable(True) self.horizontalLayout.addWidget(self.reconciliationButton) self.verticalLayout.addLayout(self.horizontalLayout) self.splitterView = QSplitter() self.splitterView.setOrientation(Qt.Vertical) self.splitterView.setChildrenCollapsible(False) self.tableView = TableView(self) self.tableView.setAcceptDrops(True) self.tableView.setEditTriggers(QAbstractItemView.DoubleClicked|QAbstractItemView.EditKeyPressed) self.tableView.setDragEnabled(True) self.tableView.setDragDropMode(QAbstractItemView.InternalMove) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.setSortingEnabled(True) self.tableView.horizontalHeader().setHighlightSections(False) self.tableView.horizontalHeader().setMinimumSectionSize(18) self.tableView.verticalHeader().setVisible(False) self.tableView.verticalHeader().setDefaultSectionSize(18) self.splitterView.addWidget(self.tableView) self.graphView = QStackedWidget(self) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.graphView.sizePolicy().hasHeightForWidth()) self.graphView.setSizePolicy(sizePolicy) self.graphView.setMinimumSize(0, 200) self.lineGraphView = LineGraphView() self.graphView.addWidget(self.lineGraphView) self.barGraphView = BarGraphView() self.graphView.addWidget(self.barGraphView) self.splitterView.addWidget(self.graphView) self.graphView.setCurrentIndex(1) self.splitterView.setStretchFactor(0, 1) self.splitterView.setStretchFactor(1, 0) self.verticalLayout.addWidget(self.splitterView) def _setupColumns(self): h = self.tableView.horizontalHeader() h.setSectionsMovable(True) # column drag & drop reorder # --- QWidget override def setFocus(self): self.etable.view.setFocus() # --- Public def fitViewsForPrint(self, viewPrinter): hidden = self.model.mainwindow.hidden_areas viewPrinter.fitTable(self.etable) if PaneArea.BottomGraph not in hidden: viewPrinter.fit(self.graphView.currentWidget(), 300, 150, expandH=True, expandV=True) def restoreSubviewsSize(self): graphHeight = self.model.graph_height_to_restore if graphHeight: splitterHeight = self.splitterView.height() sizes = [splitterHeight-graphHeight, graphHeight] self.splitterView.setSizes(sizes) # --- model --> view def refresh_reconciliation_button(self): if self.model.can_toggle_reconciliation_mode: self.reconciliationButton.setEnabled(True) self.reconciliationButton.setChecked(self.model.reconciliation_mode) else: self.reconciliationButton.setEnabled(False) self.reconciliationButton.setChecked(False) def show_bar_graph(self): self.graphView.setCurrentIndex(1) def show_line_graph(self): self.graphView.setCurrentIndex(0) def update_visibility(self): hidden = self.model.mainwindow.hidden_areas self.graphView.setHidden(PaneArea.BottomGraph in hidden)
class ParamModWgt(QWidget): def __init__(self, parent=None): super().__init__(parent) self.main_window = parent self.buildRequiredTagsGB() # Widgets self.newParamBtn = QPushButton("New") self.deleteParamBtn = QPushButton("Delete") self.paramSaveAnnotBtn = QPushButton("Save") buttonWidget = QWidget(self) self.existingParamsGB = QGroupBox("Existing parameters", self) self.paramListTblWdg = QTableView() self.paramListModel = ParameterListModel(parent=self) self.paramListTblWdg.setSelectionBehavior(QAbstractItemView.SelectRows) self.paramListTblWdg.setSelectionMode(QAbstractItemView.SingleSelection) self.paramListTblWdg.setModel(self.paramListModel) self.paramListTblWdg.setColumnWidth(0, 150) self.paramListTblWdg.setColumnWidth(1, 350) self.relationWgt = ParamRelationWgt(parent) self.newParamsGB = QGroupBox("Parameter details", self) self.resultTypeCbo = QComboBox(self) self.isExpProp = QCheckBox("is an experimental property", self) self.resultTypeCbo.addItems(["point value", "function", "numerical trace"]) self.singleValueParamWgt = ParamValueWgt(parent) self.functionParamWgt = ParamFunctionWgt(parent) self.traceParamWgt = ParamTraceWgt(parent) self.functionParamWgt.mainWgt = self self.paramModStack = QStackedWidget(self) self.paramModStack.addWidget(self.singleValueParamWgt) self.paramModStack.addWidget(self.functionParamWgt) self.paramModStack.addWidget(self.traceParamWgt) # Signals selectionModel = self.paramListTblWdg.selectionModel() selectionModel.selectionChanged.connect(self.selectedParameterChanged) self.newParamBtn.clicked.connect(self.newParameter) self.deleteParamBtn.clicked.connect(self.deleteParameter) self.paramSaveAnnotBtn.clicked.connect(self.saveParameter) self.resultTypeCbo.currentIndexChanged.connect(self.paramModStack.setCurrentIndex) self.singleValueParamWgt.paramTypeSelected.connect(self.newParamTypeSelected) self.functionParamWgt.paramTypeSelected.connect(self.newParamTypeSelected) self.traceParamWgt.paramTypeSelected.connect(self.newParamTypeSelected) # Layout buttonLayout = QVBoxLayout(buttonWidget) buttonLayout.addWidget(self.paramSaveAnnotBtn) buttonLayout.addWidget(self.deleteParamBtn) buttonLayout.addWidget(self.newParamBtn) existGrid = QHBoxLayout(self.existingParamsGB) existGrid.addWidget(buttonWidget) existGrid.addWidget(self.paramListTblWdg) newGrid = QGridLayout(self.newParamsGB) newGrid.addWidget(QLabel("Result type"), 0, 0) newGrid.addWidget(self.resultTypeCbo, 0, 1) newGrid.addWidget(self.isExpProp, 0, 2) newGrid.addWidget(self.paramModStack, 1, 0, 1, 3) newGrid.addWidget(self.relationWgt, 1, 3) layout = QVBoxLayout(self) self.rootLayout = QSplitter(Qt.Vertical, self) self.rootLayout.setOrientation(Qt.Vertical) self.rootLayout.addWidget(self.existingParamsGB) self.rootLayout.addWidget(self.newParamsGB) self.rootLayout.addWidget(self.requireTagGB) layout.addWidget(self.rootLayout) # Initial behavior self.newParamBtn.setEnabled(True) self.deleteParamBtn.setEnabled(False) self.paramSaveAnnotBtn.setEnabled(False) self.additionMode = False self.newParamsGB.setEnabled(False) def setRootLayoutSizes(self, sizes): self.rootLayout.setSizes(sizes) def viewParameter(self, parameter): row = -1 for row, param in enumerate(self.paramListModel.parameterList): if param.id == parameter.id: break assert(row > -1) self.paramListTblWdg.selectRow(row) @pyqtSlot(str) def newParamTypeSelected(self, paramName): self.requiredTagsListModel.clear() self.requiredTagsListModel.refresh() paramType = getParameterTypeFromName(paramName) if paramType is None: raise ValueError("Parameter type with name '" + paramName + "' was not found.") for reqTag in paramType.requiredTags: self.requiredTagsListModel.addTag(reqTag.id, reqTag.name, reqTag.id, reqTag.name) self.requiredTagsListModel.refresh() def buildRequiredTagsGB(self): # Widgets self.requireTagGB = QGroupBox("Required tag categories", self) self.requiredTagsListTblWdg = RequiredTagsTableView() self.requiredTagsListModel = RequiredTagsListModel(parent=self) self.requiredTagsListTblWdg.setSelectionBehavior(QAbstractItemView.SelectRows) self.requiredTagsListTblWdg.setSelectionMode(QAbstractItemView.SingleSelection) self.requiredTagsListTblWdg.setModel(self.requiredTagsListModel) self.requiredTagsListTblWdg.setColumnWidth(0, 200) self.requiredTagsListTblWdg.setColumnWidth(1, 200) # Layout requiredTagLayout = QGridLayout(self.requireTagGB) requiredTagLayout.addWidget(self.requiredTagsListTblWdg, 0, 0, 4, 1) def newParameter(self): self.resultTypeCbo.setCurrentIndex(0) self.paramModStack.currentWidget().newParameter() self.singleValueParamWgt.newParameter() self.functionParamWgt.newParameter() self.traceParamWgt.newParameter() self.newParamsGB.setEnabled(True) self.paramListTblWdg.clearSelection() self.newParamBtn.setEnabled(False) self.deleteParamBtn.setEnabled(False) self.paramSaveAnnotBtn.setEnabled(True) self.isExpProp.setChecked(False) def saveParameter(self): relationship = self.relationWgt.getRelationship() # Get the ID of the modified parameter if we are modifying an existing # parameters if len(self.paramListTblWdg.selectionModel().selectedRows()) != 0: selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row() paramId = self.main_window.currentAnnotation.parameters[selectedRow].id else: paramId = None param = self.paramModStack.currentWidget().saveParameter(relationship, paramId) if not param is None: param.requiredTags = self.requiredTagsListModel.getRequiredTags() param.isExperimentProperty = self.isExpProp.isChecked() selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row() # Even when there is no selection, selectedRow can take a zero value. This "if" # controls for that. if len(self.paramListTblWdg.selectionModel().selectedRows()) == 0: selectedRow = -1 if selectedRow >= 0: self.main_window.currentAnnotation.parameters[selectedRow] = param else: self.main_window.currentAnnotation.parameters.append(param) self.additionMode = False nbParams = len(self.main_window.currentAnnotation.parameters) self.main_window.saveAnnotation() if selectedRow < 0 : selectedRow = nbParams-1 self.paramListTblWdg.selectRow(selectedRow) self.loadRow(selectedRow) def deleteParameter(self): selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row() del self.main_window.currentAnnotation.parameters[selectedRow] self.main_window.saveAnnotation() self.refreshModelingParameters() def refreshModelingParameters(self): selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row() self.loadModelingParameter(selectedRow) def loadModelingParameter(self, row = None): """ Call when a new annotation has been selected so that all the modeling parameters associated with this annotation are loaded in the parameter list. """ self.requiredTagsListModel.clear() self.requiredTagsListModel.refresh() if self.main_window.currentAnnotation is None: self.paramListModel.parameterList = [] else: self.paramListModel.parameterList = self.main_window.currentAnnotation.parameters aRowIsSelected = not row is None if aRowIsSelected: if row < 0: noRowToLoad = self.paramListTblWdg.model().rowCount()-row else: noRowToLoad = row else: ## No rows are selected noRowToLoad = -1 self.loadRow(noRowToLoad) self.newParamBtn.setEnabled(True) self.deleteParamBtn.setEnabled(aRowIsSelected) self.paramSaveAnnotBtn.setEnabled(aRowIsSelected) self.paramModStack.currentWidget().loadModelingParameter(row) self.relationWgt.loadModelingParameter(row) self.newParamsGB.setEnabled(aRowIsSelected) self.paramListModel.refresh() def loadRow(self, selectedRow = None): """ Called when a row has been selected in the table listing all the modeling parameters. It update the interface with the values associated with this specific parameter. """ def nlxCheck(id): if id in nlx2ks: return nlx2ks[id] return id def clear(): self.requiredTagsListModel.clear() self.paramModStack.currentWidget().loadRow(None) self.relationWgt.clear() self.paramListTblWdg.clearSelection() if selectedRow is None: selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row() if self.main_window.currentAnnotation is None: clear() return if selectedRow < 0 or selectedRow >= len(self.main_window.currentAnnotation.parameters) : clear() return currentParameter = self.main_window.currentAnnotation.parameters[selectedRow] self.newParamBtn.setEnabled(True) self.deleteParamBtn.setEnabled(True) self.paramSaveAnnotBtn.setEnabled(True) if currentParameter.description.type == "pointValue": self.resultTypeCbo.setCurrentIndex(0) self.paramModStack.setCurrentIndex(0) elif currentParameter.description.type == "function": self.resultTypeCbo.setCurrentIndex(1) self.paramModStack.setCurrentIndex(1) elif currentParameter.description.type == "numericalTrace": self.resultTypeCbo.setCurrentIndex(2) self.paramModStack.setCurrentIndex(2) else: raise ValueError("Type of parameter description " + currentParameter.description.type + " is invalid.") self.paramModStack.currentWidget().loadRow(currentParameter) self.relationWgt.loadRow(currentParameter) self.isExpProp.setChecked(currentParameter.isExperimentProperty) ## UPDATING REQUIRED TAGS self.requiredTagsListModel.clear() for tag in currentParameter.requiredTags: self.requiredTagsListModel.addTag(tag.rootId, self.main_window.dicData[tag.rootId], tag.id, tag.name) ## Adding new required tags that may have been specified since the ## creation of this parameter instance. parameterType = getParameterTypeFromID(currentParameter.typeId) reqTags = {reqTag.rootId:reqTag for reqTag in parameterType.requiredTags} for reqTagRootId, reqTag in reqTags.items(): #print(nlxCheck(reqTagRootId), [nlxCheck(tag.rootId) for tag in currentParameter.requiredTags]) if not nlxCheck(reqTagRootId) in [nlxCheck(tag.rootId) for tag in currentParameter.requiredTags]: self.requiredTagsListModel.addTag(reqTag.rootId, self.main_window.dicData[reqTag.rootId], reqTag.id, reqTag.name) self.requiredTagsListModel.refresh() self.newParamsGB.setEnabled(True) def selectedParameterChanged(self, selected, deselected): if len(selected.indexes()) == 0: return if self.additionMode: msgBox = QMessageBox(self) msgBox.setWindowTitle("Cancellation") msgBox.setText("Are you sure you want to cancel the addition of the new parameter being edited? If not, say no and then hit 'Save' to save this new parameter.") msgBox.setStandardButtons(QMessageBox.No | QMessageBox.Yes) msgBox.setDefaultButton(QMessageBox.No) if msgBox.exec_() == QMessageBox.Yes: self.additionMode = False self.loadRow() else: #self.paramListTblWdg.selectRow(-1) self.paramListTblWdg.clearSelection() else: self.loadRow()
class VariantDataDialog(QDialog): def __init__(self, species=(), item=None, tax=True, last=0, index=QModelIndex(), count=0, length=0): """The constructor initializes the class NewVariantDialog.""" super().__init__() self.item = item self.value = None self.speciesRegistry = species.keys() self.species = -1 self.count = 0 self.tax = tax self.index = index # the last added index self.last = last self.count = count self.length = length self._OXYGEN_PATH_22 = os.path.join("resources", "icons", "oxygen", "22") self._LABEL_MIN_WIDTH = 240 self._piece_unit = " St." self._currency_unit = " " + self.locale().currencySymbol(QLocale.CurrencyIsoCode) self._currency_unit_piece = self._currency_unit + "/" + self._piece_unit.strip() self._spinbox_step = 0.05 self._COMBOBOX_ITEM_LIST = (QApplication.translate("VariantDataDialog", "Fence"), # Zaun QApplication.translate("VariantDataDialog", "Tree shelter")) # Wuchshülle # general things self.generalGroup = QGroupBox() self.variantInput = QComboBox() self.variantInput.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) self.variantInput.addItems(self._COMBOBOX_ITEM_LIST) self.variantLabel = QLabel() self.variantLabel.setMinimumWidth(self._LABEL_MIN_WIDTH) self.variantLabel.setBuddy(self.variantInput) self.variantHint = ToolTipLabel() self.descriptionInput = QLineEdit() self.descriptionLabel = QLabel() self.descriptionLabel.setBuddy(self.descriptionInput) self.descriptionHint = ToolTipLabel() # create the layout of the general group box generalLayout = QGridLayout(self.generalGroup) generalLayout.setVerticalSpacing(15) generalLayout.addWidget(self.variantLabel, 0, 0, Qt.AlignTop) generalLayout.addWidget(self.variantInput, 0, 1, Qt.AlignTop) generalLayout.addWidget(self.variantHint, 0, 2, Qt.AlignTop) generalLayout.addWidget(self.descriptionLabel, 1, 0, Qt.AlignTop) generalLayout.addWidget(self.descriptionInput, 1, 1, Qt.AlignTop) generalLayout.addWidget(self.descriptionHint, 1, 2, Qt.AlignTop) # plant specific input fields self.plantGroup = QGroupBox() self.speciesInput = QComboBox() self.speciesInput.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) self.speciesInput.addItems(library.TREESPECIES_DESCRIPTION) self.speciesLabel = QLabel() self.speciesLabel.setMinimumWidth(self._LABEL_MIN_WIDTH) self.speciesLabel.setBuddy(self.speciesInput) self.speciesHint = ToolTipLabel() self.speciesHint.hide() speciesSpacer = QSpacerItem(0, 30, QSizePolicy.Minimum, QSizePolicy.Fixed) self.speciesWarningSymbol = QLabel(pixmap=QPixmap(os.path.join(self._OXYGEN_PATH_22, "dialog-warning.png"))) self.speciesWarningSymbol.hide() self.speciesWarningText = QLabel(wordWrap=True) self.speciesWarningText.hide() warningLayout = QHBoxLayout() warningLayout.setContentsMargins(0, 0, 0, 0) warningLayout.addItem(speciesSpacer) warningLayout.addWidget(self.speciesWarningSymbol, alignment=Qt.AlignTop) warningLayout.addWidget(self.speciesWarningText, alignment=Qt.AlignTop) self.costInput = QDoubleSpinBox() self.costInput.setSuffix(self._currency_unit_piece) self.costInput.setSingleStep(self._spinbox_step) self.costLabel = QLabel() self.costLabel.setBuddy(self.costInput) self.costHint = ToolTipLabel() self.costHint.hide() self.costCalculator = QPushButton() self.preparationInput = QDoubleSpinBox() self.preparationInput.setSuffix(self._currency_unit_piece) self.preparationInput.setSingleStep(self._spinbox_step) self.preparationLabel = QLabel() self.preparationLabel.setBuddy(self.preparationInput) self.preparationHint = ToolTipLabel() self.preparationHint.hide() self.preparationCalculator = QPushButton() self.plantingInput = QDoubleSpinBox() self.plantingInput.setSuffix(self._currency_unit_piece) self.plantingInput.setSingleStep(self._spinbox_step) self.plantingLabel = QLabel() self.plantingLabel.setBuddy(self.plantingInput) self.plantingHint = ToolTipLabel() self.plantingHint.hide() self.plantingCalculator = QPushButton() self.tendingInput = QDoubleSpinBox() self.tendingInput.setSuffix(self._currency_unit_piece) self.tendingInput.setSingleStep(self._spinbox_step) self.tendingLabel = QLabel() self.tendingLabel.setBuddy(self.tendingInput) self.tendingHint = ToolTipLabel() self.tendingHint.hide() self.tendingCalculator = QPushButton() self.mortalityInput = QSpinBox() self.mortalityInput.setSuffix(" %") self.mortalityInput.setMaximum(100) self.mortalityInput.setValue(0) self.mortalityInput.setDisabled(True) self.mortalityLabel = QLabel() self.mortalityLabel.setBuddy(self.mortalityInput) self.mortalityHint = ToolTipLabel() self.mortalityHint.hide() # create the layout of the plant group box plantLayout = QGridLayout(self.plantGroup) plantLayout.addWidget(self.speciesLabel, 0, 0) plantLayout.addWidget(self.speciesInput, 0, 1) plantLayout.addWidget(self.speciesHint, 0, 2) plantLayout.addLayout(warningLayout, 1, 1) plantLayout.addWidget(self.costLabel, 2, 0) plantLayout.addWidget(self.costInput, 2, 1) plantLayout.addWidget(self.costHint, 2, 2) plantLayout.addWidget(self.costCalculator, 2, 3) plantLayout.addWidget(self.preparationLabel, 3, 0) plantLayout.addWidget(self.preparationInput, 3, 1) plantLayout.addWidget(self.preparationHint, 3, 2) plantLayout.addWidget(self.preparationCalculator, 3, 3) plantLayout.addWidget(self.plantingLabel, 4, 0) plantLayout.addWidget(self.plantingInput, 4, 1) plantLayout.addWidget(self.plantingHint, 4, 2) plantLayout.addWidget(self.plantingCalculator, 4, 3) plantLayout.addWidget(self.tendingLabel, 5, 0) plantLayout.addWidget(self.tendingInput, 5, 1) plantLayout.addWidget(self.tendingHint, 5, 2) plantLayout.addWidget(self.tendingCalculator, 5, 3) plantLayout.addWidget(self.mortalityLabel, 6, 0) plantLayout.addWidget(self.mortalityInput, 6, 1) plantLayout.addWidget(self.mortalityHint, 6, 2) # stacked widget for protection group self.fenceWidget = FenceInputWidget(self.tax) self.fenceWidget.length = self.length self.tubeWidget = TubeInputWidget(self.tax) self.protectionGroup = QStackedWidget() self.protectionGroup.addWidget(self.fenceWidget) self.protectionGroup.addWidget(self.tubeWidget) # sales tax hint taxLabel = QLabel("*) " + QApplication.translate("VariantDataDialog", # Bitte beachten Sie, dass Sie den Variantentyp später nicht mehr ändern können. "Keep in mind, that all values must contain uniformly " "the sales tax or not."), wordWrap=True) # create an ok button and abort button within a button box lineFrame = QFrame(frameShadow=QFrame.Sunken, frameShape=QFrame.VLine) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel|QDialogButtonBox.Help, orientation=Qt.Vertical) # create main layout dataLayout = QVBoxLayout() dataLayout.addWidget(self.generalGroup) dataLayout.addWidget(self.plantGroup) dataLayout.addWidget(self.protectionGroup) dataLayout.addWidget(taxLabel) dataLayout.addStretch() layout = QHBoxLayout(self) layout.addLayout(dataLayout) layout.addWidget(lineFrame) layout.addWidget(self.buttonBox) # connect actions self.variantInput.currentIndexChanged.connect(self.variantChanged) self.speciesInput.currentIndexChanged.connect(self.checkSpecies) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.buttonBox.helpRequested.connect(self.help) self.costCalculator.clicked.connect(self.costCalculation) self.preparationCalculator.clicked.connect(self.preparationCalculation) self.plantingCalculator.clicked.connect(self.plantingCalculation) self.tendingCalculator.clicked.connect(self.tendingCalculation) self.tubeWidget.countChanged.connect(self.updateCount) self.fenceWidget.lengthChanged.connect(self.updateLength) # update input fields if self.item: plant = self.item[TreeModel.PlantRole] protection = self.item[TreeModel.ProtectionRole] self.species = plant.species # update input fields self.variantInput.setCurrentIndex(protection.TYPE) self.variantInput.setDisabled(True) self.descriptionInput.setText(self.item[TreeModel.NameRole]) self.speciesInput.setCurrentIndex(plant.species) self.costInput.setValue(plant.cost) self.preparationInput.setValue(plant.preparation) self.plantingInput.setValue(plant.planting) self.tendingInput.setValue(plant.tending) self.mortalityInput.setValue(plant.mortality * 100) # update the protection group self.protectionGroup.currentWidget().setValues(protection) else: self.variantInput.setCurrentIndex(self.last) if self.index.isValid(): self.speciesInput.setCurrentIndex(self.index.data(TreeModel.SpeciesRole)) # check the species and show # a warning, if necessary self.checkSpecies() # translate the graphical user interface self.retranslateUi() def updateCount(self, count): # TODO self.count = count def updateLength(self, length): # TODO self.length = length def retranslateUi(self): # dialog title self.setWindowTitle(QApplication.translate("VariantDataDialog", "Edit protection")) # Schutz bearbeiten # variant selection self.generalGroup.setTitle(QApplication.translate("VariantDataDialog", "Selection of protection")) # Auswahl des Schutzes self.variantLabel.setText(QApplication.translate("VariantDataDialog", "Protection type") + ":") # Schutztyp self.descriptionLabel.setText(QApplication.translate("VariantDataDialog", "Protection description") + ":") # Schutzbeschreibung self.variantHint.setToolTip(QApplication.translate("VariantDataDialog", # Bitte beachten Sie, dass Sie den Variantentyp später nicht mehr ändern können. "Keep in mind, that you can't change the variant type " "at a later time.")) self.descriptionHint.setToolTip(QApplication.translate("VariantDataDialog", # Geben Sie eine Beschreibung der Variante ein, um sie später identifizieren zu können. "Please describe the variant. The description helps you " "identify it.")) # plant input self.plantGroup.setTitle(QApplication.translate("VariantDataDialog", "Cost of plants and planting")) # Kosten Pflanze und Pflanzung self.speciesLabel.setText(QApplication.translate("VariantDataDialog", "Tree species") + ":") # Baumart self.speciesHint.setToolTip("Text") self.speciesWarningText.setText(QApplication.translate("VariantDataDialog", "A fence with the selected species exists already!")) # Es existiert bereits ein Zaun mit der ausgewählten Baumart! self.costLabel.setText(QApplication.translate("VariantDataDialog", "Unit cost") + "*:") # Stückkosten self.costHint.setToolTip("Text") self.costCalculator.setText(QApplication.translate("VariantDataDialog", "Calculation help")) # Umrechnungshilfe self.preparationLabel.setText(QApplication.translate("VariantDataDialog", "Cost of preparation") + "*:") # Kulturvorbereitung self.preparationHint.setToolTip("Text") self.preparationCalculator.setText(QApplication.translate("VariantDataDialog", "Calculation help")) # Umrechnungshilfe self.plantingLabel.setText(QApplication.translate("VariantDataDialog", "Cost of planting") + "*:") # Pflanzungskosten self.plantingHint.setToolTip("Text") self.plantingCalculator.setText(QApplication.translate("VariantDataDialog", "Calculation help")) # Umrechnungshilfe self.tendingLabel.setText(QApplication.translate("VariantDataDialog", "Cost of tending (5 years)") + "*:") # Kultursicherung self.tendingHint.setToolTip("Text") self.tendingCalculator.setText(QApplication.translate("VariantDataDialog", "Calculation help")) # Umrechnungshilfe self.mortalityLabel.setText(QApplication.translate("MainWindow", "Decreased &mortality over fence") + ":") # &Mortalitätsrate self.mortalityHint.setToolTip("Text") def help(self): # create the documentation path with # the current locale settings docFile = os.path.join("doc", "documentation_" + self.locale().name()[:2] + ".pdf") # on every platfrom a different # start operation is needed if sys.platform == "win32": os.startfile(docFile) elif sys.platform == "darwin": subprocess.call(("open", docFile)) elif sys.platform.startswith("linux"): subprocess.call(("xdg-open", docFile)) def variantChanged(self, index): # check for species self.checkSpecies() # update the visible status of the mortality input if index == Tube.TYPE: self.mortalityInput.setValue(10) self.mortalityInput.setEnabled(True) else: self.mortalityInput.setValue(0) self.mortalityInput.setDisabled(True) # set up the protection group self.protectionGroup.setCurrentIndex(index) def accept(self): # check name input field if not self.descriptionInput.text(): warning = QMessageBox(self) warning.setWindowModality(Qt.WindowModal) # check for mac only warning.setIcon(QMessageBox.Warning) warning.setStandardButtons(QMessageBox.Ok) warning.setWindowTitle(QApplication.translate("VariantDataDialog", "Wuchshüllenrechner")) warning.setText("<b>" + QApplication.translate("VariantDataDialog", "The variant description is missing!") + "</b>") warning.setInformativeText(QApplication.translate("VariantDataDialog", "Please describe your new variant.")) warning.exec() else: # return the input values plant = Plant() plant.species = self.speciesInput.currentIndex() plant.cost = self.costInput.value() plant.preparation = self.preparationInput.value() plant.planting = self.plantingInput.value() plant.tending = self.tendingInput.value() plant.mortality = self.mortalityInput.value() / 100 if self.mortalityInput.value() > 0 else 0 protection = self.protectionGroup.currentWidget().values() if not self.item: if protection.TYPE == Fence.TYPE: color = QColor(255, 0, 0).name() else: color = QColor(random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)).name() else: color = self.item[TreeModel.ColorRole] self.value = { TreeModel.NameRole : self.descriptionInput.text(), TreeModel.ColorRole : color, TreeModel.StatusRole : True, TreeModel.PlantRole : plant, TreeModel.ProtectionRole : protection } super().accept() def checkSpecies(self): species = self.speciesInput.currentIndex() # only for fence variants if self.variantInput.currentIndex() == Fence.TYPE: if not species == self.species and species in self.speciesRegistry: # first disable the OK button self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) self.speciesWarningSymbol.show() self.speciesWarningText.show() else: self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True) self.speciesWarningSymbol.hide() self.speciesWarningText.hide() else: self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True) self.speciesWarningSymbol.hide() self.speciesWarningText.hide() def costCalculation(self): value = self.unitCostCalculator() if value > 0: self.costInput.setValue(value) def preparationCalculation(self): value = self.unitCostCalculator() if value > 0: self.preparationInput.setValue(value) def plantingCalculation(self): value = self.unitCostCalculator() if value > 0: self.plantingInput.setValue(value) def tendingCalculation(self): value = self.unitCostCalculator() if value > 0: self.tendingInput.setValue(value) def unitCostCalculator(self): dialog = UnitCostDialog(self.count) dialog.exec() # TODO self.count = dialog.count self.tubeWidget.count = self.count return dialog.value
class PreferencesDialog(QDialog): """Creates a dialog that shows the user all of the user configurable options. A list on the left shows all of the available pages, with the page's contents shown on the right. """ def __init__(self, parent=None): """Initialize the preferences dialog with a list box and a content layout.""" super(PreferencesDialog, self).__init__(parent) self.setWindowTitle('Preferences') settings_icon = utilities.resource_filename('mosaic.images', 'md_settings.png') self.setWindowIcon(QIcon(settings_icon)) self.resize(600, 450) self.contents = QListWidget() self.contents.setFixedWidth(175) self.pages = QStackedWidget() self.button_box = QDialogButtonBox(QDialogButtonBox.Ok) self.dialog_media_library = MediaLibrary() self.dialog_playback = Playback() self.dialog_view_options = ViewOptions() self.pages.addWidget(self.dialog_media_library) self.pages.addWidget(self.dialog_playback) self.pages.addWidget(self.dialog_view_options) self.list_items() stack_layout = QVBoxLayout() stack_layout.addWidget(self.pages) stack_layout.addWidget(self.button_box) layout = QHBoxLayout() layout.addWidget(self.contents) layout.addLayout(stack_layout) self.setLayout(layout) self.contents.currentItemChanged.connect(self.change_page) self.button_box.accepted.connect(self.accept) def list_items(self): """List all of the pages available to the user.""" media_library_options = QListWidgetItem(self.contents) media_library_options.setText('Media Library') media_library_options.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.contents.setCurrentRow(0) playback_options = QListWidgetItem(self.contents) playback_options.setText('Playback') playback_options.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) view_options = QListWidgetItem(self.contents) view_options.setText('View Options') view_options.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) def change_page(self, current, previous): """Change the page according to the clicked list item.""" if not current: current = previous self.pages.setCurrentIndex(self.contents.row(current))
def setCurrentIndex(self, index): self.fader_widget = ui_tools.FaderWidget(self.currentWidget(), self.widget(index)) QStackedWidget.setCurrentIndex(self, index)
class FlowDialog(QWidget): """ Class for controlling the order of screens in the experiment. """ def __init__(self, parent=None): super(FlowDialog, self).__init__(parent) self._n_steps = 1 # number of performed steps self.pages_widget = QStackedWidget() # create widgets self.experiment_setup = ExperimentSetup() self.instructions = InstructionsScreen("./instructions/he-informed-consent.txt") self.new_user_form = NewUserForm() self.data_widget = DataWidget() # add widgets to pages_widget self.pages_widget.addWidget(self.experiment_setup) self.pages_widget.addWidget(self.instructions) self.pages_widget.addWidget(self.new_user_form) self.pages_widget.addWidget(self.data_widget) # next button self.next_button = QPushButton("&Next") self.next_button_layout = QHBoxLayout() self.next_button_layout.addStretch(1) self.next_button_layout.addWidget(self.next_button) self.next_button.pressed.connect(self.nextPressed) main_layout = QGridLayout() # set screen shoulders main_layout.setRowMinimumHeight(0, 80) main_layout.setRowMinimumHeight(3, 80) main_layout.setColumnMinimumWidth(0, 80) main_layout.setColumnMinimumWidth(2, 80) main_layout.addWidget(self.pages_widget, 1, 1) main_layout.addLayout(self.next_button_layout, 2, 1) self.setLayout(main_layout) self.pages_widget.setCurrentIndex(0) def nextPressed(self): """ control the order and number of repetitions of the experiment """ self.data_widget.count_down_timer.restart_timer() # restart timer # if on setup screen if self.pages_widget.currentIndex() == 0: # get condition index number condition_index = self.experiment_setup.conditions_combo.currentIndex() # DEBUGGING: debug_condition = config.CONDITIONS['a'][condition_index] print(debug_condition) self.raise_index() # welcome screen elif self.pages_widget.currentIndex() == 1: self.raise_index() # if on new_user screen elif self.pages_widget.currentIndex() == 2: self.new_user_form.save_results() self.raise_index() # if on data screen elif self.pages_widget.currentIndex() == 3: if self._n_steps < config.NUM_STEPS: self.data_widget.add_log_row() self._n_steps += 1 print("Step number {}".format(self._n_steps)) # DEBUGGING else: self.raise_index() elif self.pages_widget.currentIndex() == 4: print("That's it") # DEBUGGING else: # If reached wrong index raise RuntimeError("No such index") def raise_index(self): current = self.pages_widget.currentIndex() self.pages_widget.setCurrentIndex(current + 1)
class _ToolsDock(QWidget): __WIDGETS = {} __created = False __index = 0 # Signals executeFile = pyqtSignal() executeProject = pyqtSignal() executeSelection = pyqtSignal() stopApplication = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) # Register signals connections layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.__buttons = [] self.__action_number = 1 self.__buttons_visibility = {} self.__current_widget = None self.__last_index = -1 self._stack_widgets = QStackedWidget() layout.addWidget(self._stack_widgets) # Buttons Widget self.buttons_widget = QWidget() self.buttons_widget.setObjectName("tools_dock") self.buttons_widget.setFixedHeight(26) self.buttons_widget.setLayout(QHBoxLayout()) self.buttons_widget.layout().setContentsMargins(2, 2, 5, 2) self.buttons_widget.layout().setSpacing(10) IDE.register_service("tools_dock", self) _ToolsDock.__created = True @classmethod def register_widget(cls, display_name, obj): """Register a widget providing the service name and the instance""" cls.__WIDGETS[cls.__index] = (obj, display_name) cls.__index += 1 def install(self): self._load_ui() ninjaide = IDE.get_service("ide") ninjaide.place_me_on("tools_dock", self, "central") ui_tools.install_shortcuts(self, actions.ACTIONS, ninjaide) ninjaide.goingDown.connect(self._save_settings) ninja_settings = IDE.ninja_settings() index = int(ninja_settings.value("tools_dock/widgetVisible", -1)) if index == -1: self.hide() else: self._show(index) def _load_ui(self): ninjaide = IDE.get_service("ide") shortcut_number = 1 for index, (obj, name) in _ToolsDock.__WIDGETS.items(): button = ToolButton(name, index + 1) button.setCheckable(True) button.clicked.connect(self.on_button_triggered) self.__buttons.append(button) self.buttons_widget.layout().addWidget(button) self.add_widget(name, obj) self.__buttons_visibility[button] = True # Shortcut action ksequence = self._get_shortcut(shortcut_number) short = QShortcut(ksequence, ninjaide) button.setToolTip( ui_tools.tooltip_with_shortcut(button._text, ksequence)) short.activated.connect(self._shortcut_triggered) shortcut_number += 1 self.buttons_widget.layout().addItem( QSpacerItem(0, 0, QSizePolicy.Expanding)) # Python Selector btn_selector = ui_tools.FancyButton("Loading...") btn_selector.setIcon(ui_tools.get_icon("python")) btn_selector.setCheckable(True) btn_selector.setEnabled(False) self.buttons_widget.layout().addWidget(btn_selector) # QML Interface self._python_selector = python_selector.PythonSelector(btn_selector) interpreter_srv = IDE.get_service("interpreter") interpreter_srv.foundInterpreters.connect( self._python_selector.add_model) btn_selector.toggled[bool].connect( lambda v: self._python_selector.setVisible(v)) # Popup for show/hide tools widget button_toggle_widgets = ToggleButton() self.buttons_widget.layout().addWidget(button_toggle_widgets) button_toggle_widgets.clicked.connect(self._show_menu) def _get_shortcut(self, short_number: int): """Return shortcut as ALT + number""" if short_number < 1 or short_number > 9: return QKeySequence() modifier = Qt.ALT if not settings.IS_MAC_OS else Qt.CTRL return QKeySequence(modifier + (Qt.Key_0 + short_number)) def _shortcut_triggered(self): short = self.sender() widget_index = int(short.key().toString()[-1]) - 1 widget = self.widget(widget_index) if widget.isVisible(): self._hide() else: self._show(widget_index) def _show_menu(self): menu = QMenu() for n, (obj, display_name) in _ToolsDock.__WIDGETS.items(): action = menu.addAction(display_name) action.setCheckable(True) action.setData(n) button = self.__buttons[n] visible = self.__buttons_visibility.get(button) action.setChecked(visible) result = menu.exec_(QCursor.pos()) if not result: return index = result.data() btn = self.__buttons[index] visible = self.__buttons_visibility.get(btn, False) self.__buttons_visibility[btn] = not visible if visible: btn.hide() else: btn.show() def get_widget_index_by_instance(self, instance): index = -1 for i, (obj, _) in self.__WIDGETS.items(): if instance == obj: index = i break return index def execute_file(self): run_widget = IDE.get_service("run_widget") index = self.get_widget_index_by_instance(run_widget) self._show(index) self.executeFile.emit() def execute_project(self): run_widget = IDE.get_service("run_widget") index = self.get_widget_index_by_instance(run_widget) self._show(index) self.executeProject.emit() def execute_selection(self): run_widget = IDE.get_service("run_widget") index = self.get_widget_index_by_instance(run_widget) self._show(index) self.executeSelection.emit() def kill_application(self): self.stopApplication.emit() def add_widget(self, display_name, obj): self._stack_widgets.addWidget(obj) func = getattr(obj, "install_widget", None) if isinstance(func, collections.Callable): func() def on_button_triggered(self): # Get button index button = self.sender() index = self.__buttons.index(button) if index == self.current_index() and self._is_current_visible(): self._hide() else: self._show(index) def widget(self, index): return self.__WIDGETS[index][0] def _hide(self): self.__current_widget.setVisible(False) index = self.current_index() self.__buttons[index].setChecked(False) self.widget(index).setVisible(False) self.hide() def hide_widget(self, obj): index = self.get_widget_index_by_instance(obj) self.set_current_index(index) self._hide() def _show(self, index): widget = self.widget(index) self.__current_widget = widget widget.setVisible(True) widget.setFocus() self.set_current_index(index) self.show() def set_current_index(self, index): if self.__last_index != -1: self.__buttons[self.__last_index].setChecked(False) self.__buttons[index].setChecked(True) if index != -1: self._stack_widgets.setCurrentIndex(index) widget = self.widget(index) widget.setVisible(True) self.__last_index = index def current_index(self): return self._stack_widgets.currentIndex() def _is_current_visible(self): return self.__current_widget and self.__current_widget.isVisible() def _save_settings(self): ninja_settings = IDE.ninja_settings() visible_widget = self.current_index() if not self.isVisible(): visible_widget = -1 ninja_settings.setValue("tools_dock/widgetVisible", visible_widget)
class GstMediaSettings(SettingsSection): Name = 'Media Settings' def __init__(self, size, cue=None, parent=None): super().__init__(size, cue=cue, parent=parent) self._pipe = '' self._conf = {} self._check = False self.glayout = QGridLayout(self) self.listWidget = QListWidget(self) self.glayout.addWidget(self.listWidget, 0, 0) self.pipeButton = QPushButton('Change Pipe', self) self.glayout.addWidget(self.pipeButton, 1, 0) self.elements = QStackedWidget(self) self.glayout.addWidget(self.elements, 0, 1, 2, 1) self.glayout.setColumnStretch(0, 2) self.glayout.setColumnStretch(1, 5) self.listWidget.currentItemChanged.connect(self.__change_page) self.pipeButton.clicked.connect(self.__edit_pipe) def set_configuration(self, conf): # Get the media section of the cue configuration if conf is not None: conf = conf.get('media', {}) # Activate the layout, so we can get the right widgets size self.glayout.activate() # Create a local copy of the configuration self._conf = deepcopy(conf) # Create the widgets sections = sections_by_element_name() for element in conf.get('pipe', '').split('!'): widget = sections.get(element) if widget is not None: widget = widget(self.elements.size(), element, self) widget.set_configuration(self._conf['elements']) self.elements.addWidget(widget) item = QListWidgetItem(widget.NAME) self.listWidget.addItem(item) self.listWidget.setCurrentRow(0) def get_configuration(self): conf = {'elements': {}} for el in self.elements.children(): if isinstance(el, SettingsSection): conf['elements'].update(el.get_configuration()) # If in check mode the pipeline is not returned if not self._check: conf['pipe'] = self._conf['pipe'] return {'media': conf} def enable_check(self, enable): self._check = enable for element in self.elements.children(): if isinstance(element, SettingsSection): element.enable_check(enable) def __change_page(self, current, previous): if not current: current = previous self.elements.setCurrentIndex(self.listWidget.row(current)) def __edit_pipe(self): # Backup the settings self._conf.update(self.get_configuration()['media']) # Show the dialog dialog = GstPipeEdit(self._conf.get('pipe', ''), parent=self) if dialog.exec_() == dialog.Accepted: # Reset the view for _ in range(self.elements.count()): self.elements.removeWidget(self.elements.widget(0)) self.listWidget.clear() # Reload with the new pipeline self._conf['pipe'] = dialog.get_pipe() self.set_configuration({'media': self._conf}) self.enable_check(self._check)
class SettingsWidget(QWidget): settings_changed = pyqtSignal() def __init__(self, parent: QWidget): super(SettingsWidget, self).__init__(parent, Qt.Window) # config parser self._cfg = configparser.ConfigParser() # layouts self._layout_main = QVBoxLayout() self._layout_stacks = QHBoxLayout() self._layout_okcancel = QHBoxLayout() # sections list self._sections_list = QListWidget(self) self._sections_list.setSelectionMode(QAbstractItemView.SingleSelection) self._sections_list.setSelectionBehavior(QAbstractItemView.SelectItems) self._sections_list.setIconSize(QSize(32, 32)) self._sections_list.setViewMode(QListView.IconMode) self._sections_list.setMaximumWidth(80) self._sections_list.setGridSize(QSize(64, 64)) self._sections_list.setFlow(QListView.TopToBottom) self._sections_list.setMovement(QListView.Static) # items cannot be moved by user # network item lwi = QListWidgetItem() lwi.setText(self.tr("Network")) lwi.setTextAlignment(Qt.AlignCenter) lwi.setIcon(QIcon(":/i/settings_network_32.png")) lwi.setData(Qt.UserRole, QVariant(0)) self._sections_list.addItem(lwi) lwi.setSelected(True) # misc item lwi = QListWidgetItem() lwi.setText(self.tr("Other")) lwi.setTextAlignment(Qt.AlignCenter) lwi.setIcon(QIcon(":/i/settings_32.png")) lwi.setData(Qt.UserRole, QVariant(1)) self._sections_list.addItem(lwi) # connections self._sections_list.currentItemChanged.connect(self.on_section_current_item_changed) self._layout_stacks.addWidget(self._sections_list) # stacked widget self._stack = QStackedWidget(self) self._w_net = Settings_Net(self._stack) self._w_misc = Settings_Misc(self._stack) self._stack.addWidget(self._w_net) self._stack.addWidget(self._w_misc) self._stack.setCurrentIndex(0) self._layout_stacks.addWidget(self._stack) # ok cancel buttons self._btn_ok = QPushButton(self) self._btn_ok.setText(self.tr("Save")) self._btn_ok.setIcon(QIcon(":/i/save.png")) self._btn_cancel = QPushButton(self) self._btn_cancel.setText(self.tr("Cancel")) self._btn_cancel.setIcon(QIcon(":/i/cancel.png")) self._layout_okcancel.addStretch() self._layout_okcancel.addWidget(self._btn_ok) self._layout_okcancel.addWidget(self._btn_cancel) self._btn_ok.clicked.connect(self.on_ok) self._btn_cancel.clicked.connect(self.on_cancel) # final self._layout_main.addLayout(self._layout_stacks) self._layout_main.addLayout(self._layout_okcancel) self.setLayout(self._layout_main) self.setWindowTitle(self.tr("Settings")) self.setWindowIcon(QIcon(":/i/settings_32.png")) # self.load_settings() def load_settings(self): self._cfg.read("config/net.ini", encoding="utf-8") # init config of all child widgets self._w_net.load_from_config(self._cfg) self._w_misc.load_from_config(self._cfg) def save_settings(self): # read config from all child widgets self._w_net.save_to_config(self._cfg) self._w_misc.save_to_config(self._cfg) # save to file try: with open("config/net.ini", "wt", encoding="utf-8") as fp: self._cfg.write(fp) fp.write("# proxy Tor example (local Tor browser):\n") fp.write("# proxy = socks5://127.0.0.1:9050\n") fp.write("# proxy I2P example:\n") fp.write("# proxy = http://127.0.0.1:4444\n") except IOError as e: logger.error(str(e)) self.settings_changed.emit() @pyqtSlot() def on_ok(self): self.save_settings() self.hide() def on_cancel(self): self.hide() @pyqtSlot(QListWidgetItem, QListWidgetItem) def on_section_current_item_changed(self, cur: QListWidgetItem, prev: QListWidgetItem): data = int(cur.data(Qt.UserRole)) self._stack.setCurrentIndex(data)
class XTabWidget(QFrame): addClicked = pyqtSignal() currentChanged = pyqtSignal(int) tabCloseRequested = pyqtSignal(int) def __init__(self, QWidget_parent=None): super(XTabWidget, self).__init__(QWidget_parent) # setup self frame self.setFrameShadow(QFrame.Raised) # self.setFrameShape(QFrame.StyledPanel) self.setFrameShape(QFrame.NoFrame) # layouts self._layout = QVBoxLayout() self._layout.setContentsMargins(0, 0, 0, 0) self._layout.setSpacing(2) self._layout_top = QHBoxLayout() self._layout_top.setContentsMargins(0, 0, 0, 0) # stacked widget self._stack = QStackedWidget(self) # tab bar self._tabbar = QTabBar(self) self._tabbar.setTabsClosable(True) self._tabbar.setMovable(False) self._tabbar.setExpanding(False) self._tabbar.setShape(QTabBar.RoundedNorth) self._tabbar.currentChanged.connect(self.on_tab_current_changed) self._tabbar.tabCloseRequested.connect(self.on_tab_close_requested) # button "add" self._btn_add = QPushButton('+', self) self._btn_add.setMaximumSize(QSize(22, 22)) self._btn_add.clicked.connect(self.on_btn_add_clicked) # complete layout self._layout_top.addWidget(self._btn_add, 0, Qt.AlignVCenter) self._layout_top.addWidget(self._tabbar, 1, Qt.AlignVCenter) self._layout.addLayout(self._layout_top) self._layout.addWidget(self._stack) self.setLayout(self._layout) def addTab(self, widget: QWidget, title: str, closeable: bool = True) -> int: # add tab to tabbar tab_index = self._tabbar.addTab(title) if not closeable: self._tabbar.setTabButton(tab_index, QTabBar.RightSide, None) self._tabbar.setTabButton(tab_index, QTabBar.LeftSide, None) # it MAY be on the left too!! # add widget into stackedwidget self._stack.addWidget(widget) return tab_index def removeTab(self, index: int): # remove from tab bar self._tabbar.removeTab(index) # remove from stacked widget widget = self._stack.widget(index) if widget is not None: # Removes widget from the QStackedWidget. i.e., widget # is not deleted but simply removed from the stacked layout, # causing it to be hidden. self._stack.removeWidget(widget) # and now we probably want to delete it to avoid memory leak widget.close() widget.deleteLater() def tabBar(self) -> QTabBar: return self._tabbar def enableButtonAdd(self, enableState: bool = True): self._btn_add.setEnabled(enableState) def setCurrentIndex(self, index: int): self._stack.setCurrentIndex(index) self._tabbar.setCurrentIndex(index) def count(self) -> int: return self._tabbar.count() def tabWidget(self, index: int): """ Return page widget, inserted at index index :param index: :return: QWidget inserted at specified index, or None """ widget = self._stack.widget(index) return widget @pyqtSlot() def on_btn_add_clicked(self): self.addClicked.emit() @pyqtSlot(int) def on_tab_current_changed(self, idx: int): self._stack.setCurrentIndex(idx) self.currentChanged.emit(idx) @pyqtSlot(int) def on_tab_close_requested(self, idx: int): self.tabCloseRequested.emit(idx)
class AddDialog(QDialog): worker = None selected_show = None results = [] def __init__(self, parent, worker, current_status, default=None): QDialog.__init__(self, parent) self.resize(950, 700) self.setWindowTitle('Search/Add from Remote') self.worker = worker self.current_status = current_status self.default = default if default: self.setWindowTitle('Search/Add from Remote for new show: %s' % default) # Get available search methods and default to keyword search if not reported by the API search_methods = self.worker.engine.mediainfo.get('search_methods', [utils.SEARCH_METHOD_KW]) layout = QVBoxLayout() # Create top layout top_layout = QHBoxLayout() if utils.SEARCH_METHOD_KW in search_methods: self.search_rad = QRadioButton('By keyword:') self.search_rad.setChecked(True) self.search_txt = QLineEdit() self.search_txt.returnPressed.connect(self.s_search) if default: self.search_txt.setText(default) self.search_btn = QPushButton('Search') self.search_btn.clicked.connect(self.s_search) top_layout.addWidget(self.search_rad) top_layout.addWidget(self.search_txt) else: top_layout.setAlignment(QtCore.Qt.AlignRight) top_layout.addWidget(self.search_btn) # Create filter line filters_layout = QHBoxLayout() if utils.SEARCH_METHOD_SEASON in search_methods: self.season_rad = QRadioButton('By season:') self.season_combo = QComboBox() self.season_combo.addItem('Winter', utils.SEASON_WINTER) self.season_combo.addItem('Spring', utils.SEASON_SPRING) self.season_combo.addItem('Summer', utils.SEASON_SUMMER) self.season_combo.addItem('Fall', utils.SEASON_FALL) self.season_year = QSpinBox() today = date.today() current_season = (today.month - 1) / 3 self.season_year.setRange(1900, today.year) self.season_year.setValue(today.year) self.season_combo.setCurrentIndex(current_season) filters_layout.addWidget(self.season_rad) filters_layout.addWidget(self.season_combo) filters_layout.addWidget(self.season_year) filters_layout.setAlignment(QtCore.Qt.AlignLeft) filters_layout.addWidget(QSplitter()) else: filters_layout.setAlignment(QtCore.Qt.AlignRight) view_combo = QComboBox() view_combo.addItem('Table view') view_combo.addItem('Card view') view_combo.currentIndexChanged.connect(self.s_change_view) filters_layout.addWidget(view_combo) # Create central content self.contents = QStackedWidget() # Set up views tableview = AddTableDetailsView(None, self.worker) tableview.changed.connect(self.s_selected) self.contents.addWidget(tableview) cardview = AddCardView(api_info=self.worker.engine.api_info) cardview.changed.connect(self.s_selected) cardview.activated.connect(self.s_show_details) self.contents.addWidget(cardview) # Use for testing #self.set_results([{'id': 1, 'title': 'Hola', 'image': 'https://omaera.org/icon.png'}]) bottom_buttons = QDialogButtonBox() bottom_buttons.addButton("Cancel", QDialogButtonBox.RejectRole) self.add_btn = bottom_buttons.addButton("Add", QDialogButtonBox.AcceptRole) self.add_btn.setEnabled(False) bottom_buttons.accepted.connect(self.s_add) bottom_buttons.rejected.connect(self.close) # Finish layout layout.addLayout(top_layout) layout.addLayout(filters_layout) layout.addWidget(self.contents) layout.addWidget(bottom_buttons) self.setLayout(layout) if utils.SEARCH_METHOD_SEASON in search_methods: self.search_txt.setFocus() def worker_call(self, function, ret_function, *args, **kwargs): # Run worker in a thread self.worker.set_function(function, ret_function, *args, **kwargs) self.worker.start() def _enable_widgets(self, enable): self.search_btn.setEnabled(enable) self.contents.currentWidget().setEnabled(enable) def set_results(self, results): self.results = results self.contents.currentWidget().setResults(self.results) # Slots def s_show_details(self): detailswindow = DetailsDialog(self, self.worker, self.selected_show) detailswindow.setModal(True) detailswindow.show() def s_change_view(self, item): self.contents.currentWidget().getModel().setResults(None) self.contents.setCurrentIndex(item) self.contents.currentWidget().getModel().setResults(self.results) def s_search(self): if self.search_rad.isChecked(): criteria = self.search_txt.text().strip() if not criteria: return method = utils.SEARCH_METHOD_KW elif self.season_rad.isChecked(): criteria = (self.season_combo.itemData(self.season_combo.currentIndex()), self.season_year.value()) method = utils.SEARCH_METHOD_SEASON self.contents.currentWidget().clearSelection() self.selected_show = None self._enable_widgets(False) self.add_btn.setEnabled(False) self.worker_call('search', self.r_searched, criteria, method) def s_selected(self, show): self.selected_show = show self.add_btn.setEnabled(True) def s_add(self): if self.selected_show: self.worker_call('add_show', self.r_added, self.selected_show, self.current_status) # Worker responses def r_searched(self, result): self._enable_widgets(True) if result['success']: self.set_results(result['result']) """ if self.table.currentRow() is 0: # Row number hasn't changed but the data probably has! self.s_show_selected(self.table.item(0, 0)) self.table.setCurrentItem(self.table.item(0, 0))""" else: self.set_results(None) def r_added(self, result): if result['success']: if self.default: self.accept()
class PyMultiPageWidget(QWidget): currentIndexChanged = pyqtSignal(int) pageTitleChanged = pyqtSignal(str) def __init__(self, parent=None): super(PyMultiPageWidget, self).__init__(parent) self.comboBox = QComboBox() # MAGIC # It is important that the combo box has an object name beginning # with '__qt__passive_', otherwise, it is inactive in the form editor # of the designer and you can't change the current page via the # combo box. # MAGIC self.comboBox.setObjectName('__qt__passive_comboBox') self.stackWidget = QStackedWidget() self.comboBox.activated.connect(self.setCurrentIndex) self.layout = QVBoxLayout() self.layout.addWidget(self.comboBox) self.layout.addWidget(self.stackWidget) self.setLayout(self.layout) def sizeHint(self): return QSize(200, 150) def count(self): return self.stackWidget.count() def widget(self, index): return self.stackWidget.widget(index) @pyqtSlot(QWidget) def addPage(self, page): self.insertPage(self.count(), page) @pyqtSlot(int, QWidget) def insertPage(self, index, page): page.setParent(self.stackWidget) self.stackWidget.insertWidget(index, page) title = page.windowTitle() if title == "": title = "Page %d" % (self.comboBox.count() + 1) page.setWindowTitle(title) self.comboBox.insertItem(index, title) @pyqtSlot(int) def removePage(self, index): widget = self.stackWidget.widget(index) self.stackWidget.removeWidget(widget) self.comboBox.removeItem(index) def getPageTitle(self): return self.stackWidget.currentWidget().windowTitle() @pyqtSlot(str) def setPageTitle(self, newTitle): self.comboBox.setItemText(self.getCurrentIndex(), newTitle) self.stackWidget.currentWidget().setWindowTitle(newTitle) self.pageTitleChanged.emit(newTitle) def getCurrentIndex(self): return self.stackWidget.currentIndex() @pyqtSlot(int) def setCurrentIndex(self, index): if index != self.getCurrentIndex(): self.stackWidget.setCurrentIndex(index) self.comboBox.setCurrentIndex(index) self.currentIndexChanged.emit(index) pageTitle = pyqtProperty(str, fget=getPageTitle, fset=setPageTitle, stored=False) currentIndex = pyqtProperty(int, fget=getCurrentIndex, fset=setCurrentIndex)
class SettingsDialog(QDialog): def __init__(self, settings_object, parent=None): super().__init__(parent) # The settings object should not be changed directly. Use enqueue_change() to set values and call # commit_changes() to write them to file when the user clicks either the "Ok" or "Apply" button. self.settings_object = settings_object self.pending_changes = {} # A list of different settings groups, categorized by the application they apply to. self.category_list = QListWidget() self.category_list.setSpacing(3) self.category_list.setMaximumWidth(100) handlebar_category = QListWidgetItem(self.category_list) handlebar_category.setText('General') handbrake_category = QListWidgetItem(self.category_list) handbrake_category.setText('Encoder') handbrake_category = QListWidgetItem(self.category_list) handbrake_category.setText('Output') self.category_pages = QStackedWidget() self.category_pages.addWidget(GeneralSettingsPage(self, settings_object)) self.category_pages.addWidget(EncoderSettingsPage(self, settings_object)) self.category_pages.addWidget(OutputSettingsPage(self, settings_object)) self.category_list.setCurrentRow(0) self.category_list.currentItemChanged.connect(self.change_category) category_layout = QHBoxLayout() category_layout.addWidget(self.category_list) category_layout.addWidget(self.category_pages) ok_button = QPushButton('Ok') cancel_button = QPushButton('Cancel') self.apply_button = QPushButton('Apply') self.apply_button.setEnabled(False) ok_button.clicked.connect(self.commit_changes_and_close) cancel_button.clicked.connect(self.close) self.apply_button.clicked.connect(self.commit_changes) button_bar_layout = QHBoxLayout() button_bar_layout.addStretch(1) button_bar_layout.addWidget(ok_button) button_bar_layout.addWidget(cancel_button) button_bar_layout.addWidget(self.apply_button) main_layout = QVBoxLayout() main_layout.addLayout(category_layout) main_layout.addLayout(button_bar_layout) self.setLayout(main_layout) self.setWindowTitle('Configure Settings') self.resize(600, 300) def change_category(self, current, previous): if not current: current = previous self.category_pages.setCurrentIndex(self.category_list.row(current)) def commit_changes_and_close(self): """Convenience function that calls commit_changes and then closes the dialog. Used by the "OK" button""" self.commit_changes() self.close() def commit_changes(self): if len(self.pending_changes) > 0: print('Settings committed to file.') self.settings_object.read_dict(self.pending_changes) self.settings_object.save() self.pending_changes = {} self.apply_button.setEnabled(False) # There are no longer any pending changes. def enqueue_change(self, category, name, value): print('Setting "{}" changed to {}.'.format(name, value)) if category in self.pending_changes.keys(): # If a nested dict already exists for this category: self.pending_changes[category][name] = value # Add this pair to the nested dict. else: self.pending_changes[category] = {name: value} # Create the nested dict with this pair. self.apply_button.setEnabled(True) # There are now pending changes that can be applied.
class Window(QMainWindow): BOARD_HEIGHT = 621 BOARD_WIDTH = 1000 def __init__(self): super(Window, self).__init__() self.widgMain = MainForm() self.widgTeam = TeamSelectionUI() self.widgBoard = Board() print("AFTER BOARD CREATED") self.server = Server() # Set up signal to allow state change self.server.updateActiveWidget.connect(self.updateActiveWidget) # Set up signal to allow data to be sent to MAIN_SCREEN self.server.updateConnectedUsersSig.connect(self.widgMain.updateConnectedUsers) self.server.appendConnectedHistorySig.connect(self.widgMain.appendConnectedHistory) self.server.updateConnectedUsersSig.connect(self.widgMain.updateConnectedHistory) self.server.updateGameInfoSig.connect(self.widgMain.updateGameInfo) """ Set up signal to allow data to be received by the TEAM_SCREEN (self.widgTeam), data sent is used to sort clients into teams of two """ self.server.setupTeamSig.connect(self.widgTeam.setupTeam) # Set up signal to allow data to be sent to GAME_SCREEN self.server.updateGameSig.connect(self.widgBoard.updateGame) # Set up signal to allow updated teams to be sent to server self.widgTeam.updateTeamsSig.connect(self.server.updateTeams) self.stack = QStackedWidget(self) self.stack.resize(self.BOARD_WIDTH, self.BOARD_HEIGHT) self.stack.addWidget(self.widgMain) self.stack.addWidget(self.widgTeam) self.stack.addWidget(self.widgBoard) self.resize(self.BOARD_WIDTH, self.BOARD_HEIGHT) layout = QGridLayout() layout.addWidget(self.stack) self.setLayout(layout) self.setWindowTitle("Blobbageddon") self.stack.setCurrentIndex(0) self.server.start() self.show() def updateActiveWidget(self, adrs): if (self.server.state.currState == State.GAME_SCREEN): self.stack.setCurrentIndex(2) print(len(adrs)) self.widgBoard.start(adrs) elif self.server.state.currState == State.TEAM_SCREEN: self.widgTeam.setupUi(adrs) self.stack.setCurrentIndex(1) elif (self.server.state.currState == State.MAIN_SCREEN): self.stack.setCurrentIndex(0)
class Settings(QDialog): """Window showing the Settings/settings. Parameters ---------- parent : instance of QMainWindow the main window """ def __init__(self, parent): super().__init__(None, Qt.WindowSystemMenuHint | Qt.WindowTitleHint) self.parent = parent self.config = ConfigUtils(self.parent.update) self.setWindowTitle('Settings') self.create_settings() def create_settings(self): """Create the widget, organized in two parts. Notes ----- When you add widgets in config, remember to update show_settings too """ bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Apply | QDialogButtonBox.Cancel) self.idx_ok = bbox.button(QDialogButtonBox.Ok) self.idx_apply = bbox.button(QDialogButtonBox.Apply) self.idx_cancel = bbox.button(QDialogButtonBox.Cancel) bbox.clicked.connect(self.button_clicked) page_list = QListWidget() page_list.setSpacing(1) page_list.currentRowChanged.connect(self.change_widget) pages = ['General', 'Overview', 'Signals', 'Channels', 'Spectrum', 'Notes', 'Video'] for one_page in pages: page_list.addItem(one_page) self.stacked = QStackedWidget() self.stacked.addWidget(self.config) self.stacked.addWidget(self.parent.overview.config) self.stacked.addWidget(self.parent.traces.config) self.stacked.addWidget(self.parent.channels.config) self.stacked.addWidget(self.parent.spectrum.config) self.stacked.addWidget(self.parent.notes.config) self.stacked.addWidget(self.parent.video.config) hsplitter = QSplitter() hsplitter.addWidget(page_list) hsplitter.addWidget(self.stacked) btnlayout = QHBoxLayout() btnlayout.addStretch(1) btnlayout.addWidget(bbox) vlayout = QVBoxLayout() vlayout.addWidget(hsplitter) vlayout.addLayout(btnlayout) self.setLayout(vlayout) def change_widget(self, new_row): """Change the widget on the right side. Parameters ---------- new_row : int index of the widgets """ self.stacked.setCurrentIndex(new_row) def button_clicked(self, button): """Action when button was clicked. Parameters ---------- button : instance of QPushButton which button was pressed """ if button in (self.idx_ok, self.idx_apply): # loop over widgets, to see if they were modified for i_config in range(self.stacked.count()): one_config = self.stacked.widget(i_config) if one_config.modified: lg.debug('Settings for ' + one_config.widget + ' were modified') one_config.get_values() if self.parent.info.dataset is not None: one_config.update_widget() one_config.modified = False if button == self.idx_ok: self.accept() if button == self.idx_cancel: self.reject()
class SettingsDialog(QDialog): worker = None config = None configfile = None saved = QtCore.pyqtSignal() def __init__(self, parent, worker, config, configfile): QDialog.__init__(self, parent) self.worker = worker self.config = config self.configfile = configfile self.setStyleSheet("QGroupBox { font-weight: bold; } ") self.setWindowTitle('Settings') layout = QGridLayout() # Categories self.category_list = QListWidget() category_media = QListWidgetItem(getIcon('media-playback-start'), 'Media', self.category_list) category_sync = QListWidgetItem(getIcon('view-refresh'), 'Sync', self.category_list) category_ui = QListWidgetItem(getIcon('window-new'), 'User Interface', self.category_list) category_theme = QListWidgetItem(getIcon('applications-graphics'), 'Theme', self.category_list) self.category_list.setSelectionMode(QAbstractItemView.SingleSelection) self.category_list.setCurrentRow(0) self.category_list.setMaximumWidth(self.category_list.sizeHintForColumn(0) + 15) self.category_list.setFocus() self.category_list.currentItemChanged.connect(self.s_switch_page) # Media tab page_media = QWidget() page_media_layout = QVBoxLayout() page_media_layout.setAlignment(QtCore.Qt.AlignTop) # Group: Media settings g_media = QGroupBox('Media settings') g_media.setFlat(True) g_media_layout = QFormLayout() self.tracker_enabled = QCheckBox() self.tracker_enabled.toggled.connect(self.tracker_type_change) self.tracker_type = QComboBox() for (n, label) in utils.available_trackers: self.tracker_type.addItem(label, n) self.tracker_type.currentIndexChanged.connect(self.tracker_type_change) self.tracker_interval = QSpinBox() self.tracker_interval.setRange(5, 1000) self.tracker_interval.setMaximumWidth(60) self.tracker_process = QLineEdit() self.tracker_update_wait = QSpinBox() self.tracker_update_wait.setRange(0, 1000) self.tracker_update_wait.setMaximumWidth(60) self.tracker_update_close = QCheckBox() self.tracker_update_prompt = QCheckBox() self.tracker_not_found_prompt = QCheckBox() g_media_layout.addRow('Enable tracker', self.tracker_enabled) g_media_layout.addRow('Tracker type', self.tracker_type) g_media_layout.addRow('Tracker interval (seconds)', self.tracker_interval) g_media_layout.addRow('Process name (regex)', self.tracker_process) g_media_layout.addRow('Wait before updating (seconds)', self.tracker_update_wait) g_media_layout.addRow('Wait until the player is closed', self.tracker_update_close) g_media_layout.addRow('Ask before updating', self.tracker_update_prompt) g_media_layout.addRow('Ask to add new shows', self.tracker_not_found_prompt) g_media.setLayout(g_media_layout) # Group: Plex settings g_plex = QGroupBox('Plex Media Server') g_plex.setFlat(True) self.plex_host = QLineEdit() self.plex_port = QLineEdit() self.plex_user = QLineEdit() self.plex_passw = QLineEdit() self.plex_passw.setEchoMode(QLineEdit.Password) self.plex_obey_wait = QCheckBox() g_plex_layout = QGridLayout() g_plex_layout.addWidget(QLabel('Host and Port'), 0, 0, 1, 1) g_plex_layout.addWidget(self.plex_host, 0, 1, 1, 1) g_plex_layout.addWidget(self.plex_port, 0, 2, 1, 2) g_plex_layout.addWidget(QLabel('Use "wait before updating" time'), 1, 0, 1, 1) g_plex_layout.addWidget(self.plex_obey_wait, 1, 2, 1, 1) g_plex_layout.addWidget(QLabel('myPlex login (claimed server)'), 2, 0, 1, 1) g_plex_layout.addWidget(self.plex_user, 2, 1, 1, 1) g_plex_layout.addWidget(self.plex_passw, 2, 2, 1, 2) g_plex.setLayout(g_plex_layout) # Group: Library g_playnext = QGroupBox('Library') g_playnext.setFlat(True) self.player = QLineEdit() self.player_browse = QPushButton('Browse...') self.player_browse.clicked.connect(self.s_player_browse) lbl_searchdirs = QLabel('Media directories') lbl_searchdirs.setAlignment(QtCore.Qt.AlignTop) self.searchdirs = QListWidget() self.searchdirs_add = QPushButton('Add...') self.searchdirs_add.clicked.connect(self.s_searchdirs_add) self.searchdirs_remove = QPushButton('Remove') self.searchdirs_remove.clicked.connect(self.s_searchdirs_remove) self.searchdirs_buttons = QVBoxLayout() self.searchdirs_buttons.setAlignment(QtCore.Qt.AlignTop) self.searchdirs_buttons.addWidget(self.searchdirs_add) self.searchdirs_buttons.addWidget(self.searchdirs_remove) self.searchdirs_buttons.addWidget(QSplitter()) self.library_autoscan = QCheckBox() self.scan_whole_list = QCheckBox() self.library_full_path = QCheckBox() g_playnext_layout = QGridLayout() g_playnext_layout.addWidget(QLabel('Player'), 0, 0, 1, 1) g_playnext_layout.addWidget(self.player, 0, 1, 1, 1) g_playnext_layout.addWidget(self.player_browse, 0, 2, 1, 1) g_playnext_layout.addWidget(lbl_searchdirs, 1, 0, 1, 1) g_playnext_layout.addWidget(self.searchdirs, 1, 1, 1, 1) g_playnext_layout.addLayout(self.searchdirs_buttons, 1, 2, 1, 1) g_playnext_layout.addWidget(QLabel('Rescan Library at startup'), 2, 0, 1, 2) g_playnext_layout.addWidget(self.library_autoscan, 2, 2, 1, 1) g_playnext_layout.addWidget(QLabel('Scan through whole list'), 3, 0, 1, 2) g_playnext_layout.addWidget(self.scan_whole_list, 3, 2, 1, 1) g_playnext_layout.addWidget(QLabel('Take subdirectory name into account'), 4, 0, 1, 2) g_playnext_layout.addWidget(self.library_full_path, 4, 2, 1, 1) g_playnext.setLayout(g_playnext_layout) # Media form page_media_layout.addWidget(g_media) page_media_layout.addWidget(g_plex) page_media_layout.addWidget(g_playnext) page_media.setLayout(page_media_layout) # Sync tab page_sync = QWidget() page_sync_layout = QVBoxLayout() page_sync_layout.setAlignment(QtCore.Qt.AlignTop) # Group: Autoretrieve g_autoretrieve = QGroupBox('Autoretrieve') g_autoretrieve.setFlat(True) self.autoretrieve_off = QRadioButton('Disabled') self.autoretrieve_always = QRadioButton('Always at start') self.autoretrieve_days = QRadioButton('After n days') self.autoretrieve_days.toggled.connect(self.s_autoretrieve_days) self.autoretrieve_days_n = QSpinBox() self.autoretrieve_days_n.setRange(1, 100) g_autoretrieve_layout = QGridLayout() g_autoretrieve_layout.setColumnStretch(0, 1) g_autoretrieve_layout.addWidget(self.autoretrieve_off, 0, 0, 1, 1) g_autoretrieve_layout.addWidget(self.autoretrieve_always, 1, 0, 1, 1) g_autoretrieve_layout.addWidget(self.autoretrieve_days, 2, 0, 1, 1) g_autoretrieve_layout.addWidget(self.autoretrieve_days_n, 2, 1, 1, 1) g_autoretrieve.setLayout(g_autoretrieve_layout) # Group: Autosend g_autosend = QGroupBox('Autosend') g_autosend.setFlat(True) self.autosend_off = QRadioButton('Disabled') self.autosend_always = QRadioButton('Immediately after every change') self.autosend_minutes = QRadioButton('After n minutes') self.autosend_minutes.toggled.connect(self.s_autosend_minutes) self.autosend_minutes_n = QSpinBox() self.autosend_minutes_n.setRange(1, 1000) self.autosend_size = QRadioButton('After the queue reaches n items') self.autosend_size.toggled.connect(self.s_autosend_size) self.autosend_size_n = QSpinBox() self.autosend_size_n.setRange(2, 20) self.autosend_at_exit = QCheckBox('At exit') g_autosend_layout = QGridLayout() g_autosend_layout.setColumnStretch(0, 1) g_autosend_layout.addWidget(self.autosend_off, 0, 0, 1, 1) g_autosend_layout.addWidget(self.autosend_always, 1, 0, 1, 1) g_autosend_layout.addWidget(self.autosend_minutes, 2, 0, 1, 1) g_autosend_layout.addWidget(self.autosend_minutes_n, 2, 1, 1, 1) g_autosend_layout.addWidget(self.autosend_size, 3, 0, 1, 1) g_autosend_layout.addWidget(self.autosend_size_n, 3, 1, 1, 1) g_autosend_layout.addWidget(self.autosend_at_exit, 4, 0, 1, 1) g_autosend.setLayout(g_autosend_layout) # Group: Extra g_extra = QGroupBox('Additional options') g_extra.setFlat(True) self.auto_status_change = QCheckBox('Change status automatically') self.auto_status_change.toggled.connect(self.s_auto_status_change) self.auto_status_change_if_scored = QCheckBox('Change status automatically only if scored') self.auto_date_change = QCheckBox('Change start and finish dates automatically') g_extra_layout = QVBoxLayout() g_extra_layout.addWidget(self.auto_status_change) g_extra_layout.addWidget(self.auto_status_change_if_scored) g_extra_layout.addWidget(self.auto_date_change) g_extra.setLayout(g_extra_layout) # Sync layout page_sync_layout.addWidget(g_autoretrieve) page_sync_layout.addWidget(g_autosend) page_sync_layout.addWidget(g_extra) page_sync.setLayout(page_sync_layout) # UI tab page_ui = QWidget() page_ui_layout = QFormLayout() page_ui_layout.setAlignment(QtCore.Qt.AlignTop) # Group: Icon g_icon = QGroupBox('Notification Icon') g_icon.setFlat(True) self.tray_icon = QCheckBox('Show tray icon') self.tray_icon.toggled.connect(self.s_tray_icon) self.close_to_tray = QCheckBox('Close to tray') self.start_in_tray = QCheckBox('Start minimized to tray') self.tray_api_icon = QCheckBox('Use API icon as tray icon') self.notifications = QCheckBox('Show notification when tracker detects new media') g_icon_layout = QVBoxLayout() g_icon_layout.addWidget(self.tray_icon) g_icon_layout.addWidget(self.close_to_tray) g_icon_layout.addWidget(self.start_in_tray) g_icon_layout.addWidget(self.tray_api_icon) g_icon_layout.addWidget(self.notifications) g_icon.setLayout(g_icon_layout) # Group: Window g_window = QGroupBox('Window') g_window.setFlat(True) self.remember_geometry = QCheckBox('Remember window size and position') self.remember_columns = QCheckBox('Remember column layouts and widths') self.columns_per_api = QCheckBox('Use different visible columns per API') g_window_layout = QVBoxLayout() g_window_layout.addWidget(self.remember_geometry) g_window_layout.addWidget(self.remember_columns) g_window_layout.addWidget(self.columns_per_api) g_window.setLayout(g_window_layout) # Group: Lists g_lists = QGroupBox('Lists') g_lists.setFlat(True) self.filter_bar_position = QComboBox() filter_bar_positions = [(FilterBar.PositionHidden, 'Hidden'), (FilterBar.PositionAboveLists, 'Above lists'), (FilterBar.PositionBelowLists, 'Below lists')] for (n, label) in filter_bar_positions: self.filter_bar_position.addItem(label, n) self.inline_edit = QCheckBox('Enable in-line editing') g_lists_layout = QFormLayout() g_lists_layout.addRow('Filter bar position:', self.filter_bar_position) g_lists_layout.addRow(self.inline_edit) g_lists.setLayout(g_lists_layout) # UI layout page_ui_layout.addWidget(g_icon) page_ui_layout.addWidget(g_window) page_ui_layout.addWidget(g_lists) page_ui.setLayout(page_ui_layout) # Theming tab page_theme = QWidget() page_theme_layout = QFormLayout() page_theme_layout.setAlignment(QtCore.Qt.AlignTop) # Group: Episode Bar g_ep_bar = QGroupBox('Episode Bar') g_ep_bar.setFlat(True) self.ep_bar_style = QComboBox() ep_bar_styles = [(ShowsTableDelegate.BarStyleBasic, 'Basic'), (ShowsTableDelegate.BarStyle04, 'Trackma'), (ShowsTableDelegate.BarStyleHybrid, 'Hybrid')] for (n, label) in ep_bar_styles: self.ep_bar_style.addItem(label, n) self.ep_bar_style.currentIndexChanged.connect(self.s_ep_bar_style) self.ep_bar_text = QCheckBox('Show text label') g_ep_bar_layout = QFormLayout() g_ep_bar_layout.addRow('Style:', self.ep_bar_style) g_ep_bar_layout.addRow(self.ep_bar_text) g_ep_bar.setLayout(g_ep_bar_layout) # Group: Colour scheme g_scheme = QGroupBox('Color Scheme') g_scheme.setFlat(True) col_tabs = [('rows', '&Row highlights'), ('progress', '&Progress widget')] self.colors = {} self.colors['rows'] = [('is_playing', 'Playing'), ('is_queued', 'Queued'), ('new_episode', 'New Episode'), ('is_airing', 'Airing'), ('not_aired', 'Unaired')] self.colors['progress'] = [('progress_bg', 'Background'), ('progress_fg', 'Watched bar'), ('progress_sub_bg', 'Aired episodes'), ('progress_sub_fg', 'Stored episodes'), ('progress_complete', 'Complete')] self.color_buttons = [] self.syscolor_buttons = [] g_scheme_layout = QGridLayout() tw_scheme = QTabWidget() for (key, tab_title) in col_tabs: page = QFrame() page_layout = QGridLayout() col = 0 # Generate widgets from the keys and values for (key, label) in self.colors[key]: self.color_buttons.append(QPushButton()) # self.color_buttons[-1].setStyleSheet('background-color: ' + getColor(self.config['colors'][key]).name()) self.color_buttons[-1].setFocusPolicy(QtCore.Qt.NoFocus) self.color_buttons[-1].clicked.connect(self.s_color_picker(key, False)) self.syscolor_buttons.append(QPushButton('System Colors')) self.syscolor_buttons[-1].clicked.connect(self.s_color_picker(key, True)) page_layout.addWidget(QLabel(label), col, 0, 1, 1) page_layout.addWidget(self.color_buttons[-1], col, 1, 1, 1) page_layout.addWidget(self.syscolor_buttons[-1], col, 2, 1, 1) col += 1 page.setLayout(page_layout) tw_scheme.addTab(page, tab_title) g_scheme_layout.addWidget(tw_scheme) g_scheme.setLayout(g_scheme_layout) # UI layout page_theme_layout.addWidget(g_ep_bar) page_theme_layout.addWidget(g_scheme) page_theme.setLayout(page_theme_layout) # Content self.contents = QStackedWidget() self.contents.addWidget(page_media) self.contents.addWidget(page_sync) self.contents.addWidget(page_ui) self.contents.addWidget(page_theme) if pyqt_version is not 5: self.contents.layout().setMargin(0) # Bottom buttons bottombox = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Apply | QDialogButtonBox.Cancel ) bottombox.accepted.connect(self.s_save) bottombox.button(QDialogButtonBox.Apply).clicked.connect(self._save) bottombox.rejected.connect(self.reject) # Main layout finish layout.addWidget(self.category_list, 0, 0, 1, 1) layout.addWidget(self.contents, 0, 1, 1, 1) layout.addWidget(bottombox, 1, 0, 1, 2) layout.setColumnStretch(1, 1) self._load() self.update_colors() self.setLayout(layout) def _add_dir(self, path): self.searchdirs.addItem(path) def _load(self): engine = self.worker.engine tracker_type = self.tracker_type.findData(engine.get_config('tracker_type')) autoretrieve = engine.get_config('autoretrieve') autosend = engine.get_config('autosend') self.tracker_enabled.setChecked(engine.get_config('tracker_enabled')) self.tracker_type.setCurrentIndex(max(0, tracker_type)) self.tracker_interval.setValue(engine.get_config('tracker_interval')) self.tracker_process.setText(engine.get_config('tracker_process')) self.tracker_update_wait.setValue(engine.get_config('tracker_update_wait_s')) self.tracker_update_close.setChecked(engine.get_config('tracker_update_close')) self.tracker_update_prompt.setChecked(engine.get_config('tracker_update_prompt')) self.tracker_not_found_prompt.setChecked(engine.get_config('tracker_not_found_prompt')) self.player.setText(engine.get_config('player')) self.library_autoscan.setChecked(engine.get_config('library_autoscan')) self.scan_whole_list.setChecked(engine.get_config('scan_whole_list')) self.library_full_path.setChecked(engine.get_config('library_full_path')) self.plex_host.setText(engine.get_config('plex_host')) self.plex_port.setText(engine.get_config('plex_port')) self.plex_obey_wait.setChecked(engine.get_config('plex_obey_update_wait_s')) self.plex_user.setText(engine.get_config('plex_user')) self.plex_passw.setText(engine.get_config('plex_passwd')) for path in engine.get_config('searchdir'): self._add_dir(path) if autoretrieve == 'always': self.autoretrieve_always.setChecked(True) elif autoretrieve == 'days': self.autoretrieve_days.setChecked(True) else: self.autoretrieve_off.setChecked(True) self.autoretrieve_days_n.setValue(engine.get_config('autoretrieve_days')) if autosend == 'always': self.autosend_always.setChecked(True) elif autosend in ('minutes', 'hours'): self.autosend_minutes.setChecked(True) elif autosend == 'size': self.autosend_size.setChecked(True) else: self.autosend_off.setChecked(True) self.autosend_minutes_n.setValue(engine.get_config('autosend_minutes')) self.autosend_size_n.setValue(engine.get_config('autosend_size')) self.autosend_at_exit.setChecked(engine.get_config('autosend_at_exit')) self.auto_status_change.setChecked(engine.get_config('auto_status_change')) self.auto_status_change_if_scored.setChecked(engine.get_config('auto_status_change_if_scored')) self.auto_date_change.setChecked(engine.get_config('auto_date_change')) self.tray_icon.setChecked(self.config['show_tray']) self.close_to_tray.setChecked(self.config['close_to_tray']) self.start_in_tray.setChecked(self.config['start_in_tray']) self.tray_api_icon.setChecked(self.config['tray_api_icon']) self.notifications.setChecked(self.config['notifications']) self.remember_geometry.setChecked(self.config['remember_geometry']) self.remember_columns.setChecked(self.config['remember_columns']) self.columns_per_api.setChecked(self.config['columns_per_api']) self.filter_bar_position.setCurrentIndex(self.filter_bar_position.findData(self.config['filter_bar_position'])) self.inline_edit.setChecked(self.config['inline_edit']) self.ep_bar_style.setCurrentIndex(self.ep_bar_style.findData(self.config['episodebar_style'])) self.ep_bar_text.setChecked(self.config['episodebar_text']) self.autoretrieve_days_n.setEnabled(self.autoretrieve_days.isChecked()) self.autosend_minutes_n.setEnabled(self.autosend_minutes.isChecked()) self.autosend_size_n.setEnabled(self.autosend_size.isChecked()) self.close_to_tray.setEnabled(self.tray_icon.isChecked()) self.start_in_tray.setEnabled(self.tray_icon.isChecked()) self.notifications.setEnabled(self.tray_icon.isChecked()) self.color_values = self.config['colors'].copy() self.tracker_type_change(None) def _save(self): engine = self.worker.engine engine.set_config('tracker_enabled', self.tracker_enabled.isChecked()) engine.set_config('tracker_type', self.tracker_type.itemData(self.tracker_type.currentIndex())) engine.set_config('tracker_interval', self.tracker_interval.value()) engine.set_config('tracker_process', str(self.tracker_process.text())) engine.set_config('tracker_update_wait_s', self.tracker_update_wait.value()) engine.set_config('tracker_update_close', self.tracker_update_close.isChecked()) engine.set_config('tracker_update_prompt', self.tracker_update_prompt.isChecked()) engine.set_config('tracker_not_found_prompt', self.tracker_not_found_prompt.isChecked()) engine.set_config('player', self.player.text()) engine.set_config('library_autoscan', self.library_autoscan.isChecked()) engine.set_config('scan_whole_list', self.scan_whole_list.isChecked()) engine.set_config('library_full_path', self.library_full_path.isChecked()) engine.set_config('plex_host', self.plex_host.text()) engine.set_config('plex_port', self.plex_port.text()) engine.set_config('plex_obey_update_wait_s', self.plex_obey_wait.isChecked()) engine.set_config('plex_user', self.plex_user.text()) engine.set_config('plex_passwd', self.plex_passw.text()) engine.set_config('searchdir', [self.searchdirs.item(i).text() for i in range(self.searchdirs.count())]) if self.autoretrieve_always.isChecked(): engine.set_config('autoretrieve', 'always') elif self.autoretrieve_days.isChecked(): engine.set_config('autoretrieve', 'days') else: engine.set_config('autoretrieve', 'off') engine.set_config('autoretrieve_days', self.autoretrieve_days_n.value()) if self.autosend_always.isChecked(): engine.set_config('autosend', 'always') elif self.autosend_minutes.isChecked(): engine.set_config('autosend', 'minutes') elif self.autosend_size.isChecked(): engine.set_config('autosend', 'size') else: engine.set_config('autosend', 'off') engine.set_config('autosend_minutes', self.autosend_minutes_n.value()) engine.set_config('autosend_size', self.autosend_size_n.value()) engine.set_config('autosend_at_exit', self.autosend_at_exit.isChecked()) engine.set_config('auto_status_change', self.auto_status_change.isChecked()) engine.set_config('auto_status_change_if_scored', self.auto_status_change_if_scored.isChecked()) engine.set_config('auto_date_change', self.auto_date_change.isChecked()) engine.save_config() self.config['show_tray'] = self.tray_icon.isChecked() self.config['close_to_tray'] = self.close_to_tray.isChecked() self.config['start_in_tray'] = self.start_in_tray.isChecked() self.config['tray_api_icon'] = self.tray_api_icon.isChecked() self.config['notifications'] = self.notifications.isChecked() self.config['remember_geometry'] = self.remember_geometry.isChecked() self.config['remember_columns'] = self.remember_columns.isChecked() self.config['columns_per_api'] = self.columns_per_api.isChecked() self.config['filter_bar_position'] = self.filter_bar_position.itemData(self.filter_bar_position.currentIndex()) self.config['inline_edit'] = self.inline_edit.isChecked() self.config['episodebar_style'] = self.ep_bar_style.itemData(self.ep_bar_style.currentIndex()) self.config['episodebar_text'] = self.ep_bar_text.isChecked() self.config['colors'] = self.color_values utils.save_config(self.config, self.configfile) self.saved.emit() def s_save(self): self._save() self.accept() def tracker_type_change(self, checked): if self.tracker_enabled.isChecked(): self.tracker_interval.setEnabled(True) self.tracker_update_wait.setEnabled(True) self.tracker_type.setEnabled(True) if self.tracker_type.itemData(self.tracker_type.currentIndex()) == 'plex': self.plex_host.setEnabled(True) self.plex_port.setEnabled(True) self.plex_obey_wait.setEnabled(True) self.plex_user.setEnabled(True) self.plex_passw.setEnabled(True) self.tracker_process.setEnabled(False) else: self.tracker_process.setEnabled(True) self.plex_host.setEnabled(False) self.plex_port.setEnabled(False) self.plex_user.setEnabled(False) self.plex_passw.setEnabled(False) self.plex_obey_wait.setEnabled(False) else: self.tracker_type.setEnabled(False) self.plex_host.setEnabled(False) self.plex_port.setEnabled(False) self.plex_user.setEnabled(False) self.plex_passw.setEnabled(False) self.plex_obey_wait.setEnabled(False) self.tracker_process.setEnabled(False) self.tracker_interval.setEnabled(False) self.tracker_update_wait.setEnabled(False) def s_autoretrieve_days(self, checked): self.autoretrieve_days_n.setEnabled(checked) def s_autosend_minutes(self, checked): self.autosend_minutes_n.setEnabled(checked) def s_autosend_size(self, checked): self.autosend_size_n.setEnabled(checked) def s_tray_icon(self, checked): self.close_to_tray.setEnabled(checked) self.start_in_tray.setEnabled(checked) self.tray_api_icon.setEnabled(checked) self.notifications.setEnabled(checked) def s_ep_bar_style(self, index): if self.ep_bar_style.itemData(index) == ShowsTableDelegate.BarStyle04: self.ep_bar_text.setEnabled(False) else: self.ep_bar_text.setEnabled(True) def s_auto_status_change(self, checked): self.auto_status_change_if_scored.setEnabled(checked) def s_player_browse(self): if pyqt_version is 5: self.player.setText(QFileDialog.getOpenFileName(caption='Choose player executable')[0]) else: self.player.setText(QFileDialog.getOpenFileName(caption='Choose player executable')) def s_searchdirs_add(self): self._add_dir(QFileDialog.getExistingDirectory(caption='Choose media directory')) def s_searchdirs_remove(self): row = self.searchdirs.currentRow() if row != -1: self.searchdirs.takeItem(row) def s_switch_page(self, new, old): if not new: new = old self.contents.setCurrentIndex(self.category_list.row(new)) def s_color_picker(self, key, system): return lambda: self.color_picker(key, system) def color_picker(self, key, system): if system is True: current = self.color_values[key] result = ThemedColorPicker.do() if result is not None and result is not current: self.color_values[key] = result self.update_colors() else: current = getColor(self.color_values[key]) result = QColorDialog.getColor(current) if result.isValid() and result is not current: self.color_values[key] = str(result.name()) self.update_colors() def update_colors(self): for ((key, label), color) in zip(self.colors['rows']+self.colors['progress'], self.color_buttons): color.setStyleSheet('background-color: ' + getColor(self.color_values[key]).name())
class EditAnnotWgt(QWidget): def __init__(self, parent=None): super().__init__(parent) self.main_window = parent # Widgets self.annotationTypesCbo = QComboBox(self) self.newAnnotationBtn = QPushButton('New', self) self.duplicateAnnotationBtn = QPushButton('Duplicate', self) self.deleteAnnotationBtn = QPushButton('Delete', self) self.viewJSONBtn = QPushButton('View JSON', self) self.saveAnnotationBtn = QPushButton('Save', self) self.commentEdt = QTextEdit('', self) self.editAnnotWgt = OrderedDict([("text", EditAnnotTextWgt(self)), ("figure", EditAnnotFigureWgt(self)), ("table", EditAnnotTableWgt(self)), ("equation", EditAnnotEquationWgt(self)), ("position", EditAnnotPositionWgt(self)), ("null", EditAnnotNullWgt(self))]) # We use the list to as a redundancy of the list of keys in annotTypesDict # because we want these to be ordered. self.annotTypeLst = list(self.editAnnotWgt.keys()) self.annotationTypesCbo.addItems(self.annotTypeLst) self.editAnnotStack = QStackedWidget(self) for annotType in self.annotTypeLst: self.editAnnotStack.addWidget(self.editAnnotWgt[annotType]) # Layout self.editAnnotGroupBox = QGroupBox() gridAddAnnotations = QGridLayout(self.editAnnotGroupBox) gridAddAnnotations.addWidget(QLabel('Annotation type', self), 2, 0) gridAddAnnotations.addWidget(self.annotationTypesCbo, 2, 1) gridAddAnnotations.addWidget(self.saveAnnotationBtn, 2, 2) gridAddAnnotations.addWidget(self.deleteAnnotationBtn, 2, 3) gridAddAnnotations.addWidget(self.newAnnotationBtn, 2, 4) gridAddAnnotations.addWidget(self.duplicateAnnotationBtn, 2, 5) gridAddAnnotations.addWidget(self.viewJSONBtn, 2, 6) gridAddAnnotations.addWidget(self.editAnnotStack, 3, 0, 1, 7) gridAddAnnotations.addWidget(QLabel('Comment', self), 4, 0) gridAddAnnotations.addWidget(self.commentEdt, 4, 1, 1, 6) self.setLayout(gridAddAnnotations) # Signals self.saveAnnotationBtn.clicked.connect(self.saveAnnotation) self.newAnnotationBtn.clicked.connect(self.newAnnotation) self.duplicateAnnotationBtn.clicked.connect(self.duplicateAnnotation) self.viewJSONBtn.clicked.connect(self.viewJSON) self.deleteAnnotationBtn.clicked.connect(self.main_window.deleteAnnotation) self.commentEdt.textChanged.connect(self.annotationChanged) self.annotationTypesCbo.currentIndexChanged.connect(self.setCurrentStack) self.main_window.selectedAnnotationChangedConfirmed.connect(self.annotationSelectionChanged) for wgt in self.editAnnotWgt.values(): self.main_window.selectedAnnotationChangedConfirmed.connect(wgt.annotationSelectionChanged) self.main_window.annotationCleared.connect(self.clearAddAnnotation) self.main_window.savingNeeded.connect(self.savingNeeded) # Initial behavior self.deleteAnnotationBtn.setDisabled(True) self.viewJSONBtn.setDisabled(True) self.annotationTypesCbo.setCurrentIndex(0) self.setCurrentStack(0) self.annotationTypesCbo.setDisabled(True) def viewJSON(self): form = JSONDlg() form.setJSON(self.currentAnnotation) if form.exec_() == QDialog.Accepted: return def saveAnnotation(self): self.main_window.saveAnnotation() self.annotationTypesCbo.setDisabled(True) def selectAnnotType(self, annotType): ind = [no for no, a in enumerate(self.annotTypeLst) if a == annotType] if len(ind) != 1: raise ValueError("Invalid annotation type string.") ind = ind[0] self.annotationTypesCbo.setCurrentIndex(ind) self.annotationTypesCbo.setEnabled(False) def setCurrentStack(self, ind): self.editAnnotStack.setCurrentIndex(ind) #for no in range(len(self.annotTypeLst)): # self.editAnnotStack.setTabEnabled(no, no == ind) @pyqtSlot() def clearAddAnnotation(self): self.commentEdt.setText("") for widget in self.editAnnotWgt.values(): widget.clearAnnotation() @property def detectAnnotChange(self): return self.main_window.detectAnnotChange def annotationTextChanged(self): if self.detectAnnotChange: self.main_window.setNeedSaving() def annotationChanged(self): if self.detectAnnotChange: self.main_window.setNeedSaving() @property def currentAnnotation(self): return self.main_window.currentAnnotation @currentAnnotation.setter def currentAnnotation(self, annotation): self.main_window.currentAnnotation = annotation @pyqtSlot() def annotationSelectionChanged(self): #self.deleteAnnotationBtn.setEnabled(True) self.newAnnotationBtn.setEnabled(True) self.duplicateAnnotationBtn.setEnabled(True) if not self.currentAnnotation is None: self.commentEdt.setText(self.currentAnnotation.comment) enableTextWidget(self.commentEdt) else: self.commentEdt.setText("") disableTextWidget(self.commentEdt) self.deleteAnnotationBtn.setDisabled(self.currentAnnotation is None) self.viewJSONBtn.setDisabled(self.currentAnnotation is None) def newAnnotation(self): if self.main_window.newAnnotation() : self.newAnnotationBtn.setEnabled(False) self.duplicateAnnotationBtn.setEnabled(False) self.deleteAnnotationBtn.setEnabled(False) self.viewJSONBtn.setDisabled(False) self.annotationTypesCbo.setEnabled(True) self.clearAddAnnotation() for widget in self.editAnnotWgt.values(): widget.newAnnotation() if "UNPUBLISHED" in self.main_window.IdTxt.text(): self.annotationTypesCbo.setEnabled(False) self.setCurrentStack(self.annotTypeLst.index("null")) self.annotationTypesCbo.setCurrentIndex(self.annotTypeLst.index("null")) else: self.annotationTypesCbo.setEnabled(True) enableTextWidget(self.commentEdt) def duplicateAnnotation(self): self.main_window.duplicateAnnotation() @pyqtSlot(bool) def savingNeeded(self, needSaving): self.saveAnnotationBtn.setEnabled(needSaving) self.updateCurrentAnnotation() def updateCurrentAnnotation(self): if not self.currentAnnotation is None: self.currentAnnotation.comment = self.commentEdt.toPlainText() if not self.main_window.username in self.currentAnnotation.users: self.currentAnnotation.users.append(self.main_window.username) self.editAnnotWgt[self.annotationTypesCbo.currentText()].updateCurrentAnnotation()